Pár metódus még a geometry típushoz, aztán tényleg jönnek a valódi adatok és számítások.
A példáim eddig a geometry típusra építettek, azt könnyebb kezelni, de a metódusok jelentős része értelmezhető lesz a geograpy típuson is. Ha nem ebben a CTP-ben, majd a következőben (CTP6 pre-t már le tudnék tölteni mint MVP, de várok pár napot a végleges CTP-re, ne kelljen állandóan telepíteni). Nem mindent lehet viszont egy gömbön értelmezni, ezért nem teljesen azonos a két típus metóduskészlete, de erről majd később.
Csak ízelítőül, sík tartomány esetén (geometry) triviális értelmezni a kívül és a belül fogalmát, amelyik tartomány véges, az van belül. És egy gömbön? Ott mindkét tartomány véges. Akkor, most mi nézzük a majmokat az állatkertben, vagy ők néznek minket? Ezt a kérdést is elrendezzük majd. Ezeket csak azért mondom, hogy ne csüggedjen senki a sok metódus láttán, kellenek majd ezek.
Távolság meghatározás: STDistance. Ez egy pont és egy teszőleges alakzat között keresi meg a legrövidebb utat. Geometrynél ennek nincs mértékegysége, geograpy esetén pedig az SRID-től függ, mi lesz ez, sok esetben például fokban kapjuk meg a távolságot (hisz a geograpy szélesség-hosszúsággal dolgozik).
A példában még látható a STLength, az az alakzat körvonalának hosszát adja vissza (pl. egy ország kerülete).
DECLARE @g geometry;
DECLARE @h geometry;
DECLARE @i geometry;
SET @g = geometry::STGeomFromText('POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))', 0);
SET @h = geometry::STGeomFromText('POINT(10 10)', 0);
SET @i = geometry::STGeomFromText('LINESTRING(2 2,10 10)', 0);
SELECT @g, @g.STDistance(@h), 0.1 as [Thickness], 'Green' as [Color]
UNION ALL
SELECT @i, @i.STLength(), 0.1 as [Thickness], 'Gray' as [Color] -- demonstration line
UNION ALL
SELECT @h, null, 0.3 as [Thickness], 'Red' as [Color];
POLYGON ((0 0, 2 0, 2 2, 0 2, 11.3137084989848 0.1 Green
LINESTRING (2 2, 10 10) 11.3137084989848 0.1 Gray
POINT (10 10) NULL 0.3 Red

Befoglaló téglalap meghatározása: STEnvelope. Ezt könnyű elképzelni, nem mellékelek képet, csak a kimenetet:
DECLARE @g geometry;
SET @g = geometry::STGeomFromText('LINESTRING(0 0, 2 3)', 0);
SELECT @g, @g.STEnvelope(), 0.1 as [Thickness];
LINESTRING (0 0, 2 3) POLYGON ((0 0, 2 0, 2 3, 0 3, 0 0))
Egyenlő-e két alakzat? STEquals. Azt gondolnánk ez egyszerű, de lehet, hogy másként vannak összerakva. Pl. egy sokszöget össze lehet rakni multi-lineként, aminek az első és utolsó pontja ugyanaz és polygonként is. A függvény észreveszi az ilyen csibészségeket.
DECLARE @g geometry
DECLARE @h geometry;
SET @g = geometry::STGeomFromText('LINESTRING(0 2, 2 0, 4 2)', 0);
SET @h = geometry::STGeomFromText('MULTILINESTRING((4 2, 2 0), (0 2, 2 0))', 0);
SELECT @h, @h.STEquals(@g), 'Blue' as [Color], 0.2 as [Thickness]
UNION ALL
SELECT @g, @g.STEquals(@h), 'Orange' as [Color], 0.1 as [Thickness];
MULTILINESTRING ((4 2, 2 0), (0 2, 2 0)) 1
LINESTRING (0 2, 2 0, 4 2) 1
A példából látszik, hogy a művelet kommutatív (még szép).

Külső körvonal meghatározása: STExteriorRing. A korábbi lukas négyzetes példában a külső négyzetet adja vissza. Ha egy épületegyüttes van például poligonok kollekciójaként leírva, akkor ezzel könnyű meghatározni az együttes körvonalukat. Az STInteriorRingN(n) kívülről befelé haladva az n. belső körvonalat adja vissza.
DECLARE @g geometry;
SET @g = geometry::STGeomFromText('POLYGON((0 0, 3 0, 3 3, 0 3, 0 0),(2 2, 2 1, 1 1, 1 2, 2 2))', 0);
SELECT @g, 0.3 as [Thickness], 'Red' as Color
UNION ALL
SELECT @g.STExteriorRing() AS [ExteriorRing], 0.1 as [Thickness], 'Yellow' as Color
UNION ALL
SELECT @g.STInteriorRingN(1) AS [FirstInteriorRing], 0.1 as [Thickness], 'Green' as Color;
POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (2 2, 2 1, 1 1, 1 2, 2 2)) 0.3 Red
LINESTRING (0 0, 3 0, 3 3, 0 3, 0 0) 0.1 Yellow
LINESTRING (2 2, 2 1, 1 1, 1 2, 2 2) 0.1 Green

STIsEmpty: ez olyan, mint a NULL. Itt egy alakzat lehetne, de nincs. Azaz olyan, mint az ISNULL, csak geo izékre.
STIsClosed: zárt-e az alakzat. Ha a kezdő és a végpont ugyanaz, akkor zárt.
STIsSimple: ha az alakzat nem metszi saját magát. Pl. a 8-as, az X vagy az A nem egyszerű alakzat. Az O vagy a D igen.
STIsRing: akkor gyűrű valami, ha zárt és egyszerű. Az O pl. gyűrű, de a D is, az A nem, mert nem zárt (kilóg a két lába) és nem is egyszerű (a vízszintes beleér a két lábába).
STOverlaps: átfedi-e egymást két alakzat, elég egyszerű értelmezni. Mozgó alakzatoknál ütközést érzékelni is jó. (Doom for SQL Server) :)
STPointOnSurface: visszaad egy tetszőleges pontot egy felület belsejében. Nem igazán tudom még mire lehet jó, de talán arra, hogy ha pl. egy épülethez képest kell mérni valami, de nem tudjuk hol vannak az ajtók, akkor kiválasztunk a belsejében egy tetszőleges pontot a függvénnyel, és onnan mérünk. Ha valaki ismeri a pontos célját, írja meg.
Update.
Megkérdeztem az MVP newsgroupban, az egyik SQL Server fejlesztő kolléga (Isaac Kunen) azt mondta, arra jó, hogy ha az alakzathoz egy címkét szeretnénk rajzolni, akkor egy ahhoz használható pozíciót ad vissza a metódus. Hmm.
És végül (tényleg elfogyak a metódusok?) egy nem szabványos kiegészítés: Reduce.
Ezzel le lehet egyszerűsíteni alakzatokat, hogy egyszerűen fogalmazva durvább legyen a felbontásuk.
DECLARE @g geometry;
SET @g = geometry::STGeomFromText('LINESTRING(0 0, 0 1, 1 0, 2 1, 3 0, 4 1)', 0);
SELECT @g, 'Original' as [Display], 'Blue' AS [Color], 0.2 AS [Thickness]
UNION ALL
SELECT @g.Reduce(.75), 'Reduced' as [Display], 'Red' AS [Color], 0.1 AS [Thickness]
LINESTRING (0 0, 0 1, 1 0, 2 1, 3 0, 4 1) Original Blue 0.2
LINESTRING (0 0, 0 1, 3 0, 4 1) Reduced Red 0.1

