Skip to content

File LUTControl.xaml.cs

File List > PGRControls > LUTControl.xaml.cs

Go to the documentation of this file

//=============================================================================
// Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================

using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using SpinnakerNET.GenApi;

namespace SpinnakerNET.GUI
{
    namespace WPFControls
    {
        public sealed partial class LUTControl : BaseClass
        {
            private bool _disposed = false;
            private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(LUTControl));

            int _width = 2048;
            int _height = 512;

            private IInteger m_indexNode;
            private IInteger m_valueNode;
            private IBool m_enableNode;
            private IRegister m_lutValueAll;

            private bool _LUTEnabled;
            private const float MinPointRange = 10;
            private const uint NumGridPartitions = 4;
            private OpenFileDialog m_openFileDialog;
            private SaveFileDialog m_saveFileDialog;
            private ObservableCollection<Point>_points = new ObservableCollection<Point>();
            private uint[] m_lutEntries = null;
            private ArrayList m_keyPoints = new ArrayList();
            private Point m_currentSelectedPoint = new Point();
            private bool m_isCurrentlyMovingPoint;
            private LineStyle _lineStyle;
            private int m_currentSelectedPointPosition;
            private float m_pointRangeMax = 0;
            private float m_pointRangeMin = 0;
            private bool m_stopUpdateEntries;
            private List<Ellipse>_paintedKeyPoints;
            private int _xStart;
            private int _xMiddle;
            private int _xEnd;
            private int _yMiddle;
            private int _yEnd;
            private bool _skipCallBack;

#region FIELDS
            public bool LUTEnabled
            {
                get
                {
                    return _LUTEnabled;
                }
                set
                {
                    _LUTEnabled = value;
                    NotifyPropertyChanged("LUTEnabled");
                }
            }

            public int XStart
            {
                get
                {
                    return _xStart;
                }
                set
                {
                    _xStart = value;
                    NotifyPropertyChanged("XStart");
                }
            }

            public int XMiddle
            {
                get
                {
                    return _xMiddle;
                }
                set
                {
                    _xMiddle = value;
                    NotifyPropertyChanged("XMiddle");
                }
            }

            public int XEnd
            {
                get
                {
                    return _xEnd;
                }
                set
                {
                    _xEnd = value;
                    NotifyPropertyChanged("XEnd");
                }
            }

            public int YMiddle
            {
                get
                {
                    return _yMiddle;
                }
                set
                {
                    _yMiddle = value;
                    NotifyPropertyChanged("YMiddle");
                }
            }

            public int YEnd
            {
                get
                {
                    return _yEnd;
                }
                set
                {
                    _yEnd = value;
                    NotifyPropertyChanged("YEnd");
                }
            }

            public int GraphWidth
            {
                get
                {
                    return _width;
                }
                set
                {
                    _width = value;
                    NotifyPropertyChanged("GraphWidth");
                }
            }

            public int GraphHeight
            {
                get
                {
                    return _height;
                }
                set
                {
                    _height = value;
                    NotifyPropertyChanged("GraphHeight");
                }
            }

            public ObservableCollection<Point>Points
            {
                get
                {
                    return _points;
                }
                set
                {
                    _points = value;
                    NotifyPropertyChanged("Points");
                }
            }
#endregion

#region CONSTRUCTORS
            public LUTControl()
            {
                this.DataContext = this;
                InitializeComponent();
                _paintedKeyPoints = new List<Ellipse>();

                SetupAxisLabels();
                ResetLUTEntries();
                UpdatePointsOnUI();

                m_openFileDialog = new OpenFileDialog();
                m_openFileDialog.FileName = "lutdata";
                m_openFileDialog.Filter = "Look up table data files (*.lut)|*.lut";

                m_saveFileDialog = new SaveFileDialog();
                m_saveFileDialog.Filter = "Look up table data files (*.lut)|*.lut";
            }

            ~LUTControl()
            {
                Disconnect();
            }

            internal LUTControl(LUTControl originalControl)
            {
                InitializeComponent();

                // Common Properties
                this.SetMapper(originalControl.GetMapper());
                this.Connect(
                    originalControl.NodeMap, originalControl.GetNodeToControl(), originalControl.GetControlNameLabel());
                this.SetNameLabelBoldness(originalControl.NameLabelBoldness);
                this.SetVisibility(originalControl.Visibility);
                this.SetControlID(originalControl.ControlID);
                this.SetMin(originalControl.GetMin());
                this.SetMax(originalControl.GetMax());
                this.SetControlNameLabel(originalControl.ControlNameLabel);
                this.SetNameLabelVisibility(originalControl.GetNameLabelVisibility());
                this.SetNameLabelBoldness(originalControl.GetNameLabelBoldness());
                try
                {
                    this.SetToolTip(originalControl.GetToolTip());
                }
                catch
                {
                }
                this.SetMaximumControlSize(originalControl.GetMaximumControlSize());
                this.SetMinimumControlSize(originalControl.GetMinimumControlSize());
                this.SetControlHeight(originalControl.GetControlHeight());
                this.SetControlWidth(originalControl.GetControlWidth());
                this.SetRefreshTime(originalControl.GetRefreshTime());
                this.SetMargin(originalControl.GetMargin());
            }

