您的位置:首页 > 数据库 > Mongodb

通过区域坐标在mongodb中查找范围内的坐标点

2014-11-27 18:20 204 查看
如果已经熟悉 mongodb-spring在java中的操作,就继续往下看

如果比较陌生,可以先看一下




java-spring与mongodb的整合方式一 自动注入xml

首先要在reposity中增加方法:

public List<ProjectInfo> searchByRang(float latbegin, float latend,
float lngbegin, float lngend) {
Query query=new Query();
query.addCriteria(Criteria.where("lat").gt(latbegin).lt(latend));
query.addCriteria(Criteria.where("lng").gt(lngbegin).lt(lngend));
return find(query,ProjectInfo.class);
}


新建点的class

package action.projectinfo;

public class MapPoint {

private float lng;
private float lat;

public MapPoint(float lng , float lat){
this.lng = lng;
this.lat = lat;
}

public MapPoint(){

}

public float getLng() {
return lng;
}

public void setLng(float lng) {
this.lng = lng;
}

public float getLat() {
return lat;
}

public void setLat(float lat) {
this.lat = lat;
}
}


新建线的class

package action.projectinfo;

public class Line {

private float k;
private float c;
private MapPoint pointa;
private MapPoint pointb;
private int plus; //1是正 -1是负

public Line(){

}

public Line(MapPoint pointa, MapPoint pointb){
this.pointa = pointa;
this.pointb = pointb;
this.k = (pointb.getLng() - pointa.getLng())
/ (pointb.getLat() - pointa.getLat());
this.c = k * pointa.getLat() - pointa.getLng();
}

public float getK() {
return k;
}

public void setK(float k) {
this.k = k;
}

public float getC() {
return c;
}

public void setC(float c) {
this.c = c;
}

public MapPoint getPointa() {
return pointa;
}

public void setPointa(MapPoint pointa) {
this.pointa = pointa;
}

public MapPoint getPointb() {
return pointb;
}

public void setPointb(MapPoint pointb) {
this.pointb = pointb;
}

public int getPlus() {
return plus;
}

public void setPlus(int plus) {
this.plus = plus;
}

public float calculatePoint(MapPoint mapPoint) {
return mapPoint.getLng() - getK()* mapPoint.getLat() + getC();
}
}


新建多边形的class

package action.projectinfo;

import java.util.List;

public class Polygon {

private List<Line> lines;
private List<MapPoint> points;

public List<Line> getLines() {
return lines;
}
public void setLines(List<Line> lines) {
this.lines = lines;
}
public List<MapPoint> getPoints() {
return points;
}
public void setPoints(List<MapPoint> points) {
this.points = points;
}

/**
* (x2-x1)*(y3-y1) - (y2-y1)*(x3-x1);
* @param index
* @return true 是凸多边形
*/
public boolean isConcave(int index) {
Line lineA = lines.get(index);
Line lineB = lines.get(index+1);
MapPoint point1 = lineA.getPointa();
MapPoint point2 = lineA.getPointb();
MapPoint point3 = lineB.getPointb();
float x2x1 = point2.getLng() - point1.getLng();
float y3y1 = point3.getLat() - point1.getLat();
float y2y1 = point2.getLat() - point1.getLat();
float x3x1 = point3.getLng() - point1.getLng();
float temp = (x2x1*y3y1)-(y2y1*x3x1);
if(temp>0){
return true;
}else{
return false;
}
}

/**
* 寻找初始节点-
*/
public int initCurvePoint(){
int size = points.size();
boolean flag = true;
boolean plus = true;
MapPoint point0 = points.get(0);
for(Line line :lines){

}
for(int i = 0 ; i < size ; i++){
MapPoint mapPoint = points.get(i);
for(Line line : lines){
if(line.calculatePoint(mapPoint)<0){
flag = false;
plus = false;
break;
}else{

}
}
if(flag){
return i;
}
flag = true;
}
return -1;
}

public void removePoint(int j) {
Line line = new Line(points.get(j-1),points.get(j+1));
points.remove(j);
lines.remove(j);
lines.remove(j-1);
lines.add(j-1, line);
}
}


查询的方法:

查询四边形

