用例1:
DECLARE @Geom TABLE
(
shape geometry,
shapeType nvarchar(50)
);
INSERT INTO @Geom(shape,shapeType)
VALUES('LINESTRING(1 2, 3 4)', 'A'),
('LINESTRING(3.2 4, 7 8)', 'B');
SELECT *
FROM @Geom
SELECT geometry::UnionAggregate(shape).ToString(), geometry::UnionAggregate(shape)
FROM @Geom;
输出的WKT为
MULTILINESTRING ((7 8, 3.2 4), (3 4, 1 2))
我何时想要
MULTILINESTRING ((1 2, 3 4), (3.2 4, 7 8))
“ A”和“ B”行的开头应分别为(1 2)
和(3.2 4)
。
UnionAggregate
的这种行为似乎并不关心几何的“方向”,以便维持A联合B和B联合A是相同的结果。但是,我在合并街道几何图形时希望保留起点/终点,并且希望所有LINESTRING沿其原始方向移动。
他们似乎建议检查最终结果的可能解决方案,但是我不清楚如何做到这一点。
MultiLineString始终从距原点最远的点表示图形。
我不清楚这到底是什么意思,但我认为我不能仅假设UnionAggregate的结果总是与我想要的相反
如果很难了解方向意图,那么我可以在方向应遵循增加的M值的地方添加M个度量。
假设我有一种方法可以逆转直线上的点,该如何解决呢?
我发现了一个模仿STUnion
的函数,以增加对Z和M量度的支持:http://www.spatialdbadvisor.com/files/SQLServer.html#robo48,但是请注意,“它们的方向可能会改变(例如,起点/起点关系)”。这是我要避免的事情。
编辑:
我还需要的功能是,当LINESTRING具有共享端点时,结果是连接LINESTRING
用例2:
DECLARE @Geom TABLE
(
shape geometry,
shapeType nvarchar(50)
);
INSERT INTO @Geom(shape,shapeType)
VALUES('LINESTRING(1 2, 3 4)', 'A'),
('LINESTRING(3 4, 7 8)', 'B');
SELECT *
FROM @Geom
SELECT geometry::UnionAggregate(shape).ToString(), geometry::UnionAggregate(shape)
FROM @Geom;
这将导致WKT LINESTRING (7 8, 3 4, 1 2)
何时需要
LINESTRING (1 2, 3 4, 7 8)
尝试解决方案
Clay建议的geometry::CollectionAggregate(shape).Reduce(0)
解决了用例1。我尝试对结果使用STUnion并带有空的线串,并且在工作时它会退回到不正确的顺序。
我怀疑解决方案将是类似于ST_LineMerge的缩放器函数,该函数使用CollectionAggregate(MULTILINESTRING)的结果,然后在可以合并为一个LINESTRING且无法返回时返回这些点。几何形状保持不变
答案 0 :(得分:7)
The geometry types don't record/encode directionality. The lines that you give it may be considered "undirected" or "bi-directional". This returns 1:
select geometry::STGeomFromText('LINESTRING(1 2, 3 4)',0).STEquals(
geometry::STGeomFromText('LINESTRING(3 4, 1 2)',0))
So what you're looking for isn't available using these types. You consider the "start points" to be special. I suggest you separately record those as individual POINT
s.
This does make all of the resulting code uglier now though - you have to keep these data pairs processed together:
DECLARE @Geom TABLE
(
start geometry,
shape geometry,
shapeType nvarchar(50)
);
INSERT INTO @Geom(start,shape,shapeType)
VALUES('POINT(1 2)','LINESTRING(1 2, 3 4)', 'A'),
('POINT(3.2 4)','LINESTRING(3.2 4, 7 8)', 'B');
SELECT *
FROM @Geom
SELECT
geometry::UnionAggregate(start).ToString(), geometry::UnionAggregate(shape).ToString(),
geometry::UnionAggregate(start), geometry::UnionAggregate(shape)
FROM @Geom;
At this point you may decide to stop using the geography type directly - you can create a CLR UDT that references SqlGeography
(a CLR surfacing of the same type) and uses that internally but also tracks it's "directionality" too, all wrapped up together, and start using that instead.
You're unlikely to want to surface all of the geography
methods in that wrapper though - you'll have to pick and choose your battles. And, of course, since it's not really the SQL Server geography
turning up in your results, you won't get the benefit of the "Spatial Results" tab in Management Studio.
The only place I can think of where some "directionality" does exist in these types is the left-hand rule for disambiguating geography
shapes.
答案 1 :(得分:5)
最初,我建议...
DatabaseReference mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child("uid").child("username");
mDatabaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String username = Objects.requireNonNull(dataSnapshot.getValue()).toString();
mName.setText(("username" + username ));
} else {
mName.setText(null);
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
您得到:
...但是,对我来说,很明显我给出的答案还不够好。例如,很难阻止dicc['first'] = l1
简化行的一部分,
我仍然喜欢CollectionAggregate,它可以将原始的线阵列整合为一体,但是后来我发现,必须有一种构建必要的几何结构的方法。
我玩过几次,根据输入中是否存在不相交的DECLARE @Geom TABLE
(
shape geometry,
shapeType nvarchar(50)
);
INSERT @Geom(shape,shapeType) VALUES
('LINESTRING(1 2, 3 4)', 'A'),
('LINESTRING(3.2 4, 7 8)', 'B');
SELECT * FROM @Geom
SELECT
geometry::CollectionAggregate(shape).Reduce(0).ToString(),
geometry::CollectionAggregate(shape).Reduce(0)
FROM @Geom
元素,该迭代将评估为Reduce()
或LineString
:
MultiLineString
...最后,给出:
LineString
...您得到:
答案 2 :(得分:1)
摆脱Clay传入GeometryCollection的想法,我实现了一个健壮的版本,该版本将采用POINT,MULTIPOINT,LINESTRING,MULTILINESTRING的任意组合,并删除@Tolerance
中的任何触摸端点,并创建POINT,LINESTRING,MULTILINESTRING
以下是其工作原理的说明(请注意,0和0.1的公差如何影响第二和第三输出):
DECLARE @GeometryCollection GEOMETRY = GEOMETRY::STGeomFromText('GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4), LINESTRING (3 4, 100 100), LINESTRING (9 8, 3 4), LINESTRING (3 4, 1 2), POINT(1 2), POINT(1 2), POINT(1 2))',0)
SELECT [dbo].[fnSimplifyToLine](@GeometryCollection, 0).ToString();
--Output: MULTILINESTRING ((1 2, 3 4, 100 100), (9 8, 3 4, 1 2))
SET @GeometryCollection = GEOMETRY::STGeomFromText('GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4.1), LINESTRING (3 4, 9 9, 6 1))',0)
SELECT [dbo].[fnSimplifyToLine](@GeometryCollection, 0).ToString()
--Output: MULTILINESTRING ((1 2, 3 4.1), (3 4, 9 9, 6 1))
SET @GeometryCollection = GEOMETRY::STGeomFromText('GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4.1), LINESTRING (3 4, 9 9, 6 1))',0)
SELECT [dbo].[fnSimplifyToLine](@GeometryCollection, 0.1).ToString()
--Output: LINESTRING (1 2, 3 4.1, 9 9, 6 1)
SET @GeometryCollection = GEOMETRY::STGeomFromText('GEOMETRYCOLLECTION (POINT(1 2))',0)
SELECT [dbo].[fnSimplifyToLine](@GeometryCollection, 0).ToString()
--Output: POINT (1 2)
SET @GeometryCollection = GEOMETRY::STGeomFromText('GEOMETRYCOLLECTION (MULTIPOINT((1 2), (2 3)))',0)
SELECT [dbo].[fnSimplifyToLine](@GeometryCollection, 0).ToString()
--Output: (1 2, 2 3)
首先,我必须创建一个递归CTE函数,该函数需要一个几何图形并提取所有点。
CREATE FUNCTION [dbo].[fnGetPoints]
(
@Geometry GEOMETRY
)
RETURNS TABLE
AS
RETURN
(
WITH GeometryPoints(N, Point) AS (
SELECT
CAST(1 AS DECIMAL(9,2)) as N
,@Geometry.STPointN(1) as Point
UNION ALL
SELECT
CAST(N + 1.0 AS DECIMAL(9,2)) as N
,@Geometry.STPointN(N + 1) as Point
FROM GeometryPoints GP
WHERE N < @Geometry.STNumPoints()
)
SELECT *
FROM GeometryPoints
)
然后,我创建了一个函数,将fnGetPoints
交叉应用于@GeometryCollection
中的每个几何图形以获得点矩阵。使用窗口函数(LAG)查找端点在@Tolerance
内的位置,然后删除这些点。然后,我做了data smear来合并它们共享端点的几何。
CREATE FUNCTION [dbo].[fnSimplifyToLine] (@GeometryCollection GEOMETRY, @Tolerance DECIMAL(19,10))
RETURNS GEOMETRY
AS
BEGIN
DECLARE @PointMatrix TABLE (
PointId INT,
LinestringId INT,
GeometryIndex INT,
GeometryType varchar(100),
PointIndex INT,
Point GEOMETRY,
Duplicate BIT
);
DECLARE @Linestrings TABLE (
LinestringId INT,
PointArrayStr varchar(max)
);
WITH CollectionGeometries(N, Geom) AS (
SELECT
CAST(1 AS DECIMAL(9,2)) as N
,@GeometryCollection.STGeometryN(1) as Geom
UNION ALL
SELECT
CAST(N + 1.0 AS DECIMAL(9,2)) as N
, @GeometryCollection.STGeometryN(N + 1) as Geom
FROM CollectionGeometries CG
WHERE N < @GeometryCollection.STNumGeometries()
), PointMatrix AS (
SELECT
ROW_NUMBER() OVER(ORDER BY G.N, P.N) as PointId
,G.N as GeometryIndex
,G.Geom.STGeometryType() as GeometryType
,P.N as PointIndex
,P.Point
FROM CollectionGeometries G
CROSS APPLY dbo.fnGetPoints(Geom) P
)
INSERT INTO @PointMatrix
SELECT
PointId
,GeometryIndex as LinestringId
,GeometryIndex
,GeometryType
,PointIndex
,Point
,CASE
WHEN
GeometryIndex != LAG(GeometryIndex) OVER(ORDER BY PointId)
AND ABS(Point.STX - LAG(Point.STX) OVER(ORDER BY PointId)) <= @Tolerance
AND ABS(Point.STY - LAG(Point.STY) OVER(ORDER BY PointId)) <= @Tolerance
THEN 1
ELSE 0
END as Duplicate
FROM PointMatrix
OPTION (MAXRECURSION 10000)
-- POLYGON, MULTIPOLYGON, GEOMETRYCOLLECTION, CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON not supported
IF EXISTS ( SELECT * FROM @PointMatrix WHERE GeometryType NOT IN ('POINT', 'MULTIPOINT', 'LINESTRING', 'MULTILINESTRING'))
RETURN CAST('Geometries in @GeometryCollection must all be IN (''POINT'',''MULTIPOINT'', ''LINESTRING'', ''MULTILINESTRING'')' as GEOMETRY);
DECLARE @SRID INT = (SELECT DISTINCT Point.STSrid FROM @PointMatrix)
UPDATE @PointMatrix
SET LinestringId = NULL
WHERE GeometryIndex IN (
SELECT GeometryIndex FROM @PointMatrix WHERE Duplicate = 1
)
DELETE @PointMatrix
WHERE Duplicate = 1;
-- Data smear
WITH Cnt AS (
SELECT PointId, Point, LinestringId,c=COUNT(LinestringId) OVER (ORDER BY PointId)
FROM @PointMatrix
), SmearedLineStringId AS (
SELECT PointId, Point, LinestringId=MAX(LinestringId) OVER (PARTITION BY c)
FROM Cnt
)
INSERT @Linestrings
SELECT
LinestringId
,'(' +
STUFF((
SELECT ',' + CAST(Point.STX as varchar(100)) + ' ' + CAST(Point.STY as varchar(100))
FROM SmearedLineStringId t2
WHERE t1.LinestringId = t2.LinestringId
ORDER BY PointId
FOR XML PATH ('')
), 1, 1, '')
+ ')' as PointArray
FROM SmearedLineStringId t1
GROUP BY LinestringId
DECLARE @Type varchar(100) = CASE
WHEN 1 =(SELECT COUNT(*) FROM @PointMatrix) THEN
'POINT'
WHEN 1 =(SELECT COUNT(*) FROM @Linestrings) THEN
'LINESTRING'
ELSE
'MULTILINESTRING'
END
DECLARE @BeginParens char(1) = '(';
DECLARE @EndParens char(1) = ')'
IF @Type != 'MULTILINESTRING'
BEGIN
SET @BeginParens = '';
SET @EndParens = '';
END
DECLARE @Wkt varchar(max) = @Type + @BeginParens +
STUFF((
SELECT ',' + PointArrayStr
FROM @Linestrings t2
ORDER BY LinestringId
FOR XML PATH ('')
), 1, 1, '')
+ @EndParens
RETURN Geometry::STGeomFromText(@Wkt, @SRID)
END
GO