Browse Source

补点核心功能完成

任一存 1 year ago
parent
commit
8f1b80108c
2 changed files with 121 additions and 100 deletions
  1. 115 97
      src/App.vue
  2. 6 3
      src/utils.js

+ 115 - 97
src/App.vue

@@ -214,15 +214,27 @@ let brushRightPx = 0
 let brushBottomPx = 0
 
 function resetGlobalVars() {
-  pxPerUnitLength = 0 // 原始单位长度对应的像素数
+  // 视口尺寸
+  svgWidth = document.documentElement.clientWidth - 200
+  svgHeight = document.documentElement.clientHeight - 280
+  svgRatio = svgWidth / svgHeight
+
+  // 全体点位数据
   rawWholeData = []
   wholeDataForRender = []
-  xCenter = 0
-  yCenter = 0
-  startPoint = null
-  endPoint = null
-  pointDistance = 0
-  rowSlope = 0
+
+  // 由原始数据算出的几何信息
+  pxPerUnitLength = 0 // 原始数据1单位长度对应的像素数
+  pointDistance = 0 // 最近相邻点间距离(单位:原始数据中长度单位)
+  rowSlope = 0 // 点位构成的排的斜率 [0deg, 90deg)
+  xCenter = 0 
+  yCenter = 0 
+
+  // d3选择框位置
+  brushLeftPx = 0
+  brushTopPx = 0
+  brushRightPx = 0
+  brushBottomPx = 0
 }
 
 function zoomed({transform}) {
@@ -373,85 +385,95 @@ export default {
       gNode.selectAll('circle').remove()
       
 
-      const that = this
       getWholeData(this.sceneNameOrUrl).then((res) => {
         rawWholeData = res
+        this.renderWholePoints()
+      }).finally(() => {
+        this.loadingHandler.close()
+      })
+    },
+    renderWholePoints() {
+      const that = this
 
-        // 相邻点位间距离
-        const temp = computePointDistanceAndRowSlope(rawWholeData)
-        pointDistance = temp[0]
-        rowSlope = temp[1]
-        
-        // 所有点的分布情况
-        let xArray = rawWholeData.map((eachPoint) => {
-          return eachPoint.x
-        })
-        let xLength = Math.max(...xArray) - Math.min(...xArray)
-        xCenter = (Math.max(...xArray) + Math.min(...xArray)) / 2
+      // 相邻点位间距离
+      const temp = computePointDistanceAndRowSlope(rawWholeData)
+      pointDistance = temp[0]
+      rowSlope = temp[1]
+      
+      // 所有点的分布情况
+      let xArray = rawWholeData.map((eachPoint) => {
+        return eachPoint.x
+      })
+      let xLength = Math.max(...xArray) - Math.min(...xArray)
+      xCenter = (Math.max(...xArray) + Math.min(...xArray)) / 2
 
-        let yArray = rawWholeData.map((eachPoint) => {
-          return eachPoint.y
-        })
-        let yLength = Math.max(...yArray) - Math.min(...yArray)
-        yCenter = (Math.max(...yArray) + Math.min(...yArray)) / 2
-        let zArray = rawWholeData.map((eachPoint) => {
-          return eachPoint.z
-        })
-        let zLength = Math.max(...zArray) - Math.min(...zArray)
-        let zMin = Math.min(...zArray)
-        let areaRatio = xLength / yLength
+      let yArray = rawWholeData.map((eachPoint) => {
+        return eachPoint.y
+      })
+      let yLength = Math.max(...yArray) - Math.min(...yArray)
+      yCenter = (Math.max(...yArray) + Math.min(...yArray)) / 2
+      let zArray = rawWholeData.map((eachPoint) => {
+        return eachPoint.z
+      })
+      let zLength = Math.max(...zArray) - Math.min(...zArray)
+      let zMin = Math.min(...zArray)
+      let areaRatio = xLength / yLength
 
-        // 各个点坐标映射到视口坐标
-        if (svgRatio >= areaRatio) { // 分布范围应略小于svg尺寸
-          pxPerUnitLength = svgHeight / yLength * 0.9
-        } else {
-          pxPerUnitLength = svgWidth / xLength * 0.9
-        }
-        let wholeXArrayInPx = xArray.map((eachX) => {
-          return (eachX - xCenter) * pxPerUnitLength + svgWidth / 2
+      // 各个点坐标映射到视口坐标
+      if (svgRatio >= areaRatio) { // 分布范围应略小于svg尺寸
+        pxPerUnitLength = svgHeight / yLength * 0.9
+      } else {
+        pxPerUnitLength = svgWidth / xLength * 0.9
+      }
+      let wholeXArrayInPx = xArray.map((eachX) => {
+        return (eachX - xCenter) * pxPerUnitLength + svgWidth / 2
+      })
+      let wholeYArrayInPx = yArray.map((eachY) => {
+        return (eachY - yCenter) * pxPerUnitLength + svgHeight / 2
+      })
+
+      // 组合成最终数据用来渲染
+      for (let index = 0; index < rawWholeData.length; index++) {
+        console.assert(rawWholeData[index].id === (index + 1), '数据点id和数据点在数组中的位置不相符!')
+        wholeDataForRender.push([
+          wholeXArrayInPx[index],
+          wholeYArrayInPx[index],
+          zArray[index],
+          rawWholeData[index].isManuallyAdded,
+          JSON.stringify(rawWholeData[index]),
+          rawWholeData[index].id
+        ])
+      }
+
+      gNode.selectAll('rect').data(wholeDataForRender).enter().append('rect')
+        .attr('x', (d) => d[0] - pointDistance * pxPerUnitLength / 2)
+        .attr('y', (d) => d[1] - pointDistance * pxPerUnitLength / 2)
+        .attr('width', pointDistance * pxPerUnitLength)
+        .attr('height', pointDistance * pxPerUnitLength)
+        .attr('fill', (d) => {
+          return `rgba(${Math.round((d[2] -zMin) / zLength * 255)}, 0, 0, ${d[3] ? '0.7' : '1'})`
         })
-        let wholeYArrayInPx = yArray.map((eachY) => {
-          return (eachY - yCenter) * pxPerUnitLength + svgHeight / 2
+        .attr('render-data', (d) => {
+          return d
         })
 
-        // 组合成最终数据用来渲染
-        for (let index = 0; index < rawWholeData.length; index++) {
-          console.assert(rawWholeData[index].id === (index + 1), '数据点id和数据点在数组中的位置不相符!')
-          wholeDataForRender.push([wholeXArrayInPx[index], wholeYArrayInPx[index], zArray[index], JSON.stringify(rawWholeData[index]), rawWholeData[index].id])
-        }
-
-        gNode.selectAll('rect').data(wholeDataForRender).enter().append('rect')
-          .attr('x', (d) => d[0] - pointDistance * pxPerUnitLength / 2)
-          .attr('y', (d) => d[1] - pointDistance * pxPerUnitLength / 2)
-          .attr('width', pointDistance * pxPerUnitLength)
-          .attr('height', pointDistance * pxPerUnitLength)
-          .attr('fill', (d) => {
-            return `rgba(${Math.round((d[2] -zMin) / zLength * 255)}, 0, 0, 1)`
-          })
-          .attr('render-data', (d) => {
-            return d
-          })
-
-        gNode.selectAll('rect').on('mouseover', function(e) {
-          d3.select(this).attr('fill', 'orange')
-          let renderDataItem = e.target.attributes['render-data'].value
-          let renderDataItemArray = renderDataItem.split(',')
-          that.infoText = `数据点id: ${renderDataItemArray[renderDataItemArray.length - 1]}, \n具体值: ${renderDataItem.match(/^[^{]+(\{.+\})[^}]+$/)[1]}`
-        }).on('mouseleave', function (e) {
-          d3.select(this).attr('fill', (d) => {
-            return `rgba(${Math.round((d[2] -zMin) / zLength * 255)}, 0, 0, 1)`
-          })
-          that.infoText = ''
+      gNode.selectAll('rect').on('mouseover', function(e) {
+        d3.select(this).attr('fill', 'orange')
+        let renderDataItem = e.target.attributes['render-data'].value
+        let renderDataItemArray = renderDataItem.split(',')
+        that.infoText = renderDataItem.match(/^[^{]+(\{.+\})[^}]+$/)[1]
+      }).on('mouseleave', function (e) {
+        d3.select(this).attr('fill', (d) => {
+          return `rgba(${Math.round((d[2] -zMin) / zLength * 255)}, 0, 0, ${d[3] ? '0.7' : '1'})`
         })
+        that.infoText = ''
+      })
 
-        zoomObj = d3.zoom().on("zoom", zoomed)
-        svgNode.call(zoomObj);
+      zoomObj = d3.zoom().on("zoom", zoomed)
+      svgNode.call(zoomObj);
 
-        brushObj = d3.brush().on("end", (e) => {
-          brushed(e)
-        })
-      }).finally(() => {
-        this.loadingHandler.close()
+      brushObj = d3.brush().on("end", (e) => {
+        brushed(e)
       })
     },
     renderPath() {
@@ -743,22 +765,6 @@ export default {
         }
       }
 
-      gNode.selectAll('rect')
-        .attr('fill', (d) => {
-          if (affectedPointList.find((affectedPoint) => {
-            // console.log(affectedPoint.id, d[4]);
-            return affectedPoint.id === d[4]
-          })) {
-            return 'blue'
-          } else if (pointInBrushList.find((pointInBrush) => {
-            return pointInBrush.id === d[4]
-          })) {
-            return 'green'
-          } else {
-            return `black`
-          }
-        })
-        
       if (!affectedPointList.length) {
         window.alert('请在已有点位附近新增点位。')
         return
@@ -769,7 +775,7 @@ export default {
       }
       
       let activePointIdx = 0
-      let newPointId = rawWholeData[rawWholeData.length - 1].id + 1
+      let newPointId = rawWholeData[rawWholeData.length - 1].id
       // 位于框选区域内的所有点位构成稀疏图模型,用邻接表表示,依次处理其顶点表中各顶点。
       while(activePointIdx <= pointInBrushList.length - 1) {
         // 拿到当前顶点
@@ -807,12 +813,14 @@ export default {
               })
               // 如果找到了匹配点
               if (matchedPoint) {
+                console.log(matchedPoint, 'sdfsdf');
                 // 记录自己与其关系。
                 if (neighbourType === 1) {
                   tempIds1.push(String(matchedPoint.id))
                 } else {
                   tempIds2.push(String(matchedPoint.id))
                 }
+
                 // 酌情修改这个外围点位与自己的关系。
 
                 // 相邻点位数组ids中,前4项表示上下左右邻居,后四项表示斜角邻居。
@@ -827,13 +835,13 @@ export default {
                 }
                 
                 if (!matchedPoint.ids.slice(idsStartIdx, idsEndIdx).find((id) => {
-                  return id === activePoint.id
+                  return id === String(activePoint.id)
                 })) {
                   const emptyIdx = matchedPoint.ids.slice(idsStartIdx, idsEndIdx).findIndex((id) => {
                     return id === '-1'
                   })
                   console.assert(emptyIdx !== -1, 'emptyIdx居然不存在?!')
-                  matchedPoint.ids[idsStartIdx + emptyIdx] = activePoint.id
+                  matchedPoint.ids[idsStartIdx + emptyIdx] = String(activePoint.id)
                 }
               }
               // 如果没找到匹配点
@@ -850,7 +858,7 @@ export default {
             else {
               // 在顶点表中找匹配的点
               const matchedPoint = pointInBrushList.find((pointInBrush) => {
-                return getDistance2D(pointInBrush, neiPos) < pointDistance * 0.1
+                return getDistance2D(pointInBrush, neiPos) < pointDistance * 0.3
               })
               // 如果找到了匹配点
               if (matchedPoint) {
@@ -863,6 +871,8 @@ export default {
               }
               // 如果没找到匹配点
               else {
+                newPointId++
+
                 // 创建新点位,加入顶点表
                 pointInBrushList.push({
                   id: newPointId,
@@ -870,7 +880,6 @@ export default {
                   y: neiPos.y,
                   z: this.formData.addPointHeight,
                 })
-                newPointId++
 
                 // 记录自己与其关系
                 if (neighbourType === 1) {
@@ -912,7 +921,16 @@ export default {
         activePointIdx++
       } // end of 依次处理顶点表中各顶点
 
-      
+      // 新补的点加入rawWholeData
+      const oldIdMax = rawWholeData.length // 旧有的点的id最大值,据此判断哪些点是新增的
+      for (const pointInBrush of pointInBrushList) {
+        if (pointInBrush.id > oldIdMax) {
+          pointInBrush.isManuallyAdded = true
+          rawWholeData.push(pointInBrush)
+        }
+      }
+
+      this.renderWholePoints()
     }, // end of method addPoint
   },
 }

+ 6 - 3
src/utils.js

@@ -8,7 +8,7 @@ export function getDistance2D(point1, point2) {
 // 斜率slope:指的是点位阵列排列的每行斜率。计算方法:取考察点“上下左右”(注意与x轴、y轴方向无必然关系)的邻居,即与它最近的四个邻居,分别计算邻居与它的连线的斜率,限定斜率范围是[0, +Infinity),不符合则计算其负倒数。
 export function computePointDistanceAndRowSlope(rawWholeData) {
   // return 0.36
-  const sampleNumber = Math.min(1000, rawWholeData.length)
+  const sampleNumber = 1000
   let pointDistance = null
   let rowSlope = null
   while((pointDistance === null) || (rowSlope === null)) {
@@ -19,6 +19,9 @@ export function computePointDistanceAndRowSlope(rawWholeData) {
       const sample = rawWholeData[sampleIdx]
       for (const neighbourId of sample.ids.slice(0, 4)) {
         if (neighbourId !== "-1") {
+          // if (!rawWholeData[neighbourId - 1]) {
+          //   continue
+          // }
           distanceList.push(getDistance2D(sample, rawWholeData[neighbourId - 1]))
           let rowSlopeTemp = null
           if (Math.abs(Number(sample.x) - Number(rawWholeData[neighbourId - 1].x)) <= Number.EPSILON) {
@@ -96,8 +99,8 @@ export function getNeighbourLocations(centerPointPos, pointDistance, rowSlope) {
   }
   // 相当于left的top
   const posTopLeft = {
-    x: posLeft.x + pointDistance * Math.cos(alpha),
-    y: posLeft.y + pointDistance * Math.sin(alpha),
+    x: posLeft.x - pointDistance * Math.cos(Math.PI / 2 - alpha),
+    y: posLeft.y + pointDistance * Math.sin(Math.PI / 2 - alpha),
   }
   return {
     posRight,