Skip to content

Commit

Permalink
Extract a struct for building bitmaps
Browse files Browse the repository at this point in the history
  • Loading branch information
zebmason committed Jun 19, 2020
1 parent 863389f commit e6bf03a
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 210 deletions.
174 changes: 94 additions & 80 deletions src/Bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,50 @@ static CLSID encoderClsid;
#include <sys/stat.h> // 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;
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 >= 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];
}
}
}
Expand All @@ -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, pixels_, population_, infected_, treated_, recovered_, 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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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"))) {
Expand All @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
95 changes: 73 additions & 22 deletions src/Bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> bounds_;

Geometry::Vector2<int> 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<double> 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_
Loading

0 comments on commit e6bf03a

Please sign in to comment.