geometry drawing fixes

This commit is contained in:
codeimp 2008-05-08 12:04:20 +00:00
parent 3214ef4593
commit 51f57471c7
4 changed files with 268 additions and 103 deletions

View file

@ -135,6 +135,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
List<Vertex> newverts = new List<Vertex>();
List<Vertex> intersectverts = new List<Vertex>();
List<Linedef> newlines = new List<Linedef>();
List<Linedef> oldlines = new List<Linedef>(General.Map.Map.Linedefs);
List<Vertex> mergeverts = new List<Vertex>();
List<Vertex> nonmergeverts = new List<Vertex>(General.Map.Map.Vertices);
@ -182,7 +183,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
newlines.Add(ld);
// Should we split this line to merge with intersecting lines?
if(points[i - 1].stitch || points[i].stitch)
if(points[i - 1].stitch && points[i].stitch)
{
// Check if any other lines intersect this line
List<float> intersections = new List<float>();
@ -236,12 +237,103 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Join merge vertices so that overlapping vertices in the draw become one.
MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE);
// We prefer a closed polygon, because then we can determine the interior properly
// Check if the two ends of the polygon are closed
bool drawingclosed = false;
if(newlines.Count > 0)
{
// When not closed, we will try to find a path to close it
Linedef firstline = newlines[0];
Linedef lastline = newlines[newlines.Count - 1];
drawingclosed = (firstline.Start == lastline.End);
if(!drawingclosed)
{
// First and last vertex stitch with geometry?
if(points[0].stitch && points[points.Count - 1].stitch)
{
// Find out where they will stitch
Linedef l1 = MapSet.NearestLinedefRange(oldlines, firstline.Start.Position, MapSet.STITCH_DISTANCE);
Linedef l2 = MapSet.NearestLinedefRange(oldlines, lastline.End.Position, MapSet.STITCH_DISTANCE);
if((l1 != null) && (l2 != null))
{
List<LinedefSide> shortestpath = null;
// Same line?
if(l1 == l2)
{
// Then just connect the two
shortestpath = new List<LinedefSide>();
shortestpath.Add(new LinedefSide(l1, true));
}
else
{
// Find the shortest, closest path between these lines
List<List<LinedefSide>> paths = new List<List<LinedefSide>>(8);
paths.Add(SectorTools.FindClosestPath(l1, true, l2, true, true));
paths.Add(SectorTools.FindClosestPath(l1, true, l2, false, true));
paths.Add(SectorTools.FindClosestPath(l1, false, l2, true, true));
paths.Add(SectorTools.FindClosestPath(l1, false, l2, false, true));
paths.Add(SectorTools.FindClosestPath(l2, true, l1, true, true));
paths.Add(SectorTools.FindClosestPath(l2, true, l1, false, true));
paths.Add(SectorTools.FindClosestPath(l2, false, l1, true, true));
paths.Add(SectorTools.FindClosestPath(l2, false, l1, false, true));
foreach(List<LinedefSide> p in paths)
if((p != null) && ((shortestpath == null) || (p.Count < shortestpath.Count))) shortestpath = p;
}
// Found a path?
if(shortestpath != null)
{
// Go for all vertices in the path to make additional lines
v1 = firstline.Start;
for(int i = 1; i < shortestpath.Count; i++)
{
// Get the next position
Vector2D v2pos = shortestpath[i].Front ? shortestpath[i].Line.Start.Position : shortestpath[i].Line.End.Position;
// Make the new vertex
Vertex v2 = map.CreateVertex(v2pos);
v2.Marked = true;
mergeverts.Add(v2);
// Make the line
Linedef ld = map.CreateLinedef(v1, v2);
ld.Marked = true;
ld.Selected = true;
ld.ApplySidedFlags();
ld.UpdateCache();
newlines.Add(ld);
// Next
v1 = v2;
}
// Make the final line
Linedef lld = map.CreateLinedef(v1, lastline.End);
lld.Marked = true;
lld.Selected = true;
lld.ApplySidedFlags();
lld.UpdateCache();
newlines.Add(lld);
// Drawing is now closed
drawingclosed = true;
// Join merge vertices so that overlapping vertices in the draw become one.
MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE);
}
}
}
}
}
// Merge intersetion vertices with the new lines. This completes the
// self intersections for which splits were made above.
map.Update(true, false);
MapSet.SplitLinesByVertices(newlines, intersectverts, MapSet.STITCH_DISTANCE, null);
MapSet.SplitLinesByVertices(newlines, mergeverts, MapSet.STITCH_DISTANCE, null);
/***************************************************\
STEP 2: Merge the new geometry
\***************************************************/
@ -304,6 +396,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
STEP 3: Join and create new sectors
\***************************************************/
// The code below atempts to create sectors on the front sides of the drawn
// geometry and joins sectors on the back sides of the drawn geometry.
// This code does not change any geometry, it only makes/updates sidedefs.
bool[] frontsdone = new bool[newlines.Count];
bool[] backsdone = new bool[newlines.Count];
for(int i = 0; i < newlines.Count; i++)

View file

