diff --git a/Source/Builder.csproj b/Source/Builder.csproj
index a3ba0fdf..36e56856 100644
--- a/Source/Builder.csproj
+++ b/Source/Builder.csproj
@@ -114,6 +114,7 @@
+
diff --git a/Source/BuilderModes/Testing/TriangulatorMode.cs b/Source/BuilderModes/Testing/TriangulatorMode.cs
index ba0ba412..f5880025 100644
--- a/Source/BuilderModes/Testing/TriangulatorMode.cs
+++ b/Source/BuilderModes/Testing/TriangulatorMode.cs
@@ -56,7 +56,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
private Sector highlighted;
// Labels
- private ICollection labelpos;
+ private ICollection labelpos;
#endregion
@@ -140,14 +140,14 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
renderer.PlotSector(highlighted, General.Colors.Highlight);
renderer.Finish();
}
-
+
// Render labels
if(renderer.StartOverlay(true))
{
if(labelpos != null)
{
- foreach(Vector2D v in labelpos)
- renderer.RenderRectangleFilled(new RectangleF(v.x - 5, v.y - 5, 10, 10), General.Colors.Indication, true);
+ foreach(LabelPositionInfo lb in labelpos)
+ renderer.RenderRectangleFilled(new RectangleF(lb.position.x - lb.radius / 2, lb.position.y - lb.radius / 2, lb.radius, lb.radius), General.Colors.Indication, true);
}
renderer.Finish();
@@ -181,20 +181,20 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted, General.Colors.Highlight);
-
+
// Done
renderer.Finish();
}
-
+
// Render labels
if(renderer.StartOverlay(true))
{
if(labelpos != null)
{
- foreach(Vector2D v in labelpos)
- renderer.RenderRectangleFilled(new RectangleF(v.x - 5, v.y - 5, 10, 10), General.Colors.Indication, true);
+ foreach(LabelPositionInfo lb in labelpos)
+ renderer.RenderRectangleFilled(new RectangleF(lb.position.x - lb.radius / 2, lb.position.y - lb.radius / 2, lb.radius, lb.radius), General.Colors.Indication, true);
}
-
+
renderer.Finish();
}
@@ -293,6 +293,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
ICollection selected;
TriangleList triangles;
+ PixelColor c;
base.OnMouseUp(e);
@@ -301,22 +302,30 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Get a triangulator and bind events
Triangulation t = Triangulation.Create(highlighted);
-
+
// Start with a clear display
if(renderer.StartPlotter(true))
{
// Render lines and vertices
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
-
- // Go for all triangle vertices
+
+ // Go for all triangle vertices to render the inside lines only
for(int i = 0; i < t.Vertices.Count; i += 3)
{
- renderer.PlotLine(t.Vertices[i + 0], t.Vertices[i + 1], General.Colors.Selection);
- renderer.PlotLine(t.Vertices[i + 1], t.Vertices[i + 2], General.Colors.Selection);
- renderer.PlotLine(t.Vertices[i + 2], t.Vertices[i + 0], General.Colors.Selection);
+ if(t.Sidedefs[i + 0] == null) renderer.PlotLine(t.Vertices[i + 0], t.Vertices[i + 1], PixelColor.FromColor(Color.DeepSkyBlue));
+ if(t.Sidedefs[i + 1] == null) renderer.PlotLine(t.Vertices[i + 1], t.Vertices[i + 2], PixelColor.FromColor(Color.DeepSkyBlue));
+ if(t.Sidedefs[i + 2] == null) renderer.PlotLine(t.Vertices[i + 2], t.Vertices[i + 0], PixelColor.FromColor(Color.DeepSkyBlue));
}
-
+
+ // Go for all triangle vertices to renderthe outside lines only
+ for(int i = 0; i < t.Vertices.Count; i += 3)
+ {
+ if(t.Sidedefs[i + 0] != null) renderer.PlotLine(t.Vertices[i + 0], t.Vertices[i + 1], PixelColor.FromColor(Color.Red));
+ if(t.Sidedefs[i + 1] != null) renderer.PlotLine(t.Vertices[i + 1], t.Vertices[i + 2], PixelColor.FromColor(Color.Red));
+ if(t.Sidedefs[i + 2] != null) renderer.PlotLine(t.Vertices[i + 2], t.Vertices[i + 0], PixelColor.FromColor(Color.Red));
+ }
+
// Done
renderer.Finish();
renderer.Present();
diff --git a/Source/Geometry/LabelPositionInfo.cs b/Source/Geometry/LabelPositionInfo.cs
new file mode 100644
index 00000000..186af49e
--- /dev/null
+++ b/Source/Geometry/LabelPositionInfo.cs
@@ -0,0 +1,42 @@
+
+#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;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.Geometry
+{
+ public struct LabelPositionInfo
+ {
+ // Members
+ public Vector2D position;
+ public float radius;
+
+ // Constructor
+ public LabelPositionInfo(Vector2D position, float radius)
+ {
+ this.position = position;
+ this.radius = radius;
+ }
+ }
+}
diff --git a/Source/Geometry/Tools.cs b/Source/Geometry/Tools.cs
index cb15c213..5cda7d46 100644
--- a/Source/Geometry/Tools.cs
+++ b/Source/Geometry/Tools.cs
@@ -622,9 +622,9 @@ namespace CodeImp.DoomBuilder.Geometry
#region ================== Sector Labels
// This finds the ideal label positions for a sector
- public static ICollection FindLabelPositions(Sector s)
+ public static List FindLabelPositions(Sector s)
{
- List positions = new List(2);
+ List positions = new List(2);
int islandoffset = 0;
// Do we have a triangulation?
@@ -632,10 +632,10 @@ namespace CodeImp.DoomBuilder.Geometry
if(triangles != null)
{
// Go for all islands
- for(int island = 0; island < triangles.IslandVertices.Count; island++)
+ for(int i = 0; i < triangles.IslandVertices.Count; i++)
{
- Dictionary sides = new Dictionary(triangles.IslandVertices[island] >> 1);
- List candidatelines = new List(triangles.IslandVertices[island] >> 1);
+ Dictionary sides = new Dictionary(triangles.IslandVertices[i] >> 1);
+ List candidatepositions = new List(triangles.IslandVertices[i] >> 1);
float founddistance = float.MinValue;
Vector2D foundposition = new Vector2D();
float minx = float.MaxValue;
@@ -646,24 +646,26 @@ namespace CodeImp.DoomBuilder.Geometry
// Make candidate lines that are not along sidedefs
// We do this before testing the candidate against the sidedefs so that
// we can collect the relevant sidedefs first in the same run
- for(int i = 0; i < triangles.IslandVertices[island]; i += 3)
+ for(int t = 0; t < triangles.IslandVertices[i]; t += 3)
{
- Vector2D v1 = triangles.Vertices[islandoffset + i + 2];
- for(int k = 0; k < 3; k++)
+ int triangleoffset = islandoffset + t;
+ Vector2D v1 = triangles.Vertices[triangleoffset + 2];
+ Sidedef sd = triangles.Sidedefs[triangleoffset + 2];
+ for(int v = 0; v < 3; v++)
{
- Vector2D v2 = triangles.Vertices[islandoffset + i + k];
- Sidedef sd = triangles.Sidedefs[islandoffset + i + k];
+ Vector2D v2 = triangles.Vertices[triangleoffset + v];
// Not along a sidedef? Then this line is across the sector
// and guaranteed to be inside the sector!
if(sd == null)
{
// Make the line
- candidatelines.Add(new Line2D(v1, v2));
+ candidatepositions.Add(v1 + (v2 - v1) * 0.5f);
}
else
{
- // This sidedefs is part of this island and must be checked against
+ // This sidedefs is part of this island and must be checked
+ // so add it to the dictionary
sides[sd] = sd.Line;
}
@@ -674,67 +676,68 @@ namespace CodeImp.DoomBuilder.Geometry
maxy = Math.Max(maxy, v1.y);
// Next
+ sd = triangles.Sidedefs[triangleoffset + v];
v1 = v2;
}
}
// Any candidate lines found at all?
- if(candidatelines.Count > 0)
+ if(candidatepositions.Count > 0)
{
// Start with the first line
- foreach(Line2D sourceline in candidatelines)
+ foreach(Vector2D candidatepos in candidatepositions)
{
- // Get center point
- Vector2D candidateposition = sourceline.GetCoordinatesAt(0.5f);
-
// Check distance against other lines
float smallestdist = int.MaxValue;
foreach(KeyValuePair sd in sides)
{
// Check the distance
- float distance = sd.Value.DistanceToSq(candidateposition, true);
+ float distance = sd.Value.DistanceToSq(candidatepos, true);
smallestdist = Math.Min(smallestdist, distance);
}
// Keep this candidate if it is better than previous
if(smallestdist > founddistance)
{
- foundposition = candidateposition;
+ foundposition = candidatepos;
founddistance = smallestdist;
}
}
// No cceptable line found, just use the first!
- positions.Add(foundposition);
+ positions.Add(new LabelPositionInfo(foundposition, (float)Math.Sqrt(founddistance)));
}
else
{
// No candidate lines found.
// Check to see if the island is a triangle
- if(triangles.IslandVertices[island] == 3)
+ if(triangles.IslandVertices[i] == 3)
{
// Use the center of the triangle
- Vector2D v = triangles.Vertices[islandoffset] + triangles.Vertices[islandoffset + 1] + triangles.Vertices[islandoffset + 2];
- positions.Add(v / 3.0f);
+ // TODO: Use the 'incenter' instead, see http://mathworld.wolfram.com/Incenter.html
+ Vector2D v = (triangles.Vertices[islandoffset] + triangles.Vertices[islandoffset + 1] + triangles.Vertices[islandoffset + 2]) / 3.0f;
+ float d = Line2D.GetDistanceToLineSq(triangles.Vertices[islandoffset], triangles.Vertices[islandoffset + 1], v, false);
+ d = Math.Min(d, Line2D.GetDistanceToLineSq(triangles.Vertices[islandoffset + 1], triangles.Vertices[islandoffset + 2], v, false));
+ d = Math.Min(d, Line2D.GetDistanceToLineSq(triangles.Vertices[islandoffset + 2], triangles.Vertices[islandoffset], v, false));
+ positions.Add(new LabelPositionInfo(v, (float)Math.Sqrt(d)));
}
else
{
// Use the center of this island.
- positions.Add(new Vector2D(minx + (maxx - minx) * 0.5f, miny + (maxy - miny) * 0.5f));
+ float d = Math.Min((maxx - minx) * 0.5f, (maxy - miny) * 0.5f);
+ positions.Add(new LabelPositionInfo(new Vector2D(minx + (maxx - minx) * 0.5f, miny + (maxy - miny) * 0.5f), d));
}
}
// Done with this island
- islandoffset += triangles.IslandVertices[island];
+ islandoffset += triangles.IslandVertices[i];
}
}
else
{
- // No triangulation was made. Just return the center point.
- //RectangleF rect = s.CreateBBox();
- //return new Vector2D(rect.X + (rect.Width * 0.5f), rect.Y + (rect.Height * 0.5f));
- positions.Add(new Vector2D());
+ // No triangulation was made. FAIL!
+ General.Fail("No triangulation exists for sector " + s, "Triangulation is required to create label positions for a sector.");
}
// Done
diff --git a/Source/Geometry/Triangulation.cs b/Source/Geometry/Triangulation.cs
index d9785104..cdfa9553 100644
--- a/Source/Geometry/Triangulation.cs
+++ b/Source/Geometry/Triangulation.cs
@@ -501,16 +501,18 @@ namespace CodeImp.DoomBuilder.Geometry
v1 = v2;
v2 = v2.Next;
}
-
+
// Found anything?
if(insertbefore != null)
{
+ Sidedef sd = (insertbefore.Previous == null) ? insertbefore.List.Last.Value.Sidedef : insertbefore.Previous.Value.Sidedef;
+
// Find the position where we have to split the outer polygon
split = new EarClipVertex(starttoright.GetCoordinatesAt(foundu), null);
-
+
// Insert manual split vertices
- p.AddBefore(insertbefore, new EarClipVertex(split, null));
-
+ p.AddBefore(insertbefore, new EarClipVertex(split, sd));
+
// Start inserting from the start (do I make sense this time?)
v1 = start;
do
@@ -520,10 +522,9 @@ namespace CodeImp.DoomBuilder.Geometry
if(v1.Next != null) v1 = v1.Next; else v1 = v1.List.First;
}
while(v1 != start);
-
+
// Insert manual split vertices
- Sidedef sd = (insertbefore.Previous == null) ? insertbefore.List.Last.Value.Sidedef : insertbefore.Previous.Value.Sidedef;
- p.AddBefore(insertbefore, new EarClipVertex(start.Value, null));
+ p.AddBefore(insertbefore, new EarClipVertex(start.Value, sd));
p.AddBefore(insertbefore, new EarClipVertex(split, sd));
}
}
@@ -696,7 +697,7 @@ namespace CodeImp.DoomBuilder.Geometry
sidedefslist.Add(triangle[1].Sidedef);
verticeslist.Add(triangle[2].Position);
if(!last) sidedefslist.Add(null); else sidedefslist.Add(triangle[2].Sidedef);
-
+
// Modify the first earclipvertex of this triangle, it no longer lies along a sidedef
triangle[0].Sidedef = null;
}
diff --git a/Source/Map/Sector.cs b/Source/Map/Sector.cs
index 005fde0c..17399808 100644
--- a/Source/Map/Sector.cs
+++ b/Source/Map/Sector.cs
@@ -25,6 +25,7 @@ using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Geometry;
using System.Drawing;
using CodeImp.DoomBuilder.Rendering;
+using System.Collections.ObjectModel;
#endregion
@@ -74,7 +75,8 @@ namespace CodeImp.DoomBuilder.Map
private bool triangulationneeded;
private Triangulation triangles;
private FlatVertex[] flatvertices;
-
+ private ReadOnlyCollection labels;
+
#endregion
#region ================== Properties
@@ -98,7 +100,8 @@ namespace CodeImp.DoomBuilder.Map
public Sector Clone { get { return clone; } set { clone = value; } }
public Triangulation Triangles { get { return triangles; } }
public FlatVertex[] FlatVertices { get { return flatvertices; } }
-
+ public ReadOnlyCollection Labels { get { return labels; } }
+
#endregion
#region ================== Constructor / Disposer
@@ -201,13 +204,13 @@ namespace CodeImp.DoomBuilder.Map
}
}
}
-
+
// This attaches a thing and returns the listitem
public LinkedListNode AttachThing(Thing t) { return things.AddLast(t); }
-
+
// This detaches a thing
public void DetachThing(LinkedListNode l) { if(!isdisposed) things.Remove(l); }
-
+
// This updates the sector when changes have been made
public void UpdateCache()
{
@@ -219,6 +222,9 @@ namespace CodeImp.DoomBuilder.Map
{
// Triangulate sector
triangles = Triangulation.Create(this);
+
+ // Make label positions
+ labels = Array.AsReadOnly(Tools.FindLabelPositions(this).ToArray());
}
// Brightness color (alpha is opaque)