[med-svn] [SCM] aghermann branch, master, updated. 9c95ea59282c4fc6ef7eb192072500f9d0659fc3
Andrei Zavada
johnhommer at gmail.com
Tue Jan 8 00:24:50 UTC 2013
The following commit has been merged in the master branch:
commit e59fec066d5fbde2e51c75435f172a4ada47c104
Author: Andrei Zavada <johnhommer at gmail.com>
Date: Fri Jan 4 18:36:03 2013 +0200
split sf::draw_overlays into own file, and phasic events stubs
diff --git a/src/metrics/phasic-events.hh b/src/metrics/phasic-events.hh
index f71e0ab..172ecce 100644
--- a/src/metrics/phasic-events.hh
+++ b/src/metrics/phasic-events.hh
@@ -29,6 +29,11 @@ using namespace std;
namespace metrics {
namespace phasic {
+enum TEventTypes {
+ spindle,
+ K_complex
+};
+
template <typename T>
list<agh::alg::SSpan<double>>
detect_spindles( const sigfile::SNamedChannel<T>&);
diff --git a/src/ui/mw/mw-loadsave.cc b/src/ui/mw/mw-loadsave.cc
index cb67060..4ae10d9 100644
--- a/src/ui/mw/mw-loadsave.cc
+++ b/src/ui/mw/mw-loadsave.cc
@@ -47,6 +47,10 @@ saving_colors()
{"SFProfilePSD", SExpDesignUI::TColour::sf_profile_psd},
{"SFProfileSWU", SExpDesignUI::TColour::sf_profile_swu},
{"SFProfileMC", SExpDesignUI::TColour::sf_profile_mc },
+
+ {"SFPhasicSpindle", SExpDesignUI::TColour::sf_phasic_spindle},
+ {"SFPhasicKComplex", SExpDesignUI::TColour::sf_phasic_Kcomplex},
+
{"SFEMG", SExpDesignUI::TColour::sf_emg },
{"SFHypnogram", SExpDesignUI::TColour::sf_hypnogram },
{"SFArtifacts", SExpDesignUI::TColour::sf_artifact },
diff --git a/src/ui/mw/mw-widgets.hh b/src/ui/mw/mw-widgets.hh
index 86b02be..f7a0b69 100644
--- a/src/ui/mw/mw-widgets.hh
+++ b/src/ui/mw/mw-widgets.hh
@@ -345,6 +345,7 @@ struct SExpDesignUIWidgets {
sf_annotations,
sf_selection,
sf_profile_psd, sf_profile_mc, sf_profile_swu,
+ sf_phasic_spindle, sf_phasic_Kcomplex,
sf_hypnogram,
sf_cursor,
sf_emg,
diff --git a/src/ui/sf/Makefile.am b/src/ui/sf/Makefile.am
index 0e17eee..9c47b04 100644
--- a/src/ui/sf/Makefile.am
+++ b/src/ui/sf/Makefile.am
@@ -19,11 +19,13 @@ liba_a_SOURCES := \
sf-ica.cc \
sf-ica_cb.cc \
sf-montage.cc \
+ sf-montage-overlays.cc \
sf-montage_cb.cc \
sf-patterns.cc \
sf-patterns_cb.cc \
sf-phasediff.cc \
sf-phasediff_cb.cc \
+ sf-phasic-events.cc \
sf-widgets.hh \
sf.cc \
sf.hh \
diff --git a/src/ui/sf/sf-channel.cc b/src/ui/sf/sf-channel.cc
index ea2f233..5e43bc2 100644
--- a/src/ui/sf/sf-channel.cc
+++ b/src/ui/sf/sf-channel.cc
@@ -53,6 +53,8 @@ SChannel( agh::CRecording& r,
draw_selection_course (false),
draw_selection_envelope (true),
draw_selection_dzcdf (false),
+ draw_phasic_spindle (true),
+ draw_phasic_Kcomplex (true),
apply_reconstituted (false),
config_keys_b ({
confval::SValidator<bool>( string(1, seq) + ".hidden", &hidden),
@@ -65,6 +67,8 @@ SChannel( agh::CRecording& r,
confval::SValidator<bool>( string(1, seq) + ".draw_bands", &draw_bands),
confval::SValidator<bool>( string(1, seq) + ".draw_spectrum", &draw_spectrum),
confval::SValidator<bool>( string(1, seq) + ".draw_mc", &draw_mc),
+ confval::SValidator<bool>( string(1, seq) + ".draw_phasic_spindle", &draw_phasic_spindle),
+ confval::SValidator<bool>( string(1, seq) + ".draw_phasic_Kcomplex", &draw_phasic_Kcomplex),
confval::SValidator<bool>( string(1, seq) + ".autoscale_profile", &autoscale_profile),
confval::SValidator<bool>( string(1, seq) + ".resample_signal", &resample_signal),
confval::SValidator<bool>( string(1, seq) + ".resample_power", &resample_power),
@@ -136,6 +140,10 @@ SChannel( agh::CRecording& r,
emg_profile = env_u - env_l;
}
+ // prevent exceptions from phasic_events.at
+ phasic_events[metrics::phasic::TEventTypes::spindle].clear();
+ phasic_events[metrics::phasic::TEventTypes::K_complex].clear();
+
// let it be so to avoid libconfig::readFile throwing exceptions
psd.display_scale = mc.display_scale =
emg_display_scale = DBL_MIN;
diff --git a/src/ui/sf/sf-montage-overlays.cc b/src/ui/sf/sf-montage-overlays.cc
new file mode 100644
index 0000000..e03f4c2
--- /dev/null
+++ b/src/ui/sf/sf-montage-overlays.cc
@@ -0,0 +1,373 @@
+// ;-*-C++-*-
+/*
+ * File name: ui/sf/sf-montage-overlays.cc
+ * Project: Aghermann
+ * Author: Andrei Zavada <johnhommer at gmail.com>
+ * Initial version: 2013-01-04
+ *
+ * Purpose: scoring facility: montage drawing area (profile overlays)
+ *
+ * License: GPL
+ */
+
+#include <cairo/cairo-svg.h>
+
+#include "common/lang.hh"
+#include "ui/misc.hh"
+#include "sf.hh"
+
+using namespace std;
+
+
+void
+aghui::SScoringFacility::SChannel::
+draw_overlays( cairo_t* cr,
+ int wd, float zeroy) const
+{
+ float pbot = zeroy + _p.interchannel_gap / 2.2,
+ ptop = zeroy - _p.interchannel_gap / 2.2;
+ bool overlay = false;
+
+ // PSD profile
+ if ( _p.mode == TMode::scoring and
+ draw_psd and type == sigfile::SChannel::TType::eeg ) {
+ overlay = true;
+
+ cairo_set_line_width( cr, 1.);
+ cairo_set_font_size( cr, 10);
+ guint i;
+
+ if ( draw_bands ) {
+ for ( size_t b = metrics::psd::TBand::delta; b <= psd.uppermost_band; ++b ) {
+ auto& P = psd.course_in_bands[b];
+ _p._p.CwB[SExpDesignUI::band2colour((metrics::psd::TBand)b)].set_source_rgba( cr, .5);
+ double zero = 0.5 / P.size() * _p.da_wd;
+ cairo_move_to( cr, zero,
+ - P[0] * psd.display_scale + pbot);
+ for ( i = 1; i < P.size(); ++i )
+ cairo_line_to( cr, ((double)i+0.5) / P.size() * _p.da_wd,
+ - P[i] * psd.display_scale + pbot);
+ if ( b == psd.focused_band ) {
+ cairo_line_to( cr, _p.da_wd, pbot);
+ cairo_line_to( cr, zero, pbot);
+ cairo_fill( cr);
+ }
+ cairo_stroke( cr);
+
+ if ( b == psd.focused_band ) {
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ snprintf_buf( "%s %g–%g",
+ _p._p.FreqBandNames[(unsigned)b],
+ _p._p.freq_bands[(unsigned)b][0], _p._p.freq_bands[(unsigned)b][1]);
+ } else {
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ snprintf_buf( "%s", _p._p.FreqBandNames[(unsigned)b]);
+ }
+ cairo_move_to( cr, _p.da_wd - 170,
+ ptop + psd.uppermost_band*12 - 12*(unsigned)b + 12);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+ } else {
+ _p._p.CwB[SExpDesignUI::TColour::sf_profile_psd].set_source_rgba( cr, .5);
+ double zero = 0.5 / psd.course.size() * _p.da_wd;
+ cairo_move_to( cr, zero,
+ psd.course[0]);
+ for ( i = 0; i < psd.course.size(); ++i )
+ cairo_line_to( cr, ((double)i+.5) / psd.course.size() * _p.da_wd,
+ - psd.course[i] * psd.display_scale + pbot);
+ cairo_line_to( cr, _p.da_wd, pbot);
+ cairo_line_to( cr, zero, pbot);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ snprintf_buf( "%g–%g Hz", psd.from, psd.upto);
+ cairo_move_to( cr, _p.da_wd - 170, pbot - 15);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+
+ // scale
+ {
+ cairo_set_source_rgb( cr, 0., 0., 0.);
+ cairo_set_line_width( cr, 1.5);
+ double dpuf =
+ agh::alg::sensible_scale_reduction_factor(
+ 1e6 * psd.display_scale, _p.interchannel_gap/2);
+ int x = 30;
+ cairo_move_to( cr, x, pbot - 5);
+ cairo_rel_line_to( cr, 0, -dpuf * (1e6 * psd.display_scale));
+ cairo_stroke( cr);
+
+ cairo_set_font_size( cr, 9);
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_move_to( cr, x + 5, pbot - 20);
+ snprintf_buf( "%g uV2", dpuf);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+
+ if ( draw_spectrum and _p.pagesize_is_right() ) {
+ guint gx = 120,
+ gy = ptop + 25,
+ gh = min( 60.f, pbot - ptop - 5),
+ gw = 80;
+ size_t m;
+
+ cairo_set_source_rgba( cr, 1., 1., 1., .8);
+ cairo_rectangle( cr, gx-15, gy-5, gw+15+5, gh+5+5);
+ cairo_fill( cr);
+
+ // grid lines
+ _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr, .1);
+ cairo_set_line_width( cr, .3);
+ for ( size_t i = 1; i < last_spectrum_bin; ++i ) {
+ cairo_move_to( cr, gx + (float)i/last_spectrum_bin * gw, gy);
+ cairo_rel_line_to( cr, 0, gh);
+ }
+ cairo_stroke( cr);
+
+ // spectrum
+ _p._p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr, .8);
+ cairo_set_line_width( cr, 2);
+ float factor = psd.display_scale / crecording.psd_profile.Pp.binsize;
+ cairo_move_to( cr,
+ gx, gy + gh - (2 + spectrum[0] * factor));
+ for ( m = 1; m < last_spectrum_bin; ++m ) {
+ cairo_line_to( cr,
+ gx + (float)m / last_spectrum_bin * gw,
+ gy + gh - spectrum[m] * factor);
+ }
+ cairo_stroke( cr);
+
+ // axes
+ _p._p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr, .5);
+ cairo_set_line_width( cr, .5);
+ cairo_move_to( cr, gx, gy);
+ cairo_rel_line_to( cr, 0, gh);
+ cairo_rel_line_to( cr, gw, 0);
+
+ // y ticks
+ m = 0;
+ while ( (++m * 1e6) < gh / factor ) {
+ cairo_move_to( cr, gx-3, gy + gh - (2 + (float)m*1e6 * factor));
+ cairo_rel_line_to( cr, 3, 0);
+ }
+ cairo_stroke( cr);
+
+ // labels
+ cairo_text_extents_t extents;
+ _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr);
+ cairo_set_font_size( cr, 8);
+
+ snprintf_buf( "%g Hz",
+ last_spectrum_bin * crecording.psd_profile.Pp.binsize);
+// draw_spectrum_absolute ? 'A' : 'R');
+ cairo_text_extents( cr, __buf__, &extents);
+ cairo_move_to( cr,
+ gx + gw - extents.width - 5,
+ gy + 4);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+ }
+
+ if ( _p.mode == TMode::scoring and
+ draw_mc and type == sigfile::SChannel::TType::eeg ) {
+ overlay = true;
+
+ cairo_set_line_width( cr, 1.);
+ cairo_set_font_size( cr, 10);
+ guint i;
+
+ _p._p.CwB[SExpDesignUI::TColour::sf_profile_mc].set_source_rgba( cr, .5);
+ double zero = 0.5 / mc.course.size() * _p.da_wd;
+ cairo_move_to( cr, zero,
+ mc.course[0]);
+ for ( i = 0; i < mc.course.size(); ++i )
+ cairo_line_to( cr, ((double)i+.5) / mc.course.size() * _p.da_wd,
+ - mc.course[i] * mc.display_scale + pbot);
+ cairo_line_to( cr, _p.da_wd, pbot);
+ cairo_line_to( cr, zero, pbot);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ snprintf_buf( "f0:%g", mc.f0);
+ cairo_move_to( cr, _p.da_wd - 70, pbot - 30);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+
+ // scale
+ {
+ cairo_set_source_rgb( cr, 0., 0., 0.);
+ cairo_set_line_width( cr, 1.5);
+ double dpuf =
+ agh::alg::sensible_scale_reduction_factor(
+ mc.display_scale, _p.interchannel_gap/2);
+ int x = 80;
+ cairo_move_to( cr, x, pbot - 5);
+ cairo_rel_line_to( cr, 0, -dpuf * mc.display_scale);
+ cairo_stroke( cr);
+
+ cairo_set_font_size( cr, 9);
+ //cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_move_to( cr, x + 5, pbot - 20);
+ snprintf_buf( "%g a.u.", dpuf);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+
+ }
+
+ if ( _p.mode == TMode::scoring and
+ draw_swu and type == sigfile::SChannel::TType::eeg ) {
+ overlay = true;
+
+ cairo_set_line_width( cr, 1.);
+ cairo_set_font_size( cr, 10);
+ guint i;
+
+ _p._p.CwB[SExpDesignUI::TColour::sf_profile_swu].set_source_rgba( cr, .5);
+ double zero = 0.5 / swu.course.size() * _p.da_wd;
+ cairo_move_to( cr, zero,
+ swu.course[0]);
+ for ( i = 0; i < swu.course.size(); ++i )
+ cairo_line_to( cr, ((double)i+.5) / swu.course.size() * _p.da_wd,
+ - swu.course[i] * swu.display_scale + pbot);
+ cairo_line_to( cr, _p.da_wd, pbot);
+ cairo_line_to( cr, zero, pbot);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+
+ // scale
+ {
+ cairo_set_source_rgb( cr, 0., 0., 0.);
+ cairo_set_line_width( cr, 1.5);
+ double dpuf =
+ agh::alg::sensible_scale_reduction_factor(
+ swu.display_scale, _p.interchannel_gap/2);
+ int x = 140;
+ cairo_move_to( cr, x, pbot - 5);
+ cairo_rel_line_to( cr, 0, -dpuf * swu.display_scale);
+ cairo_stroke( cr);
+
+ cairo_set_font_size( cr, 9);
+ //cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_move_to( cr, x + 5, pbot - 20);
+ snprintf_buf( "%g a.u.", dpuf);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+
+ }
+
+ // phasic events
+ if ( _p.mode == TMode::scoring and
+ draw_phasic_spindle and
+ not phasic_events.at(metrics::phasic::TEventTypes::spindle).empty() ) {
+
+ }
+ if ( _p.mode == TMode::scoring and
+ draw_phasic_Kcomplex and
+ not phasic_events.at(metrics::phasic::TEventTypes::K_complex).empty() ) {
+
+ }
+
+ // EMG profile
+ if ( _p.mode == TMode::scoring and draw_emg and
+ type == sigfile::SChannel::TType::emg ) {
+ overlay = true;
+
+ _p._p.CwB[SExpDesignUI::TColour::sf_emg].set_source_rgba( cr);
+ cairo_set_line_width( cr, .3);
+ double dps = (double)emg_profile.size() / _p.da_wd;
+ cairo_move_to( cr, 0., pbot - EMGProfileHeight/2);
+ size_t i = 0;
+ for ( ; i < emg_profile.size(); ++i )
+ cairo_line_to( cr, i / dps,
+ pbot - EMGProfileHeight/2 - emg_profile[i] * signal_display_scale/2);
+ for ( --i; i > 0; --i )
+ cairo_line_to( cr, i / dps,
+ pbot - EMGProfileHeight/2 + emg_profile[i] * signal_display_scale/2);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+ }
+
+ if ( overlay )
+ _p._draw_hour_ticks( cr, zeroy, pbot);
+
+ // crosshair (is drawn once in SScoringFacility::draw_montage), voltage at
+ if ( _p.draw_crosshair ) {
+ cairo_set_font_size( cr, 10);
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ _p._p.CwB[SExpDesignUI::TColour::sf_cursor].set_source_rgb( cr);
+ if ( this == &_p.channels.front() )
+ snprintf_buf( "%4.2f (%5.2fs)",
+ (draw_filtered_signal ? signal_filtered : signal_original)
+ [ (size_t)(_p.crosshair_at_time * samplerate()) ],
+ _p.crosshair_at_time - _p.cur_xvpage_start() - _p.skirting_run_per1 * _p.vpagesize());
+ else
+ snprintf_buf( "%4.2f",
+ (draw_filtered_signal ? signal_filtered : signal_original)
+ [ (size_t)(_p.crosshair_at_time * samplerate()) ]);
+
+ cairo_move_to( cr, _p.crosshair_at+2, ptop + 22);
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+
+ // samples per pixel
+ if ( _p.mode == TMode::scoring and resample_signal ) {
+ _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgb( cr);
+ cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size( cr, 8);
+ cairo_move_to( cr, _p.da_wd-40, ptop + 11);
+ snprintf_buf( "%4.2f spp", spp());
+ cairo_show_text( cr, __buf__);
+ cairo_stroke( cr);
+ }
+}
+
+
+
+
+
+
+void
+aghui::SScoringFacility::
+_draw_hour_ticks( cairo_t *cr, int htop, int hbot, bool with_cursor)
+{
+ cairo_set_line_width( cr, 1);
+ cairo_set_font_size( cr, 10);
+ float hours4 = (float)total_pages() * pagesize() / 3600 * 4;
+ for ( size_t i = 1; i < hours4; ++i ) {
+ guint tick_pos = (float)i / hours4 * da_wd;
+ _p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr);
+ cairo_move_to( cr, tick_pos, hbot);
+ cairo_rel_line_to( cr, 0, -((i%4 == 0) ? 20 : (i%2 == 0) ? 12 : 5));
+ if ( i % 4 == 0 ) {
+ snprintf_buf( "%2zuh", i/4);
+ _p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr);
+ cairo_move_to( cr, tick_pos+5, hbot - 2);
+ cairo_show_text( cr, __buf__);
+ }
+ }
+ cairo_stroke( cr);
+
+ if ( with_cursor ) {
+ _p.CwB[SExpDesignUI::TColour::sf_cursor].set_source_rgba( cr);
+ cairo_rectangle( cr,
+ (double)cur_vpage() / total_vpages() * da_wd, htop,
+ max( .5, 1. / total_vpages() * da_wd), hbot - htop);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+ }
+}
+
+
+
+
+// eof
+
diff --git a/src/ui/sf/sf-montage.cc b/src/ui/sf/sf-montage.cc
index d9a75b2..6931ff9 100644
--- a/src/ui/sf/sf-montage.cc
+++ b/src/ui/sf/sf-montage.cc
@@ -17,8 +17,6 @@
#include "sf.hh"
using namespace std;
-using namespace aghui;
-
inline namespace {
@@ -479,6 +477,39 @@ draw_page( cairo_t *cr,
}
}
+ // phasic events
+ if ( _p.mode == TMode::scoring and
+ draw_phasic_spindle and
+ not phasic_events.at(metrics::phasic::TEventTypes::spindle).empty() ) {
+ cairo_pattern_t *cp = cairo_pattern_create_linear( 0., ptop+10, 0., ptop+30);
+ for ( auto &cA : phasic_events.at(metrics::phasic::TEventTypes::spindle) ) {
+ agh::alg::SSpan<size_t> A = cA * samplerate();
+ if ( agh::alg::overlap( (int)A.a, (int)A.z, cvpa, cvpe) ) {
+ _p._p.CwB[SExpDesignUI::TColour::sf_phasic_spindle].pattern_add_color_stop_rgba( cp, 0., 1.);
+ _p._p.CwB[SExpDesignUI::TColour::sf_phasic_spindle].pattern_add_color_stop_rgba( cp, .1, 0.3);
+ _p._p.CwB[SExpDesignUI::TColour::sf_phasic_spindle].pattern_add_color_stop_rgba( cp, 1., 0.);
+ cairo_set_source( cr, cp);
+
+ int aa = (int)A.a - cvpa,
+ ae = (int)A.z - cvpa;
+ if ( aa < 0 ) aa = 0;
+ if ( ae > evpz ) ae = evpz;
+ cairo_rectangle( cr,
+ (float)(aa % evpz) / evpz * wd, ptop+10,
+ (float)(ae - aa) / evpz * wd, ptop+30);
+ cairo_fill( cr);
+ cairo_stroke( cr);
+ } else if ( (int)A.a > cvpe ) // no more artifacts up to and on current page
+ break;
+ }
+ cairo_pattern_destroy( cp);
+ }
+ if ( _p.mode == TMode::scoring and
+ draw_phasic_Kcomplex and
+ not phasic_events.at(metrics::phasic::TEventTypes::K_complex).empty() ) {
+
+ }
+
// annotations
{
auto& Aa = crecording.F().annotations(name);
@@ -584,337 +615,18 @@ draw_page( cairo_t *cr,
void
-aghui::SScoringFacility::SChannel::
-draw_overlays( cairo_t* cr,
- int wd, float zeroy) const
-{
- float pbot = zeroy + _p.interchannel_gap / 2.2,
- ptop = zeroy - _p.interchannel_gap / 2.2;
- bool overlay = false;
-
- // PSD profile
- if ( _p.mode == TMode::scoring and
- draw_psd and type == sigfile::SChannel::TType::eeg ) {
- overlay = true;
-
- cairo_set_line_width( cr, 1.);
- cairo_set_font_size( cr, 10);
- guint i;
-
- if ( draw_bands ) {
- for ( size_t b = metrics::psd::TBand::delta; b <= psd.uppermost_band; ++b ) {
- auto& P = psd.course_in_bands[b];
- _p._p.CwB[SExpDesignUI::band2colour((metrics::psd::TBand)b)].set_source_rgba( cr, .5);
- double zero = 0.5 / P.size() * _p.da_wd;
- cairo_move_to( cr, zero,
- - P[0] * psd.display_scale + pbot);
- for ( i = 1; i < P.size(); ++i )
- cairo_line_to( cr, ((double)i+0.5) / P.size() * _p.da_wd,
- - P[i] * psd.display_scale + pbot);
- if ( b == psd.focused_band ) {
- cairo_line_to( cr, _p.da_wd, pbot);
- cairo_line_to( cr, zero, pbot);
- cairo_fill( cr);
- }
- cairo_stroke( cr);
-
- if ( b == psd.focused_band ) {
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- snprintf_buf( "%s %g–%g",
- _p._p.FreqBandNames[(unsigned)b],
- _p._p.freq_bands[(unsigned)b][0], _p._p.freq_bands[(unsigned)b][1]);
- } else {
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- snprintf_buf( "%s", _p._p.FreqBandNames[(unsigned)b]);
- }
- cairo_move_to( cr, _p.da_wd - 170,
- ptop + psd.uppermost_band*12 - 12*(unsigned)b + 12);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
- } else {
- _p._p.CwB[SExpDesignUI::TColour::sf_profile_psd].set_source_rgba( cr, .5);
- double zero = 0.5 / psd.course.size() * _p.da_wd;
- cairo_move_to( cr, zero,
- psd.course[0]);
- for ( i = 0; i < psd.course.size(); ++i )
- cairo_line_to( cr, ((double)i+.5) / psd.course.size() * _p.da_wd,
- - psd.course[i] * psd.display_scale + pbot);
- cairo_line_to( cr, _p.da_wd, pbot);
- cairo_line_to( cr, zero, pbot);
- cairo_fill( cr);
- cairo_stroke( cr);
-
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- snprintf_buf( "%g–%g Hz", psd.from, psd.upto);
- cairo_move_to( cr, _p.da_wd - 170, pbot - 15);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-
- // scale
- {
- cairo_set_source_rgb( cr, 0., 0., 0.);
- cairo_set_line_width( cr, 1.5);
- double dpuf =
- agh::alg::sensible_scale_reduction_factor(
- 1e6 * psd.display_scale, _p.interchannel_gap/2);
- int x = 30;
- cairo_move_to( cr, x, pbot - 5);
- cairo_rel_line_to( cr, 0, -dpuf * (1e6 * psd.display_scale));
- cairo_stroke( cr);
-
- cairo_set_font_size( cr, 9);
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- cairo_move_to( cr, x + 5, pbot - 20);
- snprintf_buf( "%g uV2", dpuf);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-
- if ( draw_spectrum and _p.pagesize_is_right() ) {
- guint gx = 120,
- gy = ptop + 25,
- gh = min( 60.f, pbot - ptop - 5),
- gw = 80;
- size_t m;
-
- cairo_set_source_rgba( cr, 1., 1., 1., .8);
- cairo_rectangle( cr, gx-15, gy-5, gw+15+5, gh+5+5);
- cairo_fill( cr);
-
- // grid lines
- _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr, .1);
- cairo_set_line_width( cr, .3);
- for ( size_t i = 1; i < last_spectrum_bin; ++i ) {
- cairo_move_to( cr, gx + (float)i/last_spectrum_bin * gw, gy);
- cairo_rel_line_to( cr, 0, gh);
- }
- cairo_stroke( cr);
-
- // spectrum
- _p._p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr, .8);
- cairo_set_line_width( cr, 2);
- float factor = psd.display_scale / crecording.psd_profile.Pp.binsize;
- cairo_move_to( cr,
- gx, gy + gh - (2 + spectrum[0] * factor));
- for ( m = 1; m < last_spectrum_bin; ++m ) {
- cairo_line_to( cr,
- gx + (float)m / last_spectrum_bin * gw,
- gy + gh - spectrum[m] * factor);
- }
- cairo_stroke( cr);
-
- // axes
- _p._p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr, .5);
- cairo_set_line_width( cr, .5);
- cairo_move_to( cr, gx, gy);
- cairo_rel_line_to( cr, 0, gh);
- cairo_rel_line_to( cr, gw, 0);
-
- // y ticks
- m = 0;
- while ( (++m * 1e6) < gh / factor ) {
- cairo_move_to( cr, gx-3, gy + gh - (2 + (float)m*1e6 * factor));
- cairo_rel_line_to( cr, 3, 0);
- }
- cairo_stroke( cr);
-
- // labels
- cairo_text_extents_t extents;
- _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr);
- cairo_set_font_size( cr, 8);
-
- snprintf_buf( "%g Hz",
- last_spectrum_bin * crecording.psd_profile.Pp.binsize);
-// draw_spectrum_absolute ? 'A' : 'R');
- cairo_text_extents( cr, __buf__, &extents);
- cairo_move_to( cr,
- gx + gw - extents.width - 5,
- gy + 4);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
- }
-
- if ( _p.mode == TMode::scoring and
- draw_mc and type == sigfile::SChannel::TType::eeg ) {
- overlay = true;
-
- cairo_set_line_width( cr, 1.);
- cairo_set_font_size( cr, 10);
- guint i;
-
- _p._p.CwB[SExpDesignUI::TColour::sf_profile_mc].set_source_rgba( cr, .5);
- double zero = 0.5 / mc.course.size() * _p.da_wd;
- cairo_move_to( cr, zero,
- mc.course[0]);
- for ( i = 0; i < mc.course.size(); ++i )
- cairo_line_to( cr, ((double)i+.5) / mc.course.size() * _p.da_wd,
- - mc.course[i] * mc.display_scale + pbot);
- cairo_line_to( cr, _p.da_wd, pbot);
- cairo_line_to( cr, zero, pbot);
- cairo_fill( cr);
- cairo_stroke( cr);
-
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- snprintf_buf( "f0:%g", mc.f0);
- cairo_move_to( cr, _p.da_wd - 70, pbot - 30);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
-
- // scale
- {
- cairo_set_source_rgb( cr, 0., 0., 0.);
- cairo_set_line_width( cr, 1.5);
- double dpuf =
- agh::alg::sensible_scale_reduction_factor(
- mc.display_scale, _p.interchannel_gap/2);
- int x = 80;
- cairo_move_to( cr, x, pbot - 5);
- cairo_rel_line_to( cr, 0, -dpuf * mc.display_scale);
- cairo_stroke( cr);
-
- cairo_set_font_size( cr, 9);
- //cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- cairo_move_to( cr, x + 5, pbot - 20);
- snprintf_buf( "%g a.u.", dpuf);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-
- }
-
- if ( _p.mode == TMode::scoring and
- draw_swu and type == sigfile::SChannel::TType::eeg ) {
- overlay = true;
-
- cairo_set_line_width( cr, 1.);
- cairo_set_font_size( cr, 10);
- guint i;
-
- _p._p.CwB[SExpDesignUI::TColour::sf_profile_swu].set_source_rgba( cr, .5);
- double zero = 0.5 / swu.course.size() * _p.da_wd;
- cairo_move_to( cr, zero,
- swu.course[0]);
- for ( i = 0; i < swu.course.size(); ++i )
- cairo_line_to( cr, ((double)i+.5) / swu.course.size() * _p.da_wd,
- - swu.course[i] * swu.display_scale + pbot);
- cairo_line_to( cr, _p.da_wd, pbot);
- cairo_line_to( cr, zero, pbot);
- cairo_fill( cr);
- cairo_stroke( cr);
-
- // scale
- {
- cairo_set_source_rgb( cr, 0., 0., 0.);
- cairo_set_line_width( cr, 1.5);
- double dpuf =
- agh::alg::sensible_scale_reduction_factor(
- swu.display_scale, _p.interchannel_gap/2);
- int x = 140;
- cairo_move_to( cr, x, pbot - 5);
- cairo_rel_line_to( cr, 0, -dpuf * swu.display_scale);
- cairo_stroke( cr);
-
- cairo_set_font_size( cr, 9);
- //cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- cairo_move_to( cr, x + 5, pbot - 20);
- snprintf_buf( "%g a.u.", dpuf);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-
- }
-
- // EMG profile
- if ( _p.mode == TMode::scoring and draw_emg and
- type == sigfile::SChannel::TType::emg ) {
- overlay = true;
-
- _p._p.CwB[SExpDesignUI::TColour::sf_emg].set_source_rgba( cr);
- cairo_set_line_width( cr, .3);
- double dps = (double)emg_profile.size() / _p.da_wd;
- cairo_move_to( cr, 0., pbot - EMGProfileHeight/2);
- size_t i = 0;
- for ( ; i < emg_profile.size(); ++i )
- cairo_line_to( cr, i / dps,
- pbot - EMGProfileHeight/2 - emg_profile[i] * signal_display_scale/2);
- for ( --i; i > 0; --i )
- cairo_line_to( cr, i / dps,
- pbot - EMGProfileHeight/2 + emg_profile[i] * signal_display_scale/2);
- cairo_fill( cr);
- cairo_stroke( cr);
- }
-
- if ( overlay )
- _p._draw_hour_ticks( cr, zeroy, pbot);
-
- // crosshair (is drawn once in SScoringFacility::draw_montage), voltage at
- if ( _p.draw_crosshair ) {
- cairo_set_font_size( cr, 10);
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
- _p._p.CwB[SExpDesignUI::TColour::sf_cursor].set_source_rgb( cr);
- if ( this == &_p.channels.front() )
- snprintf_buf( "%4.2f (%5.2fs)",
- (draw_filtered_signal ? signal_filtered : signal_original)
- [ (size_t)(_p.crosshair_at_time * samplerate()) ],
- _p.crosshair_at_time - _p.cur_xvpage_start() - _p.skirting_run_per1 * _p.vpagesize());
- else
- snprintf_buf( "%4.2f",
- (draw_filtered_signal ? signal_filtered : signal_original)
- [ (size_t)(_p.crosshair_at_time * samplerate()) ]);
-
- cairo_move_to( cr, _p.crosshair_at+2, ptop + 22);
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-
- // samples per pixel
- if ( _p.mode == TMode::scoring and resample_signal ) {
- _p._p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgb( cr);
- cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_BOLD);
- cairo_set_font_size( cr, 8);
- cairo_move_to( cr, _p.da_wd-40, ptop + 11);
- snprintf_buf( "%4.2f spp", spp());
- cairo_show_text( cr, __buf__);
- cairo_stroke( cr);
- }
-}
-
-
-void
aghui::SScoringFacility::
-_draw_hour_ticks( cairo_t *cr, int htop, int hbot, bool with_cursor)
+draw_montage( const char *fname) // to a file
{
- cairo_set_line_width( cr, 1);
- cairo_set_font_size( cr, 10);
- float hours4 = (float)total_pages() * pagesize() / 3600 * 4;
- for ( size_t i = 1; i < hours4; ++i ) {
- guint tick_pos = (float)i / hours4 * da_wd;
- _p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr);
- cairo_move_to( cr, tick_pos, hbot);
- cairo_rel_line_to( cr, 0, -((i%4 == 0) ? 20 : (i%2 == 0) ? 12 : 5));
- if ( i % 4 == 0 ) {
- snprintf_buf( "%2zuh", i/4);
- _p.CwB[SExpDesignUI::TColour::sf_labels].set_source_rgba( cr);
- cairo_move_to( cr, tick_pos+5, hbot - 2);
- cairo_show_text( cr, __buf__);
- }
- }
- cairo_stroke( cr);
-
- if ( with_cursor ) {
- _p.CwB[SExpDesignUI::TColour::sf_cursor].set_source_rgba( cr);
- cairo_rectangle( cr,
- (double)cur_vpage() / total_vpages() * da_wd, htop,
- max( .5, 1. / total_vpages() * da_wd), hbot - htop);
- cairo_fill( cr);
- cairo_stroke( cr);
- }
+ cairo_surface_t *cs = cairo_svg_surface_create( fname, da_wd, da_ht);
+ cairo_t *cr = cairo_create( cs);
+ draw_montage( cr);
+ cairo_destroy( cr);
+ cairo_surface_destroy( cs);
}
+
template <class T>
void
aghui::SScoringFacility::
@@ -984,16 +696,6 @@ _draw_matrix_to_montage( cairo_t *cr, const itpp::Mat<T>& mat)
}
}
-void
-aghui::SScoringFacility::
-draw_montage( const char *fname) // to a file
-{
- cairo_surface_t *cs = cairo_svg_surface_create( fname, da_wd, da_ht);
- cairo_t *cr = cairo_create( cs);
- draw_montage( cr);
- cairo_destroy( cr);
- cairo_surface_destroy( cs);
-}
void
aghui::SScoringFacility::
@@ -1031,15 +733,17 @@ draw_montage( cairo_t* cr)
switch ( mode ) {
case TMode::showing_ics:
if ( ica_components.size() == 0 ) {
- ::cairo_put_banner( cr, da_wd, da_ht,
- "Now set up ICA parameters, then press [Compute ICs]");
+ aghui::cairo_put_banner(
+ cr, da_wd, da_ht,
+ "Now set up ICA parameters, then press [Compute ICs]");
} else
_draw_matrix_to_montage( cr, ica_components);
// draw ignoring channels' zeroy
break;
case TMode::separating:
- ::cairo_put_banner( cr, da_wd, da_ht,
- "Separating...");
+ aghui::cairo_put_banner(
+ cr, da_wd, da_ht,
+ "Separating...");
break;
case TMode::showing_remixed:
case TMode::scoring:
diff --git a/src/ui/sf/sf-phasic-events.cc b/src/ui/sf/sf-phasic-events.cc
new file mode 100644
index 0000000..1328424
--- /dev/null
+++ b/src/ui/sf/sf-phasic-events.cc
@@ -0,0 +1,30 @@
+// ;-*-C++-*-
+/*
+ * File name: ui/sf/sf-phasic-events.cc
+ * Project: Aghermann
+ * Author: Andrei Zavada <johnhommer at gmail.com>
+ * Initial version: 2013-01-04
+ *
+ * Purpose: scoring facility: phasic events
+ *
+ * License: GPL
+ */
+
+#include "metrics/phasic-events.hh"
+#include "sf.hh"
+
+using namespace std;
+
+void
+aghui::SScoringFacility::SChannel::
+get_phasic_events()
+{
+ using namespace metrics::phasic;
+ auto H = sigfile::SNamedChannel<int> (crecording.F(), _h);
+ phasic_events[TEventTypes::spindle] =
+ detect_spindles( H);
+ phasic_events[TEventTypes::K_complex] =
+ detect_Kcomplexes( H);
+}
+
+// eof
diff --git a/src/ui/sf/sf.cc b/src/ui/sf/sf.cc
index 0dac616..9556f8b 100644
--- a/src/ui/sf/sf.cc
+++ b/src/ui/sf/sf.cc
@@ -319,6 +319,31 @@ channel_by_idx( size_t i)
}
+aghui::SScoringFacility::SChannel*
+__attribute__ ((pure))
+aghui::SScoringFacility::
+channel_near( int y)
+{
+ int nearest = INT_MAX, thisy;
+ auto nearest_h = &channels.front();
+ for ( auto &H : channels ) {
+ if ( H.hidden )
+ continue;
+ thisy = (y > H.zeroy) ? y - H.zeroy : H.zeroy - y;
+ // if ( thisy < nearest )
+ // return &const_cast<SChannel&>(H);
+ // else
+ // return nearest_h;
+ if ( thisy < nearest ) {
+ nearest = thisy;
+ nearest_h = &H;
+ }
+ }
+ return nearest_h;
+}
+
+
+
void
@@ -573,31 +598,6 @@ queue_redraw_all() const
-aghui::SScoringFacility::SChannel*
-__attribute__ ((pure))
-aghui::SScoringFacility::
-channel_near( int y)
-{
- int nearest = INT_MAX, thisy;
- SChannel* nearest_h = &channels.front();
- for ( auto &H : channels ) {
- if ( H.hidden )
- continue;
- thisy = (y > H.zeroy) ? y - H.zeroy : H.zeroy - y;
- // if ( thisy < nearest )
- // return &const_cast<SChannel&>(H);
- // else
- // return nearest_h;
- if ( thisy < nearest ) {
- nearest = thisy;
- nearest_h = &H;
- }
- }
- return nearest_h;
-}
-
-
-
diff --git a/src/ui/sf/sf.hh b/src/ui/sf/sf.hh
index 4a24f01..3455572 100644
--- a/src/ui/sf/sf.hh
+++ b/src/ui/sf/sf.hh
@@ -13,13 +13,17 @@
#ifndef _AGH_UI_SCORING_FACILITY_H
#define _AGH_UI_SCORING_FACILITY_H
+#include <map>
+#include <list>
+
#include <cairo/cairo.h>
#include <cairo/cairo-svg.h>
#include <gtk/gtk.h>
+#include "common/alg.hh"
#include "common/config-validate.hh"
#include "sigproc/winfun.hh"
-#include "metrics/page-metrics-base.hh"
+#include "metrics/phasic-events.hh"
#include "expdesign/primaries.hh"
#include "ica/ica.hh"
#include "ui/globals.hh"
@@ -59,9 +63,9 @@ class SScoringFacility
agh::CSubject::SEpisode&
_sepisode;
public:
- agh::CSubject& csubject() const { return _csubject; }
- agh::CSubject::SEpisode& sepisode() const { return _sepisode; }
- const string& session() const { return _session; }
+ agh::CSubject& csubject() const { return _csubject; }
+ agh::CSubject::SEpisode& sepisode() const { return _sepisode; }
+ const string& session() const { return _session; }
// channels
struct SChannel {
@@ -205,6 +209,12 @@ class SScoringFacility
emg_profile;
double emg_display_scale;
+ // phasic events
+ map<metrics::phasic::TEventTypes, list<agh::alg::SSpan<double>>>
+ phasic_events;
+ void
+ get_phasic_events();
+
// region
void mark_region_as_artifact( bool do_mark);
void mark_region_as_annotation( const char*);
@@ -241,7 +251,9 @@ class SScoringFacility
resample_power,
draw_selection_course,
draw_selection_envelope,
- draw_selection_dzcdf;
+ draw_selection_dzcdf,
+ draw_phasic_spindle,
+ draw_phasic_Kcomplex;
bool discard_marked,
apply_reconstituted;
--
Sleep experiment manager
More information about the debian-med-commit
mailing list