public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numSides = (int)_numSides.GetValue(); if (numSides < 3) { yield break; } // This is all very similar to the cylinder brush. var width = box.Width; var length = box.Length; var major = width / 2; var minor = length / 2; var angle = 2 * DMath.PI / numSides; var points = new Coordinate[numSides]; for (var i = 0; i < numSides; i++) { var a = i * angle; var xval = box.Center.X + major * DMath.Cos(a); var yval = box.Center.Y + minor * DMath.Sin(a); var zval = box.Start.Z; points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); } var faces = new List <Coordinate[]>(); var point = new Coordinate(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals); for (var i = 0; i < numSides; i++) { var next = (i + 1) % numSides; faces.Add(new[] { points[i], point, points[next] }); } faces.Add(points.ToArray()); var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
private IEnumerable <MapObject> GroupCopy(IDGenerator gen, MapObject allGroup, List <MapObject> copy) { switch (_grouping) { case PasteSpecialGrouping.None: // No grouping - add directly to tree return(copy); case PasteSpecialGrouping.Individual: // Use one group per copy var group = new Group(gen.GetNextObjectID()); copy.ForEach(x => x.SetParent(group)); return(new List <MapObject> { group }); case PasteSpecialGrouping.All: // Use one group for all copies copy.ForEach(x => x.SetParent(allGroup)); return(new MapObject[0]); default: throw new ArgumentOutOfRangeException(); } }
private static void Reindex(IEnumerable <MapObject> objs, IDGenerator generator) { foreach (var o in objs) { if (o is Solid) { ((Solid)o).Faces.ForEach(x => x.ID = generator.GetNextFaceID()); } // Remove the children var children = o.GetChildren().ToList(); children.ForEach(x => x.SetParent(null)); // re-index the children Reindex(children, generator); // Change the ID o.ID = generator.GetNextObjectID(); // Re-add the children children.ForEach(x => x.SetParent(o)); if (!o.HasChildren) { o.UpdateBoundingBox(); } } }
private Entity ReadEntity(StreamReader rdr, IDGenerator generator) { var ent = new Entity(generator.GetNextObjectID()) { EntityData = new EntityData(), Colour = Colour.GetRandomBrushColour() }; string line; while ((line = CleanLine(rdr.ReadLine())) != null) { if (String.IsNullOrWhiteSpace(line)) { continue; } if (line[0] == '"') { ReadProperty(ent, line); } else if (line[0] == '{') { var s = ReadSolid(rdr, generator); if (s != null) { s.SetParent(ent, false); } } else if (line[0] == '}') { break; } } ent.UpdateBoundingBox(false); return(ent); }
public void CopyEntityTest() { var idGen = new IDGenerator(); var box = new Box(Coordinate.One * -100, Coordinate.One * 100); // Create an entity with children var ent = new Entity(idGen.GetNextObjectID()); ent.EntityData.Name = "Test"; ent.EntityData.Properties.Add(new Property { Key = "key1", Value = "value1" }); ent.EntityData.Properties.Add(new Property { Key = "key2", Value = "value2" }); ent.EntityData.Flags = 12345; var solids = new BlockBrush().Create(idGen, box, null, 0); foreach (var mo in solids) { mo.SetParent(ent); } // Copy and reconstruct var gs = VmfProvider.CreateCopyStream(new List <MapObject> { ent }); var pasted = VmfProvider.ExtractCopyStream(gs, idGen).ToList(); // Test object Assert.AreEqual(1, pasted.Count); Assert.IsInstanceOfType(pasted[0], typeof(Entity)); // Test entity var pastedEnt = (Entity)pasted[0]; Assert.AreEqual("Test", pastedEnt.EntityData.Name); Assert.AreEqual(12345, pastedEnt.EntityData.Flags); // Test properties Assert.AreEqual(2, pastedEnt.EntityData.Properties.Count); var k1 = pastedEnt.EntityData.Properties.FirstOrDefault(x => x.Key == "key1"); var k2 = pastedEnt.EntityData.Properties.FirstOrDefault(x => x.Key == "key1"); Assert.IsNotNull(k1); Assert.IsNotNull(k2); Assert.AreEqual(k1.Value, "value1"); Assert.AreEqual(k2.Value, "value1"); // Test child Assert.AreEqual(1, pastedEnt.ChildCount); Assert.IsInstanceOfType(pastedEnt.GetChildren().ToList()[0], typeof(Solid)); // Check number of sides, values of sides not so important var pastedSolid = (Solid)pastedEnt.GetChildren().ToList()[0]; Assert.AreEqual(6, pastedSolid.Faces.Count); }
private static Group ReadMapGroup(BinaryReader br, List <Visgroup> visgroups, IDGenerator generator) { var grp = new Group(generator.GetNextObjectID()); ReadMapBase(br, grp, visgroups, generator); grp.UpdateBoundingBox(false); return(grp); }
private static long GetObjectID(GenericStructure gs, IDGenerator generator) { var id = gs.PropertyLong("id"); if (id == 0) { id = generator.GetNextObjectID(); } return(id); }
private static Entity ReadMapEntity(BinaryReader br, List <Visgroup> visgroups, IDGenerator generator) { var ent = new Entity(generator.GetNextObjectID()); ReadMapBase(br, ent, visgroups, generator); ent.EntityData = ReadEntityData(br); br.ReadBytes(2); // Unused ent.Origin = br.ReadCoordinate(); br.ReadBytes(4); // Unused ent.UpdateBoundingBox(false); return(ent); }
private static MapObject ReadMapWorld(BinaryReader br, List <Visgroup> visgroups, IDGenerator generator) { var wld = new World(generator.GetNextObjectID()); ReadMapBase(br, wld, visgroups, generator); wld.EntityData = ReadEntityData(br); var numPaths = br.ReadInt32(); for (var i = 0; i < numPaths; i++) { wld.Paths.Add(ReadPath(br)); } return(wld); }
public void BenchmarkSolidConstruction() { var idg = new IDGenerator(); var box = new Box(Coordinate.One * -100, Coordinate.One * 100); var planes = new CylinderBrush().Create(idg, box, null, 2).OfType <Solid>().SelectMany(x => x.Faces).Select(x => x.Plane).ToList(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var b = 0; b < 1000; b++) { Solid.CreateFromIntersectingPlanes(planes, idg); } stopwatch.Stop(); Debug.WriteLine(stopwatch.Elapsed); stopwatch.Restart(); for (var b = 0; b < 1000; b++) { var polys = new List <Polygon>(); for (var i = 0; i < planes.Count; i++) { var poly = new Polygon(planes[i]); for (var j = 0; j < planes.Count; j++) { if (i != j) { poly.Split(planes[j]); } } polys.Add(poly); } var solid = new Solid(idg.GetNextObjectID()); foreach (var polygon in polys) { var face = new Face(idg.GetNextFaceID()) { Plane = polygon.Plane }; face.Vertices.AddRange(polygon.Vertices.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToWorld(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); } stopwatch.Stop(); Debug.WriteLine(stopwatch.Elapsed); }
private MapObject GetBrush(Box bounds, IDGenerator idg) { var brush = BrushManager.CurrentBrush; var ti = Document.TextureCollection.SelectedTexture; var texture = ti != null?ti.GetTexture() : null; var created = brush.Create(idg, bounds, texture, BrushManager.RoundCreatedVertices ? 0 : 2).ToList(); if (created.Count > 1) { var g = new Group(idg.GetNextObjectID()); created.ForEach(x => x.SetParent(g)); g.UpdateBoundingBox(); return(g); } return(created.FirstOrDefault()); }
private static Solid ReadMapSolid(BinaryReader br, List <Visgroup> visgroups, IDGenerator generator) { var sol = new Solid(generator.GetNextObjectID()); ReadMapBase(br, sol, visgroups, generator); var numFaces = br.ReadInt32(); for (var i = 0; i < numFaces; i++) { var face = ReadFace(br, generator); face.Parent = sol; face.Colour = sol.Colour; sol.Faces.Add(face); } sol.UpdateBoundingBox(false); return(sol); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var useCentroid = _useCentroid.GetValue(); // The lower Z plane will be the triangle, with the lower Y value getting the two corners var c1 = new Coordinate(box.Start.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c2 = new Coordinate(box.End.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c3 = new Coordinate(box.Center.X, box.End.Y, box.Start.Z).Round(roundDecimals); var centroid = new Coordinate((c1.X + c2.X + c3.X) / 3, (c1.Y + c2.Y + c3.Y) / 3, box.End.Z); var c4 = (useCentroid ? centroid : new Coordinate(box.Center.X, box.Center.Y, box.End.Z)).Round(roundDecimals); var faces = new[] { new[] { c1, c2, c3 }, new[] { c4, c1, c3 }, new[] { c4, c3, c2 }, new[] { c4, c2, c1 } }; var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; // The lower Z plane will be base, the x planes will be triangles var c1 = new Coordinate(box.Start.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c2 = new Coordinate(box.End.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c3 = new Coordinate(box.End.X, box.End.Y, box.Start.Z).Round(roundDecimals); var c4 = new Coordinate(box.Start.X, box.End.Y, box.Start.Z).Round(roundDecimals); var c5 = new Coordinate(box.Center.X, box.Start.Y, box.End.Z).Round(roundDecimals); var c6 = new Coordinate(box.Center.X, box.End.Y, box.End.Z).Round(roundDecimals); var faces = new[] { new[] { c1, c2, c3, c4 }, new[] { c2, c1, c5 }, new[] { c5, c6, c3, c2 }, new[] { c4, c3, c6 }, new[] { c6, c5, c1, c4 } }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
private MapObject GetBrush(Box bounds, IDGenerator idg) { Box _bounds = new Box(bounds.Start, bounds.End); if ((_bounds.Start - _bounds.End).VectorMagnitude() > 1000000m) { _bounds = new Box(bounds.Start, ((bounds.End - bounds.Start).Normalise() * 1000000m) + bounds.Start); } var brush = BrushManager.CurrentBrush; var ti = Document.TextureCollection.SelectedTexture; var texture = ti != null?ti.GetTexture() : null; var created = brush.Create(idg, bounds, texture, BrushManager.RoundCreatedVertices ? 0 : 2).ToList(); if (created.Count > 1) { var g = new Group(idg.GetNextObjectID()); created.ForEach(x => x.SetParent(g)); g.UpdateBoundingBox(); return(g); } return(created.FirstOrDefault()); }
private Solid MakeSolid(IDGenerator generator, IEnumerable <Coordinate[]> faces, ITexture texture, Color col) { var solid = new Solid(generator.GetNextObjectID()) { Colour = col, Flags = (System.UInt32)SolidFlags.solid }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.Init(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); return(solid); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour(), Flags = (System.UInt32)SolidFlags.solid }; foreach (var arr in box.GetBoxFaces()) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture }, //Flags = FaceFlags.Visible }; face.Vertices.AddRange(arr.Select(x => new Vertex(x.Round(roundDecimals), face))); face.Init(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numSides = (int)_numSides.GetValue(); if (numSides < 3) { yield break; } // Cylinders can be elliptical so use both major and minor rather than just the radius // NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all the edges of the box. var width = box.Width; var length = box.Length; var height = box.Height; var major = width / 2; var minor = length / 2; var angle = 2 * DMath.PI / numSides; // Calculate the X and Y points for the ellipse var points = new Coordinate[numSides]; for (var i = 0; i < numSides; i++) { var a = i * angle; var xval = box.Center.X + major * DMath.Cos(a); var yval = box.Center.Y + minor * DMath.Sin(a); var zval = box.Start.Z; points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); } var faces = new List <Coordinate[]>(); // Add the vertical faces var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var i = 0; i < numSides; i++) { var next = (i + 1) % numSides; faces.Add(new[] { points[i], points[i] + z, points[next] + z, points[next] }); } // Add the elliptical top and bottom faces faces.Add(points.ToArray()); faces.Add(points.Select(x => x + z).Reverse().ToArray()); // Nothing new here, move along var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var width = box.Width; var length = Math.Max(1, Math.Abs((int)box.Length)); var height = box.Height; var flatten = (float)_flattenFactor.Value; var text = _text.GetValue(); var family = _fontChooser.GetFontFamily(); var style = Enum.GetValues(typeof(FontStyle)).OfType <FontStyle>().FirstOrDefault(fs => family.IsStyleAvailable(fs)); if (!family.IsStyleAvailable(style)) { family = FontFamily.GenericSansSerif; } var set = new PolygonSet(); var sizes = new List <RectangleF>(); using (var bmp = new Bitmap(1, 1)) { using (var g = System.Drawing.Graphics.FromImage(bmp)) { using (var font = new Font(family, length, style, GraphicsUnit.Pixel)) { for (var i = 0; i < text.Length; i += 32) { using (var sf = new StringFormat(StringFormat.GenericTypographic)) { var rem = Math.Min(text.Length, i + 32) - i; var range = Enumerable.Range(0, rem).Select(x => new CharacterRange(x, 1)).ToArray(); sf.SetMeasurableCharacterRanges(range); var reg = g.MeasureCharacterRanges(text.Substring(i, rem), font, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf); sizes.AddRange(reg.Select(x => x.GetBounds(g))); } } } } } var xOffset = box.Start.DX; var yOffset = box.End.DY; for (var ci = 0; ci < text.Length; ci++) { var c = text[ci]; var size = sizes[ci]; var gp = new GraphicsPath(); gp.AddString(c.ToString(CultureInfo.InvariantCulture), family, (int)style, length, new PointF(0, 0), StringFormat.GenericTypographic); gp.Flatten(new System.Drawing.Drawing2D.Matrix(), flatten); var polygons = new List <Polygon>(); var poly = new List <PolygonPoint>(); for (var i = 0; i < gp.PointCount; i++) { var type = gp.PathTypes[i]; var point = gp.PathPoints[i]; poly.Add(new PolygonPoint(point.X + xOffset, -point.Y + yOffset)); if ((type & 0x80) == 0x80) { polygons.Add(new Polygon(poly)); poly.Clear(); } } var tri = new List <Polygon>(); Polygon polygon = null; foreach (var p in polygons) { if (polygon == null) { polygon = p; tri.Add(p); } else if (p.CalculateWindingOrder() != polygon.CalculateWindingOrder()) { polygon.AddHole(p); } else { polygon = null; tri.Add(p); } } foreach (var pp in tri) { try { P2T.Triangulate(pp); set.Add(pp); } catch { // Ignore } } xOffset += size.Width; } var zOffset = box.Start.Z; foreach (var polygon in set.Polygons) { foreach (var t in polygon.Triangles) { var points = t.Points.Select(x => new Coordinate((decimal)x.X, (decimal)x.Y, zOffset).Round(roundDecimals)).ToList(); var faces = new List <Coordinate[]>(); // Add the vertical faces var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var j = 0; j < points.Count; j++) { var next = (j + 1) % points.Count; faces.Add(new[] { points[j], points[j] + z, points[next] + z, points[next] }); } // Add the top and bottom faces faces.Add(points.ToArray()); faces.Add(points.Select(x => x + z).Reverse().ToArray()); // Nothing new here, move along var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); } } }