Browse Source

turns out that a vector of vectors is just as fast

master
Joshua Moerman 13 years ago
parent
commit
43d96ffb6d
  1. 14
      AwesomeAttractorND.xcodeproj/project.pbxproj
  2. 36
      AwesomeAttractorND/Canvas.hpp
  3. 24
      AwesomeAttractorND/Image.hpp
  4. 139
      AwesomeAttractorND/Logging.hpp
  5. 19
      AwesomeAttractorND/Tonemapper.hpp
  6. 101
      AwesomeAttractorND/main.cpp
  7. 6
      AwesomeAttractorND/nd_array.hpp

14
AwesomeAttractorND.xcodeproj/project.pbxproj

@ -28,6 +28,7 @@
428EFECF145AF6E0001DBE1B /* Canvas.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Canvas.hpp; sourceTree = "<group>"; };
428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tonemapper.hpp; sourceTree = "<group>"; };
42C2D1521461676B001BF28D /* Image.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Image.hpp; sourceTree = "<group>"; };
42C2D1611461894E001BF28D /* Logging.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Logging.hpp; sourceTree = "<group>"; };
42D2E11D1456175C00FBC16A /* AwesomeAttractorND */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = AwesomeAttractorND; sourceTree = BUILT_PRODUCTS_DIR; };
42D2E1211456175C00FBC16A /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = AwesomeAttractorND.1; sourceTree = "<group>"; };
@ -65,6 +66,7 @@
isa = PBXGroup;
children = (
42D2E1211456175C00FBC16A /* main.cpp */,
42C2D1611461894E001BF28D /* Logging.hpp */,
42D2E12A1456176800FBC16A /* nd_array.hpp */,
428EFECF145AF6E0001DBE1B /* Canvas.hpp */,
428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */,
@ -151,9 +153,15 @@
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = /usr/local/include/;
MACOSX_DEPLOYMENT_TARGET = 10.7;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
WARNING_CFLAGS = (
"-Weffc++",
"-Wextra",
"-Wall",
);
};
name = Debug;
};
@ -171,8 +179,14 @@
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = /usr/local/include/;
MACOSX_DEPLOYMENT_TARGET = 10.7;
SDKROOT = macosx;
WARNING_CFLAGS = (
"-Weffc++",
"-Wextra",
"-Wall",
);
};
name = Release;
};

36
AwesomeAttractorND/Canvas.hpp

@ -9,6 +9,7 @@
#ifndef AwesomeAttractorND_Canvas_hpp
#define AwesomeAttractorND_Canvas_hpp
#include <vector>
#include "nd_array.hpp"
class Canvas2D : public nd_array<unsigned int, 2>{
@ -24,14 +25,45 @@ public:
const size_t width = get_size(0);
const size_t height = get_size(1);
const size_t x = position[0]*width + width*.5;
const size_t y = position[1]*width + height*.5;
const size_t x = 0.5*position[0]*width + width*.5;
const size_t y = 0.5*position[1]*width + height*.5;
if(x < width && y < height) {
(*this)[x][y]++;
}
}
};
class Canvas2Db : public std::vector<std::vector<unsigned int> > {
typedef Canvas2Db self;
typedef std::vector<std::vector<unsigned int> > super;
public:
Canvas2Db(size_t width, size_t height)
: super(width, super::value_type(height, 0))
{}
void plot(double const * const position){
const size_t width = get_size(0);
const size_t height = get_size(1);
const size_t x = 0.5*position[0]*width + width*.5;
const size_t y = 0.5*position[1]*width + height*.5;
if(x < width && y < height) {
(*this)[x][y]++;
}
}
size_t get_size(size_t n) const {
switch (n) {
case 0:
return size();
case 1:
return front().size();
}
return 0;
}
};
#endif

24
AwesomeAttractorND/Image.hpp

