@blueharford/scrypted-spatial-awareness 0.6.4 → 0.6.6
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 +90 -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 +103 -28
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -36602,7 +36602,9 @@ class TopologyDiscoveryEngine {
|
|
|
36602
36602
|
type: landmark.type,
|
|
36603
36603
|
description: landmark.description,
|
|
36604
36604
|
visibleFromCameras: [analysis.cameraId],
|
|
36605
|
-
|
|
36605
|
+
// Include bounding box for positioning (will be used by applyDiscoverySuggestion)
|
|
36606
|
+
boundingBox: landmark.boundingBox,
|
|
36607
|
+
}, // boundingBox is extra metadata not in Landmark interface
|
|
36606
36608
|
};
|
|
36607
36609
|
this.suggestions.set(suggestion.id, suggestion);
|
|
36608
36610
|
}
|
|
@@ -40305,24 +40307,65 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40305
40307
|
const direction = fov.direction || 0;
|
|
40306
40308
|
const range = fov.range || 80;
|
|
40307
40309
|
const fovAngle = fov.angle || 90;
|
|
40308
|
-
// Count existing landmarks from this camera to spread them out
|
|
40309
|
-
const cameraDeviceId = camera.deviceId;
|
|
40310
|
-
const existingFromCamera = (topology.landmarks || []).filter(l => l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
40311
|
-
l.visibleFromCameras?.includes(camera.name)).length;
|
|
40312
40310
|
// Calculate position in front of camera within its FOV
|
|
40313
40311
|
// Convert direction to radians (0 = up/north, 90 = right/east)
|
|
40314
40312
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
40315
40313
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
40316
|
-
//
|
|
40317
|
-
|
|
40318
|
-
const
|
|
40314
|
+
// Use landmark TYPE to determine distance - some things are inherently far away
|
|
40315
|
+
// regardless of where they appear in the camera frame
|
|
40316
|
+
const landmarkType = suggestion.landmark.type;
|
|
40317
|
+
const farTypes = ['neighbor', 'boundary', 'street']; // Always place at edge of FOV
|
|
40318
|
+
const isFarType = farTypes.includes(landmarkType || '');
|
|
40319
|
+
// Use bounding box if available for horizontal positioning
|
|
40320
|
+
// boundingBox format: [x, y, width, height] normalized 0-1
|
|
40321
|
+
const bbox = suggestion.landmark.boundingBox;
|
|
40322
|
+
let angleOffset;
|
|
40323
|
+
let distanceMultiplier;
|
|
40324
|
+
if (bbox && bbox.length >= 2) {
|
|
40325
|
+
// Use bounding box X for horizontal position in FOV
|
|
40326
|
+
const bboxCenterX = bbox[0] + (bbox[2] || 0) / 2; // 0 = left edge, 1 = right edge
|
|
40327
|
+
// Map X position to angle within FOV
|
|
40328
|
+
angleOffset = (bboxCenterX - 0.5) * 2 * halfFov;
|
|
40329
|
+
// For distance: use TYPE first, then bbox Y as hint
|
|
40330
|
+
if (isFarType) {
|
|
40331
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
40332
|
+
// Place at 150-200% of range to indicate they're distant background features
|
|
40333
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
40334
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" placed BEYOND FOV (${(distanceMultiplier * 100).toFixed(0)}% of range)`);
|
|
40335
|
+
}
|
|
40336
|
+
else {
|
|
40337
|
+
// For other types, use bbox Y as a hint (but cap minimum distance)
|
|
40338
|
+
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2;
|
|
40339
|
+
// Map Y to distance: 0 (top) = far, 1 (bottom) = closer (but not too close)
|
|
40340
|
+
distanceMultiplier = Math.max(0.4, 0.9 - (bboxCenterY * 0.5));
|
|
40341
|
+
}
|
|
40342
|
+
this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] for horizontal position`);
|
|
40343
|
+
}
|
|
40344
|
+
else {
|
|
40345
|
+
// No bounding box - use type and spread pattern
|
|
40346
|
+
const cameraDeviceId = camera.deviceId;
|
|
40347
|
+
const existingFromCamera = (topology.landmarks || []).filter(l => l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
40348
|
+
l.visibleFromCameras?.includes(camera.name)).length;
|
|
40349
|
+
// Spread horizontally across FOV
|
|
40350
|
+
angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6;
|
|
40351
|
+
// Distance based on type
|
|
40352
|
+
if (isFarType) {
|
|
40353
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
40354
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
40355
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" (no bbox) placed BEYOND FOV`);
|
|
40356
|
+
}
|
|
40357
|
+
else {
|
|
40358
|
+
distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
|
|
40359
|
+
this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
|
|
40360
|
+
}
|
|
40361
|
+
}
|
|
40319
40362
|
const finalAngle = dirRad + angleOffset;
|
|
40320
40363
|
const distance = range * distanceMultiplier;
|
|
40321
40364
|
position = {
|
|
40322
40365
|
x: camera.floorPlanPosition.x + Math.cos(finalAngle) * distance,
|
|
40323
40366
|
y: camera.floorPlanPosition.y + Math.sin(finalAngle) * distance,
|
|
40324
40367
|
};
|
|
40325
|
-
this.console.log(`[Discovery] Placing landmark "${suggestion.landmark.name}" in ${camera.name}'s FOV: dir=${direction}°, dist=${distance.toFixed(0)}px`);
|
|
40368
|
+
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`);
|
|
40326
40369
|
}
|
|
40327
40370
|
else {
|
|
40328
40371
|
// Position in a grid pattern starting from center
|
|
@@ -40383,29 +40426,54 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40383
40426
|
// Convert direction to radians (0 = up/north, 90 = right/east)
|
|
40384
40427
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
40385
40428
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
40386
|
-
// Count existing zones from this camera to offset new ones
|
|
40387
|
-
const existingFromCamera = (topology.drawnZones || []).filter((z) => z.linkedCameras?.includes(sourceCameras[0])).length;
|
|
40388
|
-
// Create a wedge-shaped zone within the camera's FOV
|
|
40389
|
-
// Offset based on existing zones to avoid overlap
|
|
40390
|
-
const innerRadius = range * 0.3 + existingFromCamera * 20;
|
|
40391
|
-
const outerRadius = range * 0.8 + existingFromCamera * 20;
|
|
40392
|
-
// Use a portion of the FOV for each zone
|
|
40393
|
-
const zoneSpread = halfFov * 0.7; // 70% of half FOV
|
|
40394
40429
|
const camX = camera.floorPlanPosition.x;
|
|
40395
40430
|
const camY = camera.floorPlanPosition.y;
|
|
40396
|
-
//
|
|
40431
|
+
// Use bounding box if available to position zone accurately within FOV
|
|
40432
|
+
const bbox = zone.boundingBox; // [x, y, width, height] normalized 0-1
|
|
40433
|
+
let innerRadius;
|
|
40434
|
+
let outerRadius;
|
|
40435
|
+
let angleStart;
|
|
40436
|
+
let angleEnd;
|
|
40437
|
+
if (bbox && bbox.length >= 4) {
|
|
40438
|
+
// Map bounding box to position within FOV
|
|
40439
|
+
const bboxLeft = bbox[0];
|
|
40440
|
+
const bboxRight = bbox[0] + bbox[2];
|
|
40441
|
+
const bboxTop = bbox[1];
|
|
40442
|
+
const bboxBottom = bbox[1] + bbox[3];
|
|
40443
|
+
// Map X to angle within FOV (0 = left edge, 1 = right edge)
|
|
40444
|
+
angleStart = dirRad + (bboxLeft - 0.5) * 2 * halfFov;
|
|
40445
|
+
angleEnd = dirRad + (bboxRight - 0.5) * 2 * halfFov;
|
|
40446
|
+
// Map Y to distance (0 = far, 1 = close)
|
|
40447
|
+
innerRadius = range * (0.9 - bboxBottom * 0.6);
|
|
40448
|
+
outerRadius = range * (0.9 - bboxTop * 0.6);
|
|
40449
|
+
// Ensure min size
|
|
40450
|
+
if (outerRadius - innerRadius < 20) {
|
|
40451
|
+
outerRadius = innerRadius + 20;
|
|
40452
|
+
}
|
|
40453
|
+
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)}°`);
|
|
40454
|
+
}
|
|
40455
|
+
else {
|
|
40456
|
+
// Fallback: wedge-shaped zone offset by existing count
|
|
40457
|
+
const existingFromCamera = (topology.drawnZones || []).filter((z) => z.linkedCameras?.includes(sourceCameras[0])).length;
|
|
40458
|
+
innerRadius = range * 0.3 + existingFromCamera * 20;
|
|
40459
|
+
outerRadius = range * 0.8 + existingFromCamera * 20;
|
|
40460
|
+
angleStart = dirRad - halfFov * 0.7;
|
|
40461
|
+
angleEnd = dirRad + halfFov * 0.7;
|
|
40462
|
+
this.console.log(`[Discovery] Zone "${zone.name}" using fallback spread (existing: ${existingFromCamera})`);
|
|
40463
|
+
}
|
|
40464
|
+
// Create arc polygon
|
|
40397
40465
|
const steps = 8;
|
|
40398
|
-
// Inner arc (from
|
|
40466
|
+
// Inner arc (from start angle to end angle)
|
|
40399
40467
|
for (let i = 0; i <= steps; i++) {
|
|
40400
|
-
const angle =
|
|
40468
|
+
const angle = angleStart + (angleEnd - angleStart) * i / steps;
|
|
40401
40469
|
polygon.push({
|
|
40402
40470
|
x: camX + Math.cos(angle) * innerRadius,
|
|
40403
40471
|
y: camY + Math.sin(angle) * innerRadius,
|
|
40404
40472
|
});
|
|
40405
40473
|
}
|
|
40406
|
-
// Outer arc (from
|
|
40474
|
+
// Outer arc (from end angle to start angle)
|
|
40407
40475
|
for (let i = steps; i >= 0; i--) {
|
|
40408
|
-
const angle =
|
|
40476
|
+
const angle = angleStart + (angleEnd - angleStart) * i / steps;
|
|
40409
40477
|
polygon.push({
|
|
40410
40478
|
x: camX + Math.cos(angle) * outerRadius,
|
|
40411
40479
|
y: camY + Math.sin(angle) * outerRadius,
|