By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,033 Members | 1,285 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,033 IT Pros & Developers. It's quick & easy.

Nearest point to the mouse cursor?

P: n/a
I have been developing a little project which draw's a hexgrid on a panel
within a form similar to this - it:s used as a client from a e-mail based
strategy game:
____ ____
/ \ / \
/ (0,0) \____/ (2,0) \____/
\ / \ / \
\____/(1,1) \____/ (3,1) \_
/ \ / \
/ (0,1) \____/ (2,1) \____/
\ / \ / \
\____/(1,2) \____/ (3,2) \_
/ \ / \
/ (0,2) \____/ (2,2) \____/
\ / \ / \
\____/(1,3) \____/ (3,3) \_

The number of hexes can vary depending on the mapsize. now the problem I
currently have is trying to get a label.text to display which hex coord the
mouse is currently in.

Using the mouse move function I can get it to automatically change when it
passes over the lines in the (1,y) columns by using the following formula:

(for these purposes HexHeight = 44 pixels, HexWidth = 50 pixels)

MouseYpos = LocalMousePosition.Y / HexHeight
Label1.text = "Coords: " & MouseXpos & "," & MouseYpos

however, because the colums are staggered any column starting with an even
number get's the new coords changed halfway through it.

So I'm now leaning towards trying mark the centre point of each hex, and
then establishing which one the mousepointer is nearest to. However I'm
having difficulty in figuring out how to do this.

Can anyone help?
Nov 21 '05 #1
Share this Question
Share on Google+
16 Replies


P: n/a
Hi,
Create a region for each cell. Use the region isvisble to see if
the cursor is in the cell.

Dim rgnCircle As Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

pth.AddEllipse(100, 100, 50, 50)

rgnCircle = New Region(pth)

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Me.Text = String.Format("In Circle {0}", rgnCircle.IsVisible(New Point(e.X,
e.Y)))

End Sub

Ken

-------------------------------------

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote in message
news:9E**********************************@microsof t.com...
I have been developing a little project which draw's a hexgrid on a panel
within a form similar to this - it:s used as a client from a e-mail based
strategy game:
____ ____
/ \ / \
/ (0,0) \____/ (2,0) \____/
\ / \ / \
\____/(1,1) \____/ (3,1) \_
/ \ / \
/ (0,1) \____/ (2,1) \____/
\ / \ / \
\____/(1,2) \____/ (3,2) \_
/ \ / \
/ (0,2) \____/ (2,2) \____/
\ / \ / \
\____/(1,3) \____/ (3,3) \_

The number of hexes can vary depending on the mapsize. now the problem I
currently have is trying to get a label.text to display which hex coord the
mouse is currently in.

Using the mouse move function I can get it to automatically change when it
passes over the lines in the (1,y) columns by using the following formula:

(for these purposes HexHeight = 44 pixels, HexWidth = 50 pixels)

MouseYpos = LocalMousePosition.Y / HexHeight
Label1.text = "Coords: " & MouseXpos & "," & MouseYpos

however, because the colums are staggered any column starting with an even
number get's the new coords changed halfway through it.

So I'm now leaning towards trying mark the centre point of each hex, and
then establishing which one the mousepointer is nearest to. However I'm
having difficulty in figuring out how to do this.

Can anyone help?
Nov 21 '05 #2

P: n/a
Hi,

Thanks for the help so far but I do have one further question - how do
you do it for multiple regions?

I've managed to apply the example you gave me to my program but I now
have another problem... there could be hundreds of Hexregions on the
form at any time - the problem is it's an unknown number of regions as
the person running the server can make a map of any size.

How can I take this to the next step and get the mousemove event to
cover an unknown number of regions on the form?

Niels

Ken Tucker [MVP] wrote:
Hi,
Create a region for each cell. Use the region isvisble to see if
the cursor is in the cell.

Dim rgnCircle As Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

pth.AddEllipse(100, 100, 50, 50)

rgnCircle = New Region(pth)

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Me.Text = String.Format("In Circle {0}", rgnCircle.IsVisible(New Point(e.X,
e.Y)))

End Sub

Ken

-------------------------------------

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote in message
news:9E**********************************@microsof t.com...
I have been developing a little project which draw's a hexgrid on a panel
within a form similar to this - it:s used as a client from a e-mail based
strategy game:
____ ____
/ \ / \
/ (0,0) \____/ (2,0) \____/
\ / \ / \
\____/(1,1) \____/ (3,1) \_
/ \ / \
/ (0,1) \____/ (2,1) \____/
\ / \ / \
\____/(1,2) \____/ (3,2) \_
/ \ / \
/ (0,2) \____/ (2,2) \____/
\ / \ / \
\____/(1,3) \____/ (3,3) \_

The number of hexes can vary depending on the mapsize. now the problem I
currently have is trying to get a label.text to display which hex coord the
mouse is currently in.

