Excel XY Chart (Scatter plot) Data Label No Overlap - vba

So I've been working on this for the past week. Although it can't do miracles, I can say I've got a pretty good result:
I just wanted to put this code out there for all the poor souls like me that are looking for some kind of vba macro that helps them avoid label overlaps in a scatter plot, because while doing my research on the subject, I wasn't able to find anything helpful.

Const PIXEL_TO_POINT_RATIO As Double = 0.72 '1 Pixel = 72/96*1 Point
Const tStep As Double = 0.1
Const rStep As Double = 0.1
Dim pCount As Integer
Sub ExampleMain()
RearrangeScatterLabels Sheet5
RearrangeScatterLabels Sheet25
End Sub
Sub RearrangeScatterLabels(sht As Worksheet)
Dim plot As Chart
Dim sCollection As SeriesCollection
Dim dLabels() As DataLabel
Dim dPoints() As Point
Dim xArr(), yArr(), stDevX, stDevY As Double
Dim x0, x1, y0, y1 As Double
Dim temp() As Double
Dim theta As Double
Dim r As Double
Dim isOverlapped As Boolean
Dim safetyNet, validEntry, currentPoint As Integer
Set plot = sht.ChartObjects(1).Chart 'XY chart (scatter plot)
Set sCollection = plot.SeriesCollection 'All points and labels
safetyNet = 1
pCount = (sCollection.Count - 1)
ReDim dLabels(1 To 1)
ReDim dPoints(1 To 1)
ReDim xArr(1 To 1)
ReDim yArr(1 To 1)
For pt = 1 To sCollection(1).Points.Count
For i = 1 To pCount
If sCollection(i).Points.Count <> 0 Then
'Dynamically expand the arrays
validEntry = validEntry + 1
If validEntry <> 1 Then
ReDim Preserve dLabels(1 To UBound(dLabels) + 1)
ReDim Preserve dPoints(1 To UBound(dPoints) + 1)
ReDim Preserve xArr(1 To UBound(xArr) + 1)
ReDim Preserve yArr(1 To UBound(yArr) + 1)
End If
Set dLabels(i) = sCollection(i).Points(pt).DataLabel 'Store all label objects
Set dPoints(i) = sCollection(i).Points(pt) 'Store all point objects
temp = getElementDimensions(, dPoints(i))
xArr(i) = temp(0) 'Store all points x values
yArr(i) = temp(2) 'Store all points y values
End If
Next
Next
If UBound(dLabels) < 2 Then Exit Sub
pCount = UBound(dLabels)
stDevX = Application.WorksheetFunction.StDev(xArr) 'Get standard deviation for x
stDevY = Application.WorksheetFunction.StDev(yArr) 'Get standard deviation for y
If stDevX = 0 Then stDevX = 1
If stDevY = 0 Then stDevY = 1
r = 0
For currentPoint = 1 To pCount
theta = Rnd * 2 * Application.WorksheetFunction.Pi()
x0 = xArr(currentPoint)
y0 = yArr(currentPoint)
x1 = xArr(currentPoint)
y1 = yArr(currentPoint)
isOverlapped = True
Do Until Not isOverlapped
safetyNet = safetyNet + 1
If safetyNet < 500 Then
If Not checkForOverlap(dLabels(currentPoint), dLabels, dPoints, plot) Then
'No label is within bounds and not overlapping
isOverlapped = False
r = 0
theta = Rnd * 2 * Application.WorksheetFunction.Pi()
safetyNet = 1
Else
'Move label so it does not overlap
theta = theta + tStep
r = r + rStep * tStep / (2 * Application.WorksheetFunction.Pi())
x1 = x0 + stDevX * r * Cos(theta)
y1 = y0 + stDevY * r * Sin(theta)
dLabels(currentPoint).Left = x1
dLabels(currentPoint).Top = y1
End If
Else
safetyNet = 1
Exit Do
End If
Loop
Next
End Sub
Function checkForOverlap(ByRef dLabel As DataLabel, ByRef dLabels() As DataLabel, ByRef dPoints() As Point, ByRef dChart As Chart) As Boolean
checkForOverlap = False 'Return false by default
'Detect label going over chart area
If detectOverlap(dLabel, , , dChart) Then
checkForOverlap = True
Exit Function
End If
'Detect labels overlap
For i = 1 To pCount
If Not dLabel.Left = dLabels(i).Left Then
If detectOverlap(dLabel, dLabels(i)) Then
checkForOverlap = True
Exit Function
End If
End If
Next
'Detect label overlap with point
For i = 1 To pCount
If detectOverlap(dLabel, , dPoints(i)) Then
checkForOverlap = True
Exit Function
End If
Next
End Function
Function getElementDimensions(Optional dLabel As DataLabel, Optional dPoint As Point, Optional dChart As Chart) As Double()
'Get element dimensions and compensate slack
Dim eDimensions(3) As Double
'Working in IV quadrant
If dPoint Is Nothing And dChart Is Nothing Then
'Get label dimensions and compensate padding
eDimensions(0) = dLabel.Left + PIXEL_TO_POINT_RATIO * 3 'Left
eDimensions(1) = dLabel.Left + dLabel.Width - PIXEL_TO_POINT_RATIO * 3 'Right
eDimensions(2) = dLabel.Top + PIXEL_TO_POINT_RATIO * 6 'Top
eDimensions(3) = dLabel.Top + dLabel.Height - PIXEL_TO_POINT_RATIO * 3 'Bottom
End If
If dLabel Is Nothing And dChart Is Nothing Then
'Get point dimensions
eDimensions(0) = dPoint.Left - PIXEL_TO_POINT_RATIO * 5 'Left
eDimensions(1) = dPoint.Left + PIXEL_TO_POINT_RATIO * 5 'Right
eDimensions(2) = dPoint.Top - PIXEL_TO_POINT_RATIO * 5 'Top
eDimensions(3) = dPoint.Top + PIXEL_TO_POINT_RATIO * 5 'Bottom
End If
If dPoint Is Nothing And dLabel Is Nothing Then
'Get chart dimensions
eDimensions(0) = dChart.PlotArea.Left + PIXEL_TO_POINT_RATIO * 22 'Left
eDimensions(1) = dChart.PlotArea.Left + dChart.PlotArea.Width - PIXEL_TO_POINT_RATIO * 22 'Right
eDimensions(2) = dChart.PlotArea.Top - PIXEL_TO_POINT_RATIO * 4 'Top
eDimensions(3) = dChart.PlotArea.Top + dChart.PlotArea.Height - PIXEL_TO_POINT_RATIO * 4 'Bottom
End If
getElementDimensions = eDimensions 'Return dimensions array in Points
End Function
Function detectOverlap(ByVal dLabel1 As DataLabel, Optional ByVal dLabel2 As DataLabel, Optional ByVal dPoint As Point, Optional ByVal dChart As Chart) As Boolean
'Left, Right, Top, Bottom
Dim AxL, AxR, AyT, AyB As Double 'First label coordinates
Dim BxL, BxR, ByT, ByB As Double 'Second label coordinates
Dim eDimensions() As Double 'Element dimensions
eDimensions = getElementDimensions(dLabel1)
AxL = eDimensions(0)
AxR = eDimensions(1)
AyT = eDimensions(2)
AyB = eDimensions(3)
If dPoint Is Nothing And dChart Is Nothing Then
'Compare with another label
eDimensions = getElementDimensions(dLabel2)
End If
If dLabel2 Is Nothing And dChart Is Nothing Then
'Compare with a point
eDimensions = getElementDimensions(, dPoint)
End If
If dPoint Is Nothing And dLabel2 Is Nothing Then
'Compare with chart area
eDimensions = getElementDimensions(, , dChart)
End If
BxL = eDimensions(0)
BxR = eDimensions(1)
ByT = eDimensions(2)
ByB = eDimensions(3)
If dChart Is Nothing Then
detectOverlap = (AxL <= BxR And AxR >= BxL And AyT <= ByB And AyB >= ByT) 'Reverse De Morgan's Law
Else
detectOverlap = Not (AxL >= BxL And AxR <= BxR And AyT >= ByT And AyB <= ByB) 'Is in chart bounds (working in IV quadrant)
End If
End Function
I realize the code is kinda rough and not optimized, but I can't spend more time on this project. I've left quite a few notes around to help read it, should anyone choose to continue this project. Hope this helps.
Best wishes, Schadenfreude.

Building on your function, I made a routine to randomly reposition the labels, assigning a score according to how much overlap it would cause, and thusly optimize. The results aren't great for my own data set, but I think it can be tuned easily for most usages.
There are some issues with the borders and the axis labels which maybe I'll account for later.
Option Explicit
Sub ExampleUsage()
RearrangeScatterLabels ActiveSheet.ChartObjects(1).Chart, 3
End Sub
Sub RearrangeScatterLabels(plot As Chart, Optional timelimit As Double = 5)
Dim sCollection As SeriesCollection
Set sCollection = plot.SeriesCollection
Dim pCount As Integer
pCount = sCollection(1).Points.Count
If pCount < 2 Then Exit Sub
Dim dPoints() As Point
Dim xArr() As Double ' Label center position X
Dim yArr() As Double ' Label center position Y
Dim wArr() As Double ' Label width
Dim hArr() As Double ' Label height
Dim pArr() As Double ' Marker position X
Dim qArr() As Double ' Marker position Y
Dim mArr() As Double ' Markersize
ReDim dPoints(1 To pCount)
ReDim xArr(1 To pCount)
ReDim yArr(1 To pCount)
ReDim wArr(1 To pCount)
ReDim hArr(1 To pCount)
ReDim pArr(1 To pCount)
ReDim qArr(1 To pCount)
ReDim mArr(1 To pCount)
Dim theta As Double
Dim i As Integer
Dim j As Integer
Dim dblStart As Double
' Loop through all points to get their handles and coordinates
For i = 1 To pCount
' Store all point objects
Set dPoints(i) = sCollection(1).Points(i)
' Extract their coordinates and size
pArr(i) = dPoints(i).Left
qArr(i) = dPoints(i).Top
mArr(i) = dPoints(i).MarkerSize
' Store the size of the corresponding labels
wArr(i) = dPoints(i).DataLabel.Width
hArr(i) = dPoints(i).DataLabel.Height
' Starting position (center of label) is middle below
xArr(i) = pArr(i)
yArr(i) = qArr(i) + mArr(i)
Next
Dim newX As Double
Dim newY As Double
Dim dE As Double
Dim wgtOverlap As Double
Dim wgtDistance As Double
Dim wgtClose As Double
wgtOverlap = 10000 ' Extra penalty for overlapping
wgtDistance = 10000 ' Penalty for being nearby other labels
wgtClose = 10 ' Penalty for being further from marker
' Limit the function by time
dblStart = Timer
Do Until TimerDiff(dblStart, Timer) > timelimit
' Pick a random label to move around
i = Int(Rnd * pCount + 1)
' Pick a new random position by angle
theta = Rnd * 2 * Application.WorksheetFunction.Pi()
' Determine the position it would shift to
If Abs(Sin(theta) * wArr(i)) > Abs(hArr(i) * Cos(theta)) Then
' above or below
If Sin(theta) > 0 Then
' above
newX = pArr(i) + wArr(i) * Cos(theta) / 2
newY = qArr(i) - hArr(i) / 2 - mArr(i) / 2
Else
' below
newX = pArr(i) + wArr(i) * Cos(theta) / 2
newY = qArr(i) + hArr(i) / 2 + mArr(i) / 2
End If
Else
' left or right side
If Cos(theta) < 0 Then
' left
newX = pArr(i) - wArr(i) / 2 - mArr(i) / 2
newY = qArr(i) - hArr(i) * Sin(theta) / 2
Else
' right
newX = pArr(i) + wArr(i) / 2 + mArr(i) / 2
newY = qArr(i) - hArr(i) * Sin(theta) / 2
End If
End If
' Determine increase in energy caused by this shift
dE = 0
For j = 1 To pCount
If i <> j Then
' Current overlap with labels
If 2 * Abs(xArr(i) - xArr(j)) < wArr(i) + wArr(j) _
And 2 * Abs(yArr(i) - yArr(j)) < hArr(i) + hArr(j) Then
dE = dE - Abs(xArr(i) - xArr(j) + (wArr(i) + wArr(j)) / 2) _
* Abs(yArr(i) - yArr(j) + (hArr(i) + hArr(j)) / 2)
dE = dE - wgtOverlap
End If
' New overlap with labels
If 2 * Abs(newX - xArr(j)) < wArr(i) + wArr(j) _
And 2 * Abs(newY - yArr(j)) < hArr(i) + hArr(j) Then
dE = dE + Abs(newX - xArr(j) + (wArr(i) + wArr(j)) / 2) _
* Abs(newY - yArr(j) + (hArr(i) + hArr(j)) / 2)
dE = dE + wgtOverlap
End If
' Current overlap with labels
If Abs(xArr(i) - pArr(j)) < wArr(i) / 2 + mArr(j) _
And Abs(yArr(i) - qArr(j)) < hArr(i) / 2 + mArr(j) Then
dE = dE - wgtOverlap
End If
' New overlap with points
If Abs(newX - pArr(j)) < wArr(i) / 2 + mArr(j) _
And Abs(newY - qArr(j)) < hArr(i) / 2 + mArr(j) Then
dE = dE + wgtOverlap
End If
' We like the neighbours to be far away
dE = dE - wgtDistance / ((xArr(i) - xArr(j)) ^ 2 + (yArr(i) - yArr(j)) ^ 2)
dE = dE + wgtDistance / ((newX - xArr(j)) ^ 2 + (newY - yArr(j)) ^ 2)
End If
' We like the offsets to be low
dE = dE - wgtClose * (Abs(xArr(i) - pArr(i)) + Abs(yArr(i) - qArr(i)))
dE = dE + wgtClose * (Abs(newX - pArr(i)) + Abs(newY - qArr(i)))
Next
' If it didn't get worse, adjust to new position
If dE <= 0 Then
xArr(i) = newX
yArr(i) = newY
End If
Loop
' Actually adjust the labels
For i = 1 To pCount
dPoints(i).DataLabel.Left = xArr(i) - wArr(i) / 2
dPoints(i).DataLabel.Top = yArr(i) - hArr(i) / 2
Next
End Sub
' Timer function from Peter Albert
' http://stackoverflow.com/questions/15634623
Function TimerDiff(dblTimerStart As Double, dblTimerEnd As Double)
Dim dblTemp As Double
dblTemp = dblTimerEnd - dblTimerStart
If dblTemp < -43200 Then
dblTemp = dblTemp + 86400
End If
TimerDiff = dblTemp
End Function

