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


如果已经熟悉 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;
	}


你可能感兴趣的:(mongodb,查询,多边形,地图)