Using the mouse move function I can get it to automatically change when it
passes over the lines in the (1,y) columns by using the following formula:

(for these purposes HexHeight = 44 pixels, HexWidth = 50 pixels)

MouseYpos = LocalMousePosition.Y / HexHeight
Label1.text = "Coords: " & MouseXpos & "," & MouseYpos

however, because the colums are staggered any column starting with an even
number get's the new coords changed halfway through it.

So I'm now leaning towards trying mark the centre point of each hex, and
then establishing which one the mousepointer is nearest to. However I'm
having difficulty in figuring out how to do this.

Can anyone help?

Nov 21 '05 #3

P: n/a

"Niels Jensen" <ni***@surf-spot.co.uk> wrote

Thanks for the help so far but I do have one further question - how do
you do it for multiple regions?

I've managed to apply the example you gave me to my program but I now
have another problem... there could be hundreds of Hexregions on the
form at any time - the problem is it's an unknown number of regions as
the person running the server can make a map of any size.

How can I take this to the next step and get the mousemove event to
cover an unknown number of regions on the form?

Since you have to cover some large number of cells, you might do best
by calculating the results. For an example, paste the following code in
a new form, under the Designer generated code (section).

HTH
LFS

Public Image As Bitmap
Private Rows(1) As Array

Const SX As Integer = 30 ' Red cell sizes
Const SY As Integer = 50

Const RATIO As Single = SX / SY

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Image = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
' Row map indicates which cells have angles
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}
DrawHex()
End Sub

Private Sub HexCell(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
Dim r, x, y, hx, hy As Integer
Dim a As Integer()

' Get red grid cell x and y
x = e.X \ SX
y = e.Y \ SY

' Preliminary HexX and HexY
hx = x \ 3
hy = y \ 2

' Get row map value (r)
a = CType(Rows(y And 1), Integer())
r = a(x Mod 6)

' Adjust for angled cells
If r = -1 Then
If (e.X - (x * SX)) < ((SY - (e.Y - (y * SY))) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (SY - (e.Y - (y * SY))).ToString & " -Y " & ((SY - (e.Y - (y *
SY))) * RATIO).ToString)
ElseIf r = -2 Then
If (e.X - (x * SX)) < ((e.Y - (y * SY)) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (e.Y - (y * SY)).ToString & " -Y " & ((e.Y - (y * SY)) *
RATIO).ToString)
End If

' Adjust for y offset in odd hex columns
If (hx And 1) = 1 AndAlso (y And 1) = 0 Then hy -= 1

' Show values
Dim msg As String = "X=" & hx.ToString & " Y=" & hy.ToString
If Me.Text <> msg Then Me.Text = msg

End Sub

Private Sub DrawHex()
' This just draws the cells on the screen
Dim grx As Graphics = Graphics.FromImage(Image)
Dim r, hx, hy, x, y As Integer
Dim a As Integer()

For y = 0 To 12
For x = 0 To 17
grx.DrawRectangle(Pens.Red, New Rectangle(x * SX, y * SY, SX, SY))
a = CType(Rows(y And 1), Integer())
r = a(x Mod 6)
hx = x * SX
hy = y * SY
If r = 0 Then
If (y And 1) = 0 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy)
Else
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy + SY)
End If
ElseIf r = 1 Then
If (y And 1) = 1 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy)
Else
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy + SY)
End If
ElseIf r = -1 Then
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy)
ElseIf r = -2 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy + SY)
End If
Next
Next

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim grx As Graphics = Me.CreateGraphics
grx.DrawImage(Image, 0, 0)
grx.Dispose()
End Sub

Nov 21 '05 #4

P: n/a
Thanks for this code Larry it's *yet* another was that I can draw a hexmap...

Is there any chance you could be so kind and explain what the complicated
mathematical sections do (and how they do it?) I've been trying to figure
out how the 1st section works:
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}
it doesn't make any sense to me as I thought the {} was used for formatting.
If you can't tell, I'm also a bit of a newbie in this VB lark :)

I'm also drawing the hexcells in a panel, not a form and although I've
successfully managed to do this within my program using your code, the
graphics are only drawn within the initial visible part of the panel, as soon
as I use the scrollbars I get one of two things hapening. If the drawimage
is in the "paint" sub then it re-draws all over the screen eventually drawing
a nice big red block on the panel screen. how can I make your hexmap draw a
50hex by 50hex board and then maintain the image so that the scrollbars on
the panel display the image correctly. I'll be overlaying the Hexes that
have information with small .bmp graphical images such as trees or towns, the
idea being that the end user can click on a hex containing a town image and
get the information for the town.

Niels

"Larry Serflaten" wrote:

"Niels Jensen" <ni***@surf-spot.co.uk> wrote

Thanks for the help so far but I do have one further question - how do
you do it for multiple regions?

I've managed to apply the example you gave me to my program but I now
have another problem... there could be hundreds of Hexregions on the
form at any time - the problem is it's an unknown number of regions as
the person running the server can make a map of any size.

