计算地图上正方(矩)形区域点坐标集合判断电子围栏

背景:公司业务需要在地图上绘画出以任意地址且斜长为500m的正方形区域点坐标集合作为电子围栏集合区域,绘画出来的正方形区域点坐标集合通过前端APP作为触发电子围栏条件。

实现方法:

1、将中心点地址通过高德API接口地理编码解析为高德经纬度

2、通过中心点经纬度、斜长、角度计算出正方形(矩形)每个点坐标经纬度

3、最后四个点坐标组合成区域点集合

现通过java实现代码如下:

/**
	 * 
	 * @Description: 计算正方(矩)形区域点坐标集合
	 * @param address 地址
	 * @param margin 斜长(km)
	 * @param angle 角度
	 * @return
	 * @throws NumberFormatException
	 * @author 
	 * @date 2019年1月3日 下午8:07:58
	 */
	public String calculatUtilSquareRegion(String address,double margin,double angle){
		// 地理编码(地址解析为高德经纬度)
		List<AmapGeocodes> amapGeocodesList = this.adressAnalysis(address, false);
		JSONArray jsonObject = null;
		String location = "";
		if (!CollectionUtils.isEmpty(amapGeocodesList)) {
			location = amapGeocodesList.get(0).getLocation();
		}
		String pointX = "";
		String pointY = "";
		// 获取原始点经纬度
		if (StringUtils.isNotBlank(location)) {
			pointX = location.split(",")[0];
			pointY = location.split(",")[1];
			List<LngLatPointVo> list = new ArrayList<LngLatPointVo>();
			// 计算角度为margin的经纬度
			LngLatPointVo pointA = getLngLat(Double.parseDouble(pointY), Double.parseDouble(pointX), margin, angle);
			list.add(pointA);
			// 计算角度为margin+90的经纬度
			LngLatPointVo pointB = getLngLat(Double.parseDouble(pointY), Double.parseDouble(pointX), margin, angle + 90);
			list.add(pointB);
			// 计算角度为margin+180的经纬度
			LngLatPointVo pointC = getLngLat(Double.parseDouble(pointY), Double.parseDouble(pointX), margin, angle + 180);
			list.add(pointC);
			// 计算角度为margin+270的经纬度
			LngLatPointVo pointD = getLngLat(Double.parseDouble(pointY), Double.parseDouble(pointX), margin, angle + 270);
			list.add(pointD);
			list.toArray();
			jsonObject = (JSONArray) JSONArray.toJSON(list.toArray());
		}
		return jsonObject == null ? "" : jsonObject.toString();
	}
/**
	 * @Description 根据一个点的经纬度坐标、边长距离、角度计算另一个点的经纬度(方法1)
	 * @param lat 纬度
	 * @param lng 经度
	 * @param margin 斜长距离(km)
	 * @param angle 角度
	 * @return
	 * @author 
	 */
	public LngLatPointVo getLngLat(double lat, double lng, double margin, double angle){
		LngLatPointVo lngLat = new LngLatPointVo();
		double Ea = 6378137; // 赤道半径
		double Eb = 6356725; // 极半径
		double dx = margin * 1000 * Math.sin(angle * Math.PI / 180.0);
		double dy = margin * 1000 * Math.cos(angle * Math.PI / 180.0);
		double ec = Eb + (Ea - Eb) * (90.0 - lat) / 90.0;
		double ed = ec * Math.cos(lat * Math.PI / 180);
		double newLng = (dx / ed + lng * Math.PI / 180.0) * 180.0 / Math.PI;
		double newLat = (dy / ec + lat * Math.PI / 180.0) * 180.0 / Math.PI;
		lngLat.setLat(newLat);
		lngLat.setLng(newLng);
		return lngLat;
	}
	/**
	 * @Description 根据一个点的经纬度坐标、边长距离、角度计算另一个点的经纬度(方法2)
	 * @param lat 纬度
	 * @param lng 经度
	 * @param distance 边长距离
	 * @param angle 角度
	 * @return
	 * @author liuhai
	 */
	public LngLatPointVo getLngLat1(double lat, double lng, double distance,
			double angle) {
		LngLatPointVo lngLat = new LngLatPointVo();
		double R = 6378.137;
		double φ1 = ConvertDegreesToRadians(lat);
		double λ1 = ConvertDegreesToRadians(lng);
		double θ = ConvertDegreesToRadians(angle);
		double φ2 = Math.asin(Math.sin(φ1) * Math.cos(distance / R)
				+ Math.cos(φ1) * Math.sin(distance / R) * Math.cos(θ));
		double λ2 = λ1
				+ Math.atan2(
						Math.sin(θ) * Math.sin(distance / R) * Math.cos(φ1),
						Math.cos(distance / R) - Math.sin(φ1) * Math.sin(φ2));
		λ2 = (λ2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise to
															// -180..+180°
		double lat2 = ConvertRadiansToDegrees(φ2);
		double lon2 = ConvertRadiansToDegrees(λ2);
		lngLat.setLat(lat2);
		lngLat.setLng(lon2);
		return lngLat;
	}

	public double ConvertDegreesToRadians(double degrees) {
		return degrees * Math.PI / 180;
	}
	public static double ConvertRadiansToDegrees(double radian) {
		return radian * 180.0 / Math.PI;
	}
/**
	 * @Title: adressAnalysis
	 * @param adress
	 *            ,batch(批量查询控制:batch 参数设置为 true 时进行批量查询操作,最多支持 10 个地址进行批量查询)
	 * @Description: 地理编码(地址解析为高德经纬度)
	 * @return 返回List
	 */
	public List<AmapGeocodes> adressAnalysis(String adress, Boolean batch) {
		List<AmapGeocodes> list = new ArrayList<AmapGeocodes>();
		SystemConfig scKey = systemConfigBiz.findCacheByCode("AMAP_API_SERVER_AK");
		SystemConfig scUrl = systemConfigBiz.findCacheByCode("AMP_API_ADRESS_ANALYSIS");
		String key = "", url = "";
		// 非空判断
		if (null != scUrl && null != scKey) {
			key = scKey.getConfigValue();
			url = scUrl.getConfigValue();
		}
		if (StringUtils.isBlank(key) || StringUtils.isBlank(url)) {
			log.info("缺少AMAP_API_SERVER_AK或者AMP_API_ADRESS_ANALYSIS的系統配置項,請先在系統配置管理中進行配置");
			return list;
		}
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("address", adress.trim());
		params.put("output", "JSON");
		params.put("batch", false);
		params.put("key", key);
		String json = HttpUtil.sendGet(url, params, "UTF-8");
		// 将返回结果转换成map
		Map<?, ?> reMap = JSON.parseObject(json);
		// 请求成功
		if (reMap != null && ((reMap.get("status") == null ? "" : reMap.get("status").toString()).equals("1"))) {
			String geocodesArray = reMap.get("geocodes") == null ? "" : reMap.get("geocodes").toString();
			if (Integer.parseInt(reMap.get("count") == null ? "0" : reMap.get("count").toString()) > 0) {
				list = JSONObject.parseArray(geocodesArray, AmapGeocodes.class);
			}
		}
		return list;
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值