优化算法:增加贪心计算

pull/659/head
ChenX 5 years ago
parent d3d3c1ae57
commit cf0a84594e

@ -10,6 +10,12 @@ export class Box2
this.min = min;
this.max = max;
}
get area(): number
{
return (this.max.x - this.min.x) * (this.max.y - this.min.y);
}
set(min: Vector2, max: Vector2): Box2
{
this.min.copy(min);

@ -12,6 +12,14 @@ import { Point } from "./Point";
import { equaln } from "./Util";
import { Vector2 } from "./Vector2";
export interface PlaceState
{
p: Point;
area?: number;
hull?: Point[];
box?: Box2;
}
export class Container
{
ParentId: number = -1;//父亲id,-1表示默认的bin,-2开始表示余料,大于等于0表示板件
@ -33,24 +41,18 @@ export class Container
this.StatusKey = this.BinPath.Id.toString() + "," + this.PlaceType;
}
get PlacedAll()
{
return this.Placed;
}
get UseRatio()
{
let size = this.PlacedBox.getSize(new Vector2);
return size.x * size.y / this.BinPath.Area;
return this.PlacedBox.area / this.BinPath.Area;
}
notPuts: Set<number>[] = [];
PutPart(part: Part): boolean
PrePut(part: Part): PlaceState
{
//------------无法容纳------------
//无法容纳
if (this.BinPath.Area - this.PlacedArea < part.State.Contour.Area)
return false;
return;
let cacheKey = this.StatusKey + "," + part.State.Contour.Id;
let cacheP = NestCache.PositionCache[cacheKey];
@ -58,23 +60,21 @@ export class Container
if (cacheP)
{
NestCache.count1++;
part.PlacePosition = cacheP;
this.AppendPartHoles(part);
return true;
return this.Calc(part, cacheP);
}
let binNfp = this.BinPath.GetInsideNFP(part.State.Contour);
if (!binNfp || binNfp.length === 0) return false;
if (!binNfp || binNfp.length === 0) return;
//------------首个------------
//首个
if (this.Placed.length === 0)
{
part.PlacePosition = this.GetFarLeftP(binNfp);
this.AppendPartHoles(part);
NestCache.PositionCache[cacheKey] = part.PlacePosition;
return true;
let p = this.GetFarLeftP(binNfp);
NestCache.PositionCache[cacheKey] = p;
return this.Calc(part, p);
}
//快速退出
let noSet = NestCache.NoPutCache[this.StatusKey];
if (noSet) this.notPuts.push(noSet);
for (let set of this.notPuts)
@ -82,7 +82,7 @@ export class Container
if (set.has(part.State.Contour.Id))
{
NestCache.count2++;
return false;
return;
}
}
@ -95,10 +95,10 @@ export class Container
noSet = new Set([part.State.Contour.Id]);
NestCache.NoPutCache[this.StatusKey] = noSet;
}
return false;
};
return;
}
//------------选择合适的放置点------------
//选择合适的放置点
let minArea: number = Infinity;
let translate: Point;
let bestBox: Box2;
@ -159,20 +159,88 @@ export class Container
if (translate)
{
part.PlacePosition = translate;
this.AppendPartHoles(part, false);
NestCache.PositionCache[cacheKey] = part.PlacePosition;
this.PlacedBox = bestBox ?? this.PlacedBox;
this.PlacedHull = bestHull;
return true;
NestCache.PositionCache[cacheKey] = translate;
if (!bestBox)
bestBox = this.PlacedBox.clone().union(part.State.Contour.BoundingBox.clone().translate({ x: translate.x * 1e-4, y: translate.y * 1e-4 }));
return { p: translate, area: minArea, box: bestBox, hull: bestHull };
}
}
Calc(part: Part, p: Point): PlaceState
{
let d: PlaceState = { p };
let m: Point = { x: p.x * 1e-4, y: p.y * 1e-4 };
if (this.PlacedBox)
d.box = this.PlacedBox.clone().union(part.State.Contour.BoundingBox.clone().translate(m));
else
d.box = part.State.Contour.BoundingBox.clone().translate(m);
//凸包
if (this.PlaceType === PlaceType.Hull)
{
if (!this.PlacedHull)
{
d.hull = TranslatePath(part.State.Contour.Points, m);
d.area = part.State.Contour.Area;
}
else
{
d.hull = ConvexHull2D([...this.PlacedHull, ...TranslatePath(part.State.Contour.Points, m)]);
d.area = Area(d.hull);
}
d.area = Math.abs(d.area);
}
else
{
d.area = d.box.area;
}
return d;
}
PutPart(p: Part, greedy = false): boolean
{
let bestD: PlaceState;
if (greedy)
{
let bestI: number;
for (let i = 0; i < p.RotatedStates.length; i++)
{
p.StateIndex = i;
let d = this.PrePut(p);
if (d && (!bestD || bestD.area > d.area ||
(
this.PlaceType === PlaceType.Hull
&& equaln(bestD.area, d.area, 0.1)
&& d.box.area < bestD.box.area
)
))
{
bestD = d;
bestI = i;
}
}
if (bestD)
p.StateIndex = bestI;
}
else
bestD = this.PrePut(p);
if (bestD)
{
p.PlacePosition = bestD.p;
this.PlacedBox = bestD.box ?? this.PlacedBox;
this.PlacedHull = bestD.hull;
this.AppendPartHoles(p, false);
return true;
}
return false;
}
protected GetNFPs(part: Part, binNfp: Point[][])
{
//------------计算nfp------------
//合并(零件和所有已经放置零件的NFP)
let nfps: SubjectInput[] = [];
for (let placedPart of this.Placed)
@ -207,7 +275,7 @@ export class Container
return finalNfp;
}
protected AppendPartHoles(part: Part, calc = true)
AppendPartHoles(part: Part, calc = true)
{
part.Container = this.BinPath.Id;
this.StatusKey += "," + part.State.Contour.Id;
@ -220,7 +288,7 @@ export class Container
if (this.PlaceType === PlaceType.Hull)
{
if (!this.PlacedHull)
this.PlacedHull = part.State.Contour.Points;
this.PlacedHull = TranslatePath(part.State.Contour.Points, m);
else
this.PlacedHull = ConvexHull2D([...this.PlacedHull, ...TranslatePath(part.State.Contour.Points, m)]);
}
@ -230,7 +298,7 @@ export class Container
if (this.PlacedBox)
this.PlacedBox.union(part.State.Contour.BoundingBox.clone().translate(m));
else
this.PlacedBox = part.State.Contour.BoundingBox.clone();
this.PlacedBox = part.State.Contour.BoundingBox.clone().translate(m);
}
}
@ -270,7 +338,6 @@ export class Container
part.PlacePosition = file.Read();
this.Placed.push(part);
}
return this;
}
//对象将自身数据写入到文件.

