#region === Copyright (c) 2010 Pascal van der Heiden === using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows.Forms; using CodeImp.DoomBuilder.Editing; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Windows; #endregion namespace CodeImp.DoomBuilder.Plugins.NodesViewer { public partial class NodesForm : DelayedForm { #region ================== Variables private NodesViewerMode mode; #endregion #region ================== Properties public int SelectedTab { get { return tabs.SelectedIndex; } } public int ViewSplitIndex { get { return (int)splitindex.Value; } } public int ViewSubsectorIndex { get { return (int)ssectorindex.Value; } } public int ViewSegIndex { get { return viewsegbox.Checked ? (int)segindex.Value : -1; } } public bool ShowSegsVertices { get { return showsegsvertices.Checked; } } #endregion #region ================== Constructor / Destructor // Constructor public NodesForm() { InitializeComponent(); } // Constructor public NodesForm(NodesViewerMode mode) { InitializeComponent(); this.mode = mode; // Counts numsegs.Text = mode.Segs.Length.ToString(); numsplits.Text = mode.Nodes.Length.ToString(); numssectors.Text = mode.Subsectors.Length.ToString(); numvertices.Text = mode.Vertices.Length.ToString(); showsegsvertices.Text = "Show additional vertices (" + (mode.Vertices.Length - General.Map.Map.Vertices.Count) + " seg splits)"; // Create stats on the tree List leafdepths = new List(); DiveTree(mode.Nodes.Length - 1, 0, leafdepths); int maxdepth = 0, mindepth = int.MaxValue; foreach(int d in leafdepths) { if(d < mindepth) mindepth = d; if(d > maxdepth) maxdepth = d; } treedepth.Text = maxdepth.ToString(); // Calculate the tree balance. The balance is 100% when all leafs are equal depth and // 0% when 1 leaf equals peakdepth and the others are at level 1. int balance = (int)(((float)mindepth / (float)maxdepth) * 100f); treebalance.Text = balance.ToString() + "%"; // Start viewing root split splitindex.Maximum = mode.Nodes.Length - 1; splitindex.Value = mode.Nodes.Length - 1; splitindex_ValueChanged(null, EventArgs.Empty); // Viewing subsector ssectorindex.Maximum = mode.Subsectors.Length - 1; ssectorindex.Value = 0; ssectorindex_ValueChanged(null, EventArgs.Empty); segindex_ValueChanged(null, EventArgs.Empty); } // Clean up any resources being used. protected override void Dispose(bool disposing) { if(disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #endregion #region ================== Methods // This calculates the tree depth recursively private void DiveTree(int node, int level, List leafdepths) { level++; // Process left side if(!mode.Nodes[node].leftsubsector) DiveTree(mode.Nodes[node].leftchild, level, leafdepths); else leafdepths.Add(level); // Process right side if(!mode.Nodes[node].rightsubsector) DiveTree(mode.Nodes[node].rightchild, level, leafdepths); else leafdepths.Add(level); } // Show this form public void Show(Form owner) { // Position at left-top of owner this.Location = new Point(owner.Location.X + 20, owner.Location.Y + 90); // Show window base.Show(owner); } // Switch to a subsector public void ShowSubsector(int ssindex) { ssectorindex.Value = ssindex; tabs.SelectTab(tabsubsectors); } #endregion #region ================== Form / Overview Events // Exit this mode private void closebutton_Click(object sender, EventArgs e) { this.Close(); } // Exit mode when dialog is closed private void NodesForm_FormClosing(object sender, FormClosingEventArgs e) { General.Editing.CancelMode(); } // Open tab changed private void tabs_SelectedIndexChanged(object sender, EventArgs e) { General.Interface.RedrawDisplay(); } // Show segs vertices changed private void showsegsvertices_CheckedChanged(object sender, EventArgs e) { General.Interface.RedrawDisplay(); } // (Re)build the nodes private void buildnodesbutton_Click(object sender, EventArgs e) { mode.BuildNodes(); // Restart the mode so that the new structures are loaded in. // This will automatically close and re-open this window. General.Editing.CancelMode(); NodesViewerMode newmode = new NodesViewerMode(); General.Editing.ChangeMode(newmode); newmode.Form.showsegsvertices.Checked = this.showsegsvertices.Checked; } #endregion #region ================== Splits Events // Go to the root split private void rootbutton_Click(object sender, EventArgs e) { splitindex.Value = splitindex.Maximum; } // Go to the parent split private void parentbutton_Click(object sender, EventArgs e) { Node n = mode.Nodes[(int)splitindex.Value]; if(n.parent > -1) splitindex.Value = n.parent; } // Go to the left split/subsector private void leftbutton_Click(object sender, EventArgs e) { Node n = mode.Nodes[(int)splitindex.Value]; if(n.leftsubsector) ShowSubsector(n.leftchild); else splitindex.Value = n.leftchild; } // Go to the right split/subsector private void rightbutton_Click(object sender, EventArgs e) { Node n = mode.Nodes[(int)splitindex.Value]; if(n.rightsubsector) ShowSubsector(n.rightchild); else splitindex.Value = n.rightchild; } // Split changes private void splitindex_ValueChanged(object sender, EventArgs e) { Node n = mode.Nodes[(int)splitindex.Value]; if(n.parent == -1) { parentsplit.Text = "(root split)"; parentsplit.Enabled = false; parentbutton.Enabled = false; } else { parentsplit.Text = n.parent.ToString(); parentsplit.Enabled = true; parentbutton.Enabled = true; } leftarea.Text = "(" + n.leftbox.Left + ", " + n.leftbox.Top + ") - (" + n.leftbox.Right + ", " + n.leftbox.Bottom + ")"; rightarea.Text = "(" + n.rightbox.Left + ", " + n.rightbox.Top + ") - (" + n.rightbox.Right + ", " + n.rightbox.Bottom + ")"; leftindex.Text = n.leftchild.ToString(); rightindex.Text = n.rightchild.ToString(); if(n.leftsubsector) { lefttype.Text = "Subsector:"; leftbutton.Text = "Go to subsector"; } else { lefttype.Text = "Split:"; leftbutton.Text = "Go to split"; } if(n.rightsubsector) { righttype.Text = "Subsector:"; rightbutton.Text = "Go to subsector"; } else { righttype.Text = "Split:"; rightbutton.Text = "Go to split"; } General.Interface.RedrawDisplay(); } #endregion #region ================== Subsectors Events // Go to parent split for this subsector private void ssparentsplit_Click(object sender, EventArgs e) { // Find parent split int ss = (int)ssectorindex.Value; int parentsplit = -1; for(int i = 0; i < mode.Nodes.Length; i++) { Node n = mode.Nodes[i]; if((n.leftsubsector && (n.leftchild == ss)) || (n.rightsubsector && (n.rightchild == ss))) { parentsplit = i; break; } } if(parentsplit == -1) return; splitindex.Value = parentsplit; tabs.SelectTab(tabsplits); } // Subsector changes private void ssectorindex_ValueChanged(object sender, EventArgs e) { Subsector s = mode.Subsectors[(int)ssectorindex.Value]; ssectornumsegs.Text = s.numsegs.ToString(); segindex.Minimum = s.firstseg; segindex.Maximum = s.firstseg + s.numsegs - 1; segindex.Value = s.firstseg; General.Interface.RedrawDisplay(); } // Segment changes private void segindex_ValueChanged(object sender, EventArgs e) { Seg sg = mode.Segs[(int)segindex.Value]; Linedef ld = General.Map.Map.GetLinedefByIndex(sg.lineindex); lineindex.Text = sg.lineindex.ToString(); startvertex.Text = sg.startvertex + " (" + mode.Vertices[sg.startvertex].x + ", " + mode.Vertices[sg.startvertex].y + ")"; endvertex.Text = sg.endvertex + " (" + mode.Vertices[sg.endvertex].x + ", " + mode.Vertices[sg.endvertex].y + ")"; segside.Text = sg.leftside ? "Back" : "Front"; segangle.Text = Angle2D.RealToDoom(sg.angle) + "\u00B0"; segoffset.Text = sg.offset + " mp"; sideindex.Text = sg.leftside ? ld.Back.Index.ToString() : ld.Front.Index.ToString(); sectorindex.Text = sg.leftside ? ld.Back.Sector.Index.ToString() : ld.Front.Sector.Index.ToString(); General.Interface.RedrawDisplay(); } // View segment checkbox changes private void viewsegbox_CheckedChanged(object sender, EventArgs e) { General.Interface.RedrawDisplay(); } #endregion } }