tree = printer.TreeToString();
21 |
22 | for (int y = 0; y < tree.Count; y++)
23 | {
24 | Console.WriteLine(tree[y]);
25 | }
26 |
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Parser for reading ISO 10303-21 STEP files.
2 |
3 | I needed to extract certain geometric elements from STEP files, so I put together this very basic module to handle the parsing phase of the process.
4 | This can be easily extended to other ISO 10303 formats by swapping the EXPRESS schema
5 |
6 | Various express schemas are avaliable here: https://github.com/stepcode/stepcode/tree/develop/data
7 |
8 |
9 | Sample output of tree after parsing:
10 |
11 |
12 | 1 APPLICATION_PROTOCOL_DEFINITION
13 | └──2 APPLICATION_CONTEXT
14 | 3 SHAPE_DEFINITION_REPRESENTATION
15 | ├──4 PRODUCT_DEFINITION_SHAPE
16 | │ └──5 PRODUCT_DEFINITION
17 | │ ├──6 PRODUCT_DEFINITION_FORMATION_WITH_SPECIFIED_SOURCE
18 | │ │ └──7 PRODUCT
19 | │ │ └──8 MECHANICAL_CONTEXT
20 | │ │ └──2 APPLICATION_CONTEXT
21 | │ └──9 DESIGN_CONTEXT
22 | │ └──2 APPLICATION_CONTEXT
23 | └──10 ADVANCED_BREP_SHAPE_REPRESENTATION
24 | ├──11 AXIS2_PLACEMENT_3D
25 | │ ├──12 CARTESIAN_POINT
26 | │ ├──13 DIRECTION
27 | │ └──14 DIRECTION
28 | ├──15 MANIFOLD_SOLID_BREP
29 | │ └──16 CLOSED_SHELL
30 | │ ├──17 ADVANCED_FACE
31 | │ │ ├──18 FACE_BOUND
32 | │ │ │ └──19 EDGE_LOOP
33 | │ │ │ ├──20 ORIENTED_EDGE
34 | │ │ │ │ └──21 EDGE_CURVE
35 | │ │ │ │ ├──22 VERTEX_POINT
36 | │ │ │ │ │ └──23 CARTESIAN_POINT
37 | │ │ │ │ ├──24 VERTEX_POINT
38 | │ │ │ │ │ └──25 CARTESIAN_POINT
39 | │ │ │ │ └──26 SURFACE_CURVE
40 | │ │ │ │ ├──27 LINE
41 | │ │ │ │ │ ├──28 CARTESIAN_POINT
42 | │ │ │ │ │ └──29 VECTOR
43 | │ │ │ │ │ └──30 DIRECTION
44 | │ │ │ │ ├──31 PCURVE
45 | │ │ │ │ │ ├──32 PLANE
46 | │ │ │ │ │ │ └──33 AXIS2_PLACEMENT_3D
47 | │ │ │ │ │ │ ├──34 CARTESIAN_POINT
48 | │ │ │ │ │ │ ├──35 DIRECTION
49 | │ │ │ │ │ │ └──36 DIRECTION
50 | │ │ │ │ │ └──37 DEFINITIONAL_REPRESENTATION
51 | │ │ │ │ │ ├──38 LINE
52 | │ │ │ │ │ │ ├──39 CARTESIAN_POINT
53 | │ │ │ │ │ │ └──40 VECTOR
54 | │ │ │ │ │ │ └──41 DIRECTION
55 | │ │ │ │ │ └──42 COMPLEX
56 |
57 |
--------------------------------------------------------------------------------
/STEP Parser.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9E8856DE-0720-4614-BE31-EED9274CF46C}
8 | Exe
9 | STEP_Parser
10 | STEP Parser
11 | v4.6.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/STEP Parser.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31019.35
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STEP Parser", "STEP Parser.csproj", "{9E8856DE-0720-4614-BE31-EED9274CF46C}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {9E8856DE-0720-4614-BE31-EED9274CF46C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {9E8856DE-0720-4614-BE31-EED9274CF46C}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {9E8856DE-0720-4614-BE31-EED9274CF46C}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {9E8856DE-0720-4614-BE31-EED9274CF46C}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {ABA53055-6295-4758-8903-E3FFEDB6B09B}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/StepFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.IO;
5 | using System.Text.RegularExpressions;
6 | using System.Linq;
7 |
8 |
9 |
10 | namespace STEP_Parser
11 | {
12 | public class StepFile
13 | {
14 | public StepFile(string fn, EXPRESS_Schema schema)
15 | {
16 | var watch = System.Diagnostics.Stopwatch.StartNew();
17 | this.filename = fn;
18 | this.AP203 = schema;
19 |
20 | EntityParse(fn);
21 |
22 | watch.Stop();
23 | var elapsedMs = watch.ElapsedMilliseconds;
24 | Console.WriteLine("Step File Parsed in " + elapsedMs.ToString() + " ms");
25 | }
26 |
27 | public string filename;
28 | public Dictionary Entitys;
29 | public EXPRESS_Schema AP203;
30 |
31 | private Dictionary> parentData = new Dictionary>();
32 |
33 |
34 |
35 | public void EntityParse(string fn)
36 | {
37 | TextReader tr = new StreamReader(fn);
38 | string stepstring;
39 | string line;
40 | string datastring;
41 | string[] stringarray;
42 | stepstring = tr.ReadToEnd();
43 |
44 | while ((line = tr.ReadLine()) != null)
45 | {
46 | stepstring += line;
47 | }
48 |
49 | int i1 = stepstring.IndexOf("DATA;");
50 | datastring = stepstring.Substring(i1 + 7);
51 | int i2 = datastring.IndexOf("ENDSEC;");
52 | datastring = datastring.Substring(0, i2 - 1);
53 | datastring = datastring.Replace("\r", "");
54 | datastring = datastring.Replace("\n", "");
55 | stringarray = datastring.Split(';');
56 |
57 | string[] str;
58 | string[] identifier = new string[stringarray.Length];
59 | int[] id_array = new int[stringarray.Length];
60 | Match m1;
61 | Match m2;
62 | Match m_complex;
63 | Regex g = new Regex(@"(?<=(\= ))[^\(]*(?=(\())");
64 |
65 |
66 | //Regex gData = new Regex(@"(?<=\()[^\(].*");
67 |
68 | //Regex gData = new Regex(@"(\((?>[^()]+|(?1))*\))");
69 | Regex gData = new Regex(@"\(((?>[^()]+|\((?)|\)(?<-n>))+(?(n)(?!)))\)");
70 |
71 |
72 |
73 | Regex complexmatch = new Regex(@"[\=]\s*[\(].*[\) ;]");
74 |
75 | string[] datastr = new string[stringarray.Length];
76 |
77 | List entityList = new List();
78 | Entitys = new Dictionary();
79 |
80 | string str_name;
81 | string str_dat;
82 |
83 | for (int i = 0; i < stringarray.Length; i++)
84 | {
85 | if ((!stringarray[i].Contains("#")) || (!stringarray[i].Contains("="))) continue;
86 |
87 | try
88 | {
89 | str = stringarray[i].Split('=');
90 | str[0] = str[0].Replace("#", "");
91 | int id = Convert.ToInt32(str[0]);
92 | id_array[i] = id;
93 | m1 = g.Match(stringarray[i]);
94 | m_complex = complexmatch.Match(stringarray[i]);
95 |
96 | if (m1.Success & m1.Length>0 & m_complex.Length<1)
97 | {
98 | str_name = m1.Groups[0].Value.Trim(); //name
99 | m2 = gData.Match(stringarray[i]);
100 | if (m1.Success)
101 | {
102 | //str_dat = m2.Groups[0].Value.Trim().TrimEnd(')');
103 | str_dat = m2.Groups[1].Value.Trim();
104 | Entity ent = new Entity(id, str_name, str_dat, AP203);
105 | Entitys[id] = ent;
106 | }
107 | }
108 |
109 | if (m_complex.Success && m_complex.Length > 0)
110 | {
111 | // int t = 0;
112 | str_dat = m_complex.Groups[0].Value.Trim(); //data
113 | str_dat = str_dat.TrimStart('=', '(');
114 | str_dat = str_dat.TrimEnd(';');
115 | str_dat = str_dat.TrimEnd(')');
116 |
117 | List splitLocations = new List();
118 | splitLocations.Add(0);
119 | int level = 0;
120 | for (int j = 0; j < str_dat.Length; j++)
121 | {
122 | if (str_dat[j] == '(') level++;
123 | if (str_dat[j] == ')') level--;
124 | if (str_dat[j] == ')' && level == 0)
125 | {
126 | splitLocations.Add(j + 1);
127 | }
128 | }
129 | List entList = new List();
130 | for (int j = 1; j < splitLocations.Count; j++)
131 | {
132 | entList.Add(str_dat.Substring(splitLocations[j - 1], splitLocations[j] - splitLocations[j - 1]).Trim());
133 | }
134 |
135 | List types = new List();
136 |
137 | for (int j = 0; j < entList.Count; j++)
138 | {
139 | int location1 = entList[j].IndexOf(' ');
140 | int location2 = entList[j].IndexOf('(');
141 | int location;
142 |
143 | if (location1 > 0) location = Math.Min(location1, location2);
144 | else location = location2;
145 |
146 | string type = entList[j].Substring(0, location);
147 | types.Add(type);
148 | }
149 | EntityComplex EntC = new EntityComplex(id, types, entList, this.AP203);
150 | Entitys.Add(id, EntC);
151 | }
152 | }
153 | catch (Exception ex)
154 | {
155 | Console.WriteLine("Exception while parsing entity " + ex.ToString());
156 | }
157 | }
158 |
159 |
160 |
161 | foreach (KeyValuePair entry in Entitys)
162 | {
163 | List flattenedAttributeList = GetFlattenedAttributes(entry.Value.attributesConverted);
164 |
165 | foreach (dynamic item in flattenedAttributeList)
166 | {
167 | if (item.GetType() == typeof(RefID))
168 | {
169 | List existingList;
170 |
171 | if (parentData.TryGetValue(item.id, out existingList)) //if key exists add to the existing parent list
172 | {
173 | parentData[item.id].Add(entry.Value.entityID);
174 | }
175 | else //otherwise create a key and new list
176 | {
177 | parentData[item.id] = new List { entry.Value.entityID };
178 | }
179 | }
180 | }
181 | }
182 | }
183 |
184 |
185 | //get flattened list of all attributes including those in sub-lists
186 | public List GetFlattenedAttributes(List inputList)
187 | {
188 | if (inputList == null) return new List();
189 |
190 | List flattenedList = new List();
191 | foreach (dynamic listItem in inputList)
192 | {
193 | if (listItem is System.Collections.IList)
194 | {
195 | flattenedList.AddRange(GetFlattenedAttributes(listItem));
196 | }
197 | else
198 | {
199 | flattenedList.Add(listItem);
200 | }
201 | }
202 | return flattenedList;
203 | }
204 |
205 |
206 | public List GetAllParents(int id)
207 | {
208 | try
209 | {
210 | var test = parentData[id];
211 | return parentData[id];
212 | }
213 | catch
214 | {
215 | return new List();
216 | }
217 | }
218 |
219 |
220 | public List GetChildren(int id)
221 | {
222 | if (id==-1)
223 | {
224 | return new List();
225 | }
226 |
227 | Entity e1 = Entitys[id];
228 | List childIDs = new List();
229 |
230 | if (e1.attributesConverted==null) return new List();
231 |
232 | foreach (dynamic item in e1.attributesConverted)
233 | {
234 | if (item.GetType() == typeof(RefID))
235 | {
236 | childIDs.Add(item.id);
237 | }
238 | if (item.GetType() == typeof(List