Advertisement
Guest User

Untitled

a guest
Dec 6th, 2012
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 34.23 KB | None | 0 0
  1. Option Explicit On
  2. Imports System.IO
  3.  
  4. Public Class Form1
  5. Structure DPoint
  6. Dim X As Double
  7. Dim Y As Double
  8. Sub New(ByVal pX As Double, ByVal pY As Double)
  9. X = pX
  10. Y = pY
  11. End Sub
  12. Function ToInt()
  13. Return New Point(CInt(Math.Round(X)), CInt(Math.Round(Y)))
  14. End Function
  15. Function Round(Optional ByVal digits As Integer = 0, Optional ByVal mode As System.MidpointRounding = MidpointRounding.AwayFromZero)
  16. Return New DPoint(Math.Round(X, digits, mode), Math.Round(Y, digits, mode))
  17. End Function
  18. Public Shared Operator <>(ByVal a As DPoint, ByVal b As DPoint) As Boolean
  19. If a.X <> b.X Then Return False
  20. If a.Y <> b.Y Then Return False
  21. Return True
  22. End Operator
  23. Public Shared Operator =(ByVal a As DPoint, ByVal b As DPoint) As Boolean
  24. If a.X <> b.X Then Return False
  25. If a.Y <> b.Y Then Return False
  26. Return True
  27. End Operator
  28. Public Shared Operator +(ByVal a As DPoint, ByVal b As DPoint) As DPoint
  29. Return New DPoint(a.X + b.X, a.Y + b.Y)
  30. End Operator
  31. Public Shared Operator -(ByVal a As DPoint, ByVal b As DPoint) As DPoint
  32. Return New DPoint(a.X - b.X, a.Y - b.Y)
  33. End Operator
  34. Public Shared Operator *(ByVal a As DPoint, ByVal b As DPoint) As DPoint
  35. Return New DPoint(a.X * b.X, a.Y * b.Y)
  36. End Operator
  37. Public Shared Operator /(ByVal a As DPoint, ByVal b As DPoint) As DPoint
  38. Return New DPoint(a.X / b.X, a.Y / b.Y)
  39. End Operator
  40. Public Shared Operator /(ByVal a As DPoint, ByVal b As Double) As DPoint
  41. Return New DPoint(a.X / b, a.Y / b)
  42. End Operator
  43. Public Shared Operator *(ByVal a As DPoint, ByVal b As Double) As DPoint
  44. Return New DPoint(a.X * b, a.Y * b)
  45. End Operator
  46. Public Shared Operator +(ByVal a As DPoint, ByVal b As Double) As DPoint
  47. Return New DPoint(a.X + b, a.Y + b)
  48. End Operator
  49. Public Shared Operator -(ByVal a As DPoint, ByVal b As Double) As DPoint
  50. Return New DPoint(a.X - b, a.Y - b)
  51. End Operator
  52. End Structure
  53. Dim MainImage As New DynamicBitmap
  54. Dim Points() As DPoint = {New DPoint(0.0, 0.0), New DPoint(10.0, 10.0), New DPoint(10.0, 15.0), New DPoint(15.0, 15.0), New DPoint(20.0, -20.0), New DPoint(-20.0, -20.0), New DPoint(0.0, -10.0), New DPoint(-10.0, -10.0), New DPoint(-10.0, 0.0)}
  55. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  56. Dim temp As New DynamicBitmap
  57. MainImage.CreateGrid(500, 500, 1, 1)
  58. temp.LoadBitmap("map.jpg")
  59. MainImage.DrawOnSurface(temp.Bitmap, temp.Rectangle, MainImage.Rectangle)
  60. MainImage.Surface.DrawLine(Pens.Black, 0, 250, 500, 250)
  61. MainImage.Surface.DrawLine(Pens.Black, 250, 0, 250, 500)
  62. For i As Integer = 0 To Points.Length - 2
  63. MainImage.Surface.DrawLine(Pens.Black, PointToImage(Points(i).ToInt()), PointToImage(Points(i + 1).ToInt()))
  64. Next
  65.  
  66. PictureBox1.Image = MainImage.Bitmap
  67. PictureBox1.Refresh()
  68. End Sub
  69. Function DrawCross(ByVal Point As Point, ByVal color As Pen) As Integer
  70. MainImage.Surface.DrawLine(color, Point.X - 1, Point.Y - 1, Point.X + 1, Point.Y + 1)
  71. MainImage.Surface.DrawLine(color, Point.X + 1, Point.Y - 1, Point.X - 1, Point.Y + 1)
  72. Return 1
  73. End Function
  74. Function PointToImage(ByVal P1 As Point) As Point
  75. Return New Point(250 + (P1.X * 10), 250 - (P1.Y * 10))
  76. End Function
  77. Function PointToImage(ByVal P1() As Point) As Point()
  78. Dim ret(0 To P1.Length - 1) As Point
  79. For i As Integer = 0 To P1.Length - 1
  80. ret(i) = New Point(250 + (P1(i).X * 10), 250 - (P1(0).Y * 10))
  81. Next
  82. Return ret
  83. End Function
  84. Function PointToImage(ByVal P1 As DPoint) As Point
  85. Return New Point(250 + CInt(P1.X * 10), 250 - CInt(P1.Y * 10))
  86. End Function
  87. Function PointToImage(ByVal P1() As DPoint) As Point()
  88. Dim ret(0 To P1.Length - 1) As Point
  89. For i As Integer = 0 To P1.Length - 1
  90. ret(i) = New Point(250 + (CInt(P1(i).X * 10.0)), 250 - (CInt(P1(0).Y * 10.0)))
  91. Next
  92. Return ret
  93. End Function
  94. Function func_u(ByVal P As DPoint) As DPoint ' dpoint is a simple X,Y point in decimal instead of an integer without a comma (plain *point*)
  95. Return P / ((P.X * P.X) + (P.Y * P.Y))
  96. End Function
  97. Function func_r(ByVal P As DPoint) As DPoint
  98. Return func_u(New DPoint(P.Y, -P.X))
  99. End Function
  100. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button1.Click
  101. Dim P() As DPoint = Points
  102. Dim B(0 To 1)() As DPoint
  103. Dim distance As Double = 0.3
  104. For i As Integer = 1 To P.Length - 2
  105. ReDim Preserve B(0)(i - 1)
  106. ReDim Preserve B(1)(i - 1)
  107. B(0)(i - 1) = P(i) + ((func_r(func_u(P(i + 1) - P(i)) - func_u(P(i - 1) - P(i)))) * distance)
  108. B(1)(i - 1) = P(i) - ((func_r(func_u(P(i + 1) - P(i)) - func_u(P(i - 1) - P(i)))) * distance)
  109. Next
  110. DrawCrossArray(B(0), Pens.Red)
  111. DrawCrossArray(B(1), Pens.Blue)
  112. PictureBox1.Refresh()
  113. End Sub
  114. Function DrawCrossArray(ByVal Point() As DPoint, ByVal color As Pen) As Integer
  115. For i As Integer = 0 To Point.Length - 1
  116. MainImage.Surface.DrawLine(color, PointToImage(Point(i) - 0.1), PointToImage(Point(i) + 0.1))
  117. MainImage.Surface.DrawLine(color, PointToImage(Point(i) + New DPoint(0.1, -0.1)), PointToImage(Point(i) + New DPoint(-0.1, 0.1)))
  118. Next
  119. Return 1
  120. End Function
  121. End Class
  122.  
  123.  
  124. Public Class DynamicBitmap
  125.  
  126. 'Completed 28 May 2010
  127. 'Updated to Version 2.4 on 18 June 2010
  128. 'Current Version 2.4.0
  129.  
  130. Private clsBitmapImage As Bitmap
  131. Private clsBitmapMemory As Bitmap
  132. Private clsGraphicsBuffer As Graphics
  133.  
  134. Private isGrid As Boolean
  135. Private tlWidth As Integer
  136. Private tlHeight As Integer
  137. Private rowCnt As Integer
  138. Private columnCnt As Integer
  139. Private bmpFileName As String
  140.  
  141. Private doesExist As Boolean
  142.  
  143. Public Path() As Integer
  144.  
  145. Public Enum Direction
  146. North
  147. South
  148. East
  149. West
  150. NorthEast
  151. SouthEast
  152. NorthWest
  153. SouthWest
  154. End Enum
  155.  
  156. Public Sub DrawOnSurface(ByVal source As Bitmap, ByVal srcRectangle As Rectangle, ByVal destRectangle As Rectangle, _
  157. Optional ByVal Stretch As Boolean = True, Optional ByVal Center As Boolean = False, _
  158. Optional ByVal InterpolMode As Drawing2D.InterpolationMode = Drawing2D.InterpolationMode.Default)
  159.  
  160. Dim texBrush As TextureBrush = New TextureBrush(source)
  161. Dim tmpL As Integer, tmpT As Integer
  162.  
  163. clsGraphicsBuffer.InterpolationMode = InterpolMode
  164. If Stretch = True Then
  165. clsGraphicsBuffer.DrawImage(source, destRectangle, srcRectangle, GraphicsUnit.Pixel)
  166. Else
  167. If Center = False Then
  168. clsGraphicsBuffer.DrawImage(source, destRectangle.X, destRectangle.Y, srcRectangle, GraphicsUnit.Pixel)
  169. Else
  170. tmpL = destRectangle.X + ((destRectangle.Width - srcRectangle.Width) / 2)
  171. tmpT = destRectangle.Y + ((destRectangle.Height - srcRectangle.Height) / 2)
  172. clsGraphicsBuffer.DrawImage(source, tmpL, tmpT, srcRectangle, GraphicsUnit.Pixel)
  173. End If
  174.  
  175. End If
  176. texBrush.Dispose()
  177. End Sub
  178.  
  179.  
  180.  
  181.  
  182. ''' <summary>
  183. ''' INITIALIZING CLASS SECTION
  184. ''' : 3 Options to initialize this class - load a bitmap, create a blank bitmap, or create parameters for a grid and subsequent blank bitmap
  185. ''' </summary>
  186. ''' <param name="fromFileName"></param>
  187. ''' <remarks></remarks>
  188. Public Sub LoadBitmap(ByVal fromFileName As String, Optional ByVal tilesWidth As Integer = 0, Optional ByVal tilesHeight As Integer = 0)
  189. isGrid = False 'Only set to true if "CreateGrid" is called
  190. clsBitmapImage = New Bitmap(fromFileName)
  191. clsGraphicsBuffer = Graphics.FromImage(clsBitmapImage)
  192. bmpFileName = fromFileName
  193. TileHeight = tilesHeight
  194. TileWidth = tilesWidth
  195. doesExist = True
  196. End Sub
  197. Public Sub CreateBitmap(ByVal bmpWidth As Integer, ByVal bmpHeight As Integer)
  198. isGrid = False 'Only set to true if "CreateGrid" is called
  199. clsBitmapImage = New Bitmap(bmpWidth, bmpHeight)
  200. clsGraphicsBuffer = Graphics.FromImage(clsBitmapImage)
  201. TileWidth = bmpWidth
  202. TileHeight = bmpHeight
  203. doesExist = True
  204. End Sub
  205. Public Sub CreateGrid(ByVal tilesWidth As Integer, ByVal tilesHeight As Integer, ByVal rowCount As Integer, ByVal columnCount As Integer)
  206.  
  207. 'The isGrid variable tells the TileWidth/TileHeight properties not to automatically
  208. 'determine the row/column count since the user has specified those variables in this subroutine
  209. isGrid = True
  210.  
  211. 'Creates a blank bitmap equal to the size of the grid
  212. CreateBitmap(columnCount * tilesWidth, rowCount * tilesHeight)
  213.  
  214. 'Sets the dimensions of the specified grid
  215. TileWidth = tilesWidth
  216. TileHeight = tilesHeight
  217.  
  218. 'Sets the row and column count based on what the user has input
  219. rowCnt = rowCount
  220. columnCnt = columnCount
  221.  
  222.  
  223.  
  224. doesExist = True
  225. End Sub
  226.  
  227.  
  228.  
  229.  
  230.  
  231. ''' <summary>
  232. ''' TILE METHODS SECTION
  233. ''' : Tiles can be either grid cells or sprite blocks, depending on how the user is using the class
  234. ''' </summary>
  235. ''' <value></value>
  236. ''' <returns></returns>
  237. ''' <remarks></remarks>
  238. Public Property TileHeight As Integer
  239. 'Sets the value of the tile height (for the user, this may be a cell property
  240. 'or sprite property if LoadBitmap was called and a tile sheet file was loaded
  241. Get
  242. TileHeight = tlHeight
  243. End Get
  244. Set(ByVal value As Integer)
  245. tlHeight = value
  246. If tlHeight = 0 Then tlHeight = clsBitmapImage.Height
  247. 'If the user is setting parameters for a sprite map or tile sheet,
  248. 'the property automatically determines the row count
  249. If isGrid = False Then
  250. rowCnt = Math.Truncate(clsBitmapImage.Height / tlHeight)
  251. End If
  252. End Set
  253. End Property
  254. Public Property TileWidth As Integer
  255. 'Sets the value of the tile width (for the user, this may be a cell property
  256. 'or sprite property if LoadBitmap was called and a tile sheet file was loaded
  257. Get
  258. TileWidth = tlWidth
  259. End Get
  260. Set(ByVal value As Integer)
  261. tlWidth = value
  262. If tlWidth = 0 Then tlWidth = clsBitmapImage.Width
  263. 'If the user is setting parameters for a sprite map or tile sheet,
  264. 'the property automatically determines the column count
  265. If isGrid = False Then
  266. columnCnt = Math.Truncate(clsBitmapImage.Width / tlWidth)
  267. End If
  268. End Set
  269. End Property
  270.  
  271. Public ReadOnly Property TileCount As Integer
  272. Get
  273. TileCount = rowCnt * columnCnt
  274. Return TileCount
  275. End Get
  276. End Property
  277. Public ReadOnly Property Point(Optional ByVal TileIndex As Integer = 0) As Point
  278. Get
  279. 'Sets default point to upper left/top position of bitmap
  280. Point.X = 0
  281. Point.Y = 0
  282.  
  283. 'Error Handling
  284. If TileIndex < 1 Then Exit Property
  285. If TileIndex > TileCount Then Exit Property
  286. If TileIndex = 1 And TileCount = 1 Then Exit Property
  287.  
  288. 'Determine X point
  289. Point.X = TileIndex
  290. Do While Point.X > columnCnt
  291. Point.X -= columnCnt
  292. Loop
  293. Point.X -= 1
  294. Point.X = (TileWidth * Point.X)
  295.  
  296. 'Determine Y point
  297. Point.Y = TileIndex - 1
  298. Point.Y = Math.Truncate(Point.Y / columnCnt)
  299. Point.Y = Point.Y * TileHeight
  300.  
  301. Return Point
  302. End Get
  303. End Property
  304. Public ReadOnly Property Rectangle(Optional ByVal TileIndex As Integer = 0) As Rectangle
  305. Get
  306. 'Sets default rectangle to entire bitmap
  307. Rectangle = New Rectangle(0, 0, clsBitmapImage.Width, clsBitmapImage.Height)
  308.  
  309. 'Error Handling
  310. If TileIndex < 1 Then Exit Property
  311. If TileIndex > TileCount Then Exit Property
  312. If TileIndex = 1 And TileCount = 1 Then Exit Property
  313.  
  314. 'Sets rectangle to the specified tile
  315. Rectangle = New Rectangle(Point(TileIndex), New Size(TileWidth, TileHeight))
  316.  
  317. Return Rectangle
  318. End Get
  319. End Property
  320.  
  321. Public Function Tile(ByVal AtPoint As Point) As Integer
  322. 'Passes parameters to primary Tile Function below
  323. Return Tile(AtPoint.X, AtPoint.Y)
  324. End Function
  325. Public Function Tile(ByVal X As Integer, ByVal Y As Integer) As Integer
  326. 'Determines which tile the X,Y values reside in. If 0 is returned, X,Y values are outside of bitmap area
  327. Tile = 0
  328.  
  329. 'Error Handling
  330. If X < 0 Or Y < 0 Then Exit Function
  331. 'In the event the bitmap is larger than the tiled area, class does not check against bitmap.height/width properties
  332. If X >= (TileWidth * columnCnt) Or Y >= (TileHeight * rowCnt) Then Exit Function
  333.  
  334. 'At this point, we know that a valid point within the bitmap was passed
  335. Tile = 1
  336. If TileCount = 1 Then Exit Function
  337.  
  338. Dim thisColumn As Integer
  339. Dim thisRow As Integer
  340.  
  341. thisColumn = Math.Truncate(X / TileWidth)
  342. thisRow = Math.Truncate(Y / TileHeight)
  343.  
  344. Tile = (thisRow * columnCnt) + thisColumn + 1
  345. End Function
  346.  
  347. Public Function TileNeighbor(ByVal TileIndex As Integer, ByVal MoveTo As Direction, Optional ByVal StepCount As Integer = 1) As Integer
  348. 'Return the tile index of the tile directly next to this position
  349. 'StepCount is how many tiles it steps in the specified direction
  350. Dim pntInTile As Point
  351.  
  352. TileNeighbor = 0
  353.  
  354. 'Error Handling
  355. If TileIndex < 1 Then Exit Function
  356. If TileIndex > TileCount Then Exit Function
  357. If TileIndex = 1 And TileCount = 1 Then Exit Function
  358. If StepCount > columnCnt And StepCount > rowCnt Then Exit Function
  359. If StepCount < 1 Then StepCount = 1
  360.  
  361. 'Get the point value of the TileIndex
  362. pntInTile = Point(TileIndex)
  363.  
  364. 'Add to either the X or Y values of the point value to move to a neighboring tile
  365. For clsI As Integer = 1 To StepCount
  366. Select Case MoveTo
  367. Case Direction.North
  368. pntInTile.Y -= TileHeight
  369. Case Direction.NorthEast
  370. pntInTile.X += TileWidth
  371. pntInTile.Y -= TileHeight
  372. Case Direction.East
  373.  
  374. pntInTile.X += TileWidth
  375. Case Direction.SouthEast
  376. pntInTile.X += TileWidth
  377. pntInTile.Y += TileHeight
  378. Case Direction.South
  379. pntInTile.Y += TileHeight
  380. Case Direction.SouthWest
  381. pntInTile.X -= TileWidth
  382. pntInTile.Y += TileHeight
  383. Case Direction.West
  384. pntInTile.X -= TileWidth
  385. Case Direction.NorthWest
  386. pntInTile.X -= TileWidth
  387. pntInTile.Y -= TileHeight
  388. End Select
  389. Next
  390.  
  391. 'Check to see if is a valid tile (will return 0 if not)
  392. TileNeighbor = Tile(pntInTile)
  393.  
  394. End Function
  395.  
  396.  
  397.  
  398.  
  399. ''' <summary>
  400. ''' Functions and Subroutines
  401. ''' : Primary workings of the class module
  402. ''' </summary>
  403. ''' <remarks></remarks>
  404. Public Sub DrawTileLines()
  405. 'Passes parameters to primary function below
  406. DrawTileLines(Color.Black)
  407. End Sub
  408. Public Sub DrawTileLines(ByVal LineColor As Color, Optional ByVal HideBorder As Boolean = False)
  409. 'Will draw lines onto the bitmap
  410.  
  411. 'Tiles are considered directly next to each other, so technically there is no boundary between tiles
  412. 'The border pixels of each tile will be drawn over when this subroutine is called
  413.  
  414. Dim defPen As Pen
  415. Dim point1 As Point
  416. Dim point2 As Point
  417.  
  418. 'Default Pen is defined
  419. defPen = New Pen(LineColor, 1)
  420.  
  421. 'Draw column lines
  422. For c As Long = 0 To columnCnt
  423. If HideBorder = True And (c = 0 Or c = columnCnt) Then
  424. 'Do not draw first or last column lines
  425. Else
  426. 'Set starting point to draw column lines
  427. point1.X = (TileWidth * c)
  428. point1.Y = 0
  429.  
  430. 'Set ending point to draw column lines
  431. point2.X = point1.X
  432. point2.Y = (TileHeight * rowCnt)
  433.  
  434. 'Draw each column line
  435. If c <> columnCnt Then
  436. clsGraphicsBuffer.DrawLine(defPen, point1.X, point1.Y, point2.X, point2.Y - 1)
  437. Else
  438. 'Draw last line 1 pixel to the left
  439. clsGraphicsBuffer.DrawLine(defPen, point1.X - 1, point1.Y, point2.X - 1, point2.Y - 1)
  440. End If
  441. End If
  442. Next
  443.  
  444. 'Draw row lines
  445. For r As Long = 0 To rowCnt
  446. If HideBorder = True And (r = 0 Or r = rowCnt) Then
  447. 'Do not draw first or last row lines
  448. Else
  449. 'Set starting point to draw row lines
  450. point1.X = 0
  451. point1.Y = (TileHeight * r)
  452.  
  453. 'Set ending point to draw row lines
  454. point2.X = (TileWidth * columnCnt)
  455. point2.Y = point1.Y
  456.  
  457. 'Draw each row line
  458. If r <> rowCnt Then
  459. clsGraphicsBuffer.DrawLine(defPen, point1.X, point1.Y, point2.X - 1, point2.Y)
  460. Else
  461. 'Draw last line 1 pixel higher
  462. clsGraphicsBuffer.DrawLine(defPen, point1.X, point1.Y - 1, point2.X - 1, point2.Y - 1)
  463. End If
  464. End If
  465. Next
  466. End Sub
  467. Public Sub MakeTransparent()
  468. MakeTransparent(Color.Magenta)
  469. End Sub
  470. Public Sub MakeTransparent(ByVal transparentColor As Color)
  471. clsBitmapImage.MakeTransparent(transparentColor)
  472. End Sub
  473. Public Sub AlphaBlend(Optional ByVal Alpha As Integer = 75)
  474. Dim i As Integer
  475. Dim j As Integer
  476. Dim clr As Color
  477. Dim newClr As Color
  478. For i = 0 To clsBitmapImage.Width - 1
  479. For j = 0 To clsBitmapImage.Height - 1
  480. clr = clsBitmapImage.GetPixel(i, j)
  481. newClr = Color.FromArgb(Alpha, clr.R, clr.G, clr.B)
  482. clsBitmapImage.SetPixel(i, j, newClr)
  483. Next
  484. Next
  485. End Sub
  486. Public Sub Text(ByVal txtString As String, ByVal printBox As Rectangle, ByVal useFont As Font, ByVal useBrush As Brush)
  487. Dim strFormat As New StringFormat
  488.  
  489. strFormat.Alignment = StringAlignment.Center
  490. strFormat.LineAlignment = StringAlignment.Center
  491.  
  492. clsGraphicsBuffer.DrawString(txtString, useFont, useBrush, printBox, strFormat)
  493. End Sub
  494. Public Sub FillTile(ByVal X As Integer, ByVal Y As Integer, ByVal fillColor As Color, Optional ByVal OutlineOnly As Boolean = False)
  495. 'Passes parameters to primary FillTile Function below
  496. FillTile(Tile(X, Y), fillColor, OutlineOnly)
  497. End Sub
  498. Public Sub FillTile(ByVal TileIndex As Integer, ByVal fillColor As Color, Optional ByVal OutlineOnly As Boolean = False)
  499. 'Fills the specified tile with a solid color; optional outline only
  500. Dim outlinePen As Pen
  501.  
  502. 'Error Handling
  503. If TileIndex < 1 Then Exit Sub
  504. If TileIndex > TileCount Then Exit Sub
  505.  
  506. outlinePen = New Pen(fillColor)
  507.  
  508. clsGraphicsBuffer.DrawRectangle(outlinePen, Rectangle(TileIndex))
  509.  
  510. If OutlineOnly = True Then Exit Sub
  511.  
  512. clsGraphicsBuffer.FillRectangle(New SolidBrush(fillColor), Rectangle(TileIndex))
  513.  
  514. End Sub
  515. Public Sub FloodFill(ByVal X As Integer, ByVal Y As Integer, ByVal newColor As Color)
  516. 'Passes parameters to primary FloodFill subroutine below
  517. Dim clsAPoint As Point
  518. clsAPoint.X = X
  519. clsAPoint.Y = Y
  520. FloodFill(clsAPoint, newColor)
  521. End Sub
  522. Public Sub FloodFill(ByVal AtPoint As Point, ByVal newColor As Color)
  523. Dim oldColor As Color = clsBitmapImage.GetPixel(AtPoint.X, AtPoint.Y)
  524.  
  525. If oldColor.ToArgb <> newColor.ToArgb Then
  526. Dim pts As New Stack(1000)
  527. pts.Push(New Point(AtPoint.X, AtPoint.Y))
  528. clsBitmapImage.SetPixel(AtPoint.X, AtPoint.Y, newColor)
  529.  
  530. Do While pts.Count > 0
  531. Dim pt As Point = DirectCast(pts.Pop(), Point)
  532.  
  533. If pt.X > 0 Then ProcessPoint(pts, pt.X - 1, pt.Y, oldColor, newColor)
  534. If pt.Y > 0 Then ProcessPoint(pts, pt.X, pt.Y - 1, oldColor, newColor)
  535. If pt.X < clsBitmapImage.Width - 1 Then ProcessPoint(pts, pt.X + 1, pt.Y, oldColor, newColor)
  536. If pt.Y < clsBitmapImage.Height - 1 Then ProcessPoint(pts, pt.X, pt.Y + 1, oldColor, newColor)
  537. Loop
  538.  
  539. End If
  540. End Sub
  541. Private Sub ProcessPoint(ByVal pts As Stack, ByVal X As Integer, ByVal Y As Integer, ByVal oldColor As Color, ByVal newColor As Color)
  542. Dim clr As Color = clsBitmapImage.GetPixel(X, Y)
  543. If clr.Equals(oldColor) Then
  544. pts.Push(New Point(X, Y))
  545. clsBitmapImage.SetPixel(X, Y, newColor)
  546. End If
  547. End Sub
  548.  
  549.  
  550. Public Sub ImageStore()
  551. clsBitmapMemory = New Bitmap(clsBitmapImage)
  552. End Sub
  553. Public Sub ImageRestore()
  554. DrawOnSurface(clsBitmapMemory, New Rectangle(0, 0, clsBitmapMemory.Width, clsBitmapMemory.Height), Rectangle, False)
  555. End Sub
  556.  
  557. ''' <summary>
  558. ''' Basic Class Properties
  559. ''' </summary>
  560. ''' <value></value>
  561. ''' <returns></returns>
  562. ''' <remarks></remarks>
  563. Public ReadOnly Property Exists() As Boolean
  564. Get
  565. Exists = doesExist
  566. End Get
  567. End Property
  568. Public ReadOnly Property Bitmap As Bitmap
  569. Get
  570. Bitmap = clsBitmapImage
  571. End Get
  572. End Property
  573. Public ReadOnly Property Surface As Graphics
  574. Get
  575. Surface = clsGraphicsBuffer
  576. End Get
  577. End Property
  578. Public ReadOnly Property FileName As String
  579. Get
  580. FileName = vbNullString
  581. If bmpFileName <> vbNullString Then FileName = bmpFileName
  582. End Get
  583. End Property
  584. Public Sub Clear()
  585. Clear(Color.White)
  586. End Sub
  587. Public Sub Clear(ByVal clrColor As Color, Optional ByVal transparentFill As Boolean = False)
  588. Dim fillPen As Pen
  589. fillPen = New Pen(clrColor)
  590. clsGraphicsBuffer.FillRectangle(New SolidBrush(clrColor), New Rectangle(0, 0, clsBitmapImage.Width, clsBitmapImage.Height))
  591. If transparentFill = True Then FloodFill(Point(1), Color.FromArgb(0, 255, 255, 255))
  592. End Sub
  593. Public Sub Dispose()
  594. clsGraphicsBuffer.Dispose()
  595. clsBitmapImage.Dispose()
  596. doesExist = False
  597. End Sub
  598.  
  599. ''' <summary>
  600. ''' PATH FINDING VARIABLES, ALGORITHM, AND FUNCTIONS START HERE
  601. ''' </summary>
  602. ''' <remarks></remarks>
  603. Private Enum NodeStatus
  604. Closed = 0
  605. Open = 1
  606. NotEvaluated = 2
  607. End Enum
  608. Private Structure Node
  609. Dim ParentNode As Integer 'Index of parent node
  610. Dim MoveCost As Integer 'Pulled from MovementCost()
  611. Dim ScoreG As Integer 'Movement cost from start point to this node
  612. Dim ScoreH As Integer 'Best guess movement cost from this node to end point
  613. Dim ScoreF As Integer 'Sum of ScoreG and ScoreH (estimated total movement cost from start to end point)
  614. Dim Status As NodeStatus 'Determines if node is in the closed or opened list
  615. End Structure
  616. Private ANode() As Node
  617.  
  618. Public Function FindPath(ByVal MovementCost() As Integer, ByVal StartNode As Integer, ByVal EndNode As Integer, Optional ByVal allowDiagonalMoves As Boolean = True) As Boolean
  619.  
  620. FindPath = False 'If false, no path has been found or bad data has been passed to FindPath function
  621.  
  622. 'Error catching
  623. If TileCount <= 1 Then Exit Function 'no grid properties have been defined
  624. If StartNode < 1 Then Exit Function 'node outside the grid area
  625. If StartNode > TileCount Then Exit Function 'node outside the grid area
  626. If EndNode < 1 Then Exit Function 'node outside the grid area
  627. If EndNode > TileCount Then Exit Function 'node outside the grid area
  628. If UBound(MovementCost) <> TileCount Then Exit Function 'movement cost count doesn't match tile count
  629.  
  630. 'Create nodes based on grid dimensions and transfer data from MovementCost()
  631. ReDim ANode(TileCount)
  632. 'Ignore ANode(0) to ensure nodes equal the grid dimensions exactly as used in the DynamicBitmap class (grid tiles start on 1, not 0)
  633. For i As Integer = 1 To TileCount
  634. ANode(i).MoveCost = MovementCost(i)
  635. ANode(i).Status = NodeStatus.NotEvaluated
  636. Next
  637.  
  638. 'Reset solution path in case it was previously populated
  639. ReDim Path(0)
  640. Path(0) = 0
  641.  
  642. 'Add the start node to the open list
  643. ANode(StartNode).Status = NodeStatus.Open
  644.  
  645. 'Determine the F score for the start node
  646. 'The ComputeScore function "by references" the Node, so values are changed without having to use the '=' sign
  647. ComputeScore(StartNode, EndNode, allowDiagonalMoves)
  648.  
  649.  
  650. 'Determine which neighbors to view (vertical/horizontal only or include diagonal neighbors)
  651. 'Values relate directly to "Direction" enum (See "Public Enum Direction" at top of DymamicBitmap class for more info)
  652. Dim neighborCnt As Integer = 3 'Directions 0 to 3
  653. If allowDiagonalMoves = True Then neighborCnt = 7 'Directions 0 to 7
  654.  
  655. 'Initalize variables
  656. Dim thisNode As Integer 'The current node we are working with
  657. Dim thisNeighbor As Integer 'The current neighbor of current node we are working with
  658.  
  659.  
  660. 'Begin the main A* pathfinding operations
  661. Do
  662. 'Get the node with the lowest F score
  663. thisNode = LowestF()
  664.  
  665. 'If thisNode = 0, then there are no more open nodes (no path found)
  666. If thisNode = 0 Then Exit Function
  667.  
  668. 'Move thisNode to the closed list
  669. ANode(thisNode).Status = NodeStatus.Closed
  670.  
  671. 'Check to see if thisNode is the target node. If it is, exit the loop (path found)
  672. If thisNode = EndNode Then Exit Do
  673.  
  674. 'Go through each neighbor of 'thisNode'
  675. For aNeighbor = 0 To neighborCnt
  676. thisNeighbor = TileNeighbor(thisNode, aNeighbor)
  677.  
  678. 'If thisNeighbor = 0, then it's outside the grid
  679. 'If the movement cost of thisNeighbor = 0, then it's a wall or other obstacle that can't be passed over
  680. 'If thisNeighbor is on the closed list, ignore it
  681. If thisNeighbor <> 0 And ANode(thisNeighbor).MoveCost <> 0 And ANode(thisNeighbor).Status <> NodeStatus.Closed Then
  682.  
  683.  
  684. 'If this neighbor is already on the open list, check to see if this route would be better
  685. 'In other words, check to see if it's G score would be lower using thisNode as it's parent
  686. If ANode(thisNeighbor).Status = NodeStatus.Open Then
  687.  
  688. 'Temporary save the data from thisNeighbor so we can evaluate it against thisNode as it's parent
  689. Dim tempNode As Node
  690. tempNode = ANode(thisNeighbor)
  691.  
  692. 'Calcuate the new scores based on thisNode as it's parent
  693. ANode(thisNeighbor).ParentNode = thisNode
  694. ComputeScore(thisNeighbor, EndNode, allowDiagonalMoves)
  695.  
  696. 'Compare the two G values
  697. 'If the new G score is higher than the original G score (longer route), restore thisNeighbor's original properties from tempNode
  698. 'If the new G score is lower (faster route) then leave the changes that were made in the previous step
  699. If ANode(thisNeighbor).ScoreG >= tempNode.ScoreG Then ANode(thisNeighbor) = tempNode
  700.  
  701. Else
  702. 'This neighbor has not yet been examined by any other node
  703. 'This is a possible route; add this neighbor to the open list, set thisNode as it's parent, and calculate F score
  704. ANode(thisNeighbor).Status = NodeStatus.Open
  705. ANode(thisNeighbor).ParentNode = thisNode
  706. ComputeScore(thisNeighbor, EndNode, allowDiagonalMoves)
  707.  
  708. End If
  709.  
  710. End If
  711. Next
  712. Loop
  713.  
  714.  
  715. 'PATH HAS BEEN FOUND
  716.  
  717.  
  718. 'Work backwards from the end node to determine our path and populate it into a temporary array
  719. Dim ReversePath() As Integer
  720. Dim Xcounter As Integer = 0
  721. thisNode = EndNode
  722. Do
  723. 'Count each node and populate it into a temporary array
  724. Xcounter = Xcounter + 1
  725. ReDim Preserve ReversePath(Xcounter - 1)
  726. ReversePath(Xcounter - 1) = thisNode
  727.  
  728. 'If we've reached the start node, exit loop
  729. If thisNode = StartNode Then Exit Do
  730.  
  731. 'Set the next 'thisNode' to the parent of the node we are on (work backwards until the start node is reached)
  732. thisNode = ANode(thisNode).ParentNode
  733. Loop
  734.  
  735.  
  736. 'Reverse the order of our path so that Path(0) = startNode and Ubound(Path) = endNode
  737. ReDim Path(Xcounter - 1)
  738. For theNextNode As Integer = 0 To Xcounter - 1
  739. Path(theNextNode) = ReversePath(UBound(ReversePath) - theNextNode)
  740. Next
  741.  
  742. FindPath = True
  743.  
  744. End Function
  745. Private Function LowestF() As Integer
  746. 'Returns the node with the lowest F score on the Open list
  747. Dim chkScore As Integer
  748. Dim lowScore As Integer
  749.  
  750. LowestF = 0
  751.  
  752. 'Set our lowScore large enough that the first node evaluated will become our default first low score
  753. lowScore = 32767
  754.  
  755.  
  756. 'Evaluate each of the nodes
  757. For iNode As Integer = 1 To TileCount
  758. 'Compare open list nodes with the current lowest score
  759. If ANode(iNode).Status = NodeStatus.Open Then
  760.  
  761. 'If the current nodes F score is lower, change it to the current lowest node
  762. chkScore = ANode(iNode).ScoreF
  763. If chkScore <= lowScore Then
  764. LowestF = iNode
  765. lowScore = chkScore
  766. End If
  767. End If
  768. Next
  769.  
  770. 'If LowestF = 0, then there were no open nodes
  771. End Function
  772. Private Sub ComputeScore(ByRef computeNode As Integer, ByVal ENode As Integer, ByVal ad As Boolean)
  773. 'Determines the G, H, and F values of the argument node
  774.  
  775. 'DETERMINE G VALUE
  776. ANode(computeNode).ScoreG = 0
  777. 'If the node has no parent, value G is 0
  778. If ANode(computeNode).ParentNode <> 0 Then
  779.  
  780. 'Set the G value of the node equal to it's parents G value
  781. ANode(computeNode).ScoreG = ANode(ANode(computeNode).ParentNode).ScoreG
  782.  
  783.  
  784. 'If the parent is on the same row or column, increase G value
  785. 'by 10 * the movement cost of this node
  786. If TileRow(ANode(computeNode).ParentNode) = TileRow(computeNode) Or _
  787. TileColumn(ANode(computeNode).ParentNode) = TileColumn(computeNode) Then
  788.  
  789. ANode(computeNode).ScoreG = ANode(computeNode).ScoreG + (10 * ANode(computeNode).MoveCost)
  790.  
  791. Else
  792.  
  793. 'If the parent isn't on the same row or column, it is diagonal from this node;
  794. 'increase G value by 14 * the movement cost of this node if diagonal moves are allowed
  795. If ad = True Then ANode(computeNode).ScoreG = ANode(computeNode).ScoreG + (14 * ANode(computeNode).MoveCost)
  796.  
  797. 'If diagonal moves are not allowed, this movement will take both a horizontal and vertical move to reach (x20)
  798. If ad = False Then ANode(computeNode).ScoreG = ANode(computeNode).ScoreG + (20 * ANode(computeNode).MoveCost)
  799.  
  800. End If
  801.  
  802. End If
  803.  
  804.  
  805. 'DETERMINE H VALUE
  806. ANode(computeNode).ScoreH = 0
  807.  
  808. Dim tmpRowDist As Integer
  809. Dim tmpColDist As Integer
  810.  
  811. 'Get the row and column distance from this node to the end node
  812. tmpRowDist = Math.Abs(TileRow(computeNode) - TileRow(ENode))
  813. tmpColDist = Math.Abs(TileColumn(computeNode) - TileColumn(ENode))
  814.  
  815. 'Compute H value based on estimated distance to end node
  816. If tmpRowDist < tmpColDist Then
  817. ANode(computeNode).ScoreH = (4 * tmpRowDist) + (10 * tmpColDist)
  818. Else
  819. ANode(computeNode).ScoreH = (10 * tmpRowDist) + (4 * tmpColDist)
  820. End If
  821.  
  822. 'DETERMINE F VALUE
  823. 'Add the distance from the start node (G)
  824. 'to the estimated distance to the end node (H)
  825. ANode(computeNode).ScoreF = ANode(computeNode).ScoreG + ANode(computeNode).ScoreH
  826. End Sub
  827. Public Function TileRow(ByVal TileIndex As Integer) As Integer
  828. 'Returns the row this tile is located on
  829. TileRow = Math.Truncate((TileIndex - 1) / columnCnt) + 1
  830. End Function
  831. Public Function TileColumn(ByVal TileIndex As Integer) As Integer
  832. 'Returns the column this tile is located on
  833. TileColumn = ((TileIndex - 1) Mod columnCnt) + 1
  834. If TileIndex <= columnCnt Then TileColumn = TileIndex
  835. End Function
  836.  
  837.  
  838.  
  839.  
  840. End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement