public DrawingForm(string templatePath)
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
            m_LButtonPressed	= false;
            m_CtrlPressed		= false;
            m_bRedoing			= false;

            m_selectingRect	= new System.Drawing.Rectangle(0, 0, 0, 0);
            m_selectedPen	= new Pen(System.Drawing.Color.FromArgb(150, 0, 0, 255), 1);
            m_groupSelPen	= new Pen(System.Drawing.Color.FromArgb(255, 200, 200, 200), 1);
            m_selectingPen	= new Pen(System.Drawing.Color.FromArgb(100, 0, 0, 0), 1);
            m_groupSelPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            m_selectingPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

            m_frmColor					= new ColorForm();
            m_frmColor.TopLevel			= false;
            m_frmColor.FormBorderStyle	= FormBorderStyle.None;
            m_frmColor.Visible			= false;
            m_frmColor.DrawingStyleChanged	+= new DrawingStyleChangedEvent(m_frmColor_DrawingStyleChanged);
            m_frmColor.FillingStyleChanged	+= new FillingStyleChangedEvent(m_frmColor_FillingStyleChanged);

            m_frmEdit					= new EditForm();
            m_frmEdit.TopLevel			= false;
            m_frmEdit.FormBorderStyle	= FormBorderStyle.None;
            m_frmEdit.Visible			= false;
            m_frmEdit.CommandSelected	+= new CommandSelectedEvent(m_frmEdit_CommandSelected);

            m_frmLink					= new LinkForm();
            m_frmLink.TopLevel			= false;
            m_frmLink.FormBorderStyle	= FormBorderStyle.None;
            m_frmLink.Visible			= false;
            m_frmLink.LinkStyleChanged	+= new LinkStyleChangedEvent(m_frmLink_LinkStyleChanged);
            m_frmLink.RemoveLink		+= new RemoveLinkEvent(m_frmLink_RemoveLink);

            m_frmInfo = new InfoForm();
            m_frmInfo.TopLevel = false;
            m_frmInfo.FormBorderStyle = FormBorderStyle.None;
            m_frmInfo.Visible = false;
            m_frmInfo.DrawingInfoChanged += new DrawingInfoChanged(m_frmInfo_DrawingInfoChanged);
            tagInfo.TagControl = m_frmInfo;
            //m_frmLink.LoadLinkStyle(Environment.CurrentDirectory + "\\Links");

            tagColor.TagControl	= m_frmColor;
            tagEdit.TagControl	= m_frmEdit;
            tagLink.TagControl	= m_frmLink;

            m_clipBoard	= new GOMLib.GOM_Objects();
            m_selObjs	= new GOMLib.GOM_Objects();
            m_rgObjects	= new GOMLib.GOM_Objects();
            m_bitmap	= new Bitmap(plDraw.Width, plDraw.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            m_preprocess = new PreprocessQueue();
            m_preprocess.m_bDebugging	= false;
            m_preprocess.UpdateRequired += new PreprocessOverEvent(m_preprocess_UpdateRequired);
            m_preprocess.StartPreprocessThread();

            m_recognition = new RecognitionQueue(templatePath);
            m_recognition.m_bDebugging		= false;
            m_recognition.RecognitionStart	+= new RecognitionEvent(m_recognition_RecognitionStart);
            m_recognition.RecognitionEnd	+= new RecognitionEvent(m_recognition_RecognitionEnd);
            m_recognition.RecognitionOver	+= new RecognitionOverEvent(m_recognition_RecognitionOver);
            m_recognition.StartRecognitionThread();

            m_rgRedoList= new ArrayList();
            m_rgLinks	= new GOMLib.GOM_Links();
            m_rgStroke	= null;
            m_sketch	= null;

            m_selectedPoint	= null;
            m_selectedLink	= null;
            m_selectedLinkKeyPoint = null;

            m_tracker = new MouseTrackerLib.CTrackerClass();

            Graphics.FromImage(m_bitmap).FillRectangle(System.Drawing.Brushes.White, 0, 0, plDraw.Width, plDraw.Height);
        }
        /// <summary>
        /// 1. Draw a stroke
        /// 2. Whether 2 end-points of the stroke are on the objects' connectable points?
        ///   a. Yes: The stroke is a link connecting with two objects.
        ///   b. No:  Whether there is 1 end-point of the stroke is on the object's connectable point?
        ///     (1) Yes: The stroke is a link whose one end-ponit is connecting an object.
        ///              Is another end-point on a link's empty connectable point?
        ///              (a) Yes: Merge to links into one link.
        ///              (b) No:  The other end-point of the link is empty.
        ///     (2) No:  Whether there is 1 end-point on the existing link?
        ///		         (a) Yes: The stroke is a link.
        ///		         (b) No:  Add the stroke into the current sketch object.
        /// </summary>
        public void FinishCurrentSketchStroke()
        {
            if (m_rgStroke != null)
            {
                System.Collections.ArrayList	rgStroke;

                m_tracker.StopTracker();

                rgStroke	= CalculateSegments(m_rgStroke);
                m_rgStroke	= null;

                // Prepare key points of link
                GOMLib.GOM_Points keyPoints = new GOMLib.GOM_Points();
                for( int i=1; i<(rgStroke.Count-1); i++)
                {
                    GOMLib.GOM_Point keyPt = new GOMLib.GOM_Point();
                    keyPt.x = ((GOMLib.SketchPoint)rgStroke[i]).x;
                    keyPt.y = ((GOMLib.SketchPoint)rgStroke[i]).y;
                    keyPoints.Add( keyPt );
                }

                if (rgStroke.Count >= 2)
                {
                    GOMLib.SketchPoint	startPt, endPt;
                    GOMLib.GOM_Point	pt, pt1, pt2;
                    GOMLib.GOM_Interface_Graphic_Object	obj1, obj2;

                    startPt	= (GOMLib.SketchPoint)rgStroke[0];
                    endPt	= (GOMLib.SketchPoint)rgStroke[rgStroke.Count - 1];
                    pt1		= null;
                    pt2		= null;
                    obj1	= null;
                    obj2	= null;

                    for (int i = 0; i < m_rgObjects.Count; i++)
                    {
                        if (pt1 == null)
                        {
                            pt = m_rgObjects[i].GetConnectablePointAt(startPt.x, startPt.y);

                            if (pt != null)
                            {
                                pt1		= pt;
                                obj1	= m_rgObjects[i];
                            }
                        }
                        if (pt2 == null)
                        {
                            pt = m_rgObjects[i].GetConnectablePointAt(endPt.x, endPt.y);

                            if (pt != null)
                            {
                                pt2		= pt;
                                obj2	= m_rgObjects[i];
                            }
                        }
                    }

                    // 2. Whether 2 end-points of the stroke are on the objects' connectable points?
                    if ((pt1 != null) && (pt2 != null) && (pt1 != pt2))
                    {
                        //   a. Yes: The stroke is a link connecting with two objects.
                        GOMLib.GOM_Link				link;

                        link = GOMLib.GOM_Default_Values.CreateLink(obj1, pt1, obj2, pt2, keyPoints);
                        AddLinkWithMergemence(link);
                        DrawObjectsOnCanvas();
                        return;
                    }
                    else
                    {
                        //   b. No:  Whether there is 1 end-point of the stroke is on the object's connectable point?
                        if ( pt1 != null || pt2 != null )
                        {
                            //     (1) Yes: The stroke is a link whose one end-ponit is connecting an object.
                            //              Is another end-point on a link's empty connectable point?
                            GOMLib.GOM_Object_LinkNode linkNode = null;
                            if ( pt1 == null )
                            {
                                linkNode = GetLinkNode(startPt.x, startPt.y);
                            }
                            if ( pt2 == null )
                            {
                                linkNode = GetLinkNode(endPt.x, endPt.y);
                            }

                            if ( linkNode != null )
                            {
                                //              (a) Yes: Merge to links into one link.
                                GOMLib.GOM_Link link = null;
                                if ( pt1 == null )
                                {
                                    link = GOMLib.GOM_Default_Values.CreateLink(linkNode, linkNode.LinkPoint, obj2, pt2, keyPoints);
                                }
                                else
                                {
                                    link = GOMLib.GOM_Default_Values.CreateLink(obj1, pt1, linkNode, linkNode.LinkPoint, keyPoints);
                                }
                                AddLinkWithMergemence(link);
                                DrawObjectsOnCanvas();
                                return;
                            }
                            else
                            {
                                //              (b) No:  The other end-point of the link is empty.
                                GOMLib.GOM_Link				link = null;
                                GOMLib.GOM_Object_LinkNode	newlinkNode = null;
                                if ( pt1 == null )
                                {
                                    newlinkNode = new GOMLib.GOM_Object_LinkNode(startPt.x, startPt.y);
                                    link = GOMLib.GOM_Default_Values.CreateLink( newlinkNode, newlinkNode.LinkPoint, obj2, pt2, keyPoints);
                                }
                                else
                                {
                                    newlinkNode = new GOMLib.GOM_Object_LinkNode(endPt.x, endPt.y);
                                    link = GOMLib.GOM_Default_Values.CreateLink( obj1, pt1, newlinkNode, newlinkNode.LinkPoint, keyPoints);
                                }
                                m_rgObjects.Add(newlinkNode);
                                AddLinkWithMergemence(link);
                                DrawObjectsOnCanvas();
                                return;
                            }

                        }
                        else
                        {
                            //     (2) No:  Whether there is 1 end-point on the existing link?
                            if ( GetLinkByPoint(startPt.x,startPt.y)!=null
                                || GetLinkByPoint(endPt.x,endPt.y)!=null )
                            {
                                //		         (a) Yes: The stroke is a link.
                                GOMLib.GOM_Link				link = null;
                                GOMLib.GOM_Object_LinkNode	startLinkNode = null;
                                GOMLib.GOM_Object_LinkNode	endLinkNode = null;
                                startLinkNode = new GOMLib.GOM_Object_LinkNode(startPt.x, startPt.y);
                                endLinkNode = new GOMLib.GOM_Object_LinkNode(endPt.x, endPt.y);
                                link = GOMLib.GOM_Default_Values.CreateLink(startLinkNode, startLinkNode.LinkPoint, endLinkNode, endLinkNode.LinkPoint, keyPoints);
                                m_rgObjects.Add(startLinkNode);
                                m_rgObjects.Add(endLinkNode);
                                AddLinkWithMergemence(link);
                                DrawObjectsOnCanvas();
                                return;
                            }
                            else
                            {
                                //		         (b) No:  Add the stroke into the current sketch object.
                                // Do nothing.
                            }
                        }
                    }
                }

                rgStroke = DecodePointTrackFromXML(m_tracker.GetTrack_No_Collinear(plDraw.Handle.ToInt64(), 0.5));

                if ((m_sketch != null) && (rgStroke.Count > 1))
                {
                    m_sketch.rgSketchSet.Add(rgStroke);
                    m_preprocess.PushSketchAndWait(m_sketch, rgStroke);

                    DrawObjectsOnCanvas();
                }
            }
        }
        private void plDraw_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                m_LButtonPressed = false;
            }

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                {
                    switch (status.Action)
                    {
                        case UserActions.Linking:
                        {
                            for (int i = 0; i < m_rgObjects.Count; i++)
                            {
                                GOMLib.GOM_Point pt;

                                pt = m_rgObjects[i].GetConnectablePointAt(e.X, e.Y);

                                if (pt!= null)
                                {

                                    if ( m_selObjs[0]!=m_rgObjects[i] || m_selectedPoint!=pt )
                                    {
                                        GOMLib.GOM_Link				link;

                                        link = GOMLib.GOM_Default_Values.CreateLink( m_selObjs[0], m_selectedPoint, m_rgObjects[i], pt);
                                        AddLinkWithMergemence(link);
                                        m_selObjs.Clear();
                                        m_selectedLink = link;
                                        break;
                                    }

                                }
                            }

                            status.Action	= UserActions.Editing;
                            m_selectedPoint = null;
                            DrawObjectsOnCanvas();

                            break;
                        }
                        case UserActions.Sketching:
                        {
                            FinishCurrentSketchStroke();
                            break;
                        }
                        case UserActions.Editing:
                        {
                            break;
                        }
                        case UserActions.InsertObject:
                        {
                            GOMLib.GOM_Object_Primitive	primitive;

                            primitive = new GOMLib.GOM_Object_Primitive();
                            primitive.InitializeFromTemplate(status.Template);
                            primitive.xOffset = e.X;
                            primitive.yOffset = e.Y;
                            GOMLib.GOM_Default_Values.ScaleObject(primitive, 25, 25);
                            m_rgObjects.Add(primitive);

                            status.Action	= UserActions.Editing;
                            status.Template	= null;

                            m_selObjs.Clear();
                            m_selObjs.Add(primitive);

                            DrawObjectsOnCanvas();
                            break;
                        }
                        case UserActions.Controlling:
                        {
                            plDraw.Capture	= false;

                            status.Action	= UserActions.Editing;
                            m_selectedPoint	= null;
                            break;
                        }
                        case UserActions.Moving:
                        {
                            plDraw.Capture	= false;

                            status.Action	= UserActions.Editing;

                            if ( m_selObjs.Count == 1 )
                            {
                                GOMLib.GOM_Interface_Graphic_Object graphicObject = m_selObjs[0];

                                bool touched = false;
                                for ( int i=0; i<m_rgObjects.Count; i++ )
                                {
                                    GOMLib.GOM_Object_LinkNode linkNode = m_rgObjects[i] as GOMLib.GOM_Object_LinkNode;
                                    if ( !(graphicObject is GOMLib.GOM_Object_LinkNode) && linkNode != null )
                                    {
                                        GOMLib.GOM_Links links = GetLinks(linkNode);
                                        if ( links.Count == 1 )
                                        {
                                            GOMLib.GOM_Point touchedPoint = graphicObject.GetConnectablePointAt((int)linkNode.xOffset, (int)linkNode.yOffset);
                                            if ( touchedPoint != null )
                                            {
                                                if ( links[0].m_startObj == linkNode )
                                                {
                                                    links[0].m_startObj = graphicObject;
                                                    links[0].m_startPt = touchedPoint;
                                                }
                                                else
                                                {
                                                    links[0].m_endObj = graphicObject;
                                                    links[0].m_endPt = touchedPoint;
                                                }
                                                m_rgObjects.Remove(linkNode);
                                                touched = true;
                                            }
                                        }
                                    }
                                }

                                if ( touched )
                                {
                                    DrawObjectsOnCanvas();
                                }
                            }

                            break;
                        }
                        case UserActions.MovingKeyPoint:
                        {
                            m_selectedLinkKeyPoint = null;
                            status.Action	= UserActions.Editing;

                            if ( m_selectedLink.m_keyPts != null )
                            {
                                ArrayList pts = new ArrayList();
                                PointF ptf = m_selectedLink.StartPointInCanvas(m_rgObjects);
                                GOMLib.SketchPoint spt = new GOMLib.SketchPoint();
                                spt.x = (int)ptf.X;
                                spt.y = (int)ptf.Y;
                                pts.Add( spt );
                                for( int i=0; i<m_selectedLink.m_keyPts.Count; i++ )
                                {
                                    spt = new GOMLib.SketchPoint();
                                    spt.x = (int)m_selectedLink.m_keyPts[i].x;
                                    spt.y = (int)m_selectedLink.m_keyPts[i].y;
                                    pts.Add( spt );
                                }
                                ptf = m_selectedLink.EndPointInCanvas(m_rgObjects);
                                spt = new GOMLib.SketchPoint();
                                spt.x = (int)ptf.X;
                                spt.y = (int)ptf.Y;
                                pts.Add( spt );

                                pts = CalculateSegments(pts);

                                m_selectedLink.m_keyPts = new GOMLib.GOM_Points();
                                for( int i=0; i<(pts.Count-2); i++ )
                                {
                                    GOMLib.GOM_Point pt = new GOMLib.GOM_Point();
                                    pt.x = ((GOMLib.SketchPoint)pts[i+1]).x;
                                    pt.y = ((GOMLib.SketchPoint)pts[i+1]).y;
                                    m_selectedLink.m_keyPts.Add( pt );
                                }
                            }

                            DrawObjectsOnCanvas();
                            break;
                        }
                        case UserActions.Selecting:
                        {
                            System.Drawing.Region	rgn;
                            System.Drawing.Region	rgnIntersect;
                            System.Drawing.Graphics	canvas;

                            rgn		= new Region(m_selectingRect);

                            canvas	= plDraw.CreateGraphics();

                            for (int i = 0; i < m_rgObjects.Count; i++)
                            {
                                rgnIntersect = rgn.Clone();
                                rgnIntersect.Intersect(m_rgObjects[i].BoundingRegion);

                                if (!rgnIntersect.IsEmpty(canvas))
                                {
                                    m_selObjs.Add(m_rgObjects[i]);
                                }
                            }
                            plDraw.Capture	= false;

                            status.Action	= UserActions.Editing;

                            m_selectingRect.X		= 0;
                            m_selectingRect.Y		= 0;
                            m_selectingRect.Width	= 0;
                            m_selectingRect.Height	= 0;

                            DrawObjectsOnCanvas();
                            break;
                        }
                    }
                    break;
                }
            }
        }
        private GOMLib.GOM_Point DecodeXMLToPoint(System.Xml.XmlNode node)
        {
            GOMLib.GOM_Point	pt;

            pt = new GOMLib.GOM_Point();

            for (int i = 0; i < node.Attributes.Count; i++)
            {
                if (System.String.Compare(node.Attributes[i].Name, "x", true) == 0)
                {
                    pt.x = float.Parse(node.Attributes[i].Value);
                }
                if (System.String.Compare(node.Attributes[i].Name, "y", true) == 0)
                {
                    pt.y = float.Parse(node.Attributes[i].Value);
                }
            }

            return pt;
        }
        private void plDraw_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            GOMLib.GOM_Interface_Graphic_Object	selectedObj;

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                m_LButtonPressed = true;
            }

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Right:
                {
                    if ( m_selectedLink!= null && m_selectedLink.IsPointOnLink(e.X, e.Y, m_rgObjects) )
                    {
                        m_selectedLink.AddKeyPoint(e.X, e.Y, m_rgObjects);
                        DrawObjectsOnCanvas();
                    }
                    else
                    {
                        if (status.Action == UserActions.Sketching)
                        {
                            if (!m_LButtonPressed)
                            {
                                FinishCurrentSketchObject();
                            }
                        }
                        else
                        {
                            ClearRecognitionResult();
                            m_sketch = new GOMLib.GOM_Object_Sketch();
                            status.Action = UserActions.Sketching;
                            if ( DrawingModeChanged != null )
                            {
                                DrawingModeChanged(DrawingMode.Sketching);
                            }

                        }

                        DrawObjectsOnCanvas();
                    }
                    break;
                }
                case System.Windows.Forms.MouseButtons.Left:
                {
                    switch (status.Action)
                    {
                        case UserActions.Sketching:
                        {
            //							FinishCurrentSketchStroke();

                            ClearRecognitionResult();
                            DrawObjectsOnCanvas();

                            m_orgX		= -1;
                            m_orgY		= -1;
                            m_rgStroke	= new ArrayList();
                            m_tracker.StartTracker(true);

                            break;
                        }
                        case UserActions.Editing:
                        {
                            GOMLib.GOM_Link	link;

                            plDraw.Capture	= true;

                            selectedObj				= null;
                            m_orgX					= e.X;
                            m_orgY					= e.Y;
                            m_selectedLinkKeyPoint	= null;

                            //Ckeck for link key point at the mouse position
                            if ( m_selectedLink != null && m_selObjs.Count<=0 )
                            {
                                for( int i=0; i<m_selectedLink.m_keyPts.Count; i++)
                                {
                                    if ( GOMLib.GOM_Default_Values.IsMouseOnPoint(m_selectedLink.m_keyPts[i].x, m_selectedLink.m_keyPts[i].y, e.X, e.Y ) )
                                    {
                                        m_selectedLinkKeyPoint = m_selectedLink.m_keyPts[i];
                                        status.Action = UserActions.MovingKeyPoint;
                                        if ( DrawingModeChanged != null )
                                        {
                                            DrawingModeChanged(DrawingMode.Editing);
                                        }

                                        return;
                                    }
                                }
                            }

                            //Check for object at the mouse position
                            for (int i = m_rgObjects.Count - 1; i >= 0; i--)
                            {
                                if (m_rgObjects[i].IsPointInObject(e.X, e.Y))
                                {
                                    selectedObj = m_rgObjects[i];

                                    if (!m_selObjs.Contains(selectedObj))
                                    {
                                        if (!m_CtrlPressed)
                                        {
                                            m_selObjs.Clear();
                                        }
                                        m_selObjs.Add(selectedObj);
                                    }
                                    status.Action = UserActions.Moving;
                                    if ( DrawingModeChanged != null )
                                    {
                                        DrawingModeChanged(DrawingMode.Editing);
                                    }
                                    DrawObjectsOnCanvas();

                                    return;
                                }
                            }

                            m_selectedLink = null;
                            for (int i = 0; i < m_rgLinks.Count; i++)
                            {
                                link = (GOMLib.GOM_Link)m_rgLinks[i];

                                if (link.IsPointOnLink(e.X, e.Y, m_rgObjects))
                                {
                                    m_selObjs.Clear();
                                    m_selectedLink = link;
                                    DrawObjectsOnCanvas();

                                    return;
                                }
                            }
                            //Check for controllable points
                            for (int i = 0; i < m_selObjs.Count; i++)
                            {
                                m_selectedPoint = m_selObjs[i].GetMovablePointAt(e.X, e.Y);

                                if (m_selectedPoint != null)
                                {
                                    status.Action	= UserActions.Controlling;
                                    selectedObj		= m_selObjs[i];

                                    m_selObjs.Clear();
                                    m_selObjs.Add(selectedObj);
                                    DrawObjectsOnCanvas();

                                    return;
                                }
                            }
                            //Check for connectable points
                            for (int i = 0; i < m_rgObjects.Count; i++)
                            {
                                m_selectedPoint = m_rgObjects[i].GetConnectablePointAt(e.X, e.Y);

                                if (m_selectedPoint != null)
                                {
                                    status.Action	= UserActions.Linking;
                                    selectedObj		= m_rgObjects[i];

                                    m_selObjs.Clear();
                                    m_selObjs.Add(selectedObj);
                                    DrawObjectsOnCanvas();

                                    return;
                                }
                            }
                            //A object is selected. Update the selection list
                            if (selectedObj != null)
                            {
                                if (!m_selObjs.Contains(selectedObj))
                                {
                                    if (!m_CtrlPressed)
                                    {
                                        m_selObjs.Clear();
                                    }
                                    m_selObjs.Add(selectedObj);
                                }
                                status.Action = UserActions.Moving;
                                if ( DrawingModeChanged != null )
                                {
                                    DrawingModeChanged(DrawingMode.Editing);
                                }

                            }
                            else
                            {
                                if (!m_CtrlPressed)
                                {
                                    m_selObjs.Clear();
                                }

                                m_orgX = e.X;
                                m_orgY = e.Y;

                                status.Action = UserActions.Selecting;
                                if ( DrawingModeChanged != null )
                                {
                                    DrawingModeChanged(DrawingMode.Editing);
                                }

                            }
                            DrawObjectsOnCanvas();
                            break;
                        }
                        case UserActions.InsertObject:
                        {
                            break;
                        }
                    }
                    break;
                }
            }
        }