Skip to content

Commit

Permalink
Removed ESCAPE_TIME_2
Browse files Browse the repository at this point in the history
I have removed ESCAPE_TIME_2 coloring algorithm because it was actually
the same as continuous sine but without the continuous index. The result
were were images that were only distinguishable with special tools and
that was quite confusing.

New file name substitution pattern %f that will be replaced by the
fractal type.

Added missing license file for Catch
  • Loading branch information
crapp committed Apr 7, 2016
1 parent cfe3c03 commit 2b1daf5
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 130 deletions.
85 changes: 49 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,20 @@ try to plot this set, you will find areas that are similar to the main area. You
can zoom into this figure as much as you want. You will discover new formations as
well as parts with self similarity.

Here is a video showing a zoom into the seahorse valley.
Here is a video showing a zoom into the Mandelbrot seahorse valley.

LINK TO VIDEO

Besides the Mandelbrot Fractal BLAAAAAAAAAAAAAA supports the following other fractals:
Besides the Mandelbrot Fractal geomandel supports the following other fractals:
* [Julia Set](https://en.wikipedia.org/wiki/Julia_set)
* [Tricorn](https://en.wikipedia.org/wiki/Tricorn_%28mathematics%29)
* [Burning Ship](https://en.wikipedia.org/wiki/Burning_Ship_fractal)

You may ask yourself how I came up with the name geomandel for this fractal
generator. Well my original plan was to play with fractals and GeoTIFFs to see
what kind of effects I could achieve with spatial geographic data. This is still
on my list of todos...

I also want to make you aware of the
[Mandelbrot project](https://github.com/willi-kappler/mandel-rust) a friend of
mine started. He uses Rust for his project and it motivated me to see how a C++11
Expand Down Expand Up @@ -76,6 +81,11 @@ In order to compile the source code on your machine the following requirements h
* MinGW >= 4.9
* [Simple and Fast Multimedia Library](http://www.sfml-dev.org/) for png/jpg support (optional)

The following external libraries are used by geomandel and are part of the
applications source code:
* [cxxopts](https://github.com/jarro2783/cxxopts) - Lightweight C++ command line option parser
* [CTPL](https://github.com/vit-vit/CTPL) - Modern and efficient C++ Thread Pool Library
* [Catch](https://github.com/philsquared/Catch) - A modern, C++-native, header-only, framework for unit-tests, TDD and BDD

#### Linux / OS X

Expand Down Expand Up @@ -144,8 +154,6 @@ geomandel uses the header only c++ command line parser [cxxopts](https://github.
The following command line options are available

```shell
$ geomandel --help

Usage:
geomandel [OPTION...] - command line options

Expand Down Expand Up @@ -180,17 +188,21 @@ Usage:
--image-pnm-col Write Buffer to PPM Bitmap
--image-jpg Write Buffer to JPG image
--image-png Write Buffer to PNG image
--col-algo arg Coloring algorithm 0->Escape Time, 1-> Escape Time 2,
2->Continuous Coloring (default:2)
--col-algo arg Coloring algorithm 0->Escape Time Linear,
1->Continuous Coloring Sine, 2->Continuous Coloring
Bernstein (default:1)
--grey-base arg Base grey color between 0 - 255 (default:55)
--grey-freq arg Frequency for grey shade computation (default:0.01)
--rgb-base arg Base RGB color as comma separated string
(default:127,127,127)
(default:128,128,128)
--rgb-freq arg Frequency for RGB computation as comma separated
string. You may use doubles but no negative values
(default:0.01,0.01,0.01)
--rgb-phase arg Phase for RGB computation as comma separated string
--rgb-phase arg Phase for Sine Wave RGB computation as comma separated
string
(default:0,2,4)
--rgb-amp arg Amplitude for Bernstein RGB computation as comma
separated string (default:9,15,8.5)
--set-color arg Color for pixels inside the set (default:0,0,0)
--zoom arg Zoom level. Use together with xcoord, ycoord
--xcoord arg Image X coordinate where you want to zoom into the
Expand All @@ -202,6 +214,7 @@ Usage:
-p, --print Print Buffer to terminal
--csv Export data to csv files
```
#### Fractal Options
Expand Down Expand Up @@ -306,8 +319,7 @@ These parameters have a large impact on memory footprint and computation time
The application can generate images in the [portable anymap format (PNM)](https://en.wikipedia.org/wiki/Netpbm_format).
The big advantage of this format it is easy to implement and doesn't need any external
libraries. The downside is large files, as geomandel does not use a binary format, and
low writing speed. You may also these images with a text editor of your choice
to what values geomandel actually wrote into the image file.
low writing speed.

You can choose between `--img-pnm-bw` a simple black and white image, `--img-pnm-grey`
using grey scale to render the fractal and `--img-pnm-col` that generates
Expand All @@ -319,36 +331,39 @@ You have to install the library and recompile geomandel if you want this kind of

##### Color Options

This is just a brief introduction into color command line options. See **Color**
for more information on this topic.
This is just a brief introduction into color command line options. See the **Color**
section for more information on this topic.

The `col-algo` parameter determines which coloring algorithm to use. Continuous
coloring will produce images without visible color bands. Computation time might
coloring can produce images without visible color bands. Computation time might
increase slightly though.

```
--col-algo arg Coloring algorithm 0->Escape Time, 1->Continuous Coloring
--col-algo arg Coloring algorithm 0->Escape Time Linear,
1->Continuous Coloring Sine, 2->Continuous Coloring Bernstein
```

Grey scale fractals are a nice alternative to colored ones. These parameters
control how the pgm images look like. Continuous coloring is not available for
grey scale images.
control how the pgm images look like.

```
--grey-base arg Base grey color between 0 - 255
--grey-base arg Base grey shade between 0 - 255
--grey-freq arg Frequency for grey shade computation
```

The RGB options apply to PPM as well as PNG and JPG images. The base color
The RGB options apply to PPM as well as to PNG and JPG images. The base color
(background color) is set with `--rgb-base`. The distribution of the colors in
the color spectrum for the escape time or continuous index can be defined with
`--rgb-freq` and `--rgb-base`. These options do different things depending on the
chosen coloring algorithm
`--rgb-freq`, `--rgb-phase` and `--rgb-amp`. These options do different things
depending on the chosen coloring algorithm.

```
--rgb-base arg Base RGB color as comma separated string
--rgb-freq arg Frequency for RGB computation as comma separated
string. You may use doubles but no negative values
--rgb-phase arg Phase for RGB computation as comma separated string
--rgb-base arg Base RGB color as comma separated string
--rgb-freq arg Frequency for RGB computation as comma separated
string. You may use doubles but no negative values
--rgb-phase arg Phase for Sine Wave RGB computation as comma separated string
--rgb-amp arg Amplitude for Bernstein RGB computation as comma separated string
```

### Examples
Expand All @@ -357,21 +372,20 @@ chosen coloring algorithm

## Color

The algorithms are well known and easy to implement. The more challenging part is
to draw beautiful fractals using different coloring algorithms. geomandel offers
two different color strategies, escape time based and continuous coloring. You
The fractal algorithms are well known and easy to implement. The more challenging
part is to draw beautiful fractals using different coloring algorithms. geomandel
offers different color strategies, escape time based and continuous coloring. You
can use the `col-algo` parameter too chose which one you want to apply.

### Escape Time
### Escape Time Linear

The Escape Time algorithm is the most common method to color fractals. This is
because the method is fast, easy to understand and there are a lot of implementations
int he wild one can build on.
in the wild one can build on.

The pseudo code example in [command line options](#Mandelbrot-Options) section
shows how the escape time is calculated. geomandel takes this value and calculates
a RGB tuple or a grey scale value using two different formula depending on which
escape time algorithm you chose.
a RGB tuple or a grey scale value using the following formula

!["Escape Time Coloring 1 Formula"](https://crapp.github.io/geomandel/escape_time_coloring.png)

Expand All @@ -388,15 +402,14 @@ The following Images and Plots were generated with `--grey-base=55`
!["Escape Time Fractals"](https://crapp.github.io/geomandel/color_escapetime_append_greymandel_2.jpg)

As you can see increasing the frequency will add better visual effects but also
worsen the problem of color banding. Grey scale PGM images can not be generated
with the continuous coloring algorithm.
worsens the problem of color banding.

#### RGB Images

Generating RGB images with the Escape Time algorithm works similar to grey scale
images. You now have to use `--rgb-base=R,G,B` to provide a base color and
`--rgb-freq=FREQ_R,FREQ_G,FREQ_B` to determine the frequencies. Setting a
frequency to **0** will leave the respective color component untouched.
frequency to **0** will leave the respective color channel untouched.

The first three colorbars were created with a base color of `255,0,0` and a
RGB frequency of `0,2,0;0,8,0;0,16,0`. So only the green color component will
Expand All @@ -415,7 +428,7 @@ Here is what these values will look like as mandelbrot fractals.
![Escape time fractals](https://crapp.github.io/geomandel/escape_time_fractals_all_border.png)


Feel free to experiment with this values to get the result you want. There is a
Feel free to experiment with these values to get the result you want. There is a
jupyter notebook `EscapeTimeRGB` in the resources folder that makes it easy to
visualize different values for RGB fractals generated with the escape time
algorithm.
Expand Down Expand Up @@ -462,7 +475,7 @@ Here are some examples that show what you can achieve using this type of colorin

![Continuous Coloring rainbow](https://crapp.github.io/geomandel/continuous_rainbow.png)

The first graph and colorbar show how you can get rainbow colors by using out of
The first graph and colorbar show how you can get rainbow colors by using out of
phase color channel waves. If you would use the same phase and the same frequency
this would produce grey shades.

Expand Down
23 changes: 23 additions & 0 deletions license/Catch_LICENSE_1_0
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
14 changes: 7 additions & 7 deletions src/buffwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

Buffwriter::Buffwriter(const constants::fracbuff &buff) : buff(buff) {}
Buffwriter::~Buffwriter() {}
std::string Buffwriter::out_file_name(const std::string &string_pattern,
unsigned int bailout, unsigned int xrange,
unsigned int yrange, unsigned int zoom,
unsigned int cores, double xcoord,
double ycoord, double z_real_min,
double z_real_max, double z_ima_min,
double z_ima_max)
std::string Buffwriter::out_file_name(
const std::string &string_pattern, const std::string &fractal_type,
unsigned int bailout, unsigned int xrange, unsigned int yrange,
unsigned int zoom, unsigned int cores, double xcoord, double ycoord,
double z_real_min, double z_real_max, double z_ima_min, double z_ima_max)
{
// this might represent the classic example of overengineering

std::vector<std::unique_ptr<RegexpatternIface>> regex_patterns;
regex_patterns.emplace_back(
new Regexpattern<std::string>(fractal_type, "%f"));
regex_patterns.emplace_back(new Regexpattern<unsigned int>(bailout, "%b"));
regex_patterns.emplace_back(new Regexpattern<unsigned int>(xrange, "%w"));
regex_patterns.emplace_back(new Regexpattern<unsigned int>(yrange, "%h"));
Expand Down
32 changes: 32 additions & 0 deletions src/buffwriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ struct RegexpatternIface {
virtual void parse_filename(std::string &filename) = 0;
};

/**
* @brief Regexpattern implementing interface for vector support
*
* @tparam T
*/
template <typename T>
struct Regexpattern : public RegexpatternIface {
Regexpattern(T value, std::string pattern)
Expand All @@ -63,6 +68,32 @@ struct Regexpattern : public RegexpatternIface {
std::string regpattern;
};

/**
* @brief Specialized form of the Regexpattern struct for strings
*/
template <>
struct Regexpattern<std::string> : public RegexpatternIface {
Regexpattern(std::string value, std::string pattern)
: RegexpatternIface(), value(value), regpattern(std::move(pattern)){};
virtual ~Regexpattern(){};

/**
* @brief Parse the filename string and replace every occurence of regpattern
* with value
*
* @param filename
*/
void parse_filename(std::string &filename)
{
std::regex re(this->regpattern);
filename = std::regex_replace(filename, re, this->value);
}

private:
std::string value;
std::string regpattern;
};

/**
* @brief Base class of all classes that write the mandelbrot buffer to a
* file/stream
Expand All @@ -79,6 +110,7 @@ class Buffwriter
const constants::fracbuff &buff;

std::string out_file_name(const std::string &string_pattern,
const std::string &fractal_type,
unsigned int bailout, unsigned int xrange,
unsigned int yrange, unsigned int zoom,
unsigned int cores, double xcoord, double ycoord,
Expand Down
9 changes: 5 additions & 4 deletions src/csvwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ void CSVWriter::write_buffer()
// generate a csv file for iterations and modulus
// TODO: Why not simply pass the FractalParameters object?
std::string filename = this->out_file_name(
this->params->image_base, this->params->bailout, this->params->xrange,
this->params->yrange, this->params->zoom, this->params->cores,
this->params->xcoord, this->params->ycoord, this->params->xl,
this->params->xh, this->params->yl, this->params->yh);
this->params->image_base, this->params->fractal_type,
this->params->bailout, this->params->xrange, this->params->yrange,
this->params->zoom, this->params->cores, this->params->xcoord,
this->params->ycoord, this->params->xl, this->params->xh,
this->params->yl, this->params->yh);
std::ofstream csv_stream_iter(filename + "_iterindex.csv",
std::ofstream::out);
std::ofstream csv_stream_modulus(filename + "_contindex.csv",
Expand Down
5 changes: 4 additions & 1 deletion src/fractalparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct FractalParameters {
double ycoord;

std::string image_base;
std::string fractal_type;

unsigned int cores;

Expand All @@ -58,7 +59,8 @@ struct FractalParameters {
double xl, double xh, unsigned int yrange, double yl,
double yh, double julia_real, double julia_ima,
unsigned int bailout, unsigned int zoom, double xcoord,
double ycoord, std::string image_base, unsigned int cores,
double ycoord, std::string image_base,
std::string fractal_type, unsigned int cores,
constants::COL_ALGO col_algo)
: set_type(set_type),
xrange(xrange),
Expand All @@ -74,6 +76,7 @@ struct FractalParameters {
xcoord(xcoord),
ycoord(ycoord),
image_base(image_base),
fractal_type(fractal_type),
cores(cores),
col_algo(col_algo)
{
Expand Down
5 changes: 3 additions & 2 deletions src/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ enum OUT_FORMAT {
};

enum FRACTAL { MANDELBROT, TRICORN, JULIA, BURNING_SHIP };
// TODO: Underscore 2 might not be the best name for this :/
enum COL_ALGO { ESCAPE_TIME, ESCAPE_TIME_2, CONTINUOUS_SINE, CONTINUOUS_BERN };
// TODO: I have removed ESCAPE_TIME_2 for the time beeing as it is just confusing
// and not really adding something new.
enum COL_ALGO { ESCAPE_TIME, CONTINUOUS_SINE, CONTINUOUS_BERN };

const std::map<OUT_FORMAT, std::vector<std::string>> BITMAP_DEFS{
{OUT_FORMAT::IMAGE_PNM_BW, {"pbm", "P1"}},
Expand Down
12 changes: 6 additions & 6 deletions src/image_pnm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ void ImagePNM::write_buffer()
// FIXME: Add zoom value to filename only when greater 0
// File name: FILENAME_BAILOUT_WIDTHxHEIGHT_ZOOMx.FILE_TYPE
std::string filename =
this->out_file_name(this->params->image_base, this->params->bailout,
this->params->xrange, this->params->yrange,
this->params->zoom, this->params->cores,
this->params->xcoord, this->params->ycoord,
this->params->xl, this->params->xh, this->params->yl,
this->params->yh) +
this->out_file_name(
this->params->image_base, this->params->fractal_type,
this->params->bailout, this->params->xrange, this->params->yrange,
this->params->zoom, this->params->cores, this->params->xcoord,
this->params->ycoord, this->params->xl, this->params->xh,
this->params->yl, this->params->yh) +
"." + constants::BITMAP_DEFS.at(this->format).at(0);
std::cout << "+ \u2937 " + filename << std::endl;

Expand Down
8 changes: 0 additions & 8 deletions src/image_pnm_col.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,6 @@ void Imagecol::out_format_write(std::stringstream &img_buf,
img_buf << std::get<0>(rgb) << " " << std::get<1>(rgb) << " "
<< std::get<2>(rgb) << "\t";
}
if (this->params->col_algo == constants::COL_ALGO::ESCAPE_TIME_2) {
auto rgb =
this->rgb_continuous_sine(static_cast<double>(its), this->rgb_base,
this->rgb_freq, this->rgb_phase);

img_buf << std::get<0>(rgb) << " " << std::get<1>(rgb) << " "
<< std::get<2>(rgb) << "\t";
}
if (this->params->col_algo == constants::COL_ALGO::CONTINUOUS_SINE) {
auto rgb = this->rgb_continuous_sine(continous_index, this->rgb_base,
this->rgb_freq, this->rgb_phase);
Expand Down
Loading

0 comments on commit 2b1daf5

Please sign in to comment.