diff --git a/Source/Core/Editing/GridSetup.cs b/Source/Core/Editing/GridSetup.cs
index ff1702967a071633a2bcbdc9dfd49c6628090f47..31a253f82f903fa9a9f6b24292730f790102ae71 100755
--- a/Source/Core/Editing/GridSetup.cs
+++ b/Source/Core/Editing/GridSetup.cs
@@ -49,6 +49,8 @@ namespace CodeImp.DoomBuilder.Editing
 		private int gridsize;
 		private float gridsizef;
 		private float gridsizefinv;
+		private float gridrotate;
+		private float gridoriginx, gridoriginy;
 
 		// Background
 		private string background = "";
@@ -66,6 +68,9 @@ namespace CodeImp.DoomBuilder.Editing
 
 		public int GridSize { get { return gridsize; } } //mxd
 		public float GridSizeF { get { return gridsizef; } }
+		public float GridRotate { get { return gridrotate; }}
+		public float GridOriginX { get { return gridoriginx; }}
+		public float GridOriginY { get { return gridoriginy; }}
 		internal string BackgroundName { get { return background; } }
 		internal int BackgroundSource { get { return backsource; } }
 		internal ImageData Background { get { return backimage; } }
@@ -86,6 +91,9 @@ namespace CodeImp.DoomBuilder.Editing
 			SetGridSize(DEFAULT_GRID_SIZE);
 			backscalex = 1.0f;
 			backscaley = 1.0f;
+			gridrotate = 0.0f;
+			gridoriginx = 0;
+			gridoriginy = 0;
 			
 			// Register actions
 			General.Actions.BindMethods(this);
@@ -128,6 +136,9 @@ namespace CodeImp.DoomBuilder.Editing
 			cfg.WriteSetting(path + ".backscalex", (int)(backscalex * 100.0f));
 			cfg.WriteSetting(path + ".backscaley", (int)(backscaley * 100.0f));
 			cfg.WriteSetting(path + ".gridsize", gridsizef);
+			cfg.WriteSetting(path + ".gridrotate", gridrotate);
+			cfg.WriteSetting(path + ".gridoriginx", gridoriginx);
+			cfg.WriteSetting(path + ".gridoriginy", gridoriginy);
 		}
 
 		// Read settings from configuration
@@ -141,6 +152,9 @@ namespace CodeImp.DoomBuilder.Editing
 			backscalex = cfg.ReadSetting(path + ".backscalex", 100) / 100.0f;
 			backscaley = cfg.ReadSetting(path + ".backscaley", 100) / 100.0f;
 			gridsizef = cfg.ReadSetting(path + ".gridsize", DEFAULT_GRID_SIZE);
+			gridoriginx = cfg.ReadSetting(path + ".gridoriginx", 0);
+			gridoriginy = cfg.ReadSetting(path + ".gridoriginy", 0);
+			gridrotate = cfg.ReadSetting(path + ".gridrotate", 0.0f);
 
 			// Setup
 			SetGridSize(gridsizef);
@@ -162,6 +176,19 @@ namespace CodeImp.DoomBuilder.Editing
 			General.MainWindow.UpdateGrid(gridsizef);
 		}
 
+		// Set the rotation angle of the grid
+		internal void SetGridRotation(float angle)
+		{
+			gridrotate = angle;
+		}
+
+		// Set the origin of the grid
+		internal void SetGridOrigin(float x, float y)
+		{
+			gridoriginx = x;
+			gridoriginy = y;
+		}
+
 		// This sets the background
 		internal void SetBackground(string name, int source)
 		{
@@ -226,15 +253,29 @@ namespace CodeImp.DoomBuilder.Editing
 		// This snaps to the nearest grid coordinate
 		public Vector2D SnappedToGrid(Vector2D v)
 		{
-			return SnappedToGrid(v, gridsizef, gridsizefinv);
+			return SnappedToGrid(v, gridsizef, gridsizefinv, gridrotate, gridoriginx, gridoriginy);
 		}
 
 		// This snaps to the nearest grid coordinate
-		public static Vector2D SnappedToGrid(Vector2D v, float gridsize, float gridsizeinv)
+		public static Vector2D SnappedToGrid(Vector2D v, float gridsize, float gridsizeinv, float gridrotate = 0.0f, float gridoriginx = 0, float gridoriginy = 0)
 		{
+			Vector2D origin = new Vector2D(gridoriginx, gridoriginy);
+			bool transformed = Math.Abs(gridrotate) > 1e-4 || gridoriginx != 0 || gridoriginx != 0;
+			if (transformed)
+			{
+				// Grid is transformed, so reverse the transformation first
+				v = ((v - origin).GetRotated(-gridrotate));
+			}
+		
 			Vector2D sv = new Vector2D((float)Math.Round(v.x * gridsizeinv) * gridsize,
 								(float)Math.Round(v.y * gridsizeinv) * gridsize);
 
+			if (transformed)
+			{
+				// Put back into original frame
+				sv = sv.GetRotated(gridrotate) + origin;
+			}
+
 			if(sv.x < General.Map.Config.LeftBoundary) sv.x = General.Map.Config.LeftBoundary;
 			else if(sv.x > General.Map.Config.RightBoundary) sv.x = General.Map.Config.RightBoundary;
 
diff --git a/Source/Core/Geometry/Line2D.cs b/Source/Core/Geometry/Line2D.cs
index 403868e8e40ea0ed6edab0f8e1a3640dd6f8a640..d5d0d194dd534d55867cd35dabef08985fa21d4f 100755
--- a/Source/Core/Geometry/Line2D.cs
+++ b/Source/Core/Geometry/Line2D.cs
@@ -17,6 +17,8 @@
 #region ================== Namespaces
 
 using System;
+using System.Drawing;
+using System.Windows.Forms;
 using CodeImp.DoomBuilder.Map;
 
 #endregion
@@ -223,6 +225,73 @@ namespace CodeImp.DoomBuilder.Geometry
 			// Calculate and return intersection offset
 			return new Vector2D(v1.x + u * (v2.x - v1.x), v1.y + u * (v2.y - v1.y));
 		}
+
+		// Cohen-Sutherland algorithm
+		public static Line2D ClipToRectangle(Line2D line, RectangleF rect, out bool intersects)
+		{
+			int flags1 = MapSet.GetCSFieldBits(line.v1, rect);
+			int flags2 = MapSet.GetCSFieldBits(line.v2, rect);
+			Line2D result = line;
+			intersects = false;
+
+			// Each pass will modify one coordinate of one endpoint
+			for (int pass = 0; pass < 4; pass++)
+			{
+				if (flags1 == 0 && flags2 == 0)
+				{
+					// Line is fully inside the box
+					intersects = true;
+					return result;
+				}
+				
+				if ((flags1 & flags2) != 0)
+				{
+					// Both points are in the same outer area
+					return new Line2D();
+				}
+
+				float x, y;
+				int outFlags = flags1 != 0 ? flags1 : flags2;
+				if ((outFlags & 0x1) > 0) // Top
+				{
+					x = line.v1.x + (line.v2.x - line.v1.x) * (rect.Top - line.v1.y) / (line.v2.y - line.v1.y);
+					y = rect.Top;
+				}
+				else if ((outFlags & 0x2) > 0) // Bottom
+				{
+					x = line.v1.x + (line.v2.x - line.v1.x) * (rect.Bottom - line.v1.y) / (line.v2.y - line.v1.y);
+					y = rect.Bottom;
+				}
+				else if ((outFlags & 0x4) > 0) // Left
+				{
+					y = line.v1.y + (line.v2.y - line.v1.y) * (rect.Left - line.v1.x) / (line.v2.x - line.v1.x);
+					x = rect.Left;
+				}
+				else if ((outFlags & 0x8) > 0) // Right
+				{
+					y = line.v1.y + (line.v2.y - line.v1.y) * (rect.Right - line.v1.x) / (line.v2.x - line.v1.x);
+					x = rect.Right;
+				} 
+				else
+				{
+					intersects = false;
+					return new Line2D();
+				}
+
+				if (outFlags == flags1)
+				{
+					line.v1 = new Vector2D(x, y);
+					flags1 = MapSet.GetCSFieldBits(line.v1, rect);
+				}
+				else
+				{
+					line.v2 = new Vector2D(x, y);
+					flags2 = MapSet.GetCSFieldBits(line.v2, rect);
+				}
+			}
+
+			return line;
+		}
 		
 		#endregion
 
@@ -318,6 +387,19 @@ namespace CodeImp.DoomBuilder.Geometry
 		{
 			return Line2D.GetCoordinatesAt(v1, v2, u);
 		}
+
+		public Line2D GetTransformed(float offsetx, float offsety, float scalex, float scaley)
+		{
+			return new Line2D(v1.GetTransformed(offsetx, offsety, scalex, scaley),
+				v2.GetTransformed(offsetx, offsety, scalex, scaley));
+		}
+
+		// Inverse Transform
+		public Line2D GetInvTransformed(float invoffsetx, float invoffsety, float invscalex, float invscaley)
+		{
+			return new Line2D(v1.GetInvTransformed(invoffsetx, invoffsety, invscalex, invscaley), 
+				v2.GetInvTransformed(invoffsetx, invoffsety, invscalex, invscaley));
+		}
 		
 		#endregion
 	}
diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs
index df5e3fb8f40ca60c9dc6f921f3fe8339f8d0f5a9..e270b65b648302cfe789fa13be4180d1bdf683e6 100755
--- a/Source/Core/Map/Linedef.cs
+++ b/Source/Core/Map/Linedef.cs
@@ -131,7 +131,7 @@ namespace CodeImp.DoomBuilder.Map
 			
 			if(map == General.Map.Map)
 				General.Map.UndoRedo.RecAddLinedef(this);
-            
+			
 			// We have no destructor
 			GC.SuppressFinalize(this);
 		}
@@ -893,42 +893,58 @@ namespace CodeImp.DoomBuilder.Map
 		}
 
 		// This returns all points at which the line intersects with the grid
-		public List<Vector2D> GetGridIntersections() 
+		public List<Vector2D> GetGridIntersections()
 		{
-			return GetGridIntersections(new Vector2D());
+			return GetGridIntersections(0.0f);
+		}
+
+		
+		public List<Vector2D> GetGridIntersections(float gridrotation, float gridoriginx = 0.0f, float gridoriginy = 0.0f) 
+		{
+			return GetGridIntersections(new Vector2D(), gridrotation, gridoriginx, gridoriginy);
 		}
 
 		// This returns all points at which the line intersects with the grid
-		public List<Vector2D> GetGridIntersections(Vector2D gridoffset)
+		public List<Vector2D> GetGridIntersections(Vector2D gridoffset, float gridrotation = 0.0f, float gridoriginx = 0.0f, float gridoriginy = 0.0f)
 		{
 			List<Vector2D> coords = new List<Vector2D>();
 			Vector2D v = new Vector2D();
 			float minx, maxx, miny, maxy;
 			bool reversex, reversey;
+
+			Vector2D v1 = start.Position;
+			Vector2D v2 = end.Position;
+
+			bool transformed = Math.Abs(gridrotation) > 1e-4 || Math.Abs(gridoriginx) > 1e-4 || Math.Abs(gridoriginy) > 1e-4;
+			if (transformed)
+			{
+				v1 = (v1 - new Vector2D(gridoriginx, gridoriginy)).GetRotated(-gridrotation);
+				v2 = (v2 - new Vector2D(gridoriginx, gridoriginy)).GetRotated(-gridrotation);
+			}
 			
-			if(start.Position.x > end.Position.x)
+			if(v1.x > v2.x)
 			{
-				minx = end.Position.x;
-				maxx = start.Position.x;
+				minx = v2.x;
+				maxx = v1.x;
 				reversex = true;
 			}
 			else
 			{
-				minx = start.Position.x;
-				maxx = end.Position.x;
+				minx = v1.x;
+				maxx = v2.x;
 				reversex = false;
 			}
 
-			if(start.Position.y > end.Position.y)
+			if(v1.y > v2.y)
 			{
-				miny = end.Position.y;
-				maxy = start.Position.y;
+				miny = v2.y;
+				maxy = v1.y;
 				reversey = true;
 			}
 			else
 			{
-				miny = start.Position.y;
-				maxy = end.Position.y;
+				miny = v1.y;
+				maxy = v2.y;
 				reversey = false;
 			}
 
@@ -942,7 +958,7 @@ namespace CodeImp.DoomBuilder.Map
 					float u = (gx - minx) / (maxx - minx);
 					if(reversex) u = 1.0f - u;
 					v.x = gx;
-					v.y = start.Position.y + (end.Position.y - start.Position.y) * u;
+					v.y = v1.y + (v2.y - v1.y) * u;
 					coords.Add(v);
 				}
 			}
@@ -956,11 +972,19 @@ namespace CodeImp.DoomBuilder.Map
 					// Add intersection point at this y coordinate
 					float u = (gy - miny) / (maxy - miny);
 					if(reversey) u = 1.0f - u;
-					v.x = start.Position.x + (end.Position.x - start.Position.x) * u;
+					v.x = v1.x + (v2.x - v1.x) * u;
 					v.y = gy;
 					coords.Add(v);
 				}
 			}
+
+			if (transformed)
+			{
+				for (int i = 0; i < coords.Count; i++)
+				{
+					coords[i] = coords[i].GetRotated(gridrotation) + new Vector2D(gridoriginx, gridoriginy);
+				}
+			}
 			
 			// Profit
 			return coords;
@@ -983,34 +1007,34 @@ namespace CodeImp.DoomBuilder.Map
 			// Calculate intersection offset
 			float u = ((p.x - v1.x) * (v2.x - v1.x) + (p.y - v1.y) * (v2.y - v1.y)) * lengthsqinv;
 
-            // Limit intersection offset to the line
-            if (bounded)
-            {
-                if (General.Map.UDMF)
-                {
-                    u = Math.Max(0f, Math.Min(1f, u));
-                }
-                else // restore old way for visplane explorer (which doesn't work for UDMF anyway)
-                {
-                    u = Math.Max(lengthinv, Math.Min(1f - lengthinv, u));
-                }
-            }
-
-            /*
-            // Calculate intersection point
-            Vector2D i = v1 + u * (v2 - v1);
+			// Limit intersection offset to the line
+			if (bounded)
+			{
+				if (General.Map.UDMF)
+				{
+					u = Math.Max(0f, Math.Min(1f, u));
+				}
+				else // restore old way for visplane explorer (which doesn't work for UDMF anyway)
+				{
+					u = Math.Max(lengthinv, Math.Min(1f - lengthinv, u));
+				}
+			}
+
+			/*
+			// Calculate intersection point
+			Vector2D i = v1 + u * (v2 - v1);
 
 			// Return distance between intersection and point
 			// which is the shortest distance to the line
 			float ldx = p.x - i.x;
 			float ldy = p.y - i.y;
-            */
+			*/
 
-            // ano - let's check to see if we can do the previous faster without using operator overloading and etc
-            // the answer: running it  int.MaxValue / 64 times it tended to be around 100ms faster
-            float ldx = p.x - (v1.x + u * (v2.x - v1.x));
-            float ldy = p.y - (v1.y + u * (v2.y - v1.y));
-            return ldx * ldx + ldy * ldy;
+			// ano - let's check to see if we can do the previous faster without using operator overloading and etc
+			// the answer: running it  int.MaxValue / 64 times it tended to be around 100ms faster
+			float ldx = p.x - (v1.x + u * (v2.x - v1.x));
+			float ldy = p.y - (v1.y + u * (v2.y - v1.y));
+			return ldx * ldx + ldy * ldy;
 		}
 
 		// This returns the shortest distance from given coordinates to line
diff --git a/Source/Core/Rendering/Plotter.cs b/Source/Core/Rendering/Plotter.cs
index 38e8406cd011e9ee762e785980636e70352caaf3..f51d7db8af404330c83aaa15c90f5f1d7d32e593 100755
--- a/Source/Core/Rendering/Plotter.cs
+++ b/Source/Core/Rendering/Plotter.cs
@@ -209,7 +209,7 @@ namespace CodeImp.DoomBuilder.Rendering
 
 		// This draws a line normally
 		// See: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
-		public void DrawLineSolid(int x1, int y1, int x2, int y2, ref PixelColor c)
+		public void DrawLineSolid(int x1, int y1, int x2, int y2, ref PixelColor c, uint mask = 0xffffffff)
 		{
 			// Check if the line is outside the screen for sure.
 			// This is quickly done by checking in which area both points are. When this
@@ -262,7 +262,9 @@ namespace CodeImp.DoomBuilder.Rendering
 						px += sdx;
 
 						// Draw pixel
-						pixels[py * width + px] = c;
+						if ((mask & (1 << (i & 0x7))) != 0) {
+							pixels[py * width + px] = c;
+						}
 					}
 				}
 				// Else the line is more vertical than horizontal
@@ -279,7 +281,9 @@ namespace CodeImp.DoomBuilder.Rendering
 						py += sdy;
 
 						// Draw pixel
-						pixels[py * width + px] = c;
+						if ((mask & (1 << (i & 0x7))) != 0) {
+							pixels[py * width + px] = c;
+						}
 					}
 				}
 			}
