Changed drawing behavior so that drawn lines are not corrected to clockwise orientation

This commit is contained in:
codeimp 2009-05-06 14:50:17 +00:00
parent 65521d1ea6
commit 91b76bcb5b
5 changed files with 92 additions and 44 deletions

View file

@ -75,6 +75,27 @@ namespace CodeImp.DoomBuilder.Geometry
// Initialize
foreach(EarClipVertex v in p) base.AddLast(v);
}
// This calculates the area
public float CalculateArea()
{
// Multiply the x coordinate of each vertex by the y coordinate of the next vertex.
// Multiply the y coordinate of each vertex by the x coordinate of the next vertex.
// Subtract these.
float result = 0.0f;
int firstcalculated = 0;
LinkedListNode<EarClipVertex> n1 = base.First;
while(firstcalculated < 2)
{
LinkedListNode<EarClipVertex> n2 = n1.Next ?? base.First;
float a = n1.Value.Position.x * n2.Value.Position.y;
float b = n1.Value.Position.y * n2.Value.Position.x;
result += a - b;
n1 = n2;
if(n2 == base.First) firstcalculated++;
}
return Math.Abs(result / 2.0f);
}
// This creates a bounding box from the outer polygon
public RectangleF CreateBBox()

View file

@ -827,6 +827,7 @@ namespace CodeImp.DoomBuilder.Geometry
List<Vertex> newverts = new List<Vertex>();
List<Vertex> intersectverts = new List<Vertex>();
List<Linedef> newlines = new List<Linedef>();
List<bool> newlinescw = new List<bool>();
List<Linedef> oldlines = new List<Linedef>(General.Map.Map.Linedefs);
List<Sidedef> insidesides = new List<Sidedef>();
List<Vertex> mergeverts = new List<Vertex>();
@ -839,7 +840,7 @@ namespace CodeImp.DoomBuilder.Geometry
if(points.Count > 0)
{
/***************************************************\
STEP 1: Create the new geometry
Create the drawing
\***************************************************/
// Make first vertex
@ -923,6 +924,10 @@ namespace CodeImp.DoomBuilder.Geometry
// Join merge vertices so that overlapping vertices in the draw become one.
MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE);
/***************************************************\
Find a way to close the drawing
\***************************************************/
// 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;
@ -1089,14 +1094,13 @@ namespace CodeImp.DoomBuilder.Geometry
MapSet.SplitLinesByVertices(newlines, mergeverts, MapSet.STITCH_DISTANCE, null);
/***************************************************\
STEP 2: Merge the new geometry
Determine drawing interior
\***************************************************/
// 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
// some weird polygon this could result in problems. The following code adjusts
// the direction of all new lines so that their front (right) side is facing
// the interior of the new drawn polygon.
// In step 3 we will make sectors on the interior sides and join sectors on the
// exterior sides, but because the user could have drawn counterclockwise or just
// some weird polygon. The following code figures out the interior side of all
// new lines.
map.Update(true, false);
foreach(Linedef ld in newlines)
{
@ -1107,9 +1111,9 @@ namespace CodeImp.DoomBuilder.Geometry
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
EarClipPolygon pathpoly = tracepath.MakePolygon(true);
// Check if the front of the line is outside the polygon
if(!pathpoly.Intersect(ld.GetSidePoint(true)))
if((pathpoly.CalculateArea() > 0.001f) && !pathpoly.Intersect(ld.GetSidePoint(true)))
{
// Now trace from the back side of the line to see if
// the back side lies in the interior. I don't want to
@ -1123,19 +1127,29 @@ namespace CodeImp.DoomBuilder.Geometry
tracepath = new LinedefTracePath(pathlines);
pathpoly = tracepath.MakePolygon(true);
// 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();
ld.UpdateCache();
}
// Check if the front of the line is inside the polygon
ld.FrontInterior = (pathpoly.CalculateArea() < 0.001f) || pathpoly.Intersect(ld.GetSidePoint(true));
}
else
{
ld.FrontInterior = true;
}
}
else
{
ld.FrontInterior = true;
}
}
else
{
ld.FrontInterior = true;
}
}
/***************************************************\
Merge the new geometry
\***************************************************/
// Mark only the vertices that should be merged
map.ClearMarkedVertices(false);
foreach(Vertex v in mergeverts) v.Marked = true;
@ -1157,11 +1171,11 @@ namespace CodeImp.DoomBuilder.Geometry
if(!ld.IsDisposed) oldlines.Add(ld);
/***************************************************\
STEP 3: Join and create new sectors
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.
// The code below atempts to create sectors on the interior sides of the drawn
// geometry and joins sectors on the other sides of the drawn geometry.
// This code does not change any geometry, it only makes/updates sidedefs.
bool sidescreated = false;
bool[] frontsdone = new bool[newlines.Count];
@ -1170,11 +1184,11 @@ namespace CodeImp.DoomBuilder.Geometry
{
Linedef ld = newlines[i];
// Front not marked as done?
if(!frontsdone[i])
// Interior not done yet?
if((ld.FrontInterior && !frontsdone[i]) || (!ld.FrontInterior && !backsdone[i]))
{
// Find a way to create a sector here
List<LinedefSide> sectorlines = Tools.FindPotentialSectorAt(ld, true);
List<LinedefSide> sectorlines = Tools.FindPotentialSectorAt(ld, ld.FrontInterior);
if(sectorlines != null)
{
sidescreated = true;
@ -1216,15 +1230,14 @@ namespace CodeImp.DoomBuilder.Geometry
}
}
// Back not marked as done?
if(!backsdone[i])
// Exterior not done yet?
if((ld.FrontInterior && !backsdone[i]) || (!ld.FrontInterior && !frontsdone[i]))
{
// Find a way to create a sector here
List<LinedefSide> sectorlines = Tools.FindPotentialSectorAt(ld, false);
List<LinedefSide> sectorlines = Tools.FindPotentialSectorAt(ld, !ld.FrontInterior);
if(sectorlines != null)
{
// 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
// Check if any of the surrounding lines originally have sidedefs we can join
Sidedef joinsidedef = null;
foreach(LinedefSide ls in sectorlines)
{
@ -1267,6 +1280,10 @@ namespace CodeImp.DoomBuilder.Geometry
}
}
/***************************************************\
Corrections and clean up
\***************************************************/
// Make corrections for backward linedefs
MapSet.FlipBackwardLinedefs(newlines);

