public void BisectPolygon()
        {
            List <DPoly> markedPolys = m_dmesh.GetMarkedPolys();

            if (markedPolys.Count > 0)
            {
                Clipping.ClipPlane plane = null;
                if (m_dmesh.num_marked_verts == 3)
                {
                    var markedVerts = m_dmesh.GetMarkedVerts(false).ConvertAll(vert => m_dmesh.vertex[vert]);
                    if (Clipping.Clipper.CheckColinear(markedVerts[0], markedVerts[1], markedVerts[2]) == -1)
                    {
                        plane = Clipping.ClipPlane.CreateFrom3Points(markedVerts[0], markedVerts[1], markedVerts[2]);
                    }
                }

                if (plane != null)
                {
                    SaveStateForUndo("Bisect polygon");
                    foreach (var poly in markedPolys)
                    {
                        m_dmesh.SplitPolygonByPlane(poly, plane);
                    }
                    RefreshGeometry();
                }
                else
                {
                    AddOutputText("Bisect Polygon requires three non-collinear marked vertices");
                }
            }
        }
 public bool WouldBeClipped(ClipPlane cp)
 {
     return(Clipper.WouldBeClipped(original_verts, cp));
 }
 public void ClipFacePlane(ClipPlane cp)
 {
     clipped_verts = Clipper.ClipToPlane(original_verts, cp)
                     .Cast <CVertex>()
                     .ToArray();
 }
 // Return true if any verts in the list would be clipped
 public static bool WouldBeClipped(IEnumerable <IVertex> vertList, ClipPlane plane)
 {
     return(vertList.Any(v => plane.ClassifyPoint(v.Position) == ClipSide.Back));
 }
        // Split a polygon by a plane, this is a bit faster than clipping twice with the flipped
        // plane, and will guarantee that points are exact
        public static SplitPolygon SplitPolygonByPlane(IEnumerable <IVertex> vertList, ClipPlane plane)
        {
            if (plane == null)
            {
                throw new ArgumentNullException("plane");
            }

            if (vertList == null)
            {
                throw new ArgumentNullException("vertList");
            }

            List <IVertex> front_list = new List <IVertex>();
            List <IVertex> back_list  = new List <IVertex>();

            ClipSide firstPointSide = ClipSide.CoPlanar;
            ClipSide lastPointSide  = ClipSide.CoPlanar;
            IVertex  lastVertex     = null;
            IVertex  firstVertex    = null;
            bool     isCoPlanar     = true;

            foreach (var v in vertList)
            {
                if (lastVertex == null)
                {
                    // This is the first vertex in the list, so it is specially handled
                    // because we have no prior state, and, we'll need to refer to it with
                    // regards to the final vertex
                    firstVertex    = lastVertex = v;
                    firstPointSide = lastPointSide = plane.ClassifyPoint(v.Position);
                    isCoPlanar     = isCoPlanar && firstPointSide == ClipSide.CoPlanar;

                    // Emit the point to both sides if coplanar, otherwise emit
                    // it to the particular side it is
                    if (firstPointSide == ClipSide.CoPlanar)
                    {
                        front_list.Add(v);
                        back_list.Add(v);
                    }
                    else if (firstPointSide == ClipSide.Back)
                    {
                        back_list.Add(v);
                    }
                    else
                    {
                        front_list.Add(v);
                    }

                    continue;
                }

                // Classify the current point to the plane
                ClipSide currPointSide = plane.ClassifyPoint(v.Position);
                isCoPlanar = isCoPlanar && currPointSide == ClipSide.CoPlanar;

                // One thing to be mindful of is to generate the intersection points in a consistent manner by
                // calling the intersection function with the verts in the same order.
                if (lastPointSide == ClipSide.CoPlanar)
                {
                    // The last point was on the split plane
                    if (currPointSide == ClipSide.CoPlanar)
                    {
                        // Still on the split plane
                        front_list.Add(v);
                        back_list.Add(v);
                    }
                    else if (currPointSide == ClipSide.Back)
                    {
                        // Going from the split plane to the backside
                        back_list.Add(v);
                    }
                    else
                    {
                        // Going from the split plane to the frontside
                        front_list.Add(v);
                    }
                }
                else if (lastPointSide == ClipSide.Front)
                {
                    // Last point was in the front
                    if (currPointSide == ClipSide.CoPlanar)
                    {
                        // Front -> coplanar
                        front_list.Add(v);
                        back_list.Add(v);
                    }
                    else if (currPointSide == ClipSide.Back)
                    {
                        // Front -> Back
                        var intersected_pt = plane.IntersectEdge(lastVertex, v);
                        front_list.Add(intersected_pt);
                        back_list.Add(intersected_pt);
                        back_list.Add(v);
                    }
                    else
                    {
                        // Front -> Front
                        front_list.Add(v);
                    }
                }
                else
                {
                    // Last point was in the back
                    if (currPointSide == ClipSide.CoPlanar)
                    {
                        // Back -> coplanar
                        front_list.Add(v);
                        back_list.Add(v);
                    }
                    else if (currPointSide == ClipSide.Back)
                    {
                        // Back -> Back
                        back_list.Add(v);
                    }
                    else
                    {
                        // Back -> Front
                        var intersected_pt = plane.IntersectEdge(v, lastVertex);
                        back_list.Add(intersected_pt);
                        front_list.Add(intersected_pt);
                        front_list.Add(v);
                    }
                }

                lastPointSide = currPointSide;
                lastVertex    = v;
            }

            // To finish up we need to handle the edge from the last vertex back to the first vertex
            // This is only necessary if the last point and the first point were on different sides of the plane
            if (firstPointSide != lastPointSide)
            {
                // We ended up in a different area then the first point
                if (firstPointSide == ClipSide.CoPlanar || lastPointSide == ClipSide.CoPlanar)
                {
                    // If we started or ended on a co-planar point, then we don't have to add more
                }
                else if (firstPointSide == ClipSide.Back)
                {
                    // We started in the back, we ended in the front
                    var intersection_pt = plane.IntersectEdge(lastVertex, firstVertex);
                    front_list.Add(intersection_pt);
                    back_list.Add(intersection_pt);
                }
                else if (firstPointSide == ClipSide.Front)
                {
                    // We started in the front, we ended in the back
                    var intersection_pt = plane.IntersectEdge(firstVertex, lastVertex);
                    front_list.Add(intersection_pt);
                    back_list.Add(intersection_pt);
                }
            }

            var res = new SplitPolygon();

            if (isCoPlanar)
            {
                front_list   = CleanDegenerates(front_list).ToList();
                res.coplaner = front_list.Count > 2 ? front_list.ToArray() : null;
                res.front    = null;
                res.back     = null;
            }
            else
            {
                // If there we some verts co-planar, but not all, and the remaining
                // verts are on one side, then the other side will have some verts, but not a full triangle
                front_list   = CleanDegenerates(front_list).ToList();
                back_list    = CleanDegenerates(back_list).ToList();
                res.front    = front_list.Count > 2 ? front_list.ToArray() : null;
                res.back     = back_list.Count > 2 ? back_list.ToArray() : null;
                res.coplaner = null;
            }
            return(res);
        }
 public static IEnumerable <IVertex> ClipToPlane(IEnumerable <IVertex> vertList, ClipPlane plane)
 {
     return(CleanDegenerates(ClipToPlaneRaw(vertList, plane)));
 }
        /// <summary>
        /// Generic implementation of Sutherland–Hodgman clipping algorithm
        /// </summary>
        /// <param name="vertList"></param>
        /// <returns></returns>
        public static IEnumerable <IVertex> ClipToPlaneRaw(IEnumerable <IVertex> vertList, ClipPlane plane)
        {
            if (plane == null)
            {
                throw new ArgumentNullException("plane");
            }

            if (vertList == null)
            {
                yield break;
            }

            ClipSide firstPointSide = ClipSide.CoPlanar;
            ClipSide lastPointSide  = ClipSide.CoPlanar;
            IVertex  lastVertex     = null;
            IVertex  firstVertex    = null;

            foreach (var v in vertList)
            {
                if (lastVertex == null)
                {
                    // This is the first vertex in the list, so it is specially handled
                    // because we have no prior state, and, we'll need to refer to it with
                    // regards to the final vertex
                    firstVertex    = lastVertex = v;
                    firstPointSide = lastPointSide = plane.ClassifyPoint(v.Position);

                    // If this point is in front of the plane, emit it
                    if (firstPointSide != ClipSide.Back)
                    {
                        yield return(v);
                    }
                    continue;
                }

                // Classify the current point to the plane
                ClipSide currPointSide = plane.ClassifyPoint(v.Position);

                // We have 4 possible situations:
                //   1) Last point in front of the plane, current point in front of the plane:
                //       In this situation emit the current point
                //   2) Last point in front of the plane, current point is behind the plane:
                //       In this situation emit the intersection point of the plane and the edge (last, curr)
                //   3) Last point in back of the plane, current point is behind the plane:
                //       In this situation do not emit anything
                //   4) Last point in back of the plane, current point in front of the plane:
                //       In this situation emit the intersection point of the plane and the edge (curr, last), and
                //       then emit the current point
                //
                // One thing to be mindful of is to generate the intersection points in a consistent manner by
                // calling the intersection function with the verts in the same order.
                if (lastPointSide != ClipSide.Back)
                {
                    if (currPointSide != ClipSide.Back)
                    {
                        // Situation 1
                        yield return(v);
                    }
                    else
                    {
                        // Situation 2
                        yield return(plane.IntersectEdge(lastVertex, v));
                    }
                }
                else
                {
                    if (currPointSide != ClipSide.Back)
                    {
                        // Situation 4
                        yield return(plane.IntersectEdge(v, lastVertex));

                        yield return(v);
                    }
                }

                lastPointSide = currPointSide;
                lastVertex    = v;
            }

            // To finish up we need to handle the edge from the last vertex back to the first vertex
            // This is only necessary if the last point and the first point were on different sides of the plane
            bool firstInFront = firstPointSide != ClipSide.Back;
            bool lastInFront  = lastPointSide != ClipSide.Back;

            if (firstInFront != lastInFront)
            {
                if (firstInFront)
                {
                    yield return(plane.IntersectEdge(firstVertex, lastVertex));
                }
                else
                {
                    yield return(plane.IntersectEdge(lastVertex, firstVertex));
                }
            }
        }