Hledáme v databázi dle velikosti průniku polygonů

Hledáme v databázi dle velikosti průniku polygonů

Žijeme v době elektronických udělátek. Téměř všichni máme u sebe nějaké chytré zařízení, které nás zásobuje informacemi a zároveň o nás informace ukládá. Včetně naší polohy. A občas se musí najít někdo, kdo tyto informace zpracuje :-)

Naštěstí databáze mají podporu pro prostorové (spatial) funkce a tím nám to velmi usnadňují. Úkoly jako hledání bodů v libovolném polygonu, zjišťování průniků nebo měření vzdáleností jsou díky této podpoře triviální záležitostí. Co když ale chceme najít všechny polygony, které leží v určeném polygonu z více než polovinou své plochy? Tam už je potřeba trochu zapojit geometrii a zkombinovat dostupné funkce. A abych nemusel pořád dohledávat jak přesně to zkombinovat, tak vznikl tento blogový zápisek :-)

Prostorové funkce

Prostorové funkce, které využijeme, a co o nich říká dokumentace:

  • ST_Area(g1) – vrací plochu geometrie s přesností na 2 desetinná místa.
  • ST_Intersection(g1, g2) – vrací novou geometrii, která reprezentuje průnik geometrií g1 a g2.

 

Popis řešení

Řešení je příjemně jednoduché a stručné. Necháme databázi u prohledávaných polygonů spočítat jejich plochu a tuto plochu zmenšíme (vydělíme v takovém poměru) na velikost, kterou hledáme (50% = /2 nebo * 0.5 atd). K tomu si necháme spočítat velikost průniku s porovnávaným polygonem a tyto dvě hodnoty aritmeticky porovnáme. Hotovo :-)

Příklad v SQL syntaxi vypadá cca následovně (testováno v mysql, nicméně postgresql by měl být stejný):


SET @shapeToCompare = ST_GeomFromText('polygon((0 0, 10 0, 10 10, 0 10, 0 0))');
SET @moreOutside = ST_GeomFromText('polygon((9 9, 14 9, 14 14, 9 14, 9 9))');
SET @moreInside = ST_GeomFromText('polygon((3 3, 11 3, 11 11, 3 11, 3 3))');

SELECT (ST_Area(@moreOutside) * 0.5) < ST_Area(ST_Intersection(@shapeToCompare, @moreOutside)) as result;
+--------+
| result |
+--------+
|      0 |
+--------+
1 row in set (0.00 sec)


SELECT (ST_Area(@moreInside) * 0.5) < ST_Area(ST_Intersection(@shapeToCompare, @moreInside)) as result;
+--------+
| result |
+--------+
|      1 |
+--------+
1 row in set (0.00 sec)

 

V reálné situaci při práci s databází proměnné jednoduše nahradíme názvy sloupců a vše bude fungovat stejně. A byť ten příkaz vypadá relativně složitě, jeho výsledek lze ukládat do query cache.

Napsat komentář