Browse Source

Merge remote-tracking branch 'origin/develop' into develop

lvxianyun 3 years ago
parent
commit
427582e1c1

+ 9 - 2
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/constant/CalRuleTypeEnum.java

@@ -15,11 +15,18 @@ import java.util.stream.Collectors;
  */
 @Getter
 public enum CalRuleTypeEnum {
-    /** 计算规则种类 */
+    /** 计算规则种类,1-根据关系链计算关系 */
     REL_CHAIN("1","relChainCalculateServiceImpl"),
+    /** 计算规则种类,2-根据坐标包含计算关系 */
     COORDINATE("2","coordinateCalculateServiceImpl"),
+    /** 计算规则种类,3-根据继承关系计算关系 */
     REL_EXTEND("3","relExtendCalculateServiceImpl"),
-    FL_THROUGH_FL("4","flThroughFlRelCalculateServiceImpl");
+    /** 计算规则种类,4-根据模型文件是否一样计算关系 */
+    FL_THROUGH_FL("4","flThroughFlRelCalculateServiceImpl"),
+    /** 计算规则种类,5-根据下级空间是否连通计算关系 */
+    SH_THROUGH_SH("5","shThroughShRelCalculateServiceImpl"),
+    /** 计算规则种类,6-根据门,窗,虚拟墙,元空间是否连通计算关系 */
+    SPACE_CONNECTION("6","spaceConnectionRelCalculateServiceImpl");
 
     CalRuleTypeEnum(String index, String beanName) {
         this.index = index;

+ 4 - 1
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/controller/TestController.java

@@ -8,6 +8,7 @@ import com.persagy.dmp.rwd.digital.domain.CalculatingDTO;
 import com.persagy.dmp.rwd.digital.service.calstrategy.CoordinateCalculateServiceImpl;
 import com.persagy.dmp.rwd.digital.service.calstrategy.FlThroughFlRelCalculateServiceImpl;
 import com.persagy.dmp.rwd.digital.service.calstrategy.ShThroughShRelCalculateServiceImpl;
+import com.persagy.dmp.rwd.digital.service.calstrategy.SpaceConnectionRelCalculateServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -23,6 +24,7 @@ public class TestController {
     private final CoordinateCalculateServiceImpl coordinateCalculateService;
     private final FlThroughFlRelCalculateServiceImpl flThroughFlRelCalculateService;
     private final ShThroughShRelCalculateServiceImpl shThroughShRelCalculateService;
+    private final SpaceConnectionRelCalculateServiceImpl spaceConnectionRelCalculateService;
 
     @PostMapping("/testCal")
     public CommonResult<Void> testCal(@RequestBody CalculatingDTO calculatingDTO){
@@ -41,7 +43,8 @@ public class TestController {
         calculatingDTO.setProjectId(AppContext.getContext().getProjectId());
         //coordinateCalculateService.calculateRelation(calculatingDTO.getRelationCalRule(),calculatingDTO);
         //flThroughFlRelCalculateService.calculateRelation(calculatingDTO.getRelationCalRule(),calculatingDTO);
-        shThroughShRelCalculateService.calculateRelation(calculatingDTO.getRelationCalRule(),calculatingDTO);
+        //shThroughShRelCalculateService.calculateRelation(calculatingDTO.getRelationCalRule(),calculatingDTO);
+        spaceConnectionRelCalculateService.calculateRelation(calculatingDTO.getRelationCalRule(),calculatingDTO);
         return ResultHelper.success();
     }
 

+ 24 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/dao/ObjectDigitalMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.persagy.dmp.basic.dto.RequestData;
 import com.persagy.dmp.digital.entity.ObjectDigital;
 import com.persagy.dmp.rwd.digital.domain.CalculatingDTO;
+import com.persagy.dmp.rwd.digital.domain.SpaceCalDTO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -115,4 +116,27 @@ public interface ObjectDigitalMapper extends BaseMapper<ObjectDigital> {
      * Update By lijie 2021/9/27 18:27
      */
     List<ObjectDigital> queryObjectListByIds(@Param("objIds") Set<String> objIds);
+    /***
+     * Description: 根据模型id查询门对象
+     * @param modelIds : 模型id集合
+     * @param calculatingDTO : 请求参数
+     * @param classCode : 对象类型
+     * @return : java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>
+     * @author : lijie
+     * @date :2021/10/11 18:01
+     * Update By lijie 2021/10/11 18:01
+     */
+    List<SpaceCalDTO> queryEquipmentsByModelIds(@Param("objIds") Set<String> modelIds,
+                                                @Param("param") CalculatingDTO calculatingDTO,
+                                                @Param("classCode") String classCode);
+    /***
+     * Description: 查询元空间
+     * @param modelIds : 模型id集合
+     * @param calculatingDTO : 请求参数
+     * @return : java.util.List<com.persagy.dmp.rwd.digital.domain.SpaceCalDTO>
+     * @author : lijie
+     * @date :2021/10/11 22:09
+     * Update By lijie 2021/10/11 22:09
+     */
+    List<SpaceCalDTO> queryIspacesByModelIds(Set<String> modelIds, CalculatingDTO calculatingDTO);
 }

+ 10 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/dao/ObjectRelationMapper.java

@@ -5,6 +5,7 @@ import com.persagy.dmp.basic.dto.RelationCalDTO;
 import com.persagy.dmp.digital.entity.ObjectDigital;
 import com.persagy.dmp.digital.entity.ObjectRelation;
 import com.persagy.dmp.rwd.digital.domain.CalculatingDTO;
+import com.persagy.dmp.rwd.digital.domain.SpaceCalDTO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -63,4 +64,13 @@ public interface ObjectRelationMapper extends BaseMapper<ObjectRelation> {
      * Update By lijie 2021/10/11 10:54
      */
     List<ObjectRelation> queryArchSubsetShToSp(@Param("param") CalculatingDTO calculatingDTO);
+    /***
+     * Description: 根据项目id查询项目下的所有空间及关联的楼层及楼层模型id
+     * @param calculatingDTO : 请求参数
+     * @return : java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>
+     * @author : lijie
+     * @date :2021/10/11 15:32
+     * Update By lijie 2021/10/11 15:32
+     */
+    List<SpaceCalDTO> querySpacesByProjectId(@Param("param") CalculatingDTO calculatingDTO);
 }

+ 25 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/domain/OpenPointDTO.java

@@ -0,0 +1,25 @@
+package com.persagy.dmp.rwd.digital.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class OpenPointDTO {
+    /**门,窗,虚拟墙,元空间打开后两点的第一个坐标点*/
+    private Double firstX;
+    /**门,窗,虚拟墙,元空间打开后两点的第一个坐标点*/
+    private Double firstY;
+    /**门,窗,虚拟墙,元空间打开后两点的第二个坐标点*/
+    private Double secondX;
+    /**门,窗,虚拟墙,元空间打开后两点的第二个坐标点*/
+    private Double secondY;
+    /**坐标点X*/
+    private Double destX;
+    /**坐标点Y*/
+    private Double destY;
+}

+ 36 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/domain/SpaceCalDTO.java

@@ -0,0 +1,36 @@
+package com.persagy.dmp.rwd.digital.domain;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.Data;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+@Data
+public class SpaceCalDTO {
+    /** 空间id */
+    private String spaceId;
+    /** 楼层id */
+    private String floorId;
+    /** 空间对象类型 */
+    private String classCode;
+    /** 楼层模型id */
+    private String floorModelId;
+    /** 集团编码 */
+    private String groupCode;
+    /** 项目id */
+    private String projectId;
+    /** 对象的bim点坐标 */
+    private ObjectNode bimLocation;
+    /** 对象的outline平面坐标 */
+    private List<LinkedHashMap<String,Object>> outLines;
+    /** 对象id */
+    private String id;
+    /** 模型文件id */
+    private String modelId;
+    /** 第一个点坐标 */
+    private ObjectNode firstPoint;
+    /** 第二个点坐标 */
+    private ObjectNode secondPoint;
+
+}

+ 491 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/service/calstrategy/SpaceConnectionRelCalculateServiceImpl.java

@@ -0,0 +1,491 @@
+package com.persagy.dmp.rwd.digital.service.calstrategy;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.math.MathUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.basic.dto.RelationCalRuleDTO;
+import com.persagy.dmp.basic.dto.SpaceConnectionCalDTO;
+import com.persagy.dmp.common.helper.SpringHelper;
+import com.persagy.dmp.digital.entity.ObjectRelation;
+import com.persagy.dmp.rwd.basic.utils.DigitalCommonUtils;
+import com.persagy.dmp.rwd.basic.utils.GeoToolsUtil;
+import com.persagy.dmp.rwd.digital.dao.ObjectDigitalMapper;
+import com.persagy.dmp.rwd.digital.dao.ObjectRelationMapper;
+import com.persagy.dmp.rwd.digital.domain.CalculatingDTO;
+import com.persagy.dmp.rwd.digital.domain.OpenPointDTO;
+import com.persagy.dmp.rwd.digital.domain.SpaceCalDTO;
+import com.persagy.dmp.rwd.digital.service.CalculateService;
+import com.persagy.dmp.rwd.digital.service.IObjectRelationService;
+import com.persagy.dmp.rwd.digital.utils.ObjectDigitalCriteriaHelper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/***
+ * Description: 空间连通关系计算
+ * @author : lijie
+ * @date :2021/10/9 16:26
+ * Update By lijie 2021/10/9 16:26
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SpaceConnectionRelCalculateServiceImpl implements CalculateService {
+
+    private final IObjectRelationService objectRelationService;
+    private final ObjectRelationMapper objectRelationMapper;
+    private final ObjectDigitalMapper objectDigitalMapper;
+
+
+    /***
+     * Description: 空间连通关系计算
+     * @param calRule : 计算规则
+     * @param calculatingDTO : 请求参数
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/9 16:26
+     * Update By lijie 2021/10/9 16:26
+     */
+    @Override
+    public void calculateRelation(RelationCalRuleDTO calRule, CalculatingDTO calculatingDTO) {
+        // 1.获取有所在楼层的所有业务空间, 并按照所在楼层和业务空间类型排序
+        List<SpaceCalDTO> spaceCalDTOS = objectRelationMapper.querySpacesByProjectId(calculatingDTO);
+        if (CollUtil.isEmpty(spaceCalDTOS)){
+            return;
+        }
+        // 1.1 获得[[space,space]]的二维数组
+        Map<String,List<SpaceCalDTO>> spaceMap = spaceCalDTOS.stream()
+                .collect(Collectors.groupingBy(spaceCalDTO -> spaceCalDTO.getFloorId()+StrUtil.UNDERLINE+spaceCalDTO.getClassCode()));
+
+        // 存储的关系列表
+        List<ObjectRelation> resultList = new ArrayList<>();
+        // 2.门的计算
+        calculateRelationInternal(resultList,spaceCalDTOS,calculatingDTO,spaceMap,"CFBEDR",
+                calRule.getSpaceConnectionCal().getDoorCalFlag());
+        // 3.窗的计算
+        calculateRelationInternal(resultList,spaceCalDTOS,calculatingDTO,spaceMap,"CFBEWN",
+                calRule.getSpaceConnectionCal().getWindowCalFlag());
+        // 4.虚拟墙的计算(暂时没有虚拟墙的概念,先置为false)
+        calculateRelationInternal(resultList,spaceCalDTOS,calculatingDTO,spaceMap,"CFBEXX",
+                calRule.getSpaceConnectionCal().getVirtualWindowCalFlag());
+        // 5.元空间的计算
+        ispaceCalculateRelationInternal(resultList,spaceCalDTOS,calculatingDTO,spaceMap,
+                calRule.getSpaceConnectionCal().getIspaceCalFlag());
+        if (CollUtil.isNotEmpty(resultList)){
+            // 3.根据图类型编码,边类型编码,relValue,项目id,集团编码删除关系
+            deleteRelDataByCondition(calculatingDTO);
+            // 4.新增关系
+            objectRelationService.saveBatch(resultList);
+        }
+    }
+    /***
+     * Description: 元空间的计算
+     * @param resultList : 结果集
+     * @param spaceCalDTOS : 空间数据
+     * @param calculatingDTO : 请求参数
+     * @param spaceMap:{floorId_classCode:空间对象}
+     * @param calFlag : 是否计算的标记
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/11 22:06
+     * Update By lijie 2021/10/11 22:06
+     */
+    private void ispaceCalculateRelationInternal(List<ObjectRelation> resultList, List<SpaceCalDTO> spaceCalDTOS,
+                                                 CalculatingDTO calculatingDTO,
+                                                 Map<String, List<SpaceCalDTO>> spaceMap,
+                                                 Boolean calFlag) {
+        if (!calFlag){
+            return;
+        }
+        // 1.根据modelId批量查询门
+        List<SpaceCalDTO> ispaces = objectDigitalMapper.queryIspacesByModelIds(spaceCalDTOS.stream()
+                .map(SpaceCalDTO::getFloorModelId).collect(Collectors.toSet()),calculatingDTO);
+        if (CollUtil.isEmpty(ispaces)){
+            return;
+        }
+        // 1.1 获得modelId和[door,door]的映射
+        Map<String, List<SpaceCalDTO>> ispaceMap = ispaces
+                .stream().collect(Collectors.groupingBy(SpaceCalDTO::getModelId));
+        // 2.根据空间分组及门的数据计算关系
+        Set<Map.Entry<String, List<SpaceCalDTO>>> entries = spaceMap.entrySet();
+        for (Map.Entry<String, List<SpaceCalDTO>> entry : entries) {
+            List<SpaceCalDTO> spaces = entry.getValue();
+            if (CollUtil.isEmpty(spaces) || spaces.size()<2){
+                continue;
+            }
+            SpaceCalDTO spaceCal = spaces.get(0);
+            if (!ispaceMap.containsKey(spaceCal.getFloorModelId())
+                    || CollUtil.isEmpty(ispaceMap.get(spaceCal.getFloorModelId()))){
+                continue;
+            }
+            List<SpaceCalDTO> subIspaces = ispaceMap.get(spaceCal.getFloorModelId());
+            List<String> relIds = new ArrayList<>();
+            for (SpaceCalDTO subIspace : subIspaces) {
+                List<LinkedHashMap<String, Object>> outLines = subIspace.getOutLines();
+                for (SpaceCalDTO space : spaces) {
+                    if (GeoToolsUtil.isPolyInPoly(space.getOutLines(),outLines)){
+                        relIds.add(space.getSpaceId());
+                    }
+                }
+                if (CollUtil.isNotEmpty(relIds)){
+                    for (int i = 0; i < relIds.size(); i++) {
+                        for (int j = 1; j < relIds.size(); j++) {
+                            if (relIds.get(i).equals(relIds.get(j))){
+                                continue;
+                            }
+                            resultList.add(createObjectRelation(calculatingDTO,spaceCal.getGroupCode(),
+                                    spaceCal.getProjectId(),relIds.get(i),relIds.get(j),spaceCal.getClassCode()));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /***
+     * Description: 通过门计算空间连通性
+     * @param resultList : 结果集
+     * @param spaceCalDTOS : 空间数据
+     * @param calculatingDTO : 请求参数
+     * @param spaceMap:{floorId_classCode:空间对象}
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/11 17:44
+     * Update By lijie 2021/10/11 17:44
+     */
+    private void calculateRelationInternal(List<ObjectRelation> resultList,
+                                       List<SpaceCalDTO> spaceCalDTOS,
+                                       CalculatingDTO calculatingDTO,
+                                       Map<String, List<SpaceCalDTO>> spaceMap,
+                                       String classCode,Boolean calFlag) {
+        if (!calFlag){
+            return;
+        }
+        // 1.根据modelId批量查询门
+        List<SpaceCalDTO> doors = objectDigitalMapper.queryEquipmentsByModelIds(spaceCalDTOS.stream()
+                .map(SpaceCalDTO::getFloorModelId).collect(Collectors.toSet()),calculatingDTO,classCode);
+        if (CollUtil.isEmpty(doors)){
+            return;
+        }
+        commonCalculateRelationInternal(doors,resultList,calculatingDTO,spaceMap);
+    }
+    /***
+     * Description: 通用计算空间连通性
+     * @param spaceCals : 空间数据
+     * @param resultList : 结果集
+     * @param calculatingDTO : 请求参数
+     * @param spaceMap:{floorId_classCode:空间对象}
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/11 21:51
+     * Update By lijie 2021/10/11 21:51
+     */
+    private void commonCalculateRelationInternal(List<SpaceCalDTO> spaceCals,
+                                                 List<ObjectRelation> resultList,
+                                                 CalculatingDTO calculatingDTO,
+                                                 Map<String, List<SpaceCalDTO>> spaceMap) {
+        // 1.1 获得modelId和[door,door]的映射
+        Map<String, List<SpaceCalDTO>> doorMap = spaceCals
+                .stream().collect(Collectors.groupingBy(SpaceCalDTO::getModelId));
+        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
+        // 2.根据空间分组及门的数据计算关系
+        Set<Map.Entry<String, List<SpaceCalDTO>>> entries = spaceMap.entrySet();
+        for (Map.Entry<String, List<SpaceCalDTO>> entry : entries) {
+            List<SpaceCalDTO> spaces = entry.getValue();
+            if (CollUtil.isEmpty(spaces) || spaces.size()<2){
+                continue;
+            }
+            SpaceCalDTO spaceCal = spaces.get(0);
+            if (!doorMap.containsKey(spaceCal.getFloorModelId())
+                    || CollUtil.isEmpty(doorMap.get(spaceCal.getFloorModelId()))){
+                continue;
+            }
+            // 2.1 遍历相同下的门
+            List<SpaceCalDTO> subDoors = doorMap.get(spaceCal.getFloorModelId());
+            for (SpaceCalDTO subDoor : subDoors) {
+                ObjectNode firstPoint = subDoor.getFirstPoint();
+                ObjectNode secondPoint = subDoor.getSecondPoint();
+                // 2.1.1 校验坐标点的值是否合法
+                if (!checkPointIsValid(firstPoint,secondPoint)){
+                    continue;
+                }
+                // 2.1.2 获得门打开后覆盖的坐标点
+                List<OpenPointDTO> openPoints = getOpenPoint(firstPoint,secondPoint);
+                if (CollUtil.isEmpty(openPoints)){
+                    continue;
+                }
+                List<String> relIds = new ArrayList<>();
+                // 2.1.3 通过门打开后的坐标点与空间关联性获得连通的空间数组
+                for (SpaceCalDTO space : spaces) {
+                    List<LinkedHashMap<String, Object>> outLines = space.getOutLines();
+                    for (OpenPointDTO openPoint : openPoints) {
+                        ObjectNode pointNode = objectMapper
+                                .createObjectNode()
+                                .put("X", openPoint.getDestX()).put("Y", openPoint.getDestY());
+                        if (GeoToolsUtil.isPointInPoly(pointNode,outLines)){
+                            relIds.add(space.getSpaceId());
+                            break;
+                        }
+                    }
+                    if (relIds.size()==2){
+                        break;
+                    }
+                }
+                // 2.1.4 生成关系
+                if (relIds.size()==2){
+                    resultList.add(createObjectRelation(calculatingDTO,spaceCal.getGroupCode(),
+                            spaceCal.getProjectId(),relIds.get(0),relIds.get(1),spaceCal.getClassCode()));
+                }
+            }
+        }
+    }
+
+    /***
+     * Description: 创建关系对象
+     * @return : com.persagy.dmp.digital.entity.ObjectRelation
+     * @author : lijie
+     * @date :2021/10/11 21:39
+     * Update By lijie 2021/10/11 21:39
+     * @param calculatingDTO :请求参数
+     * @param groupCode :集团编码
+     * @param projectId :项目id
+     * @param objFrom : objFrom
+     * @param objTo : objTo
+     * @param classCode: classCode
+     */
+    private ObjectRelation createObjectRelation(CalculatingDTO calculatingDTO, String groupCode,
+                                                String projectId, String objFrom, String objTo, String classCode) {
+        // 空间有相交的空间,说明两者竖井是连通的
+        ObjectRelation objectRelation = new ObjectRelation();
+        objectRelation.setGroupCode(groupCode);
+        objectRelation.setProjectId(projectId);
+        objectRelation.setGraphId(DigitalCommonUtils.getDefaultGraphIdByGraphCode(calculatingDTO.getGraphCode()));
+        objectRelation.setGraphCode(calculatingDTO.getGraphCode());
+        objectRelation.setRelCode(calculatingDTO.getRelCode());
+        objectRelation.setObjFrom(objFrom);
+        objectRelation.setObjTo(objTo);
+        objectRelation.setRelValue(classCode);
+        objectRelation.setCreateApp(calculatingDTO.getAppId());
+        objectRelation.setUpdateApp(calculatingDTO.getAppId());
+        objectRelation.setCreator(calculatingDTO.getAccountId());
+        objectRelation.setModifier(calculatingDTO.getAccountId());
+        objectRelation.setValid(1);
+        return objectRelation;
+    }
+
+    /***
+     * Description: 获得门,窗,虚拟墙,元空间打开后两点的坐标信息
+     * @param firstPoint : 第一个坐标点
+     * @param secondPoint : 第二个坐标点
+     * @return : com.persagy.dmp.rwd.digital.domain.OpenPointDTO
+     * @author : lijie
+     * @date :2021/10/11 20:19
+     * Update By lijie 2021/10/11 20:19
+     */
+    private List<OpenPointDTO> getOpenPoint(ObjectNode firstPoint, ObjectNode secondPoint) {
+        double deltaDistance = 200.0;
+        double doorLength = 1500.0;
+        double closedFirstX = NumberUtil.parseDouble(firstPoint.get("X").asText());
+        double closedFirstY = NumberUtil.parseDouble(firstPoint.get("Y").asText());
+        double closedSecondX = NumberUtil.parseDouble(secondPoint.get("X").asText());
+        double closedSecondY = NumberUtil.parseDouble(secondPoint.get("Y").asText());
+        // 1.计算两个坐标点的直线距离
+        double distance = getSegmentDistance(closedFirstX, closedFirstY, closedSecondX, closedSecondY);
+        // 2.计算该直线的斜率
+        Double k=null;
+        if(closedFirstX!=closedSecondX){
+            k=(closedFirstY-closedSecondY)/(closedFirstX-closedSecondX);
+        }
+        // 2.1 获得垂直线的斜率
+        Double verticalK = getVerticalK(k);
+        // 2.2 获得当前直线的a
+        Double closedA = getAByPointAndK(closedFirstX,closedFirstY,k);
+        List<OpenPointDTO> result = new ArrayList<>();
+        if (distance>deltaDistance){
+            // 距离大于delta_distance, 则足够开两个门
+            OpenPointDTO firstSegOpenPoint = getPointByDistanceOnSegment(closedFirstX,closedFirstY,
+                    k,closedA,deltaDistance,closedSecondX,closedSecondY);
+            OpenPointDTO secondSegOpenPoint = getPointByDistanceOnSegment(closedSecondX,closedSecondY,
+                    k,closedA,deltaDistance,closedFirstX,closedFirstY);
+            Double firstA = getAByPointAndK(firstSegOpenPoint.getDestX(), firstSegOpenPoint.getDestY(), verticalK);
+            Double secondA = getAByPointAndK(secondSegOpenPoint.getDestX(), secondSegOpenPoint.getDestY(), verticalK);
+            OpenPointDTO firstDistance = getPointByDistance(firstSegOpenPoint.getDestX(), firstSegOpenPoint.getDestY(), verticalK, firstA, doorLength);
+            OpenPointDTO secondDistance = getPointByDistance(secondSegOpenPoint.getDestX(), secondSegOpenPoint.getDestY(), verticalK, secondA, doorLength);
+            result.add(OpenPointDTO.builder().destX(firstDistance.getFirstX()).destY(firstDistance.getFirstY()).build());
+            result.add(OpenPointDTO.builder().destX(firstDistance.getSecondX()).destY(firstDistance.getSecondY()).build());
+            result.add(OpenPointDTO.builder().destX(secondDistance.getFirstX()).destY(secondDistance.getFirstY()).build());
+            result.add(OpenPointDTO.builder().destX(secondDistance.getSecondX()).destY(secondDistance.getSecondY()).build());
+            return result;
+        }
+        // 中间开门
+        OpenPointDTO openPoint = getPointByDistanceOnSegment(closedFirstX, closedFirstY,
+                k, closedA, distance / 2, closedSecondX, closedSecondY);
+        Double verticalA = getAByPointAndK(openPoint.getDestX(), openPoint.getDestY(), verticalK);
+        OpenPointDTO firstDistance = getPointByDistance(openPoint.getDestX(), openPoint.getDestY(), verticalK, verticalA, doorLength);
+        result.add(OpenPointDTO.builder().destX(firstDistance.getFirstX()).destY(firstDistance.getFirstY()).build());
+        result.add(OpenPointDTO.builder().destX(firstDistance.getSecondX()).destY(firstDistance.getSecondY()).build());
+        return result;
+    }
+    /***
+     * Description: 根据距离和坐标点计算打开后的坐标点
+     * @param baseX : 第一个坐标点的Y值
+     * @param baseY : 第一个坐标点的Y值
+     * @param k : 斜率
+     * @param a : a值
+     * @param distance : 距离
+     * @param vecX : 第二个坐标点的X值
+     * @param vecY : 第二个坐标点的Y值
+     * @return : com.persagy.dmp.rwd.digital.domain.OpenPointDTO
+     * @author : lijie
+     * @date :2021/10/11 20:54
+     * Update By lijie 2021/10/11 20:54
+     */
+    private OpenPointDTO getPointByDistanceOnSegment(double baseX, double baseY,
+                                                     Double k, Double a,
+                                                     double distance,
+                                                     double vecX,
+                                                     double vecY) {
+        OpenPointDTO openPoint = getPointByDistance(baseX,baseY,k,a,distance);
+        Double distanceOne = getSegmentDistance(openPoint.getFirstX(), openPoint.getFirstY(), vecX, vecY);
+        Double distanceTwo = getSegmentDistance(openPoint.getSecondX(), openPoint.getSecondY(), vecX, vecY);
+        if (distanceOne>distanceTwo){
+            return OpenPointDTO.builder().destX(openPoint.getSecondX()).destY(openPoint.getSecondY()).build();
+        }
+        return OpenPointDTO.builder().destX(openPoint.getFirstX()).destY(openPoint.getFirstY()).build();
+    }
+    /***
+     * Description: 根据坐标和线段长度计算坐标点
+     * @param baseX : x值
+     * @param baseY : y值
+     * @param k : 斜率
+     * @param a : a值
+     * @param distance : 距离
+     * @return : com.persagy.dmp.rwd.digital.domain.OpenPointDTO
+     * @author : lijie
+     * @date :2021/10/11 20:58
+     * Update By lijie 2021/10/11 20:58
+     */
+    private OpenPointDTO getPointByDistance(double baseX, double baseY, Double k, Double a, double distance) {
+        if (null==k){
+            return OpenPointDTO.builder()
+                    .firstX(baseX)
+                    .firstY(baseY+distance)
+                    .secondX(baseX)
+                    .secondY(baseY-distance).build();
+        }
+        double vectorX1 = Math.sqrt(distance*distance/(1+k*k));
+        double vectorX2 = -vectorX1;
+        double vectorY1 = k*vectorX1+a;
+        double vectorY2 = k*vectorX2+a;
+        return OpenPointDTO.builder()
+                .firstX(baseX+vectorX1)
+                .firstY(baseY+vectorY1)
+                .secondX(baseX+vectorX2)
+                .secondY(baseY+vectorY2).build();
+    }
+
+    /***
+     * Description: 获得直线方程式中的a值(y=kx+a)
+     * @param x : x坐标值
+     * @param y : y坐标值
+     * @param k : 斜率
+     * @return : java.lang.Double
+     * @author : lijie
+     * @date :2021/10/11 20:34
+     * Update By lijie 2021/10/11 20:34
+     */
+    private Double getAByPointAndK(double x, double y, Double k) {
+        if (null==k){
+            return 0.0;
+        }
+        return y-k*x;
+    }
+
+    /***
+     * Description: 获得垂直线的斜率
+     * @param k : 斜率
+     * @return : java.lang.Double
+     * @author : lijie
+     * @date :2021/10/11 20:31
+     * Update By lijie 2021/10/11 20:31
+     */
+    private Double getVerticalK(Double k) {
+        if (null==k){
+            return 0.0;
+        }
+        if (0.0==k){
+            return null;
+        }
+        return 1/k;
+    }
+
+    /***
+     * Description: 计算两个坐标点之间的距离
+     * @param firstX : 第一个坐标点的x值
+     * @param firstY : 第一个坐标点的Y值
+     * @param secondX : 第二个坐标点的x值
+     * @param secondY : 第二个坐标点的y值
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/11 20:24
+     * Update By lijie 2021/10/11 20:24
+     */
+    private Double getSegmentDistance(Double firstX, Double firstY, Double secondX, Double secondY) {
+        double xDistance = firstX - secondX;
+        double yDistance = firstY - secondY;
+        return Math.sqrt(xDistance*xDistance+yDistance*yDistance);
+    }
+
+    /***
+     * Description: 校验两个坐标点是否合理
+     * @param firstPoint : 第一个坐标点
+     * @param secondPoint : 第二个坐标点
+     * @return : boolean
+     * @author : lijie
+     * @date :2021/10/11 20:06
+     * Update By lijie 2021/10/11 20:06
+     */
+    private Boolean checkPointIsValid(ObjectNode firstPoint, ObjectNode secondPoint) {
+        // 1.校验是否为空
+        if (null==firstPoint
+                || null==secondPoint
+                || !firstPoint.has("X")
+                || !firstPoint.has("Y")
+                || !secondPoint.has("X")
+                || !secondPoint.has("Y")){
+            return false;
+        }
+        // 2.校验是否为数字
+        if (!NumberUtil.isNumber(firstPoint.get("X").asText())
+                || !NumberUtil.isNumber(firstPoint.get("Y").asText())
+                || !NumberUtil.isNumber(secondPoint.get("X").asText())
+                || !NumberUtil.isNumber(secondPoint.get("Y").asText())){
+            return false;
+        }
+        // 3.校验坐标点是否相等
+        return firstPoint.get("X").equals(secondPoint.get("X")) && firstPoint.get("Y").equals(secondPoint.get("Y"));
+    }
+
+    /***
+     * Description: 根据请求参数和id集合删除关系
+     * @param calculatingDTO : 请求参数
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/11 16:13
+     * Update By lijie 2021/9/11 16:13
+     */
+    private void deleteRelDataByCondition(CalculatingDTO calculatingDTO) {
+        QueryWrapper<ObjectRelation> queryWrapper = ObjectDigitalCriteriaHelper.createCommonQueryWrapper(null,calculatingDTO);
+        queryWrapper.eq(StrUtil.toUnderlineCase(ObjectRelation.GRAPH_CODE_HUM),calculatingDTO.getGraphCode());
+        queryWrapper.eq(StrUtil.toUnderlineCase(ObjectRelation.REL_CODE_HUM),calculatingDTO.getRelCode());
+        objectRelationService.remove(queryWrapper);
+    }
+}

+ 63 - 0
dmp-business/dmp-rwd/src/main/resources/mapper/ObjectDigitalMapper.xml

@@ -24,6 +24,7 @@
             <result property="modifiedTime" column="modified_time" jdbcType="CHAR"/>
             <result property="valid" column="valid" jdbcType="TINYINT"/>
             <result property="ts" column="ts" jdbcType="TIMESTAMP"/>
+            <result property="modelId" column="modelId" jdbcType="VARCHAR"/>
             <result property="objFromIds" column="objFromIds" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
             <result property="objToIds" column="objToIds" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
             <result property="relObjs" column="relObjs" jdbcType="VARCHAR"  typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
@@ -577,6 +578,68 @@
         GROUP BY
             dto.id;
     </select>
+    <resultMap id="SpaceCalResultMap" type="com.persagy.dmp.rwd.digital.domain.SpaceCalDTO">
+        <id property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="modelId" column="modelId" jdbcType="VARCHAR"/>
+        <result property="firstPoint" column="firstPoint" jdbcType="VARCHAR"  typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+        <result property="secondPoint" column="secondPoint" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+        <result property="outLines" column="outLines" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+    </resultMap>
+    <select id="queryEquipmentsByModelIds" resultMap="SpaceCalResultMap">
+        SELECT
+            id,
+            JSON_UNQUOTE(JSON_EXTRACT( dto.infos, '$.modelId' )) AS modelId,
+            JSON_UNQUOTE(JSON_EXTRACT(JSON_UNQUOTE(JSON_EXTRACT(infos, '$.outline')), '$[0][0]')) AS firstPoint,
+            JSON_UNQUOTE(JSON_EXTRACT(JSON_UNQUOTE(JSON_EXTRACT(infos, '$.outline')), '$[1][0]')) AS secondPoint
+        FROM
+            dt_object AS dto
+        WHERE
+            JSON_EXTRACT( dto.infos, '$.outline' ) IS NOT NULL
+          AND JSON_EXTRACT( dto.infos, '$.modelId' ) IS NOT NULL
+          AND dto.obj_type = 'equipment'
+          AND dto.valid=TRUE
+        <if test="null!=param.groupCode and param.groupCode.length>0">
+            AND dto.group_code = #{param.groupCode}
+        </if>
+        <if test="null!=param.projectId and param.projectId.length>0">
+            AND dto.project_id = #{param.projectId}
+        </if>
+        <if test="null!=classCode and classCode.length>0">
+            AND dto.class_code = #{classCode}
+        </if>
+        <if test="null!=objIds and objIds.size()>0">
+            <foreach collection="objIds" open="AND JSON_EXTRACT( dto.infos, '$.modelId' ) IN (" close=")" separator="," item="objId">
+                #{objId}
+            </foreach>
+        </if>
+        ;
+    </select>
+    <select id="queryIspacesByModelIds" resultMap="SpaceCalResultMap">
+        SELECT
+        id,
+        JSON_UNQUOTE(JSON_EXTRACT( dto.infos, '$.modelId' )) AS modelId,
+        JSON_UNQUOTE(JSON_EXTRACT(JSON_UNQUOTE(JSON_EXTRACT(infos, '$.outline')), '$[0][*]')) AS outLines
+        FROM
+        dt_object AS dto
+        WHERE
+        JSON_EXTRACT( dto.infos, '$.outline' ) IS NOT NULL
+        AND JSON_EXTRACT( dto.infos, '$.modelId' ) IS NOT NULL
+        AND dto.obj_type = 'ispace'
+        AND dto.class_code = 'ispace'
+        AND dto.valid=TRUE
+        <if test="null!=param.groupCode and param.groupCode.length>0">
+            AND dto.group_code = #{param.groupCode}
+        </if>
+        <if test="null!=param.projectId and param.projectId.length>0">
+            AND dto.project_id = #{param.projectId}
+        </if>
+        <if test="null!=objIds and objIds.size()>0">
+            <foreach collection="objIds" open="AND JSON_EXTRACT( dto.infos, '$.modelId' ) IN (" close=")" separator="," item="objId">
+                #{objId}
+            </foreach>
+        </if>
+        ;
+    </select>
 
 
 </mapper>

+ 72 - 0
dmp-business/dmp-rwd/src/main/resources/mapper/ObjectRelationMapper.xml

@@ -354,7 +354,79 @@
           AND JSON_LENGTH(JSON_UNQUOTE( JSON_EXTRACT( JSON_UNQUOTE( JSON_EXTRACT( dto.infos, '$.outline' ) ), '$[0][0][*]' ) )) >= 4
     </select>
 
+    <resultMap id="SpaceCalResultMap" type="com.persagy.dmp.rwd.digital.domain.SpaceCalDTO">
+        <id property="spaceId" column="spaceId" jdbcType="VARCHAR"/>
+        <result property="floorId" column="floorId" jdbcType="VARCHAR"/>
+        <result property="floorModelId" column="floorModelId" jdbcType="VARCHAR"/>
+        <result property="groupCode" column="groupCode" jdbcType="VARCHAR"/>
+        <result property="projectId" column="projectId" jdbcType="VARCHAR"/>
+        <result property="classCode" column="classCode" jdbcType="VARCHAR"/>
+        <result property="bimLocation" column="bimLocation" jdbcType="VARCHAR"  typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+        <result property="outLines" column="outLines" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+    </resultMap>
 
+    <select id="querySpacesByProjectId" resultMap="SpaceCalResultMap">
+        SELECT
+            floor.id AS floorId,
+            space.id AS spaceId,
+            space.class_code AS classCode,
+            JSON_UNQUOTE(JSON_EXTRACT(floor.infos, '$.modelId')) AS floorModelId,
+            space.group_code AS groupCode,
+            space.project_id AS projectId,
+            JSON_UNQUOTE( JSON_EXTRACT( JSON_UNQUOTE( JSON_EXTRACT( space.infos, '$.outline' ) ), '$[0][0][*]' ) ) AS outLines,
+            JSON_OBJECT(
+                    'X',
+                    JSON_EXTRACT(
+                            JSON_UNQUOTE(
+                                    CONCAT(
+                                            '[',
+                                            SUBSTRING( JSON_EXTRACT( space.infos, '$.bimLocation' ) FROM 2 FOR LENGTH( JSON_EXTRACT( space.infos, '$.bimLocation' ) ) - 2 ),
+                                            ']'
+                                        )
+                                ),
+                            '$[0]'
+                        ),
+                    'Y',
+                    JSON_EXTRACT(
+                            JSON_UNQUOTE(
+                                    CONCAT(
+                                            '[',
+                                            SUBSTRING( JSON_EXTRACT( space.infos, '$.bimLocation' ) FROM 2 FOR LENGTH( JSON_EXTRACT( space.infos, '$.bimLocation' ) ) - 2 ),
+                                            ']'
+                                        )
+                                ),
+                            '$[1]'
+                        ),
+                    'Z',
+                    JSON_EXTRACT(
+                            JSON_UNQUOTE(
+                                    CONCAT(
+                                            '[',
+                                            SUBSTRING( JSON_EXTRACT( space.infos, '$.bimLocation' ) FROM 2 FOR LENGTH( JSON_EXTRACT( space.infos, '$.bimLocation' ) ) - 2 ),
+                                            ']'
+                                        )
+                                ),
+                            '$[2]'
+                        )
+                ) AS bimLocation
+        FROM
+            dt_object AS space
+                INNER JOIN dt_relation AS dtr ON ( space.id = dtr.obj_to AND dtr.graph_code = 'ArchSubset' AND dtr.rel_code = 'Fl2Sp' AND dtr.valid = TRUE )
+                INNER JOIN dt_object AS floor ON floor.id = dtr.obj_from
+        WHERE
+          space.valid=TRUE
+          AND floor.valid = TRUE
+          AND space.obj_type = 'space'
+          AND JSON_EXTRACT( space.infos, '$.outline' ) IS NOT NULL
+          AND JSON_EXTRACT( floor.infos, '$.modelId' ) IS NOT NULL
+          AND JSON_VALID(JSON_EXTRACT( space.infos, '$.outline' ))
+        <if test="null!=param.groupCode and param.groupCode.length>0">
+            AND space.group_code = #{param.groupCode}
+        </if>
+        <if test="null!=param.projectId and param.projectId.length>0">
+            AND space.project_id = #{param.projectId}
+        </if>
+    </select>
 
 
 </mapper>

+ 10 - 1
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/dto/RelationCalRuleDTO.java

@@ -12,7 +12,14 @@ import java.util.List;
  */
 @Data
 public class RelationCalRuleDTO {
-    /**计算规则类型,1-通过关系链计算,2-通过平面图坐标计算,3-通过对象+已存在的关系数据进行计算,4-楼层连通关系计算,5-竖井连通关系计算*/
+    /**计算规则类型,
+     * 1-通过关系链计算,
+     * 2-通过平面图坐标计算,
+     * 3-通过对象+已存在的关系数据进行计算,
+     * 4-楼层连通关系计算,
+     * 5-竖井连通关系计算,
+     * 6-空间连通关系计算
+     * */
     private String calRuleType;
     /**计算规则类型为1时的关系计算链*/
     private List<RelationCalDTO> dependentRelChain;
@@ -20,6 +27,8 @@ public class RelationCalRuleDTO {
     private CoordinateCalInfo graphCalInfo;
     /**计算规则类型为3时的计算器*/
     private RelExtendCalDTO relExtendCal;
+    /**计算规则类型为6时的计算器*/
+    private SpaceConnectionCalDTO spaceConnectionCal;
 
 
 

+ 15 - 0
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/dto/SpaceConnectionCalDTO.java

@@ -0,0 +1,15 @@
+package com.persagy.dmp.basic.dto;
+
+import lombok.Data;
+
+@Data
+public class SpaceConnectionCalDTO {
+    /**是否根据门参与计算,true-参与计算,false-不参与计算*/
+    private Boolean doorCalFlag=false;
+    /**是否根据窗户参与计算,true-参与计算,false-不参与计算*/
+    private Boolean windowCalFlag=false;
+    /**是否根据虚拟墙参与计算,true-参与计算,false-不参与计算*/
+    private Boolean virtualWindowCalFlag=false;
+    /**是否根据元空间参与计算,true-参与计算,false-不参与计算*/
+    private Boolean ispaceCalFlag=false;
+}

+ 3 - 0
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/digital/entity/ObjectDigital.java

@@ -93,6 +93,9 @@ public class ObjectDigital extends AuditableEntity {
     /** CADID */
     @TableField(exist = false)
     private String cadId;
+    /** 模型id */
+    @TableField(exist = false)
+    private String modelId;
     /** 关联的对象列表 */
     @TableField(exist = false,typeHandler = JacksonTypeHandler.class)
     private List<ObjectDigital> relObjs;