我搜索过很多线程,但我仍然面临着这个问题。 我必须找出lat / lng是在多边形的内部还是外部。我使用了以下方法:
private boolean LineIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ( (aY>pY && bY>pY) || (aY<pY && bY<pY) || (aX<pX && bX<pX) ) {
return false; }
double m = (aY-bY) / (aX-bX);
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m;
return x > pX;
}
private boolean isPointInPolygon(LatLng tap, ArrayList<LatLng> vertices) {
int intersectCount = 0;
for(int j=0; j<vertices.size()-1; j++) {
if( LineIntersect(tap, vertices.get(j), vertices.get(j+1)) ) {
intersectCount++;
}
}
return ((intersectCount%2)==1); // odd = inside, even = outside;
}
我称之为:
if(isPointInPolygon(mLatLng, points))
{
Toast.makeText(getApplicationContext(), "inside",
Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(getApplicationContext(), "outside",
Toast.LENGTH_LONG).show();
}
我得到的问题是,当我在地理围栏中时,我会得到真实和错误。无论什么时候我都在地理围栏内,我在内外都会得到2个吐司。请让我知道我错在哪里。
答案 0 :(得分:1)
我创建了成功运作的地理围栏应用 这是我使用这个https://github.com/sromku/polygon-contains-point的代码来计算我们在多边形内部或外部的位置。 这是代码
public class MainActivity extends Activity {
private double Longitude, Latitude;
private LocationListener locListener;
private LocationManager lm;
private ProgressDialog gpsProgressDialog;
private Button button_gps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button_gps = (Button)findViewById(R.id.button_gps);
lm = (LocationManager) MainActivity.this.getSystemService(MainActivity.this.LOCATION_SERVICE);
button_gps.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
getLoction();
// testSimplePolygon();
// testPolygonWithHoles();
}
});
}
class GpsLogation implements LocationListener {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
lm.removeUpdates(locListener);
Longitude = location.getLongitude();
Latitude = location.getLatitude();
/* Toast.makeText(MainActivity.this,
"Longitude :" + Longitude + " Latitude :" + Latitude,
Toast.LENGTH_LONG).show();*/
Polygon polygon = Polygon.Builder()
.addVertex(new Point(6.048857f, 80.211021f)) // change polygon according to your location
.addVertex(new Point(6.048137f, 80.210546f))
.addVertex(new Point(6.048590f, 80.210197f))
.addVertex(new Point(6.049163f, 80.211050f)).build();
// isInside(polygon, new Point((float)Latitude, (float)Longitude));
if( polygon.contains(new Point((float)Latitude, (float)Longitude))==true)
{
Toast.makeText(MainActivity.this, "You are inside", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(MainActivity.this, "You are outside", Toast.LENGTH_LONG).show();
}
// /////////////do something//////////////
// insertSalesOrder();
Log.i("TTTAG", "Latitude:" + Latitude);
Log.i("TTTAG", "Longitude:" + Longitude);
if (gpsProgressDialog.isShowing()) {
gpsProgressDialog.dismiss();
}
}
}
@Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
}
public void getLoction() {
locListener = new GpsLogation();
boolean enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!enabled) {
Toast.makeText(MainActivity.this, "Please switch on the GPS",Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
MainActivity.this.startActivity(intent);
return;
}
Log.i("GPS INFO", " OK Gps Is ON");
gpsProgressDialog = ProgressDialog.show(MainActivity.this, "", "Please wait ... ", true);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,locListener);
}
// Here is the polygon java class and i'm not author of it
public class Polygon
{
private final BoundingBox _boundingBox;
private final List<Line> _sides;
private Polygon(List<Line> sides, BoundingBox boundingBox)
{
_sides = sides;
_boundingBox = boundingBox;
}
/**
* Get the builder of the polygon
*
* @return The builder
*/
public static Builder Builder()
{
return new Builder();
}
/**
* Builder of the polygon
*
* @author Roman Kushnarenko (sromku@gmail.com)
*/
public static class Builder
{
private List<Point> _vertexes = new ArrayList<Point>();
private List<Line> _sides = new ArrayList<Line>();
private BoundingBox _boundingBox = null;
private boolean _firstPoint = true;
private boolean _isClosed = false;
/**
* Add vertex points of the polygon.<br>
* It is very important to add the vertexes by order, like you were drawing them one by one.
*
* @param point
* The vertex point
* @return The builder
*/
public Builder addVertex(Point point)
{
if (_isClosed)
{
// each hole we start with the new array of vertex points
_vertexes = new ArrayList<Point>();
_isClosed = false;
}
updateBoundingBox(point);
_vertexes.add(point);
// add line (edge) to the polygon
if (_vertexes.size() > 1)
{
Line Line = new Line(_vertexes.get(_vertexes.size() - 2), point);
_sides.add(Line);
}
return this;
}
/**
* Close the polygon shape. This will create a new side (edge) from the <b>last</b> vertex point to the <b>first</b> vertex point.
*
* @return The builder
*/
public Builder close()
{
validate();
// add last Line
_sides.add(new Line(_vertexes.get(_vertexes.size() - 1), _vertexes.get(0)));
_isClosed = true;
return this;
}
/**
* Build the instance of the polygon shape.
*
* @return The polygon
*/
public Polygon build()
{
validate();
// in case you forgot to close
if (!_isClosed)
{
// add last Line
_sides.add(new Line(_vertexes.get(_vertexes.size() - 1), _vertexes.get(0)));
}
Polygon polygon = new Polygon(_sides, _boundingBox);
return polygon;
}
/**
* Update bounding box with a new point.<br>
*
* @param point
* New point
*/
private void updateBoundingBox(Point point)
{
if (_firstPoint)
{
_boundingBox = new BoundingBox();
_boundingBox.xMax = point.x;
_boundingBox.xMin = point.x;
_boundingBox.yMax = point.y;
_boundingBox.yMin = point.y;
_firstPoint = false;
}
else
{
// set bounding box
if (point.x > _boundingBox.xMax)
{
_boundingBox.xMax = point.x;
}
else if (point.x < _boundingBox.xMin)
{
_boundingBox.xMin = point.x;
}
if (point.y > _boundingBox.yMax)
{
_boundingBox.yMax = point.y;
}
else if (point.y < _boundingBox.yMin)
{
_boundingBox.yMin = point.y;
}
}
}
private void validate()
{
if (_vertexes.size() < 3)
{
throw new RuntimeException("Polygon must have at least 3 points");
}
}
}
/**
* Check if the the given point is inside of the polygon.<br>
*
* @param point
* The point to check
* @return <code>True</code> if the point is inside the polygon, otherwise return <code>False</code>
*/
public boolean contains(Point point)
{
if (inBoundingBox(point))
{
Line ray = createRay(point);
int intersection = 0;
for (Line side : _sides)
{
if (intersect(ray, side))
{
// System.out.println("intersection++");
intersection++;
}
}
/*
* If the number of intersections is odd, then the point is inside the polygon
*/
if (intersection % 2 == 1)
{
return true;
}
}
return false;
}
public List<Line> getSides()
{
return _sides;
}
/**
* By given ray and one side of the polygon, check if both lines intersect.
*
* @param ray
* @param side
* @return <code>True</code> if both lines intersect, otherwise return <code>False</code>
*/
private boolean intersect(Line ray, Line side)
{
Point intersectPoint = null;
// if both vectors aren't from the kind of x=1 lines then go into
if (!ray.isVertical() && !side.isVertical())
{
// check if both vectors are parallel. If they are parallel then no intersection point will exist
if (ray.getA() - side.getA() == 0)
{
return false;
}
float x = ((side.getB() - ray.getB()) / (ray.getA() - side.getA())); // x = (b2-b1)/(a1-a2)
float y = side.getA() * x + side.getB(); // y = a2*x+b2
intersectPoint = new Point(x, y);
}
else if (ray.isVertical() && !side.isVertical())
{
float x = ray.getStart().x;
float y = side.getA() * x + side.getB();
intersectPoint = new Point(x, y);
}
else if (!ray.isVertical() && side.isVertical())
{
float x = side.getStart().x;
float y = ray.getA() * x + ray.getB();
intersectPoint = new Point(x, y);
}
else
{
return false;
}
// System.out.println("Ray: " + ray.toString() + " ,Side: " + side);
// System.out.println("Intersect point: " + intersectPoint.toString());
if (side.isInside(intersectPoint) && ray.isInside(intersectPoint))
{
return true;
}
return false;
}
/**
* Create a ray. The ray will be created by given point and on point outside of the polygon.<br>
* The outside point is calculated automatically.
*
* @param point
* @return
*/
private Line createRay(Point point)
{
// create outside point
float epsilon = (_boundingBox.xMax - _boundingBox.xMin) / 100f;
Point outsidePoint = new Point(_boundingBox.xMin - epsilon, _boundingBox.yMin);
Line vector = new Line(outsidePoint, point);
return vector;
}
/**
* Check if the given point is in bounding box
*
* @param point
* @return <code>True</code> if the point in bounding box, otherwise return <code>False</code>
*/
private boolean inBoundingBox(Point point)
{
if (point.x < _boundingBox.xMin || point.x > _boundingBox.xMax || point.y < _boundingBox.yMin || point.y > _boundingBox.yMax)
{
return false;
}
return true;
}
private static class BoundingBox
{
public float xMax = Float.NEGATIVE_INFINITY;
public float xMin = Float.NEGATIVE_INFINITY;
public float yMax = Float.NEGATIVE_INFINITY;
public float yMin = Float.NEGATIVE_INFINITY;
}
}
//// Here is the Line java class and i'm not author of it
public class Line
{
private final Point _start;
private final Point _end;
private float _a = Float.NaN;
private float _b = Float.NaN;
private boolean _vertical = false;
public Line(Point start, Point end)
{
_start = start;
_end = end;
if (_end.x - _start.x != 0)
{
_a = ((_end.y - _start.y) / (_end.x - _start.x));
_b = _start.y - _a * _start.x;
}
else
{
_vertical = true;
}
}
/**
* Indicate whereas the point lays on the line.
*
* @param point
* - The point to check
* @return <code>True</code> if the point lays on the line, otherwise return <code>False</code>
*/
public boolean isInside(Point point)
{
float maxX = _start.x > _end.x ? _start.x : _end.x;
float minX = _start.x < _end.x ? _start.x : _end.x;
float maxY = _start.y > _end.y ? _start.y : _end.y;
float minY = _start.y < _end.y ? _start.y : _end.y;
if ((point.x >= minX && point.x <= maxX) && (point.y >= minY && point.y <= maxY))
{
return true;
}
return false;
}
/**
* Indicate whereas the line is vertical. <br>
* For example, line like x=1 is vertical, in other words parallel to axis Y. <br>
* In this case the A is (+/-)infinite.
*
* @return <code>True</code> if the line is vertical, otherwise return <code>False</code>
*/
public boolean isVertical()
{
return _vertical;
}
/**
* y = <b>A</b>x + B
*
* @return The <b>A</b>
*/
public float getA()
{
return _a;
}
/**
* y = Ax + <b>B</b>
*
* @return The <b>B</b>
*/
public float getB()
{
return _b;
}
/**
* Get start point
*
* @return The start point
*/
public Point getStart()
{
return _start;
}
/**
* Get end point
*
* @return The end point
*/
public Point getEnd()
{
return _end;
}
@Override
public String toString()
{
return String.format("%s-%s", _start.toString(), _end.toString());
}
}
//// Here is the point java class and i'm not author of it
public class Point
{
public Point(float x, float y)
{
this.x = x;
this.y = y;
}
public float x;
public float y;
@Override
public String toString()
{
return String.format("(%.2f,%.2f)", x, y);
}
}
/*I coded only Mainactivity class other owner of other classes is https://github.com/sromku and all credit goes to him*/