Related

Graphics drawline scaling vb.net

I'm trying to develop a program that has been made by another person.
What I develop is just for showing the measurement point like the picture below.
There are min and max data that appear in the form and it's showing from the smallest to the largest value and every time the mouse moves from left to right, the measuring point value will adjust to the graph value that has been determined as above.
The problem is data accuracy at the measuring point does not match with the value that has been determined, this is because the graphic is out of frame.
Here is the code for showing graphics;
Private Sub UpdateDiaGraph()
Call Me.ClearGraph(Me.gDia, Me.PicDiaGraph)
Call Me.InitializeGraph(Me.gDia, Me.PicDiaGraph, Me.recDia)
If Me.dsData.Tables("Dia").Rows.Count = 0 Then
Exit Sub
End If
Dim drs() As DataRow = Me.dsData.Tables("Dia").Select("", "[PathNo],[EquipmentNo],[Point]")
Dim pathNo As Integer = 0
Dim equipmentNo As Integer = 0
Dim diaCount As Integer = 0
Dim maxPoint As Integer = 0
Dim longestDiaCount As Integer = 0
Dim upper As New List(Of Decimal)
Dim lower As New List(Of Decimal)
For Each dr As DataRow In drs
If pathNo <> dr("PathNo") Or equipmentNo <> dr("EquipmentNo") Then
pathNo = dr("PathNo")
equipmentNo = dr("EquipmentNo")
'Count the graphics
diaCount += 1
' Get standard width
upper.Add(dr("Upper"))
lower.Add(dr("Lower"))
End If
' Get the max number of graph points and the number of graphs at that time
If maxPoint < dr("Point") Then
maxPoint = dr("Point")
longestDiaCount = diaCount
End If
Next
Dim x1, x2 As Decimal
Dim y1, y2 As Decimal
' Get the width to draw the reference line
Dim oneHeight As Decimal = Me.recDia.Height / (diaCount + 1)
'Initialize the graph
For i As Integer = 1 To diaCount
x1 = Me.recDia.Left + 1
x2 = Me.recDia.Left + Me.recDia.Width - 1
y1 = Me.recDia.Top + oneHeight * i
' Tolerance range
'※0.01mm/1 Point
Me.gDia.FillRectangle(New SolidBrush(Me.toleranceRecColor) _
, x1 _
, y1 - upper(diaCount - i) * 100 _
, Me.recDia.Width - 1 _
, (upper(diaCount - i) - lower(diaCount - i)) * 100)
' reference line
Me.gDia.DrawLine(New Pen(Me.centerLineColor), x1, y1, x2, y1)
Next
' Determine the drawing magnification of the X-axis so that the max number of points can be displayed
Dim xMag As Decimal = Me.recDia.Width / maxPoint
'Draw a graph
Dim counter As Integer = 0
Dim centerLineY As Decimal
Dim center As Decimal = 0
Dim p As Integer = -1
pathNo = 0 : equipmentNo = 0
For Each dr As DataRow In drs
' Get reference line and reference value
If pathNo <> dr("PathNo") Or equipmentNo <> dr("EquipmentNo") Then
pathNo = dr("PathNo")
equipmentNo = dr("EquipmentNo")
counter += 1
centerLineY = Me.recDia.Top + oneHeight * (diaCount - (counter - 1))
center = dr("Center")
'Draw chart title and reference value
Dim num As New Common.Numeric
Dim numFormat As String = num.GetNumericFormat(1, 2)
Dim s As String = dr("MeasuringTarget").ToString & ControlChars.CrLf
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, Me.recDia.Left - sSize.Width - 2, centerLineY - sSize.Height / 2)
s = ControlChars.CrLf & Format(center, numFormat)
sSize = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, Me.recDia.Left - sSize.Width - 2, centerLineY - sSize.Height / 2)
x1 = 0 : x2 = 0 : y1 = 0 : y2 = 0 : p = -1
End If
p += 1
'Change the drawing direction and starting point of the graph depending on the number of direction changes
If Me.extRevCnt.Item(pathNo) Mod 2 = 0 Then
x2 = Me.recDia.Left + p * xMag
Else
x2 = Me.recDia.Left + Me.recDia.Width - p * xMag
End If
y2 = centerLineY - (dr("Data") - center) * 100
If p <> 0 Then
'graph drawing
If Me.recDia.Top < y2 And y2 < Me.recDia.Top + Me.recDia.Height Then
' Change the drawing color of the graph for each outer diameter
If counter < Me.diaGraphColor.Count Then
Me.gDia.DrawLine(New Pen(Me.diaGraphColor(counter)), x1, y1, x2, y2)
Else
Me.gDia.DrawLine(New Pen(Me.graphColor), x1, y1, x2, y2)
End If
End If
' out of tolerance
If dr("DataFlag") = Common.Constant.DataFlag.NG Then
Me.gDia.DrawLine(New Pen(Me.ngColor), x1, centerLineY, x2, centerLineY)
End If
'Draw a scale every 10m * However, only when drawing the longest graph
'Drawn for the first graph (normal mandrel diameter)
If counter = 1 Then
If p Mod 100 = 0 Then
Me.gDia.DrawLine(Pens.White, x2, Me.recDia.Top + Me.recDia.Height, x2, Me.recDia.Top + Me.recDia.Height - 3)
Dim s As String = (p \ 10).ToString & "m"
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, x2 - sSize.Width / 2, Me.recDia.Top + Me.recDia.Height + 2)
End If
End If
Else
' determine the corners of a polygon
Dim points As Point() = {New Point(x2, centerLineY - 10), New Point(x2 - 10, centerLineY - 40), New Point(x2 + 10, centerLineY - 40)}
Me.gDia.FillPolygon(Brushes.Blue, points, System.Drawing.Drawing2D.FillMode.Alternate)
' Display the division number in the circle above
Dim s As String = dr("DivNo").ToString
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, New Font(Me.Font, FontStyle.Regular), Brushes.White, x2 - sSize.Width / 2 + 2, centerLineY - 35)
End If
x1 = x2
y1 = y2
Next
Type.Variable.divideTargetDia = Me.DGVDataDia.SelectedRows.Item(0).Index
Call Me.DrawingGraphDia(Me.DGVDataDia.SelectedRows.Item(0).Index)
Me.PicDiaGraph.Refresh()
End Sub
Here is the code for showing data pointer
Private Sub PicDiaGraph_Paint(ByVal gDia As Graphics)
If IsNothing(tblDataDia) = True Then Exit Sub
If tblDataDia.Rows.Count = 0 Then Exit Sub
If IsNothing(tblEquipmentNoDia) = True Then Exit Sub
If tblEquipmentNoDia.Rows.Count = 0 Then Exit Sub
' Allocate the drawing range according to the number of device numbers
Dim allHeight As Integer = Me.PicDiaGraph.Size.Height
'Drawing range per device number
Dim heightPerEN As Integer = allHeight / (tblEquipmentNoDia.Rows.Count + 1)
' Device number count
Dim count As Integer = 0
' Draw a graph for each device number
For Each rEN As DataRow In tblEquipmentNoDia.Rows
Dim eNo As Integer = rEN("EquipmentNo")
Dim tblSource As DataTable = tblDataDia.Clone
For Each r As DataRow In tblDataDia.Select("EquipmentNo = '" & eNo & "'", "Point ASC")
tblSource.ImportRow(r)
Next
' Acquisition of standard value
Dim tblStandard As New DataTable
If Me.Today = False Then
Dim SQL As String = ""
SQL &= "SELECT Standard.Center "
SQL &= "FROM Standard "
SQL &= "WHERE Standard.EquipmentNo = " & eNo & " And Standard.MfgID = '" & barcodeNo.Trim & "' "
SQL &= "GROUP BY Standard.Center;"
daDia = New OleDb.OleDbDataAdapter(SQL, cnMdbDia)
daDia.Fill(tblStandard)
Else
'
End If
Dim center As Single = Format(tblStandard.Rows(0)("center"), "0.00")
' Drawing start position (height)
Dim shift As Integer = heightPerEN * count
'get width of data
Dim margin As Integer = 0
_xMaxDia = tblSource.Select("Point = MAX(Point)")(0)("Point")
_xMinDia = tblSource.Select("Point = MIN(Point)")(0)("Point")
Dim yMax As Single = tblSource.Select("Data = MAX(Data)")(0)("Data")
Dim yMin As Single = tblSource.Select("Data = MIN(Data)")(0)("Data")
'Width on X-axis data
Dim xRange As Integer = _xMaxDia - _xMinDia
'Width on Y-axis data
Dim yRange As Single = yMax - yMin
'Get size of control
Dim height As Integer = heightPerEN - (margin * 2)
Dim width As Integer = Me.PicDiaGraph.Size.Width - 21
' Nominal length per unit
_xUnitDia = width / xRange
Dim yUnit As Single = 200
'graph drawing
For i As Integer = 0 To tblSource.Rows.Count - 2
Dim x1 As Decimal = Me.recDia.Left + 1
' starting point data
Dim row1 As DataRow = tblSource.Rows(i)
Dim point1 As Integer = row1("Point")
Dim data1 As Single = row1("Data")
' end point data
Dim row2 As DataRow = tblSource.Rows(i + 1)
Dim point2 As Integer = row2("Point")
Dim data2 As Single = row2("Data")
If point2 < point1 Then MessageBox.Show("X")
Me.gDia.DrawLine(Pens.White, _
CInt((point1 - _xMinDia) * _xUnitDia), _
height - (data1 - center) * yUnit + margin + shift, _
CInt(point2 - _xMinDia) * _xUnitDia, _
height - (data2 - center) * yUnit + margin + shift)
Next
count += 1
Next
End Sub
The problem might appear in this code

