001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package sec.sun.awt.geom;
006
007import armyc2.c2sd.graphics2d.Rectangle2D;
008
009/**
010 *
011 * @author Michael Deutch
012 */
013public class CurveObject {
014
015    private Order0 order0 = null;
016    private Order1 order1 = null;
017    private Order2 order2 = null;
018    private Order3 order3 = null;
019    int order = -1;
020
021    public CurveObject(Object obj) {
022        if (obj instanceof Order0) {
023            order0 = (Order0) obj;
024            order = 0;
025        } else if (obj instanceof Order1) {
026            order1 = (Order1) obj;
027            order = 1;
028        } else if (obj instanceof Order2) {
029            order2 = (Order2) obj;
030            order = 2;
031        } else if (obj instanceof Order3) {
032            order3 = (Order3) obj;
033            order = 3;
034        }
035        setParent();
036    }
037
038    private void setParent() {
039        switch (order) {
040            case 0:
041                order0.setParent(this);
042                break;
043            case 1:
044                order1.setParent(this);
045                break;
046            case 2:
047                order2.setParent(this);
048                break;
049            case 3:
050                order3.setParent(this);
051                break;
052            default:
053                break;
054        }
055        return;
056    }
057
058    public Object getCurve() {
059        switch (order) {
060            case 0:
061                return order0;
062            case 1:
063                return order1;
064            case 2:
065                return order2;
066            case 3:
067                return order3;
068            default:
069                return null;
070        }
071    }
072
073    public int getOrder() {
074        return order;
075    }
076
077    public double getXTop() {
078        switch (order) {
079            case 0:
080                return order0.getXTop();
081            case 1:
082                return order1.getXTop();
083            case 2:
084                return order2.getXTop();
085            case 3:
086                return order3.getXTop();
087            default:
088                return -7;
089        }
090    }
091
092    public CurveObject(int direction) {
093        //this.direction = direction;
094        switch (order) {
095            case 0:
096                order0.direction = direction;
097                break;
098            case 1:
099                order1.direction = direction;
100                break;
101            case 2:
102                order2.direction = direction;
103                break;
104            case 3:
105                order3.direction = direction;
106                break;
107            default:
108                break;
109        }
110    }
111
112    public double getYTop() {
113        switch (order) {
114            case 0:
115                return order0.getYTop();
116            case 1:
117                return order1.getYTop();
118            case 2:
119                return order2.getYTop();
120            case 3:
121                return order3.getYTop();
122            default:
123                return -7;
124        }
125    }
126
127    public double getXBot() {
128        switch (order) {
129            case 0:
130                return order0.getXBot();
131            case 1:
132                return order1.getXBot();
133            case 2:
134                return order2.getXBot();
135            case 3:
136                return order3.getXBot();
137            default:
138                return -7;
139        }
140
141    }
142
143    public double getYBot() {
144        switch (order) {
145            case 0:
146                return order0.getYBot();
147            case 1:
148                return order1.getYBot();
149            case 2:
150                return order2.getYBot();
151            case 3:
152                return order3.getYBot();
153            default:
154                return -7;
155        }
156
157    }
158
159    public double getXMin() {
160        switch (order) {
161            case 0:
162                return order0.getXMin();
163            case 1:
164                return order1.getXMin();
165            case 2:
166                return order2.getXMin();
167            case 3:
168                return order3.getXMin();
169            default:
170                return -7;
171        }
172    }
173
174    public double getXMax() {
175        switch (order) {
176            case 0:
177                return order0.getXMax();
178            case 1:
179                return order1.getXMax();
180            case 2:
181                return order2.getXMax();
182            case 3:
183                return order3.getXMax();
184            default:
185                return -7;
186        }
187    }
188
189    public final int getDirection() {
190        //return direction;
191        switch (order) {
192            case 0:
193                return order0.direction;
194            case 1:
195                return order1.direction;
196            case 2:
197                return order2.direction;
198            case 3:
199                return order3.direction;
200            default:
201                return -1;
202        }
203    }
204
205    public double XforY(double y) {
206        switch (order) {
207            case 0:
208                return order0.XforY(y);
209            case 1:
210                return order1.XforY(y);
211            case 2:
212                return order2.XforY(y);
213            case 3:
214                return order3.XforY(y);
215            default:
216                return -7;
217        }
218    }
219
220    public Object getReversedCurve() {
221        switch (order) {
222            case 0:
223                return order0.getReversedCurve();
224            case 1:
225                return order1.getReversedCurve();
226            case 2:
227                return order2.getReversedCurve();
228            case 3:
229                return order3.getReversedCurve();
230            default:
231                return null;
232        }
233    }
234
235    public double getX0() {
236        switch (order) {
237            case 0:
238                return order0.getX0();
239            case 1:
240                return order1.getX0();
241            case 2:
242                return order2.getX0();
243            case 3:
244                return order3.getX0();
245            default:
246                return -7;
247        }
248    }
249
250    public double getY0() {
251        switch (order) {
252            case 0:
253                return order0.getY0();
254            case 1:
255                return order1.getY0();
256            case 2:
257                return order2.getY0();
258            case 3:
259                return order3.getY0();
260            default:
261                return -7;
262        }
263    }
264
265    public double getX1() {
266        switch (order) {
267            case 0:
268                return order0.getX1();
269            case 1:
270                return order1.getX1();
271            case 2:
272                return order2.getX1();
273            case 3:
274                return order3.getX1();
275            default:
276                return -7;
277        }
278    }
279
280    public double getY1() {
281        switch (order) {
282            case 0:
283                return order0.getY1();
284            case 1:
285                return order1.getY1();
286            case 2:
287                return order2.getY1();
288            case 3:
289                return order3.getY1();
290            default:
291                return -7;
292        }
293    }
294
295    public double XforT(double t) {
296        switch (order) {
297            case 0:
298                return order0.XforT(t);
299            case 1:
300                return order1.XforT(t);
301            case 2:
302                return order2.XforT(t);
303            case 3:
304                return order3.XforT(t);
305            default:
306                return -7;
307        }
308    }
309
310    public double YforT(double t) {
311        switch (order) {
312            case 0:
313                return order0.YforT(t);
314            case 1:
315                return order1.YforT(t);
316            case 2:
317                return order2.YforT(t);
318            case 3:
319                return order3.YforT(t);
320            default:
321                return -7;
322        }
323    }
324
325    public double TforY(double t) {
326        switch (order) {
327            case 0:
328                return order0.TforY(t);
329            case 1:
330                return order1.TforY(t);
331            case 2:
332                return order2.TforY(t);
333            case 3:
334                return order3.TforY(t);
335            default:
336                return -7;
337        }
338    }
339
340    public double nextVertical(double t0, double t1) {
341        switch (order) {
342            case 0:
343                return order0.nextVertical(t0, t1);
344            case 1:
345                return order1.nextVertical(t0, t1);
346            case 2:
347                return order2.nextVertical(t0, t1);
348            case 3:
349                return order3.nextVertical(t0, t1);
350            default:
351                return -7;
352        }
353    }
354
355    public String controlPointString() {
356        switch (order) {
357            case 0:
358                return "";
359            case 1:
360                return "";
361            case 2:
362                return order2.controlPointString();
363            case 3:
364                return order3.controlPointString();
365            default:
366                return "";
367        }
368    }
369
370    @Override
371    public String toString() {
372        return ("Curve["
373                + getOrder() + ", "
374                + ("(" + Curve.round(this.getX0()) + ", " + Curve.round(this.getY0()) + "), ")
375                + this.controlPointString()
376                + ("(" + Curve.round(getX1()) + ", " + Curve.round(getY1()) + "), ")
377                + //(direction == Curve.INCREASING ? "D" : "U")+
378                (this.getDirection() == Curve.INCREASING ? "D" : "U")
379                + "]");
380    }
381
382    public int crossingsFor(double x, double y) {
383        if (y >= this.getYTop() && y < this.getYBot()) {
384            if (x < this.getXMax() && (x < this.getXMin() || x < this.XforY(y))) {
385                return 1;
386            }
387        }
388        return 0;
389    }
390
391    public boolean accumulateCrossings(CrossingsObject c) {
392        double xhi = c.getXHi();
393        if (getXMin() >= xhi) {
394            return false;
395        }
396        double xlo = c.getXLo();
397        double ylo = c.getYLo();
398        double yhi = c.getYHi();
399        double y0 = getYTop();
400        double y1 = getYBot();
401        double tstart, ystart, tend, yend;
402        if (y0 < ylo) {
403            if (y1 <= ylo) {
404                return false;
405            }
406            ystart = ylo;
407            tstart = this.TforY(ylo);
408        } else {
409            if (y0 >= yhi) {
410                return false;
411            }
412            ystart = y0;
413            tstart = 0;
414        }
415        if (y1 > yhi) {
416            yend = yhi;
417            tend = TforY(yhi);
418        } else {
419            yend = y1;
420            tend = 1;
421        }
422        boolean hitLo = false;
423        boolean hitHi = false;
424        while (true) {
425            double x = XforT(tstart);
426            if (x < xhi) {
427                if (hitHi || x > xlo) {
428                    return true;
429                }
430                hitLo = true;
431            } else {
432                if (hitLo) {
433                    return true;
434                }
435                hitHi = true;
436            }
437            if (tstart >= tend) {
438                break;
439            }
440            tstart = nextVertical(tstart, tend);
441        }
442        if (hitLo) {
443            //c.record(ystart, yend, direction);
444            c.record(ystart, yend, this.getDirection());
445        }
446        return false;
447    }
448
449    public double refineTforY(double t0, double yt0, double y0) {
450        double t1 = 1;
451        while (true) {
452            double th = (t0 + t1) / 2;
453            if (th == t0 || th == t1) {
454                return t1;
455            }
456            double y = YforT(th);
457            if (y < y0) {
458                t0 = th;
459                yt0 = y;
460            } else if (y > y0) {
461                t1 = th;
462            } else {
463                return t1;
464            }
465        }
466    }
467
468    public boolean findIntersect(CurveObject that, double yrange[], double ymin,
469            int slevel, int tlevel,
470            double s0, double xs0, double ys0,
471            double s1, double xs1, double ys1,
472            double t0, double xt0, double yt0,
473            double t1, double xt1, double yt1) {
474        /*
475         String pad = "        ";
476         pad = pad+pad+pad+pad+pad;
477         pad = pad+pad;
478         System.out.println("----------------------------------------------");
479         System.out.println(pad.substring(0, slevel)+ys0);
480         System.out.println(pad.substring(0, slevel)+ys1);
481         System.out.println(pad.substring(0, slevel)+(s1-s0));
482         System.out.println("-------");
483         System.out.println(pad.substring(0, tlevel)+yt0);
484         System.out.println(pad.substring(0, tlevel)+yt1);
485         System.out.println(pad.substring(0, tlevel)+(t1-t0));
486         */
487        if (ys0 > yt1 || yt0 > ys1) {
488            return false;
489        }
490        if (Math.min(xs0, xs1) > Math.max(xt0, xt1)
491                || Math.max(xs0, xs1) < Math.min(xt0, xt1)) {
492            return false;
493        }
494        // Bounding boxes intersect - back off the larger of
495        // the two subcurves by half until they stop intersecting
496        // (or until they get small enough to switch to a more
497        //  intensive algorithm).
498        if (s1 - s0 > Curve.TMIN) {
499            double s = (s0 + s1) / 2;
500            double xs = this.XforT(s);
501            double ys = this.YforT(s);
502            if (s == s0 || s == s1) {
503                System.out.println("s0 = " + s0);
504                System.out.println("s1 = " + s1);
505                throw new InternalError("no s progress!");
506            }
507            if (t1 - t0 > Curve.TMIN) {
508                double t = (t0 + t1) / 2;
509                double xt = that.XforT(t);
510                double yt = that.YforT(t);
511                if (t == t0 || t == t1) {
512                    System.out.println("t0 = " + t0);
513                    System.out.println("t1 = " + t1);
514                    throw new InternalError("no t progress!");
515                }
516                if (ys >= yt0 && yt >= ys0) {
517                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel + 1,
518                            s0, xs0, ys0, s, xs, ys,
519                            t0, xt0, yt0, t, xt, yt)) {
520                        return true;
521                    }
522                }
523                if (ys >= yt) {
524                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel + 1,
525                            s0, xs0, ys0, s, xs, ys,
526                            t, xt, yt, t1, xt1, yt1)) {
527                        return true;
528                    }
529                }
530                if (yt >= ys) {
531                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel + 1,
532                            s, xs, ys, s1, xs1, ys1,
533                            t0, xt0, yt0, t, xt, yt)) {
534                        return true;
535                    }
536                }
537                if (ys1 >= yt && yt1 >= ys) {
538                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel + 1,
539                            s, xs, ys, s1, xs1, ys1,
540                            t, xt, yt, t1, xt1, yt1)) {
541                        return true;
542                    }
543                }
544            } else {
545                if (ys >= yt0) {
546                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel,
547                            s0, xs0, ys0, s, xs, ys,
548                            t0, xt0, yt0, t1, xt1, yt1)) {
549                        return true;
550                    }
551                }
552                if (yt1 >= ys) {
553                    if (findIntersect(that, yrange, ymin, slevel + 1, tlevel,
554                            s, xs, ys, s1, xs1, ys1,
555                            t0, xt0, yt0, t1, xt1, yt1)) {
556                        return true;
557                    }
558                }
559            }
560        } else if (t1 - t0 > Curve.TMIN) {
561            double t = (t0 + t1) / 2;
562            double xt = that.XforT(t);
563            double yt = that.YforT(t);
564            if (t == t0 || t == t1) {
565                System.out.println("t0 = " + t0);
566                System.out.println("t1 = " + t1);
567                throw new InternalError("no t progress!");
568            }
569            if (yt >= ys0) {
570                if (findIntersect(that, yrange, ymin, slevel, tlevel + 1,
571                        s0, xs0, ys0, s1, xs1, ys1,
572                        t0, xt0, yt0, t, xt, yt)) {
573                    return true;
574                }
575            }
576            if (ys1 >= yt) {
577                if (findIntersect(that, yrange, ymin, slevel, tlevel + 1,
578                        s0, xs0, ys0, s1, xs1, ys1,
579                        t, xt, yt, t1, xt1, yt1)) {
580                    return true;
581                }
582            }
583        } else {
584            // No more subdivisions
585            double xlk = xs1 - xs0;
586            double ylk = ys1 - ys0;
587            double xnm = xt1 - xt0;
588            double ynm = yt1 - yt0;
589            double xmk = xt0 - xs0;
590            double ymk = yt0 - ys0;
591            double det = xnm * ylk - ynm * xlk;
592            if (det != 0) {
593                double detinv = 1 / det;
594                double s = (xnm * ymk - ynm * xmk) * detinv;
595                double t = (xlk * ymk - ylk * xmk) * detinv;
596                if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
597                    s = s0 + s * (s1 - s0);
598                    t = t0 + t * (t1 - t0);
599                    if (s < 0 || s > 1 || t < 0 || t > 1) {
600                        System.out.println("Uh oh!");
601                    }
602                    double y = (this.YforT(s) + that.YforT(t)) / 2;
603                    if (y <= yrange[1] && y > yrange[0]) {
604                        yrange[1] = y;
605                        return true;
606                    }
607                }
608            }
609            //System.out.println("Testing lines!");
610        }
611        return false;
612    }
613
614    public int compareTo(CurveObject that, double yrange[]) {
615        /*
616         System.out.println(this+".compareTo("+that+")");
617         System.out.println("target range = "+yrange[0]+"=>"+yrange[1]);
618         */
619        if (order == 1) {
620            return order1.compareTo(that, yrange);
621        }
622        double y0 = yrange[0];
623        double y1 = yrange[1];
624        //y1 = Math.min(Math.min(y1, this.getYBot()), that.getYBot());
625        y1 = Math.min(Math.min(y1, this.getYBot()), that.getYBot());
626        if (y1 <= yrange[0]) {
627            System.err.println("this == " + this);
628            System.err.println("that == " + that);
629            System.out.println("target range = " + yrange[0] + "=>" + yrange[1]);
630            throw new InternalError("backstepping from " + yrange[0] + " to " + y1);
631        }
632        yrange[1] = y1;
633        if (this.getXMax() <= that.getXMin()) {
634            if (this.getXMin() == that.getXMax()) {
635                return 0;
636            }
637            return -1;
638        }
639        if (this.getXMin() >= that.getXMax()) {
640            return 1;
641        }
642        // Parameter s for thi(s) curve and t for tha(t) curve
643        // [st]0 = parameters for top of current section of interest
644        // [st]1 = parameters for bottom of valid range
645        // [st]h = parameters for hypothesis point
646        // [d][xy]s = valuations of thi(s) curve at sh
647        // [d][xy]t = valuations of tha(t) curve at th
648        double s0 = this.TforY(y0);
649        double ys0 = this.YforT(s0);
650        if (ys0 < y0) {
651            s0 = refineTforY(s0, ys0, y0);
652            ys0 = this.YforT(s0);
653        }
654        double s1 = this.TforY(y1);
655        if (this.YforT(s1) < y0) {
656            s1 = refineTforY(s1, this.YforT(s1), y0);
657            //System.out.println("s1 problem!");
658        }
659        double t0 = that.TforY(y0);
660        double yt0 = that.YforT(t0);
661        if (yt0 < y0) {
662            t0 = that.refineTforY(t0, yt0, y0);
663            yt0 = that.YforT(t0);
664        }
665        double t1 = that.TforY(y1);
666        if (that.YforT(t1) < y0) {
667            t1 = that.refineTforY(t1, that.YforT(t1), y0);
668        }
669        double xs0 = this.XforT(s0);
670        double xt0 = that.XforT(t0);
671        double scale = Math.max(Math.abs(y0), Math.abs(y1));
672        double ymin = Math.max(scale * 1E-14, 1E-300);
673        if (Curve.fairlyClose(xs0, xt0)) {
674            double bump = ymin;
675            double maxbump = Math.min(ymin * 1E13, (y1 - y0) * .1);
676            double y = y0 + bump;
677            while (y <= y1) {
678                if (Curve.fairlyClose(this.XforY(y), that.XforY(y))) {
679                    if ((bump *= 2) > maxbump) {
680                        bump = maxbump;
681                    }
682                } else {
683                    y -= bump;
684                    while (true) {
685                        bump /= 2;
686                        double newy = y + bump;
687                        if (newy <= y) {
688                            break;
689                        }
690                        if (Curve.fairlyClose(this.XforY(newy), that.XforY(newy))) {
691                            y = newy;
692                        }
693                    }
694                    break;
695                }
696                y += bump;
697            }
698            if (y > y0) {
699                if (y < y1) {
700                    yrange[1] = y;
701                }
702                return 0;
703            }
704        }
705        //double ymin = y1 * 1E-14;
706        if (ymin <= 0) {
707            System.out.println("ymin = " + ymin);
708        }
709        /*
710         System.out.println("s range = "+s0+" to "+s1);
711         System.out.println("t range = "+t0+" to "+t1);
712         */
713        while (s0 < s1 && t0 < t1) {
714            double sh = this.nextVertical(s0, s1);
715            double xsh = this.XforT(sh);
716            double ysh = this.YforT(sh);
717            double th = that.nextVertical(t0, t1);
718            double xth = that.XforT(th);
719            double yth = that.YforT(th);
720            /*
721             System.out.println("sh = "+sh);
722             System.out.println("th = "+th);
723             */
724            try {
725                if (findIntersect(that, yrange, ymin, 0, 0,
726                        s0, xs0, ys0, sh, xsh, ysh,
727                        t0, xt0, yt0, th, xth, yth)) {
728                    break;
729                }
730            } catch (Throwable t) {
731                System.err.println("Error: " + t);
732                System.err.println("y range was " + yrange[0] + "=>" + yrange[1]);
733                System.err.println("s y range is " + ys0 + "=>" + ysh);
734                System.err.println("t y range is " + yt0 + "=>" + yth);
735                System.err.println("ymin is " + ymin);
736                return 0;
737            }
738            if (ysh < yth) {
739                if (ysh > yrange[0]) {
740                    if (ysh < yrange[1]) {
741                        yrange[1] = ysh;
742                    }
743                    break;
744                }
745                s0 = sh;
746                xs0 = xsh;
747                ys0 = ysh;
748            } else {
749                if (yth > yrange[0]) {
750                    if (yth < yrange[1]) {
751                        yrange[1] = yth;
752                    }
753                    break;
754                }
755                t0 = th;
756                xt0 = xth;
757                yt0 = yth;
758            }
759        }
760        double ymid = (yrange[0] + yrange[1]) / 2;
761        /*
762         System.out.println("final this["+s0+", "+sh+", "+s1+"]");
763         System.out.println("final    y["+ys0+", "+ysh+"]");
764         System.out.println("final that["+t0+", "+th+", "+t1+"]");
765         System.out.println("final    y["+yt0+", "+yth+"]");
766         System.out.println("final order = "+orderof(this.XforY(ymid),
767         that.XforY(ymid)));
768         System.out.println("final range = "+yrange[0]+"=>"+yrange[1]);
769         */
770        /*
771         System.out.println("final sx = "+this.XforY(ymid));
772         System.out.println("final tx = "+that.XforY(ymid));
773         System.out.println("final order = "+orderof(this.XforY(ymid),
774         that.XforY(ymid)));
775         */
776        return Curve.orderof(this.XforY(ymid), that.XforY(ymid));
777    }
778
779    public int getSegment(double coords[]) {
780        switch (order) {
781            case 0:
782                return order0.getSegment(coords);
783            case 1:
784                return order1.getSegment(coords);
785            case 2:
786                return order2.getSegment(coords);
787            case 3:
788                return order3.getSegment(coords);
789            default:
790                return -7;
791        }
792
793    }
794
795    public Object getSubCurve(double ystart, double yend, int dir) {    //did return Curve
796        switch (order) {
797            case 0:
798                return order0.getSubCurve(ystart, yend, dir);
799            case 1:
800                return order1.getSubCurve(ystart, yend, dir);
801            case 2:
802                return order2.getSubCurve(ystart, yend, dir);
803            case 3:
804                return order3.getSubCurve(ystart, yend, dir);
805            default:
806                return null;
807        }
808    }
809
810    public void enlarge(Rectangle2D r) {
811        switch (order) {
812            case 0:
813                order0.enlarge(r);
814            case 1:
815                order1.enlarge(r);
816            case 2:
817                order2.enlarge(r);
818            case 3:
819                order3.enlarge(r);
820            default:
821                return;
822        }
823    }
824
825    public Object getWithDirection(int direction) {
826        //return (this.direction == direction ? this : getReversedCurve());
827        //return (this.getDirection() == direction ? this : getReversedCurve());
828        switch (order) {
829            case 0:
830                return order0.getWithDirection(direction);
831            case 1:
832                return order1.getWithDirection(direction);
833            case 2:
834                return order2.getWithDirection(direction);
835            case 3:
836                return order3.getWithDirection(direction);
837            default:
838                return null;
839        }
840    }
841}