1 // ---------------------------------------------------------------------
2 // plot_xy.cxx
3 //
4 // Copyright (C) 2019
5 // David Freese, W1HKJ
6 //
7 // This is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This software is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
19 // ---------------------------------------------------------------------
20
21 #include <iostream>
22 #include <cmath>
23 #include <cstring>
24
25 #include "plot_xy.h"
26
plot_xy(int X,int Y,int W,int H,const char * lbl)27 plot_xy::plot_xy (int X, int Y, int W, int H, const char *lbl) :
28 Fl_Widget (X, Y, W, H, lbl)
29 {
30
31 _bk_color = FL_BACKGROUND2_COLOR;
32 _axis_color = FL_BLACK;
33 _color_1 = FL_DARK_RED;
34 _color_2 = FL_GREEN;
35 _legend_color = FL_BLACK;
36
37 color(_bk_color);
38
39 _len_1 = PLOT_XY_MAX_LEN;
40 _len_2 = PLOT_XY_MAX_LEN;
41
42 buf_1 = new PLOT_XY[PLOT_XY_MAX_LEN];
43 buf_2 = new PLOT_XY[PLOT_XY_MAX_LEN];
44
45 xmin = 0; xmax = 10.0; x_graticule = 2.0;
46 ymin = 0; ymax = 10.0; y_graticule = 2.0;
47
48 x_legend = y_legend = true;
49 sx_legend.clear();
50 sy_legend.clear();
51
52 _show_1 = true;
53 _show_2 = true;
54
55 _thick_lines = false;
56 }
57
~plot_xy()58 plot_xy::~plot_xy()
59 {
60 delete [] buf_1;
61 delete [] buf_2;
62 }
63
data_1(PLOT_XY * data,int len)64 void plot_xy::data_1(PLOT_XY *data, int len)
65 {
66 if (data == 0 || len == 0) {
67 for (int n = 0; n < PLOT_XY_MAX_LEN; n++) {
68 buf_1[n].x = 0;
69 buf_1[n].y = ymax * 2;
70 }
71 _len_1 = 0;
72 } else {
73 _len_1 = (len > PLOT_XY_MAX_LEN ) ? PLOT_XY_MAX_LEN : len;
74 for (int n = 0; n < _len_1; n++)
75 buf_1[PLOT_XY_MAX_LEN - _len_1 + n] = data[n];
76 }
77 }
78
data_2(PLOT_XY * data,int len)79 void plot_xy::data_2(PLOT_XY *data, int len)
80 {
81 if (data == 0 || len == 0) {
82 for (int n = 0; n < PLOT_XY_MAX_LEN; n++) {
83 buf_2[n].x = 0;
84 buf_2[n].y = ymax * 2;
85 }
86 _len_2 = 0;
87 } else {
88 _len_2 = (len > PLOT_XY_MAX_LEN ) ? PLOT_XY_MAX_LEN : len;
89 for (int n = 0; n < _len_2; n++)
90 buf_2[PLOT_XY_MAX_LEN - _len_2 + n] = data[n];
91 }
92 }
93
draw()94 void plot_xy::draw()
95 {
96 draw_box();
97
98 int X, Y, W, H;
99 X = x() + 2;
100 Y = y() + 2;
101 W = w() - 4;
102 H = h() - 4;
103
104 fl_clip(X, Y, W, H);
105 fl_color(_bk_color);
106 fl_rectf(X, Y, W, H);
107
108 fl_push_matrix();
109
110 if (y_legend) {
111 X += 45;
112 W -= 50;
113 } else {
114 X += 5;
115 W -= 10;
116 }
117 if (x_legend) {
118 Y += 10;
119 H -= 30;
120 } else {
121 Y += 5;
122 H -= 10;
123 }
124
125 fl_translate( X, (Y + H));
126 fl_scale (1.0 * W / (xmax - xmin), -1.0 * H / (ymax - ymin));
127
128 // horizontal & vertical grids
129 fl_line_style(FL_SOLID, 0, NULL);
130 fl_color(_axis_color);
131
132 // vertical graticules
133 for (int n = 0; n <= x_graticule; n++) {
134 fl_begin_line();
135 fl_vertex((xmax - xmin)*n/x_graticule, 0);
136 fl_vertex((xmax - xmin)*n/x_graticule, (ymax - ymin));
137 fl_end_line();
138 }
139 // horizontal graticules
140 for (int n = 0; n <= y_graticule; n++) {
141 fl_begin_line();
142 fl_vertex(0, (ymax - ymin)*n/y_graticule);
143 fl_vertex((xmax-xmin), (ymax - ymin)*n/y_graticule);
144 fl_end_line();
145 }
146
147 // data
148 float xp, yp, xp1, yp1;
149 xp = 0; yp = 0;
150 xp1 = 1.0; yp1 = 1.0;
151
152 int xs = 0;
153
154
155 // line 1
156 if (_show_1) {
157 xs = PLOT_XY_MAX_LEN - _len_1;
158 fl_color(_color_1);
159 yp = buf_1[xs].y;
160 xp = buf_1[xs].x;
161 for (int i = 1; i < _len_1; i++) {
162 yp1 = buf_1[xs + i].y;
163 xp1 = buf_1[xs + i].x;
164 if (yp == 0 && yp1 == 0 && !_plot_over_axis) {
165 fl_color (_axis_color);
166 fl_line_style(FL_SOLID, 0, NULL);
167 } else {
168 fl_color (_color_1);
169 if (_thick_lines)
170 fl_line_style(FL_SOLID, 2, NULL);
171 }
172 if (yp > ymin && yp < ymax && yp1 > ymin && yp1 < ymax) {
173 fl_begin_line();
174 if (xreverse) {
175 fl_vertex(xmax - xp, yp - ymin);
176 fl_vertex(xmax - xp1, yp - ymin);
177 } else {
178 fl_vertex(xp - xmin, yp - ymin);
179 fl_vertex(xp1 - xmin, yp1 - ymin);
180 }
181 fl_end_line();
182 }
183 xp = xp1; yp = yp1;
184 }
185 }
186
187 // line 2
188 if (_show_2) {
189 xs = PLOT_XY_MAX_LEN - _len_2;
190 fl_color(_color_2);
191 yp = buf_2[xs].y;
192 xp = buf_2[xs].x;
193 for (int i = 1; i < _len_2; i++) {
194 yp1 = buf_2[xs + i].y;
195 xp1 = buf_2[xs + i].x;
196 if (yp == 0 && yp1 == 0 && !_plot_over_axis) {
197 fl_color (_axis_color);
198 fl_line_style(FL_SOLID, 0, NULL);
199 } else {
200 fl_color (_color_2);
201 if (_thick_lines)
202 fl_line_style(FL_SOLID, 2, NULL);
203 }
204 if (yp > ymin && yp < ymax && yp1 > ymin && yp1 < ymax) {
205 fl_begin_line();
206 if (xreverse) {
207 fl_vertex(xmax - xp, yp - ymin);
208 fl_vertex(xmax - xp1, yp - ymin);
209 } else {
210 fl_vertex(xp - xmin, yp - ymin);
211 fl_vertex(xp1 - xmin, yp1 - ymin);
212 }
213 fl_end_line();
214 }
215 xp = xp1; yp = yp1;
216 }
217 }
218
219 fl_pop_matrix();
220
221 fl_line_style(FL_SOLID, 0, NULL);
222
223 // legends
224 fl_color(_legend_color);
225 fl_font(FL_COURIER, 12);
226 int lbl_w = fl_width("XX") + 2;
227 int lbl_h = fl_height();
228
229 if (x_legend && !sx_legend.empty()) {
230 std::string tmp = sx_legend;
231 std::string lgnd;
232
233 float xd = 0, yd = Y + H + 20 - lbl_h/2;
234 size_t p = tmp.find("|");
235 for (int n = 0; n <= x_graticule; n++) {
236 if (tmp.empty()) break;
237 lgnd = tmp.substr(0,p);
238 lbl_w = fl_width(lgnd.c_str());
239 if (xreverse)
240 xd = X + W - n * W / x_graticule - lbl_w / 2;
241 else
242 xd = X + n * W / x_graticule - lbl_w / 2;
243 if (lgnd != " ")
244 fl_draw(lgnd.c_str(), xd, yd);
245 tmp.erase(0, p+1);
246 p = tmp.find("|");
247 }
248 }
249
250 if (y_legend && !sy_legend.empty()) {
251 std::string tmp = sy_legend;
252 size_t p = tmp.find("|");
253 std::string lgnd;
254 float xd, yd;
255 for (int n = 0; n <= y_graticule; n++) {
256 if (tmp.empty()) break;
257 lgnd = tmp.substr(0,p);
258 lbl_w = fl_width(lgnd.c_str());
259 xd = X - lbl_w - 4; yd = Y + H * (1 - n / y_graticule) + lbl_h / 3;
260 if (lgnd != " ")
261 fl_draw(lgnd.c_str(), xd, yd);
262 tmp.erase(0, p+1);
263 p = tmp.find("|");
264 }
265 }
266
267 fl_pop_clip();
268
269 }
270
handle(int event)271 int plot_xy::handle(int event)
272 {
273 if (!Fl::event_inside(this))
274 return 0;
275 return 1;
276 }
277
resize(int x,int y,int w,int h)278 void plot_xy::resize(int x, int y, int w, int h)
279 {
280 Fl_Widget::resize(x, y, w, h);
281 }
282