UltimateZoneBuilder/Source/Core/Map/Vertex.cs
MaxED 883527c37c Sector Edit form and Linedef Edit form now support float texture offsets.
Tag Statistics form: you can now double click on Sectors, Linedefs or Things cell to select them, and right click to open their properties.
Texture size labels were displayed incorrectly in some cases.
Rewritten VerticesMode.DeleteItem() once again...
Vertex Edit form now works in realtime mode.
Vertex Edit form: ceiling and floor vertex offsets can now be cleared.
Added StairSectorBuilder plugin (I suppose some external plugins will stop working in GZDB because I've changed ButtonStep to float in ButtonsNumericTextbox a couple revisions ago...).
Preferences form: action description is now scrollable.
Changed background color of Sector Edit form.
Vertex' ZCeiling and ZFloor properties are now managed internally.
2013-07-08 13:13:28 +00:00

325 lines
7.6 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.IO;
#endregion
namespace CodeImp.DoomBuilder.Map
{
public sealed class Vertex : SelectableElement
{
#region ================== Constants
public const int BUFFERVERTICES = 1;
public const int RENDERPRIMITIVES = 1;
#endregion
#region ================== Variables
// Map
private MapSet map;
// List items
private LinkedListNode<Vertex> selecteditem;
// Position
private Vector2D pos;
//mxd. Height
private float zfloor;
private float zceiling;
// References
private LinkedList<Linedef> linedefs;
// Cloning
private Vertex clone;
private int serializedindex;
#endregion
#region ================== Properties
public MapSet Map { get { return map; } }
public ICollection<Linedef> Linedefs { get { return linedefs; } }
public Vector2D Position { get { return pos; } }
internal Vertex Clone { get { return clone; } set { clone = value; } }
internal int SerializedIndex { get { return serializedindex; } set { serializedindex = value; } }
public float ZCeiling { //mxd
get { return zceiling; }
set {
if(zceiling != value) {
BeforeFieldsChange();
zceiling = value;
}
}
}
public float ZFloor { //mxd
get { return zfloor; }
set {
if(zfloor != value) {
BeforeFieldsChange();
zfloor = value;
}
}
}
#endregion
#region ================== Constructor / Disposer
// Constructor
internal Vertex(MapSet map, int listindex, Vector2D pos)
{
// Initialize
this.map = map;
this.linedefs = new LinkedList<Linedef>();
this.listindex = listindex;
this.pos = pos;
this.zceiling = float.NaN; //mxd
this.zfloor = float.NaN; //mxd
if(map == General.Map.Map)
General.Map.UndoRedo.RecAddVertex(this);
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Already set isdisposed so that changes can be prohibited
isdisposed = true;
if(map.AutoRemove)
{
// Dispose the lines that are attached to this vertex
// because a linedef cannot exist without 2 vertices.
foreach(Linedef ld in linedefs) ld.Dispose();
}
else
{
// Detach from linedefs
foreach(Linedef ld in linedefs) ld.DetachVertexP(this);
}
if(map == General.Map.Map)
General.Map.UndoRedo.RecRemVertex(this);
// Remove from main list
map.RemoveVertex(listindex);
// Clean up
linedefs = null;
map = null;
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Management
// Call this before changing properties
protected override void BeforePropsChange()
{
if(map == General.Map.Map)
General.Map.UndoRedo.RecPrpVertex(this);
}
// This attaches a linedef and returns the listitem
internal LinkedListNode<Linedef> AttachLinedefP(Linedef l)
{
return linedefs.AddLast(l);
}
// This detaches a linedef
internal void DetachLinedefP(LinkedListNode<Linedef> l)
{
// Not disposing?
if(!isdisposed)
{
// Remove linedef
linedefs.Remove(l);
// No more linedefs left?
if((linedefs.Count == 0) && map.AutoRemove)
{
// This vertex is now useless, dispose it
this.Dispose();
}
}
}
// Serialize / deserialize
new internal void ReadWrite(IReadWriteStream s)
{
if(!s.IsWriting) BeforePropsChange();
base.ReadWrite(s);
s.rwVector2D(ref pos);
s.rwFloat(ref zceiling); //mxd
s.rwFloat(ref zfloor); //mxd
if(s.IsWriting)
{
// Let all lines know they need an update
foreach(Linedef l in linedefs) l.NeedUpdate();
}
}
// Selected
protected override void DoSelect()
{
base.DoSelect();
selecteditem = map.SelectedVertices.AddLast(this);
}
// Deselect
protected override void DoUnselect()
{
base.DoUnselect();
if(selecteditem.List != null) selecteditem.List.Remove(selecteditem);
selecteditem = null;
}
#endregion
#region ================== Methods
// This copies all properties to another thing
public void CopyPropertiesTo(Vertex v)
{
v.BeforePropsChange();
// Copy properties
v.pos = pos;
v.zceiling = zceiling; //mxd
v.zfloor = zfloor; //mxd
base.CopyPropertiesTo(v);
}
// This returns the distance from given coordinates
public float DistanceToSq(Vector2D p)
{
return (p.x - pos.x) * (p.x - pos.x) + (p.y - pos.y) * (p.y - pos.y);
}
// This returns the distance from given coordinates
public float DistanceTo(Vector2D p)
{
return Vector2D.Distance(p, pos);
}
// This finds the line closest to the specified position
public Linedef NearestLinedef(Vector2D pos) { return MapSet.NearestLinedef(linedefs, pos); }
// This moves the vertex
public void Move(Vector2D newpos)
{
// Do we actually move?
if(newpos != pos)
{
BeforePropsChange();
// Change position
pos = newpos;
#if DEBUG
if(float.IsNaN(pos.x) || float.IsNaN(pos.y) ||
float.IsInfinity(pos.x) || float.IsInfinity(pos.y))
{
General.Fail("Invalid vertex position! The given vertex coordinates cannot be NaN or Infinite.");
}
#endif
// Let all lines know they need an update
foreach(Linedef l in linedefs) l.NeedUpdate();
General.Map.IsChanged = true;
}
}
// This snaps the vertex to the map format accuracy
public void SnapToAccuracy()
{
// Round the coordinates
Vector2D newpos = new Vector2D((float)Math.Round(pos.x, General.Map.FormatInterface.VertexDecimals),
(float)Math.Round(pos.y, General.Map.FormatInterface.VertexDecimals));
this.Move(newpos);
}
// This snaps the vertex to the grid
public void SnapToGrid()
{
// Calculate nearest grid coordinates
this.Move(General.Map.Grid.SnappedToGrid(pos));
}
// This joins another vertex
// Which means this vertex is removed and the other is kept!
public void Join(Vertex other)
{
// If either of the two vertices was selected, keep the other selected
if(this.Selected) other.Selected = true;
if(this.marked) other.marked = true;
// Any linedefs to move?
if(linedefs.Count > 0)
{
// Detach all linedefs and attach them to the other
// This will automatically dispose this vertex
while(linedefs != null)
{
// Move the line to the other vertex
if(linedefs.First.Value.Start == this)
linedefs.First.Value.SetStartVertex(other);
else
linedefs.First.Value.SetEndVertex(other);
}
}
else
{
// No lines attached
// Dispose manually
this.Dispose();
}
General.Map.IsChanged = true;
}
// String representation
public override string ToString()
{
return "Vertex (" + pos + ")";
}
#endregion
}
}