]> git.mar77i.info Git - bigintmandel/blob - mandel.cpp
make zoom_factor part of MandelSettings
[bigintmandel] / mandel.cpp
1
2 /*
3 * mandel.cpp
4 *
5 * This file is covered by the LICENSE file in the root of this project.
6 */
7
8 #include <QFile>
9 #include <QJsonArray>
10 #include <QJsonDocument>
11
12 #include "colors.h"
13 #include "mandel.h"
14
15 static inline const MpzPoint calculate_offset(
16 const MpzPoint center_f, const QSize size
17 ) {
18 return MpzPoint(
19 center_f.get_x() - size.width() / 2,
20 center_f.get_y() + size.height() / 2
21 );
22 }
23
24 MandelParams::MandelParams() {}
25 MandelParams::MandelParams(
26 quint64 max_iter,
27 QSize size,
28 MpzPoint center_f,
29 mpz_class one
30 ) : max_iter(max_iter),
31 size(size),
32 center_f(center_f),
33 offset(calculate_offset(center_f, size)),
34 one(one) {}
35 MandelParams::MandelParams(const MandelParams &other)
36 : max_iter(other.max_iter),
37 size(other.size),
38 center_f(other.center_f),
39 offset(calculate_offset(other.center_f, other.size)),
40 one(other.one) {}
41
42 void MandelParams::set_size(const QSize &size) {
43 this->size = size;
44 this->offset = calculate_offset(center_f, size);
45 }
46
47 MandelParams MandelParams::from_json(const QJsonObject &json) {
48 return MandelParams(
49 json["max_iter"].toString().toULongLong(),
50 QSize(json["size_w"].toInt(), json["size_h"].toInt()),
51 MpzPoint(
52 mpz_class(json["center_f_x"].toString().toStdString()),
53 mpz_class(json["center_f_y"].toString().toStdString())
54 ),
55 mpz_class(json["one"].toString().toStdString())
56 );
57 }
58
59 QJsonObject MandelParams::to_json() const {
60 QJsonObject json;
61 json["max_iter"] = QString::number(max_iter);
62 json["size_w"] = size.width();
63 json["size_h"] = size.height();
64 json["center_f_x"] = QString::fromStdString(center_f.get_x().get_str());
65 json["center_f_y"] = QString::fromStdString(center_f.get_y().get_str());
66 json["one"] = QString::fromStdString(one.get_str());
67 return json;
68 }
69
70 static inline void incrpos(QPoint &pos, const int width) {
71 pos.setX(pos.x() + 1);
72 if (pos.x() == width) {
73 pos.setX(0);
74 pos.setY(pos.y() + 1);
75 }
76 }
77
78 static inline void setup_cells(
79 QVector<MandelCell> &cells, const MandelParams *current
80 ) {
81 QSize size = current->get_size();
82 QVector<MandelCell>::iterator i;
83 QPoint pos;
84
85 cells.resize(size.width() * size.height(), MandelCell(current));
86 for (i = cells.begin(); i != cells.end(); incrpos(pos, size.width()), i++)
87 i->setup(pos);
88 }
89
90 static inline QImage *setup_image(QImage *img, const QSize &size) {
91 if(!img || img->size() != size) {
92 delete img;
93 img = new QImage(size, QImage::Format_RGB888);
94 }
95 img->fill(Qt::GlobalColor::black);
96 return img;
97 }
98
99 MandelSettings::MandelSettings(quint64 max_iter, const QSize size)
100 : img(nullptr) {
101 reset(max_iter, size);
102 }
103
104 void MandelSettings::clear() {
105 img = setup_image(img, params.get_size());
106 img->fill(Qt::GlobalColor::black);
107 setup_cells(cells, &params);
108 }
109
110 void MandelSettings::zoom(const QSize size, int zoom_factor, const QPoint pos) {
111 MpzPoint p = cells[img->width() * pos.y() + pos.x()].get_rpos0();
112 params = MandelParams(
113 params.get_max_iter(),
114 size,
115 MpzPoint(p.get_x() * zoom_factor, p.get_y() * zoom_factor),
116 params.get_one() * zoom_factor
117 );
118 clear();
119 }
120
121 void MandelSettings::finished_cell(int num, const MandelResultCell &result) {
122 cells[num].set_result(result);
123 if (!img)
124 return;
125 img->setPixelColor(cells[num].get_pos(), cells[num].get_color());
126 return;
127 (void)colors;
128 }
129
130 void MandelSettings::save_img(QString file_name) {
131 if (img)
132 img->save(file_name);
133 }
134
135 void MandelSettings::reset(quint64 max_iter, const QSize size) {
136 mpz_class one;
137 MpzPoint center_f;
138 int ione = std::min(size.width(), size.height()) / 3;
139 ione--;
140 ione |= ione >> 1;
141 ione |= ione >> 2;
142 ione |= ione >> 4;
143 ione |= ione >> 8;
144 ione |= ione >> 16;
145 one = mpz_class(ione + 1);
146 center_f = MpzPoint(one * -3 / 4, 0);
147 params = MandelParams(max_iter, size, center_f, one);
148 clear();
149 }
150
151 void MandelSettings::from_json(const QJsonObject &json) {
152 QJsonArray json_array;
153 int i;
154 params = MandelParams::from_json(json["params"].toObject());
155 json_array = json["cells"].toArray();
156 cells.resize(json_array.size(), MandelCell(&params));
157 img = setup_image(img, params.get_size());
158 for (i = 0; i < json_array.size(); i++)
159 finished_cell(i, cells[i].from_json(json_array[i].toObject()));
160 }
161
162 QJsonObject MandelSettings::to_json() {
163 QJsonArray c;
164 QJsonObject json;
165 QVector<MandelCell>::iterator i;
166 json["params"] = params.to_json();
167 for (i = cells.begin(); i != cells.end(); i++)
168 c.append(i->to_json());
169 json["cells"] = c;
170 return json;
171 }
172
173 MandelCell::MandelCell(const MandelParams *params) : params(params) {}
174 MandelCell::MandelCell(const MandelCell &cell)
175 : params(cell.params),
176 pos(cell.pos),
177 result(cell.result),
178 rpos0(cell.rpos0) {}
179
180 void MandelCell::setup(const QPoint pos) {
181 const MpzPoint &offset = params->get_offset();
182 this->pos = pos;
183 rpos0 = MpzPoint(offset.get_x() + pos.x(), offset.get_y() - pos.y());
184 result = MandelResultCell();
185 }
186
187 MandelResultCell MandelCell::iterate() const {
188 MpzPoint rpos = result.get_rpos(), sq;
189 mpz_class one = params->get_one(), four = one * one * 4;
190 mpz_class sqx, sqy;
191 quint64 iter = result.get_iter();
192 for (; iter < params->get_max_iter(); iter++) {
193 sqx = rpos.get_x() * rpos.get_x();
194 sqy = rpos.get_y() * rpos.get_y();
195 if (sqx + sqy > four)
196 break;
197 rpos = MpzPoint(
198 (sqx - sqy) / one + rpos0.get_x(),
199 rpos.get_x() * rpos.get_y() * 2 / one + rpos0.get_y()
200 );
201 }
202 return MandelResultCell(iter, rpos);
203 }
204
205 MandelResultCell MandelCell::from_json(const QJsonObject &json) {
206 this->pos = QPoint(json["pos_x"].toInt(), json["pos_y"].toInt());
207 this->rpos0 = MpzPoint(
208 mpz_class(json["rpos0_x"].toString().toStdString()),
209 mpz_class(json["rpos0_y"].toString().toStdString())
210 );
211 return MandelResultCell(
212 json["iter"].toString().toULongLong(),
213 MpzPoint(
214 mpz_class(json["rpos_x"].toString().toStdString()),
215 mpz_class(json["rpos_y"].toString().toStdString())
216 )
217 );
218 }
219
220 QJsonObject MandelCell::to_json() const {
221 const MpzPoint rpos(result.get_rpos());
222 QJsonObject json;
223 json["pos_x"] = pos.x();
224 json["pos_y"] = pos.y();
225 json["rpos0_x"] = QString::fromStdString(rpos0.get_x().get_str());
226 json["rpos0_y"] = QString::fromStdString(rpos0.get_y().get_str());
227 json["iter"] = QString::number(result.get_iter());
228 json["rpos_x"] = QString::fromStdString(rpos.get_x().get_str());
229 json["rpos_y"] = QString::fromStdString(rpos.get_y().get_str());
230 return json;
231 }