How can I take this to the next step and get the mousemove event to
cover an unknown number of regions on the form?

Since you have to cover some large number of cells, you might do best
by calculating the results. For an example, paste the following code in
a new form, under the Designer generated code (section).

HTH
LFS

Public Image As Bitmap
Private Rows(1) As Array

Const SX As Integer = 30 ' Red cell sizes
Const SY As Integer = 50

Const RATIO As Single = SX / SY

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Image = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
' Row map indicates which cells have angles
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}
DrawHex()
End Sub

Private Sub HexCell(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
Dim r, x, y, hx, hy As Integer
Dim a As Integer()

' Get red grid cell x and y
x = e.X \ SX
y = e.Y \ SY

' Preliminary HexX and HexY
hx = x \ 3
hy = y \ 2

' Get row map value (r)
a = CType(Rows(y And 1), Integer())
r = a(x Mod 6)

' Adjust for angled cells
If r = -1 Then
If (e.X - (x * SX)) < ((SY - (e.Y - (y * SY))) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (SY - (e.Y - (y * SY))).ToString & " -Y " & ((SY - (e.Y - (y *
SY))) * RATIO).ToString)
ElseIf r = -2 Then
If (e.X - (x * SX)) < ((e.Y - (y * SY)) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (e.Y - (y * SY)).ToString & " -Y " & ((e.Y - (y * SY)) *
RATIO).ToString)
End If

' Adjust for y offset in odd hex columns
If (hx And 1) = 1 AndAlso (y And 1) = 0 Then hy -= 1

' Show values
Dim msg As String = "X=" & hx.ToString & " Y=" & hy.ToString
If Me.Text <> msg Then Me.Text = msg

End Sub

Private Sub DrawHex()
' This just draws the cells on the screen
Dim grx As Graphics = Graphics.FromImage(Image)
Dim r, hx, hy, x, y As Integer
Dim a As Integer()

For y = 0 To 12
For x = 0 To 17
grx.DrawRectangle(Pens.Red, New Rectangle(x * SX, y * SY, SX, SY))
a = CType(Rows(y And 1), Integer())
r = a(x Mod 6)
hx = x * SX
hy = y * SY
If r = 0 Then
If (y And 1) = 0 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy)
Else
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy + SY)
End If
ElseIf r = 1 Then
If (y And 1) = 1 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy)
Else
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy + SY)
End If
ElseIf r = -1 Then
grx.DrawLine(Pens.Black, hx, hy + SY, hx + SX, hy)
ElseIf r = -2 Then
grx.DrawLine(Pens.Black, hx, hy, hx + SX, hy + SY)
End If
Next
Next

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim grx As Graphics = Me.CreateGraphics
grx.DrawImage(Image, 0, 0)
grx.Dispose()
End Sub

Nov 21 '05 #5

P: n/a

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote
Thanks for this code Larry it's *yet* another was that I can draw a hexmap...

Is there any chance you could be so kind and explain what the complicated
mathematical sections do (and how they do it?)
It is very easy to get X and Y coordinates when the cells are rectangles:
' Get red grid cell x and y
x = e.X \ SX
y = e.Y \ SY


SX and SY are the size values of the red cells, so that, dividing the
current X or Y mouse position by the size of the cell give the cell's
X or Y values.

It is not so easy when there are angled lines or other such polygons.
In your case, I first set out to identify where the angled lines are, you
can see by the displayed grid they do follow a repeating pattern and
that pattern is represented in the Rows array. Second, the angle the
slopes are at is constant so one formula (based on the ratio of X to Y)
can be used to tell when the mouse crosses the angled line. When it
does, the horizontal position has to be adjusted. There is one formula
for the forward slash, and another for the backward slash. With the
correct X position, there is one other thing to address and that is that
alternating hex columns are offset by one cell difference and that is
found and altered as the last part of the process.

I've been trying to figure
out how the 1st section works:
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}

It is an array of arrays.

These statements assign arrays of Integers to the elements of the Rows
array. "New Integer()" tells VB you're creating a new array and the values
inside the brackets initialize that array with those values. In this case, a -1
represents the forward slash (angle cell) and -2 represents the backward
slash (angle cell). 0 and 1 were only used during the draw process to help
determine if the horizontal line of the hex cell should be at the top or
bottom of that group of cells.
I'm also drawing the hexcells in a panel, not a form and although I've
successfully managed to do this within my program using your code, the
graphics are only drawn within the initial visible part of the panel, as soon
as I use the scrollbars I get one of two things hapening. If the drawimage
is in the "paint" sub then it re-draws all over the screen eventually drawing
a nice big red block on the panel screen. how can I make your hexmap draw a
50hex by 50hex board and then maintain the image so that the scrollbars on
the panel display the image correctly. I'll be overlaying the Hexes that
have information with small .bmp graphical images such as trees or towns, the
idea being that the end user can click on a hex containing a town image and
get the information for the town.


