Crea tabella con colonna poligonale
Tieni presente che per utilizzare gli indici spaziali, non puoi utilizzare InnoDB. Puoi utilizzare la geometria senza indici spaziali, ma le prestazioni peggiorano come al solito.
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;
Ottieni 3 quadrati e un triangolo inseriti
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));
Seleziona tutto ciò che interseca il quadratino nell'angolo in basso a sinistra (quadrato viola n. 1)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
)
;
Seleziona tutto ciò che interseca il triangolo, dagli angoli in basso a sinistra a quelli in basso a destra fino all'angolo in alto a destra) (quadrati #1 e #2 e triangolo #4.)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
)
;
Seleziona tutto in quadrato che è al di fuori della nostra immagine (niente)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
)
;
Modifica n. 1:
Ho riletto la domanda e penso che tu abbia le relazioni spaziali un po' confuse. Se quello che vuoi è trovare tutto ciò che si adatta interamente all'interno di un quadrato (poligono), allora devi usare Contains/ST_Contains. Consulta le funzioni spaziali nella documentazione di MySQL per scoprire quale funzione fa il lavoro per te. Si noti la seguente differenza tra le funzioni ST/MBR:
Seleziona tutto ciò che è completamente all'interno di un quadrato (#0 dal basso) (quadrati n. 1, n. 2, triangolo n. 4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Seleziona tutto ciò che è completamente all'interno di un quadrato (#0 dal basso) e non condivide bordi (quadrato n. 2, triangolo n. 4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Modifica n. 2:
Aggiunta molto bella da @StephanB (SQL fiddle )
Seleziona eventuali oggetti sovrapposti
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
;
(nota solo che dovresti rimuovere AND s1.id < s2.id
se stai lavorando con CONTAINS
, come CONTAINS(a,b) <> CONTAINS(b,a)
while Intersects(a,b) = Intersects(b,a)
)
Nella figura seguente (elenco non esaustivo):
-
2 interseca #6.
-
6 interseca #2
-
0 interseca #1, #2, #3, #4, #5
-
1 interseca #0, #5
-
0 contiene n. 1, n. 3, n. 4 e n. 5 (n. 1, n. 3, n. 4 e n. 5 sono entro n. 0)
-
1 contiene #5 (#5 è entro #1)
-
0 st_contiene #3, #4 e #5
-
1 st_contiene #5
Modifica n. 3:Ricerca per distanza/Lavorare in (con) cerchi
MySQL non supporta direttamente il cerchio come geometria, ma puoi usare la funzione spaziale Buffer(geometry,distance)
per aggirarlo. Cosa Buffer()
fa, sta creando un buffer di detta distanza attorno alla geometria. Se inizi con un punto geometrico, il buffer è effettivamente un cerchio.
Puoi vedere cosa fa effettivamente il buffer chiamando solo:
SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))
(il risultato è piuttosto lungo, quindi non lo posterò qui) In realtà crea un poligono che rappresenta il buffer - in questo caso (e il mio MariaDB) il risultato è un poligono di 126 punti, che approssima un cerchio. Con un tale poligono puoi lavorare come faresti con qualsiasi altro poligono. Quindi non ci dovrebbero essere penalità per le prestazioni.
Quindi, se vuoi selezionare tutti i poligoni che cadono in un cerchio puoi risciacquare e ripetere l'esempio precedente (questo troverà solo il quadrato n. 3)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
Seleziona tutti i poligoni che si intersecano con un cerchio
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
Quando lavori con forme diverse dai rettangoli, dovresti usare ST_*
funzioni. Funziona senza ST_
usa un rettangolo di delimitazione. Quindi l'esempio precedente seleziona il triangolo #4 anche se non è nel cerchio.
Come Buffer()
crea poligoni piuttosto grandi, ci sarà sicuramente una penalizzazione delle prestazioni rispetto all'utilizzo di ST_Distance()
metodo. Purtroppo non riesco a quantificarlo. Dovrai fare un po' di benchmarking.
Un altro modo per trovare oggetti in base alla distanza è usare ST_Distance()
funzione.
Seleziona tutti gli elementi dalla tabella e calcola la loro distanza dal punto POINT(6 15)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
;
Puoi usare ST_Distance
in WHERE
anche la clausola.
Seleziona tutti gli elementi la cui distanza da POINT(0 0) è minore o uguale a 10 (seleziona #1, #2 e #3)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
;
Sebbene la distanza sia calcolata dal punto più vicino al punto più vicino. Rendendolo simile a ST_Intersect
. Quindi l'esempio sopra selezionerà #2 anche se non si adatta completamente all'interno del cerchio.
E sì, il secondo argomento (0) per GeomFromText(text,srid)
, non svolge alcun ruolo, puoi tranquillamente ignorarlo. L'ho raccolto da un campione e si è bloccato nella mia risposta. L'ho omesso nelle mie modifiche successive.
a proposito. phpMyAdmin il supporto per l'estensione spaziale non è impeccabile, ma aiuta parecchio a vedere cosa c'è nel tuo database. Mi ha aiutato con queste immagini che ho allegato.