mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2025-02-25 21:33:06 +00:00
Optimized map geometry merging performance when creating drawn lines.
Optimized map geometry merging performance when pasting map geometry. Added, Curve Linedefs mode: added "Flip Curve" button. Updater: partially rewrote fix from the previous commit.
This commit is contained in:
parent
c56f6137ec
commit
52940badf6
9 changed files with 308 additions and 82 deletions
|
@ -550,7 +550,9 @@
|
||||||
<Compile Include="Rendering\WorldVertex.cs" />
|
<Compile Include="Rendering\WorldVertex.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="JetBrains.Profiler.Core.Api, Version=1.3.1661.20096, Culture=neutral, PublicKeyToken=1010a0d8d6380325" Condition=" '$(Configuration)|$(Platform)' == 'Debug + Profiler|x86' Or '$(Configuration)|$(Platform)' == 'Release + Profiler|x86' " />
|
<Reference Include="JetBrains.Profiler.Core.Api, Version=1.3.1661.20096, Culture=neutral, PublicKeyToken=1010a0d8d6380325" Condition=" '$(Configuration)|$(Platform)' == 'Debug + Profiler|x86' Or '$(Configuration)|$(Platform)' == 'Release + Profiler|x86' ">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
</Reference>
|
||||||
<Reference Include="ScintillaNET.3.5, Version=3.5.8.0, Culture=neutral, processorArchitecture=x86">
|
<Reference Include="ScintillaNET.3.5, Version=3.5.8.0, Culture=neutral, processorArchitecture=x86">
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -225,8 +225,13 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
LinedefTracePath tracepath = new LinedefTracePath(innerlines);
|
LinedefTracePath tracepath = new LinedefTracePath(innerlines);
|
||||||
EarClipPolygon innerpoly = tracepath.MakePolygon(true);
|
EarClipPolygon innerpoly = tracepath.MakePolygon(true);
|
||||||
|
|
||||||
|
//mxd. Check bbox first...
|
||||||
|
Vector2D foundsidepoint = foundline.GetSidePoint(foundlinefront);
|
||||||
|
RectangleF innerbbox = innerpoly.CreateBBox();
|
||||||
|
bool outsidebbox = (foundsidepoint.x < innerbbox.Left || foundsidepoint.x > innerbbox.Right || foundsidepoint.y < innerbbox.Top || foundsidepoint.y > innerbbox.Bottom);
|
||||||
|
|
||||||
// Check if the front of the line is outside the polygon
|
// Check if the front of the line is outside the polygon
|
||||||
if(!innerpoly.Intersect(foundline.GetSidePoint(foundlinefront)))
|
if(outsidebbox || !innerpoly.Intersect(foundsidepoint))
|
||||||
{
|
{
|
||||||
// Valid hole found!
|
// Valid hole found!
|
||||||
alllines.AddRange(innerlines);
|
alllines.AddRange(innerlines);
|
||||||
|
@ -246,6 +251,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
{
|
{
|
||||||
Linedef scanline = line;
|
Linedef scanline = line;
|
||||||
bool scanfront = front;
|
bool scanfront = front;
|
||||||
|
Vector2D sidepoint = line.GetSidePoint(front); //mxd
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -257,8 +263,12 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
|
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
|
||||||
EarClipPolygon poly = tracepath.MakePolygon(true);
|
EarClipPolygon poly = tracepath.MakePolygon(true);
|
||||||
|
|
||||||
|
//mxd. Check bbox first...
|
||||||
|
RectangleF bbox = poly.CreateBBox();
|
||||||
|
bool outsidebbox = (sidepoint.x < bbox.Left || sidepoint.x > bbox.Right || sidepoint.y < bbox.Top || sidepoint.y > bbox.Bottom);
|
||||||
|
|
||||||
// Check if the front of the line is inside the polygon
|
// Check if the front of the line is inside the polygon
|
||||||
if(poly.Intersect(line.GetSidePoint(front)))
|
if(!outsidebbox && poly.Intersect(sidepoint))
|
||||||
{
|
{
|
||||||
// Outer lines found!
|
// Outer lines found!
|
||||||
alllines.AddRange(pathlines);
|
alllines.AddRange(pathlines);
|
||||||
|
@ -923,6 +933,11 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
List<Vertex> nonmergeverts = new List<Vertex>(General.Map.Map.Vertices);
|
List<Vertex> nonmergeverts = new List<Vertex>(General.Map.Map.Vertices);
|
||||||
MapSet map = General.Map.Map;
|
MapSet map = General.Map.Map;
|
||||||
|
|
||||||
|
//mxd. Let's use a blockmap...
|
||||||
|
RectangleF area = MapSet.CreateArea(oldlines);
|
||||||
|
BlockMap<BlockEntry> oldlinesmap = new BlockMap<BlockEntry>(area);
|
||||||
|
oldlinesmap.AddLinedefsSet(oldlines);
|
||||||
|
|
||||||
General.Map.Map.ClearAllMarks(false);
|
General.Map.Map.ClearAllMarks(false);
|
||||||
|
|
||||||
// Any points to do?
|
// Any points to do?
|
||||||
|
@ -1067,7 +1082,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
foreach(Linedef ld in newlines)
|
foreach(Linedef ld in newlines)
|
||||||
{
|
{
|
||||||
Vector2D ldcp = ld.GetCenterPoint();
|
Vector2D ldcp = ld.GetCenterPoint();
|
||||||
Linedef nld = MapSet.NearestLinedef(oldlines, ldcp);
|
Linedef nld = MapSet.NearestLinedef(oldlinesmap, ldcp); //mxd. Lines collection -> Blockmap
|
||||||
if(nld != null)
|
if(nld != null)
|
||||||
{
|
{
|
||||||
float ldside = nld.SideOfLine(ldcp);
|
float ldside = nld.SideOfLine(ldcp);
|
||||||
|
@ -1104,7 +1119,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
List<LinedefSide> endpoints = new List<LinedefSide>();
|
List<LinedefSide> endpoints = new List<LinedefSide>();
|
||||||
|
|
||||||
// Find out where the start will stitch and create test points
|
// Find out where the start will stitch and create test points
|
||||||
Linedef l1 = MapSet.NearestLinedefRange(oldlines, firstline.Start.Position, MapSet.STITCH_DISTANCE);
|
Linedef l1 = MapSet.NearestLinedefRange(oldlinesmap, firstline.Start.Position, MapSet.STITCH_DISTANCE); //mxd. Lines collection -> Blockmap
|
||||||
Vertex vv1 = null;
|
Vertex vv1 = null;
|
||||||
if(l1 != null)
|
if(l1 != null)
|
||||||
{
|
{
|
||||||
|
@ -1129,7 +1144,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find out where the end will stitch and create test points
|
// Find out where the end will stitch and create test points
|
||||||
Linedef l2 = MapSet.NearestLinedefRange(oldlines, lastline.End.Position, MapSet.STITCH_DISTANCE);
|
Linedef l2 = MapSet.NearestLinedefRange(oldlinesmap, lastline.End.Position, MapSet.STITCH_DISTANCE); //mxd. Lines collection -> Blockmap
|
||||||
Vertex vv2 = null;
|
Vertex vv2 = null;
|
||||||
if(l2 != null)
|
if(l2 != null)
|
||||||
{
|
{
|
||||||
|
@ -2200,15 +2215,23 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
{
|
{
|
||||||
if(l.Front != null && (l.Front.Sector != null && !SectorWasInvalid(l.Front.Sector)))
|
if(l.Front != null && (l.Front.Sector != null && !SectorWasInvalid(l.Front.Sector)))
|
||||||
{
|
{
|
||||||
if(!sectorsidesref.ContainsKey(l.Front.Sector)) sectorsidesref.Add(l.Front.Sector, new HashSet<Sidedef>());
|
// Add only multipart sectors
|
||||||
sectorsidesref[l.Front.Sector].Add(l.Front);
|
if(l.Front.Sector.Triangles.IslandVertices.Count > 1)
|
||||||
|
{
|
||||||
|
if(!sectorsidesref.ContainsKey(l.Front.Sector)) sectorsidesref[l.Front.Sector] = new HashSet<Sidedef>();
|
||||||
|
sectorsidesref[l.Front.Sector].Add(l.Front);
|
||||||
|
}
|
||||||
drawnsides.Add(l.Front);
|
drawnsides.Add(l.Front);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(l.Back != null && (l.Back.Sector != null && !SectorWasInvalid(l.Back.Sector)))
|
if(l.Back != null && (l.Back.Sector != null && !SectorWasInvalid(l.Back.Sector)))
|
||||||
{
|
{
|
||||||
if(!sectorsidesref.ContainsKey(l.Back.Sector)) sectorsidesref.Add(l.Back.Sector, new HashSet<Sidedef>());
|
// Add only multipart sectors
|
||||||
sectorsidesref[l.Back.Sector].Add(l.Back);
|
if(l.Back.Sector.Triangles.IslandVertices.Count > 1)
|
||||||
|
{
|
||||||
|
if(!sectorsidesref.ContainsKey(l.Back.Sector)) sectorsidesref[l.Back.Sector] = new HashSet<Sidedef>();
|
||||||
|
sectorsidesref[l.Back.Sector].Add(l.Back);
|
||||||
|
}
|
||||||
drawnsides.Add(l.Back);
|
drawnsides.Add(l.Back);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2402,28 +2425,6 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//mxd
|
|
||||||
public static Sector FindSectorContaining(Linedef line, bool front)
|
|
||||||
{
|
|
||||||
List<LinedefSide> sectorsides = FindPotentialSectorAt(line, front);
|
|
||||||
if(sectorsides == null) return null;
|
|
||||||
|
|
||||||
// Check potential sectors
|
|
||||||
foreach(LinedefSide sectorside in sectorsides)
|
|
||||||
{
|
|
||||||
Sidedef target = (sectorside.Front ? sectorside.Line.Front : sectorside.Line.Back);
|
|
||||||
if(target != null && target.Sector != null)
|
|
||||||
{
|
|
||||||
// Check if target line is inside the found sector
|
|
||||||
if(target.Sector.Intersect(line.Start.Position, false) && target.Sector.Intersect(line.End.Position, false))
|
|
||||||
return target.Sector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No dice...
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ================== Misc Exported Functions
|
#region ================== Misc Exported Functions
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
#region ================== Methods
|
#region ================== Methods
|
||||||
|
|
||||||
// This returns the block coordinates
|
// This returns the block coordinates
|
||||||
protected Point GetBlockCoordinates(Vector2D v)
|
internal Point GetBlockCoordinates(Vector2D v)
|
||||||
{
|
{
|
||||||
return new Point((int)(v.x - range.Left) >> blocksizeshift,
|
return new Point((int)(v.x - range.Left) >> blocksizeshift,
|
||||||
(int)(v.y - range.Top) >> blocksizeshift);
|
(int)(v.y - range.Top) >> blocksizeshift);
|
||||||
|
@ -119,7 +119,7 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
// This returns true when the given block is inside range
|
// This returns true when the given block is inside range
|
||||||
protected bool IsInRange(Point p)
|
internal bool IsInRange(Point p)
|
||||||
{
|
{
|
||||||
return (p.X >= 0) && (p.X < size.Width) && (p.Y >= 0) && (p.Y < size.Height);
|
return (p.X >= 0) && (p.X < size.Width) && (p.Y >= 0) && (p.Y < size.Height);
|
||||||
}
|
}
|
||||||
|
@ -356,6 +356,9 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
// This puts a sector in the blockmap
|
// This puts a sector in the blockmap
|
||||||
public virtual void AddSector(Sector s)
|
public virtual void AddSector(Sector s)
|
||||||
{
|
{
|
||||||
|
//mxd. Check range. Sector can be bigger than blockmap range
|
||||||
|
if(!range.IntersectsWith(s.BBox)) return;
|
||||||
|
|
||||||
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));
|
||||||
p1 = CropToRange(p1);
|
p1 = CropToRange(p1);
|
||||||
|
|
|
@ -1988,6 +1988,32 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
return new RectangleF(l, t, r - l, b - t);
|
return new RectangleF(l, t, r - l, b - t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>This increases and existing area with the given linedefs.</summary>
|
||||||
|
public static RectangleF IncreaseArea(RectangleF area, ICollection<Linedef> lines) //mxd
|
||||||
|
{
|
||||||
|
float l = area.Left;
|
||||||
|
float t = area.Top;
|
||||||
|
float r = area.Right;
|
||||||
|
float b = area.Bottom;
|
||||||
|
|
||||||
|
// Go for all vertices
|
||||||
|
foreach(Linedef ld in lines)
|
||||||
|
{
|
||||||
|
// Adjust boundaries by vertices
|
||||||
|
if(ld.Start.Position.x < l) l = ld.Start.Position.x;
|
||||||
|
if(ld.Start.Position.x > r) r = ld.Start.Position.x;
|
||||||
|
if(ld.Start.Position.y < t) t = ld.Start.Position.y;
|
||||||
|
if(ld.Start.Position.y > b) b = ld.Start.Position.y;
|
||||||
|
if(ld.End.Position.x < l) l = ld.End.Position.x;
|
||||||
|
if(ld.End.Position.x > r) r = ld.End.Position.x;
|
||||||
|
if(ld.End.Position.y < t) t = ld.End.Position.y;
|
||||||
|
if(ld.End.Position.y > b) b = ld.End.Position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a rect
|
||||||
|
return new RectangleF(l, t, r - l, b - t);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>This filters lines by a rectangular area.</summary>
|
/// <summary>This filters lines by a rectangular area.</summary>
|
||||||
public static HashSet<Linedef> FilterByArea(ICollection<Linedef> lines, ref RectangleF area)
|
public static HashSet<Linedef> FilterByArea(ICollection<Linedef> lines, ref RectangleF area)
|
||||||
{
|
{
|
||||||
|
@ -2436,12 +2462,21 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
if(line.Front == null) linesmissingfront.Add(line);
|
if(line.Front == null) linesmissingfront.Add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anything to do?
|
||||||
|
if(linesmissingfront.Count == 0 && linesmissingback.Count == 0) return;
|
||||||
|
|
||||||
|
// Let's use a blockmap...
|
||||||
|
RectangleF area = CreateArea(linesmissingfront);
|
||||||
|
area = IncreaseArea(area, linesmissingback);
|
||||||
|
BlockMap<BlockEntry> blockmap = new BlockMap<BlockEntry>(area);
|
||||||
|
blockmap.AddSectorsSet(General.Map.Map.Sectors);
|
||||||
|
|
||||||
// Find sectors to join singlesided lines
|
// Find sectors to join singlesided lines
|
||||||
Dictionary<Linedef, Sector> linefrontsectorref = new Dictionary<Linedef, Sector>();
|
Dictionary<Linedef, Sector> linefrontsectorref = new Dictionary<Linedef, Sector>();
|
||||||
foreach(Linedef line in linesmissingfront)
|
foreach(Linedef line in linesmissingfront)
|
||||||
{
|
{
|
||||||
// Line is now inside a sector? (check from the missing side!)
|
// Line is now inside a sector?
|
||||||
Sector nearest = Tools.FindSectorContaining(line, true);
|
Sector nearest = FindSectorContaining(blockmap, line);
|
||||||
|
|
||||||
// We can reattach our line!
|
// We can reattach our line!
|
||||||
if(nearest != null) linefrontsectorref[line] = nearest;
|
if(nearest != null) linefrontsectorref[line] = nearest;
|
||||||
|
@ -2450,8 +2485,8 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
Dictionary<Linedef, Sector> linebacksectorref = new Dictionary<Linedef, Sector>();
|
Dictionary<Linedef, Sector> linebacksectorref = new Dictionary<Linedef, Sector>();
|
||||||
foreach(Linedef line in linesmissingback)
|
foreach(Linedef line in linesmissingback)
|
||||||
{
|
{
|
||||||
// Line is now inside a sector? (check from the missing side!)
|
// Line is now inside a sector?
|
||||||
Sector nearest = Tools.FindSectorContaining(line, false);
|
Sector nearest = FindSectorContaining(blockmap, line);
|
||||||
|
|
||||||
// We can reattach our line!
|
// We can reattach our line!
|
||||||
if(nearest != null) linebacksectorref[line] = nearest;
|
if(nearest != null) linebacksectorref[line] = nearest;
|
||||||
|
@ -2512,6 +2547,28 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
private static Sector FindSectorContaining(BlockMap<BlockEntry> sectorsmap, Linedef line)
|
||||||
|
{
|
||||||
|
HashSet<BlockEntry> blocks = new HashSet<BlockEntry>
|
||||||
|
{
|
||||||
|
sectorsmap.GetBlockAt(line.Start.Position),
|
||||||
|
sectorsmap.GetBlockAt(line.End.Position),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach(BlockEntry be in blocks)
|
||||||
|
{
|
||||||
|
foreach(Sector sector in be.Sectors)
|
||||||
|
{
|
||||||
|
// Check if target line is inside the found sector
|
||||||
|
if(sector.Intersect(line.Start.Position, false) && sector.Intersect(line.End.Position, false))
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
private static string GetAdjacentMiddleTexture(Vertex v)
|
private static string GetAdjacentMiddleTexture(Vertex v)
|
||||||
{
|
{
|
||||||
|
@ -2727,46 +2784,78 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
//mxd. Create blockmap
|
||||||
|
ICollection<Vertex> biggerset, smallerset;
|
||||||
|
bool keepsmaller;
|
||||||
|
if(set1.Count > set2.Count)
|
||||||
|
{
|
||||||
|
biggerset = set1;
|
||||||
|
smallerset = set2;
|
||||||
|
keepsmaller = !keepsecond;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
biggerset = set2;
|
||||||
|
smallerset = set1;
|
||||||
|
keepsmaller = keepsecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectangleF area = CreateArea(biggerset);
|
||||||
|
BlockMap<BlockEntry> blockmap = new BlockMap<BlockEntry>(area);
|
||||||
|
blockmap.AddVerticesSet(biggerset);
|
||||||
|
|
||||||
// No joins yet
|
// No joins yet
|
||||||
joined = false;
|
joined = false;
|
||||||
|
|
||||||
// Go for all vertices in the first set
|
// Go for all vertices in the smaller set
|
||||||
foreach(Vertex v1 in set1)
|
foreach(Vertex v1 in smallerset)
|
||||||
{
|
{
|
||||||
// Go for all vertices in the second set
|
HashSet<BlockEntry> blocks = new HashSet<BlockEntry>
|
||||||
foreach(Vertex v2 in set2)
|
|
||||||
{
|
{
|
||||||
// Check if vertices are close enough
|
blockmap.GetBlockAt(v1.Position),
|
||||||
if(v1.DistanceToSq(v2.Position) <= joindist2)
|
blockmap.GetBlockAt(new Vector2D(v1.Position.x + joindist, v1.Position.y + joindist)),
|
||||||
|
blockmap.GetBlockAt(new Vector2D(v1.Position.x + joindist, v1.Position.y - joindist)),
|
||||||
|
blockmap.GetBlockAt(new Vector2D(v1.Position.x - joindist, v1.Position.y + joindist)),
|
||||||
|
blockmap.GetBlockAt(new Vector2D(v1.Position.x - joindist, v1.Position.y - joindist))
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach(BlockEntry be in blocks)
|
||||||
|
{
|
||||||
|
if(be == null) continue;
|
||||||
|
foreach(Vertex v2 in be.Vertices)
|
||||||
{
|
{
|
||||||
// Check if not the same vertex
|
// Check if vertices are close enough
|
||||||
if(v1 != v2)
|
if(v1.DistanceToSq(v2.Position) <= joindist2)
|
||||||
{
|
{
|
||||||
// Move the second vertex to match the first
|
// Check if not the same vertex
|
||||||
v2.Move(v1.Position);
|
if(v1 != v2)
|
||||||
|
|
||||||
// Check which one to keep
|
|
||||||
if(keepsecond)
|
|
||||||
{
|
{
|
||||||
// Join the first into the second
|
// Move the second vertex to match the first
|
||||||
// Second is kept, first is removed
|
v2.Move(v1.Position);
|
||||||
v1.Join(v2);
|
|
||||||
set1.Remove(v1);
|
// Check which one to keep
|
||||||
set2.Remove(v1);
|
if(keepsmaller)
|
||||||
|
{
|
||||||
|
// Join the first into the second
|
||||||
|
// Second is kept, first is removed
|
||||||
|
v1.Join(v2);
|
||||||
|
biggerset.Remove(v1);
|
||||||
|
smallerset.Remove(v1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Join the second into the first
|
||||||
|
// First is kept, second is removed
|
||||||
|
v2.Join(v1);
|
||||||
|
biggerset.Remove(v2);
|
||||||
|
smallerset.Remove(v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the join
|
||||||
|
joinsdone++;
|
||||||
|
joined = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Join the second into the first
|
|
||||||
// First is kept, second is removed
|
|
||||||
v2.Join(v1);
|
|
||||||
set1.Remove(v2);
|
|
||||||
set2.Remove(v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count the join
|
|
||||||
joinsdone++;
|
|
||||||
joined = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3176,6 +3265,62 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>This finds the line closest to the specified position.</summary>
|
||||||
|
public static Linedef NearestLinedef(BlockMap<BlockEntry> selectionmap, Vector2D pos) //mxd
|
||||||
|
{
|
||||||
|
Linedef closest = null;
|
||||||
|
float distance = float.MaxValue;
|
||||||
|
|
||||||
|
Point p = selectionmap.GetBlockCoordinates(pos);
|
||||||
|
int minx = p.X;
|
||||||
|
int maxx = p.X;
|
||||||
|
int miny = p.Y;
|
||||||
|
int maxy = p.Y;
|
||||||
|
int step = 0;
|
||||||
|
|
||||||
|
// Check square block ranges around pos...
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
bool noblocksfound = true;
|
||||||
|
for(int x = minx; x < maxx + 1; x++)
|
||||||
|
{
|
||||||
|
for(int y = miny; y < maxy + 1; y++)
|
||||||
|
{
|
||||||
|
// Skip inner blocks...
|
||||||
|
if(x > minx && x < maxx && y > miny && y < maxy) continue;
|
||||||
|
if(!selectionmap.IsInRange(new Point(x, y))) continue;
|
||||||
|
|
||||||
|
// Go for all linedefs in block
|
||||||
|
BlockEntry be = selectionmap.Map[x, y];
|
||||||
|
foreach(Linedef l in be.Lines)
|
||||||
|
{
|
||||||
|
// Calculate distance and check if closer than previous find
|
||||||
|
float d = l.SafeDistanceToSq(pos, true);
|
||||||
|
if(d < distance)
|
||||||
|
{
|
||||||
|
// This one is closer
|
||||||
|
closest = l;
|
||||||
|
distance = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noblocksfound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort if line was found or when outside of blockmap range...
|
||||||
|
// Check at least 3x3 blocks, because there's a possibility that a line closer to pos exists in a nearby block than in the first block
|
||||||
|
if(noblocksfound || (closest != null && step > 0)) return closest;
|
||||||
|
|
||||||
|
// Increase search range...
|
||||||
|
minx--;
|
||||||
|
maxx++;
|
||||||
|
miny--;
|
||||||
|
maxy++;
|
||||||
|
step++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>This finds the line closest to the specified position.</summary>
|
/// <summary>This finds the line closest to the specified position.</summary>
|
||||||
public static Linedef NearestLinedef(ICollection<Linedef> selection, Vector2D pos)
|
public static Linedef NearestLinedef(ICollection<Linedef> selection, Vector2D pos)
|
||||||
{
|
{
|
||||||
|
@ -3223,6 +3368,48 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>This finds the line closest to the specified position.</summary>
|
||||||
|
public static Linedef NearestLinedefRange(BlockMap<BlockEntry> selectionmap, Vector2D pos, float maxrange) //mxd
|
||||||
|
{
|
||||||
|
Linedef closest = null;
|
||||||
|
float distance = float.MaxValue;
|
||||||
|
float maxrangesq = maxrange * maxrange;
|
||||||
|
HashSet<Linedef> processed = new HashSet<Linedef>();
|
||||||
|
|
||||||
|
HashSet<BlockEntry> blocks = new HashSet<BlockEntry>
|
||||||
|
{
|
||||||
|
selectionmap.GetBlockAt(pos),
|
||||||
|
selectionmap.GetBlockAt(new Vector2D(pos.x + maxrange, pos.y + maxrange)),
|
||||||
|
selectionmap.GetBlockAt(new Vector2D(pos.x + maxrange, pos.y - maxrange)),
|
||||||
|
selectionmap.GetBlockAt(new Vector2D(pos.x - maxrange, pos.y + maxrange)),
|
||||||
|
selectionmap.GetBlockAt(new Vector2D(pos.x - maxrange, pos.y - maxrange))
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach(BlockEntry be in blocks)
|
||||||
|
{
|
||||||
|
if(be == null) continue;
|
||||||
|
|
||||||
|
foreach(Linedef l in be.Lines)
|
||||||
|
{
|
||||||
|
if(processed.Contains(l)) continue;
|
||||||
|
|
||||||
|
// Calculate distance and check if closer than previous find
|
||||||
|
float d = l.SafeDistanceToSq(pos, true);
|
||||||
|
if(d < distance && d <= maxrangesq)
|
||||||
|
{
|
||||||
|
// This one is closer
|
||||||
|
closest = l;
|
||||||
|
distance = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
processed.Add(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>mxd. This finds the line closest to the specified position excluding given list of linedefs.</summary>
|
/// <summary>mxd. This finds the line closest to the specified position excluding given list of linedefs.</summary>
|
||||||
public Linedef NearestLinedef(Vector2D pos, HashSet<Linedef> linesToExclude)
|
public Linedef NearestLinedef(Vector2D pos, HashSet<Linedef> linesToExclude)
|
||||||
{
|
{
|
||||||
|
|
|
@ -399,6 +399,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
else if(editpressed && prevoffset != 0)
|
else if(editpressed && prevoffset != 0)
|
||||||
{
|
{
|
||||||
int diff = (int)Math.Round((offset - prevoffset) * renderer.Scale);
|
int diff = (int)Math.Round((offset - prevoffset) * renderer.Scale);
|
||||||
|
if(panel.FixedCurve) diff *= Math.Sign(panel.Distance); // Special cases...
|
||||||
if(panel.Angle + diff > 0) panel.Angle += diff;
|
if(panel.Angle + diff > 0) panel.Angle += diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1589,6 +1589,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
|
|
||||||
// Go for all sidedes in the new geometry
|
// Go for all sidedes in the new geometry
|
||||||
List<Sidedef> newsides = General.Map.Map.GetMarkedSidedefs(true);
|
List<Sidedef> newsides = General.Map.Map.GetMarkedSidedefs(true);
|
||||||
|
List<Linedef> oldlines = General.Map.Map.GetMarkedLinedefs(false); //mxd
|
||||||
|
|
||||||
|
//mxd. Let's use a blockmap...
|
||||||
|
RectangleF area = MapSet.CreateArea(oldlines);
|
||||||
|
BlockMap<BlockEntry> blockmap = new BlockMap<BlockEntry>(area);
|
||||||
|
blockmap.AddLinedefsSet(oldlines);
|
||||||
|
|
||||||
foreach(Sidedef s in newsides)
|
foreach(Sidedef s in newsides)
|
||||||
{
|
{
|
||||||
// Connected to a virtual sector?
|
// Connected to a virtual sector?
|
||||||
|
@ -1607,7 +1614,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
{
|
{
|
||||||
// Find out in which sector this was pasted
|
// Find out in which sector this was pasted
|
||||||
Vector2D testpoint = s.Line.GetSidePoint(!s.IsFront);
|
Vector2D testpoint = s.Line.GetSidePoint(!s.IsFront);
|
||||||
Linedef nl = MapSet.NearestLinedef(General.Map.Map.GetMarkedLinedefs(false), testpoint);
|
Linedef nl = MapSet.NearestLinedef(blockmap, testpoint); //mxd
|
||||||
if(nl != null)
|
if(nl != null)
|
||||||
{
|
{
|
||||||
Sidedef joinsidedef = (nl.SideOfLine(testpoint) <= 0 ? nl.Front : nl.Back);
|
Sidedef joinsidedef = (nl.SideOfLine(testpoint) <= 0 ? nl.Front : nl.Back);
|
||||||
|
|
|
@ -1810,6 +1810,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
// Go into curve linedefs mode
|
// Go into curve linedefs mode
|
||||||
General.Editing.ChangeMode(new CurveLinedefsMode());
|
General.Editing.ChangeMode(new CurveLinedefsMode());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//mxd
|
||||||
|
General.Interface.DisplayStatus(StatusType.Warning, "This action requres a selection!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BeginAction("fliplinedefs")]
|
[BeginAction("fliplinedefs")]
|
||||||
|
|
|
@ -35,12 +35,13 @@
|
||||||
this.distance = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
|
this.distance = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
|
||||||
this.anglelabel = new System.Windows.Forms.ToolStripLabel();
|
this.anglelabel = new System.Windows.Forms.ToolStripLabel();
|
||||||
this.angle = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
|
this.angle = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
|
||||||
|
this.reset = new System.Windows.Forms.ToolStripButton();
|
||||||
this.separator1 = new System.Windows.Forms.ToolStripSeparator();
|
this.separator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.fixedcurve = new System.Windows.Forms.ToolStripButton();
|
this.fixedcurve = new System.Windows.Forms.ToolStripButton();
|
||||||
this.separator2 = new System.Windows.Forms.ToolStripSeparator();
|
this.separator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.apply = new System.Windows.Forms.ToolStripButton();
|
this.apply = new System.Windows.Forms.ToolStripButton();
|
||||||
this.cancel = new System.Windows.Forms.ToolStripButton();
|
this.cancel = new System.Windows.Forms.ToolStripButton();
|
||||||
this.reset = new System.Windows.Forms.ToolStripButton();
|
this.flip = new System.Windows.Forms.ToolStripButton();
|
||||||
this.toolstrip.SuspendLayout();
|
this.toolstrip.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
this.distance,
|
this.distance,
|
||||||
this.anglelabel,
|
this.anglelabel,
|
||||||
this.angle,
|
this.angle,
|
||||||
|
this.flip,
|
||||||
this.reset,
|
this.reset,
|
||||||
this.separator1,
|
this.separator1,
|
||||||
this.fixedcurve,
|
this.fixedcurve,
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
this.cancel});
|
this.cancel});
|
||||||
this.toolstrip.Location = new System.Drawing.Point(0, 0);
|
this.toolstrip.Location = new System.Drawing.Point(0, 0);
|
||||||
this.toolstrip.Name = "toolstrip";
|
this.toolstrip.Name = "toolstrip";
|
||||||
this.toolstrip.Size = new System.Drawing.Size(620, 25);
|
this.toolstrip.Size = new System.Drawing.Size(760, 25);
|
||||||
this.toolstrip.TabIndex = 0;
|
this.toolstrip.TabIndex = 0;
|
||||||
this.toolstrip.Text = "toolStrip1";
|
this.toolstrip.Text = "toolStrip1";
|
||||||
//
|
//
|
||||||
|
@ -170,6 +172,17 @@
|
||||||
0});
|
0});
|
||||||
this.angle.ValueChanged += new System.EventHandler(this.OnUIValuesChanged);
|
this.angle.ValueChanged += new System.EventHandler(this.OnUIValuesChanged);
|
||||||
//
|
//
|
||||||
|
// reset
|
||||||
|
//
|
||||||
|
this.reset.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||||
|
this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
|
||||||
|
this.reset.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||||
|
this.reset.Margin = new System.Windows.Forms.Padding(0, 1, 3, 2);
|
||||||
|
this.reset.Name = "reset";
|
||||||
|
this.reset.Size = new System.Drawing.Size(23, 22);
|
||||||
|
this.reset.Text = "Reset";
|
||||||
|
this.reset.Click += new System.EventHandler(this.reset_Click);
|
||||||
|
//
|
||||||
// separator1
|
// separator1
|
||||||
//
|
//
|
||||||
this.separator1.Name = "separator1";
|
this.separator1.Name = "separator1";
|
||||||
|
@ -212,16 +225,15 @@
|
||||||
this.cancel.Text = "Cancel";
|
this.cancel.Text = "Cancel";
|
||||||
this.cancel.Click += new System.EventHandler(this.cancel_Click);
|
this.cancel.Click += new System.EventHandler(this.cancel_Click);
|
||||||
//
|
//
|
||||||
// reset
|
// flip
|
||||||
//
|
//
|
||||||
this.reset.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
this.flip.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||||
this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
|
this.flip.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Flip;
|
||||||
this.reset.ImageTransparentColor = System.Drawing.Color.Magenta;
|
this.flip.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||||
this.reset.Margin = new System.Windows.Forms.Padding(0, 1, 3, 2);
|
this.flip.Name = "flip";
|
||||||
this.reset.Name = "reset";
|
this.flip.Size = new System.Drawing.Size(23, 22);
|
||||||
this.reset.Size = new System.Drawing.Size(23, 22);
|
this.flip.Text = "Flip Curve";
|
||||||
this.reset.Text = "Reset";
|
this.flip.Click += new System.EventHandler(this.flip_Click);
|
||||||
this.reset.Click += new System.EventHandler(this.reset_Click);
|
|
||||||
//
|
//
|
||||||
// CurveLinedefsOptionsPanel
|
// CurveLinedefsOptionsPanel
|
||||||
//
|
//
|
||||||
|
@ -229,7 +241,7 @@
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||||
this.Controls.Add(this.toolstrip);
|
this.Controls.Add(this.toolstrip);
|
||||||
this.Name = "CurveLinedefsOptionsPanel";
|
this.Name = "CurveLinedefsOptionsPanel";
|
||||||
this.Size = new System.Drawing.Size(620, 60);
|
this.Size = new System.Drawing.Size(760, 60);
|
||||||
this.toolstrip.ResumeLayout(false);
|
this.toolstrip.ResumeLayout(false);
|
||||||
this.toolstrip.PerformLayout();
|
this.toolstrip.PerformLayout();
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
@ -252,5 +264,6 @@
|
||||||
private System.Windows.Forms.ToolStripButton apply;
|
private System.Windows.Forms.ToolStripButton apply;
|
||||||
private System.Windows.Forms.ToolStripButton cancel;
|
private System.Windows.Forms.ToolStripButton cancel;
|
||||||
private System.Windows.Forms.ToolStripButton reset;
|
private System.Windows.Forms.ToolStripButton reset;
|
||||||
|
private System.Windows.Forms.ToolStripButton flip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface
|
||||||
General.Interface.AddButton(distance);
|
General.Interface.AddButton(distance);
|
||||||
General.Interface.AddButton(anglelabel);
|
General.Interface.AddButton(anglelabel);
|
||||||
General.Interface.AddButton(angle);
|
General.Interface.AddButton(angle);
|
||||||
|
General.Interface.AddButton(flip);
|
||||||
General.Interface.AddButton(reset);
|
General.Interface.AddButton(reset);
|
||||||
General.Interface.AddButton(separator1);
|
General.Interface.AddButton(separator1);
|
||||||
General.Interface.AddButton(fixedcurve);
|
General.Interface.AddButton(fixedcurve);
|
||||||
|
@ -77,6 +78,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface
|
||||||
General.Interface.RemoveButton(fixedcurve);
|
General.Interface.RemoveButton(fixedcurve);
|
||||||
General.Interface.RemoveButton(separator1);
|
General.Interface.RemoveButton(separator1);
|
||||||
General.Interface.RemoveButton(reset);
|
General.Interface.RemoveButton(reset);
|
||||||
|
General.Interface.RemoveButton(flip);
|
||||||
General.Interface.RemoveButton(angle);
|
General.Interface.RemoveButton(angle);
|
||||||
General.Interface.RemoveButton(anglelabel);
|
General.Interface.RemoveButton(anglelabel);
|
||||||
General.Interface.RemoveButton(distance);
|
General.Interface.RemoveButton(distance);
|
||||||
|
@ -115,6 +117,11 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface
|
||||||
if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
|
if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void flip_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
distance.Value = -distance.Value;
|
||||||
|
}
|
||||||
|
|
||||||
private void reset_Click(object sender, EventArgs e)
|
private void reset_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetValues(CurveLinedefsMode.DEFAULT_VERTICES_COUNT, CurveLinedefsMode.DEFAULT_DISTANCE, CurveLinedefsMode.DEFAULT_ANGLE, false);
|
SetValues(CurveLinedefsMode.DEFAULT_VERTICES_COUNT, CurveLinedefsMode.DEFAULT_DISTANCE, CurveLinedefsMode.DEFAULT_ANGLE, false);
|
||||||
|
|
Loading…
Reference in a new issue