Пример #1
0
        /// <summary>
        /// Find the optimal split for a polygon
        /// </summary>
        /// <param name="poly"></param>
        /// <returns></returns>
        private (Vector3 point, Vector3 normal, List <BSPPoly <T> > left, List <BSPPoly <T> > right) FindOptimalSplit(BSPPoly <T>[] poly)
        {
            //init
            Vector3             point = Vector3.zero, normal = Vector3.zero;
            List <BSPPoly <T> > left = null, right = null;

            //optimal diff
            int diff = int.MaxValue;

            //get the working polygon
            IPoly working = poly[0].working;

            for (int i = 0; i < working.Resolution; i++)
            {
                //get the current point and normal
                Vector3 localPoint  = working.GetPoint(i),
                        localNormal = working.GetSurfaceNormal(i);

                //get output
                (List <BSPPoly <T> > localInside, List <BSPPoly <T> > localOutput) = GetSplit(poly, localPoint, localNormal);

                //calc the diff, and compare
                int localDiff = Math.Abs(localInside.Count - localOutput.Count);
                if (localDiff < diff)
                {
                    left   = localInside;
                    right  = localOutput;
                    point  = localPoint;
                    normal = localNormal;
                    diff   = localDiff;
                }
            }

            return(point, normal, left, right);
        }
Пример #2
0
        /// <summary>
        /// Get the next bsp node for the polygons
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="optimize"></param>
        /// <returns></returns>
        private BSPNode <T> GetNode(BSPPoly <T>[] polygons, bool optimize)
        {
            if (polygons.Length == 0)
            {
                return(null);
            }
            if (polygons.Length == 1)
            {
                return(new BSPNode <T>(polygons[0], null, null, Vector3.zero, Vector3.zero));
            }

            if (optimize)
            {
                polygons = FindOptimalPoly(polygons);

                Vector3             point, normal;
                List <BSPPoly <T> > left, right;

                (point, normal, left, right) = FindOptimalSplit(polygons);

                return(new BSPNode <T>(polygons[0], GetNode(left.ToArray(), optimize), GetNode(right.ToArray(), optimize), point, normal));
            }

            else
            {
                IPoly   working = polygons[0].working;
                Vector3 point   = working.GetPoint(0),
                        normal  = working.GetSurfaceNormal(0);

                (List <BSPPoly <T> > left, List <BSPPoly <T> > right) = GetSplit(polygons, point, normal);

                return(new BSPNode <T>(polygons[0], GetNode(left.ToArray(), optimize), GetNode(right.ToArray(), optimize), point, normal));
            }
        }
