Пример #1
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;
        }
Пример #2
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 ;
        }
Пример #3
0
 private static LmtNode bound_list( LmtTable lmt_table, double y )
 {
     if( lmt_table.top_node == null )
     {
         lmt_table.top_node = new LmtNode(y);
         return lmt_table.top_node ;
     }
     else
     {
         LmtNode prev = null ;
         LmtNode node = lmt_table.top_node ;
         bool done = false ;
         while( !done )
         {
             if( y < node.y )
             {
                 /* Insert a new LMT node before the current node */
                 LmtNode existing_node = node ;
                 node = new LmtNode(y);
                 node.next = existing_node ;
                 if( prev == null )
                 {
                     lmt_table.top_node = node ;
                 }
                 else
                 {
                     prev.next = node ;
                 }
                 //               if( existing_node == lmt_table.top_node )
                 //               {
                 //                  lmt_table.top_node = node ;
                 //               }
                 done = true ;
             }
             else if ( y > node.y )
             {
                 /* Head further up the LMT */
                 if( node.next == null )
                 {
                     node.next = new LmtNode(y);
                     node = node.next ;
                     done = true ;
                 }
                 else
                 {
                     prev = node ;
                     node = node.next ;
                 }
             }
             else
             {
                 /* Use this existing LMT node */
                 done = true ;
             }
         }
         return node ;
     }
 }