@ -14,9 +14,7 @@
#include <stdexcept>
#include <tr1/memory>
struct pixel {
friend class Image;
struct pixel {
pixel(double red, double green, double blue)
: red(clamp(255*red))
, green(clamp(255*green))
@ -29,6 +27,10 @@ struct pixel {
, blue(clamp(blue))
{}
void swapRB(){
std::swap(red, blue);
}
private:
uint8_t clamp(int n){
return std::min(255, std::max(0, n));
@ -116,21 +118,29 @@ namespace ImageFormats {
: dib_header(width, height)
, header(dib_header)
, file(filename.c_str())
, x(0)
, y(0)
{
if(!file)
throw std::runtime_error("bitmap file could not be opened.");
header.write(file);
dib_header.write(file);
}
bitmap_stream& operator<<(pixel const & p){
file.write(&p, 3);
if (y >= dib_header.height){
throw std::out_of_range("Writing BMP image out of bounds.");
}
pixel p2(p);
p2.swapRB();
file.write((char const *)&p2, 3);
++x;
if (x >= dib_header.width){
x = 0;
++y;
}
if (y >= dib_header.height){
throw std::out_of_range("Writing BMP image out of bounds.");
}
return *this;
}
private:

139
AwesomeAttractorND/Logging.hpp

@ -0,0 +1,139 @@
//
// Logging.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 11/2/11.
// Copyright 2011 Vadovas. All rights reserved.
//
#ifndef AwesomeAttractorND_Logging_hpp
#define AwesomeAttractorND_Logging_hpp
#pragma once
#include <iostream>
#define INFORMATION __FILE__ << ":" << __LINE__ << "(" << __FUNCTION__ << ")"
#define COUT std::cout << INFORMATION << "\n"
#define CERR std::cerr << INFORMATION << "\n"
#define VCOUT if(verbose) COUT
#define VCERR if(verbose) CERR
#pragma once
#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <cassert>
#include <boost/date_time/posix_time/posix_time.hpp>
/* Usage:
When timing anything:
Before starting the task: start("with a string");
When the task is done: stop();
The shorthand for that is
{
start("foo");
foo();
stop();
}
Note that a call to stop without parameters, stops the last started event. This works like a stack:
{
start("Task of several small tasks");
start("Small task 1");
small_task_1();
stop();
start("Small task 2");
small_task_2();
stop();
stop(); // Stops "Task of several small tasks"
}
The indenting is, of course, only to help you understand what's going on.
Questions/Suggestions mail nick@astrant.net
*/
struct Logger {
Logger(std::ostream& logging_stream_, std::string prefix_ = std::string(""))
: logging_stream(&logging_stream_)
, prefix(prefix_)
{}
void log(std::string what){
*logging_stream << get_prefix() << "(" << what << ") took place at (" << boost::posix_time::microsec_clock::local_time() << std::endl;
}
void start(std::string what){
Event e;
e.start = boost::posix_time::microsec_clock::local_time();
e.name = what;
EventMap::iterator it = event_map.find(what);
if(it != event_map.end()){
*logging_stream << get_prefix() << "WARNING: Overwriting event(" << e.name << "), did you forget to call stop()?";
} else {
event_name_stack.push(what);
}
event_map.insert(it, std::make_pair(what, e));
}
void stop() {
assert(!event_name_stack.empty());
stop(event_name_stack.top());
}
private:
void stop(std::string what){
EventMap::iterator it = event_map.find(what);
if(it == event_map.end()){
*logging_stream << get_prefix() << "WARNING: No such, or already stopped, event(" << what << "), did you forget to call start()?";
} else {
it->second.end = boost::posix_time::microsec_clock::local_time();
log_event(it->second);
event_map.erase(it);
}
event_name_stack.pop();
}
struct Event {
boost::posix_time::ptime start;
boost::posix_time::ptime end;
std::string name;
};
// A map containing strings -> Event, used by start() and stop()
typedef std::map<std::string, Event> EventMap;
EventMap event_map;
// A stack used by 0-parameter stop() to stop the last start()ed event.
std::stack<std::string> event_name_stack;
std::ostream* logging_stream;
std::string prefix;
void log_event(Event const& e){
*logging_stream << get_prefix() << "Event(" << e.name << ") started at (" << e.start << ") ended at (" << e.end << ") duration (" << e.end - e.start << " ms) " << std::endl;
}
std::string get_prefix() const {
if(prefix == std::string("")){
return prefix;
} else {
return prefix + ": ";
}
}
};
#endif

19
AwesomeAttractorND/Tonemapper.hpp

@ -10,15 +10,23 @@
#define AwesomeAttractorND_Tonemapper_hpp
#include <algorithm>
#include <cmath>
namespace Tonemappers {
class Normalizer2D {
unsigned int max;
struct Normalizer2D {
Normalizer2D()
: max(0)
{}
template <typename C>
void analyse(C const & canvas){
max = *std::max_element(canvas.cbegin(), canvas.cend());
//max = *std::max_element(canvas.cbegin(), canvas.cend());
for (size_t x = 0; x < canvas.get_size(0); ++x) {
for (size_t y = 0; y < canvas.get_size(1); ++y) {
max = std::max(max, (unsigned int)canvas[x][y]);
}
}
}
template <typename C, typename I>
@ -26,10 +34,13 @@ namespace Tonemappers {
for (size_t x = 0; x < canvas.get_size(0); ++x) {
for (size_t y = 0; y < canvas.get_size(1); ++y) {
const double grayscale = (double) canvas[x][y] / (double) max;
image << I::pixel(grayscale, grayscale, grayscale);
image << typename I::pixel(std::pow(grayscale, 0.2), std::pow(grayscale, 0.6), grayscale*1.5);
}
}
}
private:
unsigned int max;
};
}

101
AwesomeAttractorND/main.cpp

@ -12,91 +12,40 @@
#include "Canvas.hpp"
#include "Tonemapper.hpp"
#include "Image.hpp"
#include "Logging.hpp"
const size_t width = 512;
const size_t height = 64;
const size_t depth = 32;
typedef Canvas2D Canvas;
typedef nd_array<double, 3> array;
double calculate1(array & c){
double mean = 0.0;
for (unsigned int x = 0; x < width; ++x) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int z = 0; z < depth; ++z) {
mean += 1.0/(width*height*depth) * c[x][y][z];
}
}
}
return mean;
}
void calculate2(array & c, double mean){
for (unsigned int x = 0; x < width; ++x) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int z = 0; z < depth; ++z) {
c[x][y][z] = c[x/3][y][z/2] * mean / 200.0 + mean - x;
}
}
}
}
void calculate(array & c){
std::cout << "Calculating..." << std::endl;
for (unsigned int i = 0; i < 1000; ++i) {
double mean = calculate1(c);
calculate2(c, mean);
}
}
void fill(array & c){
std::cout << "Filling..." << std::endl;
void fill(Canvas & canvas){
const unsigned int it = 100000000/2;
for (unsigned int x = 0; x < width; ++x) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int z = 0; z < depth; ++z) {
c[x][y][z] = x + z;
if (y == 5) {
c[x][y][z] = 5;
}
}
}
for (unsigned int i = 0; i < it; ++i){
double x = 2.0 * (rand() / (double) RAND_MAX - 0.5);
double y = 2.0 * (rand() / (double) RAND_MAX - 0.5);
double position[2] = {sin(x / (y*y - 1)), sin(y / (x*x - 1))};
canvas.plot(position);
}
}
void output(array & c){
std::cout << "Outputting..." << std::endl;
void output(Canvas const & canvas){
ImageFormats::bmp::bitmap_stream<> image(canvas.get_size(0), canvas.get_size(1), "test.bmp");
Tonemappers::Normalizer2D tonemapper;
for (unsigned int y = 0; y < 10; ++y) {
for (unsigned int x = 0; x < 10; ++x) {
std::cout << c[x][y][2] << '\t';
}
std::cout << '\n';
}
std::cout << "Outputting addresses..." << std::endl;
for (unsigned int z = 20; z < 30; ++z) {
double & n = c[32][64][z];
std::cout << &n << '\n';
}
tonemapper.analyse(canvas);
tonemapper.process(canvas, image);
}
int main (int argc, const char * argv[]){
std::cout << "Creating..." << std::endl;
array c(width, height, depth);
int main (int, const char * []){
Logger l(std::cout);
l.start("all");
fill(c);
calculate(c);
output(c);
std::cout << "Done" << std::endl;
l.log("creating canvas");
Canvas canvas(2048, 2048);
l.log("filling canvas");
fill(canvas);
l.log("outputting canvas");
output(canvas);
l.stop();
return 0;
}
}

6
AwesomeAttractorND/nd_array.hpp

@ -76,7 +76,7 @@ public:
const_proxy<N-1> operator[](size_t y) const {
if (N == 0) throw std::logic_error("called operator[] on a value");
return proxy<N-1>(data, data->sizes[dimension - N]*offset + y);
return const_proxy<N-1>(data, data->sizes[dimension - N]*offset + y);
}
operator const_reference() const {
@ -115,7 +115,7 @@ public:
}
size_type size() const {
return std::accumulate(sizes.begin(), sizes.end(), 0, std::multiplies<size_type>());
return std::accumulate(sizes.begin(), sizes.end(), 1, std::multiplies<size_type>());
}
proxy<dimension-1> operator[](size_t x){
@ -123,7 +123,7 @@ public:
}
const_proxy<dimension-1> operator[](size_t x) const {
return proxy<dimension-1>(this, x);
return const_proxy<dimension-1>(this, x);
}
iterator begin(){