Пример #3
0
        public static bool IsEdgeIntersectingPolygon(IPoly polygon, Vector3 point1, Vector3 point2)
        {
            for (int i = 0; i < polygon.Resolution; i++)
            {
                Vector3 a = polygon.GetPoint(i);
                Vector3 b = polygon.GetPointWrapped(i + 1);
                if ((point1 - a).sqrMagnitude < 0.0001f)
                {
                    continue;
                }
                if ((point1 - b).sqrMagnitude < 0.0001f)
                {
                    continue;
                }
                if ((point2 - a).sqrMagnitude < 0.0001f)
                {
                    continue;
                }
                if ((point2 - b).sqrMagnitude < 0.0001f)
                {
                    continue;
                }

                if (Math3d.AreLineSegmentsCrossing(a, b, point1, point2))
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #4
0
        public static IPoly RemoveDuplicateVerticies(IPoly poly)
        {
            List <Vector3> output = new List <Vector3>();

            for (int i = 0; i < poly.Resolution; i++)
            {
                if (output.Count == 0)
                {
                    output.Add(poly.GetPoint(i));
                }
                else
                {
                    Vector3 point = poly.GetPoint(i);
                    Vector3 last  = output[output.Count - 1];
                    if (!Math3d.Compare(point, last))
                    {
                        output.Add(point);
                    }
                }
            }
            if (Math3d.Compare(output[0], output[output.Count - 1]))
            {
                output.RemoveAt(0);
            }
            return(poly.Clone(output.ToArray()));
        }
Пример #5
0
        /// <summary>
        /// Make a concave polygon into a convex one
        /// </summary>
        /// <param name="poly"></param>
        /// <returns></returns>
        public static IEnumerable <IPoly> MakeConvex(IPoly poly)
        {
            List <Vector3>         input  = poly.GetPoints().ToList();
            List <List <Vector3> > output = BayazitDecomposer.ConvexPartition(input);

            return(output.Select(x => poly.Clone(x.ToArray())));
        }
Пример #6
0
        public static (float[], int[]) GetBisectedThetaValues(IPoly polygon, int index)
        {
            Vector3 center = polygon.GetPoint(index);
            Vector3 left   = polygon.GetPointWrapped(index - 1);
            Vector3 right  = polygon.GetPointWrapped(index + 1);
            Vector3 biSect = Vector3.Lerp((left - center).normalized, (right - center).normalized, 0.5f).normalized;

            int[]   indicies = new int[polygon.Resolution - 1];
            float[] tValues  = new float[polygon.Resolution - 1];
            for (int i = 0; i < polygon.Resolution; i++)
            {
                if (i < index)
                {
                    indicies[i] = i;
                    tValues[i]  = Vector3.Dot(biSect, (polygon.GetPoint(i) - center).normalized);
                }
                else if (i == index)
                {
                    continue;
                }
                else
                {
                    indicies[i - 1] = i;
                    tValues[i - 1]  = Vector3.Dot(biSect, (polygon.GetPoint(i) - center).normalized);
                }
            }
            Array.Sort(tValues, indicies);
            return(tValues, indicies);
        }
 public ComplexPoly(IPoly poly, IPoly[] holes)
 {
     Debug.Assert(poly.Holes.Length == 0, "Outline can not have holes");
     Debug.Assert(holes.All(p => p.Holes.Length == 0), "Holes can not have holes");
     Holes = holes;
     _poly = poly;
 }
Пример #8
0
Файл: Poly.cs Проект: X-Hax/SA3D
 internal static void DefaultWrite(this IPoly poly, EndianWriter writer)
 {
     foreach (ushort i in poly.Indices)
     {
         writer.WriteUInt16(i);
     }
 }
Пример #9
0
 public static IPoly InjectEdge(IPoly poly, IEdge newEdge)
 {
     if (poly is EdgePoly)
     {
         return(InjectEdge(poly as EdgePoly, newEdge));
     }
     throw new System.NotImplementedException();
 }
Пример #10
0
Файл: Poly.cs Проект: X-Hax/SA3D
 internal static void DefaultWriteNJA(this IPoly poly, TextWriter writer)
 {
     foreach (ushort i in poly.Indices)
     {
         writer.Write(i);
         writer.Write(", ");
     }
 }
Пример #11
0
 /// <summary>
 /// Divide a polygon using the specified plane.
 /// </summary>
 /// <param name="poly">
 /// The polygon to divide.
 /// </param>
 /// <param name="inside">
 /// The new polygon inside the plane.
 /// </param>
 /// <param name="outside">
 /// The new polygon outside the plane.
 /// </param>
 /// <param name="p0">
 /// Plane Origin.
 /// </param>
 /// <param name="pn">
 /// Plane Normal.
 /// </param>
 /// <param name="threshold">
 /// The percision threshold for comparing points to the plane.
 /// </param>
 public static void Divide(
     IPoly poly,
     out IPoly inside,
     out IPoly outside,
     Vector3 p0,
     Vector3 pn,
     float threshold = 0.001f)
 {
     Divide(poly, out inside, out outside, p0, pn, (x, y) => x.Clone(y), threshold);
 }
Пример #12
0
        /// <summary>
        /// Calculates the collision status of two polygons.
        /// Returns colliding is the polygons are intersecting, not colliding if they are not, AEnclosedInB is A is inside B, and BEnclosedInA for ...
        /// This method also returns the offending index
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="offendingIndex"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static CollisionType CalcCollision2D(IPoly a, IPoly b, out int offendingIndex, float threshold = 0.001f)
        {
            offendingIndex = -1;

            //check for a
            bool enclosed = true;

            for (int i = 0; i < a.Resolution; i++)
            {
                Vector3 point = a.GetPoint(i);
                Vector3 surfaceNormal = a.GetSurfaceNormal(i);
                bool    inside, outside;
                CheckPoly(b, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
                if (inside && outside)
                {
                    offendingIndex = i;
                }
            }
            if (enclosed)
            {
                return(CollisionType.BEnclosedInA);
            }

            //check for b
            enclosed = true;
            for (int i = 0; i < b.Resolution; i++)
            {
                Vector3 point = b.GetPoint(i);
                Vector3 surfaceNormal = b.GetSurfaceNormal(i);
                bool    inside, outside;
                CheckPoly(a, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
            }
            if (enclosed)
            {
                return(CollisionType.AEnclosedInB);
            }

            return(CollisionType.Colliding);
        }
Пример #13
0
        /// <summary>
        /// Calculates the collision status of two blocks.
        /// Returns colliding is the polygons are intersecting, not colliding if they are not, AEnclosedInB is A is inside B, and BEnclosedInA for ...
        /// The offending face is also returned, for the sake of other algorithms.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="offendingFace"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static CollisionType CalcCollision3D(IBlock a, IBlock b, out IPoly offendingFace, float threshold = 0.001f)
        {
            offendingFace = null;

            //check for a
            bool enclosed = true;

            foreach (var poly in a.GetFaces())
            {
                Vector3 point = poly.GetPoint(0);
                Vector3 surfaceNormal = poly.GetNormal();
                bool    inside, outside;
                CheckBlock(b, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
                if (inside && outside)
                {
                    offendingFace = poly;
                }
            }
            if (enclosed)
            {
                return(CollisionType.BEnclosedInA);
            }

            //check for b
            enclosed = true;
            foreach (var poly in b.GetFaces())
            {
                Vector3 point = poly.GetPoint(0);
                Vector3 surfaceNormal = poly.GetNormal();
                bool    inside, outside;
                CheckBlock(a, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
            }
            if (enclosed)
            {
                return(CollisionType.AEnclosedInB);
            }

            return(CollisionType.Colliding);
        }
        public ComplexPoly(Vector2[] points, Vector2[][] holes)
        {
            Holes = new Poly[holes.Length];

            for (int n = 0; n < holes.Length; n++)
            {
                Holes[n] = new Poly(holes[n]);
            }

            _poly  = new Poly(points);
        }
Пример #15
0
 public BSPPoly(T original, IPoly working)
 {
     this.original = original;
     if (working is NGon)
     {
         this.working = (NGon)working;
     }
     else
     {
         this.working = new NGon(working);
     }
 }
        /// <summary>
        /// Create a RenderInstruction representing a polygon. Uses triangulation via Triangulator.dll.
        /// </summary>
        /// <param name="points">The points of the polygon</param>
        /// <param name="color">The color of the polygon</param>
        public static RenderInstruction Polygon(IPoly poly, Color color)
        {
            Vector2[] pointsToSend = poly.Points;

            /*foreach (IPoly hole in poly.Holes)
            {
                pointsToSend = Triangulator.Triangulator.CutHoleInShape(pointsToSend, hole.Points);
            }*/

            Triangulation triangulation = Triangulator.Triangulate(pointsToSend);

            VertexPositionColor[] vertices = new VertexPositionColor[triangulation.Vertices.Length];

            for (int n = 0; n < triangulation.Vertices.Length; n++)
            {
                vertices[n].Position = triangulation.Vertices[n].ToVector3();
                vertices[n].Color = color;
            }

            return new RenderInstruction(vertices, triangulation.Indices, PrimitiveType.TriangleList);
        }
Пример #17
0
        private static EdgeTable build_lmt( LmtTable lmt_table, 
			ScanBeamTreeEntries sbte,
			IPoly p, 
			int type, //poly type SUBJ/CLIP
			OperationType op)
        {
            /* Create the entire input polygon edge table in one go */
            EdgeTable edge_table = new EdgeTable();

            for ( int c= 0; c < p.InnerPolygonCount; c++)
            {
                IPoly ip = p.GetInnerPoly(c);
                if( !ip.IsContributing(0) )
                {
                    /* Ignore the non-contributing contour */
                    ip.SetContributing(0, true);
                }
                else
                {
                    /* Perform contour optimisation */
                    int num_vertices= 0;
                    int e_index = 0 ;
                    edge_table = new EdgeTable();
                    for ( int i= 0; i < ip.PointCount; i++)
                    {
                        if( OPTIMAL(ip, i) )
                        {
                            double x = ip.GetX(i);
                            double y = ip.GetY(i);
                            edge_table.addNode( x, y );

                            /* Record vertex in the scanbeam table */
                            add_to_sbtree( sbte, ip.GetY(i) );

                            num_vertices++;
                        }
                    }

                    /* Do the contour forward pass */
                    for ( int min= 0; min < num_vertices; min++)
                    {
                        /* If a forward local minimum... */
                        if( edge_table.FWD_MIN( min ) )
                        {
                            /* Search for the next local maximum... */
                            int num_edges = 1;
                            int max = NEXT_INDEX( min, num_vertices );
                            while( edge_table.NOT_FMAX( max ) )
                            {
                                num_edges++;
                                max = NEXT_INDEX( max, num_vertices );
                            }

                            /* Build the next edge list */
                            int v = min;
                            EdgeNode e = edge_table.getNode( e_index );
                            e.bstate[BELOW] = BundleState.UNBUNDLED;
                            e.bundle[BELOW, CLIP] = 0;
                            e.bundle[BELOW, SUBJ] = 0;

                            for ( int i= 0; i < num_edges; i++)
                            {
                                EdgeNode ei = edge_table.getNode( e_index+i );
                                EdgeNode ev = edge_table.getNode( v );

                                ei.xb    = ev.vertex.X;
                                ei.bot.X = ev.vertex.X;
                                ei.bot.Y = ev.vertex.Y;

                                v = NEXT_INDEX(v, num_vertices);
                                ev = edge_table.getNode( v );

                                ei.top.X= ev.vertex.X;
                                ei.top.Y= ev.vertex.Y;
                                ei.dx= (ev.vertex.X - ei.bot.X) / (ei.top.Y - ei.bot.Y);
                                ei.type = type;
                                ei.outp[ABOVE] = null ;
                                ei.outp[BELOW] = null;
                                ei.next = null;
                                ei.prev = null;
                                ei.succ = ((num_edges > 1) && (i < (num_edges - 1))) ? edge_table.getNode(e_index+i+1) : null;
                                ei.pred = ((num_edges > 1) && (i > 0)) ? edge_table.getNode(e_index+i-1) : null ;
                                ei.next_bound = null ;
                                ei.bside[CLIP] = (op == OperationType.GPC_DIFF) ? RIGHT : LEFT;
                                ei.bside[SUBJ] = LEFT ;
                            }
                            insert_bound( bound_list(lmt_table, edge_table.getNode(min).vertex.Y), e);
            #if DEBUG
                                Console.WriteLine("fwd");
                                lmt_table.print();
            #endif
                            e_index += num_edges;
                        }
                    }

                    /* Do the contour reverse pass */
                    for ( int min= 0; min < num_vertices; min++)
                    {
                        /* If a reverse local minimum... */
                        if ( edge_table.REV_MIN( min ) )
                        {
                            /* Search for the previous local maximum... */
                            int num_edges= 1;
                            int max = PREV_INDEX(min, num_vertices);
                            while( edge_table.NOT_RMAX( max ) )
                            {
                                num_edges++;
                                max = PREV_INDEX(max, num_vertices);
                            }

                            /* Build the previous edge list */
                            int v = min;
                            EdgeNode e = edge_table.getNode( e_index );
                            e.bstate[BELOW] = BundleState.UNBUNDLED;
                            e.bundle[BELOW, CLIP] = 0;
                            e.bundle[BELOW, SUBJ] = 0;

                            for (int i= 0; i < num_edges; i++)
                            {
                                EdgeNode ei = edge_table.getNode( e_index+i );
                                EdgeNode ev = edge_table.getNode( v );

                                ei.xb    = ev.vertex.X;
                                ei.bot.X = ev.vertex.X;
                                ei.bot.Y = ev.vertex.Y;

                                v= PREV_INDEX(v, num_vertices);
                                ev = edge_table.getNode( v );

                                ei.top.X = ev.vertex.X;
                                ei.top.Y = ev.vertex.Y;
                                ei.dx = (ev.vertex.X - ei.bot.X) / (ei.top.Y - ei.bot.Y);
                                ei.type = type;
                                ei.outp[ABOVE] = null;
                                ei.outp[BELOW] = null;
                                ei.next = null ;
                                ei.prev = null;
                                ei.succ = ((num_edges > 1) && (i < (num_edges - 1))) ? edge_table.getNode(e_index+i+1) : null;
                                ei.pred = ((num_edges > 1) && (i > 0)) ? edge_table.getNode(e_index+i-1) : null ;
                                ei.next_bound = null ;
                                ei.bside[CLIP] = (op == OperationType.GPC_DIFF) ? RIGHT : LEFT;
                                ei.bside[SUBJ] = LEFT;
                            }
                            insert_bound( bound_list(lmt_table, edge_table.getNode(min).vertex.Y), e);
            #if DEBUG
                                Console.WriteLine("rev");
                                lmt_table.print();
            #endif
                            e_index+= num_edges;
                        }
                    }
                }
            }
            return edge_table;
        }
Пример #18
0
        /// <summary>
        /// <code>clip()</code> is the main method of the clipper This
        /// is where the conversion from really begins.
        /// </summary>
        private static IPoly Clip(
			OperationType op,
			IPoly subj, IPoly clip,
			Type polyType)
        {
            // Create an empty type
            IPoly result = CreateNewPoly(polyType) ;

            /* Test for trivial NULL result cases */
            if( (subj.IsEmpty() && clip.IsEmpty()) ||
                (subj.IsEmpty() && ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF))) ||
                (clip.IsEmpty() &&  (op == OperationType.GPC_INT)) )
            {
                return result ;
            }

            /* Identify potentialy contributing contours */
            if( ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF)) &&
                !subj.IsEmpty() && !clip.IsEmpty() )
            {
                minimax_test(subj, clip, op);
            }

            /* Build LMT */
            LmtTable lmt_table = new LmtTable();
            ScanBeamTreeEntries sbte = new ScanBeamTreeEntries();
            EdgeTable s_heap = null ;
            EdgeTable c_heap = null ;
            if (!subj.IsEmpty())
            {
                s_heap = build_lmt(lmt_table, sbte, subj, SUBJ, op);
            }
            #if DEBUG
            // Show debugging information
            Console.WriteLine("");
            Console.WriteLine(" ------------ After build_lmt for subj ---------");
            lmt_table.print();
            #endif

            if (!clip.IsEmpty())
            {
                c_heap = build_lmt(lmt_table, sbte, clip, CLIP, op);
            }

            #if DEBUG
            // Debugging information
            Console.WriteLine("");
            Console.WriteLine(" ------------ After build_lmt for clip ---------");
            lmt_table.print();
            #endif

            /* Return a NULL result if no contours contribute */
            if (lmt_table.top_node == null)
            {
                return result;
            }

            /* Build scanbeam table from scanbeam tree */
            double[] sbt = sbte.build_sbt();

            int[] parity = new int[2] ;
            parity[0] = LEFT ;
            parity[1] = LEFT ;

            /* Invert clip polygon for difference operation */
            if (op == OperationType.GPC_DIFF)
            {
                parity[CLIP]= RIGHT;
            }

            #if DEBUG
                print_sbt(sbt);
            #endif

            LmtNode local_min = lmt_table.top_node ;

            TopPolygonNode out_poly = new TopPolygonNode(); // used to create resulting Poly

            AetTree aet = new AetTree();
            int scanbeam = 0 ;

            /* Process each scanbeam */
            while( scanbeam < sbt.Length )
            {
                /* Set yb and yt to the bottom and top of the scanbeam */
                double yb = sbt[scanbeam++];
                double yt = 0.0 ;
                double dy = 0.0 ;
                if( scanbeam < sbt.Length )
                {
                    yt = sbt[scanbeam];
                    dy = yt - yb;
                }

                /* === SCANBEAM BOUNDARY PROCESSING ================================ */

                /* If LMT node corresponding to yb exists */
                if (local_min != null )
                {
                    if (local_min.y == yb)
                    {
                        /* Add edges starting at this local minimum to the AET */
                        for( EdgeNode edge = local_min.first_bound; (edge != null) ; edge= edge.next_bound)
                        {
                            add_edge_to_aet( aet, edge );
                        }

                        local_min = local_min.next;
                    }
                }

            #if DEBUG
                    aet.print();
            #endif

                /* Set dummy previous x value */
                double px = -Double.MaxValue ;

                /* Create bundles within AET */
                EdgeNode e0 = aet.top_node ;
                EdgeNode e1 = aet.top_node ;

                /* Set up bundle fields of first edge */
                aet.top_node.bundle[ABOVE, aet.top_node.type ] = (aet.top_node.top.Y != yb) ? 1 : 0;
                aet.top_node.bundle[ABOVE, ((aet.top_node.type==0) ? 1 : 0) ] = 0;
                aet.top_node.bstate[ABOVE] = BundleState.UNBUNDLED;

                for (EdgeNode next_edge= aet.top_node.next ; (next_edge != null); next_edge = next_edge.next)
                {
                    int ne_type = next_edge.type ;
                    int ne_type_opp = ((next_edge.type==0) ? 1 : 0); //next edge type opposite

                    /* Set up bundle fields of next edge */
                    next_edge.bundle[ABOVE, ne_type     ]= (next_edge.top.Y != yb) ? 1 : 0;
                    next_edge.bundle[ABOVE, ne_type_opp ] = 0 ;
                    next_edge.bstate[ABOVE] = BundleState.UNBUNDLED;

                    /* Bundle edges above the scanbeam boundary if they coincide */
                    if ( next_edge.bundle[ABOVE, ne_type] == 1 )
                    {
                        if (EQ(e0.xb, next_edge.xb) && EQ(e0.dx, next_edge.dx) && (e0.top.Y != yb))
                        {
                            next_edge.bundle[ABOVE, ne_type     ] ^= e0.bundle[ABOVE, ne_type     ];
                            next_edge.bundle[ABOVE, ne_type_opp ]  = e0.bundle[ABOVE, ne_type_opp ];
                            next_edge.bstate[ABOVE] = BundleState.BUNDLE_HEAD;
                            e0.bundle[ABOVE, CLIP] = 0;
                            e0.bundle[ABOVE, SUBJ] = 0;
                            e0.bstate[ABOVE] = BundleState.BUNDLE_TAIL;
                        }
                        e0 = next_edge;
                    }
                }

                int[] horiz = new int[2] ;
                horiz[CLIP]= HState.NH;
                horiz[SUBJ]= HState.NH;

                int[] exists = new int[2] ;
                exists[CLIP] = 0 ;
                exists[SUBJ] = 0 ;

                PolygonNode cf = null ;

                /* Process each edge at this scanbeam boundary */
                for (EdgeNode edge= aet.top_node ; (edge != null); edge = edge.next )
                {
                    exists[CLIP] = edge.bundle[ABOVE, CLIP] + (edge.bundle[BELOW, CLIP] << 1);
                    exists[SUBJ] = edge.bundle[ABOVE, SUBJ] + (edge.bundle[BELOW, SUBJ] << 1);

                    if( (exists[CLIP] != 0) || (exists[SUBJ] != 0) )
                    {
                        /* Set bundle side */
                        edge.bside[CLIP] = parity[CLIP];
                        edge.bside[SUBJ] = parity[SUBJ];

                        bool contributing = false ;
                        int br=0, bl=0, tr=0, tl=0 ;
                        /* Determine contributing status and quadrant occupancies */
                        if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
                        {
                            contributing= ((exists[CLIP]!=0) && ((parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
                                ((exists[SUBJ]!=0) && ((parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
                                ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
                            br = ((parity[CLIP]!=0) && (parity[SUBJ]!=0)) ? 1 : 0;
                            bl = ( ((parity[CLIP] ^ edge.bundle[ABOVE, CLIP])!=0) &&
                                ((parity[SUBJ] ^ edge.bundle[ABOVE, SUBJ])!=0) ) ? 1 : 0;
                            tr = ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) !=0) &&
                                ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0)) !=0) ) ? 1 : 0;
                            tl = (((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW, CLIP])!=0) &&
                                ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW, SUBJ])!=0))?1:0;
                        }
                        else if( op == OperationType.GPC_XOR )
                        {
                            contributing= (exists[CLIP]!=0) || (exists[SUBJ]!=0);
                            br= (parity[CLIP]) ^ (parity[SUBJ]);
                            bl= (parity[CLIP] ^ edge.bundle[ABOVE, CLIP]) ^ (parity[SUBJ] ^ edge.bundle[ABOVE, SUBJ]);
                            tr= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0));
                            tl= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW, CLIP])
                                ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW, SUBJ]);
                        }
                        else if( op == OperationType.GPC_UNION )
                        {
                            contributing= ((exists[CLIP]!=0) && (!(parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
                                ((exists[SUBJ]!=0) && (!(parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
                                ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
                            br= ((parity[CLIP]!=0) || (parity[SUBJ]!=0))?1:0;
                            bl= (((parity[CLIP] ^ edge.bundle[ABOVE, CLIP])!=0) || ((parity[SUBJ] ^ edge.bundle[ABOVE, SUBJ])!=0))?1:0;
                            tr= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0))!=0) ||
                                ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0))!=0) ) ?1:0;
                            tl= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW, CLIP])!=0) ||
                                ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW, SUBJ])!=0) ) ? 1:0;
                        }
                        else
                        {
                            throw new Exception("Unknown op");
                        }

                        /* Update parity */
                        parity[CLIP] ^= edge.bundle[ABOVE, CLIP];
                        parity[SUBJ] ^= edge.bundle[ABOVE, SUBJ];

                        /* Update horizontal state */
                        if (exists[CLIP]!=0)
                        {
                            horiz[CLIP] = HState.next_h_state[horiz[CLIP], ((exists[CLIP] - 1) << 1) + parity[CLIP]];
                        }
                        if( exists[SUBJ]!=0)
                        {
                            horiz[SUBJ] = HState.next_h_state[horiz[SUBJ], ((exists[SUBJ] - 1) << 1) + parity[SUBJ]];
                        }

                        if (contributing)
                        {
                            double xb = edge.xb;

                            VertexType vclass = (VertexType)
                                ( tr + (tl << 1) + (br << 2) + (bl << 3));
                            switch (vclass)
                            {
                                case VertexType.EMN:
                                case VertexType.IMN:
                                    edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
                                    px = xb;
                                    cf = edge.outp[ABOVE];
                                    break;
                                case VertexType.ERI:
                                    if (xb != px)
                                    {
                                        cf.add_right( xb, yb);
                                        px= xb;
                                    }
                                    edge.outp[ABOVE]= cf;
                                    cf= null;
                                    break;
                                case VertexType.ELI:
                                    edge.outp[BELOW].add_left( xb, yb);
                                    px= xb;
                                    cf= edge.outp[BELOW];
                                    break;
                                case VertexType.EMX:
                                    if (xb != px)
                                    {
                                        cf.add_left( xb, yb);
                                        px= xb;
                                    }
                                    out_poly.merge_right(cf, edge.outp[BELOW]);
                                    cf= null;
                                    break;
                                case VertexType.ILI:
                                    if (xb != px)
                                    {
                                        cf.add_left( xb, yb);
                                        px= xb;
                                    }
                                    edge.outp[ABOVE]= cf;
                                    cf= null;
                                    break;
                                case VertexType.IRI:
                                    edge.outp[BELOW].add_right( xb, yb );
                                    px= xb;
                                    cf= edge.outp[BELOW];
                                    edge.outp[BELOW]= null;
                                    break;
                                case VertexType.IMX:
                                    if (xb != px)
                                    {
                                        cf.add_right( xb, yb );
                                        px= xb;
                                    }
                                    out_poly.merge_left(cf, edge.outp[BELOW]);
                                    cf= null;
                                    edge.outp[BELOW]= null;
                                    break;
                                case VertexType.IMM:
                                    if (xb != px)
                                    {
                                        cf.add_right( xb, yb);
                                        px= xb;
                                    }
                                    out_poly.merge_left(cf, edge.outp[BELOW]);
                                    edge.outp[BELOW]= null;
                                    edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
                                    cf= edge.outp[ABOVE];
                                    break;
                                case VertexType.EMM:
                                    if (xb != px)
                                    {
                                        cf.add_left( xb, yb);
                                        px= xb;
                                    }
                                    out_poly.merge_right(cf, edge.outp[BELOW]);
                                    edge.outp[BELOW]= null;
                                    edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
                                    cf= edge.outp[ABOVE];
                                    break;
                                case VertexType.LED:
                                    if (edge.bot.Y == yb)
                                        edge.outp[BELOW].add_left( xb, yb);
                                    edge.outp[ABOVE]= edge.outp[BELOW];
                                    px= xb;
                                    break;
                                case VertexType.RED:
                                    if (edge.bot.Y == yb)
                                        edge.outp[BELOW].add_right( xb, yb );
                                    edge.outp[ABOVE]= edge.outp[BELOW];
                                    px= xb;
                                    break;
                                default:
                                    break;
                            } /* End of switch */
                        } /* End of contributing conditional */
                    } /* End of edge exists conditional */
            #if DEBUG
                        out_poly.print();
            #endif
                } /* End of AET loop */

                /* Delete terminating edges from the AET, otherwise compute xt */
                for (EdgeNode edge = aet.top_node ; (edge != null); edge = edge.next)
                {
                    if (edge.top.Y == yb)
                    {
                        EdgeNode prev_edge = edge.prev;
                        EdgeNode next_edge= edge.next;

                        if (prev_edge != null)
                            prev_edge.next = next_edge;
                        else
                            aet.top_node = next_edge;

                        if (next_edge != null )
                            next_edge.prev = prev_edge;

                        /* Copy bundle head state to the adjacent tail edge if required */
                        if ((edge.bstate[BELOW] == BundleState.BUNDLE_HEAD) && (prev_edge!=null))
                        {
                            if (prev_edge.bstate[BELOW] == BundleState.BUNDLE_TAIL)
                            {
                                prev_edge.outp[BELOW]= edge.outp[BELOW];
                                prev_edge.bstate[BELOW]= BundleState.UNBUNDLED;
                                if ( prev_edge.prev != null)
                                {
                                    if (prev_edge.prev.bstate[BELOW] == BundleState.BUNDLE_TAIL)
                                    {
                                        prev_edge.bstate[BELOW] = BundleState.BUNDLE_HEAD;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (edge.top.Y == yt)
                            edge.xt= edge.top.X;
                        else
                            edge.xt= edge.bot.X + edge.dx * (yt - edge.bot.Y);
                    }
                }

                if (scanbeam < sbte.sbt_entries )
                {
                    /* === SCANBEAM INTERIOR PROCESSING ============================== */

                    /* Build intersection table for the current scanbeam */
                    ItNodeTable it_table = new ItNodeTable();
                    it_table.build_intersection_table(aet, dy);

                    /* Process each node in the intersection table */
                    for (ItNode intersect = it_table.top_node ; (intersect != null); intersect = intersect.next)
                    {
                        e0= intersect.ie[0];
                        e1= intersect.ie[1];

                        /* Only generate output for contributing intersections */
                        if ( ((e0.bundle[ABOVE, CLIP]!=0) || (e0.bundle[ABOVE, SUBJ]!=0)) &&
                            ((e1.bundle[ABOVE, CLIP]!=0) || (e1.bundle[ABOVE, SUBJ]!=0)))
                        {
                            PolygonNode p = e0.outp[ABOVE];
                            PolygonNode q = e1.outp[ABOVE];
                            double ix = intersect.point.X;
                            double iy = intersect.point.Y + yb;

                            int in_clip = ( ( (e0.bundle[ABOVE, CLIP]!=0) && !(e0.bside[CLIP]!=0)) ||
                                ( (e1.bundle[ABOVE, CLIP]!=0) &&  (e1.bside[CLIP]!=0)) ||
                                (!(e0.bundle[ABOVE, CLIP]!=0) && !(e1.bundle[ABOVE, CLIP]!=0) &&
                                    (e0.bside[CLIP]!=0) && (e1.bside[CLIP]!=0) ) ) ? 1 : 0;

                            int in_subj = ( ( (e0.bundle[ABOVE, SUBJ]!=0) && !(e0.bside[SUBJ]!=0)) ||
                                ( (e1.bundle[ABOVE, SUBJ]!=0) &&  (e1.bside[SUBJ]!=0)) ||
                                (!(e0.bundle[ABOVE, SUBJ]!=0) && !(e1.bundle[ABOVE, SUBJ]!=0) &&
                                    (e0.bside[SUBJ]!=0) && (e1.bside[SUBJ]!=0) ) ) ? 1 : 0;

                            int tr=0, tl=0, br=0, bl=0 ;
                            /* Determine quadrant occupancies */
                            if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
                            {
                                tr= ((in_clip!=0) && (in_subj!=0)) ? 1 : 0;
                                tl= (((in_clip ^ e1.bundle[ABOVE, CLIP])!=0) && ((in_subj ^ e1.bundle[ABOVE, SUBJ])!=0))?1:0;
                                br= (((in_clip ^ e0.bundle[ABOVE, CLIP])!=0) && ((in_subj ^ e0.bundle[ABOVE, SUBJ])!=0))?1:0;
                                bl= (((in_clip ^ e1.bundle[ABOVE, CLIP] ^ e0.bundle[ABOVE, CLIP])!=0) &&
                                    ((in_subj ^ e1.bundle[ABOVE, SUBJ] ^ e0.bundle[ABOVE, SUBJ])!=0) ) ? 1:0;
                            }
                            else if( op == OperationType.GPC_XOR )
                            {
                                tr= (in_clip)^ (in_subj);
                                tl= (in_clip ^ e1.bundle[ABOVE, CLIP]) ^ (in_subj ^ e1.bundle[ABOVE, SUBJ]);
                                br= (in_clip ^ e0.bundle[ABOVE, CLIP]) ^ (in_subj ^ e0.bundle[ABOVE, SUBJ]);
                                bl= (in_clip ^ e1.bundle[ABOVE, CLIP] ^ e0.bundle[ABOVE, CLIP])
                                    ^ (in_subj ^ e1.bundle[ABOVE, SUBJ] ^ e0.bundle[ABOVE, SUBJ]);
                            }
                            else if( op == OperationType.GPC_UNION )
                            {
                                tr= ((in_clip!=0) || (in_subj!=0)) ? 1 : 0;
                                tl= (((in_clip ^ e1.bundle[ABOVE, CLIP])!=0) || ((in_subj ^ e1.bundle[ABOVE, SUBJ])!=0)) ? 1 : 0;
                                br= (((in_clip ^ e0.bundle[ABOVE, CLIP])!=0) || ((in_subj ^ e0.bundle[ABOVE, SUBJ])!=0)) ? 1 : 0;
                                bl= (((in_clip ^ e1.bundle[ABOVE, CLIP] ^ e0.bundle[ABOVE, CLIP])!=0) ||
                                    ((in_subj ^ e1.bundle[ABOVE, SUBJ] ^ e0.bundle[ABOVE, SUBJ])!=0)) ? 1 : 0;
                            }
                            else
                            {
                                throw new Exception("Unknown op type, "+op);
                            }

                            VertexType vclass = (VertexType)
                                ( tr + (tl << 1) + (br << 2) + (bl << 3));
                            switch (vclass)
                            {
                                case VertexType.EMN:
                                    e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
                                    e1.outp[ABOVE] = e0.outp[ABOVE];
                                    break;
                                case VertexType.ERI:
                                    if (p != null)
                                    {
                                        p.add_right(ix, iy);
                                        e1.outp[ABOVE]= p;
                                        e0.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.ELI:
                                    if (q != null)
                                    {
                                        q.add_left(ix, iy);
                                        e0.outp[ABOVE]= q;
                                        e1.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.EMX:
                                    if ((p!=null) && (q!=null))
                                    {
                                        p.add_left( ix, iy);
                                        out_poly.merge_right(p, q);
                                        e0.outp[ABOVE]= null;
                                        e1.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.IMN:
                                    e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
                                    e1.outp[ABOVE]= e0.outp[ABOVE];
                                    break;
                                case VertexType.ILI:
                                    if (p != null)
                                    {
                                        p.add_left(ix, iy);
                                        e1.outp[ABOVE]= p;
                                        e0.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.IRI:
                                    if (q!=null)
                                    {
                                        q.add_right(ix, iy);
                                        e0.outp[ABOVE]= q;
                                        e1.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.IMX:
                                    if ((p!=null) && (q!=null))
                                    {
                                        p.add_right(ix, iy);
                                        out_poly.merge_left(p, q);
                                        e0.outp[ABOVE]= null;
                                        e1.outp[ABOVE]= null;
                                    }
                                    break;
                                case VertexType.IMM:
                                    if ((p!=null) && (q!=null))
                                    {
                                        p.add_right(ix, iy);
                                        out_poly.merge_left(p, q);
                                        e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
                                        e1.outp[ABOVE]= e0.outp[ABOVE];
                                    }
                                    break;
                                case VertexType.EMM:
                                    if ((p!=null) && (q!=null))
                                    {
                                        p.add_left(ix, iy);
                                        out_poly.merge_right(p, q);
                                        e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
                                        e1.outp[ABOVE] = e0.outp[ABOVE];
                                    }
                                    break;
                                default:
                                    break;
                            } /* End of switch */
                        } /* End of contributing intersection conditional */

                        /* Swap bundle sides in response to edge crossing */
                        if (e0.bundle[ABOVE, CLIP]!=0)
                            e1.bside[CLIP] = (e1.bside[CLIP]==0)?1:0;
                        if (e1.bundle[ABOVE, CLIP]!=0)
                            e0.bside[CLIP]= (e0.bside[CLIP]==0)?1:0;
                        if (e0.bundle[ABOVE, SUBJ]!=0)
                            e1.bside[SUBJ]= (e1.bside[SUBJ]==0)?1:0;
                        if (e1.bundle[ABOVE, SUBJ]!=0)
                            e0.bside[SUBJ]= (e0.bside[SUBJ]==0)?1:0;

                        /* Swap e0 and e1 bundles in the AET */
                        EdgeNode prev_edge = e0.prev;
                        EdgeNode next_edge = e1.next;
                        if (next_edge != null)
                        {
                            next_edge.prev = e0;
                        }

                        if (e0.bstate[ABOVE] == BundleState.BUNDLE_HEAD)
                        {
                            bool search = true;
                            while (search)
                            {
                                prev_edge= prev_edge.prev;
                                if (prev_edge != null)
                                {
                                    if (prev_edge.bstate[ABOVE] != BundleState.BUNDLE_TAIL)
                                    {
                                        search= false;
                                    }
                                }
                                else
                                {
                                    search= false;
                                }
                            }
                        }
                        if (prev_edge == null)
                        {
                            aet.top_node.prev = e1;
                            e1.next           = aet.top_node;
                            aet.top_node      = e0.next;
                        }
                        else
                        {
                            prev_edge.next.prev = e1;
                            e1.next             = prev_edge.next;
                            prev_edge.next      = e0.next;
                        }
                        e0.next.prev = prev_edge;
                        e1.next.prev = e1;
                        e0.next      = next_edge;
            #if DEBUG
                            out_poly.print();
            #endif
                    } /* End of IT loop*/

                    /* Prepare for next scanbeam */
                    for ( EdgeNode edge = aet.top_node; (edge != null); edge = edge.next)
                    {
                        EdgeNode next_edge = edge.next;
                        EdgeNode succ_edge = edge.succ;
                        if ((edge.top.Y == yt) && (succ_edge!=null))
                        {
                            /* Replace AET edge by its successor */
                            succ_edge.outp[BELOW]= edge.outp[ABOVE];
                            succ_edge.bstate[BELOW]= edge.bstate[ABOVE];
                            succ_edge.bundle[BELOW, CLIP]= edge.bundle[ABOVE, CLIP];
                            succ_edge.bundle[BELOW, SUBJ]= edge.bundle[ABOVE, SUBJ];
                            EdgeNode prev_edge = edge.prev;
                            if ( prev_edge != null )
                                prev_edge.next = succ_edge;
                            else
                                aet.top_node = succ_edge;
                            if (next_edge != null)
                                next_edge.prev= succ_edge;
                            succ_edge.prev = prev_edge;
                            succ_edge.next = next_edge;
                        }
                        else
                        {
                            /* Update this edge */
                            edge.outp[BELOW]= edge.outp[ABOVE];
                            edge.bstate[BELOW]= edge.bstate[ABOVE];
                            edge.bundle[BELOW, CLIP]= edge.bundle[ABOVE, CLIP];
                            edge.bundle[BELOW, SUBJ]= edge.bundle[ABOVE, SUBJ];
                            edge.xb= edge.xt;
                        }
                        edge.outp[ABOVE]= null;
                    }
                }
            } /* === END OF SCANBEAM PROCESSING ================================== */

            /* Generate result polygon from out_poly */
            result = out_poly.getResult(polyType);

            return result ;
        }
Пример #19
0
 /**
  * Return the xor of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>polyType</code>.  See the note in the class description
  * for more on <ocde>polyType</code>.
  *
  * @param p1        One of the polygons to performt he xor with
  * @param p2        One of the polygons to performt he xor with
  * @param polyType The type of <code>Poly</code> to return
  */
 public static IPoly Xor( IPoly p1, IPoly p2, Type polyType )
 {
     return Clip( OperationType.GPC_XOR, p1, p2, polyType );
 }
Пример #20
0
 /**
  * Return the xor of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>PolyDefault</code>.
  *
  * @param p1 One of the polygons to performt he xor with
  * @param p2 One of the polygons to performt he xor with
  */
 public static IPoly Xor( IPoly p1, IPoly p2 )
 {
     return Clip( OperationType.GPC_XOR, p1, p2, typeof(PolyDefault) );
 }
Пример #21
0
 /**
  * Throws exception if called
  */
 public void Add(IPoly p)
 {
     throw new Exception("Cannot add poly to a simple poly.");
 }
Пример #22
0
 /**
  * Return the union of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>PolyDefault</code>.
  *
  * @param p1 One of the polygons to performt he union with
  * @param p2 One of the polygons to performt he union with
  */
 public static IPoly Union( IPoly p1, IPoly p2 )
 {
     return Clip( OperationType.GPC_UNION, p1, p2, typeof(PolyDefault) );
 }
Пример #23
0
        /// <summary>
        /// Recursively process the polygon to attempt to find a
        /// single polygon element that could be added to the physics
        /// layer without any holes or additional physics.
        /// </summary>
        private void CreateJunctionPhysics(
			int depth, IPoly poly, RectangleF bounds)
        {
            // Ignore empty polygons
            if (poly.InnerPolygonCount == 0)
                return;

            // See if we are a solid polygon
            double areaDifference = bounds.Width * bounds.Height - poly.Area;

            if (poly.InnerPolygonCount == 1)
            {
                if (poly.IsHole())
                    // Don't add holes
                    return;

                if (poly.PointCount == 4 && areaDifference <= 0.1f)
                    // We appear to be at least mostly solid, drop it
                    return;
            }

            // If we have more than one polygon, split it
            if (poly.InnerPolygonCount > 1 ||
                bounds.Width > Constants.MaximumJunctionPhysicsBlock ||
                bounds.Height > Constants.MaximumJunctionPhysicsBlock)
            {
                // We split the polygon into quads and process each
                // one to add it recursively.
                CreateJunctionPhysics(depth + 1, poly, bounds, 0, 0);
                CreateJunctionPhysics(depth + 1, poly, bounds, 0, 1);
                CreateJunctionPhysics(depth + 1, poly, bounds, 1, 1);
                CreateJunctionPhysics(depth + 1, poly, bounds, 1, 0);
                return;
            }

            // We should never get a hole
            if (poly.IsHole())
            {
                // We shouldn't get this
                Log.Error("Got a top-level polygon hole");
                return;
            }

            // Create a polygon shape as vectors
            LinkedList<Vector2D> vectors = new LinkedList<Vector2D>();

            for (int i = 0; i < poly.PointCount; i++)
            {
                // Get the coordinates
                float x = (float) poly.GetX(i);
                float y = (float) poly.GetY(i);

                // Create the vector
                vectors.Add(new Vector2D(x, y));
            }

            // Convert it into a physics2d polygon shape. Making the
            // PolygonShape second parameter too small makes the game
            // basically unusable in terms of stage generation but
            // more accurate for impacts with the side.
            Vector2D [] array = vectors.ToArray();
            IShape ps = new PolygonShape(array, 5f);
            physicsShapes.Add(ps);
        }
Пример #24
0
 /**
  * Return a IPoly that is the union of this polygon with the given polygon.
  * The returned polygon could be complex.
  *
  * @return the returned IPoly will be an instance of PolyDefault.
  */
 public IPoly Union(IPoly p)
 {
     return Clipper.Union( p, this, GetType() );
 }
Пример #25
0
 /// <summary>
 /// Returns true if the two polygons intersect.
 /// </summary>
 public bool HasIntersection(IPoly p)
 {
     // Get the intersection
     IPoly intersection = Intersection(p);
     return intersection.PointCount != 0;
 }
Пример #26
0
 /**
  * Add an inner polygon to this polygon - assumes that adding polygon does not
  * have any inner polygons.
  *
  * @throws IllegalStateException if the number of inner polygons is greater than
  * zero and this polygon was designated a hole.  This would break the assumption
  * that only simple polygons can be holes.
  */
 public void Add( IPoly p )
 {
     if( (m_List.Count > 0) && isHole )
     {
         throw new Exception("Cannot add polys to something designated as a hole.");
     }
     m_List.Add( p );
 }
 private void Reset()
 {
     Holes = new List<IPoly>();
     Outline = null;
 }
Пример #28
0
 /**
  * Return the difference of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>polyType</code>.  See the note in the class description
  * for more on <ocde>polyType</code>.
  *
  * @param p1        One of the polygons to performt he intersection with
  * @param p2        One of the polygons to performt he intersection with
  * @param polyType The type of <code>Poly</code> to return
  */
 public static IPoly Difference( IPoly p1, IPoly p2, Type polyType )
 {
     return Clip( OperationType.GPC_DIFF, p1, p2, polyType );
 }
Пример #29
0
 /**
  * Return the difference of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>PolyDefault</code>.
  *
  * @param p1 One of the polygons to performt he intersection with
  * @param p2 One of the polygons to performt he intersection with
  */
 public static IPoly Difference( IPoly p1, IPoly p2 )
 {
     return Clip( OperationType.GPC_DIFF, p1, p2, typeof(PolyDefault) );
 }
Пример #30
0
        /// <summary>
        /// Resets the junction node's status, including purging all
        /// generated data and resetting to a known seed value.
        /// </summary>
        public void Reset()
        {
            // Reset the flags
            builtShape = false;
            builtConnections = false;

            // Purge the stored data
            internalShape = null;
            shape = null;
            segments.Clear();
            physicsShapes.Clear();

            // Reset the random value
            random = new MersenneRandom(randomSeed);
        }
Пример #31
0
        private static RectangleF[] create_contour_bboxes( IPoly p )
        {
            RectangleF[] box = new RectangleF[p.InnerPolygonCount] ;

            /* Construct contour bounding boxes */
            for ( int c= 0; c < p.InnerPolygonCount; c++)
            {
                IPoly inner_poly = p.GetInnerPoly(c);
                box[c] = inner_poly.Bounds;
            }
            return box;
        }
Пример #32
0
        /// <summary>
        /// Splits apart a polygon into a quad and processes it for physics.
        /// </summary>
        private void CreateJunctionPhysics(
			int depth,
			IPoly poly, RectangleF bounds,
			int row, int col)
        {
            // Figure out the desired size and shape
            SizeF size = new SizeF(bounds.Width / 2, bounds.Height / 2);
            PointF point = new PointF(
                bounds.X + col * bounds.Width / 2,
                bounds.Y + row * bounds.Height / 2);
            RectangleF rect = new RectangleF(point, size);

            // Create the GPC polygon and calculate the intersection
            IPoly rectangle = Geometry.CreateRectangle(rect);
            IPoly intersection = rectangle.Intersection(poly);

            // Process this one
            CreateJunctionPhysics(depth, intersection, rect);
        }
Пример #33
0
 /**
  * Return the intersection of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>polyType</code>.  See the note in the class description
  * for more on <ocde>polyType</code>.
  *
  * @param p1        One of the polygons to performt he intersection with
  * @param p2        One of the polygons to performt he intersection with
  * @param polyType The type of <code>Poly</code> to return
  */
 public static IPoly Intersection( IPoly p1, IPoly p2, Type polyType )
 {
     return Clip( OperationType.GPC_INT, p1, p2, polyType );
 }
 private static IPoly CreatePoly(IPoly poly, List<IPoly> holes)
 {
     if (holes.Count > 0)
     {
         return new ComplexPoly(poly,  holes.ToArray());
     }
     else
     {
         return poly;   
     }
 }
Пример #35
0
        private static void minimax_test( IPoly subj, IPoly clip, OperationType op )
        {
            RectangleF[] s_bbox = create_contour_bboxes(subj);
            RectangleF[] c_bbox = create_contour_bboxes(clip);

            int subj_num_poly = subj.InnerPolygonCount;
            int clip_num_poly = clip.InnerPolygonCount;
            bool[,] o_table = new bool[subj_num_poly,clip_num_poly] ;

            /* Check all subject contour bounding boxes against clip boxes */
            for( int s = 0; s < subj_num_poly; s++ )
            {
                for( int c= 0; c < clip_num_poly ; c++ )
                {
                    o_table[s, c] =
                        (!((s_bbox[s].Right < c_bbox[c].Left) ||
                            (s_bbox[s].Left > c_bbox[c].Right))) &&
                        (!((s_bbox[s].Bottom < c_bbox[c].Top) ||
                            (s_bbox[s].Top > c_bbox[c].Bottom)));
                }
            }

            /* For each clip contour, search for any subject contour overlaps */
            for( int c = 0; c < clip_num_poly; c++ )
            {
                bool overlap = false;
                for( int s = 0; !overlap && (s < subj_num_poly) ; s++)
                {
                    overlap = o_table[s, c];
                }
                if (!overlap)
                {
                    clip.SetContributing( c, false ); // Flag non contributing status
                }
            }

            if (op == OperationType.GPC_INT)
            {
                /* For each subject contour, search for any clip contour overlaps */
                for ( int s= 0; s < subj_num_poly; s++)
                {
                    bool overlap = false;
                    for ( int c= 0; !overlap && (c < clip_num_poly); c++)
                    {
                        overlap = o_table[s, c];
                    }
                    if (!overlap)
                    {
                        subj.SetContributing( s, false ); // Flag non contributing status
                    }
                }
            }
        }
Пример #36
0
 /**
  * Return a IPoly that is the difference of this polygon with the given polygon.
  * The returned polygon could be complex.
  *
  * @return the returned IPoly will be an instance of PolyDefault.
  */
 public IPoly Difference(IPoly p)
 {
     return Clipper.Difference( p, this, GetType() );
 }
Пример #37
0
 private static bool OPTIMAL( IPoly p, int i )
 {
     return (p.GetY(PREV_INDEX(i, p.PointCount)) != p.GetY(i)) ||
         (p.GetY(NEXT_INDEX(i, p.PointCount)) != p.GetY(i)) ;
 }
Пример #38
0
 /**
  * Return a IPoly that is the intersection of this polygon with the given polygon.
  * The returned polygon could be complex.
  *
  * @return the returned IPoly will be an instance of PolyDefault.
  */
 public IPoly Intersection(IPoly p)
 {
     return Clipper.Intersection( p, this, GetType() );
 }
Пример #39
0
 /**
  * Return the intersection of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>PolyDefault</code>.
  *
  * @param p1 One of the polygons to performt he intersection with
  * @param p2 One of the polygons to performt he intersection with
  */
 public static IPoly Intersection( IPoly p1, IPoly p2 )
 {
     return Clip( OperationType.GPC_INT, p1, p2, typeof(PolyDefault) );
 }
Пример #40
0
 /**
  * Return a IPoly that is the exclusive-or of this polygon with the given polygon.
  * The returned polygon could be complex.
  *
  * @return the returned IPoly will be an instance of PolyDefault.
  */
 public IPoly Xor(IPoly p)
 {
     return Clipper.Xor( p, this, GetType() );
 }
Пример #41
0
 /**
  * Return the union of <code>p1</code> and <code>p2</code> where the
  * return type is of <code>polyType</code>.  See the note in the class description
  * for more on <ocde>polyType</code>.
  *
  * @param p1        One of the polygons to performt he union with
  * @param p2        One of the polygons to performt he union with
  * @param polyType The type of <code>Poly</code> to return
  */
 public static IPoly Union( IPoly p1, IPoly p2, Type polyType )
 {
     return Clip( OperationType.GPC_UNION, p1, p2, polyType );
 }
 private IPoly merge(IPoly poly1, IPoly poly2)
 {
     IPoly merged;
     Assert.True(poly1.TryMerge(poly2, out merged), "Should succeed with merge");
     return merged;
 }
Пример #43
0
        /// <summary>
        /// Renders an arbitrary polygon to the context.
        /// </summary>
        private void RenderPolygon(
			Context g, IPoly poly, PointF point, Color color)
        {
            // Save the first point
            PointF firstPoint = PointF.Empty;

            // Go through the points of the polygon
            for (int i = 0; i < poly.PointCount; i++)
            {
                // Pull out the coordinates
                float x = (float) poly.GetX(i);
                float y = (float) poly.GetY(i);
                PointF p = new PointF(cx + point.X + x, cy + point.Y + y);

                // Either move or line
                if (firstPoint == PointF.Empty)
                {
                    firstPoint = p;
                    g.MoveTo(p.X, p.Y);
                }
                else
                {
                    g.LineTo(p.X, p.Y);
                }
            }

            // Finish up
            g.LineTo(firstPoint.X, firstPoint.Y);
            g.Color = color;
            g.Fill();
        }