pg_orrery/test/expected/gist_index.out
Ryan Malloy a792e7e083 Extend GiST index to 2-D: altitude + inclination
The 1-D altitude-band index only pruned ~25% of the 22k satellite
catalog (eliminates MEO/GEO/HEO but 75% is LEO).  Adding inclination
as a second indexed dimension prunes an additional ~40% of remaining
candidates — objects in equatorial or low-inclination orbits that
geometrically cannot pass over the observer's latitude.

Key changes:
- tle_alt_range (16 bytes) → tle_orbital_key (32 bytes) with
  inc_low/inc_high fields
- All 8 GiST support functions updated for 2-D bounding boxes
- Penalty uses margin (half-perimeter) not area to avoid degeneracy
  when leaf entries have zero-width inclination ranges
- Picksplit selects split dimension by normalized spread
- && operator now checks altitude AND inclination overlap
- <-> operator remains altitude-only (conjunction screening is
  altitude-dominant)
- SQL operator comments updated for 2-D semantics
- Test adds Equatorial-LEO satellite at ISS altitude but 5° inclination
  to validate inclination-based pruning
2026-02-15 18:10:19 -07:00

99 lines
3.6 KiB
Plaintext

-- Test GiST index and operators (2-D: altitude + inclination)
CREATE EXTENSION IF NOT EXISTS pg_orbit;
NOTICE: extension "pg_orbit" already exists, skipping
-- Create test table with mixed orbit types
CREATE TABLE test_orbits (
id serial,
name text,
tle tle
);
-- ISS (LEO, ~400km, inclination 51.64 deg)
INSERT INTO test_orbits (name, tle) VALUES ('ISS',
'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001');
-- Hubble (LEO, ~540km, inclination 28.47 deg)
INSERT INTO test_orbits (name, tle) VALUES ('Hubble',
'1 20580U 90037B 24001.50000000 .00000790 00000+0 39573-4 0 9992
2 20580 28.4705 61.4398 0002797 317.3115 42.7577 15.09395228 00008');
-- GPS IIR-M (MEO, ~20200km, inclination 55.44 deg)
INSERT INTO test_orbits (name, tle) VALUES ('GPS-IIR',
'1 28874U 05038A 24001.50000000 .00000012 00000+0 00000+0 0 9993
2 28874 55.4408 300.3467 0117034 51.6543 309.5420 2.00557079 00006');
-- Equatorial-LEO: same altitude as ISS but near-equatorial inclination (5 deg).
-- Same mean motion (15.501 rev/day) and eccentricity as ISS → same altitude band.
-- Different inclination → should NOT overlap with ISS under 2-D key.
INSERT INTO test_orbits (name, tle) VALUES ('Equatorial-LEO',
'1 99901U 24999A 24001.50000000 .00016717 00000-0 10270-3 0 9990
2 99901 5.0000 208.9163 0006703 30.1694 61.7520 15.50100486 00001');
-- Create GiST index
CREATE INDEX test_orbits_gist ON test_orbits USING gist (tle);
-- 2-D overlap: ISS && Equatorial-LEO should be false (same altitude, different inclination)
SELECT a.name AS sat_a, b.name AS sat_b, a.tle && b.tle AS overlaps
FROM test_orbits a, test_orbits b
WHERE a.id < b.id
ORDER BY a.name, b.name;
sat_a | sat_b | overlaps
---------+----------------+----------
GPS-IIR | Equatorial-LEO | f
Hubble | Equatorial-LEO | f
Hubble | GPS-IIR | f
ISS | Equatorial-LEO | f
ISS | GPS-IIR | f
ISS | Hubble | f
(6 rows)
-- Altitude distance: ISS <-> Equatorial-LEO should be ~0 (same altitude shell)
SELECT a.name AS sat_a, b.name AS sat_b,
round((a.tle <-> b.tle)::numeric, 0) AS alt_dist_km
FROM test_orbits a, test_orbits b
WHERE a.id < b.id
ORDER BY a.name, b.name;
sat_a | sat_b | alt_dist_km
---------+----------------+-------------
GPS-IIR | Equatorial-LEO | 19451
Hubble | Equatorial-LEO | 115
Hubble | GPS-IIR | 19332
ISS | Equatorial-LEO | 0
ISS | GPS-IIR | 19451
ISS | Hubble | 115
(6 rows)
-- GiST index scan: find all sats overlapping ISS (altitude AND inclination)
-- Should return only ISS itself (Equatorial-LEO is at same altitude but wrong inclination)
SET enable_seqscan = off;
SELECT name FROM test_orbits
WHERE tle && (SELECT tle FROM test_orbits WHERE name = 'ISS')
ORDER BY name;
name
------
ISS
(1 row)
RESET enable_seqscan;
-- Nearest-neighbor via GiST: order by altitude distance to ISS
SET enable_seqscan = off;
SELECT name, round((tle <-> (SELECT tle FROM test_orbits WHERE name = 'ISS'))::numeric, 0) AS dist
FROM test_orbits
WHERE name != 'ISS'
ORDER BY tle <-> (SELECT tle FROM test_orbits WHERE name = 'ISS');
name | dist
----------------+-------
Equatorial-LEO | 0
Hubble | 115
GPS-IIR | 19451
(3 rows)
RESET enable_seqscan;
-- Self-overlap is always true
SELECT name, tle && tle AS self_overlap FROM test_orbits ORDER BY name;
name | self_overlap
----------------+--------------
Equatorial-LEO | t
GPS-IIR | t
Hubble | t
ISS | t
(4 rows)
-- Cleanup
DROP TABLE test_orbits;