Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/flatGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ s off
f ${1 + vOffset}/${1 + vOffset}/${1 + vOffset} ${2 + vOffset}/${2 + vOffset}/${1 + vOffset} ${3 + vOffset}/${3 + vOffset}/${1 + vOffset} ${4 + vOffset}/${4 + vOffset}/${1 + vOffset}
\n`;

fs.appendFileSync(`${baseName}.obj`, obj);
fs.appendFileSync(`${baseName}/objs/layout.obj`, obj);
fs.appendFileSync(`${baseName}/objs/layout.js`, obj);

//Second generate the mtl file

Expand Down
101 changes: 19 additions & 82 deletions src/geneticAlgorithm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { innerCircleLayout } from "./innerCircleLayout.js";
import fs from 'fs';
import fse from 'fs-extra';
import boot from "../../examples/src/index.js"
// import startup from "../../node/index.js"
import child_process from "child_process"


const searchSpace = [
Expand Down Expand Up @@ -31,8 +32,8 @@ for (let i = 2; i <= iterations; i++) {


function genAlgLoop(population, iteration) {
generateBuildings(population);
return removeLeastFit(evalFitness(population), population, iteration);
let fitness = generateBuildings(population);
return removeLeastFit(evalFitness(population, fitness), population, iteration);
}

function initPopulation() {
Expand Down Expand Up @@ -66,18 +67,25 @@ function repopulate(population) {

function generateBuildings(population) {
let count = 1;
let fitness = [];
population.forEach(vector => {
innerCircleLayout(
"../runs/ga/thisGeneration/a" + count,
"../../node/node_modules/@crowdedjs/assets/",
vector[0] * (searchSpace[0].max - searchSpace[0].min) + searchSpace[0].min,
vector[1] * (searchSpace[1].max - searchSpace[1].min) + searchSpace[1].min,
vector[2] * (searchSpace[2].max - searchSpace[2].min) + searchSpace[2].min,
vector[3] * (searchSpace[3].max - searchSpace[3].min) + searchSpace[3].min,
vector[4] * (searchSpace[4].max - searchSpace[4].min) + searchSpace[4].min,
vector[5] * (searchSpace[5].max - searchSpace[5].min) + searchSpace[5].min
);
console.log("Beginning Layout #" + count)
let result = parseInt(child_process.execSync("node ../../node/index.js").toString());
console.log(" > " + result)

fitness.push(result)
count++;
});
return fitness;
}

function randomVector() {
Expand Down Expand Up @@ -117,101 +125,30 @@ function removeLeastFit(fitnessVals, population, iteration, numToKeep = 5) {
if (i < numToKeep)
newPopulation.push(population[fitnessVals[i][1]])
}
fs.copyFileSync("../runs/ga/thisGeneration/a" + (fitnessVals[0][1] + 1) + ".obj", "../runs/ga/best/bestGen" + iteration + ".obj")
// fs.copyFileSync("../runs/ga/thisGeneration/a" + (fitnessVals[0][1] + 1) + ".obj", "../runs/ga/best/bestGen" + iteration + ".obj")
return newPopulation;
}

function evalFitness(population) {
//IN DEVELOPMENT. IDEAS:
//we could measure the distance between important points
//That would be keeping in mind that the most crucial, lifesaving travel distances should be weighted
//More commonly traveled distances should also be weighted
//hall width needs to be evaluated. This would be more accurate to do in our simulation, but it would take SO long.
//Probably what we need is a heuristic.
//we could get a room count. We need to make sure that the algorithm doesn't favor tiny ERs.
//we could use the average distance from the center..?


//REALLY BASIC HEURISTIC
let bestHeuristics = [0,0,0]
let roomHeuristics = []
let hallHeuristics = []
let doorHeuristics = []
// let bestResult = 0;
// let runtimeResults = []
function evalFitness(population, fitness) {
let bestResult = Infinity;
let runtimeResults = fitness;

for (let i = 0; i < population.length; i++) {
roomHeuristics.push(roomHeuristic("../runs/ga/thisGeneration/a" + (i+1) + "Labels.json"));
hallHeuristics.push(hallHeuristic(population, i));
doorHeuristics.push(doorHeuristic(population, i));
// runtimeResults.push(runSimTest(i))

if (roomHeuristics[i] > bestHeuristics[0])
bestHeuristics[0] = roomHeuristics[i];
if (hallHeuristics[i] > bestHeuristics[1])
bestHeuristics[1] = hallHeuristics[i];
if (doorHeuristics[i] > bestHeuristics[2])
bestHeuristics[2] = doorHeuristics[i];
// if (runtimeResults[i] > bestResult)
// bestResult = runtimeResults[i];
if (runtimeResults[i] < bestResult)
bestResult = runtimeResults[i];
};

let fitnessVals = [];

for (let i = 0; i < population.length; i++) {
fitnessVals.push([
(
roomHeuristics[i] +
hallHeuristics[i] +
doorHeuristics[i]
) / (
bestHeuristics[0] +
bestHeuristics[1] +
bestHeuristics[2]
), i
bestResult / runtimeResults[i], i
])
}

return fitnessVals;
}

function roomHeuristic(filePath) {
//The size of the json file should be proportional to the number of rooms.
const stats = fs.statSync(filePath)
return stats.size;
}

function hallHeuristic(population, vectorNum) {
let hallValue = population[vectorNum][0] * (searchSpace[0].max - searchSpace[0].min) + searchSpace[0].min;
let hallCutoff = 6;
return hallValue < hallCutoff ? population[vectorNum][0] : hallCutoff / hallValue;
}

function doorHeuristic(population, vectorNum) {
let doorValue = population[vectorNum][1] * (searchSpace[1].max - searchSpace[1].min) + searchSpace[1].min;
let doorCutoff = 4;
return doorValue < doorCutoff ? population[vectorNum][1] : doorCutoff / doorValue;
}

// function runSimTest(vectorNum) {
// let params = {};

// let assetBase = "../runs/ga/thisGeneration/a" + (vectorNum+1);

// params.objPath = assetBase + ".obj";
// params.arrivalPath = "../runs/ga/arrival.json"; //TODO
// params.locationsPath = assetBase + "Labels.json";
// params.secondsOfSimulation = 300;
// params.millisecondsBetweenFrames = 40;
// params = urlParser(window, params, assetBase);

// return boot(params);
// }

function evacHeuristic(params) {
//TODO: time how long it takes for all people to evacuate
}

function printStats(vector) {
let toPrint = "";
for (let i = 0; i < searchSpace.length; i++) {
Expand Down
9 changes: 6 additions & 3 deletions src/innerCircleLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import flatGenerator from "./flatGenerator.js"


export function innerCircleLayout(filePath = "test", hallWidth = 4, doorSize = 3, w = 100, l = 100, midRatio = 1/3, maxRoomSize = 15) {
fs.writeFileSync(filePath + `.obj`, "\n");
fs.writeFileSync(filePath + `objs/layout.obj`, "\n");
fs.writeFileSync(filePath + `objs/layout.js`, "export default\n`");
// fs.writeFileSync(filePath + `.obj`, "mtllib room.mtl\n");
// fs.writeFileSync(filePath + `.mtl`, "\n");

Expand Down Expand Up @@ -86,6 +87,8 @@ export function innerCircleLayout(filePath = "test", hallWidth = 4, doorSize = 3
//Adding in the exit as the first "room" of filledSpace
filledSpace.push({TL:{x:(spaceToFill.BR.x+spaceToFill.TL.x) / 2 - 15,y:spaceToFill.BR.y},BR:{x:(spaceToFill.BR.x+spaceToFill.TL.x) / 2 + 15,y:spaceToFill.BR.y - 30},isRoom:false,name:"Exit"})

generateLabels(filledSpace, filePath, "room");
arrivalOnePerRoom(filledSpace, filePath, "room")
generateLabels(filledSpace, filePath + "locations/", "room");
arrivalOnePerRoom(filledSpace, filePath + "arrivals/", "room");

fs.appendFileSync(filePath + `objs/layout.js`, "`");
}
26 changes: 13 additions & 13 deletions src/spacesSharedFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,27 +350,27 @@ function deepCloneSpace(target, source) {
*/
export function generateLabels(filledSpace, filePath, labelBase = "room") {
let nameCount = 1;
fs.writeFileSync(filePath + "Labels.json", "[\n");
fs.writeFileSync(filePath + "locations.js", "export default [\n");
filledSpace.forEach(space => {
let name;
if (space.name !== undefined) {
name = space.name;
} else {
name = labelBase + " " + (nameCount + 1);
name = labelBase + " " + nameCount;
}
let annotationName = name;
let position = {x:0,y:0,z:0};
position.x = (space.TL.x + space.BR.x) / 2;
position.y = 0;
position.z = (space.TL.y + space.BR.y) / 2;
if (filledSpace.length == nameCount) {
fs.appendFileSync(filePath + "Labels.json", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t}\n`)
fs.appendFileSync(filePath + "locations.js", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t}\n`)
} else {
fs.appendFileSync(filePath + "Labels.json", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t},\n`)
fs.appendFileSync(filePath + "locations.js", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t},\n`)
}
nameCount++;
});
fs.appendFileSync(filePath + "Labels.json", "]");
fs.appendFileSync(filePath + "locations.js", "]");
}