            protected override void Dispose(bool disposing)
            {
                if (!_disposed)
                {
                    if (disposing)
                    {
                    }

                    // Consider GenICam callbacks as unmanaged resource
                    Disconnect();
                    _disposed = true;
                }
                // Call Dispose in the base class.
                base.Dispose(disposing);
            }
#endregion

#region ICameraControlInterface
            public override void Connect(INodeMap nodemap, string nodename, string namelabel = "")
            {
                if (nodemap == null)
                {
                    throw new Exception("NodeMap is null.");
                }

                // Check whether LUT is supported on this camera
                try
                {
                    this._nodeMap = nodemap;

                    m_enableNode = nodemap.GetNode<IBool>("LUTEnable");

                    if (m_enableNode == null)
                    {
                        // Remove inner children
                        IsEnabled = false;
                        _featureAvailable = false;

                        return;
                    }

                    // Set control status
                    LUTEnabled = m_enableNode.Value;

                    // Get SelectorNode
                    m_indexNode = nodemap.GetNode<IInteger>("LUTIndex");
                    m_valueNode = nodemap.GetNode<IInteger>("LUTValue");
                    m_lutValueAll = nodemap.GetNode<IRegister>("LUTValueAll");

                    chkEnableLUT.Connect(nodemap, "LUTEnable", "");
                    cboLUTBanks.Connect(nodemap, "LUTSelector", "");

                    // Check whether LUT is supported
                    if (m_enableNode == null || m_indexNode == null || m_valueNode == null || m_lutValueAll == null ||
                        !m_enableNode.IsImplemented || !m_enableNode.IsAvailable)
                    {
                        throw new Exception(string.Format("LUT is not supported by current device"));
                    }

                    if (m_indexNode.IsAvailable && m_valueNode.IsAvailable)
                    {
                        GraphHeight = (int) m_valueNode.Max - (int) m_valueNode.Min + 1;
                        GraphWidth = (int) m_indexNode.Max - (int) m_indexNode.Min + 1;

                        SetupAxisLabels();
                    }

                    // Initialize Drawing Area
                    if (LUTEnabled)
                    {
                        // initialize the lut entries from camera
                        OnLoadFromCamera();
                    }

                    // Register GenIcam callback
                    RegisterGeniCamCallbacks();

                    _featureAvailable = true;
                }
                catch (Exception ex)
                {
                    log.Debug("LUT feature is not available.", ex);
                    // Remove inner children
                    _featureAvailable = false;
                }

                // Acquire device serial number
                if (string.IsNullOrWhiteSpace(_serialNumber))
                {
                    _serialNumber = RetrieveSerialNumber(nodemap);
                }

                // Acquire device model name
                if (string.IsNullOrWhiteSpace(_deviceModelName))
                {
                    _deviceModelName = RetrieveModelName(nodemap);
                }

                if (!_featureAvailable)
                {
                    log.Debug(string.Format("{0}LUT is not supported by current device.", FormattedSerialNumber));
                    throw new Exception(
                        string.Format("{0}LUT is not supported by current device.", FormattedSerialNumber));
                }

                _callbackRegistered = true;

                RegisterInterfaceEvents();
            }

            public override void Disconnect()
            {
                if (_callbackRegistered)
                {
                    UnregisterGeniCamCallbacks();
                    chkEnableLUT.Disconnect();
                    cboLUTBanks.Disconnect();
                    base.Disconnect();
                }
            }

            private void RegisterGeniCamCallbacks()
            {
                if (m_enableNode != null)
                {
                    m_enableNode.Updated += new NodeEventHandler(enableNode_Updated);
                }

                if (m_valueNode != null)
                {
                    m_valueNode.Updated += new NodeEventHandler(m_valueNode_Updated);
                }

                _callbackRegistered = true;
            }

            private void UnregisterGeniCamCallbacks()
            {
                if (_callbackRegistered)
                {
                    if (m_enableNode != null)
                    {
                        m_enableNode.Updated -= new NodeEventHandler(enableNode_Updated);
                    }

                    if (m_valueNode != null)
                    {
                        m_valueNode.Updated -= new NodeEventHandler(m_valueNode_Updated);
                    }
                    _callbackRegistered = false;
                }
            }

            void m_valueNode_Updated(INode node)
            {
                if (_skipCallBack)
                {
                    return;
                }

                if (!IsVisible)
                {
                    return;
                }

                try
                {
                    _skipCallBack = true;

                    int index = 0;
                    int value = 0;

                    if (m_indexNode != null && m_indexNode.IsReadable)
                    {
                        index = (int) m_indexNode.Value;
                    }

                    if (m_valueNode != null && m_valueNode.IsReadable)
                    {
                        value = (int) m_valueNode.Value;
                    }

                    UpdateLutEntries(index, value);
                }
                catch (System.Exception /*ex*/)
                {
                }
                finally
                {
                    _skipCallBack = false;
                }
            }

            private void selectorNode_Updated(INode node)
            {
                if (_skipCallBack)
                {
                    return;
                }

                if (!IsVisible)
                {
                    return;
                }

                try
                {
                    _skipCallBack = true;
                    OnLoadFromCamera();
                }
                catch (System.Exception ex)
                {
                    log.Debug(ex);
                }
                finally
                {
                    _skipCallBack = false;
                }
            }

            private void enableNode_Updated(INode node)
            {
                if (_skipCallBack)
                {
                    return;
                }

                if (!IsVisible)
                {
                    return;
                }

                try
                {
                    _skipCallBack = true;

                    if (m_enableNode != null && m_enableNode.IsReadable)
                    {
                        LUTEnabled = m_enableNode.Value;

                        if (m_indexNode.IsAvailable && m_valueNode.IsAvailable)
                        {
                            GraphHeight = (int) m_valueNode.Max - (int) m_valueNode.Min + 1;
                            GraphWidth = (int) m_indexNode.Max - (int) m_indexNode.Min + 1;

                            SetupAxisLabels();

                            OnLoadFromCamera();
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    log.Debug(ex);
                }
                finally
                {
                    _skipCallBack = false;
                }
            }

            private bool DetermineDeviceEndianness()
            {

                bool isBigEndian = true;
                bool operationCompleted = false;

                // Check for interface type
                // U3V is always small endian
                try
                {

                    Integer U3VCPCapability = _nodeMap.GetNode<Integer>("U3VCPCapability");

                    if (U3VCPCapability != null)
                    {
                        isBigEndian = false;
                    }

                    operationCompleted = true;
                }
                catch (Exception ex)
                {
                    log.Debug(ex);
                }

                if (operationCompleted)
                {
                    return isBigEndian;
                }

                try
                {
                    Enumeration DeviceRegistersEndianness = _nodeMap.GetNode<Enumeration>("DeviceRegistersEndianness");

                    long bigEndianValue = 0;

                    foreach(EnumEntry entry in DeviceRegistersEndianness.Entries)
                    {
                        if (entry.DisplayName.ToLower().Contains("standard"))
                        {
                            bigEndianValue = entry.Value;
                        }
                    }

                    if (DeviceRegistersEndianness.Value == bigEndianValue)
                    {
                        isBigEndian = true;
                    }
                    else
                    {
                        isBigEndian = false;
                    }

                    operationCompleted = true;
                }
                catch (Exception ex)
                {
                    log.Debug(ex);
                }

                if (operationCompleted)
                {
                    return isBigEndian;
                }
                else
                {
                    throw new SpinnakerException("Cannot determine device endianness.");
                }
            }

            private void OnLoadFromCamera()
            {
                try
                {
                    if (m_valueNode == null || !m_valueNode.IsReadable || !m_indexNode.IsReadable)
                    {
                        return;
                    }

                    byte[] entries = new byte[m_lutValueAll.Length];
                    uint[] intEntries = new uint[entries.Length / 4];

                    // Get Byte array
                    m_lutValueAll.Read(out entries);

                    bool isBigEndian = DetermineDeviceEndianness();

                    // convert byte array to little endian as BitConverter is in little endian
                    if (isBigEndian)
                    {
                        SwapSingles(entries);
                    }

                    for (int i = 0; i < entries.Length; i += 4)
                    {
                        intEntries[i / 4] = BitConverter.ToUInt32(entries, i);
                    }

                    SetLutEntries(intEntries);

                    UpdatePointsOnUI();

                    log.Logger.Log(null, log4net.Core.Level.Notice, "LUT data loaded from device", null);
                }
                catch (Exception ex)
                {
                    log.Error("There was a problem loading LUT data from device.", ex);
                }
            }

            private static unsafe void SwapSingles(byte[] data)
            {
                int cnt = data.Length / 4;
                fixed(byte * d = data)
                {
                    byte * p = d;
                    while (cnt-- > 0)
                    {
                        byte a = *p;
                        p++;
                        byte b = *p;
                        *p = *(p + 1);
                        p++;
                        *p = b;
                        p++;
                        *(p - 3) = *p;
                        *p = a;
                        p++;
                    }
                }
            }

            internal void UpdateControlStatus()
            {
                try
                {
                    IValue m_enableNode = _nodeMap.GetNode<IBool>("LUTEnable");
                }
                catch (System.Exception /*ex*/)
                {
                    this.IsEnabled = false;
                    return;
                }
            }

            public override void SetToolTip(string tooltip)
            {
                this.ToolTip = tooltip;
            }

            public override void SetControlNameLabel(string nameLabel)
            {
                return;
            }

            public override void SetNameLabelVisibility(System.Windows.Visibility visibility)
            {
                return;
            }

            public override void SetRefreshTime(int seconds)
            {
            }

            public override void Refresh()
            {
            }

            public override string GetToolTip()
            {
                return this.ToolTip.ToString();
            }

            public override string GetControlNameLabel()
            {
                return string.Empty;
            }

            public override System.Windows.Visibility GetNameLabelVisibility()
            {
                return this.Visibility;
            }
#endregion

#region UI Controls

            private void SetupAxisLabels()
            {
                XStart = 0;
                XMiddle = (int) GraphWidth / 2 - 1;
                XEnd = (int) GraphWidth - 1;
                YMiddle = (int) GraphHeight / 2 - 1;
                YEnd = (int) GraphHeight - 1;
            }

            private void SetLutEntries(uint[] entries)
            {
                m_lutEntries = new uint[_width];
                for (uint i = 0; i < m_lutEntries.Length; i++)
                {
                    m_lutEntries[i] = (uint) entries[i];
                }

                // set default line style to free mode.
                _lineStyle = LineStyle.Free;
            }

            private void ResetLUTEntries()
            {
                if (_width == 0)
                {
                    log.Debug("Problem resetting LUT entries. Width is zero.");
                    return;
                }

                float slope = (float) _height / (float) _width;
                m_lutEntries = new uint[_width];
                for (int i = 0; i < m_lutEntries.Length; i++)
                {
                    uint last_y = (uint)((float) i * slope);
                    if (last_y < 0)
                        last_y = (int) 0;
                    if (last_y > _height)
                        last_y = (uint) _height;
                    m_lutEntries[i] = last_y; // Canvas's origin is at top left corner.
                }
            }

            private void UpdatePointsOnUI()
            {
                if (m_lutEntries == null)
                {
                    return;
                }

                ObservableCollection<Point>points = new ObservableCollection<Point>();
                for (int x = 0; x < m_lutEntries.Length; x += 1)
                {
                    points.Add(new Point(x, m_lutEntries[x]));
                }

                this.Points = points;

                if (_lineStyle != LineStyle.Free)
                {
                    DrawKeyPoints();
                }
                else
                {
                    ClearKeyPoints();
                }
            }

            // Draw a simple graph.
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                const double margin = 10;
                double xmax = canGraph.Width - margin;
                double ymax = canGraph.Height - margin;

                // Make the X axis.
                GeometryGroup xaxis_geom = new GeometryGroup();
                xaxis_geom.Children.Add(new LineGeometry(new Point(0, 0), new Point(canGraph.Width, 0)));

                Path xaxis_path = new Path();
                xaxis_path.StrokeThickness = 1;
                xaxis_path.Stroke = Brushes.Black;
                xaxis_path.Data = xaxis_geom;

                canGraph.Children.Add(xaxis_path);

                // Make the Y axis.
                GeometryGroup yaxis_geom = new GeometryGroup();
                yaxis_geom.Children.Add(new LineGeometry(new Point(0, 0), new Point(0, canGraph.Height)));

                Path yaxis_path = new Path();
                yaxis_path.StrokeThickness = 1;
                yaxis_path.Stroke = Brushes.Black;
                yaxis_path.Data = yaxis_geom;

                canGraph.Children.Add(yaxis_path);
            }

            private void ClearKeyPoints()
            {
                // clear current ones
                foreach(Ellipse pt in _paintedKeyPoints)
                {
                    try
                    {
                        canGraph.Children.Remove(pt);
                    }
                    catch
                    {
                    }
                }

                _paintedKeyPoints.Clear();
            }

            private void DrawKeyPoints()
            {
                ClearKeyPoints();

                foreach(Point point in m_keyPoints)
                {
                    Ellipse myEllipse = new Ellipse();
                    myEllipse.Fill = Brushes.Red;
                    myEllipse.StrokeThickness = 2;
                    myEllipse.Stroke = Brushes.Red;
                    myEllipse.Width = 10;
                    myEllipse.Height = 10;
                    Canvas.SetTop(myEllipse, _height - point.Y - (myEllipse.Height / 2));
                    Canvas.SetLeft(myEllipse, point.X - (myEllipse.Width / 2));
                    canGraph.Children.Add(myEllipse);
                    _paintedKeyPoints.Add(myEllipse);
                }
            }

            private void UpdateKeyPoints(uint numOfKeyPoints)
            {
                m_keyPoints.Clear();
                float outputMax = _height;
                for (int i = 0; i < numOfKeyPoints; i++)
                {
                    float entryValue = m_lutEntries[(m_lutEntries.Length - 1) * i / (numOfKeyPoints - 1)];

                    if (((numOfKeyPoints - 1) == 0) || outputMax == 0)
                    {
                        log.Debug(string.Format(
                            "Invalid data for new key point. numOfkeypoints == {0}, outputMax == {1}",
                            numOfKeyPoints,
                            outputMax));
                        continue;
                    }

                    m_keyPoints.Add(new Point(
                        (i * (_width - 1)) / (numOfKeyPoints - 1), _height - ((entryValue * _height) / outputMax)));
                }
            }

            private int FindClosestPoint(float x)
            {
                int index = 0;
                for (int i = 1; i < m_keyPoints.Count; i++)
                {
                    float distance = (float) Math.Abs(((Point) m_keyPoints[i]).X - x);
                    float minDistance = (float) Math.Abs(((Point) m_keyPoints[index]).X - x);
                    if (distance < minDistance)
                    {
                        index = i;
                    }
                }

                return index;
            }

            private void UpdateLutEntries(int index, int value)
            {
                if (m_lutEntries != null)
                {
                    m_lutEntries[index] = (uint) value;

                    UpdatePointsOnUI();
                }
            }

            private void UpdateLutEntries()
            {
                if (m_keyPoints.Count < 2)
                {
                    // should have at least 2 key point, otherwise set all value zero
                    if (m_lutEntries != null)
                    {
                        m_lutEntries.Initialize();
                    }
                    return;
                }

                if (_lineStyle == LineStyle.Linear)
                {
                    int keyPointIndex = 0;
                    Point startKeyPoint = (Point) m_keyPoints[keyPointIndex];
                    Point endKeyPoint = (Point) m_keyPoints[keyPointIndex + 1];

                    // line up dots
                    for (int index = 0; index <= m_lutEntries.Length - 1; index++)
                    {
                        int coordinateXForGraphic = (index * _width) / m_lutEntries.Length;
                        if (coordinateXForGraphic < startKeyPoint.X)
                        {
                            m_lutEntries[index] = 0;
                            continue;
                        }

                        if (coordinateXForGraphic > endKeyPoint.X)
                        {
                            keyPointIndex++;
                            if (keyPointIndex < m_keyPoints.Count - 1)
                            {
                                startKeyPoint = (Point) m_keyPoints[keyPointIndex];
                                endKeyPoint = (Point) m_keyPoints[keyPointIndex + 1];
                            }
                            else
                            {
                                m_lutEntries[index] = 0;
                                continue;
                            }
                        }

                        float relatedHeight =
                            (float) -
                            (startKeyPoint.Y - endKeyPoint.Y); // this equation is from (outputMax- startKeyPoint.Y)
                                                               // -(outputMax - endKeyPoint.Y);
                        if ((startKeyPoint.X - endKeyPoint.X) == 0)
                        {
                            log.Debug("startKeyPoint.X == endKeyPoint.X! Abortn updating LUT Entries.");
                            return;
                        }
                        float relatedYoffsetToStartKeyPoint = (float)(coordinateXForGraphic - startKeyPoint.X) *
                                                              relatedHeight / (float)(startKeyPoint.X - endKeyPoint.X);
                        m_lutEntries[index] =
                            (uint)((int) relatedYoffsetToStartKeyPoint + _height - (int) startKeyPoint.Y);
                    }
                }
                else if (_lineStyle == LineStyle.Spline)
                {
                    // spline mode
                    int numOfKeyPoints = m_keyPoints.Count;
                    float[] keyPointX = new float[numOfKeyPoints];
                    float[] keyPointY = new float[numOfKeyPoints];

                    for (int i = 0; i < numOfKeyPoints; i++)
                    {
                        keyPointX[i] = (float)((Point) m_keyPoints[i]).X;
                        keyPointY[i] = (float)((Point) m_keyPoints[i]).Y;
                    }

                    float[] tangentValueOfKeyPointY = MathUtilities.GetTangentPoints(keyPointY, numOfKeyPoints);
                    for (float i = keyPointX[0]; i <= keyPointX[numOfKeyPoints - 1]; i++)
                    {
                        int index = Convert.ToInt32(i);
                        float entryValue = MathUtilities.SplineFunction(
                            keyPointX, keyPointY, tangentValueOfKeyPointY, i, numOfKeyPoints);
                        m_lutEntries[index] = (uint)(_height - (int) entryValue);
                    }

                    // finalize the entries' data
                    Point startKeyPoint = (Point) m_keyPoints[0];
                    Point endKeyPoint = (Point) m_keyPoints[m_keyPoints.Count - 1];
                    for (int i = 0; i < m_lutEntries.Length; i++)
                    {
                        float coordinateXForGraphic = (i * _width) / m_lutEntries.Length;
                        if (coordinateXForGraphic < startKeyPoint.X || coordinateXForGraphic > endKeyPoint.X)
                        {
                            m_lutEntries[i] = 0;
                            continue;
                        }

                        if (m_lutEntries[i] < 0)
                        {
                            m_lutEntries[i] = 0;
                        }
                        else if (m_lutEntries[i] > _height)
                        {
                            m_lutEntries[i] = (uint) _height;
                        }
                    }
                }
                else
                {
                    // free mode!?
                    // actually if it is free mode, this function will never called
                    // so it might be a bug if code goes here and current line style is free.
                    log.Error(string.Format("{0}. Unexpected drawing mode.", _lineStyle));
                }
            }

            private void canGraph_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                float x = (float) e.GetPosition(this.canGraph).X;
                float y = (float) e.GetPosition(this.canGraph).Y;
                if (_lineStyle == LineStyle.Free)
                {
                    // do nothing
                }
                else
                {
                    if (m_isCurrentlyMovingPoint)
                    {
                        int tempIndex = FindClosestPoint(x);
                        m_keyPoints.RemoveAt(tempIndex);
                    }

                    int pointIndex;
                    for (pointIndex = 0; pointIndex < m_keyPoints.Count; pointIndex++)
                    {
                        double px = ((Point) m_keyPoints[pointIndex]).X;
                        if (px > x)
                        {
                            // find the position which the point should insert
                            break;
                        }
                    }

                    m_currentSelectedPointPosition = pointIndex;
                    if (pointIndex == 0)
                    {
                        m_pointRangeMin = 0;

                        // TODO: fix no key point bug
                        m_pointRangeMax = (float)((Point) m_keyPoints[0]).X;
                    }
                    else if (pointIndex > m_keyPoints.Count - 1)
                    {
                        m_pointRangeMax = _width;
                        m_pointRangeMin = (float)((Point) m_keyPoints[pointIndex - 1]).X;
                    }
                    else
                    {
                        m_pointRangeMax = (float)((Point) m_keyPoints[pointIndex]).X;
                        m_pointRangeMin = (float)((Point) m_keyPoints[pointIndex - 1]).X;
                    }
                }

                // Update graph
                UpdatePointsOnUI();
            }

