Merge branch 'master' of gitorious.org:fg/fgdata into Work
This commit is contained in:
commit
91ab9b540d
1 changed files with 115 additions and 52 deletions
|
@ -8,7 +8,7 @@
|
||||||
##
|
##
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# The cellular automata model used here is based on
|
# The cellular automata model used here is loosely based on
|
||||||
# A. Hernandez Encinas, L. Hernandez Encinas, S. Hoya White,
|
# A. Hernandez Encinas, L. Hernandez Encinas, S. Hoya White,
|
||||||
# A. Martin del Rey, G. Rodriguez Sanchez,
|
# A. Martin del Rey, G. Rodriguez Sanchez,
|
||||||
# "Simulation of forest fire fronts using cellular automata",
|
# "Simulation of forest fire fronts using cellular automata",
|
||||||
|
@ -134,7 +134,7 @@ var models_enabled_pp = "environment/wildfire/models/enabled";
|
||||||
var fire_LOD_pp = "environment/wildfire/models/fire-lod";
|
var fire_LOD_pp = "environment/wildfire/models/fire-lod";
|
||||||
var smoke_LOD_pp = "environment/wildfire/models/smoke-lod";
|
var smoke_LOD_pp = "environment/wildfire/models/smoke-lod";
|
||||||
var LOD_High = 20;
|
var LOD_High = 20;
|
||||||
var LOD_Low = 80;
|
var LOD_Low = 50;
|
||||||
var mp_last_limited_event = {}; # source : time
|
var mp_last_limited_event = {}; # source : time
|
||||||
|
|
||||||
var score = { extinguished : 0, protected : 0, waste : 0 };
|
var score = { extinguished : 0, protected : 0, waste : 0 };
|
||||||
|
@ -202,7 +202,7 @@ var parse_msg = func (source, msg) {
|
||||||
var pos = Binary.decodeCoord(substr(msg, 6));
|
var pos = Binary.decodeCoord(substr(msg, 6));
|
||||||
ignite(pos, 0);
|
ignite(pos, 0);
|
||||||
} else {
|
} else {
|
||||||
printlog("warn", "wildfire.nas: Ignored ignite event from " ~
|
printlog("alert", "wildfire.nas: Ignored ignite event flood from " ~
|
||||||
source.getNode("callsign").getValue());
|
source.getNode("callsign").getValue());
|
||||||
}
|
}
|
||||||
mp_last_limited_event[i] = cur_time;
|
mp_last_limited_event[i] = cur_time;
|
||||||
|
@ -240,13 +240,13 @@ var SimTime = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Class that maintains one fire cell.
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Class that maintains the state of one fire cell.
|
||||||
var FireCell = {
|
var FireCell = {
|
||||||
############################################################
|
############################################################
|
||||||
new : func (x, y) {
|
new : func (x, y) {
|
||||||
# print("Creating FireCell[" ~ x ~ "," ~ y ~ "]");
|
trace("Creating FireCell[" ~ x ~ "," ~ y ~ "]");
|
||||||
var m = { parents: [FireCell] };
|
var m = { parents: [FireCell] };
|
||||||
m.lat = y * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
m.lat = y * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
||||||
m.lon = x * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
m.lon = x * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
||||||
|
@ -269,7 +269,7 @@ var FireCell = {
|
||||||
m.burn_rate = CAFire.BURN_RATE[mat];
|
m.burn_rate = CAFire.BURN_RATE[mat];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.model = CellModel.new(x, y, m.alt);
|
CAFireModels.add(x, y, m.alt);
|
||||||
append(CAFire.active, m);
|
append(CAFire.active, m);
|
||||||
CAFire.cells_created += 1;
|
CAFire.cells_created += 1;
|
||||||
return m;
|
return m;
|
||||||
|
@ -280,7 +280,7 @@ var FireCell = {
|
||||||
trace("FireCell[" ~ me.x ~ "," ~me.y ~ "] Ignited!");
|
trace("FireCell[" ~ me.x ~ "," ~me.y ~ "] Ignited!");
|
||||||
me.burning[CAFire.next] = 1;
|
me.burning[CAFire.next] = 1;
|
||||||
me.burning[CAFire.old] = 1;
|
me.burning[CAFire.old] = 1;
|
||||||
me.model.set_type("fire");
|
CAFireModels.set_type(me.x, me.y, "fire");
|
||||||
# Prevent update() on this cell in this generation.
|
# Prevent update() on this cell in this generation.
|
||||||
me.last = CAFire.generation;
|
me.last = CAFire.generation;
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,16 +300,16 @@ var FireCell = {
|
||||||
# Prevent update() on this cell in this generation.
|
# Prevent update() on this cell in this generation.
|
||||||
me.last = CAFire.generation;
|
me.last = CAFire.generation;
|
||||||
if ((me.state[CAFire.old] > 0.0) and (me.burning[CAFire.old] > 0)) {
|
if ((me.state[CAFire.old] > 0.0) and (me.burning[CAFire.old] > 0)) {
|
||||||
me.model.set_type("soot");
|
CAFireModels.set_type(me.x, me.y, "soot");
|
||||||
} else {
|
} else {
|
||||||
# Use a model representing contamination here.
|
# Use a model representing contamination here.
|
||||||
me.model.set_type(type);
|
CAFireModels.set_type(me.x, me.y, type);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
############################################################
|
############################################################
|
||||||
update : func () {
|
update : func () {
|
||||||
# print("FireCell[" ~ me.x ~ "," ~me.y ~ "] " ~ me.state[CAFire.old]);
|
trace("FireCell[" ~ me.x ~ "," ~me.y ~ "] " ~ me.state[CAFire.old]);
|
||||||
if ((me.state[CAFire.old] == 1) and (me.burning[CAFire.old] == 0))
|
if ((me.state[CAFire.old] == 1) and (me.burning[CAFire.old] == 0))
|
||||||
return 0;
|
return 0;
|
||||||
if ((me.burn_rate == 0) and (me.burning[CAFire.old] == 0))
|
if ((me.burn_rate == 0) and (me.burning[CAFire.old] == 0))
|
||||||
|
@ -337,7 +337,7 @@ var FireCell = {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
me.burning[CAFire.next] = me.burning[CAFire.old];
|
me.burning[CAFire.next] = me.burning[CAFire.old];
|
||||||
me.model.set_type(me.burning[CAFire.old] ? "fire" : "soot");
|
CAFireModels.set_type(me.x, me.y, me.burning[CAFire.old] ? "fire" : "soot");
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
############################################################
|
############################################################
|
||||||
|
@ -402,13 +402,13 @@ var CellModel = {
|
||||||
me.model = nil;
|
me.model = nil;
|
||||||
}
|
}
|
||||||
me.type = type;
|
me.type = type;
|
||||||
if (CAFire.MODEL[type] == "") return;
|
if (CAFireModels.MODEL[type] == "") return;
|
||||||
|
|
||||||
# Always put "cheap" models for now.
|
# Always put "cheap" models for now.
|
||||||
if (CAFire.models_enabled or (type != "fire")) {
|
if (CAFireModels.models_enabled or (type != "fire")) {
|
||||||
me.model =
|
me.model =
|
||||||
geo.put_model(CAFire.MODEL[type], me.lat, me.lon, me.alt);
|
geo.put_model(CAFireModels.MODEL[type], me.lat, me.lon, me.alt);
|
||||||
# print("Created 3d model " ~ type ~ " " ~ CAFire.MODEL[type]);
|
trace("Created 3d model " ~ type ~ " " ~ CAFireModels.MODEL[type]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
############################################################
|
############################################################
|
||||||
|
@ -420,7 +420,95 @@ var CellModel = {
|
||||||
};
|
};
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Singleton that maintains the fire CA grid.
|
# Singleton that maintains the CA models.
|
||||||
|
var CAFireModels = {};
|
||||||
|
# Constants
|
||||||
|
CAFireModels.MODEL = { # Model paths
|
||||||
|
"fire" : "Models/Effects/Wildfire/wildfire.xml",
|
||||||
|
"soot" : "Models/Effects/Wildfire/soot.xml",
|
||||||
|
"foam" : "Models/Effects/Wildfire/foam.xml",
|
||||||
|
"water" : "",
|
||||||
|
"protected" : "",
|
||||||
|
"none" : "",
|
||||||
|
};
|
||||||
|
# State
|
||||||
|
CAFireModels.grid = {}; # Sparse cell model grid storage.
|
||||||
|
CAFireModels.pending = []; # List of pending model changes.
|
||||||
|
CAFireModels.models_enabled = 1;
|
||||||
|
CAFireModels.loopid = 0;
|
||||||
|
######################################################################
|
||||||
|
# Public operations
|
||||||
|
############################################################
|
||||||
|
CAFireModels.init = func {
|
||||||
|
# Initialization.
|
||||||
|
setlistener(models_enabled_pp, func (n) {
|
||||||
|
me.set_models_enabled(n.getValue());
|
||||||
|
}, 1);
|
||||||
|
me.reset(1);
|
||||||
|
}
|
||||||
|
############################################################
|
||||||
|
# Reset the model grid to the empty state.
|
||||||
|
CAFireModels.reset = func (enabled) {
|
||||||
|
# Clear the model grid.
|
||||||
|
foreach (var x; keys(me.grid)) {
|
||||||
|
foreach (var y; keys(me.grid[x])) {
|
||||||
|
if (me.grid[x][y] != nil) me.grid[x][y].remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Reset state.
|
||||||
|
me.grid = {};
|
||||||
|
me.pending = [];
|
||||||
|
|
||||||
|
me.loopid += 1;
|
||||||
|
me._loop_(me.loopid);
|
||||||
|
}
|
||||||
|
############################################################
|
||||||
|
# Add a new cell model.
|
||||||
|
CAFireModels.add = func(x, y, alt) {
|
||||||
|
append(me.pending, { x: x, y: y, alt: alt });
|
||||||
|
}
|
||||||
|
############################################################
|
||||||
|
# Update a cell model.
|
||||||
|
CAFireModels.set_type = func(x, y, type) {
|
||||||
|
append(me.pending, { x: x, y: y, type: type });
|
||||||
|
}
|
||||||
|
############################################################
|
||||||
|
CAFireModels.set_models_enabled = func(on=1) {
|
||||||
|
me.models_enabled = on;
|
||||||
|
# We should do a pass over all cells here to add/remove models.
|
||||||
|
# For now I don't so only active cells will actually remove the
|
||||||
|
# models. All models will be hidden by their select animations, though.
|
||||||
|
}
|
||||||
|
######################################################################
|
||||||
|
# Private operations
|
||||||
|
############################################################
|
||||||
|
CAFireModels.update = func {
|
||||||
|
var work = size(me.pending)/10;
|
||||||
|
while (size(me.pending) > 0 and work > 0) {
|
||||||
|
var c = me.pending[0];
|
||||||
|
me.pending = subvec(me.pending, 1);
|
||||||
|
work -= 1;
|
||||||
|
if (contains(c, "alt")) {
|
||||||
|
if (me.grid[c.x] == nil) {
|
||||||
|
me.grid[c.x] = {};
|
||||||
|
}
|
||||||
|
me.grid[c.x][c.y] = CellModel.new(c.x, c.y, c.alt);
|
||||||
|
}
|
||||||
|
if (contains(c, "type")) {
|
||||||
|
me.grid[c.x][c.y].set_type(c.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
############################################################
|
||||||
|
CAFireModels._loop_ = func(id) {
|
||||||
|
id == me.loopid or return;
|
||||||
|
me.update();
|
||||||
|
settimer(func { me._loop_(id); }, 0);
|
||||||
|
}
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Singleton that maintains the fire cell CA grid.
|
||||||
var CAFire = {};
|
var CAFire = {};
|
||||||
# State
|
# State
|
||||||
CAFire.CELL_SIZE = 0.03; # "nm" (or rather minutes)
|
CAFire.CELL_SIZE = 0.03; # "nm" (or rather minutes)
|
||||||
|
@ -466,14 +554,6 @@ CAFire.BURN_RATE = { # Burn rate DB. grid widths per second
|
||||||
# ?
|
# ?
|
||||||
"Landmass" : 0.0005
|
"Landmass" : 0.0005
|
||||||
};
|
};
|
||||||
CAFire.MODEL = { # Model paths
|
|
||||||
"fire" : "Models/Effects/Wildfire/wildfire.xml",
|
|
||||||
"soot" : "Models/Effects/Wildfire/soot.xml",
|
|
||||||
"foam" : "Models/Effects/Wildfire/foam.xml",
|
|
||||||
"water" : "",
|
|
||||||
"protected" : "",
|
|
||||||
"none" : "",
|
|
||||||
};
|
|
||||||
CAFire.NEIGHBOURS = # Neighbour index offsets. First row and column
|
CAFire.NEIGHBOURS = # Neighbour index offsets. First row and column
|
||||||
# and then diagonal.
|
# and then diagonal.
|
||||||
[[[-1, 0], [0, 1], [1, 0], [0, -1]],
|
[[[-1, 0], [0, 1], [1, 0], [0, -1]],
|
||||||
|
@ -483,21 +563,13 @@ CAFire.NEIGHBOURS = # Neighbour index offsets. First row and column
|
||||||
############################################################
|
############################################################
|
||||||
CAFire.init = func {
|
CAFire.init = func {
|
||||||
# Initialization.
|
# Initialization.
|
||||||
setlistener(models_enabled_pp, func (n) {
|
|
||||||
me.set_models_enabled(n.getValue());
|
|
||||||
}, 1);
|
|
||||||
me.reset(1, SimTime.current_time());
|
me.reset(1, SimTime.current_time());
|
||||||
}
|
}
|
||||||
############################################################
|
############################################################
|
||||||
# Reset the CA to the empty state and set its current time to sim_time.
|
# Reset the CA to the empty state and set its current time to sim_time.
|
||||||
CAFire.reset = func (enabled, sim_time) {
|
CAFire.reset = func (enabled, sim_time) {
|
||||||
# Clear the grid.
|
# Clear the model grid.
|
||||||
foreach (var x; keys(me.grid)) {
|
CAFireModels.reset(enabled);
|
||||||
foreach (var y; keys(me.grid[x])) {
|
|
||||||
if (me.grid[x][y].model != nil) me.grid[x][y].model.remove();
|
|
||||||
me.grid[x][y] = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Reset state.
|
# Reset state.
|
||||||
me.grid = {};
|
me.grid = {};
|
||||||
me.generation = int(sim_time/CAFire.GENERATION_DURATION);
|
me.generation = int(sim_time/CAFire.GENERATION_DURATION);
|
||||||
|
@ -518,7 +590,7 @@ CAFire.reset = func (enabled, sim_time) {
|
||||||
############################################################
|
############################################################
|
||||||
# Start a fire in the cell at pos.
|
# Start a fire in the cell at pos.
|
||||||
CAFire.ignite = func (lat, lon) {
|
CAFire.ignite = func (lat, lon) {
|
||||||
# print("Fire at " ~ lat ~", " ~ lon ~ ".");
|
trace("CAFire.ignite: Fire at " ~ lat ~", " ~ lon ~ ".");
|
||||||
var x = int(lon*60/me.CELL_SIZE);
|
var x = int(lon*60/me.CELL_SIZE);
|
||||||
var y = int(lat*60/me.CELL_SIZE);
|
var y = int(lat*60/me.CELL_SIZE);
|
||||||
var cell = me.get_cell(x, y);
|
var cell = me.get_cell(x, y);
|
||||||
|
@ -537,17 +609,16 @@ CAFire.ignite = func (lat, lon) {
|
||||||
# radius - meter : double
|
# radius - meter : double
|
||||||
# Note: volume is unused ATM.
|
# Note: volume is unused ATM.
|
||||||
CAFire.resolve_water_drop = func (lat, lon, radius, volume=0) {
|
CAFire.resolve_water_drop = func (lat, lon, radius, volume=0) {
|
||||||
|
trace("CAFire.resolve_water_drop: Dumping water at " ~ lat ~", " ~ lon ~
|
||||||
|
" radius " ~ radius ~".");
|
||||||
var x = int(lon*60/me.CELL_SIZE);
|
var x = int(lon*60/me.CELL_SIZE);
|
||||||
var y = int(lat*60/me.CELL_SIZE);
|
var y = int(lat*60/me.CELL_SIZE);
|
||||||
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
||||||
# print("Dumping water at " ~ lat ~", " ~ lon ~
|
|
||||||
# ". Center (" ~ x ~ "," ~ y ~ ") radius " ~ r ~".");
|
|
||||||
var result = { extinguished : 0, protected : 0, waste : 0 };
|
var result = { extinguished : 0, protected : 0, waste : 0 };
|
||||||
for (var dx = -r; dx <= r; dx += 1) {
|
for (var dx = -r; dx <= r; dx += 1) {
|
||||||
for (var dy = -r; dy <= r; dy += 1) {
|
for (var dy = -r; dy <= r; dy += 1) {
|
||||||
var cell = me.get_cell(x + dx, y + dy);
|
var cell = me.get_cell(x + dx, y + dy);
|
||||||
if (cell == nil) {
|
if (cell == nil) {
|
||||||
# print(" (" ~ (x + dx) ~ ", " ~ (y + dy) ~ ")");
|
|
||||||
cell = FireCell.new(x + dx, y + dy);
|
cell = FireCell.new(x + dx, y + dy);
|
||||||
me.set_cell(x + dx, y + dy,
|
me.set_cell(x + dx, y + dy,
|
||||||
cell);
|
cell);
|
||||||
|
@ -584,17 +655,16 @@ CAFire.resolve_retardant_drop = func (lat, lon, radius, volume=0) {
|
||||||
# radius - meter : double
|
# radius - meter : double
|
||||||
# Note: volume is unused ATM.
|
# Note: volume is unused ATM.
|
||||||
CAFire.resolve_foam_drop = func (lat, lon, radius, volume=0) {
|
CAFire.resolve_foam_drop = func (lat, lon, radius, volume=0) {
|
||||||
|
trace("CAFire.resolve_foam_drop: Dumping foam at " ~ lat ~", " ~ lon ~
|
||||||
|
" radius " ~ radius ~".");
|
||||||
var x = int(lon*60/me.CELL_SIZE);
|
var x = int(lon*60/me.CELL_SIZE);
|
||||||
var y = int(lat*60/me.CELL_SIZE);
|
var y = int(lat*60/me.CELL_SIZE);
|
||||||
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
||||||
# print("Dumping foam at " ~ lat ~", " ~ lon ~
|
|
||||||
# ". Center (" ~ x ~ "," ~ y ~ ") radius " ~ r ~".");
|
|
||||||
var result = { extinguished : 0, protected : 0, waste : 0 };
|
var result = { extinguished : 0, protected : 0, waste : 0 };
|
||||||
for (var dx = -r; dx <= r; dx += 1) {
|
for (var dx = -r; dx <= r; dx += 1) {
|
||||||
for (var dy = -r; dy <= r; dy += 1) {
|
for (var dy = -r; dy <= r; dy += 1) {
|
||||||
var cell = me.get_cell(x + dx, y + dy);
|
var cell = me.get_cell(x + dx, y + dy);
|
||||||
if (cell == nil) {
|
if (cell == nil) {
|
||||||
# print(" (" ~ (x + dx) ~ ", " ~ (y + dy) ~ ")");
|
|
||||||
cell = FireCell.new(x + dx, y + dy);
|
cell = FireCell.new(x + dx, y + dy);
|
||||||
me.set_cell(x + dx, y + dy,
|
me.set_cell(x + dx, y + dy,
|
||||||
cell);
|
cell);
|
||||||
|
@ -661,12 +731,12 @@ CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
||||||
if (!fgcommand("loadxml",
|
if (!fgcommand("loadxml",
|
||||||
props.Node.new({ filename : filename,
|
props.Node.new({ filename : filename,
|
||||||
targetnode : logbase }))) {
|
targetnode : logbase }))) {
|
||||||
printlog("warn", "Wildfire ... failed loading '" ~ filename ~ "'");
|
printlog("alert", "Wildfire ... failed loading '" ~ filename ~ "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fast forward the automaton from the first logged event to the current time.
|
# Fast forward the automaton from the first logged event to the current time.
|
||||||
me.set_models_enabled(0);
|
CAFireModels.set_models_enabled(0);
|
||||||
var first = 1;
|
var first = 1;
|
||||||
var events = props.globals.getNode(logbase).getChildren("event");
|
var events = props.globals.getNode(logbase).getChildren("event");
|
||||||
foreach (var event; events) {
|
foreach (var event; events) {
|
||||||
|
@ -720,14 +790,7 @@ CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
||||||
while (me.generation * me.GENERATION_DURATION < now)
|
while (me.generation * me.GENERATION_DURATION < now)
|
||||||
me.update();
|
me.update();
|
||||||
}
|
}
|
||||||
me.set_models_enabled(getprop(models_enabled_pp));
|
CAFireModels.set_models_enabled(getprop(models_enabled_pp));
|
||||||
}
|
|
||||||
############################################################
|
|
||||||
CAFire.set_models_enabled = func(on=1) {
|
|
||||||
me.models_enabled = on;
|
|
||||||
# We should do a pass over all cells here to add/remove models.
|
|
||||||
# For now I don't so only active cells will actually remove the
|
|
||||||
# models. All models will be hidden by there select animations, though.
|
|
||||||
}
|
}
|
||||||
######################################################################
|
######################################################################
|
||||||
# Internal operations
|
# Internal operations
|
||||||
|
|
Loading…
Add table
Reference in a new issue