@@ -303,8 +307,10 @@ namespace CodeImp.DoomBuilder.Rendering
 						px += sdx;
 						
 						// Draw pixel
-						if((px >= 0) && (px < visiblewidth) && (py >= 0) && (py < visibleheight))
-							pixels[py * width + px] = c;
+						if ((mask & (1 << (i & 0x7))) != 0) {
+							if((px >= 0) && (px < visiblewidth) && (py >= 0) && (py < visibleheight))
+								pixels[py * width + px] = c;
+						}
 					}
 				}
 				// Else the line is more vertical than horizontal
@@ -321,8 +327,10 @@ namespace CodeImp.DoomBuilder.Rendering
 						py += sdy;
 						
 						// Draw pixel
-						if((px >= 0) && (px < visiblewidth) && (py >= 0) && (py < visibleheight))
-							pixels[py * width + px] = c;
+						if ((mask & (1 << (i & 0x7))) != 0) {
+							if((px >= 0) && (px < visiblewidth) && (py >= 0) && (py < visibleheight))
+								pixels[py * width + px] = c;
+						}
 					}
 				}
 			}
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index fc4963b307ed735ea90e7600bcbd852395257cd2..06742a1f617223c9653eb00117c870d91df62b20 100755
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -19,6 +19,7 @@
 using System;
 using System.Collections.Generic;
 using System.Drawing;
+using System.Net;
 using CodeImp.DoomBuilder.Map;
 using SlimDX.Direct3D9;
 using SlimDX;
@@ -28,6 +29,7 @@ using CodeImp.DoomBuilder.Editing;
 using CodeImp.DoomBuilder.GZBuilder.Data; //mxd
 using CodeImp.DoomBuilder.Config; //mxd
 using CodeImp.DoomBuilder.GZBuilder;
+using SlimDX.Direct3D10_1;
 
 #endregion
 
@@ -549,17 +551,17 @@ namespace CodeImp.DoomBuilder.Rendering
 					return new PixelColor(255, 255, 255, 255);
 				if (t.DynamicLightType.LightDef == GZGeneral.LightDef.VAVOOM_COLORED) //vavoom colored light
 					return new PixelColor(255, (byte)t.Args[1], (byte)t.Args[2], (byte)t.Args[3]);
-                if (t.DynamicLightType.LightType == GZGeneral.LightType.SPOT)
-                {
-                    if (t.Fields.ContainsKey("arg0str"))
-                    {
-                        PixelColor pc;
-                        ZDoom.ZDTextParser.GetColorFromString(t.Fields["arg0str"].Value.ToString(), out pc);
-                        pc.a = 255;
-                        return pc;
-                    }
-                    return new PixelColor(255, (byte)((t.Args[0] & 0xFF0000) >> 16), (byte)((t.Args[0] & 0x00FF00) >> 8), (byte)((t.Args[0] & 0x0000FF)));
-                }
+				if (t.DynamicLightType.LightType == GZGeneral.LightType.SPOT)
+				{
+					if (t.Fields.ContainsKey("arg0str"))
+					{
+						PixelColor pc;
+						ZDoom.ZDTextParser.GetColorFromString(t.Fields["arg0str"].Value.ToString(), out pc);
+						pc.a = 255;
+						return pc;
+					}
+					return new PixelColor(255, (byte)((t.Args[0] & 0xFF0000) >> 16), (byte)((t.Args[0] & 0x00FF00) >> 8), (byte)((t.Args[0] & 0x0000FF)));
+				}
 				return new PixelColor(255, (byte)t.Args[0], (byte)t.Args[1], (byte)t.Args[2]);
 			}
 
@@ -837,11 +839,30 @@ namespace CodeImp.DoomBuilder.Rendering
 
 				if(General.Settings.RenderGrid) //mxd
 				{
-					// Render normal grid
-					RenderGrid(General.Map.Grid.GridSizeF, General.Colors.Grid, gridplotter);
+					bool transformed = General.Map.Grid.GridOriginX != 0 || General.Map.Grid.GridOriginY != 0 || Math.Abs(General.Map.Grid.GridRotate) > 1e-4;
+
+					if (transformed)
+					{
+						// Render normal grid
+						RenderGridTransformed(General.Map.Grid.GridSizeF, General.Map.Grid.GridRotate,
+							General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY, General.Colors.Grid, gridplotter);
+
+						// Render 64 grid
+						if(General.Map.Grid.GridSizeF <= 64)
+						{
+							RenderGridTransformed(64f, General.Map.Grid.GridRotate,
+								General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY, General.Colors.Grid64, gridplotter);
+						}
+					} 
+					else
+					{
+						// Render normal grid
+						RenderGrid(General.Map.Grid.GridSizeF, General.Colors.Grid, gridplotter);
 
-					// Render 64 grid
-					if(General.Map.Grid.GridSizeF <= 64) RenderGrid(64f, General.Colors.Grid64, gridplotter);
+						// Render 64 grid
+						if(General.Map.Grid.GridSizeF <= 64) RenderGrid(64f, General.Colors.Grid64, gridplotter);
+					}
+					
 				}
 				else
 				{
@@ -877,6 +898,88 @@ namespace CodeImp.DoomBuilder.Rendering
 			}
 		}
 		
+		// This renders the grid with a transform applied
+		private void RenderGridTransformed(float size, float angle, float originx, float originy, PixelColor c, Plotter gridplotter)
+		{
+			const int mask = 0x55555555; // dotted line mask
+			Vector2D pos = new Vector2D();
+
+			//mxd. Increase rendered grid size if needed
+			if(!General.Settings.DynamicGridSize && size * scale <= 6f)
+				do { size *= 2; } while(size * scale <= 6f);
+			float sizeinv = 1f / size;
+
+			if (size < 1 || size > 1024)
+			{
+				return;
+			}
+
+			// Determine map coordinates for view window
+			Vector2D ltpos = DisplayToMap(new Vector2D(0, 0));
+			Vector2D rbpos = DisplayToMap(new Vector2D(windowsize.Width, windowsize.Height));
+			Vector2D mapsize = rbpos - ltpos;
+
+			Vector2D ltbound = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary);
+			Vector2D rbbound = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary);
+
+			// Translate top left boundary and right bottom boundary of map to screen coords
+			Vector2D tlb = ltbound.GetTransformed(translatex, translatey, scale, -scale);
+			Vector2D rbb = rbbound.GetTransformed(translatex, translatey, scale, -scale);
+
+			Vector2D xcenter = GridSetup.SnappedToGrid(0.5f * (ltpos + rbpos), size, sizeinv, angle, originx, originy);
+			Vector2D ycenter = xcenter;
+
+			// Get the angle vectors for the gridlines
+			Vector2D dx = new Vector2D((float)Math.Cos(angle), (float)Math.Sin(angle));
+			Vector2D dy = new Vector2D((float)-Math.Sin(angle), (float)Math.Cos(angle));
+
+			float maxextent = Math.Max(mapsize.x, mapsize.y);
+			RectangleF bounds = new RectangleF(tlb.x, tlb.y, rbb.x - tlb.x, rbb.y - tlb.y);
+
+			bool xminintersect = true, xmaxintersect = true, yminintersect = true, ymaxintersect = true;
+
+			int num = 0;            
+			while (xminintersect || xmaxintersect || yminintersect || ymaxintersect) {
+				Vector2D xminstart = xcenter - num * size * dy;
+				Vector2D xmaxstart = xcenter + num * size * dy;
+				Vector2D yminstart = ycenter - num * size * dx;
+				Vector2D ymaxstart = ycenter + num * size * dx;
+
+				Line2D xminscanline = new Line2D(xminstart - dx * maxextent, xminstart + dx * maxextent);
+				Line2D xmaxscanline = new Line2D(xmaxstart - dx * maxextent, xmaxstart + dx * maxextent);
+				Line2D yminscanline = new Line2D(yminstart - dy * maxextent, yminstart + dy * maxextent);
+				Line2D ymaxscanline = new Line2D(ymaxstart - dy * maxextent, ymaxstart + dy * maxextent);
+
+				Line2D xminplotline = xminscanline.GetTransformed(translatex, translatey, scale, -scale);
+				Line2D xmaxplotline = xmaxscanline.GetTransformed(translatex, translatey, scale, -scale);
+				Line2D yminplotline = yminscanline.GetTransformed(translatex, translatey, scale, -scale);
+				Line2D ymaxplotline = ymaxscanline.GetTransformed(translatex, translatey, scale, -scale);
+				xminplotline = Line2D.ClipToRectangle(xminplotline, bounds, out xminintersect);
+				xmaxplotline = Line2D.ClipToRectangle(xmaxplotline, bounds, out xmaxintersect);
+				yminplotline = Line2D.ClipToRectangle(yminplotline, bounds, out yminintersect);
+				ymaxplotline = Line2D.ClipToRectangle(ymaxplotline, bounds, out ymaxintersect);
+
+				if (xminintersect)
+				{
+					gridplotter.DrawLineSolid((int)xminplotline.v1.x, (int)xminplotline.v1.y, (int)xminplotline.v2.x, (int)xminplotline.v2.y, ref c, mask);
+				}
+				if (xmaxintersect)
+				{
+					gridplotter.DrawLineSolid((int)xmaxplotline.v1.x, (int)xmaxplotline.v1.y, (int)xmaxplotline.v2.x, (int)xmaxplotline.v2.y, ref c, mask);
+				}
+				if (yminintersect)
+				{
+					gridplotter.DrawLineSolid((int)yminplotline.v1.x, (int)yminplotline.v1.y, (int)yminplotline.v2.x, (int)yminplotline.v2.y, ref c, mask);
+				}
+				if (ymaxintersect)
+				{
+					gridplotter.DrawLineSolid((int)ymaxplotline.v1.x, (int)ymaxplotline.v1.y, (int)ymaxplotline.v2.x, (int)ymaxplotline.v2.y, ref c, mask);
+				}
+
+				num++;
+			}
+		}
+
 		// This renders the grid
 		private void RenderGrid(float size, PixelColor c, Plotter gridplotter)
 		{
diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg
index e66d169a191834f365fe26ae8c6fe4bb6178b9a7..22191cf6860cdebf88671cbc3f9c0c352cfe882e 100755
--- a/Source/Core/Resources/Actions.cfg
+++ b/Source/Core/Resources/Actions.cfg
@@ -416,6 +416,36 @@ gridsetup
 	allowscroll = true;
 }
 
