-
-
Notifications
You must be signed in to change notification settings - Fork 360
C++ sample code for The Barnsley Fern #835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#include <array> | ||
#include <cassert> | ||
#include <fstream> | ||
#include <random> | ||
|
||
using Vec2 = std::array<double, 2>; | ||
using Vec3 = std::array<double, 3>; | ||
using Row = std::array<double, 3>; | ||
using Op = std::array<Row, 3>; | ||
|
||
constexpr auto OpN = 4; | ||
|
||
template <int N> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should probably be template There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is a template. What do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wooops, not sure what happened here. |
||
auto operator+(std::array<double, N> x, std::array<double, N> y) { | ||
for (auto i = 0U; i < N; ++i) | ||
x[i] += y[i]; | ||
return x; | ||
} | ||
|
||
template <int N> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same, this should probably be template |
||
auto operator*(double k, std::array<double, N> v) { | ||
for (auto i = 0U; i < N; ++i) | ||
v[i] *= k; | ||
return v; | ||
} | ||
|
||
template <int N> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same, this should probably be template |
||
auto operator*(std::array<double, N> v, double k) { | ||
return k * v; | ||
} | ||
|
||
auto operator*(const Op& x, const Vec3& y) { | ||
auto ret = Vec3{}; | ||
for (auto i = 0; i < 3; ++i) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should probably be |
||
ret[i] = 0; | ||
for (auto j = 0; j < 3; ++j) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should probably be auto j = 0U |
||
ret[i] += y[j] * x[i][j]; | ||
} | ||
return ret; | ||
} | ||
|
||
// Returns a pseudo-random number generator | ||
std::default_random_engine& rng() { | ||
// Initialize static pseudo-random engine with non-deterministic random seed | ||
static std::default_random_engine randEngine(std::random_device{}()); | ||
return randEngine; | ||
} | ||
|
||
// Returns a random double in [0, 1) | ||
double drand() { | ||
return std::uniform_real_distribution<double>(0.0, 1.0)(rng()); | ||
} | ||
|
||
// This is a function that reads in the Hutchinson operator and | ||
// corresponding | ||
// probabilities and outputs a randomly selected transform | ||
// This works by choosing a random number and then iterating through all | ||
// probabilities until it finds an appropriate bin | ||
auto select_array( | ||
const std::array<Op, OpN>& hutchinson_op, | ||
const std::array<double, OpN>& probabilities) { | ||
|
||
// random number to be binned | ||
auto rnd = drand(); | ||
|
||
// This checks to see if a random number is in a bin, if not, that | ||
// probability is subtracted from the random number and we check the | ||
// next bin in the list | ||
for (auto i = 0U; i < probabilities.size(); ++i) { | ||
if (rnd < probabilities[i]) | ||
return hutchinson_op[i]; | ||
rnd -= probabilities[i]; | ||
} | ||
assert(!"check if probabilities adding up to 1"); | ||
mika314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// This is a general function to simulate a chaos game | ||
// n is the number of iterations | ||
// initial_location is the the starting point of the chaos game | ||
// hutchinson_op is the set of functions to iterate through | ||
// probabilities is the set of probabilities corresponding to the likelihood | ||
// of choosing their corresponding function in hutchinson_op | ||
auto chaos_game( | ||
size_t n, | ||
Vec2 initial_location, | ||
const std::array<Op, OpN>& hutchinson_op, | ||
const std::array<double, OpN>& probabilities) { | ||
|
||
// Initializing the output array and the initial point | ||
auto output_points = std::vector<Vec2>{}; | ||
|
||
// extending point to 3D for affine transform | ||
auto point = Vec3{initial_location[0], initial_location[1], 1}; | ||
|
||
for (auto i = 0U; i < n; ++i) { | ||
output_points.push_back(Vec2{point[0], point[1]}); | ||
point = select_array(hutchinson_op, probabilities) * point; | ||
} | ||
|
||
return output_points; | ||
} | ||
|
||
int main() { | ||
|
||
const std::array barnsley_hutchinson = { | ||
Op{Row{0.0, 0.0, 0.0}, Row{0.0, 0.16, 0.0}, Row{0.0, 0.0, 1.0}}, | ||
Op{Row{0.85, 0.04, 0.0}, Row{-0.04, 0.85, 1.60}, Row{0.0, 0.0, 1.0}}, | ||
Op{Row{0.20, -0.26, 0.0}, Row{0.23, 0.22, 1.60}, Row{0.0, 0.0, 1.0}}, | ||
Op{Row{-0.15, 0.28, 0.0}, Row{0.26, 0.24, 0.44}, Row{0.0, 0.0, 1.0}}}; | ||
|
||
const std::array barnsley_probabilities = {0.01, 0.85, 0.07, 0.07}; | ||
auto output_points = chaos_game( | ||
10'000, Vec2{0, 0}, barnsley_hutchinson, barnsley_probabilities); | ||
|
||
std::ofstream ofs("out.dat"); | ||
for (auto pt : output_points) | ||
ofs << pt[0] << '\t' << pt[1] << '\n'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be 4U, because of signedness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is your motivation? I do not understand why it should be unsigned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I get warnings of signed/unsigned comparisons. Sorry I should've been clearer on this...