private TreeNode BuildPlanePortalLines(SectorGroup sectorgroup, string name, List<int> tags)
		{
			TreeNode node = new TreeNode(name + " Linedefs", 2, 2);
			List<Linedef> linedefs = new List<Linedef>();

			foreach (Sector s in sectorgroup.Sectors)
			{
				foreach (Sidedef sd in s.Sidedefs)
				{
					if (!linedefs.Contains(sd.Line) && (sd.Line.Action == 385 || (sd.Line.Action >= 358 && sd.Line.Action <= 361)) && tags.Contains(sd.Line.Tag))
						linedefs.Add(sd.Line);
				}
			}

			foreach (Linedef ld in linedefs.OrderBy(o => o.Action))
			{
				NodeInfo info = new NodeInfo(ld);
				LinedefActionInfo ldai = General.Map.Config.GetLinedefActionInfo(ld.Action);
				string ldname = string.Format("Ld {0}: {1} - {2}", ld.Index, ldai.Index, ldai.Name);
				node.Nodes.Add(new TreeNode(ldname, 2, 2) { Tag = info });
			}

			return node;
		}
		private ContextMenuStrip CreateContextMenu(SectorGroup a, SectorGroup b, bool geometrymatches, bool topspecialmatch, bool bottomspecialmatch)
		{
			ContextMenuStrip cms = new ContextMenuStrip();
			cms.ItemClicked += SelectUnmatchedLinedefs;

			ToolStripMenuItem option;

			if (!geometrymatches)
			{
				option = new ToolStripMenuItem("Select all unmatched linedefs");
				option.Tag = new ContextMenuInfo(a, b, UnmatchingLinedefsType.Bottom | UnmatchingLinedefsType.Top);
				cms.Items.Add(option);

				option = new ToolStripMenuItem("Select unmatched linedefs of top");
				option.Tag = new ContextMenuInfo(a, b, UnmatchingLinedefsType.Top);
				cms.Items.Add(option);

				option = new ToolStripMenuItem("Select unmatched linedefs of bottom");
				option.Tag = new ContextMenuInfo(a, b, UnmatchingLinedefsType.Bottom);
				cms.Items.Add(option);
			}

			if (!topspecialmatch || !bottomspecialmatch)
			{
				if (!geometrymatches)
					cms.Items.Add(new ToolStripSeparator());

				if (!topspecialmatch)
				{
					option = new ToolStripMenuItem("Select unmatched special linedefs of top");
					option.Tag = new ContextMenuInfo(a, b, UnmatchingLinedefsType.SpecialsTop);
					cms.Items.Add(option);
				}

				if (!bottomspecialmatch)
				{
					option = new ToolStripMenuItem("Select unmatched special linedefs of bottom");
					option.Tag = new ContextMenuInfo(a, b, UnmatchingLinedefsType.SpecialsBottom);
					cms.Items.Add(option);
				}
			}

			return cms;
		}
		private TreeNode BuildPlanePortalSectors(SectorGroup sectorgroup, string name)
		{
			NodeInfo info = new NodeInfo(sectorgroup);
			TreeNode node = new TreeNode(name + " Sectors", 0, 0) { Tag = info };

			foreach (Sector s in sectorgroup.Sectors.OrderBy(o => o.Index))
			{
				info = new NodeInfo(s);
				node.Nodes.Add(new TreeNode(s.ToString(), 0, 0) { Tag = info });
			}

			return node;
		}
		public static List<Linedef> GetUnmatchingLinedefs(SectorGroup a, SectorGroup b, UnmatchingLinedefsType type)
		{
			List<Linedef> unmatching = new List<Linedef>();
			Vector2D offset = b.BBAnchor - a.BBAnchor;

			if ((type & UnmatchingLinedefsType.Top) == UnmatchingLinedefsType.Top)
			{
				offset = SectorGroup.GetOffset(a, b);

				foreach (Linedef ld in b.Linedefs)
				{
					bool matches = false;

					foreach (Line2D line in a.Lines)
					{
						float d1 = line.GetDistanceToLine(ld.Start.Position - offset, true);
						float d2 = line.GetDistanceToLine(ld.End.Position - offset, true);

						if ((d1 >= -float.Epsilon && d1 <= float.Epsilon) && (d2 >= -float.Epsilon && d2 <= float.Epsilon))
						{
							matches = true;
							break;
						}
					}

					if (!matches)
						unmatching.Add(ld);
				}
			}

			if ((type & UnmatchingLinedefsType.Bottom) == UnmatchingLinedefsType.Bottom)
			{
				offset = SectorGroup.GetOffset(a, b);

				foreach (Linedef ld in a.Linedefs)
				{
					bool matches = false;

					foreach (Line2D line in b.Lines)
					{
						float d1 = line.GetDistanceToLine(ld.Start.Position + offset, true);
						float d2 = line.GetDistanceToLine(ld.End.Position + offset, true);

						if ((d1 >= -float.Epsilon && d1 <= float.Epsilon) && (d2 >= -float.Epsilon && d2 <= float.Epsilon))
						{
							matches = true;
							break;
						}
					}

					if (!matches)
						unmatching.Add(ld);
				}
			}

			if ((type & UnmatchingLinedefsType.SpecialsTop) == UnmatchingLinedefsType.SpecialsTop)
			{
				SectorGroup.TopSpecialsMatch(a, b, out unmatching);
			}

			if ((type & UnmatchingLinedefsType.SpecialsBottom) == UnmatchingLinedefsType.SpecialsBottom)
			{
				SectorGroup.BottomSpecialsMatch(a, b, out unmatching);
			}

			return unmatching;
		}
		public static Vector2D GetOffset(SectorGroup a, SectorGroup b)
		{
			Linedef ld1 = null;
			Linedef ld2 = null;
			Vector2D offset = new Vector2D(0, 0);

			ld1 = a.SpecialLinedefs.FirstOrDefault(o => o.Action == 360);
			ld2 = b.SpecialLinedefs.FirstOrDefault(o => o.Action == 358);

			if (ld1 == null || ld2 == null)
			{
				ld1 = b.SpecialLinedefs.FirstOrDefault(o => o.Action == 360);
				ld2 = a.SpecialLinedefs.FirstOrDefault(o => o.Action == 358);
			}

			if (ld1 == null || ld2 == null)
				throw new Exception("Line specials are missing");

			if (ld1.Angle == ld2.Angle)
				return new Vector2D(ld2.Start.Position - ld1.Start.Position);
			else
				return new Vector2D(ld2.Start.Position - ld1.End.Position);
		}
		public static bool BottomSpecialsMatch(SectorGroup a, SectorGroup b, out List<Linedef> unmatchedlinedefs)
		{
			Linedef ld1 = a.Linedefs.FirstOrDefault(o => o.Action == 360);
			Linedef ld2 = b.Linedefs.FirstOrDefault(o => o.Action == 358);

			unmatchedlinedefs = new List<Linedef>();

			if (ld1 == null || ld2 == null)
				return false;

			if (ld1.Length != ld2.Length)
			{
				unmatchedlinedefs.AddRange(new Linedef[] { ld1, ld2 });
				return false;
			}

			float difference = Angle2D.Difference(ld1.Angle, ld2.Angle);

			if (difference != 0f && difference != Angle2D.PI)
			{
				unmatchedlinedefs.AddRange(new Linedef[] { ld1, ld2 });
				return false;
			}

			return true;
		}
		public static List<Linedef> GetUnmatchingLinedefs(SectorGroup a, SectorGroup b)
		{
			return GetUnmatchingLinedefs(a, b, UnmatchingLinedefsType.Bottom | UnmatchingLinedefsType.Top);
		}
		public static bool GeometryMatches(SectorGroup a, SectorGroup b)
		{
			Vector2D offset = b.BBAnchor - a.BBAnchor;

			foreach (Line2D l in a.Lines)
			{
				if (b.Lines.Count(ol => ol.v1 == l.v1+offset && ol.v2 == l.v2+offset) == 0)
					return false;
			}

			return true;
		}
		public static bool BottomSpecialsMatch(SectorGroup a, SectorGroup b)
		{
			List<Linedef> temp;
			return BottomSpecialsMatch(a, b, out temp);
		}