+aligngridtolinedef
+{
+	title = "Align Grid to Selected Linedef";
+	category = "classic";
+	description = "Realigns the grid so that the selected linedef is on a grid line.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+}
+
+setgridorigintovertex
+{
+	title = "Set Grid Origin to Selected Vertex";
+	category = "classic";
+	description = "Repositions the grid so that the selected vertex is at the origin.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+}
+
+resetgrid
+{
+	title = "Reset Grid Transform";
+	category = "classic";
+	description = "Resets the grid to the default coordinate system.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+}
+
 griddec		// Note, these were incorrectly swapped before, hence the wrong action name
 {
 	title = "Grid Increase";
diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs
index 84a3f4ab9f58127a106d4a7bd22542f5c3d544f4..554ab8d3ac32a79cc25b8cbff38eccf364d766e7 100755
--- a/Source/Core/Windows/MainForm.Designer.cs
+++ b/Source/Core/Windows/MainForm.Designer.cs
@@ -287,6 +287,9 @@ namespace CodeImp.DoomBuilder.Windows
 			this.itemtogglecomments = new System.Windows.Forms.ToolStripMenuItem();
 			this.itemtogglefixedthingsscale = new System.Windows.Forms.ToolStripMenuItem();
 			this.itemdynamicgridsize = new System.Windows.Forms.ToolStripMenuItem();
+			this.itemaligngridtolinedef = new System.Windows.Forms.ToolStripMenuItem();
+			this.itemsetgridorigintovertex = new System.Windows.Forms.ToolStripMenuItem();
+			this.itemresetgrid = new System.Windows.Forms.ToolStripMenuItem();
 			toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
 			toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
 			toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator();
@@ -402,13 +405,13 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			this.menumain.Dock = System.Windows.Forms.DockStyle.None;
 			this.menumain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.menufile,
-            this.menuedit,
-            this.menuview,
-            this.menumode,
-            this.menuprefabs,
-            this.menutools,
-            this.menuhelp});
+			this.menufile,
+			this.menuedit,
+			this.menuview,
+			this.menumode,
+			this.menuprefabs,
+			this.menutools,
+			this.menuhelp});
 			this.menumain.Location = new System.Drawing.Point(0, 0);
 			this.menumain.Name = "menumain";
 			this.menumain.Size = new System.Drawing.Size(328, 24);
@@ -418,21 +421,21 @@ namespace CodeImp.DoomBuilder.Windows
 			// menufile
 			// 
 			this.menufile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemnewmap,
-            this.itemopenmap,
-            this.itemopenmapincurwad,
-            this.itemclosemap,
-            this.seperatorfileopen,
-            this.itemsavemap,
-            this.itemsavemapas,
-            this.itemsavemapinto,
-            this.seperatorfilesave,
-            this.itemimport,
-            this.itemexport,
-            this.separatorio,
-            this.itemnorecent,
-            this.seperatorfilerecent,
-            this.itemexit});
+			this.itemnewmap,
+			this.itemopenmap,
+			this.itemopenmapincurwad,
+			this.itemclosemap,
+			this.seperatorfileopen,
+			this.itemsavemap,
+			this.itemsavemapas,
+			this.itemsavemapinto,
+			this.seperatorfilesave,
+			this.itemimport,
+			this.itemexport,
+			this.separatorio,
+			this.itemnorecent,
+			this.seperatorfilerecent,
+			this.itemexit});
 			this.menufile.Name = "menufile";
 			this.menufile.Size = new System.Drawing.Size(37, 20);
 			this.menufile.Text = "&File";
@@ -538,36 +541,39 @@ namespace CodeImp.DoomBuilder.Windows
 			// menuedit
 			// 
 			this.menuedit.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemundo,
-            this.itemredo,
-            this.seperatoreditundo,
-            this.itemcut,
-            this.itemcopy,
-            this.itempaste,
-            this.itempastespecial,
-            this.seperatoreditcopypaste,
+			this.itemundo,
+			this.itemredo,
+			this.seperatoreditundo,
+			this.itemcut,
+			this.itemcopy,
+			this.itempaste,
+			this.itempastespecial,
+			this.seperatoreditcopypaste,
 			this.itemmergegeoclassic,
 			this.itemmergegeo,
 			this.itemreplacegeo,
 			this.separatorgeomerge,
-            this.itemsnaptogrid,
-            this.itemdynamicgridsize,
-            this.itemautomerge,
+			this.itemsnaptogrid,
+			this.itemdynamicgridsize,
+			this.itemautomerge,
 			this.itemsplitjoinedsectors,
-            this.itemautoclearsidetextures,
-            this.seperatoreditgeometry,
-            this.itemgridinc,
-            this.itemgriddec,
-            this.itemdosnaptogrid,
-            this.itemgridsetup,
-            this.toolStripSeparator5,
-            this.addToGroup,
-            this.selectGroup,
-            this.clearGroup,
-            this.seperatoreditgrid,
-            this.itemmapoptions,
-            this.itemviewusedtags,
-            this.itemviewthingtypes});
+			this.itemautoclearsidetextures,
+			this.seperatoreditgeometry,
+			this.itemgridinc,
+			this.itemgriddec,
+			this.itemdosnaptogrid,
+			this.itemaligngridtolinedef,
+			this.itemsetgridorigintovertex,
+			this.itemresetgrid,
+			this.itemgridsetup,
+			this.toolStripSeparator5,
+			this.addToGroup,
+			this.selectGroup,
+			this.clearGroup,
+			this.seperatoreditgrid,
+			this.itemmapoptions,
+			this.itemviewusedtags,
+			this.itemviewthingtypes});
 			this.menuedit.Name = "menuedit";
 			this.menuedit.Size = new System.Drawing.Size(39, 20);
 			this.menuedit.Text = "&Edit";
@@ -775,32 +781,32 @@ namespace CodeImp.DoomBuilder.Windows
 			// menuview
 			// 
 			this.menuview.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemthingsfilter,
-            this.itemlinedefcolors,
-            this.seperatorviewthings,
-            this.itemviewnormal,
-            this.itemviewbrightness,
-            this.itemviewfloors,
-            this.itemviewceilings,
-            this.seperatorviewviews,
-            this.itemfullbrightness,
-            this.itemtogglegrid,
-            this.itemtogglecomments,
+			this.itemthingsfilter,
+			this.itemlinedefcolors,
+			this.seperatorviewthings,
+			this.itemviewnormal,
+			this.itemviewbrightness,
+			this.itemviewfloors,
+			this.itemviewceilings,
+			this.seperatorviewviews,
+			this.itemfullbrightness,
+			this.itemtogglegrid,
+			this.itemtogglecomments,
 			this.itemtogglefixedthingsscale,
 			this.separatorrendering,
