package com.fdkankan.contro.mq.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.fdkankan.common.constant.*; import com.fdkankan.common.util.FileUtils; import com.fdkankan.contro.constant.UserEditDataType; import com.fdkankan.contro.entity.*; import com.fdkankan.contro.mq.service.IBuildSceneService; import com.fdkankan.contro.service.ICommonService; import com.fdkankan.contro.service.*; import com.fdkankan.contro.service.impl.FdkkV4Service; import com.fdkankan.fyun.face.FYunFileServiceInterface; import com.fdkankan.model.constants.ConstantFileName; import com.fdkankan.model.constants.ConstantFilePath; import com.fdkankan.model.constants.UploadFilePath; import com.fdkankan.model.utils.CreateObjUtil; import com.fdkankan.rabbitmq.bean.BuildSceneCallMessage; import com.fdkankan.rabbitmq.bean.BuildSceneResultMqMessage; import com.fdkankan.rabbitmq.util.RabbitMqProducer; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.redis.util.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.io.File; import java.util.*; /** *

* TODO *

* * @author dengsixing * @since 2022/3/1 **/ @Slf4j @Service @RefreshScope public class BuildObjServiceImpl implements IBuildSceneService { @Value("${queue.modeling.modeling-call}") private String queueModelingCall; @Value("${queue.modeling.obj.modeling-post}") private String queueObjModelingPost; @Value("${queue.modeling.obj.modeling-pre}") private String queueObjModelingPre; @Value("${model.modelKind:3dtiles}") private String modelKind; @Value("#{'${model.3dtiles.sceneSource:}'.split(',')}") private List sdTilesSceneSourceList; @Value("${env:gn}") private String env; @Autowired private RabbitMqProducer mqProducer; @Resource private FYunFileServiceInterface fYunFileService; @Autowired private ISceneProService sceneProService; @Autowired private IFdkkLaserService fdkkLaserService; @Autowired private FdkkV4Service fdkkV4Service; @Autowired private IBuildSceneDTService buildSceneDTService; @Autowired private ISceneProEditService sceneProEditService; @Autowired private IScenePlusService scenePlusService; @Autowired private ISceneBuildProcessLogService sceneBuildProcessLogService; @Autowired private ICommonService commonService; @Autowired private IScenePlusExtService scenePlusExtService; @Autowired private RedisUtil redisUtil; @Autowired private ICameraDetailService cameraDetailService; @Autowired private ICompanyService companyService; @Override public void buildScenePre(BuildSceneCallMessage message) throws Exception{ boolean success = false; String num = message.getSceneNum(); String path = message.getPath(); String laserObjFilePath = path + "_laser_obj"; try { //根据相机类型,组装资源路径 log.info("开始准备生成OBJ场景资源,路径:{}", laserObjFilePath); FileUtils.delAllFile(laserObjFilePath); //获取解压后的资源的data.fdage中的数据 File folderPath = new File(path); fYunFileService.downloadFile(ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_LASER_PATH, "") + "/data.fdage", laserObjFilePath + "/capture/data.fdage"); JSONObject jsonObject = FileUtils.readJson(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage"); if(ObjectUtils.isEmpty(jsonObject)){ log.error("data.fdage文件不存在"); return ; } //下载资源到本地 this.downLoadSource(message, laserObjFilePath); if (!jsonObject.containsKey("exportMeshObj") || jsonObject.getIntValue("exportMeshObj") != 1) { // 写入data.fdage 防止重算 jsonObject.put("exportMeshObj", 1); FileUtil.writeUtf8String(jsonObject.toJSONString(), laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage"); fYunFileService.uploadFile(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage", ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_LASER_PATH, "") + "/data.fdage"); } // 重新构造datafdage文件,添加生成obt文件选项 jsonObject.put("OnlyExportMeshObj",true); FileUtils.writeFile(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage", jsonObject.toJSONString()); message.getBuildContext().put("previousPath",path); message.setCameraType("14"); message.setResolution(jsonObject.getString("resolution")); message.setPath(laserObjFilePath); message.setResultReceiverMqName(queueObjModelingPost); //发送mq,就进行计算 mqProducer.sendByWorkQueue(queueModelingCall, message); success = true; log.info("场景计算资源准备结束,场景码:{}", message.getSceneNum()); }catch (Exception e){ log.error("生成OBJ场景资源准备异常,num=" + num, e); buildSceneDTService.handBaseFail("生成OBJ场景资源准备异常", message.getPath(), message.getSceneNum(), "计算控制服务器"); throw e; }finally { fdkkLaserService.pushBuildStatusToLaserSystem(num, laserObjFilePath + "/laserData/mesh", success ? CommonOperStatus.SUCCESS.code() : CommonOperStatus.FAILD.code()); } } @Override public void downLoadSource(BuildSceneCallMessage message,String path) throws Exception{ //下载原始资源文件 String ossPath = commonService.getOssOrignPath(message.getPath()); fYunFileService.downloadFileByCommand(path + File.separator + "capture", ossPath); //下载caches/image,算法会执行快一些 String ossResultPath = String.format(UploadFilePath.scene_result_data_path, message.getSceneNum()); fYunFileService.downloadFileByCommand(path + "/caches/images/", ossResultPath + "caches/images/"); //下载点位校准文件 fYunFileService.downloadFileByCommand(path + "/extras/", ossResultPath + "extras/"); } @Override public void buildScenePost(BuildSceneResultMqMessage message) throws Exception { String path = message.getPath(); String projectNum = message.getBuildContext().get("sceneNum").toString(); String laserObjFilePath = path; boolean success = false; try { //上传计算日志 String buildLogPath = String.format(UploadFilePath.BUILD_LOG_PATH, projectNum); fYunFileService.uploadFile(path + File.separator + "console.log", buildLogPath + "console.log"); if (!message.getBuildSuccess()) { log.error("生成OBJ场景计算失败!"); // 发送钉钉消息,计算失败 buildSceneDTService.handModelFail("生成OBJ场景计算失败!", message.getPath(), message.getBuildContext().get("sceneNum").toString(), message.getHostName()); return; } ScenePro scenePro = sceneProService.getByNum(projectNum); String version = "v4"; String ossImagePath = String.format(UploadFilePath.IMG_VIEW_PATH, projectNum); //如果是微服务上线之前的存量场景且未生成过obj(未升级过),需要上传到v3的目录,在函数最后调用升级接口进行文件拷贝 if(Objects.nonNull(scenePro) && scenePro.getIsUpgrade() != CommonStatus.YES.code().intValue()){ ossImagePath = String.format(ConstantFilePath.IMAGE_PATH_FORMAT, projectNum); version = "v3"; } //上传obj String resultsPath = path + File.separator + "results" + File.separator; if(this.modelKind.equals(ModelKind.DAM.code())){ CreateObjUtil.convertTxtToDam(path + File.separator + "results" + File.separator + "tex" + File.separator + "modeldata.txt", path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam"); CreateObjUtil.convertDamToLzma(path + File.separator + "results/"); CreateObjUtil.convertTxtToDam(path + File.separator + "results" + File.separator + "tex" + File.separator + "modeldata.txt", path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam"); File file = new File(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam.lzma"); while (!file.exists()) { Thread.sleep(60000); } fYunFileService.uploadFile(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam.lzma", ossImagePath + ConstantFileName.modelUUID + "_50k.dam.lzma"); fYunFileService.uploadFile(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam", ossImagePath + ConstantFileName.modelUUID + "_50k.dam"); } if(this.modelKind.equals(ModelKind.THREE_D_TILE.code()) && CollUtil.isNotEmpty(sdTilesSceneSourceList) && sdTilesSceneSourceList.contains(SceneSource.JG.code())){ String threedtilesPath = resultsPath + ModelKind.THREE_D_TILE.code(); String oss3dtilesPath = ossImagePath + ModelKind.THREE_D_TILE.code(); List list = FileUtils.list(new File(threedtilesPath)); if(CollUtil.isEmpty(list)){ log.error("3dtiles目录异常,3dtiles地址:{}", new File(path + File.separator + "results" + File.separator + ModelKind.THREE_D_TILE.code())); throw new Exception("3dtiles目录异常"); } //上传3dtiles文件 fYunFileService.uploadFileByCommand(threedtilesPath, oss3dtilesPath); } String texPath = laserObjFilePath + File.separator + "results" + File.separator + "tex"; File texFile = new File(texPath); if(texFile.exists()){ for (File textureFile : texFile.listFiles()) { if(textureFile.getName().endsWith(".jpg")){ fYunFileService.uploadFile(textureFile.getAbsolutePath(), ossImagePath + ConstantFileName.modelUUID + "_50k_texture_jpg_high1/"+textureFile.getName()); } } } fYunFileService.uploadFile(laserObjFilePath + File.separator + "results" + File.separator + "tex/texture1.jpg", ossImagePath + ConstantFileName.modelUUID + "_50k_texture_jpg_high1/texture1.jpg"); // 拷贝结果 log.info("开始拷贝obj文件"); FileUtils.copyFolderAllFiles(laserObjFilePath + "/results/mesh", laserObjFilePath + "/laserData/mesh/", true); //上传mesh文件 fYunFileService.uploadFileByCommand(laserObjFilePath + "/results/mesh", String.format(UploadFilePath.DATA_VIEW_PATH, projectNum) + "mesh"); CreateObjUtil.convertTxtToVisionmodeldata(resultsPath + "vision.txt", resultsPath + "vision.modeldata"); fYunFileService.uploadFile(resultsPath + "vision.txt", ossImagePath.concat("vision.txt")); fYunFileService.uploadFile(resultsPath + "vision.modeldata", ossImagePath.concat("vision.modeldata")); if(!ObjectUtils.isEmpty(scenePro)){ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() .set(ScenePro::getStatus, -2).eq(ScenePro::getNum, projectNum); sceneProService.update(updateWrapper); sceneProEditService.update(new LambdaUpdateWrapper().set(SceneProEdit::getMapVisi,0) .eq(SceneProEdit::getProId,scenePro.getId())); } ScenePlus scenePlus = scenePlusService.getScenePlusByNum(projectNum); if(Objects.nonNull(scenePlus)){ //清除用户编辑业务数据 Set bizs = new HashSet<>(); bizs.add(UserEditDataType.BOX_MODEL.message()); bizs.add(UserEditDataType.FLOORPLAN.message()); commonService.initUserEditData(projectNum, bizs, null); LambdaUpdateWrapper plusUpdateWrapper = new LambdaUpdateWrapper() .set(ScenePlus::getSceneStatus, -2).eq(ScenePlus::getNum, projectNum); scenePlusService.update(plusUpdateWrapper); ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId()); scenePlusExt.setAlgorithmTime(Calendar.getInstance().getTime()); //计算容量 Long space = commonService.getSpace(projectNum); scenePlusExt.setSpace(space); Object[] editInfoArr = commonService.updateEditInfo(scenePlus); SceneEditInfo sceneEditInfo = (SceneEditInfo)editInfoArr[0]; SceneEditInfoExt sceneEditInfoExt = (SceneEditInfoExt)editInfoArr[1]; SceneEditControls sceneEditControls = (SceneEditControls)editInfoArr[2]; if(this.modelKind.equals(ModelKind.THREE_D_TILE.code()) && CollUtil.isNotEmpty(sdTilesSceneSourceList) && sdTilesSceneSourceList.contains(scenePlus.getSceneSource())){ scenePlusExt.setModelKind(ModelKind.THREE_D_TILE.code()); scenePlusExtService.updateById(scenePlusExt); } log.info("生成scene.json上传oss并设置缓存,num:{}", projectNum); CameraDetail cameraDetail = cameraDetailService.getByCameraId(scenePlus.getCameraId()); Company company = !org.apache.commons.lang3.ObjectUtils.isEmpty(cameraDetail.getCompanyId()) ? companyService.getById(cameraDetail.getCompanyId()) : null; //写scene.json commonService.writeSceneJson(projectNum, new JSONObject(),sceneEditInfo, sceneEditInfoExt, sceneEditControls, scenePlus,scenePlusExt,company); } // 如果未升级V4,则升级V4 if("v3".equals(version)){ fdkkV4Service.upgradeToV4(projectNum); } success = true; //国际环境需要发邮件通知 if("eur".equals(env)){ commonService.sendEmail(projectNum); } }catch (Exception e){ log.error("生成OBJ场景计算结果处理异常,num=" + projectNum, e); buildSceneDTService.handBaseFail("生成OBJ场景计算结果处理异常", message.getPath(), projectNum, "计算控制服务器"); throw e; }finally { fdkkLaserService.pushBuildStatusToLaserSystem(projectNum, laserObjFilePath + "/laserData/mesh", success ? CommonOperStatus.SUCCESS.code() : CommonOperStatus.FAILD.code()); } } }