diff --git a/Main.cpp b/Main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cd88549e46e520ed4bda6da171999bc59d39e3c --- /dev/null +++ b/Main.cpp @@ -0,0 +1,9 @@ +#include <iostream> + +int main(void) +{ + for (double i{0}; i < 1; i += 0.1) + { + std::cout << i << ", " << i * i << std::endl; + } +} \ No newline at end of file diff --git a/Main.exe b/Main.exe new file mode 100644 index 0000000000000000000000000000000000000000..f5db5197ebcace1de7c5f69736fc43a7ea4c3d11 Binary files /dev/null and b/Main.exe differ diff --git a/Main.obj b/Main.obj new file mode 100644 index 0000000000000000000000000000000000000000..8d5677a173b968ede47ecb0936090869b70444f4 Binary files /dev/null and b/Main.obj differ diff --git a/src/main.ts b/src/main.ts index 02481fb426df2cb6cf13f1c27f9d282ee26df86c..502c7c2bcd8d26ab77384ab47577007b509a3c2b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,29 +1,29 @@ import * as CG from "./uitls/rendering"; import * as THREE from "three"; import { UI } from "./uitls/ui"; -import { Vector3 } from "three"; import * as Interpolation from "./uitls/bezierCurve"; const render = new CG.RenderManager('#canvas', { near: 0.1, far: 1000, fov: 45, height: 1 }); const ui = new UI(); -// create a cube -let geometry = new THREE.BoxGeometry(1, 1, 1); -let material = new THREE.MeshBasicMaterial({ color: 0xfffffff }); -let cube = new THREE.Mesh(geometry, material); -// render.add(cube); - const startPoint = new THREE.Vector2(-1, -1); const endPoint = new THREE.Vector2(1, 1); const startControlPoint = new THREE.Vector2(-1, 1); const endControlPoint = new THREE.Vector2(1, -1); -const curve = new Interpolation.BezierCurveTest( +// const curve = new Interpolation.BezierCurveTest( +// startPoint, +// startControlPoint, +// endControlPoint, +// endPoint +// ) +const curve = new Interpolation.BezierCurve( startPoint, endPoint, startControlPoint, endControlPoint ) + const line = curve.createLine(); render.add(line); diff --git a/src/uitls/bezierCurve.ts b/src/uitls/bezierCurve.ts index bb9c912fe583281309828f3136dd7a8a3d39ee40..40465d9a8f4529e9deb26a865fce99253cc326c2 100644 --- a/src/uitls/bezierCurve.ts +++ b/src/uitls/bezierCurve.ts @@ -9,13 +9,17 @@ import { } from "three"; import { GUI } from "dat.gui"; +function lerp(a: Vector2, b: Vector2, t: number): Vector2 { + return new Vector2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); +} + export abstract class AbstractBezierCurve implements Modifiable, Updatable { constructor(startPoint: Vector2, endPoint: Vector2, startControlPoint: Vector2, endControlPoint: Vector2) { - this._startPoint = startPoint; - this._endPoint = endPoint; - this._startControlPoint = startControlPoint; - this._endControlPoint = endControlPoint; + this.startPoint = startPoint; + this.endPoint = endPoint; + this.startControlPoint = startControlPoint; + this.endControlPoint = endControlPoint; this._geomBuffer = new BufferGeometry(); } @@ -44,22 +48,24 @@ export abstract class AbstractBezierCurve implements Modifiable, Updatable { createElement(gui: GUI): void { const folder = gui.addFolder('Bezier Curve'); - UI.addVector(folder, this, this._startPoint, 'Start Point'); - UI.addVector(folder, this, this._endPoint, 'End Point'); - UI.addVector(folder, this, this._startControlPoint, 'Start Control Point'); - UI.addVector(folder, this, this._endControlPoint, 'End Control Point'); + UI.addVector(folder, this, this.startPoint, 'Start Point'); + UI.addVector(folder, this, this.endPoint, 'End Point'); + UI.addVector(folder, this, this.startControlPoint, 'Start Control Point'); + UI.addVector(folder, this, this.endControlPoint, 'End Control Point'); folder.add(this, "_numPoints", 10, 100).step(1).name("Points").onChange(() => { this.update(); }); } - public _startPoint: Vector2; - public _endPoint: Vector2; - public _startControlPoint: Vector2; - public _endControlPoint: Vector2; - public _numPoints: number = 100; - public _line?: Line; - public _curvePoints: Vector2[] = []; - public _geomBuffer: BufferGeometry; + public startPoint: Vector2; + public endPoint: Vector2; + public startControlPoint: Vector2; + public endControlPoint: Vector2; + + protected _numPoints: number = 100; + + private _line?: Line; + private _curvePoints: Vector2[] = []; + private _geomBuffer: BufferGeometry; } // TODO: Handles for the control points @@ -81,16 +87,16 @@ export class BezierCurveTest extends AbstractBezierCurve { generateCurvePoints(): Vector2[] { const curve = new CubicBezierCurve3( - new Vector3(this._startPoint.x, this._startPoint.y, 0), - new Vector3(this._startControlPoint.x, this._startControlPoint.y, 0), - new Vector3(this._endPoint.x, this._endPoint.y, 0), - new Vector3(this._endControlPoint.x, this._endControlPoint.y, 0) + new Vector3(this.startPoint.x, this.startPoint.y, 0), + new Vector3(this.startControlPoint.x, this.startControlPoint.y, 0), + new Vector3(this.endPoint.x, this.endPoint.y, 0), + new Vector3(this.endControlPoint.x, this.endControlPoint.y, 0) ); - + let curvePoints: Vector2[] = []; curve.getPoints(this._numPoints).forEach(point => { - curvePoints.push(new Vector2(point.x, point.y)); + curvePoints.push(new Vector2(point.x, point.y)); }); return curvePoints; @@ -99,12 +105,79 @@ export class BezierCurveTest extends AbstractBezierCurve { export class BezierCurve extends AbstractBezierCurve { - - generateCurvePoints(): Vector2[] { - let curvePoints: Vector2[] = []; - - // TODO: implement bezier curves - return curvePoints; + + bernstain(s: number): [Vector2, number[]] { + + // p(t) = (1-t)³ * p0 + 3 * (1-t)² * t * p1 + + // 3 * (1-t) * t² * p2 + t³ * p3 + // => subtitute: 1 - t = s + // p(t) = k³ * p0 + 3 * k² * t * p1 + + // 3 * k * t² * p2 + t³ * p3 + + const p0 = this.startPoint; + const p1 = this.startControlPoint; + const p2 = this.endControlPoint; + const p3 = this.endPoint; + + // set k = 1 - s => substitution + const t = s; + const k = 1 - s; + + // calculate the coefficients + const u0 = 1 * Math.pow(k, 3) * Math.pow(t, 0); + const u1 = 3 * Math.pow(k, 2) * Math.pow(t, 1); + const u2 = 3 * Math.pow(k, 1) * Math.pow(t, 2); + const u3 = 1 * Math.pow(k, 0) * Math.pow(t, 3); + + // calculate the point + const p = new Vector2( + u0 * p0.x + u1 * p1.x + u2 * p2.x + u3 * p3.x, + u0 * p0.y + u1 * p1.y + u2 * p2.y + u3 * p3.y + ); + + return [p, [u0, u1, u2, u3]]; + } + + + deCasteljau(t: number): Vector2 { + + const p0 = this.startPoint; + const p1 = this.startControlPoint; + const p2 = this.endControlPoint; + const p3 = this.endPoint; + + // iterative implementation of deCasteljau + let points: Vector2[] = [p0, p1, p2, p3]; + let temporary: Vector2[] = []; + while (points.length > 1) { + temporary = []; + for (let i = 0; i < points.length - 1; i++) + temporary.push(lerp(points[i], points[i + 1], t)); + points = temporary; } + + return points[0]; + } + + + generateCurvePoints(): Vector2[] { + const curvePoints: Vector2[] = []; + const sampleSize = 1 / this._numPoints; + + if (true) + for (let t = 0; t < 1; t += sampleSize) { + t = Math.round(t * 10000) / 10000; + curvePoints.push(this.deCasteljau(t)); + } + else + for (let s = 0; s < 1; s += sampleSize) { + s = Math.round(s * 10000) / 10000; + const [point, coefficient] = this.bernstain(s); + curvePoints.push(point); + } + + + return curvePoints; + } } \ No newline at end of file