Kronecker product based fractals: Difference between revisions
Content deleted Content added
SqrtNegInf (talk | contribs) m →{{header|Sidef}}: Fix link: Perl 6 --> Raku |
Added C++ solution |
||
Line 294: | Line 294: | ||
} |
} |
||
</lang> |
</lang> |
||
=={{header|C++}}== |
|||
{{libheader|Qt}} |
|||
This program produces image files in PNG format. The C++ code from [[Kronecker product| Kronecker product]] is reused here. |
|||
<lang cpp>#include <cassert> |
|||
#include <vector> |
|||
#include <QImage> |
|||
template <typename scalar_type> class matrix { |
|||
public: |
|||
matrix(size_t rows, size_t columns) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) {} |
|||
matrix(size_t rows, size_t columns, |
|||
const std::initializer_list<std::initializer_list<scalar_type>>& values) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) { |
|||
assert(values.size() <= rows_); |
|||
size_t i = 0; |
|||
for (const auto& row : values) { |
|||
assert(row.size() <= columns_); |
|||
std::copy(begin(row), end(row), row_data(i++)); |
|||
} |
|||
} |
|||
size_t rows() const { return rows_; } |
|||
size_t columns() const { return columns_; } |
|||
scalar_type* row_data(size_t row) { |
|||
assert(row < rows_); |
|||
return &elements_[row * columns_]; |
|||
} |
|||
const scalar_type* row_data(size_t row) const { |
|||
assert(row < rows_); |
|||
return &elements_[row * columns_]; |
|||
} |
|||
const scalar_type& at(size_t row, size_t column) const { |
|||
assert(column < columns_); |
|||
return row_data(row)[column]; |
|||
} |
|||
scalar_type& at(size_t row, size_t column) { |
|||
assert(column < columns_); |
|||
return row_data(row)[column]; |
|||
} |
|||
private: |
|||
size_t rows_; |
|||
size_t columns_; |
|||
std::vector<scalar_type> elements_; |
|||
}; |
|||
// See https://en.wikipedia.org/wiki/Kronecker_product |
|||
template <typename scalar_type> |
|||
matrix<scalar_type> kronecker_product(const matrix<scalar_type>& a, |
|||
const matrix<scalar_type>& b) { |
|||
size_t arows = a.rows(); |
|||
size_t acolumns = a.columns(); |
|||
size_t brows = b.rows(); |
|||
size_t bcolumns = b.columns(); |
|||
size_t rows = arows * brows; |
|||
size_t columns = acolumns * bcolumns; |
|||
matrix<scalar_type> c(rows, columns); |
|||
for (size_t i = 0; i < rows; ++i) { |
|||
auto* crow = c.row_data(i); |
|||
auto* arow = a.row_data(i/brows); |
|||
auto* brow = b.row_data(i % brows); |
|||
for (size_t j = 0; j < columns; ++j) |
|||
crow[j] = arow[j/bcolumns] * brow[j % bcolumns]; |
|||
} |
|||
return c; |
|||
} |
|||
bool kronecker_fractal(const char* fileName, const matrix<unsigned char>& m, int order) { |
|||
matrix<unsigned char> result = m; |
|||
for (int i = 0; i < order; ++i) |
|||
result = kronecker_product(result, m); |
|||
size_t height = result.rows(); |
|||
size_t width = result.columns(); |
|||
size_t bytesPerLine = 4 * ((width + 3)/4); |
|||
std::vector<uchar> imageData(bytesPerLine * height); |
|||
for (size_t i = 0; i < height; ++i) |
|||
std::copy_n(result.row_data(i), width, &imageData[i * bytesPerLine]); |
|||
QImage image(&imageData[0], width, height, bytesPerLine, QImage::Format_Indexed8); |
|||
QVector<QRgb> colours(2); |
|||
colours[0] = qRgb(0, 0, 0); |
|||
colours[1] = qRgb(255, 255, 255); |
|||
image.setColorTable(colours); |
|||
return image.save(fileName); |
|||
} |
|||
int main() { |
|||
matrix<unsigned char> matrix1(3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}); |
|||
matrix<unsigned char> matrix2(3, 3, {{1,1,1}, {1,0,1}, {1,1,1}}); |
|||
matrix<unsigned char> matrix3(2, 2, {{1,1}, {0,1}}); |
|||
kronecker_fractal("vicsek.png", matrix1, 5); |
|||
kronecker_fractal("sierpinski_carpet.png", matrix2, 5); |
|||
kronecker_fractal("sierpinski_triangle.png", matrix3, 8); |
|||
return 0; |
|||
}</lang> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |