Bläddra i källkod

完成剪切模型

wuweihao 3 år sedan
förälder
incheckning
b5dbede59a

+ 11 - 0
laser/src/main/java/com/fdkankan/indoor/base/constant/CmdConstant.java

@@ -54,4 +54,15 @@ public class CmdConstant {
      * @target 服务器存放位置(会把当前目录也下载)
      */
     public final static String OSSUTIL_DOWNLOAD_DIR = "bash /root/user/java/jar_run/ossdownload.sh @downloadDir @target";
+
+
+    /**
+     * 2021-09-23
+     * 多数据集模型剪切
+     * bash /home/ubuntu/bin/PotreeConverter.sh "" xxx/xxx.las xxx/merge_cut_param.json"
+     * 三个参数,合并裁剪的,第一个参数为空字符串"", 第二个是输出.las路径,第三个是merge_cut_param.json文件路径
+     * outPath: 是输出.las路径
+     * inPath: merge_cut_param.json文件路径
+     */
+    public final static String MERGE_CUT_MODEL = "bash /home/ubuntu/bin/PotreeConverter.sh '' @outPath @inPath";
 }

+ 15 - 16
laser/src/main/java/com/fdkankan/indoor/core/controller/CutModelController.java

@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*;
 /**
  * Created by owen on 2021/8/17 0017 15:10
  */
