worked on geometry drawing (i think it is actually working perfect now, aside from some default settings on the new sidedefs then)

This commit is contained in:
codeimp 2008-05-07 22:46:15 +00:00
parent c43f0dc3a6
commit e63ee4dc81
5 changed files with 180 additions and 92 deletions

View file

@ -133,6 +133,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
public override void Disengage()
{
List<Vertex> newverts = new List<Vertex>();
List<Vertex> intersectverts = new List<Vertex>();
List<Linedef> newlines = new List<Linedef>();
List<Vertex> mergeverts = new List<Vertex>();
List<Vertex> nonmergeverts = new List<Vertex>(General.Map.Map.Vertices);
@ -155,6 +156,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Make first vertex
Vertex v1 = map.CreateVertex(points[0].pos);
v1.Marked = true;
// Keep references
newverts.Add(v1);
@ -165,7 +167,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Create vertex for point
Vertex v2 = map.CreateVertex(points[i].pos);
v2.Marked = true;
// Keep references
newverts.Add(v2);
if(points[i].stitch) mergeverts.Add(v2); else nonmergeverts.Add(v2);
@ -182,16 +185,17 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Check if any other lines intersect this line
List<float> intersections = new List<float>();
Line2D measureline = ld.Line;
foreach(Linedef ld2 in map.Linedefs)
{
// Not the same as the subject line
if(ld2 != ld)
// Intersecting?
// We only keep the unit length from the start of the line and
// do the real splitting later, when all intersections are known
float u;
if(ld2.Line.GetIntersection(measureline, out u))
{
// Intersecting?
// We only keep the unit length from the start of the line and
// do the real splitting later, when all intersections are known
float u = ld.GetIntersectionU(ld2);
if(!float.IsNaN(u) && (u > 0.0f) && (u < 1.0f)) intersections.Add(u);
if(!float.IsNaN(u) && (u > 0.0f) && (u < 1.0f) && (ld2 != ld))
intersections.Add(u);
}
}
@ -200,7 +204,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Go for all found intersections
Linedef splitline = ld;
Line2D measureline = ld.GetLine2D();
foreach(float u in intersections)
{
// Calculate exact coordinates where to split
@ -210,6 +213,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Make the vertex
Vertex splitvertex = map.CreateVertex(splitpoint);
splitvertex.Marked = true;
newverts.Add(splitvertex);
mergeverts.Add(splitvertex); // <-- add to merge?
intersectverts.Add(splitvertex);
// The Split method ties the end of the original line to the given
// vertex and starts a new line at the given vertex, so continue
@ -217,8 +224,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// from low to high (beginning at the original line start)
splitline = splitline.Split(splitvertex);
newlines.Add(splitline);
newverts.Add(splitvertex);
mergeverts.Add(splitvertex);
}
}
@ -226,14 +231,17 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
v1 = v2;
}
// 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);
/***************************************************\
STEP 2: Merge the new geometry
\***************************************************/
// Mark our new vertices that need to merge and merge them with themselves
// This completes the self intersections for which splits were made in step 1.
foreach(Vertex v in mergeverts) v.Marked = true;
MapSet.JoinVertices(mergeverts, mergeverts, true, MapSet.STITCH_DISTANCE);
// In step 3 we will make sectors on the front sides and join sectors on the
// back sides, but because the user could have drawn counterclockwise or just
@ -254,28 +262,47 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Check if the front of the line is outside the polygon
if(!pathpoly.Intersect(ld.GetSidePoint(true)))
{
// TODO: Maybe we also need to trace from the back side of the line
// here and see if that side lies in the interior? Just to make
// sure this flip will really help?
// Now trace from the back side of the line to see if
// the back side lies in the interior. I don't want to
// flip the line if it is not helping.
/*
// Find closest path starting with the back of this linedef
pathlines = SectorTools.FindClosestPath(ld, false);
if(pathlines != null)
{
// Make polygon
tracepath = new LinedefTracePath(pathlines);
pathpoly = tracepath.MakePolygon();
// Check if the back of the line is inside the polygon
if(pathpoly.Intersect(ld.GetSidePoint(false)))
{
// We must flip this linedef to face the interior
ld.FlipVertices();
ld.FlipSidedefs();
}
}
*/
// We must flip this linedef to face the interior
ld.FlipVertices();
ld.FlipSidedefs();
ld.UpdateCache();
}
}
}
// Perform standard geometry stitching between new and existing geometry
// The marked vertices indicate the new geometry
// Before this point, the new geometry is not linked with the existing geometry.
// Now perform standard geometry stitching to merge the new geometry with the rest
// of the map. The marked vertices indicate the new geometry.
map.StitchGeometry();
map.Update(true, false);
// 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, MapSet.STITCH_DISTANCE, null);
/***************************************************\
STEP 3: Join and create new sectors
\***************************************************/

View file

@ -84,7 +84,7 @@ namespace CodeImp.DoomBuilder.Geometry
Vector2D v1 = base.Last.Value.Position;
Vector2D v2;
LinkedListNode<EarClipVertex> n = base.First;
int c = 0;
uint c = 0;
// Go for all vertices
while(n != null)
@ -115,8 +115,24 @@ namespace CodeImp.DoomBuilder.Geometry
n = n.Next;
}
// Return result
return ((c & 0x01) != 0);
// Inside this polygon?
if((c & 0x00000001UL) != 0)
{
// Check if not inside the children
foreach(Polygon child in children)
{
// Inside this child? Then it is not inside this polygon.
if(child.Intersect(p)) return false;
}
// Inside polygon!
return true;
}
else
{
// Not inside the polygon
return false;
}
}
// This inserts a polygon if it is a child of this one

View file

@ -62,9 +62,6 @@ namespace CodeImp.DoomBuilder.Geometry
{
List<LinedefSide> alllines = new List<LinedefSide>();
// TODO: Right now this will fail when it has found inner lines
// So fix it to make it find the outer lines first!
// Find the outer lines
Polygon p = FindOuterLines(line, front, alllines);
if(p != null)
@ -144,8 +141,8 @@ namespace CodeImp.DoomBuilder.Geometry
// We already know that each linedef will go from this vertex
// to the left, because this is the right-most vertex in this area.
// If the line goes to the right, that means the other vertex of that
// line must lie outside this area and the mapper made an error.
// If the line would go to the right, that means the other vertex of
// that line must lie outside this area and the mapper made an error.
// Should I check for this error and fail to create a sector in
// that case or ignore it and create a malformed sector (possibly
// breaking another sector also)?
@ -165,9 +162,9 @@ namespace CodeImp.DoomBuilder.Geometry
// Check if the front of the line is outside the polygon
if(!innerpoly.Intersect(foundline.GetSidePoint(foundlinefront)))
{
// Valid island found!
// Valid hole found!
alllines.AddRange(innerlines);
p.Add(innerpoly);
p.InsertChild(innerpoly);
findmore = true;
}
}
@ -181,27 +178,95 @@ namespace CodeImp.DoomBuilder.Geometry
// Returns null when no valid outer polygon can be found
private static Polygon FindOuterLines(Linedef line, bool front, List<LinedefSide> alllines)
{
// Find inner path
List<LinedefSide> pathlines = FindClosestPath(line, front);
if(pathlines != null)
{
// Keep the lines
alllines.AddRange(pathlines);
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
Polygon poly = tracepath.MakePolygon();
Linedef scanline = line;
bool scanfront = front;
// Check if the front of the line is inside the polygon
if(poly.Intersect(line.GetSidePoint(front)))
do
{
// Find closest path
List<LinedefSide> pathlines = FindClosestPath(scanline, scanfront);
if(pathlines != null)
{
// Valid polygon!
return poly;
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
Polygon poly = tracepath.MakePolygon();
// Check if the front of the line is inside the polygon
if(poly.Intersect(line.GetSidePoint(front)))
{
// Outer lines found!
alllines.AddRange(pathlines);
return poly;
}
else
{
// Inner lines found. This is not what we need, we want the outer lines.
// Find the right-most vertex to start a scan from there towards the outer lines.
Vertex foundv = null;
foreach(LinedefSide ls in pathlines)
{
if((foundv == null) || (ls.Line.Start.Position.x > foundv.Position.x))
foundv = ls.Line.Start;
if((foundv == null) || (ls.Line.End.Position.x > foundv.Position.x))
foundv = ls.Line.End;
}
// If foundv is null then something is horribly wrong with the
// path we received from FindClosestPath!
if(foundv == null) throw new Exception("FAIL!");
// From the right-most vertex trace outward to the right to
// find the next closest linedef, this is based on the idea that
// all sectors are closed.
Vector2D lineoffset = new Vector2D(100.0f, 0.0f);
Line2D testline = new Line2D(foundv.Position, foundv.Position + lineoffset);
scanline = null;
float foundu = float.MaxValue;
foreach(Linedef ld in General.Map.Map.Linedefs)
{
// Line to the right of start point?
if((ld.Start.Position.x > foundv.Position.x) ||
(ld.End.Position.x > foundv.Position.x))
{
// Line intersecting the y axis?
if( !((ld.Start.Position.y > foundv.Position.y) &&
(ld.End.Position.y > foundv.Position.y)) &&
!((ld.Start.Position.y < foundv.Position.y) &&
(ld.End.Position.y < foundv.Position.y)))
{
// Check if this linedef intersects our test line at a closer range
float thisu;
ld.Line.GetIntersection(testline, out thisu);
if((thisu > 0.00001f) && (thisu < foundu) && !float.IsNaN(thisu))
{
scanline = ld;
foundu = thisu;
}
}
}
}
// Did we meet another line?
if(scanline != null)
{
// Determine on which side we should start the next pathfind
scanfront = (scanline.SideOfLine(foundv.Position) < 0.0f);
}
else
{
// Appearently we reached the end of the map, no sector possible here
return null;
}
}
}
else
{
// Can't find a path
return null;
}
}
// Path is invalid for sector outer lines
return null;
while(true);
}
/// <summary>
@ -233,7 +298,7 @@ namespace CodeImp.DoomBuilder.Geometry
if(lines.Count == 1)
{
// Are we allowed to trace along this line again?
if(!tracecount.ContainsKey(nextline) || (tracecount[nextline] < 2))
if(!tracecount.ContainsKey(nextline) || (tracecount[nextline] < 3))
{
// Turn around and go back along the other side of the line
nextfront = !nextfront;
@ -251,7 +316,7 @@ namespace CodeImp.DoomBuilder.Geometry
if(lines[0] == nextline) nextline = lines[1]; else nextline = lines[0];
// Are we allowed to trace this line again?
if(!tracecount.ContainsKey(nextline) || (tracecount[nextline] < 2))
if(!tracecount.ContainsKey(nextline) || (tracecount[nextline] < 3))
{
// Check if front side changes
if((prevline.Start == nextline.Start) ||
@ -266,7 +331,7 @@ 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));
while((path != null) && ((nextline != start) || (nextfront != front)));
// Return path (null when trace failed)
return path;
@ -368,18 +433,23 @@ namespace CodeImp.DoomBuilder.Geometry
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);
if(ls.Line.Front == null)
{
General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
ls.Line.ApplySidedFlags();
}
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);
if(ls.Line.Back == null)
{
General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
ls.Line.ApplySidedFlags();
}
original.CopyPropertiesTo(ls.Line.Back);
}
// Update line
ls.Line.ApplySidedFlags();
}
// Return the new sector

View file

@ -93,6 +93,7 @@ namespace CodeImp.DoomBuilder.Map
public Sidedef Front { get { return front; } }
public Sidedef Back { get { return back; } }
public bool IsDisposed { get { return isdisposed; } }
public Line2D Line { get { return new Line2D(start.Position, end.Position); } }
public int Flags { get { return flags; } set { flags = value; } }
public int Action { get { return action; } set { action = value; } }
public int Tag { get { return tag; } set { tag = value; if((tag < 0) || (tag > MapSet.HIGHEST_TAG)) throw new ArgumentOutOfRangeException("Tag", "Invalid tag number"); } }
@ -334,34 +335,6 @@ namespace CodeImp.DoomBuilder.Map
back = sd;
}
// This makes a Line2D instance
public Line2D GetLine2D()
{
return new Line2D(start.Position, end.Position);
}
// This gets the intersection point with another line
public float GetIntersectionU(Linedef other)
{
return GetIntersectionU(other.GetLine2D());
}
// This gets the intersection point with another line
// Returns NaN when no intersection exists.
public float GetIntersectionU(Line2D otherline)
{
float u;
Line2D thisline = this.GetLine2D();
if(!otherline.GetIntersection(thisline, out u)) u = float.NaN;
return u;
}
// This returns a vector of coordinates at the given unit length
public Vector2D GetCoordinatesAt(float u)
{
return GetLine2D().GetCoordinatesAt(u);
}
// This returns a point for testing on one side
public Vector2D GetSidePoint(bool front)
{

View file

@ -984,7 +984,6 @@ namespace CodeImp.DoomBuilder.Map
float splitdist2 = splitdist * splitdist;
int splitsdone = 0;
bool splitted;
Linedef nl;
do
{
@ -1009,7 +1008,7 @@ namespace CodeImp.DoomBuilder.Map
(Math.Abs(deltaend.y) > 0.001f)))
{
// Split line l with vertex v
nl = l.Split(v);
Linedef nl = l.Split(v);
// Add the new line to the list
lines.Add(nl);
@ -1020,8 +1019,11 @@ namespace CodeImp.DoomBuilder.Map
nl.UpdateCache();
// Add both lines to changedlines
if(changedlines != null) changedlines.Add(l);
if(changedlines != null) changedlines.Add(nl);
if(changedlines != null)
{
changedlines.Add(l);
changedlines.Add(nl);
}
// Count the split
splitsdone++;