annotate trunk/src/Modules/Output/Graphics/GraphicsView.cc @ 410:7af493eb1563

- SWIG fixes. Graphics updates.
author tomwalters
date Tue, 19 Oct 2010 19:48:37 +0000
parents 69466da9745e
children a908972d234e
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@410 33 m_pDev = new GraphicsOutputDeviceCairo();
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
tomwalters@410 43 if (!m_pAxisY->Initialize(parameters_,
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@410 51 m_fMarginLeft = parameters_->GetFloat(_S("graph.margin.left"));
tomwalters@410 52 m_fMarginRight = parameters_->GetFloat(_S("graph.margin.right"));
tomwalters@410 53 m_fMarginTop = parameters_->GetFloat(_S("graph.margin.top"));
tomwalters@410 54 m_fMarginBottom = parameters_->GetFloat(_S("graph.margin.bottom"));
tomwalters@410 55 m_bPlotLabels = parameters_->GetBool(_S("graph.plotlabels"));
tomwalters@397 56
tomwalters@410 57 const char *sGraphType = parameters_->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@410 69 if (strcmp(parameters_->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@410 73 m_fMinPlotDistance = parameters_->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@410 93 if (!m_pAxisFreq->Initialize(parameters_,
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@410 104 if (!m_pAxisX->Initialize(parameters_,
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