/// <summary> /// Метод возвращает режим спектрограммы по режиму визуализации /// </summary> /// <param name="Mode">Режим для преобразования</param> /// <returns>Возвращает режим спектрограммы</returns> public static SpectrogramModes VisualizationModeToSpectrogramMode(VisualizationModes Mode) { switch (Mode) { case VisualizationModes.Static_spectrogram: return(SpectrogramModes.StaticSpectrogram); case VisualizationModes.Moving_spectrogram: return(SpectrogramModes.MovingSpectrogram); case VisualizationModes.Symmetric_moving_spectrogram: return(SpectrogramModes.SymmetricMovingSpectrogram); case VisualizationModes.Histogram_with_no_symmetry: return(SpectrogramModes.HistogramWithNoSymmetry); case VisualizationModes.Histogram_with_horizontal_symmetry: return(SpectrogramModes.HistogramWithHorizontalSymmetry); case VisualizationModes.Histogram_with_vertical_symmetry: return(SpectrogramModes.HistogramWithVerticalSymmetry); case VisualizationModes.Histogram_with_full_symmetry: return(SpectrogramModes.HistogramWithFullSymmetry); case VisualizationModes.Static_amplitude: return(SpectrogramModes.StaticAmplitude); case VisualizationModes.Moving_amplitude: return(SpectrogramModes.MovingAmplitude); default: return(SpectrogramModes.NoSpectrogram); } }
/////////////////////////////////////////////////////////////////////////////// // Methods for doing main class job // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Small helping Methods // /////////////////////////////////////////////////////////////////////////////// /// <summary> /// This method calculates the bounding rectangle of a circle /// with the given value and <see cref="VisualizationModes"/> /// at the given center. /// </summary> /// <param name="pointF"> /// A <see cref="PointF"/> with the circles center. /// </param> /// <param name="sum"> /// The <see cref="double"/> with the circles value. /// </param> /// <param name="mode"> /// The <see cref="VisualizationModes"/> to use. /// </param> /// <returns> /// A <see cref="RectangleF"/> with the circles bounding rect. /// </returns> private RectangleF GetCircleBounds(PointF pointF, double sum, VisualizationModes mode) { var offset = (float)(sum * this.bubbleFactor); if ((mode & VisualizationModes.NumberOfFixations) == VisualizationModes.NumberOfFixations) { offset *= 500; } if ((mode & VisualizationModes.AverageFixationDuration) == VisualizationModes.AverageFixationDuration) { offset *= 50; } var bounds = new RectangleF(pointF.X - offset, pointF.Y - offset, offset * 2, offset * 2); return(bounds); }
/// <summary> /// This method draws the statistic bubbles and transisiton arrows /// of given <see cref="SampleType"/> in given <see cref="VisualizationModes"/>. /// </summary> /// <param name="mode"> /// The <see cref="VisualizationModes"/> to be used. /// </param> /// <param name="sampleType"> /// The <see cref="SampleType"/> of the data. /// </param> public void DrawAOIStatistics(VisualizationModes mode, SampleType sampleType) { // Skip if no data available if (this.aoiStatistics == null) { return; } // Get all statistical elements var statisticalElements = this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_ARROW); statisticalElements.AddRange(this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_BUBBLE)); this.Elements.RemoveAll(statisticalElements); var distances = new List<int>(); var aoisWithoutSearchRects = new VGElementCollection(); foreach (VGElement aoi in this.AoiCollection) { if (aoi.StyleGroup != VGStyleGroup.AOI_SEARCHRECT) { aoisWithoutSearchRects.Add(aoi); } } foreach (VGElement aoi in aoisWithoutSearchRects) { if (!this.aoiStatistics.ContainsKey(aoi.Name)) { continue; } var aoiStatistic = this.aoiStatistics[aoi.Name]; if ((mode & VisualizationModes.FixationTime) == VisualizationModes.FixationTime) { if (aoiStatistic.SumOfTimeOfAllFixations > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.SumOfTimeOfAllFixations, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.SumOfTimeOfAllFixations + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.NumberOfFixations) == VisualizationModes.NumberOfFixations) { if (aoiStatistic.FixationCount > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationCount, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationCount.ToString(CultureInfo.InvariantCulture), string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.AverageFixationDuration) == VisualizationModes.AverageFixationDuration) { if (aoiStatistic.FixationDurationMean > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationDurationMean, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationDurationMean.ToString("N0") + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } } // Check for absolute or relative transition values var absolute = (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions; if ((mode & VisualizationModes.RelativeTransitions) == VisualizationModes.RelativeTransitions || (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions) { DataView trialsFixations = null; // Get filtered fixations data view switch (sampleType) { case SampleType.Gaze: trialsFixations = this.GazeFixationsView; break; case SampleType.Mouse: trialsFixations = this.MouseFixationsView; break; } var transitions = Statistics.Statistic.CreateTransitionMatrixForSingleAOIs( trialsFixations, aoisWithoutSearchRects); float transitionSum = 0; // Calculate transition total sum only if relative values are requested. if (!absolute) { for (var i = 0; i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = 0; j <= transitions.GetUpperBound(1); j++) { // Only take values outside the diagonal if (i == j || j == 0) { continue; } transitionSum += (int)transitions.GetValue(i, j); } } } // Write transitionMatrix to dgv for (var i = transitions.GetLowerBound(0); i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = transitions.GetLowerBound(1); j <= transitions.GetUpperBound(1); j++) { // Only take values above the diagonal if (i >= j) { continue; } float transAtoB; float transBtoA; if (absolute) { transAtoB = (int)transitions.GetValue(i, j); transBtoA = (int)transitions.GetValue(j, i); } else { transAtoB = (float)Math.Round((int)transitions.GetValue(i, j) / transitionSum * 100, 1); transBtoA = (float)Math.Round((int)transitions.GetValue(j, i) / transitionSum * 100, 1); } if (transAtoB > 0 || transBtoA > 0) { var showNumbers = false; if ((this.ArrowDrawAction & ShapeDrawAction.Name) == ShapeDrawAction.Name) { this.ArrowDrawAction |= ~ShapeDrawAction.Name; showNumbers = true; } var arrow = new VGArrow(this.ArrowDrawAction, this.ArrowPen); arrow.Brush = this.ArrowBrush; if (!showNumbers) { arrow.HideWeights = true; } var location1 = aoisWithoutSearchRects[i - 1].Center; var location2 = aoisWithoutSearchRects[j - 1].Center; var distanceFirst = distances.Count >= i ? distances[i - 1] : 15; var distanceSecond = distances.Count >= j ? distances[j - 1] : 15; if (location1.X <= location2.X) { arrow.FirstPoint = location1; arrow.SecondPoint = location2; arrow.FirstPointDistance = distanceFirst; arrow.SecondPointDistance = distanceSecond; arrow.FirstPointWeight = transBtoA; arrow.SecondPointWeight = transAtoB; } else { arrow.FirstPoint = location2; arrow.SecondPoint = location1; arrow.FirstPointDistance = distanceSecond; arrow.SecondPointDistance = distanceFirst; arrow.FirstPointWeight = transAtoB; arrow.SecondPointWeight = transBtoA; } arrow.FormatString = "N0"; if (!absolute) { if (arrow.FirstPointWeight < 1 && arrow.SecondPointWeight < 1) { arrow.FormatString = "N1"; } arrow.AddOnString = "%"; } arrow.WeightFont = this.ArrowFont; arrow.WeightFontColor = this.ArrowFontColor; arrow.ScaleFactor = this.ArrowFactor; arrow.StyleGroup = VGStyleGroup.AOI_STATISTICS_ARROW; arrow.TextAlignment = this.ArrowTextAlignment; this.Elements.Add(arrow); } } } } this.DrawForeground(true); }
/////////////////////////////////////////////////////////////////////////////// // Methods for doing main class job // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Small helping Methods // /////////////////////////////////////////////////////////////////////////////// /// <summary> /// This method calculates the bounding rectangle of a circle /// with the given value and <see cref="VisualizationModes"/> /// at the given center. /// </summary> /// <param name="pointF"> /// A <see cref="PointF"/> with the circles center. /// </param> /// <param name="sum"> /// The <see cref="double"/> with the circles value. /// </param> /// <param name="mode"> /// The <see cref="VisualizationModes"/> to use. /// </param> /// <returns> /// A <see cref="RectangleF"/> with the circles bounding rect. /// </returns> private RectangleF GetCircleBounds(PointF pointF, double sum, VisualizationModes mode) { var offset = (float)(sum * this.bubbleFactor); if ((mode & VisualizationModes.NumberOfFixations) == VisualizationModes.NumberOfFixations) { offset *= 500; } if ((mode & VisualizationModes.AverageFixationDuration) == VisualizationModes.AverageFixationDuration) { offset *= 50; } var bounds = new RectangleF(pointF.X - offset, pointF.Y - offset, offset * 2, offset * 2); return bounds; }
/// <summary> /// This method draws the statistic bubbles and transisiton arrows /// of given <see cref="SampleType"/> in given <see cref="VisualizationModes"/>. /// </summary> /// <param name="mode"> /// The <see cref="VisualizationModes"/> to be used. /// </param> /// <param name="sampleType"> /// The <see cref="SampleType"/> of the data. /// </param> public void DrawAOIStatistics(VisualizationModes mode, SampleType sampleType) { // Skip if no data available if (this.aoiStatistics == null) { return; } // Get all statistical elements var statisticalElements = this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_ARROW); statisticalElements.AddRange(this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_BUBBLE)); this.Elements.RemoveAll(statisticalElements); var distances = new List <int>(); var aoisWithoutSearchRects = new VGElementCollection(); foreach (VGElement aoi in this.AoiCollection) { if (aoi.StyleGroup != VGStyleGroup.AOI_SEARCHRECT) { aoisWithoutSearchRects.Add(aoi); } } foreach (VGElement aoi in aoisWithoutSearchRects) { if (!this.aoiStatistics.ContainsKey(aoi.Name)) { continue; } var aoiStatistic = this.aoiStatistics[aoi.Name]; if ((mode & VisualizationModes.FixationTime) == VisualizationModes.FixationTime) { if (aoiStatistic.SumOfTimeOfAllFixations > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.SumOfTimeOfAllFixations, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.SumOfTimeOfAllFixations + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.NumberOfFixations) == VisualizationModes.NumberOfFixations) { if (aoiStatistic.FixationCount > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationCount, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationCount.ToString(CultureInfo.InvariantCulture), string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.AverageFixationDuration) == VisualizationModes.AverageFixationDuration) { if (aoiStatistic.FixationDurationMean > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationDurationMean, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationDurationMean.ToString("N0") + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } } // Check for absolute or relative transition values var absolute = (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions; if ((mode & VisualizationModes.RelativeTransitions) == VisualizationModes.RelativeTransitions || (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions) { DataView trialsFixations = null; // Get filtered fixations data view switch (sampleType) { case SampleType.Gaze: trialsFixations = this.GazeFixationsView; break; case SampleType.Mouse: trialsFixations = this.MouseFixationsView; break; } var transitions = Statistics.Statistic.CreateTransitionMatrixForSingleAOIs( trialsFixations, aoisWithoutSearchRects); float transitionSum = 0; // Calculate transition total sum only if relative values are requested. if (!absolute) { for (var i = 0; i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = 0; j <= transitions.GetUpperBound(1); j++) { // Only take values outside the diagonal if (i == j || j == 0) { continue; } transitionSum += (int)transitions.GetValue(i, j); } } } // Write transitionMatrix to dgv for (var i = transitions.GetLowerBound(0); i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = transitions.GetLowerBound(1); j <= transitions.GetUpperBound(1); j++) { // Only take values above the diagonal if (i >= j) { continue; } float transAtoB; float transBtoA; if (absolute) { transAtoB = (int)transitions.GetValue(i, j); transBtoA = (int)transitions.GetValue(j, i); } else { transAtoB = (float)Math.Round((int)transitions.GetValue(i, j) / transitionSum * 100, 1); transBtoA = (float)Math.Round((int)transitions.GetValue(j, i) / transitionSum * 100, 1); } if (transAtoB > 0 || transBtoA > 0) { var showNumbers = false; if ((this.ArrowDrawAction & ShapeDrawAction.Name) == ShapeDrawAction.Name) { this.ArrowDrawAction |= ~ShapeDrawAction.Name; showNumbers = true; } var arrow = new VGArrow(this.ArrowDrawAction, this.ArrowPen); arrow.Brush = this.ArrowBrush; if (!showNumbers) { arrow.HideWeights = true; } var location1 = aoisWithoutSearchRects[i - 1].Center; var location2 = aoisWithoutSearchRects[j - 1].Center; var distanceFirst = distances.Count >= i ? distances[i - 1] : 15; var distanceSecond = distances.Count >= j ? distances[j - 1] : 15; if (location1.X <= location2.X) { arrow.FirstPoint = location1; arrow.SecondPoint = location2; arrow.FirstPointDistance = distanceFirst; arrow.SecondPointDistance = distanceSecond; arrow.FirstPointWeight = transBtoA; arrow.SecondPointWeight = transAtoB; } else { arrow.FirstPoint = location2; arrow.SecondPoint = location1; arrow.FirstPointDistance = distanceSecond; arrow.SecondPointDistance = distanceFirst; arrow.FirstPointWeight = transAtoB; arrow.SecondPointWeight = transBtoA; } arrow.FormatString = "N0"; if (!absolute) { if (arrow.FirstPointWeight < 1 && arrow.SecondPointWeight < 1) { arrow.FormatString = "N1"; } arrow.AddOnString = "%"; } arrow.WeightFont = this.ArrowFont; arrow.WeightFontColor = this.ArrowFontColor; arrow.ScaleFactor = this.ArrowFactor; arrow.StyleGroup = VGStyleGroup.AOI_STATISTICS_ARROW; arrow.TextAlignment = this.ArrowTextAlignment; this.Elements.Add(arrow); } } } } this.DrawForeground(true); }
/// <summary> /// Метод возвращает true, если режим предполагает гистограмму-перспективу /// </summary> /// <param name="Mode">Режим для проверки</param> /// <returns>Возвращает true в случае, если предполагается гистограмма-перспектива</returns> public static bool IsPerspective(VisualizationModes Mode) { return(Mode == VisualizationModes.Perspective_histogram); }
/// <summary> /// Метод возвращает true, если режим предполагает гистограмму-бабочку /// </summary> /// <param name="Mode">Режим для проверки</param> /// <returns>Возвращает true в случае, если предполагается гистограмма-бабочка или её аналог</returns> public static bool IsButterflyOrSnail(VisualizationModes Mode) { return((Mode == VisualizationModes.Butterfly_histogram_with_full_symmetry) || (Mode == VisualizationModes.Butterfly_histogram_with_vertical_symmetry) || (Mode == VisualizationModes.Snail_histogram)); }
/// <summary> /// Метод проверяет, требует ли указанный режим отрисовки только спектрограммы /// или амплитудной гистограммы /// </summary> /// <param name="Mode">Режим для проверки</param> /// <returns>Возвращает true в случае, если спектрограмма необходима</returns> public static bool ContainsSGorWF(VisualizationModes Mode) { return(ContainsSGonly(Mode) || (VisualizationModeToSpectrogramMode(Mode) == SpectrogramModes.StaticAmplitude) || (VisualizationModeToSpectrogramMode(Mode) == SpectrogramModes.MovingAmplitude)); }
/// <summary> /// Метод проверяет, требует ли указанный режим отрисовки только спектрограммы /// </summary> /// <param name="Mode">Режим для проверки</param> /// <returns>Возвращает true в случае, если спектрограмма необходима</returns> public static bool ContainsSGonly(VisualizationModes Mode) { return((VisualizationModeToSpectrogramMode(Mode) == SpectrogramModes.MovingSpectrogram) || (VisualizationModeToSpectrogramMode(Mode) == SpectrogramModes.StaticSpectrogram) || (VisualizationModeToSpectrogramMode(Mode) == SpectrogramModes.SymmetricMovingSpectrogram)); }
/// <summary> /// Метод проверяет, требует ли указанный режим отрисовки спектрограммы, гистограммы или волновые формы /// </summary> /// <param name="Mode">Режим для проверки</param> /// <returns>Возвращает true в случае, если спектрограмма необходима</returns> public static bool ContainsSGHGorWF(VisualizationModes Mode) { return(VisualizationModeToSpectrogramMode(Mode) != SpectrogramModes.NoSpectrogram); }