You will probably want to back up that panel with a memory bitmap such that
you draw your 50X50 board to the bitmap, and then copy it over to the panel
(in its Paint event) depending on the scroll position.

While doing your drawing in the paint event is a low impact method, it gets a
bit useless when you have several items to draw and are erasing the screen to
reposition them all. In that case it is better to draw to memory and then copy
the finished image in one go.

Take a look at what I did, I gave the form a public Image property that was
my memory bitmap. It is such a common methodology that I did it by habit!
In the form's Paint event I simply copied over the image in one go. Doing it
that way (and even that can be improved) allows for automatic repainting when
the form is restored from being minimized, or when some other window covers
and then exposes that form.

Where I have 0, 0 you'd add in values from your scroll control....

HTH
LFS


Nov 21 '05 #6

P: n/a
Hi,

Try something like this.

Dim arShapes As New ArrayList

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

For x As Integer = 0 To 4

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

Dim rgnCircle As Region

pth.AddEllipse(100, 10 + x * 50, 50, 50)

rgnCircle = New Region(pth)

arShapes.Add(rgnCircle)

Next x

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

For Each rgnCircle As Region In arShapes

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

Next

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Dim strOut As String = "Not over circle"

For x As Integer = 0 To arShapes.Count - 1

If DirectCast(arShapes.Item(x), Region).IsVisible(e.X, e.Y) Then

strOut = String.Format("Over Circle {0}", x)

End If

Next

Me.Text = strOut

End Sub

Ken

----------------------

"Niels Jensen" <ni***@surf-spot.co.uk> wrote in message
news:6Z********************@pipex.net...
Hi,

Thanks for the help so far but I do have one further question - how do
you do it for multiple regions?

I've managed to apply the example you gave me to my program but I now
have another problem... there could be hundreds of Hexregions on the
form at any time - the problem is it's an unknown number of regions as
the person running the server can make a map of any size.

How can I take this to the next step and get the mousemove event to
cover an unknown number of regions on the form?

Niels

Ken Tucker [MVP] wrote:
Hi,
Create a region for each cell. Use the region isvisble to see if
the cursor is in the cell.

Dim rgnCircle As Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

pth.AddEllipse(100, 100, 50, 50)

rgnCircle = New Region(pth)

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Me.Text = String.Format("In Circle {0}", rgnCircle.IsVisible(New
Point(e.X,
e.Y)))

End Sub

Ken

-------------------------------------

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote in message
news:9E**********************************@microsof t.com...
I have been developing a little project which draw's a hexgrid on a panel
within a form similar to this - it:s used as a client from a e-mail based
strategy game:
____ ____
/ \ / \
/ (0,0) \____/ (2,0) \____/
\ / \ / \
\____/(1,1) \____/ (3,1) \_
/ \ / \
/ (0,1) \____/ (2,1) \____/
\ / \ / \
\____/(1,2) \____/ (3,2) \_
/ \ / \
/ (0,2) \____/ (2,2) \____/
\ / \ / \
\____/(1,3) \____/ (3,3) \_

The number of hexes can vary depending on the mapsize. now the problem I
currently have is trying to get a label.text to display which hex coord
the
mouse is currently in.

Using the mouse move function I can get it to automatically change when it
passes over the lines in the (1,y) columns by using the following formula:

(for these purposes HexHeight = 44 pixels, HexWidth = 50 pixels)

MouseYpos = LocalMousePosition.Y / HexHeight
Label1.text = "Coords: " & MouseXpos & "," & MouseYpos

however, because the colums are staggered any column starting with an even
number get's the new coords changed halfway through it.

So I'm now leaning towards trying mark the centre point of each hex, and
then establishing which one the mousepointer is nearest to. However I'm
having difficulty in figuring out how to do this.

Can anyone help?

Nov 21 '05 #7

P: n/a
I'd just like to thank averyone who helped me out on this - I'm getting
there..... slowly and you've all been a great help holding my hand as I go

Thanks guys
Niels

"Larry Serflaten" wrote:

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote
Thanks for this code Larry it's *yet* another was that I can draw a hexmap...

Is there any chance you could be so kind and explain what the complicated
mathematical sections do (and how they do it?)


It is very easy to get X and Y coordinates when the cells are rectangles:
' Get red grid cell x and y
x = e.X \ SX
y = e.Y \ SY


SX and SY are the size values of the red cells, so that, dividing the
current X or Y mouse position by the size of the cell give the cell's
X or Y values.

It is not so easy when there are angled lines or other such polygons.
In your case, I first set out to identify where the angled lines are, you
can see by the displayed grid they do follow a repeating pattern and
that pattern is represented in the Rows array. Second, the angle the
slopes are at is constant so one formula (based on the ratio of X to Y)
can be used to tell when the mouse crosses the angled line. When it
does, the horizontal position has to be adjusted. There is one formula
for the forward slash, and another for the backward slash. With the
correct X position, there is one other thing to address and that is that
alternating hex columns are offset by one cell difference and that is
found and altered as the last part of the process.

