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

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolygon"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D is defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15.  
  16. Private NumPts As Integer ' Number of points.
  17. Private Points() As Point3D  ' Data points.
  18.  
  19. Private IsCulled As Boolean
  20. ' ************************************************
  21. ' Draw the transformed points on a Form, Printer,
  22. ' or PictureBox. Use the API function Polygon so
  23. ' the polygon will be properly filled to cover
  24. ' polygons behind it.
  25. '
  26. ' Assume the point light source is infinitely far
  27. ' away so the color is the same for the whole
  28. ' polygon.
  29. ' ************************************************
  30. Public Sub DrawShaded(canvas As Object, Optional r As Variant)
  31. Dim pts() As POINTAPI
  32. Dim pt As Integer
  33. Dim status As Integer
  34. Dim nx As Single
  35. Dim ny As Single
  36. Dim nz As Single
  37. Dim lx As Single
  38. Dim ly As Single
  39. Dim lz As Single
  40. Dim vx As Single
  41. Dim vy As Single
  42. Dim vz As Single
  43. Dim rx As Single
  44. Dim ry As Single
  45. Dim rz As Single
  46. Dim l_len As Single
  47. Dim v_len As Single
  48. Dim r_len As Single
  49. Dim intensity As Single
  50. Dim clr As Long
  51. Dim NdotL As Single
  52. Dim RdotV As Single
  53. Dim r_dif As Single
  54. Dim g_dif As Single
  55. Dim b_dif As Single
  56. Dim r_amb As Single
  57. Dim g_amb As Single
  58. Dim b_amb As Single
  59. Dim spec As Single
  60. Dim Ir As Single
  61. Dim Ig As Single
  62. Dim Ib As Single
  63.  
  64.     ' Don't draw if culled.
  65.     If IsCulled Then Exit Sub
  66.        
  67.     ' Fill in the point array.
  68.     ReDim pts(1 To NumPts)
  69.     For pt = 1 To NumPts
  70.         pts(pt).x = Points(pt).trans(1)
  71.         pts(pt).y = Points(pt).trans(2)
  72.     Next pt
  73.  
  74.     ' Find the unit vector pointing toward the light.
  75.     lx = LightX - Points(1).coord(1)
  76.     ly = LightY - Points(1).coord(2)
  77.     lz = LightZ - Points(1).coord(3)
  78.     l_len = Sqr(lx * lx + ly * ly + lz * lz)
  79.     lx = lx / l_len
  80.     ly = ly / l_len
  81.     lz = lz / l_len
  82.     ' We will use l_len later as the distance from
  83.     ' the light to the surface.
  84.     
  85.     ' Find the surface unit normal.
  86.     UnitNormalVector nx, ny, nz
  87.     
  88.     ' Calculate the part due to diffuse reflection.
  89.     NdotL = nx * lx + ny * ly + nz * lz
  90.     If NdotL < 0 Then
  91.         ' The light does not hit the surface.
  92.         r_dif = 0
  93.         g_dif = 0
  94.         b_dif = 0
  95.         spec = 0
  96.     Else
  97.         r_dif = LightKdr * NdotL
  98.         g_dif = LightKdg * NdotL
  99.         b_dif = LightKdb * NdotL
  100.         
  101.         ' Find the vector V from the surface to the
  102.         ' viewpoint.
  103.         vx = EyeX - Points(1).coord(1)
  104.         vy = EyeY - Points(1).coord(2)
  105.         vz = EyeZ - Points(1).coord(3)
  106.         v_len = Sqr(vx * vx + vy * vy + vz * vz)
  107.         vx = vx / v_len
  108.         vy = vy / v_len
  109.         vz = vz / v_len
  110.         
  111.         ' Find vector R in the mirror direction.
  112.         rx = 2 * nx * NdotL - lx
  113.         ry = 2 * ny * NdotL - ly
  114.         rz = 2 * nz * NdotL - lz
  115.         
  116.         ' Calculate the part due to specular reflection.
  117.         RdotV = rx * vx + ry * vy + rz * vz
  118.         If RdotV < 0 Then
  119.             spec = 0
  120.         Else
  121.             spec = LightKs * RdotV ^ LightN
  122.         End If
  123.     End If
  124.     
  125.     ' Calculate the part due to ambient light.
  126.     r_amb = LightIar * LightKar
  127.     g_amb = LightIag * LightKag
  128.     b_amb = LightIab * LightKab
  129.     
  130.     ' See how intense to make the color.
  131.     Ir = r_amb + _
  132.         LightIir / (l_len + LightKdist) * _
  133.             (r_dif + spec)
  134.     Ig = g_amb + _
  135.         LightIig / (l_len + LightKdist) * _
  136.             (g_dif + spec)
  137.     Ib = b_amb + _
  138.         LightIib / (l_len + LightKdist) * _
  139.             (b_dif + spec)
  140.  
  141.     ' Compute the color.
  142.     clr = &H2000000 + RGB(Ir, Ig, Ib)
  143.     canvas.FillColor = clr
  144.  
  145.     ' Draw the polygon.
  146.     On Error Resume Next
  147.     status = Polygon(canvas.hdc, pts(1), NumPts)
  148. End Sub
  149.  
  150. ' ************************************************
  151. ' Draw the transformed points on a Form, Printer,
  152. ' or PictureBox. Use the API function Polygon so
  153. ' the polygon will be properly filled to cover
  154. ' polygons behind it.
  155. ' ************************************************
  156. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  157. Dim pts() As POINTAPI
  158. Dim pt As Integer
  159. Dim status As Integer
  160.  
  161.     ' Don't draw if culled.
  162.     If IsCulled Then Exit Sub
  163.        
  164.     ' Fill in the point array.
  165.     ReDim pts(1 To NumPts)
  166.     For pt = 1 To NumPts
  167.         pts(pt).x = Points(pt).trans(1)
  168.         pts(pt).y = Points(pt).trans(2)
  169.     Next pt
  170.  
  171.     ' Draw the polygon.
  172.     On Error Resume Next
  173.     status = Polygon(canvas.hdc, pts(1), NumPts)
  174. End Sub
  175.  
  176.  
  177.  
  178. ' ************************************************
  179. ' Return the minimum and maximum coordinates.
  180. ' ************************************************
  181. Public Sub GetExtent(xmin As Single, xmax As Single, ymin As Single, ymax As Single, zmin As Single, zmax As Single)
  182. Dim i As Integer
  183. Dim x As Single
  184. Dim y As Single
  185. Dim Z As Single
  186.  
  187.     xmin = Points(1).trans(1)
  188.     xmax = xmin
  189.     ymin = Points(1).trans(2)
  190.     ymax = ymin
  191.     zmin = Points(1).trans(3)
  192.     zmax = zmin
  193.     For i = 2 To NumPts
  194.         x = Points(i).trans(1)
  195.         y = Points(i).trans(2)
  196.         Z = Points(i).trans(3)
  197.         If xmin > x Then xmin = x
  198.         If xmax < x Then xmax = x
  199.         If ymin > y Then ymin = y
  200.         If ymax < y Then ymax = y
  201.         If zmin > Z Then zmin = Z
  202.         If zmax < Z Then zmax = Z
  203.     Next i
  204. End Sub
  205.  
  206.  
  207.  
  208.  
  209. ' ************************************************
  210. ' Return the coordinates of a point on the polygon.
  211. ' ************************************************
  212. Public Sub GetTransformedPoint(index As Integer, x As Single, y As Single, Z As Single)
  213.     x = Points(index).trans(1)
  214.     y = Points(index).trans(2)
  215.     Z = Points(index).trans(3)
  216. End Sub
  217.  
  218.  
  219. ' ************************************************
  220. ' See where the projections of two segments cross.
  221. ' Return true if the segments cross, false
  222. ' otherwise.
  223. ' ************************************************
  224. Function FindCrossing( _
  225.     ax1 As Single, ay1 As Single, az1 As Single, _
  226.     ax2 As Single, ay2 As Single, az2 As Single, _
  227.     bx1 As Single, by1 As Single, bz1 As Single, _
  228.     bx2 As Single, by2 As Single, bz2 As Single, _
  229.     x As Single, y As Single, z1 As Single, z2 As Single) _
  230.         As Boolean
  231. Dim dxa As Single
  232. Dim dya As Single
  233. Dim dza As Single
  234. Dim dxb As Single
  235. Dim dyb As Single
  236. Dim dzb As Single
  237. Dim t1 As Single
  238. Dim t2 As Single
  239. Dim denom As Single
  240.  
  241.     dxa = ax2 - ax1
  242.     dya = ay2 - ay1
  243.     dxb = bx2 - bx1
  244.     dyb = by2 - by1
  245.     
  246.     FindCrossing = False
  247.     
  248.     denom = dxb * dya - dyb * dxa
  249.     ' If the segments are parallel, stop.
  250.     If denom < 0.01 And denom > -0.01 Then Exit Function
  251.  
  252.     t2 = (ax1 * dya - ay1 * dxa - bx1 * dya + by1 * dxa) / denom
  253.     If t2 < 0 Or t2 > 1 Then Exit Function
  254.     
  255.     t1 = (ax1 * dyb - ay1 * dxb - bx1 * dyb + by1 * dxb) / denom
  256.     If t1 < 0 Or t1 > 1 Then Exit Function
  257.  
  258.     ' Compute the points of overlap.
  259.     x = ax1 + t1 * dxa
  260.     y = ay1 + t1 * dya
  261.     dza = az2 - az1
  262.     dzb = bz2 - bz1
  263.     z1 = az1 + t1 * dza
  264.     z2 = bz1 + t2 * dzb
  265.     FindCrossing = True
  266. End Function
  267.  
  268. ' ************************************************
  269. ' Return the number of points.
  270. ' ************************************************
  271. Property Get NumPoints() As Integer
  272.     NumPoints = NumPts
  273. End Property
  274.  
  275. ' ************************************************
  276. ' Return true if this polygon partially obscures
  277. ' (has greater Z value than) polygon obj.
  278. '
  279. ' We assume one polygon may obscure the other, but
  280. ' they cannot obscure each other.
  281. '
  282. ' This check is executed by seeing where the
  283. ' projections of the edges of the polygons cross.
  284. ' Where they cross, see if one Z value is greater
  285. ' than the other.
  286. '
  287. ' If no edges cross, see if one polygon contains
  288. ' the other. If so, there is an overlap.
  289. ' ************************************************
  290. Public Function Obscures(obj As ObjPolygon) As Boolean
  291. Dim num As Integer
  292. Dim i As Integer
  293. Dim j As Integer
  294. Dim xi1 As Single
  295. Dim yi1 As Single
  296. Dim zi1 As Single
  297. Dim xi2 As Single
  298. Dim yi2 As Single
  299. Dim zi2 As Single
  300. Dim xj1 As Single
  301. Dim yj1 As Single
  302. Dim zj1 As Single
  303. Dim xj2 As Single
  304. Dim yj2 As Single
  305. Dim zj2 As Single
  306. Dim x As Single
  307. Dim y As Single
  308. Dim z1 As Single
  309. Dim z2 As Single
  310.  
  311.     num = obj.NumPoints
  312.     
  313.     ' Check each edge in this polygon.
  314.     GetTransformedPoint NumPts, xi1, yi1, zi1
  315.     For i = 1 To NumPts
  316.         GetTransformedPoint i, xi2, yi2, zi2
  317.     
  318.         ' Compare with each edge in the other.
  319.         obj.GetTransformedPoint num, xj1, yj1, zj1
  320.         For j = 1 To num
  321.             obj.GetTransformedPoint j, xj2, yj2, zj2
  322.             ' See if the segments cross.
  323.             If FindCrossing( _
  324.                 xi1, yi1, zi1, _
  325.                 xi2, yi2, zi2, _
  326.                 xj1, yj1, zj1, _
  327.                 xj2, yj2, zj2, _
  328.                 x, y, z1, z2) _
  329.             Then
  330.                 If z1 - z2 > 0.01 Then
  331.                     ' z1 > z2. We obscure it.
  332.                     Obscures = True
  333.                     Exit Function
  334.                 End If
  335.                 If z2 - z1 > 0.01 Then
  336.                     ' z2 > z1. It obscures us.
  337.                     Obscures = False
  338.                     Exit Function
  339.                 End If
  340.             End If
  341.             
  342.             xj1 = xj2
  343.             yj1 = yj2
  344.             zj1 = zj2
  345.         Next j
  346.         
  347.         xi1 = xi2
  348.         yi1 = yi2
  349.         zi1 = zi2
  350.     Next i
  351.     
  352.     ' No edges cross. See if one polygon contains
  353.     ' the other.
  354.     
  355.     ' If any points of one polygon are inside the
  356.     ' other, then they must all be. Since the
  357.     ' IsAbove tests were inconclusive, some points
  358.     ' in one polygon are on the "bad" side of the
  359.     ' other. In that case there is an overlap.
  360.     
  361.     ' See if this polygon is inside the other.
  362.     GetTransformedPoint 1, xi1, yi1, zi1
  363.     If obj.PointInside(xi1, yi1) Then
  364.         Obscures = True
  365.         Exit Function
  366.     End If
  367.     
  368.     ' See if the other polygon is inside this one.
  369.     obj.GetTransformedPoint 1, xi1, yi1, zi1
  370.     If PointInside(xi1, yi1) Then
  371.         Obscures = True
  372.         Exit Function
  373.     End If
  374.     
  375.     Obscures = False
  376. End Function
  377.  
  378. ' ************************************************
  379. ' Return true if the point projection lies within
  380. ' this polygon's projection.
  381. ' ************************************************
  382. Function PointInside(x As Single, y As Single) As Boolean
  383. Dim i As Integer
  384. Dim theta1 As Double
  385. Dim theta2 As Double
  386. Dim dtheta As Double
  387. Dim dx As Double
  388. Dim dy As Double
  389. Dim angles As Double
  390.  
  391.     dx = Points(NumPts).trans(1) - x
  392.     dy = Points(NumPts).trans(2) - y
  393.     theta1 = Arctan2(CSng(dx), CSng(dy))
  394.     If theta1 < 0 Then theta1 = theta1 + 2 * PI
  395.     For i = 1 To NumPts
  396.         dx = Points(i).trans(1) - x
  397.         dy = Points(i).trans(2) - y
  398.         theta2 = Arctan2(CSng(dx), CSng(dy))
  399.         If theta2 < 0 Then theta2 = theta2 + 2 * PI
  400.         dtheta = theta2 - theta1
  401.         If dtheta > PI Then dtheta = dtheta - 2 * PI
  402.         If dtheta < -PI Then dtheta = dtheta + 2 * PI
  403.         angles = angles + dtheta
  404.         theta1 = theta2
  405.     Next i
  406.     
  407.     PointInside = (Abs(angles) > 0.001)
  408. End Function
  409.  
  410. ' ************************************************
  411. ' Return true if this polygon is completly below
  412. ' the plane containing obj.
  413. ' ************************************************
  414. Public Function IsBelow(obj As ObjPolygon) As Boolean
  415. Dim nx As Single
  416. Dim ny As Single
  417. Dim nz As Single
  418. Dim px As Single
  419. Dim py As Single
  420. Dim pz As Single
  421. Dim dx As Single
  422. Dim dy As Single
  423. Dim dz As Single
  424. Dim cx As Single
  425. Dim cy As Single
  426. Dim cz As Single
  427. Dim i As Integer
  428.  
  429.     ' Compute a downward pointing normal to the plane.
  430.     obj.TransformedNormalVector nx, ny, nz
  431.     If nz > 0 Then
  432.         nx = -nx
  433.         ny = -ny
  434.         nz = -nz
  435.     End If
  436.     
  437.     ' Get a point on the plane.
  438.     obj.GetTransformedPoint 1, px, py, pz
  439.     
  440.     ' See if the points in this polygon all lie
  441.     For i = 1 To NumPts
  442.         ' Get the vector from plane to point.
  443.         dx = Points(i).trans(1) - px
  444.         dy = Points(i).trans(2) - py
  445.         dz = Points(i).trans(3) - pz
  446.             
  447.         ' If the dot product < 0, the point is
  448.         ' below the plane.
  449.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  450.             IsBelow = False
  451.             Exit Function
  452.         End If
  453.     Next i
  454.     IsBelow = True
  455. End Function
  456.  
  457.  
  458. ' ************************************************
  459. ' Return true if this polygon is completly above
  460. ' the plane containing obj.
  461. ' ************************************************
  462. Public Function IsAbove(obj As ObjPolygon) As Boolean
  463. Dim nx As Single
  464. Dim ny As Single
  465. Dim nz As Single
  466. Dim px As Single
  467. Dim py As Single
  468. Dim pz As Single
  469. Dim dx As Single
  470. Dim dy As Single
  471. Dim dz As Single
  472. Dim cx As Single
  473. Dim cy As Single
  474. Dim cz As Single
  475. Dim i As Integer
  476.  
  477.     ' Compute an upward pointing normal to the plane.
  478.     obj.TransformedNormalVector nx, ny, nz
  479.     If nz < 0 Then
  480.         nx = -nx
  481.         ny = -ny
  482.         nz = -nz
  483.     End If
  484.     
  485.     ' Get a point on the plane.
  486.     obj.GetTransformedPoint 1, px, py, pz
  487.     
  488.     ' See if the points in this polygon all lie
  489.     For i = 1 To NumPts
  490.         ' Get the vector from plane to point.
  491.         dx = Points(i).trans(1) - px
  492.         dy = Points(i).trans(2) - py
  493.         dz = Points(i).trans(3) - pz
  494.             
  495.         ' If the dot product < 0, the point is
  496.         ' below the plane.
  497.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  498.             IsAbove = False
  499.             Exit Function
  500.         End If
  501.     Next i
  502.     IsAbove = True
  503. End Function
  504.  
  505.  
  506. ' ***********************************************
  507. ' Return the maximum transformed Z value for this
  508. ' object.
  509. ' ***********************************************
  510. Property Get Distance(x As Single, y As Single, Z As Single) As Single
  511. Dim best As Single
  512. Dim dist As Single
  513. Dim dx As Single
  514. Dim dy As Single
  515. Dim dz As Single
  516. Dim i As Integer
  517.  
  518.     best = INFINITY
  519.     For i = 1 To NumPts
  520.         dx = Points(i).coord(1) - x
  521.         dy = Points(i).coord(2) - y
  522.         dz = Points(i).coord(3) - Z
  523.         dist = dx * dx + dy * dy + dz * dz
  524.         If best > dist Then best = dist
  525.     Next i
  526.     Distance = Sqr(best)
  527. End Property
  528.  
  529. ' ***********************************************
  530. ' Return the maximum transformed Z value for this
  531. ' object.
  532. ' ***********************************************
  533. Property Get zmax() As Single
  534. Dim best As Single
  535. Dim Z As Single
  536. Dim i As Integer
  537.  
  538.     best = Points(1).trans(3)
  539.     For i = 2 To NumPts
  540.         Z = Points(i).trans(3)
  541.         If best < Z Then best = Z
  542.     Next i
  543.     zmax = best
  544. End Property
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551. ' ***********************************************
  552. ' Compute a transformed normal vector.
  553. ' ***********************************************
  554. Public Sub TransformedNormalVector(nx As Single, ny As Single, nz As Single)
  555. Dim Ax As Single
  556. Dim Ay As Single
  557. Dim Az As Single
  558. Dim Bx As Single
  559. Dim By As Single
  560. Dim Bz As Single
  561.  
  562.     Ax = Points(2).trans(1) - Points(1).trans(1)
  563.     Ay = Points(2).trans(2) - Points(1).trans(2)
  564.     Az = Points(2).trans(3) - Points(1).trans(3)
  565.     Bx = Points(3).trans(1) - Points(2).trans(1)
  566.     By = Points(3).trans(2) - Points(2).trans(2)
  567.     Bz = Points(3).trans(3) - Points(2).trans(3)
  568.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  569. End Sub
  570.  
  571.  
  572.  
  573. ' ***********************************************
  574. ' Compute a normal vector for this polygon.
  575. ' ***********************************************
  576. Public Sub NormalVector(nx As Single, ny As Single, nz As Single)
  577. Dim Ax As Single
  578. Dim Ay As Single
  579. Dim Az As Single
  580. Dim Bx As Single
  581. Dim By As Single
  582. Dim Bz As Single
  583.  
  584.     Ax = Points(2).coord(1) - Points(1).coord(1)
  585.     Ay = Points(2).coord(2) - Points(1).coord(2)
  586.     Az = Points(2).coord(3) - Points(1).coord(3)
  587.     Bx = Points(3).coord(1) - Points(2).coord(1)
  588.     By = Points(3).coord(2) - Points(2).coord(2)
  589.     Bz = Points(3).coord(3) - Points(2).coord(3)
  590.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  591. End Sub
  592.  
  593.  
  594.  
  595.  
  596. ' ***********************************************
  597. ' Compute the unit normal line segment for this
  598. ' polygon.
  599. ' ***********************************************
  600. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  601. Dim i As Integer
  602. Dim nx As Single
  603. Dim ny As Single
  604. Dim nz As Single
  605.     
  606.     UnitNormalVector nx, ny, nz
  607.     
  608.     x1 = 0
  609.     y1 = 0
  610.     z1 = 0
  611.     For i = 1 To NumPts
  612.         x1 = x1 + Points(i).coord(1)
  613.         y1 = y1 + Points(i).coord(2)
  614.         z1 = z1 + Points(i).coord(3)
  615.     Next i
  616.     x1 = x1 / NumPts
  617.     y1 = y1 / NumPts
  618.     z1 = z1 / NumPts
  619.  
  620.     x2 = x1 + nx
  621.     y2 = y1 + ny
  622.     z2 = z1 + nz
  623. End Sub
  624.  
  625.  
  626. ' ***********************************************
  627. ' Compute the unit normal vector for this
  628. ' polygon.
  629. ' ***********************************************
  630. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  631. Dim D As Single
  632.  
  633.     NormalVector nx, ny, nz
  634.     D = Sqr(nx * nx + ny * ny + nz * nz)
  635.     nx = nx / D
  636.     ny = ny / D
  637.     nz = nz / D
  638. End Sub
  639.  
  640.  
  641.  
  642.  
  643.  
  644. ' ***********************************************
  645. ' Set or clear the IsCulled flag.
  646. ' ***********************************************
  647. Property Let Culled(value As Boolean)
  648.     IsCulled = value
  649. End Property
  650.  
  651.  
  652. ' ***********************************************
  653. ' Return true if the polygon has been culled.
  654. ' ***********************************************
  655. Property Get Culled() As Boolean
  656.     Culled = IsCulled
  657. End Property
  658.  
  659. ' ***********************************************
  660. ' Return a string indicating the object type.
  661. ' ***********************************************
  662. Property Get ObjectType() As String
  663.     ObjectType = "POLYGON"
  664. End Property
  665.  
  666. ' ************************************************
  667. ' Add one or more points to the polygon.
  668. ' ************************************************
  669. Public Sub AddPoint(ParamArray coord() As Variant)
  670. Dim num_pts As Integer
  671. Dim i As Integer
  672. Dim pt As Integer
  673.  
  674.     num_pts = (UBound(coord) + 1) \ 3
  675.     ReDim Preserve Points(1 To NumPts + num_pts)
  676.  
  677.     pt = 0
  678.     For i = 1 To num_pts
  679.         Points(NumPts + i).coord(1) = coord(pt)
  680.         Points(NumPts + i).coord(2) = coord(pt + 1)
  681.         Points(NumPts + i).coord(3) = coord(pt + 2)
  682.         Points(NumPts + i).coord(4) = 1#
  683.         pt = pt + 3
  684.     Next i
  685.  
  686.     NumPts = NumPts + num_pts
  687. End Sub
  688.  
  689.  
  690. ' ************************************************
  691. ' Draw the object into a metafile.
  692. ' ************************************************
  693. Public Sub MakeWMF(mhdc As Integer)
  694. Dim pts() As POINTAPI
  695. Dim pt As Integer
  696. Dim status As Integer
  697.  
  698.     ' Don't draw if culled.
  699.     If IsCulled Then Exit Sub
  700.        
  701.     ' Fill in the point array.
  702.     ReDim pts(1 To NumPts)
  703.     For pt = 1 To NumPts
  704.         pts(pt).x = Points(pt).trans(1)
  705.         pts(pt).y = Points(pt).trans(2)
  706.     Next pt
  707.  
  708.     ' Draw the polygon.
  709.     On Error Resume Next
  710.     status = Polygon(mhdc, pts(1), NumPts)
  711. End Sub
  712.  
  713. ' ***********************************************
  714. ' Fix the data coordinates at their transformed
  715. ' values.
  716. ' ***********************************************
  717. Public Sub FixPoints()
  718. Dim i As Integer
  719. Dim j As Integer
  720.  
  721.     For i = 1 To NumPts
  722.         For j = 1 To 3
  723.             Points(i).coord(j) = Points(i).trans(j)
  724.         Next j
  725.     Next i
  726. End Sub
  727.  
  728. ' ************************************************
  729. ' Apply a transformation matrix which may not
  730. ' contain 0, 0, 0, 1 in the last column to the
  731. ' object.
  732. ' ************************************************
  733. Public Sub ApplyFull(M() As Single)
  734. Dim i As Integer
  735.  
  736.     If IsCulled Then Exit Sub
  737.     For i = 1 To NumPts
  738.         m3ApplyFull Points(i).coord, M, Points(i).trans
  739.     Next i
  740. End Sub
  741.  
  742. ' ************************************************
  743. ' Apply a transformation matrix to the object.
  744. ' ************************************************
  745. Public Sub Apply(M() As Single)
  746. Dim i As Integer
  747.  
  748.     If IsCulled Then Exit Sub
  749.     For i = 1 To NumPts
  750.         m3Apply Points(i).coord, M, Points(i).trans
  751.     Next i
  752. End Sub
  753.  
  754.  
  755. ' ************************************************
  756. ' Apply a nonlinear transformation.
  757. ' ************************************************
  758. Public Sub Distort(D As Object)
  759. Dim i As Integer
  760.  
  761.     For i = 1 To NumPts
  762.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  763.     Next i
  764. End Sub
  765.  
  766. ' ************************************************
  767. ' Write a polyline to a file using Write.
  768. ' Begin with "POLYGON" to identify this object.
  769. ' ************************************************
  770. Public Sub FileWrite(filenum As Integer)
  771. Dim i As Integer
  772.  
  773.     Write #filenum, "POLYGON", NumPts
  774.     
  775.     ' Write the points.
  776.     For i = 1 To NumPts
  777.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  778.     Next i
  779. End Sub
  780.  
  781. ' ************************************************
  782. ' Draw the transformed points on a Form, Printer,
  783. ' or PictureBox.
  784. ' ************************************************
  785. Public Sub Draw(canvas As Object, Optional r As Variant)
  786. Dim pt As Integer
  787.  
  788.     ' Don't draw if culled.
  789.     If IsCulled Then Exit Sub
  790.     
  791.     On Error Resume Next
  792.     canvas.CurrentX = Points(NumPts).trans(1)
  793.     canvas.CurrentY = Points(NumPts).trans(2)
  794.     For pt = 1 To NumPts
  795.         canvas.Line _
  796.             -(Points(pt).trans(1), Points(pt).trans(2))
  797.     Next pt
  798. End Sub
  799. ' ***********************************************
  800. ' Cull if any points are behind the center of
  801. ' projection.
  802. ' ***********************************************
  803. Public Sub ClipEye(r As Single)
  804. Dim pt As Integer
  805.  
  806.     If IsCulled Then Exit Sub
  807.     For pt = 1 To NumPts
  808.         If Points(pt).trans(3) >= r Then Exit For
  809.     Next pt
  810.     If pt <= NumPts Then IsCulled = True
  811. End Sub
  812. ' ***********************************************
  813. ' Perform backface removal.
  814. ' ***********************************************
  815. Public Sub Cull(x As Single, y As Single, Z As Single)
  816. Dim Ax As Single
  817. Dim Ay As Single
  818. Dim Az As Single
  819. Dim nx As Single
  820. Dim ny As Single
  821. Dim nz As Single
  822.  
  823.     ' Compute a normal to the face.
  824.     NormalVector nx, ny, nz
  825.  
  826.     ' Compute a vector from the center of
  827.     ' projection to the face.
  828.     Ax = Points(1).coord(1) - x
  829.     Ay = Points(1).coord(2) - y
  830.     Az = Points(1).coord(3) - Z
  831.     
  832.     ' See if the vectors meet at an angle < 90.
  833.     IsCulled = (Ax * nx + Ay * ny + Az * nz > -0.0001)
  834. End Sub
  835.  
  836. ' ************************************************
  837. ' Read a polyline from a file using Input.
  838. ' Assume the "POLYGON" label has already been
  839. ' read.
  840. ' ************************************************
  841. Public Sub FileInput(filenum As Integer)
  842. Dim i As Integer
  843.  
  844.     Input #filenum, NumPts
  845.     
  846.     ' Allocate and read the points.
  847.     ReDim Points(1 To NumPts)
  848.     For i = 1 To NumPts
  849.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  850.         Points(i).coord(4) = 1#
  851.     Next i
  852. End Sub
  853.  
  854.  
  855.