[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