|
@@ -0,0 +1,484 @@
|
|
|
+package com.fdkankan.indoor.core.service.impl;
|
|
|
+
|
|
|
+import com.fdkankan.indoor.base.constant.ConfigConstant;
|
|
|
+import com.fdkankan.indoor.base.constant.MsgCode;
|
|
|
+import com.fdkankan.indoor.base.constant.TypeConstant;
|
|
|
+import com.fdkankan.indoor.base.convert.ConvertToVision;
|
|
|
+import com.fdkankan.indoor.base.convert.ModifyCloud;
|
|
|
+import com.fdkankan.indoor.base.convert.ModifyDataSets;
|
|
|
+import com.fdkankan.indoor.base.exception.BaseRuntimeException;
|
|
|
+import com.fdkankan.indoor.base.util.Result;
|
|
|
+import com.fdkankan.indoor.core.entity.*;
|
|
|
+import com.fdkankan.indoor.core.entity.dto.FilterHotDto;
|
|
|
+import com.fdkankan.indoor.core.entity.dto.SiteDto;
|
|
|
+import com.fdkankan.indoor.core.entity.dto.SitePolygon;
|
|
|
+import com.fdkankan.indoor.core.entity.merge.MergeDateSetDto;
|
|
|
+import com.fdkankan.indoor.core.entity.po.DataSetPo;
|
|
|
+import com.fdkankan.indoor.core.service.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import net.sf.json.JSONArray;
|
|
|
+import net.sf.json.JSONObject;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Created by owen on 2021/8/25 0025 10:59
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class MergeSceneServiceImpl extends IBaseServiceImpl implements MergeSceneService {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ DataSetService dataSetService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ FilterService filterService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ SiteModelService siteModelService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ SpecialPointService specialPointService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ ConvertToVision convertToVision;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ ControlPointService controlPointService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ ConfigConstant configConstant;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ InitService initService;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 目前只支持没有合并过的场景
|
|
|
+ * @param sceneCode
|
|
|
+ * @param mergeCode
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Result merge(String sceneCode, String mergeCode) {
|
|
|
+
|
|
|
+ ControlPointEntity controlPoint = controlPointService.findById(sceneCode);
|
|
|
+
|
|
|
+ String mergePath = "";
|
|
|
+
|
|
|
+ if ("dev".equals(configConstant.active)) {
|
|
|
+ mergePath = configConstant.serverBasePath + "/" + mergeCode + "/laserData";
|
|
|
+ } else {
|
|
|
+ mergePath = redisPath(mergeCode) + "/laserData";
|
|
|
+ }
|
|
|
+ log.info("合并场景路径:{}", mergePath);
|
|
|
+
|
|
|
+ // siteMode要优先处理;
|
|
|
+ Map<Object, Object> resMap = mergeSiteModel(sceneCode, mergeCode, mergePath, controlPoint);
|
|
|
+
|
|
|
+ Integer maxId = (Integer)resMap.get("maxId");
|
|
|
+
|
|
|
+ // dateSet.siteModelId是数组
|
|
|
+ List<Integer> siteModeIds = (List<Integer>)resMap.get("ids");
|
|
|
+ mergeDateSet(sceneCode, mergeCode, siteModeIds);
|
|
|
+
|
|
|
+
|
|
|
+ mergeFilter(sceneCode, mergeCode, controlPoint, mergePath, maxId);
|
|
|
+
|
|
|
+
|
|
|
+ return Result.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void mergeDateSet(String sceneCode, String mergeCode, List<Integer> siteModeIds){
|
|
|
+
|
|
|
+ // 获取原场景数据
|
|
|
+ DataSetEntity entity = dataSetService.findById(sceneCode);
|
|
|
+ if (entity == null) {
|
|
|
+ throw new BaseRuntimeException("原dataSet数据不存在: " + sceneCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<DataSetPo> originalData = entity.getData();
|
|
|
+
|
|
|
+
|
|
|
+ Integer originalMaxId = 0;
|
|
|
+ // 获取原场景数据最大id
|
|
|
+ if (originalData.size() != 0) {
|
|
|
+ Optional<DataSetPo> max = originalData.stream().max(Comparator.comparingInt(DataSetPo::getId));
|
|
|
+ originalMaxId = max.get().getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新添加数据
|
|
|
+ MergeDateSetDto mergeDto = new MergeDateSetDto();
|
|
|
+ mergeDto.setId(originalMaxId + 1);
|
|
|
+ // 使用场景码
|
|
|
+ mergeDto.setName(mergeCode);
|
|
|
+ mergeDto.setTitle(mergeCode);
|
|
|
+ // new Integer[0]:实例化一个Integer类的对象,并给该对象附值为0
|
|
|
+ mergeDto.setSite_model_entity_ids(siteModeIds.toArray(new Integer[0]));
|
|
|
+
|
|
|
+
|
|
|
+ List<DataSetPo> dataSetPos = initMergeDataSet(sceneCode, mergeDto);
|
|
|
+
|
|
|
+ // 添加数据
|
|
|
+ originalData.addAll(dataSetPos);
|
|
|
+
|
|
|
+ entity.setData(originalData);
|
|
|
+
|
|
|
+ dataSetService.save(entity);
|
|
|
+ log.info("dataSet合并完成");
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void mergeFilter(String sceneCode, String mergeCode, ControlPointEntity controlPoint, String mergePath, Integer newSiteModelId){
|
|
|
+
|
|
|
+
|
|
|
+ // 获取原场景数据
|
|
|
+ FilterEntity entity = filterService.findBySceneCode(sceneCode);
|
|
|
+ if (entity == null) {
|
|
|
+ throw new BaseRuntimeException("原Filter数据不存在: " + sceneCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<FilterHotDto> originalData = entity.getData();
|
|
|
+
|
|
|
+
|
|
|
+ Integer originalMaxId = 0;
|
|
|
+ // 获取原场景数据最大id
|
|
|
+ if (originalData.size() != 0) {
|
|
|
+ Optional<FilterHotDto> max = originalData.stream().max(Comparator.comparingInt(FilterHotDto::getId));
|
|
|
+ originalMaxId = max.get().getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取合并的场景码数据
|
|
|
+ List<FilterHotDto> mergeData = initMergeFilter(mergeCode, mergePath, controlPoint);
|
|
|
+
|
|
|
+
|
|
|
+ for (FilterHotDto merge : mergeData) {
|
|
|
+ originalMaxId ++;
|
|
|
+ log.info("处理后maxId: {}", originalMaxId);
|
|
|
+ merge.setId(originalMaxId);
|
|
|
+
|
|
|
+ // todo 使用场景码作为路径
|
|
|
+ merge.setFile_path("data/" + mergeCode);
|
|
|
+ merge.setSite_model_entity_id(newSiteModelId);
|
|
|
+ // 添加数据
|
|
|
+ originalData.add(merge);
|
|
|
+ }
|
|
|
+
|
|
|
+ entity.setData(originalData);
|
|
|
+
|
|
|
+ filterService.save(entity);
|
|
|
+ log.info("filter合并完成");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private Map<Object, Object> mergeSiteModel(String sceneCode, String mergeCode, String mergePath, ControlPointEntity controlPoint){
|
|
|
+
|
|
|
+ // 获取原场景数据
|
|
|
+ SiteModelEntity entity = siteModelService.findById(sceneCode);
|
|
|
+ if (entity == null) {
|
|
|
+ throw new BaseRuntimeException("原SiteModel数据不存在: " + sceneCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<SiteDto> originalData = entity.getData();
|
|
|
+
|
|
|
+
|
|
|
+ // 初始化房间数据
|
|
|
+ SiteDto roomDto = initMergeSiteModel(mergeCode, mergePath,controlPoint);
|
|
|
+
|
|
|
+ // 添加数据
|
|
|
+ Map<Object, Object> resMap = setRoom(originalData, roomDto);
|
|
|
+ originalData = (List<SiteDto>) resMap.get("data");
|
|
|
+
|
|
|
+
|
|
|
+ // 添加数据
|
|
|
+
|
|
|
+ entity.setData(originalData);
|
|
|
+ entity.setUpdateTime(LocalDateTime.now());
|
|
|
+
|
|
|
+ siteModelService.save(entity);
|
|
|
+ log.info("siteModel合并完成");
|
|
|
+
|
|
|
+ return resMap;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param dto 原数据
|
|
|
+ * @param roomDto 需要加入的房间
|
|
|
+ */
|
|
|
+ private Map<Object, Object> setRoom(List<SiteDto> dto, SiteDto roomDto) {
|
|
|
+ // 用来获取最大id
|
|
|
+ List<Integer> ids = new ArrayList<>();
|
|
|
+ dto.forEach(p -> {
|
|
|
+ ids.add(p.getId());
|
|
|
+ List<SiteDto> floorChild = p.getChildren();
|
|
|
+ floorChild.forEach(f -> {
|
|
|
+ ids.add(f.getId());
|
|
|
+
|
|
|
+ List<SiteDto> roomChild = f.getChildren();
|
|
|
+ roomChild.forEach(r -> {
|
|
|
+ ids.add(r.getId());
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取最大id
|
|
|
+ Integer maxId = ids.stream().reduce(Integer::max).get();
|
|
|
+ log.info("最大id: {}" , maxId);
|
|
|
+
|
|
|
+ for (SiteDto buildingDto : dto) {
|
|
|
+ List<SiteDto> floorChild = buildingDto.getChildren();
|
|
|
+ for (SiteDto roomDtos : floorChild) {
|
|
|
+ maxId ++;
|
|
|
+ roomDto.setId(maxId);
|
|
|
+ List<SiteDto> children = roomDtos.getChildren();
|
|
|
+ // 加入房间
|
|
|
+ children.add(roomDto);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Map<Object, Object> result = new HashMap<>();
|
|
|
+ log.info("返回值最大id: {}" , maxId);
|
|
|
+ result.put("maxId", maxId);
|
|
|
+ result.put("data", dto);
|
|
|
+
|
|
|
+ // 提供给dataSet使用
|
|
|
+ ids.add(maxId);
|
|
|
+ result.put("ids", ids);
|
|
|
+ return result;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化DataSet
|
|
|
+ * location: 原点坐标(特殊点表)
|
|
|
+ * bounding_box_max:(特殊点表)
|
|
|
+ * bounding_box_min:(特殊点表)
|
|
|
+ * @param sceneCode
|
|
|
+ *
|
|
|
+ */
|
|
|
+ private List<DataSetPo> initMergeDataSet(String sceneCode, MergeDateSetDto mergeDto){
|
|
|
+ // 设置原点坐标,通过场景码查询特殊点表的原点
|
|
|
+ List<SpecialPointEntity> spList = specialPointService.findBySceneCode(sceneCode);
|
|
|
+ // 正常是5条记录: db.getCollection('t_special_point').find({"sceneCode":"t97"})
|
|
|
+ if (spList.size() != 5) {
|
|
|
+ throw new BaseRuntimeException(MsgCode.e3001, "特殊点表坐标异常");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Double[]> map = new HashMap<>();
|
|
|
+ for (SpecialPointEntity sp : spList) {
|
|
|
+ String key = sp.getPoiKey();
|
|
|
+ // 使用虚拟坐标
|
|
|
+ if (TypeConstant.POI_BOUNDINGBOX_MAX.equals(key) || TypeConstant.POI_BOUNDINGBOX_MIN.equals(key)) {
|
|
|
+ map.put(key, sp.getPoi());
|
|
|
+ }
|
|
|
+ // 使用gps坐标
|
|
|
+ if (TypeConstant.POI_ORIGIN.equals(key)){
|
|
|
+ map.put(key, sp.getGpsPoi());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DataSetPo po = ModifyDataSets.mergeDataSetPo(map, mergeDto);
|
|
|
+ List<DataSetPo> dataSetPos = Arrays.asList(po);
|
|
|
+ log.info("DataSet数据初始化创建完成");
|
|
|
+
|
|
|
+ return dataSetPos;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param sceneCode
|
|
|
+ * @param mergePath 合并文件地址
|
|
|
+ * @param dto
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<FilterHotDto> initMergeFilter(String sceneCode, String mergePath, ControlPointEntity dto){
|
|
|
+ String path = mergePath +"/vision.txt";
|
|
|
+ log.info("path: {}", path);
|
|
|
+ if (!cn.hutool.core.io.FileUtil.isFile(path)){
|
|
|
+ throw new BaseRuntimeException(MsgCode.e3001, "vision.txt不存在");
|
|
|
+ }
|
|
|
+ JSONArray jsonArray = convertToVision.createFilter(sceneCode, path, dto);
|
|
|
+ FilterEntity entity = new FilterEntity();
|
|
|
+ entity.setId(sceneCode);
|
|
|
+ entity.setCreateTime(LocalDateTime.now());
|
|
|
+ //将array数组转换成对象
|
|
|
+ List<FilterHotDto> list = JSONArray.toList(jsonArray, FilterHotDto.class);
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化点云、siteModel
|
|
|
+ * @param maxId
|
|
|
+ * @param mergeCode
|
|
|
+ * @param mergePath
|
|
|
+ * @param dto
|
|
|
+ */
|
|
|
+ private SiteDto initMergeSiteModel(String mergeCode, String mergePath, ControlPointEntity dto){
|
|
|
+ SiteDto siteDto = processCould(mergeCode, mergePath, dto);
|
|
|
+ return siteDto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理could.js 并做相应的计算
|
|
|
+ * @param sceneCode
|
|
|
+ * @param path
|
|
|
+ */
|
|
|
+ private SiteDto processCould(String sceneCode, String path, ControlPointEntity dto){
|
|
|
+ path = path + "/webcloud/cloud.js";
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 修改cloud.js文件
|
|
|
+ JSONObject info = ModifyCloud.fixCloud(path);
|
|
|
+
|
|
|
+ cn.hutool.core.io.FileUtil.writeUtf8String(info.toString(), path);
|
|
|
+ log.info("新的cloud.js写入服务器完成:{}", path);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将boundingBox坐标转换成gis坐标, site_model需要
|
|
|
+ * boundingBox:虚拟点坐标,存特殊点, dataSet数据要使用
|
|
|
+ */
|
|
|
+ JSONObject boundingBox = ModifyCloud.getBoundingBox(info);
|
|
|
+ Double maxX = boundingBox.getDouble("maxX");
|
|
|
+ Double maxY = boundingBox.getDouble("maxY");
|
|
|
+ Double maxZ = boundingBox.getDouble("maxZ");
|
|
|
+
|
|
|
+ Double minX = boundingBox.getDouble("minX");
|
|
|
+ Double minY = boundingBox.getDouble("minY");
|
|
|
+ Double minZ = boundingBox.getDouble("minZ");
|
|
|
+
|
|
|
+ Double centreX = boundingBox.getDouble("centreX");
|
|
|
+ Double centreY = boundingBox.getDouble("centreY");
|
|
|
+ Double centreZ = boundingBox.getDouble("centreZ");
|
|
|
+
|
|
|
+
|
|
|
+ // 虚拟点坐标(四维看看坐标)
|
|
|
+// Double[] ageMax = {maxX,maxY,maxZ};
|
|
|
+// Double[] ageMin = {minX,minY,minZ};
|
|
|
+// Double[] ageCentre = {centreX,centreY,centreZ};
|
|
|
+
|
|
|
+ JSONObject resJson = ModifyCloud.convertFromBoundingBox(boundingBox, dto);
|
|
|
+
|
|
|
+ Double[] gpsMax = getKey(resJson, "max");
|
|
|
+ Double[] gpsMin = getKey(resJson, "min");
|
|
|
+ Double[] gpsCentre = getKeyZ(resJson, "centre");
|
|
|
+
|
|
|
+ // 将数据保存到db
|
|
|
+// saveSpecialPoint(sceneCode, TypeConstant.POI_BOUNDINGBOX_MAX, ageMax, gpsMax);
|
|
|
+// saveSpecialPoint(sceneCode, TypeConstant.POI_BOUNDINGBOX_MIN, ageMin, gpsMin);
|
|
|
+// saveSpecialPoint(sceneCode, TypeConstant.POI_CENTRE, ageCentre, gpsCentre);
|
|
|
+ log.info("max、min、中心点保存成功");
|
|
|
+
|
|
|
+
|
|
|
+ // 创建sitModel
|
|
|
+ SiteDto siteModel = createSiteModel(sceneCode, gpsMax, gpsMin, gpsCentre, maxZ, minZ);
|
|
|
+ return siteModel;
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取两个值的
|
|
|
+ * json数组转 double[]
|
|
|
+ * @param resJson
|
|
|
+ * @param key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Double[] getKey(JSONObject resJson , String key){
|
|
|
+ JSONArray array = resJson.getJSONArray(key);
|
|
|
+ Double[] res = {array.getDouble(0), array.getDouble(1)};
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取三个值的
|
|
|
+ * @param resJson
|
|
|
+ * @param key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Double[] getKeyZ(JSONObject resJson , String key){
|
|
|
+ JSONArray array = resJson.getJSONArray(key);
|
|
|
+ Double[] res = {array.getDouble(0), array.getDouble(1), array.getDouble(2)};
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private SiteDto createSiteModel(String sceneCode, Double[] max, Double[] min, Double[] centre, Double maxZ, Double minZ){
|
|
|
+ // z_max、z_min 替换site_model的Floor、root类型
|
|
|
+ // max、min四个顶点替换BUILDING、FLOOR 的coordinates,
|
|
|
+ // 顺时针,(x_max,y_max),(x_max,y_min),(x_min,y_min),(x_min,y_max)
|
|
|
+ // 一般参数1:x, 参数2:Y
|
|
|
+ Double[] peak_1 = {max[0],max[1]};
|
|
|
+ Double[] peak_2 = {max[0],min[1]};
|
|
|
+ Double[] peak_3 = {min[0],min[1]};
|
|
|
+ Double[] peak_4 = {min[0],max[1]};
|
|
|
+ List<List<Double[]>> doubles = Arrays.asList(Arrays.asList(peak_1, peak_2, peak_3, peak_4));
|
|
|
+
|
|
|
+ // centre 替换BUILDING、FLOOR、ROOM 的center
|
|
|
+ log.info("中心点:{}, {}, {}", centre[0], centre[1], centre[2]);
|
|
|
+
|
|
|
+ // 获取模板对象
|
|
|
+ SiteDto siteDto = initSiteModelRoom();
|
|
|
+ siteDto.setCenter(centre);
|
|
|
+ siteDto.setZ_max(maxZ);
|
|
|
+ siteDto.setZ_min(minZ);
|
|
|
+
|
|
|
+ SitePolygon rPolygon = new SitePolygon();
|
|
|
+ rPolygon.setCoordinates(doubles);
|
|
|
+ rPolygon.setType("Polygon");
|
|
|
+ siteDto.setPolygon(rPolygon);
|
|
|
+
|
|
|
+ log.info("siteModel数据初始化创建完成");
|
|
|
+ return siteDto;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private SiteDto initSiteModelRoom(){
|
|
|
+ SiteDto dto = new SiteDto();
|
|
|
+ dto.setType("ROOM");
|
|
|
+ dto.setName("港10-1");
|
|
|
+ dto.setArea(2503.30551910935);
|
|
|
+ dto.setVolume(295513.21880627);
|
|
|
+ dto.setGeometry_hash(1605756229L);
|
|
|
+ return dto;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private String redisPath(String sceneCode) {
|
|
|
+ String initKey = TypeConstant.REDIS_INIT_PATH + sceneCode;
|
|
|
+ log.info("initKey: {}", initKey);
|
|
|
+ String initPath = redisTemplate.opsForValue().get(initKey);
|
|
|
+ if (initPath == null) {
|
|
|
+ log.info("initPath走数据库");
|
|
|
+ InitEntity initEntity = initService.findById(sceneCode);
|
|
|
+ if (initEntity == null) {
|
|
|
+ throw new BaseRuntimeException("init初始化数据不存: {}" +sceneCode);
|
|
|
+ }
|
|
|
+ initPath = initEntity.getPath();
|
|
|
+ redisTemplate.opsForValue().set(initKey, initPath, 24, TimeUnit.HOURS);
|
|
|
+ }
|
|
|
+ return initPath;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|