diff --git a/source/Model/Behavior.ts b/source/Model/Behavior.ts index 33c7e3b..d86de8c 100644 --- a/source/Model/Behavior.ts +++ b/source/Model/Behavior.ts @@ -38,13 +38,32 @@ abstract class Behavior< */ abstract parameter?: P; + /** + * 全部影响作用前 + * @param individual 影响个体 + * @param group 影响组 + * @param model 模型 + * @param t 经过时间 + */ + public beforeEffect(individual: Individual, group: Group, model: Model, t: number): void {}; + /** * 作用影响于个体 * @param individual 影响个体 * @param group 影响组 + * @param model 模型 * @param t 经过时间 */ - abstract effect(individual: Individual, group: Group, model: Model, t: number): void; + public effect(individual: Individual, group: Group, model: Model, t: number): void {}; + + /** + * 全部影响作用后 + * @param individual 影响个体 + * @param group 影响组 + * @param model 模型 + * @param t 经过时间 + */ + public afterEffect(individual: Individual, group: Group, model: Model, t: number): void {}; } diff --git a/source/Model/CtrlObject.ts b/source/Model/CtrlObject.ts index 0a633f1..638cf7e 100644 --- a/source/Model/CtrlObject.ts +++ b/source/Model/CtrlObject.ts @@ -7,6 +7,21 @@ import type { ObjectID } from "./Renderer"; */ class CtrlObject extends LabelObject { + /** + * 颜色 + */ + public color: number[] = [.5, .5, .5]; + + /** + * 是否显示 + */ + public display: boolean = true; + + /** + * 是否更新 + */ + public update: boolean = true; + /** * 唯一标识符 */ @@ -25,6 +40,13 @@ class CtrlObject extends LabelObject { this.model = model; this.id = id; } + + /** + * 移除 + */ + public delete() { + this.model.deleteObject([this]); + } } export default CtrlObject; diff --git a/source/Model/Group.ts b/source/Model/Group.ts index 5e1e1e3..58b6cc3 100644 --- a/source/Model/Group.ts +++ b/source/Model/Group.ts @@ -37,9 +37,11 @@ class Group extends CtrlObject { public add(individual: Individual[] | Individual): this { if (Array.isArray(individual)) { for (let i = 0; i < individual.length; i++) { + individual[i].group = this; this.individuals.add(individual[i]); } } else { + individual.group = this; this.individuals.add(individual); } return this; @@ -112,13 +114,32 @@ class Group extends CtrlObject { * 执行行为影响 * @param */ - public runner(t: number): void { + public runner(t: number, effectType: "beforeEffect" | "effect" | "afterEffect" ): void { this.individuals.forEach((individual) => { for(let j = 0; j < this.behaviors.length; j++) { - this.behaviors[j].effect(individual, this, this.model, t); + this.behaviors[j][effectType](individual, this, this.model, t); } }); } + + /** + * 导出坐标数据 + */ + public exportPositionData(): Float32Array { + let index = 0; + let dataBuffer = new Float32Array(this.individuals.size * 3); + this.individuals.forEach((individual) => { + dataBuffer[index ++] = individual.position[0]; + dataBuffer[index ++] = individual.position[1]; + dataBuffer[index ++] = individual.position[2]; + }); + return dataBuffer; + } + + /** + * 绘制大小 + */ + public size: number = 60; } export default Group; diff --git a/source/Model/Model.ts b/source/Model/Model.ts index c8092ce..d07c4ed 100644 --- a/source/Model/Model.ts +++ b/source/Model/Model.ts @@ -1,13 +1,17 @@ import { Individual } from "./Individual"; import { Group } from "./Group"; +import { Range } from "./Range"; import { Emitter, EventType, EventMixin } from "./Emitter"; import { CtrlObject } from "./CtrlObject"; -import { ObjectID } from "./Renderer"; +import { ObjectID, AbstractRenderer } from "./Renderer"; type ModelEvent = { - addGroup: Group; - deleteGroup: Group[]; + groupAdd: Group; + rangeAdd: Range; + objectAdd: CtrlObject; + objectDelete: CtrlObject[]; + objectChange: CtrlObject[]; }; /** @@ -31,43 +35,127 @@ class Model extends Emitter { /** * 添加组 */ - public addGroup(): void { + public addGroup(): Group { console.log(`Model: Creat group with id ${this.idIndex}`); let group = new Group(this, this.nextId); this.objectPool.push(group); - this.emit("addGroup", group); + this.emit("groupAdd", group); + this.emit("objectAdd", group); + this.emit("objectChange", this.objectPool); + return group; } /** - * 删除组 + * 添加范围 */ - public deleteGroup(groups: Group[] | ObjectID[]): void { - let deletedGroups: Group[] = []; - this.objectPool = this.objectPool.filter((object) => { - if (!(object instanceof Group)) return true; - let deletedGroup: Group | undefined; + public addRange(): Range { + console.log(`Model: Creat range with id ${this.idIndex}`); + let range = new Range(this, this.nextId); + this.objectPool.push(range); + this.emit("rangeAdd", range); + this.emit("objectAdd", range); + this.emit("objectChange", this.objectPool); + return range; + } - for (let i = 0; i < groups.length; i++) { - if (groups[i] instanceof Group) { - if (groups[i] === object) { - deletedGroup = object; + /** + * 删除对象 + */ + public deleteObject(object: CtrlObject[] | ObjectID[]): CtrlObject[] { + let deletedObject: CtrlObject[] = []; + this.objectPool = this.objectPool.filter((currentObject) => { + let needDeleted: boolean = false; + + for (let i = 0; i < object.length; i++) { + if (object[i] instanceof CtrlObject) { + if (object[i] === currentObject) { + needDeleted = true; } } else { - if (groups[i] === object.id) { - deletedGroup = object; + if (object[i] == currentObject.id) { + needDeleted = true; } } } - if (deletedGroup) { - deletedGroups.push(deletedGroup); + if (needDeleted) { + deletedObject.push(currentObject); return false; } else { return true; } }); - this.emit("deleteGroup", deletedGroups); + if (deletedObject.length) { + console.log(`Model: Delete object ${deletedObject.map((object) => object.id).join(", ")}`); + this.emit("objectDelete", deletedObject); + this.emit("objectChange", this.objectPool); + } + return deletedObject; + } + + /** + * 渲染器 + */ + public renderer: AbstractRenderer = undefined as any; + + /** + * 绑定渲染器 + * @param renderer 渲染器 + */ + public bindRenderer(renderer: AbstractRenderer): this { + this.renderer = renderer; + return this; + } + + /** + * 更新渲染数据 + */ + public update(t: number) { + + // 清除全部渲染状态 + this.renderer.clean(); + + // 第一轮更新 + for (let i = 0; i < this.objectPool.length; i++) { + let object = this.objectPool[i]; + if (object instanceof Group && object.update) { + object.runner(t, "beforeEffect"); + } + } + + // 第二轮更新 + for (let i = 0; i < this.objectPool.length; i++) { + let object = this.objectPool[i]; + if (object instanceof Group && object.update) { + object.runner(t, "effect"); + } + } + + // 第三轮更新 + for (let i = 0; i < this.objectPool.length; i++) { + let object = this.objectPool[i]; + if (object instanceof Group && object.update) { + object.runner(t, "afterEffect"); + } + } + + // 渲染 + for (let i = 0; i < this.objectPool.length; i++) { + let object = this.objectPool[i]; + if (object.display && object instanceof Group) { + this.renderer.points(object.id, object.exportPositionData(), { + color: object.color, + size: object.size + } as any); + } + if (object.display && object instanceof Range) { + this.renderer.cube(object.id, object.position, { + color: object.color, + radius: object.radius + } as any); + } + } } } diff --git a/source/Model/Range.ts b/source/Model/Range.ts index 4bab060..6177d68 100644 --- a/source/Model/Range.ts +++ b/source/Model/Range.ts @@ -10,6 +10,11 @@ class Range extends CtrlObject { */ public position: number[] = []; + /** + * 半径 + */ + public radius: number[] = [1, 1, 1]; + } export default Range; diff --git a/source/Page/Laboratory/Laboratory.tsx b/source/Page/Laboratory/Laboratory.tsx index dc6afc7..04f1a93 100644 --- a/source/Page/Laboratory/Laboratory.tsx +++ b/source/Page/Laboratory/Laboratory.tsx @@ -24,15 +24,23 @@ class Laboratory extends Component { const canvas = document.createElement("canvas"); const renderer = new ClassicRenderer(canvas, { className: "canvas" }); this.canvasContRef.current.appendChild(renderer.canvas.dom); - renderer.onLoad(); - let model = new Model(); - model.addGroup(); - model.addGroup(); + let model = new Model().bindRenderer(renderer); + let group = model.addGroup(); + let range = model.addRange(); + range.color = [.1, .5, .9]; + group.new(100); + group.color = [.8, .1, .6]; + group.individuals.forEach((individual) => { + individual.position[0] = (Math.random() - .5) * 2; + individual.position[1] = (Math.random() - .5) * 2; + individual.position[2] = (Math.random() - .5) * 2; + }) + model.update(0); // 测试渲染器 - if (true) { + if (false) { renderer.points("0"); renderer.points("1", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2)); renderer.points("2", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2), {