Click here to Skip to main content
15,886,806 members
Articles / Containers / Virtual Machine

Statistical parsing of English sentences

Rate me:
Please Sign up or sign in to vote.
4.95/5 (88 votes)
13 Dec 200617 min read 988.2K   23.6K   239  
Shows how to generate parse trees for English language sentences, using a C# port of OpenNLP, a statistical natural language parsing library.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Netron.Lithium
{
	/// <summary>
	/// Represents the connection between two connectors
	/// </summary>
	public class Connection : Entity
	{

		#region Fields
		/// <summary>
		/// the shape where the connection starts
		/// </summary>
		protected ShapeBase from;
		/// <summary>
		/// the shape where the connection ends
		/// </summary>
		protected ShapeBase to;
		/// <summary>
		/// the start and end points
		/// </summary>
		protected Point start, end;
		/// <summary>
		/// the pen used to draw the connection,
		/// can switch depending on the hovering state e.g.
		/// </summary>
		protected Pen currentPen;

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the shape where the connection starts
		/// </summary>
		public ShapeBase From
		{
			get{return from;}
			set{from = value;}
		}

		/// <summary>
		/// Gets or sets where the connection ends
		/// </summary>
		public ShapeBase To
		{
			get{return to;}
			set{to = value;}
		}

		/// <summary>
		/// Get the point where the connection starts
		/// </summary>
		public Point Start
		{
			get
			{
				
				
				return new Point(from.X+from.Width/2,from.Y+from.Height/2);	
			}
		}

		/// <summary>
		/// Gets the point where connection ends
		/// </summary>
		public Point End
		{
			get
			{
				end = new Point(to.X+to.Width/2,to.Y+to.Height/2);
				
				return end;
			}
		}

		#endregion

		#region Constructors
		/// <summary>
		/// Default ctor
		/// </summary>
		public Connection()
		{
			
		}
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="from">the shape where the connection starts</param>
		/// <param name="to">the shape where the connection ends</param>
		public Connection(ShapeBase from, ShapeBase to)
		{
			this.from = from;			
			this.to = to;
			currentPen = blackPen;
			
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="from">the shape where the connection starts</param>
		/// <param name="to">the shape where the connection ends</param>
		/// <param name="color">the color of the connection</param>
		public Connection(ShapeBase from, ShapeBase to, Color color) : this(from, to)
		{
			currentPen = new Pen(color, 1f);
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="from">the shape where the connection starts</param>
		/// <param name="to">the shape where the connection ends</param>
		/// <param name="color">the color of the connection</param>
		/// <param name="width">the (float) width of the connection (in pixels)</param>
		public Connection(ShapeBase from, ShapeBase to, Color color, float width) : this(from, to, color)
		{
			currentPen = new Pen(color, width);
		}
		#endregion

		#region Methods

		/// <summary>
		/// Paints the connection on the canvas
		/// The From part is always the child node while the To part is 
		/// always the parent node.
		/// Hence; 
		/// - vertical: Parent->Child <=> Top->Bottom
		/// - horizontal: Parent->Child <=> Left->Right
		/// </summary>
		/// <param name="g"></param>
		public override void Paint(System.Drawing.Graphics g)
		{
			g.SmoothingMode = SmoothingMode.AntiAlias;
			PointF p1, p2, p3, p4; //intermediate points
			if(visible)
			{
				if(hovered || isSelected)
					pen = redPen;
				else
					pen = currentPen;

				switch(site.ConnectionType)
				{
					case ConnectionType.Default:
					switch(site.LayoutDirection)
					{
						case TreeDirection.Vertical:
							p1 = new PointF(from.Left + from.Width/2, from.Top); 
							p2 = new PointF(to.Left + to.Width/2, to.Bottom+5);
							g.DrawLine(pen,p1,p2);
							break;
						case TreeDirection.Horizontal:
							p1 = new PointF(from.Left, from.Top +  from.Height/2); 
							p2 = new PointF(to.Right +4, to.Top + to.Height/2);
							g.DrawLine(pen,p1,p2);
							break;
					}
						break;
					case ConnectionType.Traditional:
					switch(site.LayoutDirection)
					{
						case TreeDirection.Vertical:
							p1 = new PointF(from.Left + from.Width/2, from.Top - (from.Top - to.Bottom)/2); 
							p2 = new PointF(to.Left + to.Width/2, from.Top - (from.Top - to.Bottom)/2);
							g.DrawLine(pen, Start,p1);
							g.DrawLine(pen, p1, p2);
							g.DrawLine(pen, End, p2);
							break;
						case TreeDirection.Horizontal:

							p1 = new PointF(to.Right + (from.Left - to.Right)/2, from.Top + from.Height/2); 
							p2 = new PointF(to.Right + (from.Left - to.Right)/2, to.Top + to.Height/2);
							g.DrawLine(pen, Start,p1);
							g.DrawLine(pen, p1, p2);
							g.DrawLine(pen, End, p2);
							break;
					}
						break;
					
					case ConnectionType.Bezier:
					switch(site.LayoutDirection)
					{
						case TreeDirection.Vertical:
							p1 = new PointF(from.Left+from.Width/2,from.Top);
							p2 = new PointF(from.Left + from.Width/2, from.Top - (from.Top - to.Bottom)/2); 
							p3 = new PointF(to.Left + to.Width/2, from.Top - (from.Top - to.Bottom)/2);
							p4 = new PointF(to.Left+to.Width/2,to.Bottom);
							g.DrawBezier(pen, p1, p2, p3, p4);
							
							break;
						case TreeDirection.Horizontal:

							p1 = new PointF(to.Right, to.Top + to.Height/2); 							
							p2 = new PointF(to.Right + (from.Left - to.Right)/2, to.Top + to.Height/2);
							p3 = new PointF(to.Right + (from.Left - to.Right)/2, from.Top + from.Height/2); 
							p4 = new PointF(from.Left,from.Top + from.Height/2);
							g.DrawBezier(pen, p1, p2, p3, p4);
							break;
					}
						break;
				}
			}
			
		}
		/// <summary>
		/// Invalidates the connection
		/// </summary>
		public override void Invalidate()
		{
			
			site.Invalidate(Rectangle.Union(from.rectangle,to.rectangle));
		}

		/// <summary>
		/// Tests if the mouse hits this connection
		/// </summary>
		/// <param name="p"></param>
		/// <returns></returns>
		public override bool Hit(Point p)
		{
			PointF p1,p2, p3, s;
			RectangleF r1, r2, r3;

			switch(site.ConnectionType)
			{
				case ConnectionType.Default:
					#region The default Hit method
					
					float o,u;
					p1 = start; p2 = end;
	
					// p1 must be the leftmost point.
					if (p1.X > p2.X) { s = p2; p2 = p1; p1 = s; }

					//this is specifically necessary when the layout works horizontally
					//the method beneth will not return true as should be in this case
					if(p1.Y==p2.Y)
					{
						p1.Y+=-3;
						return new RectangleF(p1,new SizeF(p2.X-p1.X,6)).Contains(p);
					}
					r1 = new RectangleF(p1.X, p1.Y, 0, 0);
					r2 = new RectangleF(p2.X, p2.Y, 0, 0);
					r1.Inflate(3, 3);
					r2.Inflate(3, 3);
					//this is like a topological neighborhood
					//the connection is shifted left and right
					//and the point under consideration has to be in between.						
					if (RectangleF.Union(r1, r2).Contains(p))
					{
				
						if (p1.Y < p2.Y) //SWNE
						{
							o = r1.Left + (((r2.Left - r1.Left) * (p.Y - r1.Bottom)) / (r2.Bottom - r1.Bottom));
							u = r1.Right + (((r2.Right - r1.Right) * (p.Y - r1.Top)) / (r2.Top - r1.Top));
							return ((p.X > o) && (p.X < u));
						}
						else //NWSE
						{
							o = r1.Left + (((r2.Left - r1.Left) * (p.Y - r1.Top)) / (r2.Top - r1.Top));
							u = r1.Right + (((r2.Right - r1.Right) * (p.Y - r1.Bottom)) / (r2.Bottom - r1.Bottom));
							return ((p.X > o) && (p.X < u));
						}
					}
					#endregion
					break;
				case ConnectionType.Traditional:
					#region The rectangular Hit method
						switch(site.LayoutDirection)
						{
							case TreeDirection.Vertical:
								p1 = new PointF(from.Left + from.Width/2-5, from.Top - (from.Top - to.Bottom)/2-5); //shift 5 to contain the connection
								p2 = new PointF(to.Left + to.Width/2-5, from.Top - (from.Top - to.Bottom)/2-5);
								p3 = new Point(to.Left+to.Width/2-5,to.Bottom-5);

								r1 = new RectangleF(p1, new SizeF(10,(from.Top - to.Bottom)/2+5)); 
								if(p1.X<p2.X)
									r2 = new RectangleF(p1,new SizeF(p2.X-p1.X,10));
								else
									r2 = new RectangleF(p2,new SizeF(p1.X-p2.X,10));
								r3 = new RectangleF(p3, new SizeF(10, (from.Top - to.Bottom)/2+5));
								return r1.Contains(p.X,p.Y) || r2.Contains(p.X,p.Y) || r3.Contains(p.X,p.Y) ;
								
							case TreeDirection.Horizontal:

								p1 = new PointF(to.Right + (from.Left - to.Right)/2, from.Top + from.Height/2); 
								p2 = new PointF(to.Right + (from.Left - to.Right)/2, to.Top + to.Height/2);
							
								break;
						}
					#endregion
					break;
			}


			return false;
		}

		/// <summary>
		/// Moves the connection with the given shift
		/// </summary>
		/// <param name="p"></param>
		public override void Move(Point p)
		{

		}


		#endregion

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
Richard Northedge is a senior developer with a UK Microsoft Gold Partner company. He has a postgraduate degree in English Literature, has been programming professionally since 1998 and has been an MCSD since 2000.

Comments and Discussions