@blueharford/scrypted-spatial-awareness 0.6.0 → 0.6.1

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/plugin.zip CHANGED
Binary file
@@ -40224,20 +40224,34 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
40224
40224
  const topology = this.trackingEngine.getTopology();
40225
40225
  let updated = false;
40226
40226
  if (suggestion.type === 'landmark' && suggestion.landmark) {
40227
- // Calculate a reasonable position for the landmark
40228
- // Use the first visible camera's position as a starting point, or canvas center
40227
+ // Calculate position for the landmark WITHIN the camera's field of view
40229
40228
  let position = suggestion.landmark.position;
40230
40229
  if (!position || (position.x === 0 && position.y === 0)) {
40231
40230
  // Find a camera that can see this landmark
40232
40231
  const visibleCameraId = suggestion.landmark.visibleFromCameras?.[0];
40233
40232
  const camera = visibleCameraId ? topology.cameras.find(c => c.deviceId === visibleCameraId) : null;
40234
40233
  if (camera?.floorPlanPosition) {
40235
- // Position near the camera with some offset
40236
- const offset = (topology.landmarks?.length || 0) * 30;
40234
+ // Get camera's FOV direction and range (cast to any for flexible access)
40235
+ const fov = (camera.fov || { mode: 'simple', angle: 90, direction: 0, range: 80 });
40236
+ const direction = fov.direction || 0;
40237
+ const range = fov.range || 80;
40238
+ const fovAngle = fov.angle || 90;
40239
+ // Count existing landmarks from this camera to spread them out
40240
+ const existingFromCamera = (topology.landmarks || []).filter(l => l.visibleFromCameras?.includes(visibleCameraId)).length;
40241
+ // Calculate position in front of camera within its FOV
40242
+ // Convert direction to radians (0 = up/north, 90 = right/east)
40243
+ const dirRad = (direction - 90) * Math.PI / 180;
40244
+ const halfFov = (fovAngle / 2) * Math.PI / 180;
40245
+ // Spread landmarks across the FOV cone at varying distances
40246
+ const angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6; // -0.6, 0, +0.6 of half FOV
40247
+ const distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3; // 50% or 80% of range
40248
+ const finalAngle = dirRad + angleOffset;
40249
+ const distance = range * distanceMultiplier;
40237
40250
  position = {
40238
- x: camera.floorPlanPosition.x + 50 + (offset % 100),
40239
- y: camera.floorPlanPosition.y + 50 + Math.floor(offset / 100) * 30,
40251
+ x: camera.floorPlanPosition.x + Math.cos(finalAngle) * distance,
40252
+ y: camera.floorPlanPosition.y + Math.sin(finalAngle) * distance,
40240
40253
  };
40254
+ this.console.log(`[Discovery] Placing landmark "${suggestion.landmark.name}" in ${camera.name}'s FOV: dir=${direction}°, dist=${distance.toFixed(0)}px`);
40241
40255
  }
40242
40256
  else {
40243
40257
  // Position in a grid pattern starting from center
@@ -40276,28 +40290,67 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
40276
40290
  const camera = sourceCameras[0]
40277
40291
  ? topology.cameras.find(c => c.deviceId === sourceCameras[0] || c.name === sourceCameras[0])
40278
40292
  : null;
40279
- // Create a default polygon near the camera or at a default location
40280
- let centerX = 300;
40281
- let centerY = 200;
40293
+ // Create zone polygon WITHIN the camera's field of view
40294
+ let polygon = [];
40295
+ const timestamp = Date.now();
40282
40296
  if (camera?.floorPlanPosition) {
40283
- centerX = camera.floorPlanPosition.x;
40284
- centerY = camera.floorPlanPosition.y + 80;
40297
+ // Get camera's FOV direction and range (cast to any for flexible access)
40298
+ const fov = (camera.fov || { mode: 'simple', angle: 90, direction: 0, range: 80 });
40299
+ const direction = fov.direction || 0;
40300
+ const range = fov.range || 80;
40301
+ const fovAngle = fov.angle || 90;
40302
+ // Convert direction to radians (0 = up/north, 90 = right/east)
40303
+ const dirRad = (direction - 90) * Math.PI / 180;
40304
+ const halfFov = (fovAngle / 2) * Math.PI / 180;
40305
+ // Count existing zones from this camera to offset new ones
40306
+ const existingFromCamera = (topology.drawnZones || []).filter((z) => z.linkedCameras?.includes(sourceCameras[0])).length;
40307
+ // Create a wedge-shaped zone within the camera's FOV
40308
+ // Offset based on existing zones to avoid overlap
40309
+ const innerRadius = range * 0.3 + existingFromCamera * 20;
40310
+ const outerRadius = range * 0.8 + existingFromCamera * 20;
40311
+ // Use a portion of the FOV for each zone
40312
+ const zoneSpread = halfFov * 0.7; // 70% of half FOV
40313
+ const camX = camera.floorPlanPosition.x;
40314
+ const camY = camera.floorPlanPosition.y;
40315
+ // Create arc polygon (wedge shape)
40316
+ const steps = 8;
40317
+ // Inner arc (from left to right)
40318
+ for (let i = 0; i <= steps; i++) {
40319
+ const angle = dirRad - zoneSpread + (zoneSpread * 2 * i / steps);
40320
+ polygon.push({
40321
+ x: camX + Math.cos(angle) * innerRadius,
40322
+ y: camY + Math.sin(angle) * innerRadius,
40323
+ });
40324
+ }
40325
+ // Outer arc (from right to left)
40326
+ for (let i = steps; i >= 0; i--) {
40327
+ const angle = dirRad - zoneSpread + (zoneSpread * 2 * i / steps);
40328
+ polygon.push({
40329
+ x: camX + Math.cos(angle) * outerRadius,
40330
+ y: camY + Math.sin(angle) * outerRadius,
40331
+ });
40332
+ }
40333
+ this.console.log(`[Discovery] Creating zone "${zone.name}" in ${camera.name}'s FOV: dir=${direction}°`);
40334
+ }
40335
+ else {
40336
+ // Fallback: rectangular zone at default location
40337
+ const centerX = 300 + (topology.drawnZones?.length || 0) * 120;
40338
+ const centerY = 200;
40339
+ const size = 100;
40340
+ polygon = [
40341
+ { x: centerX - size / 2, y: centerY - size / 2 },
40342
+ { x: centerX + size / 2, y: centerY - size / 2 },
40343
+ { x: centerX + size / 2, y: centerY + size / 2 },
40344
+ { x: centerX - size / 2, y: centerY + size / 2 },
40345
+ ];
40285
40346
  }
40286
- // Create a rectangular zone (user can edit later)
40287
- const size = 100;
40288
- const timestamp = Date.now();
40289
40347
  // 1. Create DrawnZone (visual on floor plan)
40290
40348
  const drawnZone = {
40291
40349
  id: `zone_${timestamp}`,
40292
40350
  name: zone.name,
40293
40351
  type: (zone.type || 'custom'),
40294
40352
  description: zone.description,
40295
- polygon: [
40296
- { x: centerX - size / 2, y: centerY - size / 2 },
40297
- { x: centerX + size / 2, y: centerY - size / 2 },
40298
- { x: centerX + size / 2, y: centerY + size / 2 },
40299
- { x: centerX - size / 2, y: centerY + size / 2 },
40300
- ],
40353
+ polygon: polygon,
40301
40354
  linkedCameras: sourceCameras,
40302
40355
  };
40303
40356
  if (!topology.drawnZones) {