-@Api(tags = "剪切模型")
+@Api(tags = "cut-las-剪切模型")
 @RestController
 public class CutModelController {
 
@@ -26,28 +26,27 @@ public class CutModelController {
 //    }
 
 
-    @WebControllerLog(description = "剪切模型-剪切模型")
-    @ApiOperation("剪切模型")
-    @PostMapping("indoor/{sceneCode}/api/pointcloud/crop")
-    public Object crop(@PathVariable String sceneCode, @RequestBody CropDto param){
-        Result result = entityService.crop(sceneCode, param);
-        return  result.getData();
-    }
+//    @WebControllerLog(description = "剪切模型-剪切模型")
+//    @ApiOperation("剪切模型")
+//    @PostMapping("indoor/{sceneCode}/api/pointcloud/crop")
+//    public Object crop(@PathVariable String sceneCode, @RequestBody CropDto param){
+//        Result result = entityService.crop(sceneCode, param);
+//        return  result.getData();
+//    }
 
     /**
      * 2021-09-23
      * 更新,支持多数据集点云剪裁
      * @param sceneCode
-     * @param param
      * @return
      */
-//    @WebControllerLog(description = "剪切模型-剪切模型")
-//    @ApiOperation("剪切模型")
-//    @PostMapping("indoor/{sceneCode}/api/pointcloud/crop")
-//    public Object crop(@PathVariable String sceneCode, @RequestBody CropDto param){
-//        Result result = entityService.multipleCrop(sceneCode, param);
-//        return  result.getData();
-//    }
+    @WebControllerLog(description = "剪切模型-剪切模型")
+    @ApiOperation("剪切模型")
+    @PostMapping("indoor/{sceneCode}/api/pointcloud/crop")
+    public Object multipleCrop(@PathVariable String sceneCode){
+        Result result = entityService.multipleCrop(sceneCode);
+        return  result.getData();
+    }
 
     @WebControllerLog(description = "剪切模型-查询详情")
     @ApiOperation("查询详情")

+ 8 - 0
laser/src/main/java/com/fdkankan/indoor/core/controller/TiledMapController.java

@@ -74,6 +74,14 @@ public class TiledMapController {
         return entityMap.upload(sceneCode, file);
     }
 
+
+    @WebControllerLog(description = "平面图-上传平面图")
+    @ApiOperation(value = "上传平面图2", notes = "只支持zip, 压缩文件不能包含目录")
+    @PostMapping("indoor/{sceneCode}/api/tiled_maps/upload2")
+    public Result upload2(@PathVariable String sceneCode, MultipartFile file){
+        return entityMap.upload(sceneCode, file);
+    }
+
     @ApiOperation(value = "下载平面图", notes = "下载zip包, 前端自己拼接oss域名")
     @GetMapping("indoor/{sceneCode}/api/tiled_maps/download")
     public Result download(@PathVariable String sceneCode){

+ 1 - 1
laser/src/main/java/com/fdkankan/indoor/core/service/CutModelService.java

@@ -19,5 +19,5 @@ public interface CutModelService {
 
     Result findByDataId(String sceneCode, Integer dataId);
 
-    Result multipleCrop(String sceneCode, CropDto param);
+    Result multipleCrop(String sceneCode);
 }

+ 148 - 11
laser/src/main/java/com/fdkankan/indoor/core/service/impl/CutModelServiceImpl.java

@@ -2,29 +2,29 @@ package com.fdkankan.indoor.core.service.impl;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.indoor.base.constant.CmdConstant;
+import com.fdkankan.indoor.base.constant.ConfigConstant;
 import com.fdkankan.indoor.base.constant.MsgCode;
+import com.fdkankan.indoor.base.convert.GisCoordinateUtil;
 import com.fdkankan.indoor.base.convert.ImageClipUtil;
 import com.fdkankan.indoor.base.exception.BaseRuntimeException;
 import com.fdkankan.indoor.base.util.AliYunOssUtil;
 import com.fdkankan.indoor.base.util.CmdUtils;
 import com.fdkankan.indoor.base.util.MyFileUtils;
 import com.fdkankan.indoor.base.util.Result;
-import com.fdkankan.indoor.core.entity.CutModelEntity;
-import com.fdkankan.indoor.core.entity.InitEntity;
-import com.fdkankan.indoor.core.entity.MapEntity;
+import com.fdkankan.indoor.core.entity.*;
 import com.fdkankan.indoor.core.entity.dto.CropDto;
 import com.fdkankan.indoor.core.entity.dto.CutModelDto;
 import com.fdkankan.indoor.core.entity.dto.MapDto;
 import com.fdkankan.indoor.core.entity.dto.PoiTypeDto;
+import com.fdkankan.indoor.core.entity.po.DataSetPo;
 import com.fdkankan.indoor.core.entity.po.MapPo;
 import com.fdkankan.indoor.core.mapper.CutModelMapper;
 import com.fdkankan.indoor.core.mapper.InitMapper;
 import com.fdkankan.indoor.core.mapper.MapMapper;
-import com.fdkankan.indoor.core.service.CutModelService;
-import com.fdkankan.indoor.core.service.InitService;
-import com.fdkankan.indoor.core.service.MapService;
+import com.fdkankan.indoor.core.service.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -52,6 +52,17 @@ public class CutModelServiceImpl extends IBaseServiceImpl implements CutModelSer
     @Autowired
     AliYunOssUtil aliYunOssUtil;
 
+    @Autowired
+    MergeInfoService mergeInfoService;
+
+    @Autowired
+    DataSetService dataSetService;
+
+    @Autowired
+    ControlPointCalculateService controlPointCalculateService;
+
+    @Autowired
+    ConfigConstant configConstant;
 
 
 
@@ -252,14 +263,140 @@ public class CutModelServiceImpl extends IBaseServiceImpl implements CutModelSer
      * 2021-9-23
      * 多点云剪裁
      * @param sceneCode
-     * @param param
      * @return
      */
     @Override
-    public Result multipleCrop(String sceneCode, CropDto param) {
-        // 1. 合并场景表(t_merge_info)获取dataSetId, 场景码
-        // 2. 根据dataSetId 将dataSet表location(需要转本地坐标), orientation, path, 封装到merge_cut_model.json
-        return null;
+    public Result multipleCrop(String sceneCode) {
+
+
+        // 1. 根据dataSetId 将dataSet表location(需要转本地坐标), orientation, path, 封装到merge_cut_model.json
+        List<DataSetPo> dataSetInfos = dataSetService.getDataBySceneCode(sceneCode);
+
+
+        // 转坐标,获取控制点计算值
+        ControlPointCalculateEntity pointCalculate = controlPointCalculateService.findById(sceneCode);
+
+        HashMap<Object, double[] > covertPoint = new HashMap<>();
+        for (DataSetPo po : dataSetInfos) {
+            Double[] location = po.getLocation();
+            // gis坐标转本地坐标
+            double[] doubles = GisCoordinateUtil.transformBLToLocation(location[0], location[1], pointCalculate);
+
+            Double orientation = po.getOrientation();
+
+            // 将本地坐标, 旋转角度按顺序封装起来
+            double[] resParam = {doubles[0], doubles[1], location[2], orientation};
+            Integer id = po.getId();
+
+            // dataSetId做为key
+            covertPoint.put(id, resParam);
+        }
+
+
+        // 2. 合并场景表(t_merge_info)获取dataSetId, 场景码
+        List<MergeInfoEntity> mergeInfo = mergeInfoService.findBySceneCode(sceneCode);
+
+        int SizeDataSet = dataSetInfos.size();
+        int SizeMergeDataSet = mergeInfo.size();
+        log.info("数据集数量:{}, 合并数据集数量: {}", SizeDataSet, SizeMergeDataSet);
+
+
+
+        JSONArray models = new JSONArray();
+        for (MergeInfoEntity info : mergeInfo) {
+            // 获取本地坐标,旋转角度
+            Integer dataSetId = info.getDataSetId();
+            double[] point = covertPoint.get(dataSetId);
+
+            JSONObject cutJson = new JSONObject();
+            cutJson.put("file", info.getPath() + "/laser.las");
+            cutJson.put("sceneCode", info.getMergeCode());
+            cutJson.put("dataSetId", dataSetId);
+            // 算法要求用空格隔开
+            cutJson.put("translation", point[0] + " " + point[1] + " " + point[2]);
+            cutJson.put("rotation", point[3]);
+            models.add(cutJson);
+        }
+
+        // 修剪模型参数
+        JSONObject mergeCut = new JSONObject();
+        mergeCut.put("model", models);
+        // 这个值目前写死
+        mergeCut.put("aabb", "b-0.5 -0.5 -0.5 0.5 0.5 0.5");
+
+        // json写入服务器
+        String basePath = redisPath(sceneCode);
+        if ("dev".equals(configConstant.active)){
+            basePath = configConstant.serverBasePath + "/" + sceneCode + "/results/laserData";
+        }
+        String savePath = basePath + "/merge_cut_param.json";
+        log.info("剪切参数:{}", savePath);
+        FileUtil.writeUtf8String(mergeCut.toJSONString(), savePath);
+        log.info("剪切参数json写入完成");
+
+         // 剪切并上传模型
+        String ossUrl = cutLas(basePath, sceneCode);
+
+        // 数据更新到数据库
+        saveLasInfo(sceneCode, ossUrl);
+
+        JSONObject result = new JSONObject();
+        // 返回值id, 默认1
+        result.put("job_id", 1);
+        return Result.success(result);
+
+    }
+
+    /**
+     * 模型剪切信息保存数据库
+     */
+    private void saveLasInfo(String sceneCode, String ossUrl){
+        // 保存数据到数据库
+        CutModelEntity cutEntity = this.findById(sceneCode);
+        if (cutEntity == null) {
+            cutEntity = new CutModelEntity();
+            cutEntity.setId(sceneCode);
+            cutEntity.setCreateTime(LocalDateTime.now());
+            cutEntity.setData(initCutModelDto(ossUrl, null));
+        } else {
+            // 更新las数据
+            cutEntity.setData(initCutModelDto(ossUrl, null));
+            cutEntity.setUpdateTime(LocalDateTime.now());
+        }
+        entityMapper.save(cutEntity);
+        log.info("模型剪切信息保存完成");
+    }
+
+
+    /**
+     * 2021-9-23
+     * 剪切模型 , 并上传oss
+     * String ossPath = "data/" +sceneCode + "/data/chunk1/cut/" + time + ".las";
+     * String ossPath = "data/" +sceneCode + "/data/cut/download.las"?time;
+     * @param basePath
+     */
+    //
+    private String cutLas(String basePath, String sceneCode){
+        // 调用命令切模型
+        String cmd = CmdConstant.MERGE_CUT_MODEL;
+        String inPath = basePath + "/merge_cut_param.json";
+
+        String outPath = basePath + "/merge_cut.las";
+
+        cmd = cmd.replace("@inPath", inPath);
+        cmd = cmd.replace("@outPath", outPath);
+
+        CmdUtils.callLineSh(cmd);
+        log.info("剪切模型完成: {}", outPath);
+
+        // 将剪裁后的las上传oss
+        String ossPath = "data/" +sceneCode + "/data/cut/download.las";
+        aliYunOssUtil.upload(outPath, ossPath);
+
+        String ossUrl = configConstant.ossDomain + ossPath + "?" + System.currentTimeMillis();
+        log.info("剪切模型上传oss完成: {}", ossUrl);
+
+        return ossUrl;
     }
 
     private List<CutModelDto> getDataBySceneCode(String sceneCode){

+ 22 - 1
laser/src/main/java/com/fdkankan/indoor/core/service/impl/InitServiceImpl.java

@@ -120,13 +120,13 @@ public class InitServiceImpl implements InitService {
         InitEntity init = findById(sceneCode);
         if (init != null) {
             log.info("初始化数据已存在: {}", sceneCode);
-
             // 重算
 
             if ("recount".equals(from)) {
                 log.info("进行手动重新");
 //                path = init.getPath();
 //                title = init.getTitle();
+
             }
         } else {
             // 新场景
@@ -151,6 +151,8 @@ public class InitServiceImpl implements InitService {
         // 删除旧数据, 重算使用
         initRemove(sceneCode);
 
+        path = init.getPath();
+        title = init.getTitle();
         // 路径在这里检测
         if (StrUtil.isBlank(path)) {
             throw new BaseRuntimeException("init.path路径不能为空");
@@ -209,6 +211,8 @@ public class InitServiceImpl implements InitService {
 
         init.setUpdateTime(LocalDateTime.now());
         init.setTitle(title);
+        // 2021-09-23 旧场景地址需要更新
+        init.setPath(param.getPath());
         Integer recount = init.getRecount();
         recount = recount == null ? 1 : recount + 1;
         init.setRecount(recount);
@@ -562,6 +566,7 @@ public class InitServiceImpl implements InitService {
         createConfig(sceneCode);
 
         // step7 创建t_datasets表, 使用的是代码, 需要处理原点之后执行, dataSet.orientation: 计算控制点结果rotation2
+        // 2021-09-23 会初始化一条信息到合并场景信息表t_merge_info, 存dataSet数据
         DataSetPo dataSet = createDataSet(sceneCode, laserDataPath, calculateEntity.getRotation2(), from);
 
         // Route数据重新计算, 并保存数据库
@@ -890,11 +895,27 @@ public class InitServiceImpl implements InitService {
         entity.setData(Arrays.asList(po));
         dataSetService.save(entity);
         log.info("DataSet数据初始化创建完成");
+
+        // 2021-09-23 初始化一条dataSet数据到合并场景信息表, 剪裁模式时需要使用数据
+        MergeInfoEntity info = new MergeInfoEntity();
+        info.setDataSetId(mergeDto.getId());
+        info.setMergeCode(sceneCode);
+        info.setTitle(sceneCode + "_原始数据集");
+        info.setPath(laserDataPath);
+        info.setSceneCode(sceneCode);
+        info.setCreateTime(LocalDateTime.now());
+        info.setId(SnowFlakeUUidUtils.getUuid("MI"));
+        mergeInfoService.save(info);
+        log.info("DataSet合并场景信息创建完成");
+
+
         return po;
     }
 
 
 
+
+
     private void createConfig(String sceneCode) {
 
         // 根据场景码查询特殊点

+ 1 - 1
laser/src/main/java/com/fdkankan/indoor/core/service/impl/MergeSceneServiceImpl.java

@@ -339,7 +339,7 @@ public class MergeSceneServiceImpl extends IBaseServiceImpl implements MergeScen
         mergeDto.setSite_model_entity_ids(new Integer[0]);
         mergeDto.setSceneNum(mergeCode);
 
-        mergePath = StrUtil.subBefore(mergePath, "/results", true);
+//        mergePath = StrUtil.subBefore(mergePath, "/results", true);
 
         mergeDto.setPath(mergePath);
         // 处理弧度