Elements above, and the gap to each
32-bit in partWhat sits over an element's footprint and how far above its top each one starts.
gap = max(0, lowest Y of the other element − top Y of this element)
The box corners come from the viewer's 32-bit positions (viewer3d.js keyBoundsMap reads ifc-vis.js boundsMapOf). The gap is rounded to two decimals of a meter in the answer. A 32-bit number in meters is spaced less than 0.0001 m apart below 1024 m, which is under that rounding.
const reach = a.within_m ?? 3, tol = 0.02, top = tb.max[1];
const hit = [];
for (const [k, b] of app.bounds(ix.keys.filter((x) => x !== key))) {
if (b.min[1] < top - tol || b.min[1] > top + reach) continue;
if (b.max[0] < tb.min[0] || b.min[0] > tb.max[0] || b.max[2] < tb.min[2] || b.min[2] > tb.max[2]) continue;
if (a.class && String(ix.value('cls', k - ix.keyBase)).toLowerCase() !== a.class.toLowerCase()) continue;
hit.push({ key: k, gap: Math.max(0, b.min[1] - top) });
}
hit.sort((x, y) => x.gap - y.gap);
const pg = page(hit, a), shown = show(a, hit.map((h) => h.key));
const byClass = {};
for (const h of hit) { const cl = String(ix.value('cls', h.key - ix.keyBase) ?? '?'); byClass[cl] = (byClass[cl] || 0) + 1; }
return {
model: app.name(), of: describe(ix, key), lookedAbove_m: reach, how: 'elements whose 3D bounding box starts within ' + reach + ' m above the top of the element and overlaps its footprint',
total: hit.length, returned: pg.returned, next: pg.next, selected: shown, byClass, notes: ['A survey from bounding boxes: an element may be in the box without touching the footprint. Use a clash check for a decision.'],
elements: pg.rows.map((h) => ({ ...describe(ix, h.key), gap_m: r2(h.gap) })),