teaching machines

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

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

Agenda

TODO

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);
  glLoadIdentity();
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  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);
  glLoadIdentity();
  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
  // read
  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