View file

@ -75,6 +75,7 @@ namespace CodeImp.DoomBuilder.Map
private int activate;
private int tag;
private int[] args;
private bool frontinterior; // for drawing only
// Clone
private int serializedindex;
@ -101,6 +102,7 @@ namespace CodeImp.DoomBuilder.Map
public RectangleF Rect { get { return rect; } }
public int[] Args { get { return args; } }
internal int SerializedIndex { get { return serializedindex; } set { serializedindex = value; } }
internal bool FrontInterior { get { return frontinterior; } set { frontinterior = value; } }
#endregion
@ -489,6 +491,9 @@ namespace CodeImp.DoomBuilder.Map
startvertexlistitem = endvertexlistitem;
endvertexlistitem = vn;
// For drawing, the interior now lies on the other side
frontinterior = !frontinterior;
// Update required (angle changed)
NeedUpdate();
General.Map.IsChanged = true;

View file

@ -1886,21 +1886,23 @@ namespace CodeImp.DoomBuilder.Map
// Not the same line?
if(l1 != l2)
{
bool flipresult = (l1.End == l2.Start);
bool oppositedirection = (l1.End == l2.Start);
// Merge these two linedefs
//while(lines.Remove(l1));
//l1.Join(l2);
while(lines.Remove(l2)) ;
l2.Join(l1);
// The flipping is purely a cosmetic to preserve orientation
// when drawing new lines over older lines
if(flipresult)
if(oppositedirection)
{
l1.FlipVertices();
l1.FlipSidedefs();
}
// Direction is now the same, so the interior side is also the same
// We have to copy the interior side to preserve this for drawing
l1.FrontInterior = l2.FrontInterior;
joinsdone++;
joined = true;
@ -1922,22 +1924,24 @@ namespace CodeImp.DoomBuilder.Map
// Not the same line?
if(l1 != l2)
{
bool flipresult = (l1.End == l2.Start);
bool oppositedirection = (l1.Start == l2.End);
// Merge these two linedefs
//while(lines.Remove(l1));
//l1.Join(l2);
while(lines.Remove(l2)) ;
l2.Join(l1);
// The flipping is purely a cosmetic to preserve orientation
// when drawing new lines over older lines
if(flipresult)
if(oppositedirection)
{
l1.FlipVertices();
l1.FlipSidedefs();
}
// Direction is now the same, so the interior side is also the same
// We have to copy the interior side to preserve this for drawing
l1.FrontInterior = l2.FrontInterior;
joinsdone++;
joined = true;
break;

View file

@ -291,6 +291,14 @@ namespace CodeImp.DoomBuilder.Map
// This removes textures that are not required
public void RemoveUnneededTextures(bool removemiddle, bool force)
{
// The middle texture can be removed regardless of any sector tag or linedef action
if(!MiddleRequired() && removemiddle)
{
this.texnamemid = "-";
this.longtexnamemid = MapSet.EmptyLongName;
General.Map.IsChanged = true;
}
// Check if the line or sectors have no action or tags because
// if they do, any texture on this side could be needed
if(((linedef.Tag <= 0) && (linedef.Action == 0) && (sector.Tag <= 0) &&
@ -304,13 +312,6 @@ namespace CodeImp.DoomBuilder.Map
General.Map.IsChanged = true;
}
if(!MiddleRequired() && removemiddle)
{
this.texnamemid = "-";
this.longtexnamemid = MapSet.EmptyLongName;
General.Map.IsChanged = true;
}
if(!LowRequired())
{
this.texnamelow = "-";