I've been trying to figure
out how the 1st section works:
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}


It is an array of arrays.

These statements assign arrays of Integers to the elements of the Rows
array. "New Integer()" tells VB you're creating a new array and the values
inside the brackets initialize that array with those values. In this case, a -1
represents the forward slash (angle cell) and -2 represents the backward
slash (angle cell). 0 and 1 were only used during the draw process to help
determine if the horizontal line of the hex cell should be at the top or
bottom of that group of cells.
I'm also drawing the hexcells in a panel, not a form and although I've
successfully managed to do this within my program using your code, the
graphics are only drawn within the initial visible part of the panel, as soon
as I use the scrollbars I get one of two things hapening. If the drawimage
is in the "paint" sub then it re-draws all over the screen eventually drawing
a nice big red block on the panel screen. how can I make your hexmap draw a
50hex by 50hex board and then maintain the image so that the scrollbars on
the panel display the image correctly. I'll be overlaying the Hexes that
have information with small .bmp graphical images such as trees or towns, the
idea being that the end user can click on a hex containing a town image and
get the information for the town.


You will probably want to back up that panel with a memory bitmap such that
you draw your 50X50 board to the bitmap, and then copy it over to the panel
(in its Paint event) depending on the scroll position.

While doing your drawing in the paint event is a low impact method, it gets a
bit useless when you have several items to draw and are erasing the screen to
reposition them all. In that case it is better to draw to memory and then copy
the finished image in one go.

Take a look at what I did, I gave the form a public Image property that was
my memory bitmap. It is such a common methodology that I did it by habit!
In the form's Paint event I simply copied over the image in one go. Doing it
that way (and even that can be improved) allows for automatic repainting when
the form is restored from being minimized, or when some other window covers
and then exposes that form.

Where I have 0, 0 you'd add in values from your scroll control....

HTH
LFS


Nov 21 '05 #8

P: n/a
Hi Ken,

I've almost got this sorted now - I have the regions all being drawn out in
a panel (around 100 for test purposes) and it looks good. however when I
scroll the panel using autoscroll

The regions vanish as I scroll down, I also noticed that no-matter where in
the panel I scroll to the regions are always in the same position on the
panel, i.e hex 1 is in the top left of the panel even though it should be hex
three due to scrolling approx three hexes down.

Is there any way for the regions to scroll around the panel properly and
also to make the correct regions be in the correct locations?

Cheers
Niels

"Ken Tucker [MVP]" wrote:
Hi,

Try something like this.

Dim arShapes As New ArrayList

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

For x As Integer = 0 To 4

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

Dim rgnCircle As Region

pth.AddEllipse(100, 10 + x * 50, 50, 50)

rgnCircle = New Region(pth)

arShapes.Add(rgnCircle)

Next x

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

For Each rgnCircle As Region In arShapes

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

Next

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Dim strOut As String = "Not over circle"

For x As Integer = 0 To arShapes.Count - 1

If DirectCast(arShapes.Item(x), Region).IsVisible(e.X, e.Y) Then

strOut = String.Format("Over Circle {0}", x)

End If

Next

Me.Text = strOut

End Sub

Ken

----------------------

"Niels Jensen" <ni***@surf-spot.co.uk> wrote in message
news:6Z********************@pipex.net...
Hi,

Thanks for the help so far but I do have one further question - how do
you do it for multiple regions?

I've managed to apply the example you gave me to my program but I now
have another problem... there could be hundreds of Hexregions on the
form at any time - the problem is it's an unknown number of regions as
the person running the server can make a map of any size.

How can I take this to the next step and get the mousemove event to
cover an unknown number of regions on the form?

Niels

Ken Tucker [MVP] wrote:
Hi,
Create a region for each cell. Use the region isvisble to see if
the cursor is in the cell.

Dim rgnCircle As Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim pth As New System.Drawing.Drawing2D.GraphicsPath

pth.AddEllipse(100, 100, 50, 50)

rgnCircle = New Region(pth)

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.FillRegion(Brushes.Blue, rgnCircle)

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

Me.Text = String.Format("In Circle {0}", rgnCircle.IsVisible(New
Point(e.X,
e.Y)))

End Sub

Ken

-------------------------------------

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote in message
news:9E**********************************@microsof t.com...
I have been developing a little project which draw's a hexgrid on a panel
within a form similar to this - it:s used as a client from a e-mail based
strategy game:
____ ____
/ \ / \
/ (0,0) \____/ (2,0) \____/
\ / \ / \
\____/(1,1) \____/ (3,1) \_
/ \ / \
/ (0,1) \____/ (2,1) \____/
\ / \ / \
\____/(1,2) \____/ (3,2) \_
/ \ / \
/ (0,2) \____/ (2,2) \____/
\ / \ / \
\____/(1,3) \____/ (3,3) \_

