Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProgram.cs
More file actions
Latest commit
182 lines (158 loc) · 7.76 KB
/
Copy pathProgram.cs
File metadata and controls
182 lines (158 loc) · 7.76 KB
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
// MIT License
// Copyright the Difference Engine Team AECTech 20222 Hackathon
//
// This program uses the VIM SDK (visit https://vimaec.com) to compute
// delta from a list of VIM files in a folder.
// The folder is passed as a command line arguments
// For every two files compared a JSON file is created containing the list of deltas
// And a geometry file is output in OBJ form for each type of change.
usingSystem.Diagnostics;
usingVim;
usingVim.DotNetUtilities;
usingVim.DotNetUtilities.JsonSerializer;
usingVim.G3d;
usingVim.Geometry;
usingVim.Math3d;
// The different types of changes computed
publicenumChangeType
{
Unchanged,// No detected change
Addition,// Addition of a new element ID
Deletion,// Removal of an element (looking at element ID)
Resized,// Change in volumen of the bounding box
Moved,// Movement of the center of the bounding box in world space
Changed,// A change to one of the parameters
};
// Expresses the difference between a node and the previous node.
recordChangeRecord(
stringChangeType,
stringCategory,
stringFamilyName,
stringFamilyType,
stringPreviousFamilyType,
intElementId,
floatVolume,
floatVolumeChange,
Vector3Center,
floatDistanceMoved,
intNodeIndex
);
publicstaticclassProgram
{
// The different change types represented as strings
publicstaticreadonlyIReadOnlyList<string>ChangeTypes
=Enum.GetNames(typeof(ChangeType));
// The amount of volume change required to consider an object resized (calculated from bounding box)
publicconstfloatVolumeTolerance=1.0f/12;
// The distance required to be moved (calculated from bounding box centers) before an object is considered moved
publicconstfloatPositionTolerance=1.0f/12;
// Creates a change record for a node in the VIM file compared to the previous VIM file
staticChangeRecordCreateChangeRecord(ChangeTypechangeType,VimSceneNodenode,VimSceneNode?prevNode)
{
varbox=node.TransformedBoundingBox();
if(prevNode==null)
{
returnnew(changeType.ToString(),node.CategoryName,node.FamilyName,node.FamilyTypeName,"",node.ElementId,
box.Volume,0,box.Center,0,node.Id);
}
varprevBox=prevNode.TransformedBoundingBox();
returnnew(changeType.ToString(),node.CategoryName,node.FamilyName,node.FamilyTypeName,prevNode.FamilyTypeName,
node.ElementId,box.Volume,box.Volume-prevBox.Volume,box.Center,prevBox.Center.Distance(box.Center),
node.Id);
}
// Outputs a single OBJ file containing the geometry of all objects of a specific change Type
staticvoidOutputObj(IEnumerable<ChangeRecord>changes,VimScenevim,ChangeTypechangeType,intprefix,
stringoutputFolder)
{
varmeshes=changes.Where(c =>c.ChangeType==changeType.ToString())
.Select(c =>vim.VimNodes[c.NodeIndex].TransformedMesh());
if(!meshes.Any())return;
meshes.Merge().ToG3d().WriteObj(Path.Combine(outputFolder,$"{changeType}_{prefix}.obj"));
}
// A simplistic computation to check if the family or family type changed.
// A more sophisticated algorithm would create a detailed comparison of parameters and common field values
staticboolIsChanged(VimSceneNodenode1,VimSceneNodenode2)
=>node1.FamilyName!=node2.FamilyName
||node1.FamilyTypeName!=node2.FamilyTypeName;
/// Main entry point of the script
publicstaticvoidMain(paramsstring[]args)
{
// Start a stopwatch
varsw=Stopwatch.StartNew();
// The first parameter on the command line is the input folder
varinputFolder=args[0];
// Get all of the VIM files in the input folder ordered by their name
varvimFilePaths=Directory.GetFiles(inputFolder,"*.vim").OrderBy(f =>f).ToList();
// Output folder is created as a sub-folder of the input folder and is named
varoutputFolder=Path.Combine(inputFolder,"output");
Util.CreateAndClearDirectory(outputFolder);
// We are going to loop through all VIM files and load them in memory one by one
// comparing with the previous one.
varprevVim=VimScene.LoadVim(vimFilePaths[0]);
for(vari=0;i<vimFilePaths.Count;++i)
{
// When looking at the first file we have to treat it as a special case, so current and previous is the same
varcurrVim=i>0?VimScene.LoadVim(vimFilePaths[i]):prevVim;
varprevNodes=prevVim.VimNodesWithGeometry().ToDictionaryIgnoreDuplicates(n =>n.ElementId, n =>n);
varcurrNodes=currVim.VimNodesWithGeometry().ToDictionaryIgnoreDuplicates(n =>n.ElementId, n =>n);
varchanges=newList<ChangeRecord>();
foreach(varcurrNodeincurrVim.VimNodesWithGeometry())
{
// All nodes in the first file are treated as additions
// In other files,
if(i==0||!prevNodes.ContainsKey(currNode.ElementId))
{
changes.Add(CreateChangeRecord(ChangeType.Addition,currNode,null));
}
else
{
// Look for the different possible types of change
varprevNode=prevNodes[currNode.ElementId];
varprevBox=prevNode.TransformedBoundingBox();
varcurrBox=currNode.TransformedBoundingBox();
if(IsChanged(prevNode,currNode))
{
changes.Add(CreateChangeRecord(ChangeType.Changed,currNode,prevNode));
}
elseif(!prevBox.Volume.AlmostEquals(currBox.Volume,VolumeTolerance))
{
changes.Add(CreateChangeRecord(ChangeType.Resized,currNode,prevNode));
}
elseif(!prevBox.Center.AlmostEquals(currBox.Center,PositionTolerance))
{
changes.Add(CreateChangeRecord(ChangeType.Moved,currNode,prevNode));
}
else
{
changes.Add(CreateChangeRecord(ChangeType.Unchanged,currNode,prevNode));
}
}
}
// To look for deleted nodes we have to loop through the previous nodes
// We can skip this process if we are in a new node
if(i!=0)
{
foreach(varnode1inprevVim.VimNodesWithGeometry())
{
if(!currNodes.ContainsKey(node1.ElementId))
{
changes.Add(CreateChangeRecord(ChangeType.Deletion,node1,null));
}
}
}
// Output a merged OBJ for each change type
OutputObj(changes,currVim,ChangeType.Changed,i,outputFolder);
OutputObj(changes,currVim,ChangeType.Moved,i,outputFolder);
OutputObj(changes,currVim,ChangeType.Resized,i,outputFolder);
OutputObj(changes,currVim,ChangeType.Addition,i,outputFolder);
OutputObj(changes,currVim,ChangeType.Unchanged,i,outputFolder);
// Notice that Deletion records required the previous VIM
OutputObj(changes,prevVim,ChangeType.Deletion,i,outputFolder);
// The delta file contains all of the change records
vardeltaFile=Path.Combine(outputFolder,$"delta_{i}.json");
changes.ToJsonFile(deltaFile);
prevVim=currVim;
}
Util.OutputTimeElapsed(sw,"Computing all deltas");
}
}