Add sample tracking behavior

This commit is contained in:
MrKBear 2022-05-11 11:43:41 +08:00
parent 571e80d542
commit 4768667803
2 changed files with 156 additions and 0 deletions

View File

@ -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),
]
/**

View File

@ -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<ISampleTrackingBehaviorParameter, ISampleTrackingBehaviorEvent> {
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<string, Record<string, string>> = {
"$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 };