The number of hexes can vary depending on the mapsize. now the problem I
currently have is trying to get a label.text to display which hex coord
the
mouse is currently in.

Using the mouse move function I can get it to automatically change when it
passes over the lines in the (1,y) columns by using the following formula:

(for these purposes HexHeight = 44 pixels, HexWidth = 50 pixels)

MouseYpos = LocalMousePosition.Y / HexHeight
Label1.text = "Coords: " & MouseXpos & "," & MouseYpos

however, because the colums are staggered any column starting with an even
number get's the new coords changed halfway through it.

So I'm now leaning towards trying mark the centre point of each hex, and
then establishing which one the mousepointer is nearest to. However I'm
having difficulty in figuring out how to do this.

Can anyone help?


Nov 21 '05 #9

P: n/a
Hi Larry,

I've been tinkering with the code you gave me as it needed expanding a little:
What I have is a panel which is 300x200 in size. The heximage that is drawn
is 50 by 50 hexes making it a lot larger than the panel so using a HScrollBar
& VScrollBar I calculate the position of those and move the image in the
panel to represent the display (see the code at the bottom of the form). Now
I have two issues whch I can't get my head round:

I have modified your original:

x = e.X \ SX
y = e.Y \ SY

to:

x = (e.X + HScrollBar1.Value) \ SX + (HScrollBar1.Value \ SX)
y = (e.Y + VScrollBar1.Value) \ SY + (VScrollBar1.Value \ SY)

this now gives a partially correct hex reading in even cells (0, 2, 3 etc)
but when I scroll down to reveal more hexes, as long as the top half of the
hex (the hex is divided by the two red rectangular cells) is at the top of
the panel, it's fine. As soon as the bottom half of the hex is displayed then
the hex number change occoured mid way through the next hex.does this make
sense?

It also doesn't seem to work on the angles, although I have a feeling that's
because I need to change the following somehow:

' Adjust for angled cells
If r = -1 Then
If (e.X - (x * SX)) < ((SY - (e.Y - (y * SY))) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (SY - (e.Y
- (y * SY))).ToString & " -Y " & ((SY - (e.Y - (y *
SY))) * RATIO).ToString)
ElseIf r = -2 Then
If (e.X - (x * SX)) < ((e.Y - (y * SY)) * RATIO) Then
hx -= 1
End If
'Debug.WriteLine((e.X - (x * SX)).ToString & " X " & (e.Y - (y *
SY)).ToString & " -Y " & ((e.Y - (y * SY)) *
RATIO).ToString)
End If

