@realsee/dnalogel 4.0.0-webgpu.18 → 4.0.0-webgpu.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/floorplan.js +1 -1
- package/dist/index.js +18 -18
- package/dist/internal/{BasePlugin-Cr_atQUC.js → BasePlugin-AYcNjiyG.js} +2 -2
- package/dist/internal/{BasePlugin-Cr_atQUC.js.map → BasePlugin-AYcNjiyG.js.map} +1 -1
- package/dist/internal/BasePluginWithData-CWgZY4u8.js +7 -0
- package/dist/internal/{BasePluginWithData-CIQpqYGe.js.map → BasePluginWithData-CWgZY4u8.js.map} +1 -1
- package/dist/internal/{Controller-Cq-mYkzT.js → Controller-DPpDpYsR.js} +3 -3
- package/dist/internal/{Controller-Cq-mYkzT.js.map → Controller-DPpDpYsR.js.map} +1 -1
- package/dist/internal/{Controller-5BvatEWD.js → Controller-DSKeCecj.js} +171 -154
- package/dist/internal/Controller-DSKeCecj.js.map +1 -0
- package/dist/internal/{Controller-BDT5_ZNe.js → Controller-DZwww-c4.js} +2 -2
- package/dist/internal/{Controller-BDT5_ZNe.js.map → Controller-DZwww-c4.js.map} +1 -1
- package/dist/internal/PointHelper-G9EgUMWo.js +1052 -0
- package/dist/internal/PointHelper-G9EgUMWo.js.map +1 -0
- package/dist/internal/{Rectangle-Z2T_h74M.js → Rectangle-DSOdWXl_.js} +3 -3
- package/dist/internal/{Rectangle-Z2T_h74M.js.map → Rectangle-DSOdWXl_.js.map} +1 -1
- package/dist/internal/{Work-PKaUMpXd.js → Work-HQHipxJj.js} +4 -4
- package/dist/internal/{Work-PKaUMpXd.js.map → Work-HQHipxJj.js.map} +1 -1
- package/dist/internal/{area-maker-BTGqxG6D.js → area-maker-Diy_UkTD.js} +2 -2
- package/dist/internal/{area-maker-BTGqxG6D.js.map → area-maker-Diy_UkTD.js.map} +1 -1
- package/dist/internal/{controller-B0hqJtoB.js → controller-DZUdbdd8.js} +4 -4
- package/dist/internal/{controller-B0hqJtoB.js.map → controller-DZUdbdd8.js.map} +1 -1
- package/dist/internal/{cruise-BkSbiLjd.js → cruise-Bo8CD4vF.js} +2 -2
- package/dist/internal/{cruise-BkSbiLjd.js.map → cruise-Bo8CD4vF.js.map} +1 -1
- package/dist/internal/{current-pano-image-DqyUFIP6.js → current-pano-image-Cqq4DRPh.js} +2 -2
- package/dist/internal/{current-pano-image-DqyUFIP6.js.map → current-pano-image-Cqq4DRPh.js.map} +1 -1
- package/dist/internal/{edgeSnap-8fdFCcXB.js → edgeSnap-CH0HidZm.js} +206 -83
- package/dist/internal/edgeSnap-CH0HidZm.js.map +1 -0
- package/dist/internal/{floorplan-Dkp7omYn.js → floorplan-DwcrbASA.js} +2 -2
- package/dist/internal/{floorplan-Dkp7omYn.js.map → floorplan-DwcrbASA.js.map} +1 -1
- package/dist/internal/{measure-KVSCjRnS.js → measure-DIstq55p.js} +2 -2
- package/dist/internal/{measure-KVSCjRnS.js.map → measure-DIstq55p.js.map} +1 -1
- package/dist/internal/measure-v2-Byp1mE5q.js +215 -0
- package/dist/internal/measure-v2-Byp1mE5q.js.map +1 -0
- package/dist/internal/{model-maker-L5eqUgkU.js → model-maker-pQcaAh5M.js} +2 -2
- package/dist/internal/{model-maker-L5eqUgkU.js.map → model-maker-pQcaAh5M.js.map} +1 -1
- package/dist/internal/object3d-helper-zRXHAcbm.js +7 -0
- package/dist/internal/{object3d-helper-CUhRRdCQ.js.map → object3d-helper-zRXHAcbm.js.map} +1 -1
- package/dist/internal/{pano-compass-dmcsnFDQ.js → pano-compass-CMIljzhC.js} +2 -2
- package/dist/internal/{pano-compass-dmcsnFDQ.js.map → pano-compass-CMIljzhC.js.map} +1 -1
- package/dist/internal/{pano-door-label-C0sd66vf.js → pano-door-label-B4nqTTzN.js} +2 -2
- package/dist/internal/{pano-door-label-C0sd66vf.js.map → pano-door-label-B4nqTTzN.js.map} +1 -1
- package/dist/internal/{pano-measure-NbB7-uVE.js → pano-measure-C2r0ecHk.js} +2 -2
- package/dist/internal/{pano-measure-NbB7-uVE.js.map → pano-measure-C2r0ecHk.js.map} +1 -1
- package/dist/internal/{pano-measure-v2-CRPvPs0e.js → pano-measure-v2-BfSAjO-I.js} +4 -4
- package/dist/internal/{pano-measure-v2-CRPvPs0e.js.map → pano-measure-v2-BfSAjO-I.js.map} +1 -1
- package/dist/internal/{pano-tag-j8ZPJDDK.js → pano-tag-BXo_4I6D.js} +2 -2
- package/dist/internal/{pano-tag-j8ZPJDDK.js.map → pano-tag-BXo_4I6D.js.map} +1 -1
- package/dist/internal/{pano-video-Dcspq4j1.js → pano-video-CS6-eXci.js} +2 -2
- package/dist/internal/{pano-video-Dcspq4j1.js.map → pano-video-CS6-eXci.js.map} +1 -1
- package/dist/internal/{pipeline-CD2YkN5U.js → pipeline-BN9A4lPZ.js} +2 -2
- package/dist/internal/{pipeline-CD2YkN5U.js.map → pipeline-BN9A4lPZ.js.map} +1 -1
- package/dist/internal/{sculpt-CbEBEh9F.js → sculpt-e0IRMtjB.js} +3 -3
- package/dist/internal/{sculpt-CbEBEh9F.js.map → sculpt-e0IRMtjB.js.map} +1 -1
- package/dist/plugins/area-maker.js +1 -1
- package/dist/plugins/cruise.js +2 -2
- package/dist/plugins/current-pano-image.js +1 -1
- package/dist/plugins/guide-line.js +1 -1
- package/dist/plugins/measure-v2.js +2 -2
- package/dist/plugins/measure.js +2 -2
- package/dist/plugins/model-maker.js +1 -1
- package/dist/plugins/object3d-helper.js +2 -2
- package/dist/plugins/pano-compass.js +1 -1
- package/dist/plugins/pano-door-label.js +1 -1
- package/dist/plugins/pano-measure-v2.js +1 -1
- package/dist/plugins/pano-measure.js +1 -1
- package/dist/plugins/pano-tag.js +2 -2
- package/dist/plugins/pano-video.js +1 -1
- package/dist/plugins/pipeline.js +1 -1
- package/dist/plugins/sculpt.js +2 -2
- package/dist/types/MeasurePlugin/Controller.d.ts +7 -0
- package/dist/types/MeasurePlugin/utils/MeasureMesh.d.ts +5 -0
- package/dist/types/MeasurePluginV2/Controller.d.ts +9 -0
- package/dist/types/MeasurePluginV2/Magnifier.d.ts +33 -0
- package/dist/types/MeasurePluginV2/PointOverlay.d.ts +5 -0
- package/dist/types/MeasurePluginV2/closeupView.d.ts +69 -0
- package/dist/types/MeasurePluginV2/normalMeasure.d.ts +116 -0
- package/dist/types/shared-utils/three/Magnifier.d.ts +55 -0
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/internal/BasePluginWithData-CIQpqYGe.js +0 -7
- package/dist/internal/Controller-5BvatEWD.js.map +0 -1
- package/dist/internal/PointHelper-grrf8vu1.js +0 -953
- package/dist/internal/PointHelper-grrf8vu1.js.map +0 -1
- package/dist/internal/edgeSnap-8fdFCcXB.js.map +0 -1
- package/dist/internal/measure-v2-DqjBlSeF.js +0 -83
- package/dist/internal/measure-v2-DqjBlSeF.js.map +0 -1
- package/dist/internal/object3d-helper-CUhRRdCQ.js +0 -7
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PointHelper-grrf8vu1.js","names":["createPlaneMesh","createLineMesh","createBallMesh","__toESM","bindFiveOwner","LineMesh","generateBehindFiveElement","CSS3DSprite","CSS3DObjectPlus","getFiveModel","waitFiveModelLoaded","THREERaycaster","rayOnLine","THREE","Magnifier","Subscribe","five","options","context","m","Hammer","element","point","newScale","newWidth","newHeight","imageWidth","imageHeight","revision","renderSize","projected","x","y","readWidth","width","scale","readHeight","height","pixelRatio","hidden","pixelsPromise","object","visible","pixels","error","canvasClientRect","containerDomRect","maxOffsetX","maxOffsetY","minOffsetX","minOffsetY","left","right","top","position2d","clientWidth","clientHeight","canvas","offsetRange","offsetX","event","offsetY","translateX","translateY","sessions","activeSessions","disposedOwners","frontScene","behindScene","legacyOwners","belongsToFive","scene","legacyScenes","mode","sceneMap","initialCSS3DRender","addScene","map","sceneKey","key","removeScene","sceneOrKey","maps","session","removed","addFrontScene","removeFrontScene","addBehindScene","removeBehindScene","scenesForOwner","existing","front","ICSS3DRenderer","behind","pending","disposed","dispose","onFiveDispose","ownedHere","root","movedToAnotherScene","wrapper","behindWrapper","ICSS3DSprite","createPlaneMesh$1","group","fill","border","createCrossline","length","style","lineX","lineY","createLineMesh$1","zPath","zGeometry","zMaterial","createRingMesh","geometry","material","createBallMesh$1","ballGeometry","ballMaterial","createCSSBallMesh","img","cssMesh","PointHelper2","lineLength","intersect","normal","lookAtPosition","mesh","PointSelectorHelper","pointHelper","PointHelper","config","updateMagnifier","navigatorTouchPoints","isTouchDevice","createIntersectionFace","Vector3","getRaycasterByNdcPosition","position","raycaster","getIntersectByRaycaster","realIntersect","getRealIntersectByRaycaster","getVirtualIntersectByRaycaster","distance","CURSOR_NOT_ALLOW_URL","_vector3","disableFiveEvent","PointSelector","cursorError","outOfFive","enabled","defaultMagnifierParams","fiveElement","points","intersection","cancel","render","clientX","clientY","timestamp","success","moved","ndcPosition","realIntersection","intersectionPoint","virtualIntersection","targetIntersect","mouseNdcPosition","size","adherePlane","newPoint","adhereLine","closestPoint","projectPoint","positionOffset","_point","pointIsVisible","cameraToPointDistance","mouseX","mouseY","mousePosition","POINT_HELPER_TEXTURE_URL","rangePieceImg","html_default","createPlaneMesh","planGeometry","planTextureUrl","planTexture","planMaterial","createLineMesh","colors","uv","i","createBallMesh","ballMesh","createBorderMesh","radius","borderMesh","contentElement"],"sources":["../../src/shared-utils/three/Magnifier.ts","../../src/shared-utils/CSS3DRender/index.ts","../../src/CSS3DRenderPlugin/utils/three/CSS3DSprite.ts","../../src/shared-utils/three/PointSelector/utils/PointHelper2.ts","../../src/shared-utils/three/PointSelector/utils/PointSelectorHelper.ts","../../src/shared-utils/isTouchDevice.ts","../../src/shared-utils/three/createIntersectionFace.ts","../../src/shared-utils/five/getRaycasterByNdcPosition.ts","../../src/shared-utils/five/getPosition.ts","../../src/shared-utils/three/PointSelector/utils/contents.ts","../../src/shared-utils/three/PointSelector/index.ts","../../src/shared-utils/three/Assets/index.ts","../../src/shared-utils/three/PointSelector/utils/html.ts","../../src/shared-utils/three/PointSelector/utils/PointHelper.ts"],"sourcesContent":["import type { Five, SubscribeEventMap } from '@realsee/five-webgpu'\n\nimport type Hammer from 'hammerjs'\nimport * as THREE from 'three/webgpu'\nimport { Subscribe } from '../Subscribe'\n\ninterface MagnifierConfig {\n /** 允许拖动放大镜 */\n dragEnabled: boolean\n /** renderWithPoint 时,是否应该自动更新放大镜的位置 */\n autoFixPCPosition: boolean\n /** 放大镜初始位置应该设置在容器的哪个位置 */\n initialPosition: { left: string; top: string }\n /** 是否跳过全景图渲染 */\n skipPanorama: boolean\n}\n\ninterface MagnifierEvent extends SubscribeEventMap {\n wantsPanGesture: (event: (typeof Hammer)['Input']) => boolean\n}\n\n/** 放大镜配置参数 */\nexport interface MagnifierParameter extends Partial<MagnifierConfig> {\n width?: number\n height?: number\n scale?: number\n}\n\n/** 像素读回并绘制到放大镜 canvas 之后,供插件叠加 2D 内容使用的渲染信息 */\nexport interface MagnifierRenderInfo {\n /** 本次渲染使用的相机 */\n camera: THREE.Camera\n /** five renderer 的尺寸 */\n renderSize: THREE.Vector2\n /** 读取区域左边缘(renderer 像素) */\n readLeft: number\n /** 读取区域下边缘(renderer 像素,y 轴向上) */\n readTop: number\n /** 读取区域宽高(renderer 像素) */\n readWidth: number\n readHeight: number\n /** 一个 renderer 像素在 canvas 上占的设备像素 */\n pixelRatio: number\n /** 放大镜 canvas 的设备像素宽高 */\n canvasWidth: number\n canvasHeight: number\n}\n\nexport class Magnifier {\n public width: number\n public height: number\n public containerDom?: Element\n public hooks = new Subscribe<MagnifierEvent>()\n public canvas = document.createElement('canvas')\n public config: MagnifierConfig\n public state = { enabled: false }\n /** 像素绘制完成后的回调(默认不设置,原行为不变) */\n public afterRender?: (info: MagnifierRenderInfo) => void\n\n private five: Five\n private scale: number\n private offset = { x: 0, y: 0 }\n private context: CanvasRenderingContext2D\n private renderCenter: THREE.Vector3 | { x: number; y: number } = new THREE.Vector3()\n private hammer?: InstanceType<typeof Hammer>\n private offsetRange?: { min: { x: number; y: number }; max: { x: number; y: number } }\n private isPanning = false\n private isDisposed = false\n private imageData: ImageData = new ImageData(1, 1)\n private pendingRender?: Promise<void>\n private renderRevision = 0\n private invalidatedRevision = -1\n\n public constructor(five: Five, options: MagnifierParameter) {\n if (!five.renderer) {\n console.error('Five Render 未初始化')\n return\n }\n\n this.five = five\n this.scale = options?.scale ?? 2\n this.width = options?.width ?? 190\n this.height = options?.height ?? options?.width ?? 190\n this.config = {\n dragEnabled: options?.dragEnabled || false,\n autoFixPCPosition: options?.autoFixPCPosition || false,\n initialPosition: options?.initialPosition || { left: '0', top: '0' },\n skipPanorama: options?.skipPanorama || false,\n }\n\n const context = this.canvas.getContext('2d')\n if (!context) throw new Error('CANNOT CREATE CONTEXT2D')\n this.context = context\n\n if (this.config.dragEnabled) {\n void import('hammerjs').then(({ default: Hammer }) => {\n if (this.isDisposed) return\n this.hammer = new Hammer(this.canvas)\n this.hammer.on('pan', this.onPan)\n this.hammer.on('panstart', this.onPanstart)\n this.hammer.on('panend', this.onPanend)\n })\n }\n this.initStyle()\n }\n\n public enable() {\n if (this.isDisposed || this.state.enabled) return\n this.state.enabled = true\n if (this.containerDom) this._appendTo(this.containerDom)\n return this\n }\n\n public disable() {\n if (!this.state.enabled) return\n this.state.enabled = false\n this.invalidatedRevision = this.renderRevision\n this.canvas.style.visibility = 'hidden'\n this.canvas.remove()\n return this\n }\n\n public dispose() {\n if (this.isDisposed) return\n this.isDisposed = true\n this.clear()\n this.disable()\n this.hammer?.destroy()\n }\n\n /** 把放大镜放到某一个容器中 */\n public appendTo(element: Element) {\n if (this.containerDom) this.containerDom?.removeChild(this.canvas)\n this.containerDom = element\n if (this.state.enabled) this._appendTo(element)\n return this\n }\n\n /** 清除放大镜渲染内容 */\n public clear() {\n this.invalidatedRevision = this.renderRevision\n this.context?.clearRect(0, 0, this.canvas.width, this.canvas.height)\n return this\n }\n\n /** 放大传入点位周围的内容 */\n public renderWithPoint(point: THREE.Vector3) {\n if (!this.containerDom) return\n if (!this.state.enabled) return\n this.renderCenter = point\n this.render()\n if (this.config.autoFixPCPosition) this.autoFixPCPosition()\n }\n\n /** 放大传入点位周围的内容 */\n public renderWithScreenPoint(point: { x: number; y: number }) {\n if (!this.containerDom) return\n if (!this.state.enabled) return\n this.renderCenter = point\n this.render()\n if (this.config.autoFixPCPosition) this.autoFixPCPosition()\n }\n\n public resetOffset() {\n this.offset = { x: 0, y: 0 }\n this.canvas.style.transform = `translate3d(${0}px, ${0}px, 100px)`\n }\n\n /** 更新放大镜的缩放比例 */\n public updateScale(newScale: number) {\n if (newScale > 0) {\n this.scale = newScale\n this.invalidatedRevision = this.renderRevision\n }\n }\n\n /** 更新放大镜的尺寸 */\n public updateSize(newWidth: number, newHeight?: number) {\n if (newWidth > 0) {\n this.width = newWidth\n this.height = newHeight || newWidth\n\n // 更新canvas样式\n const pixelRatio = 1\n this.canvas.setAttribute('width', (this.width * pixelRatio).toString())\n this.canvas.setAttribute('height', (this.height * pixelRatio).toString())\n this.canvas.style.width = this.width + 'px'\n this.canvas.style.height = this.height + 'px'\n\n // 重新初始化ImageData\n const imageWidth = Math.floor(this.width * pixelRatio)\n const imageHeight = Math.floor(this.height * pixelRatio)\n this.imageData = new ImageData(imageWidth, imageHeight)\n\n // 清除之前的渲染内容\n this.clear()\n }\n }\n\n public render(): Promise<void> {\n this.renderRevision += 1\n if (!this.pendingRender) {\n this.pendingRender = this.renderLatest().finally(() => { this.pendingRender = undefined })\n }\n return this.pendingRender\n }\n\n private async renderLatest() {\n while (!this.isDisposed && this.state.enabled && this.containerDom && this.five.renderer) {\n const revision = this.renderRevision\n const { scale, width, height } = this\n const renderSize = this.five.renderer.getSize(new THREE.Vector2())\n const point = this.renderCenter\n const projected = point instanceof THREE.Vector3 ? point.clone().project(this.five.camera) : null\n const x = projected ? ((projected.x + 1) / 2) * renderSize.x : point.x\n const y = projected ? ((projected.y + 1) / 2) * renderSize.y : renderSize.y - point.y\n\n // Five accepts integer dimensions and pixel ratios. Keep fractional zoom\n // in the CSS size instead of expecting an impossible fractional readback.\n const readWidth = Math.max(1, Math.round(width / scale))\n const readHeight = Math.max(1, Math.round(height / scale))\n const pixelRatio = Math.max(1, Math.ceil(scale))\n const imageWidth = readWidth * pixelRatio\n const imageHeight = readHeight * pixelRatio\n const hidden = new Map<THREE.Object3D, boolean>()\n let pixelsPromise: ReturnType<Five['getPixels']>\n\n try {\n this.five.scene.traverse((object) => {\n if ((object as THREE.Object3D & { disableGetPixel?: boolean }).disableGetPixel) {\n hidden.set(object, object.visible)\n object.visible = false\n }\n })\n try {\n // getPixels renders synchronously before its asynchronous GPU readback.\n pixelsPromise = this.five.getPixels({\n x: x - readWidth / 2,\n y: y - readHeight / 2,\n width: readWidth,\n height: readHeight,\n pixelRatio,\n skipPanorama: this.config.skipPanorama,\n flipY: true,\n })\n } finally {\n hidden.forEach((visible, object) => { object.visible = visible })\n }\n const pixels = await pixelsPromise\n if (this.isDisposed || !this.state.enabled) return\n if (this.invalidatedRevision === this.renderRevision) return\n if (revision !== this.renderRevision) continue\n if (pixels.length !== imageWidth * imageHeight * 4) {\n console.warn('Magnifier: Invalid pixel data length')\n return\n }\n if (this.imageData.width !== imageWidth || this.imageData.height !== imageHeight) {\n this.imageData = new ImageData(imageWidth, imageHeight)\n }\n this.canvas.width = imageWidth\n this.canvas.height = imageHeight\n this.imageData.data.set(pixels)\n this.context.putImageData(this.imageData, 0, 0)\n this.canvas.style.visibility = 'visible'\n\n // 叠加层是纯装饰:插件回调出错不能把异常抛回 five 的渲染循环。\n if (this.afterRender) {\n try {\n this.afterRender({\n camera: this.five.camera,\n renderSize,\n readLeft: x - readWidth / 2,\n readTop: y - readHeight / 2,\n readWidth,\n readHeight,\n pixelRatio,\n canvasWidth: imageWidth,\n canvasHeight: imageHeight,\n })\n } catch (error) {\n console.warn('Magnifier: afterRender 失败', error)\n }\n }\n } catch (error) {\n console.error('Magnifier: Failed to read pixels', error)\n }\n if (revision === this.renderRevision) return\n }\n }\n\n private _appendTo(element: Element) {\n this.resetOffset()\n element.appendChild(this.canvas)\n if (!this.offsetRange) {\n const canvasClientRect = this.canvas.getBoundingClientRect()\n const containerDomRect = element.getBoundingClientRect()\n const maxOffsetX = containerDomRect.right - canvasClientRect.right\n const maxOffsetY = containerDomRect.bottom - canvasClientRect.bottom\n const minOffsetX = containerDomRect.left - canvasClientRect.left\n const minOffsetY = containerDomRect.top - canvasClientRect.top\n this.offsetRange = {\n min: { x: minOffsetX, y: minOffsetY },\n max: { x: maxOffsetX, y: maxOffsetY },\n }\n }\n }\n\n private autoFixPCPosition() {\n if (!this.containerDom) return\n const { width, height } = this\n const { clientWidth, clientHeight } = this.containerDom\n\n const [left, right, top] = (() => {\n if ((this.renderCenter as any).isVector3) {\n const position2d = (this.renderCenter as THREE.Vector3).clone().project(this.five.camera)\n\n return [\n //\n ((position2d.x + 1) / 2) * clientWidth,\n (-(position2d.x - 1) / 2) * clientWidth,\n (-(position2d.y - 1) / 2) * clientHeight,\n ]\n } else {\n return [this.renderCenter.x, clientWidth - this.renderCenter.x, this.renderCenter.y]\n }\n })()\n\n if (left < 183) {\n this.canvas.style.top = -height / 2 + 'px'\n this.canvas.style.left = 90 + 'px'\n } else if (top < 183) {\n this.canvas.style.top = 90 + 'px'\n this.canvas.style.left = -width / 2 + 'px'\n } else if (right < 183) {\n this.canvas.style.top = -height / 2 + 'px'\n this.canvas.style.left = -width - 90 + 'px'\n } else {\n this.canvas.style.left = -width / 2 + 'px'\n this.canvas.style.top = -height - 90 + 'px'\n }\n this.canvas.style.transform = `translate3d(${left}px, ${top}px, 10px)`\n this.offset = { x: left, y: top }\n }\n\n private initStyle() {\n const canvas = this.canvas\n canvas.classList.add('five-plugin__magnifier')\n canvas.style.position = 'absolute'\n canvas.style.pointerEvents = this.config.dragEnabled ? 'all' : 'none'\n canvas.style.borderRadius = '50%'\n canvas.style.zIndex = '99'\n const pixelRatio = 1\n canvas.setAttribute('width', (this.width * pixelRatio).toString())\n canvas.setAttribute('height', (this.height * pixelRatio).toString())\n canvas.style.border = '2px solid rgba(255,255,255,0.20)'\n canvas.style.width = this.width + 'px'\n canvas.style.height = this.height + 'px'\n canvas.style.top = this.config.initialPosition.top\n canvas.style.left = this.config.initialPosition.left\n canvas.style.transform = 'translate(0,0,100px)'\n canvas.style.visibility = 'hidden'\n\n if (this.config.dragEnabled) {\n this.canvas.style.cursor = 'pointer'\n }\n }\n\n private getPanOffset(event: (typeof Hammer)['Input'], offsetRange: { min: { x: number; y: number }; max: { x: number; y: number } }) {\n const {\n min: { x: minOffsetX, y: minOffsetY },\n max: { x: maxOffsetX, y: maxOffsetY },\n } = offsetRange\n const offsetX = this.offset.x + event.deltaX\n const offsetY = this.offset.y + event.deltaY\n const translateX = Math.min(Math.max(offsetX, minOffsetX), maxOffsetX)\n const translateY = Math.min(Math.max(offsetY, minOffsetY), maxOffsetY)\n return { translateX, translateY }\n }\n\n private onPanstart = () => {\n this.isPanning = true\n this.canvas.style.boxShadow = '0 2px 30px 0 rgba(0,0,0,0.20)'\n }\n\n private onPan = (event: (typeof Hammer)['Input']) => {\n if (!this.isPanning) return\n if (!this.offsetRange) return\n const prevented = this.hooks.emit('wantsPanGesture', event)\n if (prevented) return\n\n const { translateX, translateY } = this.getPanOffset(event, this.offsetRange)\n this.canvas.style.transform = `translate3d(${translateX}px, ${translateY}px, 100px)`\n }\n\n private onPanend = (event: (typeof Hammer)['Input']) => {\n this.isPanning = false\n this.canvas.style.boxShadow = 'none'\n if (!this.offsetRange) return\n const { translateX, translateY } = this.getPanOffset(event, this.offsetRange)\n this.canvas.style.transform = `translate3d(${translateX}px, ${translateY}px, 100px)`\n this.offset = { x: translateX, y: translateY }\n }\n}\n","import type * as THREE from 'three/webgpu'\nimport { ICSS3DRenderer } from '../../CSS3DRenderPlugin/utils/three/CSS3DRenderer'\nimport type { Five } from '@realsee/five-webgpu'\nimport { waitFiveModelLoaded } from '../five/fiveModelLoad'\nimport { generateBehindFiveElement } from '../../CSS3DRenderPlugin/utils/generateBehindFiveElement'\n\ntype CSSScene = THREE.Object3D\ntype SceneMode = 'front' | 'behind'\ninterface CSSSession {\n five: Five\n front: Map<string, CSSScene>\n behind: Map<string, CSSScene>\n dispose: () => void\n}\nconst sessions = new WeakMap<Five, CSSSession>()\nconst activeSessions = new Set<CSSSession>()\nconst disposedOwners = new WeakSet<Five>()\n// Existing calls without an owner stay supported. Their scene ancestry is\n// checked every frame, including objects added after construction or reparented.\nconst frontScene = new Map<string, CSSScene>()\nconst behindScene = new Map<string, CSSScene>()\nconst legacyOwners = new WeakMap<CSSScene, Five>()\n\nfunction belongsToFive(scene: CSSScene, five: Five) {\n for (let object: THREE.Object3D | null = scene; object; object = object.parent) {\n if (object === five.scene) return true\n }\n return false\n}\nfunction legacyScenes(mode: SceneMode) {\n return mode === 'front' ? frontScene : behindScene\n}\nfunction sceneMap(mode: SceneMode, five?: Five) {\n if (!five) return legacyScenes(mode)\n initialCSS3DRender(five)\n return sessions.get(five)?.[mode]\n}\nfunction addScene(mode: SceneMode, scene: CSSScene, key?: string, five?: Five): boolean {\n if (!scene) return false\n const map = sceneMap(mode, five),\n sceneKey = key || scene.uuid\n if (!map || map.has(sceneKey)) return false\n map.set(sceneKey, scene)\n return true\n}\nfunction removeScene(mode: SceneMode, sceneOrKey: CSSScene | string, five?: Five): boolean {\n if (!sceneOrKey) return false\n const maps = five\n ? [sessions.get(five)?.[mode]]\n : [legacyScenes(mode), ...Array.from(activeSessions, (session) => session[mode])]\n let removed = false\n for (const map of maps) {\n if (!map) continue\n if (typeof sceneOrKey === 'string') removed = map.delete(sceneOrKey) || removed\n else for (const [key, scene] of map) if (scene === sceneOrKey) removed = map.delete(key) || removed\n }\n return removed\n}\n/** Add a front scene; the optional owner keeps identical keys in separate Five sessions. */\nexport function addFrontScene(scene: CSSScene, key?: string, five?: Five): boolean {\n return addScene('front', scene, key, five)\n}\nexport function removeFrontScene(sceneOrKey: CSSScene | string, five?: Five): boolean {\n return removeScene('front', sceneOrKey, five)\n}\nexport function addBehindScene(scene: CSSScene, key?: string, five?: Five): boolean {\n return addScene('behind', scene, key, five)\n}\nexport function removeBehindScene(sceneOrKey: CSSScene | string, five?: Five): boolean {\n return removeScene('behind', sceneOrKey, five)\n}\n/** The existing no-argument clear functions retain their explicit global semantics. */\nexport function clearFrontScenes(): void {\n frontScene.clear()\n for (const session of activeSessions) session.front.clear()\n}\nexport function clearBehindScenes(): void {\n behindScene.clear()\n for (const session of activeSessions) session.behind.clear()\n}\nexport function clearAllScenes(): void {\n clearFrontScenes()\n clearBehindScenes()\n}\n\nfunction* scenesForOwner(session: CSSSession, mode: SceneMode): Iterable<CSSScene> {\n yield* session[mode].values()\n for (const scene of legacyScenes(mode).values()) {\n if (belongsToFive(scene, session.five)) {\n legacyOwners.set(scene, session.five)\n yield scene\n }\n }\n}\n\nexport function initialCSS3DRender(five: Five) {\n const existing = sessions.get(five)\n if (existing) return existing.dispose\n if (disposedOwners.has(five)) return () => {}\n const front = new ICSS3DRenderer('front'),\n behind = new ICSS3DRenderer('behind')\n front.domElementWrapper.style.zIndex = '1'\n const pending = new AbortController()\n let disposed = false\n const dispose = () => {\n if (disposed) return\n disposed = true\n pending.abort()\n five.off('dispose', onFiveDispose)\n front.dispose()\n behind.dispose()\n session.front.clear()\n session.behind.clear()\n for (const map of [frontScene, behindScene]) {\n for (const [key, scene] of map) {\n const ownedHere = belongsToFive(scene, five)\n let root: THREE.Object3D = scene\n while (root.parent) root = root.parent\n // A legacy object may already be in another scene before that owner's\n // next frame updates the observation. Do not erase its new registry entry.\n const movedToAnotherScene = !ownedHere && (root as THREE.Scene).isScene === true\n if (ownedHere || (legacyOwners.get(scene) === five && !movedToAnotherScene)) map.delete(key)\n }\n }\n if (sessions.get(five) === session) sessions.delete(five)\n activeSessions.delete(session)\n }\n const onFiveDispose = () => {\n disposedOwners.add(five)\n dispose()\n }\n const session: CSSSession = { five, front: new Map(), behind: new Map(), dispose }\n sessions.set(five, session)\n activeSessions.add(session)\n five.on('dispose', onFiveDispose)\n waitFiveModelLoaded(five, pending.signal).then(() => {\n if (disposed) return\n const wrapper = five.getElement()?.parentElement\n if (!wrapper) {\n // A host can detach its canvas before Five emits public dispose. Treat\n // that async mount as cancelled and release this session's resources.\n // A later append may create a fresh session through the normal entry.\n dispose()\n return\n }\n const behindWrapper = generateBehindFiveElement(five)\n if (!behindWrapper) {\n console.error('initialCSS3DRender: behindWrapper is not exist')\n return\n }\n front.appendToElement(wrapper)\n front.renderCss3dObjectEveryFrame(() => scenesForOwner(session, 'front'), five.camera)\n behind.appendToElement(behindWrapper)\n behind.renderCss3dObjectEveryFrame(() => scenesForOwner(session, 'behind'), five.camera)\n })\n return dispose\n}\n","import { CSS3DSprite } from '../../../shared-utils/three/CSS3DRenderer'\n\nexport class ICSS3DSprite extends CSS3DSprite {\n public isCSS3DSprite = true\n public isCSS3DObject = true\n}\n","import { bindFiveOwner } from '../../../five/getFiveFromParentChain'\nimport * as THREE from 'three/webgpu'\nimport type { Intersection } from '../../../../typings/typings'\nimport { addFrontScene, removeFrontScene } from '../../../CSS3DRender'\nimport type { Five } from '@realsee/five-webgpu'\nimport { LineMesh, type LineMeshStyle } from '../../../../Sculpt/Meshes/Line'\nimport type { PointHelperAbstract } from './typing'\nimport { ICSS3DSprite } from '../../../../CSS3DRenderPlugin/utils/three/CSS3DSprite'\n\n\nexport interface MouseGroupParameter {\n isMobile?: boolean\n useNormalVector?: boolean // 是否展示法向量\n ballColor?: number // 法向量小球色值\n}\n\nfunction createPlaneMesh() {\n const radius = 0.2\n const group = new THREE.Group()\n const fill = new THREE.Mesh(\n new THREE.CircleGeometry(radius - 0.01, 64),\n new THREE.MeshBasicMaterial({ color: 0xffffff, opacity: 0.2, side: THREE.DoubleSide, depthTest: false, transparent: true }),\n )\n const border = new THREE.Mesh(\n new THREE.RingGeometry(radius - 0.01, radius, 64),\n new THREE.MeshBasicMaterial({ color: 0xffffff, opacity: 0.3, side: THREE.DoubleSide, depthTest: false, transparent: true }),\n )\n group.add(fill, border)\n return group\n}\n\nfunction createCrossline() {\n const length = 0.5\n const group = new THREE.Group()\n const style: Partial<LineMeshStyle> = {\n lineWidth: 1,\n lineColor: 0x33ffdd,\n lineOpacity: 0.7,\n occlusionVisibility: true,\n }\n const lineX = new LineMesh({ points: [{ x: -length }, { x: length }], ...style, lineColor: 0x33ffdd })\n const lineY = new LineMesh({ points: [{ y: -length }, { y: length }], ...style, lineColor: 0x33ffdd })\n\n group.add(lineX, lineY)\n return group\n}\n\nfunction createLineMesh(length: number) {\n // 法向量垂直管\n const zPath = new THREE.CurvePath<THREE.Vector3>()\n zPath.add(new THREE.LineCurve3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, length)))\n const zGeometry = new THREE.TubeGeometry(zPath, 32, 0.003)\n const zMaterial = new THREE.MeshBasicMaterial({\n color: 0xa7c3ff,\n depthTest: false,\n transparent: true, // 必须要开启透明度,要和PlaneMesh一起渲染\n })\n const zMesh = new THREE.Mesh(zGeometry, zMaterial)\n return zMesh\n}\n\nfunction createRingMesh() {\n // 法向量圆环\n const geometry = new THREE.RingGeometry(0.03, 0.035, 64)\n const material = new THREE.MeshBasicMaterial({\n color: 0xffffff,\n depthTest: false,\n transparent: true, // 必须要开启透明度,要和PlaneMesh一起渲染\n side: THREE.DoubleSide,\n })\n const ringMesh = new THREE.Mesh(geometry, material)\n return ringMesh\n}\n\nfunction createBallMesh() {\n // mesh 球\n const ballGeometry = new THREE.SphereGeometry(0.018, 32, 32)\n const ballMaterial = new THREE.MeshBasicMaterial({\n color: 0x4d97ff,\n depthTest: false,\n transparent: true, // 必须要开启透明度,要和PlaneMesh一起渲染\n })\n const ballMesh = new THREE.Mesh(ballGeometry, ballMaterial)\n\n return ballMesh\n}\n\nfunction createCSSBallMesh() {\n // css 球\n const img = document.createElement('img')\n img.src =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAVCAMAAAB8FU7dAAAAw1BMVEUAAACDuuiAsu11q/x8r/+HxtKHxtKIx9J4ut6Hx9Jcn/uNwNlmmf+RuP9ppf9orel3ud2HxtJrpf9oremev/9ppP9orelQmP9ZoPWSuP92q/9cnv9prel4ut53qv9orelYoPWIxdJPmP+HxtGRuP9oo/+Suf9Qmf92q/+RuP+DsP9Pmv+FxdFtre2SyMiRuP9PmP+evv9ppf9cnv+rxf9orepZofV4ut52q/+Dsf+Esv+5y/93q/9aofbF0f93rP9qpf8IzZ1iAAAAL3RSTlMAEg4s3dK5nodgVQoF/Pf39vbt7evr39rV1NTOzs6srJ+fiIZ9fWlpW09ERCwcHMH8LhIAAADRSURBVBjTjdDHkoMwEIThBrzOm3POOQwSYCRhe/f9n2p75FD2zX/VXL5qOAjzkixLsFL6fOFF5PwpXUj/eEwx7Oh9Jq+FdV5MqZkXlU9K4KZsmqY02x/A8LSwv14o0ylJWkP087WVhDfcjmjj5b/E3+CEpDPdGY58C7tKfzSiiA9uB4dV/NIF7yVQ7AGuq0lOIzrvnLP2Et2aMzUqryge8FVX0Zjl5XkG3KsR593pM2zVEScjvbMU7IdGjF19IzZ43Ceyve4Ai5Jep93u9BJs3j/gXjHbRgy31AAAAABJRU5ErkJggg=='\n const cssMesh = new ICSS3DSprite(img)\n img.style.pointerEvents = 'none'\n cssMesh.scale.set(0.003, 0.003, 0.003)\n\n return cssMesh\n}\n\nexport class PointHelper2 extends THREE.Object3D implements PointHelperAbstract {\n public disableGetPixel = true\n public planeMesh: ReturnType<typeof createPlaneMesh>\n public ringMesh: ReturnType<typeof createRingMesh>\n public crossline: ReturnType<typeof createCrossline>\n public lineMesh: ReturnType<typeof createLineMesh>\n public ballMesh: ReturnType<typeof createBallMesh>\n public cssBallMesh: ReturnType<typeof createCSSBallMesh>\n\n public constructor(private readonly five: Five) {\n super()\n bindFiveOwner(this, five)\n\n const lineLength = 0.18\n this.planeMesh = createPlaneMesh()\n this.ringMesh = createRingMesh()\n this.crossline = createCrossline()\n this.lineMesh = createLineMesh(lineLength)\n this.ballMesh = createBallMesh()\n this.cssBallMesh = createCSSBallMesh()\n\n this.ballMesh.position.setZ(lineLength)\n this.cssBallMesh.position.setZ(lineLength)\n\n this.planeMesh.renderOrder = 0\n this.ringMesh.renderOrder = 1\n this.crossline.renderOrder = 2\n this.lineMesh.renderOrder = 3\n this.ballMesh.renderOrder = 4\n\n // 暂时移除 crossline,之后产品要再加上\n this.add(this.planeMesh, this.lineMesh, this.ballMesh, this.ringMesh, this.cssBallMesh)\n\n addFrontScene(this, undefined, five)\n }\n\n public updateWithIntersect(intersect: Intersection) {\n if (!intersect.face) return\n\n const normal = (() => {\n const normal = intersect.face.normal.clone().normalize()\n // 地面\n if (normal.y > 0.99) return new THREE.Vector3(0, 1, 0)\n\n // 天花板\n if (normal.y < -0.99) return new THREE.Vector3(0, -1, 0)\n\n // 标准墙面\n if (normal.x > 0.99) return new THREE.Vector3(1, 0, 0)\n if (normal.x < -0.99) return new THREE.Vector3(-1, 0, 0)\n if (normal.z > 0.99) return new THREE.Vector3(0, 0, 1)\n if (normal.z < -0.99) return new THREE.Vector3(0, 0, -1)\n\n // 斜墙\n if (normal.y < 0.01 && normal.y > -0.01) return new THREE.Vector3(normal.x, 0, normal.z)\n\n return normal\n })()\n\n const lookAtPosition = new THREE.Vector3().addVectors(intersect.point, normal)\n this.position.copy(intersect.point)\n this.lookAt(lookAtPosition)\n }\n\n public show() {\n this.visible = true\n this.add(this.cssBallMesh)\n }\n\n public hide() {\n this.visible = false\n this.remove(this.cssBallMesh)\n }\n\n public dispose() {\n this.traverse((object) => {\n const mesh = object as THREE.Mesh\n mesh.geometry?.dispose()\n if (mesh.material) {\n const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]\n materials.forEach((material) => material.dispose())\n }\n })\n removeFrontScene(this, this.five)\n this.cssBallMesh.element.remove()\n this.removeFromParent()\n }\n}\n","import * as THREE from 'three/webgpu'\nimport type { Five } from '@realsee/five-webgpu'\nimport { Magnifier, PointHelper } from '../..'\nimport type { Intersection } from '../../../../typings/typings'\nimport { Subscribe } from '../../../Subscribe'\nimport { PointHelper2 } from './PointHelper2'\nimport type { PointHelperAbstract } from './typing'\n\nexport interface PointSelectorHelperConfig {\n magnifier?: Magnifier | null\n magnifierParams?: ConstructorParameters<typeof Magnifier>[1]\n pointHelper?: PointHelperAbstract | 'default' | 'highlight' | null\n container?: Element\n skipPanorama?: boolean\n}\n\ntype EventMap = {\n intersectionUpdate: (intersection: PointIntersection) => void\n /** 功能开启 */\n enabled: () => void\n /** 功能关闭 */\n disabled: () => void\n}\n\nexport interface PointIntersection extends Intersection {\n /**\n * @description 被吸附\n */\n isAdsorbed?: boolean\n /**\n * @description 原始焦点\n */\n originalPoint?: THREE.Vector3\n /**\n * @description 虚拟生成的点\n */\n isVirtual?: boolean\n /**\n * @description 射线\n */\n raycaster?: THREE.Raycaster\n /**\n * @description 如果开启了吸附并且吸附到了平面,这里会有吸附的平面\n */\n adherePlane?: THREE.Plane\n /**\n * @description 如果开启了吸附并且吸附到了点,这里会有吸附的点\n */\n adherePoint?: THREE.Vector3\n /**\n * @description 如果开启了吸附并且吸附到了线,这里会有吸附的线\n */\n adhereLine?: THREE.Line3\n}\n\nexport class PointSelectorHelper {\n public five: Five\n public hooks = new Subscribe<EventMap>()\n public position: PointIntersection | null = null\n public magnifier: Magnifier | null = null\n public pointHelper: PointHelperAbstract | null = null\n public state = { enabled: false, visible: true }\n private group = new THREE.Group()\n\n public constructor(five: Five, options?: PointSelectorHelperConfig) {\n this.five = five\n\n this.magnifier =\n options?.magnifier !== undefined ? options.magnifier : new Magnifier(five, { dragEnabled: true, ...options?.magnifierParams, skipPanorama: options?.skipPanorama ?? false })\n\n let pointHelper: PointHelperAbstract | null = null\n if (options?.pointHelper === 'default' || options?.pointHelper === undefined) {\n pointHelper = new PointHelper(five)\n // pointHelper = new PointHelper2(five)\n } else if (options?.pointHelper === 'highlight') {\n pointHelper = new PointHelper2(five)\n } else if (options?.pointHelper === null) {\n pointHelper = null\n } else {\n pointHelper = options.pointHelper\n }\n this.pointHelper = pointHelper\n\n this.group.name = 'five-point-selector'\n this.five.scene.add(this.group)\n this.magnifier?.appendTo(options.container ?? five.getElement()?.parentElement ?? document.body)\n }\n\n public show = () => {\n if (this.state.visible) return\n this.state.visible = true\n this.pointHelper?.show()\n this.magnifier?.enable()\n this.five.needsRender = true\n }\n\n public hide = () => {\n if (!this.state.visible) return\n this.state.visible = false\n this.pointHelper?.hide()\n this.magnifier?.disable()\n this.five.needsRender = true\n }\n\n public enable() {\n if (this.state.enabled) return\n this.state.enabled = true\n if (this.pointHelper) {\n this.group.add(this.pointHelper)\n }\n this.magnifier?.enable()\n this.five.needsRender = true\n this.hooks.emit('enabled')\n }\n\n public disable() {\n if (!this.state.enabled) return\n this.state.enabled = false\n if (this.pointHelper) {\n this.group.remove(this.pointHelper)\n }\n this.magnifier?.disable()\n this.hooks.emit('disabled')\n }\n\n public dispose() {\n this.hooks.off()\n this.disable()\n this.abortUpdateMagnifier()\n this.magnifier?.dispose()\n this.magnifier = null\n this.pointHelper?.dispose()\n this.pointHelper = null\n this.group.removeFromParent()\n }\n\n public updateWithIntersect = (intersect?: Intersection, config: { emitEvent: boolean } = { emitEvent: true }) => {\n if (!intersect) return\n this.abortUpdateMagnifier()\n this.position = intersect\n if (config.emitEvent) this.hooks.emit('intersectionUpdate', intersect)\n\n // update pointer helper\n this.pointHelper?.updateWithIntersect(intersect)\n // update magnifier\n // 因为 Magnifier 的渲染依赖场景渲染 ,所以需要在场景渲染完成后再渲染 Magnifier\n const updateMagnifier = () => this.magnifier?.renderWithPoint(intersect.point)\n this.abortUpdateMagnifier = () => this.five.off('renderFrame', updateMagnifier)\n this.five.once('renderFrame', updateMagnifier)\n\n this.five.needsRender = true\n }\n\n private abortUpdateMagnifier: () => any = () => {}\n}\n","const navigatorTouchPoints = typeof navigator === 'undefined' ? 0 : navigator.maxTouchPoints || (navigator as any).msMaxTouchPoints || 0\n\nexport const isTouchDevice = typeof window !== 'undefined' && ('ontouchstart' in window || navigatorTouchPoints > 0)\n","import { Vector3, type Face } from 'three/webgpu'\n\nexport function createIntersectionFace(normal = new Vector3()): Face {\n return { a: 0, b: 0, c: 0, normal, materialIndex: 0 }\n}\n","import type { Five } from '@realsee/five-webgpu'\nimport * as THREE from 'three/webgpu'\n\nexport function getRaycasterByNdcPosition(five: Five, position: { x: number; y: number }) {\n const { x: left, y: top } = position\n const x = left * 2 - 1\n const y = top * 2 - 1\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), five.camera)\n raycaster.params.Points.threshold = 0.02\n return raycaster\n}\n","import * as THREE from 'three/webgpu'\nimport type { Five, Intersection } from '@realsee/five-webgpu'\nimport { getRaycasterByNdcPosition } from './getRaycasterByNdcPosition'\nimport { getFiveModel } from './getFiveModel'\nimport { createIntersectionFace } from '../three/createIntersectionFace'\n\ninterface IIntersection extends THREE.Intersection {\n raycaster: THREE.Raycaster\n isVirtual: boolean\n}\n\n/**\n * @description 根据 ndc 坐标获取 Intersect\n */\nexport function getIntersectByNdcPosition(\n five: Five,\n position: { x: number; y: number },\n config?: { virtualPoint?: boolean },\n): IIntersection | undefined {\n const raycaster = getRaycasterByNdcPosition(five, position)\n return getIntersectByRaycaster(five, raycaster, config)\n}\n\n/**\n * @description 根据射线获取 Intersect\n */\nexport function getIntersectByRaycaster(\n five: Five,\n raycaster: THREE.Raycaster,\n config?: { virtualPoint?: boolean },\n): IIntersection | undefined {\n const realIntersect = getRealIntersectByRaycaster(five, raycaster)\n if (!config?.virtualPoint) {\n return realIntersect\n } else {\n return realIntersect ?? getVirtualIntersectByRaycaster(raycaster)\n }\n}\n\nexport function getVirtualIntersectByRaycaster(raycaster: THREE.Raycaster, distance: number = 3): IIntersection {\n const position = new THREE.Vector3().addVectors(\n raycaster.ray.origin,\n raycaster.ray.direction.clone().normalize().multiplyScalar(distance),\n )\n const normal = raycaster.ray.direction.clone().negate()\n const virtualIntersect = {\n distance,\n point: position,\n object: new THREE.Object3D(),\n face: createIntersectionFace(normal),\n raycaster,\n isVirtual: true,\n }\n return virtualIntersect\n}\n\nexport function getRealIntersectByRaycaster(five: Five, raycaster: THREE.Raycaster): IIntersection {\n const model = getFiveModel(five)\n const intersects = model.intersectRaycaster(raycaster) as Intersection[]\n const intersect = intersects[0]\n if (intersect) {\n return { ...intersect, raycaster, isVirtual: false }\n }\n}\n","export const CURSOR_NOT_ALLOW_URL = `url(\"data:image/svg+xml,%3Csvg width='12px' height='12px' viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cpath d='M6,12 C9.3137085,12 12,9.3137085 12,6 C12,2.6862915 9.3137085,0 6,0 C2.6862915,0 0,2.6862915 0,6 C0,9.3137085 2.6862915,12 6,12 Z' fill='%23FF5959'%3E%3C/path%3E%3Cg transform='translate(2, 2)' stroke='%23FFFFFF'%3E%3Ccircle cx='4' cy='4' r='4'%3E%3C/circle%3E%3Cline x1='1.07141075' y1='1.23997894' x2='6.64700843' y2='6.81557662'%3E%3C/line%3E%3C/g%3E%3C/g%3E%3C/svg%3E\") 6 6, auto`\n","\n\n\n\n\nimport type { Five } from '@realsee/five-webgpu'\nimport { PointSelectorHelper, type PointIntersection, type PointSelectorHelperConfig } from './utils/PointSelectorHelper'\nimport { isTouchDevice } from '../../isTouchDevice'\nimport type { MagnifierParameter } from '../Magnifier'\nimport type { Intersection, Vector3 } from 'three/webgpu'\nimport * as THREE from 'three/webgpu'\nimport { createIntersectionFace } from '../createIntersectionFace'\nimport { Subscribe } from '../../Subscribe'\nimport { getIntersectByRaycaster, getVirtualIntersectByRaycaster } from '../../five/getPosition'\nimport { getRaycasterByNdcPosition } from '../../five/getRaycasterByNdcPosition'\nimport type { LiteralString } from '../../../typings/utils.type'\nimport { CURSOR_NOT_ALLOW_URL } from './utils/contents'\nimport { rayOnLine } from '../../../Sculpt/utils/three/rayOnLine'\nimport { THREERaycaster } from '../core/Raycaster'\n\nexport type { PointIntersection }\n\nconst _vector3 = new THREE.Vector3()\n\nconst disableFiveEvent = (): false => false\n\nexport type ActionIfNoIntersection = LiteralString<'virtualPoint' | 'lastPoint' | 'disable'>\n\nexport type AdherePoint = Vector3 & {\n normal?: THREE.Vector3\n /**\n * @description 被模型遮挡也能看到的点\n */\n IsAlwaysVisible?: boolean\n}\n\ntype PointerSelectorMode = 'fixed' | 'cursor'\n\ninterface Config {\n /**\n * @description: 选点的两种模式, 'fixed' 为固定选点为屏幕中心点,拖动five画布来更新点,'cursor' 为跟随鼠标移动来更新点, 'auto' 则根据设备类型自动选择\n * @default: 'auto'\n */\n mode: PointerSelectorMode | 'auto'\n /**\n * @description 当鼠标位置没有模型时的行为\n * ```markdown\n * virtualPoint: 生成一个虚拟点\n * lastPoint: 选点器停留在上一个点处\n * disable: 禁止选点\n * ```\n * @default 'virtualPoint'\n */\n actionIfNoIntersection: ActionIfNoIntersection\n helper: PointSelectorHelperConfig\n /**\n * @description 是否跳过全景图渲染\n * @default false\n */\n skipPanorama: boolean\n /**\n * five 6.7.0 特性,可配置是否自定义拾取点过滤函数\n */\n hitFilter?: (intersect: Intersection) => boolean\n}\n\nexport type PointSelectorConfig = Partial<Config>\n\ntype EventMap = {\n /**\n * @description 与模型交点更新时触发,移出监听范围时为null\n */\n intersectionUpdate: (intersection?: PointIntersection | null) => void\n /**\n * @description 试图打点,返回false则不打点\n */\n wantsSelect: (intersection?: PointIntersection | null) => boolean | void\n /**\n * @description 打点成功\n */\n select: (intersection?: PointIntersection | null) => void\n /**\n * @description 功能开启\n */\n enable: () => void\n /**\n * @description 功能关闭\n */\n disable: () => void\n}\n\n/**\n * @description: 在屏幕上选点\n */\nexport class PointSelector extends Subscribe<EventMap> {\n public get position() {\n if (this.outOfFive) return undefined\n return this.pointSelectorHelper.position\n }\n\n /**\n * @description: 不在 five canvas 上时为 true\n */\n public get outOfFive() {\n return this._outOfFive\n }\n\n public get enabled() {\n return this._enabled\n }\n\n public get cursorError() {\n return this._cursorError\n }\n\n public set cursorError(cursorError: boolean) {\n this._cursorError = cursorError\n this.five.getElement().style.cursor = cursorError ? CURSOR_NOT_ALLOW_URL : ''\n cursorError ? this.pointSelectorHelper.hide() : this.pointSelectorHelper.show()\n }\n\n public _cursorError = false\n\n public actionIfNoIntersection: ActionIfNoIntersection = 'virtualPoint'\n\n public plane?: THREE.Plane | null\n\n /**\n * @description 结果区别:vertical: 射线和模型的交点在plane上的投影点;onlyPlane: 不论射线和模型是否有交点,都为射线和plane的焦点;onlyVirtual: 仅当射线和模型没有交点时,为射线和plane的焦点\n */\n public planeMode: 'vertical' | 'onlyPlane' | 'onlyVirtual' = 'onlyVirtual'\n\n /**\n * @description 射线没有命中模型时,是否一律禁止点选\n * @default false\n */\n public disableIfNoIntersection = false\n\n public readonly pointSelectorHelper: PointSelectorHelper\n\n public five: Five\n\n /**\n * @description 吸附功能总开关,方便临时的一键开启/关闭\n */\n protected adhereEnabled = true\n\n /**\n * @description 吸附半径\n */\n public adhereRadius = 0.1\n\n /**\n * @description 吸附面\n */\n public adherePlane: THREE.Plane[] = []\n\n /**\n * @description 吸附线\n */\n public adhereLine: THREE.Line3[] = []\n\n private set outOfFive(outOfFive: boolean) {\n this._outOfFive = outOfFive\n }\n private _outOfFive = false\n\n private set enabled(enabled: boolean) {\n this._enabled = enabled\n }\n private _enabled = false\n\n protected mode: PointerSelectorMode\n\n /** 长按屏幕的动作触发后为true,手指抬起后为false */\n private pressDown = false\n\n /** 一组吸附的点,光标靠近这些点时,会将helper以及放大镜的位置设置为这些点 */\n protected adherePoints: ((params: { intersection: PointIntersection; pointSelectorInstance: PointSelector }) => AdherePoint[]) | null\n\n /** 有值时表明处于按压检查阶段 */\n private setPressDown?: ReturnType<typeof setTimeout>\n\n private lastFiveHelperVisible?: boolean\n\n private lastIntersection?: PointIntersection\n\n private mousePosition: { clientX: number; clientY: number } | null\n\n private _mouseDownInfo: { clientX: number; clientY: number; timestamp: number } | null\n\n private _touchStartInfo: { clientX: number; clientY: number; timestamp: number } | null\n\n private config: PointSelectorConfig = {}\n\n protected get mouseNdcPosition(): { x: number; y: number } | null {\n if (!this.mousePosition) return null\n return this.mousePositionToNdcPosition(this.mousePosition)\n }\n\n public constructor(five: Five, config?: PointSelectorConfig) {\n super()\n this.five = five\n\n this.config = { ...this.config, ...config }\n\n this.actionIfNoIntersection = config?.actionIfNoIntersection ?? 'virtualPoint'\n\n const mode = config?.mode ?? 'auto'\n if (mode === 'auto') {\n this.mode = isTouchDevice ? 'fixed' : 'cursor'\n } else {\n this.mode = mode\n }\n\n const defaultMagnifierParams: MagnifierParameter = {\n autoFixPCPosition: this.mode === 'cursor',\n initialPosition: this.mode === 'fixed' ? { left: '35%', top: '20%' } : undefined,\n }\n\n this.pointSelectorHelper = new PointSelectorHelper(this.five, {\n ...config?.helper,\n magnifierParams: {\n ...defaultMagnifierParams,\n ...config?.helper?.magnifierParams,\n },\n skipPanorama: config?.skipPanorama ?? false,\n })\n\n // 刚开始的时候,因为没有选点,所以不显示,后面鼠标移动了或者点了之后才显示\n this.pointSelectorHelper.hide()\n }\n\n public enable() {\n if (this.enabled) return\n this.enabled = true\n\n // 设置一些初始化的值\n this.outOfFive = false\n\n this.pointSelectorHelper.enable()\n // 刚开始的时候,因为没有选点,所以不显示,后面鼠标移动了或者点了之后才显示\n this.pointSelectorHelper.hide()\n\n const fiveElement = this.five.getElement()\n\n if (!fiveElement) throw new Error('five element not found')\n\n // 添加一堆监听\n if (this.mode === 'cursor') {\n // 鼠标选点 / 触摸屏选点\n\n this.five.on('wantsMoveToPano', disableFiveEvent)\n this.five.on('wantsChangeMode', disableFiveEvent)\n this.five.on('wantsTapGesture', disableFiveEvent)\n\n // touch 设备事件\n fiveElement.addEventListener('touchstart', this.onTouchStart, { passive: true })\n fiveElement.addEventListener('touchmove', this.onTouchMove)\n fiveElement.addEventListener('touchend', this.onTouchEnd)\n fiveElement.addEventListener('touchcancel', this.onTouchCancel)\n // PC 设备事件\n fiveElement.addEventListener('mousedown', this.onMouseDown)\n fiveElement.addEventListener('mouseup', this.onMouseUp)\n fiveElement.addEventListener('mousemove', this.updateByMousePosition)\n fiveElement.addEventListener('wheel', this.onMouseWheel)\n fiveElement.addEventListener('mouseenter', this.onMouseEnter)\n fiveElement.addEventListener('mouseout', this.onMouseLeave)\n\n this.five.on('wantsPanGesture', this.onFiveWantsPanGesture)\n } else if (this.mode === 'fixed') {\n // 固定在屏幕中心的\n this.five.on('panoArrived', this.renderScreenCenter)\n this.five.on('panGesture', this.renderScreenCenter)\n this.five.on('interiaPan', this.renderScreenCenter)\n this.renderScreenCenter() // enable 时,自动加载屏幕中心点, 而不是动一下屏幕才加载\n this.pointSelectorHelper.show()\n }\n\n // shared\n document.addEventListener('keydown', this.onKeyDown)\n document.addEventListener('keyup', this.onKeyUp)\n this.pointSelectorHelper.hooks.on('intersectionUpdate', this.emitIntersectionUpdate)\n this.lastFiveHelperVisible = this.five.helperVisible\n this.five.helperVisible = false\n\n this.emit('enable')\n }\n\n public disable() {\n this.onTouchCancel()\n if (!this.enabled) return\n this.enabled = false\n\n this.adherePoints = null\n this.adhereLine = []\n this.adherePlane = []\n this.plane = undefined\n\n this.pointSelectorHelper.disable()\n this.five.getElement().style.cursor = ''\n\n // 移除一堆监听\n const fiveElement = this.five.getElement()\n this.five.off('wantsPanGesture', this.onFiveWantsPanGesture)\n this.five.off('wantsMoveToPano', disableFiveEvent)\n this.five.off('wantsChangeMode', disableFiveEvent)\n this.five.off('wantsTapGesture', disableFiveEvent)\n\n this.five.helperVisible = this.lastFiveHelperVisible\n\n fiveElement?.removeEventListener('touchstart', this.onTouchStart)\n fiveElement?.removeEventListener('touchmove', this.onTouchMove)\n fiveElement?.removeEventListener('touchend', this.onTouchEnd)\n fiveElement?.removeEventListener('touchcancel', this.onTouchCancel)\n\n fiveElement?.removeEventListener('mousedown', this.onMouseDown)\n fiveElement?.removeEventListener('mouseup', this.onMouseUp)\n fiveElement?.removeEventListener('mousemove', this.updateByMousePosition)\n fiveElement?.removeEventListener('wheel', this.onMouseWheel)\n fiveElement?.removeEventListener('mouseenter', this.onMouseEnter)\n fiveElement?.removeEventListener('mouseout', this.onMouseLeave)\n\n this.five.off('panoArrived', this.renderScreenCenter)\n this.five.off('panGesture', this.renderScreenCenter)\n this.five.off('interiaPan', this.renderScreenCenter)\n\n document.removeEventListener('keydown', this.onKeyDown)\n document.removeEventListener('keyup', this.onKeyUp)\n this.pointSelectorHelper.hooks.off('intersectionUpdate', this.emitIntersectionUpdate)\n\n this.emit('disable')\n }\n\n public dispose() {\n this.disable()\n this.pointSelectorHelper.dispose()\n this.off()\n }\n\n public setAdherePoints(\n points: AdherePoint[] | ((params: { intersection: PointIntersection; pointSelectorInstance: PointSelector }) => AdherePoint[]) | null,\n ) {\n if (!points) {\n this.adherePoints = null\n } else if (typeof points === 'function') {\n this.adherePoints = points\n } else {\n this.adherePoints = () => points\n }\n }\n\n /**\n * @description: 主动触发一次选点\n * @return: select 是否成功\n */\n public select = (intersection?: PointIntersection) => {\n if (intersection) this.updatePointSelectorHelperIntersect(intersection)\n\n const cancel = this.emit('wantsSelect', this.position)\n if (!cancel) {\n this.pointSelectorHelper.hide()\n this.emit('select', this.position)\n console.debug(this.position)\n }\n return !cancel\n }\n\n private onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Shift') this.adhereEnabled = false\n }\n\n private onKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Shift') this.adhereEnabled = true\n }\n\n private onMouseWheel = (e: MouseEvent) => {\n this.updateByMousePosition(e)\n\n const render = () => this.updateByMousePosition()\n this.five.off('render.prepare', render)\n this.five.on('render.prepare', render)\n setTimeout(() => {\n this.five.off('render.prepare', render)\n }, 200)\n }\n\n /**\n * @description: 鼠标进入five canvas时\n */\n protected onEnter = () => {\n if (!this.cursorError) {\n this.pointSelectorHelper.show()\n }\n this.outOfFive = false\n }\n\n /**\n * @description: 鼠标进入five canvas时\n */\n private onMouseEnter = () => {\n this.onEnter()\n this.emit('intersectionUpdate', this.position)\n }\n\n /**\n * @description: 鼠标离开five canvas时\n */\n private onMouseLeave = () => {\n this.pointSelectorHelper.hide()\n this.outOfFive = true\n this.emit('intersectionUpdate', undefined)\n }\n\n private onMouseDown = (e: MouseEvent) => {\n this._mouseDownInfo = {\n clientX: e.clientX,\n clientY: e.clientY,\n timestamp: performance.now(),\n }\n }\n\n private onMouseUp = (e: MouseEvent) => {\n if (!this._mouseDownInfo) return\n\n const { clientX, clientY, timestamp } = this._mouseDownInfo\n\n if (Math.abs(e.clientX - clientX) < 2 && Math.abs(e.clientY - clientY) < 2 && performance.now() - timestamp < 500) {\n this.select()\n } else {\n this._mouseDownInfo = null\n }\n }\n\n private onTouchCancel = () => {\n if (this.setPressDown) clearTimeout(this.setPressDown)\n this.setPressDown = undefined\n this.pressDown = false\n this._touchStartInfo = null\n }\n\n private onTouchStart = (e: TouchEvent) => {\n this.onTouchCancel()\n if (e.touches.length !== 1) return\n this._touchStartInfo = {\n clientX: e.touches[0].clientX,\n clientY: e.touches[0].clientY,\n timestamp: performance.now(),\n }\n\n this.setPressDown = setTimeout(() => {\n this.setPressDown = undefined\n\n // 触发长按事件\n this.mousePosition = {\n clientX: e.touches[0].clientX,\n clientY: e.touches[0].clientY,\n }\n if (!this.mouseNdcPosition) return\n const success = this.updateByNdcPosition(this.mouseNdcPosition)\n this.pressDown = success\n }, 200)\n }\n\n private onTouchMove = (e: TouchEvent) => {\n if (e.touches.length !== 1) { this.onTouchCancel(); return }\n if (this.setPressDown) {\n let moved = false\n\n if (this._touchStartInfo) {\n const { clientX, clientY } = this._touchStartInfo\n if (Math.abs(e.touches[0].clientX - clientX) > 2 || Math.abs(e.touches[0].clientY - clientY) > 2) {\n moved = true\n }\n }\n\n if (moved) {\n clearTimeout(this.setPressDown)\n this.setPressDown = undefined\n }\n\n return\n }\n\n // 触发拖动事件\n if (this.pressDown) {\n this.mousePosition = {\n clientX: e.touches[0].clientX,\n clientY: e.touches[0].clientY,\n }\n if (!this.mouseNdcPosition) return\n this.updateByNdcPosition(this.mouseNdcPosition)\n }\n }\n\n private onTouchEnd = (e: TouchEvent) => {\n if (this.setPressDown) {\n clearTimeout(this.setPressDown)\n this.setPressDown = undefined\n return\n }\n\n // 触发完成事件\n if (this.pressDown) {\n setTimeout(() => {\n this.pressDown = false\n }, 100) // 慢点结束,不然有可能触发five事件\n this.select()\n }\n }\n\n private updateByMousePosition = (event?: MouseEvent) => {\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n if (!event || event?.buttons !== 0) {\n this.pointSelectorHelper.hide()\n // 鼠标按下时不更新\n return\n } else {\n this.pointSelectorHelper.show()\n }\n\n if (event) {\n this.mousePosition = {\n clientX: event.clientX,\n clientY: event.clientY,\n }\n }\n\n this.updateByNdcPosition(this.mouseNdcPosition)\n }\n\n /**\n * @description: 根据鼠标位置计算焦点位置并更新\n */\n protected updateByNdcPosition = (ndcPosition: { x: number; y: number }) => {\n const raycaster = getRaycasterByNdcPosition(this.five, ndcPosition)\n\n if (this.config.hitFilter) {\n raycaster.hitFilter = this.config.hitFilter\n }\n\n let realIntersection: PointIntersection = getIntersectByRaycaster(this.five, raycaster)\n if (realIntersection) {\n if (this.plane && this.planeMode === 'vertical') {\n realIntersection = {\n ...realIntersection,\n point: this.plane.projectPoint(realIntersection.point, new THREE.Vector3()),\n face: createIntersectionFace(this.plane.normal.clone()),\n originalPoint: realIntersection.point.clone(),\n }\n }\n\n if (this.plane && this.planeMode === 'onlyPlane') {\n const intersectionPoint = raycaster.ray.intersectPlane(this.plane, _vector3)\n if (!intersectionPoint) return false\n realIntersection = {\n distance: this.five.camera.position.distanceTo(intersectionPoint),\n point: intersectionPoint.clone(),\n originalPoint: realIntersection.point.clone(),\n face: createIntersectionFace(this.plane.normal.clone()),\n raycaster,\n }\n }\n\n this.updatePointSelectorHelperIntersect(realIntersection)\n this.lastIntersection = realIntersection\n\n return true\n }\n\n if (this.disableIfNoIntersection) {\n this.updatePointSelectorHelperIntersect(null)\n return false\n }\n if (this.plane) {\n const intersectionPoint = raycaster.ray.intersectPlane(this.plane, _vector3)\n if (intersectionPoint) {\n const virtualIntersection = {\n distance: this.five.camera.position.distanceTo(intersectionPoint),\n point: intersectionPoint.clone(),\n object: new THREE.Object3D(),\n face: createIntersectionFace(this.plane.normal.clone()),\n raycaster,\n isVirtual: true,\n }\n this.updatePointSelectorHelperIntersect(virtualIntersection)\n return true\n }\n }\n\n if (this.actionIfNoIntersection === 'lastPoint') {\n this.updatePointSelectorHelperIntersect(this.lastIntersection)\n return true\n } else if (this.actionIfNoIntersection === 'virtualPoint') {\n const virtualIntersection = getVirtualIntersectByRaycaster(raycaster, this.lastIntersection?.distance)\n virtualIntersection.face = createIntersectionFace(this.lastIntersection?.face?.normal)\n virtualIntersection.isVirtual = true\n this.lastIntersection = virtualIntersection\n this.updatePointSelectorHelperIntersect(virtualIntersection)\n return true\n } else if (this.actionIfNoIntersection === 'disable') {\n this.updatePointSelectorHelperIntersect(null)\n return false\n }\n }\n\n /**\n * @description: 更新 pointSelectorHelper 的焦点位置\n */\n protected updatePointSelectorHelperIntersect = (intersect?: PointIntersection | null) => {\n if (!intersect) {\n this.pointSelectorHelper.hide()\n this.pointSelectorHelper.position = intersect\n this.emit('intersectionUpdate', intersect)\n this.five.getElement().style.cursor = CURSOR_NOT_ALLOW_URL\n return\n }\n\n this.onEnter()\n if (!this.cursorError) this.five.getElement().style.cursor = ''\n\n // 有吸附点的话,就吸附到最近的点.adherePoints\n const targetIntersect = { ...intersect }\n\n if (this.adhereEnabled && this.mouseNdcPosition && this.five.renderer) {\n const mouseNdcPosition = {\n x: this.mouseNdcPosition.x,\n y: 1 - this.mouseNdcPosition.y,\n }\n const size = this.five.renderer!.getSize(new THREE.Vector2())\n\n if (this.adhereEnabled && typeof this.adherePoints === 'function' && typeof this.adhereRadius === 'number') {\n // // ========== 吸附面 ==========\n for (const adherePlane of this.adherePlane) {\n const distance = adherePlane.distanceToPoint(intersect.point)\n let newPoint = adherePlane.projectPoint(intersect.point, new THREE.Vector3())\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n if (distance < this.adhereRadius) {\n targetIntersect.point = newPoint.clone()\n targetIntersect.adherePoint = newPoint.clone()\n if (!this.plane) {\n targetIntersect.face = createIntersectionFace(adherePlane.normal.clone())\n }\n targetIntersect.isAdsorbed = true\n }\n }\n }\n\n // ========== 吸附线 ==========\n for (const adhereLine of this.adhereLine) {\n let newPoint = adhereLine.closestPointToPoint(intersect.point, false, new THREE.Vector3())\n if (newPoint.distanceTo(intersect.point) < this.adhereRadius) {\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n targetIntersect.point = newPoint.clone()\n targetIntersect.adhereLine = adhereLine.clone()\n targetIntersect.isAdsorbed = true\n }\n } else {\n const closestPoint = rayOnLine({\n raycaster: new THREERaycaster(this.five.camera.position, intersect.point.clone().sub(this.five.camera.position).normalize()),\n line: adhereLine,\n clampToLine: false,\n })\n const projectPoint = closestPoint.clone().project(this.five.camera)\n if (projectPoint.z <= 1) {\n const ndcPosition = {\n x: (projectPoint.x + 1) / 2,\n y: (1 - projectPoint.y) / 2,\n }\n\n const positionOffset = {\n x: Math.abs(ndcPosition.x - mouseNdcPosition.x) * size.width,\n y: Math.abs(ndcPosition.y - mouseNdcPosition.y) * size.height,\n }\n\n let newPoint = closestPoint.clone()\n if (positionOffset.x < 10 && positionOffset.y < 10) {\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n targetIntersect.point = newPoint.clone()\n targetIntersect.adhereLine = adhereLine.clone()\n targetIntersect.isAdsorbed = true\n }\n }\n }\n }\n }\n\n // ========== 吸附点 ==========\n for (const _point of this.adherePoints({ intersection: intersect, pointSelectorInstance: this })) {\n const point = _point\n point.IsAlwaysVisible = _point.IsAlwaysVisible\n\n if (this.plane && this.plane.distanceToPoint(point) > 0.01) continue\n\n const distance = point.distanceTo(intersect.point)\n if (distance < this.adhereRadius) {\n // 1. 距离吸附判断\n targetIntersect.point = this.plane?.projectPoint(point, new THREE.Vector3()) ?? point.clone()\n if (!this.plane && _point.normal) targetIntersect.face = createIntersectionFace(_point.normal)\n targetIntersect.isAdsorbed = true\n\n break\n } else {\n // 2. 屏幕位置吸附判断\n const projectPoint = point.clone().project(this.five.camera)\n if (projectPoint.z > 1) continue // 屏幕外的点不吸附\n const size = this.five.renderer!.getSize(new THREE.Vector2())\n\n const ndcPosition = {\n x: (projectPoint.x + 1) / 2,\n y: (1 - projectPoint.y) / 2,\n }\n\n const positionOffset = {\n x: Math.abs(ndcPosition.x - mouseNdcPosition.x) * size.width,\n y: Math.abs(ndcPosition.y - mouseNdcPosition.y) * size.height,\n }\n\n if (positionOffset.x < 10 && positionOffset.y < 10) {\n // 2.1 满足屏幕位置吸附条件,还需要判断点是否可见\n let pointIsVisible = false\n if (point.IsAlwaysVisible) {\n pointIsVisible = true\n } else {\n // 碰撞检测\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(ndcPosition.x, ndcPosition.y), this.five.camera)\n const intersect = this.five.model.intersectRaycaster(raycaster)[0]\n const distanceError = 0.1\n const cameraToPointDistance = this.five.camera.position.distanceTo(point)\n if (intersect && intersect.distance < cameraToPointDistance + distanceError) {\n pointIsVisible = true\n }\n }\n\n if (pointIsVisible) {\n targetIntersect.point = point.clone()\n if (!this.plane && _point.normal) {\n targetIntersect.face = createIntersectionFace(_point.normal)\n }\n targetIntersect.isAdsorbed = true\n break\n }\n }\n }\n }\n }\n }\n this.pointSelectorHelper.updateWithIntersect(targetIntersect, { emitEvent: false }) // 关掉pointSelectorHelper的事件,自己手动触发,否则会触发两次\n this.emit('intersectionUpdate', targetIntersect)\n }\n\n private mousePositionToNdcPosition = (mousePosition: { clientX: number; clientY: number }) => {\n const fiveElement = this.five.getElement()\n if (!fiveElement) return null\n\n const { top, left, width, height } = fiveElement.getBoundingClientRect()\n\n const { clientX: mouseX, clientY: mouseY } = mousePosition\n return {\n x: (mouseX - left) / width,\n y: 1 - (mouseY - top) / height,\n }\n }\n\n private onFiveWantsPanGesture = (): false | void => {\n if (this.pressDown) return false\n }\n\n private renderScreenCenter = () => {\n this.updateByNdcPosition({ x: 0.5, y: 0.5 })\n }\n\n private emitIntersectionUpdate = (intersection: PointIntersection) => {\n this.emit('intersectionUpdate', intersection)\n }\n}\n","/** PointHelper 纹理贴图 */\nexport const POINT_HELPER_TEXTURE_URL = `data:image/png;base64,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`\n\nexport const POINT_DOM_HELPER_IMAGE =\n 'data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSI2NyIKICBoZWlnaHQ9IjY3IgogIHZpZXdCb3g9IjAgMCA2NyA2NyIKICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCj4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCB4MT0iNTAlIiB5MT0iMCUiIHgyPSI1MCUiIHkyPSIxMDAlIiBpZD0iYSI+CiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGRkYiIG9mZnNldD0iMCUiIC8+CiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGRkYiIHN0b3Atb3BhY2l0eT0iLjM5NiIgb2Zmc2V0PSIxMDAlIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCB4MT0iNTAlIiB5MT0iMCUiIHgyPSI1MCUiIHkyPSIxMDAlIiBpZD0iYiI+CiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGRkYiIG9mZnNldD0iMCUiIC8+CiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGRkYiIG9mZnNldD0iMTAwJSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxwYXRoCiAgICBkPSJNMzQuOTAzIDc0LjI2OGEyOS45NjMgMjkuOTYzIDAgMCAwIDExLjY0OCAyLjM0YzMuOTE4IDAgNy42Ni0uNzUgMTEuMDkzLTIuMTEzbDEuOTc2IDEuOTc3YTMyLjUzMSAzMi41MzEgMCAwIDEtMTMuMDY5IDIuNzIgMzIuNTIgMzIuNTIgMCAwIDEtMTMuNjA5LTIuOTYzek03Ni4wNSAzMy4zMzNjLjkxIDEuMzQ3IDEuMjIyIDIuMTM5IDEuNDIyIDIuNzI4YTMyLjYwMiAzMi42MDIgMCAwIDEgMS43MjIgMTAuNDljMCAzLjg0OS0uNjY2IDcuNTQyLTEuODkgMTAuOTdhMzUuMzQgMzUuMzQgMCAwIDEtLjc4IDEuOTQ0LjUwOC41MDggMCAwIDEtLjYzLjI4M2wtMS4yOTktMS4yMjdjLjEzNi0xLjQ5Ni4zNTEtMi4wNzYuNDktMi40OTVhMzAuMDI3IDMwLjAyNyAwIDAgMCAxLjUyNC05LjQ3NSAzMC4wNCAzMC4wNCAwIDAgMC0xLjQwOC05LjExNiAzNi4xODMgMzYuMTgzIDAgMCAwLS43Ni0yLjA4NWwxLjI2Ni0xLjg4NGEuNTA4LjUwOCAwIDAgMSAuMzQzLS4xMzN6bS01OS40MzQuNTgxbDEuNjczIDEuMjNjLS4wODUgMS40LS4yNjcgMS45MTYtLjM4NiAyLjI5YTMwLjA0IDMwLjA0IDAgMCAwLTEuNDA4IDkuMTE3YzAgMy4yNDcuNTE1IDYuMzc0IDEuNDY4IDkuMzAzLjEwNy4zMy4yNjguNzguNDggMS4zNDZsLTEuMjg0IDEuODkzYS41MDcuNTA3IDAgMCAxLS42NzQuMDExYy0uNDI2LS44OTMtLjYzLTEuNDIxLS43Ny0xLjgyNWEzMi41OTQgMzIuNTk0IDAgMCAxLTEuODA0LTEwLjcyOGMwLTMuODY3LjY3Mi03LjU3NiAxLjkwNi0xMS4wMTguMTIzLS4zNDUuMjk4LS43OTEuNTI1LTEuMzQyYS41MDYuNTA2IDAgMCAxIC4yNzQtLjI3N3pNNDYuNTUxIDEzLjkxYzMuNzM1IDAgNy4zMjQuNjI3IDEwLjY2NyAxLjc4Mi40MjcuMTQ4Ljk5MS4zNjUgMS42OS42NTFsLS45NSAxLjk0NGMtMS41NzctLjE0NC0yLjIyMy0uMzY4LTIuNjg4LS41MDhhMzAuMDU2IDMwLjA1NiAwIDAgMC04LjcxOS0xLjI4NWMtMy41NSAwLTYuOTU3LjYxNi0xMC4xMTkgMS43NDYtLjI2OS4wOTctLjYyOS4yMzUtMS4wNzkuNDE1bC0xLjg5OC0xLjI3Yy42NjQtMS4wMjIgMS4wMzUtMS4xNzYgMS4zMjUtMS4yODlhMzIuNDUzIDMyLjQ1MyAwIDAgMSA4Ljc3LTIuMDVjLjk4OS0uMDkgMS45OS0uMTM2IDMuMDAxLS4xMzZ6IgogICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEyLjcxOCAtMTIuNzE4KSIKICAgIGZpbGw9InVybCgjYSkiCiAgICBzdHJva2U9InVybCgjYikiCiAgICBzdHJva2Utd2lkdGg9Ii41NSIKICAgIGZpbGwtcnVsZT0iZXZlbm9kZCIKICAgIG9wYWNpdHk9Ii42IgogIC8+Cjwvc3ZnPgo='\n","export const rangePieceImg =\n 'data:image/png;base64,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'\n\nexport const rangePieceIntersectImg =\n 'data:image/png;base64,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'\n\nexport default `\n <style>\n .range-piece__container {\n position: absolute;\n top: 39%;\n left: 50%;\n margin-left: -54px;\n width: 108px;\n height: 108px;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: pieceContainer 0.3s ease-in-out;\n animation-fill-mode: forwards;\n }\n .range-piece__content {\n width: 100%;\n height: 100%;\n background-image: url(${rangePieceImg});\n opacity: 0.4;\n background-size: 100%;\n background-repeat: no-repeat;\n transition: linear transform 0.1s;\n }\n .range-piece__content--active {\n animation: dotting ease-in-out 0.5s;\n }\n .range-piece__aim {\n width: 100%;\n height: 100%;\n opacity: 1;\n position: absolute;\n background: url(${rangePieceIntersectImg}) center / contain no-repeat;\n }\n @keyframes dotting {\n 0% {\n opacity: 0.4;\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n transform: scale(0.8);\n }\n 100% {\n opacity: 0.4;\n transform: scale(1);\n }\n }\n @keyframes pieceContainer {\n from {\n top: 49%;\n }\n to {\n top: 39%;\n }\n }\n </style>\n <div class=\"range-piece__container\">\n <div class='range-piece__content'></div>\n <div class=\"range-piece__aim\"></div>\n </div>\n`\n","import * as THREE from 'three/webgpu'\nimport { POINT_HELPER_TEXTURE_URL } from '../../Assets'\nimport type { Intersection } from '../../../../typings/typings'\nimport type { PointHelperAbstract } from './typing'\nimport { CSS3DObjectPlus } from '../../../../CSS3DRenderPlugin/utils/three/CSS3DObject'\nimport { rangePieceImg } from './html'\nimport { initialCSS3DRender } from '../../../five/initialCSS3DRender'\nimport type { Five } from '@realsee/five-webgpu'\n\n\nexport interface MouseGroupParameter {\n isMobile?: boolean\n useNormalVector?: boolean // 是否展示法向量\n ballColor?: number // 法向量小球色值\n}\n\nfunction createPlaneMesh() {\n // TODO: 改成参数传入\n // 底部纹理贴图面片\n const planGeometry = new THREE.PlaneGeometry(0.4, 0.4)\n const planTextureUrl = POINT_HELPER_TEXTURE_URL\n const planTexture = new THREE.TextureLoader().load(planTextureUrl)\n planTexture.colorSpace = THREE.SRGBColorSpace\n planTexture.minFilter = THREE.LinearFilter\n const planMaterial = new THREE.MeshBasicMaterial({\n map: planTexture,\n transparent: true,\n depthTest: false,\n })\n const planMesh = new THREE.Mesh(planGeometry, planMaterial)\n return planMesh\n}\n\nfunction createLineMesh() {\n // 法向量垂直管\n const zPath = new THREE.CurvePath<THREE.Vector3>()\n zPath.add(new THREE.LineCurve3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, 0.1)))\n const zGeometry = new THREE.TubeGeometry(zPath, 8, 0.003)\n const colors = new Float32Array(zGeometry.getAttribute('position').count * 4)\n const uv = zGeometry.getAttribute('uv')\n for (let i = 0; i < uv.count; i++) colors.set([1, 1, 1, 1 - uv.getX(i)], i * 4)\n zGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 4))\n const zMaterial = new THREE.MeshBasicMaterial({\n vertexColors: true,\n depthTest: false,\n transparent: true,\n })\n const zMesh = new THREE.Mesh(zGeometry, zMaterial)\n return zMesh\n}\n\nfunction createBallMesh() {\n // 法向量圆球\n const ballGeometry = new THREE.SphereGeometry(0.01, 20, 20)\n const ballMaterial = new THREE.MeshBasicMaterial({\n color: 0x9ded6b,\n depthTest: false,\n transparent: true,\n side: THREE.DoubleSide,\n })\n const ballMesh = new THREE.Mesh(ballGeometry, ballMaterial)\n ballMesh.position.set(0, 0, 0.1)\n return ballMesh\n}\n\nfunction createBorderMesh() {\n const radius = 0.2\n const borderMesh = new CSS3DObjectPlus({\n pointerEvents: 'none',\n cornerPoints: [\n new THREE.Vector3(-radius, radius, 0),\n new THREE.Vector3(-radius, -radius, 0),\n new THREE.Vector3(radius, -radius, 0),\n new THREE.Vector3(radius, radius, 0),\n ],\n })\n\n const contentElement = document.createElement('div')\n contentElement.style.width = '100%'\n contentElement.style.height = '100%'\n contentElement.style.backgroundImage = `url(${rangePieceImg})`\n contentElement.style.backgroundSize = '100%'\n contentElement.style.backgroundRepeat = 'no-repeat'\n\n borderMesh.container.appendChild(contentElement)\n\n return borderMesh\n}\n\ntype PlanMesh = ReturnType<typeof createPlaneMesh>\ntype LineMesh = ReturnType<typeof createLineMesh>\ntype BallMesh = ReturnType<typeof createBallMesh>\ntype BorderMesh = ReturnType<typeof createBorderMesh>\n\nexport class PointHelper extends THREE.Object3D implements PointHelperAbstract {\n public planeMesh: PlanMesh\n public lineMesh: LineMesh\n public ballMesh: BallMesh\n public borderMesh: BorderMesh\n private five: Five\n\n public constructor(five: Five) {\n super()\n this.planeMesh = createPlaneMesh()\n this.lineMesh = createLineMesh()\n this.ballMesh = createBallMesh()\n this.borderMesh = createBorderMesh()\n\n this.addEventListener('added', () => {\n this.add(this.planeMesh, this.lineMesh, this.ballMesh, this.borderMesh)\n })\n\n this.addEventListener('removed', () => {\n this.remove(this.planeMesh, this.lineMesh, this.ballMesh, this.borderMesh)\n })\n\n initialCSS3DRender(five)\n\n this.five = five\n }\n\n public updateWithIntersect(intersect: Intersection) {\n const lookAtPosition = intersect?.face?.normal\n ? new THREE.Vector3().addVectors(intersect.point, intersect.face.normal)\n : this.five.camera.position\n this.position.copy(intersect.point)\n this.lookAt(lookAtPosition)\n }\n\n public show() {\n this.visible = true\n if (!this.borderMesh.parent) {\n this.add(this.borderMesh)\n }\n }\n\n public hide() {\n this.visible = false\n this.remove(this.borderMesh)\n }\n\n public dispose() {\n this.planeMesh.material.map?.dispose()\n for (const mesh of [this.planeMesh, this.lineMesh, this.ballMesh]) {\n mesh.geometry.dispose(); mesh.material.dispose()\n }\n this.borderMesh.dispose()\n this.removeFromParent()\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edgeSnap-8fdFCcXB.js","names":["Magnifier","CURSOR_NOT_ALLOW_URL","getRaycasterByNdcPosition","createIntersectionFace","PointHelper2","THREERaycaster","rayOnLine","THREE","_lineDirection","_rayToLineStart","_snapPoint","_screenPoint","DYNAMIC_ADHERE_STICKY_BONUS","DYNAMIC_ADHERE_LOCK_RADIUS_SCALE","DYNAMIC_ADHERE_DEPTH_WEIGHT","getClosestPointParameterOnRay","params","line","lineLengthSq","rayOrigin","b","rayDirection","d","e","denominator","t","clampToLine","MeasurePointSelector","PointSelector","position","intersect","targetIntersect","mouseNdcPosition","size","dynamicAdhereLines","adherePlane","distance","newPoint","adhereLine","closestPoint","projectPoint","ndcPosition","positionOffset","dynamicResult","_point","point","pointIsVisible","raycaster","cameraToPointDistance","lines","cursorX","cursorY","candidates","evaluate","depthDistance","screenDistance","depthScale","isSticky","stickyLine","stickyCandidate","candidate","best","bestScore","score","snapPoint","OVERLAY_STYLE","WORLD_AXES","AXIS_COLORS","projectToCanvas","ndc","worldPoint","viewport","screenX","screenY","getWorldNormal","face","intersection","normal","snapNormal","n","nearestAxisIndex","nearestDot","dot","axis","index","snapThreshold","sign","buildPlaneFrame","snapped","upComponent","yAxis","getProbeLength","camera","projectDirection","origin","scene","tip","direction","getWorldLengthForCanvasLength","projected","projectedLength","length","canvasLength","iteration","actual","drawPlaneFrame","halfSideLength","halfX","frame","halfY","corners","corner","context","drawAxes","radius","axisLength","tipDotRadius","canvasDirection","worldLength","drawLine","from","to","value","color","drawFullAxis","opposite","positiveLength","negativeLength","negative","positive","withTipDot","drawMeasureOverlay","MeasureMagnifier","five","options","enabled","info","centerX","centerY","error","TUBE_RADIUS","createTube","path","geometry","material","mesh","MeasurePointHelperV2","frameHalfSide","xAxis","edge","DEFAULT_EDGE_SNAP_OPTIONS","resolveEdgeSnapOptions","_closestPoint","distanceSqToSegment","collectNearbyEdges","model","edges","radiusSq","item","a","EdgeSnapCache","stepSq"],"sources":["../../src/MeasurePluginV2/PointSelector.ts","../../src/MeasurePluginV2/PointOverlay.ts","../../src/MeasurePluginV2/Magnifier.ts","../../src/MeasurePluginV2/PointHelper.ts","../../src/MeasurePluginV2/edgeSnap.ts"],"sourcesContent":["import { CURSOR_NOT_ALLOW_URL } from '../shared-utils/three/PointSelector/utils/contents'\nimport * as THREE from 'three/webgpu'\nimport { PointSelector, type PointIntersection } from '../shared-utils/three/PointSelector'\nimport { getRaycasterByNdcPosition } from '../shared-utils/five/getRaycasterByNdcPosition'\nimport { createIntersectionFace } from '../shared-utils/three/createIntersectionFace'\nimport { rayOnLine } from '../Sculpt/utils/three/rayOnLine'\nimport { THREERaycaster } from '../shared-utils/three/core/Raycaster'\n\nconst _lineDirection = new THREE.Vector3()\nconst _rayToLineStart = new THREE.Vector3()\nconst _snapPoint = new THREE.Vector3()\nconst _screenPoint = new THREE.Vector3()\n\n\n/**\n * 已经吸住的边在评分时额外减去的像素值。\n * 新边必须比它好出这个「死区」,才允许切换,避免 1px 级鼠标抖动时在相邻边之间来回跳。\n */\nconst DYNAMIC_ADHERE_STICKY_BONUS = 4\n\n/**\n * 「锁定」半径(相对进入半径的比例)。\n * 光标离已吸住的边这么近时不再重新评估其它边;两条边在屏幕上重叠时,\n * 若允许重新评分,光标 1px 的移动就足以让两者互换,表现为落点来回跳。\n */\nconst DYNAMIC_ADHERE_LOCK_RADIUS_SCALE = 0.6\n\n/**\n * 动态吸附选择时,深度(米)折算成像素的权重。\n * 屏幕上一样近时优先吸离落点更近的边,避免吸到后面那层被遮挡的轮廓。\n */\nconst DYNAMIC_ADHERE_DEPTH_WEIGHT = 60\n\n/**\n * @description 求离射线(origin + s * direction, s >= 0)最近的线段参数 t。\n *\n * 不能像 `rayOnLine` 那样在屏幕上取仿射比例再回推 3D 点:透视投影沿线段不是线性的,\n * 线段两端深度不同时,屏幕上的等分点并不对应 3D 线段的等分点,落点会偏离光标。\n * 这里直接解射线与直线的最小距离,得到的就是「投影后离光标最近」的那个 3D 点。\n */\nfunction getClosestPointParameterOnRay(params: {\n rayOrigin: THREE.Vector3\n rayDirection: THREE.Vector3\n line: THREE.Line3\n clampToLine: boolean\n}): number {\n const { rayOrigin, rayDirection, line, clampToLine } = params\n _lineDirection.subVectors(line.end, line.start)\n const lineLengthSq = _lineDirection.lengthSq()\n if (lineLengthSq < 1e-12) return 0\n\n _rayToLineStart.subVectors(rayOrigin, line.start)\n const b = rayDirection.dot(_lineDirection)\n const d = rayDirection.dot(_rayToLineStart)\n const e = _lineDirection.dot(_rayToLineStart)\n const denominator = lineLengthSq - b * b\n\n let t: number\n if (denominator < 1e-9) {\n // 视线与线段几乎平行:参数对位置不敏感,退化为离射线更近的那个端点\n const startDistance = new THREE.Vector3().subVectors(line.start, rayOrigin).cross(rayDirection).length()\n const endDistance = new THREE.Vector3().subVectors(line.end, rayOrigin).cross(rayDirection).length()\n t = startDistance <= endDistance ? 0 : 1\n } else {\n t = (e - b * d) / denominator\n }\n\n return clampToLine ? Math.min(1, Math.max(0, t)) : t\n}\n\n/** V2 snapping only. The original PointSelector keeps its existing algorithm. */\nexport class MeasurePointSelector extends PointSelector {\n /**\n * @description 动态吸附线提供器:每次选点更新、吸附计算前调用,返回本次参与吸附的线段,不会写回 adhereLine。\n * 适合按光标位置实时从模型提取的边线。返回的线按有限线段处理(clampToLine),\n * 与 adhereLine 里的无限轴线(如量尺的 XYZ 轴)区分开。\n */\n public adhereLineProvider: ((params: { intersection: PointIntersection; pointSelector: PointSelector }) => THREE.Line3[]) | null = null\n\n /**\n * @description 动态吸附线的屏幕吸附半径(像素)\n * 动态线按「光标到线段投影的屏幕距离」取最近的一条,而不是按 3D 距离排序后让远边覆盖近边\n */\n public dynamicAdhereScreenRadius = 10\n\n /**\n * @description 已吸附后保持吸附的屏幕半径(像素),略大于进入半径,避免在阈值边界来回跳动\n */\n public dynamicAdhereKeepScreenRadius = 14\n\n /**\n * @description 动态吸附线允许的最大 3D 距离(米),用于排除画面深处或明显不在落点附近的边\n */\n public dynamicAdhereMaxDistance = 0.45\n\n /**\n * 上一次吸住的动态线。候选线集合会随查询球心移动而变化,\n * 把吸住的边单独留住,光标在保持半径内时优先继续用它,避免在相邻边之间来回跳。\n */\n private dynamicAdhereLine: THREE.Line3 | null = null\n\n protected override get mouseNdcPosition() {\n return this.mode === 'fixed' ? { x: 0.5, y: 0.5 } : super.mouseNdcPosition\n }\n\n public refresh() {\n const position = this.mouseNdcPosition\n if (this.enabled && position) this.updateByNdcPosition(position)\n }\n\n private readonly onFocusLost = () => {\n this.adhereEnabled = true\n this.clearDynamicAdhereLine()\n }\n\n public override enable() {\n super.enable()\n window.addEventListener('blur', this.onFocusLost)\n }\n\n public override disable() {\n window.removeEventListener('blur', this.onFocusLost)\n this.clearDynamicAdhereLine()\n super.disable()\n this.adhereEnabled = true\n }\n\n public clearDynamicAdhereLine() {\n this.dynamicAdhereLine = null\n }\n\n protected override updatePointSelectorHelperIntersect = (intersect?: PointIntersection | null) => {\n if (!intersect) {\n this.dynamicAdhereLine = null\n this.pointSelectorHelper.hide()\n this.pointSelectorHelper.position = intersect\n this.emit('intersectionUpdate', intersect)\n this.five.getElement().style.cursor = CURSOR_NOT_ALLOW_URL\n return\n }\n\n this.onEnter()\n if (!this.cursorError) this.five.getElement().style.cursor = ''\n\n // 有吸附点的话,就吸附到最近的点.adherePoints\n const targetIntersect = { ...intersect }\n\n if (this.adhereEnabled && this.mouseNdcPosition && this.five.renderer && typeof this.adhereRadius === 'number') {\n const mouseNdcPosition = {\n x: this.mouseNdcPosition.x,\n y: 1 - this.mouseNdcPosition.y,\n }\n const size = this.five.renderer!.getSize(new THREE.Vector2())\n\n // 按当前落点实时计算的吸附线(例如模型边线)。不能写回 adhereLine,\n // 否则每次 mousemove 都会把上一次的线累积进去。\n const dynamicAdhereLines = this.adhereLineProvider?.({ intersection: intersect, pointSelector: this }) ?? []\n // V2 同时处理静态目标、动态候选以及上次锁定的边。\n const hasAdhereTarget = typeof this.adherePoints === 'function' || this.adherePlane.length > 0 || this.adhereLine.length > 0 || dynamicAdhereLines.length > 0 || this.dynamicAdhereLine !== null\n\n if (hasAdhereTarget) {\n // // ========== 吸附面 ==========\n for (const adherePlane of this.adherePlane) {\n const distance = adherePlane.distanceToPoint(intersect.point)\n let newPoint = adherePlane.projectPoint(intersect.point, new THREE.Vector3())\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n if (distance < this.adhereRadius) {\n targetIntersect.point = newPoint.clone()\n targetIntersect.adherePoint = newPoint.clone()\n if (!this.plane) {\n targetIntersect.face = createIntersectionFace(adherePlane.normal.clone())\n }\n targetIntersect.isAdsorbed = true\n }\n }\n }\n\n // ========== 吸附线 ==========\n for (const adhereLine of this.adhereLine) {\n let newPoint = adhereLine.closestPointToPoint(intersect.point, false, new THREE.Vector3())\n if (newPoint.distanceTo(intersect.point) < this.adhereRadius) {\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n targetIntersect.point = newPoint.clone()\n targetIntersect.adhereLine = adhereLine.clone()\n targetIntersect.isAdsorbed = true\n }\n } else {\n const closestPoint = rayOnLine({\n raycaster: new THREERaycaster(this.five.camera.position, intersect.point.clone().sub(this.five.camera.position).normalize()),\n line: adhereLine,\n clampToLine: false,\n })\n const projectPoint = closestPoint.clone().project(this.five.camera)\n if (projectPoint.z <= 1) {\n const ndcPosition = {\n x: (projectPoint.x + 1) / 2,\n y: (1 - projectPoint.y) / 2,\n }\n\n const positionOffset = {\n x: Math.abs(ndcPosition.x - mouseNdcPosition.x) * size.width,\n y: Math.abs(ndcPosition.y - mouseNdcPosition.y) * size.height,\n }\n\n let newPoint = closestPoint.clone()\n if (positionOffset.x < 10 && positionOffset.y < 10) {\n if (!this.plane || this.plane.distanceToPoint(newPoint) < 0.01) {\n newPoint = this.plane?.projectPoint(newPoint, new THREE.Vector3()) ?? newPoint\n targetIntersect.point = newPoint.clone()\n targetIntersect.adhereLine = adhereLine.clone()\n targetIntersect.isAdsorbed = true\n }\n }\n }\n }\n }\n\n // ========== 动态吸附线(模型边) ==========\n // 取屏幕上离光标最近的一条,并吸附到线段上离光标最近的点。\n // 不能沿用「后匹配者优先」:候选边很多时,最后一条匹配的往往是远处的边,会造成落点跳动和不精确。\n const dynamicResult = this.getBestDynamicAdhereResult({\n lines: dynamicAdhereLines,\n point: intersect.point,\n mouseNdcPosition,\n size,\n })\n if (dynamicResult) {\n targetIntersect.point = dynamicResult.point\n targetIntersect.adhereLine = dynamicResult.line.clone()\n targetIntersect.isAdsorbed = true\n }\n\n // ========== 吸附点 ==========\n for (const _point of this.adherePoints?.({ intersection: intersect, pointSelectorInstance: this }) ?? []) {\n const point = _point\n point.IsAlwaysVisible = _point.IsAlwaysVisible\n\n if (this.plane && this.plane.distanceToPoint(point) > 0.01) continue\n\n const distance = point.distanceTo(intersect.point)\n if (distance < this.adhereRadius) {\n // 1. 距离吸附判断\n targetIntersect.point = this.plane?.projectPoint(point, new THREE.Vector3()) ?? point.clone()\n if (!this.plane && _point.normal) targetIntersect.face = createIntersectionFace(_point.normal)\n targetIntersect.isAdsorbed = true\n\n break\n } else {\n // 2. 屏幕位置吸附判断\n const projectPoint = point.clone().project(this.five.camera)\n if (projectPoint.z > 1) continue // 屏幕外的点不吸附\n const size = this.five.renderer!.getSize(new THREE.Vector2())\n\n const ndcPosition = {\n x: (projectPoint.x + 1) / 2,\n y: (1 - projectPoint.y) / 2,\n }\n\n const positionOffset = {\n x: Math.abs(ndcPosition.x - mouseNdcPosition.x) * size.width,\n y: Math.abs(ndcPosition.y - mouseNdcPosition.y) * size.height,\n }\n\n if (positionOffset.x < 10 && positionOffset.y < 10) {\n // 2.1 满足屏幕位置吸附条件,还需要判断点是否可见\n let pointIsVisible = false\n if (point.IsAlwaysVisible) {\n pointIsVisible = true\n } else {\n // 碰撞检测\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(ndcPosition.x, ndcPosition.y), this.five.camera)\n const intersect = this.five.model.intersectRaycaster(raycaster)[0]\n const distanceError = 0.1\n const cameraToPointDistance = this.five.camera.position.distanceTo(point)\n if (intersect && intersect.distance < cameraToPointDistance + distanceError) {\n pointIsVisible = true\n }\n }\n\n if (pointIsVisible) {\n targetIntersect.point = point.clone()\n if (!this.plane && _point.normal) {\n targetIntersect.face = createIntersectionFace(_point.normal)\n }\n targetIntersect.isAdsorbed = true\n break\n }\n }\n }\n }\n }\n } else {\n this.dynamicAdhereLine = null\n }\n this.pointSelectorHelper.updateWithIntersect(targetIntersect, { emitEvent: false }) // 关掉pointSelectorHelper的事件,自己手动触发,否则会触发两次\n this.emit('intersectionUpdate', targetIntersect)\n }\n\n /**\n * @description 在动态吸附线(模型边)中选出屏幕上离光标最近的一条。\n *\n * 三个要点:\n * 1. 用射线与线段的最近点求落点,避免透视投影下屏幕比例回推 3D 点造成的偏差;\n * 2. 光标贴着已吸住的边时直接锁定,不让相邻边参与评分,消除来回跳;\n * 3. 需要换边时按「屏幕距离 + 深度惩罚」择优,避免吸到屏幕上重叠、但实际更远的边。\n */\n private getBestDynamicAdhereResult(params: {\n lines: THREE.Line3[]\n point: THREE.Vector3\n mouseNdcPosition: { x: number; y: number }\n size: THREE.Vector2\n }): { point: THREE.Vector3; line: THREE.Line3 } | null {\n const { lines, point, mouseNdcPosition, size } = params\n if (lines.length === 0 && !this.dynamicAdhereLine) {\n this.dynamicAdhereLine = null\n return null\n }\n\n const raycaster = getRaycasterByNdcPosition(this.five, { x: mouseNdcPosition.x, y: 1 - mouseNdcPosition.y })\n const rayOrigin = raycaster.ray.origin\n const rayDirection = raycaster.ray.direction\n const cursorX = mouseNdcPosition.x * size.width\n const cursorY = mouseNdcPosition.y * size.height\n\n type Candidate = {\n line: THREE.Line3\n t: number\n screenDistance: number\n depthDistance: number\n isSticky: boolean\n }\n const candidates: Candidate[] = []\n\n const evaluate = (line: THREE.Line3, isSticky: boolean): Candidate | null => {\n const t = getClosestPointParameterOnRay({ rayOrigin, rayDirection, line, clampToLine: true })\n _snapPoint.lerpVectors(line.start, line.end, t)\n\n const depthDistance = _snapPoint.distanceTo(point)\n if (depthDistance > this.dynamicAdhereMaxDistance) return null\n if (this.plane && Math.abs(this.plane.distanceToPoint(_snapPoint)) > 0.01) return null\n\n _screenPoint.copy(_snapPoint).project(this.five.camera)\n // 点在相机后方时投影坐标不可靠,跳过\n if (_screenPoint.z > 1) return null\n\n const screenDistance = Math.hypot(\n ((_screenPoint.x + 1) / 2) * size.width - cursorX,\n ((1 - _screenPoint.y) / 2) * size.height - cursorY,\n )\n // 越深的边要求光标对得越准,避免远处轮廓在 10px 外把落点拽走\n const depthRatio = this.dynamicAdhereMaxDistance > 0 ? Math.min(1, depthDistance / this.dynamicAdhereMaxDistance) : 0\n const depthScale = 1 - 0.6 * depthRatio\n const screenRadius = (isSticky ? this.dynamicAdhereKeepScreenRadius : this.dynamicAdhereScreenRadius) * depthScale\n if (screenDistance > screenRadius) return null\n\n return { line, t, screenDistance, depthDistance, isSticky }\n }\n\n // 上一帧吸住的边可能已经不在本次 provider 返回的集合里(查询球心移动会换一批边),\n // 单独保留它,只要光标还在保持半径内就继续作为候选。\n const stickyLine = this.dynamicAdhereLine\n if (stickyLine) {\n const stickyCandidate = evaluate(stickyLine, true)\n if (stickyCandidate) candidates.push(stickyCandidate)\n }\n for (const line of lines) {\n const candidate = evaluate(line, false)\n if (candidate) candidates.push(candidate)\n }\n\n if (candidates.length === 0) {\n this.dynamicAdhereLine = null\n return null\n }\n\n // 1. 光标仍贴着已吸住的边时直接锁定它,不再和别的边比较。\n // 两条边在屏幕上重叠时,重新评分会让它们随 1px 光标抖动来回互换,落点就会跳。\n let best: Candidate | null = null\n const stickyCandidate = candidates.find((candidate) => candidate.isSticky)\n if (stickyCandidate && stickyCandidate.screenDistance <= this.dynamicAdhereScreenRadius * DYNAMIC_ADHERE_LOCK_RADIUS_SCALE) {\n best = stickyCandidate\n }\n\n // 2. 否则按「屏幕距离 + 深度惩罚 - 已吸住边的奖励」择优:\n // 深度项让更远/更可能被遮挡的边需要明显更靠近光标才可能胜出,\n // 奖励项让已吸住的边只要不是明显更差就继续用。\n if (!best) {\n let bestScore = Infinity\n for (const candidate of candidates) {\n const score =\n candidate.screenDistance +\n candidate.depthDistance * DYNAMIC_ADHERE_DEPTH_WEIGHT -\n (candidate.isSticky ? DYNAMIC_ADHERE_STICKY_BONUS : 0)\n if (score < bestScore) {\n bestScore = score\n best = candidate\n }\n }\n }\n\n if (!best) {\n this.dynamicAdhereLine = null\n return null\n }\n\n this.dynamicAdhereLine = best.line.clone()\n const snapPoint = new THREE.Vector3().lerpVectors(best.line.start, best.line.end, best.t)\n return {\n line: best.line,\n point: this.plane?.projectPoint(snapPoint, new THREE.Vector3()) ?? snapPoint,\n }\n }\n\n}\n","import * as THREE from 'three/webgpu'\nimport type { PointIntersection } from '../shared-utils'\n\n/**\n * 放大镜内的叠加绘制:坐标轴(PRD M1)+ 落点平面框(PRD M2)\n *\n * 为什么画在 2D canvas 上而不是往场景里加 THREE 物体:\n * 放大镜并不是「再渲染一遍场景」,而是用 five.getPixels() 读一小块像素,翻转后 putImageData 到 2D canvas 上。\n * 所以场景里加什么物体都不会出现在放大镜里,只有 putImageData 之后在 2D context 上画的才会出现。\n */\n\n/** PRD 五、视觉与设计规范 */\nexport const OVERLAY_STYLE = {\n /** M1-2 X 轴颜色 */\n axisXColor: '#EC4A4E',\n /** M1-2 Y 轴颜色 */\n axisYColor: '#1677FF',\n /** M1-2 Z 轴颜色 */\n axisZColor: '#065C08',\n /** M1-5 线条宽度 */\n axisLineWidth: 1.5,\n /** 轴线不透明度 */\n axisOpacity: 0.9,\n /** M1-4 轴线长度 = 放大镜半径 × 0.9 */\n axisLengthRadiusScale: 0.9,\n /** Z 轴端点(朝外的一端)绿色圆点半径 = 放大镜半径 × 该系数 */\n axisTipDotRadiusScale: 0.03,\n /** M2 平面框边框颜色 */\n planeBorderColor: '#FF4D4F',\n /** M2-3 边框宽度 */\n planeBorderWidth: 1.5,\n /** M2-3 边框不透明度 */\n planeBorderOpacity: 0.9,\n /** M2-2 轴对齐面框边长 = 放大镜半径 × 1.2 */\n planeSideRadiusScale: 1.2,\n /** M2 轴对齐判定:表面法线与最近世界轴的夹角小于该值即视为墙 / 地 / 顶 */\n axisSnapAngle: 15,\n} as const\n\nconst WORLD_AXES = [new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 1)]\n\nconst AXIS_COLORS = [OVERLAY_STYLE.axisXColor, OVERLAY_STYLE.axisYColor, OVERLAY_STYLE.axisZColor]\n\ninterface CanvasPoint {\n x: number\n y: number\n}\n\n/**\n * 放大镜把渲染目标上的一块矩形区域拉伸到了 canvas 上,这里描述这块区域以及映射关系。\n * 字段取值与 Magnifier.render() 内部完全一致,父类改动时需要同步。\n */\nexport interface MagnifierViewport {\n camera: THREE.Camera\n /** 渲染目标尺寸,与 Magnifier.render() 里 getSize() 的结果一致 */\n renderSize: THREE.Vector2\n /** 读取区域左边缘在渲染目标像素坐标系中的横坐标 */\n readLeft: number\n /** 读取区域下边缘的纵坐标(渲染目标像素坐标系 y 轴向上,与 Magnifier.render() 里的同名量一致) */\n readTop: number\n /** 读取区域的高度(渲染目标像素) */\n readPixelsHeight: number\n /** 一个渲染像素在放大镜 canvas 上重复的倍数 */\n pixelRadio: number\n /** 放大镜 canvas 的宽高(设备像素) */\n canvasWidth: number\n canvasHeight: number\n}\n\n/** 世界坐标 → 放大镜 canvas 坐标(左上角为原点,y 轴向下) */\nfunction projectToCanvas(worldPoint: THREE.Vector3, viewport: MagnifierViewport): CanvasPoint {\n const ndc = worldPoint.clone().project(viewport.camera)\n const screenX = ((ndc.x + 1) / 2) * viewport.renderSize.x\n const screenY = ((ndc.y + 1) / 2) * viewport.renderSize.y\n return {\n x: (screenX - viewport.readLeft) * viewport.pixelRadio,\n // 读出来的像素做过 Y 翻转(canvas 与渲染目标 Y 轴相反),所以要从读取区域的底边往回收\n y: (viewport.readTop + viewport.readPixelsHeight - screenY) * viewport.pixelRadio,\n }\n}\n\n/**\n * 求交点的世界坐标系法线。\n * 点云等拿不到 face 的情况返回 null(此时只画坐标轴,不画平面框)。\n *\n * 注意:这里不能再乘模型的法线矩阵。THREE.Mesh.raycast 在生成相交结果时已经把面法线\n * 用 normalMatrix 变换到世界坐标系了;PointSelector 吸附到平面时合成的 Face3 更是直接写入\n * 世界坐标系的平面法线。再乘一次会让法线偏离真实表面法线,红色平面框也就不再贴合选点所在面。\n */\nexport function getWorldNormal(intersection: PointIntersection): THREE.Vector3 | null {\n // three 0.183 已经移除 Face3 类型,这里只依赖运行时存在的 normal 字段\n const face = (intersection as unknown as { face?: { normal?: THREE.Vector3 | null } | null }).face\n if (!face?.normal) return null\n\n const normal = face.normal.clone()\n if (normal.lengthSq() < 1e-12) return null\n return normal.normalize()\n}\n\nexport interface PlaneFrame {\n /** 平面法线,也就是绿色 Z 轴的方向(朝表面外侧) */\n normal: THREE.Vector3\n /** 平面内的水平方向 = 红色 X 轴 */\n xAxis: THREE.Vector3\n /** 平面内最接近竖直的方向 = 蓝色 Y 轴 */\n yAxis: THREE.Vector3\n /** 轴对齐面吸附到的世界轴下标(0=X / 1=Y / 2=Z),斜面为 -1 */\n alignedAxisIndex: number\n}\n\n/** 法线接近世界轴时吸附过去(保留正负号),保证墙 / 地 / 顶上的框是正的 */\nfunction snapNormal(normal: THREE.Vector3) {\n const n = normal.clone().normalize()\n let nearestAxisIndex = 0\n let nearestDot = 0\n WORLD_AXES.forEach((axis, index) => {\n const dot = Math.abs(n.dot(axis))\n if (dot > nearestDot) {\n nearestDot = dot\n nearestAxisIndex = index\n }\n })\n\n const snapThreshold = Math.cos(THREE.MathUtils.degToRad(OVERLAY_STYLE.axisSnapAngle))\n if (nearestDot < snapThreshold) return { normal: n, alignedAxisIndex: -1 }\n\n const axis = WORLD_AXES[nearestAxisIndex]\n const sign = n.dot(axis) >= 0 ? 1 : -1\n return { normal: axis.clone().multiplyScalar(sign), alignedAxisIndex: nearestAxisIndex }\n}\n\n/**\n * 由表面法线构造落点所在平面的坐标系。\n * 绿色 Z 轴 = 法线;蓝色 Y 轴取平面内最接近「世界向上」的方向;红色 X 轴 = 剩下的那条平面内方向。\n * 平面接近水平(地板 / 天花板)时平面内没有竖直方向,退化为用世界 Z 当蓝色轴。\n *\n * 放大镜里的叠加层和场景里的小光标共用这一份坐标系,保证两处看到的红 / 绿 / 蓝完全一致。\n */\nexport function buildPlaneFrame(normal: THREE.Vector3): PlaneFrame {\n const snapped = snapNormal(normal)\n const n = snapped.normal\n\n const upComponent = n.clone().multiplyScalar(n.dot(WORLD_AXES[1]))\n let yAxis = WORLD_AXES[1].clone().sub(upComponent)\n if (yAxis.lengthSq() < 1e-8) {\n yAxis = WORLD_AXES[2].clone().sub(n.clone().multiplyScalar(n.dot(WORLD_AXES[2])))\n }\n yAxis.normalize()\n\n const xAxis = new THREE.Vector3().crossVectors(yAxis, n).normalize()\n return { normal: n, xAxis, yAxis, alignedAxisIndex: snapped.alignedAxisIndex }\n}\n\n/** 探针长度:只用来求投影方向与投影比例,取相机到落点距离的 1% */\nfunction getProbeLength(point: THREE.Vector3, camera: THREE.Camera) {\n return Math.max(1e-4, camera.position.distanceTo(point) * 0.01)\n}\n\n/** 一次绘制过程中反复要用的几个量,打包传参免得函数签名过长 */\ninterface OverlayScene {\n context: CanvasRenderingContext2D\n viewport: MagnifierViewport\n /** 落点(世界坐标) */\n point: THREE.Vector3\n probeLength: number\n}\n\n/** 某世界方向上一段长度投影到 canvas 上的向量 */\nfunction projectDirection(scene: OverlayScene, direction: THREE.Vector3): CanvasPoint {\n const origin = projectToCanvas(scene.point, scene.viewport)\n const tip = projectToCanvas(scene.point.clone().addScaledVector(direction, scene.probeLength), scene.viewport)\n return { x: tip.x - origin.x, y: tip.y - origin.y }\n}\n\n/**\n * 想让某方向从落点出发、在 canvas 上占 canvasLength 像素时,需要多长的世界长度。\n * 透视下投影长度与世界长度不是线性关系(端点越远越被压缩),\n * 所以先用落点处的局部比例估初值,再按实测像素迭代修正两次。\n * 需要反方向的长度时把 direction 取反再调一次,因为两侧的透视压缩不一样。\n */\nfunction getWorldLengthForCanvasLength(scene: OverlayScene, direction: THREE.Vector3, canvasLength: number) {\n const projected = projectDirection(scene, direction)\n const projectedLength = Math.hypot(projected.x, projected.y)\n if (!Number.isFinite(projectedLength) || projectedLength < 1e-6) return 0\n\n const origin = projectToCanvas(scene.point, scene.viewport)\n let length = (canvasLength / projectedLength) * scene.probeLength\n\n for (let iteration = 0; iteration < 2; iteration += 1) {\n const tip = projectToCanvas(scene.point.clone().addScaledVector(direction, length), scene.viewport)\n const actual = Math.hypot(tip.x - origin.x, tip.y - origin.y)\n if (!Number.isFinite(actual) || actual < 1e-6) break\n length *= canvasLength / actual\n }\n\n return length\n}\n\n/** 平面框:以落点为中心的四边形,只描边不填充 */\nfunction drawPlaneFrame(scene: OverlayScene, frame: PlaneFrame) {\n const { context, viewport, point } = scene\n const radius = Math.min(viewport.canvasWidth, viewport.canvasHeight) / 2\n // M2-2:边长 = 半径 × 1.2,框以落点为中心 => 半边长 = 边长 / 2\n const halfSideLength = (radius * OVERLAY_STYLE.planeSideRadiusScale) / 2\n\n const halfX = getWorldLengthForCanvasLength(scene, frame.xAxis, halfSideLength)\n const halfY = getWorldLengthForCanvasLength(scene, frame.yAxis, halfSideLength)\n if (!(halfX > 0) || !(halfY > 0)) return\n\n // 四个角都真实投影一次,这样斜面和强透视下得到的是梯形而不是平行四边形\n const corners = [\n point.clone().addScaledVector(frame.xAxis, halfX).addScaledVector(frame.yAxis, halfY),\n point.clone().addScaledVector(frame.xAxis, -halfX).addScaledVector(frame.yAxis, halfY),\n point.clone().addScaledVector(frame.xAxis, -halfX).addScaledVector(frame.yAxis, -halfY),\n point.clone().addScaledVector(frame.xAxis, halfX).addScaledVector(frame.yAxis, -halfY),\n ].map((corner) => projectToCanvas(corner, viewport))\n\n if (corners.some((corner) => !Number.isFinite(corner.x) || !Number.isFinite(corner.y))) return\n\n context.save()\n context.beginPath()\n corners.forEach((corner, index) => {\n if (index === 0) context.moveTo(corner.x, corner.y)\n else context.lineTo(corner.x, corner.y)\n })\n context.closePath()\n // M2-3 / M2-4:只描边,不填充\n context.strokeStyle = OVERLAY_STYLE.planeBorderColor\n context.globalAlpha = OVERLAY_STYLE.planeBorderOpacity\n context.lineWidth = OVERLAY_STYLE.planeBorderWidth\n context.stroke()\n context.restore()\n}\n\n/**\n * 坐标轴。\n * X(红)/ Y(蓝)是贯穿落点的整条线;Z(绿)= 平面法线,只画朝外的一半,端点带一个绿色圆点,\n * 与 PRD 图示一致。线段在 canvas 上的长度固定为半径 × 0.9(M1-4),超出放大镜圆形的部分由 CSS 裁掉。\n */\nfunction drawAxes(scene: OverlayScene, frame: PlaneFrame | null) {\n const { context, viewport, point } = scene\n const radius = Math.min(viewport.canvasWidth, viewport.canvasHeight) / 2\n const axisLength = radius * OVERLAY_STYLE.axisLengthRadiusScale\n const tipDotRadius = radius * OVERLAY_STYLE.axisTipDotRadiusScale\n\n const origin = projectToCanvas(point, viewport)\n if (!Number.isFinite(origin.x) || !Number.isFinite(origin.y)) return\n\n /** 某方向投影到 canvas 上的单位向量;几乎正对相机时返回 null(方向会乱跳,不画) */\n const canvasDirection = (direction: THREE.Vector3) => {\n const projected = projectDirection(scene, direction)\n const projectedLength = Math.hypot(projected.x, projected.y)\n if (!Number.isFinite(projectedLength) || projectedLength < 1e-3) return null\n return { x: projected.x / projectedLength, y: projected.y / projectedLength }\n }\n\n const worldLength = (direction: THREE.Vector3) => getWorldLengthForCanvasLength(scene, direction, axisLength)\n\n const drawLine = (from: CanvasPoint, to: CanvasPoint, color: string) => {\n // NaN 会让 arc() 直接抛异常,异常从放大镜的 renderFrame 回调里抛出去会打断 five 的渲染循环\n if (![from.x, from.y, to.x, to.y].every((value) => Number.isFinite(value))) return\n context.strokeStyle = color\n context.globalAlpha = OVERLAY_STYLE.axisOpacity\n context.lineWidth = OVERLAY_STYLE.axisLineWidth\n context.beginPath()\n context.moveTo(from.x, from.y)\n context.lineTo(to.x, to.y)\n context.stroke()\n }\n\n /** 贯穿落点的整条轴:两侧分别求解,保证每侧端点都距落点 0.9R */\n const drawFullAxis = (direction: THREE.Vector3, color: string) => {\n if (!canvasDirection(direction)) return\n const opposite = direction.clone().negate()\n const positiveLength = getWorldLengthForCanvasLength(scene, direction, axisLength)\n const negativeLength = getWorldLengthForCanvasLength(scene, opposite, axisLength)\n if (!(positiveLength > 0) || !(negativeLength > 0)) return\n const negative = projectToCanvas(point.clone().addScaledVector(opposite, negativeLength), viewport)\n const positive = projectToCanvas(point.clone().addScaledVector(direction, positiveLength), viewport)\n drawLine(negative, positive, color)\n }\n\n /** 从落点朝外的半条轴;withTipDot 为 true 时在端点补一个实心圆点 */\n const drawHalfAxis = (direction: THREE.Vector3, color: string, withTipDot: boolean) => {\n if (!canvasDirection(direction)) return\n const length = worldLength(direction)\n if (!(length > 0)) return\n const tip = projectToCanvas(point.clone().addScaledVector(direction, length), viewport)\n drawLine(origin, tip, color)\n\n if (!withTipDot) return\n if (!Number.isFinite(tip.x) || !Number.isFinite(tip.y)) return\n context.fillStyle = color\n context.globalAlpha = OVERLAY_STYLE.axisOpacity\n context.beginPath()\n context.arc(tip.x, tip.y, tipDotRadius, 0, Math.PI * 2)\n context.fill()\n }\n\n context.save()\n context.lineCap = 'round'\n\n if (frame) {\n drawFullAxis(frame.xAxis, OVERLAY_STYLE.axisXColor)\n drawFullAxis(frame.yAxis, OVERLAY_STYLE.axisYColor)\n drawHalfAxis(frame.normal, OVERLAY_STYLE.axisZColor, true)\n } else {\n // 点云等拿不到法线:三条世界轴都画整条\n WORLD_AXES.forEach((axis, index) => drawFullAxis(axis, AXIS_COLORS[index]))\n }\n\n context.restore()\n}\n\n/**\n * 绘制落点叠加层。\n * 调用时机:Magnifier.render() 里 putImageData 之后。\n */\nexport function drawMeasureOverlay(context: CanvasRenderingContext2D, viewport: MagnifierViewport, intersection: PointIntersection) {\n const point = intersection.point\n if (!point) return\n if (!Number.isFinite(point.x) || !Number.isFinite(point.y) || !Number.isFinite(point.z)) return\n\n const scene: OverlayScene = { context, viewport, point, probeLength: getProbeLength(point, viewport.camera) }\n const normal = getWorldNormal(intersection)\n const frame = normal ? buildPlaneFrame(normal) : null\n\n if (frame) drawPlaneFrame(scene, frame)\n drawAxes(scene, frame)\n}\n","import type { Five } from '@realsee/five-webgpu'\nimport type { PointIntersection } from '../shared-utils'\nimport { Magnifier, type MagnifierParameter, type MagnifierRenderInfo } from '../shared-utils/three/Magnifier'\nimport { drawMeasureOverlay, type MagnifierViewport } from './PointOverlay'\n\nexport interface MeasureMagnifierOptions extends MagnifierParameter {\n /** 是否绘制坐标轴 / 平面框叠加层,默认 true(关掉后行为与现状 Magnifier 完全一致) */\n overlayEnabled?: boolean\n}\n\n/**\n * 量尺 V2 用的放大镜。\n *\n * 完全复用 Magnifier 的「读像素 + 放大」逻辑,只在像素绘制完成后往同一个 2D canvas 上叠加坐标轴与落点平面框。\n * 这里不重写 render():V1 的 Magnifier 是异步读回像素的,用 afterRender 回调才能保证叠加层和当前这帧像素严格对应。\n */\nexport class MeasureMagnifier extends Magnifier {\n /** 父类把 five 存成了 private,这里自己留一份 */\n private readonly overlayFive: Five\n /** 父类把 context 存成了 private;getContext('2d') 拿到的是同一个实例 */\n private overlayContext: CanvasRenderingContext2D | null = null\n /** 由 PointSelector 的 intersectionUpdate 事件注入 */\n private overlayIntersection: PointIntersection | null = null\n private overlayEnabled: boolean\n\n public constructor(five: Five, options?: MeasureMagnifierOptions) {\n super(five, options ?? {})\n this.overlayFive = five\n this.overlayEnabled = options?.overlayEnabled !== false\n this.afterRender = this.renderOverlay\n }\n\n /** 每次交点更新时调用;传 null 表示当前没有命中任何模型 */\n public setIntersection(intersection: PointIntersection | null) {\n this.overlayIntersection = intersection\n }\n\n /** 开关叠加层,用于灰度 / 排查问题 */\n public setOverlayEnabled(enabled: boolean) {\n this.overlayEnabled = enabled\n }\n\n private renderOverlay = (info: MagnifierRenderInfo) => {\n if (!this.overlayEnabled) return\n if (!this.state.enabled) return\n\n const intersection = this.overlayIntersection\n // 未命中模型(悬空处生成的虚拟点)不画:PRD M2 要求「不绘制平面框和轴线」\n if (!intersection || intersection.isVirtual || !intersection.point) return\n\n const camera = this.overlayFive.camera\n // 像素读回是异步的:只有本次读取的中心仍是当前落点时才画,避免快速移动时叠加层和新像素错开。\n const ndc = intersection.point.clone().project(camera)\n if (![ndc.x, ndc.y].every((value) => Number.isFinite(value))) return\n const screenX = ((ndc.x + 1) / 2) * info.renderSize.x\n const screenY = ((ndc.y + 1) / 2) * info.renderSize.y\n const centerX = info.readLeft + info.readWidth / 2\n const centerY = info.readTop + info.readHeight / 2\n if (Math.abs(screenX - centerX) > 1 || Math.abs(screenY - centerY) > 1) return\n\n const context = this.getOverlayContext()\n if (!context) return\n\n const viewport: MagnifierViewport = {\n camera,\n renderSize: info.renderSize,\n readLeft: info.readLeft,\n readTop: info.readTop,\n readPixelsHeight: info.readHeight,\n pixelRadio: info.pixelRatio,\n canvasWidth: info.canvasWidth,\n canvasHeight: info.canvasHeight,\n }\n\n try {\n drawMeasureOverlay(context, viewport, intersection)\n } catch (error) {\n console.warn('MeasureMagnifier: 叠加层绘制失败', error)\n }\n }\n\n private getOverlayContext() {\n if (!this.overlayContext) this.overlayContext = this.canvas.getContext('2d')\n return this.overlayContext\n }\n}\n","import * as THREE from 'three/webgpu'\nimport type { Five } from '@realsee/five-webgpu'\nimport type { Intersection } from '../typings/typings'\nimport type { PointIntersection } from '../shared-utils'\nimport { PointHelper2 } from '../shared-utils/three/PointSelector/utils/PointHelper2'\nimport { buildPlaneFrame, getWorldNormal, OVERLAY_STYLE } from './PointOverlay'\n\n/** 与 PointHelper2 里那根法线管的半径一致 */\nconst TUBE_RADIUS = 0.003\n\nfunction createTube(from: THREE.Vector3, to: THREE.Vector3, color: string) {\n const path = new THREE.CurvePath<THREE.Vector3>()\n path.add(new THREE.LineCurve3(from, to))\n const geometry = new THREE.TubeGeometry(path, 4, TUBE_RADIUS, 8)\n const material = new THREE.MeshBasicMaterial({\n color,\n depthTest: false,\n transparent: true, // 与 PointHelper2 的管一致,要参与透明排序\n })\n const mesh = new THREE.Mesh(geometry, material)\n // 放大镜是读像素放大的,这些物体不能被画进放大镜里\n ;(mesh as any).disableGetPixel = true\n return mesh\n}\n\n/**\n * 场景里的小光标(选点处那团白圈 + 法线管)的 V2 版本。\n *\n * 完全继承 PointHelper2,只做两件事:\n * 1. 把那根浅蓝色的法线管换成绿色(PRD 里绿色 = Z 轴);\n * 2. 按和放大镜同一套平面坐标系(buildPlaneFrame)补上红色 X、蓝色 Y 和红色截面框。\n *\n * 选点算法(射线、吸附、打点)全都在 PointSelector 里,这里只负责画,不参与任何选点判断。\n */\nexport class MeasurePointHelperV2 extends PointHelper2 {\n /** 只放 V2 新增的红 / 蓝轴和截面框,拿不到法线时整体隐藏 */\n private readonly overlayGroup = new THREE.Group()\n\n public constructor(five: Five) {\n super(five)\n\n // V1 光标自带的蓝色 CSS 小球也是法线端点,和绿色 Z 轴的球重叠;\n // PRD 里端点只保留绿色,这里去掉它。\n this.remove(this.cssBallMesh)\n\n this.paintAxisMesh(this.lineMesh, OVERLAY_STYLE.axisZColor)\n this.paintAxisMesh(this.ballMesh, OVERLAY_STYLE.axisZColor)\n\n // 绿管就是 Z 轴,球在管端,所以球的 z 就是轴长,红 / 蓝轴沿用同一个尺度\n const axisLength = this.ballMesh.position.z || 0.18\n // 红框半边长度按放大镜里的比例换算:框边长 / 轴长 = planeSideRadiusScale / axisLengthRadiusScale\n const frameHalfSide = (axisLength * OVERLAY_STYLE.planeSideRadiusScale) / (2 * OVERLAY_STYLE.axisLengthRadiusScale)\n\n // X(红)/ Y(蓝):贯穿落点的整条线,与放大镜里的画法一致\n const xAxis = createTube(new THREE.Vector3(-axisLength, 0, 0), new THREE.Vector3(axisLength, 0, 0), OVERLAY_STYLE.axisXColor)\n const yAxis = createTube(new THREE.Vector3(0, -axisLength, 0), new THREE.Vector3(0, axisLength, 0), OVERLAY_STYLE.axisYColor)\n xAxis.renderOrder = 3\n yAxis.renderOrder = 3\n this.overlayGroup.add(xAxis, yAxis)\n\n // 截面框:落点所在平面内的正方形,只描边(用四根细管拼出来)\n const corners = [\n new THREE.Vector3(-frameHalfSide, -frameHalfSide, 0),\n new THREE.Vector3(frameHalfSide, -frameHalfSide, 0),\n new THREE.Vector3(frameHalfSide, frameHalfSide, 0),\n new THREE.Vector3(-frameHalfSide, frameHalfSide, 0),\n ]\n corners.forEach((corner, index) => {\n const edge = createTube(corner, corners[(index + 1) % corners.length], OVERLAY_STYLE.planeBorderColor)\n edge.renderOrder = 2\n this.overlayGroup.add(edge)\n })\n\n this.add(this.overlayGroup)\n this.hide()\n }\n\n public override updateWithIntersect(intersect: Intersection) {\n const point = intersect?.point\n if (!point) return\n\n this.position.copy(point)\n\n const normal = (intersect as PointIntersection).isVirtual ? null : getWorldNormal(intersect as unknown as PointIntersection)\n // 点云 / 全景等拿不到法线时不画红蓝轴和平面框,避免沿用上一次的姿态\n this.overlayGroup.visible = normal !== null\n this.lineMesh.visible = normal !== null\n this.ballMesh.visible = normal !== null\n this.planeMesh.visible = normal !== null\n this.ringMesh.visible = normal !== null\n if (!normal) return\n\n const frame = buildPlaneFrame(normal)\n // 直接用平面坐标系当姿态:局部 +X = 红、+Y = 蓝、+Z = 绿(法线)。\n // 这样绿管沿法线朝外、红蓝两条线落在平面内、红框与选点所在面平行。\n this.quaternion.setFromRotationMatrix(new THREE.Matrix4().makeBasis(frame.xAxis, frame.yAxis, frame.normal))\n }\n\n /** 不挂载 cssBallMesh,避免蓝色小球盖住绿色 Z 轴端点 */\n public override show() {\n this.visible = true\n }\n\n public override hide() {\n this.visible = false\n }\n\n private paintAxisMesh(mesh: THREE.Mesh, color: string) {\n const material = mesh.material as THREE.MeshBasicMaterial\n material.color.set(color)\n material.needsUpdate = true\n }\n}\n","import * as THREE from 'three/webgpu'\n\n/**\n * 模型边缘吸附。\n *\n * 选点器本身已经支持吸附到 `THREE.Line3`,five 的 Model 也提供了 `getEdgesBySphere()`,\n * 这里只做两件事:\n * 1. 把光标附近的模型边界线取出来、按离落点的距离排序并限量;\n * 2. 缓存查询结果,避免每次 mousemove 都重走一遍 BVH。\n *\n * 取出来的线交给 `PointSelector.adhereLineProvider`,由选点器完成真正的吸附。\n */\nexport interface EdgeSnapOptions {\n /** 是否启用。V2 默认 true;原测量插件不接入此能力 */\n enabled?: boolean\n /** 查询球半径(米),只在这个范围内找模型边线,默认 0.3 */\n radius?: number\n /** 面片夹角阈值(度),越小越只保留硬边,默认 30 */\n threshold?: number\n /** 单次最多参与吸附的边数,默认 240 */\n maxEdges?: number\n /** 光标移动超过该距离(米)才重新查询,默认 0.12 */\n cacheStep?: number\n}\n\nexport interface ResolvedEdgeSnapOptions extends Required<EdgeSnapOptions> {}\n\nexport const DEFAULT_EDGE_SNAP_OPTIONS: ResolvedEdgeSnapOptions = {\n enabled: true,\n radius: 0.3,\n threshold: 30,\n maxEdges: 240,\n cacheStep: 0.12,\n}\n\nexport function resolveEdgeSnapOptions(options?: boolean | EdgeSnapOptions): ResolvedEdgeSnapOptions {\n // V2 默认开启,支持整体开关和细项配置。\n if (options === undefined) return { ...DEFAULT_EDGE_SNAP_OPTIONS }\n if (options === false) return { ...DEFAULT_EDGE_SNAP_OPTIONS, enabled: false }\n if (options === true) return { ...DEFAULT_EDGE_SNAP_OPTIONS, enabled: true }\n return { ...DEFAULT_EDGE_SNAP_OPTIONS, enabled: true, ...options }\n}\n\n/** 只依赖 getEdgesBySphere,避免把 dnalogel 绑死在某个 five 版本上 */\ntype EdgeSource = {\n getEdgesBySphere?: (sphere: THREE.Sphere, threshold?: number) => THREE.Line3[]\n}\n\nconst _closestPoint = new THREE.Vector3()\n\n/** 点到线段的最短距离平方(clamp 到线段内,模型边不是无限直线) */\nfunction distanceSqToSegment(point: THREE.Vector3, line: THREE.Line3) {\n line.closestPointToPoint(point, true, _closestPoint)\n return _closestPoint.distanceToSquared(point)\n}\n\n/**\n * 取落点附近的模型边界线,按离落点从近到远排序,最多 maxEdges 条。\n * five 的 getEdgesBySphere 返回的是世界坐标线段,可以直接交给 PointSelector。\n *\n * 注意:getEdgesBySphere 是按「三角形与球相交」筛选的,大三角形的边可能落在球外很远,\n * 所以这里再按「点到线段」的真实距离过滤一次,避免把远处的边也当成候选。\n */\nexport function collectNearbyEdges(\n model: EdgeSource | null | undefined,\n point: THREE.Vector3,\n options: ResolvedEdgeSnapOptions,\n): THREE.Line3[] {\n if (!options.enabled) return []\n if (!model || typeof model.getEdgesBySphere !== 'function') return []\n if (![point.x, point.y, point.z].every((value) => Number.isFinite(value))) return []\n\n const edges = model.getEdgesBySphere(new THREE.Sphere(point.clone(), options.radius), THREE.MathUtils.degToRad(options.threshold))\n if (!edges?.length) return []\n\n const radiusSq = options.radius * options.radius\n return edges\n .map((line) => ({ line, distanceSq: distanceSqToSegment(point, line) }))\n .filter((item) => item.distanceSq <= radiusSq)\n .sort((a, b) => a.distanceSq - b.distanceSq)\n .slice(0, options.maxEdges)\n .map((item) => item.line)\n}\n\n/**\n * `getEdgesBySphere` 每次都要遍历可见瓦片、合几何、重建邻接关系,开销不低;\n * 光标在 cacheStep 范围内移动时复用上一次结果,足够贴近“附近有哪些边”的事实。\n */\nexport class EdgeSnapCache {\n private center = new THREE.Vector3()\n private edges: THREE.Line3[] = []\n private valid = false\n\n public query(model: EdgeSource | null | undefined, point: THREE.Vector3, options: ResolvedEdgeSnapOptions): THREE.Line3[] {\n if (!options.enabled) {\n this.clear()\n return []\n }\n\n const stepSq = options.cacheStep * options.cacheStep\n if (this.valid && this.center.distanceToSquared(point) <= stepSq) return this.edges\n\n this.center.copy(point)\n this.edges = collectNearbyEdges(model, point, options)\n this.valid = true\n return this.edges\n }\n\n public clear() {\n this.valid = false\n this.edges = []\n }\n\n /** 最近一次查询到的边数,调试 / 示例页展示用 */\n public get size() {\n return this.edges.length\n }\n}\n"],"mappings":"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"}
|