more on geometry drawing

This commit is contained in:
codeimp 2008-05-05 21:38:52 +00:00
parent 88d1be35cc
commit 87ca45f93d
4 changed files with 108 additions and 72 deletions

View file

@ -95,7 +95,7 @@
<Compile Include="Geometry\Angle2D.cs" />
<Compile Include="Geometry\LinedefsTracePath.cs" />
<Compile Include="Geometry\LinedefAngleSorter.cs" />
<Compile Include="Geometry\SectorMaker.cs" />
<Compile Include="Geometry\SectorTools.cs" />
<Compile Include="Geometry\Triangulator.cs" />
<Compile Include="Geometry\EarClipVertex.cs" />
<Compile Include="Geometry\Line2D.cs" />

View file

@ -136,7 +136,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
List<Linedef> newlines = new List<Linedef>();
List<Vertex> mergeverts = new List<Vertex>();
List<Vertex> nonmergeverts = new List<Vertex>(General.Map.Map.Vertices);
MapSet map = General.Map.Map;
base.Disengage();
@ -149,7 +149,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Make undo for the draw
General.Map.UndoRedo.CreateUndo("line draw", UndoGroup.None, 0);
// STEP 1: Create the new geometry
/***************************************************\
STEP 1: Create the new geometry
\***************************************************/
// Make first vertex
Vertex v1 = map.CreateVertex((int)points[0].pos.x, (int)points[0].pos.y);
@ -223,18 +225,29 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
v1 = v2;
}
// STEP 2: Merge the new geometry
/***************************************************\
STEP 2: Merge the new geometry
\***************************************************/
// Mark our new vertices that need to merge and merge them with themselves
foreach(Vertex v in mergeverts) v.Marked = true;
MapSet.JoinVertices(mergeverts, mergeverts, true, General.Settings.StitchDistance);
// Perform standard geometry stitching between new and existing geometry
// The marked vertices indicate the new geometry
map.StitchGeometry();
// Re-find our new lines, because they have been merged with the other geometry
// Find our new lines again, because they have been merged with the other geometry
// but their Marked property is copied where they have joined!
newlines = map.GetMarkedLinedefs(true);
// Split the new lines with the new vertices so that self-intersecting draws also work
MapSet.SplitLinesByVertices(newlines, mergeverts, General.Settings.StitchDistance, null);
// STEP 3: Make sectors where possible
/***************************************************\
STEP 3: Join and create new sectors
\***************************************************/
bool[] frontsdone = new bool[newlines.Count];
bool[] backsdone = new bool[newlines.Count];
for(int i = 0; i < newlines.Count; i++)
@ -244,11 +257,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Front not marked as done?
if(!frontsdone[i])
{
// Make sector here
SectorMaker maker = new SectorMaker();
Sector newsector = maker.MakeAt(ld, true);
if(newsector != null)
// Find a way to create a sector here
List<LinedefSide> sectorlines = SectorTools.FindPotentialSectorAt(ld, true);
if(sectorlines != null)
{
// Make the new sector
Sector newsector = SectorTools.MakeSector(sectorlines);
// Go for all sidedefs in this new sector
foreach(Sidedef sd in newsector.Sidedefs)
{
@ -269,23 +284,46 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Back not marked as done?
if(!backsdone[i])
{
// Make sector here
SectorMaker maker = new SectorMaker();
Sector newsector = maker.MakeAt(ld, false);
if(newsector != null)
// Find a way to create a sector here
List<LinedefSide> sectorlines = SectorTools.FindPotentialSectorAt(ld, false);
if(sectorlines != null)
{
// Go for all sidedefs in this new sector
foreach(Sidedef sd in newsector.Sidedefs)
// We don't always want to create a new sector on the back sides
// So first check if any of the surrounding lines originally have sidedefs
Sidedef joinsidedef = null;
foreach(LinedefSide ls in sectorlines)
{
// Side matches with a side of our new lines?
int lineindex = newlines.IndexOf(sd.Line);
if(lineindex > -1)
if(ls.Front && (ls.Line.Front != null))
{
// Mark this side as done
if(sd.IsFront)
frontsdone[lineindex] = true;
else
backsdone[lineindex] = true;
joinsidedef = ls.Line.Front;
break;
}
else if(!ls.Front && (ls.Line.Back != null))
{
joinsidedef = ls.Line.Back;
break;
}
}
// Join?
if(joinsidedef != null)
{
// Join the new sector
Sector newsector = SectorTools.JoinSector(sectorlines, joinsidedef);
// Go for all sidedefs in this new sector
foreach(Sidedef sd in newsector.Sidedefs)
{
// Side matches with a side of our new lines?
int lineindex = newlines.IndexOf(sd.Line);
if(lineindex > -1)
{
// Mark this side as done
if(sd.IsFront)
frontsdone[lineindex] = true;
else
backsdone[lineindex] = true;
}
}
}
}

View file

@ -35,77 +35,47 @@ namespace CodeImp.DoomBuilder.Geometry
/// This makes a sector from all surrounding lines from a given coordinate.
/// Automatically finds the sidedef/sector properties from surrounding sectors/sidedefs.
/// </summary>
public class SectorMaker
public static class SectorTools
{
#region ================== Constants
#endregion
#region ================== Variables
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Destructor
#region ================== Pathfinding
/// <summary>
/// This makes a sector from all surrounding lines from a given coordinate.
/// Automatically finds the sidedef/sector properties from surrounding sectors/sidedefs.
/// This finds a potential sector at the given coordinates,
/// or returns null when a sector is not possible there.
/// </summary>
public SectorMaker()
{
// Initialize
// We have no destructor
GC.SuppressFinalize(this);
}
#endregion
#region ================== Methods
/// <summary>
/// This makes a sector at the given coordinates, or returns null
/// when sector could not be created.
/// </summary>
public Sector MakeAt(Vector2D pos)
public static List<LinedefSide> FindPotentialSectorAt(Vector2D pos)
{
// Find the nearest line and determine side, then use the other method to create the sector
Linedef l = General.Map.Map.NearestLinedef(pos);
return MakeAt(l, (l.SideOfLine(pos) <= 0));
return FindPotentialSectorAt(l, (l.SideOfLine(pos) <= 0));
}
/// <summary>
/// This makes a sector starting at the given line and side, or
/// returns null when sector could not be created.
/// This finds a potential sector starting at the given line and side,
/// or returns null when sector is not possible.
/// </summary>
public Sector MakeAt(Linedef line, bool front)
public static List<LinedefSide> FindPotentialSectorAt(Linedef line, bool front)
{
List<LinedefSide> alllines = new List<LinedefSide>();
// STEP 1: Find the outer lines
// Find the outer lines
Polygon p = FindOuterLines(line, front, alllines);
if(p != null)
{
// STEP 2: Find the inner lines
// Find the inner lines
FindInnerLines(p, alllines);
// STEP 3: Make the sector
return MakeSector(alllines);
return alllines;
}
else
return null;
}
#endregion
#region ================== Pathfinding
// This finds the inner lines of the sector and adds them to the sector polygon
private void FindInnerLines(Polygon p, List<LinedefSide> alllines)
private static void FindInnerLines(Polygon p, List<LinedefSide> alllines)
{
Vertex foundv;
bool vvalid, findmore;
@ -206,7 +176,7 @@ namespace CodeImp.DoomBuilder.Geometry
// This finds the outer lines of the sector as a polygon
// Returns null when no valid outer polygon can be found
private Polygon FindOuterLines(Linedef line, bool front, List<LinedefSide> alllines)
private static Polygon FindOuterLines(Linedef line, bool front, List<LinedefSide> alllines)
{
// Find inner path
List<LinedefSide> pathlines = FindInnerMostPath(line, front);
@ -233,7 +203,7 @@ namespace CodeImp.DoomBuilder.Geometry
// This finds the inner path from the beginning of a line to the end of the line.
// Returns null when no path could be found.
private List<LinedefSide> FindInnerMostPath(Linedef start, bool front)
private static List<LinedefSide> FindInnerMostPath(Linedef start, bool front)
{
List<LinedefSide> path = new List<LinedefSide>();
Dictionary<Linedef, int> tracecount = new Dictionary<Linedef, int>();
@ -302,7 +272,7 @@ namespace CodeImp.DoomBuilder.Geometry
#region ================== Sector Making
// This makes the sector from the given lines and sides
private Sector MakeSector(List<LinedefSide> alllines)
public static Sector MakeSector(List<LinedefSide> alllines)
{
Sidedef source = null;
Sector newsector = General.Map.Map.CreateSector();
@ -383,6 +353,34 @@ namespace CodeImp.DoomBuilder.Geometry
return newsector;
}
// This joins a sector with the given lines and sides
public static Sector JoinSector(List<LinedefSide> alllines, Sidedef original)
{
// Go for all sides to make sidedefs
foreach(LinedefSide ls in alllines)
{
if(ls.Front)
{
// Create sidedef is needed and ensure it points to the new sector
if(ls.Line.Front == null) General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
original.CopyPropertiesTo(ls.Line.Front);
}
else
{
// Create sidedef is needed and ensure it points to the new sector
if(ls.Line.Back == null) General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
original.CopyPropertiesTo(ls.Line.Back);
}
// Update line
ls.Line.ApplySidedFlags();
}
// Return the new sector
return original.Sector;
}
#endregion
}
}

View file

@ -231,7 +231,7 @@ namespace CodeImp.DoomBuilder.Map
if(this.selected) other.selected = true;
if(this.marked) other.marked = true;
// Detach all linedefs
// Detach all linedefs and attach them to the other
// This will automatically dispose this vertex
while(linedefs != null)
{