Sub-Space Mapping for Small Compartments
Sub-Space Mapping for Small Compartments
This document extends the Spatial Relationships System and the Container Pattern to support identifying and managing tiny compartments (e.g. dividers in a screw organiser) when individual QR/NFC tags are impractical.
1 Problem Statement
Certain containers—tackle boxes, pill organisers, hardware assortments—contain many small sub-containers. These slots are too small for their own physical identifiers, yet users still need to:
- Locate the slot that holds a specific
ObjectClass. - Track implicit quantities per slot (“25 screws left”).
- Instantiate or remove explicit
ObjectInstances from a slot.
2 Solution Overview
- Overview Image – A photograph (or schematic) of the parent container is stored once.
- Sub-Space Nodes – Each compartment is modelled as a node with a polygon (normalised coordinates) that points to a region on the image.
- Fixed Spatial Anchor – A new relationship
(:SubSpace)-[:FIXED_IN]->(:ObjectInstance {id:"Box-001"})asserts the polygon is rigidly attached to the container. - Implicit Quantity – Each
SubSpacecarries its ownimplicit_quantitycounter for bulk items stored inside.
3 Data Model Additions
3.1 Node: :SubSpace
| Property | Type | Description |
|---|---|---|
name |
String |
Human-friendly label (e.g. “Slot C3”) |
polygon |
List<List<Float>> |
Normalised 0-1 coordinate pairs [[x,y]…] |
expected_class_id |
String (FK) |
Default ObjectClass stored here |
implicit_quantity |
Integer |
Count of un-instantiated units remaining |
3.2 Relationship: FIXED_IN
| Start | Type | End | Semantics |
|---|---|---|---|
:SubSpace |
FIXED_IN |
:ObjectInstance |
Polygon is physically part of the container |
FIXED_INbehaves likePART_OFbut is 2-D image-centric: moving the parent moves all its sub-spaces.
4 Workflow (UX)
- Capture – User scans the parent container’s QR → selects “Add compartment map” → uploads / snaps photo.
- Annotate – In-app polygon editor lets user draw slots, assign
ObjectClass& starting quantity. - Persist – Frontend sends
addSubSpacemutations; backend writes nodes & edges. - Daily Ops – Tapping a slot opens quick actions: Remove N, Instantiate items, Add items back.
- Aggregate View – Container detail page sums
implicit_quantityof its slots plus explicit descendants.
5 GraphQL API Sketch
type SubSpace {
id: ID!
name: String!
polygon: [[Float!]!]!
expectedClass: ObjectClass!
implicitQuantity: Int!
parentContainer: ObjectInstance!
}
input SubSpaceInput {
name: String!
polygon: [[Float!]!]!
expectedClassId: ID!
implicitQuantity: Int!
}
extend type Mutation {
addSubSpace(containerId: ID!, input: SubSpaceInput!): SubSpace!
updateSubSpaceQuantity(subSpaceId: ID!, delta: Int!): SubSpace!
deleteSubSpace(id: ID!): Boolean! # fails if quantity > 0 or has explicit children
}
6 Integrity & Safeguards
- Polygon overlap – API validates new polygon does not intersect existing ones (optional tolerance).
- Normalised Coordinates – Stored 0-1 so replacing the background image (higher resolution) does not break mapping.
- Deletion Guard – Cannot delete a
SubSpacewith non-zeroimplicit_quantityor with child objects linked viaREMOVED_FROM.
7 Storage Notes
- Overview image stored per Image Management rules; mark with
purpose = "layout". polygonJSON typically < 1 KB; negligible storage.implicit_quantityupdates write a single Postgres row, supporting optimistic UI counters.
8 Compatibility with Existing Patterns
| Requirement | Covered By |
|---|---|
| Bulk ownership | Container pattern (implicit) |
| Partial instantiation | REMOVED_FROM edges from :SubSpace |
| Spatial queries | Treat SubSpace as any ObjectInstance in IN chains |
| Analytics & alerts | Same aggregation queries; just include SubSpace |
No breaking changes to the core schema are introduced; merely a new label + edge type fully aligned with the extensible spatial system.