comparison src/Modules/Output/Graphics/GraphicsView.cc @ 227:73c6d61440ad

- First add of a lot of graphics code from the old version. Not working yet, not even compiling yet.
author tomwalters
date Fri, 15 Oct 2010 05:40:53 +0000
parents 48e5fc566441
children 82e0dc3dfd16
comparison
equal deleted inserted replaced
226:eaeba1fd41e6 227:73c6d61440ad
13 // distributed under the License is distributed on an "AS IS" BASIS, 13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and 15 // See the License for the specific language governing permissions and
16 // limitations under the License. 16 // limitations under the License.
17 17
18 #include <algorithm>
19
20 #include "Support/Common.h" 18 #include "Support/Common.h"
21 19
22 #include "Modules/Output/Graphics/GraphicsView.h" 20 #include "Output/GraphicsView.h"
23 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" 21 #include "Output/GraphicsOutputDevice.h"
24 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
25
26 namespace aimc {
27 22
28 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) { 23 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) {
29 module_description_ = "Graphics output."; 24 module_description_ = "";
30 module_identifier_ = "graphics"; 25 module_identifier_ = "graphics";
31 module_type_ = "output"; 26 module_type_ = "output";
32 module_version_ = "$Id: $"; 27 module_version_ = "$Id: $";
33 28
34 if (parameters_->DefaultBool("output.images", false)) { 29 m_pDev = NULL;
35 m_pDev = new GraphicsOutputDeviceCairo(parameters_); 30 m_bPlotLabels = false;
36 } else { 31 m_pAxisX = new GraphAxisSpec();
37 m_pDev = new GraphicsOutputDeviceMovie(parameters_); 32 AIM_ASSERT(m_pAxisX);
38 } 33 m_pAxisY = new GraphAxisSpec();
39 m_bPlotLabels = false; 34 AIM_ASSERT(m_pAxisY);
40 m_pAxisX = new GraphAxisSpec(); 35 m_pAxisFreq = new GraphAxisSpec();
41 AIM_ASSERT(m_pAxisX); 36 AIM_ASSERT(m_pAxisFreq);
42 m_pAxisY = new GraphAxisSpec(); 37
43 AIM_ASSERT(m_pAxisY); 38 m_pAxisY->Initialize(m_pParam,
44 m_pAxisFreq = new GraphAxisSpec(); 39 _S("graph.y"),
45 AIM_ASSERT(m_pAxisFreq); 40 -1,
46 initialized_ = true; 41 1,
47 42 Scale::SCALE_LINEAR);
48 if (!m_pAxisY->Initialize(parameters_, 43 m_fMarginLeft = m_pParam->GetFloat(_S("graph.margin.left"));
49 _S("graph.y"), 44 m_fMarginRight = m_pParam->GetFloat(_S("graph.margin.right"));
50 -1, 45 m_fMarginTop = m_pParam->GetFloat(_S("graph.margin.top"));
51 1, 46 m_fMarginBottom = m_pParam->GetFloat(_S("graph.margin.bottom"));
52 Scale::SCALE_LINEAR)) { 47 m_bPlotLabels = m_pParam->GetBool(_S("graph.plotlabels"));
53 LOG_ERROR("Axis initialization failed"); 48
54 initialized_ = false; 49 const char *sGraphType = m_pParam->GetString(_S("graph.type"));
55 } 50 if (strcmp(sGraphType, _S("line"))==0)
56 m_fMarginLeft = parameters_->DefaultFloat(_S("graph.margin.left"), 0.05); 51 m_iGraphType = GraphTypeLine;
57 m_fMarginRight = parameters_->DefaultFloat(_S("graph.margin.right"), 0.005); 52 else if (strcmp(sGraphType, _S("colormap"))==0)
58 m_fMarginTop = parameters_->DefaultFloat(_S("graph.margin.top"), 0.005); 53 m_iGraphType = GraphTypeColormap;
59 m_fMarginBottom = parameters_->DefaultFloat(_S("graph.margin.bottom"), 0.05); 54 else if (strcmp(sGraphType, _S("none"))==0)
60 m_bPlotLabels = parameters_->DefaultBool(_S("graph.plotlabels"), true); 55 m_iGraphType = GraphTypeNone;
61 56 else {
62 const char *sGraphType = parameters_->DefaultString(_S("graph.type"), "line"); 57 ret = false;
63 if (strcmp(sGraphType, _S("line"))==0) 58 AIM_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType);
64 m_iGraphType = GraphTypeLine; 59 }
65 else if (strcmp(sGraphType, _S("colormap"))==0) 60
66 m_iGraphType = GraphTypeColormap; 61 if (strcmp(m_pParam->GetString(_S("graph.mindistance")),"auto") == 0)
67 else if (strcmp(sGraphType, _S("none"))==0) 62 // -1 means detect later, based on type and Fire() argument
68 m_iGraphType = GraphTypeNone; 63 m_fMinPlotDistance = -1;
69 else { 64 else
70 LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType); 65 m_fMinPlotDistance = m_pParam->GetFloat(_S("graph.mindistance"));
71 initialized_ = false; 66
72 }
73
74 if (strcmp(parameters_->DefaultString(_S("graph.mindistance"), "auto"),"auto") == 0)
75 // -1 means detect later, based on type and Fire() argument
76 m_fMinPlotDistance = -1;
77 else
78 m_fMinPlotDistance = parameters_->GetFloat(_S("graph.mindistance"));
79 } 67 }
80 68
81 GraphicsView::~GraphicsView() { 69 GraphicsView::~GraphicsView() {
82 DELETE_IF_NONNULL(m_pAxisX); 70 DELETE_IF_NONNULL(m_pAxisX);
83 DELETE_IF_NONNULL(m_pAxisY); 71 DELETE_IF_NONNULL(m_pAxisY);
84 DELETE_IF_NONNULL(m_pAxisFreq); 72 DELETE_IF_NONNULL(m_pAxisFreq);
85 } 73 }
86 74
87 void GraphicsView::ResetInternal() { 75 bool
88 if (m_pDev != NULL) {
89 m_pDev->Reset(global_parameters_);
90 }
91 }
92 76
93 bool GraphicsView::InitializeInternal(const SignalBank &bank) { 77 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
94 if (!m_pDev) { 78 if (!m_pDev) {
95 LOG_ERROR("Output device not connected"); 79 LOG_ERROR("Output device not connected");
80 return false;
81 }
82
83 float y_min = bank.centre_frequency(0);
84 float y_max = bank.centre_frequency(bank.channel_count() - 1);
85 if (!m_pAxisFreq->Initialize(m_pParam,
86 "graph.freq",
87 y_min,
88 y_max,
89 Scale::SCALE_ERB)) {
90 LOG_ERROR("");
96 return false; 91 return false;
97 } 92 }
98 93
99 float y_min = bank.centre_frequency(0); 94 float x_min = 0.0;
100 float y_max = bank.centre_frequency(bank.channel_count() - 1); 95 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
101 if (!m_pAxisFreq->Initialize(parameters_, 96 if (!m_pAxisX->Initialize(m_pParam,
102 "graph.freq", 97 "graph.x",
103 y_min, 98 x_min,
104 y_max, 99 x_max,
105 Scale::SCALE_ERB)) { 100 Scale::SCALE_LINEAR)) {
106 LOG_ERROR("Frequency axis init failed."); 101 LOG_ERROR("");
102 return false;
103 }
104
105 /* Inform graphics output of maximum number of vertices between
106 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
107 */
108 if (!m_pDev->Initialize(MAX(10, bank.buffer_length() * 2 + 2))) {
109 LOG_ERROR("");
107 return false; 110 return false;
108 } 111 }
109
110 float x_min = 0.0;
111 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
112 if (!m_pAxisX->Initialize(parameters_,
113 "graph.x",
114 x_min,
115 x_max,
116 Scale::SCALE_LINEAR)) {
117 LOG_ERROR("Time axis init failed.");
118 return false;
119 }
120
121 /* Inform graphics output of maximum number of vertices between
122 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
123 */
124 LOG_INFO("Initializing graphics output device.");
125
126 if (!m_pDev->Initialize(global_parameters_)) {
127 LOG_ERROR("Graphics output device init failed.");
128 return false;
129 }
130 m_pDev->Start();
131 previous_start_time_ = 0;
132 return true;
133 } 112 }
134 113
135 void GraphicsView::Process(const SignalBank &bank) { 114 void GraphicsView::Process(const SignalBank &bank) {
136 float height = 1.0 / bank.channel_count(); 115 float height = 1.0 / bank.channel_count();
137 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop); 116 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop);
138 float xScaling = 1.0f; 117 float xScaling = 1.0f;
139 118
140 m_pDev->gGrab(); 119 m_pDev->gGrab();
141 PlotAxes(bank); 120 PlotAxes(bank);
142 m_pDev->gColor3f(1.0f, 1.0f, 0.8f); 121 m_pDev->gColor3f(1.0f, 1.0f, 0.8f);
143 for (int i = 0; i < bank.channel_count(); i++) { 122 for (int i = 0; i < bank.channel_count(); i++) {
144 float yOffs = bank.centre_frequency(i); 123 float yOffs = bank.centre_frequency(i);
145 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f; 124 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f;
146 /* Don't plot below zero and stop when above 1, since yOffs is 125 /* Don't plot below zero and stop when above 1, since yOffs is
147 * monotonically increasing. Because of rounding errors, we need 126 * monotonically increasing. Because of rounding errors, we need
148 * to check for yOffs < -1e-6 instead of yOffs < 0. */ 127 * to check for yOffs < -1e-6 instead of yOffs < 0. */
149 if (yOffs < -1e-6) 128 if (yOffs < -1e-6)
150 continue; 129 continue;
151 if (yOffs > 1) 130 if (yOffs > 1)
152 break; 131 break;
153 132
154 // Scale to single channel graphing. 133 // Scale to single channel graphing.
155 yOffs = yOffs * (1.0f - height) + height / 2.0; 134 yOffs = yOffs * (1.0f - height) + height / 2.0;
156 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom; 135 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom;
157 PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling); 136 PlotData(bank[i], yOffs, heightMinMargin, xScaling);
158 } 137 }
159 m_pDev->gRelease(); 138 m_pDev->gRelease();
160
161 frame_rate_ = bank.sample_rate()
162 / (bank.start_time() - previous_start_time_);
163 previous_start_time_ = bank.start_time();
164 global_parameters_->SetFloat("frame_rate", frame_rate_);
165 } 139 }
166 140
167 void GraphicsView::SetAxisScale(Scale::ScaleType iHori, 141 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
168 Scale::ScaleType iVert, 142 Scale::ScaleType iVert,
169 Scale::ScaleType iFreq) { 143 Scale::ScaleType iFreq) {
170 AIM_ASSERT(m_pAxisX); 144 AIM_ASSERT(m_pAxisX);
171 AIM_ASSERT(m_pAxisY); 145 AIM_ASSERT(m_pAxisY);
172 AIM_ASSERT(m_pAxisFreq); 146 AIM_ASSERT(m_pAxisFreq);
173 m_pAxisX->SetDisplayScale(iHori); 147 m_pAxisX->SetDisplayScale(iHori);
174 m_pAxisY->SetDisplayScale(iVert); 148 m_pAxisY->SetDisplayScale(iVert);
175 m_pAxisFreq->SetDisplayScale(iFreq); 149 m_pAxisFreq->SetDisplayScale(iFreq);
176 } 150 }
177 151
178 void GraphicsView::BeginDataStrip() { 152 void GraphicsView::BeginDataStrip() {
179 m_iPrevValEqual=0; 153 m_iPrevValEqual=0;
180 m_bFirstPoint=true; 154 m_bFirstPoint=true;
181 switch(m_iGraphType) { 155 switch(m_iGraphType) {
182 case GraphTypeLine: 156 case GraphTypeLine:
183 m_pDev->gBeginLineStrip(); 157 m_pDev->gBeginLineStrip();
184 break; 158 break;
185 case GraphTypeColormap: 159 case GraphTypeColormap:
186 m_pDev->gBeginQuadStrip(); 160 m_pDev->gBeginQuadStrip();
187 break; 161 break;
188 case GraphTypeNone: 162 case GraphTypeNone:
189 // Nothing: just for testing computation overhead of graphing 163 // Nothing: just for testing computation overhead of graphing
190 break; 164 break;
191 } 165 }
192 } 166 }
193 167
194 void GraphicsView::PlotDataPoint(float x, 168 void GraphicsView::PlotDataPoint(float x,
195 float y, 169 float y,
196 float val, 170 float val,
197 float height, 171 float height,
198 bool isLast) { 172 bool isLast) {
199 AIM_ASSERT(m_pDev); 173 AIM_ASSERT(m_pDev);
200 174
201 /* Reduce the number of points plotted by eliminating duplicate values: 175 /* Reduce the number of points plotted by eliminating duplicate values:
202 * 176 *
203 * oooo o--o 177 * oooo o--o
204 * o / o 178 * o / o
205 * oooo ooo => o--o o--o 179 * oooo ooo => o--o o--o
206 * oooo ooo o--o o-o 180 * oooo ooo o--o o-o
207 * 181 *
208 * with 'o' points that are plotted, and '-' by the graphics output 182 * with 'o' points that are plotted, and '-' by the graphics output
209 * device interpolated points. We could be smarter and include 183 * device interpolated points. We could be smarter and include
210 * first-order interpolation, but we leave that as an exercise for 184 * first-order interpolation, but we leave that as an exercise for
211 * the reader. Please send your patches :) 185 * the reader. Please send your patches :)
212 * 186 *
213 * So, we don't draw points that are too close to the previous value. 187 * So, we don't draw points that are too close to the previous value.
214 * But if the value changes (or it's the last point), we must draw the 188 * But if the value changes (or it's the last point), we must draw the
215 * previous point too. 189 * previous point too.
216 */ 190 */
217 if (!m_bFirstPoint 191 if (!m_bFirstPoint
218 && !isLast 192 && !isLast
219 && abs(m_fPrevVal-val) < m_fMinPlotDistance) { 193 && fabs(m_fPrevVal-val) < m_fMinPlotDistance) {
220 m_iPrevValEqual++; 194 m_iPrevValEqual++;
221 // Don't set m_fPrevVal to avoid not catching slow changes 195 // Don't set m_fPrevVal to avoid not catching slow changes
222 m_fPrevX = x; 196 m_fPrevX = x;
223 m_fPrevY = y; 197 m_fPrevY = y;
224 m_fPrevHeight = height; 198 m_fPrevHeight = height;
225 return; 199 return;
226 } else { 200 } else {
227 if (m_iPrevValEqual > 0) { 201 if (m_iPrevValEqual > 0) {
228 // Draw previous point 202 // Draw previous point
229 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight); 203 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight);
230 } 204 }
231 m_iPrevValEqual = 0; 205 m_iPrevValEqual = 0;
232 m_fPrevVal = val; 206 m_fPrevVal = val;
233 m_bFirstPoint = false; 207 m_bFirstPoint = false;
234 } 208 }
235 PlotDataPointDirect(x, y, val, height); 209 PlotDataPointDirect(x, y, val, height);
236 } 210 }
237 211
238 void GraphicsView::PlotDataPointDirect(float x, 212 void GraphicsView::PlotDataPointDirect(float x,
239 float y, 213 float y,
240 float val, 214 float val,
241 float height) { 215 float height) {
242 // Draw it in the right way 216 // Draw it in the right way
243 switch(m_iGraphType) { 217 switch(m_iGraphType) {
244 case GraphTypeLine: 218 case GraphTypeLine:
245 m_pDev->gVertex2f(x, y + val * height); 219 m_pDev->gVertex2f(x, y + val * height);
246 break; 220 break;
247 case GraphTypeColormap: 221 case GraphTypeColormap:
248 //! \todo make it a real colormap instead of grayscale 222 //! \todo make it a real colormap instead of grayscale
249 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5); 223 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5);
250 m_pDev->gVertex2f(x, y - height / 2); 224 m_pDev->gVertex2f(x, y - height / 2);
251 m_pDev->gVertex2f(x, y + height / 2); 225 m_pDev->gVertex2f(x, y + height / 2);
252 break; 226 break;
253 case GraphTypeNone: 227 case GraphTypeNone:
254 // Nothing: just for testing computation overhead of graphing 228 // Nothing: just for testing computation overhead of graphing
255 break; 229 break;
256 default: 230 default:
257 // Shouldn't happen 231 // Shouldn't happen
258 AIM_ASSERT(0); 232 AIM_ASSERT(0);
259 } 233 }
260 } 234 }
261 } // namespace aimc