# teaching machines

## CS 330 Lecture 33 – Marching Squares: A C++ Case Study

April 26, 2013 by . Filed under cs330, lectures, spring 2013.

### Agenda

• what ?s
• contourer: a case study on OOP and C++
• bit manipulation

### TODO

• Get two homeworks done before the networks students ruin us all.

### Code

Marching squares cases.

#### msquares.cpp

#include <iostream>
#include <fstream>
#include <limits>
#include <GL/glut.h>

using std::string;

class Map {
public:
Map() {}
Map(const string &path);

const int &operator()(int c, int r) const;
int &operator()(int c, int r);
int GetWidth() const;
int GetHeight() const;
int GetMin() const;
int GetMax() const;

private:
int *elevation;
int width;
int height;
int max;
int min;
};

Map::Map(const string &path) {
std::ifstream in(path.c_str());
int nfac, nocean, nland;
in >> width >> height >> nfac >> nocean >> nland;

elevation = new int[width * height];
min = std::numeric_limits<int>::max();
max = std::numeric_limits<int>::min();
for (int lat = 0; lat < height; ++lat) {
for (int lon = 0; lon < width; ++lon) {
int height;
in >> height;

if (height == nocean) {
height = 0;
}

if (height > max) {
max = height;
} else if (height < min) {
min = height;
}

(*this)(lon, GetHeight() - 1 - lat) = height;
}
}
in.close();
}

int &Map::operator()(int c, int r) {
return elevation[r * GetWidth() + c];
}

const int &Map::operator()(int c, int r) const {
return elevation[r * GetWidth() + c];
}

int Map::GetWidth() const {
return width;
}

int Map::GetHeight() const {
return height;
}

int Map::GetMin() const {
return min;
}

int Map::GetMax() const {
return max;
}

static int iso = 1000;
static Map map;

void on_draw() {
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glColor3f(1.0f, 1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_PROJECTION);

glEnable(GL_TEXTURE_2D);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);

glMatrixMode(GL_PROJECTION);
glOrtho(0.0f, map.GetWidth(), 0.0f, map.GetHeight(), -1.0f, 1.0f);

// TODO draw contour lines
glBegin(GL_LINES);
for (int lat = 0; lat < map.GetHeight() - 1; ++lat) {
for (int lon = 0; lon < map.GetWidth() - 1; ++lon) {
int bl = map(lon, lat) >= iso;
int br = map(lon + 1, lat) >= iso;
int tl = map(lon, lat + 1) >= iso;
int tr = map(lon + 1, lat + 1) >= iso;

int config = bl | (br << 1) | (tl << 2) | (tr << 3);

if (config > 7) {
config = 15 - config;
}

switch (config) {
case 0:
break;
case 1:
glVertex2f(lon, lat + 0.5f);
glVertex2f(lon + 0.5f, lat);
break;
case 2:
glVertex2f(lon + 0.5f, lat);
glVertex2f(lon + 1.0f, lat + 0.5f);
break;
case 3:
glVertex2f(lon, lat + 0.5f);
glVertex2f(lon + 1.0f, lat + 0.5f);
break;
case 4:
glVertex2f(lon, lat + 0.5f);
glVertex2f(lon + 0.5f, lat + 1.0f);
break;
case 5:
glVertex2f(lon + 0.5f, lat);
glVertex2f(lon + 0.5f, lat + 1.0f);
break;
case 6:
glVertex2f(lon + 0.5f, lat);
glVertex2f(lon, lat + 0.5f);
glVertex2f(lon + 0.5f, lat + 1.0f);
glVertex2f(lon + 1.0f, lat + 0.5f);
break;
case 7:
glVertex2f(lon + 0.5f, lat + 1.0f);
glVertex2f(lon + 1.0f, lat + 0.5f);
break;
}
}
}

glEnd();

glutSwapBuffers();
}

void on_special_key(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
iso += 25;
break;
case GLUT_KEY_DOWN:
iso -= 25;
break;
default:
break;
}

std::cout << "iso: " << iso << std::endl;
glutPostRedisplay();
}

int main(int argc, char **argv) {
// open file
// read nlon, nlat, nfac, nocean, nland
// allocate
map = Map("dem030_ascii.dat");

// TODO normalize
float *normalized = new float[map.GetWidth() * map.GetHeight()];
for (int lat = 0; lat < map.GetHeight(); ++lat) {
for (int lon = 0; lon < map.GetWidth(); ++lon) {
int i = lat * map.GetWidth() + lon;
normalized[i] = (map(lon, lat) - map.GetMin()) / (float) (map.GetMax() - map.GetMin());
}
}
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(1200, 600);
glutInit(&argc, argv);

glutCreateWindow("Contours");
glutDisplayFunc(on_draw);
glutSpecialFunc(on_special_key);

GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, map.GetWidth(), map.GetHeight(), 0, GL_LUMINANCE, GL_FLOAT, normalized);
delete[] normalized;

glutMainLoop();

return 0;
}

### Haiku

Boole cleaved us in two
Not just once, but many times
Don’t be only white