-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGeodesicDistance.cs
153 lines (133 loc) · 4.7 KB
/
GeodesicDistance.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Collections;
using System.Collections.Generic;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using System.Threading.Tasks;
using System.Linq;
public class Script_Instance : GH_ScriptInstance
{
/// <summary>
/// This procedure contains the user code. Input parameters are provided as regular arguments,
/// Output parameters as ref arguments. You don't have to assign output parameters,
/// they will have a default value.
/// </summary>
private void RunScript(Mesh mesh, Point3d startPoint, ref object U)
{
int nVertex = mesh.Vertices.Count;
double[] distances = new double[nVertex];
bool[] visited = new bool[nVertex];
List<int>[] connectedIndices = new List<int>[nVertex];
// Initialize distances and connectedIndices
for (int i = 0; i < nVertex; i++)
{
distances[i] = double.MaxValue;
connectedIndices[i] = new List<int>();
}
// Find nearest vertex to the startPoint and set its distance to 0
int startIndex = FindNearestVertexIndex(mesh, startPoint);
distances[startIndex] = 0.0;
// Populate connected indices
for (int i = 0; i < mesh.TopologyVertices.Count; i++)
{
connectedIndices[i] = mesh.TopologyVertices.ConnectedTopologyVertices(i).ToList();
}
// Dijkstra's Algorithm
PriorityQueue<int, double> vertexQueue = new PriorityQueue<int, double>();
vertexQueue.Enqueue(startIndex, 0.0);
while (vertexQueue.Count > 0)
{
int i = vertexQueue.Dequeue();
if (visited[i]) continue;
visited[i] = true;
foreach (int j in connectedIndices[i])
{
double tentativeDistance = distances[i] + mesh.Vertices[i].DistanceTo(mesh.Vertices[j]);
if (tentativeDistance < distances[j])
{
distances[j] = tentativeDistance;
vertexQueue.Enqueue(j, tentativeDistance);
}
}
}
// Convert distances to GH_Number and return
U = distances.Select(d => new GH_Number(d)).ToArray();
}
// <Custom additional code>
private static int FindNearestVertexIndex(Mesh mesh, Point3d point)
{
double minDistance = double.MaxValue;
int nearestIndex = -1;
for (int i = 0; i < mesh.Vertices.Count; i++)
{
double distance = point.DistanceTo(mesh.Vertices[i]);
if (distance < minDistance)
{
minDistance = distance;
nearestIndex = i;
}
}
return nearestIndex;
}
public class PriorityQueueNode<TElement, TPriority> where TPriority : IComparable<TPriority>
{
public TElement Element { get; set; }
public TPriority Priority { get; set; }
public PriorityQueueNode(TElement element, TPriority priority)
{
Element = element;
Priority = priority;
}
}
public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TPriority>
{
private List<PriorityQueueNode<TElement, TPriority>> elements = new List<PriorityQueueNode<TElement, TPriority>>();
public int Count
{
get
{
return elements.Count;
}
}
public void Enqueue(TElement element, TPriority priority)
{
var node = new PriorityQueueNode<TElement, TPriority>(element, priority);
elements.Add(node);
int ci = elements.Count - 1; // Child index; start at end
while (ci > 0)
{
int pi = (ci - 1) / 2; // Parent index
if (elements[ci].Priority.CompareTo(elements[pi].Priority) >= 0) break; // Child item is larger than (or equal) parent so we're done
var tmp = elements[ci]; elements[ci] = elements[pi]; elements[pi] = tmp;
ci = pi;
}
}
public TElement Dequeue()
{
// Assumes pq is not empty
int li = elements.Count - 1; // Last index (before removal)
var frontItem = elements[0]; // Fetch the front
elements[0] = elements[li];
elements.RemoveAt(li);
--li; // Last index (after removal)
int pi = 0; // Parent index. Start at front of pq
while (true)
{
int ci = pi * 2 + 1; // Left child index of parent
if (ci > li) break; // No children so done
int rc = ci + 1; // Right child
if (rc <= li && elements[rc].Priority.CompareTo(elements[ci].Priority) < 0) // If there is a right child and it is smaller than left child, use the right child instead
ci = rc;
if (elements[pi].Priority.CompareTo(elements[ci].Priority) <= 0) break; // Parent is smaller than (or equal to) smallest child so done
var tmp = elements[pi]; elements[pi] = elements[ci]; elements[ci] = tmp; // Swap parent and child
pi = ci;
}
return frontItem.Element;
}
}
// </Custom additional code>
}