-            this.itemdynlightmodes,
-            this.itemmodelmodes,
-            this.itemtogglefog,
-            this.itemtogglesky,
-            this.itemtoggleeventlines,
-            this.itemtogglevisualverts,
-            this.separatorhelpers,
-            this.menuzoom,
-            this.itemgotocoords,
-            this.itemfittoscreen,
-            this.itemtoggleinfo,
-            this.seperatorviewzoom,
-            this.itemscripteditor});
+			this.itemdynlightmodes,
+			this.itemmodelmodes,
+			this.itemtogglefog,
+			this.itemtogglesky,
+			this.itemtoggleeventlines,
+			this.itemtogglevisualverts,
+			this.separatorhelpers,
+			this.menuzoom,
+			this.itemgotocoords,
+			this.itemfittoscreen,
+			this.itemtoggleinfo,
+			this.seperatorviewzoom,
+			this.itemscripteditor});
 			this.menuview.Name = "menuview";
 			this.menuview.Size = new System.Drawing.Size(44, 20);
 			this.menuview.Text = "&View";
@@ -925,6 +931,34 @@ namespace CodeImp.DoomBuilder.Windows
 			this.itemtogglegrid.Tag = "builder_togglegrid";
 			this.itemtogglegrid.Text = "&Render Grid";
 			this.itemtogglegrid.Click += new System.EventHandler(this.InvokeTaggedAction);
+
+			// 
+			// itemaligngridtolinedef
+			//
+			this.itemaligngridtolinedef.Name = "itemaligngridtolinedef";
+			this.itemaligngridtolinedef.Size = new System.Drawing.Size(215, 22);
+			this.itemaligngridtolinedef.Tag = "builder_aligngridtolinedef";
+			this.itemaligngridtolinedef.Text = "Align Grid To Selected Linedef";
+			this.itemaligngridtolinedef.Click += new System.EventHandler(this.InvokeTaggedAction);
+
+			// 
+			// itemsetgridorigintovertex
+			//
+			this.itemsetgridorigintovertex.Name = "itemsetgridorigintovertex";
+			this.itemsetgridorigintovertex.Size = new System.Drawing.Size(215, 22);
+			this.itemsetgridorigintovertex.Tag = "builder_setgridorigintovertex";
+			this.itemsetgridorigintovertex.Text = "Set Grid Origin To Selected Vertex";
+			this.itemsetgridorigintovertex.Click += new System.EventHandler(this.InvokeTaggedAction);
+
+			// 
+			// itemresetgrid
+			//
+			this.itemresetgrid.Name = "itemresetgrid";
+			this.itemresetgrid.Size = new System.Drawing.Size(215, 22);
+			this.itemresetgrid.Tag = "builder_resetgrid";
+			this.itemresetgrid.Text = "Reset Grid Transform";
+			this.itemresetgrid.Click += new System.EventHandler(this.InvokeTaggedAction);
+
 			// 
 			// toolStripSeparator4
 			// 
@@ -934,14 +968,14 @@ namespace CodeImp.DoomBuilder.Windows
 			// menuzoom
 			// 
 			this.menuzoom.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.item2zoom800,
-            this.item2zoom400,
-            this.item2zoom200,
-            this.item2zoom100,
-            this.item2zoom50,
-            this.item2zoom25,
-            this.item2zoom10,
-            this.item2zoom5});
+			this.item2zoom800,
+			this.item2zoom400,
+			this.item2zoom200,
+			this.item2zoom100,
+			this.item2zoom50,
+			this.item2zoom25,
+			this.item2zoom10,
+			this.item2zoom5});
 			this.menuzoom.Image = global::CodeImp.DoomBuilder.Properties.Resources.Zoom;
 			this.menuzoom.Name = "menuzoom";
 			this.menuzoom.Size = new System.Drawing.Size(215, 22);
@@ -1053,8 +1087,8 @@ namespace CodeImp.DoomBuilder.Windows
 			// menumode
 			// 
 			this.menumode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.separatorDrawModes,
-            this.separatorTransformModes});
+			this.separatorDrawModes,
+			this.separatorTransformModes});
 			this.menumode.Name = "menumode";
 			this.menumode.Size = new System.Drawing.Size(50, 20);
 			this.menumode.Text = "&Mode";
@@ -1072,10 +1106,10 @@ namespace CodeImp.DoomBuilder.Windows
 			// menuprefabs
 			// 
 			this.menuprefabs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.iteminsertprefabfile,
-            this.iteminsertpreviousprefab,
-            this.seperatorprefabsinsert,
-            this.itemcreateprefab});
+			this.iteminsertprefabfile,
+			this.iteminsertpreviousprefab,
+			this.seperatorprefabsinsert,
+			this.itemcreateprefab});
 			this.menuprefabs.Name = "menuprefabs";
 			this.menuprefabs.Size = new System.Drawing.Size(58, 20);
 			this.menuprefabs.Text = "&Prefabs";
@@ -1115,18 +1149,18 @@ namespace CodeImp.DoomBuilder.Windows
 			// menutools
 			// 
 			this.menutools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemreloadresources,
-            this.itemReloadModedef,
-            this.itemReloadGldefs,
-            this.itemshowerrors,
-            this.seperatortoolsresources,
-            this.configurationToolStripMenuItem,
-            this.preferencesToolStripMenuItem,
-            this.seperatortoolsconfig,
-            this.itemsavescreenshot,
-            this.itemsaveeditareascreenshot,
-            this.separatortoolsscreenshots,
-            this.itemtestmap});
+			this.itemreloadresources,
+			this.itemReloadModedef,
+			this.itemReloadGldefs,
+			this.itemshowerrors,
+			this.seperatortoolsresources,
+			this.configurationToolStripMenuItem,
+			this.preferencesToolStripMenuItem,
+			this.seperatortoolsconfig,
+			this.itemsavescreenshot,
+			this.itemsaveeditareascreenshot,
+			this.separatortoolsscreenshots,
+			this.itemtestmap});
 			this.menutools.Name = "menutools";
 			this.menutools.Size = new System.Drawing.Size(48, 20);
 			this.menutools.Text = "&Tools";
@@ -1232,14 +1266,14 @@ namespace CodeImp.DoomBuilder.Windows
 			// menuhelp
 			// 
 			this.menuhelp.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemhelprefmanual,
-            this.itemShortcutReference,
+			this.itemhelprefmanual,
+			this.itemShortcutReference,
 			this.itemopenconfigfolder,
-            this.itemhelpeditmode,
+			this.itemhelpeditmode,
 			this.itemhelpissues,
-            this.itemhelpcheckupdates,
-            this.seperatorhelpmanual,
-            this.itemhelpabout});
+			this.itemhelpcheckupdates,
+			this.seperatorhelpmanual,
+			this.itemhelpabout});
 			this.menuhelp.Name = "menuhelp";
 			this.menuhelp.Size = new System.Drawing.Size(44, 20);
 			this.menuhelp.Text = "&Help";
@@ -1315,57 +1349,57 @@ namespace CodeImp.DoomBuilder.Windows
 			this.toolbar.ContextMenuStrip = this.toolbarContextMenu;
 			this.toolbar.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
 			this.toolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.buttonnewmap,
-            this.buttonopenmap,
-            this.buttonsavemap,
-            this.seperatorfile,
-            this.buttonscripteditor,
-            this.seperatorscript,
-            this.buttonundo,
-            this.buttonredo,
-            this.seperatorundo,
-            this.buttoncut,
-            this.buttoncopy,
-            this.buttonpaste,
-            this.seperatorcopypaste,
-            this.buttoninsertprefabfile,
-            this.buttoninsertpreviousprefab,
-            this.seperatorprefabs,
-            this.buttonthingsfilter,
-            this.thingfilters,
-            this.separatorlinecolors,
-            this.buttonlinededfcolors,
-            this.linedefcolorpresets,
-            this.separatorfilters,
-            this.buttonfullbrightness,
-            this.buttontogglegrid,
-            this.buttontogglecomments,
+			this.buttonnewmap,
+			this.buttonopenmap,
+			this.buttonsavemap,
+			this.seperatorfile,
+			this.buttonscripteditor,
+			this.seperatorscript,
+			this.buttonundo,
+			this.buttonredo,
+			this.seperatorundo,
+			this.buttoncut,
+			this.buttoncopy,
+			this.buttonpaste,
+			this.seperatorcopypaste,
+			this.buttoninsertprefabfile,
+			this.buttoninsertpreviousprefab,
+			this.seperatorprefabs,
+			this.buttonthingsfilter,
+			this.thingfilters,
+			this.separatorlinecolors,
+			this.buttonlinededfcolors,
+			this.linedefcolorpresets,
+			this.separatorfilters,
+			this.buttonfullbrightness,
+			this.buttontogglegrid,
+			this.buttontogglecomments,
 			this.buttontogglefixedthingsscale,
