habrã³ãã¥ããã£ã®èªè
ã«ãCLRã©ã€ãã©ãª
Microsoft.SqlServer.Typesã䜿çšããŠãé»åå°å³ã®ã¿ã€ã«ãäœæããæ¹æ³ãäŒããããšæããŸãã ãã®èšäºã§ã¯ãããã«ã¬ã³ããªã³ã°ããããã®ãããã¿ã€ã«ã®ãªã¹ãã®çæã«ã€ããŠèª¬æããŸãã MS SQL 2008ããŒã¿ããŒã¹ã«æ ŒçŽãããŠãããªããžã§ã¯ãã®ãžãªã¡ããªã«ãã£ãŠã¿ã€ã«ãçæããã¢ã«ãŽãªãºã ã«ã€ããŠèª¬æããå
šäœã®ã¬ã³ããªã³ã°ããã»ã¹ã«ã€ããŠã¯ãèšäºã®æåŸã®äŸã§æ®µéçã«èª¬æããŸãã
å
容
åé¡ãœãŒã¹ããŒã¿è§£æ±ºçã¿ã€ã«ãªããžããªã¿ã€ã«ã®æºåæé 䜿çšããæ©èœããªã©ã€ã³ã®äŸäº€å·®ç¹ãã§ãã¯ã¿ã€ã«ç»åãä¿åããããã®ããŒãã«ã¿ã€ã«ã«ã¢ã€ã³ã³ãé
眮ããã¿ã€ã«ã®é¢é£ä»ãã¿ã€ã«äžã®ãžãªã¡ããªã®æç»ãããã«åé¡
ãã©ãŠã¶ãŒã倧éã®å°çããŒã¿ããã¯ã¿ãŒã°ã©ãã£ãã¯ã¹ã§è¡šç€ºããå ŽåïŒSVGãŸãã¯CANVASã䜿çšïŒãããŒã¿ãã¯ã©ã€ã¢ã³ããã·ã³ã«ããŠã³ããŒããããã®ãåŸ
ã€ã ãã§ãªããæç»ããã»ã¹ã«æéãããããããããšããããŸãã
ãã©ãŠã¶ãŒã®å°å³ã«å€æ°ã®ã¢ã€ã³ã³ã衚瀺ããå Žåãã¯ã©ã¹ã¿ãªã³ã°ãé©çšã§ããŸãããè€éãªå¹ŸäœåŠçãªããžã§ã¯ãã®å Žåã¯å¥ã®ã¢ãããŒãã䜿çšããå¿
èŠããããŸãã
ãœãŒã¹ããŒã¿ïŒ
ãžãªã¡ããªãªããžã§ã¯ãã®ã»ããã¯Microsoft SQL 2008ããŒã¿ããŒã¹ããŒãã«ã«æ ŒçŽãããããŒãã®åº§æšã¯ç·¯åºŠãšçµåºŠïŒEPSGïŒ4326ïŒã§ãã å°çããŒã¿ãã£ãŒã«ãã®ã¿ã€ãã¯
GEOMETRYã§ãã ãªããžã§ã¯ãã¯ã
ãã€ã³ããžãªã¡ããªã®ã¢ã€ã³ã³ãšããŠãããäžã«è¡šç€ºãããå¿
èŠããããŸãã
ããªã©ã€ã³ãžãªã¡ããªã®ç¹å®ã®å€ªãã®ããªã©ã€ã³ã®åœ¢åŒã ããªãŽã³ãžãªã¡ããªã¯ãã¢ãŠãã©ã€ã³ä»ãã®1ã€ä»¥äžã®ã·ã§ãŒãã£ã³ã°ããªãŽã³ãšããŠè¡šç€ºããå¿
èŠããããŸãã ã¿ã€ã«ã¯
Webã¡ã«ã«ãã«å³æ³ãšäžèŽããå¿
èŠããã
ãŸã解決çïŒ
ãã¯ã¿ãŒã°ã©ãã£ãã¯ã¹ã®ä»£ããã«ããããäžã®ãªããžã§ã¯ããã©ã¹ã¿ãŒã¬ã€ã€ãŒãšããŠãã€ãŸããããèªäœãšåãç»åïŒã¿ã€ã«ïŒã§è¡šç€ºããŸãã ãããè¡ãã«ã¯ããªããžã§ã¯ãã®ç»åã䜿çšããŠåã¹ã±ãŒã«ã®ãããã¿ã€ã«ã®ã»ãããæºåããå¿
èŠããããŸãã ã¿ã€ã«ãäœæããã«ã¯ã
Google Webã¡ã«ã«ãã«å³æ³ã䜿çšã
ãŸã ãã€ãŸãã
ã¡ã«ã«ãã«å³æ³ã説æããåŒ
ã䜿çšããã Googleã³ãŒãã䜿çšããŠã緯床ãšçµåºŠã®ããããã¯ã»ã«ãžã®å€æãå®è¡
ãããŸãã
äºæž¬ã®è©³çŽ°ã«ã€ããŠã¯ã
ãã¡ããã芧ãã ãã ã
Sql Server 2008ã®ããŒãžã§ã³ä»¥éã
GEOMETRYããã³
GEOGRAPHYããŒã¿
å㯠ã空éããŒã¿ãæäœããããã«ãµããŒããããŠããŸãã
YandexãGoogleããŸãã¯OpenStreetMapãããã³ã°ã®æ¢åã®ãããã³ã°ãµãŒãã¹ãPNGç»åã®åœ¢åŒã§æäŸãããéåžžã¯256x256ãã¯ã»ã«ã®åºå®ãµã€ãºã§ãã çŸåšãSVGãCANVASãªã©ã®ãã¯ãããžãŒã䜿çšããŠã¿ã€ã«ã圢æããããµãŒãã¹ããããŸãã PNG圢åŒïŒç»åãããã¯ãŒã¯ã°ã©ãã£ãã¯ïŒã®ã©ã¹ã¿ãŒã¿ã€ã«ãæ€èšããŸãã PNG圢åŒã¯éæ床ïŒã¢ã«ãã¡ãã£ã³ãã«ã§ç€ºãããïŒããµããŒãããŸããããã«ãããè€æ°ã®ã¬ã€ã€ãŒã衚瀺ãããšãã«ã絶察ã«ãªãŒããŒã©ããããããšãªãã¿ã€ã«ãéããããšãã§ããŸãã
ã¿ã€ã«ãªããžããª
åã¹ã±ãŒã«ã«å¯ŸããŠãç¹å®ã®ã¿ã€ã«ã»ãããä¿åãããŸãã 0ã¬ãã«-1ã¿ã€ã«ã®ã¹ã±ãŒã«ã®å ŽåïŒ
第1ã¬ãã«ã¹ã±ãŒã«ã®å Žåã4ã€ã®2 * 2ã¿ã€ã«ïŒ
ã¹ã±ãŒã«nã®å Žåã2n * 2nã¿ã€ã«ãä¿åãããŸãã ã¹ã±ãŒã«æ°ãå¢å ããã¿ã€ã«ã®æ°ã¯ææ°é¢æ°çã«å¢å ããŸãã
ã¿ã€ã«ã¯ãWebãµãŒããŒã®ãã¡ã€ã«ã·ã¹ãã ã«ä¿åãããhttpèŠæ±ã«ãã£ãŠã¯ã©ã€ã¢ã³ããã·ã³ã«éä¿¡ãããŸãã次ã«äŸã瀺ããŸãã
someurl / layer {Z} / {X} / {Y} .png
ããã§ãZãXãYã¯ããããã¹ã±ãŒãªã³ã°ãXã¿ã€ã«äœçœ®ãYã¿ã€ã«äœçœ®ã§ãã ããšãã°ã次ã®URLã§ããµã³ã¯ãããã«ãã«ã¯ã®ããªããã£ããªããžã®ç»åãå«ãã¿ã€ã«ã䜿çšã§ããŸãã
b.tile.openstreetmap.org/15/19144/9524.png
ãã®URLã§ïŒ
15-ã¹ã±ãŒã«çªå·ã
19144â Xã¿ã€ã«ã®äœçœ®ã
9524-Yã¿ã€ã«ã®äœçœ®ã
åœç¶ãç°ãªãã·ã¹ãã ã§ã¯ãªã¯ãšã¹ãURLã®åœ¢åŒã¯ç°ãªããŸãã ã¿ã€ã«çªå·ãšã¹ã±ãŒã«ã®ä»£ããã«ã QUADããŒã䜿çšããŠã¿ã€ã«ããªã¯ãšã¹ãã§ããŸãã ã¿ã€ã«ãã¡ã€ã«ã¯ããµãŒããŒã«ãã£ãŠãã¡ã€ã«ã·ã¹ãã ããçŽæ¥ããŸãã¯httpãã³ãã©ãŒã䜿çšããŠã¯ã©ã€ã¢ã³ãã«éä¿¡ã§ããŸãã XãYãZã®ãªãã·ã§ã³ãæ€èšããŸãã
ã¿ã€ã«ã®æºåæé
- åãªããžã§ã¯ãã®ãžãªã¡ããªã«å¿ããã¿ã€ã«ã®ãªã¹ãã®åœ¢æã
- åãªããžã§ã¯ãã®ã¿ã€ã«ã®çæã
- äžæã®ã»ãããååŸããããã®ã¿ã€ã«ã®é¢é£ä»ãã
- ãã¡ã€ã«ã·ã¹ãã ã«ä¿åããŠããŸãã
䜿çšããæ©èœ
ã¿ã¹ã¯ãå®è£
ããã«ã¯ãã¿ã€ã«ã®XãYäœçœ®ããã³ã¹ã±ãŒã«çªå·ã«ãã£ãŠã¿ã€ã«ãžãªã¡ããªã圢æããæ©èœãå¿
èŠã«ãªããŸãã ãã®å Žåã®ã¿ã€ã«ãžãªã¡ããªã¯ã緯床ãšçµåºŠã§è¡šãããè§åºŠã®åº§æšã§ã¿ã€ã«ãèŠãé·æ¹åœ¢ã§ãã ãã®ãããªãžãªã¡ããªã®åœ¢æã¯ãSQLé¢æ°ãŸãã¯SQL CLRé¢æ°ã§å®è£
ã§ããŸãã SQL CLRé¢æ°ãšéåžžã®SQLé¢æ°ã®å®è¡æéã®éãã¯ç®ç«ã¡ãŸããã SQL CLRé¢æ°ã³ãŒãã¯ãæ·»ä»ãœãŒã¹ã³ãŒãã®Coords2PixelConversionã¯ã©ã¹ã«å®è£
ãããŠããŸãã
次ã®ãžãªã¡ããªã¯ããã®ã¿ã€ã«ã®èŒªéã§ããã€ãŸãããã®å¢çã«æ²¿ã£ãŠããŸãã ããã®ããŒã¯ã®åº§æšã¯çµåºŠãšç·¯åºŠã§ãã
ã¿ã€ã«ããŒããŒãžãªã¡ããª'POLYGON ((30.322265625 59.955010262062061, 30.322265625 59.949509172252277, 30.333251953125 59.949509172252277, 30.333251953125 59.955010262062061, 30.322265625 59.955010262062061))'
tile.GetTileBoundsïŒïŒã®ã¹ã«ã©ãŒSQLã³ãŒã tile.GetTileBounds(@level int, @x int, @y int) CREATE FUNCTION [tile].[GetTileBounds] (@level int, @x int, @y int) RETURNS geometry AS BEGIN DECLARE @res GEOMETRY = NULL IF @level IS NOT NULL AND @x IS NOT NULL AND @y IS NOT NULL BEGIN DECLARE @n1 FLOAT = PI() - 2.0 * PI() * @y / POWER(2.0, @level); DECLARE @n2 FLOAT = PI() - 2.0 * PI() * (@y + 1) / POWER(2.0, @level); DECLARE @top FLOAT = (180.0 / PI() * ATAN(0.5 * (EXP(@n1) - EXP(-@n1)))); DECLARE @bottom FLOAT = (180.0 / PI() * ATAN(0.5 * (EXP(@n2) - EXP(-@n2)))); DECLARE @tileWidth FLOAT = 360 / CONVERT(float, POWER(2, @level)) DECLARE @left FLOAT = @tileWidth * @x - 180, @right FLOAT = @tileWidth * (@x + 1) - 180 SET @res = geometry::STPolyFromText('POLYGON ((' + LTRIM(STR(@left, 25, 16)) + ' ' + LTRIM(STR(@top, 25, 16)) + ', ' + LTRIM(STR(@left, 25, 16)) + ' ' + LTRIM(STR(@bottom, 25, 16)) + ', ' + LTRIM(STR(@right, 25, 16)) + ' ' + LTRIM(STR(@bottom, 25, 16)) + ', ' + LTRIM(STR(@right, 25, 16)) + ' ' + LTRIM(STR(@top, 25, 16)) + ', ' + LTRIM(STR(@left, 25, 16)) + ' ' + LTRIM(STR(@top, 25, 16)) + '))', 0) END RETURN @res END
ãã®æ©èœã®äœ¿çšæ¹æ³ã«ã€ããŠã¯ããã®èšäºã®åŸåã§èª¬æããŸãã
ã¿ã€ã«ã®ãªã¹ããäœæããæ¹æ³ãæ€èšããŠãã ããã ããŸããŸãªãžãªã¡ããªã«å¯ŸããŠãã¿ã€ã«ã®ãªã¹ãã圢æããããã®ããŸããŸãªã¢ãããŒããéžæã§ããŸãã
æ¹æ³1ïŒ
ãã®ç¶æ³ã䜿çšããŸãã1ã€ã®ã¹ã±ãŒã«ã§ãªããžã§ã¯ããã¿ã€ã«ãšäº€å·®ããªãå Žåã倧ããæ°å€4ã®ã¹ã±ãŒã«ã§ã¯ããã§ãã¯å¯Ÿè±¡ã®ã¿ã€ã«ãšéãªãã¿ã€ã«ããªããžã§ã¯ããšäº€å·®ããŸããã ã€ãŸãã次ã®ã¹ã±ãŒã«ã«ç§»åãããšããåã®ã¹ã±ãŒã«ã®ã¿ã€ã«ããªããžã§ã¯ãã®ãžãªã¡ããªãšäº€å·®ããå Žåã«ã®ã¿ãã¿ã€ã«ããã§ãã¯ããŸãã ããã«ãããæ¹æ³2ã§å®è¡ãããäžèŠãªãã§ãã¯ããªããªããŸãã
æ¹æ³2ïŒ
å®éããã®æ¹æ³ã¯ææªã®ã·ããªãªã§ãã åãªããžã§ã¯ãã®å瞮尺ã«ã€ããŠã GEOMETRY :: STEnvelopeïŒïŒé¢æ°ã䜿çšããŠã¿ã€ã«ã®ãµãã»ããã決å®ãããã®ãµãã»ããã®ã¿ã€ã«ãšãªããžã§ã¯ãã®äº€å·®ã確èªããŸãã ãã®æ¹æ³ã¯ãããå€ãã®ã¿ã€ã«ããã§ãã¯ããããããç¹ã«é¢ç©ãŸãã¯é·ãã倧ãããªããžã§ã¯ãã®å Žåã¯å¹æãäœããªããŸãã
æ¹æ³3ïŒ
åãªããžã§ã¯ãã«ã€ããŠãã¿ã€ã«ã¡ãã·ã¥ã®ãžãªã¡ããªã圢æããã¡ãã·ã¥ãšãªããžã§ã¯ãã®ãžãªã¡ããªã®äº€å·®éšã§ããã€ã³ãã®ã»ãããååŸããŸãã ååŸããåãã€ã³ãã«ã€ããŠã2ã€ã®ã¿ã€ã«ãå®çŸ©ããã¿ã€ã«ã®æçµãªã¹ãã«è¿œå ããŸããããšãã°ã倧éžãééããè€éãªå°ççã©ã€ã³ã®å Žåãã¿ã€ã«ã®å¢çã«æ²¿ã£ãŠééããã°ãªãããšã®äº€ç¹ãèŠã€ãããããã®ãã€ã³ãããã¬ã³ããªã³ã°ããã¿ã€ã«ãæ¢ã«æ±ºå®ã§ããŸãã ã°ãªããã¯ãç·ãå«ãé·æ¹åœ¢é åã®å¢çå
ã«äœæãããåçŽç·ãšæ°Žå¹³ç·ã®ã»ããã§ãã ããã¯ããªããžã§ã¯ãã®é·æ¹åœ¢é åã®å¢çå
ã«ãããã¹ãŠã®ã¿ã€ã«ããã§ãã¯ãããããã¯ããã«å¹æçã§ãã
æåã®æ¹æ³ã«ã€ããŠè©³ãã説æããŸãã é åãæã€ãªããžã§ã¯ãã®ãžãªã¡ããªã®å Žåããªããžã§ã¯ããšã®äº€å·®ããã§ãã¯ããããã®ã¿ã€ã«ã®ã»ããã¯ããªããžã§ã¯ããšéãªãé·æ¹åœ¢ã®é åïŒbboxïŒã®æ¥µç«¯ãªã¿ã€ã«ã«å¶éã§ããŸãã
ãªããžã§ã¯ãã®ãžãªã¡ããªïŒ POINTãžãªã¡ããªã¿ã€ããé€ãïŒã«åŸã£ãŠãCLRã®åè§åœ¢ã¯MSSQLé¢æ°GEOMETRY :: STEnvelopeïŒïŒã«ãã£ãŠåœ¢æãããŸãã POINTãžãªã¡ããªãæã€ãªããžã§ã¯ãã®å Žåãé·æ¹åœ¢ã®é åãbboxã®å¢çãšããŠäœ¿çšãããå°å³äžã®ãªããžã§ã¯ãã®ã¢ã€ã³ã³ãšéãªããŸãã éè€ããã¢ã€ã³ã³ã®ãžãªã¡ããªãè¿ãGetImageBoundé¢æ°ã¯ã GoogleProjectionã¯ã©ã¹ã«å®è£
ãããŠããŸãã ãŸãã緯床ãšçµåºŠããã¯ã»ã«äœçœ®çªå·ã«å€æããã¡ãœãããå®è£
ããŠããŸãã é·æ¹åœ¢é åã®ã³ãŒããŒãã€ã³ãã®åº§æšã¯ã緯床ãšçµåºŠã§è¡šãããŸãã 次ã«ãçµæã®é·æ¹åœ¢ãã«ããŒããã¿ã€ã«ã®ãµãã»ãããååŸããŸãã ãããè¡ãã«ã¯ãå°ç座æšãé©åãªã¹ã±ãŒã«ã®ã¿ã€ã«çªå·ã«å€æããæ©èœãå¿
èŠã§ãã çµåºŠãšç·¯åºŠã§ã¿ã€ã«ã®Xäœçœ®ãšYäœçœ®ãååŸããã«ã¯ãåŸã§èª¬æããSQL CLRé¢æ°ãšã以äžã«ç€ºãSQLé¢æ°ã®äž¡æ¹ã䜿çšã§ããŸãã
tile.GetXTilePos((@Longitude FLOAT, @Zoom INT) tile.GetYTilePos((@Latitude FLOAT, @Zoom INT)
ã³ãŒããŒã¿ã€ã«ã®äœçœ®ã決å®ããåŸãæ€åºãããã³ãŒããŒã¿ã€ã«éã®é·æ¹åœ¢é åã«ãããã¹ãŠã®ã¿ã€ã«ã¯ã tile.fn_FetchGeometryTilesZoomDepthïŒïŒé¢æ°ã§ãªããžã§ã¯ãã®ãžãªã¡ããªãšã®äº€å·®ã«ã€ããŠãã§ãã¯ãããŸãã
çµåºŠãšã¹ã±ãŒã«çªå·ã®Xã¿ã€ã«äœçœ®ãååŸããSQLé¢æ° CREATE FUNCTION tile.GetXTilePos(@Longitude FLOAT, @Zoom INT) RETURNS INT AS BEGIN DECLARE @D FLOAT,@E FLOAT,@F FLOAT,@G FLOAT, @tileY INT, @tileX INT SET @D = 128 * POWER(2, @Zoom) SET @E = ROUND(@D + @Longitude * 256 / 360 * POWER(2, @Zoom), 0) SET @tileX = Floor(@E / 256); RETURN @tileX END
緯床ãšçž®å°ºçªå·ã®ã¿ã€ã«ã®Yäœçœ®ãååŸããæ©èœ CREATE FUNCTION tile.GetYTilePos(@Latitude FLOAT, @Zoom INT) RETURNS INT AS BEGIN DECLARE @A FLOAT, @B FLOAT, @C FLOAT, @D FLOAT, @E FLOAT, @F FLOAT, @G FLOAT, @tileY INT SET @D = 128 * POWER(2, @Zoom) SET @A = Sin(PI() / 180 * @Latitude) SET @B = -0.9999 SET @C = 0.9999 IF @A < @B SET @A = @B IF @A > @C SET @A = @C SET @F = @A SET @G = Round(@D + 0.5 * Log((1.0 + @F) / (1.0 - @F)) * (-256) * POWER(2, @Zoom) / (2 * PI()),0) SET @tileY = Floor(@G / 256) RETURN @tileY END
tile.fn_FetchGeometryTilesZoomDepthïŒïŒé¢æ°ã¯ããžãªã¡ããªãã«ããŒããæå°ã®é·æ¹åœ¢é åã®å·Šäžãšå³äžã®ã¿ã€ã«ãèšç®ããŸãã 次ã«ããã¹ããããã«ãŒãå
ã®å³ãšã¿ã€ã«ã®äº€å·®ç¹ã決å®ããããã«ããã®é åã®åã¿ã€ã«ã«å¯ŸããŠtile.fn_GetTilesByTileNumZoomDepthïŒïŒé¢æ°ã䜿çšããŸããå·Šããå³ãäžããäžãå·Šäžããå³äžã«ç§»åããŸãã ãã®é¢æ°ã¯ããªããžã§ã¯ãã®ãžãªã¡ããªãšã®äº€å·®ãå®çŸ©ãããŠããã¿ã€ã«ã®ãªã¹ããè¿ããŸãã
ã¿ã€ã«ã»ããæ©èœ CREATE FUNCTION tile.fn_FetchGeometryTilesZoomDepth ( @GeoData GEOMETRY, @Zoom INT, @Depth INT) RETURNS @retTiles TABLE ( Zoom INT, TileX INT, TileY INT) AS BEGIN DECLARE @Left FLOAT, @Right FLOAT, @Top FLOAT, @Bottom FLOAT DECLARE @CurrentXTile INT, @CurrentYTile INT, @Quanttiles INT DECLARE @Envelope GEOMETRY, @RightTop GEOMETRY, @LeftBottom GEOMETRY DECLARE @CurTileGeom GEOMETRY, @res GEOMETRY DECLARE @tiletop FLOAT,@tilebottom FLOAT,@tileleft FLOAT, @tileright FLOAT DECLARE @LeftTilePos INT,@RightTilePos INT,@TopTilePos INT DECLARE @BottomTilePos INT SET @envelope = @GeoData.STEnvelope() SET @RightTop = @envelope.STPointN(3) SET @LeftBottom = @envelope.STPointN(1) SET @Right = @RightTop.STX SET @Left = @LeftBottom.STX SET @Top = @RightTop.STY SET @Bottom = @LeftBottom.STY SET @LeftTilePos = tile.GetXTilePos( @Left,@Zoom) SET @RightTilePos = tile.GetXTilePos( @Right,@Zoom) SET @TopTilePos = tile.GetYTilePos( @Top,@Zoom) SET @BottomTilePos = tile.GetYTilePos( @Bottom,@Zoom) SET @CurrentXTile = @LeftTilePos WHILE @CurrentXTile <= @RightTilePos BEGIN SET @currentYTile = @TopTilePos WHILE @CurrentYTile <= @BottomTilePos BEGIN INSERT INTO @retTiles (Zoom, TileX, TileY) SELECT * FROM tile.fn_GetTilesByTileNumZoomDepth ( @GeoData, @Zoom, @CurrentXTile, @CurrentYTile, @Depth ) SET @CurrentYTile = @CurrentYTile + 1 END SET @CurrentXTile =@CurrentXTile + 1 END RETURN END
ã¿ã€ã«ãžãªã¡ããªãšãªããžã§ã¯ãã®ãžãªã¡ããªã®äº€å·®ã確èªããã«ã¯ãGEOMETRY :: STIntersectsïŒïŒé¢æ°ã䜿çšããŸãã ãªããžã§ã¯ãã®ãžãªã¡ããªãšã¿ã€ã«ã®ãžãªã¡ããªã亀差ããå Žåã以åã«äœæããtile.TileOverlapããŒãã«ã«ãšã³ããªãè¿œå ãã次ã®ã¹ã±ãŒã«ã®4ã€ã®ã¿ã€ã«ã«å¯ŸããŠåãé¢æ°ãååž°çã«åŒã³åºããŸãããã©ã¡ãŒã¿@Depthã1æžãããŠãçŸåšã®ã¹ã±ãŒã«ãã«ããŒããŸãã 亀差ãã§ãã¯ã¯ãé¢æ°tile.fn_FetchGeometryTilesZoomDepthïŒïŒã§å®è£
ãããŸãã
æå®ãããã¿ã€ã«ã®ãžãªã¡ããªã«ããã¿ã€ã«ã®ãªã¹ãã®ååŸ CREATE FUNCTION tile.fn_GetTilesByTileNumZoomDepth ( @GeoData GEOMETRY, @Zoom INT, @tileX INT, @tileY INT, @Depth INT) RETURNS @retTiles TABLE ( Zoom INT, X INT, Y INT) AS BEGIN DECLARE @currentTile TABLE ( Zoom INT, X INT, Y INT) IF GEOGRAPHY::STGeomFromWKB([tile].[GetTileBounds](@Zoom, @tileX, @tileY).STAsBinary(),4326).STIntersects(GEOGRAPHY::STGeomFromWKB(@GeoData.MakeValid().STUnion(@GeoData.STStartPoint()).STAsBinary(),4326)) = 1 BEGIN INSERT INTO @currentTile SELECT @Zoom , @tileX , @tileY INSERT INTO @retTiles SELECT d.zoom, dX, dY FROM @currentTile c CROSS APPLY (SELECT * FROM [tile].[fn_GetTilesForObjectByTileNumZoomDepth]( @GeoData , c.Zoom + 1, cX * 2, cY * 2, @Depth - 1) WHERE @Depth > 0) AS d INSERT INTO @retTiles SELECT d.zoom, dX, dY FROM @currentTile c CROSS APPLY (SELECT * FROM [tile].[fn_GetTilesForObjectByTileNumZoomDepth]( @GeoData , c.Zoom + 1, cX * 2 + 1, cY * 2, @Depth - 1) WHERE @Depth > 0) AS d INSERT INTO @retTiles SELECT d.zoom, dX, dY FROM @currentTile c CROSS APPLY (SELECT * FROM [tile].[fn_GetTilesForObjectByTileNumZoomDepth]( @GeoData , c.Zoom + 1, cX * 2, cY * 2 + 1, @Depth - 1) WHERE @Depth > 0) AS d INSERT INTO @retTiles SELECT d.zoom, dX, dY FROM @currentTile c CROSS APPLY (SELECT * FROM [tile].[fn_GetTilesForObjectByTileNumZoomDepth]( @GeoData , c.Zoom + 1, cX * 2 + 1, cY * 2 + 1, @Depth - 1) WHERE @Depth > 0) AS d INSERT INTO @retTiles SELECT * FROM @currentTile END RETURN END
1ã€ã®ãªããžã§ã¯ãã®ã¿ã€ã«ãäœæããå¿
èŠãããå Žåãã¿ã€ã«ã®ã»ããã¯äžæã§ãããããã¿ã€ã«çªå·ãããã«tile.TileããŒãã«ã«æžã蟌ãããšãã§ããŸãã è€æ°ã®ãªããžã§ã¯ãã®ãžãªã¡ããªã亀差ããã¿ã€ã«ã圢æããã«ã¯ãç°ãªããªããžã§ã¯ãçšã«äœæãããäºãã«éãªãåãã¿ã€ã«ãçµåããå¿
èŠããããŸãã
tile.fn_GetTilesByTileNumZoomDepthïŒïŒé¢æ°ã¯ãæå®ãããæ·±ããèæ
®ããŠããªããžã§ã¯ããžãªã¡ããªãšã¹ã±ãŒã«ã¿ã€ã«ã®äº€å·®ããã§ãã¯ããŸãã @Depthãã©ã¡ãŒã¿ãŒã¯ã¹ãã£ã³ã®æ·±ãã瀺ããŸããããšãã°ã @ Zoom = 2ããã³@Depth = 1ã®å Žåãã¹ã±ãŒã«2ã¿ã€ã«ããã§ãã¯ããã亀差ãããå Žåã4ã¹ã±ãŒã«3ã¿ã€ã«ããã§ãã¯ãããŸãã ã GEOMETRYããŒã¿ã¿ã€ããGEOGRAPHYã«å€æããåŸã亀差ãã§ãã¯ãå®è¡ããå¿
èŠããããŸããGEOGRAPHYããŒã¿ã¿ã€ãã®å Žåã4326æ圱ã®ãžãªã¡ããªãã€ã³ãã®ãã¹ãŠã®åº§æšãèæ
®ããŠãã§ãã¯ãå®è¡ããããããããã¯éèŠã§ãã
ããªã©ã€ã³ã®äŸ
ãµã³ã¯ãããã«ãã«ã¯ã®äžå¿éšãšã¢ã¹ã¯ã¯ã®äžå¿éšãçµã¶å£ããã¿ã€ã«ãå
¥æããããšããŸãããã é·ãã¯çŽ800 kmã§ãã å£ããå±
äœå°ãééããŸãïŒããŽãŽãã-ãŽã£ã·ã¥ããŒãŽã©ãããã¯-ãããªã
ãµã³ã¯ãããã«ãã«ã¯ããã¢ã¹ã¯ã¯ãŸã§ã®ç Žç·ã®åœ¢ç¶ 'LINESTRING( 30.381113 59.971474, 31.26002 58.539215, 34.564158 57.591722, 35.915476 56.876838,37.622242 55.773125)'
ã¹ã±ãŒã«3ãã17ã®ãã®ãžãªã¡ããªã®å Žåãã¿ã€ã«ã®åèš11076ãååŸããŸããã¹ã±ãŒã«ã®ãžãªã¡ããªãšäº€å·®ããã¿ã€ã«ã®æ°ã®ååžãè¡š1ã«ç€ºããŸã
è¡š1-ã¹ã±ãŒã«ã¬ãã«ã«ããã¿ã€ã«æ°ã®ååžã¹ã±ãŒã« | ã¿ã€ã«æ° |
---|
3 | 1 |
4 | 2 |
5 | 3 |
6 | 4 |
7 | 7 |
8 | 12 |
9 | 23 |
10 | 45 |
11 | 88 |
12 | 174 |
13 | 347 |
14 | 692 |
15 | 1383 |
16 | 2766 |
17 | 5529 |
3çªç®ãš4çªç®ã®ã¹ã±ãŒã«ã§åŸãããã¿ã€ã«ãå³1ã«ç€ºããŸãã
å³1-ã¿ã€ã«ïŒ3/4/2ããã³4/9/4
åã¹ã±ãŒã«ã«å¯ŸããŠãã¿ã€ã«ã®ãµãã»ãããçæãããåã¿ã€ã«ãäŸå€ãªããã§ãã¯ãããŸãã 4ã5ã®ã¹ã±ãŒã«ã§ã¯ããªããžã§ã¯ãã®ãžãªã¡ããªã§GEOMETRY :: STEnvelopeïŒïŒé¢æ°ã«ãã£ãŠååŸãããé·æ¹åœ¢ã®é åã«åãŸãã¿ã€ã«ã®æ°ã¯å°ãªããªããŸãã 4çªç®ã®ã¹ã±ãŒã«ã«ã¯åèš2 ^ 4 * 2 ^ 4 = 256ã®ã¿ã€ã«ããããŸãããããã16çªç®ãš17çªç®ã®ã¹ã±ãŒã«ã§ã¯ãããã«å€ãã®ã¿ã€ã«ããã§ãã¯ããå¿
èŠããããŸãã æåã®æ¹æ³ã§ãäžèŠãªããã§ãã¯ãé€å€ãããšãäœæ¥ãã¹ããŒãã¢ããããŸãã ãã€ã³ããžãªã¡ããªïŒ POINT ïŒãæã€ãªããžã§ã¯ãã®å Žåãäž¡æ¹ã®æ¹æ³ã®å¹çã¯åãã«ãªããŸãã
亀差ç¹ãã§ãã¯
GEOMETRY :: STIntersectsïŒïŒé¢æ°ã¯ãGEOMETRYããŒã¿åã®STIntersectsïŒïŒé¢æ°ãå¹³é¢å
ã®åº§æšã§æ©èœãã緯床ãšçµåºŠã¯ãã«ã«ã座æšã§ã¯ãªãããããªããžã§ã¯ããžãªã¡ããªãšã¿ã€ã«ãžãªã¡ããªã®äº€å·®ã決å®ã§ããŸããã ãããã£ãŠã亀ç¹ã確å®ã«å€å¥ããã«ã¯ã GEOMETRYã¿ã€ããGEOGRAPHYã¿ã€ãã«å€æããŸãã GEOMETRYããŒã¿åãšã¯ç°ãªãã GEOGRAPHYããŒã¿åã§ã¯ããªãŽã³ãªã³ã°ã®åããå¿
èŠã§ããããšã«æ³šæããŠãã ããã å€èŒªã®åº§æšã¯åæèšåãã«ç§»åããå¿
èŠããããŸãã å
åŽã®ãªã³ã°ïŒãã€ãïŒã®å Žåã座æšã¯æèšåãã«ãªã¹ãããå¿
èŠããããŸãã å°çã®åœ¢æã«ããããšã©ãŒãåé¿ããããã«ã GEOMETRY :: MakeValidïŒïŒããã³GEOMETRY :: STUnionïŒïŒé¢æ°ã䜿çšããŠãGEOMETRYåãGEOGRAPHYåã«å€æãããšãã«æ£ãã座æšã·ãŒã±ã³ã¹ãååŸããŸãã å°çãäœæããå Žåããã©ã¡ãŒã¿ãŒSRID = 4326ãæå®ããŸããããã¯ã座æšã«å¯Ÿãããã¹ãŠã®æäœãçé¢ã·ã¹ãã ã§å®è¡ãããããšãæå³ããŸã ã
ãã®æ®µéã§ãã¿ã€ã«ã®ãªã¹ããã€ãŸã3ã€ã®åãæã€ããŒãã«ãZãXãYã mapnik åã¬ã³ããªã³ã°ããã°ã©ã ã䜿çšããŠãããã«äœæ¥ãè¡ãããšãã§ããŸããããã«ããããªããžã§ã¯ãã®ç»åã§ã¿ã€ã«ã圢æã§ããŸãã Microsoft SQL ServerããŒã¿ããŒã¹ãžã®mapnikã¢ã¯ã»ã¹ãæŽçããã«ã¯ãããçšåºŠã®åªåãå¿
èŠã§ãã mapnikã§ã¿ã€ã«ãçæããæºåã«ã¯ã次ã®æé ãå«ãŸããŸãã
â¢ã¬ã³ããªã³ã°çšã®ãªããžã§ã¯ãã®ã¹ã¿ã€ã«ã宣èšããŸãã
â¢ãªããžã§ã¯ãã®ãžãªã¡ããªã®ããŒã¿ãœãŒã¹ã®èª¬æã
â¢ãã¹ãŠã®ã¿ã€ã«ãé£ç¶ããŠçæãããªãããã«ãã¬ã³ããªã³ã°çšã®ã¿ã€ã«ã®ãªã¹ããå«ãããŒãã«ãæå®ããŸãã
MS SQL Server 2008ããŒã¿ããŒã¹å
ã«ã¿ã€ã«ãçæããŸããããè¡ãã«ã¯ãããŒã¿ããŒã¹ã«æ ŒçŽãããŠãããžãªã¡ããªãæäœããããã®ããã€ãã®CLRé¢æ°ãå®è£
ããå¿
èŠããããŸãã å¿
èŠãšãªãäž»ãªæ©èœã¯ä»¥äžã®ãšããã§ãã
- tile.IconTileïŒïŒã
- tile.ShapeTileïŒïŒã
- tile.TileAggïŒïŒã
- tile.SaveToFolderByZoomXYïŒïŒ
ã
ã¿ã€ã«ç»åãä¿åããããã®ããŒãã«
å³2ã¯ãã¬ã³ããªã³ã°çšã®ã¿ã€ã«ã®ãªã¹ããä¿åãããŠããããŒãã«æ§é ã瀺ããŠããŸãã ãããã®ããŒãã«ã®[ããŒã¿]ãã£ãŒã«ãã«ã¯ãã¿ã€ã«äžã«èœäžãããªããžã§ã¯ãã®ç»åãå«ãPNGç»åãä¿åãããŸãã ããŒãã«ã«å€æ°ã®ç»åãä¿åããŠåŠçãããšãããã©ãŒãã³ã¹ã«åœ±é¿ããå¯èœæ§ããããŸãã ãã®ã¿ã¹ã¯ã®å Žåãããé©åãªãªãã·ã§ã³ã¯ãããŒãã«å
ã«åœ¢æãããåãªããžã§ã¯ãã®ã¿ã€ã«ã®ãªã¹ãã䜿çšããŠããŒã¿ããŒã¹å€ã«ã¿ã€ã«ã€ã¡ãŒãžãäœæãããã¡ã€ã«ã·ã¹ãã ã«ä¿åããããšã§ãã
å³2-ã¿ã€ã«ã®ãªã¹ããä¿åããããã®ããŒãã«
ã¿ã€ã«ã«ã¢ã€ã³ã³ãé
眮ãã
ã¿ã€ã«äžã«ã¢ã€ã³ã³ãé
眮ããããã®ã¢ã«ãŽãªãºã ãåæããŠã¿ãŸãããïŒãžãªã¡ããªã®çš®é¡POINTïŒã
ãããªããžã§ã¯ãã®ç·¯åºŠãšçµåºŠããããçŸåšã®ã¹ã±ãŒã«ã®ã¿ã€ã«ã®ãªã¹ããããããã®äžã«ã¢ã€ã³ã³ãéããããŠããŸãã ã¿ã€ã«ã®ãªã¹ãã®åœ¢æã¯ä»¥åã«èª¬æãããŠããŸãã ã¿ã€ã«äžã®ã¢ã€ã³ã³ã®äœçœ®ã®èšç®ã¯ã次ã®ã¢ã¯ã·ã§ã³ã§æ§æãããŸãã
1.æåã«ã緯床ãšçµåºŠã絶察ãã¯ã»ã«åº§æšã«å€æããŸãã
2.次ã«ã䜿çšå¯èœãªãªã¹ãã®åã¿ã€ã«ã«ã€ããŠãçŸåšã®ã¹ã±ãŒã«ã§ãå·Šäžé
ã®çµ¶å¯Ÿãã¯ã»ã«åº§æšãèšç®ããŸãã ã¿ã€ã«ã®å·Šäžã®ãã¯ã»ã«ïŒpixXtileãpixYtileïŒã®åº§æšã¯ãã¿ã€ã«äœçœ®ã®xçªå·ãšyçªå·ã«ãã®ãµã€ãºïŒãã®å Žåã¯256ãã¯ã»ã«ïŒãæããŠèšç®ãããŸãã
3.ãªããžã§ã¯ãã®çµ¶å¯Ÿãã¯ã»ã«åº§æšãšã¿ã€ã«ã®å·Šäžé
ã®çµ¶å¯Ÿãã¯ã»ã«åº§æšã®å·®ã¯ãGetPixelXOnTileïŒïŒããã³GetPixelXOnTileïŒïŒé¢æ°ã§æ±ºå®ãããŸãã ãã®éãã¯ãã¿ã€ã«äžã®ã¢ã€ã³ã³ã®äžå¿ã®çžå¯Ÿãã¯ã»ã«åº§æšã§ãã
4.ã¿ã€ã«äžã«ã¢ã€ã³ã³ãæç»ããã«ã¯ãã¿ã€ã«äžã®æç»é åã®å¢çããã¯ã»ã«åäœã§ååŸããå¿
èŠããããããã«æ¿å
¥ãè¡ãããŸãã ã¿ã€ã«äžã®ãªããžã§ã¯ãã®çžå¯Ÿãã¯ã»ã«åº§æšã¯ãåã®æé ã§ååŸãããŸããã ããã§ãã¢ã€ã³ã³ã®ãµã€ãºã«ãã£ãŠãæ¿å
¥ããé·æ¹åœ¢ã®é åã®å¢çã決ãŸããŸãã
5.ã¿ã€ã«ã«ã¢ã€ã³ã³ãæç»ããŸãã
ã¿ã€ã«ã«ã¢ã€ã³ã³ãé
眮ããCLR SQLé¢æ° [Microsoft.SqlServer.Server.SqlFunction] public static SqlBinary IconTile(SqlBinary image, SqlInt32 zoom, SqlDouble Lon, SqlDouble Lat, SqlInt32 xTile, SqlInt32 yTile, SqlDouble scale) { SqlBinary result = null; using (Icon2TileRendering paster = new Icon2TileRendering()) { using (MemoryStream ms = new MemoryStream()) { ms.Write(image.Value, 0, image.Length); SetBeginPosition(ms); paster.PasteFromStreamScaledImageToTile((int)zoom, (double)Lon, (double)Lat, (int)xTile, (int)yTile, (double)scale, ms); result = paster.GetBytes(); } } return result; }
æç»é åã®å¢çç·ãååŸããŸã #region [Pixel Position Calculation] Rectangle GetTargetBound(int zoom, double Lon, double Lat, int xTile, int yTile, int width, int height) { int xPix = _conv.FromLongitudeToXPixel(Lon, zoom); int yPix = _conv.FromLatitudeToYPixel(Lat, zoom); int xPos = xPix - xTile * TILE_SIZE; int yPos = yPix - yTile * TILE_SIZE; int halfWidth = width / 2; int halfHeight = height / 2; return new Rectangle(xPos - halfWidth, yPos - halfHeight, width, height } int GetPixelXOnTile(int zoom, double Lon, int xTile) { return _conv.FromLongitudeToXPixel(Lon, zoom) - xTile * TILE_SIZE; } int GetPixelYOnTile(int zoom, double Lat, int yTile) { return _conv.FromLatitudeToYPixel(Lat, zoom) - yTile * TILE_SIZE; } #endregion [Pixel Position Calculation]
ã¢ã€ã³ã³ãã¿ã€ã«ã«ã³ããŒ
ã¿ã€ã«ã®é¢é£ä»ã
è€æ°ã®ãªããžã§ã¯ãã®ã¢ã€ã³ã³ãåãã¿ã€ã«ã«éããããšãã§ããŸãã ãã¹ãŠã®ãªããžã§ã¯ãã§ã¿ã€ã«ãååŸããã«ã¯ããŸãåãªããžã§ã¯ãã®ã¿ã€ã«ãäœæããŠããããããã1ã€ã«ããŒãžããŸãã ãã®ãããªãœãªã¥ãŒã·ã§ã³ã¯ãããŒã¿ããŒã¹ããŒãã«ã®è¡ãã°ã«ãŒãåããããšã§å®è£
ã§ããŸã;ãã®ããã«ãCLRé¢æ°éèštile.TileAggïŒïŒãäœæãã ãã¿ã€ã«ã1ã€ã«çµåããŸããã ãã®ãœãªã¥ãŒã·ã§ã³ã«ã¯ãã€ãã¹ã1ã€ãããŸããã¿ã€ã«ã§åãè©°ããããåãªããžã§ã¯ãã«å¯ŸããŠãã¿ã€ã«ã€ã¡ãŒãžãæ ŒçŽããBINARYãã£ãŒã«ããæã€åå¥ã®ã¬ã³ãŒããæ ŒçŽãããã®ãªããžã§ã¯ãã®ã¿ãéžæãããããã倧éã®ã¡ã¢ãªãå¿
èŠã«ãªãããã§ãã ããé©åãªè§£æ±ºçã¯ãã¿ã€ã«ã®1ã€ã®ã€ã³ã¹ã¿ã³ã¹ã䜿çšããã¿ã€ã«äžã«ãããªããžã§ã¯ãã®ãã¹ãŠã®ã¢ã€ã³ã³ãåžžã«è¡šç€ºããããšã§ãã ãããã£ãŠãã¡ã¢ãªã®æ¶è²»ãå°ãªããªããŸãã ãã®å Žåãã°ã«ãŒãåãããã®ã¯äœããããŸããã ã°ã«ãŒãåã䜿çšãããã
ããŒãã«ã«ã¿ã€ã«ã®äœçœ®ãšã¢ã€ã³ã³ã«æãããã¿ã€ã«ç»åãå
¥åãã CREATE PROC [tile].[FillObjectTilesIntersection]( @StartZoom INT, @EndZoom INT) AS BEGIN DECLARE @CurrentZoom INT SET @CurrentZoom = @StartZoom WHILE @CurrentZoom <= @EndZoom BEGIN INSERT INTO tile.Tile (X,Y,Data,Zoom) SELECT t.TileX,t.TileY, [tile].[TileAgg] (tile.IconTile(i.Data, @CurrentZoom,o.Longitude,o.Latitude,t.tileX,t.tileY, 1.0) ),@CurrentZoom AS Zoom FROM tile.Shape o INNER JOIN tile.[Image] i ON i.ImageID = o.ImageID CROSS APPLY tile.fn_FetchObjectTiles(tile.GetIconBoundForZoom(o.Longitude, o.Latitude, 64, 64, @CurrentZoom, 0),@CurrentZoom) t WHERE o.TypeID = @TypeID GROUP BY t.TileX,t.TileY SET @CurrentZoom = @CurrentZoom + 1 END END
ãªããžã§ã¯ãã®ãœãŒã¹ãšããŠããªããžã§ã¯ãã®åº§æšãšã Binaryã¿ã€ãã®ãã£ãŒã«ãã®tile.ImageããŒãã«ã«ä¿åãããŠããã¢ã€ã³ã³ã®ç»åã®èå¥åãå«ãtile.ObjectããŒãã«ã䜿çšããŸãã
ã¢ã€ã³ã³ãçµåºŠ30.381113ããã³ç·¯åºŠ59.971474ã«é
眮ããŠã¿ã€ã«3/4/2ããã³4/9/4ã圢æããããã®ã¹ã¯ãªãã DECLARE @Image VARBINARY(MAX) SELECT TOP (1) @image = ( SELECT * FROM OPENROWSET(BULK N'd:\media\icons\pin_orange.png', SINGLE_BLOB) As tile) SELECT [tile].[SaveToFolderByZoomXY]([tile].[IconTile](@image, 3,30.381113, 59.971474, 4, 2, 1.0), N'D:\Tiles\',3,4,2) SELECT [tile].[SaveToFolderByZoomXY]([tile].[IconTile](@image, 4,30.381113, 59.971474, 9, 4, 1.0), N'D:\Tiles\',4,9,4)
å³3-åä¿¡ããã¿ã€ã«ãšã¢ã€ã³ã³
ã¿ã€ã«äžã®ãžãªã¡ããªã®æç»
ããªã©ã€ã³ïŒPOLYLINEãMULTIPOLYLINEïŒã®å Žåãã¿ã€ã«ãžãªã¡ããªãããªã©ã€ã³ãžãªã¡ããªãšçµã¿åãããŠãã¿ã€ã«é åå€ã®ããªã©ã€ã³ã®äžéšãé€å€ãããããã«ããŸãã 茪éãšåœ±ä»ãé åã決å®ããã¢ã«ãŽãªãºã ã¯ãé åãæã€ãžãªã¡ããªãã€ãŸãPOLYGONãŸãã¯MULTIPOLYGON ã POLYGONãŸãã¯MULTYPOLYGONãå«ãGEOMETRYCOLLECTIONã«é©çšã§ããŸãã ãã®ã¢ã«ãŽãªãºã ã¯ShapeToTileRenderingã¯ã©ã¹ã«å®è£
ãããŠããã次ã®æé ãå«ãŸããŠããŸãã
1.ãžãªã¡ããªã®åº§æšïŒç·¯åºŠãçµåºŠïŒã¯ã緯床ãçµåºŠããã¯ã»ã«PSG3857ïŒGoogleãããžã§ã¯ã·ã§ã³ïŒã«å€æããåŒã䜿çšããŠã¹ã±ãŒã«ãèæ
®ããŠãã¯ã»ã«åº§æšã«å€æãããçµæã®ãžãªã¡ããªã®å座æšããã¿ãŒã²ããã¿ã€ã«ã®å·Šäžã®ãã¯ã»ã«ã®åº§æšãåŒããŸãã ãããããžãªã¡ããªïŒ A ïŒãååŸããŸãã ãããã®ã¢ã¯ã·ã§ã³ã¯ãé¢æ°ConvertToZoomedPixelZeroedByTileGeometryïŒpolyãZãXãYïŒã§å®è£
ãããŸã
2.ã¿ã€ã«ã®ãžãªã¡ããªïŒ B ïŒã¯ãã¹ã±ãŒã«ãèæ
®ããŠãã¯ã»ã«åº§æšã§åœ¢æãããŸã
3.ã¿ã€ã«ã®ãã¯ã»ã«ãžãªã¡ããªïŒ B ïŒãšãªããžã§ã¯ãã®ãžãªã¡ããªïŒ A ïŒã®äº€å·®ïŒ STIntersection ïŒã«ãã£ãŠååŸããã圢ææžã¿ãžãªã¡ããªïŒ C ïŒ
4.ãžãªã¡ããªã®èŒªéïŒ C ïŒãšã¿ã€ã«ã®ãžãªã¡ããªã®èŒªéïŒ B ïŒã®äº€å·®ã®çµæãšããŠåŸããããžãªã¡ããªïŒ D ïŒã圢æãããŸããã¿ã€ã«ã®å¢çã«æ²¿ã£ãŠãã¿ã€ã«å
ã®ããªãŽã³ã®æ³å®ã·ã§ãŒãã£ã³ã°ãšãªã¢ã«æ¥ããã©ã€ã³ãååŸããŸãã æžç®ã®çµæãšããŠåŸããããžãªã¡ããªïŒ E ïŒã¯ã .STDifferenceïŒother_geometryïŒé¢æ°ã䜿çšããŠåœ¢æãããŸã
5.ãžãªã¡ããªïŒ E ïŒã¯æç»çšã®èŒªéã§ãé¢æ°ïŒ
6.ãžãªã¡ããªããªãŽã³ãå¡ãã€ã¶ãããŸãïŒ C ïŒ-å¡ãã€ã¶ãããé åãååŸãããŸã
7.ããªãŽã³ã®ïŒ E ïŒèŒªéã®ãžãªã¡ããªã¯ãã¿ã€ã«ã®å¢çãšã®äº€å·®ãé€å»ããåŸã«æç»ãããŸã
8.çŸåšã®ãªããžã§ã¯ãã®ãã¹ãŠã®ã¿ã€ã«ã«ã€ããŠæé 1ã7ãç¹°ãè¿ããã¿ã€ã«ã«ä¿åããŸããTileOverlapããŒãã«
3 15- X 19144 Y 9524. T-SQL . , :
SELECT [tile].[GetTileBounds](15,19144,9524).ToString()
:
'POLYGON ((30.322265625 59.955010262062061, 30.322265625 59.949509172252277, 30.333251953125 59.949509172252277, 30.333251953125 59.955010262062061, 30.322265625 59.955010262062061))'
, . . . , , 6367 . , ( ), , . , . , 360 90 , . , c , . :
SELECT [tile].[fn_GetCircleSegment](30.3277587890625, 59.952259717159905,0,360,440,90)
CREATE FUNCTION [tile].[fn_ GetCircleSegment] (@X float, @Y float, @azimuth float, @angle float, @distance float, @step FLOAT) RETURNS geometry WITH EXEC AS CALLER AS BEGIN IF @X IS NULL OR @Y IS NULL OR @azimuth IS NULL OR ISNULL(@angle, 0) = 0 OR ISNULL(@distance, 0) <= 0 RETURN NULL DECLARE @sectorStepAngle FLOAT SET @sectorStepAngle = @step IF ABS(@angle) > 360 SET @angle = 360 DECLARE @pointsStr VARCHAR(MAX) DECLARE @firstPointsStr VARCHAR(MAX) DECLARE @earthRadius FLOAT DECLARE @lat FLOAT DECLARE @lon FLOAT DECLARE @d FLOAT IF ABS(@angle) < 360 SET @pointsStr = LTRIM(STR(@X, 25, 16)) + ' ' + LTRIM(STR(@Y, 25, 16)) ELSE SET @pointsStr = '' SET @earthRadius = 6367 SET @lat = RADIANS(@Y) SET @lon = RADIANS(@X) SET @d = (@distance / 1000) / @earthRadius DECLARE @angleStart FLOAT DECLARE @angleEnd FLOAT SET @angleStart = @azimuth - @angle / 2; SET @angleEnd = @azimuth + @angle / 2; DECLARE @pointsCount INT SET @pointsCount = FLOOR(@angle / @sectorStepAngle) DECLARE @brng FLOAT DECLARE @latRadians FLOAT DECLARE @lngRadians FLOAT DECLARE @ptX FLOAT DECLARE @ptY FLOAT DECLARE @i INT SET @i = 0 DECLARE @addPrefix TINYINT IF ABS(@angle) < 360 SET @addPrefix = 1 ELSE SET @addPrefix = 0 WHILE @i <= @pointsCount BEGIN SET @brng = RADIANS(@angleStart + @i * @sectorStepAngle); SET @latRadians = ASIN(SIN(@lat) * COS(@d) + COS(@lat) * SIN(@d) * COS(@brng)); SET @lngRadians = @lon + ATN2(SIN(@brng) * SIN(@d) * COS(@lat), COS(@d) - SIN(@lat) * SIN(@latRadians)); SET @ptX = 180.0 * @lngRadians / PI(); SET @ptY = 180.0 * @latRadians / PI(); IF @addPrefix = 1 BEGIN SET @pointsStr += ', ' + LTRIM(STR(@ptX, 25, 16)) + ' ' + LTRIM(STR(@ptY, 25, 16)) END ELSE BEGIN SET @pointsStr += LTRIM(STR(@ptX, 25, 16)) + ' ' + LTRIM(STR(@ptY, 25, 16)) SET @addPrefix = 1 END IF @i = 0 SET @firstPointsStr = LTRIM(STR(@ptX, 25, 16)) + ' ' + LTRIM(STR(@ptY, 25, 16)) IF @i = @pointsCount AND (@angleStart + @pointsCount * @sectorStepAngle) < @angleEnd BEGIN SET @brng = RADIANS(@angleEnd); SET @latRadians = ASIN(SIN(@lat) * COS(@d) + COS(@lat) * SIN(@d) * COS(@brng)); SET @lngRadians = @lon + ATN2(SIN(@brng) * SIN(@d) * COS(@lat), COS(@d) - SIN(@lat) * SIN(@latRadians)); SET @ptX = 180.0 * @lngRadians / PI(); SET @ptY = 180.0 * @latRadians / PI(); SET @pointsStr = @pointsStr + ', ' + LTRIM(STR(@ptX, 25, 16)) + ' ' + LTRIM(STR(@ptY, 25, 16)) END SET @i = @i + 1 END IF ABS(@angle) < 360 SET @pointsStr += ', ' + LTRIM(STR(@X, 25, 16)) + ' ' + LTRIM(STR(@Y, 25, 16)) ELSE SET @pointsStr += ', ' + @firstPointsStr RETURN geometry::STPolyFromText('POLYGON ((' + @pointsStr + '))', 0) END GO
, CLR , . .
() DECLARE @bbox GEOMETRY DECLARE @octagon GEOMETRY SELECT @bbox = [tile].[GetTileBounds](15,19144,9524), @octagon = [tile].[fn_GetCircleSegment](30.3277587890625, 59.952259717159905,0,360,440,90)
30.3277587890625, 59.952259717159905 â ;
, :
SELECT @bbox.STIntersection(@octagon)
:
'POLYGON ((30.3253442162734 59.949509172234684, 30.3301733618516 59.949509172234684, 30.333251953125 59.9510505967796, 30.333251953125 59.953468509045528, 30.330173073498937 59.955010262085125, 30.325344504626063 59.955010262085125, 30.322265625 59.953468509045528, 30.322265625 59.9510505967796, 30.3253442162734 59.949509172234684))'
, :
X Y SELECT [tile].[GetPixelXPosFromLongitude](30.3253442162734,15), [tile].[GetPixelYPosFromLatitude](59.949509172234684,15) , [tile].[GetPixelXPosFromLongitude](30.3301733618516,15), [tile].[GetPixelYPosFromLatitude]( 59.949509172234684,15) , [tile].[GetPixelXPosFromLongitude](30.333251953125,15), [tile].[GetPixelYPosFromLatitude]( 59.9510505967796,15) , [tile].[GetPixelXPosFromLongitude](30.333251953125,15), [tile].[GetPixelYPosFromLatitude]( 59.953468509045528,15) , [tile].[GetPixelXPosFromLongitude](30.330173073498937,15), [tile].[GetPixelYPosFromLatitude]( 59.955010262085125,15) , [tile].[GetPixelXPosFromLongitude](30.325344504626063,15), [tile].[GetPixelYPosFromLatitude]( 59.955010262085125,15) ,[tile].[GetPixelXPosFromLongitude](30.322265625,15), [tile].[GetPixelYPosFromLatitude]( 59.953468509045528,15) , [tile].[GetPixelXPosFromLongitude](30.322265625,15), [tile].[GetPixelYPosFromLatitude]( 59.9510505967796,15) , [tile].[GetPixelXPosFromLongitude](30.3253442162734,15), [tile].[GetPixelYPosFromLatitude]( 59.949509172234684,15)
| | X 15- | Y 15- |
---|
30.3253442162734 | 59.949509172234684 | 4900936 | 2438400 |
30.3301733618516 | 59.949509172234684 | 4901048 | 2438400 |
30.333251953125 | 59.9510505967796 | 4901120 | 2438328 |
30.333251953125 | 59.953468509045528 | 4901120 | 2438216 |
30.330173073498937 | 59.955010262085125 | 4901048 | 2438144 |
30.325344504626063 | 59.955010262085125 | 4900936 | 2438144 |
30.322265625 | 59.953468509045528 | 4900864 | 2438216 |
30.322265625 | 59.9510505967796 | 4900864 | 2438328 |
30.3253442162734 | 59.949509172234684 | 4900936 | 2438400 |
:
SELECT GEOMETRY::STGeomFromText('LINESTRING(4900936 2438400, 4901048 2438400, 4901120 2438328, 4901120 2438216, 4901048 2438144, 4900936 2438144, 4900864 2438216, 4900864 2438328, 4900936 2438400 )',0)
( ) 3 , , 4 .
4 â
( D ) , , , 5 , ( ) ( D ), 5.
.
( E ):
SELECT GEOMETRY::STGeomFromText('MULTILINESTRING((4901048 2438400, 4901120 2438328),( 4901120 2438216, 4901048 2438144),( 4900936 2438144, 4900864 2438216), (4900864 2438328, 4900936 2438400) )',0)
5 â ( )
T-SQL PNG Z/X/Y. .
DECLARE @bbox GEOMETRY DECLARE @rhomb GEOMETRY DECLARE @image VARBINARY(MAX) SELECT @bbox = [tile].[GetTileBounds](15,19144,9524), @rhomb = [tile].[fn_GetSector](30.3277587890625, 59.952259717159905,0,360,440,90) SET @image = [tile].[ShapeTile]( @octagon,15,19144,9524,'4400B050','9601B41E',3) SELECT[tile].[SaveToFolderByZoomXY](@image,'d:/tiles',15,19144,9524) SET @image = [tile].[ShapeTile]( @octagon,15,19143,9524,'4400B050','9601B41E',3) SELECT[tile].[SaveToFolderByZoomXY](@image,'d:/tiles',15,19143,9524) SET @image = [tile].[ShapeTile]( @octagon,15,19145,9524,'4400B050','9601B41E',3) SELECT[tile].[SaveToFolderByZoomXY](@image,'d:/tiles',15,19145,9524) SET @image = [tile].[ShapeTile]( @octagon,15,19144,9523,'4400B050','9601B41E',3) SELECT[tile].[SaveToFolderByZoomXY](@image,'d:/tiles',15,19144,9523) SET @image = [tile].[ShapeTile]( @octagon,15,19144,9525,'4400B050','9601B41E',3) SELECT[tile].[SaveToFolderByZoomXY](@image,'d:/tiles',15,19144,9525)
PNG :
DrawPartObjectShapeOnTile() ShapeToTileRendering :
PasteShapeOnTile() .
private void PasteShapeOnTile(Color fillcolor, Color strokecolor, int width, List<SqlGeometry> geom) { SqlGeometry shape = geom[0]; int geomnum = (int) shape.STNumGeometries(); SqlGeometry stroke = null; SqlGeometry ring; int intnum; if (geom != null) switch (GetOpenGisGeometryType(shape)) { case OpenGisGeometryType.LineString: case OpenGisGeometryType.MultiLineString: DrawMultiLineStringBordered2(shape, fillcolor, strokecolor, width, 1); break; case OpenGisGeometryType.Polygon: intnum = (int) shape.STNumInteriorRing(); ring = shape.STExteriorRing();
3-7, , CutPolygonByZoomedPixelZeroTile() , .
GeometryParser «» â X, Y. , :
ShapeToTileRendering CutZoomedPixelPolygonByZeroTile() . . , poly , .
private List<SqlGeometry> CutZoomedPixelPolygonByZeroTile(SqlGeometry poly, int X, int Y) { List<SqlGeometry> result = new List<SqlGeometry>(); SqlGeometry stroke = null; SqlGeometry contour; SqlGeometry tileLineString; SqlGeometry tobecut; SqlGeometry tile = _conv.GetTilePixelBound(0, 0, 1); var tiled = poly.STIntersection(tile); result.Add(tiled); switch (GetOpenGisGeometryType(tiled)) { case OpenGisGeometryType.Polygon:
. tile.FillShapeTiles , @GeoData @FolderPath .
CLR :
ã
BitmapFunctions SQL CLR SqlBitmapOperation :
ShapeTile() PNG xTile, yTile:
ShapeTile() [SqlFunction] public static SqlBinary ShapeTile(SqlGeometry shape, SqlInt32 zoom, SqlInt32 xTile, SqlInt32 yTile, SqlString argbFill,SqlString argbStroke,SqlInt32 strokeWidth) { SqlBinary result = null; using (ShapeToTileRendering paster = new ShapeToTileRendering()) { using (MemoryStream ms = new MemoryStream()) { try { paster.DrawPartObjectShapeOnTile(shape, (int) xTile, (int) yTile, (int) zoom, argbFill.ToString(), argbStroke.ToString(), (int) strokeWidth); result = paster.GetBytes(); } catch (System.Exception ex) { string innerMessage = ex.InnerException.Message; throw new Exception(string.Format("zoom: {1}; X:{2}; Y:{3} {0} , inner: {4}", shape, zoom, xTile,yTile, innerMessage)); } return result; } } }
SqlBitmapOperation TileRendering .
.NET TileRendering .NET :
- ã·ã¹ãã
- Microsoft.SqlServer.Types
- System.Drawing
msdn.microsoft.com/en-us/library/ms345099.aspx
SqlBitmapOperation TileRendering , , :
CREATE ASSEMBLY [Microsoft.SqlServer.Types] AUTHORIZATION [dbo] FROM 'd:\SQLCLR\BIN\TileRendering\Microsoft.SqlServer.Types.dll' WITH PERMISSION_SET = UNSAFE GO CREATE ASSEMBLY [System.Drawing] AUTHORIZATION [dbo] FROM 'd:\SQLCLR\BIN\TileRendering\ System.Drawing.dll' WITH PERMISSION_SET = UNSAFE GO CREATE ASSEMBLY [TileRendering] AUTHORIZATION [dbo] FROM 'd:\SQLCLR\BIN\TileRendering\TileRendering.dll' WITH PERMISSION_SET = UNSAFE GO CREATE ASSEMBLY nQuant.Core FROM 'd:\SQLCLR\BIN\TileRendering\ nQuant.Core.dll' WITH PERMISSION_SET = UNSAFE GO CREATE ASSEMBLY SqlBitmapOperation FROM 'd:\SQLCLR\BIN\TileRendering\SqlBitmapOperation.dll' WITH PERMISSION_SET = UNSAFE GO
SqlBitmapOperation nQuant.Core . PNG 8 .
SqlGeometry Microsoft.SqlServer.Types , Microsoft.SqlServer.Types .
System.Drawing â GDI+ c , EXTERNAL_ACCESS , Sytem.Drawing . , EXTERNAL_ACCESS UNSAFE T-SQL :
ALTER DATABASE [dataBaseName] SET TRUSTWORTHY ON;
CLR , , :
CREATE AGGREGATE [tile].[TileAgg] (@Value [varbinary](max)) RETURNS[varbinary](max) EXTERNAL NAME [SqlBitmapOperation].[TileAgg] GO CREATE AGGREGATE [tile].[IconTileAgg] (@Value [varbinary](max), @PixelX [int], @PixelY [int]) RETURNS[varbinary](max) EXTERNAL NAME [SqlBitmapOperation].[IconTileAgg] GO CREATE FUNCTION [tile].[IconTile](@image [varbinary](max), @zoom [int], @Lon [float], @Lat [float], @xTile [int], @yTile [int], @scale [float]) RETURNS [varbinary](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SqlBitmapOperation].[BitmapFunctions].[IconTile] GO
ShapeToTileRendering . 4326 . GeometryParser, PSG3857, . PastShapeOnTile , geom . 256 .
void PasteShapeOnTile(Color fillcolor,Color strokecolor, int width, List<SqlGeometry> geom) { SqlGeometry shape = geom[0]; int geomnum = (int)shape.STNumGeometries(); SqlGeometry stroke = null; SqlGeometry ring; int intnum; if (geom != null) switch (GetOpenGisGeometryType(shape)) { case OpenGisGeometryType.LineString: case OpenGisGeometryType.MultiLineString: DrawMultiLineStringBordered2(shape, fillcolor, strokecolor, width, 1); break; case OpenGisGeometryType.Polygon: intnum = (int)shape.STNumInteriorRing(); ring = shape.STExteriorRing();
tile.FillShapeTiles .
tile.FillShapeTiles CREATE PROC tile.FillShapeTiles @GeoData GEOMETRY, @fillArgb VARCHAR(20),@strokeArgb VARCHAR(20), @FolderPath NVARCHAR(20), @EndZoom INT = 17, @StartZoom INT = 4, @Thickness INT = 2 AS BEGIN IF @EndZoom < @StartZoom OR @GeoData IS NULL RETURN INSERT INTO tile.tile (Zoom, X,Y,Data) SELECT t.Zoom, t.TileX AS X,t.TileY AS Y, tile.ShapeTile(@GeoData, t.Zoom, t.TileX, t.TileY, @fillArgb, @strokeArgb ,@Thickness) AS Data FROM (SELECT * FROM tile.fn_FetchGeometryTilesZoomDepth(@GeoData,@StartZoom, @EndZoom - @StartZoom)) t SELECT tile.SaveToFolderByZoomXY (Data, @FolderPath ,Zoom,X,Y) FROM tile.Tile END
, 100 000 , . . , CLR .
tile.FillShapeTilesIntersection() CLR tile.ShapeTile() .PNG , . CLR . , CLR tile.TileAgg(@Data VARBINARY(MAX)) , .PNG , VABINARY(MAX).
CLR :
- Init();
- Accumulate(value);
- Merge(Agg);
- Terminate()
tile.FillShapeTilesIntersection tile.Shape. @StartZoom â , @EndZoom â . tile.Shapes.fillArgb tile.Shapes.strokeArgb . : AARRGGBB ,
AA â (), RR â , GG â , BB â . : DDDDFFDD.
CREATE PROC tile.FillShapeTilesIntersection( @StartZoom INT, @EndZoom INT) AS BEGIN DECLARE @Shape GEOMETRY DECLARE @CurrentZoom INT DECLARE @ObjectTypeID INT DECLARE @fillArgb NVARCHAR(10), @strokeArgb NVARCHAR(10) IF @ObjectTypeID IS NOT NULL BEGIN SET @CurrentZoom = @StartZoom DECLARE shape_cursor CURSOR FOR SELECT o.Shape, fillARGB, strokeARGB FROM tile.Shape o OPEN shape_cursor FETCH NEXT FROM shape_cursor INTO @Shape, @fillArgb, @strokeArgb WHILE @@FETCH_STATUS = 0 BEGIN SET @CurrentZoom = @StartZoom WHILE @CurrentZoom <= @EndZoom BEGIN INSERT INTO tile.tileOverlap (Zoom, X,Y,Data) SELECT t.Zoom, t.TileX AS X,t.TileY AS Y, tile.ShapeTile(@Shape, t.Zoom, t.TileX, t.TileY, @fillArgb, @strokeArgb ,2) AS Data FROM (SELECT * FROM tile.fn_FetchGeometryTiles(@Shape,@CurrentZoom)) t SET @CurrentZoom = @CurrentZoom + 1 END FETCH NEXT FROM shape_cursor INTO @Shape, @fillArgb, @strokeArgb END CLOSE shape_cursor; DEALLOCATE shape_cursor; DELETE tile.TileOverlap END END
ãããã«
èŠçŽãããšãããã§èª¬æããã¿ã€ã«åœ¢æã©ã€ãã©ãªã¯ãããã¿ã€ãã«ãããªãããšã«æ³šæããŠãã ããããã¡ãããããŒã¿ããŒã¹åŽã§ã¿ã€ã«ãçæããã®ã¯ããªãå¥åŠãªã¢ãããŒãã§ãããå€ãã®æè²ç代æ¿æ段ããããŸãããããããã®èšäºãæåŸãŸã§èªãã 人ã¯ãé»åå°å³ã®ã¿ã€ã«ã¢ãã«ã®èšèšã«ã€ããŠã®èããæã¡ãSQL Serverã®ç©ºéããŒã¿åã®äœ¿çšæ¹æ³ãç¥ã£ãŠããŸãã
github ã®ã©ã€ãã©ãª
ã®ãœãŒã¹ã³ãŒãã©ã€ãã©ãªããã³ããã¯ã¢ããããŒã¿ããŒã¹ã®ãœãŒã¹ã³ãŒã3.5Mb