From 257db2f3d3d9ac801231cf19650ba8d27bfbb634 Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Tue, 28 Nov 2023 15:29:31 +0800 Subject: [PATCH 1/6] feat(lb-annotation): Add filterPreResult to mainViewInstance --- .../src/core/pointCloud/cache.ts | 39 +++- .../core/pointCloud/generateIndexWorker.js | 24 +++ .../src/core/pointCloud/index.ts | 15 ++ packages/lb-annotation/src/types/index.d.ts | 5 + packages/lb-annotation/src/utils/MathUtils.ts | 176 +++++++++++++++++- 5 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 packages/lb-annotation/src/core/pointCloud/generateIndexWorker.js diff --git a/packages/lb-annotation/src/core/pointCloud/cache.ts b/packages/lb-annotation/src/core/pointCloud/cache.ts index 471e76b8d..ca32fd19d 100644 --- a/packages/lb-annotation/src/core/pointCloud/cache.ts +++ b/packages/lb-annotation/src/core/pointCloud/cache.ts @@ -4,12 +4,15 @@ * @author Ron */ +import GenerateIndexWorker from 'web-worker:./generateIndexWorker.js'; import { PCDLoader } from './PCDLoader'; type TCacheInfo = { src: string; }; +const generateIndexWorker = new GenerateIndexWorker({ type: 'module' }); + export class PointCloudCache { public pcdLoader: PCDLoader; @@ -19,6 +22,8 @@ export class PointCloudCache { private colorMap: Map; + private cacheIndexMap: Map>; + private cacheList: Array = []; private static instance: PointCloudCache; @@ -29,7 +34,7 @@ export class PointCloudCache { this.pcdLoader = new PCDLoader(); this.pointsMap = new Map(); this.colorMap = new Map(); - + this.cacheIndexMap = new Map(); this.cache2DHighlightIndex = new Map(); } @@ -95,4 +100,36 @@ export class PointCloudCache { public clearCache2DHighlightIndex() { this.cache2DHighlightIndex.clear(); } + + /** + * Asynchronously loads an index map from a given source. + * If the index map is already cached, it returns the cached version. + * Otherwise, it creates a new worker to generate the index map, + * caches it for future use, and then returns it. + * + * @param {string} src - The source from which to load the index map. + * @param {Float32Array} points - The points to be used in generating the index map. + * @returns {Promise} - A promise that resolves to the loaded index map. + */ + public loadIndexMap = async (src: string, points: Float32Array) => { + const currentCacheIndexMap = this.cacheIndexMap.get(src); + + if (currentCacheIndexMap) { + return currentCacheIndexMap; + } + + return new Promise((resolve) => { + if (window.Worker) { + generateIndexWorker.postMessage({ + points, + }); + + generateIndexWorker.onmessage = (e: any) => { + const { indexMap } = e.data; + this.cacheIndexMap.set(src, indexMap); + resolve(indexMap); + }; + } + }); + }; } diff --git a/packages/lb-annotation/src/core/pointCloud/generateIndexWorker.js b/packages/lb-annotation/src/core/pointCloud/generateIndexWorker.js new file mode 100644 index 000000000..305c138f8 --- /dev/null +++ b/packages/lb-annotation/src/core/pointCloud/generateIndexWorker.js @@ -0,0 +1,24 @@ +onmessage = function onmessage(e) { + const { points } = e.data; + + const indexMap = new Map(); + + for (let i = 0; i < points.length; i += 3) { + const x = points[i]; + const y = points[i + 1]; + const z = points[i + 2]; + + const key = `${Math.ceil(x)}@${Math.ceil(y)}@${Math.ceil(z)}`; + + if (!indexMap.has(key)) { + indexMap.set(key, []); + } + indexMap.get(key).push({ + x, + y, + z, + }); + } + + this.postMessage({ indexMap }); +}; diff --git a/packages/lb-annotation/src/core/pointCloud/index.ts b/packages/lb-annotation/src/core/pointCloud/index.ts index aa911b393..d8adf7fae 100644 --- a/packages/lb-annotation/src/core/pointCloud/index.ts +++ b/packages/lb-annotation/src/core/pointCloud/index.ts @@ -1013,6 +1013,21 @@ export class PointCloud extends EventListener { return mergeList; }; + public filterPreResult = async (src: string, config: any, boxParamsList) => { + const { points } = await this.cacheInstance.loadPCDFile(src); + const indexMap = await this.cacheInstance.loadIndexMap(src, points as Float32Array); + + return new Promise((resolve) => { + const boxes = boxParamsList.map((boxParams) => { + const newBox = MathUtils.calculatePointsInsideBox(indexMap, boxParams); + + const valid = newBox.count > config.lowerLimitPointsNumInBox; + return { ...newBox, valid }; + }); + resolve(boxes); + }); + }; + /** * It needs to be updated after load PointCloud's data. * @param boxParams diff --git a/packages/lb-annotation/src/types/index.d.ts b/packages/lb-annotation/src/types/index.d.ts index 09423ad48..bc4cfbd96 100644 --- a/packages/lb-annotation/src/types/index.d.ts +++ b/packages/lb-annotation/src/types/index.d.ts @@ -21,3 +21,8 @@ declare module 'web-worker:./MathUtilsWorker.js' { const content: any; export default content; } + +declare module 'web-worker:./generateIndexWorker.js' { + const content: any; + export default content; +} diff --git a/packages/lb-annotation/src/utils/MathUtils.ts b/packages/lb-annotation/src/utils/MathUtils.ts index 562f209b5..eed491587 100644 --- a/packages/lb-annotation/src/utils/MathUtils.ts +++ b/packages/lb-annotation/src/utils/MathUtils.ts @@ -4,13 +4,12 @@ // eslint-disable-next-line import MathUtilsWorker from 'web-worker:./MathUtilsWorker.js'; -import { IBasicLine, IBasicPoint, TAnnotationViewData } from '@labelbee/lb-utils'; +import { IBasicLine, IBasicPoint, IPointCloudBox, TAnnotationViewData } from '@labelbee/lb-utils'; import { DEFAULT_FONT, DEFAULT_TEXT_MAX_WIDTH, ELineTypes, SEGMENT_NUMBER } from '@/constant/tool'; import { IPolygonData, IPolygonPoint } from '@/types/tool/polygon'; -import { createSmoothCurvePointsFromPointList } from './tool/polygonTool'; +import { createSmoothCurvePointsFromPointList, isInPolygon } from './tool/polygonTool'; import PolygonUtils from './tool/PolygonUtils'; import Vector from './VectorUtils'; - /** * 基础的三角运算 */ @@ -28,6 +27,90 @@ export class Trigonometric { } } +enum CubePosition { + Outside = 0, + PartiallyInside = 1, + FullyInside = 2, +} + +function getCubePosition(bigCube: Cube, smallCube: Cube): CubePosition { + // 计算小立方体的8个顶点 + const smallCubeVertices: Point[] = [ + { + x: smallCube.x - smallCube.width / 2, + y: smallCube.y - smallCube.height / 2, + z: smallCube.z - smallCube.depth / 2, + }, + { + x: smallCube.x + smallCube.width / 2, + y: smallCube.y - smallCube.height / 2, + z: smallCube.z - smallCube.depth / 2, + }, + { + x: smallCube.x - smallCube.width / 2, + y: smallCube.y + smallCube.height / 2, + z: smallCube.z - smallCube.depth / 2, + }, + { + x: smallCube.x + smallCube.width / 2, + y: smallCube.y + smallCube.height / 2, + z: smallCube.z - smallCube.depth / 2, + }, + { + x: smallCube.x - smallCube.width / 2, + y: smallCube.y - smallCube.height / 2, + z: smallCube.z + smallCube.depth / 2, + }, + { + x: smallCube.x + smallCube.width / 2, + y: smallCube.y - smallCube.height / 2, + z: smallCube.z + smallCube.depth / 2, + }, + { + x: smallCube.x - smallCube.width / 2, + y: smallCube.y + smallCube.height / 2, + z: smallCube.z + smallCube.depth / 2, + }, + { + x: smallCube.x + smallCube.width / 2, + y: smallCube.y + smallCube.height / 2, + z: smallCube.z + smallCube.depth / 2, + }, + ]; + + // 计算在大立方体内的顶点数量 + let insideCount = 0; + for (let i = 0; i < smallCubeVertices.length; i++) { + if (MathUtils.isPointInsideCube(smallCubeVertices[i], bigCube)) { + insideCount++; + } + } + + // 根据在大立方体内的顶点数量返回结果 + if (insideCount === 0) { + return CubePosition.Outside; // 所有顶点都在大立方体外 + } + if (insideCount === 8) { + return CubePosition.FullyInside; // 所有顶点都在大立方体内 + } + return CubePosition.PartiallyInside; // 部分顶点在大立方体内,部分顶点在大立方体外 +} + +interface Point { + x: number; + y: number; + z: number; +} + +interface Cube { + x: number; + y: number; + z: number; + width: number; + height: number; + depth: number; +} + export default class MathUtils { /** * 是否在指定范围内 @@ -654,4 +737,91 @@ export default class MathUtils { return [fixedPoint, newSecondPoint, newThirdPoint, newFourthPoint]; } + + public static calculatePointsInsideBox = ( + indexMap: Map, + box: IPointCloudBox, + ) => { + const { center, width, height, depth } = box; + const { x, y, z } = center; + + const boxCube = { + x, + y, + z, + width, + height, + depth, + }; + + let count = 0; + + indexMap.forEach((point, key) => { + const keyArr = key.split('@'); + const cubicX = Number(keyArr[0]); + const cubicY = Number(keyArr[1]); + const cubicZ = Number(keyArr[2]); + + const cubePosition = getCubePosition(boxCube, { + x: cubicX - 0.5, + y: cubicY - 0.5, + z: cubicZ - 0.5, + width: 1, + height: 1, + depth: 1, + }); + + if (cubePosition === CubePosition.FullyInside) { + count += point.length; + } + + if (cubePosition === CubePosition.PartiallyInside) { + point.forEach((p) => { + if (MathUtils.isPointInsideCube(p, boxCube)) { + count++; + } + }); + } + }); + + return { ...box, count }; + }; + + public static isPointInsideCube(point: Point, cube: Cube): boolean { + const halfWidth = cube.width / 2; + const halfHeight = cube.height / 2; + const halfDepth = cube.depth / 2; + + const xMin = cube.x - halfWidth; + const xMax = cube.x + halfWidth; + const yMin = cube.y - halfHeight; + const yMax = cube.y + halfHeight; + const zMin = cube.z - halfDepth; + const zMax = cube.z + halfDepth; + + const polygon = [ + { + x: xMin, + y: yMin, + }, + { + x: xMax, + y: yMin, + }, + { + x: xMax, + y: yMax, + }, + { + x: xMin, + y: yMax, + }, + ]; + + const inPolygon = isInPolygon({ x: point.x, y: point.y }, polygon); + if (inPolygon && point.z >= zMin && point.z <= zMax) { + return true; + } + return false; + } } From a786d0569b279cc7b62f8243c3c623b83f965c48 Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Tue, 28 Nov 2023 15:32:00 +0800 Subject: [PATCH 2/6] feat(lb-components): When pointCloudData update filter preResult by PCD --- .../src/core/pointCloud/cache.ts | 1 + .../src/core/pointCloud/index.ts | 9 ++++--- packages/lb-annotation/src/utils/MathUtils.ts | 1 + .../hooks/usePointCloudViews.ts | 25 ++++++++++++++++--- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/lb-annotation/src/core/pointCloud/cache.ts b/packages/lb-annotation/src/core/pointCloud/cache.ts index ca32fd19d..f811bde14 100644 --- a/packages/lb-annotation/src/core/pointCloud/cache.ts +++ b/packages/lb-annotation/src/core/pointCloud/cache.ts @@ -4,6 +4,7 @@ * @author Ron */ +// eslint-disable-next-line import GenerateIndexWorker from 'web-worker:./generateIndexWorker.js'; import { PCDLoader } from './PCDLoader'; diff --git a/packages/lb-annotation/src/core/pointCloud/index.ts b/packages/lb-annotation/src/core/pointCloud/index.ts index d8adf7fae..c61a90065 100644 --- a/packages/lb-annotation/src/core/pointCloud/index.ts +++ b/packages/lb-annotation/src/core/pointCloud/index.ts @@ -1013,13 +1013,16 @@ export class PointCloud extends EventListener { return mergeList; }; - public filterPreResult = async (src: string, config: any, boxParamsList) => { + public filterPreResult = async (src: string, config: any, boxParamsList: any) => { const { points } = await this.cacheInstance.loadPCDFile(src); const indexMap = await this.cacheInstance.loadIndexMap(src, points as Float32Array); return new Promise((resolve) => { - const boxes = boxParamsList.map((boxParams) => { - const newBox = MathUtils.calculatePointsInsideBox(indexMap, boxParams); + const boxes = boxParamsList.map((boxParams: any) => { + const newBox = MathUtils.calculatePointsInsideBox( + indexMap as Map, + boxParams, + ); const valid = newBox.count > config.lowerLimitPointsNumInBox; return { ...newBox, valid }; diff --git a/packages/lb-annotation/src/utils/MathUtils.ts b/packages/lb-annotation/src/utils/MathUtils.ts index eed491587..159579098 100644 --- a/packages/lb-annotation/src/utils/MathUtils.ts +++ b/packages/lb-annotation/src/utils/MathUtils.ts @@ -81,6 +81,7 @@ function getCubePosition(bigCube: Cube, smallCube: Cube): CubePosition { // 计算在大立方体内的顶点数量 let insideCount = 0; for (let i = 0; i < smallCubeVertices.length; i++) { + // eslint-disable-next-line if (MathUtils.isPointInsideCube(smallCubeVertices[i], bigCube)) { insideCount++; } diff --git a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts index f6ed139dc..9c98a3c0d 100644 --- a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts +++ b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts @@ -1296,16 +1296,35 @@ export const usePointCloudViews = () => { * 2. Reload PointCloud * 3. Clear Polygon */ - topViewInstance.updateData(newData.url, newData.result, { - radius: config?.radius ?? DEFAULT_RADIUS, - }); if (newData.result) { boxParamsList = PointCloudUtils.getBoxParamsFromResultList(newData.result); + + if ( + boxParamsList?.length > 0 && + newData.isPreResult && + config?.lowerLimitPointsNumInBox > 0 + ) { + // @ts-ignore + boxParamsList = await mainViewInstance?.filterPreResult(newData.url, config, boxParamsList); + + const newDataResultObj = jsonParser(newData.result); + + const DEFAULT_STEP = `step_1`; + + newDataResultObj[DEFAULT_STEP].result = boxParamsList; + + newData.result = JSON.stringify(newDataResultObj); + + ptCtx.setPointCloudResult(boxParamsList); + } polygonList = PointCloudUtils.getPolygonListFromResultList(newData.result); lineList = PointCloudUtils.getLineListFromResultList(newData.result); sphereParamsList = PointCloudUtils.getSphereParamsFromResultList(newData.result); + topViewInstance.updateData(newData.url, newData.result, { + radius: config?.radius ?? DEFAULT_RADIUS, + }); // Add Init Box mainViewInstance?.generateBoxes(boxParamsList); mainViewInstance?.generateSpheres(sphereParamsList); From aa804c9b84f83ece1fb01946a97abc27b666a49a Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Wed, 29 Nov 2023 17:00:15 +0800 Subject: [PATCH 3/6] feat(lb-components): Set valid box by lowerLimitPointsNumInBox --- .../pointCloudView/PointCloudInfos.tsx | 2 +- .../hooks/usePointCloudViews.ts | 39 +++++++------------ 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/lb-components/src/components/pointCloudView/PointCloudInfos.tsx b/packages/lb-components/src/components/pointCloudView/PointCloudInfos.tsx index 34a5da09e..31821fe9e 100644 --- a/packages/lb-components/src/components/pointCloudView/PointCloudInfos.tsx +++ b/packages/lb-components/src/components/pointCloudView/PointCloudInfos.tsx @@ -145,7 +145,7 @@ export const BoxInfos = ({ infos.push({ label: t('PointCount'), - value: `${data.num}`, + value: `${selectedBox.info?.count ?? 0}`, }); // SubAttribute is shown in checkMode diff --git a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts index 9c98a3c0d..945677169 100644 --- a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts +++ b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts @@ -776,17 +776,6 @@ export const usePointCloudViews = () => { boxParams = nextResult[0]; - // If the count is less than lowerLimitPointsNumInBox, needs to delete it - if ( - config?.lowerLimitPointsNumInBox && - typeof boxParams.count === 'number' && - boxParams.count < config.lowerLimitPointsNumInBox - ) { - message.info(t('LowerLimitPointsNumInBox', { num: config.lowerLimitPointsNumInBox })); - polygonOperation.deletePolygon(boxParams.id); - return; - } - if (intelligentFit && newPointList?.length) { newPolygon.pointList = newPointList; } @@ -927,20 +916,6 @@ export const usePointCloudViews = () => { sideViewInstance.pointCloudInstance, ); - const nextResult = dispatch( - PreDataProcess({ - tool: EPointCloudName.PointCloud, - dataList: [newBoxParams], - stepConfig: config, - action: 'viewUpdateBox', - }), - ) as unknown as IPointCloudBox[]; - const newBox = nextResult[0]; - // 如果更新后的box valid没有变化,则不更新当前视图 - const updateCurrentView = newBoxParams.valid !== newBox.valid; - - newBoxParams = newBox; - // Update count if (mainViewInstance) { const { count } = mainViewInstance.getSensesPointZAxisInPolygon( @@ -957,6 +932,20 @@ export const usePointCloudViews = () => { }; } + const nextResult = dispatch( + PreDataProcess({ + tool: EPointCloudName.PointCloud, + dataList: [newBoxParams], + stepConfig: config, + action: 'viewUpdateBox', + }), + ) as unknown as IPointCloudBox[]; + const newBox = nextResult[0]; + // 如果更新后的box valid没有变化,则不更新当前视图 + const updateCurrentView = newBoxParams.valid !== newBox.valid; + + newBoxParams = newBox; + const newPointCloudBoxList = updateSelectedBox(newBoxParams); newBoxParams = newPointCloudBoxList.find( From 2bbacfaaa9dcc8b8e8c8eee7be558beba39ef0a7 Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Fri, 1 Dec 2023 14:33:43 +0800 Subject: [PATCH 4/6] feat(lb-annotation): Fix issues in calculatePointsInsideBox --- .../src/core/pointCloud/cache.ts | 24 +++-- .../src/core/pointCloud/index.ts | 24 ++--- packages/lb-annotation/src/utils/MathUtils.ts | 92 ++++++------------- .../hooks/usePointCloudViews.ts | 3 - 4 files changed, 50 insertions(+), 93 deletions(-) diff --git a/packages/lb-annotation/src/core/pointCloud/cache.ts b/packages/lb-annotation/src/core/pointCloud/cache.ts index f811bde14..d4d680408 100644 --- a/packages/lb-annotation/src/core/pointCloud/cache.ts +++ b/packages/lb-annotation/src/core/pointCloud/cache.ts @@ -12,7 +12,7 @@ type TCacheInfo = { src: string; }; -const generateIndexWorker = new GenerateIndexWorker({ type: 'module' }); +export type TIndexMap = Map; export class PointCloudCache { public pcdLoader: PCDLoader; @@ -23,7 +23,7 @@ export class PointCloudCache { private colorMap: Map; - private cacheIndexMap: Map>; + private cacheIndexMap: Map; private cacheList: Array = []; @@ -103,24 +103,21 @@ export class PointCloudCache { } /** - * Asynchronously loads an index map from a given source. - * If the index map is already cached, it returns the cached version. - * Otherwise, it creates a new worker to generate the index map, - * caches it for future use, and then returns it. + * Loads index map from cache or generates it in a worker. * - * @param {string} src - The source from which to load the index map. - * @param {Float32Array} points - The points to be used in generating the index map. - * @returns {Promise} - A promise that resolves to the loaded index map. + * @param src The path to the source image. + * @param points The points of the source image. + * @returns A promise that resolves to the index map. */ public loadIndexMap = async (src: string, points: Float32Array) => { const currentCacheIndexMap = this.cacheIndexMap.get(src); - if (currentCacheIndexMap) { - return currentCacheIndexMap; - } - return new Promise((resolve) => { + if (currentCacheIndexMap) { + return resolve(currentCacheIndexMap); + } if (window.Worker) { + const generateIndexWorker = new GenerateIndexWorker({ type: 'module' }); generateIndexWorker.postMessage({ points, }); @@ -129,6 +126,7 @@ export class PointCloudCache { const { indexMap } = e.data; this.cacheIndexMap.set(src, indexMap); resolve(indexMap); + generateIndexWorker.terminate(); }; } }); diff --git a/packages/lb-annotation/src/core/pointCloud/index.ts b/packages/lb-annotation/src/core/pointCloud/index.ts index c61a90065..7be73b731 100644 --- a/packages/lb-annotation/src/core/pointCloud/index.ts +++ b/packages/lb-annotation/src/core/pointCloud/index.ts @@ -30,7 +30,7 @@ import MathUtils from '@/utils/MathUtils'; import ImgUtils from '@/utils/ImgUtils'; import { PCDLoader } from './PCDLoader'; import { OrbitControls } from './OrbitControls'; -import { PointCloudCache } from './cache'; +import { PointCloudCache, TIndexMap } from './cache'; import { getCuboidFromPointCloudBox, getHighlightIndexByPoints, mergeHighlightList } from './matrix'; import { PointCloudSegmentOperation } from './segmentation'; import PointCloudStore from './store'; @@ -1013,19 +1013,21 @@ export class PointCloud extends EventListener { return mergeList; }; - public filterPreResult = async (src: string, config: any, boxParamsList: any) => { + public filterPreResult = async (src: string, config: any, boxParamsList: IPointCloudBox[]) => { const { points } = await this.cacheInstance.loadPCDFile(src); - const indexMap = await this.cacheInstance.loadIndexMap(src, points as Float32Array); + const indexMap = (await this.cacheInstance.loadIndexMap(src, points as Float32Array)) as TIndexMap; return new Promise((resolve) => { - const boxes = boxParamsList.map((boxParams: any) => { - const newBox = MathUtils.calculatePointsInsideBox( - indexMap as Map, - boxParams, - ); - - const valid = newBox.count > config.lowerLimitPointsNumInBox; - return { ...newBox, valid }; + const boxes = boxParamsList.map((boxParams: IPointCloudBox) => { + const count = MathUtils.calculatePointsInsideBox({ + indexMap, + polygon: getCuboidFromPointCloudBox(boxParams).polygonPointList as IPolygonPoint[], + zScope: [boxParams.center.z - boxParams.depth / 2, boxParams.center.z + boxParams.depth / 2], + box: boxParams, + }); + const valid = count >= config.lowerLimitPointsNumInBox; + + return { ...boxParams, valid, count }; }); resolve(boxes); }); diff --git a/packages/lb-annotation/src/utils/MathUtils.ts b/packages/lb-annotation/src/utils/MathUtils.ts index 159579098..a36cea019 100644 --- a/packages/lb-annotation/src/utils/MathUtils.ts +++ b/packages/lb-annotation/src/utils/MathUtils.ts @@ -4,9 +4,10 @@ // eslint-disable-next-line import MathUtilsWorker from 'web-worker:./MathUtilsWorker.js'; -import { IBasicLine, IBasicPoint, IPointCloudBox, TAnnotationViewData } from '@labelbee/lb-utils'; +import { I3DSpaceCoord, IBasicLine, IBasicPoint, IPointCloudBox, TAnnotationViewData } from '@labelbee/lb-utils'; import { DEFAULT_FONT, DEFAULT_TEXT_MAX_WIDTH, ELineTypes, SEGMENT_NUMBER } from '@/constant/tool'; import { IPolygonData, IPolygonPoint } from '@/types/tool/polygon'; +import { TIndexMap } from '@/core/pointCloud/cache'; import { createSmoothCurvePointsFromPointList, isInPolygon } from './tool/polygonTool'; import PolygonUtils from './tool/PolygonUtils'; import Vector from './VectorUtils'; @@ -33,9 +34,9 @@ enum CubePosition { FullyInside = 2, } -function getCubePosition(bigCube: Cube, smallCube: Cube): CubePosition { +function getCubePosition(polygon: IPolygonPoint[], zScope: [number, number], smallCube: Cube): CubePosition { // 计算小立方体的8个顶点 - const smallCubeVertices: Point[] = [ + const smallCubeVertices: I3DSpaceCoord[] = [ { x: smallCube.x - smallCube.width / 2, y: smallCube.y - smallCube.height / 2, @@ -82,7 +83,7 @@ function getCubePosition(bigCube: Cube, smallCube: Cube): CubePosition { let insideCount = 0; for (let i = 0; i < smallCubeVertices.length; i++) { // eslint-disable-next-line - if (MathUtils.isPointInsideCube(smallCubeVertices[i], bigCube)) { + if (MathUtils.isPointInsideCube(smallCubeVertices[i], polygon, zScope)) { insideCount++; } } @@ -97,12 +98,6 @@ function getCubePosition(bigCube: Cube, smallCube: Cube): CubePosition { return CubePosition.PartiallyInside; // 部分顶点在大立方体内,部分顶点在大立方体外 } -interface Point { - x: number; - y: number; - z: number; -} - interface Cube { x: number; y: number; @@ -112,6 +107,13 @@ interface Cube { depth: number; } +interface ICalculatePointsInsideBoxParams { + indexMap: TIndexMap; + polygon: IPolygonPoint[]; + zScope: [number, number]; + box: IPointCloudBox; +} + export default class MathUtils { /** * 是否在指定范围内 @@ -739,21 +741,8 @@ export default class MathUtils { return [fixedPoint, newSecondPoint, newThirdPoint, newFourthPoint]; } - public static calculatePointsInsideBox = ( - indexMap: Map, - box: IPointCloudBox, - ) => { - const { center, width, height, depth } = box; - const { x, y, z } = center; - - const boxCube = { - x, - y, - z, - width, - height, - depth, - }; + public static calculatePointsInsideBox = (params: ICalculatePointsInsideBoxParams) => { + const { indexMap, polygon, zScope, box } = params; let count = 0; @@ -763,63 +752,34 @@ export default class MathUtils { const cubicY = Number(keyArr[1]); const cubicZ = Number(keyArr[2]); - const cubePosition = getCubePosition(boxCube, { - x: cubicX - 0.5, - y: cubicY - 0.5, - z: cubicZ - 0.5, - width: 1, - height: 1, - depth: 1, - }); + const smallCube = { x: cubicX - 0.5, y: cubicY - 0.5, z: cubicZ - 0.5, width: 1, height: 1, depth: 1 }; + + const cubePosition = getCubePosition(polygon, zScope, smallCube); if (cubePosition === CubePosition.FullyInside) { count += point.length; } - if (cubePosition === CubePosition.PartiallyInside) { + if ( + cubePosition === CubePosition.PartiallyInside || + (cubePosition === CubePosition.Outside && (box.width <= 1 || box.height <= 1)) + ) { point.forEach((p) => { - if (MathUtils.isPointInsideCube(p, boxCube)) { + if (MathUtils.isPointInsideCube(p, polygon, zScope)) { count++; } }); } }); - return { ...box, count }; + return count; }; - public static isPointInsideCube(point: Point, cube: Cube): boolean { - const halfWidth = cube.width / 2; - const halfHeight = cube.height / 2; - const halfDepth = cube.depth / 2; - - const xMin = cube.x - halfWidth; - const xMax = cube.x + halfWidth; - const yMin = cube.y - halfHeight; - const yMax = cube.y + halfHeight; - const zMin = cube.z - halfDepth; - const zMax = cube.z + halfDepth; - - const polygon = [ - { - x: xMin, - y: yMin, - }, - { - x: xMax, - y: yMin, - }, - { - x: xMax, - y: yMax, - }, - { - x: xMin, - y: yMax, - }, - ]; + public static isPointInsideCube(point: I3DSpaceCoord, polygon: IPolygonPoint[], zScope: [number, number]): boolean { + const [zMin, zMax] = zScope; const inPolygon = isInPolygon({ x: point.x, y: point.y }, polygon); + if (inPolygon && point.z >= zMin && point.z <= zMax) { return true; } diff --git a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts index 945677169..231dc039c 100644 --- a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts +++ b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts @@ -38,8 +38,6 @@ import { SetPointCloudLoading, SetLoadPCDFileLoading, } from '@/store/annotation/actionCreators'; -import { message } from 'antd'; -import { useTranslation } from 'react-i18next'; import { useHistory } from './useHistory'; import { usePolygon } from './usePolygon'; import { IFileItem, IMappingImg } from '@/types/data'; @@ -654,7 +652,6 @@ export const usePointCloudViews = () => { const { selectedBox, updateSelectedBox, updateSelectedBoxes, getPointCloudByID } = useSingleBox({ generateRects, }); - const { t } = useTranslation(); const selectedPointCloudBox = selectedBox?.info; From a737fb33dc40774491cafa6f3d0b8312be111c4c Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Mon, 4 Dec 2023 15:39:09 +0800 Subject: [PATCH 5/6] feat(lb-annotation): Delete oldest entries when exceeded --- packages/lb-annotation/src/core/pointCloud/cache.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/lb-annotation/src/core/pointCloud/cache.ts b/packages/lb-annotation/src/core/pointCloud/cache.ts index d4d680408..af0a1f741 100644 --- a/packages/lb-annotation/src/core/pointCloud/cache.ts +++ b/packages/lb-annotation/src/core/pointCloud/cache.ts @@ -125,6 +125,12 @@ export class PointCloudCache { generateIndexWorker.onmessage = (e: any) => { const { indexMap } = e.data; this.cacheIndexMap.set(src, indexMap); + // 按照缓存一个 1.8M PCD(包含 points.length:360804)文件需要占用 2.8MB 内存粗略估算,缓存 50 个 pcd 文件大概需要 140MB 内存 + if (this.cacheIndexMap.size > this.MAX_SIZE) { + const firstKey = Array.from(this.cacheIndexMap.keys())[0]; + this.cacheIndexMap.delete(firstKey); + } + resolve(indexMap); generateIndexWorker.terminate(); }; From e4be5cdd5aeb99e2d71f1eafdead2ddfb7410fee Mon Sep 17 00:00:00 2001 From: lihqi <455711093@qq.com> Date: Mon, 4 Dec 2023 17:01:18 +0800 Subject: [PATCH 6/6] feat(lb-utils): Export point cloud default step --- .../hooks/usePointCloudViews.ts | 5 ++-- packages/lb-utils/src/PointCloudUtils.ts | 29 ++++++++----------- packages/lb-utils/src/index.ts | 3 +- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts index 231dc039c..b4565329a 100644 --- a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts +++ b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts @@ -22,6 +22,7 @@ import { IDefaultSize, IPolygonData, IBasicRect, + POINT_CLOUD_DEFAULT_STEP, } from '@labelbee/lb-utils'; import { useContext } from 'react'; import { PointCloudContext } from '../PointCloudContext'; @@ -1296,9 +1297,7 @@ export const usePointCloudViews = () => { const newDataResultObj = jsonParser(newData.result); - const DEFAULT_STEP = `step_1`; - - newDataResultObj[DEFAULT_STEP].result = boxParamsList; + newDataResultObj[POINT_CLOUD_DEFAULT_STEP].result = boxParamsList; newData.result = JSON.stringify(newDataResultObj); diff --git a/packages/lb-utils/src/PointCloudUtils.ts b/packages/lb-utils/src/PointCloudUtils.ts index b9458cd07..d33aa3d6f 100644 --- a/packages/lb-utils/src/PointCloudUtils.ts +++ b/packages/lb-utils/src/PointCloudUtils.ts @@ -8,6 +8,8 @@ import { IPointCloudBox, IPointCloudConfig, IPointCloudSphere } from './types/po import { ICoordinate, ISize } from './types/common'; import { IBasicBox3d } from './types'; +export const POINT_CLOUD_DEFAULT_STEP = `step_1`; + class PointCloudUtils { public static genColorByCoord(x: number, y: number, z: number) { if (z <= 0) { @@ -46,9 +48,8 @@ class PointCloudUtils { public static parsePointCloudCurrentResult(result: string) { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - const ptResult = data?.[DEFAULT_STEP] ?? {}; + const ptResult = data?.[POINT_CLOUD_DEFAULT_STEP] ?? {}; const boxParamsList = ptResult?.result ?? []; /** @@ -73,8 +74,7 @@ class PointCloudUtils { public static getBoxParamsFromResultList(result: string): IPointCloudBox[] { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - const pointCloudDataList = data?.[DEFAULT_STEP]?.result ?? []; + const pointCloudDataList = data?.[POINT_CLOUD_DEFAULT_STEP]?.result ?? []; return pointCloudDataList; } @@ -82,8 +82,7 @@ class PointCloudUtils { public static getSphereParamsFromResultList(result: string): IPointCloudSphere[] { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - const pointCloudDataList = data?.[DEFAULT_STEP]?.resultPoint ?? []; + const pointCloudDataList = data?.[POINT_CLOUD_DEFAULT_STEP]?.resultPoint ?? []; return pointCloudDataList; } @@ -91,8 +90,7 @@ class PointCloudUtils { public static getSegmentFromResultList(result: string) { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - const pointCloudDataList = data?.[DEFAULT_STEP]?.segmentation ?? []; + const pointCloudDataList = data?.[POINT_CLOUD_DEFAULT_STEP]?.segmentation ?? []; return pointCloudDataList; } @@ -143,9 +141,7 @@ class PointCloudUtils { public static getLineListFromResultList(result: string): any[] { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - - const pointCloudDataList = data?.[DEFAULT_STEP]?.resultLine ?? []; + const pointCloudDataList = data?.[POINT_CLOUD_DEFAULT_STEP]?.resultLine ?? []; return pointCloudDataList; } @@ -153,15 +149,15 @@ class PointCloudUtils { public static getPolygonListFromResultList(result: string): any[] { const data = this.jsonParser(result); - const DEFAULT_STEP = `step_1`; - /** * Notice. * * It needs to be compatible with the error data structure(`renderPolygon`), `resultPolygon` is the correct one. */ const pointCloudDataList = - data?.[DEFAULT_STEP]?.resultPolygon ?? data?.[DEFAULT_STEP]?.renderPolygon ?? []; + data?.[POINT_CLOUD_DEFAULT_STEP]?.resultPolygon ?? + data?.[POINT_CLOUD_DEFAULT_STEP]?.renderPolygon ?? + []; return pointCloudDataList; } @@ -306,7 +302,7 @@ class PointCloudUtils { * @param boxParams * @returns */ - public static getAllViewData(boxParams: IPointCloudBox | IBasicBox3d) { + public static getAllViewData(boxParams: IPointCloudBox | IBasicBox3d) { const { center: { x, y, z }, width, @@ -567,9 +563,8 @@ class PointCloudUtils { let basicSize: { width: number; height: number; depth: number } | undefined = undefined; imgList.forEach((imgInfo) => { - const DEFAULT_STEP_NAME = `step_${1}`; const originResult = this.jsonParser(imgInfo.result); - const dataList = originResult?.[DEFAULT_STEP_NAME]?.result; // PointCloudData1 + const dataList = originResult?.[POINT_CLOUD_DEFAULT_STEP]?.result; // PointCloudData1 if (!dataList) { return; diff --git a/packages/lb-utils/src/index.ts b/packages/lb-utils/src/index.ts index 9e918f373..6bedb68bd 100644 --- a/packages/lb-utils/src/index.ts +++ b/packages/lb-utils/src/index.ts @@ -7,7 +7,7 @@ import i18n from './i18n/index'; import toolStyleConverter, { ToolStyleUtils } from './toolStyle'; import PerspectiveShiftUtils from './PerspectiveShiftUtils'; -import PointCloudUtils from './PointCloudUtils'; +import PointCloudUtils, { POINT_CLOUD_DEFAULT_STEP } from './PointCloudUtils'; import MatrixUtils from './MatrixUtils'; import { resourceManagerInstance } from './annotation/ResourceManager'; @@ -24,6 +24,7 @@ export { ToolStyleUtils, PerspectiveShiftUtils, PointCloudUtils, + POINT_CLOUD_DEFAULT_STEP, MatrixUtils, resourceManagerInstance, };