-            this.separatorfullbrightness,
-            this.buttonviewnormal,
-            this.buttonviewbrightness,
-            this.buttonviewfloors,
-            this.buttonviewceilings,
+			this.separatorfullbrightness,
+			this.buttonviewnormal,
+			this.buttonviewbrightness,
+			this.buttonviewfloors,
+			this.buttonviewceilings,
 			this.separatorgeomergemodes,
 			this.buttonmergegeoclassic,
 			this.buttonmergegeo,
 			this.buttonplacegeo,
-            this.seperatorviews,
-            this.buttonsnaptogrid,
-            this.buttontoggledynamicgrid,
-            this.buttonautomerge,
+			this.seperatorviews,
+			this.buttonsnaptogrid,
+			this.buttontoggledynamicgrid,
+			this.buttonautomerge,
 			this.buttonsplitjoinedsectors,
-            this.buttonautoclearsidetextures,
-            this.seperatorgeometry,
-            this.dynamiclightmode,
-            this.modelrendermode,
-            this.buttontogglefog,
+			this.buttonautoclearsidetextures,
+			this.seperatorgeometry,
+			this.dynamiclightmode,
+			this.modelrendermode,
+			this.buttontogglefog,
 			this.buttontogglesky,
-            this.buttontoggleeventlines,
-            this.buttontogglevisualvertices,
-            this.separatorgzmodes,
-            this.buttontest,
-            this.seperatortesting});
+			this.buttontoggleeventlines,
+			this.buttontogglevisualvertices,
+			this.separatorgzmodes,
+			this.buttontest,
+			this.seperatortesting});
 			this.toolbar.Location = new System.Drawing.Point(0, 24);
 			this.toolbar.Name = "toolbar";
 			this.toolbar.Size = new System.Drawing.Size(1012, 25);
@@ -1374,16 +1408,16 @@ namespace CodeImp.DoomBuilder.Windows
 			// toolbarContextMenu
 			// 
 			this.toolbarContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.toggleFile,
-            this.toggleScript,
-            this.toggleUndo,
-            this.toggleCopy,
-            this.togglePrefabs,
-            this.toggleFilter,
-            this.toggleViewModes,
-            this.toggleGeometry,
-            this.toggleTesting,
-            this.toggleRendering});
+			this.toggleFile,
+			this.toggleScript,
+			this.toggleUndo,
+			this.toggleCopy,
+			this.togglePrefabs,
+			this.toggleFilter,
+			this.toggleViewModes,
+			this.toggleGeometry,
+			this.toggleTesting,
+			this.toggleRendering});
 			this.toolbarContextMenu.Name = "toolbarContextMenu";
 			this.toolbarContextMenu.Size = new System.Drawing.Size(227, 224);
 			this.toolbarContextMenu.ImageScalingSize = MainForm.ScaledIconSize;
@@ -1653,9 +1687,9 @@ namespace CodeImp.DoomBuilder.Windows
 			// itemdynlightmodes
 			// 
 			this.itemdynlightmodes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemnodynlights,
-            this.itemdynlights,
-            this.itemdynlightsanim});
+			this.itemnodynlights,
+			this.itemdynlights,
+			this.itemdynlightsanim});
 			this.itemdynlightmodes.Image = global::CodeImp.DoomBuilder.Properties.Resources.Light;
 			this.itemdynlightmodes.Name = "itemdynlightmodes";
 			this.itemdynlightmodes.Size = new System.Drawing.Size(273, 22);
@@ -1694,10 +1728,10 @@ namespace CodeImp.DoomBuilder.Windows
 			// itemmodelmodes
 			// 
 			this.itemmodelmodes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemnomdl,
-            this.itemselmdl,
-            this.itemfiltermdl,
-            this.itemallmdl});
+			this.itemnomdl,
+			this.itemselmdl,
+			this.itemfiltermdl,
+			this.itemallmdl});
 			this.itemmodelmodes.Image = global::CodeImp.DoomBuilder.Properties.Resources.Model;
 			this.itemmodelmodes.Name = "itemmodelmodes";
 			this.itemmodelmodes.Size = new System.Drawing.Size(273, 22);
@@ -2015,9 +2049,9 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			this.dynamiclightmode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
 			this.dynamiclightmode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.sightsdontshow,
-            this.lightsshow,
-            this.lightsshowanimated});
+			this.sightsdontshow,
+			this.lightsshow,
+			this.lightsshowanimated});
 			this.dynamiclightmode.Image = global::CodeImp.DoomBuilder.Properties.Resources.Light;
 			this.dynamiclightmode.ImageTransparentColor = System.Drawing.Color.Magenta;
 			this.dynamiclightmode.Name = "dynamiclightmode";
@@ -2060,10 +2094,10 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			this.modelrendermode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
 			this.modelrendermode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.modelsdontshow,
-            this.modelsshowselection,
-            this.modelsshowfiltered,
-            this.modelsshowall});
+			this.modelsdontshow,
+			this.modelsshowselection,
+			this.modelsshowfiltered,
+			this.modelsshowall});
 			this.modelrendermode.Image = global::CodeImp.DoomBuilder.Properties.Resources.Model;
 			this.modelrendermode.ImageTransparentColor = System.Drawing.Color.Magenta;
 			this.modelrendermode.Name = "modelrendermode";
@@ -2185,20 +2219,20 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			this.statusbar.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
 			this.statusbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.statuslabel,
-            this.configlabel,
-            toolStripSeparator12,
-            this.gridlabel,
-            this.buttongrid,
-            toolStripSeparator1,
-            this.zoomlabel,
-            this.buttonzoom,
-            toolStripSeparator3,
-            this.xposlabel,
-            this.poscommalabel,
-            this.yposlabel,
-            toolStripSeparator9,
-            this.warnsLabel});
+			this.statuslabel,
+			this.configlabel,
+			toolStripSeparator12,
+			this.gridlabel,
+			this.buttongrid,
+			toolStripSeparator1,
+			this.zoomlabel,
+			this.buttonzoom,
+			toolStripSeparator3,
+			this.xposlabel,
+			this.poscommalabel,
+			this.yposlabel,
+			toolStripSeparator9,
+			this.warnsLabel});
 			this.statusbar.Location = new System.Drawing.Point(0, 670);
 			this.statusbar.Name = "statusbar";
 			this.statusbar.ShowItemToolTips = true;
@@ -2243,21 +2277,21 @@ namespace CodeImp.DoomBuilder.Windows
 			this.buttongrid.AutoToolTip = false;
 			this.buttongrid.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
 			this.buttongrid.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemgrid1024,
-            this.itemgrid512,
-            this.itemgrid256,
-            this.itemgrid128,
-            this.itemgrid64,
-            this.itemgrid32,
-            this.itemgrid16,
-            this.itemgrid8,
-            this.itemgrid4,
-            this.itemgrid1,
-            this.itemgrid05,
-            this.itemgrid025,
-            this.itemgrid0125,
-            toolStripMenuItem4,
-            this.itemgridcustom});
+			this.itemgrid1024,
+			this.itemgrid512,
+			this.itemgrid256,
+			this.itemgrid128,
+			this.itemgrid64,
+			this.itemgrid32,
+			this.itemgrid16,
+			this.itemgrid8,
+			this.itemgrid4,
+			this.itemgrid1,
+			this.itemgrid05,
+			this.itemgrid025,
+			this.itemgrid0125,
+			toolStripMenuItem4,
+			this.itemgridcustom});
 			this.buttongrid.Image = global::CodeImp.DoomBuilder.Properties.Resources.Grid2_arrowup;
 			this.buttongrid.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
 			this.buttongrid.ImageTransparentColor = System.Drawing.Color.Transparent;
@@ -2393,16 +2427,16 @@ namespace CodeImp.DoomBuilder.Windows
 			this.buttonzoom.AutoToolTip = false;
 			this.buttonzoom.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
 			this.buttonzoom.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.itemzoom800,
-            this.itemzoom400,
-            this.itemzoom200,
-            this.itemzoom100,
-            this.itemzoom50,
-            this.itemzoom25,
-            this.itemzoom10,
-            this.itemzoom5,
-            toolStripSeparator2,
-            this.itemzoomfittoscreen});
+			this.itemzoom800,
+			this.itemzoom400,
+			this.itemzoom200,
+			this.itemzoom100,
+			this.itemzoom50,
+			this.itemzoom25,
+			this.itemzoom10,
+			this.itemzoom5,
+			toolStripSeparator2,
+			this.itemzoomfittoscreen});
 			this.buttonzoom.Image = global::CodeImp.DoomBuilder.Properties.Resources.Zoom_arrowup;
 			this.buttonzoom.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
 			this.buttonzoom.ImageTransparentColor = System.Drawing.Color.Transparent;
@@ -2800,8 +2834,8 @@ namespace CodeImp.DoomBuilder.Windows
 			this.MainMenuStrip = this.menumain;
 			this.Name = "MainForm";
 			this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
