// -*- C++ -*-
// $RCSfile: burner.C,v $
// $Revision: 1.10 $
// $Author: langer $
// $Date: 2000/10/30 19:23:23 $
/* This software was produced by NIST, an agency of the U.S. government,
* and by statute is not subject to copyright in the United States.
* Recipients of this software assume all responsibilities associated
* with its operation, modification and maintenance. However, to
* facilitate maintenance we ask that before distributing modifed
* versions of this software, you first contact the authors at
* oof_manager@ctcms.nist.gov.
*/
#include "burner.h"
#include "goof.h"
#include "vec.h"
void Burner::ignite(const Image &img, const Cell_coordinate &where,
int shiftkey)
{
nburned_ = 0;
forest = &img;
fireproof = ¤t_goof->fireproof;
startingpoint = where;
startingcolor = (*forest)[startingpoint];
burned.resize(forest->query_size());
burned.clear(false);
burn(startingpoint);
current_goof->init_selection(shiftkey);
Vec<Cell_coordinate> burnt;
store_burned(burnt);
current_goof->select(burnt);
}
void Burner::igniteNoUndo(const Image &img, const Cell_coordinate &where,
int shiftkey)
{
//same as above ignite, but no undo information is saved
nburned_ = 0;
forest = &img;
fireproof = ¤t_goof->fireproof;
startingpoint = where;
startingcolor = (*forest)[startingpoint];
burned.resize(forest->query_size());
burned.clear(false);
burn(startingpoint);
current_goof->selected().clear();
Vec<Cell_coordinate> burnt;
store_burned(burnt);
current_goof->select(burnt);
}
// The recursive burning algorithm is simpler than the non-recursive
// one, and uses one fewer large array. But it uses more stack space,
// and can seg fault when it runs out of stack space on large
// burns. The non-recursive version uses more memory for small burns
// and is more complicated, but doesn't have stack problems and
// doesn't seem to run any slower. So the non-recursive version is
// preferred.
//#define RECURSIVE
#ifdef RECURSIVE
void Burner::burn(const Cell_coordinate &here) {
if(!current_goof->active(here) || (fireproof && (*fireproof)[here]))
// can't burn this pixel
return;
nburned_++;
burned[here] = true;
Color thiscolor((*forest)[here]);
// this relies on the order in which nbrs are listed in the Nbr class:
int nbrmax = (next_nearest? 8 : 4);
for(int i=0; i<nbrmax; i++) {
Cell_coordinate target = here + neighbor[i];
if(forest->contains(target) && !burned[target] &&
spread(thiscolor, (*forest)[target]))
burn(target);
}
}
void Burner::burn_nbrs(Vec<Cell_coordinate>&, const Cell_coordinate&) {}
// only used in non-recursive method
#else // not RECURSIVE
void Burner::burn_nbrs(Vec<Cell_coordinate> &activelist,
const Cell_coordinate &here)
{
// Burn neighboring pixels and put them in the active list if
// they're flammable
int nbrmax = (next_nearest? 8 : 4);
Color thiscolor((*forest)[here]);
for(int i=0; i<nbrmax; i++) {
Cell_coordinate target = here + neighbor[i];
if(forest->contains(target) && !burned[target]
&& (!fireproof || !(*fireproof)[target])
&& current_goof->active(target)
&& spread(thiscolor, (*forest)[target])) {
burned[target] = true;
nburned_++;
activelist.grow(1, target);
}
}
}
void Burner::burn(const Cell_coordinate &start) { // non-recursive
// see if the first pixel is flammable
if(!current_goof->active(start) || (fireproof && (*fireproof)[start]))
return;
// active sites are sites whose neighbors have to be checked
Vec<Cell_coordinate> activesites;
// preallocate maximum amount of space to avoid reallocation
activesites.setphysicalsize(forest->query_height()*forest->query_width());
// burn the first pixel
burned[start] = true;
nburned_++;
activesites.grow(1, start);
while(activesites.capacity() > 0) {
// Remove last site in the active list, burn its neighbors, and add
// them to the list.
int n = activesites.capacity()-1;
const Cell_coordinate here = activesites[n];
activesites.resize(n); // remove last active pixel from list
burn_nbrs(activesites, here);
}
}
#endif // RECURSIVE
void Burner::store_burned(Vec<Cell_coordinate> &list) const {
list.resize(0);
list.setphysicalsize(nburned_);
ArrayIterator iter(burned);
Cell_coordinate pxl;
while(iter(pxl))
if(burned[pxl])
list.grow(1, pxl);
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
Burner::Nbr Burner::neighbor;
Burner::Nbr::Nbr() {
// don't change the order here without changing Burner::burn(), or
// the nearest neighbor/next nearest neighbor distinction will be
// screwed up.
nbr[0] = Cell_coordinate( 0, -1);
nbr[1] = Cell_coordinate(-1, 0);
nbr[2] = Cell_coordinate( 1, 0);
nbr[3] = Cell_coordinate( 0, 1);
nbr[4] = Cell_coordinate(-1, -1);
nbr[5] = Cell_coordinate( 1, -1);
nbr[6] = Cell_coordinate(-1, 1);
nbr[7] = Cell_coordinate( 1, 1);
}
syntax highlighted by Code2HTML, v. 0.9.1