1 /*
2 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3 *
4 * See the LICENSE file for terms of use.
5 */
6
7 #include <algorithm>
8 #include <cmath>
9 #include <stdio.h>
10 #include <fstream>
11 #include <iostream>
12
13 #include <Wt/WResource.h>
14 #include <Wt/WImage.h>
15 #include <Wt/WPainter.h>
16 #include <Wt/WPen.h>
17 #include <Wt/WRasterImage.h>
18 #include <Wt/Http/Response.h>
19
20 #include "MandelbrotImage.h"
21
22 namespace {
23 class MandelbrotResource : public WResource
24 {
25 public:
MandelbrotResource(MandelbrotImage * img,int64_t x,int64_t y,int w,int h)26 MandelbrotResource(MandelbrotImage *img,
27 int64_t x, int64_t y, int w, int h)
28 : img_(img),
29 x_(x), y_(y), w_(w), h_(h)
30 { }
31
~MandelbrotResource()32 virtual ~MandelbrotResource() {
33 beingDeleted();
34 }
35
handleRequest(const Http::Request & request,Http::Response & response)36 void handleRequest(const Http::Request& request,
37 Http::Response& response) {
38 WRasterImage image("png", w_, h_);
39 img_->generate(x_, y_, &image);
40 image.handleRequest(request, response);
41 }
42
43 private:
44 MandelbrotImage *img_;
45 int64_t x_, y_;
46 int w_, h_;
47 };
48 }
49
MandelbrotImage(int width,int height,int64_t virtualWidth,int64_t virtualHeight,double bx1,double by1,double bx2,double by2)50 MandelbrotImage::MandelbrotImage(int width, int height,
51 int64_t virtualWidth,
52 int64_t virtualHeight,
53 double bx1, double by1,
54 double bx2, double by2)
55 : WVirtualImage(width, height, virtualWidth, virtualHeight, 256),
56 bx1_(bx1), by1_(by1),
57 bwidth_(bx2 - bx1), bheight_(by2 - by1),
58 maxDepth_(50),
59 bailOut2_(30*30)
60 {
61 enableDragging();
62 redrawAll();
63 scroll(width*2, virtualHeight/2 - height);
64 }
65
zoomIn()66 void MandelbrotImage::zoomIn()
67 {
68 resizeImage(imageWidth() * 2, imageHeight() * 2);
69
70 scrollTo(currentTopLeftX() * 2 + viewPortWidth()/2,
71 currentTopLeftY() * 2 + viewPortHeight()/2);
72 }
73
zoomOut()74 void MandelbrotImage::zoomOut()
75 {
76 scrollTo(currentTopLeftX() / 2 - viewPortWidth()/4,
77 currentTopLeftY() / 2 - viewPortHeight()/4);
78
79 resizeImage(std::max((int64_t)viewPortWidth(), imageWidth() / 2),
80 std::max((int64_t)viewPortHeight(), imageHeight() / 2));
81 }
82
render(int64_t x,int64_t y,int w,int h)83 std::unique_ptr<WResource> MandelbrotImage::render(int64_t x, int64_t y, int w, int h)
84 {
85 return std::make_unique<MandelbrotResource>(this, x, y, w, h);
86 }
87
generate(int64_t x,int64_t y,WRasterImage * img)88 void MandelbrotImage::generate(int64_t x, int64_t y, WRasterImage *img)
89 {
90 int w = img->width().toPixels();
91 int h = img->height().toPixels();
92
93 std::cerr << "rendering: (" << x << "," << y << ") ("
94 << x+w << "," << y+h << ")" << std::endl;
95
96 for (int i = 0; i < w; ++i)
97 for (int j = 0; j < h; ++j) {
98 double bx = convertPixelX(x + i);
99 double by = convertPixelY(y + j);
100 double d = calcPixel(bx, by);
101
102 int lowr = 100;
103
104 int r, g, b;
105 if (d == maxDepth_)
106 r = g = b = 0;
107 else {
108 r = lowr + (int)((d * (255-lowr))/maxDepth_);
109 g = 0 + (int)((d * 255)/maxDepth_);
110 b = 0;
111 }
112
113 img->setPixel(i, j, WColor(r, g, b));
114 }
115
116 img->done();
117 }
118
convertPixelX(int64_t x)119 double MandelbrotImage::convertPixelX(int64_t x) const
120 {
121 return bx1_ + ((double) (x) / imageWidth() * bwidth_);
122 }
123
convertPixelY(int64_t y)124 double MandelbrotImage::convertPixelY(int64_t y) const
125 {
126 return by1_ + ((double) (y) / imageHeight() * bheight_);
127 }
128
currentX1()129 double MandelbrotImage::currentX1() const
130 {
131 return convertPixelX(currentTopLeftX());
132 }
133
currentY1()134 double MandelbrotImage::currentY1() const
135 {
136 return convertPixelY(currentTopLeftY());
137 }
138
currentX2()139 double MandelbrotImage::currentX2() const
140 {
141 return convertPixelX(currentBottomRightX());
142 }
143
currentY2()144 double MandelbrotImage::currentY2() const
145 {
146 return convertPixelY(currentBottomRightY());
147 }
148
calcPixel(double x,double y)149 double MandelbrotImage::calcPixel(double x, double y)
150 {
151 double x1 = x;
152 double y1 = y;
153
154 for (int i = 0; i < maxDepth_; ++i) {
155 double xs = x1 * x1;
156 double ys = y1 * y1;
157 double x2 = xs - ys + x;
158 double y2 = x1 * y1 * 2 + y;
159 x1 = x2;
160 y1 = y2;
161
162 double z = xs + ys;
163
164 if (xs + ys > bailOut2_)
165 return (double)i + 1 - log(log(sqrt(z)))/log(2.0);
166 }
167
168 return maxDepth_;
169 }
170