瀏覽代碼

feat(draw): update

gemercheung 1 年之前
父節點
當前提交
c401afbb47

+ 8 - 0
src/app/map/App.vue

@@ -50,6 +50,7 @@
 
 
 <script setup lang="ts">
 <script setup lang="ts">
 import { onMounted, ref, computed, onBeforeMount } from "vue";
 import { onMounted, ref, computed, onBeforeMount } from "vue";
+// import { useRouteQuery } from "@vueuse/router";
 import AMapLoader from "@amap/amap-jsapi-loader";
 import AMapLoader from "@amap/amap-jsapi-loader";
 import axios from "axios";
 import axios from "axios";
 import { getFuseCodeLink } from "../../view/case/help";
 import { getFuseCodeLink } from "../../view/case/help";
@@ -61,8 +62,12 @@ import linkIco from "@/assets/image/fire.ico";
 
 
 const current = ref(0);
 const current = ref(0);
 const list = ref<any>([]);
 const list = ref<any>([]);
+
+// const caseId = useRouteQuery("caseId");
+// console.log("caseId", caseId);
 const state = reactive({
 const state = reactive({
   deptId: "",
   deptId: "",
+  caseId: "",
 });
 });
 
 
 const link = document.querySelector<HTMLLinkElement>("#app-icon")!;
 const link = document.querySelector<HTMLLinkElement>("#app-icon")!;
@@ -249,6 +254,9 @@ body {
   justify-content: center;
   justify-content: center;
   align-items: center;
   align-items: center;
 }
 }
+.el-form-item {
+  margin-bottom: 0px;
+}
 
 
 .tabbar .nav .nav_item {
 .tabbar .nav .nav_item {
   padding: 10px;
   padding: 10px;

+ 11 - 1
src/core/Scene.js

@@ -93,12 +93,22 @@ export default class Scene extends Mitt {
       if (
       if (
         String(obj.name).includes("marker_") ||
         String(obj.name).includes("marker_") ||
         String(obj.name).includes("line_") ||
         String(obj.name).includes("line_") ||
-        String(obj.name).includes("line_point_")
+        String(obj.name).includes("line_point_") ||
+        String(obj.name).includes("circle_")
       ) {
       ) {
         this.scene.remove(obj);
         this.scene.remove(obj);
       }
       }
     }
     }
   }
   }
