政区四至与地图四至范围聚合效果计算方法
程序员文章站
2022-05-11 13:07:31
...
目录
地图聚合屏幕占比 = 政区四至面积/屏幕四至面积x100%. 两个矩形确定一个同位点然后计算两点相交部分的长宽面积即可。
地图屏占比
图形面积与当前四至面积比对占比值,合理的比重是20%。
屏占比算法
F= 矩形面积/地图四至面积* 100%
矩形集已知,轮询计算
- 小于20% 显示聚合-计算结束
- 大于20% 继续下级计算,直到计算占比面积小于20%结束,没有下级结束,显示空间点。
两点确定一条直线,两线确定一面
矩形的面积= 长* 宽
geometry多边形的面积 = geometry直接求算 Postgresql有函数
矩形求重叠面积算法
定义矩形
package com.boonya.beans.gis;
import java.io.Serializable;
/**
* @Copyright: 2019-2021
* @FileName: Rectangle.java
* @Author: PJL
* @Date: 2020/7/14 18:19
* @Description: 矩形
*/
public class Rectangle implements Comparable<Rectangle>, Serializable {
private double x; //矩形左下角的x坐标
private double y; //矩形左下角的y坐标
private double length;
private double width;
public Rectangle(double x, double y, double length, double width) {
this.x = x;
this.y = y;
this.length = length;
this.width = width;
}
public double getArea() {
return length * width;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getLength() {
return length;
}
public double getWidth() {
return width;
}
@Override
public int compareTo(Rectangle o) {
return Double.compare(this.getArea(), o.getArea());
}
}
定义计算面积方法
package com.boonya.beans.gis;
/**
* @Copyright: 2019-2021
* @FileName: RectangleOverlap.java
* @Author: PJL
* @Date: 2020/7/14 18:21
* @Description: 矩形重叠面积
*/
public class RectangleOverlap {
/**
* 计算重叠区域面积
*
* @param rect1
* @param rect2
* @return
*/
public double calculateOverlapArea(Rectangle rect1, Rectangle rect2) {
if (rect1 == null || rect2 == null) {
return -1;
}
double p1_x = rect1.getX(), p1_y = rect1.getY();
double p2_x = p1_x + rect1.getLength(), p2_y = p1_y + rect1.getWidth();
double p3_x = rect2.getX(), p3_y = rect2.getY();
double p4_x = p3_x + rect2.getLength(), p4_y = p3_y + rect2.getWidth();
if (p1_x > p4_x || p2_x < p3_x || p1_y > p4_y || p2_y < p3_y) {
return 0;
}
double Len = Math.min(p2_x, p4_x) - Math.max(p1_x, p3_x);
double Wid = Math.min(p2_y, p4_y) - Math.max(p1_y, p3_y);
return Len * Wid;
}
public static void main(String[] args) {
Rectangle rect1 = new Rectangle(0, 1, 3, 2);
Rectangle rect2 = new Rectangle(2, 0, 2, 2);
RectangleOverlap overlap = new RectangleOverlap();
System.out.println(overlap.calculateOverlapArea(rect1, rect2));
}
}
聚合计算工具类
package com.boonya.beans.util;
import com.alibaba.fastjson.JSONArray;
import com.boonya.beans.Constants;
import com.boonya.beans.gis.Rectangle;
import com.boonya.beans.gis.RectangleOverlap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import java.util.List;
import java.util.Map;
/**
* @Copyright: 2019-2021
* @FileName: LogicUtil.java
* @Author: PJL
* @Date: 2020/6/29 15:34
* @Description: 逻辑处理工具类
*/
@Slf4j
public class LogicUtil {
/**
* 获取四至范围数组
*
* @param extentArray
* @return
*/
public static Double[] getExtent(JSONArray extentArray) {
int count = extentArray.size();
Double[] extent = new Double[count];
for (int i = 0; i < count; i++) {
extent[i] = extentArray.getDouble(i);
}
return extent;
}
/**
* 解析组织机构数组
*
* @param list
* @return
*/
public static String[] getOrgIds(List<Map<String, Object>> list) {
if (ObjectUtils.isEmpty(list)) {
return new String[]{};
}
String[] orgIds = new String[list.size()];
int index = 0;
for (Map<String, Object> map : list) {
orgIds[index] = null == map.get("I_ORGID") ? map.get("i_orgid").toString() : map.get("I_ORGID").toString();
index++;
}
return orgIds;
}
/**
* 组织机构过滤条件
*
* @param orgIds
* @return
*/
public static String getOrgFilterString(String[] orgIds) {
if (ObjectUtils.isEmpty(orgIds)) {
return "-1";
}
StringBuffer sb = new StringBuffer();
for (int i = 0, j = orgIds.length; i < j; i++) {
if (i == 0) {
sb.append(orgIds[i]);
} else {
sb.append(",").append(orgIds[i]);
}
}
return sb.toString();
}
/**
* 根据地图缩放层级获取组织机构编号长度条件位数
*
* @param level
* @param isAll
* @return
*/
public static int getOrgCodeLengthByLevel(Integer level, boolean isAll) {
int result = 0;
switch (level) {
/****************一级*****************/
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
if (isAll) {
/****************全国*****************/
result = 1;
} else {
result = 4;
}
break;
/****************二级*****************/
case 7:
case 8:
result = 4 * 2;
break;
/****************三级级*****************/
case 9:
case 10:
result = 4 * 3;
break;
/****************四级*****************/
case 11:
case 12:
result = 4 * 4;
break;
/****************五级*****************/
case 13:
case 14:
result = 4 * 5;
break;
/****************默认*****************/
default:
result = 4 * 5;
break;
}
return result;
}
/**
* 四至范围扩大计算
*
* @param zoom
* @param extent
* @return
*/
public static Double[] extentBetter(Integer zoom, Double[] extent) {
// 15级之前四至范围扩大百分之20(解决四至范围没有组织机构中心点问题)
if (zoom.intValue() <= Constants.MAP_AGGREGATION_MAX_ZOOM_NUMBER) {
double factor = 1.2;
extent[0] /= factor;// 左下角点X缩小
extent[1] /= factor;// 左下角点Y缩小
extent[2] *= factor;// 右上角点X扩大
extent[3] *= factor;// 右上角点Y扩大
}
return extent;
}
/**
* 获取重叠部分面积值
*
* @param screenExtent
* @param orgExtent
* @return
*/
public static double getRectangleArea(Double[] screenExtent, Double[] orgExtent) {
double screenLength = Math.abs(screenExtent[2] - screenExtent[0]);
double screenWidth = Math.abs(screenExtent[3] - screenExtent[1]);
double orgLength = Math.abs(orgExtent[2] - orgExtent[0]);
double orgWidth = Math.abs(orgExtent[3] - orgExtent[1]);
Rectangle rectangle = new Rectangle(screenExtent[0], screenExtent[1], screenLength, screenWidth);
Rectangle rectangle2 = new Rectangle(orgExtent[0], orgExtent[1], orgLength, orgWidth);
RectangleOverlap overlap = new RectangleOverlap();
return overlap.calculateOverlapArea(rectangle, rectangle2);
}
/**
* 矩形相交屏幕占比计算(百分数值)
*
* @param screenExtent
* @param orgExtent
* @return
*/
public static long getShadowRateOfRectangle(Double[] screenExtent, Double[] orgExtent) {
double screenLength = Math.abs(screenExtent[2] - screenExtent[0]);
double screenWidth = Math.abs(screenExtent[3] - screenExtent[1]);
double areaScreen = screenLength * screenWidth;
double overlayArea = getRectangleArea(screenExtent, orgExtent);
long percentage = Math.round(overlayArea / areaScreen * 100);
log.info(">>>>LogicUtil overlayArea={} percentage = {}", overlayArea, percentage);
return percentage;
}
/**
* 判断两个矩形是否有重叠部分
*
* @param screenExtent
* @param orgExtent
* @return
*/
public static boolean isIntersected(Double[] screenExtent, Double[] orgExtent) {
boolean flag = false;
double overlayArea = getRectangleArea(screenExtent, orgExtent);
if (overlayArea > 0) {
flag = true;
}
log.info(">>>>LogicUtil overlayArea={} isIntersected = {}", overlayArea, flag);
return flag;
}
}
政区聚合递归算法:
/**
* 根据四至计算地图显示数据方式【聚合/散点】==返回组织机构标识
*
* @param org
* @param screenExtent
* @param orgMap k-v = 组织机构ID-组织机构编码:是否聚合(true|false)
* @return
*/
public Map<String, Boolean> calculateOrgAggregationData(Org org, Double[] screenExtent, Map<String, Boolean> orgMap) {
Double[] orgExtent = org.getExtent();
// 第一步: 屏幕四至求交组织机构四至
boolean intersected = LogicUtil.isIntersected(screenExtent, orgExtent);
if (intersected) {
// 计算当前组织机构占比
long rate = LogicUtil.getShadowRateOfRectangle(screenExtent, orgExtent);
String key = new StringBuffer(org.getId()).append("-").append(org.getCode()).toString();
if (rate < Constants.MAP_AGGREGATION_SCREEN_RATE) {
orgMap.put(key, true);// 设置是否聚合
} else {
try {
List<Map<String, Object>> list = this.getDirectChildrenOrgListById(org.getId());
if (ObjectUtils.isNotEmpty(list)) {
for (Map<String, Object> childOrg : list) {
Org tempOrg = this.getOrgPositionByMap(childOrg);
// 递归获取下级单位占比值
calculateOrgAggregationData(tempOrg, screenExtent, orgMap);
}
} else {
// 没有下级单位 但面积大于MAP_AGGREGATION_SCREEN_RATE
orgMap.put(key, false);// 设置是否聚合
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return orgMap;
}
Constants.MAP_AGGREGATION_SCREEN_RATE =20
聚合效果图
推荐阅读