예제 #1
0
        public static Solid CreateFromIntersectingPlanes(IEnumerable<Plane> planes, IDGenerator generator)
        {
            var solid = new Solid(generator.GetNextObjectID());
            var list = planes.ToList();
            for (var i = 0; i < list.Count; i++)
            {
                // Split the polygon by all the other planes
                var poly = new Polygon(list[i]);
                for (var j = 0; j < list.Count; j++)
                {
                    if (i != j) poly.Split(list[j]);
                }

                // The final polygon is the face
                var face = new Face(generator.GetNextFaceID()) { Plane = poly.Plane , Parent = solid };
                face.Vertices.AddRange(poly.Vertices.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToWorld();
                solid.Faces.Add(face);
            }

            // Ensure all the faces point outwards
            var origin = solid.GetOrigin();
            foreach (var face in solid.Faces)
            {
                if (face.Plane.OnPlane(origin) >= 0) face.Flip();
            }

            solid.UpdateBoundingBox();
            return solid;
        }
예제 #2
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);
 }
예제 #3
0
파일: Polygon.cs 프로젝트: jpiolho/sledge
 public void Unclone(Polygon polygon)
 {
     Vertices = new List<Coordinate>(polygon.Vertices);
     Plane = polygon.Plane.Clone();
 }
예제 #4
0
파일: Polygon.cs 프로젝트: jpiolho/sledge
        /// <summary>
        /// Splits this polygon by a clipping plane, returning the back and front planes.
        /// The original polygon is not modified.
        /// </summary>
        /// <param name="clip">The clipping plane</param>
        /// <param name="back">The back polygon</param>
        /// <param name="front">The front polygon</param>
        /// <returns>True if the split was successful</returns>
        public bool Split(Plane clip, out Polygon back, out Polygon front)
        {
            // If the polygon doesn't span the plane, return false.
            var classify = ClassifyAgainstPlane(clip);
            if (classify != PlaneClassification.Spanning)
            {
                back = front = null;
                if (classify == PlaneClassification.Back) back = this;
                else if (classify == PlaneClassification.Front) front = this;
                return false;
            }

            // Get the new front and back vertices
            var backVerts = new List<Coordinate>();
            var frontVerts = new List<Coordinate>();
            var prev = 0;

            for (var i = 0; i <= Vertices.Count; i++)
            {
                var end = Vertices[i % Vertices.Count];
                var cls = clip.OnPlane(end);

                // Check plane crossing
                if (i > 0 && cls != 0 && prev != 0 && prev != cls)
                {
                    // This line end point has crossed the plane
                    // Add the line intersect to the
                    var start = Vertices[i - 1];
                    var line = new Line(start, end);
                    var isect = clip.GetIntersectionPoint(line, true);
                    if (isect == null) throw new Exception("Expected intersection, got null.");
                    frontVerts.Add(isect);
                    backVerts.Add(isect);
                }

                // Add original points
                if (i < Vertices.Count)
                {
                    // OnPlane points get put in both polygons, doesn't generate split
                    if (cls >= 0) frontVerts.Add(end);
                    if (cls <= 0) backVerts.Add(end);
                }

                prev = cls;
            }

            back = new Polygon(backVerts);
            front = new Polygon(frontVerts);

            return true;
        }
예제 #5
0
파일: ObjProvider.cs 프로젝트: silky/sledge
        private IEnumerable<Solid> CreateSolids(DataStructures.MapObjects.Map map, List<Coordinate> points, IEnumerable<ObjFace> objFaces)
        {
            var faces = objFaces.Select(x => CreateFace(map, points, x)).ToList();

            // See if the solid is valid
            var solid = new Solid(map.IDGenerator.GetNextObjectID());
            solid.Colour = Colour.GetRandomBrushColour();
            solid.Faces.AddRange(faces);
            faces.ForEach(x => x.Parent = solid);
            if (solid.IsValid())
            {
                // Do an additional check to ensure that all edges are shared
                var edges = solid.Faces.SelectMany(x => x.GetEdges()).ToList();
                if (edges.All(x => edges.Count(y => x.EquivalentTo(y)) == 2))
                {
                    // Valid! let's get out of here!
                    yield return solid;
                    yield break;
                }
            }

            // Not a valid solid, decompose into tetrahedrons/etc
            foreach (var face in faces)
            {
                var polygon = new Polygon(face.Vertices.Select(x => x.Location));
                if (!polygon.IsValid() || !polygon.IsConvex())
                {
                    // tetrahedrons
                    foreach (var triangle in face.GetTriangles())
                    {
                        var tf = new Face(map.IDGenerator.GetNextFaceID());
                        tf.Plane = new Plane(triangle[0].Location, triangle[1].Location, triangle[2].Location);
                        tf.Vertices.AddRange(triangle.Select(x => new Vertex(x.Location, tf)));
                        tf.UpdateBoundingBox();
                        yield return SolidifyFace(map, tf);
                    }
                }
                else
                {
                    // cone/pyramid/whatever
                    yield return SolidifyFace(map, face);
                }
            }
        }
