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 NonZero {
012
013    public static final boolean debug = false;
014    int limit = 0;
015    double yranges[] = new double[10];
016    double xlo, ylo, xhi, yhi;
017    private int crosscounts[];
018
019    public NonZero(double xlo, double ylo, double xhi, double yhi) {
020        //super(xlo, ylo, xhi, yhi);
021        this.xlo = xlo;
022        this.ylo = ylo;
023        this.xhi = xhi;
024        this.yhi = yhi;
025        crosscounts = new int[yranges.length / 2];
026    }
027
028    public final boolean covers(double ystart, double yend) {
029        int i = 0;
030        while (i < limit) {
031            double ylo = yranges[i++];
032            double yhi = yranges[i++];
033            if (ystart >= yhi) {
034                continue;
035            }
036            if (ystart < ylo) {
037                return false;
038            }
039            if (yend <= yhi) {
040                return true;
041            }
042            ystart = yhi;
043        }
044        return (ystart >= yend);
045    }
046
047    public void remove(int cur) {
048        limit -= 2;
049        int rem = limit - cur;
050        if (rem > 0) {
051            System.arraycopy(yranges, cur + 2, yranges, cur, rem);
052            System.arraycopy(crosscounts, cur / 2 + 1,
053                    crosscounts, cur / 2,
054                    rem / 2);
055        }
056    }
057
058    public void insert(int cur, double lo, double hi, int dir) {
059        int rem = limit - cur;
060        double oldranges[] = yranges;
061        int oldcounts[] = crosscounts;
062        if (limit >= yranges.length) {
063            yranges = new double[limit + 10];
064            System.arraycopy(oldranges, 0, yranges, 0, cur);
065            crosscounts = new int[(limit + 10) / 2];
066            System.arraycopy(oldcounts, 0, crosscounts, 0, cur / 2);
067        }
068        if (rem > 0) {
069            System.arraycopy(oldranges, cur, yranges, cur + 2, rem);
070            System.arraycopy(oldcounts, cur / 2,
071                    crosscounts, cur / 2 + 1,
072                    rem / 2);
073        }
074        yranges[cur + 0] = lo;
075        yranges[cur + 1] = hi;
076        crosscounts[cur / 2] = dir;
077        limit += 2;
078    }
079
080    public void record(double ystart, double yend, int direction) {
081        if (ystart >= yend) {
082            return;
083        }
084        int cur = 0;
085        // Quickly jump over all pairs that are completely "above"
086        while (cur < limit && ystart > yranges[cur + 1]) {
087            cur += 2;
088        }
089        if (cur < limit) {
090            int rdir = crosscounts[cur / 2];
091            double yrlo = yranges[cur + 0];
092            double yrhi = yranges[cur + 1];
093            if (yrhi == ystart && rdir == direction) {
094                // Remove the range from the list and collapse it
095                // into the range being inserted.  Note that the
096                // new combined range may overlap the following range
097                // so we must not simply combine the ranges in place
098                // unless we are at the last range.
099                if (cur + 2 == limit) {
100                    yranges[cur + 1] = yend;
101                    return;
102                }
103                remove(cur);
104                ystart = yrlo;
105                rdir = crosscounts[cur / 2];
106                yrlo = yranges[cur + 0];
107                yrhi = yranges[cur + 1];
108            }
109            if (yend < yrlo) {
110                // Just insert the new range at the current location
111                insert(cur, ystart, yend, direction);
112                return;
113            }
114            if (yend == yrlo && rdir == direction) {
115                // Just prepend the new range to the current one
116                yranges[cur] = ystart;
117                return;
118            }
119            // The ranges must overlap - (yend > yrlo && yrhi > ystart)
120            if (ystart < yrlo) {
121                insert(cur, ystart, yrlo, direction);
122                cur += 2;
123                ystart = yrlo;
124            } else if (yrlo < ystart) {
125                insert(cur, yrlo, ystart, rdir);
126                cur += 2;
127                yrlo = ystart;
128            }
129            // assert(yrlo == ystart);
130            int newdir = rdir + direction;
131            double newend = Math.min(yend, yrhi);
132            if (newdir == 0) {
133                remove(cur);
134            } else {
135                crosscounts[cur / 2] = newdir;
136                yranges[cur++] = ystart;
137                yranges[cur++] = newend;
138            }
139            ystart = yrlo = newend;
140            if (yrlo < yrhi) {
141                insert(cur, yrlo, yrhi, rdir);
142            }
143        }
144        if (ystart < yend) {
145            insert(cur, ystart, yend, direction);
146        }
147    }
148
149    public final double getXLo() {
150        return xlo;
151    }
152
153    public final double getYLo() {
154        return ylo;
155    }
156
157    public final double getXHi() {
158        return xhi;
159    }
160
161    public final double getYHi() {
162        return yhi;
163    }
164    public final boolean isEmpty() {
165        return (limit == 0);
166    }
167    public boolean accumulateLine(double x0, double y0,
168                                  double x1, double y1)
169    {
170        if (y0 <= y1) {
171            return accumulateLine2(x0, y0, x1, y1, 1);
172        } else {
173            return accumulateLine2(x1, y1, x0, y0, -1);
174        }
175    }
176
177    public boolean accumulateLine2(double x0, double y0,
178                                  double x1, double y1,
179                                  int direction)
180    {
181        if (yhi <= y0 || ylo >= y1) {
182            return false;
183        }
184        if (x0 >= xhi && x1 >= xhi) {
185            return false;
186        }
187        if (y0 == y1) {
188            return (x0 >= xlo || x1 >= xlo);
189        }
190        double xstart, ystart, xend, yend;
191        double dx = (x1 - x0);
192        double dy = (y1 - y0);
193        if (y0 < ylo) {
194            xstart = x0 + (ylo - y0) * dx / dy;
195            ystart = ylo;
196        } else {
197            xstart = x0;
198            ystart = y0;
199        }
200        if (yhi < y1) {
201            xend = x0 + (yhi - y0) * dx / dy;
202            yend = yhi;
203        } else {
204            xend = x1;
205            yend = y1;
206        }
207        if (xstart >= xhi && xend >= xhi) {
208            return false;
209        }
210        if (xstart > xlo || xend > xlo) {
211            return true;
212        }
213        record(ystart, yend, direction);
214        return false;
215    }
216}