|
@@ -0,0 +1,236 @@
|
|
|
+package cn.sagacloud.server.algorithm.common.utils;
|
|
|
+
|
|
|
+import cn.sagacloud.server.algorithm.models.dataCheck.GridCheckResult;
|
|
|
+import cn.sagacloud.server.algorithm.models.entities.Grid;
|
|
|
+import cn.sagacloud.server.algorithm.models.jsonAnalyzer.Location;
|
|
|
+import cn.sagacloud.server.algorithm.models.jsonAnalyzer.Point;
|
|
|
+import cn.sagacloud.server.algorithm.models.modelFile.FloorModelView;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.collections4.MapUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Grid分组工具
|
|
|
+ * 基于python代码改写
|
|
|
+ * @author Administrator
|
|
|
+ * @date 2021-10-21
|
|
|
+ */
|
|
|
+public class GridGroupUtil {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取分组信息
|
|
|
+ * @param views
|
|
|
+ * @param gridMap
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static List<GridCheckResult> checkGridUpright(List<FloorModelView> views, Map<String, List<Grid>> gridMap) {
|
|
|
+ if(CollectionUtils.isEmpty(views)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 组装名称位置信息
|
|
|
+ Map<String, Map<String, Location>> gridNameMap = convertGridMap(gridMap);
|
|
|
+ // 获取分组
|
|
|
+ Map<String, Integer> groupMap = groupGrids(gridNameMap);
|
|
|
+ // 转换结果
|
|
|
+ List<GridCheckResult> rsList = new ArrayList<>();
|
|
|
+ for(FloorModelView view:views) {
|
|
|
+ GridCheckResult rs = new GridCheckResult();
|
|
|
+ BeanUtils.copyProperties(view, rs);
|
|
|
+ rs.setGroupId(MapUtils.getInteger(groupMap, view.getCurrentModelId()));
|
|
|
+ rsList.add(rs);
|
|
|
+ }
|
|
|
+ return rsList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将GridMap转换为名称、位置对照
|
|
|
+ * @param gridMap
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static Map<String, Map<String, Location>> convertGridMap(Map<String, List<Grid>> gridMap) {
|
|
|
+ if(MapUtils.isEmpty(gridMap)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 组装名称位置信息
|
|
|
+ Map<String, Map<String, Location>> gridNameMap = new HashMap<>(16);
|
|
|
+ for(String modelId:gridMap.keySet()) {
|
|
|
+ List<Grid> gridList = gridMap.get(modelId);
|
|
|
+ if(CollectionUtils.isEmpty(gridList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Map<String, Location> nameMap = new HashMap<>(16);
|
|
|
+ gridNameMap.put(modelId, nameMap);
|
|
|
+ // 获取Name, Location存入Map
|
|
|
+ for(Grid grid:gridList) {
|
|
|
+ String name = grid.getName();
|
|
|
+ Location location = grid.getLocation();
|
|
|
+ if(StringUtils.isBlank(name) || location == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ nameMap.put(name, location);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return gridNameMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按Grid冲突关系,将ModelId分组
|
|
|
+ * 分组号从1开始.
|
|
|
+ * @param gridMap
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static Map<String, Integer> groupGrids(Map<String, Map<String, Location>> gridMap){
|
|
|
+ if(MapUtils.isEmpty(gridMap)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<List<String>> modelIdList = groupGridToList(gridMap);
|
|
|
+ Map<String, Integer> modelIdMap = new HashMap<>(16);
|
|
|
+ for(int i = 0,j = modelIdList.size();i < j;i++) {
|
|
|
+ List<String> idList = modelIdList.get(i);
|
|
|
+ for(String modelId:idList) {
|
|
|
+ modelIdMap.put(modelId, i+1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return modelIdMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将grid按modelId分组
|
|
|
+ * 每组的ModelId都是不冲突的
|
|
|
+ * @param gridMap
|
|
|
+ * @return List<[id1,id2,id5],[id3,id4]>
|
|
|
+ */
|
|
|
+ private static List<List<String>> groupGridToList(Map<String, Map<String, Location>> gridMap){
|
|
|
+ List<List<String>> modelIdList = new ArrayList<>();
|
|
|
+ // 按ModelId循环
|
|
|
+ for(String modelId : gridMap.keySet()) {
|
|
|
+ // 是否所有分组都有冲突
|
|
|
+ boolean isAllConflict = true;
|
|
|
+ // 按分组循环
|
|
|
+ for(int i = 0,j = modelIdList.size();i < j;i++) {
|
|
|
+ List<String> idList = modelIdList.get(i);
|
|
|
+ // 当前分组内是否有冲突
|
|
|
+ boolean isConflict = false;
|
|
|
+ for(String toId:idList) {
|
|
|
+ Map<String, Location> fromMap = gridMap.get(modelId);
|
|
|
+ Map<String, Location> toMap = gridMap.get(modelIdList.get(i));
|
|
|
+ // 如果有冲突,则不再比较
|
|
|
+ if (isConflict(fromMap, toMap)) {
|
|
|
+ isConflict = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果没有冲突,则放入此队列中
|
|
|
+ if(!isConflict) {
|
|
|
+ idList.add(modelId);
|
|
|
+ isAllConflict = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果所有分组内都有冲突,则新增分组
|
|
|
+ if(isAllConflict) {
|
|
|
+ List<String> idList = new ArrayList<>();
|
|
|
+ idList.add(modelId);
|
|
|
+ modelIdList.add(idList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return modelIdList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 模型中的Grid是否有冲突
|
|
|
+ * @param fromMap
|
|
|
+ * @param toMap
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static boolean isConflict(Map<String, Location> fromMap, Map<String, Location> toMap) {
|
|
|
+ if(MapUtils.isEmpty(fromMap) || MapUtils.isEmpty(toMap)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 按名称循环处理
|
|
|
+ for(String name:fromMap.keySet()) {
|
|
|
+ if(!toMap.containsKey(name)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 只处理名称相同的比较
|
|
|
+ Location from = fromMap.get(name);
|
|
|
+ Location to = toMap.get(name);
|
|
|
+ if(from == null || to == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 位置有冲突
|
|
|
+ if(isConflict(from, to)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 位置是否冲突
|
|
|
+ * @param from
|
|
|
+ * @param to
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isConflict(Location from, Location to) {
|
|
|
+ // 只有都是线的类型才判断冲突
|
|
|
+ if(!(StringUtils.contains(from.getType(), "Line")
|
|
|
+ && StringUtils.contains(to.getType(), from.getType()))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 点位应在2个以上
|
|
|
+ if(CollectionUtils.size(from.getPoints()) < 2 || CollectionUtils.size(to.getPoints()) < 2) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 取开始结束点位
|
|
|
+ Point fromBegin = from.getPoints().get(0);
|
|
|
+ Point fromEnd = from.getPoints().get(1);
|
|
|
+ Point toBegin = to.getPoints().get(0);
|
|
|
+ Point toEnd = to.getPoints().get(1);
|
|
|
+ // 计算相对角度和偏移量
|
|
|
+ try {
|
|
|
+ BigDecimal fromAngle = calAngle(fromBegin, fromEnd);
|
|
|
+ BigDecimal fromOffset = calOffset(fromBegin, fromAngle);
|
|
|
+ BigDecimal toAngle = calAngle(toBegin, toEnd);
|
|
|
+ BigDecimal toOffset = calOffset(toBegin, toAngle);
|
|
|
+ // 都相同则冲突
|
|
|
+ return fromAngle.equals(toAngle) && fromOffset.equals(toOffset);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 计算异常则直接判断点位X坐标
|
|
|
+ return fromEnd.getX() == toBegin.getX() && fromEnd.getX() == toEnd.getX();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算两个点的相对角度
|
|
|
+ * @param begin
|
|
|
+ * @param end
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static BigDecimal calAngle(Point begin, Point end) {
|
|
|
+ BigDecimal beginX = BigDecimal.valueOf(begin.getX());
|
|
|
+ BigDecimal beginY = BigDecimal.valueOf(begin.getY());
|
|
|
+ BigDecimal endX = BigDecimal.valueOf(end.getX());
|
|
|
+ BigDecimal endY = BigDecimal.valueOf(end.getY());
|
|
|
+ return beginY.subtract(endY).divide(beginX.subtract(endX));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算点位的偏移量
|
|
|
+ * @param begin
|
|
|
+ * @param angle
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static BigDecimal calOffset(Point begin, BigDecimal angle) {
|
|
|
+ BigDecimal beginX = BigDecimal.valueOf(begin.getX());
|
|
|
+ BigDecimal beginY = BigDecimal.valueOf(begin.getY());
|
|
|
+ return beginY.subtract(angle.multiply(beginX));
|
|
|
+ }
|
|
|
+}
|