Fixed text file permissions
[snark14.git] / tools / Display / line_window_onevar_t.cpp
1 /** @file line_window_onevar_t.cpp
2     @author Deniz
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
6 */
7
8 #include <iostream>
9 #include <list>
10 #include <stdexcept>
11 #include <exception>
12
13 #include "verbosity.hpp"
14 #include "sd_line_t.hpp"
15 #include "line_real_t.hpp"
16 #include "line_window_onevar_t.hpp"
17
18 typedef std::list<line_window_t> data_onevar_t;
19
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. 
27 */
28
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!                                   *
38  */
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;
42   }
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");
46   }
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
52   }
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;
62   }
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;
67   }
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
73   }
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...
88   int xw, yw;
89   double xr;  // , yr;
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)
96   // in general:
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;
105     return;
106   }
107   // first real point gets 'special treatment' in that it has no previous data point
108   cr_x = it->x;
109   if(cr_x > xrmax) return; // nothing will be within range, x's increasing
110   cr_y = it->y;
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)) {
115     it++;
116     cr_x = it->x;
117     cr_y = it->y;
118     cur_r_low  = (cr_y < yrmin);
119     cur_r_high = (cr_y > yrmax);
120   }
121   if(cr_x < xrmin) {
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;
124     }
125     return; // nothing was within range
126   }
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!
129   if(cr_x > xrmax) {
130     if(std::verbose > 1) {
131       std::cerr << "in line_window_onevar_t ctor: But this is impossible!" << std::endl;
132     }
133     return;
134   }
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));
139     LW.add(xw, yw);
140   }
141   it++; // now do all the other points!
142   for(; it != line_real.data.end(); it++) {
143     pr_x = cr_x;
144     pr_y = cr_y;
145     prev_r_low = cur_r_low;
146     prev_r_high = cur_r_high;
147     cr_x = it->x;
148     if(cr_x > xrmax) break; // this one is fine: we won't look at the rest of the data...
149     cr_y = it->y;
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
168         LW.clear();
169       } else { // 1.3
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));
178         LW.add(xw,yw);
179       }
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
190         LW.clear();
191       } else if(cur_r_high) { // 2.2
192         // do nothing! (except to set prev eq to cur, which happens near the closing brace)
193       } else { // 2.3
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));
201         LW.add(xw,yw);
202       }
203     } else { // 3
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
211         LW.clear();
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
218         LW.clear();
219       } else { // 3.3
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));
223         LW.add(xw,yw);
224       }
225     }
226   } // --for
227   // flush if LW is non-empty
228   if(!LW.empty()) {
229     data.push_back(LW);
230   }
231   else {
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.
234   }
235   if(std::verbose > 2) {
236     std::cerr << std::endl << "line_window_onevar_t ctor--" << std::endl;
237   }
238 } // -- line_window_onevar_t constructor, might just be the longest constructor ever written
239
240
241 bool line_window_onevar_t::empty() { return data.empty(); }  // --line_window_onevar_t::empty()
242
243
244 QString line_window_onevar_t::getName() { return plotname; } // --line_window_onevar_t::getName()
245
246
247 //    void add(line_window_t& LW) {
248 //      data.push_back(LW);
249 //    } // --line_window_onevar_t::add()
250
251
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++) {
255     it->plot(P, C, Ps);
256   }
257 } // --line_window_onevar_t::plot()
258
259
260 void line_window_onevar_t::show() {
261   for(data_onevar_t::iterator it = data.begin();
262       it != data.end(); it++) {
263     it->show();
264   }
265   std::cerr << std::endl;
266 }