snapping to nearest lines where they intersect the grid! this is hot!

This commit is contained in:
codeimp 2008-04-29 14:41:16 +00:00
parent 2606487474
commit 6ba6d7416d
8 changed files with 242 additions and 40 deletions

View file

@ -66,6 +66,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// List of unstable lines // List of unstable lines
protected ICollection<Linedef> unstablelines; protected ICollection<Linedef> unstablelines;
// List of unselected lines
protected ICollection<Linedef> unselectedlines;
// Keep track of view changes // Keep track of view changes
private float lastoffsetx; private float lastoffsetx;
private float lastoffsety; private float lastoffsety;
@ -145,25 +148,68 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapnearest) private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapnearest)
{ {
Vector2D oldpos = dragitem.Position; Vector2D oldpos = dragitem.Position;
Vertex nearest;
int i = 0; int i = 0;
// Snap to nearest? // Snap to nearest?
if(snapnearest) if(snapnearest)
{ {
// Find nearest unselected item within selection range // Find nearest unselected vertex within range
nearest = MapSet.NearestVertexSquareRange(unselectedverts, mousemappos, VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale); Vertex nv = MapSet.NearestVertexSquareRange(unselectedverts, mousemappos, VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale);
if(nearest != null) if(nv != null)
{ {
// Move the dragged item // Move the dragged item
dragitem.Move(nearest.Position); dragitem.Move(nv.Position);
// Adjust the offset // Adjust the offset
offset = nearest.Position - dragitemposition; offset = nv.Position - dragitemposition;
// Do not snap to grid! // Do not snap to grid!
snapgrid = false; snapgrid = false;
} }
else
{
// Find the nearest unselected line within range
Linedef nl = MapSet.NearestLinedefRange(unselectedlines, mousemappos, LinedefsMode.LINEDEF_HIGHLIGHT_RANGE / renderer.Scale);
if(nl != null)
{
// Snap to grid?
if(snaptogrid)
{
// Get grid intersection coordinates
List<Vector2D> coords = nl.GetGridIntersections();
// Find nearest grid intersection
float found_distance = float.MaxValue;
Vector2D found_coord = new Vector2D();
foreach(Vector2D v in coords)
{
Vector2D delta = mousemappos - v;
if(delta.GetLengthSq() < found_distance)
{
found_distance = delta.GetLengthSq();
found_coord = v;
}
}
// Move the dragged item
dragitem.Move(found_coord);
// Align to line here
offset = found_coord - dragitemposition;
// Do not snap to grid anymore
snapgrid = false;
}
else
{
// Move the dragged item
dragitem.Move(nl.NearestOnLine(mousemappos));
// Align to line here
offset = nl.NearestOnLine(mousemappos) - dragitemposition;
}
}
}
} }
// Snap to grid? // Snap to grid?
@ -286,7 +332,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
private void Update() private void Update()
{ {
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
snaptonearest = General.Interface.CtrlState; snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
// Move selected geometry // Move selected geometry
if(MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptonearest)) if(MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptonearest))
@ -318,16 +364,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
public override void KeyUp(KeyEventArgs e) public override void KeyUp(KeyEventArgs e)
{ {
base.KeyUp(e); base.KeyUp(e);
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update(); if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
if(snaptonearest != General.Interface.CtrlState) Update(); (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
} }
// When a key is pressed // When a key is pressed
public override void KeyDown(KeyEventArgs e) public override void KeyDown(KeyEventArgs e)
{ {
base.KeyDown(e); base.KeyDown(e);
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update(); if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
if(snaptonearest != General.Interface.CtrlState) Update(); (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
} }
#endregion #endregion

View file

@ -51,7 +51,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
#region ================== Variables #region ================== Variables
private ICollection<Linedef> selectedlines; private ICollection<Linedef> selectedlines;
private ICollection<Linedef> unselectedlines;
#endregion #endregion

View file

@ -51,7 +51,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
#region ================== Variables #region ================== Variables
private ICollection<Linedef> selectedlines; private ICollection<Linedef> selectedlines;
private ICollection<Linedef> unselectedlines;
private ICollection<Sector> selectedsectors; private ICollection<Sector> selectedsectors;
#endregion #endregion

View file

@ -67,6 +67,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Get selected vertices // Get selected vertices
selectedverts = General.Map.Map.GetVerticesSelection(true); selectedverts = General.Map.Map.GetVerticesSelection(true);
unselectedverts = General.Map.Map.GetVerticesSelection(false); unselectedverts = General.Map.Map.GetVerticesSelection(false);
unselectedlines = General.Map.Map.LinedefsFromSelectedVertices(true, false, false);
// Initialize // Initialize
base.StartDrag(basemode, dragitem, dragstartmappos, base.StartDrag(basemode, dragitem, dragstartmappos,

View file

@ -41,6 +41,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
public class DrawGeometryMode : ClassicMode public class DrawGeometryMode : ClassicMode
{ {
#region ================== Structures
private struct DrawnVertex
{
public Vector2D pos;
public bool stitch;
}
#endregion
#region ================== Constants #region ================== Constants
private const float LINE_THICKNESS = 0.6f; private const float LINE_THICKNESS = 0.6f;
@ -53,7 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
private EditMode basemode; private EditMode basemode;
// Drawing points // Drawing points
private List<Vector2D> points; private List<DrawnVertex> points;
// Keep track of view changes // Keep track of view changes
private float lastoffsetx; private float lastoffsetx;
@ -80,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{ {
// Initialize // Initialize
this.basemode = General.Map.Mode; this.basemode = General.Map.Mode;
points = new List<Vector2D>(); points = new List<DrawnVertex>();
// We have no destructor // We have no destructor
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
@ -127,8 +137,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Make undo for the draw // Make undo for the draw
General.Map.UndoRedo.CreateUndo("line draw", UndoGroup.None, 0); General.Map.UndoRedo.CreateUndo("line draw", UndoGroup.None, 0);
// Update cached values // Update cached values
General.Map.Map.Update(); General.Map.Map.Update();
@ -189,10 +197,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
private void Update() private void Update()
{ {
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
snaptonearest = General.Interface.CtrlState; snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
Vector2D lastp = new Vector2D(0, 0); Vector2D lastp = new Vector2D(0, 0);
Vector2D curp = GetCurrentPosition(); DrawnVertex curp = GetCurrentPosition();
float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale; float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale;
// Render drawing lines // Render drawing lines
@ -202,23 +210,32 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
if(points.Count > 0) if(points.Count > 0)
{ {
// Render lines // Render lines
lastp = points[0]; lastp = points[0].pos;
for(int i = 1; i < points.Count; i++) for(int i = 1; i < points.Count; i++)
{ {
renderer.RenderLine(lastp, points[i], LINE_THICKNESS, General.Colors.Selection, true); renderer.RenderLine(lastp, points[i].pos, LINE_THICKNESS, General.Colors.Selection, true);
lastp = points[i]; lastp = points[i].pos;
} }
// Render line to cursor // Render line to cursor
renderer.RenderLine(lastp, curp, LINE_THICKNESS, General.Colors.Highlight, true); renderer.RenderLine(lastp, curp.pos, LINE_THICKNESS, General.Colors.Highlight, true);
// Render vertices // Render vertices
for(int i = 0; i < points.Count; i++) for(int i = 0; i < points.Count; i++)
renderer.RenderRectangleFilled(new RectangleF(points[i].x - vsize, points[i].y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Selection, true); {
if(points[i].stitch)
{
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Highlight, true);
}
else
{
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Selection, true);
}
}
} }
// Render vertex at cursor // Render vertex at cursor
renderer.RenderRectangleFilled(new RectangleF(curp.x - vsize, curp.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Highlight, true); renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Highlight, true);
// Done // Done
renderer.Finish(); renderer.Finish();
@ -229,23 +246,35 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
} }
// This gets the aligned and snapped draw position // This gets the aligned and snapped draw position
private Vector2D GetCurrentPosition() private DrawnVertex GetCurrentPosition()
{ {
DrawnVertex p = new DrawnVertex();
// Snap to nearest? // Snap to nearest?
if(snaptonearest) if(snaptonearest)
{ {
float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale; float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale;
// Go for all drawn points // Go for all drawn points
foreach(Vector2D v in points) foreach(DrawnVertex v in points)
{ {
Vector2D delta = mousemappos - v; Vector2D delta = mousemappos - v.pos;
if(delta.GetLengthSq() < (vrange * vrange)) return v; if(delta.GetLengthSq() < (vrange * vrange))
{
p.pos = v.pos;
p.stitch = true;
return p;
}
} }
// Try the nearest vertex // Try the nearest vertex
Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
if(nv != null) return nv.Position; if(nv != null)
{
p.pos = nv.Position;
p.stitch = true;
return p;
}
// Try the nearest linedef // Try the nearest linedef
Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, LinedefsMode.LINEDEF_HIGHLIGHT_RANGE / renderer.Scale); Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, LinedefsMode.LINEDEF_HIGHLIGHT_RANGE / renderer.Scale);
@ -254,14 +283,33 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Snap to grid? // Snap to grid?
if(snaptogrid) if(snaptogrid)
{ {
// Aligned to line and grid // Get grid intersection coordinates
// TODO: Find nearest horzontal and vertical grid intersections and align there List<Vector2D> coords = nl.GetGridIntersections();
return nl.NearestOnLine(mousemappos);
// Find nearest grid intersection
float found_distance = float.MaxValue;
Vector2D found_coord = new Vector2D();
foreach(Vector2D v in coords)
{
Vector2D delta = mousemappos - v;
if(delta.GetLengthSq() < found_distance)
{
found_distance = delta.GetLengthSq();
found_coord = v;
}
}
// Align to the closest grid intersection
p.pos = found_coord;
p.stitch = true;
return p;
} }
else else
{ {
// Aligned to line // Aligned to line
return nl.NearestOnLine(mousemappos); p.pos = nl.NearestOnLine(mousemappos);
p.stitch = true;
return p;
} }
} }
} }
@ -270,12 +318,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
if(snaptogrid) if(snaptogrid)
{ {
// Aligned to grid // Aligned to grid
return General.Map.Grid.SnappedToGrid(mousemappos); p.pos = General.Map.Grid.SnappedToGrid(mousemappos);
p.stitch = false;
return p;
} }
else else
{ {
// Normal position // Normal position
return mousemappos; p.pos = mousemappos;
p.stitch = false;
return p;
} }
} }
@ -318,14 +370,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
public override void KeyUp(KeyEventArgs e) public override void KeyUp(KeyEventArgs e)
{ {
base.KeyUp(e); base.KeyUp(e);
Update(); if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
} }
// When a key is pressed // When a key is pressed
public override void KeyDown(KeyEventArgs e) public override void KeyDown(KeyEventArgs e)
{ {
base.KeyDown(e); base.KeyDown(e);
Update(); if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
} }
#endregion #endregion

View file

@ -144,6 +144,18 @@ namespace CodeImp.DoomBuilder.Editing
backimage.CreateTexture(); backimage.CreateTexture();
} }
// This returns the next higher coordinate
public float GetHigher(float offset)
{
return (float)Math.Round((offset + (gridsizef * 0.5f)) * gridsizefinv) * gridsizef;
}
// This returns the next lower coordinate
public float GetLower(float offset)
{
return (float)Math.Round((offset - (gridsizef * 0.5f)) * gridsizefinv) * gridsizef;
}
// This snaps to the nearest grid coordinate // This snaps to the nearest grid coordinate
public Vector2D SnappedToGrid(Vector2D v) public Vector2D SnappedToGrid(Vector2D v)
{ {

View file

@ -319,6 +319,82 @@ namespace CodeImp.DoomBuilder.Map
} }
} }
// This returns all points at which the line intersects with the grid
public List<Vector2D> GetGridIntersections()
{
List<Vector2D> coords = new List<Vector2D>();
/*
float startx = start.Position.x;
float endx = end.Position.x;
float starty = start.Position.y;
float endy = end.Position.y;
float dirx = (float)Math.Sign(endx - startx);
float diry = (float)Math.Sign(endy - starty);
*/
Vector2D v = new Vector2D();
float gx, gy, minx, maxx, miny, maxy;
bool reversex, reversey;
if(start.Position.x > end.Position.x)
{
minx = end.Position.x;
maxx = start.Position.x;
reversex = true;
}
else
{
minx = start.Position.x;
maxx = end.Position.x;
reversex = false;
}
if(start.Position.y > end.Position.y)
{
miny = end.Position.y;
maxy = start.Position.y;
reversey = true;
}
else
{
miny = start.Position.y;
maxy = end.Position.y;
reversey = false;
}
// Go for all vertical grid lines in between line start and end
gx = General.Map.Grid.GetHigher(minx);
if(gx < maxx)
{
for(; gx < maxx; gx += General.Map.Grid.GridSizeF)
{
// Add intersection point at this x coordinate
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;
coords.Add(v);
}
}
// Go for all horizontal grid lines in between line start and end
gy = General.Map.Grid.GetHigher(miny);
if(gy < maxy)
{
for(; gy < maxy; gy += General.Map.Grid.GridSizeF)
{
// 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.y = gy;
coords.Add(v);
}
}
// Profit
return coords;
}
// This returns the closest coordinates ON the line // This returns the closest coordinates ON the line
public Vector2D NearestOnLine(Vector2D pos) public Vector2D NearestOnLine(Vector2D pos)
{ {

View file

@ -2,8 +2,21 @@
Doom Builder Actions Configuration Doom Builder Actions Configuration
\******************************************/ \******************************************/
// This just defines which actions there are and what description they have // This just defines which actions there are, what description they have and
// The source code will bind to these actions with delegates (function pointers) // some behaviour options. The Doom Builder core will bind to these actions
// with delegates (function pointers) where you use the BeginAction and
// EndAction attributes.
// Behaviour options:
//
// allowkeys: Allows the user to bind standard keys to this action.
// allowmouse: Allows the user to bind mouse buttons to this action.
// allowscroll: Allows the user to bind the scrollwheel to this action.
// disregardshift: This action will be triggered regardless if Shift or Control are used.
// repeat: BeginAction will be called for automatic key repetition.
//
// allowkeys and allowmouse are true by default, the others are false by default.
//
testaction testaction
{ {
@ -120,6 +133,7 @@ classicselect
allowkeys = true; allowkeys = true;
allowmouse = true; allowmouse = true;
allowscroll = false; allowscroll = false;
disregardshift = true;
} }
classicedit classicedit
@ -129,6 +143,7 @@ classicedit
allowkeys = true; allowkeys = true;
allowmouse = true; allowmouse = true;
allowscroll = false; allowscroll = false;
disregardshift = true;
} }
scrollwest scrollwest