@ -1,10 +1,10 @@
import { arrayLast } from "../Common/ArrayExt";
import { Container } from "./Container";
import { CADFiler } from "./Filer";
import { Part } from "./Part";
import { Path } from "./Path";
import { RandomIndex } from "./Random";
import { PlaceType } from "./PlaceType";
import { CADFiler } from "./Filer";
import { RandomIndex } from "./Random";
/**
*
@ -76,7 +76,7 @@ export class Individual
/**
*
*/
Evaluate(bin: Path, bestCount: number)
Evaluate(bin: Path, bestCount: number, greedy = false, type?: PlaceType)
{
let parts = this.Parts;
this.Containers = [];
@ -114,8 +114,10 @@ export class Individual
};
let container = new Container(bin);
container.ParentId = -1;
container.PlaceType = RandomIndex(3);
// container.PlaceType = PlaceType.Box;
if (greedy)
container.PlaceType = type;
else
container.PlaceType = RandomIndex(2);
if (this.mutationRate > 0.5)
{
let area = 0;
@ -129,12 +131,12 @@ export class Individual
area = p.State.Contour.Area;
}
}
if (container.PutPart(maxP))
if (container.PutPart(maxP, greedy))
parts = parts.filter(p => p !== maxP);
}
parts = parts.filter(p =>
{
return container.PutPart(p) !== true;
return container.PutPart(p, greedy) !== true;
});
this.Containers.push(container);
}

