Skip to content

Commit

Permalink
Add solid factories for pyramid, tetrahedron, UV sphere, wedge
Browse files Browse the repository at this point in the history
  • Loading branch information
LogicAndTrick committed Jul 10, 2024
1 parent 183c776 commit e9052f1
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 21 deletions.
1 change: 0 additions & 1 deletion Sledge.Formats.Map/Factories/Solids/ConeSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;
Expand Down
3 changes: 1 addition & 2 deletions Sledge.Formats.Map/Factories/Solids/ISolidFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel;
using Sledge.Formats.Map.Objects;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
Expand Down
17 changes: 0 additions & 17 deletions Sledge.Formats.Map/Factories/Solids/PipeSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;
Expand All @@ -22,22 +21,6 @@ public class PipeSolidFactory : SolidFactoryBase
[MapObjectFactoryPropertyData(MinValue = 0.01, DecimalPrecision = 2)]
public int WallWidth { get; set; }

private static Solid MakeSolid(IEnumerable<(string textureName, Vector3[] points)> faces, Color col)
{
var solid = new Solid { Color = col };
foreach (var (texture, arr) in faces)
{
var face = new Face
{
Plane = Plane.CreateFromVertices(arr[0], arr[1], arr[2]),
TextureName = texture
};
face.Vertices.AddRange(arr);
solid.Faces.Add(face);
}
return solid;
}

public override IEnumerable<MapObject> Create(Box box)
{
var numSides = NumberOfSides;
Expand Down
46 changes: 46 additions & 0 deletions Sledge.Formats.Map/Factories/Solids/PyramidSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
public class PyramidSolidFactory : SolidFactoryBase
{
public override string Name => "Pyramid";

public override IEnumerable<MapObject> Create(Box box)
{
var solid = new Solid
{
Color = ColorUtils.GetRandomBrushColour()
};

// The lower Z plane will be base
var c1 = new Vector3(box.Start.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c2 = new Vector3(box.End.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c3 = new Vector3(box.End.X, box.End.Y, box.Start.Z).Round(RoundDecimals);
var c4 = new Vector3(box.Start.X, box.End.Y, box.Start.Z).Round(RoundDecimals);
var c5 = new Vector3(box.Center.X, box.Center.Y, box.End.Z).Round(RoundDecimals);
var faces = new[]
{
new[] { c4, c3, c2, c1 },
new[] { c5, c1, c2 },
new[] { c5, c2, c3 },
new[] { c5, c3, c4 },
new[] { c5, c4, c1 }
};
foreach (var arr in faces)
{
var face = new Face
{
Plane = Plane.CreateFromVertices(arr[0], arr[1], arr[2]),
TextureName = VisibleTextureName
};
face.Vertices.AddRange(arr);
solid.Faces.Add(face);
}
yield return solid;
}
}
}
22 changes: 21 additions & 1 deletion Sledge.Formats.Map/Factories/Solids/SolidFactoryBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System.ComponentModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Numerics;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
Expand All @@ -18,5 +22,21 @@ public abstract class SolidFactoryBase : MapObjectFactoryBase, ISolidFactory
[DisplayName("Round decimals")]
[Description("The number of decimals to round vertex positions to")]
public int RoundDecimals { get; set; }

protected static Solid MakeSolid(IEnumerable<(string textureName, Vector3[] points)> faces, Color col)
{
var solid = new Solid { Color = col };
foreach (var (texture, arr) in faces)
{
var face = new Face
{
Plane = Plane.CreateFromVertices(arr[0], arr[1], arr[2]),
TextureName = texture
};
face.Vertices.AddRange(arr);
solid.Faces.Add(face);
}
return solid;
}
}
}
53 changes: 53 additions & 0 deletions Sledge.Formats.Map/Factories/Solids/TetrahedronSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
public class TetrahedronSolidFactory : SolidFactoryBase
{
public override string Name => "Tetrahedron";

[DisplayName("Top vertex at centroid")]
[Description("Put the top vertex at the centroid of the base triangle instead of at the center of the bounding box")]
public bool TopVertexAtCentroid { get; set; }

public override IEnumerable<MapObject> Create(Box box)
{
var useCentroid = TopVertexAtCentroid;

// The lower Z plane will be the triangle, with the lower Y value getting the two corners
var c1 = new Vector3(box.Start.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c2 = new Vector3(box.End.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c3 = new Vector3(box.Center.X, box.End.Y, box.Start.Z).Round(RoundDecimals);
var centroid = new Vector3((c1.X + c2.X + c3.X) / 3, (c1.Y + c2.Y + c3.Y) / 3, box.End.Z);
var c4 = (useCentroid ? centroid : new Vector3(box.Center.X, box.Center.Y, box.End.Z)).Round(RoundDecimals);

var faces = new[] {
new[] { c3, c2, c1 },
new[] { c3, c1, c4 },
new[] { c2, c3, c4 },
new[] { c1, c2, c4 }
};

var solid = new Solid
{
Color = ColorUtils.GetRandomBrushColour()
};

foreach (var arr in faces)
{
var face = new Face
{
Plane = Plane.CreateFromVertices(arr[0], arr[1], arr[2]),
TextureName = VisibleTextureName
};
face.Vertices.AddRange(arr);
solid.Faces.Add(face);
}
yield return solid;
}
}
}
90 changes: 90 additions & 0 deletions Sledge.Formats.Map/Factories/Solids/UVSphereSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
public class UVSphereSolidFactory : SolidFactoryBase
{
public override string Name => "UV Sphere";

[DisplayName("Number of segments (vertical)")]
[Description("The number of segments the sphere will have vertically")]
[MapObjectFactoryPropertyData(MinValue = 3)]
public int NumberOfSegmentsVertical { get; set; }

[DisplayName("Number of segments (horizontal)")]
[Description("The number of segments the sphere will have horizontally")]
[MapObjectFactoryPropertyData(MinValue = 3)]
public int NumberOfSegmentsHorizontal { get; set; }

public override IEnumerable<MapObject> Create(Box box)
{
var numSidesV = NumberOfSegmentsVertical;
if (numSidesV < 3) throw new ArgumentException("NumberOfSegmentsVertical must be >= 3", nameof(NumberOfSegmentsVertical));

var numSidesH = NumberOfSegmentsHorizontal;
if (numSidesH < 3) throw new ArgumentException("NumberOfSegmentsHorizontal must be >= 3", nameof(NumberOfSegmentsHorizontal));

var roundDecimals = Math.Max(2, RoundDecimals); // don't support rounding < 2 because it would result in invalid faces too often

var width = box.Width;
var length = box.Length;
var height = box.Height;
var major = width / 2;
var minor = length / 2;
var heightRadius = height / 2;

var angleV = (float)Math.PI / numSidesV;
var angleH = (float)(Math.PI * 2) / numSidesH;

var faces = new List<(string textureName, Vector3[] points)>();
var bottom = new Vector3(box.Center.X, box.Center.Y, box.Start.Z).Round(roundDecimals);
var top = new Vector3(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals);

for (var i = 0; i < numSidesV; i++)
{
// Top -> bottom
var zAngleStart = angleV * i;
var zAngleEnd = angleV * (i + 1);
var zStart = heightRadius * (float)Math.Cos(zAngleStart);
var zEnd = heightRadius * (float)Math.Cos(zAngleEnd);
var zMultStart = (float)Math.Sin(zAngleStart);
var zMultEnd = (float)Math.Sin(zAngleEnd);
for (var j = 0; j < numSidesH; j++)
{
// Go around the circle in X/Y
var xyAngleStart = angleH * j;
var xyAngleEnd = angleH * ((j + 1) % numSidesH);
var xyStartX = major * (float)Math.Cos(xyAngleStart);
var xyStartY = minor * (float)Math.Sin(xyAngleStart);
var xyEndX = major * (float)Math.Cos(xyAngleEnd);
var xyEndY = minor * (float)Math.Sin(xyAngleEnd);
var one = (new Vector3(xyStartX * zMultStart, xyStartY * zMultStart, zStart) + box.Center).Round(roundDecimals);
var two = (new Vector3(xyEndX * zMultStart, xyEndY * zMultStart, zStart) + box.Center).Round(roundDecimals);
var three = (new Vector3(xyEndX * zMultEnd, xyEndY * zMultEnd, zEnd) + box.Center).Round(roundDecimals);
var four = (new Vector3(xyStartX * zMultEnd, xyStartY * zMultEnd, zEnd) + box.Center).Round(roundDecimals);
if (i == 0)
{
// Top faces are triangles
faces.Add((VisibleTextureName, new[] { four, three, top }));
}
else if (i == numSidesV - 1)
{
// Bottom faces are also triangles
faces.Add((VisibleTextureName, new[] { two, one, bottom }));
}
else
{
// Inner faces are quads
faces.Add((VisibleTextureName, new[] { four, three, two, one }));
}
}
}
yield return MakeSolid(faces, ColorUtils.GetRandomBrushColour());
}
}
}
47 changes: 47 additions & 0 deletions Sledge.Formats.Map/Factories/Solids/WedgeSolidFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Numerics;
using Sledge.Formats.Geometric;
using Sledge.Formats.Map.Objects;

namespace Sledge.Formats.Map.Factories.Solids
{
public class WedgeSolidFactory : SolidFactoryBase
{
public override string Name => "Wedge";

public override IEnumerable<MapObject> Create(Box box)
{
var solid = new Solid
{
Color = ColorUtils.GetRandomBrushColour()
};

// The lower Z plane will be base, the x planes will be triangles
var c1 = new Vector3(box.Start.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c2 = new Vector3(box.End.X, box.Start.Y, box.Start.Z).Round(RoundDecimals);
var c3 = new Vector3(box.End.X, box.End.Y, box.Start.Z).Round(RoundDecimals);
var c4 = new Vector3(box.Start.X, box.End.Y, box.Start.Z).Round(RoundDecimals);
var c5 = new Vector3(box.Center.X, box.Start.Y, box.End.Z).Round(RoundDecimals);
var c6 = new Vector3(box.Center.X, box.End.Y, box.End.Z).Round(RoundDecimals);
var faces = new[]
{
new[] { c4, c3, c2, c1 },
new[] { c5, c1, c2 },
new[] { c2, c3, c6, c5 },
new[] { c6, c3, c4 },
new[] { c4, c1, c5, c6 }
};
foreach (var arr in faces)
{
var face = new Face
{
Plane = Plane.CreateFromVertices(arr[0], arr[1], arr[2]),
TextureName = VisibleTextureName
};
face.Vertices.AddRange(arr);
solid.Faces.Add(face);
}
yield return solid;
}
}
}
2 changes: 2 additions & 0 deletions Sledge.Formats.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UV/@EntryIndexedValue">UV</s:String></wpf:ResourceDictionary>

0 comments on commit e9052f1

Please sign in to comment.