            private void canGraph_MouseMove(object sender, MouseEventArgs e)
            {
                float x = (float) e.GetPosition(this.canGraph).X;
                float y = (float) e.GetPosition(this.canGraph).Y;

                if (x > _width)
                {
                    // take care of the corner condition to allow setting free line at 0 and 511
                    x = _width;
                }
                else if (x < 0)
                {
                    // take care of the corner condition to allow setting free line at 0
                    x = 0;
                }

                if (y > _height)
                {
                    y = _height;
                }
                else if (y < 0)
                {
                    y = 0;
                }

                if (_lineStyle == LineStyle.Free)
                {
                    Mouse.OverrideCursor = null;

                    if (e.LeftButton == MouseButtonState.Pressed && !m_stopUpdateEntries)
                    {
                        int endIndex = (int) x;
                        int startIndex = (int) m_currentSelectedPoint.X;
                        while (startIndex != endIndex)
                        {
                            try
                            {
                                m_lutEntries[startIndex] = (uint)(y);
                                if (startIndex > endIndex)
                                {
                                    startIndex--;
                                }
                                else
                                {
                                    startIndex++;
                                }
                            }
                            catch (System.Exception ex)
                            {
                                log.Debug(ex);
                                return;
                            }
                        }

                        m_currentSelectedPoint.X = x;

                        // Update graphics
                        UpdatePointsOnUI();
                    }
                    else
                    {
                        m_currentSelectedPoint.X = x;
                        m_stopUpdateEntries = false;
                    }
                }
                else
                {
                    if (m_keyPoints.Count == 0)
                    {
                        log.Debug("Key points count == 0");
                        return;
                    }

                    float distance = (float) Math.Abs(((Point) m_keyPoints[FindClosestPoint(x)]).X - x);
                    if (distance < MinPointRange)
                    {
                        m_isCurrentlyMovingPoint = true;
                        Mouse.OverrideCursor = Cursors.SizeAll;
                    }
                    else
                    {
                        m_isCurrentlyMovingPoint = false;
                        Mouse.OverrideCursor = Cursors.Cross;
                    }

                    if (m_currentSelectedPointPosition != -1)
                    {
                        // take care of the corner condition to allow setting keypoints at 0 and 511
                        if (x == -1)
                        {
                            m_currentSelectedPoint.X = 0;
                        }
                        else if (x == _width)
                        {
                            m_currentSelectedPoint.X = _width - 1;
                        }
                        else
                        {
                            m_currentSelectedPoint.X = x;
                        }
                        m_currentSelectedPoint.Y = _height - y;
                        if (m_currentSelectedPoint.X <= m_pointRangeMax && m_currentSelectedPoint.X >= m_pointRangeMin)
                        {
                            m_keyPoints.Insert(m_currentSelectedPointPosition, m_currentSelectedPoint);
                            Mouse.OverrideCursor = Cursors.SizeAll;
                            // update normal points
                            UpdateLutEntries();
                            m_keyPoints.Remove(m_currentSelectedPoint);
                            // Update graphic
                            UpdatePointsOnUI();
                        }
                        else
                        {
                            UpdateLutEntries();
                            // Update graphic
                            UpdatePointsOnUI();
                        }
                    }
                }
            }

