Do the hillshading in alpha layer only
[GPXSee.git] / src / map / hillshading.cpp
blob75d3d0e6ac0959ba543a937c53ea6287138ef965
1 #include <cmath>
2 #include "hillshading.h"
4 struct Constants
6 double a1;
7 double a2;
8 double a3;
9 };
11 struct SubMatrix
13 double z1;
14 double z2;
15 double z3;
16 double z4;
17 double z6;
18 double z7;
19 double z8;
20 double z9;
23 struct Derivatives
25 double dzdx;
26 double dzdy;
29 static void getConstants(double azimuth, double elevation, Constants &c)
31 double alpha = (M_PI / 180.0) * azimuth;
32 double beta = (M_PI / 180.0) * elevation;
34 c.a1 = sin(beta);
35 c.a2 = cos(beta) * sin(alpha);
36 c.a3 = cos(beta) * cos(alpha);
39 static void getDerivativesHorn(const SubMatrix &sm, double z, Derivatives &d)
41 d.dzdx = (z * (sm.z3 + 2 * sm.z6 + sm.z9 - sm.z1 - 2 * sm.z4 - sm.z7)) / 8;
42 d.dzdy = (z * (sm.z1 + 2 * sm.z2 + sm.z3 - sm.z7 - 2 * sm.z8 - sm.z9)) / 8;
45 static void getSubmatrix(int x, int y, const Matrix &m, SubMatrix &sm)
47 int left = x - 1;
48 int right = x + 1;
49 int top = y - 1;
50 int bottom = y + 1;
52 sm.z1 = m.m(top, left);
53 sm.z2 = m.m(top, x);
54 sm.z3 = m.m(top, right);
55 sm.z4 = m.m(y, left);
56 sm.z6 = m.m(y, right);
57 sm.z7 = m.m(bottom, left);
58 sm.z8 = m.m(bottom, x);
59 sm.z9 = m.m(bottom, right);
62 QImage HillShading::render(const Matrix &m, quint8 alpha, double z,
63 double azimuth, double elevation)
65 QImage img(m.w() - 2, m.h() - 2, QImage::Format_ARGB32_Premultiplied);
66 uchar *bits = img.bits();
67 int bpl = img.bytesPerLine();
69 Constants c;
70 SubMatrix sm;
71 Derivatives d;
73 getConstants(azimuth, elevation, c);
75 for (int y = 1; y < m.h() - 1; y++) {
76 for (int x = 1; x < m.w() - 1; x++) {
77 getSubmatrix(x, y, m, sm);
78 getDerivativesHorn(sm, z, d);
80 double L = (c.a1 - c.a2 * d.dzdx - c.a3 * d.dzdy)
81 / sqrt(1.0 + d.dzdx * d.dzdx + d.dzdy * d.dzdy);
83 quint32 pixel;
84 if (std::isnan(L))
85 pixel = 0;
86 else {
87 quint8 val = (L < 0) ? 0 : L * alpha;
88 pixel = (alpha - val)<<24;
91 *(quint32*)(bits + (y - 1) * bpl + (x - 1) * 4) = pixel;
95 return img;