-
Notifications
You must be signed in to change notification settings - Fork 26
/
Containers.cs
270 lines (243 loc) · 7.67 KB
/
Containers.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
namespace RevitExportGltf
{
/// <summary>
/// Container for holding a strict set of items
/// that is also addressable by a unique ID.
/// </summary>
/// <typeparam name="T">The type of item contained.</typeparam>
class IndexedDictionary<T>
{
private Dictionary<string, int> _dict = new Dictionary<string, int>();
public List<T> List { get; } = new List<T>();
public string CurrentKey { get; private set; }
public Dictionary<string,T> Dict
{
get
{
var output = new Dictionary<string, T>();
foreach (var kvp in _dict)
{
output.Add(kvp.Key, List[kvp.Value]);
}
return output;
}
}
/// <summary>
/// The most recently accessed item (not effected by GetElement()).
/// </summary>
public T CurrentItem
{
get { return List[_dict[CurrentKey]]; }
}
/// <summary>
/// The index of the most recently accessed item (not effected by GetElement()).
/// </summary>
public int CurrentIndex
{
get { return _dict[CurrentKey]; }
}
/// <summary>
/// Add a new item to the list, if it already exists then the
/// current item will be set to this item.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <param name="elem">The item to add.</param>
/// <returns>true if item did not already exist.</returns>
public bool AddOrUpdateCurrent(string uuid, T elem)
{
if (!_dict.ContainsKey(uuid))
{
List.Add(elem);
_dict.Add(uuid, (List.Count - 1));
CurrentKey = uuid;
return true;
}
CurrentKey = uuid;
return false;
}
/// <summary>
/// Check if the container already has an item with this key.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <returns></returns>
public bool Contains(string uuid)
{
return _dict.ContainsKey(uuid);
}
/// <summary>
/// Returns the index for an item given it's unique identifier.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <returns>index of item or -1</returns>
public int GetIndexFromUUID(string uuid)
{
if (!Contains(uuid)) throw new Exception("Specified item could not be found.");
return _dict[uuid];
}
/// <summary>
/// Returns an item given it's unique identifier.
/// </summary>
/// <param name="uuid">Unique identifier for the item</param>
/// <returns>the item</returns>
public T GetElement(string uuid)
{
int index = GetIndexFromUUID(uuid);
return List[index];
}
/// <summary>
/// Returns as item given it's index location.
/// </summary>
/// <param name="index">The item's index location.</param>
/// <returns>the item</returns>
public T GetElement(int index)
{
if (index < 0 || index > List.Count - 1) throw new Exception("Specified item could not be found.");
return List[index];
}
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// A vertex lookup class to eliminate
/// duplicate vertex definitions.
/// </summary>
class VertexLookupXyz : Dictionary<XYZ, int>
{
/// <summary>
/// Define equality for Revit XYZ points.
/// Very rough tolerance, as used by Revit itself.
/// </summary>
class XyzEqualityComparer : IEqualityComparer<XYZ>
{
const double _sixteenthInchInFeet = 1.0 / (16.0 * 12.0);
public bool Equals(XYZ p, XYZ q)
{
return p.IsAlmostEqualTo(q, _sixteenthInchInFeet);
}
public int GetHashCode(XYZ p)
{
return Util.PointString(p).GetHashCode();
}
}
public VertexLookupXyz() : base(new XyzEqualityComparer())
{
}
/// <summary>
/// Return the index of the given vertex,
/// adding a new entry if required.
/// </summary>
public int AddVertex(XYZ p)
{
return ContainsKey(p)
? this[p]
: this[p] = Count;
}
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// An integer-based 3D point class.
/// </summary>
class PointInt : IComparable<PointInt>
{
public long X { get; set; }
public long Y { get; set; }
public long Z { get; set; }
/// <summary>
/// Consider a Revit length zero
/// if is smaller than this.
/// </summary>
const double _eps = 1.0e-9;
/// <summary>
/// Conversion factor from feet to millimetres.
/// </summary>
const double _feet_to_mm = 25.4 * 12;
/// <summary>
/// Conversion a given length value
/// from feet to millimetre.
/// </summary>
static long ConvertFeetToMillimetres(double d)
{
if (0 < d)
{
return _eps > d
? 0
: (long)(_feet_to_mm * d + 0.5);
}
else
{
return _eps > -d
? 0
: (long)(_feet_to_mm * d - 0.5);
}
}
public PointInt(XYZ p, bool switch_coordinates)
{
X = ConvertFeetToMillimetres(p.X);
Y = ConvertFeetToMillimetres(p.Y);
Z = ConvertFeetToMillimetres(p.Z);
if (switch_coordinates)
{
X = -X;
long tmp = Y;
Y = Z;
Z = tmp;
}
}
public int CompareTo(PointInt a)
{
long d = X - a.X;
if (0 == d)
{
d = Y - a.Y;
if (0 == d)
{
d = Z - a.Z;
}
}
return (0 == d) ? 0 : ((0 < d) ? 1 : -1);
}
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// A vertex lookup class to eliminate
/// duplicate vertex definitions.
/// </summary>
class VertexLookupInt : Dictionary<PointInt, int>
{
/// <summary>
/// Define equality for integer-based PointInt.
/// </summary>
class PointIntEqualityComparer : IEqualityComparer<PointInt>
{
public bool Equals(PointInt p, PointInt q)
{
return 0 == p.CompareTo(q);
}
public int GetHashCode(PointInt p)
{
return (p.X.ToString()
+ "," + p.Y.ToString()
+ "," + p.Z.ToString())
.GetHashCode();
}
}
public VertexLookupInt() : base(new PointIntEqualityComparer())
{
}
/// <summary>
/// Return the index of the given vertex,
/// adding a new entry if required.
/// </summary>
public int AddVertex(PointInt p)
{
return ContainsKey(p)
? this[p]
: this[p] = Count;
}
}
}