Mercurial > hg > aimc
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 |