mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
177 lines
5.2 KiB
C#
177 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using CodeImp.DoomBuilder.Editing;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Windows;
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
|
|
{
|
|
[EditMode(DisplayName = "Snap Map Elements to Grid",
|
|
SwitchAction = "snapvertstogrid",
|
|
AllowCopyPaste = false,
|
|
Optional = false,
|
|
Volatile = true)]
|
|
public class SnapVerticesMode : BaseClassicMode
|
|
{
|
|
public SnapVerticesMode() {
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
// Mode engages
|
|
public override void OnEngage() {
|
|
base.OnEngage();
|
|
|
|
//get selection
|
|
General.Map.Map.ClearAllMarks(false);
|
|
General.Map.Map.MarkAllSelectedGeometry(true, false, true, false, false);
|
|
List<Vertex> verts = General.Map.Map.GetMarkedVertices(true);
|
|
|
|
//nothing selected?
|
|
if (verts.Count == 0) {
|
|
//check things
|
|
List<Thing> things = General.Map.Map.GetMarkedThings(true);
|
|
if (things.Count == 0) {
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Select any map element first!");
|
|
base.OnCancel();
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
} else {
|
|
snapThings(things);
|
|
}
|
|
} else {
|
|
snapVertices(verts);
|
|
}
|
|
}
|
|
|
|
private void snapVertices(List<Vertex> verts) {
|
|
// Make undo for the snapping
|
|
General.Map.UndoRedo.CreateUndo("Snap vertices");
|
|
|
|
int snappedCount = 0;
|
|
List<Vertex> movedVerts = new List<Vertex>();
|
|
List<Linedef> movedLines = new List<Linedef>();
|
|
|
|
//snap them all!
|
|
foreach(Vertex v in verts) {
|
|
Vector2D pos = v.Position;
|
|
v.SnapToGrid();
|
|
|
|
if(v.Position.x != pos.x || v.Position.y != pos.y) {
|
|
snappedCount++;
|
|
movedVerts.Add(v);
|
|
foreach(Linedef l in v.Linedefs){
|
|
if(!movedLines.Contains(l)) movedLines.Add(l);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Create blockmap
|
|
RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices);
|
|
BlockMap<BlockEntry> blockmap = new BlockMap<BlockEntry>(area);
|
|
blockmap.AddVerticesSet(General.Map.Map.Vertices);
|
|
|
|
//merge overlapping vertices using teh power of BLOCKMAP!!!11
|
|
BlockEntry block;
|
|
foreach (Vertex v in movedVerts) {
|
|
block = blockmap.GetBlockAt(v.Position);
|
|
if (block == null) continue;
|
|
|
|
foreach (Vertex blockVert in block.Vertices) {
|
|
if(blockVert.IsDisposed || blockVert.Index == v.Index || blockVert.Position != v.Position) continue;
|
|
|
|
foreach(Linedef l in blockVert.Linedefs)
|
|
if(!movedLines.Contains(l)) movedLines.Add(l);
|
|
v.Join(blockVert);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Update cached values of lines because we may need their length/angle
|
|
General.Map.Map.Update(true, false);
|
|
|
|
General.Map.Map.BeginAddRemove();
|
|
MapSet.RemoveLoopedLinedefs(movedLines);
|
|
MapSet.JoinOverlappingLines(movedLines);
|
|
General.Map.Map.EndAddRemove();
|
|
|
|
//get changed sectors
|
|
List<Sector> changedSectors = new List<Sector>();
|
|
foreach(Linedef l in movedLines) {
|
|
if(l == null || l.IsDisposed) continue;
|
|
if(l.Front != null && l.Front.Sector != null && !changedSectors.Contains(l.Front.Sector))
|
|
changedSectors.Add(l.Front.Sector);
|
|
if(l.Back != null && l.Back.Sector != null && !changedSectors.Contains(l.Back.Sector))
|
|
changedSectors.Add(l.Back.Sector);
|
|
}
|
|
|
|
// Now update area of sectors
|
|
General.Map.Map.Update(false, true);
|
|
|
|
//fix invalid sectors
|
|
foreach (Sector s in changedSectors) {
|
|
if(s.BBox.IsEmpty) {
|
|
s.Dispose();
|
|
}else if (s.Sidedefs.Count < 3) {
|
|
bool merged = false;
|
|
foreach(Sidedef side in s.Sidedefs) {
|
|
if(side.Other != null && side.Other.Sector != null) {
|
|
s.Join(side.Other.Sector);
|
|
merged = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//oh well, I don't know what else I can do here...
|
|
if(!merged) s.Dispose();
|
|
}
|
|
}
|
|
|
|
//done
|
|
General.Interface.DisplayStatus(StatusType.Info, "Snapped " + snappedCount + " vertices.");
|
|
MessageBox.Show("Snapped " + snappedCount + " vertices." + Environment.NewLine + "It's a good idea to run Map Analysis Mode now.");
|
|
base.OnAccept();
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
}
|
|
|
|
private void snapThings(List<Thing> things) {
|
|
// Make undo for the snapping
|
|
General.Map.UndoRedo.CreateUndo("Snap things");
|
|
|
|
int snappedCount = 0;
|
|
|
|
//snap them all!
|
|
foreach(Thing t in things) {
|
|
Vector2D pos = t.Position;
|
|
t.SnapToGrid();
|
|
|
|
if(t.Position.x != pos.x || t.Position.y != pos.y)
|
|
snappedCount++;
|
|
}
|
|
|
|
//done
|
|
General.Interface.DisplayStatus(StatusType.Info, "Snapped " + snappedCount + " things.");
|
|
base.OnAccept();
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
}
|
|
|
|
// Disenagaging
|
|
public override void OnDisengage() {
|
|
base.OnDisengage();
|
|
Cursor.Current = Cursors.AppStarting;
|
|
|
|
if (!cancelled) {
|
|
// Update cached values
|
|
General.Map.Map.Update();
|
|
// Map is changed
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// Done
|
|
Cursor.Current = Cursors.Default;
|
|
}
|
|
}
|
|
}
|