예제 #6
0
파일: SketchTool.cs 프로젝트: silky/sledge
 private MapObject GetBrush(Polygon bounds, decimal depth, IDGenerator idGenerator)
 {
     return null;
 }
예제 #7
0
파일: SketchTool.cs 프로젝트: silky/sledge
 private void CreateBrush(Polygon poly, decimal depth)
 {
     var brush = GetBrush(poly, depth, Document.Map.IDGenerator);
     if (brush == null) return;
     IAction action = new Create(Document.Map.WorldSpawn.ID, brush);
     if (Select.SelectCreatedBrush)
     {
         brush.IsSelected = true;
         if (Select.DeselectOthersWhenSelectingCreation)
         {
             action = new ActionCollection(new ChangeSelection(new MapObject[0], Document.Selection.GetSelectedObjects()), action);
         }
     }
     Document.PerformAction("Create " + BrushManager.CurrentBrush.Name.ToLower(), action);
 }
예제 #8
0
파일: SketchTool.cs 프로젝트: silky/sledge
 public override void ToolSelected(bool preventHistory)
 {
     _state = SketchState.None;
     _currentFace = _cloneFace = null;
     _intersection = null;
     _base = null;
     _depth = 0;
     _volumePlane = null;
 }
예제 #9
0
파일: SketchTool.cs 프로젝트: silky/sledge
 public override void MouseDown(ViewportBase viewport, ViewportEvent e)
 {
     //
     switch (_state)
     {
         case SketchState.None:
             // nothin
             break;
         case SketchState.Ready:
             if (e.Button != MouseButtons.Left) break;
             _base = new Polygon(_currentFace.Plane, 1);
             _base.Transform(new UnitTranslate(_intersection - _base.Vertices[0]));
             _state = SketchState.DrawingBase;
             break;
         case SketchState.DrawingBase:
             if (e.Button == MouseButtons.Right)
             {
                 // Cancel
                 _state = SketchState.None;
                 _base = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 ExpandBase(_intersection);
                 _volumePlane = new Plane(_base.Vertices[1], _base.Vertices[2], _base.Vertices[2] + _base.Plane.Normal);
                 _state = SketchState.DrawingVolume;
             }
             break;
         case SketchState.DrawingVolume:
             if (e.Button == MouseButtons.Right)
             {
                 _state = SketchState.DrawingBase;
                 _volumePlane = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 var diff = _intersection - _base.Vertices[2];
                 var sign = _base.Plane.OnPlane(_intersection) < 0 ? -1 : 1;
                 _depth = diff.VectorMagnitude() * sign;
                 CreateBrush(_base, _depth);
                 _base = null;
                 _volumePlane = null;
                 _state = SketchState.None;
             }
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
예제 #10
0
파일: Polygon.cs 프로젝트: silky/sledge
 /// <summary>
 /// Splits this polygon by a clipping plane, returning the back and front planes.
 /// The original polygon is not modified.
 /// </summary>
 /// <param name="clip">The clipping plane</param>
 /// <param name="back">The back polygon</param>
 /// <param name="front">The front polygon</param>
 /// <returns>True if the split was successful</returns>
 public bool Split(Plane clip, out Polygon back, out Polygon front)
 {
     Polygon cFront, cBack;
     return Split(clip, out back, out front, out cBack, out cFront);
 }
예제 #11
0
        private void Split(object sender)
        {
            var face = GetSplitFace();
            if (face == null) return;

            var solid = face.Parent;

            var sel = MainTool.Points.Where(x => x.IsSelected).ToList();
            var p1 = sel[0];
            var p2 = sel[1];

            if (p1.IsMidPoint) AddAdjacentPoint(face, p1);
            if (p2.IsMidPoint) AddAdjacentPoint(face, p2);

            var polygon = new Polygon(face.Vertices.Select(x => x.Location));
            var clip = new Plane(p1.Coordinate, p2.Coordinate, p1.Coordinate + face.Plane.Normal * 10);
            Polygon back, front;
            polygon.Split(clip, out back, out front);
            if (back == null || front == null) return;

            solid.Faces.Remove(face);
            face.Parent = null;

            CreateFace(back, solid, face);
            CreateFace(front, solid, face);

            solid.UpdateBoundingBox();

            MainTool.SetDirty(true, true);
        }
예제 #12
0
 private void CreateFace(Polygon polygon, Solid parent, Face original)
 {
     var verts = polygon.Vertices;
     var f = new Face(Document.Map.IDGenerator.GetNextFaceID())
     {
         Parent = parent,
         Plane = new Plane(verts[0], verts[1], verts[2]),
         Colour = parent.Colour,
         Texture = original.Texture.Clone()
     };
     f.Vertices.AddRange(verts.Select(x => new Vertex(x, f)));
     f.UpdateBoundingBox();
     f.CalculateTextureCoordinates(true);
     parent.Faces.Add(f);
 }
예제 #13
0
파일: ClipTool.cs 프로젝트: silky/sledge
        private void Render3D(Viewport3D vp)
        {
            if (_state == ClipState.None
                || _clipPlanePoint1 == null
                || _clipPlanePoint2 == null
                || _clipPlanePoint3 == null
                || Document.Selection.IsEmpty()) return; // Nothing to draw at this point

            TextureHelper.Unbind();

            // Draw points

            if (!_clipPlanePoint1.EquivalentTo(_clipPlanePoint2)
                    && !_clipPlanePoint2.EquivalentTo(_clipPlanePoint3)
                    && !_clipPlanePoint1.EquivalentTo(_clipPlanePoint3))
            {
                var plane = new Plane(_clipPlanePoint1, _clipPlanePoint2, _clipPlanePoint3);

                // Draw clipped solids
                GL.Enable(EnableCap.LineSmooth);
                GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);

                var faces = new List<Face>();
                var idg = new IDGenerator();
                foreach (var solid in Document.Selection.GetSelectedObjects().OfType<Solid>().ToList())
                {
                    Solid back, front;
                    if (solid.Split(plane, out back, out front, idg))
                    {
                        if (_side != ClipSide.Front) faces.AddRange(back.Faces);
                        if (_side != ClipSide.Back) faces.AddRange(front.Faces);
                    }
                }
                GL.LineWidth(2);
                GL.Color3(Color.White);
                Rendering.Immediate.MapObjectRenderer.DrawWireframe(faces, true, false);
                GL.LineWidth(1);

                GL.Hint(HintTarget.LineSmoothHint, HintMode.Fastest);
                GL.Disable(EnableCap.LineSmooth);

                // Draw the clipping plane
                var poly = new Polygon(plane);
                var bbox = Document.Selection.GetSelectionBoundingBox();
                var point = bbox.Center;
                foreach (var boxPlane in bbox.GetBoxPlanes())
                {
                    var proj = boxPlane.Project(point);
                    var dist = (point - proj).VectorMagnitude() * 0.1m;
                    poly.Split(new Plane(boxPlane.Normal, proj + boxPlane.Normal * Math.Max(dist, 100)));
                }

                GL.Disable(EnableCap.CullFace);
                GL.Begin(PrimitiveType.Polygon);
                GL.Color4(Color.FromArgb(100, Color.Turquoise));
                foreach (var c in poly.Vertices) GL.Vertex3(c.DX, c.DY, c.DZ);
                GL.End();
                GL.Enable(EnableCap.CullFace);
            }
        }
예제 #14
0
 public void TestPolygonSplitting()
 {
     var planes = new[]
                      {
                          new Plane(new Coordinate(-64, 64, 64), new Coordinate(64, 64, 64), new Coordinate(64, -64, 64)),
                          new Plane(new Coordinate(-64, -64, -64), new Coordinate(64, -64, -64), new Coordinate(64, 64, -64)),
                          new Plane(new Coordinate(-64, 64, 64), new Coordinate(-64, -64, 64), new Coordinate(-64, -64, -64)),
                          new Plane(new Coordinate(64, 64, -64), new Coordinate(64, -64, -64), new Coordinate(64, -64, 64)),
                          new Plane(new Coordinate(64, 64, 64), new Coordinate(-64, 64, 64), new Coordinate(-64, 64, -64)),
                          new Plane(new Coordinate(64, -64, -64), new Coordinate(-64, -64, -64), new Coordinate(-64, -64, 64))
                      }.ToList();
     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);
     }
     Assert.AreEqual(6, polys.Count);
 }