Как сделать пространственное перепроецирование в SQL Server - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь выполнить перепроектирование в SQL Server, но, к сожалению, я не могу найти никакого решения для этого.Я знаю, что это не реализовано в SQL Server, поэтому интересно, есть ли ярлык для этого.

Некоторые люди предлагали использовать внешние библиотеки, такие как ogr2ogr, хотя это не очень хороший вариант для меня, поскольку мне нужно делать это на лету.Я нашел пост здесь Преобразование / проецирование геометрии из одного SRID в другой , но этот конвертируется в широту и долготу и имеет некоторые ограниченные возможности.

Я ищу решение, позволяющее мне делать перепроецирование в любом srid, очень похожее на ST_Transform в postgresql (postgis)

1 Ответ

0 голосов
/ 03 октября 2018

Ну, если вы ищете простой вариант, я боюсь, что это невозможно.Но есть обходной путь для этой проблемы.У меня была похожая проблема некоторое время назад, и мне пришлось реализовать CLR в .NET, а затем импортировать ее как сборку в MSSQL, немного медленно, но работает нормально.Входные данные: исходная проекция, целевая проекция и геометрия как текст, а выходные данные - это повторно спроецированная геометрия как текст.Пожалуйста, смотрите результат этой сборки из .Net и PostgreSQL рядом друг с другом (почти одинаково).enter image description here

и ввод был:

     POLYGON ((1755828.2027002387 5944302.7072003055, 1755826.3549002428 5944302.8313003061, 1755825.1724002406 5944285.1574003045, 1755809.5710002393 5944286.4007003047, ......))";// geomobj.line; //"POINT (1736946.0983 5923253.9175)";

Итак, решение выглядит следующим образом:

1- Откройте .NET и создайтеac # library и вставьте туда следующий код (этот код получает каждую строку данных, проходит через каждый элемент, разбивает его, извлекает каждый long и lat, перепроектирует его и заменяет его)

 using Microsoft.SqlServer.Server;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;

public class classval
{
    public string line;
    public string src;
    public string dst;

    public classval(string line, string src, string dst)
    {
        this.line = line;
        this.src = src;
        this.dst = dst;
    }



}
public class RPG_Transform
{
    private static IEnumerable<classval> ConvertedEnumerable(string line, string src, string dst)
    {
        return new List<classval> { new classval(line, src, dst) };
    }

    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable STRPG_Transform(string Geometry, string src, string dst)
    {
        return ConvertedEnumerable(Geometry, src, dst);
    }

    private static void FillRow(Object classvalobj, out string Geometry, out string srcprj, out string dstprj)
    {

        classval geomobj = (classval)classvalobj;
        string _geometry = geomobj.line;  
        string proj4_src = geomobj.src;  
        string proj4_dst = geomobj.dst; 
        string _originalgeom = _geometry;
        _geometry = _geometry.Remove(0, _geometry.IndexOf('('));
        // _geometry = _geometry.Replace("(", "[ ");
        // _geometry = _geometry.Replace(")", " ]");
        string[] splitbycomma = _geometry.Split(',');

        foreach (var itembycomma in splitbycomma)
        {

            string tmpitem = itembycomma;
            tmpitem = tmpitem.Replace('(', ' ');
            tmpitem = tmpitem.Replace(')', ' ');
            tmpitem = tmpitem.Trim();
            string[] splitbyspace = tmpitem.Split(' ');
            for (int ibs = 0; ibs < splitbyspace.Length - 1; ibs++)
            {
                string originallonglat = splitbyspace[ibs] + " " + splitbyspace[ibs + 1];

                double[] yxval = new double[] { double.Parse(splitbyspace[ibs]), double.Parse(splitbyspace[ibs + 1]) };

                double[] z = new double[1] { 0 };




                DotSpatial.Projections.ProjectionInfo src =
                    DotSpatial.Projections.ProjectionInfo.FromProj4String(proj4_src);
                DotSpatial.Projections.ProjectionInfo trg =
                    DotSpatial.Projections.ProjectionInfo.FromProj4String(proj4_dst);

                DotSpatial.Projections.Reproject.ReprojectPoints(yxval, z, src, trg, 0, 1);

                string longlat = yxval[0] + " " + yxval[1];

                _originalgeom = _originalgeom.Replace(originallonglat, longlat);
            }
        }
        srcprj = proj4_src;
        dstprj = proj4_dst;
        Geometry = _originalgeom;
    }

}

2-Перед запуском необходимо установить несколько библиотек, и самая простая из них - использовать Nugget Manager, как показано ниже.

enter image description here

enter image description here

enter image description here

3- Затем вам нужно скомпилировать код и получить DLL, а затем скопировать эти DLL в новую папку,если хотите, оставьте их в папке отладки (некоторые из этих dll добавляются в проекты из-за зависимостей), как показано ниже enter image description here.

4- Включите CLR в MSSQL, а затем добавьте сборку на сервер MSSQL (создав функцию, как показано ниже)

  sp_configure 'show advanced options', 1;  
 GO  
 RECONFIGURE;  
 GO  
 sp_configure 'clr enabled', 1;  
 GO  
 RECONFIGURE;  
 GO  

 ALTER DATABASE Prod SET trustworthy ON
  CREATE ASSEMBLY CLRFunctionAssem
  FROM N'E:\CLR\RPG_Transform\RPG_Transform\bin\Debug\RPG_Transform.dll'
  WITH PERMISSION_SET = UNSAFE
  GO

--DROP ASSEMBLY CLRFunctionAssem ---if you need to drop it in the future

   CREATE FUNCTION dbo.RPG_STTransform(@Geometry nvarchar(max), @src 
  nvarchar(max),@dst nvarchar(max))
    RETURNS TABLE
   ( _geom  nvarchar(max) ,srcprj  nvarchar(max) ,dstprj  nvarchar(max) 
  ) with execute as caller
  AS
   EXTERNAL NAME CLRFunctionAssem.[RPG_Transform].STRPG_Transform

5- Получение формулы для исходной и целевой проекции.Вы должны получить эти две формулы откуда-то.Для получения исходной и конечной проекций я использую следующий веб-сайт (в этом решении используется Proj4j, поэтому вам необходимо получить эквивалент srid откуда-то).
https://epsg.io/, как показано ниже:

enter image description here

и то же самое для пункта назначения

6- Запуск функции sql, как показано ниже:

         SELECT   top 1000 pk   , geom.STAsText() as input,conv._geom as ouput, 
    geometry::STGeomFromText(conv._geom,4326)
  FROM [Prod].[dbo].DPO_Geographic_Units as a  CROSS APPLY dbo.RPG_STTransform (
  a.Geom.STAsText()--geometry as text
 ,'+proj=tmerc +lat_0=0 +lon_0=173 +k=0.9996 +x_0=1600000 +y_0=10000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ',--source =2193
 '+proj=longlat +datum=WGS84 +no_defs'--destination =4326
 ) as conv
 where [Geom] is not null

и вход и выход рядом друг с другом:

enter image description here

Если хотите, вы можете сохранить эти формулы проекции в коде ииспользуйте регистр переключения для получения соответствующей формулы для каждой проекции, затем вы можете передать число (например, 2193), а затем код найдет эквивалентную формулу.

...