diff --git a/dist/bresenham.html b/dist/bresenham.html new file mode 100644 index 0000000..0ef2613 --- /dev/null +++ b/dist/bresenham.html @@ -0,0 +1,43 @@ + + + + + + + + Graphische Datenverarbeitung - 2D - Bresenham + + + + + + +
+
+
+
+ +
+ Implement the Bresenham algorithm to create a rotating line +
+
+
+ +
+ Reference image. The reference uses the build-in line drawing functionality + and is smoothed. Your line will look a bit more jagged. +
+
+
+
+ + + diff --git a/dist/bresenhamsimple.html b/dist/bresenhamsimple.html new file mode 100644 index 0000000..1025ed9 --- /dev/null +++ b/dist/bresenhamsimple.html @@ -0,0 +1,43 @@ + + + + + + + + Graphische Datenverarbeitung - 2D - Bresenham + + + + + + +
+
+
+
+ +
+ Implement the Bresenham algorithm to create a single line +
+
+
+ +
+ Reference image. The reference uses the build-in line drawing functionality + and is smoothed. Your line will look a bit more jagged. +
+
+
+
+ + + diff --git a/dist/dda.html b/dist/dda.html new file mode 100644 index 0000000..95905f2 --- /dev/null +++ b/dist/dda.html @@ -0,0 +1,42 @@ + + + + + + + Graphische Datenverarbeitung - 2D - DDA + + + + + + +
+
+
+
+ +
+ Implement the DDA algorithm to create a rotating line +
+
+
+ +
+ Reference image. The reference uses the build-in line drawing functionality + and is smoothed. Your line will look a bit more jagged. +
+
+
+
+ + + diff --git a/dist/ddasimple.html b/dist/ddasimple.html new file mode 100644 index 0000000..596952d --- /dev/null +++ b/dist/ddasimple.html @@ -0,0 +1,42 @@ + + + + + + + Graphische Datenverarbeitung - 2D - Simple DDA + + + + + + +
+
+
+
+ +
+ Implement the DDA algorithm to create an single line +
+
+
+ +
+ Reference image. The reference uses the build-in line drawing functionality + and is smoothed. Your line will look a bit more jagged. +
+
+
+
+ + + diff --git a/src/04/bresenham.ts b/src/04/bresenham.ts new file mode 100644 index 0000000..f6c8cf7 --- /dev/null +++ b/src/04/bresenham.ts @@ -0,0 +1,13 @@ +/** + * Draws a line from pointA to pointB on the canvas + * with the Bresenham algorithm. + * @param {Uint8ClampedArray} data - The linearised pixel array + * @param {[number, number]} pointA - The start point of the line + * @param {[number, number]} pointB - The end point of the line + * @param {number} width - The width of the canvas + * @param {number} height - The height of the canvas + */ +export function bresenham(data: Uint8ClampedArray, pointA: [number, number], pointB: [number, number], width: number, height: number) { + + // TODO: Adapt the C-implementation at https://de.wikipedia.org/wiki/Bresenham-Algorithmus#C-Implementierung +} diff --git a/src/04/bresenhamsimple.ts b/src/04/bresenhamsimple.ts new file mode 100644 index 0000000..e680b39 --- /dev/null +++ b/src/04/bresenhamsimple.ts @@ -0,0 +1,24 @@ + function setPixel(data: Uint8ClampedArray, x: number, y: number, width: number, height: number) { + + var index = (x + y * width) * 4; + data[index + 0] = 0; + data[index + 1] = 0; + data[index + 2] = 0; + data[index + 3] = 255; +} + +/** + * Draws a line from pointA to pointB on the canvas + * with the Bresenham algorithm. + * @param {Uint8ClampedArray} data - The linearised pixel array + * @param {[number, number]} pointA - The start point of the line + * @param {[number, number]} pointB - The end point of the line + * @param {number} width - The width of the canvas + * @param {number} height - The height of the canvas + */ +export function bresenhamSimple(data: Uint8ClampedArray, pointA: [number, number], pointB: [number, number], width: number, height: number) { + + // TODO: 1. Calculate dx and dy and set the start position x and y + // TODO: 2. Calculate the initial epsilon of the bresenham algorithm + // TODO: 3. Go from pointA[0] to pointB[0], and update epsilon in each step as given in the bresenham algorithm. Increase y when necessary. +} diff --git a/src/04/dda.ts b/src/04/dda.ts new file mode 100644 index 0000000..18cc79e --- /dev/null +++ b/src/04/dda.ts @@ -0,0 +1,31 @@ +/** + * Draws a line from pointA to pointB on the canvas + * with the DDA algorithm. + * @param {Array.} data - The linearised pixel array + * @param {Array.} pointA - The start point of the line + * @param {Array.} pointB - The end point of the line + * @param {number} width - The width of the canvas + * @param {number} height - The height of the canvas + */ +export function dda( + data: Uint8ClampedArray, + pointA: [number, number], + pointB: [number, number], + width: number, height: number +) { + let setPixel = function ( + x: number, y: number, + data: Uint8ClampedArray, width: number + ) { + data[4 * (width * y + x) + 0] = 0; + data[4 * (width * y + x) + 1] = 0; + data[4 * (width * y + x) + 2] = 0; + data[4 * (width * y + x) + 3] = 255; + } + + setPixel(pointA[0], pointA[1], data, width); + setPixel(pointB[0], pointB[1], data, width); + + // TODO: Distinguish between the main direction x and y. + // TODO: Swap start and end points if necessary to reduce the number of cases. +} diff --git a/src/04/ddasimple.ts b/src/04/ddasimple.ts new file mode 100644 index 0000000..0d3898c --- /dev/null +++ b/src/04/ddasimple.ts @@ -0,0 +1,28 @@ +function setPixel(data: Uint8ClampedArray, x: number, y: number, width: number, height: number) { + + var index = (x + y * width) * 4; + data[index + 0] = 0; + data[index + 1] = 0; + data[index + 2] = 0; + data[index + 3] = 255; +} + +/** + * Draws a line from pointA to pointB on the canvas + * with the DDA algorithm. + * @param {Array.} data - The linearised pixel array + * @param {Array.} pointA - The start point of the line + * @param {Array.} pointB - The end point of the line + * @param {number} width - The width of the canvas + * @param {number} height - The height of the canvas + */ +export function ddaSimple( + data: Uint8ClampedArray, + pointA: [number, number], + pointB: [number, number], + width: number, height: number +) { + // TODO: Calculcate the slope m for a line from pointA to pointB. + // TODO: In this example, the main direction of the line is the x-direction. + // TODO: Go from the x-coordinate of pointA (pointA[0]) to the x-coordinate of pointB (pointB[0]) and calculate the y-coordinate of the pixels in between. +} diff --git a/src/04/setup-bresenham.ts b/src/04/setup-bresenham.ts new file mode 100644 index 0000000..7972e67 --- /dev/null +++ b/src/04/setup-bresenham.ts @@ -0,0 +1,64 @@ + +import 'bootstrap'; +import 'bootstrap/scss/bootstrap.scss'; +import { bresenham } from './bresenham'; + +let canvasExample: HTMLCanvasElement; +let ctxExample: CanvasRenderingContext2D; + +function updateExample(pointA: [number, number], pointB: [number, number]) { + ctxExample.clearRect(0, 0, canvasExample.width, canvasExample.height); + ctxExample.beginPath(); + ctxExample.moveTo(pointA[0], pointA[1]); + ctxExample.lineTo(pointB[0], pointB[1]); + ctxExample.stroke(); +} + +let canvasBresenham: HTMLCanvasElement; +let ctxBresenham: CanvasRenderingContext2D; +let imageDataBresenham: ImageData; + +function updateBresenham(pointA: [number, number], pointB: [number, number]) { + const data = imageDataBresenham.data; + data.fill(0); + bresenham(data, pointA, pointB, canvasBresenham.width, canvasBresenham.height); + ctxBresenham.putImageData(imageDataBresenham, 0, 0); +} + +let t = 0; + +function calculatePoints(t: number): [[number, number], [number, number]] { + const pointA = [ + Math.round((Math.cos(t) + 1) / 2 * canvasBresenham.width), + Math.round((Math.sin(t) + 1) / 2 * canvasBresenham.height) + ] as [number, number]; + const pointB = [ + Math.round((Math.cos(t + Math.PI) + 1) / 2 * canvasBresenham.width), + Math.round((Math.sin(t + Math.PI) + 1) / 2 * canvasBresenham.height) + ] as [number, number]; + return [pointA, pointB]; +} + +function updateCanvas(timestamp: number) { + t += 0.01; + const points = calculatePoints(t); + updateExample(points[0], points[1]); + updateBresenham(points[0], points[1]); + window.requestAnimationFrame(updateCanvas); +} + +window.addEventListener('load', evt => { + canvasBresenham = document.getElementById("result") as HTMLCanvasElement; + if (canvasBresenham === null) + return; + canvasBresenham.height = canvasBresenham.width; + ctxBresenham = canvasBresenham.getContext("2d"); + imageDataBresenham = ctxBresenham.getImageData( + 0, 0, canvasBresenham.width, canvasBresenham.height); + + canvasExample = document.getElementById("original") as HTMLCanvasElement; + canvasExample.height = canvasExample.width; + ctxExample = canvasExample.getContext("2d"); + + window.requestAnimationFrame(updateCanvas); +}); \ No newline at end of file diff --git a/src/04/setup-bresenhamsimple.ts b/src/04/setup-bresenhamsimple.ts new file mode 100644 index 0000000..2901fd5 --- /dev/null +++ b/src/04/setup-bresenhamsimple.ts @@ -0,0 +1,40 @@ +import 'bootstrap'; +import 'bootstrap/scss/bootstrap.scss'; +import { bresenhamSimple } from './bresenhamsimple'; + +var pointA: [ number, number ] = [ 0, 0 ]; +var pointB: [ number, number ] = [ 200, 100 ]; + +let canvasBresenham: HTMLCanvasElement; +let ctxBresenham: CanvasRenderingContext2D; +let imageDataBresenham: ImageData; + +function drawBresenham() { + + const data = imageDataBresenham.data; + data.fill(0); + bresenhamSimple(data, pointA, pointB, canvasBresenham.width, canvasBresenham.height); + ctxBresenham.putImageData(imageDataBresenham, 0, 0); +} + +window.addEventListener('load', evt => { + + canvasBresenham = document.getElementById("result") as HTMLCanvasElement; + if (canvasBresenham === null) + return; + + ctxBresenham = canvasBresenham.getContext("2d"); + imageDataBresenham = ctxBresenham.getImageData(0, 0, canvasBresenham.width, canvasBresenham.height); + + const canvasExample = document.getElementById("original") as HTMLCanvasElement; + canvasExample.height = canvasExample.width; + const ctxExample = canvasExample.getContext("2d"); + + ctxExample.clearRect(0, 0, canvasExample.width, canvasExample.height); + ctxExample.beginPath(); + ctxExample.moveTo(pointA[0], pointA[1]); + ctxExample.lineTo(pointB[0], pointB[1]); + ctxExample.stroke(); + + drawBresenham(); +}); diff --git a/src/04/setup-dda.ts b/src/04/setup-dda.ts new file mode 100644 index 0000000..845c242 --- /dev/null +++ b/src/04/setup-dda.ts @@ -0,0 +1,68 @@ + +import 'bootstrap'; +import 'bootstrap/scss/bootstrap.scss'; +import { dda } from './dda'; + +let canvasDDA: HTMLCanvasElement; +let ctxDDA: CanvasRenderingContext2D; +let imageDataDDA: ImageData; + +function updateDDA( + pointA: [number, number], + pointB: [number, number] +) { + const data = imageDataDDA.data; + data.fill(0); + dda(data, pointA, pointB, canvasDDA.width, canvasDDA.height); + ctxDDA.putImageData(imageDataDDA, 0, 0); +} + +let canvasExample: HTMLCanvasElement; +let ctxExample: CanvasRenderingContext2D; + +function updateExample( + pointA: [number, number], + pointB: [number, number] +) { + ctxExample.clearRect(0, 0, canvasExample.width, canvasExample.height); + ctxExample.beginPath(); + ctxExample.moveTo(pointA[0], pointA[1]); + ctxExample.lineTo(pointB[0], pointB[1]); + ctxExample.stroke(); +} + +let t = 0; + +function calculatePoints(t: number): [[number, number], [number, number]] { + const pointA = [ + Math.round((Math.cos(t) + 1) / 2 * canvasDDA.width), + Math.round((Math.sin(t) + 1) / 2 * canvasDDA.height) + ] as [number, number]; + const pointB = [ + Math.round((Math.cos(t + Math.PI) + 1) / 2 * canvasDDA.width), + Math.round((Math.sin(t + Math.PI) + 1) / 2 * canvasDDA.height) + ] as [number, number]; + return [pointA, pointB]; +} + +function updateCanvas(timestamp: number) { + t += 0.01; + const points = calculatePoints(t); + updateExample(points[0], points[1]); + updateDDA(points[0], points[1]); + window.requestAnimationFrame(updateCanvas); +} + +window.addEventListener('load', evt => { + canvasDDA = document.getElementById("result") as HTMLCanvasElement; + if (canvasDDA === null) + return; + ctxDDA = canvasDDA.getContext("2d"); + imageDataDDA = ctxDDA.getImageData(0, 0, canvasDDA.width, canvasDDA.height); + + canvasExample = document.getElementById("original") as HTMLCanvasElement; + canvasExample.height = canvasExample.width; + ctxExample = canvasExample.getContext("2d"); + + window.requestAnimationFrame(updateCanvas); +}); \ No newline at end of file diff --git a/src/04/setup-ddasimple.ts b/src/04/setup-ddasimple.ts new file mode 100644 index 0000000..6ddb25d --- /dev/null +++ b/src/04/setup-ddasimple.ts @@ -0,0 +1,39 @@ +import 'bootstrap'; +import 'bootstrap/scss/bootstrap.scss'; +import { ddaSimple } from './ddasimple'; + +var pointA: [ number, number ] = [ 0, 0 ]; +var pointB: [ number, number ] = [ 200, 100 ]; + +let canvasDDA: HTMLCanvasElement; +let ctxDDA: CanvasRenderingContext2D; +let imageDataDDA: ImageData; + +function drawDDA() { + + const data = imageDataDDA.data; + data.fill(0); + ddaSimple(data, pointA, pointB, canvasDDA.width, canvasDDA.height); + ctxDDA.putImageData(imageDataDDA, 0, 0); +} + +window.addEventListener('load', evt => { + + canvasDDA = document.getElementById("result") as HTMLCanvasElement; + if (canvasDDA === null) + return; + ctxDDA = canvasDDA.getContext("2d"); + imageDataDDA = ctxDDA.getImageData(0, 0, canvasDDA.width, canvasDDA.height); + + const canvasExample = document.getElementById("original") as HTMLCanvasElement; + canvasExample.height = canvasExample.width; + const ctxExample = canvasExample.getContext("2d"); + + ctxExample.clearRect(0, 0, canvasExample.width, canvasExample.height); + ctxExample.beginPath(); + ctxExample.moveTo(pointA[0], pointA[1]); + ctxExample.lineTo(pointB[0], pointB[1]); + ctxExample.stroke(); + + drawDDA(); +});