-            this.Text = Application.ProductName + " R" + General.ThisAssembly.GetName().Version.Revision;
-            this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
+			this.Text = Application.ProductName + " R" + General.ThisAssembly.GetName().Version.Revision;
+			this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
 			this.Load += new System.EventHandler(this.MainForm_Load);
 			this.Shown += new System.EventHandler(this.MainForm_Shown);
 			this.Activated += new System.EventHandler(this.MainForm_Activated);
@@ -3066,6 +3100,9 @@ namespace CodeImp.DoomBuilder.Windows
 		private ToolStripDropDownButton linedefcolorpresets;
 		private ToolStripDropDownButton thingfilters;
 		private ToolStripMenuItem itemtogglegrid;
+		private ToolStripMenuItem itemaligngridtolinedef;
+		private ToolStripMenuItem itemsetgridorigintovertex;
+		private ToolStripMenuItem itemresetgrid;
 		private ToolStripButton buttontogglegrid;
 		private ToolStripButton buttontoggledynamicgrid;
 		private ToolStripMenuItem itemdynamicgridsize;
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index d9f04220771f30ff55aa59c524a2a70a66787bcc..0141d2c9bd18b56d5ec589c3269f65046bee9fd9 100755
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -439,12 +439,12 @@ namespace CodeImp.DoomBuilder.Windows
 		//mxd
 		private void UpdateTitle()
 		{
-            string programname = this.Text = Application.ProductName + " R" + General.ThisAssembly.GetName().Version.Revision;
-            if (Environment.Is64BitProcess)
-                programname += " (64-bit)";
+			string programname = this.Text = Application.ProductName + " R" + General.ThisAssembly.GetName().Version.Revision;
+			if (Environment.Is64BitProcess)
+				programname += " (64-bit)";
 
-            // Map opened?
-            if (General.Map != null)
+			// Map opened?
+			if (General.Map != null)
 			{
 				// Get nice name
 				string maptitle = (!string.IsNullOrEmpty(General.Map.Data.MapInfo.Title) ? ": " + General.Map.Data.MapInfo.Title : "");
@@ -454,9 +454,9 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 			else
 			{
-                // Show normal caption
-                this.Text = programname;
-            }
+				// Show normal caption
+				this.Text = programname;
+			}
 		}
 		
 		// Generic event that invokes the tagged action
@@ -1364,28 +1364,28 @@ namespace CodeImp.DoomBuilder.Windows
 			base.OnMouseWheel(e);
 		}
 
-        // [ZZ]
-        private void OnMouseHWheel(int delta)
-        {
-            int mod = 0;
-            if (alt) mod |= (int)Keys.Alt;
-            if (shift) mod |= (int)Keys.Shift;
-            if (ctrl) mod |= (int)Keys.Control;
-
-            // Scrollwheel left?
-            if (delta < 0)
-            {
-                General.Actions.KeyPressed((int)SpecialKeys.MScrollLeft | mod);
-                General.Actions.KeyReleased((int)SpecialKeys.MScrollLeft | mod);
-            }
-            else if (delta > 0)
-            {
-                General.Actions.KeyPressed((int)SpecialKeys.MScrollRight | mod);
-                General.Actions.KeyReleased((int)SpecialKeys.MScrollRight | mod);
-            }
-
-            // base? what base?
-        }
+		// [ZZ]
+		private void OnMouseHWheel(int delta)
+		{
+			int mod = 0;
+			if (alt) mod |= (int)Keys.Alt;
+			if (shift) mod |= (int)Keys.Shift;
+			if (ctrl) mod |= (int)Keys.Control;
+
+			// Scrollwheel left?
+			if (delta < 0)
+			{
+				General.Actions.KeyPressed((int)SpecialKeys.MScrollLeft | mod);
+				General.Actions.KeyReleased((int)SpecialKeys.MScrollLeft | mod);
+			}
+			else if (delta > 0)
+			{
+				General.Actions.KeyPressed((int)SpecialKeys.MScrollRight | mod);
+				General.Actions.KeyReleased((int)SpecialKeys.MScrollRight | mod);
+			}
+
+			// base? what base?
+		}
 		
 		// When a key is pressed
 		private void MainForm_KeyDown(object sender, KeyEventArgs e)
@@ -2140,12 +2140,12 @@ namespace CodeImp.DoomBuilder.Windows
 		// This checks one of the edit mode items (and unchecks all others)
 		internal void CheckEditModeButton(string modeclassname)
 		{
-            // Go for all items
-            //foreach(ToolStripItem item in editmodeitems)
-            int itemCount = editmodeitems.Count;
-            for(int i = 0; i < itemCount; i++)
+			// Go for all items
+			//foreach(ToolStripItem item in editmodeitems)
+			int itemCount = editmodeitems.Count;
+			for(int i = 0; i < itemCount; i++)
 			{
-                ToolStripItem item = editmodeitems[i];
+				ToolStripItem item = editmodeitems[i];
 				// Check what type it is
 				if(item is ToolStripMenuItem)
 				{
@@ -2163,14 +2163,14 @@ namespace CodeImp.DoomBuilder.Windows
 		// This removes the config-specific editing mode buttons
 		internal void RemoveEditModeButtons()
 		{
-            // Go for all items
-            //foreach(ToolStripItem item in editmodeitems)
-            int itemCount = editmodeitems.Count;
-            for (int i = 0; i < itemCount; i++)
-            {
-                ToolStripItem item = editmodeitems[i];
-                // Remove it and restart
-                menumode.DropDownItems.Remove(item);
+			// Go for all items
+			//foreach(ToolStripItem item in editmodeitems)
+			int itemCount = editmodeitems.Count;
+			for (int i = 0; i < itemCount; i++)
+			{
+				ToolStripItem item = editmodeitems[i];
+				// Remove it and restart
+				menumode.DropDownItems.Remove(item);
 				item.Dispose();
 			}
 			
@@ -2911,6 +2911,45 @@ namespace CodeImp.DoomBuilder.Windows
 			General.Map.CRenderer2D.GridVisibilityChanged();
 			General.Interface.RedrawDisplay();
 		}
+		
+		[BeginAction("aligngridtolinedef")]
+		protected void AlignGridToLinedef()
+		{
+			if (General.Map.Map.SelectedLinedefsCount != 1)
+			{
+				General.ShowErrorMessage("Exactly one linedef must be selected.", MessageBoxButtons.OK);
+				return;
+			}
+			Linedef line = General.Map.Map.SelectedLinedefs.First.Value;
+			Vertex vertex = line.Start;
+			General.Map.Grid.SetGridRotation(line.Angle);
+			General.Map.Grid.SetGridOrigin(vertex.Position.x, vertex.Position.y);
+			General.Map.CRenderer2D.GridVisibilityChanged();
+			General.Interface.RedrawDisplay();
+		}
+
+		[BeginAction("setgridorigintovertex")]
+		protected void SetGridOriginToVertex()
+		{
+			if (General.Map.Map.SelectedVerticessCount != 1)
+			{
+				General.ShowErrorMessage("Exactly one vertex must be selected.", MessageBoxButtons.OK);
+				return;
+			}
+			Vertex vertex = General.Map.Map.SelectedVertices.First.Value;
+			General.Map.Grid.SetGridOrigin(vertex.Position.x, vertex.Position.y);
+			General.Map.CRenderer2D.GridVisibilityChanged();
+			General.Interface.RedrawDisplay();
+		}
+
+		[BeginAction("resetgrid")]
+		protected void ResetGrid()
+		{
+			General.Map.Grid.SetGridRotation(0.0f);
+			General.Map.Grid.SetGridOrigin(0, 0);
+			General.Map.CRenderer2D.GridVisibilityChanged();
+			General.Interface.RedrawDisplay();
+		}
 
 		//mxd
 		[BeginAction("toggledynamicgrid")]
@@ -3657,9 +3696,9 @@ namespace CodeImp.DoomBuilder.Windows
 		// This hides all info panels
 		public void HideInfo()
 		{
-            // Hide them all
-            // [ZZ]
-            panelinfo.SuspendLayout();
+			// Hide them all
+			// [ZZ]
+			panelinfo.SuspendLayout();
 			bool showModeName = ((General.Map != null) && IsInfoPanelExpanded); //mxd
 			lastinfoobject = null;
 			if(linedefinfo.Visible) linedefinfo.Hide();
@@ -3678,8 +3717,8 @@ namespace CodeImp.DoomBuilder.Windows
 
 			//mxd. Let the plugins know
 			General.Plugins.OnHighlightLost();
-            // [ZZ]
-            panelinfo.ResumeLayout();
+			// [ZZ]
+			panelinfo.ResumeLayout();
 		}
 		
 		// This refreshes info
@@ -3690,11 +3729,11 @@ namespace CodeImp.DoomBuilder.Windows
 			else if(lastinfoobject is Sector) ShowSectorInfo((Sector)lastinfoobject);
 			else if(lastinfoobject is Thing) ShowThingInfo((Thing)lastinfoobject);
 
-            //mxd. Let the plugins know
-            // [ZZ]
-            panelinfo.SuspendLayout();
+			//mxd. Let the plugins know
+			// [ZZ]
+			panelinfo.SuspendLayout();
 			General.Plugins.OnHighlightRefreshed(lastinfoobject);
-            panelinfo.ResumeLayout();
+			panelinfo.ResumeLayout();
 		}
 
 		//mxd
@@ -3743,9 +3782,9 @@ namespace CodeImp.DoomBuilder.Windows
 				return;
 			}
 
-            // [ZZ]
-            panelinfo.SuspendLayout();
-            lastinfoobject = l;
+			// [ZZ]
+			panelinfo.SuspendLayout();
+			lastinfoobject = l;
 			modename.Visible = false;
 #if DEBUG
 			console.Visible = console.AlwaysOnTop; //mxd
@@ -3772,11 +3811,11 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 			labelcollapsedinfo.Refresh();
 
-            //mxd. let the plugins know
-            General.Plugins.OnHighlightLinedef(l);
-            // [ZZ]
-            panelinfo.ResumeLayout();
-        }
+			//mxd. let the plugins know
+			General.Plugins.OnHighlightLinedef(l);
+			// [ZZ]
+			panelinfo.ResumeLayout();
+		}
 
 		// Show vertex info
 		public void ShowVertexInfo(Vertex v) 
