12

The other day I did a class in Java to calculate if a point(X,Y) is inside a polygon. (X and Y are double, because will be geo-coordinates).

I know that Java has the class Polygon, but I had to use Path2D and Point2D, because Polygon don't allow double's, just integers :(

Once I have the polygon done in Path2D, I used the method contains (Path2D had it), and my problem was solved.

But now, I want to import to Android, and the problem is here, because Path2D needs to import:

import java.awt.geom.Path2D;
import java.awt.geom.Point2D;

and in Android don't exist awt, so I can't use.

So, is there any class similar to Path2D that had contains method? or I have to calculate by myself?

Here is how I did in Java using Path2D:

private void ConstructPolygon(Vector<Point2D> coodinates)
{       
    this.polygon.moveTo(coodinates.get(0).getX(), coodinates.get(0).getY());        

    //System.out.println(coodinates.get(0).getX() + "   " + coodinates.get(0).getY());
    //System.out.println("asda");

    for(int i = 1; i < this.num_points; i++)
    {
        //System.out.println(coodinates.get(i).getX() + "   " + coodinates.get(i).getY());
        this.polygon.lineTo(coodinates.get(i).getX(), coodinates.get(i).getY());
    }
    this.polygon.closePath();
}
public boolean InsideCity(Point2D punto)
{
    return this.polygon.contains(punto);                
}
Ziezi
  • 6,375
  • 3
  • 39
  • 49
Shudy
  • 7,806
  • 19
  • 63
  • 98
  • Maybe you could have just multiplied all the `double` values by 10,000 and used them with the Java `Polygon` class? – Carlos P Apr 20 '16 at 07:51

4 Answers4

37

You can use my simple library exactly for this: https://github.com/snatik/polygon-contains-point.

Prepare polygon:

Polygon polygon = Polygon.Builder()
    .addVertex(new Point(1, 3))
    .addVertex(new Point(2, 8))
    .addVertex(new Point(5, 4))
    .addVertex(new Point(5, 9))
    .addVertex(new Point(7, 5))
    .addVertex(new Point(6, 1))
    .addVertex(new Point(3, 1))
    .build();

And check whereas the point is inside the polygon:

Point point = new Point(4.5f, 7);
boolean contains = polygon.contains(point);

It works with float types and with polygons that contain holes :)

sromku
  • 4,663
  • 1
  • 36
  • 37
  • 1
    Hi @sromku ! I got one question, I have to read a KML file to obtain the coordinates, but this can be more than 100 points... so how can i use the Builder for all, these points? Cause my idea is to read the kml, obtain the points in a vector(for example), and then build the polygon... soo.. I don't kwow how to use in the way you did :( Can you help me? Thanks!!(the code works perfect!) – Shudy Apr 10 '13 at 16:15
  • Do note that this code fails the test case where you happen to directly hit the vertex with a weird slanted ray it uses. – Tatarize Apr 26 '16 at 00:21
  • This library has issues even with the simplest shapes, check the issues list before considering. https://github.com/sromku/polygon-contains-point/issues – Fernando N. Jul 09 '16 at 07:37
  • @KaveeshKanwal yes, it will – sromku Mar 11 '18 at 08:01
  • @sromku In case of map coordinates, is the correct order new Point(lat , lon) ? or new Point(lon, lat) ? – Inosh Perera Mar 16 '18 at 17:14
26

You can use Google Maps PolyUtil:

import com.google.maps.android.PolyUtil;

boolean inside = PolyUtil.containsLocation(new LatLng(...), poly, true);
Fernando N.
  • 6,369
  • 4
  • 27
  • 30
7

Here is how I did it in Android. It is based on this java program (ray casting algorithm) : https://gis.stackexchange.com/questions/42879/check-if-lat-long-point-is-within-a-set-of-polygons-using-google-maps/46720#46720

    public boolean pointInPolygon(LatLng point, Polygon polygon) {
        // ray casting alogrithm http://rosettacode.org/wiki/Ray-casting_algorithm
        int crossings = 0;
        List<LatLng> path = polygon.getPoints();
        path.remove(path.size()-1); //remove the last point that is added automatically by getPoints()

        // for each edge
        for (int i=0; i < path.size(); i++) {
            LatLng a = path.get(i);
            int j = i + 1;
            //to close the last edge, you have to take the first point of your polygon
            if (j >= path.size()) {
                j = 0;
            }
            LatLng b = path.get(j);
            if (rayCrossesSegment(point, a, b)) {
                crossings++;
            }
        }

        // odd number of crossings?
        return (crossings % 2 == 1);
     }

    public boolean rayCrossesSegment(LatLng point, LatLng a,LatLng b) {
                // Ray Casting algorithm checks, for each segment, if the point is 1) to the left of the segment and 2) not above nor below the segment. If these two conditions are met, it returns true
                double px = point.longitude,
                py = point.latitude,
                ax = a.longitude,
                ay = a.latitude,
                bx = b.longitude,
                by = b.latitude;
            if (ay > by) {
                ax = b.longitude;
                ay = b.latitude;
                bx = a.longitude;
                by = a.latitude;
            }
            // alter longitude to cater for 180 degree crossings
            if (px < 0 || ax <0 || bx <0) { px += 360; ax+=360; bx+=360; }
            // if the point has the same latitude as a or b, increase slightly py
            if (py == ay || py == by) py += 0.00000001;


            // if the point is above, below or to the right of the segment, it returns false
            if ((py > by || py < ay) || (px > Math.max(ax, bx))){ 
                return false;
            }
            // if the point is not above, below or to the right and is to the left, return true
            else if (px < Math.min(ax, bx)){ 
                return true;
            }
            // if the two above conditions are not met, you have to compare the slope of segment [a,b] (the red one here) and segment [a,p] (the blue one here) to see if your point is to the left of segment [a,b] or not
            else {
                double red = (ax != bx) ? ((by - ay) / (bx - ax)) : Double.POSITIVE_INFINITY;
                double blue = (ax != px) ? ((py - ay) / (px - ax)) : Double.POSITIVE_INFINITY;
                return (blue >= red);
            }

     }
Community
  • 1
  • 1
ylag75
  • 81
  • 1
  • 2
5

Sorry @sromku I asked my self (I never used this type of things)

That's how I solved if anyone have the same question

Builder poly2 = new Polygon.Builder();
    for(int i = 0; i< xpoints.length;i++){
        poly2.addVertex(new Point(xpoints[i],ypoints[i]));
    }
    Polygon polygon2 = poly2.build();
Shudy
  • 7,806
  • 19
  • 63
  • 98