001/*
002 * To change this license header, choose License Headers in Project Properties.
003 * To change this template file, choose Tools | Templates
004 * and open the template in the editor.
005 */
006
007package armyc2.c2sd.graphics2d;
008//package java.awt;
009
010//import java.awt.geom.AffineTransform;
011//import java.awt.geom.PathIterator;
012//import java.awt.geom.Point2D;
013//import java.awt.geom.Rectangle2D;
014//import sun.awt.geom.Crossings;
015import android.graphics.Path;
016import android.graphics.RectF;
017import java.util.Arrays;
018
019/**
020 *
021 * @author Michael Deutch
022 */
023public class Polygon {
024    /**
025     * The total number of points.  The value of <code>npoints</code>
026     * represents the number of valid points in this <code>Polygon</code>
027     * and might be less than the number of elements in
028     * {@link #xpoints xpoints} or {@link #ypoints ypoints}.
029     * This value can be NULL.
030     *
031     * @serial
032     * @see #addPoint(int, int)
033     * @since 1.0
034     */
035    public int npoints;
036
037    /**
038     * The array of X coordinates.  The number of elements in
039     * this array might be more than the number of X coordinates
040     * in this <code>Polygon</code>.  The extra elements allow new points
041     * to be added to this <code>Polygon</code> without re-creating this
042     * array.  The value of {@link #npoints npoints} is equal to the
043     * number of valid points in this <code>Polygon</code>.
044     *
045     * @serial
046     * @see #addPoint(int, int)
047     * @since 1.0
048     */
049    public int xpoints[];
050
051    /**
052     * The array of Y coordinates.  The number of elements in
053     * this array might be more than the number of Y coordinates
054     * in this <code>Polygon</code>.  The extra elements allow new points
055     * to be added to this <code>Polygon</code> without re-creating this
056     * array.  The value of <code>npoints</code> is equal to the
057     * number of valid points in this <code>Polygon</code>.
058     *
059     * @serial
060     * @see #addPoint(int, int)
061     * @since 1.0
062     */
063    public int ypoints[];
064
065    /**
066     * The bounds of this {@code Polygon}.
067     * This value can be null.
068     *
069     * @serial
070     * @see #getBoundingBox()
071     * @see #getBounds()
072     * @since 1.0
073     */
074    protected Rectangle bounds;
075
076    /*
077     * JDK 1.1 serialVersionUID
078     */
079    private static final long serialVersionUID = -6460061437900069969L;
080
081    /*
082     * Default length for xpoints and ypoints.
083     */
084    private static final int MIN_LENGTH = 4;
085
086    /**
087     * Creates an empty polygon.
088     * @since 1.0
089     */
090    public Polygon() {
091        xpoints = new int[MIN_LENGTH];
092        ypoints = new int[MIN_LENGTH];
093    }
094
095    /**
096     * Constructs and initializes a <code>Polygon</code> from the specified
097     * parameters.
098     * @param xpoints an array of X coordinates
099     * @param ypoints an array of Y coordinates
100     * @param npoints the total number of points in the
101     *                          <code>Polygon</code>
102     * @exception  NegativeArraySizeException if the value of
103     *                       <code>npoints</code> is negative.
104     * @exception  IndexOutOfBoundsException if <code>npoints</code> is
105     *             greater than the length of <code>xpoints</code>
106     *             or the length of <code>ypoints</code>.
107     * @exception  NullPointerException if <code>xpoints</code> or
108     *             <code>ypoints</code> is <code>null</code>.
109     * @since 1.0
110     */
111    public Polygon(int xpoints[], int ypoints[], int npoints) {
112        // Fix 4489009: should throw IndexOutofBoundsException instead
113        // of OutofMemoryException if npoints is huge and > {x,y}points.length
114        if (npoints > xpoints.length || npoints > ypoints.length) {
115            throw new IndexOutOfBoundsException("npoints > xpoints.length || "+
116                                                "npoints > ypoints.length");
117        }
118        // Fix 6191114: should throw NegativeArraySizeException with
119        // negative npoints
120        if (npoints < 0) {
121            throw new NegativeArraySizeException("npoints < 0");
122        }
123        // Fix 6343431: Applet compatibility problems if arrays are not
124        // exactly npoints in length
125        this.npoints = npoints;
126        this.xpoints = Arrays.copyOf(xpoints, npoints);
127        this.ypoints = Arrays.copyOf(ypoints, npoints);
128    }
129
130    /**
131     * Resets this <code>Polygon</code> object to an empty polygon.
132     * The coordinate arrays and the data in them are left untouched
133     * but the number of points is reset to zero to mark the old
134     * vertex data as invalid and to start accumulating new vertex
135     * data at the beginning.
136     * All internally-cached data relating to the old vertices
137     * are discarded.
138     * Note that since the coordinate arrays from before the reset
139     * are reused, creating a new empty <code>Polygon</code> might
140     * be more memory efficient than resetting the current one if
141     * the number of vertices in the new polygon data is significantly
142     * smaller than the number of vertices in the data from before the
143     * reset.
144     * @since 1.4
145     */
146    public void reset() {
147        npoints = 0;
148        bounds = null;
149    }
150
151    /**
152     * Invalidates or flushes any internally-cached data that depends
153     * on the vertex coordinates of this <code>Polygon</code>.
154     * This method should be called after any direct manipulation
155     * of the coordinates in the <code>xpoints</code> or
156     * <code>ypoints</code> arrays to avoid inconsistent results
157     * from methods such as <code>getBounds</code> or <code>contains</code>
158     * that might cache data from earlier computations relating to
159     * the vertex coordinates.
160     * @since 1.4
161     */
162    public void invalidate() {
163        bounds = null;
164    }
165
166
167
168    /*
169     * Calculates the bounding box of the points passed to the constructor.
170     * Sets <code>bounds</code> to the result.
171     * @param xpoints[] array of <i>x</i> coordinates
172     * @param ypoints[] array of <i>y</i> coordinates
173     * @param npoints the total number of points
174     */
175    void calculateBounds(int xpoints[], int ypoints[], int npoints) {
176        int boundsMinX = Integer.MAX_VALUE;
177        int boundsMinY = Integer.MAX_VALUE;
178        int boundsMaxX = Integer.MIN_VALUE;
179        int boundsMaxY = Integer.MIN_VALUE;
180
181        for (int i = 0; i < npoints; i++) {
182            int x = xpoints[i];
183            boundsMinX = Math.min(boundsMinX, x);
184            boundsMaxX = Math.max(boundsMaxX, x);
185            int y = ypoints[i];
186            boundsMinY = Math.min(boundsMinY, y);
187            boundsMaxY = Math.max(boundsMaxY, y);
188        }
189        bounds = new Rectangle(boundsMinX, boundsMinY,
190                               boundsMaxX - boundsMinX,
191                               boundsMaxY - boundsMinY);
192    }
193
194    /*
195     * Resizes the bounding box to accommodate the specified coordinates.
196     * @param x,&nbsp;y the specified coordinates
197     */
198    void updateBounds(int x, int y) {
199        if (x < bounds.x) {
200            bounds.width = bounds.width + (bounds.x - x);
201            bounds.x = x;
202        }
203        else {
204            bounds.width = Math.max(bounds.width, x - bounds.x);
205            // bounds.x = bounds.x;
206        }
207
208        if (y < bounds.y) {
209            bounds.height = bounds.height + (bounds.y - y);
210            bounds.y = y;
211        }
212        else {
213            bounds.height = Math.max(bounds.height, y - bounds.y);
214            // bounds.y = bounds.y;
215        }
216    }
217
218    /**
219     * Appends the specified coordinates to this <code>Polygon</code>.
220     * <p>
221     * If an operation that calculates the bounding box of this
222     * <code>Polygon</code> has already been performed, such as
223     * <code>getBounds</code> or <code>contains</code>, then this
224     * method updates the bounding box.
225     * @param       x the specified X coordinate
226     * @param       y the specified Y coordinate
227
228     * @since 1.0
229     */
230    public void addPoint(int x, int y) {
231        if (npoints >= xpoints.length || npoints >= ypoints.length) {
232            int newLength = npoints * 2;
233            // Make sure that newLength will be greater than MIN_LENGTH and
234            // aligned to the power of 2
235            if (newLength < MIN_LENGTH) {
236                newLength = MIN_LENGTH;
237            } else if ((newLength & (newLength - 1)) != 0) {
238                newLength = Integer.highestOneBit(newLength);
239            }
240
241            xpoints = Arrays.copyOf(xpoints, newLength);
242            ypoints = Arrays.copyOf(ypoints, newLength);
243        }
244        xpoints[npoints] = x;
245        ypoints[npoints] = y;
246        npoints++;
247        if (bounds != null) {
248            updateBounds(x, y);
249        }
250    }
251
252    /**
253     * Gets the bounding box of this <code>Polygon</code>.
254     * The bounding box is the smallest {@link Rectangle} whose
255     * sides are parallel to the x and y axes of the
256     * coordinate space, and can completely contain the <code>Polygon</code>.
257     * @return a <code>Rectangle</code> that defines the bounds of this
258     * <code>Polygon</code>.
259     * @since 1.1
260     */
261    public Rectangle getBounds() {
262        return getBoundingBox();
263    }
264
265    /**
266     * Returns the bounds of this <code>Polygon</code>.
267     * @return the bounds of this <code>Polygon</code>.
268     * @deprecated As of JDK version 1.1,
269     * replaced by <code>getBounds()</code>.
270     * @since 1.0
271     */
272    @Deprecated
273    public Rectangle getBoundingBox() {
274        if (npoints == 0) {
275            return new Rectangle();
276        }
277        if (bounds == null) {
278            calculateBounds(xpoints, ypoints, npoints);
279        }
280        return bounds.getBounds();
281    }
282
283    /**
284     * Determines whether the specified {@link Point} is inside this
285     * <code>Polygon</code>.
286     * @param p the specified <code>Point</code> to be tested
287     * @return <code>true</code> if the <code>Polygon</code> contains the
288     *                  <code>Point</code>; <code>false</code> otherwise.
289     * @see #contains(double, double)
290     * @since 1.0
291     */
292    public boolean contains(Point p) {
293        return contains(p.x, p.y);
294    }
295
296    /**
297     * Determines whether the specified coordinates are inside this
298     * <code>Polygon</code>.
299     * <p>
300     * @param x the specified X coordinate to be tested
301     * @param y the specified Y coordinate to be tested
302     * @return {@code true} if this {@code Polygon} contains
303     *         the specified coordinates {@code (x,y)};
304     *         {@code false} otherwise.
305     * @see #contains(double, double)
306     * @since 1.1
307     */
308    public boolean contains(int x, int y) {
309        return contains((double) x, (double) y);
310    }
311
312    /**
313     * Determines whether the specified coordinates are contained in this
314     * <code>Polygon</code>.
315     * @param x the specified X coordinate to be tested
316     * @param y the specified Y coordinate to be tested
317     * @return {@code true} if this {@code Polygon} contains
318     *         the specified coordinates {@code (x,y)};
319     *         {@code false} otherwise.
320     * @see #contains(double, double)
321     * @deprecated As of JDK version 1.1,
322     * replaced by <code>contains(int, int)</code>.
323     * @since 1.0
324     */
325    @Deprecated
326    public boolean inside(int x, int y) {
327        return contains((double) x, (double) y);
328    }
329
330    /**
331     * {@inheritDoc}
332     * @since 1.2
333     */
334    public Rectangle2D getBounds2D() {
335        //return getBounds();
336        return null;
337    }
338
339    /**
340     * {@inheritDoc}
341     * @since 1.2
342     */
343    public boolean contains(double x, double y) {
344        if (npoints <= 2 || !getBoundingBox().contains((int)x, (int)y)) {
345            return false;
346        }
347        int hits = 0;
348
349        int lastx = xpoints[npoints - 1];
350        int lasty = ypoints[npoints - 1];
351        int curx, cury;
352
353        // Walk the edges of the polygon
354        for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++) {
355            curx = xpoints[i];
356            cury = ypoints[i];
357
358            if (cury == lasty) {
359                continue;
360            }
361
362            int leftx;
363            if (curx < lastx) {
364                if (x >= lastx) {
365                    continue;
366                }
367                leftx = curx;
368            } else {
369                if (x >= curx) {
370                    continue;
371                }
372                leftx = lastx;
373            }
374
375            double test1, test2;
376            if (cury < lasty) {
377                if (y < cury || y >= lasty) {
378                    continue;
379                }
380                if (x < leftx) {
381                    hits++;
382                    continue;
383                }
384                test1 = x - curx;
385                test2 = y - cury;
386            } else {
387                if (y < lasty || y >= cury) {
388                    continue;
389                }
390                if (x < leftx) {
391                    hits++;
392                    continue;
393                }
394                test1 = x - lastx;
395                test2 = y - lasty;
396            }
397
398            if (test1 < (test2 / (lasty - cury) * (lastx - curx))) {
399                hits++;
400            }
401        }
402
403        return ((hits & 1) != 0);
404    }
405
406//    private Crossings getCrossings(double xlo, double ylo,
407//                                   double xhi, double yhi)
408//    {
409//        Crossings cross = new Crossings.EvenOdd(xlo, ylo, xhi, yhi);
410//        int lastx = xpoints[npoints - 1];
411//        int lasty = ypoints[npoints - 1];
412//        int curx, cury;
413//
414//        // Walk the edges of the polygon
415//        for (int i = 0; i < npoints; i++) {
416//            curx = xpoints[i];
417//            cury = ypoints[i];
418//            if (cross.accumulateLine(lastx, lasty, curx, cury)) {
419//                return null;
420//            }
421//            lastx = curx;
422//            lasty = cury;
423//        }
424//
425//        return cross;
426//    }
427
428    /**
429     * {@inheritDoc}
430     * @since 1.2
431     */
432    public boolean contains(Point2D p) {
433        return contains(p.getX(), p.getY());
434    }
435
436    /**
437     * {@inheritDoc}
438     * @since 1.2
439     */
440    public boolean intersects(double x, double y, double w, double h) {
441        if (npoints <= 0 || !getBoundingBox().intersects(x, y, w, h)) {
442            return false;
443        }
444
445        //Crossings cross = getCrossings(x, y, x+w, y+h);
446        //return (cross == null || !cross.isEmpty());
447        if (bounds != null) {
448            float fx = (float) x;
449            float fy = (float) y;
450            float fw = (float) w;
451            float fh = (float) h;
452//not sure if math is correct here
453            Path that = new Path();
454//start
455            that.moveTo(fx, fy);
456//go right
457            that.lineTo(fx + fw, fy);
458//go down
459            that.lineTo(fx + fw, fy - fh);
460//go left
461            that.lineTo(fx, fy - fh);
462//close
463            that.close();
464//bounds holder
465            RectF thatBounds = new RectF();
466            RectF rectf=new RectF((float)bounds.x,(float)bounds.y,(float)bounds.x+(float)bounds.width,(float)bounds.y+(float)bounds.height);
467            return RectF.intersects(rectf, thatBounds);
468        } 
469        else 
470        {
471            return false;
472        }        
473    }
474
475    /**
476     * {@inheritDoc}
477     * @since 1.2
478     */
479    public boolean intersects(Rectangle2D r) {
480        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
481    }
482
483    /**
484     * {@inheritDoc}
485     * @since 1.2
486     */
487    public boolean contains(double x, double y, double w, double h) {
488        if (npoints <= 0 || !getBoundingBox().intersects(x, y, w, h)) {
489            return false;
490        }
491
492        //Crossings cross = getCrossings(x, y, x+w, y+h);
493        //return (cross != null && cross.covers(y, y+h));
494        return false;
495    }
496
497    /**
498     * {@inheritDoc}
499     * @since 1.2
500     */
501    public boolean contains(Rectangle2D r) {
502        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
503    }
504
505    /**
506     * Returns an iterator object that iterates along the boundary of this
507     * <code>Polygon</code> and provides access to the geometry
508     * of the outline of this <code>Polygon</code>.  An optional
509     * {@link AffineTransform} can be specified so that the coordinates
510     * returned in the iteration are transformed accordingly.
511     * @param at an optional <code>AffineTransform</code> to be applied to the
512     *          coordinates as they are returned in the iteration, or
513     *          <code>null</code> if untransformed coordinates are desired
514     * @return a {@link PathIterator} object that provides access to the
515     *          geometry of this <code>Polygon</code>.
516     * @since 1.2
517     */
518    public PathIterator getPathIterator(AffineTransform at) {
519        //return new PolygonPathIterator(this, at);
520        PathIterator pi=new PathIterator(null);
521        int j=0;
522        if(npoints>0)
523        {
524            pi.moveTo(xpoints[0], ypoints[0]);
525            for(j=1;j<npoints;j++)
526            {
527                pi.lineTo(xpoints[j], ypoints[j]);
528            }
529        }
530        pi.reset();
531        return pi;        
532    }
533
534    /**
535     * Returns an iterator object that iterates along the boundary of
536     * the <code>Shape</code> and provides access to the geometry of the
537     * outline of the <code>Shape</code>.  Only SEG_MOVETO, SEG_LINETO, and
538     * SEG_CLOSE point types are returned by the iterator.
539     * Since polygons are already flat, the <code>flatness</code> parameter
540     * is ignored.  An optional <code>AffineTransform</code> can be specified
541     * in which case the coordinates returned in the iteration are transformed
542     * accordingly.
543     * @param at an optional <code>AffineTransform</code> to be applied to the
544     *          coordinates as they are returned in the iteration, or
545     *          <code>null</code> if untransformed coordinates are desired
546     * @param flatness the maximum amount that the control points
547     *          for a given curve can vary from colinear before a subdivided
548     *          curve is replaced by a straight line connecting the
549     *          endpoints.  Since polygons are already flat the
550     *          <code>flatness</code> parameter is ignored.
551     * @return a <code>PathIterator</code> object that provides access to the
552     *          <code>Shape</code> object's geometry.
553     * @since 1.2
554     */
555    public PathIterator getPathIterator(AffineTransform at, double flatness) {
556        return getPathIterator(at);
557    }
558
559//    class PolygonPathIterator implements PathIterator {
560//        Polygon poly;
561//        AffineTransform transform;
562//        int index;
563//
564//        public PolygonPathIterator(Polygon pg, AffineTransform at) {
565//            poly = pg;
566//            transform = at;
567//            if (pg.npoints == 0) {
568//                // Prevent a spurious SEG_CLOSE segment
569//                index = 1;
570//            }
571//        }
572//
573//        /**
574//         * Returns the winding rule for determining the interior of the
575//         * path.
576//         * @return an integer representing the current winding rule.
577//         * @see PathIterator#WIND_NON_ZERO
578//         */
579////        public int getWindingRule() {
580////            return WIND_EVEN_ODD;
581////        }
582//
583//        /**
584//         * Tests if there are more points to read.
585//         * @return <code>true</code> if there are more points to read;
586//         *          <code>false</code> otherwise.
587//         */
588//        public boolean isDone() {
589//            return index > poly.npoints;
590//        }
591//
592//        /**
593//         * Moves the iterator forwards, along the primary direction of
594//         * traversal, to the next segment of the path when there are
595//         * more points in that direction.
596//         */
597//        public void next() {
598//            index++;
599//        }
600//
601//        /**
602//         * Returns the coordinates and type of the current path segment in
603//         * the iteration.
604//         * The return value is the path segment type:
605//         * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
606//         * A <code>float</code> array of length 2 must be passed in and
607//         * can be used to store the coordinates of the point(s).
608//         * Each point is stored as a pair of <code>float</code> x,&nbsp;y
609//         * coordinates.  SEG_MOVETO and SEG_LINETO types return one
610//         * point, and SEG_CLOSE does not return any points.
611//         * @param coords a <code>float</code> array that specifies the
612//         * coordinates of the point(s)
613//         * @return an integer representing the type and coordinates of the
614//         *              current path segment.
615//         * @see PathIterator#SEG_MOVETO
616//         * @see PathIterator#SEG_LINETO
617//         * @see PathIterator#SEG_CLOSE
618//         */
619//        public int currentSegment(float[] coords) {
620//            if (index >= poly.npoints) {
621//                return SEG_CLOSE;
622//            }
623//            coords[0] = poly.xpoints[index];
624//            coords[1] = poly.ypoints[index];
625//            if (transform != null) {
626//                transform.transform(coords, 0, coords, 0, 1);
627//            }
628//            return (index == 0 ? SEG_MOVETO : SEG_LINETO);
629//        }
630//
631//        /**
632//         * Returns the coordinates and type of the current path segment in
633//         * the iteration.
634//         * The return value is the path segment type:
635//         * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
636//         * A <code>double</code> array of length 2 must be passed in and
637//         * can be used to store the coordinates of the point(s).
638//         * Each point is stored as a pair of <code>double</code> x,&nbsp;y
639//         * coordinates.
640//         * SEG_MOVETO and SEG_LINETO types return one point,
641//         * and SEG_CLOSE does not return any points.
642//         * @param coords a <code>double</code> array that specifies the
643//         * coordinates of the point(s)
644//         * @return an integer representing the type and coordinates of the
645//         *              current path segment.
646//         * @see PathIterator#SEG_MOVETO
647//         * @see PathIterator#SEG_LINETO
648//         * @see PathIterator#SEG_CLOSE
649//         */
650//        public int currentSegment(double[] coords) 
651//        {
652//            if (index >= poly.npoints) {
653//                return SEG_CLOSE;
654//            }
655//            coords[0] = poly.xpoints[index];
656//            coords[1] = poly.ypoints[index];
657//            if (transform != null) {
658//                transform.transform(coords, 0, coords, 0, 1);
659//            }
660//            return (index == 0 ? SEG_MOVETO : SEG_LINETO);
661//        }
662//    }
663}