            private void canGraph_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                if (_lineStyle == LineStyle.Free)
                {
                    // do nothing
                }
                else
                {
                    // start to insert a key point
                    if (m_currentSelectedPointPosition != -1 && m_currentSelectedPoint.X <= m_pointRangeMax &&
                        m_currentSelectedPoint.X >= m_pointRangeMin)
                    {
                        if (m_currentSelectedPoint.Y < 0)
                        {
                            m_currentSelectedPoint.Y = 0;
                        }
                        else if (m_currentSelectedPoint.Y > (float) _height)
                        {
                            m_currentSelectedPoint.Y = _height;
                        }

                        m_keyPoints.Insert(m_currentSelectedPointPosition, m_currentSelectedPoint);
                    }

                    m_currentSelectedPointPosition = -1;
                    if (m_keyPoints.Count < 2)
                    {
                        // if there is less than 2 key points,
                        // it will cause problem of update LUT entries
                        UpdateKeyPoints(2);
                    }

                    UpdateLutEntries();
                }

                Mouse.OverrideCursor = null;

                // Update graph
                UpdatePointsOnUI();
            }

            private void canGraph_MouseLeave(object sender, MouseEventArgs e)
            {
                Mouse.OverrideCursor = null;
            }

            private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                ComboBox cbo = sender as ComboBox;

