Skip to content

Commit

Permalink
feat: change interface to consume a single polygon with holes
Browse files Browse the repository at this point in the history
  • Loading branch information
frederic-schwarz committed Jan 11, 2024
1 parent 2762ea9 commit eebbb75
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 172 deletions.
56 changes: 36 additions & 20 deletions src/demo.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { drawScene } from './draw-scene';
import { loadMap } from './load-map';
import { calculateVisibility } from './visibility';
import { Rectangle } from './rectangle';
import { Segment } from './segment';
import { Point } from './point';
import { Point, PolygonWithHoles } from './types';

// Prepare canvas
const canvas = document.getElementById('scene') as HTMLCanvasElement;
Expand All @@ -18,28 +16,46 @@ const xOffset = 0.5;
const yOffset = 0.5;
ctx.translate(xOffset, yOffset);

// Setup scene
const room = new Rectangle(0, 0, 700, 500);

const walls = [
new Segment(20, 20, 20, 120),
new Segment(20, 20, 100, 20),
new Segment(100, 20, 150, 100),
new Segment(150, 100, 50, 100),
const polygon: PolygonWithHoles = [
[
[0, 0],
[200, 0],
[200, 200],
[220, 200],
[220, 50],
[700, 50],
[700, 500],
[600, 500],
[600, 300],
[400, 300],
[400, 320],
[580, 320],
[580, 450],
[0, 450],
],
[
[120, 100],
[150, 100],
[150, 250],
[250, 250],
[250, 270],
[120, 270],
],
[
[400, 150],
[500, 150],
[500, 250],
[400, 250]
]
];

const blocks = [
new Rectangle(50, 150, 20, 20),
new Rectangle(150, 150, 40, 80),
new Rectangle(400, 400, 40, 40),
];

const run = (lightSource: Point) => {
const endpoints = loadMap(room, blocks, walls, lightSource);
const visibility = calculateVisibility(lightSource, endpoints);
const run = (point: Point) => {
const { endPoints, segments} = loadMap(polygon, point);
const visibility = calculateVisibility(point, endPoints);

requestAnimationFrame(() =>
drawScene(ctx, lightSource, blocks, walls, visibility));
drawScene(ctx, point, segments, visibility));
};

canvas.addEventListener('mousemove', ({ pageX, pageY }) => {
Expand Down
24 changes: 6 additions & 18 deletions src/draw-scene.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { Point } from './point';
import { Rectangle } from './rectangle';
import { Segment } from './segment';
import { EndPoint } from './end-point';

const drawRectangle = (ctx: CanvasRenderingContext2D, color: string, rectangle: Rectangle) => {
ctx.save();
ctx.strokeStyle = 'black';
ctx.strokeRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
ctx.restore();
};
import { Point, Segment } from './types';

const drawSegment = (ctx: CanvasRenderingContext2D, color: string, segment: Segment) => {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.strokeStyle = color;
ctx.moveTo(segment.p1.x, segment.p1.y);
ctx.lineTo(segment.p2.x, segment.p2.y);
ctx.closePath();
Expand All @@ -36,13 +26,11 @@ const drawVisibilityTriangles = (ctx: CanvasRenderingContext2D, color: string, l
ctx.restore();
};

export const drawScene = (ctx: CanvasRenderingContext2D, lightSource: Point, blocks: Rectangle[], walls: Segment[], visibilityOutput: Point[][]) => {
export const drawScene = (ctx: CanvasRenderingContext2D, lightSource: Point, segments: Segment[], visibilityOutput: Point[][]) => {
ctx.clearRect(-10000, -10000, 20000, 20000);
for (const block of blocks) {
drawRectangle(ctx, 'blue', block);
}
for (const wall of walls) {
drawSegment(ctx, 'red', wall);
for (const segment of segments) {
drawSegment(ctx, 'blue', segment);
}

drawVisibilityTriangles(ctx, 'gray', lightSource, visibilityOutput);
};
14 changes: 0 additions & 14 deletions src/end-point.ts

This file was deleted.

17 changes: 0 additions & 17 deletions src/endpoint-compare.ts

This file was deleted.

4 changes: 1 addition & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export { loadMap } from './load-map';
export { calculateVisibility } from './visibility';
export { Rectangle } from './rectangle';
export { Segment } from './segment';
export { Point } from './point';
export { Point, EndPoint, Segment, type PolygonWithHoles } from './types';
16 changes: 0 additions & 16 deletions src/line-intersection.ts

This file was deleted.

25 changes: 9 additions & 16 deletions src/load-map.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { Segment } from './segment';
import { Rectangle } from './rectangle';
import { Point } from './point';
import { EndPoint } from './end-point';
import { Point, EndPoint, Segment, PolygonWithHoles } from './types';

const calculateEndPointAngles = (lightSource: Point, segment: Segment) => {
const { x, y } = lightSource;
Expand Down Expand Up @@ -36,22 +33,18 @@ const processSegments = (lightSource: Point, segments: Segment[]) => {
return segments;
};

export function loadMap(room: Rectangle, blocks: Rectangle[], walls: Segment[], lightSource: Point): EndPoint[] {
export function loadMap(polygon: PolygonWithHoles, point: Point): { endPoints: EndPoint[], segments: Segment[] } {
const segments: Segment[] = [];
for (const segment of room.getCornerSegments()) {
segments.push(segment);
}
for (const block of blocks) {
for (const segment of block.getCornerSegments()) {
segments.push(segment);
for (const loop of polygon) {
for (let i = 0; i < loop.length; i++) {
const currentPoint = loop[i];
const nextPoint = loop[i < loop.length - 1 ? i + 1 : 0];
segments.push(new Segment(currentPoint[0], currentPoint[1], nextPoint[0], nextPoint[1]));
}
}
for (const segment of walls) {
segments.push(segment);
}
const endPoints: EndPoint[] = [];
for (const segment of processSegments(lightSource, segments)) {
for (const segment of processSegments(point, segments)) {
endPoints.push(segment.p1, segment.p2);
}
return endPoints;
return { endPoints, segments };
}
7 changes: 0 additions & 7 deletions src/point.ts

This file was deleted.

32 changes: 0 additions & 32 deletions src/rectangle.ts

This file was deleted.

19 changes: 0 additions & 19 deletions src/segment.ts

This file was deleted.

30 changes: 30 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export class Point {
constructor(public x: number, public y: number) {}
}

export class EndPoint extends Point {
public beginsSegment?: any;
public segment?: any;
public angle?: any;

constructor(public x: number, public y: number) {
super(x, y);
}
}

export class Segment {
public p1: EndPoint;
public p2: EndPoint;
public d: number = 0;

constructor(x1: number, y1: number, x2: number, y2: number) {
this.p1 = new EndPoint(x1, y1);
this.p2 = new EndPoint(x2, y2);
this.p1.segment = this;
this.p2.segment = this;
}
}

export type Vector2 = [number, number];

export type PolygonWithHoles = Vector2[][];
31 changes: 29 additions & 2 deletions src/segment-in-front-of.ts → src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Point } from './point';
import { Segment } from './segment';
import { EndPoint, Point, Segment } from './types';

const leftOf = (segment: Segment, point: Point) => {
const cross = (segment.p2.x - segment.p1.x) * (point.y - segment.p1.y)
Expand Down Expand Up @@ -37,3 +36,31 @@ export const segmentInFrontOf = (segmentA: Segment, segmentB: Segment, relativeP

return false;
};

export function lineIntersection(point1: Point, point2: Point, point3: Point, point4: Point): Point {
const s = (
(point4.x - point3.x) * (point1.y - point3.y) -
(point4.y - point3.y) * (point1.x - point3.x)
) / (
(point4.y - point3.y) * (point2.x - point1.x) -
(point4.x - point3.x) * (point2.y - point1.y)
);

return new Point(point1.x + s * (point2.x - point1.x), point1.y + s * (point2.y - point1.y));
}

export function endpointCompare(pointA: EndPoint, pointB: EndPoint) {
if (pointA.angle > pointB.angle) {
return 1;
}
if (pointA.angle < pointB.angle) {
return -1;
}
if (!pointA.beginsSegment && pointB.beginsSegment) {
return 1;
}
if (pointA.beginsSegment && !pointB.beginsSegment) {
return -1;
}
return 0;
}
12 changes: 4 additions & 8 deletions src/visibility.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { lineIntersection } from './line-intersection';
import { endpointCompare } from './endpoint-compare';
import { segmentInFrontOf } from './segment-in-front-of';
import { Point } from './point';
import { EndPoint } from './end-point';
import { Segment } from './segment';
import { segmentInFrontOf, endpointCompare, lineIntersection } from './utils';
import { Point, EndPoint, Segment } from './types';

function getTrianglePoints(origin: Point, angle1: number, angle2: number, segment: Segment): Point[] {
const p1 = origin;
Expand Down Expand Up @@ -34,8 +30,8 @@ function getTrianglePoints(origin: Point, angle1: number, angle2: number, segmen
}

export function calculateVisibility(origin: Point, endpoints: EndPoint[]): Point[][] {
const openSegments = [];
const output = [];
const openSegments: Segment[] = [];
const output: Point[][] = [];
let beginAngle = 0;

endpoints.sort(endpointCompare);
Expand Down

0 comments on commit eebbb75

Please sign in to comment.