Add sample tracking behavior
This commit is contained in:
parent
571e80d542
commit
4768667803
@ -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),
|
||||
]
|
||||
|
||||
/**
|
||||
|
154
source/Behavior/SampleTracking.ts
Normal file
154
source/Behavior/SampleTracking.ts
Normal 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 };
|
Loading…
Reference in New Issue
Block a user