Diamond Square Algorithm in VBA (to run in excel)

I've written a script in VBA to create random terrain generation in excel, based on this following matlab script (http://knight.temple.edu/~lakamper/courses/cis350_2004/sources/matlabFractal/createFractalTerrain.m)
After compiling my script I found no bugs, but upon running in excel only cell A1 is assigned a value of zero, and then the script ends.
Now, I wondered if anyone had the time to look through my VBA script and see if they have any idea what's going wrong. I think maybe perhaps I mess around with an array called TR quite a bit when I could perhaps refer to the Cells directly from the get go.
Now, the code is bit long so I have provided a link to the text file that here, and so if nobody has the time I completely understand
https://www.dropbox.com/sh/c2l2ha0awirlowb/AAARGVpidQGP7I9Yu0XRN8yaa?dl=0
Also, here is the code indented.
Public TR(1 To 129, 1 To 129) As Double
Sub DiamondSquare()
Dim tsize As Long: tsize = 129
Dim StartRangRange As Double: startRandRange = 64.5
Dim H As Double: H = 0.9
Call createFractalTerrain(tsize, startRandRange, H)
End Sub
Function createFractalTerrain(ByVal tsize As Long, ByVal startRandRange As Double, ByVal H As Double) As Variant
'Function creates fractal terrain by midpoint displacement (diamond square algorithm)
'Output should be a tsize by tsize matrix
'tSize must be a (power of 2) + 1 ie 129
'startRandRange defines the overall elevation; size/2 gives natural images
'Roughness H (between 0 and 1); 0.9 is a natural value
'H=0 is max roughness
'Initiate Terrain
Dim i As Long
Dim j As Long
Dim ii As Long
Dim jj As Long
For i = 1 To tsize
For j = 1 To tsize
TR(i, j) = 10000
Next
Next
TR(1, 1) = 0
TR(1, tsize) = 0
TR(tsize, 1) = 0
TR(tsize, tsize) = 0
tsize = tsize - 1
randRange = startRandRange
'Main Loop
While tsize > 1
Call diamondStep(tsize, randRange)
Call squareStep(tsize, randRange)
tsize = tsize / 2
randRange = randRange * (1 / (2 ^ H))
Wend
For ii = 1 To tsize
For jj = 1 To tsize
Cells(ii, jj).Value = TR(ii, jj)
Next
Next
End Function
Sub diamondStep(ByVal tsize As Integer, ByVal randRange As Double)
sh = tsize / 2
maxIndex = UBound(TR, 1)
RowVal = 1 + sh
ColVal = 1 + sh
While RowVal < maxIndex
While ColVal < maxIndex
'Average height value of 4 cornerpoints
ValueH = TR(RowVal - sh, ColVal - sh) + TR(RowVal - sh, ColVal + sh) + TR(RowVal + sh, ColVal - sh) + TR(RowVal + sh, ColVal + sh)
ValueH = ValueH / 4
'Displacement
displacement = Int((1 - 0 + 1) * Rnd + 0) * randRange - randRange / 2
ValueH = ValueH + displacement
'Set diamond point
If TR(RowVal, ColVal) = 10000 Then TR(RowVal, ColVal) = ValueH
'Next square in same row
ColVal = ColVal + tsize
Wend
'Next row
ColVal = 1 + sh
RowVal = RowVal + tsize
Wend
End Sub
Sub squareStep(ByVal tsize As Integer, ByVal randRange As Double)
sh = tsize / 2
maxIndex = UBound(TR, 1)
colStart = 1 + sh
RowVal = 1
ColVal = colStart
While (RowVal <= maxIndex)
While (ColVal <= maxIndex)
ValueH = 0
nop = 4 'number of points
'the following cases handle the boundary points,
'i.e. the incomplete diamonds
'north
If RowVal > 1 Then
ValueH = ValueH + TR(RowVal - sh, ColVal)
Else
nop = nop - 1
End If
'east
If ColVal < maxIndex Then
ValueH = ValueH + TR(RowVal, ColVal + sh)
Else
nop = nop - 1
End If
'south
If RowVal < maxIndex Then
ValueH = ValueH + TR(RowVal + sh, ColVal)
Else
nop = nop - 1
End If
'west
If ColVal > 1 Then
ValueH = ValueH + TR(RowVal, ColVal - sh)
Else
nop = nop - 1
End If
'displacement
displacement = Int((1 - 0 + 1) * Rnd + 0) * randRange - randRange / 2
ValueH = ValueH / nop + displacement
'set square point (if not predefined)
If TR(RowVal, ColVal) = 10000 Then TR(RowVal, ColVal) = ValueH
'next diamond in same row
ColVal = ColVal + sh
Wend
'next row
'the starting column alternates between 1 and sh
If colStart = 1 Then
colStart = sh + 1
Else
colStart = 1
End If
ColVal = colStart
RowVal = RowVal + sh
Wend
End Sub
I think the issue you are experiencing is from not iterating over the array you created as you are resetting the tsize variable to 1.
Changing your code to something like this:
For ii = 1 To 129
For jj = 1 To 129
Cells(ii, jj).Value = TR(ii, jj)
Next
Next
Produces a grid of 129 Rows and 129 columns with numeric values. Alternatively you could use the LBound(TR) and UBound(TR) to achieve the same result as manually typing 1 to 129 in each of the For...Loop. I played around with this, and used a conditional format to color the cells based on their relative size either black or white. Here is the result, I think this is the type of output you are expecting.

