From 4ade5d4bc330f2945a48ab9b4e58f58caf011278 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Sun, 8 May 2022 21:33:38 +0800 Subject: [PATCH 1/7] Add manufacture behavior --- source/Behavior/Behavior.ts | 2 + source/Behavior/Manufacture.ts | 83 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 source/Behavior/Manufacture.ts diff --git a/source/Behavior/Behavior.ts b/source/Behavior/Behavior.ts index b603a2f..bc06b78 100644 --- a/source/Behavior/Behavior.ts +++ b/source/Behavior/Behavior.ts @@ -10,6 +10,7 @@ import { DelayAssimilate } from "@Behavior/DelayAssimilate"; import { Avoidance } from "@Behavior/Avoidance"; import { DirectionCluster } from "@Behavior/DirectionCluster"; import { CentralCluster } from "@Behavior/CentralCluster"; +import { Manufacture } from "@Behavior/Manufacture"; const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(Template), @@ -23,6 +24,7 @@ const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(Avoidance), new BehaviorRecorder(DirectionCluster), new BehaviorRecorder(CentralCluster), + new BehaviorRecorder(Manufacture), ] /** diff --git a/source/Behavior/Manufacture.ts b/source/Behavior/Manufacture.ts new file mode 100644 index 0000000..7a8e0fe --- /dev/null +++ b/source/Behavior/Manufacture.ts @@ -0,0 +1,83 @@ +import { Behavior } from "@Model/Behavior"; +import { Group } from "@Model/Group"; +import { Individual } from "@Model/Individual"; +import { Model } from "@Model/Model"; + +type IManufactureBehaviorParameter = { + maxFrequency: "number", + minFrequency: "number", + genTarget: "CG", +} + +type IManufactureBehaviorEvent = {} + +class Manufacture extends Behavior { + + public override behaviorId: string = "Manufacture"; + + public override behaviorName: string = "$Title"; + + public override iconName: string = "ProductionFloorManagement"; + + public override describe: string = "$Intro"; + + public override category: string = "$Initiative"; + + public override parameterOption = { + genTarget: { type: "CG", name: "$Gen.Target" }, + maxFrequency: { type: "number", name: "$Max.Frequency", defaultValue: 5, numberStep: .1, numberMin: 0 }, + minFrequency: { type: "number", name: "$Min.Frequency", defaultValue: 0, numberStep: .1, numberMin: 0 } + }; + + public effect = (individual: Individual, group: Group, model: Model, t: number): void => { + + const {genTarget, maxFrequency, minFrequency} = this.parameter; + + if (genTarget.objects) { + + let nextTime = individual.getData("Manufacture.nextTime") ?? + minFrequency + Math.random() * (maxFrequency - minFrequency); + let currentTime = individual.getData("Manufacture.currentTime") ?? 0; + + if (currentTime > nextTime) { + + // 生成个体 + let newIndividual = genTarget.objects.new(1); + newIndividual.position = individual.position.concat([]); + + nextTime = minFrequency + Math.random() * (maxFrequency - minFrequency); + currentTime = 0; + } + + currentTime += t; + + individual.setData("Manufacture.nextTime", nextTime); + individual.setData("Manufacture.currentTime", currentTime); + } + } + + public override terms: Record> = { + "$Title": { + "ZH_CN": "生产", + "EN_US": "Manufacture" + }, + "$Intro": { + "ZH_CN": "在指定的群创造新的个体", + "EN_US": "Create new individuals in a given group" + }, + "$Gen.Target": { + "ZH_CN": "目标群", + "EN_US": "Target group" + }, + "$Max.Frequency": { + "ZH_CN": "最大频率", + "EN_US": "Maximum frequency" + }, + "$Min.Frequency": { + "ZH_CN": "最小频率", + "EN_US": "Minimum frequency" + } + }; +} + +export { Manufacture }; \ No newline at end of file From 904de02140e57c7a7a2feccea955806cdf78c9aa Mon Sep 17 00:00:00 2001 From: MrKBear Date: Mon, 9 May 2022 21:24:28 +0800 Subject: [PATCH 2/7] Brownian behavior add limit by range --- source/Behavior/Brownian.ts | 133 ++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 6 deletions(-) diff --git a/source/Behavior/Brownian.ts b/source/Behavior/Brownian.ts index 5f6293a..fab6cae 100644 --- a/source/Behavior/Brownian.ts +++ b/source/Behavior/Brownian.ts @@ -7,7 +7,9 @@ type IBrownianBehaviorParameter = { maxFrequency: "number", minFrequency: "number", maxStrength: "number", - minStrength: "number" + minStrength: "number", + dirLimit: "boolean", + angle: "number" } type IBrownianBehaviorEvent = {} @@ -28,9 +30,88 @@ class Brownian extends Behavior { const {maxFrequency, minFrequency, maxStrength, minStrength} = this.parameter; @@ -41,11 +122,43 @@ class Brownian extends Behavior nextTime) { + + let randomDir: number[]; + + // 开启角度限制 + if (this.parameter.dirLimit) { + + // 计算当前速度大小 + const vLen = individual.vectorLength(individual.velocity); + + // 随机旋转算法 + if (vLen !== 0) { + randomDir = this.randomFocusRange( + [ + individual.velocity[0] / vLen, + individual.velocity[1] / vLen, + individual.velocity[2] / vLen + ], + this.parameter.angle / 2 + ); + } + + else { + randomDir = this.randomFocus360() + } + } + + // 随机生成算法 + else { + randomDir = this.randomFocus360() + } + individual.applyForce( - minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength), - minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength), - minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength) + minStrength + randomDir[0] * (maxStrength - minStrength), + minStrength + randomDir[1] * (maxStrength - minStrength), + minStrength + randomDir[2] * (maxStrength - minStrength) ); + nextTime = minFrequency + Math.random() * (maxFrequency - minFrequency); currentTime = 0; } @@ -78,7 +191,15 @@ class Brownian extends Behavior Date: Mon, 9 May 2022 23:26:17 +0800 Subject: [PATCH 3/7] Contact Attacking behavior add assimilate & Tracking add view range --- source/Behavior/ContactAttacking.ts | 14 ++++++++++-- source/Behavior/Tracking.ts | 35 ++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/source/Behavior/ContactAttacking.ts b/source/Behavior/ContactAttacking.ts index 93e9e32..b5f898f 100644 --- a/source/Behavior/ContactAttacking.ts +++ b/source/Behavior/ContactAttacking.ts @@ -6,7 +6,8 @@ import { Model } from "@Model/Model"; type IContactAttackingBehaviorParameter = { target: "CLG", success: "number", - range: "number" + range: "number", + assimilate: "CG", } type IContactAttackingBehaviorEvent = {} @@ -26,7 +27,8 @@ class ContactAttacking extends Behavior { @@ -46,6 +48,10 @@ class ContactAttacking extends Behavior Date: Tue, 10 May 2022 14:55:45 +0800 Subject: [PATCH 4/7] Fix boundary logic & Add wastage behavior --- source/Behavior/Behavior.ts | 2 + source/Behavior/BoundaryConstraint.ts | 14 ++-- source/Behavior/ContactAssimilate.ts | 22 ++++-- source/Behavior/Wastage.ts | 100 ++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 source/Behavior/Wastage.ts diff --git a/source/Behavior/Behavior.ts b/source/Behavior/Behavior.ts index bc06b78..147427e 100644 --- a/source/Behavior/Behavior.ts +++ b/source/Behavior/Behavior.ts @@ -11,6 +11,7 @@ import { Avoidance } from "@Behavior/Avoidance"; import { DirectionCluster } from "@Behavior/DirectionCluster"; import { CentralCluster } from "@Behavior/CentralCluster"; import { Manufacture } from "@Behavior/Manufacture"; +import { Wastage } from "@Behavior/Wastage"; const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(Template), @@ -25,6 +26,7 @@ const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(DirectionCluster), new BehaviorRecorder(CentralCluster), new BehaviorRecorder(Manufacture), + new BehaviorRecorder(Wastage), ] /** diff --git a/source/Behavior/BoundaryConstraint.ts b/source/Behavior/BoundaryConstraint.ts index d77b3d5..2d2aee3 100644 --- a/source/Behavior/BoundaryConstraint.ts +++ b/source/Behavior/BoundaryConstraint.ts @@ -48,11 +48,17 @@ class BoundaryConstraint extends Behavior { - let assimilateGroup = this.parameter.assimilate.objects; - if (!assimilateGroup) return; - for (let i = 0; i < this.parameter.target.objects.length; i++) { const targetGroup = this.parameter.target.objects[i]; @@ -50,7 +49,18 @@ class ContactAssimilate extends Behavior { + + public override behaviorId: string = "Wastage"; + + public override behaviorName: string = "$Title"; + + public override iconName: string = "BackgroundColor"; + + public override describe: string = "$Intro"; + + public override category: string = "$Initiative"; + + public override parameterOption = { + key: { type: "string", name: "$Key" }, + value: { type: "number", name: "$Value", defaultValue: 100, numberStep: 1 }, + speed: { type: "number", name: "$Speed", defaultValue: 1, numberStep: .1 }, + threshold: { type: "number", name: "$Threshold", defaultValue: 0, numberStep: 1 }, + kill: { type: "boolean", name: "$Kill", defaultValue: true }, + assimilate: { type: "CG", name: "$Assimilate", condition: { key: "kill", value: false } } + }; + + public effect = (individual: Individual, group: Group, model: Model, t: number): void => { + const key = this.parameter.key; + if (!key) return; + + let currentValue = individual.getData(`Wastage.${key}`) ?? this.parameter.value; + currentValue -= this.parameter.speed * t; + + // 超过阈值 + if (currentValue < this.parameter.threshold) { + + currentValue = undefined; + + // 杀死个体 + if (this.parameter.kill) { + individual.die(); + } + + // 开启同化 + else if (this.parameter.assimilate.objects) { + individual.transfer(this.parameter.assimilate.objects); + } + } + + individual.setData(`Wastage.${key}`, currentValue); + } + + public override terms: Record> = { + "$Title": { + "ZH_CN": "流逝", + "EN_US": "Wastage" + }, + "$Intro": { + "ZH_CN": "随着时间流逝", + "EN_US": "As time goes by" + }, + "$Key": { + "ZH_CN": "元数据", + "EN_US": "Metadata" + }, + "$Value": { + "ZH_CN": "默认数值", + "EN_US": "Default value" + }, + "$Speed": { + "ZH_CN": "流逝速度 (c/s)", + "EN_US": "Passing speed (c/s)" + }, + "$Threshold": { + "ZH_CN": "阈值", + "EN_US": "Threshold" + }, + "$Kill": { + "ZH_CN": "死亡", + "EN_US": "Death" + }, + "$Assimilate": { + "ZH_CN": "同化", + "EN_US": "Assimilate" + } + }; +} + +export { Wastage }; \ No newline at end of file From 476866780391975ad30bcb2da1bcee3ccfe82355 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Wed, 11 May 2022 11:43:41 +0800 Subject: [PATCH 5/7] Add sample tracking behavior --- source/Behavior/Behavior.ts | 2 + source/Behavior/SampleTracking.ts | 154 ++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 source/Behavior/SampleTracking.ts diff --git a/source/Behavior/Behavior.ts b/source/Behavior/Behavior.ts index 147427e..3abf452 100644 --- a/source/Behavior/Behavior.ts +++ b/source/Behavior/Behavior.ts @@ -12,6 +12,7 @@ import { DirectionCluster } from "@Behavior/DirectionCluster"; import { CentralCluster } from "@Behavior/CentralCluster"; import { Manufacture } from "@Behavior/Manufacture"; import { Wastage } from "@Behavior/Wastage"; +import { SampleTracking } from "@Behavior/SampleTracking"; const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(Template), @@ -27,6 +28,7 @@ const AllBehaviors: IAnyBehaviorRecorder[] = [ new BehaviorRecorder(CentralCluster), new BehaviorRecorder(Manufacture), new BehaviorRecorder(Wastage), + new BehaviorRecorder(SampleTracking), ] /** diff --git a/source/Behavior/SampleTracking.ts b/source/Behavior/SampleTracking.ts new file mode 100644 index 0000000..83d30fc --- /dev/null +++ b/source/Behavior/SampleTracking.ts @@ -0,0 +1,154 @@ +import { Behavior } from "@Model/Behavior"; +import { Group } from "@Model/Group"; +import { Individual } from "@Model/Individual"; +import { Model } from "@Model/Model"; + +type ISampleTrackingBehaviorParameter = { + target: "CLG", + strength: "number", + range: "number", + angle: "number", + accuracy: "number" +} + +type ISampleTrackingBehaviorEvent = {} + +class SampleTracking extends Behavior { + + public override behaviorId: string = "SampleTracking"; + + public override behaviorName: string = "$Title"; + + public override iconName: string = "Video360Generic"; + + public override describe: string = "$Intro"; + + public override category: string = "$Initiative"; + + public override parameterOption = { + target: { type: "CLG", name: "$Target" }, + range: { type: "number", name: "$Range", defaultValue: 4, numberMin: 0, numberStep: .1 }, + angle: { type: "number", name: "$Angle", defaultValue: 180, numberMin: 0, numberMax: 360, numberStep: 5 }, + strength: { type: "number", name: "$Strength", defaultValue: 1, numberMin: 0, numberStep: .1 }, + accuracy: { type: "number", name: "$Accuracy", defaultValue: 5, numberMin: 0, numberMax: 180, numberStep: 1 } + }; + + private angle2Vector(v1: number[], v2: number[]): number { + return Math.acos( + (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) / + ( + (v1[0] ** 2 + v1[1] ** 2 + v1[2] ** 2) ** 0.5 * + (v2[0] ** 2 + v2[1] ** 2 + v2[2] ** 2) ** 0.5 + ) + ) * 180 / Math.PI; + } + + public effect = (individual: Individual, group: Group, model: Model, t: number): void => { + + const dirArr: number[][] = []; const valArr: number[] = []; + + for (let i = 0; i < this.parameter.target.objects.length; i++) { + const targetGroup = this.parameter.target.objects[i]; + + targetGroup.individuals.forEach((targetIndividual) => { + + // 计算距离 + let dis = targetIndividual.distanceTo(individual); + if (dis > this.parameter.range) return; + + // 计算方向 + let targetDir = [ + targetIndividual.position[0] - individual.position[0], + targetIndividual.position[1] - individual.position[1], + targetIndividual.position[2] - individual.position[2] + ]; + + // 计算视线角度 + let angle = this.angle2Vector(individual.velocity, targetDir); + + // 在可视角度内 + if (angle < (this.parameter.angle ?? 360) / 2) { + + // 采样 + let isFindNest = false; + for (let i = 0; i < valArr.length; i++) { + + // 计算采样角度 + let sampleAngle = this.angle2Vector(dirArr[i], targetDir); + + // 小于采样精度,合并 + if (sampleAngle < this.parameter.accuracy ?? 5) { + dirArr[i][0] += targetDir[0]; + dirArr[i][1] += targetDir[1]; + dirArr[i][2] += targetDir[2]; + valArr[i] += targetIndividual.getData("Wastage.Pheromone") ?? 0; + isFindNest = true; + } + } + + if (!isFindNest) { + + // 保存 + dirArr.push(targetDir); + valArr.push(targetIndividual.getData("Wastage.Pheromone") ?? 0); + } + } + }); + } + + // 计算最大方向 + let maxVal = -1; let maxDir: number[] | undefined; + for (let i = 0; i < valArr.length; i++) { + if (valArr[i] > maxVal) { + maxVal = valArr[i]; + maxDir = dirArr[i]; + } + } + + if (maxDir) { + const dir = individual.vectorNormalize(maxDir); + individual.applyForce( + dir[0] * this.parameter.strength, + dir[1] * this.parameter.strength, + dir[2] * this.parameter.strength + ); + } + } + + public override terms: Record> = { + "$Title": { + "ZH_CN": "采样追踪", + "EN_US": "Sample tracking" + }, + "$Target": { + "ZH_CN": "追踪目标", + "EN_US": "Tracking target" + }, + "$Accuracy": { + "ZH_CN": "采样精度", + "EN_US": "Sampling accuracy" + }, + "$Range": { + "ZH_CN": "追踪范围 (m)", + "EN_US": "Tracking range (m)" + }, + "$Strength": { + "ZH_CN": "追踪强度系数", + "EN_US": "Tracking intensity coefficient" + }, + "$Intro": { + "ZH_CN": "个体将主动向目标个体较多的方向发起追踪", + "EN_US": "Individuals will actively initiate tracking in the direction of more target individuals" + }, + "$Interactive": { + "ZH_CN": "交互", + "EN_US": "Interactive" + }, + "$Angle": { + "ZH_CN": "可视角度", + "EN_US": "Viewing angle" + } + }; +} + +export { SampleTracking }; \ No newline at end of file From 8670b577f956455761d4decde528fa2ebc04eb01 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Wed, 11 May 2022 13:09:51 +0800 Subject: [PATCH 6/7] Add sample tracking behavior --- source/Behavior/SampleTracking.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/Behavior/SampleTracking.ts b/source/Behavior/SampleTracking.ts index 83d30fc..5e56141 100644 --- a/source/Behavior/SampleTracking.ts +++ b/source/Behavior/SampleTracking.ts @@ -5,6 +5,7 @@ import { Model } from "@Model/Model"; type ISampleTrackingBehaviorParameter = { target: "CLG", + key: "string", strength: "number", range: "number", angle: "number", @@ -27,6 +28,7 @@ class SampleTracking extends Behavior Date: Thu, 12 May 2022 20:22:18 +0800 Subject: [PATCH 7/7] fix brownian behavior --- source/Behavior/Brownian.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/Behavior/Brownian.ts b/source/Behavior/Brownian.ts index fab6cae..34528c3 100644 --- a/source/Behavior/Brownian.ts +++ b/source/Behavior/Brownian.ts @@ -132,7 +132,7 @@ class Brownian extends Behavior 0) { randomDir = this.randomFocusRange( [ individual.velocity[0] / vLen, @@ -141,6 +141,10 @@ class Brownian extends Behavior