1- using CSMath ;
2- using CSUtilities . Converters ;
3- using CSUtilities . IO ;
4- using MeshIO . Entities . Geometries ;
5- using MeshIO . Entities . Geometries . Layers ;
1+ using MeshIO . Entities . Geometries ;
2+ using System ;
3+ using System . Collections . Generic ;
64using System . IO ;
7- using System . Text . RegularExpressions ;
5+ using System . Text ;
86
97namespace MeshIO . Formats . Stl
108{
@@ -41,31 +39,46 @@ public StlReader(Stream stream, NotificationEventHandler notification = null)
4139 }
4240
4341 /// <summary>
44- /// Determines whether the underlying stream contains data in binary format .
42+ /// Determines the content type of a mesh stream by inspecting its header .
4543 /// </summary>
46- /// <remarks>This method inspects the stream from its beginning to assess whether the data is in binary format.
47- /// The stream position is reset to the start before analysis. Calling this method will modify the stream's current
48- /// position.</remarks>
49- /// <returns>true if the stream is detected to be in binary format; otherwise, false.</returns>
50- public bool IsBinary ( )
44+ /// <remarks>The method reads the first five bytes of the stream to identify the content type. The stream
45+ /// position is reset to its original position after the operation. The method assumes the stream contains data in a
46+ /// supported mesh format.</remarks>
47+ /// <param name="stream">The input stream containing mesh data to analyze. The stream must be readable and seekable.</param>
48+ /// <returns>A value indicating whether the mesh data in the stream is in ASCII or binary format.</returns>
49+ /// <exception cref="NullReferenceException">Thrown if <paramref name="stream"/> is null.</exception>
50+ public static MeshIO . Formats . ContentType GetContentType ( Stream stream )
5151 {
52- this . _stream . Position = 0 ;
53- this . _stream . ReadString ( 80 ) ;
54- int nTriangles = this . _stream . ReadInt < LittleEndianConverter > ( ) ;
52+ if ( stream == null )
53+ {
54+ throw new NullReferenceException ( nameof ( stream ) ) ;
55+ }
56+
57+ if ( stream . Length < 5 )
58+ {
59+ return ContentType . Binary ;
60+ }
61+
62+ byte [ ] buffer = new byte [ 5 ] ;
63+ string header ;
64+
65+ stream . Seek ( 0 , SeekOrigin . Begin ) ;
66+ stream . Read ( buffer , 0 , buffer . Length ) ;
67+ stream . Seek ( 0 , SeekOrigin . Begin ) ;
5568
56- return this . checkStreamLenth ( nTriangles ) ;
69+ header = Encoding . ASCII . GetString ( buffer ) ;
70+
71+ return StlFileToken . Solid . Equals ( header , StringComparison . InvariantCultureIgnoreCase ) ? ContentType . ASCII : ContentType . Binary ;
5772 }
5873
74+ /// <inheritdoc/>
5975 public override Scene Read ( )
6076 {
6177 Scene scene = new Scene ( ) ;
6278
63- Mesh mesh = this . ReadAsMesh ( ) ;
79+ var meshes = this . ReadMeshes ( ) ;
6480
65- Node node = new Node ( mesh . Name ) ;
66- node . Entities . Add ( mesh ) ;
67-
68- scene . RootNode . Nodes . Add ( node ) ;
81+ scene . RootNode . Entities . AddRange ( meshes ) ;
6982
7083 return scene ;
7184 }
@@ -74,99 +87,31 @@ public override Scene Read()
7487 /// Read the STL file
7588 /// </summary>
7689 /// <returns><see cref="Mesh"/> defined in the file</returns>
77- public Mesh ReadAsMesh ( )
90+ public IEnumerable < Mesh > ReadMeshes ( )
7891 {
7992 this . _stream . Position = 0 ;
8093
81- string header = this . _stream . ReadString ( 80 ) ;
82- this . triggerNotification ( header . Replace ( "\0 " , "" ) , NotificationType . Information ) ;
83-
84- Mesh mesh = new Mesh ( ) ;
85- LayerElementNormal normals = new LayerElementNormal ( ) ;
86- mesh . Layers . Add ( normals ) ;
87-
88- int nTriangles = this . _stream . ReadInt < LittleEndianConverter > ( ) ;
89-
90- if ( this . checkStreamLenth ( nTriangles ) )
94+ IStlStreamReader reader = null ;
95+ var contentType = StlReader . GetContentType ( this . _stream . Stream ) ;
96+ switch ( contentType )
9197 {
92- for ( int i = 0 ; i < nTriangles ; i ++ )
93- {
94- XYZ normal = new XYZ ( this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) ) ;
95-
96- normals . Add ( normal ) ;
97-
98- XYZ v1 = new XYZ ( this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) ) ;
99- XYZ v2 = new XYZ ( this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) ) ;
100- XYZ v3 = new XYZ ( this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) , this . _stream . ReadSingle ( ) ) ;
101-
102- mesh . AddPolygons ( v1 , v2 , v3 ) ;
103-
104- ushort attByteCount = this . _stream . ReadUShort ( ) ;
105- }
98+ case ContentType . Binary :
99+ reader = new StlBinaryStreamReader ( this . _stream . Stream ) ;
100+ break ;
101+ case ContentType . ASCII :
102+ reader = new StlTextStreamReader ( this . _stream . Stream ) ;
103+ break ;
106104 }
107- else
108- {
109- this . _stream . Position = 0 ;
110-
111- string line = this . _stream . ReadUntil ( '\n ' ) ;
112- string name = Regex . Match ( line , @"solid \s\n" , options : RegexOptions . IgnoreCase ) . Value ;
113- mesh . Name = name ;
114105
115- line = this . _stream . ReadUntil ( ' \n ' ) ;
106+ reader . OnNotification + = this . onNotificationEvent ;
116107
117- while ( ! line . Contains ( $ "endsolid { name } ") )
118- {
119- XYZ normal = this . readPoint ( line , "facet normal" ) ;
120- normals . Add ( normal ) ;
121-
122- this . checkLine ( this . _stream . ReadUntil ( '\n ' ) , "outer loop" ) ;
123-
124- XYZ v1 = this . readPoint ( this . _stream . ReadUntil ( '\n ' ) , "vertex" ) ;
125- XYZ v2 = this . readPoint ( this . _stream . ReadUntil ( '\n ' ) , "vertex" ) ;
126- XYZ v3 = this . readPoint ( this . _stream . ReadUntil ( '\n ' ) , "vertex" ) ;
127-
128- mesh . AddPolygons ( v1 , v2 , v3 ) ;
129-
130- this . checkLine ( this . _stream . ReadUntil ( '\n ' ) , "endloop" ) ;
131- this . checkLine ( this . _stream . ReadUntil ( '\n ' ) , "endfacet" ) ;
132-
133- line = this . _stream . ReadUntil ( '\n ' ) ;
134- }
135- }
136-
137- return mesh ;
108+ return reader . Read ( ) ;
138109 }
139110
140111 /// <inheritdoc/>
141112 public override void Dispose ( )
142113 {
143114 this . _stream . Dispose ( ) ;
144115 }
145-
146- private bool checkStreamLenth ( int nTriangles )
147- {
148- //Compare the length of the stream to check if is ascii file
149- return this . _stream . Length == 84 + nTriangles * 50 ;
150- }
151-
152- private void checkLine ( string line , string match )
153- {
154- if ( string . IsNullOrEmpty ( match ) &&
155- Regex . Match ( line , match + @" \s\n" , options : RegexOptions . IgnoreCase ) . Success )
156- {
157- throw new StlException ( $ "Expected match: { match } | line: { line } ") ;
158- }
159- }
160-
161- private XYZ readPoint ( string line , string match )
162- {
163- this . checkLine ( line , match ) ;
164-
165- var x = Regex . Match ( line , @"\d+(\.\d+)?" ) ;
166- var y = x . NextMatch ( ) ;
167- var z = y . NextMatch ( ) ;
168-
169- return new XYZ ( double . Parse ( x . Value ) , double . Parse ( y . Value ) , double . Parse ( z . Value ) ) ;
170- }
171116 }
172117}
0 commit comments