diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index 79d24902e..2423b4f27 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -24,12 +24,26 @@ 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 j; @@ -37,23 +51,23 @@ void CaptureBitmap() 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 >= 0)) + 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]; } } } @@ -70,45 +84,45 @@ void CaptureBitmap() if ((i >= P.get_number_of_micro_cells_high()) && (Mcells[i - P.get_number_of_micro_cells_high()].n > 0) && (Mcells[i].country != Mcells[i - P.get_number_of_micro_cells_high()].country)) f = 1; if (f) { - x = (int)(P.in_microcells_.width * (((double)(i / P.get_number_of_micro_cells_high())) + 0.5) * P.scale.x) - P.bmin.x; - y = (int)(P.in_microcells_.height * (((double)(i % P.get_number_of_micro_cells_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.get_number_of_micro_cells_high())) + 0.5) * scale_.x) - min_.x; + y = (int)(P.in_microcells_.height * (((double)(i % P.get_number_of_micro_cells_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) && (j >= 0)) 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) +void CovidSim::BitMap::Builder::output(int tp) { char buf[3000], OutF[3000]; int j = 0; @@ -146,7 +160,7 @@ void OutputBitmap(int tp) break; } - if (P.BitmapFormat == BitmapFormats::PNG) + if (format_ == CovidSim::BitMap::Formats::PNG) { #ifdef IMAGE_MAGICK FILE* dat; @@ -155,9 +169,9 @@ void OutputBitmap(int tp) 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); @@ -172,7 +186,7 @@ void OutputBitmap(int tp) size_t a; //Add new bitmap to AVI - //if ((P.OutputBitmap == 1) && (tp == 0)) AddAviFrame(avi, bmpdib, (unsigned char*)(&bmh->palette[0][0])); + //if ((P.OutputBitmap == 1) && (tp == 0)) AddAviFrame(avi, bmpdib, (unsigned char*)(&header_->palette[0][0])); //This transfers HBITMAP to GDI+ Bitmap object Bitmap* gdip_bmp = Bitmap::FromHBITMAP(bmpdib, NULL); @@ -198,7 +212,7 @@ void OutputBitmap(int tp) 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, j); FILE* dat; if (!(dat = fopen(buf, "wb"))) { @@ -209,72 +223,72 @@ void OutputBitmap(int tp) 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() +void CovidSim::BitMap::Builder::initialise_header() { 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); - if (!(bmf = (unsigned char*)calloc((size_t)k + k2, sizeof(unsigned char)))) + if (!(bitmap_ = (unsigned char*)calloc((size_t)k + k2, sizeof(unsigned char)))) ERR_CRITICAL("Unable to allocate storage for bitmap\n"); - 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 + 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; } - if (!(bmPopulation = (int32_t*)malloc(bmh->imagesize * sizeof(int32_t))) || - !(bmInfected = (int32_t*)malloc(bmh->imagesize * sizeof(int32_t))) || - !(bmRecovered = (int32_t*)malloc(bmh->imagesize * sizeof(int32_t))) || - !(bmTreated = (int32_t*)malloc(bmh->imagesize * sizeof(int32_t)))) + if (!(population_ = (int32_t*)malloc(header_->imagesize * sizeof(int32_t))) || + !(infected_ = (int32_t*)malloc(header_->imagesize * sizeof(int32_t))) || + !(recovered_ = (int32_t*)malloc(header_->imagesize * sizeof(int32_t))) || + !(treated_ = (int32_t*)malloc(header_->imagesize * sizeof(int32_t)))) ERR_CRITICAL("Unable to allocate storage for bitmap\n"); #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, NULL); + bmpdib = CreateDIBSection(GetDC(NULL), (BITMAPINFO*)info_, DIB_RGB_COLORS, (void**)&pixels_, NULL, NULL); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); @@ -309,10 +323,10 @@ void InitBMHead() #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 a11d53155..125a2ddeb 100644 --- a/src/Bitmap.h +++ b/src/Bitmap.h @@ -21,30 +21,81 @@ #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); -void InitBMHead(); - -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::Vector2 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); + void initialise_header(); + + 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 f92749583..cd1319d85 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -78,7 +78,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; @@ -92,12 +91,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. - char OutFile[1024], OutFileBase[1024], OutDensFile[1024], SnapshotLoadFile[1024], SnapshotSaveFile[1024], AdunitFile[1024]; int ns, DoInitUpdateProbs, InterruptRun = 0; @@ -127,9 +120,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 ///// Read in command line arguments - lots of things, e.g. random number seeds; (pre)parameter files; binary files; population data; output directory? etc. @@ -294,7 +287,7 @@ int main(int argc, char* argv[]) if (strcasecmp(buf, "png") == 0) { #if defined(IMAGE_MAGICK) || defined(_WIN32) - P.BitmapFormat = BitmapFormats::PNG; + P.bitmap.format_ = CovidSim::BitMap::Formats::PNG; #else fprintf(stderr, "PNG Bitmaps not supported - please build with Image Magic or WIN32 support\n"); Perr = 1; @@ -302,7 +295,7 @@ int main(int argc, char* argv[]) } else if (strcasecmp(buf, "bmp") == 0) { - P.BitmapFormat = BitmapFormats::BMP; + P.bitmap.format_ = CovidSim::BitMap::Formats::BMP; } else { @@ -319,7 +312,7 @@ int main(int argc, char* argv[]) sprintf(OutFile, "%s", OutFileBase); fprintf(stderr, "Param=%s\nOut=%s\nDens=%s\n", ParamFile, OutFile, DensityFile); - 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"); if (Perr) ERR_CRITICAL_FMT("Syntax:\n%s /P:ParamFile /O:OutputFile [/AP:AirTravelFile] [/s:SchoolFile] [/D:DensityFile] [/L:NetworkFileToLoad | /S:NetworkFileToSave] [/R:R0scaling] SetupSeed1 SetupSeed2 RunSeed1 RunSeed2\n", argv[0]); //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** //// **** @@ -473,7 +466,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); @@ -1211,7 +1204,7 @@ void ReadParams(char* ParamFile, char* PreParamFile) 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; @@ -2432,7 +2425,7 @@ 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) @@ -2442,9 +2435,9 @@ void InitModel(int run) // passing run number so we can save run number in the i // 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; @@ -3353,7 +3346,7 @@ void SaveResults(void) // 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 sprintf(outname, "%s.ge" DIRECTORY_SEPARATOR "%s.ge.kml", OutFile, OutFile); //sprintf(outname,"%s.ge" DIRECTORY_SEPARATOR "%s.kml",OutFileBase,OutFile); @@ -5231,11 +5224,11 @@ void RecordSample(double t, int n) } } - if (P.OutputBitmap >= 1) + if (P.bitmap.output_ >= 1) { TSMean = TSMeanNE; TSVar = TSVarNE; - CaptureBitmap (); - OutputBitmap (0); + P.bitmap.capture(); + P.bitmap.output (0); } } diff --git a/src/Param.h b/src/Param.h index 2ca62dc08..42d4a0f02 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" @@ -10,13 +11,6 @@ #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. * @@ -57,14 +51,8 @@ struct Param int DoOutputPlaceDistForOneAdunit, OutputPlaceDistAdunit, OutputDensFile; int DoOneGen, OutputEveryRealisation, BitmapMovieFrame, MaxCorrSample, DoLatent, InfQueuePeakLength, NumThreads, MaxNumThreads; - /// Size in pixels of the map area in the bitmap output - Geometry::Size b; + CovidSim::BitMap::Builder bitmap; - /// Height in pixels of the entire bitmap output, including both the spectrum at the top and the map area - int bheight2; - - Geometry::Vector2 bmin; - BitmapFormats BitmapFormat; // Format of bitmap (platform dependent and command-line /BM: specified). int DoSI, DoHeteroDensity, 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; @@ -79,7 +67,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 double LongitudeCutLine; // Longitude to image earth is cut at to produce a flat map. Default -360 degrees (effectively -180). Use to ensure countries have a contiguous boundary double SpatialBoundingBox[4], LocationInitialInfection[MAX_NUM_SEED_LOCATIONS][2], InitialInfectionsAdminUnitWeight[MAX_NUM_SEED_LOCATIONS], TimeStepsPerDay; double FalsePositiveRate, FalsePositivePerCapitaIncidence, FalsePositiveAgeRate[NUM_AGE_GROUPS]; @@ -104,9 +91,6 @@ struct Param int ts_age; int DoSeverity; // Non-zero (true) if severity analysis should be done - /// Number of pixels per degree in bitmap output - Geometry::Vector2 scale; - /// Size of spatial domain in degrees Geometry::Size in_degrees_; diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index d7eea1a6a..a25761e75 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -180,17 +180,17 @@ void SetupModel(char* DensityFile, char* NetworkFile, char* SchoolFile, char* Re } P.NMC = P.NMCL * P.NMCL * P.NC; 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[2] - P.BoundingBox[0]) * 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[3] - P.BoundingBox[1]) * 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[0] * P.scale.x); - P.bmin.y = (int)(P.in_degrees_.height * P.BoundingBox[1] * 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[2] - P.BoundingBox[0]) * 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[3] - P.BoundingBox[1]) * 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[0] * P.bitmap.scale_.x); + P.bitmap.min_.y = (int)(P.in_degrees_.height * P.BoundingBox[1] * 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++) @@ -638,9 +638,9 @@ void SetupModel(char* DensityFile, char* NetworkFile, char* SchoolFile, char* Re } } - if (P.OutputBitmap) + if (P.bitmap.output_) { - InitBMHead(); + P.bitmap.initialise_header(); } if (P.DoMassVacc) { diff --git a/src/Update.cpp b/src/Update.cpp index 0ace8e9b0..0827252b5 100644 --- a/src/Update.cpp +++ b/src/Update.cpp @@ -61,16 +61,16 @@ void DoImmune(int ai) } - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2 pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2 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]++; } } } @@ -143,18 +143,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))) { - Vector2 pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2 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]++; } } } @@ -944,20 +944,20 @@ void DoRecover(int ai, int tn, int run) 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))) { - Vector2 pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2 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]--; } } } @@ -993,20 +993,20 @@ void DoDeath(int ai, int tn, int run) 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))) { - Vector2 pixel((Households[a->hh].loc * P.scale) - P.bmin); - if (P.b.contains(pixel)) + Vector2 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]--; } } } @@ -1030,16 +1030,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_) { - Vector2 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]++; } } } @@ -1061,16 +1061,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 critical (tot_treat) Cells[Hosts[ai].pcell].tot_treat++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2 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]++; } } } @@ -1089,16 +1089,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 critical (tot_treat) Cells[Hosts[ai].pcell].tot_treat++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2 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]++; } } } @@ -1325,16 +1325,16 @@ void DoVacc(int ai, unsigned short int ts) } #pragma omp critical (tot_vacc) Cells[Hosts[ai].pcell].tot_vacc++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2 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]++; } } } @@ -1363,16 +1363,16 @@ void DoVaccNoDelay(int ai, unsigned short int ts) } #pragma omp critical (tot_vacc) Cells[Hosts[ai].pcell].tot_vacc++; - if (P.OutputBitmap) + if (P.bitmap.output_) { - Vector2 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]++; } } }