Add individuals gen function

This commit is contained in:
MrKBear 2022-03-16 22:08:57 +08:00
parent 1acc83e41c
commit c44c10ad42
4 changed files with 138 additions and 9 deletions

View File

@ -37,6 +37,7 @@ interface IStatusEvent {
rangeAttrChange: void; rangeAttrChange: void;
labelAttrChange: void; labelAttrChange: void;
groupAttrChange: void; groupAttrChange: void;
individualChange: void;
} }
class Status extends Emitter<IStatusEvent> { class Status extends Emitter<IStatusEvent> {
@ -74,6 +75,16 @@ class Status extends Emitter<IStatusEvent> {
*/ */
public focusLabel?: Label; public focusLabel?: Label;
private drawtimer?: NodeJS.Timeout;
private delayDraw = () => {
this.drawtimer ? clearTimeout(this.drawtimer) : null;
this.drawtimer = setTimeout(() => {
this.model.draw();
this.drawtimer = undefined;
});
}
public constructor() { public constructor() {
super(); super();
@ -85,11 +96,11 @@ class Status extends Emitter<IStatusEvent> {
this.model.on("labelChange", () => this.emit("labelChange")); this.model.on("labelChange", () => this.emit("labelChange"));
// 对象变换时执行渲染,更新渲染器数据 // 对象变换时执行渲染,更新渲染器数据
this.on("objectChange", () => { this.on("objectChange", this.delayDraw);
setTimeout(() => { this.model.on("individualChange", this.delayDraw);
this.model.draw(); this.model.on("individualChange", () => {
}); this.emit("individualChange");
}) });
} }
public bindRenderer(renderer: AbstractRenderer) { public bindRenderer(renderer: AbstractRenderer) {

View File

@ -1,7 +1,8 @@
import { Individual } from "./Individual"; import { Individual } from "./Individual";
import { CtrlObject } from "./CtrlObject"; import { CtrlObject } from "./CtrlObject";
import type { Behavior } from "./Behavior"; import type { Behavior } from "./Behavior";
import type { Label } from "./Label"; import { Label } from "./Label";
import { Range } from "./Range";
enum GenMod { enum GenMod {
Point = "p", Point = "p",
@ -36,7 +37,123 @@ class Group extends CtrlObject {
/** /**
* *
*/ */
public genCount?: number = 0; public genCount: number = 1;
/**
*
*/
public genErrorMessage?: string;
/**
*
*/
public genErrorMessageShowCount?: string;
private genInSingelRange(count: number, range: Range) {
for (let i = 0; i < count; i++) {
let individual = new Individual(this);
individual.position[0] = range.position[0] + (Math.random() - .5) * 2 * range.radius[0];
individual.position[1] = range.position[1] + (Math.random() - .5) * 2 * range.radius[1];
individual.position[2] = range.position[2] + (Math.random() - .5) * 2 * range.radius[2];
this.add(individual);
}
}
private genWithPointMod(): boolean {
for (let i = 0; i < this.genCount; i++) {
let individual = new Individual(this);
individual.position[0] = this.genPoint[0];
individual.position[1] = this.genPoint[1];
individual.position[2] = this.genPoint[2];
this.add(individual);
}
return true;
}
private genWithRangeMod(): boolean {
let rangeList: Range[] = [];
// 单一范围对象
if (this.genRange instanceof Range) {
rangeList = [this.genRange];
}
// 多重范围对象
if (this.genRange instanceof Label) {
let objList: CtrlObject[] = this.model.getObjectByLabel(this.genRange);
rangeList = objList.filter((obj) => obj instanceof Range) as Range[]
}
// 单一范围生成
if (rangeList.length === 1) {
this.genInSingelRange(this.genCount, rangeList[0]);
return true;
}
// 多重范围
else if (rangeList.length > 1) {
let allVolume: number = 0;
let allGenCount: number = 0;
let genData: number[] = [];
// 计算体积
for (let i = 0; i < rangeList.length; i++) {
let volume =
rangeList[i].radius[0] *
rangeList[i].radius[1] *
rangeList[i].radius[2];
allVolume += volume;
genData.push(volume);
}
// 按权重分配生成个数
for (let i = 0; i < genData.length; i++) {
const count = Math.floor((genData[i] / allVolume) * this.genCount) + 1;
allGenCount += count;
genData[i] = count;
}
// 按照溢出个数删除冗余个数
let morCount = allGenCount - this.genCount;
let safeCount = 0;
while (morCount > 0 && safeCount < 1000) {
safeCount ++;
let randomIndex = Math.floor(Math.random() * genData.length);
if (genData[randomIndex] > 0) {
genData[randomIndex] --;
morCount --;
}
}
// 数据生成
for (let i = 0; i < rangeList.length; i++) {
this.genInSingelRange(genData[i], rangeList[i]);
}
return true;
}
return false;
}
/**
*
*/
public genIndividuals(): boolean {
let success = false;
switch (this.genMethod) {
case GenMod.Point:
success = this.genWithPointMod();
break;
case GenMod.Range:
success = this.genWithRangeMod();
break;
}
if (success) {
this.model.emit("individualChange", this);
}
return success;
}
/** /**
* *

View File

@ -17,6 +17,7 @@ type ModelEvent = {
objectAdd: CtrlObject; objectAdd: CtrlObject;
objectDelete: CtrlObject[]; objectDelete: CtrlObject[];
objectChange: CtrlObject[]; objectChange: CtrlObject[];
individualChange: Group;
}; };
/** /**

View File

@ -116,7 +116,7 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> {
<AttrInput <AttrInput
id={group.id} isNumber={true} step={1} keyI18n="Common.Attr.Key.Generation.Count" id={group.id} isNumber={true} step={1} keyI18n="Common.Attr.Key.Generation.Count"
value={group.genCount} min={0} max={1000} value={group.genCount} min={1} max={1000}
valueChange={(val) => { valueChange={(val) => {
this.props.status?.changeGroupAttrib(group.id, "genCount", (val as any) / 1); this.props.status?.changeGroupAttrib(group.id, "genCount", (val as any) / 1);
}} }}
@ -130,7 +130,7 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> {
keyI18n="Common.Attr.Key.Generation" keyI18n="Common.Attr.Key.Generation"
onIconName="BuildDefinition" offIconName="BuildDefinition" onIconName="BuildDefinition" offIconName="BuildDefinition"
valueChange={() => { valueChange={() => {
console.log("gen"); group.genIndividuals();
}} }}
/> />