2012-05-08 25 views
6

Tengo una tabla de base de datos que actualmente contiene datos geométricos en SRID 27700 (British National Grid). Mientras recupero los datos, sin embargo, necesito transformarlo a SRID 4326 (WGS84). ¿Hay alguna forma de aplicar una función como ST_Transform encontrada en PostGIS a mis datos para obtener el resultado que necesito?Transformar/Proyectar una geometría de un SRID a otro

NOTA: La solución debe poder implementarse utilizando T-SQL y no procedimientos almacenados, etc. Tengo que ser capaz de construir una declaración y guardarla en una tabla como un campo de cadena para su posterior recuperación. Esto se debe a que mi solución es independiente de la base de datos.

La forma en que actualmente estoy haciendo esto en Oracle es el siguiente:

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' 

En PostgreSQL con PostGIS lo estoy haciendo de esta manera:

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)) 

Respuesta

7

Usted puede envolver algo así como DotNetCoords en una Función SQL CLR para hacer esto.

Ver aquí: - http://www.doogal.co.uk/dotnetcoords.php

me he envuelto en una función CLR para convertir las coordenadas de Este/Norte de latitud/longitud que creo que es lo que está pidiendo. Una vez que se implementa la función CLR, se trata de una solución pura de SQL (es decir, puede ejecutarlo todo en un Procedimiento almacenado o Vista).

EDIT: Voy a publicar un código de muestra aquí cuando llegue a trabajar mañana, con suerte lo ayudará.

EDIT: Deberá descargar el código fuente desde http://www.doogal.co.uk/dotnetcoords.php y necesitará Visual Studio para abrirlo y modificarlo. Documentación para la biblioteca está aquí http://www.doogal.co.uk/Help/Index.html

Lo que puede hacer es, entonces, se puede añadir una nueva clase a la fuente de archivos similar a esto: -

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); 
    } 

} 

A continuación, tendrá para construir e importar el conjunto en Servidor SQL (reemplace las rutas con sus propias ubicaciones) (por alguna razón no puedo hacer que el ensamblaje se instale cuando PERMISSION_SET es 'SEGURO', así que primero ordenaría esto antes de instalarlo en un entorno de producción).

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

A continuación, tendrá que crear una función de SQL Server para interactuar con la función 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] 

Ésta es la función CLR que instalar.

Debería poder llamar a la función directamente desde SQL Server para hacer su conversión (he mezclado los números en esta publicación también guardo el anonimato para que no tengan sentido aquí pero la función funciona bien).

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

(1 row(s) affected) 

Para utilizarlo en un conjunto de resultados es necesario utilizar la cláusula 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 
10.3453417606796 -3.19252323679263 

(10 row(s) affected) 
+1

Si bien esto no se ha probado en mi situación, parece ser la mejor solución para mi problema que he encontrado hasta ahora y no veo ningún problema con su implementación. Gracias por tomarse el tiempo de publicarlo. Te he otorgado la recompensa. – CSharpened

+2

Gracias, no he tenido tiempo de profundizar en él, pero sería bueno implementar todas las funciones de la biblioteca como funciones CLR y ordenarlas para que se instalen con pestañas "SEGURAS". –

2

Desafortunadamente, esto simplemente no es posible.Las herramientas espaciales de SQL Server proporcionan algunas funciones de reproyección, pero solo son para un número muy reducido de proyecciones (y no la que usted necesita).

Hay un example from SQL server tools - https://bitbucket.org/geographika/sql-server-spatial-tools/src/5ca44b55d3f3/SQL%20Scripts/projection_example.sql - pero no lo ayudará porque no son compatibles con la proyección de la que está hablando.

Por lo tanto, deberá adoptar una solución diferente: preprocesar los datos para agregar una nueva columna con valores proyectados o reproyectar en su código.

Cuestiones relacionadas