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

feat: curveHelper

parent e7d527bd
No related branches found
No related tags found
1 merge request!1feat: base project
......@@ -22,11 +22,11 @@ class Example extends PipelineData {
const line2d = new Line2d(pointsB, .01, new THREE.Color(0xffffff));
const mesh = new Mesh("../assets/suzanne.obj", new THREE.Color(0xffffff));
this.addShape(point2d, true, true);
this.addShape(point3d, true, true);
this.addShape(line1d, true, true); // gives a waring
this.addShape(line2d, true, false);
this.addShape(mesh, true, true);
this.addObject(point2d, true);
this.addObject(point3d, true);
this.addObject(line1d), true; // gives a waring
this.addObject(line2d);
this.addObject(mesh, true);
const debugHelper = new DebugHelper();
this.observers.push(debugHelper);
......
......@@ -6,8 +6,8 @@ class Demo extends PipelineData {
data(): void {
const spinningCube = new SpinningCube();
this.scene.add(spinningCube.object3d);
this.addShape(spinningCube, true, false);
this.addObject(spinningCube, false);
this.addObserver(spinningCube);
}
}
......
import * as THREE from "three";
import { Vector3 } from "three";
abstract class CubicBezierAlgorithm {
/**
......@@ -38,11 +37,11 @@ class BernsteinAlgorithm extends CubicBezierAlgorithm {
class DeCasteljauAlgorithm extends CubicBezierAlgorithm {
evaluatePosition(positions: Array<THREE.Vector3>, t: number): THREE.Vector3 {
while (positions.length > 1)
positions = DeCasteljauAlgorithm.Iteration(positions, t);
positions = DeCasteljauAlgorithm.iteration(positions, t);
return positions[0];
}
public static Iteration(points: Array<THREE.Vector3>, t: number): Array<THREE.Vector3>
public static iteration(points: Array<THREE.Vector3>, t: number): Array<THREE.Vector3>
{
var result = new Array<THREE.Vector3>();
for (let i = 0; i < points.length - 1; i++)
......
import * as THREE from 'three';
import { Line2d, Point2d } from "../core/Shapes";
import { CubicBezierCurve, DeCasteljauAlgorithm } from "./CubicBezierCurve";
......@@ -15,6 +16,8 @@ interface CurveParameter {
class Curve extends Line2d {
public positions: Array<THREE.Vector3>;
private _generator: CubicBezierCurve;
private _resolution: number;
private _offset: number;
......@@ -25,13 +28,14 @@ class Curve extends Line2d {
this._resolution = parameter.resolution;
this._offset = parameter.offset;
const positions = new Array<THREE.Vector3>();
positions.push(parameter.pointA.position);
positions.push(parameter.tangentA.position);
positions.push(parameter.tangentB.position);
positions.push(parameter.pointB.position);
this.positions = [
parameter.pointA.position(),
parameter.tangentA.position(),
parameter.tangentB.position(),
parameter.pointB.position(),
];
this._generator = new CubicBezierCurve(positions, new DeCasteljauAlgorithm());
this._generator = new CubicBezierCurve(this.positions, new DeCasteljauAlgorithm());
}
public update(_deltaTime: number): void {
......
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 dat from "dat.gui";
class CurveHelper implements PipelineObserver, PipelineRenderable {
public group: THREE.Group;
private _curve: Curve;
private _lines: Array<Line1d>;
private _offset: number;
private _speed: number = 1;
t: number = 0;
constructor(curve: Curve, offset: number = 0) {
this._curve = curve;
this._offset = offset;
this._lines = new Array<Line1d>();
this.group = new THREE.Group();
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)));
document.addEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === 'a') {
this.t = Math.max(0, Math.min(1, this.t - 0.01 * this._speed));
}
if (event.key === 'd') {
this.t = Math.max(0, Math.min(1, this.t + 0.01 * this._speed));
}
if (event.key === 'w') {
this._speed = Math.max(1, Math.min(2, this._speed + 0.1));
}
if (event.key === 's') {
this._speed = Math.max(1, Math.min(2, this._speed - 0.1));
}
});
this._lines.forEach((line) => {
this.group.add(line.object());
});
this.gui()
}
object(): THREE.Object3D<THREE.Event> {
return this.group;
}
position(): THREE.Vector3 {
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) => {
const p = position.clone();
p.z = this._offset;
points.push(p);
});
this._lines[0].points = points;
points = DeCasteljauAlgorithm.iteration(points, this.t);
this._lines[1].points = points;
points = DeCasteljauAlgorithm.iteration(points, this.t);
this._lines[2].points = points;
}
}
class CurveHelperExtension {
constructor(helper: CurveHelper) {
helper.group.position.set(0, 0, 0);
}
}
export { CurveHelper }
......@@ -2,6 +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';
class BezierDemo extends PipelineData {
public constructor() { super(); }
......@@ -29,11 +30,21 @@ class BezierDemo extends PipelineData {
color: new THREE.Color(0xffffff)
});
this.addShape(pointA, true, true);
this.addShape(tangentA, true, true);
this.addShape(pointB, true, true);
this.addShape(tangentB, true, true);
this.addShape(curve, true, false);
const curveHelper = new CurveHelper(curve, -.5);
this.addObject(curve);
this.addObject(curveHelper);
this.addObject(pointA, true);
this.addObject(tangentA, true);
this.addObject(pointB, true);
this.addObject(tangentB, true);
this.addObserver(curve);
this.addObserver(curveHelper);
this.addObserver(pointA);
this.addObserver(tangentA);
this.addObserver(pointB);
this.addObserver(tangentB);
}
}
......
......@@ -2,17 +2,30 @@ import * as THREE from "three";
import { DragControls } from "three/examples/jsm/controls/DragControls";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { Shape } from "./Shapes";
interface PipelineObserver {
/**
* @breif RendererObserver is an abstract class that is used to observe the renderer.
* PipelineObserver is an abstract class that is used to observe the renderer.
* The renderer calls in the rendering loop update of this observer.
* @param {number} _deltaTime gives the time in seconds between two frames
*/
update(_deltaTime: number): void;
}
interface PipelineRenderable {
/**
* PipelineRenderable is an abstract class that is used to have a unified interface
* to access 3d objectes of an object.
*/
object(): THREE.Object3D;
/**
* Access the position of the 3d object directly.
*/
position(): THREE.Vector3;
}
abstract class PipelineData {
observers: Array<PipelineObserver>;
draggables: Array<THREE.Object3D>;
......@@ -25,16 +38,17 @@ abstract class PipelineData {
this.data();
}
protected addShape(shape: Shape, observer: boolean = true, draggable: boolean = false) {
this.scene.add(shape.object3d);
if (observer) {
this.observers.push(shape);
}
protected addObject(renderable: PipelineRenderable, draggable: boolean = false) {
this.scene.add(renderable.object());
if (draggable) {
this.draggables.push(shape.object3d);
this.draggables.push(renderable.object());
}
}
protected addObserver(observer: PipelineObserver) {
this.observers.push(observer);
}
/**
* @brief Should define a scenario with observers, draggables and scene.
* It initializes the scene and adds the draggables to the scene.
......@@ -162,4 +176,4 @@ class Pipeline {
}
export { Pipeline, PipelineData };
export type { PipelineObserver };
export type { PipelineObserver, PipelineRenderable };
import * as THREE from "three";
import { PipelineObserver } from "./Pipeline";
import { PipelineObserver, PipelineRenderable } from "./Pipeline";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
abstract class Shape implements PipelineObserver {
abstract class Shape implements PipelineObserver, PipelineRenderable {
/**
* Any class that extends Shape must initialize this field.
......@@ -14,12 +14,12 @@ abstract class Shape implements PipelineObserver {
*/
protected _object3d!: THREE.Object3D;
public get object3d(): THREE.Object3D {
public object(): THREE.Object3D {
return this._object3d!;
}
public get position(): THREE.Vector3 {
return this.object3d.position;
public position(): THREE.Vector3 {
return this._object3d.position;
}
update(_deltaTime: number): void {/* INTENTIONAL */ }
......@@ -67,7 +67,7 @@ abstract class Point extends Shape {
public set material(material: THREE.MeshBasicMaterial | THREE.MeshLambertMaterial) {
this._material = material.clone();
this._material.color = this._color;
(this.object3d as THREE.Mesh).material = material;
(this._object3d as THREE.Mesh).material = material;
}
}
......@@ -99,8 +99,13 @@ abstract class Line extends Shape {
protected abstract _createLine(): void;
public set points(points: Array<THREE.Vector3>) {
if (this._points.length !== points.length) {
this._points = points;
this._createLine();
} else {
this._points = points;
this._geometry.setFromPoints(points);
}
}
public set color(color: THREE.Color) {
......@@ -128,7 +133,7 @@ class DebugHelper implements PipelineObserver {
}
public add(shape: Shape): void {
const box = new THREE.BoxHelper(shape.object3d);
const box = new THREE.BoxHelper(shape.object());
this._debug.set(shape, box);
}
......@@ -169,7 +174,7 @@ class Point3d extends Point {
}
function pointsToBuffer(points: Array<THREE.Vector3>): LineGeometry {
if (points.length < 2) {
if (points.length < 1) {
return new LineGeometry();
}
return new LineGeometry().setPositions(points.reduce((acc, cur) => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment