示例#1
0
        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);
        }
示例#2
0
        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();
            }
        }
示例#3
0
        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();
                }
            }
        }
示例#4
0
        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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        private static long GetObjectID(GenericStructure gs, IDGenerator generator)
        {
            var id = gs.PropertyLong("id");

            if (id == 0)
            {
                id = generator.GetNextObjectID();
            }
            return(id);
        }
示例#8
0
        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);
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        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());
        }
示例#12
0
        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);
        }
示例#13
0
        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);
        }
示例#14
0
        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);
        }
示例#15
0
        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());
        }
示例#16
0
        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);
        }
示例#17
0
        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);
        }
示例#18
0
        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);
        }
示例#19
0
        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);
                }
            }
        }