                switch (cbo.SelectedIndex)
                {
                    case 0:
                        // Free
                        _lineStyle = LineStyle.Free;
                        UpdateKeyPoints(0);
                        break;
                    case 1:
                        // Linear
                        _lineStyle = LineStyle.Linear;
                        UpdateKeyPoints((NumGridPartitions * 2) + 1);
                        UpdateLutEntries();

                        break;
                    case 2:
                        // Spline
                        _lineStyle = LineStyle.Spline;
                        UpdateKeyPoints((NumGridPartitions * 2) + 1);
                        UpdateLutEntries();
                        break;
                    default:
                        // Free

                        break;
                }

                // Update graph
                UpdatePointsOnUI();
            }

            private void ResetButton_Click(object sender, RoutedEventArgs e)
            {
                ResetLUTEntries();
                UpdatePointsOnUI();
                cbo_linestyle.SelectedIndex = 0;
            }

            private void SaveToFile_Click(object sender, RoutedEventArgs e)
            {
                string initialFileName = "TempLUT";

                m_saveFileDialog.FileName = initialFileName + ".lut";
                if (m_saveFileDialog.ShowDialog() == true)
                {
                    m_stopUpdateEntries = true;
                    System.IO.StreamWriter fileStream;
                    try
                    {
                        fileStream = new System.IO.StreamWriter(m_saveFileDialog.FileName);
                    }
                    catch (UnauthorizedAccessException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. The access is unauthorized. Please contact administrator for more information.\n",
                            "Error Opening File",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (System.Security.SecurityException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file due to security policy.\n",
                            "SecurityException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (ArgumentException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. Invalid file name or mode.\n",
                            "ArgumentException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (System.IO.IOException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. Read file data failed.\n",
                            "IOException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }

                    if (this.m_lutEntries == null)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot Read LUT Entry file. Read file data failed\n",
                            "Read Data Fail",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    for (uint i = 0; i < m_lutEntries.Length; ++i)
                    {
                        string currLine;
                        try
                        {
                            currLine = string.Format("{0},{1}", i, m_lutEntries[i]);
                            fileStream.WriteLine(currLine);
                        }
                        catch (FormatException ex)
                        {
                            Debug.WriteLine(ex.Message);
                            Debug.WriteLine(ex.StackTrace);
                            fileStream.Close();
                            System.Windows.Forms.MessageBox.Show(
                                "There was an argument which does not meet the parameter specifications. Aborting file write.",
                                "FormatException",
                                System.Windows.Forms.MessageBoxButtons.OK,
                                System.Windows.Forms.MessageBoxIcon.Error);
                            break;
                        }
                        catch (System.IO.IOException ex)
                        {
                            Debug.WriteLine(ex.Message);
                            Debug.WriteLine(ex.StackTrace);
                            fileStream.Close();
                            System.Windows.Forms.MessageBox.Show(
                                "Error writing the current string to file. Aborting file write.",
                                "IOException",
                                System.Windows.Forms.MessageBoxButtons.OK,
                                System.Windows.Forms.MessageBoxIcon.Error);
                            break;
                        }
                        catch (ArgumentNullException ex)
                        {
                            Debug.WriteLine(ex.Message);
                            Debug.WriteLine(ex.StackTrace);
                            fileStream.Close();
                            System.Windows.Forms.MessageBox.Show(
                                "Error writing to file. The current string is null. Aborting file write",
                                "ArgumentNullException",
                                System.Windows.Forms.MessageBoxButtons.OK,
                                System.Windows.Forms.MessageBoxIcon.Error);
                            break;
                        }
                    }

                    fileStream.Close();
                }
            }

            private void LoadFromFile_Click(object sender, RoutedEventArgs e)
            {
                if (m_openFileDialog.ShowDialog() == true)
                {
                    // fix a bug: when user click close dialog and mouse is on the drawing area,
                    // the data in m_lutEntries will be overwrite (it means that click will also affect to drawing
                    // area), so the update from drawing area should stop now when open File Dialog shows up
                    m_stopUpdateEntries = true;
                    System.IO.StreamReader fileStream;
                    try
                    {
                        fileStream = new System.IO.StreamReader(m_openFileDialog.FileName);
                    }
                    catch (UnauthorizedAccessException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. The access is unauthorized.\n Please contact administrator for more information.\n",
                            "UnauthorizedAccessException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (System.Security.SecurityException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file due to security policy\n",
                            "SecurityException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (ArgumentException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. Invalid file name or mode\n",
                            "ArgumentException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    catch (System.IO.IOException /*ex*/)
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Cannot open the file. Read file data failed\n",
                            "IOException",
                            System.Windows.Forms.MessageBoxButtons.OK,
                            System.Windows.Forms.MessageBoxIcon.Error);
                        return;
                    }
                    for (uint i = 0; i < m_lutEntries.Length; i++)
                    {
                        uint currInput = 0;
                        uint currResult = 0;
                        string currLine = fileStream.ReadLine();
                        if (currLine == null)
                        {
                            m_lutEntries[i] = 0;
                            continue;
                        }

                        string[] numbersFromCurrLine = currLine.Split(new char[]{','});
                        if (numbersFromCurrLine.Length != 2)
                        {
                            System.Windows.Forms.MessageBox.Show(
                                "Required format not found. Aborting file load.",
                                "Error reading LUT data from file",
                                System.Windows.Forms.MessageBoxButtons.OK,
                                System.Windows.Forms.MessageBoxIcon.Error);
                            fileStream.Close();
                            return;
                        }

                        try
                        {
                            currInput = Convert.ToUInt32(numbersFromCurrLine[0]);
                            currResult = Convert.ToUInt32(numbersFromCurrLine[1]);
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("Invalid LUT data detected. {1}", ex.Message);
                            m_lutEntries[i] = 0;
                            continue;
                        }

                        if (currInput < 0 || currInput >= m_lutEntries.Length || currInput != i)
                        {
                            System.Windows.Forms.DialogResult result;
                            result = System.Windows.Forms.MessageBox.Show(
                                "LUT data appears to be invalid\r\n. Do you wish to abort file load.",
                                "Invalid LUT data detected",
                                System.Windows.Forms.MessageBoxButtons.YesNo,
                                System.Windows.Forms.MessageBoxIcon.Error);

                            if (result == System.Windows.Forms.DialogResult.No)
                            {
                                m_lutEntries[i] = 0;
                                continue;
                            }
                            else
                            {
                                fileStream.Close();
                                return;
                            }
                        }

                        // Data passed validation check, add it to the list of entries
                        m_lutEntries[i] = currResult;
                    }

                    fileStream.Close();
                    // set default line style to free mode.
                    UpdatePointsOnUI();
                    cbo_linestyle.SelectedIndex = 0;
                }
            }

#endregion

            private void LoadFromCamera_Click(object sender, RoutedEventArgs e)
            {
                OnLoadFromCamera();
            }

            private void SaveToCamera_Click(object sender, RoutedEventArgs e)
            {
                if (this.m_lutEntries == null)
                {
                    return;
                }

                _skipCallBack = true;

                try
                {
                    Mouse.OverrideCursor = Cursors.Wait;
                    UnregisterGeniCamCallbacks();
                    for (uint i = 0; i < m_lutEntries.Length; ++i)
                    {
                        m_indexNode.Value = i;
                        m_valueNode.Value = m_lutEntries[i];
                    }

                    log.Logger.Log(null, log4net.Core.Level.Notice, "LUT data has been saved to device", null);
                }
                catch (SpinnakerException ex)
                {
                    log.Error("Problem setting LUT Value.", ex);
                }
                catch (System.Exception ex)
                {
                    log.Error("Problem setting LUT Value.", ex);
                }
                finally
                {
                    RegisterGeniCamCallbacks();
                    Mouse.OverrideCursor = null;
                }

                _skipCallBack = false;
            }
        }

        public enum LineStyle { Free = 0, Linear, Spline }

#region IValueConverter Members
        public class MyPointCollectionConverter : IValueConverter
        {
            public object Convert(
                object value,
                Type targetType,
                object parameter,
                System.Globalization.CultureInfo culture)
            {
                var regPtsColl = new PointCollection();               // regular points collection.
                var obsPtsColl = (ObservableCollection<Point>) value; // observable which is used to raise INCC event.
                foreach(var point in obsPtsColl) regPtsColl.Add(point);
                return regPtsColl;
            }

            public object ConvertBack(
                object value,
                Type targetType,
                object parameter,
                System.Globalization.CultureInfo culture)
            {
                return null;
            }
        }
#endregion
    }
}