J'ai une table qui contient des informations sur les arêtes du graphe sous forme de geometry linessortingng
de geometry linessortingng
. Le résultat spatial de la requête select * from edge
ressemble à ceci CHAQUE
linessortingng
est toujours créée à partir de deux geometry points
avec une instruction insert comme:
INSERT INTO edge VALUES( geometry::Parse('LINESTRING(1 1 ,1 2)'))
Afin de find le path le plus court entre deux points j'ai implémenté l'algorithm de Dijkstra
selon Dijkstra en c # , cependant j'ai découvert la fonction STDistance () qui est de faire la même chose en exécutant une requête simple. Quelqu'un pourrait-il me donner un indice comment pourrais-je utiliser STDistance
avec des objects créés comme je l'ai décrit? Chaque exemple que je trouve utilise des linessortingngs
créées à partir de 3 points.
J'ai de la difficulté à utiliser l'exemple dans la situation que j'ai linessortingngs
dire 3 linessortingngs
comme ci-dessous:
INSERT INTO edge VALUES( geometry::Parse('LINESTRING(1 1 ,1 2)')) INSERT INTO edge VALUES( geometry::Parse('LINESTRING(1 2 ,1 3)')) INSERT INTO edge VALUES( geometry::Parse('LINESTRING(1 3 ,1 4)'))
et find le path le plus court de 1 1
à 1 4
Edit: J'ai réussi à combiner toutes les lignes en une forme en:
SELECT geometry::UnionAggregate(linessortingng) FROM edge
je reçois la forme:
Maintenant, j'utilise STDistance
comme suit:
SELECT (geometry::UnionAggregate(linessortingng)).STDistance(geometry::STGeomFromText('POINT(0 0)', 0)) FROM edge
Cependant la valeur de return est sur la distance entre le point (0,0) et la forme présentée, quand mon intention est de countr la longueur des bords d'un point à l'autre, des indices?
Code Kata . Comme d'autres l'ont dit dans les commentaires, STDistance vous donnera la distance de ligne droite minimale entre deux objects de geometry, pas un path à travers un graphique. L'implémentation de Dijkstra dans Sql me dépasse, mais la méthode de la force brute est acceptable pour un petit nombre de nœuds tel que vous l'avez démontré. Ce code calcule tous les paths dans le graphique de A à B, puis sélectionne le plus court.
S'il vous plaît noter que ceci est seulement une preuve que cela peut être fait, pas une recommandation que cela devrait être fait. Votre code existant dans c # est probablement plus simple et plus rapide.
Merci de m'avoir donné l'opportunité d'apprendre les fonctions de geometry dans le server sql.
-- Declare and set parameters. DECLARE @start geometry, @end geometry SET @start = geometry::STGeomFromText('POINT(-1 1)', 0); SET @end = geometry::STGeomFromText('POINT(1 3)', 0); -- Caching of ST function results and for reversibility. DECLARE @segments TABLE ( edge geometry, start_point geometry, end_point geometry, [weight] float ) INSERT @segments ( edge, start_point, end_point, [weight]) SELECT e, e.STStartPoint(), e.STEndPoint(), e.STLength() FROM edge UNION ALL -- Can traverse edges both ways unless we're in a directed graph? SELECT e, e.STEndPoint(), e.STStartPoint(), e.STLength() FROM edge -- We need to know number of edges for some bookkeeping later. DECLARE @total_edges INT SELECT @total_edges = COUNT(*) FROM edge; -- Meat of the procedure. Find all sensible paths from @start to @end allowed by the graph, using a recursive common table expression. WITH cte (path, start_point, end_point, [weight], segments_traversed) AS ( SELECT edge AS path, start_point, end_point, [weight] , 1 AS segments_traversed FROM @segments WHERE @start.STEquals(start_point) = 1 UNION ALL SELECT c.path.STUnion(s.edge) AS PATH, s.start_point, s.end_point, s.[weight] + c.[weight] AS weight, c.segments_traversed + 1 AS segments_traversed FROM cte c INNER JOIN @segments s ON -- next edge must start where this one ended. s.start_point.STEquals(c.end_point) = 1 AND -- terminate paths that hit the endpoint. c.start_point.STEquals(@end) = 0 AND -- if we traveled more than the number of edges there's surely a better path that doesn't loop! -- also acts as a guarantee of termination. c.segments_traversed < @total_edges ) SELECT TOP 1 path FROM cte c WHERE -- Ressortingct to paths ending at end point. c.end_point.STEquals(@end) = 1 ORDER BY weight ASC