mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-25 21:31:14 +00:00
477 lines
No EOL
12 KiB
C#
477 lines
No EOL
12 KiB
C#
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Runtime.Serialization;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Types;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.ThreeDFloorMode
|
|
{
|
|
public class SlopeVertexGroup
|
|
{
|
|
#region ================== Variables
|
|
private List<SlopeVertex> vertices;
|
|
private List<Sector> sectors;
|
|
private Dictionary<Sector, PlaneType> sectorplanes;
|
|
private List<Sector> taggedsectors; // For highlighting 3D floors
|
|
private int id;
|
|
private int height;
|
|
private Vertex anchorvertex;
|
|
private Vector2D anchor;
|
|
private bool reposition;
|
|
private bool spline;
|
|
|
|
#endregion
|
|
|
|
#region ================== Enums
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
public List<SlopeVertex> Vertices { get { return vertices; } set { vertices = value; ComputeHeight(); } }
|
|
public List<Sector> Sectors { get { return sectors; } set { sectors = value; } }
|
|
public Dictionary<Sector, PlaneType> SectorPlanes { get { return sectorplanes; } }
|
|
public List<Sector> TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } }
|
|
public int Id { get { return id; } }
|
|
public int Height { get { return height; } set { height = value; } }
|
|
public bool Reposition { get { return reposition; } set { reposition = value; } }
|
|
public bool Spline { get { return spline; }set { spline = value; } }
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructors
|
|
|
|
public SlopeVertexGroup(int id, Sector sector)
|
|
{
|
|
List<string> list = new List<string> { "floor", "ceiling" };
|
|
Type type = typeof(SlopeVertexGroup);
|
|
|
|
this.id = id;
|
|
sectors = new List<Sector>();
|
|
sectorplanes = new Dictionary<Sector, PlaneType>();
|
|
taggedsectors = new List<Sector>();
|
|
vertices = new List<SlopeVertex>();
|
|
anchorvertex = null;
|
|
|
|
// There will always be at least two slope vertices, so add them here
|
|
vertices.Add(new SlopeVertex(sector, id, 0));
|
|
vertices.Add(new SlopeVertex(sector, id, 1));
|
|
|
|
// Check if there's a third slope vertex, and add it if there is
|
|
string vertexidentifier = String.Format("user_svg{0}_v2_x", id);
|
|
|
|
foreach (KeyValuePair<string, UniValue> kvp in sector.Fields)
|
|
{
|
|
if (kvp.Key == vertexidentifier)
|
|
{
|
|
vertices.Add(new SlopeVertex(sector, id, 2));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get reposition value
|
|
reposition = sector.Fields.GetValue(String.Format("user_svg{0}_reposition", id), true);
|
|
|
|
// Get spline value
|
|
spline = sector.Fields.GetValue(String.Format("user_svg{0}_spline", id), false);
|
|
|
|
spline = false;
|
|
|
|
ComputeHeight();
|
|
FindSectors();
|
|
}
|
|
|
|
public SlopeVertexGroup(int id, List<SlopeVertex> vertices)
|
|
{
|
|
this.vertices = vertices;
|
|
this.id = id;
|
|
sectors = new List<Sector>();
|
|
sectorplanes = new Dictionary<Sector, PlaneType>();
|
|
taggedsectors = new List<Sector>();
|
|
anchorvertex = null;
|
|
height = 0;
|
|
|
|
ComputeHeight();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
public void FindSectors()
|
|
{
|
|
if (sectors == null)
|
|
sectors = new List<Sector>();
|
|
else
|
|
sectors.Clear();
|
|
|
|
if (taggedsectors == null)
|
|
taggedsectors = new List<Sector>();
|
|
else
|
|
taggedsectors.Clear();
|
|
|
|
sectorplanes.Clear();
|
|
|
|
foreach (Sector s in General.Map.Map.Sectors)
|
|
{
|
|
bool onfloor = s.Fields.GetValue("user_floorplane_id", -1) == id;
|
|
bool onceiling = s.Fields.GetValue("user_ceilingplane_id", -1) == id;
|
|
PlaneType pt = 0;
|
|
|
|
if (!onfloor && !onceiling)
|
|
continue;
|
|
|
|
sectors.Add(s);
|
|
|
|
if (onfloor && onceiling)
|
|
pt = PlaneType.Floor | PlaneType.Ceiling;
|
|
else if (onfloor)
|
|
pt = PlaneType.Floor;
|
|
else if (onceiling)
|
|
pt = PlaneType.Ceiling;
|
|
|
|
sectorplanes.Add(s, pt);
|
|
|
|
GetTaggesSectors(s, pt);
|
|
}
|
|
}
|
|
|
|
public void RemovePlanes()
|
|
{
|
|
foreach (Sector s in sectors.ToList())
|
|
{
|
|
RemoveSector(s, this.sectorplanes[s]);
|
|
}
|
|
}
|
|
|
|
public void RemoveFromSectors()
|
|
{
|
|
foreach (Sector s in sectors.ToList())
|
|
{
|
|
RemoveSector(s, PlaneType.Floor);
|
|
RemoveSector(s, PlaneType.Ceiling);
|
|
}
|
|
}
|
|
|
|
private void GetTaggesSectors(Sector s, PlaneType pt)
|
|
{
|
|
// Check if the current sector is a 3D floor control sector. If that's the case also store the
|
|
// tagged sector(s). They will be used for highlighting in slope mode
|
|
foreach (Sidedef sd in s.Sidedefs)
|
|
{
|
|
if (sd.Line.Action >= 100 && sd.Line.Action < 300)
|
|
{
|
|
foreach (Sector ts in BuilderPlug.GetSectorsByTag(sd.Line.Args[0]))
|
|
{
|
|
if (!taggedsectors.Contains(ts))
|
|
taggedsectors.Add(ts);
|
|
|
|
if(!sectorplanes.ContainsKey(ts))
|
|
sectorplanes.Add(ts, pt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddSector(Sector s, PlaneType pt)
|
|
{
|
|
if (sectorplanes.ContainsKey(s))
|
|
{
|
|
pt |= sectorplanes[s];
|
|
sectorplanes.Remove(s);
|
|
}
|
|
|
|
if (sectors.Contains(s))
|
|
sectors.Remove(s);
|
|
|
|
sectorplanes.Add(s, pt);
|
|
sectors.Add(s);
|
|
|
|
GetTaggesSectors(s, pt);
|
|
|
|
ApplyToSectors();
|
|
}
|
|
|
|
public void RemoveSector(Sector s, PlaneType pt)
|
|
{
|
|
Debug.WriteLine("Removing from Sector " + s.Index.ToString() + ": " + pt.ToString());
|
|
|
|
if (sectorplanes.ContainsKey(s))
|
|
{
|
|
if (sectors.Contains(s) && sectorplanes[s] == pt)
|
|
{
|
|
sectors.Remove(s);
|
|
sectorplanes.Remove(s);
|
|
}
|
|
else
|
|
sectorplanes[s] &= ~pt;
|
|
}
|
|
|
|
if ((pt & PlaneType.Floor) == PlaneType.Floor)
|
|
{
|
|
s.FloorSlope = new Vector3D();
|
|
s.FloorSlopeOffset = 0;
|
|
s.Fields.Remove("user_floorplane_id");
|
|
}
|
|
|
|
if ((pt & PlaneType.Ceiling) == PlaneType.Ceiling)
|
|
{
|
|
s.CeilSlope = new Vector3D();
|
|
s.CeilSlopeOffset = 0;
|
|
s.Fields.Remove("user_ceilingplane_id");
|
|
}
|
|
}
|
|
|
|
public void RemoveUndoRedoUDMFFields(Sector s)
|
|
{
|
|
string fieldname = "";
|
|
string[] comp = new string[] { "x", "y", "z" };
|
|
|
|
if (s == null || s.IsDisposed)
|
|
return;
|
|
|
|
s.Fields.BeforeFieldsChange();
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
foreach (string c in comp)
|
|
{
|
|
fieldname = string.Format("user_svg{0}_v{1}_{2}", id, i, c);
|
|
|
|
if (s.Fields.ContainsKey(fieldname))
|
|
s.Fields.Remove(fieldname);
|
|
}
|
|
}
|
|
|
|
// Remove reposition field
|
|
fieldname = string.Format("user_svg{0}_reposition", id);
|
|
if (s.Fields.ContainsKey(fieldname))
|
|
s.Fields.Remove(fieldname);
|
|
}
|
|
|
|
public void ApplyToSectors()
|
|
{
|
|
List<Sector> removesectors = new List<Sector>();
|
|
|
|
ComputeHeight();
|
|
|
|
foreach (Sector s in sectors)
|
|
{
|
|
bool hasplane = false;
|
|
|
|
if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Floor) == PlaneType.Floor)
|
|
{
|
|
hasplane = true;
|
|
|
|
if (s.Fields.ContainsKey("user_floorplane_id"))
|
|
s.Fields["user_floorplane_id"] = new UniValue(UniversalType.Integer, id);
|
|
else
|
|
s.Fields.Add("user_floorplane_id", new UniValue(UniversalType.Integer, id));
|
|
}
|
|
else if (s.Fields.ContainsKey("user_floorplane_id") && s.Fields.GetValue("user_floorplane_id", -1) == id)
|
|
{
|
|
s.Fields.Remove("user_floorplane_id");
|
|
}
|
|
|
|
if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling)
|
|
{
|
|
hasplane = true;
|
|
|
|
if (s.Fields.ContainsKey("user_ceilingplane_id"))
|
|
s.Fields["user_ceilingplane_id"] = new UniValue(UniversalType.Integer, id);
|
|
else
|
|
s.Fields.Add("user_ceilingplane_id", new UniValue(UniversalType.Integer, id));
|
|
}
|
|
else if (s.Fields.ContainsKey("user_ceilingplane_id") && s.Fields.GetValue("user_ceilingplane_id", -1) == id)
|
|
{
|
|
s.Fields.Remove("user_ceilingplane_id");
|
|
}
|
|
|
|
if (!hasplane)
|
|
removesectors.Add(s);
|
|
}
|
|
|
|
foreach (Sector s in removesectors)
|
|
sectors.Remove(s);
|
|
|
|
foreach (Sector s in sectors)
|
|
BuilderPlug.Me.UpdateSlopes(s);
|
|
}
|
|
|
|
public void StoreInSector(Sector sector)
|
|
{
|
|
// Make sure the field work with undo/redo
|
|
sector.Fields.BeforeFieldsChange();
|
|
|
|
// Also store all slope vertices in the sector
|
|
for (int i = 0; i < vertices.Count; i++)
|
|
vertices[i].StoreInSector(sector, id, i);
|
|
|
|
string identifier = String.Format("user_svg{0}_reposition", id);
|
|
|
|
// Add, update, or delete the reposition field
|
|
if (reposition)
|
|
{
|
|
//default action
|
|
if (sector.Fields.ContainsKey(identifier))
|
|
sector.Fields.Remove(identifier);
|
|
}
|
|
else
|
|
{
|
|
if (sector.Fields.ContainsKey(identifier))
|
|
sector.Fields[identifier] = new UniValue(UniversalType.Boolean, reposition);
|
|
else
|
|
sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, reposition));
|
|
}
|
|
|
|
// Spline
|
|
identifier = String.Format("user_svg{0}_spline", id);
|
|
|
|
if (!spline && sector.Fields.ContainsKey(identifier))
|
|
sector.Fields.Remove(identifier);
|
|
else if (spline)
|
|
{
|
|
if (sector.Fields.ContainsKey(identifier))
|
|
sector.Fields[identifier] = new UniValue(UniversalType.Boolean, spline);
|
|
else
|
|
sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, spline));
|
|
}
|
|
}
|
|
|
|
public void SelectVertices(bool select)
|
|
{
|
|
foreach (SlopeVertex sv in vertices)
|
|
sv.Selected = select;
|
|
}
|
|
|
|
public bool GetAnchor()
|
|
{
|
|
anchorvertex = null;
|
|
|
|
if (sectors.Count == 0)
|
|
return false;
|
|
|
|
// Try to find a sector that contains a SV
|
|
/*
|
|
foreach (Sector s in sectors)
|
|
{
|
|
foreach (SlopeVertex sv in vertices)
|
|
{
|
|
if (s.Intersect(sv.Pos))
|
|
{
|
|
anchorvertex = s.Sidedefs.First().Line.Start;
|
|
anchor = new Vector2D(anchorvertex.Position);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Just grab the next best vertex
|
|
foreach (Sector s in sectors)
|
|
{
|
|
foreach (Sidedef sd in s.Sidedefs)
|
|
{
|
|
anchorvertex = sd.Line.Start;
|
|
anchor = new Vector2D(anchorvertex.Position);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void RepositionByAnchor()
|
|
{
|
|
if (anchorvertex == null || !reposition)
|
|
return;
|
|
|
|
Vector2D diff = anchorvertex.Position - anchor;
|
|
|
|
if (diff.x == 0.0f && diff.y == 0.0f)
|
|
return;
|
|
|
|
foreach (SlopeVertex sv in vertices)
|
|
{
|
|
sv.Pos += diff;
|
|
}
|
|
|
|
anchorvertex = null;
|
|
}
|
|
|
|
public void ComputeHeight()
|
|
{
|
|
List<Vector3D> sp = new List<Vector3D>();
|
|
|
|
for (int i = 0; i < vertices.Count; i++)
|
|
{
|
|
sp.Add(new Vector3D(vertices[i].Pos.x, vertices[i].Pos.y,vertices[i].Z));
|
|
}
|
|
|
|
if (vertices.Count == 2)
|
|
{
|
|
double z = sp[0].z;
|
|
Line2D line = new Line2D(sp[0], sp[1]);
|
|
Vector3D perpendicular = line.GetPerpendicular();
|
|
|
|
Vector2D v = sp[0] + perpendicular;
|
|
|
|
sp.Add(new Vector3D(v.x, v.y, z));
|
|
}
|
|
|
|
Plane p = new Plane(sp[0], sp[1], sp[2], true);
|
|
|
|
double fheight = p.GetZ(GetCircumcenter(sp));
|
|
|
|
// If something went wrong with computing the height use the height
|
|
// of the first vertex as a workaround
|
|
if (double.IsNaN(fheight))
|
|
height = Convert.ToInt32(sp[0].z);
|
|
else
|
|
height = Convert.ToInt32(fheight);
|
|
}
|
|
|
|
private Vector2D GetCircumcenter(List<Vector3D> points)
|
|
{
|
|
double u_ray;
|
|
|
|
Line2D line1 = new Line2D(points[0], points[1]);
|
|
Line2D line2 = new Line2D(points[2], points[0]);
|
|
|
|
// Perpendicular bisectors
|
|
Line2D bisector1 = new Line2D(line1.GetCoordinatesAt(0.5f), line1.GetCoordinatesAt(0.5f) + line1.GetPerpendicular());
|
|
Line2D bisector2 = new Line2D(line2.GetCoordinatesAt(0.5f), line2.GetCoordinatesAt(0.5f) + line2.GetPerpendicular());
|
|
|
|
bisector1.GetIntersection(bisector2, out u_ray);
|
|
|
|
return bisector1.GetCoordinatesAt(u_ray);
|
|
}
|
|
|
|
public bool VerticesAreValid()
|
|
{
|
|
if (vertices.Count == 2 && vertices[0].Pos == vertices[1].Pos)
|
|
return false;
|
|
|
|
if (vertices.Count == 3)
|
|
{
|
|
double side = Line2D.GetSideOfLine(vertices[0].Pos, vertices[1].Pos, vertices[3].Pos);
|
|
|
|
if (side == 0.0f)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |