mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-02-17 01:22:18 +00:00
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:
parent
c43f0dc3a6
commit
e63ee4dc81
5 changed files with 180 additions and 92 deletions
|
@ -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
|
||||
\***************************************************/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Reference in a new issue