I need to get my head round some basic geomotry again - last time I did any
was around 12 years ago in high school (and I thought I was being clever
telling my teacher that I'd never need to know geometry in real life LOL)

Any advice you have would be great

Niels

"Larry Serflaten" wrote:

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote
Thanks for this code Larry it's *yet* another was that I can draw a hexmap...

Is there any chance you could be so kind and explain what the complicated
mathematical sections do (and how they do it?)


It is very easy to get X and Y coordinates when the cells are rectangles:
' Get red grid cell x and y
x = e.X \ SX
y = e.Y \ SY


SX and SY are the size values of the red cells, so that, dividing the
current X or Y mouse position by the size of the cell give the cell's
X or Y values.

It is not so easy when there are angled lines or other such polygons.
In your case, I first set out to identify where the angled lines are, you
can see by the displayed grid they do follow a repeating pattern and
that pattern is represented in the Rows array. Second, the angle the
slopes are at is constant so one formula (based on the ratio of X to Y)
can be used to tell when the mouse crosses the angled line. When it
does, the horizontal position has to be adjusted. There is one formula
for the forward slash, and another for the backward slash. With the
correct X position, there is one other thing to address and that is that
alternating hex columns are offset by one cell difference and that is
found and altered as the last part of the process.

I've been trying to figure
out how the 1st section works:
Rows(0) = New Integer() {-1, 0, 0, -2, 1, 1, -1}
Rows(1) = New Integer() {-2, 0, 0, -1, 1, 1, -2}


It is an array of arrays.

These statements assign arrays of Integers to the elements of the Rows
array. "New Integer()" tells VB you're creating a new array and the values
inside the brackets initialize that array with those values. In this case, a -1
represents the forward slash (angle cell) and -2 represents the backward
slash (angle cell). 0 and 1 were only used during the draw process to help
determine if the horizontal line of the hex cell should be at the top or
bottom of that group of cells.
I'm also drawing the hexcells in a panel, not a form and although I've
successfully managed to do this within my program using your code, the
graphics are only drawn within the initial visible part of the panel, as soon
as I use the scrollbars I get one of two things hapening. If the drawimage
is in the "paint" sub then it re-draws all over the screen eventually drawing
a nice big red block on the panel screen. how can I make your hexmap draw a
50hex by 50hex board and then maintain the image so that the scrollbars on
the panel display the image correctly. I'll be overlaying the Hexes that
have information with small .bmp graphical images such as trees or towns, the
idea being that the end user can click on a hex containing a town image and
get the information for the town.


You will probably want to back up that panel with a memory bitmap such that
you draw your 50X50 board to the bitmap, and then copy it over to the panel
(in its Paint event) depending on the scroll position.

While doing your drawing in the paint event is a low impact method, it gets a
bit useless when you have several items to draw and are erasing the screen to
reposition them all. In that case it is better to draw to memory and then copy
the finished image in one go.

Take a look at what I did, I gave the form a public Image property that was
my memory bitmap. It is such a common methodology that I did it by habit!
In the form's Paint event I simply copied over the image in one go. Doing it
that way (and even that can be improved) allows for automatic repainting when
the form is restored from being minimized, or when some other window covers
and then exposes that form.

Where I have 0, 0 you'd add in values from your scroll control....

HTH
LFS


Nov 21 '05 #10

P: n/a

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote

I have modified your original:

x = e.X \ SX
y = e.Y \ SY

to:

x = (e.X + HScrollBar1.Value) \ SX + (HScrollBar1.Value \ SX)
y = (e.Y + VScrollBar1.Value) \ SY + (VScrollBar1.Value \ SY) ..... It also doesn't seem to work on the angles, although I have a feeling that's
because I need to change the following somehow: ..... Any advice you have would be great

I haven't tested anything using a scrollbar, but as you saw, it works out
when the proper X and Y values are used. I am not sure why you used
the new formula but I would suggest you alter the whole routine to first
get the composite values of e.X and e.Y and use those in place of e.X and
e.Y.

First I am assuming that with a Vscroll value of 0, then clicking on 0,0, will
give you the correct 0,0 result, and when the Vscroll value is 10, then clicking
on 0,0 should actually be 0,10. (opposed to using any negative values) Likewise
when the VScroll value is 20 and you click on 0,0 you actually need it to be 0,20
(because the hex grid has been drawn 20 pixels higher than its original position)

Do you see the pattern?

So the first thing to do is to get the X and Y values back to their needed values,
then let the rest of the routine work, something like:

Dim eX, eY as Integer

eX = e.X - HScrollBar1.Value
eY = e.Y - VScrollBar1.Value

After that, replace every occurance of e.X with eX and every occurance of
e.Y with eY:

x = eX \ SX
y = eY \ SY

And do the same with the later formulas then see if things start to turn out
right again.

HTH
LFS
Nov 21 '05 #11

P: n/a
OMG!

Larry your a genius and a star! Thanks it worked a treat and just goes to
show simplicity is the key. I had a friend a I trying out some weird
mathamatical formulas trying to do the simple thing you explained :p

Ahh well - Thanks again!

Niels

"Larry Serflaten" wrote:

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote

I have modified your original:

x = e.X \ SX
y = e.Y \ SY

to:

x = (e.X + HScrollBar1.Value) \ SX + (HScrollBar1.Value \ SX)
y = (e.Y + VScrollBar1.Value) \ SY + (VScrollBar1.Value \ SY)

.....
It also doesn't seem to work on the angles, although I have a feeling that's
because I need to change the following somehow:

.....
Any advice you have would be great

I haven't tested anything using a scrollbar, but as you saw, it works out
when the proper X and Y values are used. I am not sure why you used
the new formula but I would suggest you alter the whole routine to first
get the composite values of e.X and e.Y and use those in place of e.X and
e.Y.

First I am assuming that with a Vscroll value of 0, then clicking on 0,0, will
give you the correct 0,0 result, and when the Vscroll value is 10, then clicking
on 0,0 should actually be 0,10. (opposed to using any negative values) Likewise
when the VScroll value is 20 and you click on 0,0 you actually need it to be 0,20
(because the hex grid has been drawn 20 pixels higher than its original position)

Do you see the pattern?

So the first thing to do is to get the X and Y values back to their needed values,
then let the rest of the routine work, something like:

Dim eX, eY as Integer

eX = e.X - HScrollBar1.Value
eY = e.Y - VScrollBar1.Value

After that, replace every occurance of e.X with eX and every occurance of
e.Y with eY:

x = eX \ SX
y = eY \ SY

And do the same with the later formulas then see if things start to turn out
right again.

HTH
LFS

Nov 21 '05 #12

P: n/a
Ghaaa! Larry Please save me again!

I just realised that the hex cells run down in even and odd numbers
depending on the column.

i.e if X = 0, 2, 4... then all Y's cell Values will be even 0,2,4...
if X = 1, 3, 5... then all X's cell values will be odd

I'm looking at the code, and I just cant work out what needs to be done to
make the X/Y valuse read right.

have you got any pointers?

Cheers
Niels

"Niels Jensen" wrote:
OMG!

Larry your a genius and a star! Thanks it worked a treat and just goes to
show simplicity is the key. I had a friend a I trying out some weird
mathamatical formulas trying to do the simple thing you explained :p

Ahh well - Thanks again!

Niels

"Larry Serflaten" wrote:

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote

I have modified your original:

x = e.X \ SX
y = e.Y \ SY

to:

x = (e.X + HScrollBar1.Value) \ SX + (HScrollBar1.Value \ SX)
y = (e.Y + VScrollBar1.Value) \ SY + (VScrollBar1.Value \ SY)

.....
It also doesn't seem to work on the angles, although I have a feeling that's
because I need to change the following somehow:

.....
Any advice you have would be great

I haven't tested anything using a scrollbar, but as you saw, it works out
when the proper X and Y values are used. I am not sure why you used
the new formula but I would suggest you alter the whole routine to first
get the composite values of e.X and e.Y and use those in place of e.X and
e.Y.

First I am assuming that with a Vscroll value of 0, then clicking on 0,0, will
give you the correct 0,0 result, and when the Vscroll value is 10, then clicking
on 0,0 should actually be 0,10. (opposed to using any negative values) Likewise
when the VScroll value is 20 and you click on 0,0 you actually need it to be 0,20
(because the hex grid has been drawn 20 pixels higher than its original position)

Do you see the pattern?

So the first thing to do is to get the X and Y values back to their needed values,
then let the rest of the routine work, something like:

Dim eX, eY as Integer

eX = e.X - HScrollBar1.Value
eY = e.Y - VScrollBar1.Value

After that, replace every occurance of e.X with eX and every occurance of
e.Y with eY:

x = eX \ SX
y = eY \ SY

And do the same with the later formulas then see if things start to turn out
right again.

HTH
LFS

Nov 21 '05 #13

P: n/a

"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote
I just realised that the hex cells run down in even and odd numbers
depending on the column.

i.e if X = 0, 2, 4... then all Y's cell Values will be even 0,2,4...
if X = 1, 3, 5... then all X's cell values will be odd

I'm looking at the code, and I just cant work out what needs to be done to
make the X/Y valuse read right.

have you got any pointers?

I don't understand the problem, can you explain it be little better?

LFS
Nov 21 '05 #14

P: n/a
Sure,

At the moment if you go into the top left hex cell it'll read X = 0 Y =
0. If you go down to the next it'll read X = 0, Y = 1, the next will be
X = 0 Y = 2 etc.

What I should have realized is that it should be X= 0, y = 0 x = 0, y
= 2 x = 0, y = 4 etc

and on the odd X values i.e x = 1 it should be x = 1, y = 1. X = 1 Y = 3
etc.

I can't believe how helpful you've been so far, I really would be at a
loss without you help and for that I'm very grateful. Thanks

Niels
Larry Serflaten wrote:
"Niels Jensen" <Ni*********@discussions.microsoft.com> wrote

I just realised that the hex cells run down in even and odd numbers
depending on the column.

i.e if X = 0, 2, 4... then all Y's cell Values will be even 0,2,4...
if X = 1, 3, 5... then all X's cell values will be odd

I'm looking at the code, and I just cant work out what needs to be done to
make the X/Y valuse read right.

have you got any pointers?


I don't understand the problem, can you explain it be little better?

LFS

Nov 21 '05 #15

P: n/a

"Niels Jensen" <ni***@surf-spot.co.uk> wrote
I can't believe how helpful you've been so far, I really would be at a
loss without you help and for that I'm very grateful. Thanks


Just to be clear, see if the list below is correct

OldX OldY NewX NewY
0 0 0 0
0 1 0 2
0 2 0 4
0 3 0 6
0 4 0 8
1 0 1 1
1 1 1 3
1 2 1 5
1 3 1 7
1 4 1 9
If that is it, there is definately a pattern there:

NewX = OldX
NewY = (OldY * 2) + (OldX And 1)

Since the routine correctly outputs the X and Y,
just tack on the formula to adjust Y as the last line
of the routine....
LFS
Nov 21 '05 #16

P: n/a
Yup - worked a treat... Once again :)

Thanks for your help Larry, I'll make sure you're credited in my app :)

Niels

"Larry Serflaten" wrote:

"Niels Jensen" <ni***@surf-spot.co.uk> wrote
I can't believe how helpful you've been so far, I really would be at a
loss without you help and for that I'm very grateful. Thanks


Just to be clear, see if the list below is correct

OldX OldY NewX NewY
0 0 0 0
0 1 0 2
0 2 0 4
0 3 0 6
0 4 0 8
1 0 1 1
1 1 1 3
1 2 1 5
1 3 1 7
1 4 1 9
If that is it, there is definately a pattern there:

NewX = OldX
NewY = (OldY * 2) + (OldX And 1)

Since the routine correctly outputs the X and Y,
just tack on the formula to adjust Y as the last line
of the routine....
LFS

Nov 21 '05 #17

This discussion thread is closed

Replies have been disabled for this discussion.