1 /** @file line_window_onevar_t.cpp
3 @description implementation of functions in line_window_onevar_t
4 licensed under (open-source) QPL v1.0
5 which accompanies this distribution in the file QPL
13 #include "verbosity.hpp"
14 #include "sd_line_t.hpp"
15 #include "line_real_t.hpp"
16 #include "line_window_onevar_t.hpp"
18 typedef std::list<line_window_t> data_onevar_t;
20 /** class line_window_onevar_t
21 corresponds to a set of maybe disconnected (due to falling out of window boundaries)
22 segments for a single variable, due to single execution
23 All these hacks are due to a bug i found in QT API (both versions)
24 when plotting big numbers: now being superparanoid to drawLine() ONLY within the window,
25 which is not necessarily as precise but at least guarantees that
26 there will be lines when there should be.
29 /** constuctor/1 takes one line with real coords, potentially makes many point sets from it *
30 * pre: line_real has at least 1 point *
31 * pre: x values in line_real are strictly increasing (as is the case in snark14 eval output) *
32 * (as well as in column/row profiles?) i believe those are not even given as (x,y) (yet) *
33 * trusts Painter::drawLine() with between interior and JUST outside the paint window. *
34 * this is where conversion from reals to window coords actually happens *
35 * 2004 version WAS TOO SIMPLE MINDED. *
36 * even if both points are out of range, we still want to see a line, *
37 * without there being an inside-the-box first point! *
39 line_window_onevar_t::line_window_onevar_t(line_real_t& line_real) {
40 if(std::verbose > 2) {
41 std::cerr << std::endl << "line_window_onevar_t ctor++" << std::endl;
43 if(line_real.empty()) {
44 std::cerr << ("Empty line passed to line_window_onevar_t constructor/3");
45 throw std::runtime_error("Empty line passed to line_window_onevar_t constructor/3");
47 // XWINPAD and YWINPAD are defined consts (int)
48 if ((3*sd_line_t::XWINPAD > sd_line_t::WIDTH) || (3*sd_line_t::YWINPAD > sd_line_t::HEIGHT)) {
49 std::cerr << "PADDING WITHIN WINDOW IS HUGE! ADJUST XWINPAD / YWINPAD, codeur!" << std::endl;
50 throw std::logic_error("in line_window_onevar_t ctor, too huge padding wrt W/H");
51 // this is why it's a bad idea to let the user set WIDTH and HEIGHT
53 plotname = line_real.getName();
54 int xrmin = line_real.getMinX(); // "x real min" etc. real as opposed to window coords
55 int xrmax = line_real.getMaxX();
56 double yrmin = line_real.getMinY();
57 double yrmax = line_real.getMaxY();
58 // perform fudging defensively
59 if(0 < sd_line_t::X_HALF_FUDGE_INCREMENT) {
60 xrmin -= sd_line_t::X_HALF_FUDGE_INCREMENT;
61 xrmax += sd_line_t::X_HALF_FUDGE_INCREMENT;
63 int xr_range = xrmax - xrmin; // underscore between r's for emphasis
64 double yr_range = yrmax - yrmin;
65 if(std::verbose > 2) {
66 std::cerr << "xr_range: " << xr_range << ", yr_range: " << yr_range << std::endl;
68 if(0 < sd_line_t::Y_HALF_FUDGE_FACTOR) {
69 double y_half_fudge = yr_range * sd_line_t::Y_HALF_FUDGE_FACTOR;
70 yrmin -= y_half_fudge;
71 yrmax += y_half_fudge;
72 yr_range = yrmax - yrmin; // calculate post-fudge yr_range
74 // convert to lattice points of [XWINPAD, WIDTH-XWINPAD) x [YWINPAD, HEIGHT-YWINPAD)
75 // NB: y reverses direction
76 int cr_x, pr_x; // current and previous real x's
77 double cr_y, pr_y; // current and previous real y's
78 int xwmin = sd_line_t::XWINPAD;
79 // int xwmax = WIDTH - 1 - XWINPAD;
80 int xwrange = sd_line_t::WIDTH - 1 - 2*sd_line_t::XWINPAD;
81 int ywmin = sd_line_t::YWINPAD;
82 // the following can be very slightly out of range: trust Qt to be OK with it
83 int ywmax = sd_line_t::HEIGHT - 1 - sd_line_t::YWINPAD;
84 int ywrange = ywmax - ywmin;
85 double yscalar = static_cast<double>(ywrange) / yr_range;
86 double xscalar = static_cast<double>(xwrange) / static_cast<double>(xr_range);
87 line_window_t LW; // treated like scratch paper: fills up, pushed, emptied, filled again...
90 // xwrange corresponds to xr_range
91 // ywrange corresponds to yr_range
92 // the line (xr = xrmin) intersects the *left side* of (pixels with "x coordinate" xwmin)
93 // the line (xr = xrmax) intersects the *right side* of (pixels with "x coordinate" xwmax)
94 // the line (yr = yrmin) intersects the *bottom side* of (pixels with "y coordinate" ywmax)
95 // the line (yr = yrmax) intersects the *top side* of (pixels with "y coordinate" ywmax)
97 // xw = xwmin + static_cast<int> (xscalar * (xr - xrmin));
98 // yw = ywmin + static_cast<int> (yscalar * (yrmax - yr));
99 bool firstdatapoint = true;
100 bool firstpointwithinxrange = false;
101 bool prev_r_low, prev_r_high, cur_r_low, cur_r_high;
102 line_real_t::data_real_t::const_iterator it = line_real.data.begin();
103 if(it == line_real.data.end()) {
104 std::cerr << "line_window_onevar_t ctor: No data points... but checked for this already?" << std::endl;
107 // first real point gets 'special treatment' in that it has no previous data point
109 if(cr_x > xrmax) return; // nothing will be within range, x's increasing
111 cur_r_low = (cr_y < yrmin);
112 cur_r_high = (cr_y > yrmax);
113 // for loop will execute only as long as cur x is to the left
114 while((it != line_real.data.end()) && (cr_x < xrmin)) {
118 cur_r_low = (cr_y < yrmin);
119 cur_r_high = (cr_y > yrmax);
122 if(std::verbose > 1) {
123 std::cerr << "line_window_onevar_t ctor returning because everything was to the left of x range" << std::endl;
125 return; // nothing was within range
127 // since we started with less than x (otherwise would have returned)
128 // now cur x is within the range, since x range contains at least one x value!
130 if(std::verbose > 1) {
131 std::cerr << "in line_window_onevar_t ctor: But this is impossible!" << std::endl;
135 // now, we have the first data point whose real x is within range of interest
136 if(! (cur_r_low || cur_r_high)) {
137 xw = xwmin + static_cast<int> (xscalar * (cr_x - xrmin));
138 yw = ywmin + static_cast<int> (yscalar * (yrmax - cr_y));
141 it++; // now do all the other points!
142 for(; it != line_real.data.end(); it++) {
145 prev_r_low = cur_r_low;
146 prev_r_high = cur_r_high;
148 if(cr_x > xrmax) break; // this one is fine: we won't look at the rest of the data...
150 cur_r_low = (cr_y < yrmin);
151 cur_r_high = (cr_y > yrmax);
152 // from now on, lowness and highness only concerns y, until we run out, which is the end
153 // in general: 9 (3*3) possibilities
154 if(prev_r_low) { // 1
155 if(cur_r_low) { // 1.1
156 // do nothing! (except to set prev := cur, which happens near the closing brace)
157 } else if(cur_r_high) { // 1.2
158 // calculate two x-intercepts in between prev and cur... first the lower one
159 // "xr_intercept_low" is the x intercept of yrmin
160 double xr_intercept_low = (cr_x) - ((cr_y - yrmin ) * (cr_x - pr_x)) / (cr_y - pr_y);
161 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_low - xrmin));
162 LW.add(xw,ywmax); // ywmax <=> yrmin
163 // "xr_intercept_high" means the x intercept with yrmax
164 double xr_intercept_high = (cr_x) - ((cr_y - yrmax ) * (cr_x - pr_x)) / (cr_y - pr_y);
165 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_high - xrmin));
166 LW.add(xw,ywmin); // ywmin <=> yrmax
167 data.push_back(LW); // flush
170 // prev was low, cur gets us back in the game
171 // add x-intercept first, then cur.
172 double xr_intercept_low = (cr_x) - ((cr_y - yrmin ) * (cr_x - pr_x)) / (cr_y - pr_y);
173 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_low - xrmin));
174 LW.add(xw,ywmax); // ywmax <=> yrmin
175 // convert (cr_x, cr_y) to window coords
176 xw = xwmin + static_cast<int> (xscalar * (cr_x - xrmin));
177 yw = ywmin + static_cast<int> (yscalar * (yrmax - cr_y));
180 } else if(prev_r_high) { // 2
181 if(cur_r_low) { // 2.1
182 // calculate two x-intercepts in between prev and cur
183 double xr_intercept_high = (cr_x) - ((cr_y - yrmax ) * (cr_x - pr_x)) / (cr_y - pr_y);
184 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_high - xrmin));
185 LW.add(xw,ywmin); // ywmin is top of window
186 double xr_intercept_low = (cr_x) - ((cr_y - yrmin ) * (cr_x - pr_x)) / (cr_y - pr_y);
187 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_low - xrmin));
188 LW.add(xw,ywmax); // ywmax <=> yrmin
189 data.push_back(LW); // flush
191 } else if(cur_r_high) { // 2.2
192 // do nothing! (except to set prev eq to cur, which happens near the closing brace)
194 // prev was high, cur gets us back in the game
195 // add x-intercept first, then cur
196 double xr_intercept_high = (cr_x) - ((cr_y - yrmax ) * (cr_x - pr_x)) / (cr_y - pr_y);
197 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_high - xrmin));
198 LW.add(xw,ywmin); // ywmin <=> yrmax
199 xw = xwmin + static_cast<int> (xscalar * (cr_x - xrmin));
200 yw = ywmin + static_cast<int> (yscalar * (yrmax - cr_y));
204 if(cur_r_low) { // 3.1
205 // prev was OK: add new x-intercept (other point is yrmin aka ywmax) and flush
206 double xr_intercept_low = (cr_x) - ((cr_y - yrmin ) * (cr_x - pr_x)) / (cr_y - pr_y);
207 xr = xr_intercept_low;
208 xw = xwmin + static_cast<int> (xscalar * (xr - xrmin));
209 LW.add(xw,ywmax); // ywmax is bottom of window
210 data.push_back(LW); // flush
212 } else if(cur_r_high) { // 3.2
213 // prev was OK: add new x-intercept (other point is yrmax aka ywin) and flush
214 double xr_intercept_high = (cr_x) - ((cr_y - yrmax ) * (cr_x - pr_x)) / (cr_y - pr_y);
215 xw = xwmin + static_cast<int> (xscalar * (xr_intercept_high - xrmin));
216 LW.add(xw,ywmin); // ywmin <=> yrmax
217 data.push_back(LW); // flush
220 // simplicity itself: prev and cur both ok, just add cur to LW
221 xw = xwmin + static_cast<int> (xscalar * (cr_x - xrmin));
222 yw = ywmin + static_cast<int> (yscalar * (yrmax - cr_y));
227 // flush if LW is non-empty
232 /// std::cout << "WARNING: nothing generated by line_window_onevar_t ctor" << std::endl;
233 /// commented out because this can and does happen and it's ok.
235 if(std::verbose > 2) {
236 std::cerr << std::endl << "line_window_onevar_t ctor--" << std::endl;
238 } // -- line_window_onevar_t constructor, might just be the longest constructor ever written
241 bool line_window_onevar_t::empty() { return data.empty(); } // --line_window_onevar_t::empty()
244 QString line_window_onevar_t::getName() { return plotname; } // --line_window_onevar_t::getName()
247 // void add(line_window_t& LW) {
248 // data.push_back(LW);
249 // } // --line_window_onevar_t::add()
252 void line_window_onevar_t::plot(QPainter& P, QColor& C, Qt::PenStyle & Ps) {
253 for(data_onevar_t::iterator it = data.begin();
254 it != data.end(); it++) {
257 } // --line_window_onevar_t::plot()
260 void line_window_onevar_t::show() {
261 for(data_onevar_t::iterator it = data.begin();
262 it != data.end(); it++) {
265 std::cerr << std::endl;