@working on stuff

This commit is contained in:
codeimp 2009-01-30 16:14:11 +00:00
parent 8cca92bef3
commit 7d02e5df8d
6 changed files with 224 additions and 124 deletions

View file

@ -63,6 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public override void Run() public override void Run()
{ {
Dictionary<Linedef, Linedef> donelines = new Dictionary<Linedef, Linedef>(); Dictionary<Linedef, Linedef> donelines = new Dictionary<Linedef, Linedef>();
BlockMap blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
// Go for all the liendefs // Go for all the liendefs
foreach(Linedef l in General.Map.Map.Linedefs) foreach(Linedef l in General.Map.Map.Linedefs)
@ -71,36 +72,44 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(!donelines.ContainsKey(l)) if(!donelines.ContainsKey(l))
{ {
// And go for all the linedefs that could overlap // And go for all the linedefs that could overlap
foreach(Linedef d in General.Map.Map.Linedefs) List<BlockEntry> blocks = blockmap.GetLineBlocks(l.Start.Position, l.End.Position);
Dictionary<Linedef, Linedef> doneblocklines = new Dictionary<Linedef, Linedef>(blocks.Count * 3);
foreach(BlockEntry b in blocks)
{ {
// Not the same line? foreach(Linedef d in b.Lines)
if(!object.ReferenceEquals(l, d))
{ {
float lu, du; // Not the same line and not already checked
if(!object.ReferenceEquals(l, d) && !doneblocklines.ContainsKey(d))
// Check if the lines touch. Note that I don't include 0.0 and 1.0 here because
// the lines may be touching at the ends when sharing the same vertex.
if(l.Line.GetIntersection(d.Line, out du, out lu))
{ {
if((lu > 0.0f) && (lu < 1.0f) && (du > 0.0f) && (du < 1.0f)) float lu, du;
{
// Check if not the same sector on all sides
Sector samesector = null;
if(l.Front != null) samesector = l.Front.Sector;
else if(l.Back != null) samesector = l.Back.Sector;
else if(d.Front != null) samesector = d.Front.Sector;
else if(d.Back != null) samesector = d.Back.Sector;
if((l.Front == null) || (l.Front.Sector != samesector)) samesector = null;
else if((l.Back == null) || (l.Back.Sector != samesector)) samesector = null;
else if((d.Front == null) || (d.Front.Sector != samesector)) samesector = null;
else if((d.Back == null) || (d.Back.Sector != samesector)) samesector = null;
if(samesector == null) // Check if the lines touch. Note that I don't include 0.0 and 1.0 here because
// the lines may be touching at the ends when sharing the same vertex.
if(l.Line.GetIntersection(d.Line, out du, out lu))
{
if((lu > 0.0f) && (lu < 1.0f) && (du > 0.0f) && (du < 1.0f))
{ {
SubmitResult(new ResultLineOverlapping(l, d)); // Check if not the same sector on all sides
donelines[d] = d; Sector samesector = null;
if(l.Front != null) samesector = l.Front.Sector;
else if(l.Back != null) samesector = l.Back.Sector;
else if(d.Front != null) samesector = d.Front.Sector;
else if(d.Back != null) samesector = d.Back.Sector;
if((l.Front == null) || (l.Front.Sector != samesector)) samesector = null;
else if((l.Back == null) || (l.Back.Sector != samesector)) samesector = null;
else if((d.Front == null) || (d.Front.Sector != samesector)) samesector = null;
else if((d.Back == null) || (d.Back.Sector != samesector)) samesector = null;
if(samesector == null)
{
SubmitResult(new ResultLineOverlapping(l, d));
donelines[d] = d;
}
} }
} }
// Checked
doneblocklines.Add(d, d);
} }
} }
} }

View file

@ -34,6 +34,7 @@ using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Config;
using System.Threading; using System.Threading;
using System.Drawing;
#endregion #endregion
@ -64,6 +65,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This runs the check // This runs the check
public override void Run() public override void Run()
{ {
BlockMap blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
// Go for all the things // Go for all the things
foreach(Thing t in General.Map.Map.Things) foreach(Thing t in General.Map.Map.Things)
{ {
@ -80,26 +83,34 @@ namespace CodeImp.DoomBuilder.BuilderModes
Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize); Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize);
// Go for all the lines to see if this thing is stucked // Go for all the lines to see if this thing is stucked
foreach(Linedef l in General.Map.Map.Linedefs) List<BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(lt.x, lt.y, (rb.x - lt.x), (rb.y - lt.y)));
Dictionary<Linedef, Linedef> doneblocklines = new Dictionary<Linedef, Linedef>(blocks.Count * 3);
foreach(BlockEntry b in blocks)
{ {
// Test only single-sided lines foreach(Linedef l in b.Lines)
if(l.Back == null)
{ {
// Test if line ends are inside the thing // Only test when sinlge-sided and not already checked
if(PointInRect(lt, rb, l.Start.Position) || if((l.Back == null) && !doneblocklines.ContainsKey(l))
PointInRect(lt, rb, l.End.Position))
{ {
// Thing stucked in line! // Test if line ends are inside the thing
stucked = true; if(PointInRect(lt, rb, l.Start.Position) ||
} PointInRect(lt, rb, l.End.Position))
// Test if the line intersects the square {
else if(Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) || // Thing stucked in line!
Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) || stucked = true;
Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) || }
Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y)) // Test if the line intersects the square
{ else if(Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) ||
// Thing stucked in line! Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) ||
stucked = true; Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) ||
Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y))
{
// Thing stucked in line!
stucked = true;
}
// Checked
doneblocklines.Add(l, l);
} }
} }
} }

View file

@ -58,12 +58,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
private volatile bool running = false; private volatile bool running = false;
private Thread checksthread; private Thread checksthread;
private BlockMap blockmap;
#endregion #endregion
#region ================== Properties #region ================== Properties
public ErrorResult SelectedResult { get { return results.SelectedItem as ErrorResult; } } public ErrorResult SelectedResult { get { return results.SelectedItem as ErrorResult; } }
public BlockMap BlockMap { get { return blockmap; } }
#endregion #endregion
@ -170,6 +172,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
buttoncheck.Text = "Start Analysis"; buttoncheck.Text = "Start Analysis";
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
running = false; running = false;
blockmap.Dispose();
blockmap = null;
} }
} }
@ -180,6 +184,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
Cursor.Current = Cursors.WaitCursor; Cursor.Current = Cursors.WaitCursor;
// Make blockmap
RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices);
area = MapSet.IncreaseArea(area, General.Map.Map.Things);
blockmap = new BlockMap(area);
blockmap.AddLinedefsSet(General.Map.Map.Linedefs);
blockmap.AddSectorsSet(General.Map.Map.Sectors);
blockmap.AddThingsSet(General.Map.Map.Things);
// Open the results panel // Open the results panel
this.Size = new Size(this.Width, this.Height - this.ClientSize.Height + resultspanel.Top + resultspanel.Height); this.Size = new Size(this.Width, this.Height - this.ClientSize.Height + resultspanel.Top + resultspanel.Height);
progress.Value = 0; progress.Value = 0;

View file

@ -52,8 +52,6 @@ namespace CodeImp.DoomBuilder.Map
// Blocks // Blocks
protected BlockEntry[,] blockmap; protected BlockEntry[,] blockmap;
protected Point lefttop;
protected Point rightbottom;
protected Size size; protected Size size;
protected RectangleF range; protected RectangleF range;
@ -65,27 +63,28 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Properties #region ================== Properties
public bool IsDisposed { get { return isdisposed; } } public bool IsDisposed { get { return isdisposed; } }
public Size Size { get { return size; } }
public RectangleF Range { get { return range; } }
public int BlockSize { get { return BLOCK_SIZE; } }
#endregion #endregion
#region ================== Constructor / Disposer #region ================== Constructor / Disposer
// Constructor // Constructor
internal BlockMap(RectangleF range) public BlockMap(RectangleF range)
{ {
// Initialize // Initialize
this.range = range; this.range = range;
lefttop = new Point((int)range.Left >> BLOCK_SIZE_SHIFT, (int)range.Top >> BLOCK_SIZE_SHIFT); Point lefttop = new Point((int)range.Left >> BLOCK_SIZE_SHIFT, (int)range.Top >> BLOCK_SIZE_SHIFT);
rightbottom = new Point((int)range.Right >> BLOCK_SIZE_SHIFT, (int)range.Bottom >> BLOCK_SIZE_SHIFT); Point rightbottom = new Point((int)range.Right >> BLOCK_SIZE_SHIFT, (int)range.Bottom >> BLOCK_SIZE_SHIFT);
int width = (rightbottom.X - lefttop.X) + 1; size = new Size((rightbottom.X - lefttop.X) + 1, (rightbottom.Y - lefttop.Y) + 1);
int height = (rightbottom.Y - lefttop.Y) + 1; blockmap = new BlockEntry[size.Width, size.Height];
size = new Size(width, height);
blockmap = new BlockEntry[width, height];
Clear(); Clear();
} }
// Disposer // Disposer
internal void Dispose() public void Dispose()
{ {
// Not already disposed? // Not already disposed?
if(!isdisposed) if(!isdisposed)
@ -105,15 +104,15 @@ namespace CodeImp.DoomBuilder.Map
// This returns the block coordinates // This returns the block coordinates
protected Point GetBlockCoordinates(Vector2D v) protected Point GetBlockCoordinates(Vector2D v)
{ {
return new Point(((int)v.x >> BLOCK_SIZE_SHIFT) - lefttop.X, return new Point((int)(v.x - range.Left) >> BLOCK_SIZE_SHIFT,
((int)v.y >> BLOCK_SIZE_SHIFT) - lefttop.Y); (int)(v.y - range.Top) >> BLOCK_SIZE_SHIFT);
} }
// This returns the block center in world coordinates // This returns the block center in world coordinates
protected Vector2D GetBlockCenter(Point p) protected Vector2D GetBlockCenter(Point p)
{ {
return new Vector2D((float)(((p.X + lefttop.X) << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)), return new Vector2D((float)((p.X << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)) + range.Left,
(float)(((p.Y + lefttop.Y) << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1))); (float)((p.Y << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)) + range.Top);
} }
// This returns true when the given block is inside range // This returns true when the given block is inside range
@ -148,7 +147,7 @@ namespace CodeImp.DoomBuilder.Map
} }
// This clears the blockmap // This clears the blockmap
public void Clear() public virtual void Clear()
{ {
for(int x = 0; x < size.Width; x++) for(int x = 0; x < size.Width; x++)
{ {
@ -160,7 +159,7 @@ namespace CodeImp.DoomBuilder.Map
} }
// This returns a range of blocks in a square // This returns a range of blocks in a square
public List<BlockEntry> GetSquareRange(RectangleF rect) public virtual List<BlockEntry> GetSquareRange(RectangleF rect)
{ {
// Calculate block coordinates // Calculate block coordinates
Point lt = GetBlockCoordinates(new Vector2D(rect.Left, rect.Top)); Point lt = GetBlockCoordinates(new Vector2D(rect.Left, rect.Top));
@ -186,7 +185,7 @@ namespace CodeImp.DoomBuilder.Map
} }
// This returns all blocks along the given line // This returns all blocks along the given line
public List<BlockEntry> GetLineBlocks(Vector2D v1, Vector2D v2) public virtual List<BlockEntry> GetLineBlocks(Vector2D v1, Vector2D v2)
{ {
float deltax, deltay; float deltax, deltay;
float posx, posy; float posx, posy;
@ -201,66 +200,107 @@ namespace CodeImp.DoomBuilder.Map
pos = GetBlockCoordinates(v1); pos = GetBlockCoordinates(v1);
end = GetBlockCoordinates(v2); end = GetBlockCoordinates(v2);
// Add this block // Horizontal straight line?
if(IsInRange(pos)) entries.Add(blockmap[pos.X, pos.Y]); if(pos.Y == end.Y)
// Moving outside the block?
if(pos != end)
{ {
// Calculate current block edges // Simple loop
float cl = pos.X * BLOCK_SIZE; pos.X = CropToRangeX(pos.X);
float cr = (pos.X + 1) * BLOCK_SIZE; end.X = CropToRangeX(end.X);
float ct = pos.Y * BLOCK_SIZE; if(IsInRange(new Point(pos.X, pos.Y)))
float cb = (pos.Y + 1) * BLOCK_SIZE;
// Line directions
dirx = Math.Sign(v2.x - v1.x);
diry = Math.Sign(v2.y - v1.y);
// Calculate offset and delta movement over x
if(dirx >= 0)
{ {
posx = (cr - v1.x) / (v2.x - v1.x); dirx = Math.Sign(v2.x - v1.x);
deltax = BLOCK_SIZE / (v2.x - v1.x); if(dirx != 0)
}
else
{
// Calculate offset and delta movement over x
posx = (v1.x - cl) / (v1.x - v2.x);
deltax = BLOCK_SIZE / (v1.x - v2.x);
}
// Calculate offset and delta movement over y
if(diry >= 0)
{
posy = (cb - v1.y) / (v2.y - v1.y);
deltay = BLOCK_SIZE / (v2.y - v1.y);
}
else
{
posy = (v1.y - ct) / (v1.y - v2.y);
deltay = BLOCK_SIZE / (v1.y - v2.y);
}
// Continue while not reached the end
while(pos != end)
{
// Check in which direction to move
if(posx < posy)
{ {
// Move horizontally for(int x = pos.X; x != end.X; x += dirx)
posx += deltax; {
if(pos.X != end.X) pos.X += dirx; entries.Add(blockmap[x, pos.Y]);
}
}
entries.Add(blockmap[end.X, end.Y]);
}
}
// Vertical straight line?
else if(pos.X == end.X)
{
// Simple loop
pos.Y = CropToRangeY(pos.Y);
end.Y = CropToRangeY(end.Y);
if(IsInRange(new Point(pos.X, pos.Y)))
{
diry = Math.Sign(v2.y - v1.y);
if(diry != 0)
{
for(int y = pos.Y; y != end.Y; y += diry)
{
entries.Add(blockmap[pos.X, y]);
}
}
entries.Add(blockmap[end.X, end.Y]);
}
}
else
{
// Add this block
if(IsInRange(pos)) entries.Add(blockmap[pos.X, pos.Y]);
// Moving outside the block?
if(pos != end)
{
// Calculate current block edges
float cl = pos.X * BLOCK_SIZE;
float cr = (pos.X + 1) * BLOCK_SIZE;
float ct = pos.Y * BLOCK_SIZE;
float cb = (pos.Y + 1) * BLOCK_SIZE;
// Line directions
dirx = Math.Sign(v2.x - v1.x);
diry = Math.Sign(v2.y - v1.y);
// Calculate offset and delta movement over x
if(dirx >= 0)
{
posx = (cr - v1.x) / (v2.x - v1.x);
deltax = BLOCK_SIZE / (v2.x - v1.x);
} }
else else
{ {
// Move vertically // Calculate offset and delta movement over x
posy += deltay; posx = (v1.x - cl) / (v1.x - v2.x);
if(pos.Y != end.Y) pos.Y += diry; deltax = BLOCK_SIZE / (v1.x - v2.x);
} }
// Add lines to this block // Calculate offset and delta movement over y
if(IsInRange(pos)) entries.Add(blockmap[pos.X, pos.Y]); if(diry >= 0)
{
posy = (cb - v1.y) / (v2.y - v1.y);
deltay = BLOCK_SIZE / (v2.y - v1.y);
}
else
{
posy = (v1.y - ct) / (v1.y - v2.y);
deltay = BLOCK_SIZE / (v1.y - v2.y);
}
// Continue while not reached the end
while(pos != end)
{
// Check in which direction to move
if(posx < posy)
{
// Move horizontally
posx += deltax;
if(pos.X != end.X) pos.X += dirx;
}
else
{
// Move vertically
posy += deltay;
if(pos.Y != end.Y) pos.Y += diry;
}
// Add lines to this block
if(IsInRange(pos)) entries.Add(blockmap[pos.X, pos.Y]);
}
} }
} }
@ -269,26 +309,26 @@ namespace CodeImp.DoomBuilder.Map
} }
// This puts a thing in the blockmap // This puts a thing in the blockmap
public void AddThingsSet(ICollection<Thing> things) public virtual void AddThingsSet(ICollection<Thing> things)
{ {
foreach(Thing t in things) AddThing(t); foreach(Thing t in things) AddThing(t);
} }
// This puts a thing in the blockmap // This puts a thing in the blockmap
public void AddThing(Thing t) public virtual void AddThing(Thing t)
{ {
Point p = GetBlockCoordinates(t.Position); Point p = GetBlockCoordinates(t.Position);
if(IsInRange(p)) blockmap[p.X, p.Y].Things.Add(t); if(IsInRange(p)) blockmap[p.X, p.Y].Things.Add(t);
} }
// This puts a secotr in the blockmap // This puts a secotr in the blockmap
public void AddSectorsSet(ICollection<Sector> sectors) public virtual void AddSectorsSet(ICollection<Sector> sectors)
{ {
foreach(Sector s in sectors) AddSector(s); foreach(Sector s in sectors) AddSector(s);
} }
// This puts a sector in the blockmap // This puts a sector in the blockmap
public void AddSector(Sector s) public virtual void AddSector(Sector s)
{ {
Point p1 = GetBlockCoordinates(new Vector2D(s.BBox.Left, s.BBox.Top)); Point p1 = GetBlockCoordinates(new Vector2D(s.BBox.Left, s.BBox.Top));
Point p2 = GetBlockCoordinates(new Vector2D(s.BBox.Right, s.BBox.Bottom)); Point p2 = GetBlockCoordinates(new Vector2D(s.BBox.Right, s.BBox.Bottom));
@ -304,13 +344,13 @@ namespace CodeImp.DoomBuilder.Map
} }
// This puts a whole set of linedefs in the blocks they cross // This puts a whole set of linedefs in the blocks they cross
public void AddLinedefsSet(ICollection<Linedef> lines) public virtual void AddLinedefsSet(ICollection<Linedef> lines)
{ {
foreach(Linedef l in lines) AddLinedef(l); foreach(Linedef l in lines) AddLinedef(l);
} }
// This puts a single linedef in all blocks it crosses // This puts a single linedef in all blocks it crosses
public void AddLinedef(Linedef line) public virtual void AddLinedef(Linedef line)
{ {
Vector2D v1, v2; Vector2D v1, v2;
float deltax, deltay; float deltax, deltay;
@ -335,9 +375,12 @@ namespace CodeImp.DoomBuilder.Map
if(IsInRange(new Point(pos.X, pos.Y))) if(IsInRange(new Point(pos.X, pos.Y)))
{ {
dirx = Math.Sign(v2.x - v1.x); dirx = Math.Sign(v2.x - v1.x);
for(int x = pos.X; x != end.X; x += dirx) if(dirx != 0)
{ {
blockmap[x, pos.Y].Lines.Add(line); for(int x = pos.X; x != end.X; x += dirx)
{
blockmap[x, pos.Y].Lines.Add(line);
}
} }
blockmap[end.X, end.Y].Lines.Add(line); blockmap[end.X, end.Y].Lines.Add(line);
} }
@ -351,9 +394,12 @@ namespace CodeImp.DoomBuilder.Map
if(IsInRange(new Point(pos.X, pos.Y))) if(IsInRange(new Point(pos.X, pos.Y)))
{ {
diry = Math.Sign(v2.y - v1.y); diry = Math.Sign(v2.y - v1.y);
for(int y = pos.Y; y != end.Y; y += diry) if(diry != 0)
{ {
blockmap[pos.X, y].Lines.Add(line); for(int y = pos.Y; y != end.Y; y += diry)
{
blockmap[pos.X, y].Lines.Add(line);
}
} }
blockmap[end.X, end.Y].Lines.Add(line); blockmap[end.X, end.Y].Lines.Add(line);
} }

View file

@ -1299,6 +1299,28 @@ namespace CodeImp.DoomBuilder.Map
return new RectangleF(l, t, r - l, b - t); return new RectangleF(l, t, r - l, b - t);
} }
// This increases and existing area with the given vertices
public static RectangleF IncreaseArea(RectangleF area, ICollection<Thing> things)
{
float l = area.Left;
float t = area.Top;
float r = area.Right;
float b = area.Bottom;
// Go for all vertices
foreach(Thing th in things)
{
// Adjust boundaries by vertices
if(th.Position.x < l) l = th.Position.x;
if(th.Position.x > r) r = th.Position.x;
if(th.Position.y < t) t = th.Position.y;
if(th.Position.y > b) b = th.Position.y;
}
// Return a rect
return new RectangleF(l, t, r - l, b - t);
}
// This increases and existing area with the given vertices // This increases and existing area with the given vertices
public static RectangleF IncreaseArea(RectangleF area, ICollection<Vector2D> verts) public static RectangleF IncreaseArea(RectangleF area, ICollection<Vector2D> verts)
{ {

Binary file not shown.