Skip to content

Commit

Permalink
Merge pull request #370 from lihqi/lhq-dev-3.5.0
Browse files Browse the repository at this point in the history
feat(lb-components): When pointCloudData update filter preResult by PCD
  • Loading branch information
Glenfiddish authored Dec 4, 2023
2 parents db3bf83 + e4be5cd commit f07dff1
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 55 deletions.
44 changes: 43 additions & 1 deletion packages/lb-annotation/src/core/pointCloud/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
* @author Ron <[email protected]>
*/

// eslint-disable-next-line
import GenerateIndexWorker from 'web-worker:./generateIndexWorker.js';
import { PCDLoader } from './PCDLoader';

type TCacheInfo = {
src: string;
};

export type TIndexMap = Map<string, { x: number; y: number; z: number }[]>;

export class PointCloudCache {
public pcdLoader: PCDLoader;

Expand All @@ -19,6 +23,8 @@ export class PointCloudCache {

private colorMap: Map<string, Float32Array>;

private cacheIndexMap: Map<string, TIndexMap>;

private cacheList: Array<TCacheInfo> = [];

private static instance: PointCloudCache;
Expand All @@ -29,7 +35,7 @@ export class PointCloudCache {
this.pcdLoader = new PCDLoader();
this.pointsMap = new Map();
this.colorMap = new Map();

this.cacheIndexMap = new Map();
this.cache2DHighlightIndex = new Map();
}

Expand Down Expand Up @@ -95,4 +101,40 @@ export class PointCloudCache {
public clearCache2DHighlightIndex() {
this.cache2DHighlightIndex.clear();
}

/**
* Loads index map from cache or generates it in a worker.
*
* @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);

return new Promise((resolve) => {
if (currentCacheIndexMap) {
return resolve(currentCacheIndexMap);
}
if (window.Worker) {
const generateIndexWorker = new GenerateIndexWorker({ type: 'module' });
generateIndexWorker.postMessage({
points,
});

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();
};
}
});
};
}
24 changes: 24 additions & 0 deletions packages/lb-annotation/src/core/pointCloud/generateIndexWorker.js
Original file line number Diff line number Diff line change
@@ -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 });
};
22 changes: 21 additions & 1 deletion packages/lb-annotation/src/core/pointCloud/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -1013,6 +1013,26 @@ export class PointCloud extends EventListener {
return mergeList;
};

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)) as TIndexMap;

return new Promise((resolve) => {
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);
});
};

/**
* It needs to be updated after load PointCloud's data.
* @param boxParams
Expand Down
5 changes: 5 additions & 0 deletions packages/lb-annotation/src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
137 changes: 134 additions & 3 deletions packages/lb-annotation/src/utils/MathUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

// eslint-disable-next-line
import MathUtilsWorker from 'web-worker:./MathUtilsWorker.js';
import { IBasicLine, IBasicPoint, 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 { createSmoothCurvePointsFromPointList } from './tool/polygonTool';
import { TIndexMap } from '@/core/pointCloud/cache';
import { createSmoothCurvePointsFromPointList, isInPolygon } from './tool/polygonTool';
import PolygonUtils from './tool/PolygonUtils';
import Vector from './VectorUtils';

/**
* 基础的三角运算
*/
Expand All @@ -28,6 +28,92 @@ export class Trigonometric {
}
}

enum CubePosition {
Outside = 0,
PartiallyInside = 1,
FullyInside = 2,
}

function getCubePosition(polygon: IPolygonPoint[], zScope: [number, number], smallCube: Cube): CubePosition {
// 计算小立方体的8个顶点
const smallCubeVertices: I3DSpaceCoord[] = [
{
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++) {
// eslint-disable-next-line
if (MathUtils.isPointInsideCube(smallCubeVertices[i], polygon, zScope)) {
insideCount++;
}
}

// 根据在大立方体内的顶点数量返回结果
if (insideCount === 0) {
return CubePosition.Outside; // 所有顶点都在大立方体外
}
if (insideCount === 8) {
return CubePosition.FullyInside; // 所有顶点都在大立方体内
}
return CubePosition.PartiallyInside; // 部分顶点在大立方体内,部分顶点在大立方体外
}

interface Cube {
x: number;
y: number;
z: number;
width: number;
height: number;
depth: number;
}

interface ICalculatePointsInsideBoxParams {
indexMap: TIndexMap;
polygon: IPolygonPoint[];
zScope: [number, number];
box: IPointCloudBox;
}

export default class MathUtils {
/**
* 是否在指定范围内
Expand Down Expand Up @@ -654,4 +740,49 @@ export default class MathUtils {

return [fixedPoint, newSecondPoint, newThirdPoint, newFourthPoint];
}

public static calculatePointsInsideBox = (params: ICalculatePointsInsideBoxParams) => {
const { indexMap, polygon, zScope, box } = params;

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 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 ||
(cubePosition === CubePosition.Outside && (box.width <= 1 || box.height <= 1))
) {
point.forEach((p) => {
if (MathUtils.isPointInsideCube(p, polygon, zScope)) {
count++;
}
});
}
});

return count;
};

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;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit f07dff1

Please sign in to comment.