How to draw very specific annular sectors using visual basic .NET 2

This question furthers a previous question. In that question valter provided me with a very good answer that used two lines of code to perform all the math. I'm hoping he would like to try his hand at this problem also. Even though it looks similar I have not been able to get any math to work.
I need to now draw exactly the same annular sectors accept that the OuterRadius in that question becomes a Rectangle. I include this image to explain what I mean. You will notice the red line that represents the Rectangle plugged into the function. The image is actually a screen capture of what the code I tried up to now produces. Naturally most them are is wrong, but the top left annular sector for instance is correct. All the annular sectors should terminate on the rectangle edge, whilst compensating for the gap. Corner cases would probably need 3 points.
I have decided to post the code I have so far, so the puritans must please close their eyes, because it is pretty brutal:
<Extension()> Friend Sub AddAnnularSector(
ByVal aGraphicsPath As GraphicsPath,
ByVal aCenterPoint As PointR,
ByVal aInnerRadius As Double,
ByVal aOuterRectangle As RectangleF,
ByVal aStartAngle As Double,
ByVal aSweepAngle As Double,
ByVal aStartGap As Double,
ByVal aEndGap As Double)
'Declare local variables...
Dim tInnerStartOffset As Double = (Math.Asin(aStartGap / aInnerRadius) * 180.0R) / Math.PI
Dim tInnerEndOffset As Double = (Math.Asin(aEndGap / aInnerRadius) * 180.0R) / Math.PI
Dim tTestAngle1 As Double = aStartAngle + aSweepAngle - tInnerEndOffset
If tTestAngle1 > 360.0R Then tTestAngle1 -= 360.0R
If tTestAngle1 > 270.0R Then tTestAngle1 = 360.0R - tTestAngle1
If tTestAngle1 > 180.0R Then tTestAngle1 -= 180.0R
If tTestAngle1 > 90.0R Then tTestAngle1 = 180.0R - tTestAngle1
Dim tOuterEndLength As Double = (Math.Min(aOuterRectangle.Width, aOuterRectangle.Height) / 2) / Math.Sin(tTestAngle1.ToRadians)
Dim tTestAngle2 As Double = aStartAngle + tInnerStartOffset
If tTestAngle2 > 360.0R Then tTestAngle2 -= 360.0R
If tTestAngle2 > 270.0R Then tTestAngle2 = 360.0R - tTestAngle2
If tTestAngle2 > 180.0R Then tTestAngle2 -= 180.0R
If tTestAngle2 > 90.0R Then tTestAngle2 = 180.0R - tTestAngle2
Dim tOuterStartLength As Double = (Math.Min(aOuterRectangle.Width, aOuterRectangle.Height) / 2) / Math.Sin(tTestAngle2.ToRadians)
'Add the annular sector to the figure...
aGraphicsPath.StartFigure()
aGraphicsPath.AddArc(CSng(aCenterPoint.X - aInnerRadius), CSng(aCenterPoint.Y - aInnerRadius), CSng(aInnerRadius * 2.0R), CSng(aInnerRadius * 2.0R), CSng(aStartAngle + tInnerStartOffset), CSng(aSweepAngle - (tInnerStartOffset + tInnerEndOffset)))
aGraphicsPath.AddLines(New PointF() {
New PointF(CSng((aCenterPoint.X) + (Math.Cos((aStartAngle + aSweepAngle - tInnerEndOffset).ToRadians) * tOuterEndLength)), CSng((aCenterPoint.Y) + (Math.Sin((aStartAngle + aSweepAngle - tInnerEndOffset).ToRadians) * tOuterEndLength))),
New PointF(CSng((aCenterPoint.X) + (Math.Cos((aStartAngle + tInnerStartOffset).ToRadians) * tOuterStartLength)), CSng((aCenterPoint.Y) + (Math.Sin((aStartAngle + tInnerStartOffset).ToRadians) * tOuterStartLength)))
})
aGraphicsPath.CloseFigure()
Return
End Sub
You will notice how OuterRadius of the previous question changed to aOuterRectangle. Also the inner arc is drawn exactly like the previous outer arc was drawn.
EDIT 1: Just chopped the code off a bit to make it more legible.
EDIT 2: Here is an image of what is actually required unlike the above image that just shows the current result.
Light Cyan - Figure that will actually be added to the GraphicsPath.
Dark Cyan - The part of the figure that is cut away by the OuterRectangle.
Green - The OuterRectangle's dimensions including its center point.
Yellow - The InnerRadius's dimensions including its center point.
Pink - Figure added in a previous call to the function with different inputs just for reference.
EDIT 3: This image shows what I thought would be a quick mathematical solution.
Thanks
drifter
For wdthRect = 250, hgtRect = 200, innerR = 65, startA = 280.0, angle = 30.0, gap = 10.0R
Private Sub DrawAnnular2(ByVal pntC As Point, ByVal wdthRect As Integer, ByVal hgtRect As Integer, ByVal innerR As Integer, ByVal startA As Single, ByVal angle As Single, ByVal gap As Double)
Dim g As Graphics
Dim pth As New GraphicsPath
Dim pthRct As New GraphicsPath
Dim pthCrclIn As New GraphicsPath
Dim pthCrclOut As New GraphicsPath
Dim fe, theta, dbl As Double
Dim outerR, wdth As Integer
Dim rect As Rectangle
wdth = Math.Min(wdthRect, hgtRect)
outerR = CInt(Math.Sqrt(2.0R * (CDbl(wdth) / 2.0R) * (CDbl(wdth) / 2.0R))) 'πυθαγόρειο θεώρημα
rect.X = CInt(CDbl(pntC.X) - CDbl(wdth) / 2.0R)
rect.Y = CInt(CDbl(pntC.Y) - CDbl(wdth) / 2.0R)
rect.Width = wdth
rect.Height = wdth
pthCrclOut.AddEllipse(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR)
pthCrclIn.AddEllipse(rect)
pthRct.AddRectangle(rect)
'////// The same as annular 1 //////////////////////////////////////////////////
g = Me.CreateGraphics
g.SmoothingMode = SmoothingMode.AntiAlias
gap /= 2.0R
dbl = gap / CDbl(outerR)
theta = Math.Asin(dbl) * 180.0R / Math.PI
fe = theta
pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + CSng(fe), angle - CSng(2.0R * fe)) 'Outer
dbl = gap / CDbl(innerR)
theta = Math.Asin(dbl) * 180.0R / Math.PI
fe = theta
pth.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner
'////////////////////////////////////////////////////////////
Dim Reg1 As New Region(pth)
Dim Reg2 As New Region(pthRct)
Reg2.Intersect(Reg1)
g.FillRegion(Brushes.Aqua, Reg2) 'This is the actual annular 2.
g.DrawPath(Pens.Green, pthCrclIn)
g.DrawPath(Pens.Green, pthCrclOut)
g.DrawPath(Pens.Red, pthRct)
Reg1.Dispose()
Reg2.Dispose()
pthRct.Dispose()
pthCrclOut.Dispose()
pthCrclIn.Dispose()
pth.Dispose()
g.Dispose()
End Sub
This line of code:
Reg2.Intersect(Reg1)
is actually the intersect between the blue and the red
EDIT
Private Function DrawAnnular2(ByVal pntC As Point, ByVal wdthRect As Integer, ByVal hgtRect As Integer, ByVal innerR As Integer, ByVal startA As Single, ByVal angle As Single, ByVal gap As Double) As GraphicsPath
Dim g As Graphics
Dim pth As New GraphicsPath
Dim pthRct As New GraphicsPath
Dim pthFinal As New GraphicsPath
Dim fe, theta, dbl As Double
Dim outerR, wdth As Integer
Dim rect As Rectangle
Dim lst1 As New List(Of Integer)
Dim lst2 As New List(Of Integer)
Dim lst3 As New List(Of Integer)
Dim lst4 As New List(Of Integer)
Dim i As Integer
Dim lstBl(3) As Boolean
Dim position As Integer
lstBl(0) = False
lstBl(1) = False
lstBl(2) = False
lstBl(3) = False
wdth = Math.Min(wdthRect, hgtRect)
outerR = CInt(Math.Sqrt(2.0R * (CDbl(wdth) / 2.0R) * (CDbl(wdth) / 2.0R))) 'πυθαγόρειο θεώρημα
rect.X = CInt(CDbl(pntC.X) - CDbl(wdth) / 2.0R)
rect.Y = CInt(CDbl(pntC.Y) - CDbl(wdth) / 2.0R)
rect.Width = wdth
rect.Height = wdth
pthRct.AddRectangle(rect)
'////////////////////////////////////////////////////////
g = Me.CreateGraphics
g.SmoothingMode = SmoothingMode.AntiAlias
gap /= 2.0R
dbl = gap / CDbl(outerR)
theta = Math.Asin(dbl) * 180.0R / Math.PI
fe = theta
If CDbl(angle) - 2.0R * fe >= 360.0R Then
pthFinal.AddEllipse(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR)
pthFinal.AddRectangle(rect)
g.FillPath(Brushes.Aqua, pthFinal)
g.DrawPath(Pens.Red, pthRct)
pthRct.Dispose()
pth.Dispose()
g.Dispose()
Return pthFinal
End If
pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + CSng(fe), angle - CSng(2.0R * fe)) 'Outer
dbl = gap / CDbl(innerR)
theta = Math.Asin(dbl) * 180.0R / Math.PI
fe = theta
pth.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner
'////////////////////////////////////////////////////////////
For i = rect.X To rect.X + wdth
If pth.IsVisible(i, rect.Y) Then
If lst1.Count <> 0 Then
If i <> lst1(lst1.Count - 1) + 1 Then
lstBl(0) = True
position = lst1.Count
End If
End If
lst1.Add(i)
End If
Next
For i = rect.Y To rect.Y + wdth
If pth.IsVisible(rect.X + wdth, i) Then
If lst2.Count <> 0 Then
If i <> lst2(lst2.Count - 1) + 1 Then
lstBl(1) = True
position = lst2.Count
End If
End If
lst2.Add(i)
End If
Next
For i = rect.X To rect.X + wdth
If pth.IsVisible(i, rect.Y + wdth) Then
If lst3.Count <> 0 Then
If i <> lst3(lst3.Count - 1) + 1 Then
lstBl(2) = True
position = lst3.Count
End If
End If
lst3.Add(i)
End If
Next
For i = rect.Y To rect.Y + wdth
If pth.IsVisible(rect.X, i) Then
If lst4.Count <> 0 Then
If i <> lst4(lst4.Count - 1) + 1 Then
lstBl(3) = True
position = lst4.Count
End If
End If
lst4.Add(i)
End If
Next
'If lstBl(0) = True Or lstBl(1) = True Or lstBl(2) = True Or lstBl(3) = True Then
'It is a rare case that i have to work on, when angle is too large
'MsgBox(lstBl(0).ToString + " " + lstBl(1).ToString + " " + lstBl(2).ToString + " " + lstBl(3).ToString + " ")
'Application.Exit()
'End If
'TextBox1.Text = lst1.Count.ToString + " " + lst2.Count.ToString + " " + lst3.Count.ToString + " " + " " + lst4.Count.ToString
pthFinal.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner
If CDbl(startA) + fe >= 225.0R And CDbl(startA) + fe <= 315.0R Then '1
If lst1.Count <> 0 Then
If lstBl(0) = True Then
pthFinal.AddLine(lst1(position), rect.Y, lst1(lst1.Count - 1), rect.Y)
Else
pthFinal.AddLine(lst1(0), rect.Y, lst1(lst1.Count - 1), rect.Y)
End If
End If
If lst2.Count <> 0 Then
pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
End If
If lst3.Count <> 0 Then
pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
End If
If lst4.Count <> 0 Then
pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(0))
End If
If lstBl(0) = True Then
pthFinal.AddLine(rect.X, lst4(0), lst1(position - 1), rect.Y)
End If
ElseIf (CDbl(startA) + fe > 315.0R And CDbl(startA) + fe <= 360.0R) Or _
(CDbl(startA) + fe >= 0.0R And CDbl(startA) + fe <= 45.0R) Then '2
If lst2.Count <> 0 Then
If lstBl(1) = True Then
pthFinal.AddLine(rect.X + wdth, lst2(position), rect.X + wdth, lst2(lst2.Count - 1))
Else
pthFinal.AddLine(rect.X + wdth, lst2(0), rect.X + wdth, lst2(lst2.Count - 1))
End If
End If
If lst3.Count <> 0 Then
pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
End If
If lst4.Count <> 0 Then
pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(0))
End If
If lst1.Count <> 0 Then
pthFinal.AddLine(rect.X, lst4(0), lst1(lst1.Count - 1), rect.Y)
End If
If lstBl(1) = True Then
pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(position - 1))
End If
ElseIf CDbl(startA) + fe > 45.0R And CDbl(startA) + fe <= 135.0R Then '3
If lst3.Count <> 0 Then
If lstBl(2) = True Then
pthFinal.AddLine(lst3(position - 1), rect.Y + wdth, lst3(0), rect.Y + wdth)
Else
pthFinal.AddLine(lst3(lst3.Count - 1), rect.Y + wdth, lst3(0), rect.Y + wdth)
End If
End If
If lst4.Count <> 0 Then
pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst3(0))
End If
If lst1.Count <> 0 Then
pthFinal.AddLine(rect.X, lst3(0), lst1(lst1.Count - 1), rect.Y)
End If
If lst2.Count <> 0 Then
pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
End If
If lstBl(2) = True Then
pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(position), rect.Y + wdth)
End If
Else '4
If lst4.Count <> 0 Then
If lstBl(3) = True Then
pthFinal.AddLine(rect.X, lst4(position - 1), rect.X, lst4(0))
Else
pthFinal.AddLine(rect.X, lst4(lst4.Count - 1), rect.X, lst4(0))
End If
End If
If lst1.Count <> 0 Then
pthFinal.AddLine(rect.X, lst4(0), lst1(lst1.Count - 1), rect.Y)
End If
If lst2.Count <> 0 Then
pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
End If
If lst3.Count <> 0 Then
pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
End If
If lstBl(3) = True Then
pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(position))
End If
End If
'g.FillPath(Brushes.Blue, pth)
g.FillPath(Brushes.Aqua, pthFinal)
g.DrawPath(Pens.Red, pthRct)
pthRct.Dispose()
pth.Dispose()
g.Dispose()
Return pthFinal
End Function
Your values:

