Преобразование / проецирование геометрии из одного SRID в другой

У меня есть таблица базы данных, в которой в настоящее время хранятся геометрические данные в SRID 27700 (Британская национальная сеть). Однако при извлечении данных мне нужно преобразовать их в SRID 4326 (WGS84). Есть ли способ применить к моим данным такую ​​функцию, как ST_Transform, найденную в PostGIS, чтобы получить нужный мне результат?

ПРИМЕЧАНИЕ. Решение должно быть реализовано с использованием T-SQL, а не хранимых процедур и т. Д. Я должен иметь возможность построить оператор и сохранить его в таблице в виде строкового поля для последующего извлечения. Это потому, что мое решение не зависит от базы данных.

В настоящее время я делаю это в Oracle следующим образом:

select CLUSTER_ID, 
       NUM_POINTS, 
       FEATURE_PK, 
       A.CELL_CENTROID.SDO_POINT.X, 
       A.CELL_CENTROID.SDO_POINT.Y, 
       A.CLUSTER_CENTROID.SDO_POINT.X, 
       A.CLUSTER_CENTROID.SDO_POINT.Y, 
       TO_CHAR (A.CLUSTER_EXTENT.GET_WKT ()),  
       TO_CHAR (A.CELL_GEOM.GET_WKT ()), 
       A.CLUSTER_EXTENT.SDO_SRID 
from (SELECT CLUSTER_ID, 
             NUM_POINTS, 
             FEATURE_PK, 
             SDO_CS.transform (CLUSTER_CENTROID, 4326) cluster_centroid,
             CLUSTER_EXTENT, 
             SDO_CS.transform (CELL_CENTROID, 4326) cell_centroid, 
             CELL_GEOM FROM :0) a  
where sdo_filter( A.CELL_GEOM, 
                  SDO_CS.transform(mdsys.sdo_geometry(2003, :1, NULL, mdsys.sdo_elem_info_array(1,1003,3),mdsys.sdo_ordinate_array(:2, :3, :4, :5)),81989)) = 'TRUE'

В PostgreSQL с использованием PostGIS я делаю это так:

select CLUSTER_ID, 
       NUM_POINTS, 
       FEATURE_PK, ST_X(a.CELL_CENTROID), 
       ST_Y(a.CELL_CENTROID), 
       ST_X(ST_TRANSFORM(a.CLUSTER_CENTROID, 4326)),  
       ST_Y(ST_TRANSFORM(a.CLUSTER_CENTROID, 4326)), 
       ST_AsText(a.CLUSTER_EXTENT),  
       ST_AsText(a.CELL_GEOM), 
       ST_SRID(a.CLUSTER_EXTENT)  
FROM (SELECT CLUSTER_ID, 
      NUM_POINTS, 
      FEATURE_PK, 
      ST_TRANSFORM(ST_SetSRID(CLUSTER_CENTROID, 27700), 4326) cluster_centroid, 
      CLUSTER_EXTENT, 
      ST_TRANSFORM(ST_SetSRID(CELL_CENTROID, 27700), 4326) cell_centroid, 
      CELL_GEOM 
from :0) AS a 
where ST_Intersects(ST_Transform(ST_SetSRID(a.CELL_GEOM, 27700), :1), ST_Transform(ST_GeomFromText('POLYGON(('||:2||' '||:3||', '||:4||' '||:3||', '||:4||' '||:5||', '||:2||' '||:5||', '||:2||' '||:3||'))', 4326), :1))

person CSharpened    schedule 08.05.2012    source источник


Ответы (2)


Для этого вы можете заключить что-то вроде DotNetCoords в функцию SQL CLR.

См. Здесь: - http://www.doogal.co.uk/dotnetcoords.php

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

ИЗМЕНИТЬ. Я отправлю сюда образец кода, когда завтра приступлю к работе. Надеюсь, это поможет.

ИЗМЕНИТЬ: вам нужно будет загрузить исходный код со страницы http://www.doogal.co.uk/dotnetcoords.php, и вам понадобится Visual Studio, чтобы открыть и изменить его. Документация к библиотеке находится здесь http://www.doogal.co.uk/Help/Index.html

Что вы можете сделать, так это добавить новый класс в исходные файлы, подобный этому: -

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using DotNetCoords;
using Microsoft.SqlServer.Server;

/// <summary>
/// Sql Server CLR functions for the DotNetCoords library.
/// </summary>
public class CLRFunctions
{

    /// <summary>
    /// Coordinateses the enumerable.
    /// </summary>
    /// <param name="Easting">The easting.</param>
    /// <param name="Northing">The northing.</param>
    /// <returns></returns>
    private static IEnumerable<OSRef> CoordinatesEnumerable(double Easting, double Northing)
    {
        return new List<OSRef> { new OSRef(Easting,Northing) };
    }

    /// <summary>
    /// Toes the lat long.
    /// </summary>
    /// <param name="Easting">The easting.</param>
    /// <param name="Northing">The northing.</param>
    /// <returns></returns>
    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable ToLatLong(double Easting, double Northing)
    {
        return CoordinatesEnumerable(Easting, Northing);
    }

    /// <summary>
    /// Fills the row.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <param name="Lat">The lat.</param>
    /// <param name="Long">The long.</param>
    private static void FillRow(Object obj, out SqlDouble Lat, out SqlDouble Long)
    {
        OSRef Coordinates = (OSRef)obj;
        LatLng latlong = Coordinates.ToLatLng();
        latlong.ToWGS84();
        Lat = new SqlDouble(latlong.Latitude);
        Long = new SqlDouble(latlong.Longitude);
    }

}

Затем вам нужно будет создать и импортировать сборку в SQL Server (замените пути своими собственными местоположениями) (по какой-то причине я не могу установить сборку, когда PERMISSION_SET является `` БЕЗОПАСНЫМ '', поэтому я бы сначала отсортировал это перед установкой в ​​производственной среде ).

CREATE ASSEMBLY DotNetCoords
FROM N'C:\Projects\DotNetCoords\bin\Debug\DotNetCoords.dll'
WITH PERMISSION_SET = UNSAFE
GO

Затем вам нужно будет создать функцию SQL Server для взаимодействия с функцией CLR: -

CREATE FUNCTION dbo.ToLatLong(@Easting float, @Northing float)
RETURNS TABLE
(Latitude float null, Longitude float null) with execute as caller
AS
EXTERNAL NAME [DotNetCoords].[CLRFunctions].[ToLatLong]

Это и есть установленная тогда функция CLR.

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

/*------------------------
SELECT Latitude, Longitude FROM dbo.ToLatLong(327262, 357394)
------------------------*/
Latitude            Longitude
52.13413530182533       -9.34267170569508

(1 row(s) affected)

Чтобы использовать его в наборе результатов, вам необходимо использовать предложение CROSS APPLY: -

/*------------------------
SELECT TOP 2    a.[Column 0] AS osaddessp,
                            a.[Column 9] AS east,
                            a.[Column 10] AS north,
                            c.[Latitude] AS lat,
                            c.[Longitude] AS long
FROM    MyTable AS a CROSS APPLY ToLatLong (a.[Column 9], a.[Column 10]) AS c;
------------------------*/
osaddessp       east    north   lat         long
100134385607    327862  334794  52.3434530182533    -2.19342342569508
100123433149    780268  353406  52.3453417606796    -3.19252323679263

(10 row(s) affected)
person general exception    schedule 29.05.2012
comment
Хотя это в настоящее время не проверено в моей ситуации, это действительно кажется лучшим решением моей проблемы, с которой я столкнулся до сих пор, и я не вижу проблемы с его реализацией. Спасибо, что нашли время опубликовать это. Я назначил вам награду. - person CSharpened; 30.05.2012
comment
Спасибо, у меня не было времени изучить это подробнее, но было бы хорошо реализовать все функции библиотеки как функции CLR и отсортировать их, чтобы она устанавливалась с разрешениями «БЕЗОПАСНО». - person general exception; 30.05.2012

К сожалению, это просто невозможно. SQL Server Spatial Tools предоставляет несколько функций перепроецирования, но они предназначены только для очень небольшого числа проекций (а не для того, которое вам нужно).

Существует пример из инструментов сервера SQL - https://bitbucket.org/geographika/sql-server-spatial-tools/src/5ca44b55d3f3/SQL%20Scripts/projection_example.sql - но это вам не поможет, потому что они не поддерживают проекцию, о которой вы говорите .

Итак, вам нужно принять другое решение - либо предварительно обработать данные, чтобы добавить новый столбец с прогнозируемыми значениями, либо перепроецировать в своем коде.

person Josh Marcus    schedule 29.05.2012