mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
Add support to analyse driveresponse for drawing its own graphs via AGG.
This commit is contained in:
@@ -22,9 +22,6 @@
|
||||
#ifndef AGG2D_INCLUDED
|
||||
#define AGG2D_INCLUDED
|
||||
|
||||
// With this define uncommented you can use FreeType font engine
|
||||
//#define AGG2D_USE_FREETYPE
|
||||
|
||||
// With this define uncommented you can use floating-point pixel format
|
||||
//#define AGG2D_USE_FLOAT_FORMAT
|
||||
|
||||
@@ -50,18 +47,9 @@
|
||||
#include "agg_rounded_rect.h"
|
||||
#include "agg_font_cache_manager.h"
|
||||
|
||||
// Font drawing is deactivated here because the implementation is platform-dependent and incomplete.
|
||||
//#define AGG_USE_FONTS
|
||||
#ifdef AGG_USE_FONTS
|
||||
# ifdef AGG2D_USE_FREETYPE
|
||||
# include "agg_font_freetype.h"
|
||||
# else
|
||||
# include "agg_font_win32_tt.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_image_accessors.h"
|
||||
#include <string>
|
||||
|
||||
class Agg2D
|
||||
{
|
||||
@@ -95,16 +83,6 @@ class Agg2D
|
||||
typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_x, GradientArray> LinearGradientSpan;
|
||||
typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_circle, GradientArray> RadialGradientSpan;
|
||||
|
||||
#ifdef AGG_USE_FONTS
|
||||
# ifdef AGG2D_USE_FREETYPE
|
||||
typedef agg::font_engine_freetype_int32 FontEngine;
|
||||
# else
|
||||
typedef agg::font_engine_win32_tt_int32 FontEngine;
|
||||
# endif
|
||||
typedef agg::font_cache_manager<FontEngine> FontCacheManager;
|
||||
typedef FontCacheManager::gray8_adaptor_type FontRasterizer;
|
||||
typedef FontCacheManager::gray8_scanline_type FontScanline;
|
||||
#endif
|
||||
typedef agg::conv_curve<agg::path_storage> ConvCurve;
|
||||
typedef agg::conv_stroke<ConvCurve> ConvStroke;
|
||||
typedef agg::conv_transform<ConvCurve> PathTransform;
|
||||
@@ -147,8 +125,6 @@ public:
|
||||
AlignLeft,
|
||||
AlignRight,
|
||||
AlignCenter,
|
||||
AlignTop = AlignRight,
|
||||
AlignBottom = AlignLeft
|
||||
};
|
||||
|
||||
|
||||
@@ -337,6 +313,10 @@ public:
|
||||
void fillEvenOdd(bool evenOddFlag);
|
||||
bool fillEvenOdd() const;
|
||||
|
||||
void textAlignment(TextAlignment alignment);
|
||||
void textSize(double sizeX, double sizeY);
|
||||
inline void textSize(double size) { textSize(size, size); }
|
||||
|
||||
// Transformations
|
||||
//-----------------------
|
||||
Transformations transformations() const;
|
||||
@@ -371,23 +351,6 @@ public:
|
||||
void polygon(double* xy, int numPoints);
|
||||
void polyline(double* xy, int numPoints);
|
||||
|
||||
#ifdef AGG_USE_FONTS
|
||||
// Text
|
||||
//-----------------------
|
||||
void flipText(bool flip);
|
||||
void font(const char* fileName, double height,
|
||||
bool bold = false,
|
||||
bool italic = false,
|
||||
FontCacheType ch = RasterFontCache,
|
||||
double angle = 0.0);
|
||||
double fontHeight() const;
|
||||
void textAlignment(TextAlignment alignX, TextAlignment alignY);
|
||||
bool textHints() const;
|
||||
void textHints(bool hints);
|
||||
double textWidth(const char* str);
|
||||
void text(double x, double y, const char* str, bool roundOff=false, double dx=0.0, double dy=0.0);
|
||||
#endif
|
||||
|
||||
// Path commands
|
||||
//-----------------------
|
||||
void resetPath();
|
||||
@@ -438,6 +401,7 @@ public:
|
||||
double xTo, double yTo);
|
||||
|
||||
void addEllipse(double cx, double cy, double rx, double ry, Direction dir);
|
||||
void text(double x, double y, const std::string& text);
|
||||
void closePolygon();
|
||||
|
||||
void drawPath(DrawPathFlag flag = FillAndStroke);
|
||||
@@ -552,14 +516,9 @@ private:
|
||||
double m_fillGradientD2;
|
||||
double m_lineGradientD2;
|
||||
|
||||
double m_textAngle;
|
||||
TextAlignment m_textAlignX;
|
||||
TextAlignment m_textAlignY;
|
||||
bool m_textHints;
|
||||
double m_fontHeight;
|
||||
double m_fontAscent;
|
||||
double m_fontDescent;
|
||||
FontCacheType m_fontCacheType;
|
||||
TextAlignment m_textAlignment;
|
||||
double m_textSizeX;
|
||||
double m_textSizeY;
|
||||
|
||||
ImageFilter m_imageFilter;
|
||||
ImageResample m_imageResample;
|
||||
|
||||
@@ -172,6 +172,9 @@ namespace agg
|
||||
//--------------------------------------------------------------------
|
||||
static rgba from_wavelength(double wl, double gamma = 1.0);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static rgba from_hsv(double h, double s, double v);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
explicit rgba(double wavelen, double gamma=1.0)
|
||||
{
|
||||
@@ -235,6 +238,30 @@ namespace agg
|
||||
return t;
|
||||
}
|
||||
|
||||
inline rgba rgba::from_hsv(double h, double s, double v)
|
||||
{
|
||||
h = fmod(h, 360.0);
|
||||
double hh = h / 60.0;
|
||||
int i = (int)hh;
|
||||
double ff = hh - i;
|
||||
double p = v * (1.0 - s);
|
||||
double q = v * (1.0 - s*ff);
|
||||
double t = v * (1.0 - s*(1.0 - ff));
|
||||
|
||||
double r, g, b;
|
||||
switch (i) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5:
|
||||
default: r = v; g = p; b = q; break;
|
||||
}
|
||||
|
||||
return rgba(r, g, b, 1.0);
|
||||
}
|
||||
|
||||
inline rgba rgba_pre(double r, double g, double b, double a)
|
||||
{
|
||||
return rgba(r, g, b, a).premultiply();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "agg2d.h"
|
||||
#include "agg_gsv_text.h"
|
||||
|
||||
static const double g_approxScale = 2.0;
|
||||
|
||||
@@ -79,14 +80,9 @@ Agg2D::Agg2D() :
|
||||
m_fillGradientD2(100.0),
|
||||
m_lineGradientD2(100.0),
|
||||
|
||||
m_textAngle(0.0),
|
||||
m_textAlignX(AlignLeft),
|
||||
m_textAlignY(AlignBottom),
|
||||
m_textHints(true),
|
||||
m_fontHeight(0.0),
|
||||
m_fontAscent(0.0),
|
||||
m_fontDescent(0.0),
|
||||
m_fontCacheType(RasterFontCache),
|
||||
m_textAlignment(AlignLeft),
|
||||
m_textSizeX(10.0),
|
||||
m_textSizeY(10.0),
|
||||
|
||||
m_imageFilter(Bilinear),
|
||||
m_imageResample(NoResample),
|
||||
@@ -138,15 +134,9 @@ void Agg2D::attach(unsigned char* buf, unsigned width, unsigned height, int stri
|
||||
lineWidth(1.0),
|
||||
lineColor(0,0,0);
|
||||
fillColor(255,255,255);
|
||||
#ifdef AGG_USE_FONTS
|
||||
textAlignment(AlignLeft, AlignBottom);
|
||||
#endif
|
||||
clipBox(0, 0, width, height);
|
||||
lineCap(CapRound);
|
||||
lineJoin(JoinRound);
|
||||
#ifdef AGG_USE_FONTS
|
||||
flipText(false);
|
||||
#endif
|
||||
imageFilter(Bilinear);
|
||||
imageResample(NoResample);
|
||||
m_masterAlpha = 1.0;
|
||||
@@ -908,183 +898,19 @@ void Agg2D::polyline(double* xy, int numPoints)
|
||||
drawPath(StrokeOnly);
|
||||
}
|
||||
|
||||
#ifdef AGG_USE_FONTS
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::flipText(bool flip)
|
||||
void Agg2D::textSize(double sizeX, double sizeY)
|
||||
{
|
||||
m_fontEngine.flip_y(flip);
|
||||
m_textSizeX = sizeX;
|
||||
m_textSizeY = sizeY;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::font(const char* fontName,
|
||||
double height,
|
||||
bool bold,
|
||||
bool italic,
|
||||
FontCacheType ch,
|
||||
double angle)
|
||||
void Agg2D::textAlignment(TextAlignment alignment)
|
||||
{
|
||||
m_textAngle = angle;
|
||||
m_fontHeight = height;
|
||||
m_fontCacheType = ch;
|
||||
|
||||
#ifdef AGG2D_USE_FREETYPE
|
||||
m_fontEngine.load_font(fontName,
|
||||
0,
|
||||
(ch == VectorFontCache) ?
|
||||
agg::glyph_ren_outline :
|
||||
agg::glyph_ren_agg_gray8);
|
||||
m_fontEngine.hinting(m_textHints);
|
||||
m_fontEngine.height((ch == VectorFontCache) ? height : worldToScreen(height));
|
||||
#else
|
||||
m_fontEngine.hinting(m_textHints);
|
||||
|
||||
m_fontEngine.create_font(fontName,
|
||||
(ch == VectorFontCache) ?
|
||||
agg::glyph_ren_outline :
|
||||
agg::glyph_ren_agg_gray8,
|
||||
(ch == VectorFontCache) ? height : worldToScreen(height),
|
||||
0.0,
|
||||
bold ? 700 : 400,
|
||||
italic);
|
||||
#endif
|
||||
m_textAlignment = alignment;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double Agg2D::fontHeight() const
|
||||
{
|
||||
return m_fontHeight;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::textAlignment(TextAlignment alignX, TextAlignment alignY)
|
||||
{
|
||||
m_textAlignX = alignX;
|
||||
m_textAlignY = alignY;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double Agg2D::textWidth(const char* str)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
bool first = true;
|
||||
while(*str)
|
||||
{
|
||||
const agg::glyph_cache* glyph = m_fontCacheManager.glyph(*str);
|
||||
if(glyph)
|
||||
{
|
||||
if(!first) m_fontCacheManager.add_kerning(&x, &y);
|
||||
x += glyph->advance_x;
|
||||
y += glyph->advance_y;
|
||||
first = false;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
return (m_fontCacheType == VectorFontCache) ? x : screenToWorld(x);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Agg2D::textHints() const
|
||||
{
|
||||
return m_textHints;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::textHints(bool hints)
|
||||
{
|
||||
m_textHints = hints;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::text(double x, double y, const char* str, bool roundOff, double ddx, double ddy)
|
||||
{
|
||||
double dx = 0.0;
|
||||
double dy = 0.0;
|
||||
|
||||
switch(m_textAlignX)
|
||||
{
|
||||
case AlignCenter: dx = -textWidth(str) * 0.5; break;
|
||||
case AlignRight: dx = -textWidth(str); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
double asc = fontHeight();
|
||||
const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
|
||||
if(glyph)
|
||||
{
|
||||
asc = glyph->bounds.y2 - glyph->bounds.y1;
|
||||
}
|
||||
|
||||
if(m_fontCacheType == RasterFontCache)
|
||||
{
|
||||
asc = screenToWorld(asc);
|
||||
}
|
||||
|
||||
switch(m_textAlignY)
|
||||
{
|
||||
case AlignCenter: dy = -asc * 0.5; break;
|
||||
case AlignTop: dy = -asc; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(m_fontEngine.flip_y()) dy = -dy;
|
||||
|
||||
agg::trans_affine mtx;
|
||||
|
||||
double start_x = x + dx;
|
||||
double start_y = y + dy;
|
||||
|
||||
if (roundOff)
|
||||
{
|
||||
start_x = int(start_x);
|
||||
start_y = int(start_y);
|
||||
}
|
||||
start_x += ddx;
|
||||
start_y += ddy;
|
||||
|
||||
mtx *= agg::trans_affine_translation(-x, -y);
|
||||
mtx *= agg::trans_affine_rotation(m_textAngle);
|
||||
mtx *= agg::trans_affine_translation(x, y);
|
||||
|
||||
agg::conv_transform<FontCacheManager::path_adaptor_type> tr(m_fontCacheManager.path_adaptor(), mtx);
|
||||
|
||||
if(m_fontCacheType == RasterFontCache)
|
||||
{
|
||||
worldToScreen(start_x, start_y);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; str[i]; i++)
|
||||
{
|
||||
glyph = m_fontCacheManager.glyph(str[i]);
|
||||
if(glyph)
|
||||
{
|
||||
if(i) m_fontCacheManager.add_kerning(&start_x, &start_y);
|
||||
m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);
|
||||
|
||||
if(glyph->data_type == agg::glyph_data_outline)
|
||||
{
|
||||
m_path.remove_all();
|
||||
//m_path.add_path(tr, 0, false);
|
||||
m_path.concat_path(tr,0); // JME
|
||||
drawPath();
|
||||
}
|
||||
|
||||
if(glyph->data_type == agg::glyph_data_gray8)
|
||||
{
|
||||
render(m_fontCacheManager.gray8_adaptor(),
|
||||
m_fontCacheManager.gray8_scanline());
|
||||
}
|
||||
start_x += glyph->advance_x;
|
||||
start_y += glyph->advance_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // AGG_USE_FONTS
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::resetPath() { m_path.remove_all(); }
|
||||
|
||||
@@ -1237,6 +1063,33 @@ void Agg2D::addEllipse(double cx, double cy, double rx, double ry, Direction dir
|
||||
m_path.close_polygon();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::text(double x, double y, const std::string& text)
|
||||
{
|
||||
agg::gsv_text t;
|
||||
t.flip(true);
|
||||
t.size(m_textSizeX, m_textSizeY);
|
||||
t.text(text.c_str());
|
||||
double w = t.text_width();
|
||||
switch (m_textAlignment)
|
||||
{
|
||||
case AlignLeft:
|
||||
break;
|
||||
|
||||
case AlignRight:
|
||||
x -= w;
|
||||
break;
|
||||
|
||||
case AlignCenter:
|
||||
x -= w/2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
t.start_point(x, y);
|
||||
m_path.concat_path(t);
|
||||
drawPath();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Agg2D::closePolygon()
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
namespace agg
|
||||
{
|
||||
int8u gsv_default_font[] =
|
||||
const int8u gsv_default_font[] =
|
||||
{
|
||||
0x40,0x00,0x6c,0x0f,0x15,0x00,0x0e,0x00,0xf9,0xff,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
||||
@@ -45,28 +45,137 @@ static DataSpecFlag writeImg(
|
||||
"Draw a graph of the response data",
|
||||
":w=640:h=480");
|
||||
|
||||
static agg::srgba8 hsvToRgb(double h, double s, double v)
|
||||
/* This is the Turbo colourmap.
|
||||
* https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html
|
||||
*/
|
||||
static const uint8_t turbo_srgb_bytes[256][3] = {
|
||||
{48,18,59}, {50,21,67}, {51,24,74}, {52,27,81}, {53,30,88}, {54,33,95},
|
||||
{55,36,102}, {56,39,109}, {57,42,115}, {58,45,121}, {59,47,128},
|
||||
{60,50,134}, {61,53,139}, {62,56,145}, {63,59,151}, {63,62,156},
|
||||
{64,64,162}, {65,67,167}, {65,70,172}, {66,73,177}, {66,75,181},
|
||||
{67,78,186}, {68,81,191}, {68,84,195}, {68,86,199}, {69,89,203},
|
||||
{69,92,207}, {69,94,211}, {70,97,214}, {70,100,218}, {70,102,221},
|
||||
{70,105,224}, {70,107,227}, {71,110,230}, {71,113,233}, {71,115,235},
|
||||
{71,118,238}, {71,120,240}, {71,123,242}, {70,125,244}, {70,128,246},
|
||||
{70,130,248}, {70,133,250}, {70,135,251}, {69,138,252}, {69,140,253},
|
||||
{68,143,254}, {67,145,254}, {66,148,255}, {65,150,255}, {64,153,255},
|
||||
{62,155,254}, {61,158,254}, {59,160,253}, {58,163,252}, {56,165,251},
|
||||
{55,168,250}, {53,171,248}, {51,173,247}, {49,175,245}, {47,178,244},
|
||||
{46,180,242}, {44,183,240}, {42,185,238}, {40,188,235}, {39,190,233},
|
||||
{37,192,231}, {35,195,228}, {34,197,226}, {32,199,223}, {31,201,221},
|
||||
{30,203,218}, {28,205,216}, {27,208,213}, {26,210,210}, {26,212,208},
|
||||
{25,213,205}, {24,215,202}, {24,217,200}, {24,219,197}, {24,221,194},
|
||||
{24,222,192}, {24,224,189}, {25,226,187}, {25,227,185}, {26,228,182},
|
||||
{28,230,180}, {29,231,178}, {31,233,175}, {32,234,172}, {34,235,170},
|
||||
{37,236,167}, {39,238,164}, {42,239,161}, {44,240,158}, {47,241,155},
|
||||
{50,242,152}, {53,243,148}, {56,244,145}, {60,245,142}, {63,246,138},
|
||||
{67,247,135}, {70,248,132}, {74,248,128}, {78,249,125}, {82,250,122},
|
||||
{85,250,118}, {89,251,115}, {93,252,111}, {97,252,108}, {101,253,105},
|
||||
{105,253,102}, {109,254,98}, {113,254,95}, {117,254,92}, {121,254,89},
|
||||
{125,255,86}, {128,255,83}, {132,255,81}, {136,255,78}, {139,255,75},
|
||||
{143,255,73}, {146,255,71}, {150,254,68}, {153,254,66}, {156,254,64},
|
||||
{159,253,63}, {161,253,61}, {164,252,60}, {167,252,58}, {169,251,57},
|
||||
{172,251,56}, {175,250,55}, {177,249,54}, {180,248,54}, {183,247,53},
|
||||
{185,246,53}, {188,245,52}, {190,244,52}, {193,243,52}, {195,241,52},
|
||||
{198,240,52}, {200,239,52}, {203,237,52}, {205,236,52}, {208,234,52},
|
||||
{210,233,53}, {212,231,53}, {215,229,53}, {217,228,54}, {219,226,54},
|
||||
{221,224,55}, {223,223,55}, {225,221,55}, {227,219,56}, {229,217,56},
|
||||
{231,215,57}, {233,213,57}, {235,211,57}, {236,209,58}, {238,207,58},
|
||||
{239,205,58}, {241,203,58}, {242,201,58}, {244,199,58}, {245,197,58},
|
||||
{246,195,58}, {247,193,58}, {248,190,57}, {249,188,57}, {250,186,57},
|
||||
{251,184,56}, {251,182,55}, {252,179,54}, {252,177,54}, {253,174,53},
|
||||
{253,172,52}, {254,169,51}, {254,167,50}, {254,164,49}, {254,161,48},
|
||||
{254,158,47}, {254,155,45}, {254,153,44}, {254,150,43}, {254,147,42},
|
||||
{254,144,41}, {253,141,39}, {253,138,38}, {252,135,37}, {252,132,35},
|
||||
{251,129,34}, {251,126,33}, {250,123,31}, {249,120,30}, {249,117,29},
|
||||
{248,114,28}, {247,111,26}, {246,108,25}, {245,105,24}, {244,102,23},
|
||||
{243,99,21}, {242,96,20}, {241,93,19}, {240,91,18}, {239,88,17},
|
||||
{237,85,16}, {236,83,15}, {235,80,14}, {234,78,13}, {232,75,12},
|
||||
{231,73,12}, {229,71,11}, {228,69,10}, {226,67,10}, {225,65,9},
|
||||
{223,63,8}, {221,61,8}, {220,59,7}, {218,57,7}, {216,55,6}, {214,53,6},
|
||||
{212,51,5}, {210,49,5}, {208,47,5}, {206,45,4}, {204,43,4}, {202,42,4},
|
||||
{200,40,3}, {197,38,3}, {195,37,3}, {193,35,2}, {190,33,2}, {188,32,2},
|
||||
{185,30,2}, {183,29,2}, {180,27,1}, {178,26,1}, {175,24,1}, {172,23,1},
|
||||
{169,22,1}, {167,20,1}, {164,19,1}, {161,18,1}, {158,16,1}, {155,15,1},
|
||||
{152,14,1}, {149,13,1}, {146,11,1}, {142,10,1}, {139,9,2}, {136,8,2},
|
||||
{133,7,2}, {129,6,2}, {126,5,2}, {122,4,3}};
|
||||
|
||||
static void palette(double value, agg::srgba8* pixel)
|
||||
{
|
||||
h = fmod(h, 360.0);
|
||||
double hh = h / 60.0;
|
||||
int i = (int)hh;
|
||||
double ff = hh - i;
|
||||
double p = v * (1.0 - s);
|
||||
double q = v * (1.0 - s*ff);
|
||||
double t = v * (1.0 - s*(1.0 - ff));
|
||||
int index = std::min((int)(value * 256.0), 255);
|
||||
pixel->r = turbo_srgb_bytes[index][0];
|
||||
pixel->g = turbo_srgb_bytes[index][1];
|
||||
pixel->b = turbo_srgb_bytes[index][2];
|
||||
pixel->a = 255;
|
||||
}
|
||||
|
||||
double r, g, b;
|
||||
switch (i) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5:
|
||||
default: r = v; g = p; b = q; break;
|
||||
}
|
||||
static void do_in_steps(double c1, double c2, double lo, double hi,
|
||||
double step, std::function<void(double c, double v)> func)
|
||||
{
|
||||
double scale = (c2 - c1) / (hi - lo);
|
||||
double v = lo;
|
||||
while (v <= hi + step/10.0)
|
||||
{
|
||||
double c = c1 + scale*(v - lo);
|
||||
func(c, v);
|
||||
v += step;
|
||||
}
|
||||
}
|
||||
|
||||
return agg::srgba8(b*255.0, g*255.0, r*255.0, 255);
|
||||
static void draw_y_axis(Agg2D& painter, double x, double y1, double y2,
|
||||
double lo, double hi, double step, const char* format)
|
||||
{
|
||||
painter.noFill();
|
||||
painter.lineColor(0, 0, 0);
|
||||
painter.line(x, y1, x, y2);
|
||||
painter.textSize(10.0);
|
||||
painter.textAlignment(Agg2D::AlignRight);
|
||||
|
||||
do_in_steps(y1, y2, lo, hi, step, [&](double y, double v)
|
||||
{
|
||||
painter.line(x, y, x-5, y);
|
||||
painter.text(x-8, y+5.0, fmt::format(format, v));
|
||||
});
|
||||
}
|
||||
|
||||
static void draw_x_axis(Agg2D& painter, double x1, double x2, double y,
|
||||
double lo, double hi, double step, const char* format)
|
||||
{
|
||||
painter.noFill();
|
||||
painter.lineColor(0, 0, 0);
|
||||
painter.line(x1, y, x2, y);
|
||||
painter.textSize(10.0);
|
||||
painter.textAlignment(Agg2D::AlignCenter);
|
||||
|
||||
do_in_steps(x1, x2, lo, hi, step, [&](double x, double v)
|
||||
{
|
||||
painter.line(x, y, x, y+5);
|
||||
painter.text(x, y+18, fmt::format(format, v));
|
||||
});
|
||||
}
|
||||
|
||||
static void draw_y_graticules(Agg2D& painter, double x1, double y1, double x2, double y2,
|
||||
double lo, double hi, double step)
|
||||
{
|
||||
painter.noFill();
|
||||
painter.lineColor(0, 0, 0, 128);
|
||||
|
||||
do_in_steps(y1, y2, lo, hi, step, [&](double y, double v)
|
||||
{
|
||||
painter.line(x1, y, x2, y);
|
||||
});
|
||||
}
|
||||
|
||||
static void draw_x_graticules(Agg2D& painter, double x1, double y1, double x2, double y2,
|
||||
double lo, double hi, double step)
|
||||
{
|
||||
painter.noFill();
|
||||
painter.lineColor(0, 0, 0, 128);
|
||||
|
||||
do_in_steps(x1, x2, lo, hi, step, [&](double x, double v)
|
||||
{
|
||||
painter.line(x, y1, x, y2);
|
||||
});
|
||||
}
|
||||
|
||||
int mainAnalyseDriveResponse(int argc, const char* argv[])
|
||||
@@ -91,7 +200,7 @@ int mainAnalyseDriveResponse(int argc, const char* argv[])
|
||||
|
||||
int numRows = (maxInterval - minInterval) / intervalStep;
|
||||
const int numColumns = 512;
|
||||
double frequencies[numRows][numColumns] = {};
|
||||
double frequencies[numRows+1][numColumns] = {};
|
||||
|
||||
int row = 0;
|
||||
for (double interval = minInterval; interval<maxInterval; interval += intervalStep, row++)
|
||||
@@ -169,38 +278,60 @@ int mainAnalyseDriveResponse(int argc, const char* argv[])
|
||||
Agg2D& painter = bitmapSpec.painter();
|
||||
painter.clearAll(0xdd, 0xdd, 0xdd);
|
||||
|
||||
const double MARGIN = 20;
|
||||
const double MARGIN = 30;
|
||||
agg::rect_d drawableBounds = {
|
||||
MARGIN, MARGIN,
|
||||
MARGIN*1.5, MARGIN,
|
||||
bitmapSpec.width - MARGIN, bitmapSpec.height - MARGIN
|
||||
};
|
||||
agg::rect_d colourbarBounds = {
|
||||
drawableBounds.x2 - MARGIN*4, drawableBounds.y1,
|
||||
drawableBounds.x2 - MARGIN, drawableBounds.y1,
|
||||
drawableBounds.x2, drawableBounds.y2
|
||||
};
|
||||
agg::rect_d graphBounds = {
|
||||
drawableBounds.x1, drawableBounds.y1,
|
||||
colourbarBounds.x1, drawableBounds.y2
|
||||
colourbarBounds.x1 - MARGIN*2, drawableBounds.y2
|
||||
};
|
||||
double blockWidth = (graphBounds.x2 - graphBounds.x1) / numColumns;
|
||||
double blockHeight = (graphBounds.y2 - graphBounds.y1) / numRows;
|
||||
painter.imageFilter(Agg2D::NoFilter);
|
||||
painter.imageResample(Agg2D::NoResample);
|
||||
painter.imageBlendMode(Agg2D::BlendDst);
|
||||
|
||||
/* Create the off-screen buffer which the actual bitmap goes into, and draw it. */
|
||||
|
||||
painter.noLine();
|
||||
for (int x=0; x<numColumns; x++)
|
||||
{
|
||||
for (int y=0; y<numRows; y++)
|
||||
{
|
||||
double xx = graphBounds.x1 + x*blockWidth;
|
||||
double yy = graphBounds.y2 - y*blockHeight;
|
||||
const int width = numRows; /* input interval on X axis */
|
||||
const int height = numColumns; /* response spread on Y axis */
|
||||
agg::srgba8 rbufdata[height][width];
|
||||
for (int y=0; y<height; y++)
|
||||
for (int x=0; x<width; x++)
|
||||
palette(frequencies[x][y], &rbufdata[y][x]);
|
||||
|
||||
painter.fillColor(hsvToRgb(360.0 * ((double)x/numColumns), 1.0, 1.0));
|
||||
painter.rectangle(xx, yy-blockHeight, xx+blockWidth, yy);
|
||||
}
|
||||
Agg2D::Image image((uint8_t*)&rbufdata[0][0], width, height, width*sizeof(agg::srgba8));
|
||||
painter.transformImage(image, graphBounds.x1, graphBounds.y2, graphBounds.x2, graphBounds.y1);
|
||||
}
|
||||
|
||||
/* Likewise for the colour bar. */
|
||||
|
||||
{
|
||||
const int HEIGHT = graphBounds.y2 - graphBounds.y1;
|
||||
agg::srgba8 rbufdata[HEIGHT];
|
||||
for (int y=0; y<HEIGHT; y++)
|
||||
palette((double)y / HEIGHT, &rbufdata[y]);
|
||||
|
||||
Agg2D::Image image((uint8_t*)&rbufdata[0], 1, HEIGHT, sizeof(agg::srgba8));
|
||||
painter.transformImage(image, colourbarBounds.x1, colourbarBounds.y2, colourbarBounds.x2, colourbarBounds.y1);
|
||||
}
|
||||
|
||||
draw_y_axis(painter, colourbarBounds.x1-5, colourbarBounds.y2, colourbarBounds.y1, 0.0, 1.0, 0.1, "{:.1f}");
|
||||
draw_y_axis(painter, graphBounds.x1-5, graphBounds.y2, graphBounds.y1, 0.0, 512.0/TICKS_PER_US, 5.0, "{:.0f}");
|
||||
draw_y_graticules(painter, graphBounds.x1, graphBounds.y2, graphBounds.x2, graphBounds.y1, 0.0, 512.0/TICKS_PER_US, 5.0);
|
||||
draw_x_axis(painter, graphBounds.x1, graphBounds.x2, graphBounds.y2+5, minInterval, maxInterval, 5.0, "{:.0f}");
|
||||
draw_x_graticules(painter, graphBounds.x1, graphBounds.y1, graphBounds.x2, graphBounds.y2, minInterval, maxInterval, 5.0);
|
||||
|
||||
painter.noFill();
|
||||
painter.lineColor(0, 0, 0);
|
||||
painter.rectangle(graphBounds.x1, drawableBounds.y1, drawableBounds.x2, drawableBounds.y2);
|
||||
painter.rectangle(graphBounds.x1, graphBounds.y1, graphBounds.x2, graphBounds.y2);
|
||||
painter.rectangle(colourbarBounds.x1, drawableBounds.y1, drawableBounds.x2, drawableBounds.y2);
|
||||
bitmapSpec.save();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user