annotate src/Modules/Output/Graphics/GraphicsView.cc @ 232:af531fc3f280

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