/**
* points为四边形的四个顶点
*latmin 是左上角的X坐标,lngmax 是左上角的Y坐标
*latmax 是右下角的X坐标,lngmin 是右下角的Y坐标
* @param projectInfos
* @return
*/
private void getQuadProjectInfos(List<ProjectInfo> pls) {
String[] pstr = points.split(";");
String[] pts0 = pstr[0].split(" ");
String[] pts1 = pstr[1].split(" ");
String[] pts2 = pstr[2].split(" ");
float lngmax = Float.valueOf(pts0[0]);
float lngmin = Float.valueOf(pts1[0]);
float latmax = Float.valueOf(pts0[1]);
float latmin = Float.valueOf(pts2[1]);
float templng;
float templat;
if (lngmax < lngmin) {
templng = lngmax;
lngmax = lngmin;
lngmin = templng;
}
if (latmax < latmin) {
templat = latmax;
latmax = latmin;
latmin = templat;
}
List<ProjectInfo> pis = projectInfoReposity.searchByRang(latmin,
latmax, lngmin, lngmax);
for (ProjectInfo pi : pis) {
pls.add(pi);
}
}


查询圆的范围的坐标:

private static double EARTH_RADIUS = 6378.137; //坐标和距离之间转化需要的值
private void getCircleProjectInfos(List<ProjectInfo> projectInfos) {
float r = Float.valueOf(raidus) / 1000;
float flat = Float.valueOf(lat);
float flng = Float.valueOf(lng);
float maxLat = calMaxLat(flat, r);
float minLat = calMinLat(flat, r);
float maxLng = calMaxLng(flng, r);
float minLng = calMinLng(flng, r);
List<ProjectInfo> allPis = projectInfoReposity.searchByRang(minLat,
maxLat, minLng, maxLng);
System.out.println(flat + "  " + flng);
System.out.println(r);
//上面得到的是 圆外的四边形区域的点的范围,所以要再判断一轮点到圆心的距离是否在半径内
for (ProjectInfo projectInfo : allPis) {
double s1 = calDistance(projectInfo.getLat(), flat,
projectInfo.getLng(), flng);
if (s1 < r) {
projectInfos.add(projectInfo);
}
}
allPis = null;
allCommers = null;
}

//通过圆心坐标以及半径,算出圆外的四边形的左上角和右下角的坐标
private float calMinLng(float lng, double s) {
s = s * 1.15d;
s = calMeters(s);
double a = rad(lng) - s;
return (float) (a * 180d / Math.PI);
}

private float calMaxLng(float lng, double s) {
s = s * 1.16d;
s = calMeters(s);
double a = rad(lng) + s;
return (float) (a * 180d / Math.PI);
}

private float calMaxLat(float lat, double s) {
s = s / EARTH_RADIUS;
s = s / 2d;
s = Math.asin(Math.sin(s)) * 2d;
double a = rad(lat) + s;
return (float) (a * 180d / Math.PI);
}

private float calMinLat(float lat, double s) {
s = s / EARTH_RADIUS;
s = s / 2d;
s = Math.asin(Math.sin(s)) * 2d;
double a = rad(lat) - s;
return (float) (a * 180d / Math.PI);
}

private double calMeters(double s) {
s = s / EARTH_RADIUS;
s = s / 2d;
s = Math.asin(Math.sin(s)) * 2d;
return s;
}

private double rad(double d) {
return d * Math.PI / 180.0;
}

private double calDistance(float beginlat, float endlat, float beginlng,
float endlng) {
double radLat1 = rad(beginlat);
double radLat2 = rad(endlat);
double a = radLat1 - radLat2;
double b = rad(beginlng) - rad(endlng);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+ Math.cos(radLat1) * Math.cos(radLat2)
* Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
s = Math.round(s * 10000) / (double) 10000;
return s;
}


查询多边形的范围的坐标:

