地理转换LINESTRING到POLYGON

时间:2018-02-23 20:38:03

标签: c# sql sql-server

如何使用MS SQL或C#将封闭的线串转换为适用于Geography的polgyon。我正在尝试构建此数据,以便我可以搜索MS SQL数据库中的数据。当我尝试使用函数STGeomFromWKB转换数据时,它没有返回正确的形状。

import numpy as np
result = m.readshapefile('shapefiles/nic_autoc2018046n_pl_a', 'IceEdge', zorder = 10, color = 'blue')#, drawbounds = False)

col = result[-1]
segments = col.get_segments()
seglens =  [len(seg) for seg in col.get_segments()]

segments = np.array(segments)
seglens  = np.array(seglens)

idx = np.argsort(seglens)
seglens  = seglens[idx]
segments = segments[idx]

col.remove()

new_col = LineCollection(segments[-100:],linewidths = 2, linestyles='dotted', colors='b')
ax.add_collection(new_col)

plt.show()

enter image description here

DECLARE @data geography;
 SET @data= 'LINESTRING(145.13527778 13.64166667, 144.74694444 13.47666667, 144.63722222 13.51194444, 144.61944444 13.5875, 144.62337227 13.60962359, 144.62777753 13.63154738, 144.63412072 13.65301205, 144.64235403 13.6738541, 144.65241522 13.69391474, 144.66422807 13.71304108, 144.67770294 13.73108731, 144.69273746 13.74791585, 144.70921729 13.76339835, 144.72701699 13.7774167,144.74600098 13.78986396,144.76602456 13.80064514,144.78693505 13.80967796,144.80857293 13.81689348,144.83077307 13.82223661,144.85336602 13.82566656,144.87617929 13.82715716,144.8990387 13.826697,144.92176971 13.82428962,144.94419878 13.81995338,144.96615467 13.8137214,144.98746983 13.80564125,145.0079816 13.79577461,145.02753354 13.78419678,145.0459766 13.77099612,145.06317023 13.75627335,145.07898353 13.74014079,145.09329617 13.7227215,145.10599934 13.70414829,145.1169966 13.68456278,145.12620454 13.66411424, 145.13355348 13.64295851, 145.13527778 13.64166667)'; 

 --This shape looks like this

结果如下所示。     Return wrong shape

3 个答案:

答案 0 :(得分:2)

如果您将最后一行更改为

select @Polygon.ReorientObject();

我认为你会找到理想的结果。您的线串具有所谓的环形方向问题。指定点的顺序很重要。根据定义,多边形是整个地球减去预期的多边形。通过调用多边形上的ReorientObject(),它就可以重新定位对象。

答案 1 :(得分:0)

这是一个难以回答的问题,因为您获得了预期的结果,但问题是如何将LINESTRING转换为POLYGON。这个答案将使用REPLACE,但肯定可以通过其他方式完成(例如您尝试的方法)。此外,我们将添加一些“不必要的”代码来显示方法。这是基于源值处于封闭LINESTRING格式的假设。

查看这组查询:

DECLARE @predata varchar(MAX) = 'LINESTRING(145.13527778 13.64166667, 144.74694444 13.47666667, 144.63722222 13.51194444, 144.61944444 13.5875, 144.62337227 13.60962359, 144.62777753 13.63154738, 144.63412072 13.65301205, 144.64235403 13.6738541, 144.65241522 13.69391474, 144.66422807 13.71304108, 144.67770294 13.73108731, 144.69273746 13.74791585, 144.70921729 13.76339835, 144.72701699 13.7774167,144.74600098 13.78986396,144.76602456 13.80064514,144.78693505 13.80967796,144.80857293 13.81689348,144.83077307 13.82223661,144.85336602 13.82566656,144.87617929 13.82715716,144.8990387 13.826697,144.92176971 13.82428962,144.94419878 13.81995338,144.96615467 13.8137214,144.98746983 13.80564125,145.0079816 13.79577461,145.02753354 13.78419678,145.0459766 13.77099612,145.06317023 13.75627335,145.07898353 13.74014079,145.09329617 13.7227215,145.10599934 13.70414829,145.1169966 13.68456278,145.12620454 13.66411424, 145.13355348 13.64295851, 145.13527778 13.64166667)';
DECLARE @data geography;
DECLARE @linestring geography = @predata;
DECLARE @srid int;
SET @predata = REPLACE(@predata, 'LINESTRING', 'POLYGON(') + ')';
SELECT @predata AS PolygonString
SET @data = geography::STGeomFromText(@predata, @linestring.STSrid);
SELECT @data AS GeographyPolygon

在声明变量之后,我在REPLACE的字符串/ varchar表示上做了一个简单的LINESTRING,将其变为POLYGON

SET @predata = REPLACE(@predata, 'LINESTRING', 'POLYGON(') + ')';

结果:

PolygonString
POLYGON((145.13527778 13.64166667, 144.74694444 13.47666667, 144.63722222 13.51194444, 144.61944444 13.5875, 144.62337227 13.60962359, 144.62777753 13.63154738, 144.63412072 13.65301205, 144.64235403 13.6738541, 144.65241522 13.69391474, 144.66422807 13.71304108, 144.67770294 13.73108731, 144.69273746 13.74791585, 144.70921729 13.76339835, 144.72701699 13.7774167,144.74600098 13.78986396,144.76602456 13.80064514,144.78693505 13.80967796,144.80857293 13.81689348,144.83077307 13.82223661,144.85336602 13.82566656,144.87617929 13.82715716,144.8990387 13.826697,144.92176971 13.82428962,144.94419878 13.81995338,144.96615467 13.8137214,144.98746983 13.80564125,145.0079816 13.79577461,145.02753354 13.78419678,145.0459766 13.77099612,145.06317023 13.75627335,145.07898353 13.74014079,145.09329617 13.7227215,145.10599934 13.70414829,145.1169966 13.68456278,145.12620454 13.66411424, 145.13355348 13.64295851, 145.13527778 13.64166667))

我们有一个有效的POLYGON字符串值,最后一个括号为+字符串连接后,我们可以将其传递给STGeomFromText函数:

SET @data =  geography::STGeomFromText(@predata, @linestring.STSrid);

最后,通过选择地理类型@data变量,我们得出空间结果。

SELECT @data AS GeographyPolygon

您显示的是哪个多边形。该比例与LINESTRING值的比例非常不同,因为它放在SRID 4326的完整地理平面表示上。这样的定义:

http://spatialreference.org/ref/epsg/wgs-84/

由于SRID 4326的预计界限是:

  

预计界限:-180.0000,-90.0000,180.0000,90.0000

这意味着与初始LINESTRING相比,结果的比例大量。如果放大9°-18°x 140°-160°的象限,你会看到多边形。

答案 2 :(得分:0)

ReorientObject占问题的50%。如果EnvelopeAngle低于90度,我们只需要这样做。

 /// <summary>
        /// Fixing ring orientation problem By calling ReorientObject() for all any shapes
        /// Shape must be reposition before insert into the database otherwise you have the wrong result especially with the polygon
        /// SQL Script example
        //        DECLARE @Polygon geography;
        //SET @Polygon = 'POLYGON((145.13527778 13.64166667, 144.74694444 13.47666667, 144.63722222 13.51194444, 144.61944444 13.5875, 144.62337227 13.60962359, 144.62777753 13.63154738, 144.63412072 13.65301205, 144.64235403 13.6738541, 144.65241522 13.69391474, 144.66422807 13.71304108, 144.67770294 13.73108731, 144.69273746 13.74791585, 144.70921729 13.76339835, 144.72701699 13.7774167,144.74600098 13.78986396,144.76602456 13.80064514,144.78693505 13.80967796,144.80857293 13.81689348,144.83077307 13.82223661,144.85336602 13.82566656,144.87617929 13.82715716,144.8990387 13.826697,144.92176971 13.82428962,144.94419878 13.81995338,144.96615467 13.8137214,144.98746983 13.80564125,145.0079816 13.79577461,145.02753354 13.78419678,145.0459766 13.77099612,145.06317023 13.75627335,145.07898353 13.74014079,145.09329617 13.7227215,145.10599934 13.70414829,145.1169966 13.68456278,145.12620454 13.66411424, 145.13355348 13.64295851, 145.13527778 13.64166667))'; 
        // --This shape looks like this, you have to zoom in to see, it is really small
        //select @Polygon, 'error here' as ErrorHere

        //set @Polygon=@Polygon.ReorientObject();
        //select @Polygon;

        //--Only convert if the EnvelopeAngle> 90
        //select 
        //case when @Polygon.EnvelopeAngle() > 90 then
        //@Polygon.ReorientObject()
        //  else
        //   @Polygon
        //end  

        //--Do not duplicate ReorientObject it will cost error like below
        //set @Polygon = @Polygon.ReorientObject();
        //        select @Polygon;

        /// </summary>
        /// <param name="dataPoints">Example POLYGON((145.13527778 13.64166667, 144.74694444 13.47666667, 144.63722222 13.51194444, 144.61944444 13.5875, 144.62337227 13.60962359, 144.62777753 13.63154738, 144.63412072 13.65301205, 144.64235403 13.6738541, 144.65241522 13.69391474, 144.66422807 13.71304108, 144.67770294 13.73108731, 144.69273746 13.74791585, 144.70921729 13.76339835, 144.72701699 13.7774167,144.74600098 13.78986396,144.76602456 13.80064514,144.78693505 13.80967796,144.80857293 13.81689348,144.83077307 13.82223661,144.85336602 13.82566656,144.87617929 13.82715716,144.8990387 13.826697,144.92176971 13.82428962,144.94419878 13.81995338,144.96615467 13.8137214,144.98746983 13.80564125,145.0079816 13.79577461,145.02753354 13.78419678,145.0459766 13.77099612,145.06317023 13.75627335,145.07898353 13.74014079,145.09329617 13.7227215,145.10599934 13.70414829,145.1169966 13.68456278,145.12620454 13.66411424, 145.13355348 13.64295851, 145.13527778 13.64166667))</param>
        /// <returns></returns>
        public static string ReorientObject(string dataPoints)
        {
            //Convert to DbGeography
            DbGeography newGeography = DbGeography.FromText(dataPoints.ToString(), 4326);

            //Fixing ring orientation problem By calling ReorientObject() on the polygon
            SqlGeography parseData = SqlGeography.Parse(dataPoints);
            if (parseData.EnvelopeAngle() > 90)
            {
                parseData= parseData.ReorientObject();
            }
            //Take the new reposition of the poing
            dataPoints = DbGeography.FromText(parseData.ToString(), 4326).AsText();
            return dataPoints;
        }
相关问题