@ -56,6 +56,7 @@ export class OptimizeMachine
for (let i = 1; i < this.Config.PopulationCount; i++)
{
let parts = this.Parts.map(p => p.Clone());
if (i < 3)
ShuffleArray(parts);
this._Individuals.push(new Individual(parts, 0.8));
}
@ -74,7 +75,6 @@ export class OptimizeMachine
//开始自然选择
while (!this._IsSuspend) //实验停止信号
{
this.calcCount += this._Individuals.length;
let goBack = this.calcCount - this.bestCount > 8000;
//1.适应环境(放置零件)
for (let i = 0; i < this._Individuals.length; i++)
@ -82,8 +82,12 @@ export class OptimizeMachine
if (globalThis.document || !clipperCpp.lib)
await Sleep(0);
let p = this._Individuals[i];
if (this.calcCount < 2000 || this.calcCount % 1000 === 0)
p.Evaluate(this.Bin, this.best, true, i % 2);
else
p.Evaluate(this.Bin, this.best);
if (!this.bestP)
if (!this.bestP || p.Fitness < this.bestP.Fitness)
{
this.bestP = p;
await this.callBack(p);
@ -93,6 +97,7 @@ export class OptimizeMachine
}
await Sleep(0);
this.calcCount += this._Individuals.length;
if (this.calcCount % 50 === 0)
console.timeLog("1", this.best, this.calcCount, NestCache.count1, NestCache.count2);

@ -1,7 +1,7 @@
export enum PlaceType
{
Box = 0,
Hull = 1,
Hull = 0,
Box = 1,
Gravity = 2,
}

@ -0,0 +1,27 @@
import { Command } from "../../Editor/CommandMachine";
import { HotCMD } from "../../Hot/HotCommand";
import { app } from "../../ApplicationServices/Application";
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { PromptStatus } from "../../Editor/PromptResult";
import { FileSystem } from "../../Common/FileSystem";
@HotCMD
export class Command_NFPData implements Command
{
async exec()
{
let ssRes = await app.Editor.GetSelection({ Filter: { filterTypes: [Polyline] } });
if (ssRes.Status !== PromptStatus.OK) return;
let ents = ssRes.SelectSet.SelectEntityList;
let arr = [];
for (let pl of ents)
{
let pts = pl.GetStretchPoints();
arr.push(pts);
}
FileSystem.WriteFile("aaa.json", JSON.stringify(arr));
}
}

@ -8,6 +8,7 @@ import { HotCMD } from "../../Hot/HotCommand";
import { Curves2Points } from "../Converter/ConverBoard2Part";
import { Path2Polyline } from "../Converter/Path2Polyline";
import { Path, PathScale } from "../Path";
import { InitClipperCpp } from "../ClipperCpp";
const TesetPerformance = true;
@ -16,12 +17,14 @@ export class Command_TestNFP implements Command
{
async exec()
{
let w = InitClipperCpp();
let plsRes = await app.Editor.GetSelection({
Filter: {
filterTypes: [Polyline, Circle]
}
});
await w;
if (plsRes.Status !== PromptStatus.OK)
return;
@ -39,7 +42,7 @@ export class Command_TestNFP implements Command
if (TesetPerformance)
{
console.time();
for (let j = 0; j < 1000; j++)
for (let j = 0; j < 1; j++)
for (let i = 0; i < paths.length; i++)
{
let path = paths[i];
@ -47,7 +50,7 @@ export class Command_TestNFP implements Command
}
console.timeEnd();
console.time();
for (let j = 0; j < 1000; j++)
for (let j = 0; j < 1; j++)
for (let i = 0; i < paths.length; i++)
{
let path = paths[i];

@ -13,3 +13,23 @@ export function FixIndex(index: number, arr: Array<any> | number)
else
return index;
}
/**
* @param compart t2t1t2
* @returns
*/
export function Max<T>(arr: T[], compart: (t1: T, t2: T) => boolean): number
{
let best: T = arr[0];
let bestIndex = 0;
for (let i = 1; i < arr.length; i++)
{
let t1 = arr[i];
if (compart(best, t1))
{
best = t1;
bestIndex = i;
}
}
return bestIndex;
}

Loading…
Cancel
Save