/**
Expand All @@ -379,21 +379,21 @@ export function generateLabels(filledSpace, filePath, labelBase = "room") {
* @param {String} filePath The base path to the files we write to
*/
export function arrivalOnePerRoom(filledSpace, filePath, labelBase = "room") {
fs.writeFileSync(filePath + "Arrivals.json", "[\n");
for (let i = 0; i < filledSpace.length; i++) {
fs.writeFileSync(filePath + "arrivals.js", "export default [\n");
for (let i = 1; i < filledSpace.length; i++) {
let name = "EscapePerson";
let type = name;
let arrivalLocation = labelBase + " " + (i + 1);
let arrivalLocation = labelBase + " " + i;
let arrivalTick = 10;
let id = i;
let id = i - 1;

if ((i+1) < filledSpace.length) {
fs.appendFileSync(filePath + "Arrivals.json", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": "${arrivalTick}",\n\t\t"id": "${id}"\n\t},\n`)
if (i < filledSpace.length) {
fs.appendFileSync(filePath + "arrivals.js", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": ${arrivalTick},\n\t\t"id": ${id}\n\t},\n`)
} else {
fs.appendFileSync(filePath + "Arrivals.json", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": "${arrivalTick}",\n\t\t"id": "${id}"\n\t}\n`)
fs.appendFileSync(filePath + "arrivals.js", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": ${arrivalTick},\n\t\t"id": ${id}\n\t}\n`)
}
}
fs.appendFileSync(filePath + "Arrivals.json", "]");
fs.appendFileSync(filePath + "arrivals.js", "]");
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/wallGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function wallGenerator(width, length, height, baseName, textureOptions, wOffset
//First generate the wavefront obj file
let obj =
`
o object${vOffset}
o object${vOffset}
v ${halfWidth + wOffset} ${halfHeight + hOffset} ${halfLength + lOffset}
v ${halfWidth + wOffset} ${halfHeight + hOffset} ${-halfLength + lOffset}
v ${halfWidth + wOffset} ${-halfHeight + hOffset} ${halfLength + lOffset}
Expand Down Expand Up @@ -64,7 +64,8 @@ f ${1 + vOffset}/${1 + vOffset}/${1 + vOffset} ${3 + vOffset}/${3 + vOffset}/${1
f ${4 + vOffset}/${4 + vOffset}/${1 + vOffset} ${2 + vOffset}/${2 + vOffset}/${1 + vOffset} ${6 + vOffset}/${6 + vOffset}/${1 + vOffset} ${8 + vOffset}/${8 + vOffset}/${1 + vOffset}
\n`;

fs.appendFileSync(`${baseName}.obj`, obj);
fs.appendFileSync(`${baseName}/objs/layout.obj`, obj);
fs.appendFileSync(`${baseName}/objs/layout.js`, obj);

//Second generate the mtl file

Expand Down