private void getPolyProjectInfos(List<ProjectInfo> npis) {
String[] pstr = points.split(";");
MapPoint[] mapPoints = translateMapPoints(pstr);
int length = mapPoints.length;
float maxLat = 0.0f;
float maxLng = 0.0f;
float minLat = mapPoints[0].getLat();
float minLng = mapPoints[0].getLng();
List<Line> lines = new ArrayList<Line>();
for (int i = 0; i < mapPoints.length - 1; i++) {
if (mapPoints[i].getLat() > maxLat) {
maxLat = mapPoints[i].getLat();
}
if (mapPoints[i].getLng() > maxLng) {
maxLng = mapPoints[i].getLng();
}
if (mapPoints[i].getLat() < minLat) {
minLat = mapPoints[i].getLat();
}
if (mapPoints[i].getLng() < minLng) {
minLng = mapPoints[i].getLng();
}
try {
Line line = getLineByPoints(mapPoints[i], mapPoints[i + 1]);
if (i < length - 2) {
if (mapPoints[i + 2].getLng() - line.getK()
* mapPoints[i + 2].getLat() + line.getC() < 0) {
line.setPlus(-1);
} else {
line.setPlus(1);
}
} else {
if (mapPoints[1].getLng() - line.getK()
* mapPoints[1].getLat() + line.getC() < 0) {
line.setPlus(-1);
} else {
line.setPlus(1);
}
}
lines.add(line);
} catch (Exception e) {
e.printStackTrace();
}
}
for (Line line : lines) {
System.out.println(line.getK());
}
List<ProjectInfo> pls = projectInfoReposity.searchByRang(minLat,
maxLat, minLng, maxLng);
for (ProjectInfo pl : pls) {
float lat = pl.getLat();
float lng = pl.getLng();
MapPoint mapPoint3 = new MapPoint(lng, lat);
MapPoint mapPoint4 = new MapPoint(maxLng, lat);
//我们得到的是多边形外的四边形的范围的点,还要判断它是否在多边形内,可以向量差积来进行判断
boolean flag = isInArea(lines, mapPoint3, mapPoint4);
if (flag) {
npis.add(pl);
}
}

}

private MapPoint[] translateMapPoints(String[] pstrs) {
MapPoint[] mapPoints = new MapPoint[pstrs.length + 1];
for (int i = 0; i < pstrs.length; i++) {
String pstr = pstrs[i];
MapPoint mapPoint = new MapPoint();
String[] pts = pstr.split(" ");
mapPoint.setLat(Float.valueOf(pts[1]));
mapPoint.setLng(Float.valueOf(pts[0]));
mapPoints[i] = mapPoint;
}
MapPoint mapPoint = new MapPoint();
mapPoint.setLat(mapPoints[0].getLat());
mapPoint.setLng(mapPoints[0].getLng());
mapPoints[pstrs.length] = mapPoint;
return mapPoints;
}

private Line getLineByPoints(MapPoint pointa, MapPoint pointb) {
float k = (pointb.getLng() - pointa.getLng())
/ (pointb.getLat() - pointa.getLat());
float c = k * pointa.getLat() - pointa.getLng();
Line line = new Line();
line.setC(c);
line.setPointa(pointa);
line.setPointb(pointb);
line.setK(k);
return line;
}

// ( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) ≥ 0
// (x1*y2-x2*y1)*(x1*y3-x3*y1)<0
// 计算AB(为(x1b-x1a,y1b-y1a))向量与AC(为(x2a-x1a,y2a-y1a))向量的差积
// (x2-x1)*(y3-y1) - (y2-y1)*(x3-x1)
private boolean isInArea(List<Line> lines, MapPoint point3, MapPoint point4) {
int num = 0;
for (Line line : lines) {
MapPoint point1 = line.getPointa();
MapPoint point2 = line.getPointb();
float x1 = point1.getLng();
float x2 = point2.getLng();
float x3 = point3.getLng();
float x4 = point4.getLng();
float y1 = point1.getLat();
float y2 = point2.getLat();
float y3 = point3.getLat();
float y4 = point4.getLat();
float t1 = (x1 - x3) * (y4 - y3) - (y1 - y3) * (x4 - x3);
float t2 = (x4 - x3) * (y2 - y3) - (y4 - y3) * (x2 - x3);
if (t1 * t2 >= 0) {
float t3 = (x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2);
float t4 = (x1 - x2) * (y1 - y4) - (y1 - y2) * (x1 - x4);
if (t3 * t4 >= 0) {
num++;
}
}
}
if (num > 0 && num % 2 != 0) {
return true;
}
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: