- UID
- 1
- 精华
- 积分
- 76365
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
这个类用于读取stl格式的3D模型(一种后缀是.stl的3D模型文件,这个和C++的stl库无关)
stl格式的3D模型可以被几乎所有的3D软件加载,比如3dsmax或maya。
不保证有无BUG。可以用于研究stl的文件格式。
原作者:嗷嗷叫的老马
这是一个VB6的类,不是VB.NET的东西。
据说……这种格式不存储纹理坐标。- VERSION 1.0 CLASS
- BEGIN
- MultiUse = -1 'True
- Persistable = 0 'NotPersistable
- DataBindingBehavior = 0 'vbNone
- DataSourceBehavior = 0 'vbNone
- MTSTransactionMode = 0 'NotAnMTSObject
- END
- Attribute VB_Name = "cLoadSTL"
- Attribute VB_GlobalNameSpace = False
- Attribute VB_Creatable = True
- Attribute VB_PredeclaredId = False
- Attribute VB_Exposed = False
- Option Explicit
- Option Compare Text
- '加载STL格式文件
- '
- '判断STL文件的格式(ASCII与BINARY),并读入内存
- '
- 'By 嗷嗷叫的老马
- '
- Private Type MyFacet
- PNX As Single '法向量
- PNY As Single '法向量
- PNZ As Single '法向量
-
- P1X As Single '第一个顶点
- P1Y As Single '第一个顶点
- P1Z As Single '第一个顶点
-
- P2X As Single '第一个顶点
- P2Y As Single '第一个顶点
- P2Z As Single '第一个顶点
-
- P3X As Single '第一个顶点
- P3Y As Single '第一个顶点
- P3Z As Single '第一个顶点
-
- FacetProperties As Integer '面片属性
- End Type
- Dim mFileName As String '文件名
- Dim mDescription As String '文件信息
- Dim mData() As MyFacet '三角面片数据
- Dim mFacetIndex As Long '当前索引
- Dim mXMax As Single, mYMax As Single, mXMin As Single, mYMin As Single, mZMin As Single, mZMax As Single
- Public Function LoadSTLFile(ByVal sFileName As String) As Long
- Dim sBuff As String, sLBuff() As String, byteBuff() As Byte, mFacetCount As Long
- Dim IsAscii As Boolean, DataIndex As Long, VIndex As Long
- Dim Fn As Long, I As Long, J As Long, sTmp() As String
-
- ' On Error GoTo errH
-
- LoadSTLFile = -1
-
- If FileLen(sFileName) < 0 Then Exit Function
-
- mFileName = sFileName
-
- mXMax = -999
- mXMin = 999
- mYMax = -999
- mYMin = 999
- mZMax = -999
- mZMin = 999
-
- Fn = FreeFile
- Open mFileName For Binary As #Fn
- ReDim byteBuff(79)
- Get #Fn, , byteBuff()
-
- IsAscii = False
- For I = 0 To 79
- If byteBuff(I) = &HA Then
- IsAscii = True
- Exit For
- End If
- Next
-
- ' MsgBox IsAscii
-
- If IsAscii = True Then 'ASCII格式包含换行符
- '以ASCII格式读取数据
- '
- ' solid OpenSCAD_Model '文件信息
- ' facet normal -1.000000 0.000000 0.000000 '一个三角面片开始,法向量坐标
- ' outer loop '开始描述三角面片顶点坐标
- ' vertex -25.000000 -29.250000 8.000000 '第一个点
- ' vertex -25.000000 -27.586706 7.825181 '第二个点
- ' vertex -25.000000 -30.913294 7.825181 '第三个点
- ' endloop '结束顶点描述
- ' endfacet '一个三角面片结束
- ' endsolid OpenSCAD_Model
-
- sBuff = Space(LOF(1))
- Get #Fn, 1, sBuff
- sLBuff() = Split(Replace(sBuff, Chr(0), " "), vbLf)
-
- ' MsgBox "00"
-
- mFacetCount = -1
-
- mDescription = Replace(sLBuff(0), "solid ", "") '得到文件信息
-
- ' MsgBox "11"
-
- For I = 1 To UBound(sLBuff)
- sTmp() = Split(Trim(sLBuff(I)), " ")
- For J = 0 To UBound(sTmp)
- sTmp(J) = Trim(sTmp(J))
- Next
- If J > 0 Then
- Select Case sTmp(0)
- Case "facet" '一个三角面片开始,得到法向量坐标
- mFacetCount = mFacetCount + 1
- ReDim Preserve mData(mFacetCount)
-
- With mData(mFacetCount)
- .PNX = sTmp(2)
- .PNY = sTmp(3)
- .PNZ = sTmp(4)
- End With
- Case "outer" '描述三角面片顶点坐标
- VIndex = 1
- Case "vertex" '顶点坐标值
- With mData(mFacetCount)
- Select Case VIndex
- Case 1
- .P1X = sTmp(1)
- .P1Y = sTmp(2)
- .P1Z = sTmp(3)
- Case 2
- .P2X = sTmp(1)
- .P2Y = sTmp(2)
- .P2Z = sTmp(3)
- Case 3
- .P3X = sTmp(1)
- .P3Y = sTmp(2)
- .P3Z = sTmp(3)
- Case Else
- GoTo errH
- End Select
- VIndex = VIndex + 1
- End With
- Case "end" '结束顶点描述
- Case "endfacet" '一个三角面片结束
- Case "endsolid" '文件结束
- End Select
- End If
- Next
-
- ' MsgBox "22"
- Else
- '以BINARY格式读取数据
- mDescription = StrConv(byteBuff(), vbUnicode) '得到文件信息
- mDescription = Trim(Replace(mDescription, Chr(0), " "))
-
- Get #Fn, , mFacetCount
-
- ReDim mData(mFacetCount - 1)
- Get #Fn, , mData()
- End If
-
- For I = 0 To mFacetCount - 1
- With mData(I)
- If mXMax < .PNX Then mXMax = .PNX
- If mXMin > .PNX Then mXMin = .PNX
-
- If mYMax < .PNY Then mYMax = .PNY
- If mYMin > .PNY Then mYMin = .PNY
-
- If mZMax > .PNZ Then mZMax = .PNZ
- If mZMin > .PNZ Then mZMin = .PNZ
-
- If mXMax < .P1X Then mXMax = .P1X
- If mXMin > .P1X Then mXMin = .P1X
-
- If mYMax < .P1Y Then mYMax = .P1Y
- If mYMin > .P1Y Then mYMin = .P1Y
-
- If mZMax > .P1Z Then mZMax = .P1Z
- If mZMin > .P1Z Then mZMin = .P1Z
-
- If mXMax < .P2X Then mXMax = .P2X
- If mXMin > .P2X Then mXMin = .P2X
-
- If mYMax < .P2Y Then mYMax = .P2Y
- If mYMin > .P2Y Then mYMin = .P2Y
-
- If mZMax > .P2Z Then mZMax = .P2Z
- If mZMin > .P2Z Then mZMin = .P2Z
-
- If mXMax < .P3X Then mXMax = .P1X
- If mXMin > .P3X Then mXMin = .P1X
-
- If mYMax < .P3Y Then mYMax = .P3Y
- If mYMin > .P3Y Then mYMin = .P3Y
-
- If mZMax > .P3Z Then mZMax = .P3Z
- If mZMin > .P3Z Then mZMin = .P3Z
- End With
- Next
-
- LoadSTLFile = UBound(mData) + 1
- errH:
- Close #Fn
- End Function
- Public Function SaveSTLFile(ByVal FileName As String, ByVal IsAscii As Boolean) As Long
- '保存当前数据为STL文件
- '
- Dim I As Long, J As Long, K As Long, sBuff() As String, LineUbound As Long, sTmp As String * 80
- Dim Fn As Long
-
- If IsAscii = True Then
- LineUbound = (UBound(mData) + 1) * 7 + 2 - 1
- ReDim sBuff(LineUbound)
-
- sBuff(0) = "solid " & mDescription
- sBuff(LineUbound) = "endsolid " & mDescription
-
- For I = 1 To LineUbound - 1
- With mData(J)
- Select Case K
- Case 0
- sBuff(I) = " facet normal " & .PNX & " " & .PNY & " " & .PNZ
- Case 1
- sBuff(I) = " outer loop"
- Case 2
- sBuff(I) = " vertex " & .P1X & " " & .P1Y & " " & .P1Z
- Case 3
- sBuff(I) = " vertex " & .P2X & " " & .P2Y & " " & .P2Z
- Case 4
- sBuff(I) = " vertex " & .P3X & " " & .P3Y & " " & .P3Z
- Case 5
- sBuff(I) = " endloop"
- Case 6
- sBuff(I) = " endfacet"
- K = -1
- J = J + 1
- End Select
- K = K + 1
- End With
- Next
-
- On Error Resume Next
- Kill FileName
- On Error GoTo 0
-
- Fn = FreeFile
- Open FileName For Binary As #Fn
- Put #Fn, , Join(sBuff(), vbLf)
- Close #Fn
- Else
- On Error Resume Next
- Kill FileName
- On Error GoTo 0
-
- Fn = FreeFile
- Open FileName For Binary As #Fn
- sTmp = mDescription
- I = UBound(mData) + 1
-
- Put #Fn, , sTmp
- Put #Fn, , I
- Put #Fn, , mData()
- Close #Fn
- End If
-
- SaveSTLFile = FileLen(FileName)
- End Function
- Public Sub MoveToPoint(ByVal oX As Single, ByVal oY As Single, ByVal oZ As Single)
- '整体平移到指定的点
- '
- Dim I As Long
- Dim XOffset As Single, YOffset As Single, ZOffset As Single '最终偏移量
-
- XOffset = oX + mXMin + (mXMax - mXMin) / 2
- YOffset = oY + mYMin + (mYMax - mYMin) / 2
- ZOffset = 0 - mZMin
-
- For I = 0 To FacetCount - 1
- With mData(I)
- .PNX = .PNX + XOffset
- .PNY = .PNY + YOffset
- .PNZ = .PNZ + ZOffset
-
- .P1X = .P1X + XOffset
- .P1Y = .P1Y + YOffset
- .P1Z = .P1Z + ZOffset
-
- .P2X = .P2X + XOffset
- .P2Y = .P2Y + YOffset
- .P2Z = .P2Z + ZOffset
-
- .P3X = .P3X + XOffset
- .P3Y = .P3Y + YOffset
- .P3Z = .P3Z + ZOffset
- End With
- Next
- End Sub
- Public Sub Rotate(ByVal BaseAxis As Long, ByVal lDir As Long)
- '整体90度翻转
- '
- 'BaseAxis - 基于哪个轴翻转.0=X,1=Y,2=Z
- 'lDir - 翻转方向,正数=顺时针,否则逆时针
- '
- Dim I As Long, tmpVar As Single
- Dim oX As Single, oY As Single, oZ As Single
- Dim maxX As Single, minX As Single, maxY As Single, minY As Single, maxZ As Single, minZ As Single
-
- For I = 0 To UBound(mData) '得到XYZ的范围
- With mData(I)
- If maxX < .P1X Then maxX = .P1X
- If maxY < .P1Y Then maxY = .P1Y
- If maxZ < .P1Z Then maxZ = .P1Z
-
- If maxX < .P2X Then maxX = .P2X
- If maxY < .P2Y Then maxY = .P2Y
- If maxZ < .P2Z Then maxZ = .P2Z
-
- If maxX < .P3X Then maxX = .P3X
- If maxY < .P3Y Then maxY = .P3Y
- If maxZ < .P3Z Then maxZ = .P3Z
-
- If minX > .P1X Then minX = .P1X
- If minY > .P1Y Then minY = .P1Y
- If minZ > .P1Z Then minZ = .P1Z
-
- If minX > .P2X Then minX = .P2X
- If minY > .P2Y Then minY = .P2Y
- If minZ > .P2Z Then minZ = .P2Z
-
- If minX > .P3X Then minX = .P3X
- If minY > .P3Y Then minY = .P3Y
- If minZ > .P3Z Then minZ = .P3Z
- End With
- Next
-
- oX = minX + (maxX - minX) / 2 '得到对象的中心点
- oY = minY + (maxY - minY) / 2
- oZ = minZ + (maxZ - minZ) / 2
-
- For I = 0 To UBound(mData)
- With mData(I)
- Select Case BaseAxis
- Case 0 '基于X,则翻转Z,Y,圆心为oZ,oY
- Call RotatePoint(.P1Z, .P1Y, oZ, oY, lDir)
- Call RotatePoint(.P2Z, .P2Y, oZ, oY, lDir)
- Call RotatePoint(.P3Z, .P3Y, oZ, oY, lDir)
- Call RotatePoint(.PNZ, .PNY, oZ, oY, lDir)
- Case 1 '基于Y,则翻转X,Z,圆心为oX,oZ
- Call RotatePoint(.P1X, .P1Z, oX, oZ, lDir)
- Call RotatePoint(.P2X, .P2Z, oX, oZ, lDir)
- Call RotatePoint(.P3X, .P3Z, oX, oZ, lDir)
- Call RotatePoint(.PNX, .PNZ, oX, oZ, lDir)
- Case 2 '基于Z,则翻转Y,X,圆心为oY,oX
- Call RotatePoint(.P1Y, .P1X, oY, oX, lDir)
- Call RotatePoint(.P2Y, .P2X, oY, oX, lDir)
- Call RotatePoint(.P3Y, .P3X, oY, oX, lDir)
- Call RotatePoint(.PNY, .PNX, oY, oX, lDir)
- End Select
- End With
- Next
- End Sub
- Private Sub RotatePoint(ByRef X As Single, ByRef Y As Single, ByVal oX As Single, ByVal oY As Single, ByVal lDir As Long)
- '对一个点进行90度旋转
- '
- Dim tX As Single, tY As Single
- Dim tXBase As Long, tYBase As Long, PPos As Long, destPPos As Long
-
- tX = X
- tY = Y
-
- tXBase = Abs(tX - oX) '得到绝对距离
- tYBase = Abs(tY - oY) '得到绝对距离
-
- If tX > oX And tY > oY Then '得到旋转前所在象限
- PPos = 1
- ElseIf tX > oX And tY < oY Then
- PPos = 4
- ElseIf tX < oX And tY > oY Then
- PPos = 2
- Else
- PPos = 3
- End If
-
- '得到旋转后所在象限
- If lDir > 0 Then '顺时针旋转
- destPPos = PPos - 1
- If destPPos = 0 Then destPPos = 4
- Else '逆时针旋转
- destPPos = PPos + 1
- If destPPos = 5 Then destPPos = 1
- End If
-
- Select Case destPPos '得到绝对距离在这个象限中的运算方式
- Case 1
- Case 2
- tXBase = -tXBase
- Case 3
- tXBase = -tXBase
- tYBase = -tYBase
- Case 4
- tYBase = -tYBase
- End Select
-
- X = oX + tXBase '得出结果
- Y = oY + tYBase
- End Sub
- Public Property Get FileName() As String
- FileName = mFileName
- End Property
- Public Property Get FacetCount() As Long
- On Error Resume Next
-
- FacetCount = UBound(mData) + 1
- End Property
- Public Property Get FacetIndex() As Long
- FacetIndex = mFacetIndex
- End Property
- Public Property Let FacetIndex(ByVal vNewValue As Long)
- mFacetIndex = vNewValue
- End Property
- Public Property Get PN_X() As Single
- PN_X = mData(mFacetIndex).PNX
- End Property
- Public Property Let PN_X(ByVal vNewValue As Single)
- mData(mFacetIndex).PNX = vNewValue
- End Property
- Public Property Get PN_Y() As Single
- PN_Y = mData(mFacetIndex).PNY
- End Property
- Public Property Let PN_Y(ByVal vNewValue As Single)
- mData(mFacetIndex).PNY = vNewValue
- End Property
- Public Property Get PN_Z() As Single
- PN_Z = mData(mFacetIndex).PNZ
- End Property
- Public Property Let PN_Z(ByVal vNewValue As Single)
- mData(mFacetIndex).PNZ = vNewValue
- End Property
- Public Property Get P1_X() As Single
- P1_X = mData(mFacetIndex).P1X
- End Property
- Public Property Let P1_X(ByVal vNewValue As Single)
- mData(mFacetIndex).P1X = vNewValue
- End Property
- Public Property Get P1_Y() As Single
- P1_Y = mData(mFacetIndex).P1Y
- End Property
- Public Property Let P1_Y(ByVal vNewValue As Single)
- mData(mFacetIndex).P1Y = vNewValue
- End Property
- Public Property Get P1_Z() As Single
- P1_Z = mData(mFacetIndex).P1Z
- End Property
- Public Property Let P1_Z(ByVal vNewValue As Single)
- mData(mFacetIndex).P1Z = vNewValue
- End Property
- Public Property Get P2_X() As Single
- P2_X = mData(mFacetIndex).P2X
- End Property
- Public Property Let P2_X(ByVal vNewValue As Single)
- mData(mFacetIndex).P2X = vNewValue
- End Property
- Public Property Get P2_Y() As Single
- P2_Y = mData(mFacetIndex).P2Y
- End Property
- Public Property Let P2_Y(ByVal vNewValue As Single)
- mData(mFacetIndex).P2Y = vNewValue
- End Property
- Public Property Get P2_Z() As Single
- P2_Z = mData(mFacetIndex).P2Z
- End Property
- Public Property Let P2_Z(ByVal vNewValue As Single)
- mData(mFacetIndex).P2Z = vNewValue
- End Property
- Public Property Get P3_X() As Single
- P3_X = mData(mFacetIndex).P3X
- End Property
- Public Property Let P3_X(ByVal vNewValue As Single)
- mData(mFacetIndex).P3X = vNewValue
- End Property
- Public Property Get P3_Y() As Single
- P3_Y = mData(mFacetIndex).P3Y
- End Property
- Public Property Let P3_Y(ByVal vNewValue As Single)
- mData(mFacetIndex).P3Y = vNewValue
- End Property
- Public Property Get P3_Z() As Single
- P3_Z = mData(mFacetIndex).P3Z
- End Property
- Public Property Let P3_Z(ByVal vNewValue As Single)
- mData(mFacetIndex).P3Z = vNewValue
- End Property
复制代码 |
|