diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index cc4369e9d..91494306c 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -12,6 +12,18 @@ #include "Model.h" #include "Memory.h" +#define STRICT +#ifdef _WIN32 +#define _WIN32_WINNT 0x0400 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#endif +#ifdef IMAGE_MAGICK +#include "Magick++.h" +#endif + //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** BITMAP stuff. @@ -26,33 +38,50 @@ static CLSID encoderClsid; #include // for mkdir #endif -static unsigned char* bmf, *bmPixels, *bmp; +namespace CovidSim +{ + namespace BitMap + { + int32_t *Builder::population_ = nullptr; + int32_t *Builder::infected_ = nullptr; + int32_t *Builder::recovered_ = nullptr; + int32_t *Builder::treated_ = nullptr; + + unsigned char *Builder::bitmap_ = nullptr; + unsigned char *Builder::pixels_ = nullptr; + unsigned char *Builder::info_ = nullptr; + } +} + +// externs from CovidSim.cpp +// TODO: move these to a header files +extern char OutFile[1024], OutFileBase[1024]; -void CaptureBitmap() +void CovidSim::BitMap::Builder::capture() { int x, y, f, mi; - unsigned int j; + unsigned j; static double logMaxPop; static int fst = 1; double prev; - mi = (int)(P.b.width * P.b.height); + mi = (int)(bounds_.width * bounds_.height); if (fst) { fst = 0; int32_t maxPop = 0; - for (int i = 0; i < mi; i++) bmPopulation[i] = 0; + for (int i = 0; i < mi; i++) population_[i] = 0; for (int i = 0; i < P.PopSize; i++) { - x = ((int)(Households[Hosts[i].hh].loc.x * P.scale.x)) - P.bmin.x; - y = ((int)(Households[Hosts[i].hh].loc.y * P.scale.y)) - P.bmin.y; - if ((x >= 0) && (x < P.b.width) && (y >= 0) && (y < P.b.height)) + x = ((int)(Households[Hosts[i].hh].loc.x * scale_.x)) - min_.x; + y = ((int)(Households[Hosts[i].hh].loc.y * scale_.y)) - min_.y; + if ((x >= 0) && (x < bounds_.width) && (y >= 0) && (y < bounds_.height)) { - j = y * bmh->width + x; - if (j < bmh->imagesize) + j = y * header_->width + x; + if ((j < header_->imagesize) && (j >= 0)) { - bmPopulation[j]++; - if (bmPopulation[j] > maxPop) maxPop = bmPopulation[j]; + population_[j]++; + if (population_[j] > maxPop) maxPop = population_[j]; } } } @@ -69,45 +98,45 @@ void CaptureBitmap() if ((i >= P.total_microcells_high_) && (Mcells[i - P.total_microcells_high_].n > 0) && (mcell_country[i] != mcell_country[i - P.total_microcells_high_])) f = 1; if (f) { - x = (int)(P.in_microcells_.width * (((double)(i / P.total_microcells_high_)) + 0.5) * P.scale.x) - P.bmin.x; - y = (int)(P.in_microcells_.height * (((double)(i % P.total_microcells_high_)) + 0.5) * P.scale.y) - P.bmin.y; - if ((x >= 0) && (x < P.b.width) && (y >= 0) && (y < P.b.height)) + x = (int)(P.in_microcells_.width * (((double)(i / P.total_microcells_high_)) + 0.5) * scale_.x) - min_.x; + y = (int)(P.in_microcells_.height * (((double)(i % P.total_microcells_high_)) + 0.5) * scale_.y) - min_.y; + if ((x >= 0) && (x < bounds_.width) && (y >= 0) && (y < bounds_.height)) { - j = y * bmh->width + x; - if (j < bmh->imagesize) bmPopulation[j] = -1; + j = y * header_->width + x; + if ((j < header_->imagesize) && (j >= 0)) population_[j] = -1; } } } - for (int i = 0; i < P.b.width / 2; i++) + for (int i = 0; i < bounds_.width / 2; i++) { - prev = floor(3.99999 * ((double)i) * BWCOLS / ((double)P.b.width) * 2); + prev = floor(3.99999 * ((double)i) * BWCOLS / ((double)bounds_.width) * 2); f = ((int)prev); for (j = 0; j < 10; j++) { - bmPixels[(j + P.b.height + 5) * bmh->width + P.b.width / 4 + i] = f; + pixels_[(j + bounds_.height + 5) * header_->width + bounds_.width / 4 + i] = f; } } } #pragma omp parallel for schedule(static,5000) default(none) \ - shared(mi, bmPixels, bmPopulation, bmInfected, bmTreated, bmRecovered, logMaxPop) + shared(mi, logMaxPop) for (int i = 0; i < mi; i++) { - if (bmPopulation[i] == -1) - bmPixels[i] = BWCOLS - 1; /* black for country boundary */ - else if (bmInfected[i] > 0) - bmPixels[i] = (unsigned char)(BWCOLS + BWCOLS * log((double)bmInfected[i]) / logMaxPop); /* red for infected */ - else if (bmTreated[i] > 0) - bmPixels[i] = (unsigned char)(2 * BWCOLS + BWCOLS * log((double)bmTreated[i]) / logMaxPop); /* blue for treated */ - else if (bmRecovered[i] > 0) - bmPixels[i] = (unsigned char)(3 * BWCOLS + BWCOLS * log((double)bmRecovered[i]) / logMaxPop); /* green for recovered */ - else if (bmPopulation[i] > 0) - bmPixels[i] = (unsigned char)(BWCOLS * log((double)bmPopulation[i]) / logMaxPop); /* grey for just people */ + if (population_[i] == -1) + pixels_[i] = BWCOLS - 1; /* black for country boundary */ + else if (infected_[i] > 0) + pixels_[i] = (unsigned char)(BWCOLS + BWCOLS * log((double)infected_[i]) / logMaxPop); /* red for infected */ + else if (treated_[i] > 0) + pixels_[i] = (unsigned char)(2 * BWCOLS + BWCOLS * log((double)treated_[i]) / logMaxPop); /* blue for treated */ + else if (recovered_[i] > 0) + pixels_[i] = (unsigned char)(3 * BWCOLS + BWCOLS * log((double)recovered_[i]) / logMaxPop); /* green for recovered */ + else if (population_[i] > 0) + pixels_[i] = (unsigned char)(BWCOLS * log((double)population_[i]) / logMaxPop); /* grey for just people */ else - bmPixels[i] = 0; + pixels_[i] = 0; } } -void OutputBitmap(int tp, std::string const& output_file_base) +void CovidSim::BitMap::Builder::output(int tp, std::string const& output_file_base) { char buf[3000]; int j = 0; @@ -130,7 +159,7 @@ void OutputBitmap(int tp, std::string const& output_file_base) cn[tp]++; auto OutF = output_file_base + ".ge" DIRECTORY_SEPARATOR + OutPrefix[tp] + leaf_name; - if (P.BitmapFormat == BitmapFormats::PNG) + if (format_ == CovidSim::BitMap::Formats::PNG) { #ifdef IMAGE_MAGICK FILE* dat; @@ -139,9 +168,9 @@ void OutputBitmap(int tp, std::string const& output_file_base) sprintf(buf, "%s.bmp", OutF); if (!(dat = fopen(buf, "wb"))) ERR_CRITICAL("Unable to open bitmap file\n"); fprintf(dat, "BM"); - //fwrite_big((void *) &bmf,sizeof(unsigned char),(sizeof(bitmap_header)/sizeof(unsigned char))+bmh->imagesize,dat); - fwrite_big((void*)bmf, sizeof(bitmap_header), 1, dat); - for (int i = 0; i < bmh->imagesize; i++) fputc(bmPixels[i], dat); + //fwrite_big((void *) &bitmap_,sizeof(unsigned char),(sizeof(bitmap_header)/sizeof(unsigned char))+header_->imagesize,dat); + fwrite_big((void*)bitmap_, sizeof(bitmap_header), 1, dat); + for (int i = 0; i < header_->imagesize; i++) fputc(pixels_[i], dat); fclose(dat); Image bmap(buf); sprintf(buf, "%s.%d.png", OutF, j); @@ -181,7 +210,7 @@ void OutputBitmap(int tp, std::string const& output_file_base) fprintf(stderr, "Do not know how to output PNG\n"); #endif } - else if (P.BitmapFormat == BitmapFormats::BMP) { + else if (format_ == CovidSim::BitMap::Formats::BMP) { sprintf(buf, "%s.%05i.bmp", OutF.c_str(), j); FILE* dat; if (!(dat = fopen(buf, "wb"))) { @@ -192,70 +221,70 @@ void OutputBitmap(int tp, std::string const& output_file_base) ERR_CRITICAL_FMT("Unable to open bitmap file %s (%d): %s\n", buf, errno, errMsg); } fprintf(dat, "BM"); - fwrite_big((void*)bmf, sizeof(unsigned char), sizeof(BitmapHeader) / sizeof(unsigned char) + bmh->imagesize, dat); + fwrite_big((void*)bitmap_, sizeof(unsigned char), sizeof(CovidSim::BitMap::Header) / sizeof(unsigned char) + header_->imagesize, dat); fclose(dat); } else { - fprintf(stderr, "Unknown Bitmap format: %d\n", (int)P.BitmapFormat); + fprintf(stderr, "Unknown Bitmap format: %d\n", (int)format_); } } -void InitBMHead(std::string const& out_file_base) +void CovidSim::BitMap::Builder::initialise_header(std::string const& out_file_base) { int i, j, k, k2, value; fprintf(stderr, "Initialising bitmap\n"); - k = P.b.width * P.bheight2; - k2 = sizeof(BitmapHeader) / sizeof(unsigned char); + k = bounds_.width * height2_; + k2 = sizeof(CovidSim::BitMap::Header) / sizeof(unsigned char); - bmf = (unsigned char*)Memory::xcalloc((size_t)k + k2, sizeof(unsigned char)); - bmPixels = &(bmf[k2]); - bmp = &(bmf[12]); - bmh = (BitmapHeader*)bmf; - bmh->spare = 0; - bmh->boffset = 2 + sizeof(BitmapHeader); - bmh->headersize = 40; // BITMAPINFOHEADER - bmh->width = P.b.width; - bmh->height = P.bheight2; - bmh->PlanesAndBitspp = 1 // Number of colour planes; must be 1 + bitmap_ = (unsigned char*)Memory::xcalloc((size_t)k + k2, sizeof(unsigned char)); + pixels_ = &(bitmap_[k2]); + info_ = &(bitmap_[12]); + header_ = (CovidSim::BitMap::Header*)bitmap_; + header_->spare = 0; + header_->boffset = 2 + sizeof(CovidSim::BitMap::Header); + header_->headersize = 40; // BITMAPINFOHEADER + header_->width = bounds_.width; + header_->height = height2_; + header_->PlanesAndBitspp = 1 // Number of colour planes; must be 1 + (8 << 16); // Colour depth: 8 bits per pixel - bmh->compr = 0; // No compression (BI_RGB) - bmh->imagesize = bmh->width * bmh->height; - bmh->filesize = 2 // "BM" - + ((unsigned int) sizeof(BitmapHeader)) // BITMAP_HEADER - + bmh->imagesize; // Image data - bmh->hres = bmh->vres = (int)(bmh->width * 10); // Resolution, in pixels per metre - bmh->colours = BWCOLS * 4; // Number of colours in the palette - bmh->impcol = 0; // Every colour is important + header_->compr = 0; // No compression (BI_RGB) + header_->imagesize = header_->width * header_->height; + header_->filesize = 2 // "BM" + + ((unsigned int) sizeof(CovidSim::BitMap::Header)) // BITMAP_HEADER + + header_->imagesize; // Image data + header_->hres = header_->vres = (int)(header_->width * 10); // Resolution, in pixels per metre + header_->colours = BWCOLS * 4; // Number of colours in the palette + header_->impcol = 0; // Every colour is important for (i = 0; i < BWCOLS * 4; i++) - bmh->palette[i][3] = 0; + header_->palette[i][3] = 0; for (j = 0; j < BWCOLS; j++) { value = 255 - 255 * j / (BWCOLS - 1); // Shades of gray: - bmh->palette[j][0] = bmh->palette[j][1] = bmh->palette[j][2] = (unsigned char)value; + header_->palette[j][0] = header_->palette[j][1] = header_->palette[j][2] = (unsigned char)value; // Shades of red: - bmh->palette[BWCOLS + j][0] = 0; - bmh->palette[BWCOLS + j][1] = 0; - bmh->palette[BWCOLS + j][2] = (unsigned char)value; + header_->palette[BWCOLS + j][0] = 0; + header_->palette[BWCOLS + j][1] = 0; + header_->palette[BWCOLS + j][2] = (unsigned char)value; // Shades of blue: - bmh->palette[2 * BWCOLS + j][0] = (unsigned char)value; - bmh->palette[2 * BWCOLS + j][1] = 0; - bmh->palette[2 * BWCOLS + j][2] = 0; + header_->palette[2 * BWCOLS + j][0] = (unsigned char)value; + header_->palette[2 * BWCOLS + j][1] = 0; + header_->palette[2 * BWCOLS + j][2] = 0; // Shades of green: - bmh->palette[3 * BWCOLS + j][0] = 0; - bmh->palette[3 * BWCOLS + j][1] = (unsigned char)value; - bmh->palette[3 * BWCOLS + j][2] = 0; + header_->palette[3 * BWCOLS + j][0] = 0; + header_->palette[3 * BWCOLS + j][1] = (unsigned char)value; + header_->palette[3 * BWCOLS + j][2] = 0; } - bmPopulation = (int32_t*)Memory::xcalloc(bmh->imagesize, sizeof(int32_t)); - bmInfected = (int32_t*)Memory::xcalloc(bmh->imagesize, sizeof(int32_t)); - bmRecovered = (int32_t*)Memory::xcalloc(bmh->imagesize, sizeof(int32_t)); - bmTreated = (int32_t*)Memory::xcalloc(bmh->imagesize, sizeof(int32_t)); + population_ = (int32_t*)Memory::xcalloc(header_->imagesize, sizeof(int32_t)); + infected_ = (int32_t*)Memory::xcalloc(header_->imagesize, sizeof(int32_t)); + recovered_ = (int32_t*)Memory::xcalloc(header_->imagesize, sizeof(int32_t)); + treated_ = (int32_t*)Memory::xcalloc(header_->imagesize, sizeof(int32_t)); #ifdef _WIN32 - if (P.BitmapFormat == BitmapFormats::PNG) + if (format_ == CovidSim::BitMap::Formats::PNG) { - bmpdib = CreateDIBSection(GetDC(NULL), (BITMAPINFO*)bmp, DIB_RGB_COLORS, (void**)&bmPixels, NULL, 0); + bmpdib = CreateDIBSection(GetDC(NULL), (BITMAPINFO*)info_, DIB_RGB_COLORS, (void**)&pixels_, NULL, NULL); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); @@ -266,16 +295,14 @@ void InitBMHead(std::string const& out_file_base) Gdiplus::GetImageEncodersSize(&num, &size); pImageCodecInfo = (Gdiplus::ImageCodecInfo*)Memory::xcalloc(1, size); Gdiplus::GetImageEncoders(num, size, pImageCodecInfo); - for (UINT j2 = 0; j2 < num; ++j2) { + for (UINT j = 0; j < num; ++j) { // Visual Studio Analyze incorrectly reports this because it doesn't understand Gdiplus::GetImageEncodersSize() // warning C6385: Reading invalid data from 'pImageCodecInfo': the readable size is 'size' bytes, but '208' bytes may be read. -#ifdef _MSC_VER #pragma warning( suppress: 6385 ) -#endif - const WCHAR* type = pImageCodecInfo[j2].MimeType; + const WCHAR* type = pImageCodecInfo[j].MimeType; if (wcscmp(type, L"image/png") == 0) { - encoderClsid = pImageCodecInfo[j2].Clsid; - j2 = num; + encoderClsid = pImageCodecInfo[j].Clsid; + j = num; } } free(pImageCodecInfo); @@ -291,10 +318,10 @@ void InitBMHead(std::string const& out_file_base) #endif } -void Bitmap_Finalise() +void CovidSim::BitMap::Builder::finalise() { #ifdef _WIN32 - if (P.BitmapFormat == BitmapFormats::PNG) + if (format_ == CovidSim::BitMap::Formats::PNG) { Gdiplus::GdiplusShutdown(m_gdiplusToken); } diff --git a/src/Bitmap.h b/src/Bitmap.h index f0ba1aac4..007992fdf 100644 --- a/src/Bitmap.h +++ b/src/Bitmap.h @@ -10,41 +10,81 @@ #define DIRECTORY_SEPARATOR "\\" #endif -#define STRICT -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#endif -#ifdef IMAGE_MAGICK -#include "Magick++.h" -#endif +#include "Geometry/Size.h" const int BWCOLS = 58; -struct BitmapHeader +namespace CovidSim { - unsigned int filesize; - unsigned int spare; - unsigned int boffset; - unsigned int headersize; - unsigned int width, height; - unsigned int PlanesAndBitspp; - unsigned int compr; - unsigned int imagesize; - unsigned int hres, vres; - unsigned int colours, impcol; - unsigned char palette[BWCOLS * 4][4]; -}; - -extern int32_t *bmPopulation, *bmInfected, *bmRecovered, *bmTreated; -extern BitmapHeader* bmh; - -void CaptureBitmap(); -void OutputBitmap(int, std::string const&); -void InitBMHead(std::string const&); - -void Bitmap_Finalise(); + namespace BitMap + { + struct Header + { + unsigned int filesize; + unsigned int spare; + unsigned int boffset; + unsigned int headersize; + unsigned int width, height; + unsigned int PlanesAndBitspp; + unsigned int compr; + unsigned int imagesize; + unsigned int hres, vres; + unsigned int colours, impcol; + unsigned char palette[BWCOLS * 4][4]; + }; + + /// Enumeration of bitmap formats. + enum struct Formats + { + PNG, ///< default if IMAGE_MAGICK or _WIN32 defined + BMP ///< fall-back + }; + + struct Builder + { + /// Height in pixels of the entire bitmap output, including both the spectrum at the top and the map area + int height2_; + + /// Size in pixels of the map area in the bitmap output + Geometry::Size bounds_; + + Geometry::Vector2 min_; + + ///< Format of bitmap (platform dependent and command-line /BM: specified). + Formats format_; + + /// Whether to output a bitmap + int output_; + + /// Number of pixels per degree in bitmap output + Geometry::DiagonalMatrix2d scale_; + + // These allow up to about 2 billion people per pixel, which should be ample. + /// The population in each bitmap pixel. Special value -1 means "country boundary" + static int32_t *population_; + + /// The number of infected people in each bitmap pixel. + static int32_t *infected_; + + /// The number of recovered people in each bitmap pixel. + static int32_t *recovered_; + + /// The number of treated people in each bitmap pixel. + static int32_t *treated_; + + Header *header_; + + void capture(); + void output(int, std::string const&); + void initialise_header(std::string const&); + + void finalise(); + + static unsigned char* bitmap_; + static unsigned char* pixels_; + static unsigned char* info_; + }; + } +} #endif // COVIDSIM_BITMAP_H_INCLUDED_ diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index 34755eb1c..cff30415b 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -94,7 +94,6 @@ AdminUnit AdUnits[MAX_ADUNITS]; //// TSMeanNE and TSVarNE are the mean and variance of non-extinct time series. TSMeanE and TSVarE are the mean and variance of extinct time series. TSMean and TSVar are pointers that point to either extinct or non-extinct. Results* TimeSeries, * TSMean, * TSVar, * TSMeanNE, * TSVarNE, * TSMeanE, * TSVarE; //// TimeSeries used in RecordSample, RecordInfTypes, SaveResults. TSMean and TSVar Airport* Airports; -BitmapHeader* bmh; //added declaration of pointer to events log: ggilani - 10/10/2014 Events* InfEventLog; int nEvents; @@ -108,12 +107,6 @@ double PropPlaces[NUM_AGE_GROUPS * AGE_GROUP_WIDTH][NUM_PLACE_TYPES]; double PropPlacesC[NUM_AGE_GROUPS * AGE_GROUP_WIDTH][NUM_PLACE_TYPES], AirTravelDist[MAX_DIST]; double PeakHeightSum, PeakHeightSS, PeakTimeSum, PeakTimeSS; -// These allow up to about 2 billion people per pixel, which should be ample. -int32_t *bmPopulation; // The population in each bitmap pixel. Special value -1 means "country boundary" -int32_t *bmInfected; // The number of infected people in each bitmap pixel. -int32_t *bmRecovered; // The number of recovered people in each bitmap pixel. -int32_t *bmTreated; // The number of treated people in each bitmap pixel. - int ns, DoInitUpdateProbs, InterruptRun = 0; int PlaceDistDistrib[NUM_PLACE_TYPES][MAX_DIST], PlaceSizeDistrib[NUM_PLACE_TYPES][MAX_PLACE_SIZE]; @@ -156,9 +149,9 @@ int main(int argc, char* argv[]) // Default bitmap format is platform dependent. #if defined(IMAGE_MAGICK) || defined(_WIN32) - P.BitmapFormat = BitmapFormats::PNG; + P.bitmap.format_ = CovidSim::BitMap::Formats::PNG; #else - P.BitmapFormat = BitmapFormats::BMP; + P.bitmap.format_ = CovidSim::BitMap::Formats::BMP; #endif // Set parameter defaults - read them in after @@ -233,7 +226,7 @@ int main(int argc, char* argv[]) } std::cerr << "Param=" << param_file << "\nOut=" << output_file_base << "\nDens=" << density_file << std::endl; - fprintf(stderr, "Bitmap Format = *.%s\n", P.BitmapFormat == BitmapFormats::PNG ? "png" : "bmp"); + fprintf(stderr, "Bitmap Format = *.%s\n", P.bitmap.format_ == CovidSim::BitMap::Formats::PNG ? "png" : "bmp"); fprintf(stderr, "sizeof(int)=%i sizeof(long)=%i sizeof(float)=%i sizeof(double)=%i sizeof(unsigned short int)=%i sizeof(int *)=%i\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(float), (int)sizeof(double), (int)sizeof(unsigned short int), (int)sizeof(int*)); //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** @@ -408,7 +401,7 @@ int main(int argc, char* argv[]) //sprintf(OutFile, "%s.avE", OutFileBase); //SaveSummaryResults(); - Bitmap_Finalise(); + P.bitmap.finalise(); fprintf(stderr, "Extinction in %i out of %i runs\n", P.NRactE, P.NRactNE + P.NRactE); fprintf(stderr, "Model ran in %lf seconds\n", ((double)(clock() - cl)) / CLOCKS_PER_SEC); @@ -425,13 +418,13 @@ void parse_bmp_option(std::string const& input) { if (input_copy.compare("png") == 0) { #if defined(IMAGE_MAGICK) || defined(_WIN32) - P.BitmapFormat = BitmapFormats::PNG; + P.bitmap.format_ = CovidSim::BitMap::Formats::PNG; #else ERR_CRITICAL("PNG Bitmaps not supported - please build with Image Magic or WIN32 support"); #endif } else if (input_copy.compare("bmp") == 0) { - P.BitmapFormat = BitmapFormats::BMP; + P.bitmap.format_ = CovidSim::BitMap::Formats::BMP; } else { ERR_CRITICAL_FMT("Unrecognised bitmap format: %s", input_copy.c_str()); @@ -1260,7 +1253,7 @@ void ReadParams(std::string const& ParamFile, std::string const& PreParamFile, s if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Bitmap scale", "%lf", (void*)&(P.BitmapScale), 1, 1, 0)) P.BitmapScale = 1.0; if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Bitmap y:x aspect scaling", "%lf", (void*)&(P.BitmapAspectScale), 1, 1, 0)) P.BitmapAspectScale = 1.0; if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Bitmap movie frame interval", "%i", (void*)&(P.BitmapMovieFrame), 1, 1, 0)) P.BitmapMovieFrame = 250; - if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Output bitmap", "%i", (void*)&(P.OutputBitmap), 1, 1, 0)) P.OutputBitmap = 0; + if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Output bitmap", "%i", (void*) & (P.bitmap.output_), 1, 1, 0)) P.bitmap.output_ = 0; if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Output bitmap detected", "%i", (void*)&(P.OutputBitmapDetected), 1, 1, 0)) P.OutputBitmapDetected = 0; if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Output immunity on bitmap", "%i", (void*)&(P.DoImmuneBitmap), 1, 1, 0)) P.DoImmuneBitmap = 0; if (!GetInputParameter2(ParamFile_dat, PreParamFile_dat, "Output infection tree", "%i", (void*)&(P.DoInfectionTree), 1, 1, 0)) P.DoInfectionTree = 0; @@ -2495,19 +2488,19 @@ void InitModel(int run) // passing run number so we can save run number in the i int nim; int NumSeedingInfections_byLocation[MAX_NUM_SEED_LOCATIONS]; - if (P.OutputBitmap) + if (P.bitmap.output_) { #ifdef _WIN32 - //if (P.OutputBitmap == 1) + //if (P.bitmap.output_ == 1) //{ // char buf[200]; // sprintf(buf, "%s.ge" DIRECTORY_SEPARATOR "%s.avi", OutFile, OutFile); // avi = CreateAvi(buf, P.BitmapMovieFrame, NULL); //} #endif - for (unsigned p = 0; p < bmh->imagesize; p++) + for (unsigned p = 0; p < P.bitmap.header_->imagesize; p++) { - bmInfected[p] = bmRecovered[p] = bmTreated[p] = 0; + CovidSim::BitMap::Builder::infected_[p] = CovidSim::BitMap::Builder::recovered_[p] = CovidSim::BitMap::Builder::treated_[p] = 0; } } ns = 0; @@ -3421,7 +3414,7 @@ void SaveResults(std::string const& output_file_base) // DeleteFile(outname); // } #endif - if(P.OutputBitmap >= 1 && P.BitmapFormat == BitmapFormats::PNG) + if(P.bitmap.output_ >= 1 && P.bitmap.format_ == CovidSim::BitMap::Formats::PNG) { // Generate Google Earth .kml file outname = output_file_base + ".ge" DIRECTORY_SEPARATOR + output_file_base + ".ge.kml"; // outname = output_file_base + ".ge" DIRECTORY_SEPARATOR + output_file_base ".kml"; @@ -5121,11 +5114,11 @@ void RecordSample(double t, int n, std::string const& output_file_base) StateT[j].contact_dist[i] = 0; } } - if (P.OutputBitmap >= 1) + if (P.bitmap.output_ >= 1) { TSMean = TSMeanNE; TSVar = TSVarNE; - CaptureBitmap(); - OutputBitmap(0, output_file_base); + P.bitmap.capture(); + P.bitmap.output (0, output_file_base); } } diff --git a/src/Param.h b/src/Param.h index d5e7499af..1c4a4821f 100644 --- a/src/Param.h +++ b/src/Param.h @@ -3,6 +3,7 @@ #include +#include "Bitmap.h" #include "Country.h" #include "Constants.h" #include "InverseCdf.h" @@ -12,13 +13,6 @@ #include "geometry/BoundingBox.h" #include "geometry/Size.h" -/** @brief Enumeration of bitmap formats. */ -enum struct BitmapFormats -{ - PNG, // PNG - default if IMAGE_MAGICK or _WIN32 defined - BMP // BMP - fall-back -}; - /** * @brief Stores the parameters for the simulation. * @@ -59,14 +53,8 @@ struct Param int DoOutputPlaceDistForOneAdunit, OutputPlaceDistAdunit; int DoOneGen, OutputEveryRealisation, BitmapMovieFrame, MaxCorrSample, DoLatent, InfQueuePeakLength, NumThreads, MaxNumThreads; - /// Size in pixels of the map area in the bitmap output - CovidSim::Geometry::Size b; - - /// Height in pixels of the entire bitmap output, including both the spectrum at the top and the map area - int bheight2; + CovidSim::BitMap::Builder bitmap; - CovidSim::Geometry::Vector2i bmin; - BitmapFormats BitmapFormat; // Format of bitmap (platform dependent and command-line /BM: specified). int DoSI, DoPeriodicBoundaries, DoImmuneBitmap, OutputBitmapDetected; //added OutputBitmapDetected - ggilani 04/08/15 int DoHouseholds, DoPlaces, PlaceTypeNum, Nplace[NUM_PLACE_TYPES], SmallEpidemicCases, DoPlaceGroupTreat; int NumInitialInfections[MAX_NUM_SEED_LOCATIONS], DoRandomInitialInfectionLoc, DoAllInitialInfectioninSameLoc; @@ -82,7 +70,6 @@ struct Param int32_t nextSetupSeed1, nextSetupSeed2; // The next RNG seeds to use when we need to reinitialise the RNG for setup int32_t nextRunSeed1, nextRunSeed2; // The next RNG seeds to use when we need to reinitialise the RNG for the model int ResetSeeds,KeepSameSeeds, ResetSeedsPostIntervention, ResetSeedsFlag, TimeToResetSeeds; - int OutputBitmap; // Whether to output a bitmap int ts_age; int DoSeverity; // Non-zero (true) if severity analysis should be done diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index d7f0d2ad1..43b48a64d 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -182,17 +182,17 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ P.total_microcells_wide_ = P.ncw * P.NMCL; P.total_microcells_high_ = P.nch * P.NMCL; fprintf(stderr, "Number of microcells = %i\n", P.NMC); - P.scale.x = P.BitmapScale; - P.scale.y = P.BitmapAspectScale * P.BitmapScale; - P.b.width = (int)(P.in_degrees_.width * (P.BoundingBox.width()) * P.scale.x); - P.b.width = (P.b.width + 3) / 4; - P.b.width *= 4; - P.b.height = (int)(P.in_degrees_.height * (P.BoundingBox.height()) * P.scale.y); - P.b.height += (4 - P.b.height % 4) % 4; - P.bheight2 = P.b.height + 20; // space for colour legend - fprintf(stderr, "Bitmap width = %i\nBitmap height = %i\n", P.b.width, P.b.height); - P.bmin.x = (int)(P.in_degrees_.width * P.BoundingBox.bottom_left().x * P.scale.x); - P.bmin.y = (int)(P.in_degrees_.height * P.BoundingBox.bottom_left().y * P.scale.y); + P.bitmap.scale_.x = P.BitmapScale; + P.bitmap.scale_.y = P.BitmapAspectScale * P.BitmapScale; + P.bitmap.bounds_.width = (int)(P.in_degrees_.width * (P.BoundingBox.width()) * P.bitmap.scale_.x); + P.bitmap.bounds_.width = (P.bitmap.bounds_.width + 3) / 4; + P.bitmap.bounds_.width *= 4; + P.bitmap.bounds_.height = (int)(P.in_degrees_.height * (P.BoundingBox.height()) * P.bitmap.scale_.y); + P.bitmap.bounds_.height += (4 - P.bitmap.bounds_.height % 4) % 4; + P.bitmap.height2_ = P.bitmap.bounds_.height + 20; // space for colour legend + fprintf(stderr, "Bitmap width = %i\nBitmap height = %i\n", P.bitmap.bounds_.width, P.bitmap.bounds_.height); + P.bitmap.min_.x = (int)(P.in_degrees_.width * P.BoundingBox.bottom_left().x * P.bitmap.scale_.x); + P.bitmap.min_.y = (int)(P.in_degrees_.height * P.BoundingBox.bottom_left().y * P.bitmap.scale_.y); P.in_microcells_.width = P.in_cells_.width / ((double)P.NMCL); P.in_microcells_.height = P.in_cells_.height / ((double)P.NMCL); for (int i = 0; i < P.NumSeedLocations; i++) @@ -502,9 +502,9 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ } } - if (P.OutputBitmap) + if (P.bitmap.output_) { - InitBMHead(out_file_base); + P.bitmap.initialise_header(out_file_base); } if (P.DoMassVacc) { diff --git a/src/Update.cpp b/src/Update.cpp index 9fd5c6b70..b0945516d 100644 --- a/src/Update.cpp +++ b/src/Update.cpp @@ -84,16 +84,16 @@ void DoImmune(int ai) } - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[a->hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmRecovered[j]++; + CovidSim::BitMap::Builder::recovered_[j]++; } } } @@ -165,18 +165,18 @@ void DoInfect(int ai, double t, int tn, int run) // Change person from susceptib StateT[tn].cumInf_age_adunit [HOST_AGE_GROUP(ai)][Mcells[a->mcell].adunit]++; } } - if (P.OutputBitmap) + if (P.bitmap.output_) { if ((P.OutputBitmapDetected == 0) || ((P.OutputBitmapDetected == 1) && (Hosts[ai].detected == 1))) { - Vector2i pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[a->hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmInfected[j]++; + CovidSim::BitMap::Builder::infected_[j]++; } } } @@ -917,20 +917,20 @@ void DoRecover(int ai, int tn) if (P.DoAdUnits && P.OutputAdUnitAge) StateT[tn].prevInf_age_adunit[HOST_AGE_GROUP(ai)][Mcells[a->mcell].adunit]--; - if (P.OutputBitmap) + if (P.bitmap.output_) { if ((P.OutputBitmapDetected == 0) || ((P.OutputBitmapDetected == 1) && (Hosts[ai].detected == 1))) { - Vector2i pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[a->hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned int j2 = pixel.y * bmh->width + pixel.x; - if (j2 < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmRecovered[j2]++; + CovidSim::BitMap::Builder::recovered_[j]++; #pragma omp atomic - bmInfected[j2]--; + CovidSim::BitMap::Builder::infected_[j]--; } } } @@ -965,20 +965,20 @@ void DoDeath(int ai, int tn) StateT[tn].cumD_adunit[Mcells[a->mcell].adunit]++; if (P.OutputAdUnitAge) StateT[tn].prevInf_age_adunit[HOST_AGE_GROUP(ai)][Mcells[a->mcell].adunit]--; } - if (P.OutputBitmap) + if (P.bitmap.output_) { if ((P.OutputBitmapDetected == 0) || ((P.OutputBitmapDetected == 1) && (Hosts[ai].detected == 1))) { - Vector2i pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[a->hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmRecovered[j]++; + CovidSim::BitMap::Builder::recovered_[j]++; #pragma omp atomic - bmInfected[j]--; + CovidSim::BitMap::Builder::infected_[j]--; } } } @@ -1002,16 +1002,16 @@ void DoTreatCase(int ai, unsigned short int ts, int tn) if ((++Hosts[ai].num_treats) < 2) StateT[tn].cumUT++; Cells[Hosts[ai].pcell].tot_treat++; if (P.DoAdUnits) StateT[tn].cumT_adunit[Mcells[Hosts[ai].mcell].adunit]++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[Hosts[ai].hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2 pixel((Households[Hosts[ai].hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmTreated[j]++; + CovidSim::BitMap::Builder::treated_[j]++; } } } @@ -1033,16 +1033,16 @@ void DoProph(int ai, unsigned short int ts, int tn) if (P.DoAdUnits) StateT[tn].cumT_adunit[Mcells[Hosts[ai].mcell].adunit]++; #pragma omp atomic Cells[Hosts[ai].pcell].tot_treat++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[Hosts[ai].hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[Hosts[ai].hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmTreated[j]++; + CovidSim::BitMap::Builder::treated_[j]++; } } } @@ -1061,16 +1061,16 @@ void DoProphNoDelay(int ai, unsigned short int ts, int tn, int nc) if (P.DoAdUnits) StateT[tn].cumT_adunit[Mcells[Hosts[ai].mcell].adunit] += nc; #pragma omp atomic Cells[Hosts[ai].pcell].tot_treat++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[Hosts[ai].hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[Hosts[ai].hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmTreated[j]++; + CovidSim::BitMap::Builder::treated_[j]++; } } } @@ -1297,16 +1297,16 @@ void DoVacc(int ai, unsigned short int ts) } #pragma omp atomic Cells[Hosts[ai].pcell].tot_vacc++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[Hosts[ai].hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[Hosts[ai].hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmTreated[j]++; + CovidSim::BitMap::Builder::treated_[j]++; } } } @@ -1335,16 +1335,16 @@ void DoVaccNoDelay(int ai, unsigned short int ts) } #pragma omp atomic Cells[Hosts[ai].pcell].tot_vacc++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2i pixel((Households[Hosts[ai].hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2i pixel((Households[Hosts[ai].hh].loc * P.bitmap.scale_) - P.bitmap.min_); + if (P.bitmap.bounds_.contains(pixel)) { - unsigned j = pixel.y * bmh->width + pixel.x; - if (j < bmh->imagesize) + unsigned j = pixel.y * P.bitmap.header_->width + pixel.x; + if (j < P.bitmap.header_->imagesize) { #pragma omp atomic - bmTreated[j]++; + CovidSim::BitMap::Builder::treated_[j]++; } } }