mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 22:41:46 +00:00
snapping to nearest lines where they intersect the grid! this is hot!
This commit is contained in:
parent
2606487474
commit
6ba6d7416d
8 changed files with 242 additions and 40 deletions
|
@ -66,6 +66,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// List of unstable lines
|
||||
protected ICollection<Linedef> unstablelines;
|
||||
|
||||
// List of unselected lines
|
||||
protected ICollection<Linedef> unselectedlines;
|
||||
|
||||
// Keep track of view changes
|
||||
private float lastoffsetx;
|
||||
private float lastoffsety;
|
||||
|
@ -145,25 +148,68 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapnearest)
|
||||
{
|
||||
Vector2D oldpos = dragitem.Position;
|
||||
Vertex nearest;
|
||||
int i = 0;
|
||||
|
||||
// Snap to nearest?
|
||||
if(snapnearest)
|
||||
{
|
||||
// Find nearest unselected item within selection range
|
||||
nearest = MapSet.NearestVertexSquareRange(unselectedverts, mousemappos, VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale);
|
||||
if(nearest != null)
|
||||
// Find nearest unselected vertex within range
|
||||
Vertex nv = MapSet.NearestVertexSquareRange(unselectedverts, mousemappos, VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale);
|
||||
if(nv != null)
|
||||
{
|
||||
// Move the dragged item
|
||||
dragitem.Move(nearest.Position);
|
||||
dragitem.Move(nv.Position);
|
||||
|
||||
// Adjust the offset
|
||||
offset = nearest.Position - dragitemposition;
|
||||
offset = nv.Position - dragitemposition;
|
||||
|
||||
// Do not snap to grid!
|
||||
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?
|
||||
|
@ -286,7 +332,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
private void Update()
|
||||
{
|
||||
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
|
||||
snaptonearest = General.Interface.CtrlState;
|
||||
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
|
||||
|
||||
// Move selected geometry
|
||||
if(MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptonearest))
|
||||
|
@ -318,16 +364,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
public override void KeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.KeyUp(e);
|
||||
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update();
|
||||
if(snaptonearest != General.Interface.CtrlState) Update();
|
||||
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
|
||||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
|
||||
}
|
||||
|
||||
// When a key is pressed
|
||||
public override void KeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.KeyDown(e);
|
||||
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update();
|
||||
if(snaptonearest != General.Interface.CtrlState) Update();
|
||||
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
|
||||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -51,7 +51,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
#region ================== Variables
|
||||
|
||||
private ICollection<Linedef> selectedlines;
|
||||
private ICollection<Linedef> unselectedlines;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
#region ================== Variables
|
||||
|
||||
private ICollection<Linedef> selectedlines;
|
||||
private ICollection<Linedef> unselectedlines;
|
||||
private ICollection<Sector> selectedsectors;
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// Get selected vertices
|
||||
selectedverts = General.Map.Map.GetVerticesSelection(true);
|
||||
unselectedverts = General.Map.Map.GetVerticesSelection(false);
|
||||
unselectedlines = General.Map.Map.LinedefsFromSelectedVertices(true, false, false);
|
||||
|
||||
// Initialize
|
||||
base.StartDrag(basemode, dragitem, dragstartmappos,
|
||||
|
|
|
@ -41,6 +41,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
|
||||
public class DrawGeometryMode : ClassicMode
|
||||
{
|
||||
#region ================== Structures
|
||||
|
||||
private struct DrawnVertex
|
||||
{
|
||||
public Vector2D pos;
|
||||
public bool stitch;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constants
|
||||
|
||||
private const float LINE_THICKNESS = 0.6f;
|
||||
|
@ -53,7 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
private EditMode basemode;
|
||||
|
||||
// Drawing points
|
||||
private List<Vector2D> points;
|
||||
private List<DrawnVertex> points;
|
||||
|
||||
// Keep track of view changes
|
||||
private float lastoffsetx;
|
||||
|
@ -80,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
{
|
||||
// Initialize
|
||||
this.basemode = General.Map.Mode;
|
||||
points = new List<Vector2D>();
|
||||
points = new List<DrawnVertex>();
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -127,8 +137,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// Make undo for the draw
|
||||
General.Map.UndoRedo.CreateUndo("line draw", UndoGroup.None, 0);
|
||||
|
||||
|
||||
|
||||
// Update cached values
|
||||
General.Map.Map.Update();
|
||||
|
||||
|
@ -189,10 +197,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
private void Update()
|
||||
{
|
||||
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 curp = GetCurrentPosition();
|
||||
DrawnVertex curp = GetCurrentPosition();
|
||||
float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale;
|
||||
|
||||
// Render drawing lines
|
||||
|
@ -202,23 +210,32 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
if(points.Count > 0)
|
||||
{
|
||||
// Render lines
|
||||
lastp = points[0];
|
||||
lastp = points[0].pos;
|
||||
for(int i = 1; i < points.Count; i++)
|
||||
{
|
||||
renderer.RenderLine(lastp, points[i], LINE_THICKNESS, General.Colors.Selection, true);
|
||||
lastp = points[i];
|
||||
renderer.RenderLine(lastp, points[i].pos, LINE_THICKNESS, General.Colors.Selection, true);
|
||||
lastp = points[i].pos;
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
renderer.Finish();
|
||||
|
@ -229,23 +246,35 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
}
|
||||
|
||||
// This gets the aligned and snapped draw position
|
||||
private Vector2D GetCurrentPosition()
|
||||
private DrawnVertex GetCurrentPosition()
|
||||
{
|
||||
DrawnVertex p = new DrawnVertex();
|
||||
|
||||
// Snap to nearest?
|
||||
if(snaptonearest)
|
||||
{
|
||||
float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale;
|
||||
|
||||
// Go for all drawn points
|
||||
foreach(Vector2D v in points)
|
||||
foreach(DrawnVertex v in points)
|
||||
{
|
||||
Vector2D delta = mousemappos - v;
|
||||
if(delta.GetLengthSq() < (vrange * vrange)) return v;
|
||||
Vector2D delta = mousemappos - v.pos;
|
||||
if(delta.GetLengthSq() < (vrange * vrange))
|
||||
{
|
||||
p.pos = v.pos;
|
||||
p.stitch = true;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
// Try the nearest vertex
|
||||
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
|
||||
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?
|
||||
if(snaptogrid)
|
||||
{
|
||||
// Aligned to line and grid
|
||||
// TODO: Find nearest horzontal and vertical grid intersections and align there
|
||||
return nl.NearestOnLine(mousemappos);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Align to the closest grid intersection
|
||||
p.pos = found_coord;
|
||||
p.stitch = true;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Aligned to grid
|
||||
return General.Map.Grid.SnappedToGrid(mousemappos);
|
||||
p.pos = General.Map.Grid.SnappedToGrid(mousemappos);
|
||||
p.stitch = false;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
public override void KeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.KeyDown(e);
|
||||
Update();
|
||||
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
|
||||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -144,6 +144,18 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
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
|
||||
public Vector2D SnappedToGrid(Vector2D v)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
public Vector2D NearestOnLine(Vector2D pos)
|
||||
{
|
||||
|
|
|
@ -2,8 +2,21 @@
|
|||
Doom Builder Actions Configuration
|
||||
\******************************************/
|
||||
|
||||
// This just defines which actions there are and what description they have
|
||||
// The source code will bind to these actions with delegates (function pointers)
|
||||
// This just defines which actions there are, what description they have and
|
||||
// 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
|
||||
{
|
||||
|
@ -120,6 +133,7 @@ classicselect
|
|||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = false;
|
||||
disregardshift = true;
|
||||
}
|
||||
|
||||
classicedit
|
||||
|
@ -129,6 +143,7 @@ classicedit
|
|||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = false;
|
||||
disregardshift = true;
|
||||
}
|
||||
|
||||
scrollwest
|
||||
|
|
Loading…
Reference in a new issue