Normal Distributed Random Number in VB.NET

Is there anybody know how to make normal distributed random number in vb.net?
thank you
From this forum post :
Usage:
GaussNumDist(Mean, Standard Deviation, Sample Size)
Code example below, which will populate GaussNumArray() with the sample of numbers, whose distribution will have the mean and standard deviation specified:
Imports System.Math
Module Module1
Friend GaussNumArray() As Double
Friend intICell As Long
Friend Function GaussNumDist(ByVal Mean As Double, ByVal StdDev As Double, ByVal SampleSize As Integer)
intICell = 1 'Loop variable
ReDim GaussNumArray(SampleSize)
Do While (intICell < (SampleSize + 1))
Call NumDist(Mean, StdDev)
Application.DoEvents()
Loop
End Function
Sub NumDist(ByVal meanin As Double, ByVal sdin As Double)
'---------------------------------------------------------------------------------
'Converts uniform random numbers over the region 0 to 1 into Gaussian distributed
'random numbers using Box-Muller algorithm.
'Adapted from Numerical Recipes in C
'---------------------------------------------------------------------------------
'Defining variables
Dim dblR1 As Double
Dim dblR2 As Double
Dim mean As Double
Dim var As Double
Dim circ As Double
Dim trans As Double
Dim dblY1 As Double
Dim dblY2 As Double
Dim Pi As Double
Pi = 4 * Atan(1)
'Get two random numbers
dblR1 = (2 * UniformRandomNumber()) - 1
dblR2 = (2 * UniformRandomNumber()) - 1
circ = (dblR1 ^ 2) + (dblR2 ^ 2) 'Radius of circle
If circ >= 1 Then 'If outside unit circle, then reject number
Call NumDist(meanin, sdin)
Exit Sub
End If
'Transform to Gaussian
trans = Sqrt(-2 * Log(circ) / circ)
dblY1 = (trans * dblR1 * sdin) + meanin
dblY2 = (trans * dblR2 * sdin) + meanin
GaussNumArray(intICell) = dblY1 'First number
'Increase intICell for next random number
intICell = (intICell + 1)
GaussNumArray(intICell) = dblY2 'Second number
'Increase intICell again ready for next call of ConvertNumberDistribution
intICell = (intICell + 1)
End Sub
Friend Function UniformRandomNumber() As Double
'-----------------------------------------------------------------------------------
'Outputs random numbers with a period of > 2x10^18 in the range 0 to 1 (exclusive)
'Implements a L'Ecuyer generator with Bays-Durham shuffle
'Adapted from Numerical Recipes in C
'-----------------------------------------------------------------------------------
'Defining constants
Const IM1 As Double = 2147483563
Const IM2 As Double = 2147483399
Const AM As Double = (1.0# / IM1)
Const IMM1 As Double = (IM1 - 1.0#)
Const IA1 As Double = 40014
Const IA2 As Double = 40692
Const IQ1 As Double = 53668
Const IQ2 As Double = 52774
Const IR1 As Double = 12211
Const IR2 As Double = 3791
Const NTAB As Double = 32
Const NDIV As Double = (1.0# + IM1 / NTAB)
Const ESP As Double = 0.00000012
Const RNMX As Double = (1.0# - ESP)
Dim iCell As Integer
Dim idum As Double
Dim j As Integer
Dim k As Long
Dim temp As Double
Static idum2 As Long
Static iy As Long
Static iv(NTAB) As Long
idum2 = 123456789
iy = 0
'Seed value required is a negative integer (idum)
Randomize()
idum = (-Rnd() * 1000)
'For loop to generate a sequence of random numbers based on idum
For iCell = 1 To 10
'Initialize generator
If (idum <= 0) Then
'Prevent idum = 0
If (-(idum) < 1) Then
idum = 1
Else
idum = -(idum)
End If
idum2 = idum
For j = (NTAB + 7) To 0
k = ((idum) / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
If (j < NTAB) Then
iv(j) = idum
End If
Next j
iy = iv(0)
End If
'Start here when not initializing
k = (idum / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
k = (idum2 / IQ2)
idum2 = ((IA2 * (idum2 - (k * IQ2))) - (k * IR2))
If (idum2 < 0) Then
idum2 = idum2 + IM2
End If
j = (iy / NDIV)
iy = (iv(j) - idum2)
iv(j) = idum
If (iy < 1) Then
iy = (iy + IMM1)
End If
temp = AM * iy
If (temp <= RNMX) Then
'Return the value of the random number
UniformRandomNumber = temp
End If
Next iCell
End Function
End Module
You can use following line
Dim x1 as Double = MathNet.Numerics.Distributions.Normal.Sample(MEAN, STDEV)
Math.Net Numeric package can be installed using following NuGet command
Install-Package MathNet.Numerics -Version 4.9.0
You can found more information on NuGet site

DirectX 2D grid

I have been trying to get a 2D grid going. It's for a game map.
Unfortunately, the grid is not as it should be. And I cannot figure out why.
Does anyone have an idea?
Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D
Public Class clsIsometric
'==================================
' SETTINGS
'==================================
Private tile_size As New Point(64, 64) 'Size of one tile in pixels
Private map_size As New Point(25, 25) 'Amount of tiles in total
Private gDevice As Device
Private bufVertex As VertexBuffer
Private bufIndex As IndexBuffer
Private gVertices() As CustomVertex.TransformedColored
Private gIndices() As Integer
'==================================
' CONSTRUCTOR
'==================================
Public Sub New(vDevice As Device)
gDevice = vDevice
End Sub
Public Sub dispose()
bufVertex.Dispose()
bufIndex.Dispose()
bufVertex = Nothing
bufIndex = Nothing
End Sub
'==================================
' RENDERING
'==================================
Public Sub buildMap()
' Recreate buffers to fit the map size
ReDim gVertices((map_size.X + 1) * (map_size.Y + 1)) ' x+1 * y+1
ReDim gIndices(map_size.X * map_size.Y * 6) ' x * y * 6
Dim k As Integer
For cX = 0 To map_size.X - 1 'Rows
For cY = 0 To map_size.Y - 1 'Columns
'VERTEX
k = cX * map_size.X + cY
gVertices(k) = New CustomVertex.TransformedColored(cX * tile_size.X, cY * tile_size.Y, 0, 1, Color.Blue.ToArgb)
Next cY
Next cX
Dim vertexPerCol As Integer = map_size.Y + 1
k = 0
For ccX = 0 To map_size.X - 1
For ccY = 0 To map_size.Y - 1
gIndices(k) = ccX * vertexPerCol + ccY ' 0
gIndices(k + 1) = (ccX + 1) * vertexPerCol + (ccY + 1) ' 1
gIndices(k + 2) = (ccX + 1) * vertexPerCol + ccY ' 2
gIndices(k + 3) = ccX * vertexPerCol + ccY ' 3
gIndices(k + 4) = ccX * vertexPerCol + (ccY + 1) ' 4
gIndices(k + 5) = (ccX + 1) * vertexPerCol + (ccY + 1) ' 5
k += 6 'Each tile has 6 indices. Increase for next tile
Next
Next
bufVertex = New VertexBuffer(GetType(CustomVertex.TransformedColored), gVertices.Length, gDevice, Usage.Dynamic Or Usage.WriteOnly, CustomVertex.TransformedColored.Format, Pool.Default)
bufIndex = New IndexBuffer(GetType(Integer), gIndices.Length, gDevice, Usage.WriteOnly, Pool.Default)
End Sub
Public Sub render()
'RENDER THE MAP
bufVertex.SetData(gVertices, 0, LockFlags.ReadOnly)
bufIndex.SetData(gIndices, 0, LockFlags.None)
gDevice.VertexFormat = CustomVertex.TransformedColored.Format
gDevice.SetStreamSource(0, bufVertex, 0)
gDevice.Indices = bufIndex
gDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, gVertices.Length, 0, CInt(gIndices.Length / 3))
End Sub
End Class
This should output a perfect square grid of 25 by 25 tiles. But the wireframe looks like:
http://i43.tinypic.com/2whf51c.jpg
Your loop which build the vertices seems to end too early, because you have n+1 vertices each row/column. It fills the array only to the forelast column, which leads to a shift in the vertices.
For cX = 0 To map_size.X 'Rows
For cY = 0 To map_size.Y 'Columns
'VERTEX
k = cX * (map_size.X + 1) + cY
gVertices(k) = New CustomVertex.TransformedColored(cX * tile_size.X, cY * tile_size.Y, 0, 1, Color.Blue.ToArgb)
Next cY
Next cX