/* * 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. * */ using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Text; using CodeImp.DoomBuilder.Geometry; namespace CodeImp.DoomBuilder.Map { internal class MapSet : IDisposable { #region ================== Constants #endregion #region ================== Variables // Map structures private LinkedList vertices; private LinkedList linedefs; private LinkedList sidedefs; private LinkedList sectors; private LinkedList things; // Disposing private bool isdisposed = false; #endregion #region ================== Properties public ICollection Vertices { get { return vertices; } } public ICollection Linedefs { get { return linedefs; } } public ICollection Sidedefs { get { return sidedefs; } } public ICollection Sectors { get { return sectors; } } public ICollection Things { get { return things; } } public bool IsDisposed { get { return isdisposed; } } #endregion #region ================== Constructor / Disposer // Constructor for new empty map public MapSet() { // Initialize vertices = new LinkedList(); linedefs = new LinkedList(); sidedefs = new LinkedList(); sectors = new LinkedList(); things = new LinkedList(); // We have no destructor GC.SuppressFinalize(this); } // Diposer public void Dispose() { ArrayList list; // Not already disposed? if(!isdisposed) { // Already set isdisposed so that changes can be prohibited isdisposed = true; // Dispose all things list = new ArrayList(things); foreach(Thing t in list) t.Dispose(); // Dispose all sectors list = new ArrayList(sectors); foreach(Sector s in list) s.Dispose(); // Dispose all sidedefs list = new ArrayList(sidedefs); foreach(Sidedef sd in list) sd.Dispose(); // Dispose all linedefs list = new ArrayList(linedefs); foreach(Linedef l in list) l.Dispose(); // Dispose all vertices list = new ArrayList(vertices); foreach(Vertex v in list) v.Dispose(); // Clean up vertices = null; linedefs = null; sidedefs = null; sectors = null; things = null; // Done isdisposed = true; } } #endregion #region ================== Management // This makes a deep copy and returns a new MapSet public MapSet Clone() { Dictionary vertexlink = new Dictionary(vertices.Count); Dictionary linedeflink = new Dictionary(linedefs.Count); Dictionary sectorlink = new Dictionary(sectors.Count); // Create the map set MapSet newset = new MapSet(); // Go for all vertices foreach(Vertex v in vertices) { // Make new vertex Vertex nv = newset.CreateVertex(v.Position); vertexlink.Add(v, nv); } // Go for all linedefs foreach(Linedef l in linedefs) { // Make new linedef Linedef nl = newset.CreateLinedef(vertexlink[l.Start], vertexlink[l.End]); linedeflink.Add(l, nl); // Copy properties l.CopyPropertiesTo(nl); // Recalculate l.Recalculate(); } // Go for all sectors foreach(Sector s in sectors) { // Make new sector Sector ns = newset.CreateSector(); sectorlink.Add(s, ns); // Copy properties s.CopyPropertiesTo(ns); } // Go for all sidedefs foreach(Sidedef d in sidedefs) { // Make new sidedef Sidedef nd = newset.CreateSidedef(linedeflink[d.Line], d.IsFront, sectorlink[d.Sector]); // Copy properties d.CopyPropertiesTo(nd); } // Go for all things foreach(Thing t in things) { // Make new thing Thing nt = newset.CreateThing(t.Type, t.Position); // Copy properties t.CopyPropertiesTo(nt); } // Return the new set return newset; } // This creates a new vertex public Vertex CreateVertex(Vector2D pos) { LinkedListNode listitem; Vertex v; // Make a list item listitem = new LinkedListNode(null); // Make the vertex v = new Vertex(this, listitem, pos); listitem.Value = v; // Add vertex to the list vertices.AddLast(listitem); // Return result return v; } // This creates a new linedef public Linedef CreateLinedef(Vertex start, Vertex end) { LinkedListNode listitem; Linedef l; // Make a list item listitem = new LinkedListNode(null); // Make the linedef l = new Linedef(this, listitem, start, end); listitem.Value = l; // Add linedef to the list linedefs.AddLast(listitem); // Return result return l; } // This creates a new sidedef public Sidedef CreateSidedef(Linedef l, bool front, Sector s) { LinkedListNode listitem; Sidedef sd; // Make a list item listitem = new LinkedListNode(null); // Make the sidedef sd = new Sidedef(this, listitem, l, front, s); listitem.Value = sd; // Add sidedef to the list sidedefs.AddLast(listitem); // Return result return sd; } // This creates a new sector public Sector CreateSector() { LinkedListNode listitem; Sector s; // Make a list item listitem = new LinkedListNode(null); // Make the sector s = new Sector(this, listitem); listitem.Value = s; // Add sector to the list sectors.AddLast(listitem); // Return result return s; } // This creates a new thing public Thing CreateThing(int type, Vector2D pos) { LinkedListNode listitem; Thing t; // Make a list item listitem = new LinkedListNode(null); // Make the thing t = new Thing(this, listitem, type, pos); listitem.Value = t; // Add thing to the list things.AddLast(listitem); // Return result return t; } #endregion #region ================== Static Tools // This finds the line closest to the specified position public static Linedef NearestLinedef(ICollection selection, Vector2D pos) { Linedef closest = null; float distance = float.MaxValue; float d; // Go for all linedefs in selection foreach(Linedef l in selection) { // Calculate distance and check if closer than previous find d = l.DistanceToSq(pos, true); if(d < distance) { // This one is closer closest = l; distance = d; } } // Return result return closest; } // This finds the vertex closest to the specified position public static Vertex NearestVertex(ICollection selection, Vector2D pos) { Vertex closest = null; float distance = float.MaxValue; float d; // Go for all vertices in selection foreach(Vertex v in selection) { // Calculate distance and check if closer than previous find d = v.DistanceToSq(pos); if(d < distance) { // This one is closer closest = v; distance = d; } } // Return result return closest; } #endregion #region ================== Tools // This finds the line closest to the specified position public Linedef NearestLinedef(Vector2D pos) { return MapSet.NearestLinedef(linedefs, pos); } // This finds the vertex closest to the specified position public Vertex NearestVertex(Vector2D pos) { return MapSet.NearestVertex(vertices, pos); } #endregion } }