@ -274,12 +274,22 @@ namespace CodeImp.DoomBuilder.Geometry
/// When turnatends is true, the algorithm will continue at the other side of the
/// line when a dead end has been reached. Returns null when no path could be found.
/// </summary>
public static List<LinedefSide> FindClosestPath(Linedef start, bool front, bool turnatends)
public static List<LinedefSide> FindClosestPath(Linedef startline, bool startfront, bool turnatends)
{
return FindClosestPath(startline, startfront, startline, startfront, turnatends);
}
/// <summary>
/// This finds the closest path from the beginning of a line to the end of the line.
/// When turnatends is true, the algorithm will continue at the other side of the
/// line when a dead end has been reached. Returns null when no path could be found.
/// </summary>
public static List<LinedefSide> FindClosestPath(Linedef startline, bool startfront, Linedef endline, bool endfront, bool turnatends)
{
List<LinedefSide> path = new List<LinedefSide>();
Dictionary<Linedef, int> tracecount = new Dictionary<Linedef, int>();
Linedef nextline = start;
bool nextfront = front;
Linedef nextline = startline;
bool nextfront = startfront;
do
{
@ -332,8 +342,12 @@ namespace CodeImp.DoomBuilder.Geometry
}
// Continue as long as we have not reached the start yet
// or we have no next line to trace
while((path != null) && ((nextline != start) || (nextfront != front)));
while((path != null) && ((nextline != endline) || (nextfront != endfront)));
// If start and front are not the same, add the end to the list also
if((path != null) && ((startline != endline) || (startfront != endfront)))
path.Add(new LinedefSide(endline, endfront));
// Return path (null when trace failed)
return path;
}

View file

@ -563,6 +563,11 @@ namespace CodeImp.DoomBuilder.Map
public void Join(Linedef other)
{
Sector l1fs, l1bs, l2fs, l2bs;
bool l1was2s, l2was2s;
// Check which lines were 2 sided
l1was2s = ((other.Front != null) && (other.Back != null));
l2was2s = ((this.Front != null) && (this.Back != null));
// Get sector references
if(other.front != null) l1fs = other.front.Sector; else l1fs = null;
@ -570,118 +575,143 @@ namespace CodeImp.DoomBuilder.Map
if(this.front != null) l2fs = this.front.Sector; else l2fs = null;
if(this.back != null) l2bs = this.back.Sector; else l2bs = null;
// Compare front sectors
if(l1fs == l2fs)
// This line has no sidedefs?
if((l2fs == null) && (l2bs == null))
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, back);
// We have no sidedefs, so we have no influence
// Nothing to change on the other line
}
// Compare back sectors
else if(l1bs == l2bs)
// Other line has no sidedefs?
else if((l1fs == null) && (l1bs == null))
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
// Compare front and back
else if(l1fs == l2bs)
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
}
// Compare back and front
else if(l1bs == l2fs)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
}
else
{
// Other line single sided?
if(other.back == null)
// The other has no sidedefs, so it has no influence
// Copy my sidedefs to the other
if(this.Start == other.Start)
{
// This line with its back to the other?
if(this.start == other.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
else
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
}
}
// This line single sided?
if(this.back == null)
{
// Other line with its back to this?
if(other.start == this.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
else
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
}
JoinChangeSidedefs(other, true, front);
JoinChangeSidedefs(other, false, back);
}
else
{
// This line with its back to the other?
if(this.start == other.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
JoinChangeSidedefs(other, false, front);
JoinChangeSidedefs(other, true, back);
}
}
else
{
// Compare front sectors
if(l1fs == l2fs)
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
// Change sidedefs
JoinChangeSidedefs(other, true, back);
}
// Compare back sectors
else if(l1bs == l2bs)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
// Compare front and back
else if(l1fs == l2bs)
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
}
// Compare back and front
else if(l1bs == l2fs)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
}
else
{
// Other line single sided?
if(other.back == null)
{
// This line with its back to the other?
if(this.start == other.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
else
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
}
}
// This line single sided?
if(this.back == null)
{
// Other line with its back to this?
if(other.start == this.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
else
{
// Copy textures
if(other.front != null) other.front.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.back);
// Change sidedefs
JoinChangeSidedefs(other, true, front);
}
}
else
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// This line with its back to the other?
if(this.start == other.end)
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.front);
if(this.back != null) this.back.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
// Change sidedefs
JoinChangeSidedefs(other, false, front);
}
else
{
// Copy textures
if(other.back != null) other.back.AddTexturesTo(this.back);
if(this.front != null) this.front.AddTexturesTo(other.front);
// Change sidedefs
JoinChangeSidedefs(other, false, back);
}
}
}
}
// If either of the two lines was selected, keep the other selected
if(this.selected) other.selected = true;
if(this.marked) other.marked = true;
@ -689,6 +719,10 @@ namespace CodeImp.DoomBuilder.Map
// Apply single/double sided flags
other.ApplySidedFlags();
// Remove unneeded textures
if(other.front != null) other.front.RemoveUnneededTextures(!(l1was2s && l2was2s));
if(other.back != null) other.back.RemoveUnneededTextures(!(l1was2s && l2was2s));
// I got killed by the other.
this.Dispose();
}

View file

@ -237,6 +237,28 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Methods
// This removes textures that are not required
public void RemoveUnneededTextures(bool removemiddle)
{
if(!HighRequired())
{
this.texnamehigh = "-";
this.longtexnamehigh = map.EmptyLongName;
}
if(!MiddleRequired() && removemiddle)
{
this.texnamemid = "-";
this.longtexnamemid = map.EmptyLongName;
}
if(!LowRequired())
{
this.texnamelow = "-";
this.longtexnamelow = map.EmptyLongName;
}
}
// This checks if a texture is required
public bool HighRequired()
{