home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH12 / SRC / OBJSOL1.CLS < prev    next >
Encoding:
Text File  |  1996-04-04  |  12.9 KB  |  496 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjSolid"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' These ObjPolygon objects are the oriented faces.
  11. Public Faces As New Collection
  12. Public Convex As Boolean
  13. Public MaxZ As Single
  14. ' ***********************************************
  15. ' Clip faces.
  16. ' ***********************************************
  17. Public Sub ClipEye(r As Single)
  18. Dim obj As Object
  19.  
  20.     For Each obj In Faces
  21.         obj.ClipEye r
  22.     Next obj
  23. End Sub
  24.  
  25. ' ************************************************
  26. ' Return the distance from this solid to a point.
  27. ' ************************************************
  28. Property Get Distance(x As Single, y As Single, Z As Single) As Single
  29. Dim best As Single
  30. Dim dist As Single
  31. Dim i As Integer
  32.  
  33.     best = INFINITY
  34.     For i = 1 To Faces.Count
  35.         dist = Faces(i).Distance(x, y, Z)
  36.         If best > dist Then best = dist
  37.     Next i
  38.     Distance = best
  39. End Property
  40.  
  41. ' ************************************************
  42. ' Compute and save the maximum Z value.
  43. ' ************************************************
  44. Public Sub SetZmax()
  45. Dim best As Single
  46. Dim Z As Single
  47. Dim i As Integer
  48.  
  49.     best = -INFINITY
  50.     For i = 1 To Faces.Count
  51.         If Not Faces(i).Culled Then
  52.             Z = Faces(i).zmax
  53.             If best < Z Then best = Z
  54.         End If
  55.     Next i
  56.     MaxZ = best
  57. End Sub
  58.  
  59. ' ***********************************************
  60. ' Create faces to make a pyramid of height L with
  61. ' base given by the coord array.
  62. ' ***********************************************
  63. Sub Stellate(L As Single, ParamArray coord() As Variant)
  64. Dim x0 As Single
  65. Dim y0 As Single
  66. Dim z0 As Single
  67. Dim x1 As Single
  68. Dim y1 As Single
  69. Dim z1 As Single
  70. Dim x2 As Single
  71. Dim y2 As Single
  72. Dim z2 As Single
  73. Dim x3 As Single
  74. Dim y3 As Single
  75. Dim z3 As Single
  76. Dim Ax As Single
  77. Dim Ay As Single
  78. Dim Az As Single
  79. Dim Bx As Single
  80. Dim By As Single
  81. Dim Bz As Single
  82. Dim nx As Single
  83. Dim ny As Single
  84. Dim nz As Single
  85. Dim num As Integer
  86. Dim i As Integer
  87. Dim pt As Integer
  88.  
  89.     num = (UBound(coord) + 1) \ 3
  90.     If num < 3 Then
  91.         Beep
  92.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  93.         Exit Sub
  94.     End If
  95.     
  96.     ' (x0, y0, z0) is the center of the polygon.
  97.     x0 = 0
  98.     y0 = 0
  99.     z0 = 0
  100.     pt = 0
  101.     For i = 1 To num
  102.         x0 = x0 + coord(pt)
  103.         y0 = y0 + coord(pt + 1)
  104.         z0 = z0 + coord(pt + 2)
  105.         pt = pt + 3
  106.     Next i
  107.     x0 = x0 / num
  108.     y0 = y0 / num
  109.     z0 = z0 / num
  110.     
  111.     ' Find the normal.
  112.     x1 = coord(0)
  113.     y1 = coord(1)
  114.     z1 = coord(2)
  115.     x2 = coord(3)
  116.     y2 = coord(4)
  117.     z2 = coord(5)
  118.     x3 = coord(6)
  119.     y3 = coord(7)
  120.     z3 = coord(8)
  121.     Ax = x2 - x1
  122.     Ay = y2 - y1
  123.     Az = z2 - z1
  124.     Bx = x3 - x2
  125.     By = y3 - y2
  126.     Bz = z3 - z2
  127.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  128.     
  129.     ' Give the normal length L.
  130.     m3SizeVector L, nx, ny, nz
  131.     
  132.     ' The normal + <x0, y0, z0> gives the point.
  133.     x0 = x0 + nx
  134.     y0 = y0 + ny
  135.     z0 = z0 + nz
  136.  
  137.     ' Build the triangles that make up the solid.
  138.     x1 = coord(3 * num - 3)
  139.     y1 = coord(3 * num - 2)
  140.     z1 = coord(3 * num - 1)
  141.     pt = 0
  142.     For i = 1 To num
  143.         x2 = coord(pt)
  144.         y2 = coord(pt + 1)
  145.         z2 = coord(pt + 2)
  146.         AddFace x1, y1, z1, x2, y2, z2, x0, y0, z0
  147.         x1 = x2
  148.         y1 = y2
  149.         z1 = z2
  150.         pt = pt + 3
  151.     Next i
  152. End Sub
  153.  
  154. ' ***********************************************
  155. ' Add apolygon to the solid.
  156. ' ***********************************************
  157. Public Sub AddPolygon(pgon As Object)
  158.     Faces.Add pgon
  159. End Sub
  160.  
  161. ' ***********************************************
  162. ' Add an oriented face to the solid.
  163. ' ***********************************************
  164. Public Sub AddFace(ParamArray coord() As Variant)
  165. Dim pgon As ObjPolygon
  166. Dim num As Integer
  167. Dim pt As Integer
  168. Dim i As Integer
  169.  
  170.     num = (UBound(coord) + 1) \ 3
  171.     If num < 3 Then
  172.         Beep
  173.         MsgBox "Faces in a Solid must contain at least 3 points.", , vbExclamation
  174.         Exit Sub
  175.     End If
  176.     
  177.     Set pgon = New ObjPolygon
  178.     Faces.Add pgon
  179.     
  180.     pt = 0
  181.     For i = 1 To num
  182.         pgon.AddPoint (coord(pt)), (coord(pt + 1)), (coord(pt + 2))
  183.         pt = pt + 3
  184.     Next i
  185. End Sub
  186.  
  187.  
  188. ' ************************************************
  189. ' Perform backface removal on the faces.
  190. ' ************************************************
  191. Public Sub Cull(x As Single, y As Single, Z As Single)
  192. Dim obj As Object
  193.     
  194.     For Each obj In Faces
  195.         obj.Cull x, y, Z
  196.     Next obj
  197. End Sub
  198. ' ***********************************************
  199. ' Create normals for polygon objects.
  200. ' ***********************************************
  201. Sub CreateNormal(Objects As Collection)
  202. Dim obj As Object
  203.  
  204.     For Each obj In Faces
  205.         obj.CreateNormal Objects
  206.     Next obj
  207. End Sub
  208.  
  209. ' ***********************************************
  210. ' Set or clear the Culled property for all faces.
  211. ' ***********************************************
  212. Property Let Culled(value As Boolean)
  213. Dim obj As Object
  214.  
  215.     For Each obj In Faces
  216.         obj.Culled = value
  217.     Next obj
  218. End Property
  219.  
  220.  
  221.  
  222. ' ***********************************************
  223. ' Return a string indicating the object type.
  224. ' ***********************************************
  225. Property Get ObjectType() As String
  226.     ObjectType = "SOLID"
  227. End Property
  228.  
  229.  
  230. ' ************************************************
  231. ' Draw the object into a metafile.
  232. ' ************************************************
  233. Public Sub MakeWMF(mhdc As Integer)
  234. Dim obj As Object
  235.  
  236.     For Each obj In Faces
  237.         obj.MakeWMF mhdc
  238.     Next obj
  239. End Sub
  240.  
  241. ' ***********************************************
  242. ' Fix the data coordinates at their transformed
  243. ' values.
  244. ' ***********************************************
  245. Public Sub FixPoints()
  246. Dim obj As Object
  247.  
  248.     For Each obj In Faces
  249.         obj.FixPoints
  250.     Next obj
  251. End Sub
  252.  
  253. ' ************************************************
  254. ' Apply a transformation matrix which may not
  255. ' contain 0, 0, 0, 1 in the last column to the
  256. ' object.
  257. ' ************************************************
  258. Public Sub ApplyFull(M() As Single)
  259. Dim obj As Object
  260.  
  261.     For Each obj In Faces
  262.         obj.ApplyFull M
  263.     Next obj
  264. End Sub
  265.  
  266. ' ************************************************
  267. ' Apply a transformation matrix to the object.
  268. ' ************************************************
  269. Public Sub Apply(M() As Single)
  270. Dim obj As Object
  271.  
  272.     For Each obj In Faces
  273.         obj.Apply M
  274.     Next obj
  275. End Sub
  276.  
  277.  
  278. ' ************************************************
  279. ' Apply a nonlinear transformation.
  280. ' ************************************************
  281. Public Sub Distort(D As Object)
  282. Dim obj As Object
  283.  
  284.     For Each obj In Faces
  285.         obj.Distort D
  286.     Next obj
  287. End Sub
  288.  
  289. ' ************************************************
  290. ' Write a polyline to a file using Write.
  291. ' Begin with "SOLID" to identify this object.
  292. ' ************************************************
  293. Public Sub FileWrite(filenum As Integer)
  294. Dim obj As Object
  295.  
  296.     Write #filenum, "SOLID", Convex, Faces.Count
  297.     
  298.     For Each obj In Faces
  299.         obj.FileWrite filenum
  300.     Next obj
  301. End Sub
  302.  
  303. ' ************************************************
  304. ' Order the faces of the solid with those with
  305. ' smallest transformed Z coordinates first.
  306. '
  307. ' As we switch faces around, we keep track of the
  308. ' number of switches we have made. If it clear we
  309. ' are stuck in an infinite loop, just move the
  310. ' first face to the ordered collection so we can
  311. ' continue.
  312. ' ************************************************
  313. Public Sub OrderFaces()
  314. Dim ordered As New Collection
  315. Dim obj1 As ObjPolygon
  316. Dim obji As ObjPolygon
  317. Dim i As Integer
  318. Dim xmin As Single
  319. Dim xmax As Single
  320. Dim ymin As Single
  321. Dim ymax As Single
  322. Dim zmin As Single
  323. Dim zmax As Single
  324. Dim xmini As Single
  325. Dim xmaxi As Single
  326. Dim ymini As Single
  327. Dim ymaxi As Single
  328. Dim zmini As Single
  329. Dim zmaxi As Single
  330. Dim overlap As Boolean
  331. Dim switches As Integer
  332. Dim max_switches As Integer
  333.  
  334.     ' Pull out any that are culled.
  335.     i = 1
  336.     Do While i <= Faces.Count
  337.         If Faces.Item(i).Culled Then
  338.             ordered.Add Faces.Item(i)
  339.             Faces.Remove i
  340.         Else
  341.             i = i + 1
  342.         End If
  343.     Loop
  344.     
  345.     ' Order the remaining faces.
  346.     max_switches = Faces.Count
  347.     Do While Faces.Count > 0
  348.         ' Get item 1's extent.
  349.         Set obj1 = Faces.Item(1)
  350.         obj1.GetExtent xmin, xmax, ymin, ymax, zmin, zmax
  351.         
  352.         ' Compare this face to the others.
  353.         overlap = False     ' In case Face.Count = 0.
  354.         For i = 2 To Faces.Count
  355.             Set obji = Faces.Item(i)
  356.             
  357.             ' Get item i's extent.
  358.             obji.GetExtent xmini, xmaxi, ymini, ymaxi, zmini, zmaxi
  359.             
  360.             overlap = True
  361.             If xmaxi <= xmin Or _
  362.                xmini >= xmax Or _
  363.                ymaxi <= ymin Or _
  364.                ymini >= ymax Or _
  365.                zmini >= zmax Then
  366.                 ' The extents do not overlap.
  367.                 overlap = False
  368.             ElseIf obji.IsAbove(obj1) Then
  369.                 ' Face i is all above the plane
  370.                 ' of face 1.
  371.                 overlap = False
  372.             ElseIf obj1.IsBelow(obji) Then
  373.                 ' Face 1 is all beneath the plane
  374.                 ' of face i.
  375.                 overlap = False
  376.             ElseIf Not obj1.Obscures(obji) Then
  377.                 ' If obj1 does not lie partly above
  378.                 ' obji, then there is no problem.
  379.                 overlap = False
  380.             End If
  381.             
  382.             If overlap Then Exit For
  383.         Next i
  384.         
  385.         If overlap And switches < max_switches Then
  386.             ' There's overlap, move face i to the
  387.             ' top of the list.
  388.             Faces.Remove i
  389.             Faces.Add obji, , 1 ' Before position 1.
  390.             switches = switches + 1
  391.         Else
  392.             ' There's no overlap. Move face 1 to
  393.             ' the ordered collection.
  394.             ordered.Add obj1
  395.             Faces.Remove 1
  396.             max_switches = Faces.Count
  397.             switches = 0
  398.         End If
  399.     Loop ' Loop until we've ordered all the faces.
  400.     
  401.     ' Replace the Faces collection with the
  402.     ' ordered collection.
  403.     Set Faces = ordered
  404. End Sub
  405.  
  406. ' ************************************************
  407. ' Draw the transformed solid on a Form, Printer,
  408. ' or PictureBox. Draw the faces in depth-sort
  409. ' order using polygon shading.
  410. ' ************************************************
  411. Public Sub DrawShaded(canvas As Object, Optional r As Variant)
  412. Dim obj As Object
  413.  
  414.     ' If it's not convex, order the faces.
  415.     If Not Convex Then OrderFaces
  416.  
  417.     ' Draw the faces in order.
  418.     For Each obj In Faces
  419.         obj.DrawShaded canvas, r
  420.     Next obj
  421. End Sub
  422.  
  423.  
  424.  
  425. ' ************************************************
  426. ' Draw the transformed solid on a Form, Printer,
  427. ' or PictureBox. Draw the faces in depth-sort
  428. ' order.
  429. ' ************************************************
  430. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  431. Dim obj As Object
  432.  
  433.     ' If it's not convex, order the faces.
  434.     If Not Convex Then OrderFaces
  435.  
  436.     ' Draw the faces in order.
  437.     For Each obj In Faces
  438.         obj.DrawOrdered canvas, r
  439.     Next obj
  440. End Sub
  441.  
  442.  
  443. ' ************************************************
  444. ' Draw the transformed solid on a Form, Printer,
  445. ' or PictureBox.
  446. ' ************************************************
  447. Public Sub Draw(canvas As Object, Optional r As Variant)
  448. Dim obj As Object
  449.  
  450.     For Each obj In Faces
  451.         obj.Draw canvas, r
  452.     Next obj
  453. End Sub
  454.  
  455. ' ************************************************
  456. ' Read a polyline from a file using Input.
  457. ' Assume the "SOLID" label has already been
  458. ' read.
  459. ' ************************************************
  460. Public Sub FileInput(filenum As Integer)
  461. Dim num As Integer
  462. Dim i As Integer
  463. Dim obj As Object
  464. Dim obj_type As String
  465.  
  466.     ' Read the number of faces in the solid.
  467.     Input #filenum, Convex, num
  468.     
  469.     ' Read faces from the file.
  470.     For i = 1 To num
  471.         Input #filenum, obj_type
  472.         Select Case obj_type
  473.             Case "SOLID"
  474.                 Set obj = New ObjSolid
  475.             Case "POLYGON"
  476.                 Set obj = New ObjPolygon
  477.             Case Else
  478.                 Beep
  479.                 MsgBox "Invalid Solid sub-object type """ & obj_type & """.", , vbExclamation
  480.                 Exit Sub
  481.         End Select
  482.         obj.FileInput filenum
  483.         Faces.Add obj
  484.     Next i
  485. End Sub
  486.  
  487.  
  488. ' ***********************************************
  489. ' Return the maximum transformed Z value for this
  490. ' object. Note that you must call SetZmax first
  491. ' to set the maximum Z value.
  492. ' ***********************************************
  493. Property Get zmax() As Single
  494.     zmax = MaxZ
  495. End Property
  496.