Skip to content
Snippets Groups Projects
Unverified Commit a24dfe1a authored by Jamie Temple's avatar Jamie Temple
Browse files

feat: bezierBernstein

parent 924dfca5
Branches
No related tags found
1 merge request!1feat: base project
......@@ -38,6 +38,10 @@ class Curve extends Line2d {
this._generator = new CubicBezierCurve(this.positions, new DeCasteljauAlgorithm());
}
public get resolution(): number {
return this._resolution;
}
public update(_deltaTime: number): void {
this._points = this._generator.evaluatePositions(this._resolution);
this._points.forEach((point) => {
......
import * as THREE from "three";
import { Curve } from "./Curve";
import { PipelineObserver, PipelineRenderable } from "../core/Pipeline";
import { Line1d } from "../core/Shapes";
import { DeCasteljauAlgorithm } from "./CubicBezierCurve";
import { PipelineDraggable, PipelineGUI, PipelineObserver, PipelineRenderable } from "../core/Pipeline";
import { Line1d, Point2d } from "../core/Shapes";
import { DeCasteljauAlgorithm, BernsteinAlgorithm } from "./CubicBezierCurve";
import dat from "dat.gui";
class CurveHelper implements PipelineObserver, PipelineRenderable {
class CurveHelper implements PipelineObserver, PipelineRenderable, PipelineGUI {
public curve: Curve;
public group: THREE.Group;
private _curve: Curve;
private _point: Point2d;
private _lines: Array<Line1d>;
private _offset: number;
private _speed: number = 1;
......@@ -16,11 +18,16 @@ class CurveHelper implements PipelineObserver, PipelineRenderable {
t: number = 0;
constructor(curve: Curve, offset: number = 0) {
this._curve = curve;
this.curve = curve;
this._offset = offset;
this._lines = new Array<Line1d>();
this.group = new THREE.Group();
this._point = new Point2d(.03, 32, new THREE.Color(0xff00ff));
this._point.material = new THREE.MeshBasicMaterial({
color: new THREE.Color(0xff00ff)});
this._point._object3d.position.z = this._offset;
this._lines.push(new Line1d([new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()], new THREE.Color(0xffff00)));
this._lines.push(new Line1d([new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()], new THREE.Color(0x00ffff)));
this._lines.push(new Line1d([new THREE.Vector3(), new THREE.Vector3()], new THREE.Color(0xff00ff)));
......@@ -43,11 +50,17 @@ class CurveHelper implements PipelineObserver, PipelineRenderable {
this._lines.forEach((line) => {
this.group.add(line.object());
});
this.group.add(this._point.object());
}
this.gui()
gui(gui: dat.GUI): void {
const folder = gui.addFolder('CurveHelper');
folder.add(this, 't', 0, 1, 0.01).listen();
folder.add(this, '_speed', 1, 2, 0.1).name("speed");
folder.closed = false;
}
object(): THREE.Object3D<THREE.Event> {
object(): THREE.Object3D {
return this.group;
}
......@@ -55,14 +68,9 @@ class CurveHelper implements PipelineObserver, PipelineRenderable {
return this.group.position;
}
gui() : void {
const test = new dat.GUI();
test.add(this, 't', 0, 1);
}
public update(_deltaTime: number): void {
let points = new Array<THREE.Vector3>();
this._curve.positions.forEach((position) => {
this.curve.positions.forEach((position) => {
const p = position.clone();
p.z = this._offset;
points.push(p);
......@@ -73,15 +81,107 @@ class CurveHelper implements PipelineObserver, PipelineRenderable {
this._lines[1].points = points;
points = DeCasteljauAlgorithm.iteration(points, this.t);
this._lines[2].points = points;
points = DeCasteljauAlgorithm.iteration(points, this.t);
this._point._object3d.position.x = points[0].x;
this._point._object3d.position.y = points[0].y;
}
}
class CurveHelperBernstein implements PipelineObserver, PipelineRenderable, PipelineDraggable {
private _helperReference: CurveHelper;
private _xAxis: Line1d;
private _yAxis: Line1d;
private _graphs: Array<Line1d>;
private _point: Array<Point2d>;
private _background: THREE.Mesh;
private _group: THREE.Group;
constructor(helper: CurveHelper, offset: number = 0) {
this._helperReference = helper;
this._xAxis = new Line1d(
[new THREE.Vector3(-.5, -.5, 0), new THREE.Vector3(.5, -.5, 0)],
new THREE.Color(0xff0000));
this._yAxis = new Line1d(
[new THREE.Vector3(-.5, -.5, 0), new THREE.Vector3(-.5, .5, 0)],
new THREE.Color(0x00ff00));
this._graphs = new Array<Line1d>();
this._point = new Array<Point2d>();
this._background = new THREE.Mesh(
new THREE.PlaneGeometry(1, 1),
new THREE.MeshBasicMaterial({ color: 0xffffff, opacity: 0.5, transparent: true }));
this._background.position.z = offset;
const points: Array< Array<THREE.Vector3>> = new Array< Array<THREE.Vector3>>();
for (let i = 0; i < 4; i++) {
points.push(new Array<THREE.Vector3>());
}
const resolution = this._helperReference.curve.resolution;
for (let i = 0; i < resolution + 1; i++) {
let t = i / resolution;
let coefficients = BernsteinAlgorithm.calculateCoefficients(t);
coefficients.forEach((c, index) => {
points[index].push(new THREE.Vector3(t, c, 0.001).sub(new THREE.Vector3(0.5, 0.5, 0)));
});
}
for (let i = 0; i < 4; i++) {
this._graphs.push(new Line1d(points[i], new THREE.Color(0x0000ff)));
}
const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
const coefficient = BernsteinAlgorithm.calculateCoefficients(this._helperReference.t);
for (let i = 0; i < 4; i++) {
this._point.push(new Point2d(.02, 32, new THREE.Color(0x0000ff)));
this._point[i].material = material;
this._point[i].position().copy(new THREE.Vector3(this._helperReference.t, coefficient[i], 0.001));
}
this._group = new THREE.Group();
this._group.add(this._xAxis.object());
this._group.add(this._yAxis.object());
this._graphs.forEach((graph) => {
this._group.add(graph.object());
});
this._point.forEach((point) => {
this._group.add(point.object());
});
this._group.add(this._background);
this._xAxis._object3d.parent = this._background;
this._yAxis._object3d.parent = this._background;
this._graphs.forEach((graph) => {
graph._object3d.parent = this._background;
});
this._point.forEach((point) => {
point._object3d.parent = this._background;
});
}
class CurveHelperExtension {
hitbox(): THREE.Object3D {
return this._background;
}
object(): THREE.Object3D {
return this._group;
}
constructor(helper: CurveHelper) {
helper.group.position.set(0, 0, 0);
position(): THREE.Vector3 {
return this._group.position;
}
update(_deltaTime: number): void {
const coefficient = BernsteinAlgorithm.calculateCoefficients(this._helperReference.t);
for (let i = 0; i < 4; i++) {
this._point.push(new Point2d(.02, 32, new THREE.Color(0x0000ff)));
this._point[i].position().copy(new THREE.Vector3(this._helperReference.t, coefficient[i], 0.001).sub(new THREE.Vector3(0.5, 0.5, 0)));
}
}
}
export { CurveHelper }
export { CurveHelper, CurveHelperBernstein }
......@@ -2,7 +2,7 @@ import * as THREE from 'three';
import { PipelineData } from "../core/Pipeline";
import { Point2d } from "../core/Shapes";
import { Curve } from './Curve';
import { CurveHelper } from './CurveHelper';
import { CurveHelper, CurveHelperBernstein } from './CurveHelper';
class BezierDemo extends PipelineData {
public constructor() { super(); }
......@@ -31,16 +31,30 @@ class BezierDemo extends PipelineData {
});
const curveHelper = new CurveHelper(curve, -.5);
const curveHelperBernstein = new CurveHelperBernstein(curveHelper, .25);
this.addObject(curve);
this.addObject(curveHelper);
this.addObject(pointA, true);
this.addObject(tangentA, true);
this.addObject(pointB, true);
this.addObject(tangentB, true);
this.addObject(curveHelperBernstein);
this.addDraggable(curveHelperBernstein);
this.addObserver(curve);
this.addObserver(curveHelper);
this.addObserver(curveHelperBernstein);
this.addGUI(curveHelper);
this.addObject(pointA);
this.addObject(tangentA);
this.addObject(pointB);
this.addObject(tangentB);
this.addDraggable(pointA);
this.addDraggable(tangentA);
this.addDraggable(pointB);
this.addDraggable(tangentB);
this.addObserver(pointA);
this.addObserver(tangentA);
this.addObserver(pointB);
......
import dat from "dat.gui";
import * as THREE from "three";
import { DragControls } from "three/examples/jsm/controls/DragControls";
......@@ -26,29 +27,51 @@ interface PipelineRenderable {
position(): THREE.Vector3;
}
interface PipelineDraggable {
/**
* THREE.Object3d that represents a hit box for the draggable.
*/
hitbox(): THREE.Object3D;
}
interface PipelineGUI {
/**
* THREE.Object3d that represents a hit box for the draggable.
*/
gui(gui: dat.GUI): void;
}
abstract class PipelineData {
observers: Array<PipelineObserver>;
guiElements: Array<PipelineGUI>;
draggables: Array<THREE.Object3D>;
scene: THREE.Scene;
constructor() {
this.observers = new Array<PipelineObserver>();
this.guiElements = new Array<PipelineGUI>();
this.draggables = new Array<THREE.Object3D>();
this.scene = new THREE.Scene();
this.data();
}
protected addObject(renderable: PipelineRenderable, draggable: boolean = false) {
protected addObject(renderable: PipelineRenderable) {
this.scene.add(renderable.object());
if (draggable) {
this.draggables.push(renderable.object());
}
protected addDraggable(draggable: PipelineDraggable) {
this.draggables.push(draggable.hitbox());
}
protected addObserver(observer: PipelineObserver) {
this.observers.push(observer);
}
protected addGUI(guiElement: PipelineGUI) {
this.guiElements.push(guiElement);
}
/**
* @brief Should define a scenario with observers, draggables and scene.
* It initializes the scene and adds the draggables to the scene.
......@@ -64,6 +87,7 @@ class Pipeline {
public orbitControls: OrbitControls;
public dragControls: DragControls;
public gui: dat.GUI;
private scene?: THREE.Scene;
private observer: Array<PipelineObserver>;
......@@ -71,7 +95,6 @@ class Pipeline {
constructor(perspective: boolean = true) {
// CREATE CAMERA
if (perspective) {
this.camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, 0.1, 1000);
......@@ -119,6 +142,7 @@ class Pipeline {
});
// INITIALISE OTHER FIELDS
this.gui = new dat.GUI();
this.observer = new Array<PipelineObserver>();
this.startTime = performance.now();
}
......@@ -127,19 +151,13 @@ class Pipeline {
this.setScene(data.scene);
data.draggables.forEach(draggable => { this.addDraggable(draggable); });
data.observers.forEach(observer => { this.addPipelineObserver(observer); });
data.guiElements.forEach(guiElement => { this.addGUI(guiElement); });
}
public addPipelineObserver(object: PipelineObserver): void {
this.observer.push(object);
}
public removePipelineObserver(object: PipelineObserver): void {
let index = this.observer.indexOf(object);
if (index > -1) {
this.observer.splice(index, 1);
}
}
public addDraggable(object: THREE.Object3D): void {
if (object instanceof THREE.Line) {
console.warn('Cannot add draggable to line');
......@@ -148,6 +166,10 @@ class Pipeline {
this.dragControls.getObjects().push(object);
}
public addGUI(object: PipelineGUI): void {
object.gui(this.gui);
}
public setScene(scene: THREE.Scene): void {
this.scene = scene;
}
......@@ -176,4 +198,4 @@ class Pipeline {
}
export { Pipeline, PipelineData };
export type { PipelineObserver, PipelineRenderable };
export type { PipelineObserver, PipelineRenderable, PipelineDraggable, PipelineGUI };
import * as THREE from "three";
import { PipelineObserver, PipelineRenderable } from "./Pipeline";
import { PipelineDraggable, PipelineObserver, PipelineRenderable } from "./Pipeline";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
......@@ -12,7 +12,7 @@ abstract class Shape implements PipelineObserver, PipelineRenderable {
* It is not enforced through the construct as initalization of other fields
* become uncomfortable.
*/
protected _object3d!: THREE.Object3D;
public _object3d!: THREE.Object3D;
public object(): THREE.Object3D {
return this._object3d!;
......@@ -25,7 +25,7 @@ abstract class Shape implements PipelineObserver, PipelineRenderable {
update(_deltaTime: number): void {/* INTENTIONAL */ }
}
abstract class Point extends Shape {
abstract class Point extends Shape implements PipelineDraggable {
private _geometry: THREE.BufferGeometry;
private _material: THREE.MeshBasicMaterial | THREE.MeshLambertMaterial;
......@@ -70,6 +70,10 @@ abstract class Point extends Shape {
(this._object3d as THREE.Mesh).material = material;
}
hitbox(): THREE.Object3D<THREE.Event> {
return this._object3d;
}
}
abstract class Line extends Shape {
......@@ -224,7 +228,7 @@ class Line2d extends Line {
}
}
class Mesh extends Shape {
class Mesh extends Shape implements PipelineDraggable {
protected _material: THREE.MeshBasicMaterial | THREE.MeshLambertMaterial;
protected _color: THREE.Color;
......@@ -271,6 +275,10 @@ class Mesh extends Shape {
}
});
}
hitbox(): THREE.Object3D<THREE.Event> {
return this._object3d;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment