2010-03-28 61 views

回答

2

那么,我设法在CLR用户定义函数中做到这一点。

它本身不是一个“子串”方法,但我需要将LINESTRING细分为多个LINESTRING,每个X单元的长度或与形成LINESTRING段的子点的长度一样短(它不是非常清晰,我知道)

下面是我所做的一个片段,我希望它可以运用到其他人!

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 
using Microsoft.SqlServer.Types; 
using System.Collections; 

public partial class UserDefinedFunctions 
{ 
    /// <summary> 
    /// Take a LINESTRING and return a sub LINESTRING from it given the 
    /// starting point and the distance to move 
    /// </summary> 
    /// <param name="inputLine"></param> 
    /// <param name="divideEveryDistance"></param> 
    /// <returns></returns> 
    #region DivideLineString 
    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "FillDivideLineStringRow", TableDefinition = "segment geography")] 
    public static IEnumerable DivideLineString(Microsoft.SqlServer.Types.SqlGeography inputLine, double divideEveryDistance) 
    { 
     // ArrayList to hold the resulting rows 
     ArrayList resultCollection = new ArrayList(); 

     // Check that the input geography is a LINESTRING 
     if (!inputLine.InstanceOf("LINESTRING")) 
      throw new ArgumentException("This operation may only be executed on LineString instances."); 

     // If the input distance is less than or equal zero 
     // just return the original linestring 
     if (divideEveryDistance <= 0) 
     { 
      resultCollection.Add(inputLine); 
      return resultCollection; 
     } 

     // Builder to hold the aggregated LINESTRING 
     SqlGeographyBuilder subLinestringBuilder; 

     // Initialize the starting point to the start point of the input LINESTRING 
     SqlGeography startPoint = inputLine.STStartPoint(); 
     SqlGeography currentPoint = null; 

     // Initialize the starting index to the first point on the input LINESTRING 
     int currentPointIndex = 1; 

     // Loop on all the points on the input LINESTRING 
     while (currentPointIndex < inputLine.STNumPoints()) 
     { 
      // Initialize the builder 
      subLinestringBuilder = new SqlGeographyBuilder(); 
      subLinestringBuilder.SetSrid(4326); 
      subLinestringBuilder.BeginGeography(OpenGisGeographyType.LineString); 

      // Start with the starting point of the line 
      subLinestringBuilder.BeginFigure((double)startPoint.Lat, (double)startPoint.Long); 

      // Distance traversed accumulator 
      double currentDistance = 0; 

      // While we didn't cover the required divide distance and we're still within the boundaries of the input LINESTRING 
      while (currentDistance < divideEveryDistance && currentPointIndex < inputLine.STNumPoints()) 
      { 
       // Calculate the distance between the startPoint and the nth point 
       currentPoint = inputLine.STPointN(currentPointIndex); 
       currentDistance = (double)startPoint.STDistance(currentPoint); 

       // Add the currentPoint to the subLineString 
       subLinestringBuilder.AddLine((double)currentPoint.Lat, (double)currentPoint.Long); 

       // Visit the next point 
       currentPointIndex++; 
      } 

      // We covered the required divide distance, 
      // Move on to the next segment of the line 
      if (currentPoint != null) 
       // Set the startpoint of the next segment to be the last point we visited 
       startPoint = SqlGeography.Point((double)currentPoint.Lat, (double)currentPoint.Long, 4326); 

      // If we reached the end of the LINESTRING, create a segment between the last point 
      // we visited and the end point of the LINESTRING 
      if (currentPointIndex >= inputLine.STNumPoints()) 
      { 
       // Add the endpoint of the original linestring 
       subLinestringBuilder.AddLine((double)inputLine.STEndPoint().Lat, (double)inputLine.STEndPoint().Long); 
      } 

      // End the current line segment 
      subLinestringBuilder.EndFigure(); 
      subLinestringBuilder.EndGeography(); 

      // Add the row to the result collection 
      resultCollection.Add(subLinestringBuilder.ConstructedGeography); 
     } 

     // We're done, return the table 
     return resultCollection; 
    } 
    #endregion 

    /// <summary> 
    /// Method required to fill the table-valued function 
    /// </summary> 
    /// <param name="obj"></param> 
    /// <param name="geography"></param> 
    #region FillDivideLineStringRow 
    private static void FillDivideLineStringRow(Object obj, out SqlGeography geography) 
    { 
     geography = (SqlGeography)obj; 
    } 
    #endregion 
}; 
+0

humm,这将是很好的SQL内置函数...(我们仍然可以做到这一点,如果我们导入程序集) – Nordes 2010-09-21 14:07:44

+0

函数已经可用,因为代码被编译到程序集中并被导入。 – sabbour 2010-09-22 17:55:52

1

DECLARE @g geometry; 
SET @g = geometry::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656, -122.310 47.690, -122.310 47.670, -122.300 47.630)', 0); 
SELECT @g.STPointN(1).ToString(); 
SELECT @g.STPointN(3).ToString(); 

DECLARE @h geometry; 
SET @h = geometry::STGeomFromText('POINT(-122.360 47.656)', 0); 
SELECT @h.STTouches(@g); 

如何看一看

STPointN (geometry Data Type)

而且

STStartPoint (geometry Data Type)

也许还尝试

STTouches (geometry Data Type)

+0

的事情是,我不知道会不会在线上的点的指数,我将被赋予点本身 – sabbour 2010-03-28 18:07:22

+0

我正在使用地理数据类型,所以STTouches不可用:) – sabbour 2010-03-29 14:49:43

0

declare @linestring geography = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656, -122.310 47.690, -122.310 47.670, -122.300 47.630)',4326) declare @point_n geography declare @iterator int = 1 while @iterator <= @linestring.STNumPoints() begin print @linestring.STPointN(@iterator).STAsText() set @iterator = @iterator + 1 end

相关问题