Преобразование / Проектирование геометрии от одного SRID до другого
У меня есть таблица базы данных, которая в настоящее время содержит геометрические данные в SRID 27700 (British National Grid). Однако при получении данных мне нужно преобразовать их в 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))
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 имеет значение "SAFE", поэтому я сначала отсортировал ее перед установкой в производственной среде).).
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)
К сожалению, это просто невозможно. Пространственные инструменты SQL Server предоставляют несколько функций перепроецирования, но они предназначены только для очень небольшого числа проекций (а не того, которое вам требуется).
Есть пример из инструментов сервера SQL - https://bitbucket.org/geographika/sql-server-spatial-tools/src/5ca44b55d3f3/SQL%20Scripts/projection_example.sql - но он вам не поможет, потому что они не поддерживайте прогноз, о котором вы говорите.
Поэтому вам нужно принять другое решение - либо предварительно обработать данные, чтобы добавить новый столбец с прогнозируемыми значениями, либо перепроектировать в коде.