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