bill 2 年 前
コミット
e1d1eaffb6

+ 1 - 1
src/components/base/assets/scss/_base-vars.scss

@@ -48,7 +48,7 @@
   --editer-menu-fill: 27, 27, 28;
   --editor-menu-back: #161A1A;
   --editor-menu-active-back: rgba(var(--colors-primary-fill), 0.06);
-  --editor-men-color: rgba(255,255,255,0.7);
+  --editor-men-color: rgba(255,255,255,1);
 
   --editor-toolbox-width: 340px;
   --editor-toolbox-back: var(--editor-menu-back);

+ 1 - 0
src/components/base/assets/scss/editor/_menu.scss

@@ -11,6 +11,7 @@
     bottom: 0;
     z-index: 2;
     overflow: hidden;
+    overflow-y: auto;
 
     backdrop-filter: blur(4px);
 

+ 2 - 0
src/components/group-button/index.vue

@@ -7,6 +7,7 @@
       :style="menuStyle"
       :class="{ active: activeKey === menu.key, dire, disabled: disabledMap[menu.key], border: menu.border }"
       @click="menu.onClick && menu.onClick(menu)"
+      v-show="!menu.hide"
     >
       <template v-if="$slots.default">
         <slot :data="menu" />
@@ -25,6 +26,7 @@ import {computed} from "vue";
 type Menu =  {
   key: any,
   text?: string,
+  hide?: boolean
   border?: boolean
   icon?: string,
   disabled?: boolean | (() => boolean)

+ 33 - 0
src/graphic/Geometry/Text.js

@@ -19,6 +19,39 @@ export default class Text extends Geometry {
     this.setId(vectorId);
   }
 
+  getBound(ctx) {
+    ctx.save()
+    ctx.font = `${
+      this.fontSize * coordinate.ratio
+    }px Microsoft YaHei`;
+    const text = ctx.measureText(this.value);
+    const height = text.actualBoundingBoxAscent + text.actualBoundingBoxDescent;
+    const info = { width: text.width, height };
+    const screen = coordinate.getScreenXY(this.center);
+    const center = {
+      y: screen.y + Style.Point.radius,
+      x: screen.x,
+    }
+    const p1 =  {
+      x: center.x - info.width / 2,
+      y: center.y
+    }
+    const p2 = {
+      x: center.x + info.width / 2,
+      y: center.y
+    }
+    const p3 = {
+      x: center.x + info.width / 2,
+      y: center.y + info.height
+    }
+    const p4 = {
+      x: center.x - info.width / 2,
+      y: center.y + info.height
+    }
+    ctx.restore()
+
+    return [p1, p2, p3, p4].map(pos => coordinate.getXYFromScreenNotRatio(pos))
+  }
   getAngle() {
     return this.angle;
   }

+ 1 - 0
src/graphic/Layer.js

@@ -56,6 +56,7 @@ export default class Layer {
     this.uiControl = new UIControl(this, newsletter, graphicState);
     this.renderer = new Render(this);
     this.history = new History(this);
+    this.coordinate = coordinate
     this.mousePosition = null;
     this.dragging = false; // 当前是否正在拖拽
     this.start();

+ 6 - 2
src/graphic/Renderer/Draw.js

@@ -12,7 +12,7 @@ import VectorStyle from "@/graphic/enum/VectorStyle.js";
 import VectorWeight from "@/graphic/enum/VectorWeight.js";
 
 const imgCache = {};
-const help = {
+export const help = {
   getVectorStyle(vector, geoType = vector.geoType) {
     const geoId = vector?.vectorId;
     if (!geoId || Settings.screenMode) {
@@ -149,7 +149,8 @@ const help = {
     return (
       Math.round(
         (mathUtil.getDistance(p1, p2) * coordinate.res * 100) / coordinate.ratio
-      ) / 100
+      )
+      / 100
     );
   },
   getPerpendicularPoint(p1, p2, p3, d) {
@@ -1096,6 +1097,9 @@ export default class Draw {
 
     vector.displayPoint &&
       this.drawPoint({ ...vector.center, color: vector.color }, true);
+
+
+    // vector.getBound(this.context).forEach(this.drawPoint.bind(this))
   }
 
   drawSVG(vector) {

+ 8 - 2
src/sdk/carry/measures/index.vue

@@ -11,7 +11,7 @@
 <script setup lang="ts">
 import MeasureItem from './item.vue'
 import { propsKey, laserKey } from '../constant'
-import { inject, computed, ref, watch } from 'vue'
+import {inject, computed, ref, watch, watchEffect} from 'vue'
 import {MeasureUnit} from "@/sdk";
 import {tempMeasures} from "@/store/measure";
 import {customMap} from "@/hook";
@@ -22,7 +22,13 @@ const laser = inject(laserKey)
 const refs = ref([])
 const measureMap = props.measureMap
 
-const measure = computed(() => trackMode.value ?  props.store.measure.tempMeasures : [...props.store.measure.list, ...props.store.baseLine.baseLines])
+const measure = computed(() => {
+  console.error(trackMode.value)
+  return trackMode.value ?  props.store.measure.tempMeasures : [...props.store.measure.list, ...props.store.baseLine.baseLines]
+})
+watchEffect(() => {
+  console.error(props.store.measure.tempMeasures[0])
+})
 
 watch(
   refs,

+ 1 - 1
src/sdk/types/sdk.ts

@@ -17,7 +17,7 @@ import { ModelModelAtom } from "./model";
 export type SceneEventMap = {
   buildingChange: ModelModelAtom;
   allLoaded: void;
-  posChange: Pos3D & { dataset: string[] };
+  posChange: Pos3D & { dataset: string[], meterPerPixel: number };
   loaded: void;
   webglError: void;
   visible: boolean;

+ 4 - 1
src/views/graphic/geos/road.vue

@@ -75,8 +75,11 @@ const menus = ref([
   }
 ])
 
+console.log(vector.value)
 watchEffect(() => {
-  menus.value[1].disabled = vector.value?.singleRoadDrivewayCount === 1
+  if (vector.value) {
+    menus.value[1].disabled = vector.value?.leftLanes.length + vector.value?.rightLanes.length + vector.value?.singleLanes.length === 0
+  }
 })
 
 </script>

+ 2 - 0
src/views/graphic/geos/roadEdge.vue

@@ -96,8 +96,10 @@ const appendMenus = props.geo.type === VectorType.CurveRoadEdge
     ]
   : []
 const childMenus = ref<UnwrapRef<typeof menus>>()
+// console.log(vector.value)
 const menus = ref([
   {
+    hide: props.geo.type === VectorType.CurveRoadEdge,
     key: UITypeExtend.lineType,
     text: "单实线",
     icon: "line",

+ 39 - 2
src/views/graphic/header.vue

@@ -40,21 +40,31 @@
         制表
       </ui-button>
     </div>
+    <div
+        class="meterPerPixel"
+        v-if="currentMeterPerPixel"
+        :style="{color: graphicState.showBackImage ? '#fff' : '#16181A'}"
+    >
+      1 : {{ currentMeterPerPixel }}
+    </div>
   </div>
+
 </template>
 <script lang="ts" setup>
 import UiIcon from "@/components/base/components/icon/index.vue";
 import UiButton from "@/components/base/components/button/index.vue";
 import {Mode} from './menus'
 import {changeStore, drawRef, graphicState} from '@/hook/useGraphic'
-import {computed, watchEffect} from "vue";
+import {computed, onActivated, onDeactivated, ref, watchEffect} from "vue";
 import {router, writeRouteName} from '@/router'
 import {AccidentPhoto, accidentPhotos, types} from '@/store/accidentPhotos'
 import {useData} from './data'
 import UiInput from "@/components/base/components/input/index.vue";
 import {roadPhotos} from "@/store/roadPhotos";
-import {back, uploadImage} from '@/store/sync'
+import {uploadImage} from '@/store/sync'
 import {genUseLoading} from "@/hook";
+
+
 import {dataService} from "@/graphic/Service/DataService";
 
 const data = useData()
@@ -63,6 +73,22 @@ const isRoad = computed(() => mode.value === Mode.Road)
 const options = computed(() =>
   !isRoad.value ? types.map(t => ({label: t, value: t})) : null
 )
+const currentMeterPerPixel = ref()
+let interval
+onActivated(() => {
+  interval = setInterval(() => {
+    if (drawRef.value) {
+      const coordinate = drawRef.value.coordinate;
+      const p1 = coordinate.getXYFromScreen({x: 0, y: 0})
+      const p2 = coordinate.getXYFromScreen({x: 0, y: 1})
+      const num = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
+      const meterPerPixel =((num * coordinate.res * 100) / coordinate.ratio) / 100
+      currentMeterPerPixel.value = Math.round(1 / meterPerPixel)
+    }
+  }, 200)
+})
+onDeactivated(() => clearInterval(interval))
+
 const backImageChang = (show) => {
   dataService.setGridDisplay(!show)
   drawRef.value.uiControl.menu_backgroundImg(show)
@@ -222,6 +248,17 @@ const createTable = async () => {
   align-items: center;
   margin-left: -3px;
 }
+
+.meterPerPixel {
+  position: absolute;
+  top: 100%;
+  right: 24px;
+  margin-top: 24px;
+  pointer-events: none;
+  font-size: 20px;
+  font-weight: 400;
+  line-height: 23px;
+}
 </style>
 
 <style lang="scss">

+ 1 - 1
src/views/graphic/index.vue

@@ -41,7 +41,7 @@ import {router} from '@/router'
 import {computed, watchEffect} from "vue";
 import {customMap} from '@/hook'
 import {focusMenuRaw, generateMixMenus, mainMenusRaw, photoMenusRaw, Mode, UITypeExtend} from './menus'
-import {currentVector, graphicState, uiType} from "@/hook/useGraphic";
+import {currentVector, drawRef, graphicState, uiType} from "@/hook/useGraphic";
 import geos, {GlobalComp} from "./geos/index";
 
 const menusRaws = computed(() => {

+ 15 - 13
src/views/graphic/menus.ts

@@ -83,20 +83,21 @@ export const measureMenusRaw = [
     text: '基准线',
     disabled: computed(() => graphicState.value.existsBaseLine),
   },
-  { key: UIType.BasePoint, text: '基准点', icon: 'point' },
-  {
-    key: UIType.NormalLocationMode,
-    text: '垂线定位',
-    icon: 'measure_f',
-    onClick(data) {
-      if (graphicState.value.canVerticalMeasure) {
-        uiType.change(data.key);
-      } else {
-        Message.success({ msg: '请添加基准线后再执行此操作', time: 3000 });
-      }
-    },
-  },
+  { key: UIType.BasePoint, text: '基准点', icon: 'point', border: true },
+  // {
+  //   key: UIType.NormalLocationMode,
+  //   text: '垂线定位',
+  //   icon: 'measure_f',
+  //   onClick(data) {
+  //     if (graphicState.value.canVerticalMeasure) {
+  //       uiType.change(data.key);
+  //     } else {
+  //       Message.success({ msg: '请添加基准线后再执行此操作', time: 3000 });
+  //     }
+  //   },
+  // },
   {
+    desc: "一键测量",
     key: UIType.AngleLocationMode,
     text: '直角定位法',
     icon: 'measure_r',
@@ -120,6 +121,7 @@ export const measureMenusRaw = [
         Message.success({ msg: '请添加基准线及基准点后再执行此操作', time: 3000 });
       }
     },
+    border: true
   },
   {
     key: UIType.FreeMeasureLine,

+ 3 - 7
src/views/scene/TrackMeasure.vue

@@ -22,7 +22,7 @@ import {measureDisabledStack} from '@/hook/custom'
 
 const props = defineProps<{ onConfirm: (data: SuccessMeasureAtom) => void }>()
 const active = ref(true)
-const callback = () => {4
+const callback = () => {
   props.onConfirm(tempMeasures.value[0] as any)
   tempMeasures.value = []
 }
@@ -34,17 +34,13 @@ watchEffect(() => {
         if (measure) {
           active.value = null
           tempMeasures.value = [measure]
+
+          console.log(tempMeasures.value)
         }
       })
   }
 })
 
-onMounted(() => {
-  measureDisabledStack.push(ref(true))
-})
-onActivated(() => {
-  measureDisabledStack.pop()
-})
 </script>
 
 <style lang="scss" scoped>

+ 26 - 5
src/views/scene/container.vue

@@ -1,5 +1,6 @@
 <template>
   <div class="canvas-layout">
+    <p v-if="currentMeterPerPixel" class="meterPerPixel">1: {{currentMeterPerPixel}}</p>
     <div class="scene-canvas" ref="sceneLayoutRef" />
   </div>
 </template>
@@ -27,9 +28,9 @@ const handlerSDK = (sdk: LaserSDK) => {
   })
 }
 
+const currentMeterPerPixel = ref(0)
+
 onMounted(async () => {
-  console.log(currentApp.basePath);
-  console.log("加载场景数据")
   const sdk = await useLoading(
     setupLaser({
       sceneSelector: sceneLayoutRef.value,
@@ -43,10 +44,13 @@ onMounted(async () => {
     })
   );
 
-  console.log("场景数据加载完成")
   emit('loaded')
 
-
+  sdk.scene.on('posChange', pos => {
+    currentMeterPerPixel.value = pos.meterPerPixel ? Math.round(1 / pos.meterPerPixel) : null
+  })
+  // 156  170
+  // 90
   setTimeout(() => {
     watchEffect(() => {
       const doms = Array.from(sceneLayoutRef.value.querySelectorAll("#navCube, #home")) as HTMLElement[]
@@ -93,10 +97,13 @@ onMounted(async () => {
 
 <style lang="scss">
 .canvas-layout  {
+
+  .meterPerPixel,
   #navCube{
     position: absolute !important;
     right: calc(var(--boundMargin) + 10px) !important;
     top: calc(var(--boundMargin) + 10px) !important;
+    z-index: 1;
   }
   #home {
     position: absolute !important;
@@ -113,7 +120,7 @@ onMounted(async () => {
     font-style: normal;
     -webkit-font-smoothing: antialiased;
     background: none !important;
-    z-index: 1;
+    z-index: 2;
     color: #fff;
     transition: all .3s ease;
 
@@ -126,5 +133,19 @@ onMounted(async () => {
       color: #3290ff;
     }
   }
+
+  .meterPerPixel {
+    text-align: center;
+    width: 100px;
+    color: #fff;
+    margin-top: 100px;
+    z-index: 999;
+    pointer-events: none;
+    font-weight: 400;
+    line-height: 23px;
+    font-size: 20px;
+    text-shadow: 0px 1px 0px rgba(0,0,0,0.5);
+  }
 }
+
 </style>

+ 1 - 0
src/views/scene/covers/measures.vue

@@ -25,6 +25,7 @@ import {ref} from "vue";
 import ActionsPanel from "@/views/scene/covers/actions.vue";
 import {customMap} from "@/hook";
 import ActionMenus from "@/components/group-button/index.vue";
+import * as process from "process";
 
 const active = ref<MeasureAtom>()
 const getStore = (item: MeasureAtom) =>

+ 0 - 3
src/views/scene/trackMeasureWidth.ts

@@ -12,12 +12,10 @@ import {list} from '@/store/measure'
 
 export const trackMode = ref(false)
 
-watchEffect(() => console.error(customMap.mode))
 export const trackMeasureWidth = async () => {
   trackMode.value = true
   await router.push({ name: writeRouteName.scene })
   const sdk = await useAsyncSDK()
-  list.value.forEach(item => sdk.carry.measureMap.get(item).hide())
 
   laserModeStack.push(ref(Mode.cloud))
   await new Promise(resolve => setTimeout(resolve, 10))
@@ -35,7 +33,6 @@ export const trackMeasureWidth = async () => {
   })
   laserModeStack.pop()
   await router.back()
-  list.value.forEach(item => sdk.carry.measureMap.get(item).show())
   await new Promise(resolve => setTimeout(resolve, 100))
   sdk.leaveTopView()
   trackMode.value = false

+ 3 - 2
src/views/sys/menu/item/index.vue

@@ -7,7 +7,7 @@
     :ref="attrs.children[0].menuRef"
     :data-route-name="attrs.atom.name"
     class="menu-item"
-    :class="{disabled: attrs.atom.disabled?.value}"
+    :class="{disabled: attrs.atom.disabled?.value, border: attrs.atom.border}"
     @enter="enterHandler"
     @leave="leaveHandler"
     @click="emit('select', attrs.atom)"
@@ -37,7 +37,8 @@
     :ref="attrs.children[index].menuRef"
     :data-route-name="raw.name"
     class="menu-item child-menu-item"
-    :class="{disabled: raw.disabled?.value}"
+    :class="{disabled: raw.disabled?.value, border: raw.border}"
+    :tip="raw.desc"
     @enter="enterHandler(index)"
     @leave="leaveHandler(index)"
     @click="selectHandler(index, raw)"

+ 27 - 0
src/views/sys/menu/item/style.scss

@@ -7,6 +7,19 @@
     top: 50%;
     transform: translateY(-50%);
   }
+  &[tip] {
+    margin-top: 20px;
+    position: relative;
+  }
+  &[tip]:before {
+    bottom: 100%;
+    position: absolute;
+    content: attr(tip);
+    font-size: 10px;
+    font-weight: 400;
+    color: rgba(255,255,255,0.8);
+
+  }
 }
 
 .child-menu-item {
@@ -39,3 +52,17 @@
     background-color: var(--editor-menu-active-back);
   }
 }
+
+
+.border {
+  position: relative;
+}
+.border:after {
+  content: "";
+  display: inline-block;
+  width: 70%;
+  height: 1px;
+  background-color: rgba(255, 255, 255, 0.10);
+  position: absolute;
+  bottom: 0;
+}

+ 4 - 0
src/views/sys/menu/style.scss

@@ -46,3 +46,7 @@
   align-items: center;
   justify-content: center;
 }
+
+.border {
+  border-bottom: 1px solid #fff;
+}