Exemple #10
0
		public NodeInfo(SectorGroup sg)
		{
			type = NodeInfoType.SECTOR_GROUP;
			sectorgroup = sg;
		}
		// Finds a sector group by action and tag
		private SectorGroup GetCorrespondingSectorGroup(int action, SectorGroup source, Dictionary<Linedef, SectorGroup> sectorgroups, List<SectorGroup> checkedsectorgroups)
		{
			int tag = -1;

			foreach (Sector s in source.Sectors)
				foreach (Sidedef sd in s.Sidedefs)
					if (sd.Line.Action == action)
						tag = sd.Line.Tag;

			if (tag == -1)
				return null;

			foreach (KeyValuePair<Linedef, SectorGroup> entry in sectorgroups)
				if (!checkedsectorgroups.Contains(entry.Value))
					foreach (Sector s in entry.Value.Sectors)
						if (s.Tag == tag)
							return entry.Value;

			return null;
		}
		public List<List<SectorGroup>> GetPlanePortals()
		{
			Dictionary<int, List<Sector>> taglookup = new Dictionary<int, List<Sector>>();
			Dictionary<Linedef, SectorGroup> sectorgroups = new Dictionary<Linedef, SectorGroup>();
			List<Linedef> applytofrontlines = new List<Linedef>();
			List<List<SectorGroup>> portalgroups = new List<List<SectorGroup>>();
			List<SectorGroup> checkedsectorgroups = new List<SectorGroup>();

			// Create a lookup dictionary, so we only have to crawl through all sectors once
			foreach (Sector s in General.Map.Map.Sectors)
			{
				if (!taglookup.ContainsKey(s.Tag))
					taglookup.Add(s.Tag, new List<Sector>());

				taglookup[s.Tag].Add(s);
			}

			// Go through all linedefs
			foreach (Linedef ld in General.Map.Map.Linedefs)
			{
				if (ld.Action == 358 || ld.Action == 359) // Actions: Apply linked portal to like-tagged ceilings/floors
				{
					SectorGroup sg = new SectorGroup();

					sg.Type = ld.Action == 358 ? SectorGroupType.Ceiling : SectorGroupType.Floor;

					if (taglookup.ContainsKey(ld.Tag))
						foreach (Sector s in taglookup[ld.Tag])
							sg.Sectors.Add(s);

					sectorgroups.Add(ld, sg);
				}
				else if (ld.Action == 385) // Action: Apply portal to front sector
				{
					// the sector group this line references might not exist yet, so we have
					// to store the line and check it later
					applytofrontlines.Add(ld);
				}
			}

			// Check lines again, that apply a portal to the front sector
			foreach (Linedef ld in applytofrontlines)
			{
				// Find the sector group his front sector of the line belongs to
				foreach (KeyValuePair<Linedef, SectorGroup> entry in sectorgroups)
				{
					// Found the sector group, so add the front sector to it
					if (entry.Key.Tag == ld.Tag)
					{
						entry.Value.Sectors.Add(ld.Front.Sector);
						break;
					}
				}
			}

			// Update the sector groups, but set the type to what the map author intended,
			// not what it really is
			foreach (KeyValuePair<Linedef, SectorGroup> entry in sectorgroups)
			{
				entry.Value.Update();
				entry.Value.Type = entry.Key.Action == 358 ? SectorGroupType.Ceiling : SectorGroupType.Floor;
			}

			// Form portal groups from two sector groups. Each portal group has a top and a bottom sector group
			foreach (KeyValuePair<Linedef, SectorGroup> entry in sectorgroups)
			{
				if (checkedsectorgroups.Contains(entry.Value))
					continue;

				if (entry.Key.Action == 358) // Actions: Apply linked portal to like-tagged ceilings; this is a top sector group
				{
					List<SectorGroup> portalgroup = new List<SectorGroup>() {
						entry.Value,
						GetCorrespondingSectorGroup(359, entry.Value, sectorgroups, checkedsectorgroups)
					};

					checkedsectorgroups.Add(portalgroup[0]);
					checkedsectorgroups.Add(portalgroup[1]);
					portalgroups.Add(portalgroup);
				}
				else if (entry.Key.Action == 359) // Actions: Apply linked portal to like-tagged floors; this is a bottom sector group
				{
					List<SectorGroup> portalgroup = new List<SectorGroup>() {
						GetCorrespondingSectorGroup(358, entry.Value, sectorgroups, checkedsectorgroups),
						entry.Value
					};

					checkedsectorgroups.Add(portalgroup[0]);
					checkedsectorgroups.Add(portalgroup[1]);
					portalgroups.Add(portalgroup);
				}
			}

			return portalgroups;
		}
		private bool GetLinedefPair(SectorGroup sga, SectorGroup sgb, out Linedef la, out Linedef lb)
		{
			Vector2D offset = sgb.BBAnchor - sga.BBAnchor;
			List<Sidedef> sidedefs = new List<Sidedef>();

			la = lb = null;

			foreach (Sector s in sga.Sectors)
			{
				foreach (Sidedef sd in s.Sidedefs.Where(sdx => sdx.Line.Action == 0 && sdx.Line.Tag == 0).OrderByDescending(sdx => sdx.Line.Length))
					if (!sidedefs.Contains(sd))
						sidedefs.Add(sd);
			}

			// Get all sidedefs of sector a without action and tag, ordered by their length
			foreach (Sidedef sda in sidedefs)
			{
				foreach (Sector s in sgb.Sectors)
				{
					try
					{
						
						// Sidedef sdb = s.Sidedefs.Where(sd => (sd.Line.Start.Position == sda.Line.Start.Position + offset && sd.Line.End.Position == sda.Line.End.Position + offset) || (sd.Line.Start.Position == sda.Line.End.Position + offset && sd.Line.End.Position == sda.Line.Start.Position + offset)).First();
						var x = s.Sidedefs.Where(sd => (sd.Line.Start.Position == sda.Line.Start.Position + offset && sd.Line.End.Position == sda.Line.End.Position + offset) || (sd.Line.Start.Position == sda.Line.End.Position + offset && sd.Line.End.Position == sda.Line.Start.Position + offset));

						Sidedef sdb = x.First();

						if (sdb.Line.Action == 0 && sdb.Line.Tag == 0)
						{
							la = sda.Line;
							lb = sdb.Line;

							return true;
						}
					}
					catch (Exception e) { }
				}
			}

			return false;
		}
		// Creates groups of sectors that are connected to each other
		private List<SectorGroup> CreateSectorGroups(List<Sector> sectors)
		{
			List<SectorGroup> groups = new List<SectorGroup>();

			while (sectors.Count > 0)
			{
				SectorGroup sg = new SectorGroup();
				List<Sector> sectorstocheck = new List<Sector>();

				sectorstocheck.Add(sectors[0]);
				sectors.Remove(sectorstocheck[0]);

				while (sectorstocheck.Count > 0)
				{
					foreach (Sidedef sd in sectorstocheck[0].Sidedefs)
					{
						if (sectors.Contains(sd.Sector) && !sg.Sectors.Contains(sd.Sector))
							sectorstocheck.Add(sd.Sector);

						if (sd.Other != null && sectors.Contains(sd.Other.Sector) && !sg.Sectors.Contains(sd.Other.Sector))
							sectorstocheck.Add(sd.Other.Sector);
					}

					if (!sg.Sectors.Contains(sectorstocheck[0]))
						sg.Sectors.Add(sectorstocheck[0]);

					sectors.Remove(sectorstocheck[0]);
					sectorstocheck.RemoveAt(0);
				}

				sg.Update();

				groups.Add(sg);
			}

			return groups.OrderBy(g => g.Sectors[0].FloorHeight).ToList();
		}