Joshua
15 years ago
commit
8c57b315af
44 changed files with 8436 additions and 0 deletions
@ -0,0 +1,345 @@ |
|||||
|
#include <cmath> |
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include <cstdlib> |
||||
|
#include <iomanip> |
||||
|
#include <cassert> |
||||
|
#include <string> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "Attractor.hpp" |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
Constructors & initialisers |
||||
|
*/ |
||||
|
Attractor::Attractor(): |
||||
|
dim(3), par(4), formula(LORENZ), param(NULL), point(NULL), new_point(NULL) { |
||||
|
// Default attractor: 3D Lorenz attrractor
|
||||
|
init_vector(); |
||||
|
init_param(); |
||||
|
|
||||
|
param[0] = 0.001; //dt
|
||||
|
param[1] = 10; //sigma
|
||||
|
param[2] = 28; //rho
|
||||
|
param[3] = 8.0/3.0; //beta
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
Attractor::Attractor(unsigned int dimensions, FormulaChoice formula, unsigned int orde): |
||||
|
dim(dimensions), formula(formula), orde(orde), param(NULL), point(NULL), new_point(NULL) { |
||||
|
|
||||
|
init(dimensions, formula, orde); |
||||
|
} |
||||
|
|
||||
|
Attractor::Attractor(const char* const filename) { |
||||
|
ifstream file(filename); |
||||
|
|
||||
|
cout << "Reading file " << filename << "..." << endl; |
||||
|
|
||||
|
if ( !file ) { |
||||
|
cout << " Error reading file '" << filename << "' dying now..." << endl; |
||||
|
exit(2); |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
file.attr: |
||||
|
lorenz |
||||
|
3 |
||||
|
0 |
||||
|
|
||||
|
3.24454 |
||||
|
1.25 |
||||
|
.... |
||||
|
*/ |
||||
|
|
||||
|
string fileFormula; |
||||
|
file >> fileFormula; |
||||
|
|
||||
|
for ( unsigned int i = 0; fileFormula[i] != '\0'; i++ ) { |
||||
|
fileFormula[i] = tolower(fileFormula[i]); |
||||
|
} |
||||
|
|
||||
|
unsigned int fileDim; |
||||
|
file >> fileDim; |
||||
|
|
||||
|
unsigned int fileOrde; |
||||
|
file >> fileOrde; |
||||
|
|
||||
|
cout << " Formula: " << fileFormula << endl; |
||||
|
cout << " Dimensions: " << fileDim << endl; |
||||
|
cout << " Orde: " << fileOrde << endl; |
||||
|
|
||||
|
if ( fileFormula == "lorenz" ) |
||||
|
init(fileDim, LORENZ, fileOrde); |
||||
|
else if ( fileFormula == "poly_n" ) |
||||
|
init(fileDim, POLY_N, fileOrde); |
||||
|
else if ( fileFormula == "poly_a" ) |
||||
|
init(fileDim, POLY_A, fileOrde); |
||||
|
else if ( fileFormula == "logistic" ) |
||||
|
init(fileDim, LOGISTIC, fileOrde); |
||||
|
else if ( fileFormula == "unravel" ) |
||||
|
init(fileDim, UNRAVEL, fileOrde); |
||||
|
else { |
||||
|
cout << " Formula not (yet) supported" << endl; |
||||
|
exit(3); |
||||
|
} |
||||
|
|
||||
|
for ( unsigned int i = 0; i < par; i++ ) { |
||||
|
file >> param[i]; |
||||
|
cout << " Parameter " << i << " set to " << param[i] << ", "; |
||||
|
} |
||||
|
|
||||
|
cout << endl << " Reading file complete" << endl; |
||||
|
} |
||||
|
|
||||
|
void Attractor::init(unsigned int dim_in, FormulaChoice formula_in, unsigned int orde_in) { |
||||
|
|
||||
|
dim = dim_in; |
||||
|
formula = formula_in; |
||||
|
orde = orde_in; |
||||
|
|
||||
|
switch (formula) { |
||||
|
case POLY_N: { |
||||
|
double n_coef = orde + 1; |
||||
|
for (unsigned int i = 2; i <= dim; i++) { |
||||
|
n_coef = n_coef*(orde + i)/(i - 1); |
||||
|
} |
||||
|
|
||||
|
par = (unsigned int) n_coef; |
||||
|
break; |
||||
|
} |
||||
|
case LORENZ: { |
||||
|
assert(dim == 3 || dim == 4); |
||||
|
par = dim + 1; |
||||
|
break; |
||||
|
} |
||||
|
case POLY_A: { |
||||
|
par = dim; |
||||
|
break; |
||||
|
} |
||||
|
case LOGISTIC: { |
||||
|
par = dim; |
||||
|
break; |
||||
|
} |
||||
|
case UNRAVEL: { |
||||
|
assert(dim == 3); |
||||
|
par = 7; |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
cout << "Formula not recognized" << endl; |
||||
|
exit(1); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
init_vector(); |
||||
|
init_param(); |
||||
|
} |
||||
|
|
||||
|
void Attractor::init_vector() { |
||||
|
point = new double[dim]; |
||||
|
new_point = new double[dim]; |
||||
|
|
||||
|
assert(point != NULL); |
||||
|
assert(new_point != NULL); |
||||
|
|
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
point[i] = new_point[i] = 0.9; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Attractor::init_param() { |
||||
|
param = new double[par]; |
||||
|
|
||||
|
assert(param != NULL); |
||||
|
|
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
param[i] = 0.0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Attractor::init_range() { |
||||
|
|
||||
|
// stabilize attractor
|
||||
|
for ( unsigned int i = 0; i < 100000; i++ ) { |
||||
|
iterate(); |
||||
|
if ( !is_chaos() ) { |
||||
|
cout << "Attractor died after " << i << " iterations" << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// initialize ranges
|
||||
|
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) { |
||||
|
(*it)->extern_dim = dim; |
||||
|
(*it)->intern_dim = 2; |
||||
|
(*it)->init(point); |
||||
|
} |
||||
|
|
||||
|
// update ranges
|
||||
|
for ( unsigned int i = 0; i < 100000; i++ ) { |
||||
|
iterate(); |
||||
|
if ( !is_chaos() ) { |
||||
|
cout << "Attractor died after " << i << " iterations" << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) { |
||||
|
(*it)->update_range(point); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) { |
||||
|
(*it)->finish_range(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool Attractor::is_chaos() { |
||||
|
/*
|
||||
|
check existence of attractor: |
||||
|
Escaping |
||||
|
Single point attractor |
||||
|
Lyapunov exponent |
||||
|
*/ |
||||
|
|
||||
|
double sum = 0; |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
const double dist = new_point[i] - point[i]; |
||||
|
sum += dist*dist; |
||||
|
} |
||||
|
if ( sum >= 1.0e7 ) { |
||||
|
// big change => Escaping
|
||||
|
return false; |
||||
|
} |
||||
|
if ( sum <= 1.0e-7 ) { |
||||
|
// small change => singularity
|
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
Iteration & Math |
||||
|
*/ |
||||
|
void Attractor::iterate() { |
||||
|
// pointer swap
|
||||
|
double * temp = point; |
||||
|
point = new_point; |
||||
|
new_point = temp; |
||||
|
|
||||
|
// calculations
|
||||
|
switch (formula) { |
||||
|
case POLY_N: |
||||
|
polynome(); |
||||
|
break; |
||||
|
|
||||
|
case POLY_A: |
||||
|
poly_A(); |
||||
|
break; |
||||
|
|
||||
|
case POLY_2: |
||||
|
poly_2(); |
||||
|
break; |
||||
|
|
||||
|
case LOGISTIC: |
||||
|
logistic(); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
cout << "Formula not recognized" << endl; |
||||
|
exit(1); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Formula " << formula << " is done" << endl; |
||||
|
cout << "Old Vector: "; |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
cout << point[i] << " "; |
||||
|
} |
||||
|
cout << endl << "Fresh Vector: "; |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
cout << new_point[i] << " "; |
||||
|
} |
||||
|
cout << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void Attractor::polynome() { |
||||
|
unsigned int m = 0; |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Entering new dimension: " << i << " With m = " << m << endl; |
||||
|
#endif |
||||
|
|
||||
|
new_point[i] = param[m]; |
||||
|
m++; |
||||
|
recur(i, 0, 1, m); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void Attractor::recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product) { |
||||
|
double product; |
||||
|
for (unsigned int i = prev_i; i < dim; i++) { |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
for ( unsigned int j = 0; j < n; j++ ) |
||||
|
cout << " "; |
||||
|
cout << "Calculation in dimension: " << i << " With m = " << m << " And depth = " << n << endl; |
||||
|
#endif |
||||
|
|
||||
|
product = prev_product * point[i]; |
||||
|
new_point[curr_dimension] += param[m] * product; |
||||
|
m++; |
||||
|
if (n < orde) { |
||||
|
recur(curr_dimension, i, n+1, m, product); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Attractor::poly_A() { |
||||
|
switch (dim) { |
||||
|
case 3: |
||||
|
new_point[0] = param[0] + point[1] - point[1]*point[2]; |
||||
|
new_point[1] = param[1] + point[2] - point[2]*point[0]; |
||||
|
new_point[2] = param[2] + point[0] - point[0]*point[1]; |
||||
|
break; |
||||
|
default: |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
new_point[i] = param[i] + point[(i+1) % dim] - point[(i+1) % dim]*point[(i+2) % dim]; |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Attractor::poly_2() { |
||||
|
exit(2); |
||||
|
} |
||||
|
|
||||
|
void Attractor::logistic() { |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
new_point[i] = param[i]*point[i]*(1.0 - point[i]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Attractor::plot() { |
||||
|
for ( vector<Projector *>::iterator it = projectors.begin(); it != projectors.end(); it++ ) { |
||||
|
(*it)->plot(point); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
IO & control |
||||
|
*/ |
||||
|
void Attractor::output() { |
||||
|
for ( unsigned int i = 0; i < dim; i++ ) { |
||||
|
cout << point[i] << " "; |
||||
|
} |
||||
|
cout << endl; |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
#ifndef ATTRACTOR_HPP |
||||
|
#define ATTRACTOR_HPP |
||||
|
|
||||
|
#include <vector> |
||||
|
|
||||
|
//#include "Vector.hpp"
|
||||
|
//#include "Parameters.hpp"
|
||||
|
#include "Projector.hpp" |
||||
|
#include "AttractorKernel.hpp" |
||||
|
|
||||
|
enum FormulaChoice { |
||||
|
POLY_N, LORENZ, POLY_A, POLY_2, LOGISTIC, UNRAVEL |
||||
|
}; |
||||
|
|
||||
|
class Projector; |
||||
|
|
||||
|
// TODO : Verschillende classas AttractorSystem en Attractor maken?
|
||||
|
|
||||
|
class Attractor { |
||||
|
public: |
||||
|
unsigned int dim; |
||||
|
unsigned int par; |
||||
|
unsigned int orde; |
||||
|
FormulaChoice formula; |
||||
|
|
||||
|
double * param; |
||||
|
double * point; |
||||
|
double * new_point; |
||||
|
|
||||
|
|
||||
|
vector<Projector *> projectors; |
||||
|
|
||||
|
public: |
||||
|
Attractor(); |
||||
|
Attractor(unsigned int dimensions, FormulaChoice formula, unsigned int orde = 3); |
||||
|
Attractor(const char* const filename); |
||||
|
|
||||
|
void init(unsigned int dimensions, FormulaChoice formula, unsigned int orde); |
||||
|
|
||||
|
void init_vector(); |
||||
|
void init_param(); |
||||
|
void init_range(); |
||||
|
|
||||
|
// TODO : lyapunov exponent uit rekenen
|
||||
|
bool is_chaos(); |
||||
|
|
||||
|
|
||||
|
// TODO : optimaliseren voor lage graads veeltermen
|
||||
|
void iterate(); |
||||
|
void polynome(); |
||||
|
void recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product = 1.0); |
||||
|
void poly_A(); |
||||
|
void poly_2(); |
||||
|
void logistic(); |
||||
|
|
||||
|
void plot(); |
||||
|
void output(); |
||||
|
}; |
||||
|
|
||||
|
#endif // ATTRACTOR_HPP
|
||||
|
|
@ -0,0 +1,33 @@ |
|||||
|
#ifndef ATTRACTORKERNEL_HPP |
||||
|
#define ATTRACTORKERNEL_HPP |
||||
|
|
||||
|
#include <string> |
||||
|
using namespace std; |
||||
|
|
||||
|
class AttractorKernel { |
||||
|
public: |
||||
|
|
||||
|
// AttractorKernel protocol
|
||||
|
|
||||
|
// parameters are stored in a array of doubles
|
||||
|
// if you want to use other types, use the properties
|
||||
|
virtual double& parameter(const unsigned int index) = 0; |
||||
|
virtual double*& parameters() = 0; |
||||
|
|
||||
|
// get properties of the attractor
|
||||
|
// such as the dimension
|
||||
|
// you should delete the void pointer if you used it
|
||||
|
virtual void * getProperty(const string identifier) = 0; |
||||
|
virtual void setProperty(const string identifier, const void * value) = 0; |
||||
|
|
||||
|
// iterate his formula
|
||||
|
// vector pointers will be swapped! so new remains new and old remains old
|
||||
|
virtual void iterate() = 0; |
||||
|
|
||||
|
// getter functions for teh resulta
|
||||
|
virtual double * & vector() = 0; |
||||
|
virtual double * & previousVector() = 0; |
||||
|
}; |
||||
|
|
||||
|
#endif // ATTRACTORKERNEL_HPP
|
||||
|
|
@ -0,0 +1,64 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
||||
|
<CodeBlocks_project_file> |
||||
|
<FileVersion major="1" minor="6" /> |
||||
|
<Project> |
||||
|
<Option title="AwesomeAttractor" /> |
||||
|
<Option pch_mode="2" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Build> |
||||
|
<Target title="Debug"> |
||||
|
<Option output="bin/Debug/AwesomeAttractor" prefix_auto="1" extension_auto="1" /> |
||||
|
<Option object_output="obj/Debug/" /> |
||||
|
<Option type="1" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Compiler> |
||||
|
<Add option="-g" /> |
||||
|
</Compiler> |
||||
|
</Target> |
||||
|
<Target title="Release"> |
||||
|
<Option output="bin/Release/AwesomeAttractor" prefix_auto="1" extension_auto="1" /> |
||||
|
<Option object_output="obj/Release/" /> |
||||
|
<Option type="1" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Compiler> |
||||
|
<Add option="-O2" /> |
||||
|
</Compiler> |
||||
|
<Linker> |
||||
|
<Add option="-s" /> |
||||
|
</Linker> |
||||
|
</Target> |
||||
|
</Build> |
||||
|
<Compiler> |
||||
|
<Add option="-Wall" /> |
||||
|
</Compiler> |
||||
|
<Linker> |
||||
|
<Add library="libpng" /> |
||||
|
</Linker> |
||||
|
<Unit filename="Attractor.cpp" /> |
||||
|
<Unit filename="Attractor.hpp" /> |
||||
|
<Unit filename="AttractorKernel.hpp" /> |
||||
|
<Unit filename="Canvas.cpp" /> |
||||
|
<Unit filename="Canvas.hpp" /> |
||||
|
<Unit filename="Projector.cpp" /> |
||||
|
<Unit filename="Projector.hpp"> |
||||
|
<Option compilerVar="CC" /> |
||||
|
</Unit> |
||||
|
<Unit filename="attr/test.attr" /> |
||||
|
<Unit filename="attr/test2.attr" /> |
||||
|
<Unit filename="attr/waardes.txt" /> |
||||
|
<Unit filename="kernels/Lorenz.cpp" /> |
||||
|
<Unit filename="kernels/Lorenz.hpp" /> |
||||
|
<Unit filename="kernels/Unravel.cpp" /> |
||||
|
<Unit filename="kernels/Unravel.hpp" /> |
||||
|
<Unit filename="main.cpp" /> |
||||
|
<Unit filename="myMath.hpp" /> |
||||
|
<Unit filename="pngwriter/pngwriter.cc" /> |
||||
|
<Unit filename="pngwriter/pngwriter.h" /> |
||||
|
<Extensions> |
||||
|
<code_completion /> |
||||
|
<envvars /> |
||||
|
<debugger /> |
||||
|
<lib_finder disable_auto="1" /> |
||||
|
</Extensions> |
||||
|
</Project> |
||||
|
</CodeBlocks_project_file> |
@ -0,0 +1,52 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
||||
|
<CodeBlocks_layout_file> |
||||
|
<ActiveTarget name="Release" /> |
||||
|
<File name="Attractor.cpp" open="1" top="1" tabpos="3"> |
||||
|
<Cursor position="7114" topLine="283" /> |
||||
|
</File> |
||||
|
<File name="Attractor.hpp" open="1" top="0" tabpos="4"> |
||||
|
<Cursor position="1165" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="AttractorKernel.hpp" open="0" top="0" tabpos="1"> |
||||
|
<Cursor position="165" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="Canvas.cpp" open="0" top="0" tabpos="3"> |
||||
|
<Cursor position="4379" topLine="138" /> |
||||
|
</File> |
||||
|
<File name="Canvas.hpp" open="0" top="0" tabpos="4"> |
||||
|
<Cursor position="463" topLine="12" /> |
||||
|
</File> |
||||
|
<File name="Projector.cpp" open="0" top="0" tabpos="7"> |
||||
|
<Cursor position="2483" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="Projector.hpp" open="0" top="0" tabpos="6"> |
||||
|
<Cursor position="876" topLine="3" /> |
||||
|
</File> |
||||
|
<File name="attr/test2.attr" open="0" top="0" tabpos="9"> |
||||
|
<Cursor position="43" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="kernels/Lorenz.cpp" open="1" top="0" tabpos="2"> |
||||
|
<Cursor position="541" topLine="4" /> |
||||
|
</File> |
||||
|
<File name="kernels/Lorenz.hpp" open="1" top="0" tabpos="1"> |
||||
|
<Cursor position="264" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="kernels/Unravel.cpp" open="1" top="0" tabpos="6"> |
||||
|
<Cursor position="921" topLine="9" /> |
||||
|
</File> |
||||
|
<File name="kernels/Unravel.hpp" open="1" top="0" tabpos="5"> |
||||
|
<Cursor position="133" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="main.cpp" open="0" top="0" tabpos="5"> |
||||
|
<Cursor position="350" topLine="3" /> |
||||
|
</File> |
||||
|
<File name="myMath.hpp" open="0" top="0" tabpos="8"> |
||||
|
<Cursor position="138" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="pngwriter/pngwriter.cc" open="0" top="0" tabpos="1"> |
||||
|
<Cursor position="21977" topLine="608" /> |
||||
|
</File> |
||||
|
<File name="pngwriter/pngwriter.h" open="0" top="0" tabpos="2"> |
||||
|
<Cursor position="19671" topLine="696" /> |
||||
|
</File> |
||||
|
</CodeBlocks_layout_file> |
@ -0,0 +1,40 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
||||
|
<CodeBlocks_layout_file> |
||||
|
<ActiveTarget name="Release" /> |
||||
|
<File name="Attractor.cpp" open="1" top="0" tabpos="2"> |
||||
|
<Cursor position="1475" topLine="51" /> |
||||
|
</File> |
||||
|
<File name="Attractor.hpp" open="1" top="0" tabpos="3"> |
||||
|
<Cursor position="65" topLine="14" /> |
||||
|
</File> |
||||
|
<File name="Canvas.cpp" open="1" top="0" tabpos="5"> |
||||
|
<Cursor position="0" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="Canvas.hpp" open="1" top="0" tabpos="4"> |
||||
|
<Cursor position="826" topLine="11" /> |
||||
|
</File> |
||||
|
<File name="Parameters.cpp" open="0" top="0" tabpos="3"> |
||||
|
<Cursor position="2126" topLine="49" /> |
||||
|
</File> |
||||
|
<File name="Parameters.hpp" open="0" top="0" tabpos="4"> |
||||
|
<Cursor position="464" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="Projector.cpp" open="1" top="1" tabpos="9"> |
||||
|
<Cursor position="551" topLine="13" /> |
||||
|
</File> |
||||
|
<File name="Projector.hpp" open="1" top="0" tabpos="8"> |
||||
|
<Cursor position="383" topLine="1" /> |
||||
|
</File> |
||||
|
<File name="Vector.cpp" open="1" top="0" tabpos="6"> |
||||
|
<Cursor position="1835" topLine="69" /> |
||||
|
</File> |
||||
|
<File name="Vector.hpp" open="1" top="0" tabpos="7"> |
||||
|
<Cursor position="0" topLine="0" /> |
||||
|
</File> |
||||
|
<File name="main.cpp" open="1" top="0" tabpos="1"> |
||||
|
<Cursor position="690" topLine="8" /> |
||||
|
</File> |
||||
|
<File name="waardes.txt" open="0" top="0" tabpos="8"> |
||||
|
<Cursor position="0" topLine="0" /> |
||||
|
</File> |
||||
|
</CodeBlocks_layout_file> |
@ -0,0 +1,238 @@ |
|||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include <cmath> |
||||
|
#include <cstdlib> |
||||
|
#include <cassert> |
||||
|
#include <cstdint> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "pngwriter/pngwriter.h" |
||||
|
|
||||
|
#include "Canvas.hpp" |
||||
|
|
||||
|
|
||||
|
Canvas::Canvas(unsigned int width, unsigned int height, unsigned int num_colors): |
||||
|
dim(2), width(width), height(height), num_colors(num_colors), v(0) { |
||||
|
|
||||
|
int_array = new unsigned int[width*height*num_colors]; |
||||
|
size = new unsigned int[2]; |
||||
|
size[0] = width; |
||||
|
size[1] = height; |
||||
|
|
||||
|
assert(int_array != NULL); |
||||
|
|
||||
|
clear(); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New canvas" << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void Canvas::clear() { |
||||
|
for ( unsigned int i = 0; i < width*height*num_colors; i++ ) { |
||||
|
int_array[i] = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
//void Canvas::update_viewwindow() {
|
||||
|
//
|
||||
|
// //width and height of attractor
|
||||
|
// const double dx = xmax - xmin;
|
||||
|
// const double dy = ymax - ymin;
|
||||
|
//
|
||||
|
// //fix aspect ratio
|
||||
|
// if ( dx > dy * ((float)width / height) ) {
|
||||
|
// const double height2 = dx * ((float)height / width);
|
||||
|
// const double middle = 0.5 * (ymax + ymin);
|
||||
|
// ymax = middle + 0.5 * height2;
|
||||
|
// ymin = middle - 0.5 * height2;
|
||||
|
//
|
||||
|
// } else {
|
||||
|
// const double width2 = dy * ((float)width / height);
|
||||
|
// const double middle = 0.5 * (xmax + xmin);
|
||||
|
// xmax = middle + 0.5 * width2;
|
||||
|
// xmin = middle - 0.5 * width2;
|
||||
|
// }
|
||||
|
//
|
||||
|
// //add a 4% marge
|
||||
|
// xmin -= 0.02 * dx;
|
||||
|
// xmax += 0.02 * dx;
|
||||
|
// ymin -= 0.02 * dy;
|
||||
|
// ymax += 0.02 * dy;
|
||||
|
//
|
||||
|
// //constants for speed
|
||||
|
// constant1 = width / (xmax - xmin);
|
||||
|
// constant2 = height / (ymax - ymin);
|
||||
|
//}
|
||||
|
|
||||
|
void Canvas::plot(double x, double y) { |
||||
|
// gets x and y coordinate
|
||||
|
// ranges [-1, 1] and [-1, 1]
|
||||
|
// so how to do the aspect shiz, i don't know
|
||||
|
const unsigned int x_int = x*width + width*.5; |
||||
|
const unsigned int y_int = y*width + height*.5; |
||||
|
const unsigned int index = x_int + width * y_int; |
||||
|
|
||||
|
if(x_int < width && y_int < height) { |
||||
|
int_array[index]++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Canvas::plot(double x, double y, unsigned int c) { |
||||
|
// same as plot(double x, double y)
|
||||
|
// now with color control
|
||||
|
const unsigned int x_int = x*width + width*.5; |
||||
|
const unsigned int y_int = y*width + height*.5; |
||||
|
const unsigned int index = x_int + width * y_int + width*height*c; |
||||
|
|
||||
|
if(x_int < width && y_int < height) { |
||||
|
int_array[index]++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Canvas::plot(double x, double y, unsigned int c, double intensity) { |
||||
|
// same as plot(double x, double y, unsigned int c)
|
||||
|
// but now uses the float array (not yet implemented
|
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
I/O functions |
||||
|
*/ |
||||
|
void Canvas::output() { |
||||
|
cout << "Canvas: " << endl; |
||||
|
cout << "Dimensions: " << width << " x " << height << " x " << num_colors << endl; |
||||
|
} |
||||
|
|
||||
|
void Canvas::output_file(const char * filename){ |
||||
|
unsigned int * max_int = new unsigned int[num_colors]; |
||||
|
double * power = new double[num_colors]; |
||||
|
|
||||
|
for ( unsigned int i = 0; i < num_colors; i++ ) { |
||||
|
max_int[i] = 0; |
||||
|
double cumulative = 0; |
||||
|
unsigned int n = 0; |
||||
|
|
||||
|
for ( unsigned int j = 0; j < width*height; j++) { |
||||
|
if ( max_int[i] < int_array[j+i*width*height] ) { |
||||
|
max_int[i] = int_array[j+i*width*height]; |
||||
|
} |
||||
|
if ( int_array[j+i*width*height] ) { |
||||
|
cumulative += int_array[j+i*width*height]; |
||||
|
n++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ( n > 100 ) { |
||||
|
const double average = cumulative / (double)n; |
||||
|
power[i] = -2.5/log(average/(double)max_int[i]); |
||||
|
if ( power[i] < 0 ) |
||||
|
power[i] = 1; |
||||
|
} else { |
||||
|
power[i] = 1; |
||||
|
} |
||||
|
|
||||
|
if ( n <= 10 ) { |
||||
|
cout << "not enough data" << endl; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const double vibrancy = v; |
||||
|
double averagePower = 0; |
||||
|
for ( unsigned int i = 0; i < num_colors; i++ ) { |
||||
|
averagePower += power[i]; |
||||
|
} |
||||
|
averagePower /= num_colors; |
||||
|
for ( unsigned int i = 0; i < num_colors; i++ ) { |
||||
|
power[i] = vibrancy*power[i] + (1.0 - vibrancy*averagePower); |
||||
|
} |
||||
|
|
||||
|
pngwriter * pngFile = new pngwriter(width, height, 0.0, filename); |
||||
|
pngFile->setcompressionlevel(9); |
||||
|
pngFile->settext("Attractor", "Joshua Moerman", "A awesome attractor", "AwesomeAttractor"); |
||||
|
|
||||
|
for ( unsigned int x = 0; x < width; x++ ) { |
||||
|
for ( unsigned int y = 0; y < height; y++ ) { |
||||
|
double r = 0.0; |
||||
|
double g = 0.0; |
||||
|
double b = 0.0; |
||||
|
for ( unsigned int c = 0; c < num_colors; c++ ) { |
||||
|
const double norm_value = (double)int_array[x + y*width + c*width*height]/max_int[c]; |
||||
|
switch(c){ |
||||
|
case 0: { |
||||
|
r = (pow(norm_value, power[c]))*3.0; |
||||
|
break; |
||||
|
} |
||||
|
case 1: { |
||||
|
g = (pow(norm_value, power[c]))*3.0; |
||||
|
break; |
||||
|
} |
||||
|
case 2: { |
||||
|
b = (pow(norm_value, power[c]))*3.0; |
||||
|
break; |
||||
|
} |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
//pngwriter clips values for me
|
||||
|
pngFile->plot(x, y, r, g, b); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
delete max_int; |
||||
|
delete power; |
||||
|
|
||||
|
pngFile->close(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void Canvas::output_file(){ |
||||
|
char filename[50]; |
||||
|
time_t t = time(0); |
||||
|
struct tm* lt = localtime(&t); |
||||
|
int r = rand() % 10; |
||||
|
|
||||
|
sprintf(filename, "render/attractor_%04d-%02d-%02d_%02d-%02d-%02d-%01d.png", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, r); |
||||
|
|
||||
|
output_file(filename); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Canvas::output_raw(const char * filename){ |
||||
|
|
||||
|
ofstream outfile (filename, ofstream::binary); |
||||
|
|
||||
|
outfile.write(reinterpret_cast<char*>(int_array), sizeof(unsigned int)*width*height*num_colors); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void Canvas::output_raw(){ |
||||
|
char filename[52]; |
||||
|
time_t t = time(0); |
||||
|
struct tm* lt = localtime(&t); |
||||
|
int r = rand() % 10; |
||||
|
|
||||
|
sprintf(filename, "render/canv%dx%d_%04d-%02d-%02d_%02d-%02d-%02d-%01d.canv", width, height, lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, r); |
||||
|
|
||||
|
output_raw(filename); |
||||
|
} |
||||
|
|
||||
|
void Canvas::input_raw(const char * filename){ |
||||
|
ifstream infile(filename, ifstream::binary); |
||||
|
|
||||
|
if ( ! infile ) { |
||||
|
cout << "poep" << endl; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
infile.seekg (0, ios::end); |
||||
|
int length = infile.tellg(); |
||||
|
infile.seekg (0, ios::beg); |
||||
|
|
||||
|
cout << "length: " << length << " =? " << static_cast<int>(width*height*num_colors*sizeof(unsigned int)) << endl; |
||||
|
|
||||
|
infile.read (reinterpret_cast<char*>(int_array), sizeof (unsigned int)*width*height*num_colors); |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
#ifndef CANVAS_HPP |
||||
|
#define CANVAS_HPP |
||||
|
|
||||
|
|
||||
|
//#include "Vector.hpp"
|
||||
|
#include "Attractor.hpp" |
||||
|
#include "Projector.hpp" |
||||
|
|
||||
|
// TODO : Canvas class abstraheren (zodat er makkelijk verschillende soorten canvae gemaakt kunnen worden)
|
||||
|
|
||||
|
class Canvas{ |
||||
|
friend class Projector; |
||||
|
|
||||
|
unsigned int dim; |
||||
|
unsigned int width; |
||||
|
unsigned int height; |
||||
|
unsigned int num_colors; |
||||
|
|
||||
|
unsigned int * size; |
||||
|
|
||||
|
unsigned int * int_array; |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
double v; |
||||
|
|
||||
|
Canvas(unsigned int width, unsigned int height, unsigned int num_colors = 1); |
||||
|
|
||||
|
void clear(); |
||||
|
|
||||
|
void plot(double x, double y); |
||||
|
void plot(double x, double y, unsigned int c); |
||||
|
// TODO : make double array in canvas (ander soort canvas)
|
||||
|
// TODO : subpixel sampling (anders soort canvas)
|
||||
|
void plot(double x, double y, unsigned int c, double intensity); |
||||
|
|
||||
|
void output(); |
||||
|
//void output(Vector& point);
|
||||
|
|
||||
|
void output_file(const char * filename); |
||||
|
void output_file(); |
||||
|
void output_raw(const char * filename); |
||||
|
void output_raw(); |
||||
|
void input_raw(const char * filename); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
|
||||
|
#endif // CANVAS_HPP
|
||||
|
|
@ -0,0 +1,110 @@ |
|||||
|
#include <iostream> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "Parameters.hpp" |
||||
|
|
||||
|
|
||||
|
Parameters::Parameters(unsigned int num_parameters, float default_val): |
||||
|
num_parameters(num_parameters) { |
||||
|
begin = new (nothrow) Vector(num_parameters, default_val); |
||||
|
eind = new (nothrow) Vector(num_parameters, default_val); |
||||
|
interpolated = new (nothrow) Vector(num_parameters, default_val); |
||||
|
// *interpolated = *begin
|
||||
|
|
||||
|
check_pointers(); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New Parameters with one default val:" << endl << *this << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
/*Parameters::Parameters(unsigned int num_parameters, float default_val1, float default_val2):
|
||||
|
num_parameters(num_parameters) { |
||||
|
begin = new (nothrow) Vector(num_parameters, default_val1); |
||||
|
eind = new (nothrow) Vector(num_parameters, default_val2); |
||||
|
interpolated = new (nothrow) Vector(num_parameters, default_val1); |
||||
|
// *interpolated = *begin
|
||||
|
|
||||
|
check_pointers(); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New Parameters with two default vals:" << endl << *this << endl; |
||||
|
#endif |
||||
|
}*/ |
||||
|
|
||||
|
Parameters::~Parameters() { |
||||
|
delete begin; |
||||
|
delete eind; |
||||
|
delete interpolated; |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Parameters deleted" << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void Parameters::check_pointers() { |
||||
|
assert(begin != NULL); |
||||
|
assert(eind != NULL); |
||||
|
assert(interpolated != NULL); |
||||
|
} |
||||
|
|
||||
|
void Parameters::set(unsigned int parameter, float val1, float val2) { |
||||
|
assert(parameter < num_parameters); |
||||
|
|
||||
|
begin->coordinates[parameter] = val1; |
||||
|
eind->coordinates[parameter] = val2; |
||||
|
interpolated->coordinates[parameter] = val1; |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Parameter " << parameter << " set to: " << val1 << " - " << val2 << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void Parameters::set(unsigned int parameter, float val) { |
||||
|
assert(parameter < num_parameters); |
||||
|
|
||||
|
begin->coordinates[parameter] = val; |
||||
|
eind->coordinates[parameter] = val; |
||||
|
interpolated->coordinates[parameter] = val; |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Parameter " << parameter << " set to: " << val << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
float Parameters::get(unsigned int parameter) { |
||||
|
assert(parameter < num_parameters); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Asked for parameter " << parameter << " with value:" << interpolated->coordinates[parameter] << endl; |
||||
|
#endif |
||||
|
|
||||
|
return interpolated->coordinates[parameter]; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void Parameters::interpolate(float time) { |
||||
|
/*
|
||||
|
Dit is mogelijk met vector rekenen: |
||||
|
(*interpolated) = (*begin) * ( 1.0 - time ) + (*eind) * time; |
||||
|
Maar we doen het per element, zodat we simpelere code hebben, |
||||
|
geen vectoren hoeven te returnen en makkelijker kunnen optimaliseren |
||||
|
*/ |
||||
|
const float invtime = 1.0 - time; |
||||
|
for ( unsigned int i = 0; i < num_parameters; i++ ) { |
||||
|
interpolated->coordinates[i] = invtime * begin->coordinates[i] + time * eind->coordinates[i]; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "interpolate() result" << endl << *interpolated << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
ostream& operator<<(ostream& os, const Parameters& param) { |
||||
|
os << param.num_parameters << endl; |
||||
|
os << "Begin:" << endl << *param.begin << endl; |
||||
|
os << "Eind:" << endl << *param.eind << endl; |
||||
|
os << "Interpolated:" << endl << *param.interpolated << endl; |
||||
|
os <<endl; |
||||
|
return os; |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
#ifndef PARAMETER_HPP |
||||
|
#define PARAMETER_HPP |
||||
|
|
||||
|
#include "Vector.hpp" |
||||
|
|
||||
|
class Parameters { |
||||
|
|
||||
|
Vector * begin; |
||||
|
Vector * eind; |
||||
|
Vector * interpolated; |
||||
|
|
||||
|
void check_pointers(); |
||||
|
|
||||
|
|
||||
|
public: |
||||
|
|
||||
|
// for checks and assertions
|
||||
|
unsigned int num_parameters; |
||||
|
|
||||
|
Parameters(unsigned int num_parameters, float default_val = 0.0); |
||||
|
//Parameters(unsigned int num_parameters, float default_val1, float default_val2);
|
||||
|
~Parameters(); |
||||
|
|
||||
|
void set(unsigned int parameter, float val1, float val2); |
||||
|
void set(unsigned int parameter, float val); |
||||
|
float get(unsigned int parameter); |
||||
|
|
||||
|
void interpolate(float time); |
||||
|
|
||||
|
// output operator
|
||||
|
friend ostream& operator<<(ostream& os, const Parameters& param); |
||||
|
}; |
||||
|
|
||||
|
#endif // PARAMETER_HPP
|
@ -0,0 +1,111 @@ |
|||||
|
#include <iostream> |
||||
|
#include <cmath> |
||||
|
#include <vector> |
||||
|
#include <cassert> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "Projector.hpp" |
||||
|
#include "Canvas.hpp" |
||||
|
#include "myMath.hpp" |
||||
|
|
||||
|
void Projector::init(double * point) { |
||||
|
init_vector(); |
||||
|
|
||||
|
project(point); |
||||
|
init_range(); |
||||
|
} |
||||
|
|
||||
|
void Projector::init_vector() { |
||||
|
project_point = new double[intern_dim]; |
||||
|
offset = new double[intern_dim]; |
||||
|
|
||||
|
assert(project_point != NULL); |
||||
|
assert(offset != NULL); |
||||
|
} |
||||
|
|
||||
|
void Projector::init_range() { |
||||
|
range_min = new double[intern_dim]; |
||||
|
range_max = new double[intern_dim]; |
||||
|
|
||||
|
assert(range_min != NULL); |
||||
|
assert(range_max != NULL); |
||||
|
|
||||
|
for ( unsigned int i = 0; i < intern_dim; i++ ) { |
||||
|
range_min[i] = range_max[i] = project_point[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Projector::update_range(double * point) { |
||||
|
project(point); |
||||
|
for ( unsigned int i = 0; i < intern_dim; i++ ) { |
||||
|
if ( project_point[i] < range_min[i] ) { |
||||
|
range_min[i] = project_point[i]; |
||||
|
} else if ( project_point[i] > range_max[i] ) { |
||||
|
range_max[i] = project_point[i]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Projector::finish_range() { |
||||
|
// double max_dist = 0.0;
|
||||
|
// for ( unsigned int i = 0; i < intern_dim; i++ ) {
|
||||
|
// const double dist = range_max[i] - range_min[i];
|
||||
|
// if ( dist > max_dist )
|
||||
|
// max_dist = dist;
|
||||
|
// }
|
||||
|
//
|
||||
|
// factor = 0.9/max_dist;
|
||||
|
// for ( unsigned int i = 0; i < intern_dim; i++ ) {
|
||||
|
// offset[i] = -0.5*factor*(range_min[i] + range_max[i]);
|
||||
|
// }
|
||||
|
|
||||
|
factor = canvas->size[0] / (range_max[0] - range_min[0]); |
||||
|
unsigned int teh_size = canvas->size[0]; |
||||
|
for ( unsigned int i = 1; i < intern_dim; i++ ) { |
||||
|
double dist = range_max[i] - range_min[i]; |
||||
|
if ( factor * dist > (double)canvas->size[i] ) { |
||||
|
factor = (double)canvas->size[i] / dist; |
||||
|
//teh_size = canvas->size[i];
|
||||
|
cout << "crap for dim" << i << endl; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
factor /= (double)teh_size; |
||||
|
|
||||
|
for ( unsigned int i = 0; i < intern_dim; i++ ) { |
||||
|
offset[i] = -0.5*factor*(range_min[i] + range_max[i]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Projector::project(double * point) { |
||||
|
assert(extern_dim >= 2); |
||||
|
project_point[0] = point[0]; |
||||
|
project_point[1] = point[1]; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Projector::plot(double * point) { |
||||
|
project(point); |
||||
|
|
||||
|
const double x = project_point[0]*factor + offset[0]; |
||||
|
const double y = project_point[1]*factor + offset[1]; |
||||
|
|
||||
|
//cout << x << ", " << y << endl;
|
||||
|
|
||||
|
canvas->plot(x, y); |
||||
|
if ( even(point[2]*4.0) ) |
||||
|
canvas->plot(x, y, 1); |
||||
|
else |
||||
|
canvas->plot(x, y, 2); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Projector::output(){ |
||||
|
cout << "Projector properties: " << endl; |
||||
|
cout << " factor: " << factor << endl; |
||||
|
for ( unsigned int i = 0; i < intern_dim; i++ ) { |
||||
|
cout << " dimension " << i << ": offset: " << offset[i] << ", range: [" << range_min[i] << ", " << range_max[i] << "]" << endl; |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,45 @@ |
|||||
|
#ifndef PROJECTOR_HPP |
||||
|
#define PROJECTOR_HPP |
||||
|
|
||||
|
#include <vector> |
||||
|
|
||||
|
#include "Canvas.hpp" |
||||
|
|
||||
|
class Canvas; |
||||
|
|
||||
|
class Projector{ |
||||
|
public: |
||||
|
|
||||
|
unsigned int extern_dim; |
||||
|
unsigned int intern_dim; |
||||
|
|
||||
|
Canvas * canvas; |
||||
|
double * project_point; |
||||
|
|
||||
|
double * range_min; |
||||
|
double * range_max; |
||||
|
double factor; |
||||
|
double * offset; |
||||
|
|
||||
|
void init(double * point); |
||||
|
void init_vector(); |
||||
|
void init_range(); |
||||
|
void update_range(double * point); |
||||
|
void finish_range(); |
||||
|
|
||||
|
|
||||
|
// TODO : Matrix gebruiken voor lineaire afbeelding
|
||||
|
// TODO : Over kleuren nadenken
|
||||
|
/*
|
||||
|
Kleurmodi: |
||||
|
-genormalizeerde coordinaten als kleurintensiteit (gebruikt fp canvas) |
||||
|
-kleurbanden, dus met een periodieke functie (gebruikt int canvas) |
||||
|
*/ |
||||
|
void project(double * point); |
||||
|
void plot(double * point); |
||||
|
|
||||
|
void output(); |
||||
|
}; |
||||
|
|
||||
|
#endif // PROJECTOR_HPP
|
||||
|
|
@ -0,0 +1,126 @@ |
|||||
|
#include <iostream> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "Vector.hpp" |
||||
|
|
||||
|
Vector::Vector(): |
||||
|
dimension(0) { |
||||
|
|
||||
|
coordinates = new (nothrow) float[0]; |
||||
|
|
||||
|
assert(coordinates != NULL); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New vector (without elements)" << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
Vector::Vector(unsigned int d): |
||||
|
dimension(d) { |
||||
|
|
||||
|
coordinates = new (nothrow) float[dimension]; |
||||
|
|
||||
|
assert(coordinates != NULL); |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New vector:" << endl << *this << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
Vector::Vector(unsigned int d, float default_val): |
||||
|
dimension(d) { |
||||
|
|
||||
|
coordinates = new (nothrow) float[dimension]; |
||||
|
|
||||
|
assert(coordinates != NULL); |
||||
|
|
||||
|
for (unsigned int i = 0; i < dimension; i++) { |
||||
|
coordinates[i] = default_val; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "New vector with default values:" << endl << *this << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Vector::~Vector() { |
||||
|
delete[] coordinates; |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "coordinates deleted" << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Vector& Vector::operator=(const Vector& a) { |
||||
|
if ( dimension != a.dimension ) { |
||||
|
dimension = a.dimension; |
||||
|
delete[] coordinates; |
||||
|
coordinates = new float[dimension]; |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "Dimensions were not equal, made new vector" << endl; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
for ( unsigned int i = 0; i < dimension; i++ ) { |
||||
|
coordinates[i] = a.coordinates[i]; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "operator= result" << endl << *this << endl; |
||||
|
#endif |
||||
|
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
ostream& operator<<(ostream& os, const Vector& a) { |
||||
|
os << a.dimension << endl; |
||||
|
for ( unsigned int i = 0; i < a.dimension; i++ ) { |
||||
|
os << a.coordinates[i] << " "; |
||||
|
} |
||||
|
|
||||
|
os << endl; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
float& Vector::operator[](const unsigned int index) { |
||||
|
assert(index < dimension); |
||||
|
return coordinates[index]; |
||||
|
} |
||||
|
|
||||
|
// matig werkende optelling en scalaire vermenigvuldiging van vectoren
|
||||
|
/*
|
||||
|
Vector Vector::operator+(const Vector a) const { |
||||
|
if ( dimension != a.dimension ) { |
||||
|
cout << "WARNING: dimensions not equal in vector addition" << endl; |
||||
|
exit(1); |
||||
|
} else { |
||||
|
static Vector ret(dimension); |
||||
|
for ( unsigned int i = 0; i < dimension; i++ ) { |
||||
|
ret.coordinates[i] = coordinates[i] + a.coordinates[i]; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "operator+ result" << endl << ret << endl; |
||||
|
#endif |
||||
|
return ret; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Vector Vector::operator*(const float a) const { |
||||
|
static Vector ret(dimension); |
||||
|
for ( unsigned int i = 0; i < dimension; i++ ) { |
||||
|
ret.coordinates[i] = coordinates[i] * a; |
||||
|
} |
||||
|
|
||||
|
#ifdef HARDDEBUG |
||||
|
cout << "operator* result" << endl << ret << endl; |
||||
|
#endif |
||||
|
return ret; |
||||
|
} |
||||
|
*/ |
@ -0,0 +1,31 @@ |
|||||
|
#ifndef VECTOR_HPP |
||||
|
#define VECTOR_HPP |
||||
|
|
||||
|
class Vector { |
||||
|
public: |
||||
|
|
||||
|
unsigned int dimension; |
||||
|
float * coordinates; |
||||
|
|
||||
|
// const, dest
|
||||
|
Vector(); |
||||
|
Vector(unsigned int d); |
||||
|
Vector(unsigned int d, float default_val); |
||||
|
~Vector(); |
||||
|
|
||||
|
// output operator
|
||||
|
friend ostream& operator<<(ostream& os, const Vector& a); |
||||
|
|
||||
|
// easy access
|
||||
|
float& Vector::operator[](const unsigned int index); |
||||
|
|
||||
|
// vector rekenen
|
||||
|
Vector& operator=(const Vector& a); |
||||
|
// faaloperatoren
|
||||
|
// Vector operator+(const Vector a) const;
|
||||
|
// Vector operator*(const float a) const;
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif // VECTOR_HPP
|
||||
|
|
@ -0,0 +1,14 @@ |
|||||
|
CANVEXT=".canv" |
||||
|
PNGEXT=".png" |
||||
|
CANVPATH="canvas/" |
||||
|
PNGPATH="render/" |
||||
|
|
||||
|
cd $CANVPATH |
||||
|
|
||||
|
for FILE in `ls *$CANVEXT | sed -e 's/'$CANVEXT'$//'` |
||||
|
do |
||||
|
../bin/Debug/AwesomeAttractor -c ../$CANVPATH$FILE$CANVEXT 3200 3200 3 ../$PNGPATH$FILE$PNGEXT |
||||
|
#Do other stuff with file |
||||
|
done |
||||
|
|
||||
|
|
@ -0,0 +1,17 @@ |
|||||
|
ATTREXT=".attr" |
||||
|
CANVEXT=".canv" |
||||
|
ATTRPATH="attr/" |
||||
|
CANVPATH="canvas/" |
||||
|
|
||||
|
cd $ATTRPATH |
||||
|
|
||||
|
for FILE in `ls *$ATTREXT | sed -e 's/'$ATTREXT'$//'` |
||||
|
do |
||||
|
../bin/Debug/AwesomeAttractor -a ../$ATTRPATH$FILE$ATTREXT 500 ../$CANVPATH$FILE$CANVEXT 800 600 3 |
||||
|
#Do other stuff with file |
||||
|
done |
||||
|
|
||||
|
cd .. |
||||
|
|
||||
|
zip -r canvae.zip $CANVPATH*$CANVEXT |
||||
|
|
@ -0,0 +1,73 @@ |
|||||
|
#include "Lorenz.hpp" |
||||
|
|
||||
|
Lorenz::Lorenz() { |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
void Lorenz::init() { |
||||
|
// allocation
|
||||
|
myParameters = new double[4]; |
||||
|
vectorNew = new double[3]; |
||||
|
vectorOld = new double[3]; |
||||
|
|
||||
|
// initialisation
|
||||
|
assert(myParameters != NULL); |
||||
|
assert(vectorNew != NULL); |
||||
|
assert(vectorOld != NULL); |
||||
|
for ( unsigned int i = 0; i < 4; i++ ) { |
||||
|
myParameters[i] = 0.0; |
||||
|
} |
||||
|
for ( unsigned int i = 0; i < 3; i++ ) { |
||||
|
vectorNew[i] = vectorOld[i] = 1.0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// the main function
|
||||
|
void Lorenz::iterate() { |
||||
|
swap(vectorNew, vectorOld); |
||||
|
|
||||
|
vectorNew[0] = vectorOld[0] + myParameters[0] * myParameters[1] * (vectorOld[1] - vectorOld[0]); |
||||
|
vectorNew[1] = vectorOld[1] + myParameters[0] * (vectorOld[0] * (myParameters[2] - vectorOld[2]) - vectorOld[1]); |
||||
|
vectorNew[2] = vectorOld[2] + myParameters[0] * (vectorOld[0] * vectorOld[1] - myParameters[3] * vectorOld[2]); |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
4D: |
||||
|
new_point[0] = point[0] + param[0] * param[1] * (point[1] - point[0]); |
||||
|
new_point[1] = point[1] + param[0] * (point[0] * (param[2] - point[2]) - point[1] + point[3]); |
||||
|
new_point[2] = point[2] + param[0] * (point[0] * point[1] - param[3] * point[2]); |
||||
|
new_point[3] = point[3] - param[0] * param[4] * point[0]; |
||||
|
break; |
||||
|
*/ |
||||
|
|
||||
|
// setters, getters, all i/o to other classes/objects
|
||||
|
void * Lorenz::getProperty(const string identifier) { |
||||
|
if ( identifier == "dimension" ) { |
||||
|
unsigned int * _return = new unsigned int; |
||||
|
*_return = 3; |
||||
|
return _return; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
void Lorenz::setProperty(const string identifier, const void * value) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
double * & Lorenz::parameters() { |
||||
|
return myParameters; |
||||
|
} |
||||
|
|
||||
|
double & Lorenz::parameter(const unsigned int index) { |
||||
|
return myParameters[index]; |
||||
|
} |
||||
|
|
||||
|
double * & Lorenz::vector() { |
||||
|
return vectorNew; |
||||
|
} |
||||
|
|
||||
|
double * & Lorenz::previousVector() { |
||||
|
return vectorOld; |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,48 @@ |
|||||
|
#ifndef LORENZ_HPP |
||||
|
#define LORENZ_HPP |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <cstdlib> |
||||
|
#include <cassert> |
||||
|
#include <string> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "../AttractorKernel.hpp" |
||||
|
|
||||
|
class Lorenz : public AttractorKernel { |
||||
|
|
||||
|
double * myParameters; |
||||
|
|
||||
|
double * vectorNew; |
||||
|
double * vectorOld; |
||||
|
|
||||
|
void init(); |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
Lorenz(); |
||||
|
Lorenz(const unsigned int dimensions); |
||||
|
|
||||
|
// parameters are stored in a array of doubles
|
||||
|
// if you want to use other types, use the properties
|
||||
|
virtual double& parameter(const unsigned int index); |
||||
|
virtual double*& parameters(); |
||||
|
|
||||
|
// get properties of the attractor
|
||||
|
// such as the dimension
|
||||
|
// you should delete the void pointer if you used it
|
||||
|
virtual void * getProperty(const string identifier); |
||||
|
virtual void setProperty(const string identifier, const void * value); |
||||
|
|
||||
|
// iterate his formula
|
||||
|
// vector pointers will be swapped! so new remains new and old remains old
|
||||
|
virtual void iterate(); |
||||
|
|
||||
|
// getter functions for teh resulta
|
||||
|
virtual double * & vector(); |
||||
|
virtual double * & previousVector(); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
#endif // LORENZ_HPP
|
||||
|
|
@ -0,0 +1,71 @@ |
|||||
|
#include "Unravel.hpp" |
||||
|
|
||||
|
Unravel::Unravel(){ |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
void Unravel::init() { |
||||
|
// allocation
|
||||
|
myParameters = new double[4]; |
||||
|
vectorNew = new double[3]; |
||||
|
vectorOld = new double[3]; |
||||
|
|
||||
|
// initialisation
|
||||
|
assert(myParameters != NULL); |
||||
|
assert(vectorNew != NULL); |
||||
|
assert(vectorOld != NULL); |
||||
|
for ( unsigned int i = 0; i < 7; i++ ) { |
||||
|
myParameters[i] = 0.0; |
||||
|
} |
||||
|
for ( unsigned int i = 0; i < 3; i++ ) { |
||||
|
vectorNew[i] = vectorOld[i] = 0.0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Unravel::iterate() { |
||||
|
swap(vectorNew, vectorOld); |
||||
|
|
||||
|
vectorNew[0] = myParameters[0]*(vectorOld[2] + myParameters[1]); |
||||
|
vectorNew[1] = myParameters[2]*(vectorOld[0] + myParameters[3]); |
||||
|
vectorNew[2] = myParameters[4]*(vectorOld[1] + myParameters[5]); |
||||
|
|
||||
|
const double dist = vectorNew[0]*vectorNew[0] + vectorNew[1]*vectorNew[1] + vectorNew[2]*vectorNew[2]; |
||||
|
|
||||
|
if ( dist > myParameters[6]*myParameters[6] ) { |
||||
|
const double sqrtDist = sqrt(dist); |
||||
|
const double p = 1.0 - myParameters[6] * ( static_cast<int> ( sqrtDist / myParameters[6] ) + 1.0 ) / sqrtDist; |
||||
|
vectorNew[0] *= p; |
||||
|
vectorNew[1] *= p; |
||||
|
vectorNew[2] *= p; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// setters, getters, all i/o to other classes/objects
|
||||
|
void * Unravel::getProperty(const string identifier) { |
||||
|
if ( identifier == "dimension" ) { |
||||
|
unsigned int * _return = new unsigned int; |
||||
|
*_return = 3; |
||||
|
return _return; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
void Unravel::setProperty(const string identifier, const void * value) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
double * & Unravel::parameters() { |
||||
|
return myParameters; |
||||
|
} |
||||
|
|
||||
|
double & Unravel::parameter(const unsigned int index) { |
||||
|
return myParameters[index]; |
||||
|
} |
||||
|
|
||||
|
double * & Unravel::vector() { |
||||
|
return vectorNew; |
||||
|
} |
||||
|
|
||||
|
double * & Unravel::previousVector() { |
||||
|
return vectorOld; |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
#ifndef UNRAVEL_HPP |
||||
|
#define UNRAVEL_HPP |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <cstdlib> |
||||
|
#include <cassert> |
||||
|
#include <string> |
||||
|
#include <cmath> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "../AttractorKernel.hpp" |
||||
|
|
||||
|
class Unravel : public AttractorKernel { |
||||
|
|
||||
|
double * myParameters; |
||||
|
|
||||
|
double * vectorNew; |
||||
|
double * vectorOld; |
||||
|
|
||||
|
void init(); |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
Unravel(); |
||||
|
Unravel(const unsigned int dimensions); |
||||
|
|
||||
|
// parameters are stored in a array of doubles
|
||||
|
// if you want to use other types, use the properties
|
||||
|
virtual double& parameter(const unsigned int index); |
||||
|
virtual double*& parameters(); |
||||
|
|
||||
|
// get properties of the attractor
|
||||
|
// such as the dimension
|
||||
|
// you should delete the void pointer if you used it
|
||||
|
virtual void * getProperty(const string identifier); |
||||
|
virtual void setProperty(const string identifier, const void * value); |
||||
|
|
||||
|
// iterate his formula
|
||||
|
// vector pointers will be swapped! so new remains new and old remains old
|
||||
|
virtual void iterate(); |
||||
|
|
||||
|
// getter functions for teh resulta
|
||||
|
virtual double * & vector(); |
||||
|
virtual double * & previousVector(); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
#endif // UNRAVEL_HPP
|
||||
|
|
@ -0,0 +1,133 @@ |
|||||
|
#include <iostream> |
||||
|
using namespace std; |
||||
|
|
||||
|
#include "Attractor.hpp" |
||||
|
#include "Canvas.hpp" |
||||
|
#include "Projector.hpp" |
||||
|
|
||||
|
#include "AttractorKernel.hpp" |
||||
|
#include "kernels/Lorenz.hpp" |
||||
|
|
||||
|
// TODO : Allemaal files inlezen, voor makkelijker gebruik
|
||||
|
|
||||
|
int main(int argc, char *argv[]) { |
||||
|
|
||||
|
|
||||
|
AttractorKernel * mijnAttractortje; |
||||
|
mijnAttractortje = new Lorenz(); |
||||
|
AttractorKernel &attractor = *mijnAttractortje; |
||||
|
|
||||
|
attractor.parameter(0) = 1.0; |
||||
|
attractor.parameter(2) = 2.0; |
||||
|
|
||||
|
double * & vector = attractor.vector(); |
||||
|
|
||||
|
unsigned int * _dimension = (unsigned int*)mijnAttractortje->getProperty("dimension"); |
||||
|
unsigned int dimension = *_dimension; |
||||
|
delete _dimension; |
||||
|
|
||||
|
cout << "Dimension = " << dimension << endl; |
||||
|
|
||||
|
for ( unsigned int i = 0; i < 20; i++ ) { |
||||
|
mijnAttractortje->iterate(); |
||||
|
cout << "vector = "; |
||||
|
for ( unsigned int i = 0; i < dimension; i++ ) { |
||||
|
cout << " " << vector[i]; |
||||
|
} |
||||
|
cout << endl; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*if ( argc <= 2 ) {
|
||||
|
cout << endl << "nothing to do..." << endl; |
||||
|
cout << "usage:" << endl; |
||||
|
cout << " rendering to canvas: -a my_attractor.attr 500000000 my_attractor.canv 800 600 3" << endl; |
||||
|
cout << " canvas to png: -c my_attractor.canv 800 600 3 my_atttractor.png" << endl << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
int mode; |
||||
|
string argv1 = argv[1]; |
||||
|
if ( argv1 == "-a" ) { |
||||
|
cout << "rendermode" << endl; |
||||
|
mode = 1; |
||||
|
} else if ( argv1 == "-c" ) { |
||||
|
cout << "canvasmode" << endl; |
||||
|
mode = 2; |
||||
|
} else { |
||||
|
cout << "i do.. i do... i do not understand... \"" << argv1 << "\""<< endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
switch ( mode ) { |
||||
|
case 1: { |
||||
|
if ( argc != 8 ) { |
||||
|
cout << "all parameters must be set..." << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
string attractorFile = argv[2]; |
||||
|
unsigned int iterations = atoi(argv[3]); |
||||
|
string canvasFile = argv[4]; |
||||
|
unsigned int width = atoi(argv[5]); |
||||
|
unsigned int height = atoi(argv[6]); |
||||
|
unsigned int numColors = atoi(argv[7]); |
||||
|
|
||||
|
Attractor attract(attractorFile.c_str()); |
||||
|
cout << attractorFile << " is read" << endl; |
||||
|
|
||||
|
Projector projection; |
||||
|
Canvas canvas(width, height, numColors); |
||||
|
projection.canvas = &canvas; |
||||
|
|
||||
|
attract.projectors.push_back(&projection); |
||||
|
attract.init_range(); |
||||
|
|
||||
|
projection.output(); |
||||
|
|
||||
|
for ( unsigned int j = 1; j <= 100; j++ ) { |
||||
|
for ( unsigned int i = 0; 100*i <= iterations; i++ ) { |
||||
|
attract.iterate(); |
||||
|
attract.plot(); |
||||
|
} |
||||
|
cout << j << "% done" << endl; |
||||
|
} |
||||
|
|
||||
|
canvas.output_raw(canvasFile.c_str()); |
||||
|
cout << canvasFile << " is outputted" << endl; |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
case 2: { |
||||
|
if ( argc != 7 ) { |
||||
|
cout << "all parameters must be set..." << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
string canvasFile = argv[2]; |
||||
|
unsigned int width = atoi(argv[3]); |
||||
|
unsigned int height = atoi(argv[4]); |
||||
|
unsigned int numColors = atoi(argv[5]); |
||||
|
string pngFile = argv[6]; |
||||
|
|
||||
|
Canvas canvas(width, height, numColors); |
||||
|
canvas.input_raw(canvasFile.c_str()); |
||||
|
cout << canvasFile << " is read" << endl; |
||||
|
for ( double v = -1.5; v < 1.6; v += 1.5 ) { |
||||
|
canvas.v = v; |
||||
|
canvas.output_file(); |
||||
|
} |
||||
|
cout << pngFile << " was exported" << endl; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: { |
||||
|
cout << "WTF" << endl; |
||||
|
break; |
||||
|
} |
||||
|
}*/ |
||||
|
|
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
@ -0,0 +1,12 @@ |
|||||
|
#ifndef MYMATH_HPP |
||||
|
#define MYMATH_HPP |
||||
|
|
||||
|
#include <cmath> |
||||
|
using namespace std; |
||||
|
|
||||
|
bool even(double x) { |
||||
|
return (((int)floor(x)) % 2 == 0); |
||||
|
} |
||||
|
|
||||
|
#endif // MYMATH_HPP
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,32 @@ |
|||||
|
############ PARTIAL MAKEFILE FOR PNGWRITER ######################################
|
||||
|
#
|
||||
|
# Website: Main: http://pngwriter.sourceforge.net/
|
||||
|
# Author: Paul Blackburn
|
||||
|
# Email: individual61@users.sourceforge.net
|
||||
|
# Version: 0.5.4 (19 / II / 2009)
|
||||
|
# License: GNU General Public License
|
||||
|
# Copyright 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
|
# 2008, 2009 Paul Blackburn
|
||||
|
#
|
||||
|
##################################################################################
|
||||
|
|
||||
|
|
||||
|
include ../make.include |
||||
|
|
||||
|
OBJECTS=pngwriter.o |
||||
|
all: libpngwriter.a |
||||
|
|
||||
|
libpngwriter.a: $(OBJECTS) |
||||
|
ar rv $@ $^ |
||||
|
ranlib $@ |
||||
|
|
||||
|
pngwriter.o: pngwriter.cc pngwriter.h |
||||
|
$(CXX) $(CXXFLAGS) $(INC) -g -c -o pngwriter.o pngwriter.cc |
||||
|
|
||||
|
clean : |
||||
|
rm -f $(OBJECTS) libpngwriter.a pngtest.cc~ pngwriter.cc~ |
||||
|
rm -f pngwriter.h~ Makefile~ |
||||
|
rm -f .DS_Store |
||||
|
|
||||
|
|
||||
|
|
File diff suppressed because it is too large
@ -0,0 +1,747 @@ |
|||||
|
//********** pngwriter.h **********************************************
|
||||
|
// Author: Paul Blackburn
|
||||
|
//
|
||||
|
// Email: individual61@users.sourceforge.net
|
||||
|
//
|
||||
|
// Version: 0.5.4 (19 / II / 2009)
|
||||
|
//
|
||||
|
// Description: Library that allows plotting a 48 bit
|
||||
|
// PNG image pixel by pixel, which can
|
||||
|
// then be opened with a graphics program.
|
||||
|
//
|
||||
|
// License: GNU General Public License
|
||||
|
// Copyright 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
|
// 2008, 2009 Paul Blackburn
|
||||
|
//
|
||||
|
// Website: Main: http://pngwriter.sourceforge.net/
|
||||
|
// Sourceforge.net: http://sourceforge.net/projects/pngwriter/
|
||||
|
// Freshmeat.net: http://freshmeat.net/projects/pngwriter/
|
||||
|
//
|
||||
|
// Documentation: This header file is commented, but for a
|
||||
|
// quick reference document, and support,
|
||||
|
// take a look at the website.
|
||||
|
//
|
||||
|
//*************************************************************************
|
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
* |
||||
|
* */ |
||||
|
|
||||
|
#ifndef PNGWRITER_H |
||||
|
#define PNGWRITER_H 1 |
||||
|
|
||||
|
#define PNGWRITER_VERSION 0.54 |
||||
|
|
||||
|
#define NO_FREETYPE |
||||
|
|
||||
|
#include <png.h> |
||||
|
|
||||
|
// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS
|
||||
|
// COMPILED WITHOUT FREETYPE SUPPORT!!!
|
||||
|
//
|
||||
|
// RECUERDA AGREGAR -DNO_FREETYPE A TUS OPCIONES DE COMPILACION SI PNGwriter
|
||||
|
// FUE COMPILADO SIN SOPORTE PARA FREETYPE!!!
|
||||
|
//
|
||||
|
#ifndef NO_FREETYPE |
||||
|
#include <ft2build.h> |
||||
|
#include FT_FREETYPE_H |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
|
||||
|
#ifdef OLD_CPP // For compatibility with older compilers.
|
||||
|
#include <iostream.h> |
||||
|
#include <math.h> |
||||
|
#include <wchar.h> |
||||
|
#include <string.h> |
||||
|
using namespace std; |
||||
|
#endif // from ifdef OLD_CPP
|
||||
|
|
||||
|
#ifndef OLD_CPP // Default situation.
|
||||
|
#include <iostream> |
||||
|
#include <cmath> |
||||
|
#include <cwchar> |
||||
|
#include <string> |
||||
|
#endif // from ifndef OLD_CPP
|
||||
|
|
||||
|
|
||||
|
//png.h must be included before FreeType headers.
|
||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <setjmp.h> |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
#define PNG_BYTES_TO_CHECK (4) |
||||
|
#define PNGWRITER_DEFAULT_COMPRESSION (6) |
||||
|
|
||||
|
class pngwriter |
||||
|
{ |
||||
|
private: |
||||
|
|
||||
|
char * filename_; |
||||
|
char * textauthor_; |
||||
|
char * textdescription_; |
||||
|
char * texttitle_; |
||||
|
char * textsoftware_; |
||||
|
|
||||
|
|
||||
|
|
||||
|
int height_; |
||||
|
int width_; |
||||
|
int backgroundcolour_; |
||||
|
int bit_depth_; |
||||
|
int rowbytes_; |
||||
|
int colortype_; |
||||
|
int compressionlevel_; |
||||
|
bool transformation_; // Required by Mikkel's patch
|
||||
|
|
||||
|
unsigned char * * graph_; |
||||
|
double filegamma_; |
||||
|
double screengamma_; |
||||
|
void circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue); |
||||
|
void circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue); |
||||
|
int check_if_png(char *file_name, FILE **fp); |
||||
|
int read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr); |
||||
|
int read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr, |
||||
|
png_bytepp *image, png_uint_32 *width, png_uint_32 *height); |
||||
|
void flood_fill_internal( int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue); |
||||
|
void flood_fill_internal_blend( int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue); |
||||
|
|
||||
|
#ifndef NO_FREETYPE |
||||
|
void my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue); |
||||
|
void my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y,double opacity, double red, double green, double blue); |
||||
|
#endif |
||||
|
|
||||
|
/* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
|
||||
|
* which is a page that belongs to Nan C. Schaller, though |
||||
|
* these algorithms appear to be the work of Eugene Vishnevsky. |
||||
|
* */ |
||||
|
void HSVtoRGB( double *r, double *g, double *b, double h, double s, double v ); |
||||
|
void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v ); |
||||
|
|
||||
|
/* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
|
||||
|
* ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
|
||||
|
* */ |
||||
|
void drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue); |
||||
|
void drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue); |
||||
|
void drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue); |
||||
|
void drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue); |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
/* General Notes
|
||||
|
* It is important to remember that all functions that accept an argument of type "const char *" will also |
||||
|
* accept "char *", this is done so you can have a changing filename (to make many PNG images in series |
||||
|
* with a different name, for example), and to allow you to use string type objects which can be easily |
||||
|
* turned into const char * (if theString is an object of type string, then it can be used as a const char * |
||||
|
* by saying theString.c_str()). |
||||
|
* It is also important to remember that whenever a function has a colour coeffiecient as its argument, |
||||
|
* that argument can be either an int from 0 to 65535 or a double from 0.0 to 1.0. |
||||
|
* It is important to make sure that you are calling the function with the type that you want. |
||||
|
* Remember that 1 is an int, while 1.0 is a double, and will thus determine what version of the function |
||||
|
* will be used. Similarly, do not make the mistake of calling for example plot(x, y, 0.0, 0.0, 65535), |
||||
|
* because |
||||
|
* there is no plot(int, int, double, double, int). |
||||
|
* Also, please note that plot() and read() (and the functions that use them internally) |
||||
|
* are protected against entering, for example, a colour coefficient that is over 65535 |
||||
|
* or over 1.0. Similarly, they are protected against negative coefficients. read() will return 0 |
||||
|
* when called outside the image range. This is actually useful as zero-padding should you need it. |
||||
|
* */ |
||||
|
|
||||
|
/* Compilation
|
||||
|
* A typical compilation would look like this: |
||||
|
* |
||||
|
* g++ my_program.cc -o my_program freetype-config --cflags \ |
||||
|
* -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz -lfreetype |
||||
|
* |
||||
|
* If you did not compile PNGwriter with FreeType support, then remove the |
||||
|
* FreeType-related flags and add -DNO_FREETYPE above. |
||||
|
* */ |
||||
|
|
||||
|
/* Constructor
|
||||
|
* The constructor requires the width and the height of the image, the background colour for the |
||||
|
* image and the filename of the file (a pointer or simple "myfile.png"). The background colour |
||||
|
* can only be initialized to a shade of grey (once the object has been created you can do whatever |
||||
|
* you want, though), because generally one wants either a white (65535 or 1.0) or a black (0 or 0.0) |
||||
|
* background to start with. |
||||
|
* The default constructor creates a PNGwriter instance that is 250x250, white background, |
||||
|
* and filename "out.png". |
||||
|
* Tip: The filename can be given as easily as: |
||||
|
* pngwriter mypng(300, 300, 0.0, "myfile.png"); |
||||
|
* Tip: If you are going to create a PNGwriter instance for reading in a file that already exists, |
||||
|
* then width and height can be 1 pixel, and the size will be automatically adjusted once you use |
||||
|
* readfromfile(). |
||||
|
* */ |
||||
|
pngwriter(); |
||||
|
pngwriter(const pngwriter &rhs); |
||||
|
pngwriter(int width, int height, int backgroundcolour, char * filename); |
||||
|
pngwriter(int width, int height, double backgroundcolour, char * filename); |
||||
|
pngwriter(int width, int height, int backgroundcolour, const char * filename); |
||||
|
pngwriter(int width, int height, double backgroundcolour, const char * filename); |
||||
|
|
||||
|
/* Destructor
|
||||
|
* */ |
||||
|
~pngwriter(); |
||||
|
|
||||
|
/* Assignment Operator
|
||||
|
* */ |
||||
|
pngwriter & operator = (const pngwriter & rhs); |
||||
|
|
||||
|
/* Plot
|
||||
|
* With this function a pixel at coordinates (x, y) can be set to the desired colour. |
||||
|
* The pixels are numbered starting from (1, 1) and go to (width, height). |
||||
|
* As with most functions in PNGwriter, it has been overloaded to accept either int arguments |
||||
|
* for the colour coefficients, or those of type double. If they are of type int, |
||||
|
* they go from 0 to 65535. If they are of type double, they go from 0.0 to 1.0. |
||||
|
* Tip: To plot using red, then specify plot(x, y, 1.0, 0.0, 0.0). To make pink, |
||||
|
* just add a constant value to all three coefficients, like this: |
||||
|
* plot(x, y, 1.0, 0.4, 0.4). |
||||
|
* Tip: If nothing is being plotted to your PNG file, make sure that you remember |
||||
|
* to close() the instance before your program is finished, and that the x and y position |
||||
|
* is actually within the bounds of your image. If either is not, then PNGwriter will |
||||
|
* not complain-- it is up to you to check for this! |
||||
|
* Tip: If you try to plot with a colour coefficient out of range, a maximum or minimum |
||||
|
* coefficient will be assumed, according to the given coefficient. For example, attempting |
||||
|
* to plot plot(x, y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red coefficient |
||||
|
* to 1.0. |
||||
|
* */ |
||||
|
void plot(int x, int y, int red, int green, int blue); |
||||
|
void plot(int x, int y, double red, double green, double blue); |
||||
|
|
||||
|
/* Plot HSV
|
||||
|
* With this function a pixel at coordinates (x, y) can be set to the desired colour, |
||||
|
* but with the colour coefficients given in the Hue, Saturation, Value colourspace. |
||||
|
* This has the advantage that one can determine the colour that will be plotted with |
||||
|
* only one parameter, the Hue. The colour coefficients must go from 0 to 65535 and |
||||
|
* be of type int, or be of type double and go from 0.0 to 1.0. |
||||
|
* */ |
||||
|
void plotHSV(int x, int y, double hue, double saturation, double value); |
||||
|
void plotHSV(int x, int y, int hue, int saturation, int value); |
||||
|
|
||||
|
/* Read
|
||||
|
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1, |
||||
|
* it will return the red coefficient, if it is set to 2, the green one, and if |
||||
|
* it set to 3, the blue colour coefficient will be returned, |
||||
|
* and this returned value will be of type int and be between 0 and 65535. |
||||
|
* Note that if you call read() on a pixel outside the image range, the value returned |
||||
|
* will be 0. |
||||
|
* */ |
||||
|
int read(int x, int y, int colour); |
||||
|
|
||||
|
/* Read, Average
|
||||
|
* Same as the above, only that the average of the three colour coefficients is returned. |
||||
|
*/ |
||||
|
int read(int x, int y); |
||||
|
|
||||
|
/* dRead
|
||||
|
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1, |
||||
|
* it will return the red coefficient, if it is set to 2, the green one, and if |
||||
|
* it set to 3, the blue colour coefficient will be returned, |
||||
|
* and this returned value will be of type double and be between 0.0 and 1.0. |
||||
|
* Note that if you call dread() outside the image range, the value returned will be 0.0 |
||||
|
* */ |
||||
|
double dread(int x, int y, int colour); |
||||
|
|
||||
|
/* dRead, Average
|
||||
|
* Same as the above, only that the average of the three colour coefficients is returned. |
||||
|
*/ |
||||
|
double dread(int x, int y); |
||||
|
|
||||
|
/* Read HSV
|
||||
|
* With this function we find out what colour the pixel (x, y) is, but in the Hue, |
||||
|
* Saturation, Value colourspace. If "colour" is 1, |
||||
|
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if |
||||
|
* it set to 3, the Value colour coefficient will be returned, and this returned |
||||
|
* value will be of type int and be between 0 and 65535. Important: If you attempt |
||||
|
* to read the Hue of a pixel that is a shade of grey, the value returned will be |
||||
|
* nonsensical or even NaN. This is just the way the RGB -> HSV algorithm works: |
||||
|
* the Hue of grey is not defined. You might want to check whether the pixel |
||||
|
* you are reading is grey before attempting a readHSV(). |
||||
|
* Tip: This is especially useful for categorizing sections of the image according |
||||
|
* to their colour. |
||||
|
* */ |
||||
|
int readHSV(int x, int y, int colour); |
||||
|
|
||||
|
/* dRead HSV
|
||||
|
* With this function we find out what colour the pixel (x, y) is, but in the Hue, |
||||
|
* Saturation, Value colourspace. If "colour" is 1, |
||||
|
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if |
||||
|
* it set to 3, the Value colour coefficient will be returned, |
||||
|
* and this returned value will be of type double and be between 0.0 and 1.0. |
||||
|
* */ |
||||
|
double dreadHSV(int x, int y, int colour); |
||||
|
|
||||
|
/* Clear
|
||||
|
* The whole image is set to black. |
||||
|
* */ |
||||
|
void clear(void); |
||||
|
|
||||
|
/* Close
|
||||
|
* Close the instance of the class, and write the image to disk. |
||||
|
* Tip: If you do not call this function before your program ends, no image |
||||
|
* will be written to disk. |
||||
|
* */ |
||||
|
void close(void); |
||||
|
|
||||
|
/* Rename
|
||||
|
* To rename the file once an instance of pngwriter has been created. |
||||
|
* Useful for assigning names to files based upon their content. |
||||
|
* Tip: This is as easy as calling pngwriter_rename("newname.png") |
||||
|
* If the argument is a long unsigned int, for example 77, the filename will be changed to |
||||
|
* 0000000077.png |
||||
|
* Tip: Use this to create sequences of images for movie generation. |
||||
|
* */ |
||||
|
void pngwriter_rename(char * newname); |
||||
|
void pngwriter_rename(const char * newname); |
||||
|
void pngwriter_rename(long unsigned int index); |
||||
|
|
||||
|
/* Figures
|
||||
|
* These functions draw basic shapes. Available in both int and double versions. |
||||
|
* The line functions use the fast Bresenham algorithm. Despite the name, |
||||
|
* the square functions draw rectangles. The circle functions use a fast |
||||
|
* integer math algorithm. The filled circle functions make use of sqrt(). |
||||
|
* */ |
||||
|
void line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); |
||||
|
void line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); |
||||
|
|
||||
|
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue); |
||||
|
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue); |
||||
|
|
||||
|
void square(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); |
||||
|
void square(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); |
||||
|
|
||||
|
void filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); |
||||
|
void filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); |
||||
|
|
||||
|
void circle(int xcentre, int ycentre, int radius, int red, int green, int blue); |
||||
|
void circle(int xcentre, int ycentre, int radius, double red, double green, double blue); |
||||
|
|
||||
|
void filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue); |
||||
|
void filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue); |
||||
|
|
||||
|
|
||||
|
/* Read From File
|
||||
|
* Open the existing PNG image, and copy it into this instance of the class. It is important to mention |
||||
|
* that PNG variants are supported. Very generally speaking, most PNG files can now be read (as of version 0.5.4), |
||||
|
* but if they have an alpha channel it will be completely stripped. If the PNG file uses GIF-style transparency |
||||
|
* (where one colour is chosen to be transparent), PNGwriter will not read the image properly, but will not |
||||
|
* complain. Also, if any ancillary chunks are included in the PNG file (chroma, filter, etc.), it will render |
||||
|
* with a slightly different tonality. For the vast majority of PNGs, this should not be an issue. Note: |
||||
|
* If you read an 8-bit PNG, the internal representation of that instance of PNGwriter will be 8-bit (PNG |
||||
|
* files of less than 8 bits will be upscaled to 8 bits). To convert it to 16-bit, just loop over all pixels, |
||||
|
* reading them into a new instance of PNGwriter. New instances of PNGwriter are 16-bit by default. |
||||
|
* */ |
||||
|
|
||||
|
void readfromfile(char * name); |
||||
|
void readfromfile(const char * name); |
||||
|
|
||||
|
/* Get Height
|
||||
|
* When you open a PNG with readfromfile() you can find out its height with this function. |
||||
|
* */ |
||||
|
int getheight(void); |
||||
|
|
||||
|
/* Get Width
|
||||
|
* When you open a PNG with readfromfile() you can find out its width with this function. |
||||
|
* */ |
||||
|
int getwidth(void); |
||||
|
|
||||
|
/* Set Compression Level
|
||||
|
* Set the compression level that will be used for the image. -1 is to use the default, |
||||
|
* 0 is none, 9 is best compression. |
||||
|
* Remember that this will affect how long it will take to close() the image. A value of 2 or 3 |
||||
|
* is good enough for regular use, but for storage or transmission you might want to take the time |
||||
|
* to set it at 9. |
||||
|
* */ |
||||
|
void setcompressionlevel(int level); |
||||
|
|
||||
|
/* Get Bit Depth
|
||||
|
* When you open a PNG with readfromfile() you can find out its bit depth with this function. |
||||
|
* Mostly for troubleshooting uses. |
||||
|
* */ |
||||
|
int getbitdepth(void); |
||||
|
|
||||
|
/* Get Colour Type
|
||||
|
* When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes |
||||
|
* different styles of image data with this number). |
||||
|
* Mostly for troubleshooting uses. |
||||
|
* */ |
||||
|
int getcolortype(void); |
||||
|
|
||||
|
/* Set Gamma Coeff
|
||||
|
* Set the image's gamma (file gamma) coefficient. This is experimental, but use it if your image's colours seem too bright |
||||
|
* or too dark. The default value of 0.5 should be fine. The standard disclaimer about Mac and PC gamma |
||||
|
* settings applies. |
||||
|
* */ |
||||
|
void setgamma(double gamma); |
||||
|
|
||||
|
|
||||
|
/* Get Gamma Coeff
|
||||
|
* Get the image's gamma coefficient. This is experimental. |
||||
|
* */ |
||||
|
double getgamma(void); |
||||
|
|
||||
|
/* Bezier Curve
|
||||
|
* (After Frenchman Pierre BŽzier from Regie Renault) |
||||
|
* A collection of formulae for describing curved lines |
||||
|
* and surfaces, first used in 1972 to model automobile surfaces. |
||||
|
* (from the The Free On-line Dictionary of Computing) |
||||
|
* See http://www.moshplant.com/direct-or/bezier/ for one of many
|
||||
|
* available descriptions of bezier curves. |
||||
|
* There are four points used to define the curve: the two endpoints |
||||
|
* of the curve are called the anchor points, while the other points, |
||||
|
* which define the actual curvature, are called handles or control points. |
||||
|
* Moving the handles lets you modify the shape of the curve. |
||||
|
* */ |
||||
|
|
||||
|
void bezier( int startPtX, int startPtY, |
||||
|
int startControlX, int startControlY, |
||||
|
int endPtX, int endPtY, |
||||
|
int endControlX, int endControlY, |
||||
|
double red, double green, double blue); |
||||
|
|
||||
|
void bezier( int startPtX, int startPtY, |
||||
|
int startControlX, int startControlY, |
||||
|
int endPtX, int endPtY, |
||||
|
int endControlX, int endControlY, |
||||
|
int red, int green, int blue); |
||||
|
|
||||
|
/* Set Text
|
||||
|
* Sets the text information in the PNG header. If it is not called, the default is used. |
||||
|
*/ |
||||
|
void settext(char * title, char * author, char * description, char * software); |
||||
|
void settext(const char * title, const char * author, const char * description, const char * software); |
||||
|
|
||||
|
|
||||
|
/* Version Number
|
||||
|
* Returns the PNGwriter version number. |
||||
|
*/ |
||||
|
static double version(void); |
||||
|
|
||||
|
/* Write PNG
|
||||
|
* Writes the PNG image to disk. You can still change the PNGwriter instance after this. |
||||
|
* Tip: This is exactly the same as close(), but easier to remember. |
||||
|
* Tip: To make a sequence of images using only one instance of PNGwriter, alter the image, change its name, |
||||
|
* write_png(), then alter the image, change its name, write_png(), etc. |
||||
|
*/ |
||||
|
void write_png(void); |
||||
|
|
||||
|
/* Plot Text
|
||||
|
* Uses the Freetype2 library to set text in the image. face_path is the file path to a |
||||
|
* TrueType font file (.ttf) (FreeType2 can also handle other types). fontsize specifices the approximate |
||||
|
* height of the rendered font in pixels. x_start and y_start specify the placement of the |
||||
|
* lower, left corner of the text string. angle is the text angle in radians. text is the text to be rendered. |
||||
|
* The colour coordinates can be doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* Tip: PNGwriter installs a few fonts in /usr/local/share/pngwriter/fonts to get you started. |
||||
|
* Tip: Remember to add -DNO_FREETYPE to your compilation flags if PNGwriter was compiled without FreeType support. |
||||
|
* */ |
||||
|
void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue); |
||||
|
void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue); |
||||
|
|
||||
|
|
||||
|
/* Plot UTF-8 Text
|
||||
|
* Same as the above, but the text to be plotted is encoded in UTF-8. Why would you want this? To be able to plot |
||||
|
* all characters available in a large TrueType font, for example: for rendering Japenese, Chinese and other |
||||
|
* languages not restricted to the standard 128 character ASCII space. |
||||
|
* Tip: The quickest way to get a string into UTF-8 is to write it in an adequate text editor, and save it as a file |
||||
|
* in UTF-8 encoding, which can then be read in in binary mode. |
||||
|
* */ |
||||
|
void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue); |
||||
|
void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue); |
||||
|
|
||||
|
|
||||
|
/* Bilinear Interpolation of Image
|
||||
|
* Given a floating point coordinate (x from 0.0 to width, y from 0.0 to height), |
||||
|
* this function will return the interpolated colour intensity specified by |
||||
|
* colour (where red = 1, green = 2, blue = 3). |
||||
|
* bilinear_interpolate_read() returns an int from 0 to 65535, and |
||||
|
* bilinear_interpolate_dread() returns a double from 0.0 to 1.0. |
||||
|
* Tip: Especially useful for enlarging an image. |
||||
|
* */ |
||||
|
int bilinear_interpolation_read(double x, double y, int colour); |
||||
|
double bilinear_interpolation_dread(double x, double y, int colour); |
||||
|
|
||||
|
/* Plot Blend
|
||||
|
* Plots the colour given by red, green blue, but blended with the existing pixel |
||||
|
* value at that position. opacity is a double that goes from 0.0 to 1.0. |
||||
|
* 0.0 will not change the pixel at all, and 1.0 will plot the given colour. |
||||
|
* Anything in between will be a blend of both pixel levels. Please note: This is neither |
||||
|
* alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels. |
||||
|
* */ |
||||
|
|
||||
|
void plot_blend(int x, int y, double opacity, int red, int green, int blue); |
||||
|
void plot_blend(int x, int y, double opacity, double red, double green, double blue); |
||||
|
|
||||
|
|
||||
|
/* Invert
|
||||
|
* Inverts the image in RGB colourspace. |
||||
|
* */ |
||||
|
void invert(void); |
||||
|
|
||||
|
/* Resize Image
|
||||
|
* Resizes the PNGwriter instance. Note: All image data is set to black (this is |
||||
|
* a resizing, not a scaling, of the image). |
||||
|
* */ |
||||
|
void resize(int width, int height); |
||||
|
|
||||
|
/* Boundary Fill
|
||||
|
* All pixels adjacent to the start pixel will be filled with the fill colour, until the boundary colour is encountered. |
||||
|
* For example, calling boundary_fill() with the boundary colour set to red, on a pixel somewhere inside a red circle, |
||||
|
* will fill the entire circle with the desired fill colour. If, on the other hand, the circle is not the boundary colour, |
||||
|
* the rest of the image will be filled. |
||||
|
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void boundary_fill(int xstart, int ystart, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ; |
||||
|
void boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ; |
||||
|
|
||||
|
/* Flood Fill
|
||||
|
* All pixels adjacent to the start pixel will be filled with the fill colour, if they are the same colour as the |
||||
|
* start pixel. For example, calling flood_fill() somewhere in the interior of a solid blue rectangle will colour |
||||
|
* the entire rectangle the fill colour. The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) ; |
||||
|
void flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) ; |
||||
|
|
||||
|
/* Polygon
|
||||
|
* This function takes an array of integer values containing the coordinates of the vertexes of a polygon. |
||||
|
* Note that if you want a closed polygon, you must repeat the first point's coordinates for the last point. |
||||
|
* It also requires the number of points contained in the array. For example, if you wish to plot a triangle, |
||||
|
* the array will contain 6 elements, and the number of points is 3. Be very careful about this; if you specify the wrong number |
||||
|
* of points, your program will either segfault or produce points at nonsensical coordinates. |
||||
|
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void polygon(int * points, int number_of_points, double red, double green, double blue); |
||||
|
void polygon(int * points, int number_of_points, int red, int green, int blue); |
||||
|
|
||||
|
/* Plot CMYK
|
||||
|
* Plot a point in the Cyan, Magenta, Yellow, Black colourspace. Please note that this colourspace is |
||||
|
* lossy, i.e. it cannot reproduce all colours on screen that RGB can. The difference, however, is |
||||
|
* barely noticeable. The algorithm used is a standard one. The colour components are either |
||||
|
* doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black); |
||||
|
void plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black); |
||||
|
|
||||
|
/* Read CMYK, Double version
|
||||
|
* Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if 'colour' is 1, the Cyan component will be returned |
||||
|
* as a double from 0.0 to 1.0. If 'colour is 2, the Magenta colour component will be returned, and so on, up to 4. |
||||
|
* */ |
||||
|
double dreadCMYK(int x, int y, int colour); |
||||
|
|
||||
|
/* Read CMYK
|
||||
|
* Same as the above, but the colour components returned are an int from 0 to 65535. |
||||
|
* */ |
||||
|
int readCMYK(int x, int y, int colour); |
||||
|
|
||||
|
/* Scale Proportional
|
||||
|
* Scale the image using bilinear interpolation. If k is greater than 1.0, the image will be enlarged. |
||||
|
* If k is less than 1.0, the image will be shrunk. Negative or null values of k are not allowed. |
||||
|
* The image will be resized and the previous content will be replaced by the scaled image. |
||||
|
* Tip: use getheight() and getwidth() to find out the new width and height of the scaled image. |
||||
|
* Note: After scaling, all images will have a bit depth of 16, even if the original image had |
||||
|
* a bit depth of 8. |
||||
|
* */ |
||||
|
void scale_k(double k); |
||||
|
|
||||
|
/* Scale Non-Proportional
|
||||
|
* Scale the image using bilinear interpolation, with different horizontal and vertical scale factors. |
||||
|
* */ |
||||
|
void scale_kxky(double kx, double ky); |
||||
|
|
||||
|
/* Scale To Target Width and Height
|
||||
|
* Scale the image in such a way as to meet the target width and height. |
||||
|
* Tip: if you want to keep the image proportional, scale_k() might be more appropriate. |
||||
|
* */ |
||||
|
void scale_wh(int finalwidth, int finalheight); |
||||
|
|
||||
|
|
||||
|
/* Blended Functions
|
||||
|
* All these functions are identical to their non-blended types. They take an extra argument, opacity, which is |
||||
|
* a double from 0.0 to 1.0 and represents how much of the original pixel value is retained when plotting the |
||||
|
* new pixel. In other words, if opacity is 0.7, then after plotting, the new pixel will be 30% of the |
||||
|
* original colour the pixel was, and 70% of the new colour, whatever that may be. As usual, each function |
||||
|
* is available in int or double versions. Please note: This is neither alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels. |
||||
|
* */ |
||||
|
|
||||
|
// Start Blended Functions
|
||||
|
|
||||
|
void plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value); |
||||
|
void plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value); |
||||
|
|
||||
|
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); |
||||
|
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); |
||||
|
|
||||
|
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); |
||||
|
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); |
||||
|
|
||||
|
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); |
||||
|
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); |
||||
|
|
||||
|
void circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue); |
||||
|
void circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue); |
||||
|
|
||||
|
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue); |
||||
|
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue); |
||||
|
|
||||
|
void bezier_blend( int startPtX, int startPtY, |
||||
|
int startControlX, int startControlY, |
||||
|
int endPtX, int endPtY, |
||||
|
int endControlX, int endControlY, |
||||
|
double opacity, |
||||
|
double red, double green, double blue); |
||||
|
|
||||
|
void bezier_blend( int startPtX, int startPtY, |
||||
|
int startControlX, int startControlY, |
||||
|
int endPtX, int endPtY, |
||||
|
int endControlX, int endControlY, |
||||
|
double opacity, |
||||
|
int red, int green, int blue); |
||||
|
|
||||
|
void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue); |
||||
|
void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue); |
||||
|
|
||||
|
void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue); |
||||
|
void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue); |
||||
|
|
||||
|
void boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ; |
||||
|
void boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ; |
||||
|
|
||||
|
void flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) ; |
||||
|
void flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) ; |
||||
|
|
||||
|
void polygon_blend(int * points, int number_of_points, double opacity, double red, double green, double blue); |
||||
|
void polygon_blend(int * points, int number_of_points, double opacity, int red, int green, int blue); |
||||
|
|
||||
|
void plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black); |
||||
|
void plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black); |
||||
|
|
||||
|
// End of Blended Functions
|
||||
|
|
||||
|
/* Laplacian
|
||||
|
* This function applies a discrete laplacian to the image, multiplied by a constant factor. |
||||
|
* The kernel used in this case is: |
||||
|
* 1.0 1.0 1.0 |
||||
|
* 1.0 -8.0 1.0 |
||||
|
* 1.0 1.0 1.0 |
||||
|
* Basically, this works as an edge detector. The current pixel is assigned the sum of all neighbouring |
||||
|
* pixels, multiplied by the corresponding kernel element. For example, imagine a pixel and its 8 neighbours: |
||||
|
* 1.0 1.0 0.0 0.0 |
||||
|
* 1.0 ->1.0<- 0.0 0.0 |
||||
|
* 1.0 1.0 0.0 0.0 |
||||
|
* This represents a border between white and black, black is on the right. Applying the laplacian to |
||||
|
* the pixel specified above pixel gives: |
||||
|
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 + |
||||
|
* 1.0*1.0 + 1.0*-8.0 + 0.0*1.0 + |
||||
|
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 = -3.0 |
||||
|
* Applying this to the pixel to the right of the pixel considered previously, we get a sum of 3.0. |
||||
|
* That is, after passing over an edge, we get a high value for the pixel adjacent to the edge. Since |
||||
|
* PNGwriter limits the colour components if they are off-scale, and the result of the laplacian |
||||
|
* may be negative, a scale factor and an offset value are included. This might be useful for |
||||
|
* keeping things within range or for bringing out more detail in the edge detection. The |
||||
|
* final pixel value will be given by: |
||||
|
* final value = laplacian(original pixel)*k + offset |
||||
|
* Tip: Try a value of 1.0 for k to start with, and then experiment with other values. |
||||
|
* */ |
||||
|
void laplacian(double k, double offset); |
||||
|
|
||||
|
/* Filled Triangle
|
||||
|
* Draws the triangle specified by the three pairs of points in the colour specified |
||||
|
* by the colour coefficients. The colour components are either doubles from 0.0 to |
||||
|
* 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue); |
||||
|
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue); |
||||
|
|
||||
|
/* Filled Triangle, Blended
|
||||
|
* Draws the triangle specified by the three pairs of points in the colour specified |
||||
|
* by the colour coefficients, and blended with the background. See the description for Blended Functions. |
||||
|
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. |
||||
|
* */ |
||||
|
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue); |
||||
|
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue); |
||||
|
|
||||
|
/* Arrow, Filled Arrow
|
||||
|
* Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at the second point, given the size in pixels |
||||
|
* and the angle in radians of the arrowhead. The plotted arrow consists of one main line, and two smaller |
||||
|
* lines originating from the second point. Filled Arrow plots the same, but the arrowhead is a solid triangle. |
||||
|
* Tip: An angle of 10 to 30 degrees looks OK. |
||||
|
* */ |
||||
|
|
||||
|
void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue); |
||||
|
void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue); |
||||
|
|
||||
|
void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue); |
||||
|
void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue); |
||||
|
|
||||
|
/* Cross, Maltese Cross
|
||||
|
* Plots a simple cross at x, y, with the specified height and width, and in the specified colour. |
||||
|
* Maltese cross plots a cross, as before, but adds bars at the end of each arm of the cross. |
||||
|
* The size of these bars is specified with x_bar_height and y_bar_width. |
||||
|
* The cross will look something like this: |
||||
|
* |
||||
|
* ----- <-- ( y_bar_width) |
||||
|
* | |
||||
|
* | |
||||
|
* |-------| <-- ( x_bar_height ) |
||||
|
* | |
||||
|
* | |
||||
|
* ----- |
||||
|
* */ |
||||
|
|
||||
|
void cross( int x, int y, int xwidth, int yheight, double red, double green, double blue); |
||||
|
void cross( int x, int y, int xwidth, int yheight, int red, int green, int blue); |
||||
|
|
||||
|
void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue); |
||||
|
void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue); |
||||
|
|
||||
|
/* Diamond and filled diamond
|
||||
|
* Plots a diamond shape, given the x, y position, the width and height, and the colour. |
||||
|
* Filled diamond plots a filled diamond. |
||||
|
* */ |
||||
|
|
||||
|
void filleddiamond( int x, int y, int width, int height, int red, int green, int blue); |
||||
|
void diamond(int x, int y, int width, int height, int red, int green, int blue); |
||||
|
|
||||
|
void filleddiamond( int x, int y, int width, int height, double red, double green, double blue); |
||||
|
void diamond(int x, int y, int width, int height, double red, double green, double blue); |
||||
|
|
||||
|
/* Get Text Width, Get Text Width UTF8
|
||||
|
* Returns the approximate width, in pixels, of the specified *unrotated* text. It is calculated by adding |
||||
|
* each letter's width and kerning value (as specified in the TTF file). Note that this will not |
||||
|
* give the position of the farthest pixel, but it will give a pretty good idea of what area the |
||||
|
* text will occupy. Tip: The text, when plotted unrotated, will fit approximately in a box with its lower left corner at |
||||
|
* (x_start, y_start) and upper right at (x_start + width, y_start + size), where width is given by get_text_width() |
||||
|
* and size is the specified size of the text to be plotted. Tip: Text plotted at position |
||||
|
* (x_start, y_start), rotated with a given 'angle', and of a given 'size' |
||||
|
* whose width is 'width', will fit approximately inside a rectangle whose corners are at |
||||
|
* 1 (x_start, y_start) |
||||
|
* 2 (x_start + width*cos(angle), y_start + width*sin(angle)) |
||||
|
* 3 (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle)) |
||||
|
* 4 (x_start - size*sin(angle), y_start + size*cos(angle)) |
||||
|
* */ |
||||
|
|
||||
|
int get_text_width(char * face_path, int fontsize, char * text); |
||||
|
|
||||
|
int get_text_width_utf8(char * face_path, int fontsize, char * text); |
||||
|
|
||||
|
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
./bin/Debug/AwesomeAttractor -a attr/quick.attr 15000000 canvas/quick.canv 600 600 3 |
||||
|
./bin/Debug/AwesomeAttractor -c canvas/quick.canv 600 600 3 quick.png |
@ -0,0 +1,11 @@ |
|||||
|
Screen options: { |
||||
|
Brightness: "1.5" |
||||
|
Contrast: "70.1" |
||||
|
heigth: "1200" |
||||
|
rendermode: "OpenGL" |
||||
|
width: "1920" |
||||
|
} |
||||
|
Sound options: { |
||||
|
max soundfx: "128" |
||||
|
outputmode: "5.1" |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
Copyright (c) 2009 Maurice Bos and Nick Overdijk |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are met: |
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in the |
||||
|
documentation and/or other materials provided with the distribution. |
||||
|
* The names of the authors may not be used to endorse or promote |
||||
|
products derived from this software without specific prior written |
||||
|
permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
- Maurice Bos (maurice@bosbyte.nl) |
||||
|
- Nick Overdijk (nick@dotsimplicity.net) |
||||
|
|
@ -0,0 +1,45 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
||||
|
<CodeBlocks_project_file> |
||||
|
<FileVersion major="1" minor="6" /> |
||||
|
<Project> |
||||
|
<Option title="STFU" /> |
||||
|
<Option pch_mode="2" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Build> |
||||
|
<Target title="Debug"> |
||||
|
<Option output="bin\Debug\STFU" prefix_auto="1" extension_auto="1" /> |
||||
|
<Option object_output="obj\Debug\" /> |
||||
|
<Option type="1" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Compiler> |
||||
|
<Add option="-Wall" /> |
||||
|
<Add option="-g" /> |
||||
|
</Compiler> |
||||
|
</Target> |
||||
|
<Target title="Release"> |
||||
|
<Option output="bin\Release\SSSParser" prefix_auto="1" extension_auto="1" /> |
||||
|
<Option object_output="obj\Release\" /> |
||||
|
<Option type="1" /> |
||||
|
<Option compiler="gcc" /> |
||||
|
<Compiler> |
||||
|
<Add option="-O2" /> |
||||
|
</Compiler> |
||||
|
<Linker> |
||||
|
<Add option="-s" /> |
||||
|
</Linker> |
||||
|
</Target> |
||||
|
</Build> |
||||
|
<Compiler> |
||||
|
<Add option="-Wall" /> |
||||
|
</Compiler> |
||||
|
<Unit filename="main.cpp" /> |
||||
|
<Unit filename="stf.cpp" /> |
||||
|
<Unit filename="stf.hpp" /> |
||||
|
<Extensions> |
||||
|
<code_completion /> |
||||
|
<envvars /> |
||||
|
<debugger /> |
||||
|
<lib_finder disable_auto="1" /> |
||||
|
</Extensions> |
||||
|
</Project> |
||||
|
</CodeBlocks_project_file> |
@ -0,0 +1,21 @@ |
|||||
|
# depslib dependency file v1.0 |
||||
|
1241021944 source:/media/Data/Code/C/AwesomeAttractor/stfu/main.cpp |
||||
|
<iostream> |
||||
|
<fstream> |
||||
|
"stf.hpp" |
||||
|
|
||||
|
1241022258 /media/Data/Code/C/AwesomeAttractor/stfu/stf.hpp |
||||
|
<fstream> |
||||
|
<string> |
||||
|
<sstream> |
||||
|
<map> |
||||
|
<stdexcept> |
||||
|
|
||||
|
1241019586 source:/media/Data/Code/C/AwesomeAttractor/stfu/stf.cpp |
||||
|
<iostream> |
||||
|
<fstream> |
||||
|
<map> |
||||
|
<string> |
||||
|
<typeinfo> |
||||
|
"stf.hpp" |
||||
|
|
@ -0,0 +1,26 @@ |
|||||
|
imthefirst: "The first value!" |
||||
|
name with spaces: "Names can contain spaces" |
||||
|
name |
||||
|
with |
||||
|
newlines: "And even newlines!" |
||||
|
|
||||
|
test: { |
||||
|
blah: "The value of [root].test.blah" |
||||
|
newlines: "newlines and all their whitespace |
||||
|
get stored" |
||||
|
comment: This comment value contains some information about how to comment in SSS files. |
||||
|
"You can place comment before the quotes, the parser will ignore it." |
||||
|
output this: "This particular value is retrieved in the code." |
||||
|
output child: |
||||
|
Same goes for children. The parser ignores anything until a curly bracket is found. { |
||||
|
info: "Awwwwwwright! Tree output oh yeah." |
||||
|
coolness: "+20" |
||||
|
} |
||||
|
Array: { :"This" :"is" :"like" :"an" :"array" } |
||||
|
|
||||
|
2D array: |
||||
|
{ |
||||
|
: { :"First" :"Row" } |
||||
|
: { :"Second" :"Row" :"!" } |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
array: { :"Some" :"Unnamed" :"Values" } |
||||
|
2D array: |
||||
|
{ |
||||
|
: { :"First" :"Row" } |
||||
|
: { :"Second" :"Row" :"!" } |
||||
|
} |
@ -0,0 +1,282 @@ |
|||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include "stf.hpp" |
||||
|
using namespace std; |
||||
|
using stfu::node; |
||||
|
|
||||
|
/*! \author Nick Overdijk
|
||||
|
* \version 1.2 |
||||
|
* \date 2009-04-27 |
||||
|
* |
||||
|
* STFU Example App |
||||
|
*/ |
||||
|
|
||||
|
void prettyprint(const string &title) { |
||||
|
cout |
||||
|
<< "\t\t-----" << title << "-----\t\t\n" |
||||
|
<< endl; |
||||
|
} |
||||
|
|
||||
|
void read_examples(node &n) { |
||||
|
prettyprint("Reading Examples"); |
||||
|
cout |
||||
|
<< "Reading a STF file in a node is trivial with the stream insertion operator, it returns whether it had success: true/false\n" |
||||
|
<< endl; |
||||
|
|
||||
|
if ("test.stf" >> n) { |
||||
|
prettyprint("Outputting a node/tree"); |
||||
|
cout << n; |
||||
|
|
||||
|
cout |
||||
|
<< "\n\nnode::getChild() returns a node&, so we can easily output nested nodes:\n" |
||||
|
<< endl; |
||||
|
cout << n.getChild("child"); |
||||
|
|
||||
|
cout |
||||
|
<< "\n\nnode::getValue() returns a string&, so we can easily output values too:\n" |
||||
|
<< endl; |
||||
|
cout << n.getValue("imthefirst"); |
||||
|
|
||||
|
cout |
||||
|
<< "\n\nThe constness of getChild and getValue depend on the object." |
||||
|
<< endl; |
||||
|
} else { |
||||
|
cerr << "Couldn't read file!" << endl; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void change_examples(node &n) { |
||||
|
cout |
||||
|
<< "\t\t-----Change examples------\t\t\n" |
||||
|
<< endl; |
||||
|
|
||||
|
if ("test.stf" >> n) { |
||||
|
prettyprint("Edit a value"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
n.value("imthefirst") = "O YEAH!"; |
||||
|
|
||||
|
cout << "After: " << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
prettyprint("Edit a node"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
n.child("child") = n; |
||||
|
|
||||
|
cout << "After: " << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
prettyprint("Edit the name of a value"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
n.renameValue("imthefirst", "roflolmao"); |
||||
|
|
||||
|
cout << "After: " << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
prettyprint("Edit the name of a child"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
n.renameChild("child", "NEW NAMEZ"); |
||||
|
|
||||
|
cout << "After: " << endl; |
||||
|
cout << n; |
||||
|
} else { |
||||
|
cerr << "Couldn't read file!" << endl; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void create_examples(node &n) { |
||||
|
prettyprint("Creation examples"); |
||||
|
node screenoptions; |
||||
|
node soundoptions; |
||||
|
|
||||
|
if (!("screenoptions.stf" >> screenoptions && "soundoptions.stf" >> soundoptions)) { |
||||
|
cerr << "Couldn't read files!" << endl; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
cout << "You can merge these two tree quite easily into one tree (aka \"Adding children\"):" << endl; |
||||
|
|
||||
|
cout << "Before (screenoptions):" << endl; |
||||
|
cout << screenoptions << endl; |
||||
|
cout << "Before (soundoptions):" << endl; |
||||
|
cout << soundoptions << endl; |
||||
|
|
||||
|
//child() creates the child when it doesn't exist
|
||||
|
n.child("Screen options") = screenoptions; |
||||
|
//but you can do this too
|
||||
|
n.addChild("Sound options", soundoptions); |
||||
|
|
||||
|
cout << "After (both are now children of options):" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
prettyprint("Adding a value"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
//this way, NOT sure child() won't create a child (if it doesn't exist, it'll create it)
|
||||
|
//also not sure value() won't alter a value (if the value[index] exists, it'll change that)
|
||||
|
n.child("Screen options").value("Contrast") = "70.1"; |
||||
|
//this way, 100% sure that getChild() won't create a child, and addValue() will always add a value
|
||||
|
//get{Child|Value} throw an out_of_range when they can't find the {Child|Value}.
|
||||
|
n.getChild("Screen options").addValue("Brightness") = "1.5"; |
||||
|
|
||||
|
cout << "After:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
prettyprint("Writing to a file (aka \"Saving to a file\")"); |
||||
|
const char *filename = "ExampleProgramOutput.stf"; |
||||
|
if (!(filename << n)) { |
||||
|
cerr << "Couldn't write to "; |
||||
|
} else { |
||||
|
cout << "Node succesfully saved to "; |
||||
|
} |
||||
|
cout << filename << endl << endl; |
||||
|
} |
||||
|
|
||||
|
void remove_examples(node &n) { |
||||
|
prettyprint("Removal examples"); |
||||
|
if (!("test.stf" >> n)) { |
||||
|
cerr << "Couldn't open file!" << endl; |
||||
|
} |
||||
|
|
||||
|
prettyprint("Deleting a value"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
//remove{Child|Value} throws an out_of_range when the child/value isn't found
|
||||
|
n.removeValue("imthefirst"); |
||||
|
|
||||
|
cout << "After:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
|
||||
|
prettyprint("Deleting a child/node"); |
||||
|
cout << "Before:" << endl; |
||||
|
cout << n; |
||||
|
|
||||
|
n.removeChild("child"); |
||||
|
|
||||
|
cout << "After:" << endl; |
||||
|
cout << n; |
||||
|
} |
||||
|
|
||||
|
void array_examples(node &n) { |
||||
|
prettyprint("Array Examples"); |
||||
|
if (!("arrays.stf" >> n)) { |
||||
|
cerr << "Couldn't open arrays.stf!" << endl; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
prettyprint("Iterating over an array: try/catch method"); |
||||
|
node &array = n.getChild("array"); |
||||
|
try { |
||||
|
size_t i = 0; |
||||
|
while (true) { |
||||
|
//use getValue(), it throws an out_of_range when there are no more elements
|
||||
|
cout << array.getValue(i) << endl; |
||||
|
i++; |
||||
|
} |
||||
|
} catch (out_of_range &e) {/*we're done! ;-)*/} |
||||
|
|
||||
|
prettyprint("Iterating over an array: size() method"); |
||||
|
size_t max = array.values.size(); |
||||
|
for(size_t i = 0; i < max; i++){ |
||||
|
cout << array.getValue(i) << endl; |
||||
|
} |
||||
|
|
||||
|
prettyprint("Iterating over a 2D-array: size() method"); |
||||
|
node &multiarray = n.getChild("2D array"); |
||||
|
|
||||
|
//rows are children
|
||||
|
size_t rows = multiarray.children.size(); |
||||
|
//each row can have a different amount of cols
|
||||
|
size_t cols[rows]; |
||||
|
|
||||
|
for(size_t i = 0; i < rows; i++){ |
||||
|
//same as with size() method above
|
||||
|
cols[i] = multiarray.getChild(i).values.size(); |
||||
|
//output to see it for yourself
|
||||
|
cout << i << ',' << cols[i] << endl; |
||||
|
} |
||||
|
|
||||
|
//so, we're done. Code could've been written in 100 ways, but this does it step by step to be clear.
|
||||
|
for(size_t row = 0; row < rows; row++){ |
||||
|
for(size_t col = 0; col < cols[row]; col++){ |
||||
|
cout << multiarray.getChild(row).getValue(col) << ", "; |
||||
|
} |
||||
|
cout << "\b\b " << endl; |
||||
|
} |
||||
|
|
||||
|
/*Arrays are simply unnamed nodes/values. Nothing more, nothing less.
|
||||
|
You can change them like nodes/values, add them the same way, etc. |
||||
|
Most of the functions are overloaded so that you don't have to specify a name |
||||
|
These functions call their overloaded brethren with name = "" */ |
||||
|
|
||||
|
prettyprint("Creating an array"); |
||||
|
|
||||
|
cout << "Before:\n\n"; |
||||
|
cout << n << endl; |
||||
|
|
||||
|
node &newarray = n.addChild("my new array"); |
||||
|
stringstream buf; |
||||
|
for(size_t i = 0; i < 10; i++){ |
||||
|
buf << i; |
||||
|
newarray.addValue() = buf.str(); |
||||
|
} |
||||
|
|
||||
|
cout << "After:\n\n"; |
||||
|
cout << n << endl; |
||||
|
} |
||||
|
|
||||
|
int main() { |
||||
|
prettyprint("Welcome to the stf example app"); |
||||
|
|
||||
|
ifstream license("LICENSE.txt"); |
||||
|
if (license.good()) { |
||||
|
string line; |
||||
|
while (getline(license, line)) { |
||||
|
cout << line << endl; |
||||
|
} |
||||
|
license.close(); |
||||
|
} else { |
||||
|
cerr << "Couldn't open/read LICENSE.txt" << endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
|
||||
|
cout << endl; |
||||
|
|
||||
|
cout |
||||
|
<< "This application shows how easy it is to use STFU (Simple Tree File Utility).\n" |
||||
|
<< "STF is a \"new\" way to store leveled data, just as XML can do, for example.\n" |
||||
|
<< "The format looks like a C(++) struct, which we think is easier to read than XML.\n" |
||||
|
<< "Each {...} is a node, a node has other nodes and values. The file itself is the\n" |
||||
|
<< "(unnamed) root node.\n" |
||||
|
<< endl; |
||||
|
|
||||
|
//create an empty node
|
||||
|
node n; |
||||
|
read_examples(n); |
||||
|
n.clear(); |
||||
|
|
||||
|
change_examples(n); |
||||
|
n.clear(); |
||||
|
|
||||
|
create_examples(n); |
||||
|
n.clear(); |
||||
|
|
||||
|
remove_examples(n); |
||||
|
n.clear(); |
||||
|
|
||||
|
array_examples(n); |
||||
|
n.clear(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
|
||||
|
width: "1920" |
||||
|
heigth: "1200" |
||||
|
rendermode: (OpenGL or DirectX) "OpenGL" |
@ -0,0 +1,107 @@ |
|||||
|
<h1>STF - Simple Tree Format</h1> |
||||
|
<p> |
||||
|
STF is a new file format to store a tree of values, just like XML and JSON can do. It has support for only 2 types: values and nodes. A node can have values and other nodes, allowing the creation of a tree format. A STF file itself is a node (the virtual root node). Nodes are a collection of other values and (child)nodes. |
||||
|
</p> |
||||
|
|
||||
|
<h2>Usage</h2> |
||||
|
<p> |
||||
|
Nodes and values are named, the smallest name being "". We refer to the nodes with "" as name as unnamed nodes/values, but the same rules apply for the syntax; examples will follow, don't worry. Each name is followed by a ':' which signifies the end of the name (the name-terminator). The ':' is followed by either a '{' or a '"', which signifies the type of the name (the type-specifier): '{' are lists, '"' are values. The parser will extract and ignore anything in between the name-terminator and the type-specifier. |
||||
|
</p> |
||||
|
|
||||
|
<h2>Examples</h2> |
||||
|
<h3>Starting easy</h3> |
||||
|
<p> |
||||
|
Here's an example of a very small STF file. It shows values and nodes and their syntax, without fancy stuff. |
||||
|
<pre> |
||||
|
name: "First value in the file" |
||||
|
childnode: { |
||||
|
value: "This is another value, inside a child node with the name "childnode" |
||||
|
} |
||||
|
</pre> |
||||
|
</p> |
||||
|
|
||||
|
<h3>Comments</h3> |
||||
|
<p> |
||||
|
Don't want to have a very long descriptive name, but do want a bit of extra info? Comments (or anything really) can be place in between the name-terminator and the type-specifier. |
||||
|
<pre> |
||||
|
name: This text will be ignore by the parser "First value in the file." |
||||
|
childnode: This text will too, be ignored { |
||||
|
value: You probably already guessed it |
||||
|
|
||||
|
But this text will to be ignored. Anything here is allowed, except for a type-specifier of course! ;-) |
||||
|
|
||||
|
"This is another value, inside a child node with the name ""childnode""." |
||||
|
} |
||||
|
|
||||
|
<h3>Getting more interesting</h3> |
||||
|
<p> |
||||
|
This example shows what characters are allowed inside names and values. |
||||
|
<pre> |
||||
|
firstnode: { |
||||
|
subnode: { |
||||
|
blah: "xyz" |
||||
|
blah: "names of values/childs don't have to be unique!" |
||||
|
} |
||||
|
} |
||||
|
secondnode: { |
||||
|
name with space: "names can contain spaces" |
||||
|
name |
||||
|
with |
||||
|
newlines: "names can contain newlines" |
||||
|
blah: "values can contain |
||||
|
newlines too!" |
||||
|
} |
||||
|
</pre> |
||||
|
</p> |
||||
|
<p> |
||||
|
NOTE: Take a look at the other .stf files included with this project for more examples. |
||||
|
</p> |
||||
|
|
||||
|
<h1>STFU - Simple Tree Format Utility</h1> |
||||
|
<p> |
||||
|
STFU is the first C++ implementation for STF. |
||||
|
</p> |
||||
|
<p> |
||||
|
This example will show you some of the basic features of STFU: |
||||
|
<pre> |
||||
|
#include <iostream> |
||||
|
#include "stf.hpp" |
||||
|
using namespace std; |
||||
|
using stfu::node; |
||||
|
|
||||
|
int main(){ |
||||
|
node n,f; |
||||
|
if (n.read("blah.stf")){ //could also do: 'if ("blah.stf" >> n){' |
||||
|
cout << n.value("test"); // Read a value |
||||
|
|
||||
|
cout << n.child("subnode").value("hi",0); //Read the first value |
||||
|
cout << n.child("subnode").value("hi",1); //Read the second value |
||||
|
|
||||
|
n.child("subnode").value("test") = "blah"; //Add a value |
||||
|
|
||||
|
if (f.read("another_file.stf")){ |
||||
|
n.child("secondnode") = f; //add a child |
||||
|
} |
||||
|
|
||||
|
n.write("blah.stf"); //Write changes back to the file |
||||
|
// "blah.stf" << n; would also be valid. |
||||
|
|
||||
|
cout << n; //output the file to the console instead of a file. |
||||
|
|
||||
|
} else { |
||||
|
cout << "ERROR!" << endl; |
||||
|
} |
||||
|
} |
||||
|
//NOTE: For more detailed examples, please take a look at the 'main.cpp' file of this project. |
||||
|
</pre> |
||||
|
</p> |
||||
|
<p> |
||||
|
As you see, the .child() and .value() functions can be used to read, create and change values/childs. More advanced functions are available, 'main.cpp' contains examples to explain all of them. |
||||
|
</p> |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,9 @@ |
|||||
|
|
||||
|
max soundfx: |
||||
|
A value between 0 and 255 |
||||
|
"128" |
||||
|
|
||||
|
outputmode: |
||||
|
Options are: 2.0, 4.0, 4.1, 5.1, 7.1 and 412.28 |
||||
|
"5.1" |
||||
|
|
@ -0,0 +1,276 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2009 Maurice Bos and Nick Overdijk |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are met: |
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in the |
||||
|
documentation and/or other materials provided with the distribution. |
||||
|
* The names of the authors may not be used to endorse or promote |
||||
|
products derived from this software without specific prior written |
||||
|
permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
- Maurice Bos (maurice@bosbyte.nl) |
||||
|
- Nick Overdijk (nick@dotsimplicity.net) |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include <map> |
||||
|
#include <string> |
||||
|
#include <typeinfo> |
||||
|
|
||||
|
#include "stf.hpp" |
||||
|
|
||||
|
using namespace std; |
||||
|
using stfu::node; |
||||
|
using stfu::child; |
||||
|
using stfu::value; |
||||
|
|
||||
|
ostream &stfu::operator<< (ostream &out, const node &root) { |
||||
|
root.write(out); |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
bool stfu:: operator<< (const char *filename, const node &root){ |
||||
|
return root.write(filename); |
||||
|
} |
||||
|
|
||||
|
bool stfu::operator<< (ofstream &out, const node &root) { |
||||
|
return root.write(out); |
||||
|
} |
||||
|
|
||||
|
bool stfu::operator>> (istream &in, node &root) { |
||||
|
return root.read(in); |
||||
|
} |
||||
|
|
||||
|
bool stfu::operator>> (const char *filename, node &root) { |
||||
|
return root.read(filename); |
||||
|
} |
||||
|
|
||||
|
const string &node::getValue(const string &name, size_t index) const throw (out_of_range) { |
||||
|
return get_indexed<string, string>(values, name, index); |
||||
|
} |
||||
|
|
||||
|
/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/ |
||||
|
string &node::getValue(const string &name, size_t index) throw (out_of_range) { |
||||
|
return get_indexed<string, string>(values, name, index); |
||||
|
} |
||||
|
|
||||
|
string &node::addValue(const string &name) { |
||||
|
return values.insert(pair<string, string>(name, string()))->second; |
||||
|
} |
||||
|
|
||||
|
string &node::value(const string &name, size_t index) { |
||||
|
try { |
||||
|
return getValue(name, index); |
||||
|
} catch (out_of_range &e) { |
||||
|
//it doesn't exist: create it
|
||||
|
return addValue(name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void node::removeValue(const string &name, size_t index) throw (out_of_range) { |
||||
|
values.erase(get_indexed_it(values, name, index)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
void node::renameValue(const string &oldName, const string &newName, size_t index) { |
||||
|
addValue(newName) = value(oldName, index); |
||||
|
removeValue(oldName, index); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const node &node::getChild(const string &name, size_t index) const throw (out_of_range) { |
||||
|
return get_indexed<string, node>(children, name, index); |
||||
|
} |
||||
|
|
||||
|
node &node::getChild(const string &name, size_t index) throw (out_of_range) { |
||||
|
return get_indexed<string, node>(children, name, index); |
||||
|
} |
||||
|
|
||||
|
node &node::addChild(const string &name) { |
||||
|
return children.insert(pair<string, node>(name, node()))->second; |
||||
|
} |
||||
|
|
||||
|
node &node::addChild(const string &name, node &newNode) { |
||||
|
return children.insert(pair<string, node>(name, newNode))->second; |
||||
|
} |
||||
|
|
||||
|
node &node::child(const string &name, size_t index) { |
||||
|
//if there's no such child, add one
|
||||
|
try { |
||||
|
return getChild(name, index); |
||||
|
} catch (out_of_range &e) { |
||||
|
//it doesn't exist: create it
|
||||
|
return addChild(name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void node::renameChild(const string &oldName, const string &newName, size_t index) { |
||||
|
node copy = child(oldName, index); |
||||
|
removeChild(oldName, index); |
||||
|
addChild(newName) = copy; |
||||
|
} |
||||
|
|
||||
|
void node::removeChild(const string &name, size_t index) throw (out_of_range) { |
||||
|
children.erase(get_indexed_it(children, name, index)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
bool node::read(const char *filename) { |
||||
|
ifstream f(filename); |
||||
|
|
||||
|
if (!f.good()) return false; |
||||
|
|
||||
|
bool success = read(f); |
||||
|
f.close(); |
||||
|
|
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
bool node::read(istream &in) { |
||||
|
while (1) { |
||||
|
in >> ws; //Skip whitespace
|
||||
|
|
||||
|
//if end of node is reached, return
|
||||
|
if (in.peek() == '}') { |
||||
|
in.ignore(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (in.eof()) { |
||||
|
return true; //End of the file is reached
|
||||
|
} |
||||
|
|
||||
|
string name; |
||||
|
char type; // '{' or '"'
|
||||
|
streamRead(in, name, ':'); //Read name (all chars before ':')
|
||||
|
type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
|
||||
|
|
||||
|
switch (type) { |
||||
|
|
||||
|
//in case of value
|
||||
|
case '"': { |
||||
|
string value; |
||||
|
while (1) { |
||||
|
if (streamRead(in, value, '"') == 0) { //Read to the closing-"
|
||||
|
return false; |
||||
|
} |
||||
|
if (in.peek() == '"') { |
||||
|
in.ignore(); |
||||
|
value += '"'; |
||||
|
continue; |
||||
|
} else { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
this->values.insert(pair<string,string>(name, value)); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
//in case of child
|
||||
|
case '{': { |
||||
|
node sub; |
||||
|
if (!sub.read(in)) { //Recursively read the subnode
|
||||
|
return false; |
||||
|
} |
||||
|
this->children.insert(pair<string,node>(name,sub)); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*Writes to a file using it's overloaded self*/ |
||||
|
bool node::write(const char *filename) const { |
||||
|
ofstream f(filename); |
||||
|
|
||||
|
if (!f.good()) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool success = write(f); |
||||
|
f.close(); |
||||
|
|
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
|
||||
|
bool node::write(ostream &out, size_t depth, string indent) const { |
||||
|
string indentation; |
||||
|
for (size_t i = 0; i < depth; i++) { |
||||
|
indentation += indent; |
||||
|
} |
||||
|
|
||||
|
for (multimap<string, string>::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) { |
||||
|
//Escape all the '"' by adding a second '"'
|
||||
|
string value(value_it->second); |
||||
|
size_t found = value.find('"'); |
||||
|
|
||||
|
//while there are more ", insert second "s
|
||||
|
while (found != value.npos) { |
||||
|
value.insert(found, 1, '"'); |
||||
|
found = value.find('"', found+2); |
||||
|
} |
||||
|
out << indentation << value_it->first << ": \"" << value << '"' << endl; |
||||
|
} |
||||
|
|
||||
|
for (multimap<string, node>::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) { |
||||
|
out << indentation << child_it->first << ": {" << endl; |
||||
|
child_it->second.write(out, depth+1); |
||||
|
out << indentation << '}' << endl; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
char node::streamSkip(istream &in, const string &delimiters) { |
||||
|
char cur; |
||||
|
|
||||
|
//Return if the current char is part of delimiters[]
|
||||
|
while (in >> noskipws >> cur) { |
||||
|
if (delimiters.find_first_of(cur) != delimiters.npos) return cur; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
char node::streamRead(istream &in, string &out, const string &delimiters) { |
||||
|
char cur; |
||||
|
|
||||
|
//Return if the current char is part of delimiters[]
|
||||
|
while (in >> noskipws >> cur) { |
||||
|
if (delimiters.find(cur) != delimiters.npos) return cur; |
||||
|
out += cur; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
char node::streamRead(istream &in, string &out, const char delimiter) { |
||||
|
char cur; |
||||
|
|
||||
|
//Return if the current char is delimiter
|
||||
|
while (in >> noskipws >> cur) { |
||||
|
if (delimiter == cur) return cur; |
||||
|
out += cur; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,358 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2009 Maurice Bos and Nick Overdijk |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are met: |
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in the |
||||
|
documentation and/or other materials provided with the distribution. |
||||
|
* The names of the authors may not be used to endorse or promote |
||||
|
products derived from this software without specific prior written |
||||
|
permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
- Maurice Bos (maurice@bosbyte.nl) |
||||
|
- Nick Overdijk (nick@dotsimplicity.net) |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <fstream> |
||||
|
#include <string> |
||||
|
#include <sstream> |
||||
|
#include <map> |
||||
|
#include <stdexcept> |
||||
|
|
||||
|
#ifndef STFU_HPP |
||||
|
#define STFU_HPP |
||||
|
|
||||
|
namespace stfu { |
||||
|
using namespace std; |
||||
|
const static string not_found("search->No such child/value"); |
||||
|
|
||||
|
/*! \class node
|
||||
|
* \brief A node in an STF tree. |
||||
|
* \author Maurice Bos |
||||
|
* \author Nick Overdijk |
||||
|
* \version 1.0 |
||||
|
* \date 2009-04-25 |
||||
|
* |
||||
|
* When you read an STF file through a node (with read() for example), this node will be the root node, without a name. See the examples for more information. |
||||
|
*/ |
||||
|
class node { |
||||
|
|
||||
|
/** Overloaded ostream's operator<< */ |
||||
|
friend ostream &operator<< (ostream &out, const node &root); |
||||
|
|
||||
|
/** Returns whether it was succesful or not*/ |
||||
|
friend bool operator<< (ofstream &out, const node &root); |
||||
|
|
||||
|
/** Acts like write(), but looks like this: "filename" << node */ |
||||
|
friend bool operator<< (const char *filename, const node &root); |
||||
|
|
||||
|
/** Overloaded istream's operator>> */ |
||||
|
friend bool operator>> (istream &in, node &root); |
||||
|
|
||||
|
/** Acts like read(), but looks like this: "filename" >> node */ |
||||
|
friend bool operator>> (const char *filename, node &root); |
||||
|
|
||||
|
public: |
||||
|
//@{
|
||||
|
/** The values and children belonging to this node. To add, remove, do whatever: you CAN use these variables directly. To use indexing, use the member functions below*/ |
||||
|
multimap<string, string> values; |
||||
|
multimap<string, node> children; |
||||
|
//@}
|
||||
|
|
||||
|
/**
|
||||
|
Clears the whole node recursively. |
||||
|
*/ |
||||
|
void clear() { |
||||
|
values.clear(); |
||||
|
children.clear(); |
||||
|
} |
||||
|
/**
|
||||
|
Gets the string value from a variable |
||||
|
\param name The name of the value you wish to retrieve |
||||
|
\param index If there are more values with the same name, they are indexed. Here you can supply its indexnumber. |
||||
|
\return The retrieved value |
||||
|
*/ |
||||
|
string &value(const string &name, size_t index = 0); |
||||
|
|
||||
|
/**
|
||||
|
Same as value(), but for unnamed values |
||||
|
\note same as value("", index) |
||||
|
\param index If there are more unnamed values, they are indexed. Here you can supply its indexnumber.
\return Same as value |
||||
|
*/ |
||||
|
string &value(size_t index){ |
||||
|
return value("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Creates and adds a value. |
||||
|
\param name The name of the value to be created |
||||
|
\return A reference to the value of the created value. |
||||
|
*/ |
||||
|
string &addValue(const string &name = ""); |
||||
|
|
||||
|
/**
|
||||
|
Const function for const objects to get a value. It's NOT possible to call value() on constant objects for value() isn't const. |
||||
|
\param name Name of the value to be retrieved |
||||
|
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a const string& to the value of value with the name and index specified |
||||
|
*/ |
||||
|
const string &getValue(const string &name, size_t index) const throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
Same as getValue() const, but for unnamed values |
||||
|
\note same as getValue("", index) const |
||||
|
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a const string& to the value of value with the name and index specified |
||||
|
*/ |
||||
|
const string &getValue(size_t index) const throw (out_of_range){ |
||||
|
return getValue("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Same as getValue() const, but for non-const objects. The returned string& can safely be modified. |
||||
|
\param name Name of the value to be retrieved |
||||
|
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a string& to the value of value with the name and index specified |
||||
|
*/ |
||||
|
string &getValue(const string &name, size_t index = 0) throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
Same as getValue(), but for unnamed values |
||||
|
\note same as getValue("", index) |
||||
|
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a string& to the value of value with the name and index specified |
||||
|
*/ |
||||
|
string &getValue(size_t index) throw (out_of_range){ |
||||
|
return getValue("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Removes a value. Surprise huh? |
||||
|
\param name Name of the value to be removed |
||||
|
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void removeValue(const string &name, size_t index = 0) throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
Removes an unnamed value. |
||||
|
\note same as removeValue("", index); |
||||
|
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void removeValue(size_t index) throw (out_of_range){ |
||||
|
removeValue("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Renames a value. |
||||
|
\param oldName Name of the value to be renamed |
||||
|
\param newName The name that the oldName-value should have |
||||
|
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void renameValue(const string &oldName, const string &newName, size_t index = 0); |
||||
|
|
||||
|
/**
|
||||
|
Changes, adds or retrieves node |
||||
|
\param name The name of the child you wish to retrieve, change or add. |
||||
|
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
\return The retrieved node |
||||
|
|
||||
|
If this index number is > the number of variables with that name, a new variable with that name is created with index = current number of same name variables + 1. |
||||
|
So say you have 4 variables named "tree", you call child("tree", 10), another tree gets made with index 5, NOT 10. |
||||
|
*/ |
||||
|
node &child(const string &name, size_t index = 0); |
||||
|
|
||||
|
/**
|
||||
|
Same as child(), but for unnamed children. |
||||
|
\note same as child("", index) |
||||
|
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber. |
||||
|
\return The retrieved node |
||||
|
*/ |
||||
|
node &child(size_t index = 0){ |
||||
|
return child("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Guarranteed to add a child |
||||
|
\param name Name for the child |
||||
|
\return A reference to the created node |
||||
|
*/ |
||||
|
node &addChild(const string &name = ""); |
||||
|
|
||||
|
/**
|
||||
|
As addChild(name), but copies data from newChild as well. |
||||
|
\param name Name for the child |
||||
|
\param newChild Data to copy from the child. |
||||
|
\return A reference to the created node |
||||
|
*/ |
||||
|
node &addChild(const string &name, node &newChild); |
||||
|
|
||||
|
/**
|
||||
|
As addChild(name, newChild), but without name, for unnamed children |
||||
|
\note same as addChild("", newChild); |
||||
|
\param newChild Data to copy from the child. |
||||
|
\return A reference to the created node |
||||
|
*/ |
||||
|
node &addChild(node &newChild){ |
||||
|
return addChild("", newChild); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Const function for const objects to get a node. It's NOT possible to call child() for this, for child() isn't const. |
||||
|
\param name Name of the child to be retrieved |
||||
|
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a const node& to the node with the name and index specified |
||||
|
*/ |
||||
|
const node &getChild(const string &name, size_t index = 0) const throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
Const function for const objects to get an unnamed const node&. |
||||
|
\note same as getChild("", index) const; |
||||
|
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a const node& to the node with the name and index specified |
||||
|
*/ |
||||
|
const node &getChild(size_t index = 0) const throw (out_of_range){ |
||||
|
return getChild("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Same as getChild() const, but for non-const objects. The returned child & can be modified |
||||
|
\param name Name of the child to be retrieved |
||||
|
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a node& to the node with the name and index specified |
||||
|
*/ |
||||
|
node &getChild(const string &name, size_t index = 0) throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
Same as getChild() const, but for non-const objects. |
||||
|
\note same as getChild("", index); |
||||
|
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber. |
||||
|
\return Returns a node& to the node with the name and index specified |
||||
|
*/ |
||||
|
node &getChild(size_t index = 0) throw (out_of_range){ |
||||
|
return getChild("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Removes a child. Surprise huh? |
||||
|
\param name Name of the child to be removed |
||||
|
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void removeChild(const string &name, size_t index = 0) throw (out_of_range); |
||||
|
|
||||
|
/**
|
||||
|
As removeChild() for unnamed children. |
||||
|
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void removeChild(size_t index = 0) throw (out_of_range){ |
||||
|
removeChild("", index); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Renames a child. |
||||
|
\param oldName Name of the child to be renamed |
||||
|
\param newName The name that the oldName-child should have |
||||
|
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber. |
||||
|
*/ |
||||
|
void renameChild(const string &oldName, const string &newName, size_t index = 0); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
Reads the STF from an istream |
||||
|
|
||||
|
\return Returns whether it was succesful |
||||
|
*/ |
||||
|
bool read(istream &in); |
||||
|
|
||||
|
/**
|
||||
|
Reads the STF from a file |
||||
|
|
||||
|
\return Returns whether it was succesful |
||||
|
*/ |
||||
|
bool read(const char *filename); |
||||
|
|
||||
|
/**
|
||||
|
Writes the STF to an ostream with optional indentation |
||||
|
\param out ostream to write to |
||||
|
\param depth how much indentation to start with |
||||
|
\param indent What string to use as indenation |
||||
|
\return Returns whether it was succesful |
||||
|
*/ |
||||
|
bool write(ostream &out, size_t depth = 0, string indent = "\t") const; |
||||
|
|
||||
|
/**
|
||||
|
Writes to a file. Simply first opens a file and passes that ostream to itself. |
||||
|
\param filename File to write to |
||||
|
\return Returns whether it was succesful |
||||
|
*/ |
||||
|
bool write(const char *filename) const; |
||||
|
|
||||
|
private: |
||||
|
char streamRead(istream &in,string &out, const string &delim); |
||||
|
char streamRead(istream &in, string &out, const char delim); |
||||
|
char streamSkip(istream &in, const string &delim); |
||||
|
|
||||
|
/*
|
||||
|
returns a T2&, not a const T2&. The functions getValue/getChild make sure this will be done correctly for const objects |
||||
|
this function can NOT use get_indexed_it, because that function can't be const: |
||||
|
const_iterators can not be transformed into iterators, and the iterator is needed for erase(), which wants an iterator. |
||||
|
*/ |
||||
|
template <typename T1, typename T2> |
||||
|
T2& get_indexed(const multimap<T1, T2> &container, const T1 &key, size_t index = 0) const throw (out_of_range) { |
||||
|
size_t count = container.count(key); |
||||
|
|
||||
|
if (count != 0 && count-1 >= index) { |
||||
|
typename multimap<T1, T2>::const_iterator it = container.find(key); |
||||
|
while (index--) it++; |
||||
|
return const_cast<T2&>(it->second); |
||||
|
} else { |
||||
|
throw out_of_range((string)"get_indexed->"+"Element " + key + "doesn't exist!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// template <typename T1, typename T2>
|
||||
|
// typename multimap<T1, T2>::iterator get_indexed_it(multimap<T1, T2> &container, const T1 &key, size_t index = 0) throw (out_of_range) {
|
||||
|
// size_t count = container.count(key);
|
||||
|
//
|
||||
|
// if (count != 0 && count-1 >= index) {
|
||||
|
// typename multimap<T1, T2>::iterator it = container.find(key);
|
||||
|
// while (index--) it++;
|
||||
|
// return it;
|
||||
|
// } else {
|
||||
|
// throw out_of_range((string)"get_indexed_it->"+"Element " + key + "doesn't exist!");
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
template <typename Container, typename T> |
||||
|
typename Container::iterator get_indexed_it(Container& container, const T& key, size_t index = 0) |
||||
|
throw (out_of_range) { |
||||
|
typename Container::iterator it = container.find(key); |
||||
|
while (index-- && it != container.end() && it->first==key) it++; |
||||
|
if (it == container.end()) throw out_of_range("get_indexed_it(Container&, const T&, size_t)"); |
||||
|
return it; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
typedef pair<string, string> value; |
||||
|
typedef pair<string, node> child; |
||||
|
|
||||
|
typedef multimap<string, string>::iterator valueiterator; |
||||
|
typedef multimap<string, node>::iterator childiterator; |
||||
|
} |
||||
|
|
||||
|
#endif // STFU_HPP
|
@ -0,0 +1,4 @@ |
|||||
|
imthefirst: "The first value inside root!" |
||||
|
child: { |
||||
|
blah: "The value of [root].child.blah" |
||||
|
} |
Reference in new issue