Clip via recursive subdivision

This commit is contained in:
Patrick Walton 2018-12-03 12:20:12 -08:00
parent b05e5d5281
commit 7bf5ac1098
1 changed files with 48 additions and 23 deletions

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
import {Point2D, Rect, Size2D, cross} from "./geometry"; import {Point2D, Rect, Size2D, cross, lerp} from "./geometry";
import {panic, staticCast, unwrapNull} from "./util"; import {panic, staticCast, unwrapNull} from "./util";
export const TILE_SIZE: Size2D = {width: 16.0, height: 16.0}; export const TILE_SIZE: Size2D = {width: 16.0, height: 16.0};
@ -260,45 +260,57 @@ export class Tiler {
} }
private clipEdgeX(edge: Edge, x: number): ClippedEdgesX { private clipEdgeX(edge: Edge, x: number): ClippedEdgesX {
const EPSILON: number = 0.001;
if (edge.from.x < x && edge.to.x < x) if (edge.from.x < x && edge.to.x < x)
return {left: edge, right: null}; return {left: edge, right: null};
if (edge.from.x > x && edge.to.x > x) if (edge.from.x > x && edge.to.x > x)
return {left: null, right: edge}; return {left: null, right: edge};
const from = {x: edge.from.x, y: edge.from.y, z: 1.0}; let minT = 0.0, maxT = 1.0;
const to = {x: edge.to.x, y: edge.to.y, z: 1.0}; while (maxT - minT > EPSILON) {
const clipLine = {x: 1.0, y: 0.0, z: -x }; const midT = lerp(minT, maxT, 0.5);
const edges = edge.subdivideAt(midT);
const intersectionHC = cross(cross(from, to), clipLine); if ((edges.prev.from.x < x && edges.prev.to.x > x) ||
const intersection = new Point2D(intersectionHC.x / intersectionHC.z, (edges.prev.from.x > x && edges.prev.to.x < x)) {
intersectionHC.y / intersectionHC.z); maxT = midT;
const fromEdge = new Edge(edge.from, intersection); } else {
const toEdge = new Edge(intersection, edge.to); minT = midT;
}
}
const midT = lerp(minT, maxT, 0.5);
const edges = edge.subdivideAt(midT);
if (edge.from.x < x) if (edge.from.x < x)
return {left: fromEdge, right: toEdge}; return {left: edges.prev, right: edges.next};
return {left: toEdge, right: fromEdge}; return {left: edges.next, right: edges.prev};
} }
private clipEdgeY(edge: Edge, y: number): ClippedEdgesY { private clipEdgeY(edge: Edge, y: number): ClippedEdgesY {
const EPSILON: number = 0.001;
if (edge.from.y < y && edge.to.y < y) if (edge.from.y < y && edge.to.y < y)
return {upper: edge, lower: null}; return {upper: edge, lower: null};
if (edge.from.y > y && edge.to.y > y) if (edge.from.y > y && edge.to.y > y)
return {upper: null, lower: edge}; return {upper: null, lower: edge};
const from = {x: edge.from.x, y: edge.from.y, z: 1.0}; let minT = 0.0, maxT = 1.0;
const to = {x: edge.to.x, y: edge.to.y, z: 1.0}; while (maxT - minT > EPSILON) {
const clipLine = {x: 0.0, y: 1.0, z: -y }; const midT = lerp(minT, maxT, 0.5);
const edges = edge.subdivideAt(midT);
const intersectionHC = cross(cross(from, to), clipLine); if ((edges.prev.from.y < y && edges.prev.to.y > y) ||
const intersection = new Point2D(intersectionHC.x / intersectionHC.z, (edges.prev.from.y > y && edges.prev.to.y < y)) {
intersectionHC.y / intersectionHC.z); maxT = midT;
const fromEdge = new Edge(edge.from, intersection); } else {
const toEdge = new Edge(intersection, edge.to); minT = midT;
}
}
const midT = lerp(minT, maxT, 0.5);
const edges = edge.subdivideAt(midT);
if (edge.from.y < y) if (edge.from.y < y)
return {upper: fromEdge, lower: toEdge}; return {upper: edges.prev, lower: edges.next};
return {upper: toEdge, lower: fromEdge}; return {upper: edges.next, lower: edges.prev};
} }
private prevEdgeFromEndpoint(endpointIndex: EndpointIndex): Edge { private prevEdgeFromEndpoint(endpointIndex: EndpointIndex): Edge {
@ -371,6 +383,19 @@ class Edge {
this.to = to; this.to = to;
Object.freeze(this); Object.freeze(this);
} }
subdivideAt(t: number): SubdividedEdges {
const mid = this.from.lerp(this.to, t);
return {
prev: new Edge(this.from, mid),
next: new Edge(mid, this.to),
};
}
}
interface SubdividedEdges {
prev: Edge;
next: Edge;
} }
class Strip { class Strip {