@blueharford/scrypted-spatial-awareness 0.6.4 → 0.6.5
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/dist/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +71 -22
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/core/topology-discovery.ts +3 -1
- package/src/main.ts +84 -28
package/out/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -659,7 +659,9 @@ export class TopologyDiscoveryEngine {
|
|
|
659
659
|
type: landmark.type,
|
|
660
660
|
description: landmark.description,
|
|
661
661
|
visibleFromCameras: [analysis.cameraId],
|
|
662
|
-
|
|
662
|
+
// Include bounding box for positioning (will be used by applyDiscoverySuggestion)
|
|
663
|
+
boundingBox: landmark.boundingBox,
|
|
664
|
+
} as any, // boundingBox is extra metadata not in Landmark interface
|
|
663
665
|
};
|
|
664
666
|
this.suggestions.set(suggestion.id, suggestion);
|
|
665
667
|
}
|
package/src/main.ts
CHANGED
|
@@ -1861,21 +1861,47 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1861
1861
|
const range = fov.range || 80;
|
|
1862
1862
|
const fovAngle = fov.angle || 90;
|
|
1863
1863
|
|
|
1864
|
-
// Count existing landmarks from this camera to spread them out
|
|
1865
|
-
const cameraDeviceId = camera.deviceId;
|
|
1866
|
-
const existingFromCamera = (topology.landmarks || []).filter(l =>
|
|
1867
|
-
l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
1868
|
-
l.visibleFromCameras?.includes(camera.name)
|
|
1869
|
-
).length;
|
|
1870
|
-
|
|
1871
1864
|
// Calculate position in front of camera within its FOV
|
|
1872
1865
|
// Convert direction to radians (0 = up/north, 90 = right/east)
|
|
1873
1866
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
1874
1867
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
1875
1868
|
|
|
1876
|
-
//
|
|
1877
|
-
|
|
1878
|
-
const
|
|
1869
|
+
// Use bounding box if available to position landmark accurately within FOV
|
|
1870
|
+
// boundingBox format: [x, y, width, height] normalized 0-1
|
|
1871
|
+
const bbox = (suggestion.landmark as any).boundingBox as [number, number, number, number] | undefined;
|
|
1872
|
+
|
|
1873
|
+
let angleOffset: number;
|
|
1874
|
+
let distanceMultiplier: number;
|
|
1875
|
+
|
|
1876
|
+
if (bbox && bbox.length >= 2) {
|
|
1877
|
+
// Use bounding box center to determine position in FOV
|
|
1878
|
+
const bboxCenterX = bbox[0] + (bbox[2] || 0) / 2; // 0 = left edge, 1 = right edge
|
|
1879
|
+
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2; // 0 = top (far), 1 = bottom (close)
|
|
1880
|
+
|
|
1881
|
+
// Map X position to angle within FOV
|
|
1882
|
+
// bboxCenterX 0 → left side of FOV (-halfFov)
|
|
1883
|
+
// bboxCenterX 0.5 → center of FOV (0)
|
|
1884
|
+
// bboxCenterX 1 → right side of FOV (+halfFov)
|
|
1885
|
+
angleOffset = (bboxCenterX - 0.5) * 2 * halfFov;
|
|
1886
|
+
|
|
1887
|
+
// Map Y position to distance from camera
|
|
1888
|
+
// bboxCenterY 0 (top of frame) → far from camera (90% of range)
|
|
1889
|
+
// bboxCenterY 1 (bottom of frame) → close to camera (30% of range)
|
|
1890
|
+
distanceMultiplier = 0.9 - (bboxCenterY * 0.6);
|
|
1891
|
+
|
|
1892
|
+
this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] → center (${bboxCenterX.toFixed(2)}, ${bboxCenterY.toFixed(2)})`);
|
|
1893
|
+
} else {
|
|
1894
|
+
// Fallback: spread landmarks across FOV if no bounding box
|
|
1895
|
+
const cameraDeviceId = camera.deviceId;
|
|
1896
|
+
const existingFromCamera = (topology.landmarks || []).filter(l =>
|
|
1897
|
+
l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
1898
|
+
l.visibleFromCameras?.includes(camera.name)
|
|
1899
|
+
).length;
|
|
1900
|
+
|
|
1901
|
+
angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6;
|
|
1902
|
+
distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
|
|
1903
|
+
this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
|
|
1904
|
+
}
|
|
1879
1905
|
|
|
1880
1906
|
const finalAngle = dirRad + angleOffset;
|
|
1881
1907
|
const distance = range * distanceMultiplier;
|
|
@@ -1885,7 +1911,7 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1885
1911
|
y: camera.floorPlanPosition.y + Math.sin(finalAngle) * distance,
|
|
1886
1912
|
};
|
|
1887
1913
|
|
|
1888
|
-
this.console.log(`[Discovery] Placing landmark "${suggestion.landmark.name}" in ${camera.name}'s FOV: dir=${direction}°, dist=${distance.toFixed(0)}px`);
|
|
1914
|
+
this.console.log(`[Discovery] Placing landmark "${suggestion.landmark.name}" in ${camera.name}'s FOV: dir=${direction}°, angle=${(angleOffset * 180 / Math.PI).toFixed(1)}°, dist=${distance.toFixed(0)}px`);
|
|
1889
1915
|
} else {
|
|
1890
1916
|
// Position in a grid pattern starting from center
|
|
1891
1917
|
const landmarkCount = topology.landmarks?.length || 0;
|
|
@@ -1956,35 +1982,65 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1956
1982
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
1957
1983
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
1958
1984
|
|
|
1959
|
-
|
|
1960
|
-
const
|
|
1961
|
-
z.linkedCameras?.includes(sourceCameras[0])
|
|
1962
|
-
).length;
|
|
1985
|
+
const camX = camera.floorPlanPosition.x;
|
|
1986
|
+
const camY = camera.floorPlanPosition.y;
|
|
1963
1987
|
|
|
1964
|
-
//
|
|
1965
|
-
|
|
1966
|
-
const innerRadius = range * 0.3 + existingFromCamera * 20;
|
|
1967
|
-
const outerRadius = range * 0.8 + existingFromCamera * 20;
|
|
1988
|
+
// Use bounding box if available to position zone accurately within FOV
|
|
1989
|
+
const bbox = zone.boundingBox; // [x, y, width, height] normalized 0-1
|
|
1968
1990
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1991
|
+
let innerRadius: number;
|
|
1992
|
+
let outerRadius: number;
|
|
1993
|
+
let angleStart: number;
|
|
1994
|
+
let angleEnd: number;
|
|
1971
1995
|
|
|
1972
|
-
|
|
1973
|
-
|
|
1996
|
+
if (bbox && bbox.length >= 4) {
|
|
1997
|
+
// Map bounding box to position within FOV
|
|
1998
|
+
const bboxLeft = bbox[0];
|
|
1999
|
+
const bboxRight = bbox[0] + bbox[2];
|
|
2000
|
+
const bboxTop = bbox[1];
|
|
2001
|
+
const bboxBottom = bbox[1] + bbox[3];
|
|
2002
|
+
|
|
2003
|
+
// Map X to angle within FOV (0 = left edge, 1 = right edge)
|
|
2004
|
+
angleStart = dirRad + (bboxLeft - 0.5) * 2 * halfFov;
|
|
2005
|
+
angleEnd = dirRad + (bboxRight - 0.5) * 2 * halfFov;
|
|
2006
|
+
|
|
2007
|
+
// Map Y to distance (0 = far, 1 = close)
|
|
2008
|
+
innerRadius = range * (0.9 - bboxBottom * 0.6);
|
|
2009
|
+
outerRadius = range * (0.9 - bboxTop * 0.6);
|
|
2010
|
+
|
|
2011
|
+
// Ensure min size
|
|
2012
|
+
if (outerRadius - innerRadius < 20) {
|
|
2013
|
+
outerRadius = innerRadius + 20;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
this.console.log(`[Discovery] Zone "${zone.name}" using bbox [${bbox.join(',')}] → angles ${(angleStart * 180 / Math.PI).toFixed(1)}° to ${(angleEnd * 180 / Math.PI).toFixed(1)}°`);
|
|
2017
|
+
} else {
|
|
2018
|
+
// Fallback: wedge-shaped zone offset by existing count
|
|
2019
|
+
const existingFromCamera = (topology.drawnZones || []).filter((z: any) =>
|
|
2020
|
+
z.linkedCameras?.includes(sourceCameras[0])
|
|
2021
|
+
).length;
|
|
2022
|
+
|
|
2023
|
+
innerRadius = range * 0.3 + existingFromCamera * 20;
|
|
2024
|
+
outerRadius = range * 0.8 + existingFromCamera * 20;
|
|
2025
|
+
angleStart = dirRad - halfFov * 0.7;
|
|
2026
|
+
angleEnd = dirRad + halfFov * 0.7;
|
|
2027
|
+
|
|
2028
|
+
this.console.log(`[Discovery] Zone "${zone.name}" using fallback spread (existing: ${existingFromCamera})`);
|
|
2029
|
+
}
|
|
1974
2030
|
|
|
1975
|
-
// Create arc polygon
|
|
2031
|
+
// Create arc polygon
|
|
1976
2032
|
const steps = 8;
|
|
1977
|
-
// Inner arc (from
|
|
2033
|
+
// Inner arc (from start angle to end angle)
|
|
1978
2034
|
for (let i = 0; i <= steps; i++) {
|
|
1979
|
-
const angle =
|
|
2035
|
+
const angle = angleStart + (angleEnd - angleStart) * i / steps;
|
|
1980
2036
|
polygon.push({
|
|
1981
2037
|
x: camX + Math.cos(angle) * innerRadius,
|
|
1982
2038
|
y: camY + Math.sin(angle) * innerRadius,
|
|
1983
2039
|
});
|
|
1984
2040
|
}
|
|
1985
|
-
// Outer arc (from
|
|
2041
|
+
// Outer arc (from end angle to start angle)
|
|
1986
2042
|
for (let i = steps; i >= 0; i--) {
|
|
1987
|
-
const angle =
|
|
2043
|
+
const angle = angleStart + (angleEnd - angleStart) * i / steps;
|
|
1988
2044
|
polygon.push({
|
|
1989
2045
|
x: camX + Math.cos(angle) * outerRadius,
|
|
1990
2046
|
y: camY + Math.sin(angle) * outerRadius,
|