annotate trunk/src/Modules/Output/Graphics/GraphicsView.cc @ 402:69466da9745e

- Massive refactoring to make module tree stuff work. In theory we now support configuration files again. The graphics stuff is untested as yet.
author tomwalters
date Mon, 18 Oct 2010 04:42:28 +0000
parents 7bfed53caacf
children 7af493eb1563
rev   line source
tomwalters@397 1 // Copyright 2006, Willem van Engen
tomwalters@397 2 //
tomwalters@397 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@397 4 // http://www.acousticscale.org/AIMC
tomwalters@397 5 //
tomwalters@397 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@397 7 // you may not use this file except in compliance with the License.
tomwalters@397 8 // You may obtain a copy of the License at
tomwalters@397 9 //
tomwalters@397 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@397 11 //
tomwalters@397 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@397 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@397 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@397 15 // See the License for the specific language governing permissions and
tomwalters@397 16 // limitations under the License.
tomwalters@397 17
tom@399 18 #include <algorithm>
tom@399 19
tomwalters@397 20 #include "Support/Common.h"
tomwalters@397 21
tom@399 22 #include "Modules/Output/Graphics/GraphicsView.h"
tom@399 23 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h"
tom@399 24
tom@399 25 namespace aimc {
tomwalters@397 26
tomwalters@397 27 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) {
tomwalters@402 28 module_description_ = "Graphics output.";
tomwalters@397 29 module_identifier_ = "graphics";
tomwalters@397 30 module_type_ = "output";
tomwalters@397 31 module_version_ = "$Id: $";
tomwalters@397 32
tomwalters@398 33 m_pDev = NULL;
tomwalters@398 34 m_bPlotLabels = false;
tomwalters@398 35 m_pAxisX = new GraphAxisSpec();
tomwalters@398 36 AIM_ASSERT(m_pAxisX);
tomwalters@398 37 m_pAxisY = new GraphAxisSpec();
tomwalters@398 38 AIM_ASSERT(m_pAxisY);
tomwalters@398 39 m_pAxisFreq = new GraphAxisSpec();
tomwalters@398 40 AIM_ASSERT(m_pAxisFreq);
tom@399 41 initialized_ = true;
tomwalters@397 42
tom@399 43 if (!m_pAxisY->Initialize(m_pParam,
tom@399 44 _S("graph.y"),
tom@399 45 -1,
tom@399 46 1,
tom@399 47 Scale::SCALE_LINEAR)) {
tom@399 48 LOG_ERROR("Axis initialization failed");
tom@399 49 initialized_ = false;
tom@399 50 }
tomwalters@398 51 m_fMarginLeft = m_pParam->GetFloat(_S("graph.margin.left"));
tomwalters@398 52 m_fMarginRight = m_pParam->GetFloat(_S("graph.margin.right"));
tomwalters@398 53 m_fMarginTop = m_pParam->GetFloat(_S("graph.margin.top"));
tomwalters@398 54 m_fMarginBottom = m_pParam->GetFloat(_S("graph.margin.bottom"));
tomwalters@398 55 m_bPlotLabels = m_pParam->GetBool(_S("graph.plotlabels"));
tomwalters@397 56
tomwalters@398 57 const char *sGraphType = m_pParam->GetString(_S("graph.type"));
tomwalters@398 58 if (strcmp(sGraphType, _S("line"))==0)
tomwalters@398 59 m_iGraphType = GraphTypeLine;
tomwalters@398 60 else if (strcmp(sGraphType, _S("colormap"))==0)
tomwalters@398 61 m_iGraphType = GraphTypeColormap;
tomwalters@398 62 else if (strcmp(sGraphType, _S("none"))==0)
tomwalters@398 63 m_iGraphType = GraphTypeNone;
tomwalters@398 64 else {
tom@399 65 LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType);
tom@399 66 initialized_ = false;
tomwalters@398 67 }
tomwalters@397 68
tomwalters@398 69 if (strcmp(m_pParam->GetString(_S("graph.mindistance")),"auto") == 0)
tomwalters@398 70 // -1 means detect later, based on type and Fire() argument
tomwalters@398 71 m_fMinPlotDistance = -1;
tomwalters@398 72 else
tomwalters@398 73 m_fMinPlotDistance = m_pParam->GetFloat(_S("graph.mindistance"));
tomwalters@397 74 }
tomwalters@397 75
tomwalters@397 76 GraphicsView::~GraphicsView() {
tomwalters@398 77 DELETE_IF_NONNULL(m_pAxisX);
tomwalters@398 78 DELETE_IF_NONNULL(m_pAxisY);
tomwalters@398 79 DELETE_IF_NONNULL(m_pAxisFreq);
tomwalters@397 80 }
tomwalters@397 81
tom@399 82 void GraphicsView::ResetInternal() {
tom@399 83 }
tomwalters@397 84
tomwalters@397 85 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
tomwalters@398 86 if (!m_pDev) {
tomwalters@398 87 LOG_ERROR("Output device not connected");
tomwalters@398 88 return false;
tomwalters@398 89 }
tomwalters@397 90
tomwalters@397 91 float y_min = bank.centre_frequency(0);
tomwalters@397 92 float y_max = bank.centre_frequency(bank.channel_count() - 1);
tomwalters@398 93 if (!m_pAxisFreq->Initialize(m_pParam,
tomwalters@397 94 "graph.freq",
tomwalters@398 95 y_min,
tomwalters@398 96 y_max,
tomwalters@398 97 Scale::SCALE_ERB)) {
tomwalters@397 98 LOG_ERROR("");
tomwalters@397 99 return false;
tomwalters@397 100 }
tomwalters@397 101
tomwalters@397 102 float x_min = 0.0;
tomwalters@397 103 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
tomwalters@398 104 if (!m_pAxisX->Initialize(m_pParam,
tomwalters@397 105 "graph.x",
tomwalters@398 106 x_min,
tomwalters@397 107 x_max,
tomwalters@398 108 Scale::SCALE_LINEAR)) {
tomwalters@397 109 LOG_ERROR("");
tomwalters@397 110 return false;
tomwalters@397 111 }
tomwalters@397 112
tomwalters@398 113 /* Inform graphics output of maximum number of vertices between
tomwalters@398 114 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
tomwalters@398 115 */
tom@399 116 if (!m_pDev->Initialize(std::max<int>(10, bank.buffer_length() * 2 + 2))) {
tomwalters@397 117 LOG_ERROR("");
tomwalters@397 118 return false;
tomwalters@397 119 }
tom@399 120 return true;
tomwalters@397 121 }
tomwalters@397 122
tomwalters@397 123 void GraphicsView::Process(const SignalBank &bank) {
tomwalters@398 124 float height = 1.0 / bank.channel_count();
tomwalters@398 125 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop);
tomwalters@398 126 float xScaling = 1.0f;
tomwalters@397 127
tomwalters@398 128 m_pDev->gGrab();
tomwalters@398 129 PlotAxes(bank);
tomwalters@398 130 m_pDev->gColor3f(1.0f, 1.0f, 0.8f);
tomwalters@398 131 for (int i = 0; i < bank.channel_count(); i++) {
tomwalters@398 132 float yOffs = bank.centre_frequency(i);
tomwalters@398 133 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f;
tomwalters@398 134 /* Don't plot below zero and stop when above 1, since yOffs is
tomwalters@397 135 * monotonically increasing. Because of rounding errors, we need
tomwalters@397 136 * to check for yOffs < -1e-6 instead of yOffs < 0. */
tomwalters@398 137 if (yOffs < -1e-6)
tomwalters@397 138 continue;
tomwalters@398 139 if (yOffs > 1)
tomwalters@397 140 break;
tomwalters@397 141
tomwalters@397 142 // Scale to single channel graphing.
tomwalters@398 143 yOffs = yOffs * (1.0f - height) + height / 2.0;
tomwalters@398 144 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom;
tom@399 145 PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling);
tomwalters@398 146 }
tomwalters@398 147 m_pDev->gRelease();
tomwalters@397 148 }
tomwalters@397 149
tomwalters@397 150 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
tomwalters@397 151 Scale::ScaleType iVert,
tomwalters@397 152 Scale::ScaleType iFreq) {
tomwalters@398 153 AIM_ASSERT(m_pAxisX);
tomwalters@398 154 AIM_ASSERT(m_pAxisY);
tomwalters@398 155 AIM_ASSERT(m_pAxisFreq);
tomwalters@398 156 m_pAxisX->SetDisplayScale(iHori);
tomwalters@398 157 m_pAxisY->SetDisplayScale(iVert);
tomwalters@398 158 m_pAxisFreq->SetDisplayScale(iFreq);
tomwalters@397 159 }
tomwalters@397 160
tomwalters@397 161 void GraphicsView::BeginDataStrip() {
tomwalters@398 162 m_iPrevValEqual=0;
tomwalters@398 163 m_bFirstPoint=true;
tomwalters@398 164 switch(m_iGraphType) {
tomwalters@398 165 case GraphTypeLine:
tomwalters@398 166 m_pDev->gBeginLineStrip();
tomwalters@398 167 break;
tomwalters@398 168 case GraphTypeColormap:
tomwalters@398 169 m_pDev->gBeginQuadStrip();
tomwalters@398 170 break;
tomwalters@398 171 case GraphTypeNone:
tomwalters@398 172 // Nothing: just for testing computation overhead of graphing
tomwalters@398 173 break;
tomwalters@398 174 }
tomwalters@397 175 }
tomwalters@397 176
tomwalters@397 177 void GraphicsView::PlotDataPoint(float x,
tomwalters@397 178 float y,
tomwalters@397 179 float val,
tomwalters@397 180 float height,
tomwalters@397 181 bool isLast) {
tomwalters@398 182 AIM_ASSERT(m_pDev);
tomwalters@397 183
tomwalters@398 184 /* Reduce the number of points plotted by eliminating duplicate values:
tomwalters@398 185 *
tomwalters@398 186 * oooo o--o
tomwalters@398 187 * o / o
tomwalters@398 188 * oooo ooo => o--o o--o
tomwalters@398 189 * oooo ooo o--o o-o
tomwalters@398 190 *
tomwalters@398 191 * with 'o' points that are plotted, and '-' by the graphics output
tomwalters@398 192 * device interpolated points. We could be smarter and include
tomwalters@398 193 * first-order interpolation, but we leave that as an exercise for
tomwalters@398 194 * the reader. Please send your patches :)
tomwalters@398 195 *
tomwalters@398 196 * So, we don't draw points that are too close to the previous value.
tomwalters@398 197 * But if the value changes (or it's the last point), we must draw the
tomwalters@398 198 * previous point too.
tomwalters@398 199 */
tomwalters@398 200 if (!m_bFirstPoint
tomwalters@397 201 && !isLast
tom@399 202 && abs(m_fPrevVal-val) < m_fMinPlotDistance) {
tomwalters@398 203 m_iPrevValEqual++;
tomwalters@398 204 // Don't set m_fPrevVal to avoid not catching slow changes
tomwalters@398 205 m_fPrevX = x;
tomwalters@398 206 m_fPrevY = y;
tomwalters@398 207 m_fPrevHeight = height;
tomwalters@398 208 return;
tomwalters@398 209 } else {
tomwalters@398 210 if (m_iPrevValEqual > 0) {
tomwalters@398 211 // Draw previous point
tomwalters@398 212 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight);
tomwalters@398 213 }
tomwalters@398 214 m_iPrevValEqual = 0;
tomwalters@398 215 m_fPrevVal = val;
tomwalters@398 216 m_bFirstPoint = false;
tomwalters@398 217 }
tomwalters@398 218 PlotDataPointDirect(x, y, val, height);
tomwalters@397 219 }
tomwalters@397 220
tomwalters@397 221 void GraphicsView::PlotDataPointDirect(float x,
tomwalters@397 222 float y,
tomwalters@397 223 float val,
tomwalters@397 224 float height) {
tomwalters@398 225 // Draw it in the right way
tomwalters@398 226 switch(m_iGraphType) {
tomwalters@398 227 case GraphTypeLine:
tomwalters@398 228 m_pDev->gVertex2f(x, y + val * height);
tomwalters@398 229 break;
tomwalters@398 230 case GraphTypeColormap:
tomwalters@398 231 //! \todo make it a real colormap instead of grayscale
tomwalters@398 232 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5);
tomwalters@398 233 m_pDev->gVertex2f(x, y - height / 2);
tomwalters@398 234 m_pDev->gVertex2f(x, y + height / 2);
tomwalters@398 235 break;
tomwalters@398 236 case GraphTypeNone:
tomwalters@398 237 // Nothing: just for testing computation overhead of graphing
tomwalters@398 238 break;
tomwalters@398 239 default:
tomwalters@398 240 // Shouldn't happen
tomwalters@398 241 AIM_ASSERT(0);
tomwalters@398 242 }
tomwalters@397 243 }
tom@399 244 } // namespace aimc