diff --git a/packages/lb-annotation/src/core/pointCloud/index.ts b/packages/lb-annotation/src/core/pointCloud/index.ts index c85d6763c..873914f5f 100644 --- a/packages/lb-annotation/src/core/pointCloud/index.ts +++ b/packages/lb-annotation/src/core/pointCloud/index.ts @@ -115,6 +115,8 @@ export class PointCloud extends EventListener { private rangeObjectName = 'range'; + private highlightGroupName = 'highlightBoxes'; + private cacheInstance: PointCloudCache; // PointCloud Cache Map private showDirection: boolean = true; // Whether to display the direction of box @@ -1025,6 +1027,74 @@ export class PointCloud extends EventListener { }); } + /** + * Clean all highlightBox + */ + public clearHighlightBoxes() { + this.removeObjectByName(this.highlightGroupName); + } + + public clearHighlightBoxesAndRender() { + this.clearHighlightBoxes(); + this.render(); + } + + public highlightBoxes(boxes: IPointCloudBox[]) { + const group = new THREE.Group(); + + // 1. Highlight all box. + boxes.forEach((box) => { + const { + center: { x, y, z }, + width, + height, + depth, + rotation, + } = box; + const { fill } = toolStyleConverter.getColorFromConfig( + { attribute: box.attribute }, + { ...this.config, attributeConfigurable: true }, + {}, + ); + + // 1-1. Add Transparent Box. + const geometry = new THREE.BoxGeometry(width, height, depth); + const material = new THREE.MeshBasicMaterial({ + color: fill, + transparent: true, + opacity: 0.2, + depthTest: false, + }); + geometry.rotateZ(rotation); + geometry.translate(x, y, z); + const mesh = new THREE.Mesh(geometry, material); + group.add(mesh); + + // 1-2. Add plane for direction. + const planeGeo = new THREE.PlaneGeometry(depth, height); + planeGeo.rotateY(Math.PI / 2); + planeGeo.rotateZ(rotation); + // The plane center Offset + const vector = new THREE.Vector3(width / 2, 0, 0); + const rM = new THREE.Matrix4().makeRotationY(Math.PI / 2).makeRotationZ(rotation); + vector.applyMatrix4(rM); + planeGeo.translate(x + vector.x, y + vector.y, z + vector.z); + const plainMaterial = new THREE.MeshBasicMaterial({ + color: fill, + side: THREE.DoubleSide, + transparent: true, + opacity: 0.8, + depthTest: false, + }); + const plainMesh = new THREE.Mesh(planeGeo, plainMaterial); + group.add(plainMesh); + }); + + group.name = this.highlightGroupName; + this.scene.add(group); + this.render(); + } + public updateColor(color: any[]) { const oldPointCloud = this.scene.getObjectByName(this.pointCloudObjectName) as THREE.Points; if (oldPointCloud) { diff --git a/packages/lb-annotation/src/core/toolOperation/pointCloud2dOperation.ts b/packages/lb-annotation/src/core/toolOperation/pointCloud2dOperation.ts index 2f9658bc2..772b0927e 100644 --- a/packages/lb-annotation/src/core/toolOperation/pointCloud2dOperation.ts +++ b/packages/lb-annotation/src/core/toolOperation/pointCloud2dOperation.ts @@ -35,6 +35,8 @@ class PointCloud2dOperation extends PolygonOperation { private checkMode: boolean; + private highlightAttributeList: string[] = []; // + constructor(props: IPolygonOperationProps & IPointCloud2dOperationProps) { super(props); @@ -216,8 +218,10 @@ class PointCloud2dOperation extends PolygonOperation { } const lineColor = this.getPointCloudLineColor(polygon); const transformPointList = AxisUtils.changePointListByZoom(polygon.pointList || [], this.zoom, this.currentPos); + const isHighlight = this.highlightAttributeList.includes(polygon.attribute); + DrawUtils.drawPolygonWithFillAndLine(this.canvas, transformPointList, { - fillColor: 'transparent', + fillColor: isHighlight ? lineColor : 'transparent', strokeColor: lineColor, pointColor: 'white', thickness: this.style?.width ?? 2, @@ -493,6 +497,11 @@ class PointCloud2dOperation extends PolygonOperation { } } }; + + public setHighlightAttribute(attribute: string) { + this.highlightAttributeList = [attribute]; + this.render(); + } } export default PointCloud2dOperation; diff --git a/packages/lb-components/src/components/pointCloudView/PointCloud2DView.tsx b/packages/lb-components/src/components/pointCloudView/PointCloud2DView.tsx index 96e9d8cb4..94fba6fc4 100644 --- a/packages/lb-components/src/components/pointCloudView/PointCloud2DView.tsx +++ b/packages/lb-components/src/components/pointCloudView/PointCloud2DView.tsx @@ -50,7 +50,7 @@ interface IProps extends IA2MapStateProps { thumbnailWidth?: number; } -const PointCloud2DView = ({ currentData, config, thumbnailWidth }: IProps) => { +const PointCloud2DView = ({ currentData, config, thumbnailWidth, highlightAttribute }: IProps) => { const [annotations2d, setAnnotations2d] = useState([]); const { topViewInstance, displayPointCloudList } = useContext(PointCloudContext); const [selectedID, setSelectedID] = useState(''); @@ -67,9 +67,16 @@ const PointCloud2DView = ({ currentData, config, thumbnailWidth }: IProps) => { currentData?.mappingImgList.forEach((mappingData: IMappingImg) => { const newAnnotations2d: IAnnotationDataTemporarily[] = displayPointCloudList.reduce( (acc: IAnnotationDataTemporarily[], pointCloudBox: IPointCloudBox) => { + /** + * Is need to create range. + * 1. pointCloudBox is selected; + * 2. HighlightAttribute is same with pointCloudBox's attribute. + */ + const createRange = + pointCloudBox.id === selectedID || highlightAttribute === pointCloudBox.attribute; const { transferViewData: viewDataPointList, viewRangePointList } = pointCloudLidar2image(pointCloudBox, mappingData.calib, { - createRange: pointCloudBox.id === selectedID, + createRange, }); const stroke = toolStyleConverter.getColorFromConfig( @@ -88,7 +95,7 @@ const PointCloud2DView = ({ currentData, config, thumbnailWidth }: IProps) => { }); const newArr = [...acc, ...viewDataPointLists]; - if (pointCloudBox.id === selectedID && viewRangePointList.length > 0) { + if (viewRangePointList?.length > 0) { newArr.push({ type: 'polygon', annotation: { @@ -113,7 +120,7 @@ const PointCloud2DView = ({ currentData, config, thumbnailWidth }: IProps) => { }); setAnnotations2d(newAnnotations2dList); } - }, [displayPointCloudList, currentData?.mappingImgList, selectedID]); + }, [displayPointCloudList, currentData?.mappingImgList, selectedID, highlightAttribute]); useEffect(() => { window.addEventListener('keydown', onKeyDown); diff --git a/packages/lb-components/src/components/pointCloudView/PointCloud3DView.tsx b/packages/lb-components/src/components/pointCloudView/PointCloud3DView.tsx index fb1905c6e..173527c84 100644 --- a/packages/lb-components/src/components/pointCloudView/PointCloud3DView.tsx +++ b/packages/lb-components/src/components/pointCloudView/PointCloud3DView.tsx @@ -120,7 +120,7 @@ const PointCloud3DSideBar = ({ isEnlarge }: { isEnlarge?: boolean }) => { ); }; -const PointCloud3D: React.FC = ({ currentData, config }) => { +const PointCloud3D: React.FC = ({ currentData, config, highlightAttribute }) => { const ptCtx = useContext(PointCloudContext); const [showDirection, setShowDirection] = useState(true); const [isEnlarge, setIsEnlarge] = useState(false); @@ -257,6 +257,22 @@ const PointCloud3D: React.FC = ({ currentData, config }) => { return { reset3DView, setTarget3DView, isActive: !!selectedBox, followTopView }; }, [selectedBox, ptCtx.mainViewInstance]); + // Highlight 3D Box when `highAttribute` updated. + useEffect(() => { + const highlightBoxes = ptCtx.pointCloudBoxList.filter( + (v) => v.attribute === highlightAttribute, + ); + + if (highlightBoxes?.length > 0) { + ptCtx.mainViewInstance?.clearHighlightBoxes(); + ptCtx.mainViewInstance?.highlightBoxes(highlightBoxes); + } + + if (highlightBoxes.length === 0) { + ptCtx.mainViewInstance?.clearHighlightBoxesAndRender(); + } + }, [highlightAttribute, ptCtx.mainViewInstance]); + const PointCloud3DTitle = ( <> = ({ }, [imgIndex, ptSegmentInstance]); useEffect(() => { - let attributeValue = config.attributeList.find( - (v: IInputList) => v?.key === highlightAttribute, - )?.value; - ptSegmentInstance?.store?.highlightPointsByAttribute(attributeValue ?? ''); + ptSegmentInstance?.store?.highlightPointsByAttribute(highlightAttribute ?? ''); }, [highlightAttribute, ptSegmentInstance]); const segmentKeydownEvents = (lowerCaseKey: string, e: KeyboardEvent) => { diff --git a/packages/lb-components/src/components/pointCloudView/PointCloudTopView.tsx b/packages/lb-components/src/components/pointCloudView/PointCloudTopView.tsx index 9704f8b64..3ffa8969d 100644 --- a/packages/lb-components/src/components/pointCloudView/PointCloudTopView.tsx +++ b/packages/lb-components/src/components/pointCloudView/PointCloudTopView.tsx @@ -198,6 +198,7 @@ const PointCloudTopView: React.FC = ({ setIsEnlargeTopView, isEnlargeTopView, onExitZoom, + highlightAttribute, }) => { const [annotationPos, setAnnotationPos] = useState({ zoom: 1, currentPos: { x: 0, y: 0 } }); const ref = useRef(null); @@ -435,6 +436,10 @@ const PointCloudTopView: React.FC = ({ onExitZoom(); } }; + // Highlight TopView Box when `hightAttribute` updated. + useEffect(() => { + ptCtx.topViewInstance?.pointCloud2dOperation?.setHighlightAttribute?.(highlightAttribute); + }, [ptCtx.topViewInstance, highlightAttribute]); return (