@@ -3786,10 +3825,10 @@ namespace CodeImp.DoomBuilder.Windows
 				HideInfo();
 				return;
 			}
-            
-            // [ZZ]
-            panelinfo.SuspendLayout();
-            lastinfoobject = v;
+			
+			// [ZZ]
+			panelinfo.SuspendLayout();
+			lastinfoobject = v;
 			modename.Visible = false;
 #if DEBUG
 			console.Visible = console.AlwaysOnTop; //mxd
@@ -3806,12 +3845,12 @@ namespace CodeImp.DoomBuilder.Windows
 
 			//mxd. let the plugins know
 			General.Plugins.OnHighlightVertex(v);
-            // [ZZ]
-            panelinfo.ResumeLayout();
-        }
+			// [ZZ]
+			panelinfo.ResumeLayout();
+		}
 
-        //mxd. Show sector info
-        public void ShowSectorInfo(Sector s) 
+		//mxd. Show sector info
+		public void ShowSectorInfo(Sector s) 
 		{
 			ShowSectorInfo(s, false, false);
 		}
@@ -3825,9 +3864,9 @@ namespace CodeImp.DoomBuilder.Windows
 				return;
 			}
 
-            // [ZZ]
-            panelinfo.SuspendLayout();
-            lastinfoobject = s;
+			// [ZZ]
+			panelinfo.SuspendLayout();
+			lastinfoobject = s;
 			modename.Visible = false;
 #if DEBUG
 			console.Visible = console.AlwaysOnTop; //mxd
@@ -3848,14 +3887,14 @@ namespace CodeImp.DoomBuilder.Windows
 
 			labelcollapsedinfo.Refresh();
 
-            //mxd. let the plugins know
-            General.Plugins.OnHighlightSector(s);
-            // [ZZ]
-            panelinfo.ResumeLayout();
-        }
+			//mxd. let the plugins know
+			General.Plugins.OnHighlightSector(s);
+			// [ZZ]
+			panelinfo.ResumeLayout();
+		}
 
-        // Show thing info
-        public void ShowThingInfo(Thing t)
+		// Show thing info
+		public void ShowThingInfo(Thing t)
 		{
 			if(t.IsDisposed)
 			{
@@ -3863,9 +3902,9 @@ namespace CodeImp.DoomBuilder.Windows
 				return;
 			}
 
-            // [ZZ]
-            panelinfo.SuspendLayout();
-            lastinfoobject = t;
+			// [ZZ]
+			panelinfo.SuspendLayout();
+			lastinfoobject = t;
 			modename.Visible = false;
 #if DEBUG
 			console.Visible = console.AlwaysOnTop; //mxd
@@ -3881,19 +3920,19 @@ namespace CodeImp.DoomBuilder.Windows
 			labelcollapsedinfo.Text = t.Type + " - " + ti.Title;
 			labelcollapsedinfo.Refresh();
 
-            //mxd. let the plugins know
-            General.Plugins.OnHighlightThing(t);
-            // [ZZ]
-            panelinfo.ResumeLayout();
-        }
+			//mxd. let the plugins know
+			General.Plugins.OnHighlightThing(t);
+			// [ZZ]
+			panelinfo.ResumeLayout();
+		}
 
-        #endregion
+		#endregion
 
-        #region ================== Dialogs
+		#region ================== Dialogs
 
-        // This browses for a texture
-        // Returns the new texture name or the same texture name when cancelled
-        public string BrowseTexture(IWin32Window owner, string initialvalue)
+		// This browses for a texture
+		// Returns the new texture name or the same texture name when cancelled
+		public string BrowseTexture(IWin32Window owner, string initialvalue)
 		{
 			return TextureBrowserForm.Browse(owner, initialvalue, false);//mxd
 		}
@@ -4106,7 +4145,7 @@ namespace CodeImp.DoomBuilder.Windows
 					if((General.Map != null) && (General.Map.Data != null))
 					{
 						ImageData img = General.Map.Data.GetFlatImage(imagename);
-                        ImageDataLoaded(img);
+						ImageDataLoaded(img);
 					}
 					break;
 
@@ -4137,11 +4176,11 @@ namespace CodeImp.DoomBuilder.Windows
 					}
 					break;
 
-                case General.WM_MOUSEHWHEEL:
-                    int delta = m.WParam.ToInt32() >> 16;
-                    OnMouseHWheel(delta);
-                    m.Result = new IntPtr(delta);
-                    break;
+				case General.WM_MOUSEHWHEEL:
+					int delta = m.WParam.ToInt32() >> 16;
+					OnMouseHWheel(delta);
+					m.Result = new IntPtr(delta);
+					break;
 					
 				default:
 					// Let the base handle the message
@@ -4208,11 +4247,11 @@ namespace CodeImp.DoomBuilder.Windows
 		// but only when first loaded or when dimensions were changed
 		internal void ImageDataLoaded(ImageData img)
 		{
-            // Image is used in the map?
-            if ((img != null) && img.UsedInMap && !img.IsDisposed)
+			// Image is used in the map?
+			if ((img != null) && img.UsedInMap && !img.IsDisposed)
 			{
-                // Go for all setors
-                bool updated = false;
+				// Go for all setors
+				bool updated = false;
 				long imgshorthash = General.Map.Data.GetShortLongFlatName(img.LongName); //mxd. Part of long name support shennanigans
 
 				foreach(Sector s in General.Map.Map.Sectors)
@@ -4227,7 +4266,7 @@ namespace CodeImp.DoomBuilder.Windows
 					// Update ceiling buffer if needed
 					if(s.LongCeilTexture == img.LongName || s.LongCeilTexture == imgshorthash)
 					{
-                        s.UpdateCeilingSurface();
+						s.UpdateCeilingSurface();
 						updated = true;
 					}
 				}
@@ -4235,7 +4274,7 @@ namespace CodeImp.DoomBuilder.Windows
 				// If we made updates, redraw the screen
 				if(updated) DelayedRedraw();
 			}
-        }
+		}
 
 		public void EnableProcessing()
 		{
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
index 841d2734a63135b1dff2c8ea5934d2c990020530..39f8b91193b78532b7827f9a10bd930a8c7facd5 100755
--- a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
@@ -266,7 +266,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if(snapgrid || snapgridincrement)
 						{
 							// Get grid intersection coordinates
-							List<Vector2D> coords = nl.GetGridIntersections(snapgridincrement ? dragstartoffset : new Vector2D());
+							List<Vector2D> coords = nl.GetGridIntersections(snapgridincrement ? dragstartoffset : new Vector2D(),
+								General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY);
 
 							// mxd. Do the rest only if we actually have some coordinates
 							if(coords.Count > 0) 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 89caa38e0d535c4c62b642c066a6296eafabdf60..59c55ca21dbdf7c9532f413540d1ae8df5385269 100755
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -421,7 +421,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					else if(snaptogrid)
 					{
 						// Get grid intersection coordinates
-						List<Vector2D> coords = nl.GetGridIntersections();
+						List<Vector2D> coords = nl.GetGridIntersections(General.Map.Grid.GridRotate,
+							General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY);
 
 						// Find nearest grid intersection
 						bool found = false;