public void Init(int rows, int cols, int maxNumPoints, List <MultiChartArray_TraceItem> traces, AggregateChart aggregateChart) { int numTraces = traces.Count; int margin = 1; int padding = 3; //////////////////////////////////////////////////////////////////////////////////////////////// m_chartArrayWidth = 0; m_chartArrayHeight = 0; m_cols = cols; m_rows = rows; m_padding = padding; m_margin = margin; m_maxPoints = maxNumPoints; m_numTraces = traces.Count; m_aggregateChart = aggregateChart; // initialize traces and trace colors int traceNum = 0; m_traces = new Dictionary <int, MultiChartArray_TraceItem>(); m_traceColors = new Dictionary <Tuple <int, MultiChartArray.SIGNAL_TYPE>, Color>(); foreach (MultiChartArray_TraceItem item in traces) { item.traceNum = traceNum; m_traces.Add(item.id, item); traceNum++; // initialize trace colors foreach (int value in Enum.GetValues(typeof(MultiChartArray.SIGNAL_TYPE))) { MultiChartArray.SIGNAL_TYPE signal = (MultiChartArray.SIGNAL_TYPE)value; m_traceColors.Add(Tuple.Create <int, MultiChartArray.SIGNAL_TYPE>(item.id, signal), Colors.Yellow); // default to yellow } } int pixelsPerChart = 42; int newWidth = (pixelsPerChart * m_cols) + ((m_cols - 1) * m_padding) + (2 * m_margin); int newHeight = (pixelsPerChart * m_rows) + ((m_rows - 1) * m_padding) + (2 * m_margin); byte[] img = SynthesizeImage(newWidth, newHeight); SetBitmap(img, newWidth, newHeight); if (aggregateChart != null) { aggregateChart.SetBitmap(img, newWidth / 2, newHeight / 2); aggregateChart.SetRanges(1, 0, 1); } //////////////////////////////////////////////////////////////////////////////////////// m_mouseDownRow = -1; m_mouseDownCol = -1; m_numPoints = 0; InitializeComponent(); m_visibleSignal = SIGNAL_TYPE.RAW; m_buttonColorNotSelected = Colors.LightGray; m_buttonColorSelected = Colors.Red; m_rowButton = new List <Button>(); m_columnButton = new List <Button>(); BuildChartArray(); SetupVisiblityCheckBoxes(m_traces); m_refreshTimer = new DispatcherTimer(); m_refreshTimer.Tick += M_refreshTimer_Tick; m_refreshTimer.Interval = TimeSpan.FromMilliseconds(100); m_refreshTimer.Start(); m_newDataAdded = false; m_dataPipeline = CreateDataPipeline(m_tokenSource.Token, m_chartArrays); m_guiPipeline = CreateGuiPipeline(m_uiTask, m_tokenSource.Token, m_chartArrays, aggregateChart); if (aggregateChart != null) { aggregateChart.SizeChanged += AggregateChart_SizeChanged; } }
public ITargetBlock <Tuple <int[], int[], SIGNAL_TYPE, int, COMMAND_TYPE> > CreateGuiPipeline(TaskScheduler uiTask, CancellationToken cancelToken, Dictionary <SIGNAL_TYPE, ChartArray> _charts, AggregateChart _aggregateChart) { Dictionary <SIGNAL_TYPE, ChartArray> charts = _charts; AggregateChart aggregateChart = _aggregateChart; SIGNAL_TYPE visibleSignal = SIGNAL_TYPE.RAW; float[] axisRange = new float[4]; var GuiUpdates = new ActionBlock <Tuple <int[], int[], SIGNAL_TYPE, int, COMMAND_TYPE> >(inputData => { // INPUTS: // item 1 - x data array // item 2 - y data array // item 3 - the data's signal type, i.e. RAW, STATIC_RATIO, CONTROL_SUBTRACTION, or DYNAMIC_RATIO // item 4 - the index of the indicator to which this data belongs // item 5 - command type that is put on the queue. Depending on what this is, the previous parameters are // interpreted differently. For example, if it is RESIZE, the new bitmap dimensions should be // in x and y (items 1 and 2 above). The new chartArray should be x[0], y[0], // and the new aggregate chart should be x[1], y[1]. if (inputData == null) { return; } int[] x = inputData.Item1; int[] y = inputData.Item2; SIGNAL_TYPE signalType = inputData.Item3; int indicatorNdx = inputData.Item4; COMMAND_TYPE commandType = inputData.Item5; try { switch (commandType) { case COMMAND_TYPE.RESIZE: // resize chartArray and aggregate bitmaps // find the optimal size to best fit the Actual window size int pixelWidthPerChart = (x[0] - (2 * m_margin) - ((m_cols - 1) * m_padding)) / m_cols; int pixelHeightPerChart = (y[0] - (2 * m_margin) - ((m_rows - 1) * m_padding)) / m_rows; int w = (pixelWidthPerChart * m_cols) + ((m_cols - 1) * m_padding) + (2 * m_margin); int h = (pixelHeightPerChart * m_rows) + ((m_rows - 1) * m_padding) + (2 * m_margin); if (w != m_chartArrayWidth || h != m_chartArrayHeight) { m_chartArrayWidth = w; m_chartArrayHeight = h; if (aggregateChart != null) { aggregateChart.SetBitmap(BitmapFactory.New(x[1], y[1])); } m_bitmap = BitmapFactory.New(w, h); m_overlay = BitmapFactory.New(w, h); imageBitmap.Source = m_bitmap; overlayBitmap.Source = m_overlay; foreach (int value in Enum.GetValues(typeof(SIGNAL_TYPE))) { SIGNAL_TYPE signal = (SIGNAL_TYPE)value; charts[signal].Resize(w, h, x[1], y[1]); } } // refresh chart array charts[visibleSignal].Redraw(); WriteableBitmap bitmapRef4 = m_bitmap; charts[visibleSignal].Refresh(ref bitmapRef4); // refresh aggregate chart if (aggregateChart != null) { charts[visibleSignal].RedrawAggregate(); WriteableBitmap aggregateBitmapRef4 = aggregateChart.m_bitmap; charts[visibleSignal].RefreshAggregate(ref aggregateBitmapRef4); } break; case COMMAND_TYPE.REFRESH: visibleSignal = signalType; // refresh chart array image charts[visibleSignal].Redraw(); WriteableBitmap bitmapRef1 = m_bitmap; charts[visibleSignal].Refresh(ref bitmapRef1); // refresh aggregate image if (aggregateChart != null) { charts[visibleSignal].RedrawAggregate(); WriteableBitmap aggregateBitmapRef4 = aggregateChart.m_bitmap; charts[visibleSignal].RefreshAggregate(ref aggregateBitmapRef4); // update the range labels charts[visibleSignal].GetRanges(ref axisRange, indicatorNdx); aggregateChart.SetRanges(axisRange[1], axisRange[2], axisRange[3]); } break; case COMMAND_TYPE.RESET: // clears data from all charts foreach (int value in Enum.GetValues(typeof(SIGNAL_TYPE))) { SIGNAL_TYPE signal = (SIGNAL_TYPE)value; charts[signal].Reset(); charts[signal].Redraw(); charts[signal].RedrawAggregate(); } WriteableBitmap bitmapRef2 = m_bitmap; charts[visibleSignal].Refresh(ref bitmapRef2); if (aggregateChart != null) { WriteableBitmap aggregateBitmapRef2 = aggregateChart.m_bitmap; charts[visibleSignal].RefreshAggregate(ref aggregateBitmapRef2); // update the range labels charts[visibleSignal].GetRanges(ref axisRange, indicatorNdx); aggregateChart.SetRanges(axisRange[1], axisRange[2], axisRange[3]); } m_totalPoints = 0; break; case COMMAND_TYPE.SET_SELECTED: // have to convert to a 1D bool array, because that's what is needed by the C++ function bool[] temp = new bool[m_rows * m_cols]; for (int r = 0; r < m_rows; r++) { for (int c = 0; c < m_cols; c++) { temp[r * m_cols + c] = m_chartSelected[r, c]; } } foreach (int value in Enum.GetValues(typeof(SIGNAL_TYPE))) { SIGNAL_TYPE signal = (SIGNAL_TYPE)value; // refresh chart array charts[signal].Redraw(); if (signal == visibleSignal) { WriteableBitmap bitmapRef3 = m_bitmap; charts[signal].SetSelectedCharts(temp, ref bitmapRef3); } else { charts[signal].SetSelectedCharts(temp); } if (aggregateChart != null) { // refresh aggregate chart charts[signal].RedrawAggregate(); if (signal == visibleSignal) { WriteableBitmap aggregateBitmapRef3 = aggregateChart.m_bitmap; charts[visibleSignal].RefreshAggregate(ref aggregateBitmapRef3); } } } break; } } catch (OperationCanceledException) { return; } }, new ExecutionDataflowBlockOptions { TaskScheduler = uiTask, CancellationToken = cancelToken, MaxDegreeOfParallelism = 4 }); return(GuiUpdates); }