0

Is it possible to get result of STIntersection() with the same points order as original object?

DECLARE @g geography;  
DECLARE @h geography;  

SET @g = geography::STGeomFromText('POLYGON((25.84568061650872 49.69890972163677,25.844941083373904 49.69189373653131,25.900405504271674 49.69173426681988,25.900898532630585 49.69667747509544,25.84568061650872 49.69890972163677))', 4326);  

SET @h = geography::STGeomFromText('LINESTRING(25.84863871143376 49.68886378946257,25.85578746277756 49.702736200117556,25.874275603076814 49.69013957742882,25.88117784964471 49.696518021079896,25.890791686361744 49.693647826244444)', 4326);  

SELECT @g.STIntersection(@h)   

-- output is MULTILINESTRING ((25.890791686361744 49.693647826244444, 25.881177849644711 49.696518021079896, 25.876080243405344 49.691807467094165), (25.871810347453074 49.691819790540073, 25.862392696595393 49.698236908740775), (25.85364996544109 49.698589185269235, 25.8501925460631 49.691879772894147)) 

If you check the output here for example, you can find it is like reversed.

I don't know if it's really reversed, o it's random order of points and segments but i need them in "original" order to save line direction.

Is there any solution for this?

Thanks.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Dimon S
  • 21
  • 2
  • Are you trying to create a line string of orderly lat/long coordinates to escape the zig-zag effect? If so, I had the same challenge and had to convert the points to degrees, then order by degree. Worked great, but it's dicey. – Mike Petri May 18 '21 at 17:20
  • Thanks for reply. The linestring is the track of the vehicle. I want to show it on map, using Leaflet. Also I'm adding arrows to show movement direction. When linestring is not splitted to multilinestring - it works correctly. But when i want to show track in zone - segments of multilinestring are directed randomly. – Dimon S May 18 '21 at 20:41

1 Answers1

0

... split the @h linestring into an ordered list of individual lines (the starting point of each line is the reference point for the line), intersect each individual line with the polygon @g, and split the intersections to individual lines (if more than one). If the starting point of the intersection is closer to the reference point then keep the intersection as is otherwise reverse it (endpoint of intersection becomes the startpoint and vice versa). Finally aggregate the intersections in a geometry collection in order (of reference point/line ordinal, intersection line ordinal)

DECLARE @g geography;  
DECLARE @h geography;  

SET @g = geography::STGeomFromText('POLYGON((25.84568061650872 49.69890972163677,25.844941083373904 49.69189373653131,25.900405504271674 49.69173426681988,25.900898532630585 49.69667747509544,25.84568061650872 49.69890972163677))', 4326);  
SET @h = geography::STGeomFromText('LINESTRING(25.84863871143376 49.68886378946257,25.85578746277756 49.702736200117556,25.874275603076814 49.69013957742882,25.88117784964471 49.696518021079896,25.890791686361744 49.693647826244444)', 4326);  

--reverse linestring..test
--SET @h = geography::STGeomFromText('LINESTRING(25.890791686361744 49.693647826244444, 25.88117784964471 49.696518021079896, 25.874275603076814 49.69013957742882, 25.85578746277756 49.702736200117556, 25.84863871143376 49.68886378946257)', 4326);  

select 
concat(
'GEOMETRYCOLLECTION(', 
string_agg(directionline.ToString(), ',') within group (order by pnum, ilnum), 
')'
) as geometrycollection_string

 --geography::CollectionAggregate(directionline) -- no option for order...
from
(
select 
p.pnum,
io.ilnum,

case when
--reverse the interection when starting point is farther to the reference point
io.iline.STStartPoint().STDistance(p.spoint) > io.iline.STEndPoint().STDistance(p.spoint)
then 
--...assume intersection is linestring since @h is linestring 
cast(
  replace(
    concat( --lazy...string manipulation
      cast('linestring(' as varchar(4000)), 
      translate(io.iline.STEndPoint().ToString(),'()','  '),',', translate(io.iline.STStartPoint().ToString(),'()','  '), ')'
    )
  ,'point','') 
as geography)
--if the starting point of the intesection is closer to the reference point then keep the intersection as is
--this also covers if intersection is point (when @h is tangent to @g)
else io.iline end  as directionline

from
(

select 
    @h.STPointN(n.pnum) as spoint, --starting point of each line/reference
    n.pnum, --starting point ordinal
    --linestring starting from spoint till the next point
    cast(
      replace(
        concat(
          cast('linestring(' as varchar(4000)), --lazy...
          translate(@h.STPointN(n.pnum).ToString(),'()','  '),',', translate(@h.STPointN(n.pnum+1).ToString(),'()','  '), ')'
        )
      ,'point','') 
    as geography) as thelines --each line of the @h linestring
from
    (
        --points (excluding the last) of the @h linestring
        select top (@h.STNumPoints()-1) row_number() over(order by @@spid) as pnum --point number
        from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as a(n)
        cross join (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as b(n)
    ) as n

) as p   

--get each intersection "object" of each line (in the @h linestring) with @g
cross apply
(
    --intersection of each line (of the @h linestring) with the polygon @g
    --the intersection could be multiple "objects", get each object
    select p.thelines.STIntersection(@g).STGeometryN(n.ilnum) as iline, ilnum
    from
    (
        --split any multi-object intersection into individual objects
        select top (p.thelines.STIntersection(@g).STNumGeometries()) row_number() over(order by @@spid) as ilnum
        from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as a(n)
        cross join (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as b(n)
    ) as n
) as io
) as src
--order by pnum, ilnum
lptr
  • 1
  • 2
  • 6
  • 16