package com.persagy.bdtp.adm.service.impl; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import com.persagy.bdtp.adm.common.AdmConst; import com.persagy.bdtp.adm.dao.AdmJobSpaceMapper; import com.persagy.bdtp.adm.entity.Pagination; import com.persagy.bdtp.adm.entity.db.AdmJobSpace; import com.persagy.bdtp.adm.entity.db.AdmObject; import com.persagy.bdtp.adm.service.ISyncSpace; import com.persagy.bdtp.adm.service.ServiceUtil; import com.persagy.bdtp.adm.util.GeomUtil; import com.persagy.dmp.basic.model.QueryCriteria; import com.persagy.dmp.common.constant.ValidEnum; import com.persagy.dmp.digital.client.DigitalObjectClient; import org.locationtech.jts.geom.Polygon; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.*; @Service public class SyncSpaceImpl implements ISyncSpace { @Autowired private ObjectMapper objectMapper; @Autowired private DigitalObjectClient objectClient; @Autowired private AdmJobSpaceMapper jobSpaceMapper; @Override @Transactional(rollbackFor = Exception.class) public Map sync(String groupCode, String projectId, String userId, String floorId, String zone) { if(StrUtil.isBlank(floorId)) floorId = null; //查询bdtp的空间数据 QueryCriteria criteria = ServiceUtil.getQueryCriteria(objectMapper, AdmConst.OBJ_TYPE_SPACE); criteria.getCriteria().put("classCode", zone); //默认工作空间为物业分区 //按楼层查询 if (floorId != null) { ObjectNode rt = criteria.getCriteria().putObject("relationTo"); rt.put("graphCode", "ArchSubset"); rt.put("relCode", "Fl2Sp"); rt.put("objFrom", floorId); } List spList = ServiceUtil.queryAllPage(() -> objectClient.query(groupCode, projectId, AdmConst.APP_ID, userId, criteria), criteria, new Pagination(500)); List toCreate = new ArrayList<>(); List toModify = new ArrayList<>(); if(floorId == null){ HashMap> floorMap = new HashMap<>(); for(ObjectNode sp : spList) { JsonNode fId = sp.get("floorId"); if(fId != null) { String flId = fId.asText(); List flSps = floorMap.get(flId); if(flSps == null) floorMap.put(flId, flSps = new ArrayList<>()); flSps.add(sp); } } for (Map.Entry> entry : floorMap.entrySet()) { syncByFloor(projectId, entry.getKey(), entry.getValue(), toCreate, toModify); } } else { syncByFloor(projectId, floorId, spList, toCreate, toModify); } String time = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN); for(AdmJobSpace job : toCreate) { job.setCreationTime(time); job.setCreator(AdmConst.CREATOR_SYNC); jobSpaceMapper.insert(job); } for(AdmJobSpace job : toModify) { job.setModifiedTime(time); job.setModifier(AdmConst.CREATOR_SYNC); jobSpaceMapper.updateById(job); } HashMap rtn = new HashMap<>(); rtn.put("syncSpaces", toCreate.size() + toModify.size()); return rtn; } private void syncByFloor(String projectId, String floorId, List spList, List toCreate, List toModify){ //查询任务空间数据 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("project_id", projectId).eq("floor_id", floorId).eq("valid", ValidEnum.TRUE.getType()); List jobSpaceList = jobSpaceMapper.selectList(wrapper); HashMap jobMap = new HashMap<>(jobSpaceList.size()); jobSpaceList.forEach(job -> jobMap.put(job.getBimId() != null ? job.getBimId() : job.getSpaceId(), job)); //同步操作 for(ObjectNode sp : spList){ String spId = sp.get("id").asText(); String bimId = sp.get("bimId") != null ? sp.get("bimId").asText() : null; ArrayNode spOutline = null; Object o1 = sp.get("outline"); if(o1 instanceof TextNode) { try { spOutline = objectMapper.readValue(((TextNode) o1).asText().toLowerCase(), ArrayNode.class); //暂时toLowerCase()处理 } catch (IOException e) { } } if(!GeomUtil.checkPolygon(spOutline)) continue; AdmJobSpace job = jobMap.remove(bimId != null ? bimId : spId); if(job != null) { //id匹配 boolean change = false; //轮廓变化的空间,重置任务状态 if(!outlineMatch(job.getOutline(), spOutline)){ job.setArchState(AdmConst.JOB_STATE_PROCESSING); job.setEquipState(AdmConst.JOB_STATE_PROCESSING); job.setOutline(spOutline); change = true; } //重置空间id if(!Objects.equals(spId, job.getSpaceId()) || !Objects.equals(bimId, job.getBimId())) { job.setBimId(bimId); job.setSpaceId(spId); change = true; } //轮廓和空间id都一致的,不需要做处理 if(change) toModify.add(job); } else { //bimId未匹配 job = matchByOutline(jobMap, sp); if(job != null) { //轮廓完全一致的任务空间,重新设置bimId和spaceId job.setBimId(bimId); job.setSpaceId(spId); toModify.add(job); } } if (job == null) { job = new AdmJobSpace(); job.setId(IdUtil.fastSimpleUUID()); job.setSpaceId(spId); job.setBimId(bimId); job.setOutline(spOutline); job.setArchState(AdmConst.JOB_STATE_PROCESSING); job.setEquipState(AdmConst.JOB_STATE_PROCESSING); job.setProjectId(projectId); job.setBuildingId(sp.get("buildingId").asText()); job.setFloorId(floorId != null ? floorId : sp.get("floorId").asText()); job.setValid(ValidEnum.TRUE.getType()); toCreate.add(job); } } //未找到匹配关系的任务空间,删除 for(AdmJobSpace job : jobMap.values()){ job.setValid(ValidEnum.FALSE.getType()); toModify.add(job); } } @Override public Map sync(String groupCode, String projectId, String userId, String zone) { return sync(groupCode, projectId, userId, null, zone); } private AdmJobSpace matchByOutline(HashMap jobMap, ObjectNode space){ if(jobMap.size() == 0) return null; ArrayNode o1 = (ArrayNode) space.get("outline"); if(!isValidOutline(o1)) return null; Polygon[] ps = GeomUtil.getPolygon(o1); Map.Entry target = null; for(Map.Entry entry : jobMap.entrySet()){ ArrayNode o2 = entry.getValue().getOutline(); if(isValidOutline(o2) && polygonsMatch(ps, GeomUtil.getPolygon(o2))){ target = entry; break; } } if(target != null){ jobMap.remove(target.getKey()); return target.getValue(); } return null; } /** * 判断空间轮廓是否变化 * TODO 区分覆盖等情况 */ private boolean outlineMatch(ArrayNode o1, ArrayNode o2){ return polygonsMatch(GeomUtil.getPolygon(o1), GeomUtil.getPolygon(o2)); } /** * 轮廓匹配判断 * TODO 暂不考虑顺序 */ private boolean polygonsMatch(Polygon[] ps1, Polygon[] ps2){ if (ps1.length == ps2.length) { for (int i = 0; i < ps2.length; i++) { if (!ps1[i].equalsExact(ps2[i])) return false; } return true; } return false; } private boolean isValidOutline(ArrayNode outline) { if(outline != null && outline.size() > 0 && outline.get(0).isArray()) { ArrayNode o1 = (ArrayNode) outline.get(0); if (o1.size() > 0 && o1.get(0).isArray()) { ArrayNode o2 = (ArrayNode) o1.get(0); return o2.size() >= 3; } } return false; } }