+
+  deleteItemById(uuid) {
+    for (var i = this.scene.children.length - 1; i >= 0; i--) {
+      let obj = this.scene.children[i];
+      if (obj.uuid === uuid) {
+        this.scene.remove(obj);
+      }
+    }
+  }
   loadLight = () => {
   loadLight = () => {
     const light = new THREE.AmbientLight(0xffffff, 1.5); // 柔和的白光
     const light = new THREE.AmbientLight(0xffffff, 1.5); // 柔和的白光
     this.scene.add(light);
     this.scene.add(light);

+ 60 - 0
src/core/box/object/CircleTextLabel.js

@@ -0,0 +1,60 @@
+import * as THREE from "three";
+import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
+import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";
+import { LineGeometry } from "three/examples/jsm/lines/LineGeometry.js";
+
+export default class CircleTextLabel extends THREE.Mesh {
+  constructor(text, outline) {
+    let res = 5;
+    const canvas = document.createElement("canvas");
+    canvas.width = 128 * res;
+    canvas.height = 128 * res;
+    let fontSize = 68 * res;
+    const ctx = canvas.getContext("2d");
+    ctx.font = `800 ${fontSize}px Arial`; // 设置字体大小和类型
+    ctx.textAlign = "center";
+    ctx.textBaseline = "middle";
+    ctx.fillStyle = "#e44d54"; // 设置文字颜色和透明度
+    ctx.fillText(text, canvas.width / 2, canvas.height / 2);
+
+    // 步骤3: 将画布转换为纹理
+    const texture = new THREE.CanvasTexture(canvas);
+
+    // 步骤4: 创建材质并应用纹理
+    const m = new THREE.MeshBasicMaterial({
+      map: texture,
+      transparent: true, // 允许材质透明
+    });
+
+    // const canvas_map = new THREE.Texture(canvas);
+    texture.colorSpace = THREE.SRGBColorSpace;
+    texture.needsUpdate = true;
+    texture.anisotropy = 4;
+
+    const g = new THREE.CircleGeometry(0.08, 128);
+    g.rotateX(-Math.PI / 2);
+
+    super(g, m);
+
+    this.userData = text;
+
+    const edges = new THREE.EdgesGeometry(g, 50);
+
+    const geometry = new LineGeometry();
+    geometry.fromEdgesGeometry(edges);
+
+    const line_m = new LineMaterial({
+      color: 0xe44d54,
+      linewidth: 5,
+    });
+
+    line_m.resolution.set(window.innerWidth, window.innerHeight);
+
+    const line_n = new LineSegments2(geometry, line_m);
+
+    line_n.position.y += 0.5;
+
+    this.add(line_n);
+    this.name = "circle_" + text;
+  }
+}

+ 1 - 1
src/core/box/object/marker.js

@@ -17,7 +17,7 @@ export default class Marker extends THREE.Mesh {
     this.rotation.y = 0;
     this.rotation.y = 0;
     this.position.y = 5;
     this.position.y = 5;
     this.position.z -= 0.02;
     this.position.z -= 0.02;
-
+    this.userData = startPoint;
     this.visible = true;
     this.visible = true;
     this.scale.set(1, 1, 1);
     this.scale.set(1, 1, 1);
     this.position.y += 0.5;
     this.position.y += 0.5;

+ 104 - 17
src/core/player/Player.js

@@ -2,10 +2,12 @@ import * as THREE from "three";
 
 
 import FloorplanControls from "../controls/FloorplanControls.js";
 import FloorplanControls from "../controls/FloorplanControls.js";
 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
+
 import { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
 import { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
 import Line from "../box/object/Line";
 import Line from "../box/object/Line";
 import LinePoints from "../box/object/LinePoints.js";
 import LinePoints from "../box/object/LinePoints.js";
 import Marker from "../box/object/marker.js";
 import Marker from "../box/object/marker.js";
+import CircleTextLabel from "../box/object/CircleTextLabel.js";
 import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
 import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
 
 
 const convertScreenToNDC = function (event, domElement) {
 const convertScreenToNDC = function (event, domElement) {
@@ -33,16 +35,20 @@ export default class Player {
     this.drawLine = null;
     this.drawLine = null;
     this.startObj = null;
     this.startObj = null;
     this.marker = null;
     this.marker = null;
-    this.allowDrawing = false;
+    this.symbol = null;
+    this.symbolIndex = 0;
+    this.text = null;
+    this.selectItem = null;
 
 
     this.drawing = false;
     this.drawing = false;
     this.inited = false;
     this.inited = false;
     this.renderLines = [];
     this.renderLines = [];
     this.renderMarkers = [];
     this.renderMarkers = [];
     this.activeEdges = [];
     this.activeEdges = [];
+    this.renderSymbols = [];
     this.matLine = null;
     this.matLine = null;
     this.lineColor = 0xe44d54;
     this.lineColor = 0xe44d54;
-    // 1是画线,2是标方向
+    // 1是画线,2是标方向, 3符号, 4文本
     this.mode = 0;
     this.mode = 0;
     this.init();
     this.init();
   }
   }
@@ -53,6 +59,36 @@ export default class Player {
       this.reset();
       this.reset();
       this.setEditMode();
       this.setEditMode();
     }
     }
+    // 2方向
+    if (mode === 2) {
+      let pos = new THREE.Vector3(0, 0, -1);
+      pos.unproject(this.orthCamera);
+      pos.y = 5;
+
+      this.marker = new Marker(pos);
+      this.marker.visible = false;
+      this.scene.scene.add(this.marker);
+      this.drawing = true;
+    }
+    //符号
+    if (mode === 3) {
+      let pos = new THREE.Vector3(0, 0, -1);
+      pos.unproject(this.orthCamera);
+      pos.y = 5;
+      this.symbolIndex += 1;
+      this.symbol = new CircleTextLabel(this.symbolIndex, true);
+      this.symbol.visible = false;
+      this.scene.scene.add(this.symbol);
+      console.log("this.symbol", this.symbol);
+      this.drawing = true;
+    }
+
+    if (mode === 4) {
+      let pos = new THREE.Vector3(0, 0, -1);
+      pos.unproject(this.orthCamera);
+      pos.y = 5;
+    }
+
     if (mode === 0) {
     if (mode === 0) {
       this.setFreeMode();
       this.setFreeMode();
     }
     }
@@ -129,10 +165,25 @@ export default class Player {
   };
   };
 
 
   onPointerMove = (e) => {
   onPointerMove = (e) => {
-    if (!this.drawing) return;
+    // console.log("intersects", intersects);
+    // if (this.mode === 0) {
+    //   const intersects = this.raycaster.intersectObjects(
+    //     this.scene.scene.children,
+    //     true
+    //   );
+    //   intersects.forEach((i) => {
+    //     if (String(i.object.name).includes("marker")) {
+    //       // console.log("i.object.name", i.object);
+    //       // debugger
+    //     }
+    //   });
+    // }
     this.pointermove = convertScreenToNDC(e, this.scene.domElement);
     this.pointermove = convertScreenToNDC(e, this.scene.domElement);
+    this.raycaster.setFromCamera(this.pointermove, this.orthCamera);
+
+    if (!this.drawing) return;
+
     if (this.mode === 1) {
     if (this.mode === 1) {
-      this.raycaster.setFromCamera(this.pointermove, this.orthCamera);
       let intersectArr = this.scene.boxManager.imgList;
       let intersectArr = this.scene.boxManager.imgList;
       // if(this.startObj) {
       // if(this.startObj) {
       //   let i = intersectArr.indexOf(this.startObj)
       //   let i = intersectArr.indexOf(this.startObj)
@@ -146,6 +197,7 @@ export default class Player {
     }
     }
     if (this.mode === 2) {
     if (this.mode === 2) {
       if (this.marker) {
       if (this.marker) {
+        this.marker.visible = true;
         let pos = new THREE.Vector3(this.pointermove.x, this.pointermove.y, -1);
         let pos = new THREE.Vector3(this.pointermove.x, this.pointermove.y, -1);
         pos.unproject(this.orthCamera);
         pos.unproject(this.orthCamera);
         pos.y = 5;
         pos.y = 5;
@@ -153,11 +205,40 @@ export default class Player {
         this.marker.position.copy(pos);
         this.marker.position.copy(pos);
       }
       }
     }
     }
+
+    if (this.mode === 3) {
+      if (this.symbol) {
+        this.symbol.visible = true;
+        let pos = new THREE.Vector3(this.pointermove.x, this.pointermove.y, -1);
+        pos.unproject(this.orthCamera);
+        pos.y = 5;
+        // console.log("pos", pos);
+        // console.log("symbol", this.symbol);
+        this.symbol.position.copy(pos);
+      }
+    }
   };
   };
 
 
   onPointerDown = (e) => {
   onPointerDown = (e) => {
     console.log("start draw");
     console.log("start draw");
     this.pointerdown = convertScreenToNDC(e, this.scene.domElement);
     this.pointerdown = convertScreenToNDC(e, this.scene.domElement);
+
+    if (this.mode === 0) {
+      const intersects = this.raycaster.intersectObjects(
+        this.scene.scene.children,
+        true
+      );
+      intersects.forEach((i) => {
+        if (
+          String(i.object.name).includes("marker") ||
+          String(i.object.name).includes("line")
+        ) {
+          this.selectItem = i.object;
+          this.scene.emit("confirmDelete", i.object.uuid);
+        }
+      });
+    }
+
     if (this.mode === 1) {
     if (this.mode === 1) {
       this.raycaster.setFromCamera(this.pointerdown, this.orthCamera);
       this.raycaster.setFromCamera(this.pointerdown, this.orthCamera);
       let intersectArr = this.scene.boxManager.imgList;
       let intersectArr = this.scene.boxManager.imgList;
@@ -173,15 +254,7 @@ export default class Player {
     }
     }
 
 
     if (this.mode === 2) {
     if (this.mode === 2) {
-      if (!this.marker) {
-        let pos = new THREE.Vector3(this.pointerdown.x, this.pointerdown.y, -1);
-        pos.unproject(this.orthCamera);
-        pos.y = 5;
-        this.marker = new Marker(pos);
-        this.scene.scene.add(this.marker);
-        this.drawing = true;
-      } else {
-        // this.drawing = false;
+      if (this.marker) {
         this.raycaster.setFromCamera(this.pointerdown, this.orthCamera);
         this.raycaster.setFromCamera(this.pointerdown, this.orthCamera);
         let intersectArr = this.scene.boxManager.imgList;
         let intersectArr = this.scene.boxManager.imgList;
         const intersects = this.raycaster.intersectObjects(intersectArr, false);
         const intersects = this.raycaster.intersectObjects(intersectArr, false);
@@ -214,15 +287,30 @@ export default class Player {
           }
           }
 
 
           console.log("activeMarkeritem", activeMarkeritem);
           console.log("activeMarkeritem", activeMarkeritem);
+          this.setMode(0);
         }
         }
       }
       }
     }
     }
-    // this.floorplanControls.enabled = false;
+
+    if (this.mode === 3) {
+      if (this.symbol) {
+        let lasPos = new THREE.Vector3(
+          this.pointerdown.x,
+          this.pointerdown.y,
+          -1
+        );
+        const activeSymbolItem = {
+          id: this.symbolIndex,
+          point: lasPos.toArray(),
+        };
+        this.renderSymbols.push(activeSymbolItem);
+        this.setMode(0);
+      }
+    }
   };
   };
   onPointerUp = (e) => {
   onPointerUp = (e) => {
     this.pointerup = convertScreenToNDC(e, this.scene.domElement);
     this.pointerup = convertScreenToNDC(e, this.scene.domElement);
-    console.log("onPointerUp", this.pointerup);
-
+    // console.log("onPointerUp", this.pointerup);
     if (this.mode === 1) {
     if (this.mode === 1) {
       this.drawing = false;
       this.drawing = false;
       this.floorplanControls.enabled = true;
       this.floorplanControls.enabled = true;
@@ -425,7 +513,6 @@ export default class Player {
     this.scene.emit("data", data);
     this.scene.emit("data", data);
   }
   }
   load(type, data) {
   load(type, data) {
-
     if (type === 1) {
     if (type === 1) {
       console.log("data1", data);
       console.log("data1", data);
       const { hor_activeEdges, hor_lines, hor_markers } = data;
       const { hor_activeEdges, hor_lines, hor_markers } = data;

+ 29 - 6
src/view/case/photos/index.vue

@@ -22,14 +22,15 @@
     </div>
     </div>
     <div class="right">
     <div class="right">
       <div class="tools">
       <div class="tools">
-        <el-button @click="handleMark">标注方向</el-button>
-        <el-button @click="handleLine">标注连线</el-button>
+        <el-button @click="handleMark">箭头</el-button>
+        <el-button @click="handleLine">标引</el-button>
+        <el-button @click="handleSymbol">符号</el-button>
+        <el-button @click="handleText">文本</el-button>
         <el-button @click="handleSave" type="success">保存</el-button>
         <el-button @click="handleSave" type="success">保存</el-button>
 
 
         <el-button @click="handleClear" v-if="hasDrawData" type="warning"
         <el-button @click="handleClear" v-if="hasDrawData" type="warning"
           >清空</el-button
           >清空</el-button
         >
         >
-
         <el-button @click="handleFree" v-if="isShowExitEdit" type="warning"
         <el-button @click="handleFree" v-if="isShowExitEdit" type="warning"
           >退出编辑</el-button
           >退出编辑</el-button
         >
         >
@@ -81,7 +82,8 @@ import { addCaseImgFile } from "../quisk";
 import { saveCaseImgTagData, getCaseImgTagData } from "@/store/case";
 import { saveCaseImgTagData, getCaseImgTagData } from "@/store/case";
 import Scene from "@/core/Scene.js";
 import Scene from "@/core/Scene.js";
 import draggable from "./draggable.vue";
 import draggable from "./draggable.vue";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
+
 const props = defineProps({ caseId: Number });
 const props = defineProps({ caseId: Number });
 const newlist = ref([]);
 const newlist = ref([]);
 const swiperRef = ref(null);
 const swiperRef = ref(null);
@@ -165,6 +167,16 @@ const renderCanvas = () => {
   scene.on("markerExist", () => {
   scene.on("markerExist", () => {
     ElMessage.error("该案件已有方向标注!");
     ElMessage.error("该案件已有方向标注!");
   });
   });
+  scene.on("confirmDelete", async (uuid) => {
+    const res = await ElMessageBox.confirm("是否删除该部件?", "温馨提示", {
+      confirmButtonText: "确定",
+      cancelButtonText: "取消",
+      type: "default",
+    });
+    if (res) {
+      window.scene.deleteItemById(uuid);
+    }
+  });
   scene.on("data", (data) => {
   scene.on("data", (data) => {
     let hasData = false;
     let hasData = false;
     Object.keys(data).forEach((key) => {
     Object.keys(data).forEach((key) => {
@@ -199,14 +211,25 @@ const handleDetele = async (item) => {
     refresh();
     refresh();
   }
   }
 };
 };
+const handleLine = () => {
+  if (window.scene) {
+    window.scene.player.setMode(1);
+  }
+};
 const handleMark = () => {
 const handleMark = () => {
   if (window.scene) {
   if (window.scene) {
     window.scene.player.setMode(2);
     window.scene.player.setMode(2);
   }
   }
 };
 };
-const handleLine = () => {
+
+const handleSymbol = () => {
   if (window.scene) {
   if (window.scene) {
-    window.scene.player.setMode(1);
+    window.scene.player.setMode(3);
+  }
+};
+const handleText = () => {
+  if (window.scene) {
+    window.scene.player.setMode(4);
   }
   }
 };
 };
 const handleSave = async () => {
 const handleSave = async () => {