Vytvořit tabulku s polygonovým sloupcem
Vezměte prosím na vědomí, že pro použití prostorových indexů nemůžete použít InnoDB. Můžete použít geometrii bez prostorových indexů, ale výkon se jako obvykle snižuje.
CREATE TABLE IF NOT EXISTS `spatial` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`poly` geometry NOT NULL,
UNIQUE KEY `id` (`id`),
SPATIAL INDEX `poly` (`poly`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Vložte 3 čtverce a trojúhelník
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((10 50,50 50,50 10,10 10,10 50))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((1 15,5 15,5 11,1 11,1 15))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((11 5,15 5,15 1,11 5))',0));
Vyberte vše, co protíná malý čtverec v levém dolním rohu (fialový čtverec #1)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
)
;
Vyberte vše, co protíná trojúhelník od levého dolního přes pravé dolní rohy až po pravý horní roh) (čtverce #1 a #2 a trojúhelník #4.)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
)
;
Vybere vše ve čtverci, co je mimo náš obrázek (nic)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
)
;
Úprava č. 1:
Znovu jsem si přečetl otázku a myslím, že máte trochu zmatené prostorové vztahy. Pokud chcete najít vše, co se celé vejde do čtverce (polygonu), musíte použít Contains/ST_Contains. Viz prostorové funkce v dokumentaci MySQL abyste zjistili, která funkce dělá práci za vás. Všimněte si prosím následujícího rozdílu mezi funkcemi ST/MBR:
Vybere vše, co je zcela uvnitř čtverce (#0 zdola) (čtverce #1, #2, trojúhelník #4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Vybere vše, co je zcela uvnitř čtverce (#0 zdola) a nesdílí žádné hrany (čtverec č. 2, trojúhelník č. 4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Úprava č. 2:
Velmi pěkný doplněk od @StephanB (SQL housle )
Vyberte všechny překrývající se objekty
SELECT s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)
FROM `spatial` s1, `spatial` s2
WHERE
ST_Intersects(s1.poly, s2.poly)
AND s1.id < s2.id
;
(jen si všimněte, že byste měli odstranit AND s1.id < s2.id
pokud pracujete s CONTAINS
, jako CONTAINS(a,b) <> CONTAINS(b,a)
zatímco Intersects(a,b) = Intersects(b,a)
)
Na následujícím obrázku (neúplný seznam):
-
2 protínají číslo 6.
-
6 protíná #2
-
0 protíná #1, #2, #3, #4, #5
-
1 protíná #0, #5
-
0 obsahuje #1, #3, #4 a #5 (#1, #3, #4 a #5 jsou v rámci #0)
-
1 obsahuje #5 (#5 je v rámci #1)
-
0 st_obsahuje #3, #4 a #5
-
1 st_contains #5
Úprava č. 3:Vyhledávání podle vzdálenosti/Práce v (s) kruzích
MySQL přímo nepodporuje kruh jako geometrii, ale můžete použít prostorovou funkci Buffer(geometry,distance)
obejít to. Co Buffer()
vytváří vyrovnávací paměť uvedené vzdálenosti kolem geometrie. Pokud začnete s geometrickým bodem, vyrovnávací paměť je skutečně kruh.
Můžete vidět, co buffer skutečně dělá, když zavoláte:
SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))
(výsledek je poměrně dlouhý, takže ho zde nebudu zveřejňovat) Ve skutečnosti vytvoří polygon, který představuje vyrovnávací paměť - v tomto případě (a mé MariaDB) je výsledkem 126 bodový polygon, který aproximuje kruh. S takovým polygonem můžete pracovat jako s jakýmkoli jiným polygonem. Takže by neměl být žádný trest za výkon.
Pokud tedy chcete vybrat všechny polygony, které spadají do kruhu můžete opláchnout a zopakovat předchozí příklad (tím se najde pouze čtverec #3)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
Vyberte všechny mnohoúhelníky, které se protínají s kruhem
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
Při práci s tvary odlišnými od obdélníků byste měli použít ST_*
funkcí. Funguje bez ST_
použijte ohraničující obdélník. Předchozí příklad tedy vybírá trojúhelník #4, i když není v kruhu.
Jako Buffer()
vytváří poměrně velké polygony, určitě dojde k určitému snížení výkonu oproti použití ST_Distance()
metoda. Bohužel to neumím vyčíslit. Budete muset provést nějaký benchmarking.
Dalším způsobem hledání objektů podle vzdálenosti je použití ST_Distance()
funkce.
Vyberte všechny prvky z tabulky a vypočítejte jejich vzdálenost od bodu POINT(6 15)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
;
Můžete použít ST_Distance
v WHERE
klauzule také.
Vyberte všechny prvky, jejichž vzdálenost od POINT(0 0) je menší nebo rovna 10 (vybere #1, #2 a #3)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
;
I když se vzdálenost počítá od nejbližšího bodu k nejbližšímu bodu. Je to podobné jako ST_Intersect
. Výše uvedený příklad tedy vybere #2, i když se zcela nevejde do kruhu.
A ano, druhý argument (0) pro GeomFromText(text,srid)
, nehraje žádnou roli, můžete jej klidně ignorovat. Zvedl jsem to z nějakého vzorku a trochu to uvízlo v mé odpovědi. Ve svých pozdějších úpravách jsem to vynechal.
Mimochodem. phpMyAdmin podpora pro prostorové rozšíření není bezchybná, ale docela pomáhá vidět, co je ve vaší databázi. Pomohl mi s těmito obrázky, které přikládám.