// @noErrors
import { Five } from '@realsee/five'
const five: Five = {} as any
// - five
import { MeasurePlugin } from '@realsee/dnalogel'
const measurePlugin = MeasurePlugin(five, { unit: 'm' })
// - measurePluginMeasurePlugin
Overview
MeasurePlugin is the new measurement plugin, used to measure distances and areas within a space. Compared with the classic PanoMeasurePlugin, the new measurement plugin offers a more concise API and a better user experience.
Plugin comparison
For a detailed comparison between MeasurePlugin and PanoMeasurePlugin, see the measurement overview.
External Demo
Open the MeasurePlugin demo to try the current measurement workflow outside this documentation page.
Quick Start
Installation
npm install @realsee/dnalogelInitialization
Initialize via the Five SDK plugins option:
// @noErrors
import { MeasurePlugin } from '@realsee/dnalogel'
import { Five } from '@realsee/five'
const five = new Five({
plugins: [
[MeasurePlugin, 'measurePlugin', { unit: 'm' }]
]
})
const measurePlugin = five.plugins.measurePlugin as ReturnType<typeof MeasurePlugin>Or initialize it yourself:
// @noErrors
// @include: main-five
// ---cut---
import { MeasurePlugin } from '@realsee/dnalogel'
const measurePlugin = MeasurePlugin(five, { unit: 'm' })Configuration Options
// @noErrors
import type { MeasurePlugin } from '@realsee/dnalogel'
type MeasurePluginConfig = Parameters<typeof MeasurePlugin>[1]
// ---cut---
const config: MeasurePluginConfig = {
// Measurement unit: 'm' (meters) | 'ft' (feet) | 'mm' (millimeters)
unit: 'm',
// Whether to show length labels, defaults to true
lengthEnable: true,
// Number of decimal places for length measurement, defaults to 2
precision: 2,
}Basic Usage
Start Measuring
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.measure()End Measuring
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.endMeasure()Undo the Last Step
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.undo()Cancel the Current Measurement
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.cancel()Clear All Measurements
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.clear()Dispose the Plugin
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.dispose()Configuration Methods
Switch Unit
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.setUnit('ft') // switch to feet
measurePlugin.setUnit('m') // switch to meters
measurePlugin.setUnit('mm') // switch to millimetersSet Precision
// @noErrors
// @include: main-measurePlugin
// ---cut---
// Set the number of decimal places for length measurement
measurePlugin.setPrecision(3)Show / Hide Length Labels
// @noErrors
// @include: main-measurePlugin
// ---cut---
measurePlugin.setLengthEnable(false) // hide length labels
measurePlugin.setLengthEnable(true) // show length labelsEvent Listening
measureEnd Event
Important
The measureEnd event is the core event of MeasurePlugin and fires every time a measurement ends. By listening to this event, you can obtain the coordinates of the measurement points and perform custom calculations.
Event Parameters
| Parameter | Type | Description |
|---|---|---|
| reason | MeasureEndReason | The reason the measurement ended |
| points | THREE.Vector3[] | Array of measurement point coordinates |
MeasureEndReason Enum
| Value | Description |
|---|---|
'enter' | Completed by pressing the Enter key |
'escape' | Cancelled by pressing the Esc key |
'polygon' | Polygon automatically completed (first and last points coincide) |
'mode_change' | Ended due to a mode change |
'pano_move' | Ended due to panorama movement |
'floor_change' | Ended due to a floor change |
'points_insufficient' | Insufficient points (fewer than 2 points) |
'external' | Ended by an external call to endMeasure() |
Complete Usage Example
The following example shows how to listen to the measureEnd event and compute the measurement results (including line segment lengths and polygon area):
// @noErrors
import { useEffect } from 'react'
import * as THREE from 'three'
import { unsafe__useFiveInstance } from '@realsee/five/react'
import { Util, validatePolygon } from '@realsee/dnalogel'
import type { MeasurePlugin } from '@realsee/dnalogel'
// Get the measurement controller type
type MeasureController = ReturnType<typeof MeasurePlugin>
// Measurement-end reason type
type MeasureEndReason = Parameters<Parameters<MeasureController['on']>[1]>[0]
// Get utility functions from Util
const { getGeometryInfo, generatePolygonGeometry } = Util
const { transformUnit, transformUnitSquare } = Util.sculpt
/**
* Compute the measurement results (line segment lengths and polygon area)
* @param points Array of measurement points
* @param unit Unit 'm' | 'ft' | 'mm'
* @param precision Precision (number of decimal places)
*/
function calculateMeasurement(points: THREE.Vector3[], unit: 'm' | 'ft' | 'mm' = 'm', precision: number = 2) {
if (points.length < 2) {
return { lineLengths: [], totalLength: null, area: null, isPolygon: false }
}
// Compute the length of each line segment
const lineLengths: string[] = []
let totalLengthValue = 0
for (let i = 1; i < points.length; i++) {
const p0 = points[i - 1]
const p1 = points[i]
const distance = p0.distanceTo(p1)
totalLengthValue += distance
const lengthStr = transformUnit(distance, unit, precision)
if (lengthStr) {
lineLengths.push(lengthStr)
}
}
const totalLength = transformUnit(totalLengthValue, unit, precision)
// Check whether it is a polygon (first and last points coincide and there are >= 3 points)
const isPolygon = validatePolygon(points)
let area: string | undefined = undefined
if (isPolygon) {
// Generate the polygon geometry and compute its area
const geometry = generatePolygonGeometry(points)
if (geometry) {
const geometryInfo = getGeometryInfo(geometry)
if (geometryInfo) {
area = transformUnitSquare(geometryInfo.area, unit)
}
}
}
return { lineLengths, totalLength, area, isPolygon }
}
const MeasurePluginUsage = () => {
const five = unsafe__useFiveInstance()
const measurePlugin = five.plugins.measurePlugin as MeasureController
useEffect(() => {
// Listen for the measurement-end event
const handleMeasureEnd = (reason: MeasureEndReason, points: THREE.Vector3[]) => {
console.log('=== Measurement ended ===')
console.log('End reason:', reason)
console.log('Measurement points:', points.map((p) => `(${p.x.toFixed(3)}, ${p.y.toFixed(3)}, ${p.z.toFixed(3)})`))
// Compute the measurement results
const result = calculateMeasurement(points, 'm', 2)
console.log('--- Results ---')
console.log('Is polygon:', result.isPolygon)
console.log('Length of each segment:', result.lineLengths)
console.log('Total length:', result.totalLength)
if (result.area) {
console.log('Area:', result.area)
}
console.log('================')
}
measurePlugin.on('measureEnd', handleMeasureEnd)
return () => {
measurePlugin.off('measureEnd', handleMeasureEnd)
}
}, [measurePlugin])
return (
<div>
<button onClick={() => measurePlugin.measure()}>Start measuring</button>
<button onClick={() => measurePlugin.endMeasure()}>End measuring</button>
<button onClick={() => measurePlugin.clear()}>Clear</button>
<button onClick={() => measurePlugin.undo()}>Undo</button>
<button onClick={() => measurePlugin.dispose()}>Close</button>
</div>
)
}
export default MeasurePluginUsageArea Calculation
Important note
MeasurePlugin does not return the area value directly. To obtain a polygon's area, you need to compute it using the utility functions provided by Util.
Calculation Flow
- Validate the polygon: use
validatePolygon(points)to check whether the point set forms a valid polygon - Generate the geometry: use
generatePolygonGeometry(points)to generate a THREE.BufferGeometry - Compute the area: use
getGeometryInfo(geometry)to obtain the area information - Format the output: use
transformUnitSquare(area, unit)to convert it into a string with a unit
Utility Functions
| Function | Description |
|---|---|
validatePolygon(points) | Validates whether the point set forms a valid polygon (first and last points coincide, not collinear, coplanar) |
generatePolygonGeometry(points) | Generates a BufferGeometry from the polygon vertices |
getGeometryInfo(geometry) | Obtains geometry information, including area and center point |
transformUnit(value, unit, precision) | Converts a length value into a string with a unit |
transformUnitSquare(value, unit) | Converts an area value into a string with a unit |
Code Example
// @noErrors
import * as THREE from 'three'
import { Util, validatePolygon } from '@realsee/dnalogel'
const { getGeometryInfo, generatePolygonGeometry } = Util
const { transformUnitSquare } = Util.sculpt
// Assume these are the measured points
const points: THREE.Vector3[] = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(1, 0, 0),
new THREE.Vector3(1, 0, 1),
new THREE.Vector3(0, 0, 1),
new THREE.Vector3(0, 0, 0), // closing point
]
// 1. Validate that it is a polygon
if (validatePolygon(points)) {
// 2. Generate the geometry
const geometry = generatePolygonGeometry(points)
if (geometry) {
// 3. Obtain the area information
const geometryInfo = getGeometryInfo(geometry)
if (geometryInfo) {
// 4. Format the output
const areaString = transformUnitSquare(geometryInfo.area, 'm')
console.log('Area:', areaString) // outputs: "1.00m²"
}
}
}Keyboard Shortcuts
| Shortcut | Function |
|---|---|
Enter | Complete the current measurement |
Esc | Cancel the current measurement |
Ctrl/Cmd + Z | Undo the last point |
Delete / Backspace | Delete the selected measurement |
Shift + Click | When the right-triangle auxiliary lines are shown, select the perpendicular point instead of the ray intersection point |
Type Exports
// @noErrors
import type { MeasurePlugin, MeasureEndReason, MeasurePluginEventMap, MeasurePluginConfig } from '@realsee/dnalogel'// MeasurePluginConfig
type MeasurePluginConfig = {
unit: 'm' | 'ft' | 'mm'
lengthEnable?: boolean
precision?: number
}
// MeasureEndReason
type MeasureEndReason =
| 'enter'
| 'escape'
| 'polygon'
| 'mode_change'
| 'pano_move'
| 'floor_change'
| 'points_insufficient'
| 'external'
// MeasurePluginEventMap
type MeasurePluginEventMap = {
measureEnd: (reason: MeasureEndReason, points: THREE.Vector3[]) => void
undo: () => void
}