Reputation: 147
I will need to put a dynamic number of hexagons (28 in this example) inside a "rectangle" aka user's screen size (2000px width, 1000px height in this example). I wish to offset every other column. There will be a percentage margin.
I attempted to create a custom panel, my code is below:
Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
On Error Resume Next
Dim side As Double = ((((Me.ActualHeight * 2) + (Me.ActualWidth * 2)) / 6) - Me.InternalChildren.Count) / 6
Dim w As Double = 2 * side
Dim h As Double = side * Math.Sqrt(3.0)
For Each child As FrameworkElement In InternalChildren
Dim childMaxSize = New Size(w, h)
child.Measure(childMaxSize)
Next
Return availableSize
End Function
Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
On Error Resume Next
Dim side As Double = ((((Me.ActualHeight * 2) + (Me.ActualWidth * 2)) / 6) - Me.InternalChildren.Count) / 6
Dim w As Double = 2 * side
Dim h As Double = side * Math.Sqrt(3.0)
Dim x As Double = 0
Dim y As Double = 0
Dim shift As Boolean = True
Dim shiftOffset As Double
Dim offsetChild As FrameworkElement = TryCast(InternalChildren(0), FrameworkElement)
shiftOffset = h / 2
For i As Integer = 0 To InternalChildren.Count - 1 'For Each child As FrameworkElement In Me.InternalChildren
Dim child As FrameworkElement = TryCast(InternalChildren(i), FrameworkElement)
child.Margin = New Thickness(side * 0.02)
If child IsNot Nothing Then
Dim finalY As Double = y
If shift Then finalY += shiftOffset
shift = Not shift
child.Arrange(New Rect(New Point(x, finalY), New Size(w, h)))
x += w * 0.75
Dim nextWidth As Double = 0
If i + 1 < InternalChildren.Count Then nextWidth = w
If x + nextWidth > Me.ActualWidth Then
shift = True
x = 0
y += h
End If
End If
Next
Return finalSize
End Function
End Class
My issue is trying to calculate the side. I am close, but it doesn't seem to fit quite right in the "rectangle", or perhaps there is something else I'm not getting.
Any help is appreciated - thanks in advance!
EDIT: To explain a little differently - my formula works if I don't offset every other hexagon column (tested). I'm pretty sure my root issue is that my code is measuring the size each hexagon needs to be in order to fit in the specified rectangle before placing them. However, after they are placed and then offset, I'm finding the hexagons appearing out of the rectangle. Oh also my hexagons are flat-topped. Thanks! Pictures are below - top is what I need, bottom is what I'm getting. The red is the area the hexagons need to fit in:
EDIT 2: I attempted MBo's suggestion of side = side - offset (my offset is height * 0.5). It appears to make the hexagons too small:
Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
On Error Resume Next
Dim side As Double = ((((Me.ActualHeight * 2) + (Me.ActualWidth * 2)) / 6) - Me.InternalChildren.Count) / 6
Dim h As Double = side * Math.Sqrt(3.0)
'new
side = side - (h * 0.5)
h = side * Math.Sqrt(3.0)
Dim w As Double = 2 * side
For Each child As FrameworkElement In InternalChildren
Dim childMaxSize = New Size(w, h)
child.Measure(childMaxSize)
Next
Return availableSize
End Function
Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
On Error Resume Next
Dim side As Double = ((((Me.ActualHeight * 2) + (Me.ActualWidth * 2)) / 6) - Me.InternalChildren.Count) / 6
Dim h As Double = side * Math.Sqrt(3.0)
'new
side = side - (h * 0.5)
h = side * Math.Sqrt(3.0)
Dim w As Double = 2 * side
Upvotes: 1
Views: 2870
Reputation: 80287
Consider bounding box size for dense hexagonal grid with R rows, C columns, vertical hexagons orientation (pointy topped, two vertical edges), edge size A:
Height = A/2 * (3 * R + 1)
Width depends on configuration:
Odd and even rows with the same number C of hexagons (N=R*C):
Width = A * Sqrt(3)/2 * (2 * C + 1)
E E E E
O O O O
E E E E
O O O O
Odd rows are shorter with C-1 hexagons (also R=1 case) (N~R*(C-1/2)):
Width = A * Sqrt(3) * C
E E E E
O O O
E E E E
Could you apply these formulas to fit needed number N of hexes into predefined box WxH?
You probably need also to consider some factorisations of N (or slightly larger number) into R, C factors to minimize empty space (for example, 38=2x19
is not suitable for near-square regions, but 40=5x8
or 42=6x7
could be better)
Edit
For your configuration - flat-topped, first column is lower than second:
BoundWidth = Side/2 * (3 * C + 1)
BoundHeight = Side * Sqrt(3)/2 * (2 + R) = Height * (R/2 + 1)
Upvotes: 2