A doksi szerint ő a Douglas-Peucker algoritmussal közelíti meg az eredeti alakzatot, a megadott paraméternek megfelelő agresszivitással. Gondolom akkor jön jól, ha egy számítás lassú lenne a finom felbontás mellett (pl. egy poligon 1500 darabkából), és ilyenkor a pontosság rovására, de egy mondjuk tizedére csökkentett oldalszámra egyszerűsített alakzattal számolunk. Érdemes megnézni, mit csinál egy körrel:
DECLARE @g geometry;
SET @g = geometry::STGeomFromText('POINT(0 0)', 0).STBuffer(10);
SELECT @g, 'Original' as [Display], 'Blue' AS [Color], 1 AS [Thickness]
UNION ALL
SELECT @g.Reduce(.75), 'Reduced1' as [Display], 'Red' AS [Color], 0.2 AS [Thickness]
UNION ALL
SELECT @g.Reduce(2), 'Reduced2' as [Display], 'Yellow' AS [Color], 0.2 AS [Thickness]
UNION ALL
SELECT @g.Reduce(5), 'Reduced3' as [Display], 'Green' AS [Color], 0.2 AS [Thickness]

Ez volt a kör négyszögesítése projekt.
No, még mindig nem érintettünk minden metódust, de a legfontosabbakat már láttuk. A következő részben letöltünk adatokat az országról és a környékéről, és elkezdünk méricskélni rajta. Ízelítőül megmutatom a környező országok kerületének és területének kiszámítását (Addig lehet ellenőrizni, jók-e az adatok? Románia területe nem gyanúsan nagy? ;)
select
CNTRY_NAME as 'Ország',
cast([geom].STArea() /1000 /1000 as int) as 'Terület [km2]',
cast([geom].STLength() /1000 as int) as 'Kerület [km]'
from Country
Ország Terület [km2] Kerület [km]
------------------------------ ------------- ------------
Byelarus 1024 162
Poland 139576 2068
Czech Republic 54465 1303
Ukraine 43739 1240
Germany 3585 285
Slovakia 48926 1207
Hungary 92995 1562
Austria 42468 966
Slovenia 14000 651
Serbia 76621 1614
Romania 105365 1613
Bosnia and Herzegovina 51005 1173
Croatia 52209 3009
Bulgaria 19237 724
Montenegro 7780 450