001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package sec.sun.awt.geom;
006
007/**
008 *
009 * @author Michael Deutch
010 */
011public class SomeOp {
012    public static final int SUBOP = 0;
013    public static final int ADDOP = 1;
014    public static final int INTOP = 2;
015    public static final int XOROP = 3;
016    
017    public SomeOp(int type)
018    {
019        _type=type;
020    }
021    private int _type=-1;
022        boolean inLeft;
023        boolean inRight;
024        boolean inResult;
025
026        public void newRow() {
027            inLeft = false;
028            inRight = false;
029            inResult = false;
030        }
031
032        public int classify(Edge e) {
033            if (e.getCurveTag() == AreaOp2.CTAG_LEFT) {
034                inLeft = !inLeft;
035            } else {
036                inRight = !inRight;
037            }
038            boolean newClass = newClassification(inLeft, inRight);
039            if (inResult == newClass) {
040                return AreaOp2.ETAG_IGNORE;
041            }
042            inResult = newClass;
043            return (newClass ? AreaOp2.ETAG_ENTER : AreaOp2.ETAG_EXIT);
044        }
045
046        public int getState() {
047            return (inResult ? AreaOp2.RSTAG_INSIDE : AreaOp2.RSTAG_OUTSIDE);
048        }
049    public boolean newClassification(boolean inLeft, boolean inRight) {
050        switch(_type)
051        {
052            case ADDOP:
053            return (inLeft || inRight);
054            case SUBOP:
055            return (inLeft && !inRight);
056            case INTOP:
057            return (inLeft && inRight);
058            case XOROP:
059            return (inLeft != inRight);
060            default:
061                return false;
062                                
063        }
064    }
065    
066    
067    //all the code from AreaOp that this class extends
068    public Vector calculate(Vector left, Vector right) {
069        Vector edges = new Vector();
070        addEdges(edges, left, AreaOp2.CTAG_LEFT);
071        addEdges(edges, right, AreaOp2.CTAG_RIGHT);
072        edges = pruneEdges(edges);
073        if (false) {
074            System.out.println("result: ");
075            int numcurves = edges.size();
076            //Curve[] curvelist = (Curve[]) edges.toArray(new Curve[numcurves]);
077            Curve[] curvelist = (Curve[]) edges.toArray2();
078            for (int i = 0; i < numcurves; i++) {
079                System.out.println("curvelist["+i+"] = "+curvelist[i]);
080            }
081        }
082        return edges;
083    }
084
085    private static void addEdges(Vector edges, Vector curves, int curvetag) {
086        Enumeration enum_ = curves.elements();
087        CurveObject c=null;
088        Object obj=null;
089        while (enum_.hasMoreElements()) {
090            //CurveObject c = (CurveObject) enum_.nextElement();
091            obj=enum_.nextElement();
092            if(obj instanceof CurveObject)
093                c=(CurveObject)obj;
094            else
095                c=new CurveObject(obj);
096            if (c.getOrder() > 0) {
097                edges.add(new Edge(c, curvetag));
098            }
099        }
100    }
101
102    private Vector pruneEdges(Vector edges) {
103        int numedges = edges.size();
104        if (numedges < 2) {
105            return edges;
106        }
107        //Edge[] edgelist = (Edge[]) edges.toArray(new Edge[numedges]);        
108        //Edge[] edgelist = (Edge[]) edges.toArray();
109        Edge[] edgelist = new Edge[numedges];
110        Enumeration _enum=edges.elements();
111        int k=0;
112        while(_enum.hasMoreElements())
113        {
114            edgelist[k++]=(Edge)_enum.nextElement();
115        }
116        //Arrays.sort(edgelist, YXTopComparator);        
117        Arrays.sort(edgelist);        
118        if (false) {
119            System.out.println("pruning: ");
120            for (int i = 0; i < numedges; i++) {
121                System.out.println("edgelist["+i+"] = "+edgelist[i]);
122            }
123        }
124        Edge e;
125        int left = 0;
126        int right = 0;
127        int cur = 0;
128        int next = 0;
129        double yrange[] = new double[2];
130        Vector subcurves = new Vector();
131        Vector chains = new Vector();
132        Vector links = new Vector();
133        // Active edges are between left (inclusive) and right (exclusive)
134        while (left < numedges) {
135            double y = yrange[0];
136            // Prune active edges that fall off the top of the active y range
137            for (cur = next = right - 1; cur >= left; cur--) {
138                e = edgelist[cur];
139                if (e.getCurve().getYBot() > y) {
140                    if (next > cur) {
141                        edgelist[next] = e;
142                    }
143                    next--;
144                }
145            }
146            left = next + 1;
147            // Grab a new "top of Y range" if the active edges are empty
148            if (left >= right) {
149                if (right >= numedges) {
150                    break;
151                }
152                y = edgelist[right].getCurve().getYTop();
153                if (y > yrange[0]) {
154                    finalizeSubCurves(subcurves, chains);
155                }
156                yrange[0] = y;
157            }
158            // Incorporate new active edges that enter the active y range
159            while (right < numedges) {
160                e = edgelist[right];
161                if (e.getCurve().getYTop() > y) {
162                    break;
163                }
164                right++;
165            }
166            // Sort the current active edges by their X values and
167            // determine the maximum valid Y range where the X ordering
168            // is correct
169            yrange[1] = edgelist[left].getCurve().getYBot();
170            if (right < numedges) {
171                y = edgelist[right].getCurve().getYTop();
172                if (yrange[1] > y) {
173                    yrange[1] = y;
174                }
175            }
176            if (false) {
177                System.out.println("current line: y = ["+
178                                   yrange[0]+", "+yrange[1]+"]");
179                for (cur = left; cur < right; cur++) {
180                    System.out.println("  "+edgelist[cur]);
181                }
182            }
183            // Note: We could start at left+1, but we need to make
184            // sure that edgelist[left] has its equivalence set to 0.
185            int nexteq = 1;
186            for (cur = left; cur < right; cur++) {
187                e = edgelist[cur];
188                e.setEquivalence(0);
189                for (next = cur; next > left; next--) {
190                    Edge prevedge = edgelist[next-1];
191                    int ordering = e.compareTo(prevedge, yrange);
192                    if (yrange[1] <= yrange[0]) {
193                        throw new InternalError("backstepping to "+yrange[1]+
194                                                " from "+yrange[0]);
195                    }
196                    if (ordering >= 0) {
197                        if (ordering == 0) {
198                            // If the curves are equal, mark them to be
199                            // deleted later if they cancel each other
200                            // out so that we avoid having extraneous
201                            // curve segments.
202                            int eq = prevedge.getEquivalence();
203                            if (eq == 0) {
204                                eq = nexteq++;
205                                prevedge.setEquivalence(eq);
206                            }
207                            e.setEquivalence(eq);
208                        }
209                        break;
210                    }
211                    edgelist[next] = prevedge;
212                }
213                edgelist[next] = e;                
214            }
215            if (false) {
216                System.out.println("current sorted line: y = ["+
217                                   yrange[0]+", "+yrange[1]+"]");
218                for (cur = left; cur < right; cur++) {
219                    System.out.println("  "+edgelist[cur]);
220                }
221            }
222            // Now prune the active edge list.
223            // For each edge in the list, determine its classification
224            // (entering shape, exiting shape, ignore - no change) and
225            // record the current Y range and its classification in the
226            // Edge object for use later in constructing the new outline.
227            newRow();
228            double ystart = yrange[0];
229            double yend = yrange[1];
230            for (cur = left; cur < right; cur++) {
231                e = edgelist[cur];
232                int etag;
233                int eq = e.getEquivalence();
234                if (eq != 0) {
235                    // Find one of the segments in the "equal" range
236                    // with the right transition state and prefer an
237                    // edge that was either active up until ystart
238                    // or the edge that extends the furthest downward
239                    // (i.e. has the most potential for continuation)
240                    int origstate = getState();
241                    etag = (origstate == AreaOp2.RSTAG_INSIDE
242                            ? AreaOp2.ETAG_EXIT
243                            : AreaOp2.ETAG_ENTER);
244                    Edge activematch = null;
245                    Edge longestmatch = e;
246                    double furthesty = yend;
247                    do {
248                        // Note: classify() must be called
249                        // on every edge we consume here.
250                        classify(e);
251                        if (activematch == null &&
252                            e.isActiveFor(ystart, etag))
253                        {
254                            activematch = e;
255                        }
256                        y = e.getCurve().getYBot();
257                        if (y > furthesty) {
258                            longestmatch = e;
259                            furthesty = y;
260                        }
261                    } while (++cur < right &&
262                             (e = edgelist[cur]).getEquivalence() == eq);
263                    --cur;
264                    if (getState() == origstate) {
265                        etag = AreaOp2.ETAG_IGNORE;
266                    } else {
267                        e = (activematch != null ? activematch : longestmatch);
268                    }
269                } else {
270                    etag = classify(e);
271                }
272                if (etag != AreaOp2.ETAG_IGNORE) {
273                    e.record(yend, etag);
274                    links.add(new CurveLink(e.getCurve(), ystart, yend, etag));
275                }
276            }
277            // assert(getState() == AreaOp.RSTAG_OUTSIDE);
278            if (getState() != AreaOp2.RSTAG_OUTSIDE) {
279                System.out.println("Still inside at end of active edge list!");
280                System.out.println("num curves = "+(right-left));
281                System.out.println("num links = "+links.size());
282                System.out.println("y top = "+yrange[0]);
283                if (right < numedges) {
284                    System.out.println("y top of next curve = "+
285                                       edgelist[right].getCurve().getYTop());
286                } else {
287                    System.out.println("no more curves");
288                }
289                for (cur = left; cur < right; cur++) {
290                    e = edgelist[cur];
291                    System.out.println(e);
292                    int eq = e.getEquivalence();
293                    if (eq != 0) {
294                        System.out.println("  was equal to "+eq+"...");
295                    }
296                }
297            }
298            if (false) {
299                System.out.println("new links:");
300                for (int i = 0; i < links.size(); i++) {
301                    CurveLink link = (CurveLink) links.elementAt(i);
302                    System.out.println("  "+link.getSubCurve());
303                }
304            }
305            resolveLinks(subcurves, chains, links);
306            links.clear();
307            // Finally capture the bottom of the valid Y range as the top
308            // of the next Y range.
309            yrange[0] = yend;
310        }
311        finalizeSubCurves(subcurves, chains);
312        Vector ret = new Vector();
313        Enumeration enum_ = subcurves.elements();
314        CurveObject c=null;
315        Object obj=null;
316        while (enum_.hasMoreElements()) {
317            CurveLink link = (CurveLink) enum_.nextElement();
318            ret.add(link.getMoveto());
319            CurveLink nextlink = link;
320            while ((nextlink = nextlink.getNext()) != null) {
321                if (!link.absorb(nextlink)) 
322                {
323                    //ret.add(link.getSubCurve());
324                    obj=link.getSubCurve();
325//                    if(! (obj instanceof CurveObject) )
326//                    {
327//                        CurveObject c=new CurveObject(obj);
328//                        ret.add(c);
329//                    }
330//                    else
331//                        ret.add(link.getSubCurve());
332                    if(obj instanceof Order0)
333                        c=((Order0)obj).getParent();
334                    else if(obj instanceof Order1)
335                        c=((Order1)obj).getParent();
336                    else if(obj instanceof Order2)
337                        c=((Order2)obj).getParent();
338                    else if(obj instanceof Order3)
339                        c=((Order3)obj).getParent();
340                    else if(obj instanceof CurveObject)
341                        c=(CurveObject)obj;
342                    if(c==null)                    
343                        c=new CurveObject(obj);
344                    
345                    
346                    ret.add(c);
347                    link = nextlink;
348                }
349            }
350            obj=link.getSubCurve();
351            //ret.add(link.getSubCurve());
352            if(obj instanceof Order0)
353                c=((Order0)obj).getParent();
354            else if(obj instanceof Order1)
355                c=((Order1)obj).getParent();
356            else if(obj instanceof Order2)
357                c=((Order2)obj).getParent();
358            else if(obj instanceof Order3)
359                c=((Order3)obj).getParent();
360            else if(obj instanceof CurveObject)
361                c=(CurveObject)obj;
362            if(c==null)                    
363                c=new CurveObject(obj);
364            
365            ret.add(c);
366        }
367        return ret;
368    }
369
370    public static void finalizeSubCurves(Vector subcurves, Vector chains) {
371        int numchains = chains.size();
372        if (numchains == 0) {
373            return;
374        }
375        if ((numchains & 1) != 0) {
376            throw new InternalError("Odd number of chains!");
377        }
378        ChainEnd[] endlist = new ChainEnd[numchains];
379        chains.toArray(endlist);
380        for (int i = 1; i < numchains; i += 2) {
381            ChainEnd open = endlist[i - 1];
382            ChainEnd close = endlist[i];
383            CurveLink subcurve = open.linkTo(close);
384            if (subcurve != null) {
385                subcurves.add(subcurve);
386            }
387        }
388        chains.clear();
389    }
390
391    private static CurveLink[] EmptyLinkList = new CurveLink[2];
392    private static ChainEnd[] EmptyChainList = new ChainEnd[2];
393
394    public static void resolveLinks(Vector subcurves,
395                                    Vector chains,
396                                    Vector links)
397    {
398        int numlinks = links.size();
399        CurveLink[] linklist;
400        if (numlinks == 0) {
401            linklist = EmptyLinkList;
402        } else {
403            if ((numlinks & 1) != 0) {
404                throw new InternalError("Odd number of new curves!");
405            }
406            linklist = new CurveLink[numlinks+2];
407            links.toArray(linklist);
408        }
409        int numchains = chains.size();
410        ChainEnd[] endlist;
411        if (numchains == 0) {
412            endlist = EmptyChainList;
413        } else {
414            if ((numchains & 1) != 0) {
415                throw new InternalError("Odd number of chains!");
416            }
417            endlist = new ChainEnd[numchains+2];
418            chains.toArray(endlist);
419        }
420        int curchain = 0;
421        int curlink = 0;
422        chains.clear();
423        ChainEnd chain = endlist[0];
424        ChainEnd nextchain = endlist[1];
425        CurveLink link = linklist[0];
426        CurveLink nextlink = linklist[1];
427        while (chain != null || link != null) {
428            /*
429             * Strategy 1:
430             * Connect chains or links if they are the only things left...
431             */
432            boolean connectchains = (link == null);
433            boolean connectlinks = (chain == null);
434
435            if (!connectchains && !connectlinks) {
436                // assert(link != null && chain != null);
437                /*
438                 * Strategy 2:
439                 * Connect chains or links if they close off an open area...
440                 */
441                connectchains = ((curchain & 1) == 0 &&
442                                 chain.getX() == nextchain.getX());
443                connectlinks = ((curlink & 1) == 0 &&
444                                link.getX() == nextlink.getX());
445
446                if (!connectchains && !connectlinks) {
447                    /*
448                     * Strategy 3:
449                     * Connect chains or links if their successor is
450                     * between them and their potential connectee...
451                     */
452                    double cx = chain.getX();
453                    double lx = link.getX();
454                    connectchains =
455                        (nextchain != null && cx < lx &&
456                         obstructs(nextchain.getX(), lx, curchain));
457                    connectlinks =
458                        (nextlink != null && lx < cx &&
459                         obstructs(nextlink.getX(), cx, curlink));
460                }
461            }
462            if (connectchains) {
463                CurveLink subcurve = chain.linkTo(nextchain);
464                if (subcurve != null) {
465                    subcurves.add(subcurve);
466                }
467                curchain += 2;
468                chain = endlist[curchain];
469                nextchain = endlist[curchain+1];
470            }
471            if (connectlinks) {
472                ChainEnd openend = new ChainEnd(link, null);
473                ChainEnd closeend = new ChainEnd(nextlink, openend);
474                openend.setOtherEnd(closeend);
475                chains.add(openend);
476                chains.add(closeend);
477                curlink += 2;
478                link = linklist[curlink];
479                nextlink = linklist[curlink+1];
480            }
481            if (!connectchains && !connectlinks) {
482                // assert(link != null);
483                // assert(chain != null);
484                // assert(chain.getEtag() == link.getEtag());
485                chain.addLink(link);
486                chains.add(chain);
487                curchain++;
488                chain = nextchain;
489                nextchain = endlist[curchain+1];
490                curlink++;
491                link = nextlink;
492                nextlink = linklist[curlink+1];
493            }
494        }
495        if ((chains.size() & 1) != 0) {
496            System.out.println("Odd number of chains!");
497        }
498    }
499
500    /*
501     * Does the position of the next edge at v1 "obstruct" the
502     * connectivity between current edge and the potential
503     * partner edge which is positioned at v2?
504     *
505     * Phase tells us whether we are testing for a transition
506     * into or out of the interior part of the resulting area.
507     *
508     * Require 4-connected continuity if this edge and the partner
509     * edge are both "entering into" type edges
510     * Allow 8-connected continuity for "exiting from" type edges
511     */
512    public static boolean obstructs(double v1, double v2, int phase) {
513        return (((phase & 1) == 0) ? (v1 <= v2) : (v1 < v2));
514    }
515   
516}