Finding the ratio in an rgb value - vb.net

I am fairly new to coding (started early this year) and I'm making a program in VB 2010 express that makes a line chart for values that have been given by the user.
In other words, I ask for values and make the program create rectangles on a canvas, one rectangle for every item added to my ArrayList.
This part of the code works, now I want a gradient color scheme, so another color for every rectangle. To achieve this I tried this:
Dim red As Integer = 254
Dim green As Integer = 141
Dim blue As Integer = 150
calcColor(red, green, blue)
Dim MyBrushColor As Color = Color.FromRgb(red, green, blue)
Private Sub calcColor(ByVal red As Integer, ByVal green As Integer, ByVal blue As Integer)
If (red <= 0 Or green <= 0 Or blue <= 0) Then
red = 254
green = 141
blue = 150
red = red + 8
green = green + 8
blue = blue + 8
End If
If (red >= 254 Or green >= 141 Or blue >= 150) Then
red = 254
green = 141
blue = 150
red = red - 8
green = green - 8
blue = blue - 8
End If
End Sub
Just doing -8 and +8 every time is not going to cut it and once they reach either zero or their inital value they'll have another ratio..
As a very inexperienced coder I have no idea how to calculate this ratio. I just know that it's this kind of code I want.

Don't reinvent the wheel. The GDI+ library provides linear gradient brushes. You define starting point and an end point and colors in between and just use this brush for painting.
Example (will comment below):
Dim bmp As New Bitmap(400, 400)
Using brush As Drawing2D.LinearGradientBrush = New Drawing2D.LinearGradientBrush(New Point(0, 0), _
New Point(400, 400), _
Color.Blue, _
Color.Red)
Using p As New Pen(brush)
Using g As Graphics = Graphics.FromImage(bmp)
For i = 1 To 400 Step 10
g.DrawRectangle(p, i - 5, i - 5, 10, 10)
Next
End Using
End Using
End Using
If PictureBox1.Image IsNot Nothing Then PictureBox1.Image.Dispose()
PictureBox1.Image = bmp
First I create a bitmap as a canvas (bmp).
I then create a new object of the paint class. In the constructor I provide an object of the LinearGradientBrush class, with a start point in the top left corner, and an end point in the lower right with colors blue at the start and red at the end.
I then just paint a row of rectangles along the diagonal with this pen for reference.
This brush can do much more, as well. It can use several points on planes and so on and does the color interpolation for you. You just draw with it. Refer to the MSDN for further details: http://msdn.microsoft.com/de-de/library/system.drawing.drawing2d.lineargradientbrush.aspx

Please only look at this if you get stuck. You will learn more by trying it yourself first. Your teacher has probably seen this.
If you use the HSL colour representation, you should be able to get a nice effect by keeping S (saturation) and L (lightness) constant while varying H (hue). You will need to write functions to convert between RGB and HSL - there are many instances of that on the Internet, so here's another one:
Public Class ColourRepresentation
' Adapted from http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
' with conversion from C# to VB.NET by http://www.developerfusion.com/tools/convert/csharp-to-vb/
Public Class HSLcolour
Property H As Double
Property S As Double
Property L As Double
Public Overrides Function ToString() As String
Return String.Format("H={0}, S={1}, L={2}", H, S, L)
End Function
End Class
''' <summary>
''' Convert from HSL to RGB.
''' </summary>
''' <param name="c">An HSLcolour</param>
''' <returns>A System.Drawing.Color with A set to 255.</returns>
''' <remarks>H, S, L in the range [0.0, 1.0].</remarks>
Public Shared Function HSLtoRGB(c As HSLcolour) As Color
Dim r As Double = c.L
Dim g As Double = c.L
Dim b As Double = c.L
Dim v As Double = If((c.L <= 0.5), (c.L * (1.0 + c.S)), (c.L + c.S - c.L * c.S))
If v > 0 Then
Dim m As Double = c.L + c.L - v
Dim sv As Double = (v - m) / v
c.H *= 6.0
Dim sextant As Integer = CInt(Math.Truncate(c.H))
Dim fract As Double = c.H - sextant
Dim vsf As Double = v * sv * fract
Dim mid1 As Double = m + vsf
Dim mid2 As Double = v - vsf
Select Case sextant
Case 0, 6
r = v
g = mid1
b = m
Case 1
r = mid2
g = v
b = m
Case 2
r = m
g = v
b = mid1
Case 3
r = m
g = mid2
b = v
Case 4
r = mid1
g = m
b = v
Case 5
r = v
g = m
b = mid2
End Select
End If
Return Color.FromArgb(255, CByte(r * 255), CByte(g * 255), CByte(b * 255))
End Function
' Given a Color (RGB Struct) in range of 0-255
' Return H,S,L in range of 0-1
''' <summary>
''' Convert from a Color to an HSLcolour.
''' </summary>
''' <param name="rgb">A System.Drawing.Color.</param>
''' <returns>An HSLcolour.</returns>
''' <remarks>Ignores Alpha value in the parameter.</remarks>
Public Shared Function RGBtoHSL(rgb As Color) As HSLcolour
Dim r As Double = rgb.R / 255.0
Dim g As Double = rgb.G / 255.0
Dim b As Double = rgb.B / 255.0
Dim v As Double = Math.Max(r, g)
v = Math.Max(v, b)
Dim m As Double = Math.Min(r, g)
m = Math.Min(m, b)
Dim l As Double = (m + v) / 2.0
If l <= 0.0 Then
Return New HSLcolour With {.H = 0, .L = 0, .S = 0}
End If
Dim vm As Double = v - m
Dim s As Double = vm
If s > 0.0 Then
s /= If((l <= 0.5), (v + m), (2.0 - v - m))
Else
Return New HSLcolour With {.H = 0, .L = 0, .S = 0}
End If
Dim r2 As Double = (v - r) / vm
Dim g2 As Double = (v - g) / vm
Dim b2 As Double = (v - b) / vm
Dim h As Double = 0
If r = v Then
h = (If(g = m, 5.0 + b2, 1.0 - g2))
ElseIf g = v Then
h = (If(b = m, 1.0 + r2, 3.0 - b2))
Else
h = (If(r = m, 3.0 + g2, 5.0 - r2))
End If
h /= 6.0
Return New HSLcolour With {.H = h, .L = l, .S = s}
End Function
End Class
Then you will need a way of varying the hue, which I have used in this crude example of drawing a bar chart (I put one PictureBox on a Form):
Option Strict On
Option Infer On
Public Class Form1
Dim rand As New Random
Dim data As List(Of Double)
Private Function DoubleModOne(value As Double) As Double
While value > 1.0
value -= 1.0
End While
While value < 0.0
value += 1.0
End While
Return value
End Function
Sub DrawBars(sender As Object, e As PaintEventArgs)
Dim target = DirectCast(sender, PictureBox)
e.Graphics.Clear(Color.DarkGray)
' an approximation of the bar width
'TODO: Improve the approximation.
Dim barWidth As Integer = CInt(CDbl(target.Width) / data.Count)
Dim maxBarHeight = target.Height
Using br As New SolidBrush(Color.Black)
Dim r As Rectangle
'TODO: make it work for Color.Gainsboro
Dim startColour = ColourRepresentation.RGBtoHSL(Color.Fuchsia)
' these components are broken out in case something needs to be done to them.
Dim startColourH = startColour.H
Dim startColourS = startColour.S
Dim startColourL = startColour.L
' Using 1.0 as the quotient makes the colours go through the whole spectrum.
Dim colourInc As Double = 1.0 / data.Count
' Only expects data to be in the range (0, 1).
For i = 0 To data.Count - 1
Dim thisHSLcolour As New ColourRepresentation.HSLcolour With {.H = DoubleModOne(startColourH + i * colourInc), .S = startColourS, .L = startColourL}
br.Color = ColourRepresentation.HSLtoRGB(thisHSLcolour)
r = New Rectangle(CInt(i * barWidth), CInt(data(i) * maxBarHeight), barWidth, maxBarHeight)
e.Graphics.FillRectangle(br, r)
Next
End Using
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim nBars = 100
data = New List(Of Double)(nBars)
For i = 0 To nBars - 1
data.Add(rand.NextDouble())
Next
AddHandler PictureBox1.Paint, AddressOf DrawBars
End Sub
End Class
Resulting in:
No-one ever accused me of choosing subtle colours, lol.

Related

spacing between two points in 3d cordinate system

i am a bit new to this but I'm trying to create a randomly generated 3d coordinate points with equal spacing, I've tried using for each loop but im confused on how to use in. the purpose is to generate sphere around that point but some sphere are overlapping each other. thanks in advance. the code below is to show how I'm generating the sphere
For i = 0 To noofsp - 1
x = Rnd(1) * maxDist
ws1.Cells(i + 5, 2) = x
y = Rnd(1) * maxDist
ws1.Cells(i + 5, 3) = y
z = Rnd(1) * maxDist
ws1.Cells(i + 5, 4) = z
centers.Add({x, y, z})
Next
You'll need to check the new point against all the other points to make sure that your new point is at a greater distance that the sum of the radii of your new sphere and each sphere you're checking against
You'll need to use pythagoras' theorem to check that the distances and I found the code below from this site. The code on the site is written in c#, but here is the vb.net version.
Public Function Distance3D(x1 As Double, y1 As Double, z1 As Double, x2 As Double, y2 As Double, z2 As Double) As Double
' __________________________________
'd = √ (x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2
'
'Our end result
Dim result As Double
'Take x2-x1, then square it
Dim part1 As Double = Math.Pow((x2 - x1), 2)
'Take y2-y1, then square it
Dim part2 As Double = Math.Pow((y2 - y1), 2)
'Take z2-z1, then square it
Dim part3 As Double = Math.Pow((z2 - z1), 2)
'Add both of the parts together
Dim underRadical As Double = part1 + part2 + part3
'Get the square root of the parts
result = Math.Sqrt(underRadical)
'Return our result
Return result
End Function
To generate the spheres, you would need to expand your code to include checking the new point against all the previously generated points. That code is below with comments.
I have assumed the definition of a variable called minDistance to specify how far apart the centre of the spheres should be. I'm also assuming that all the spheres are the same size. The number should be twice the radius of the spheres
Private Sub GenerateSpheres()
Randomize
For i As Integer = 0 To noofsp - 1
Dim distanceOK As Boolean = False
Dim x, y, z As Integer
'keep generating points until one is found that is
'far enough away. When it is, add it to your data
While distanceOK = False
x = Rnd(1) * maxDist
y = Rnd(1) * maxDist
z = Rnd(1) * maxDist
'If no other points have been generated yet, don't bother
'checking your new point
If centers.Count = 0 Then
distanceOK = True
Else
'If other points exist, loop through the list and check distance
For j As Integer = 0 To centers.Count - 1
'if the point is too close to any other, stop checking,
'exit the For Loop and the While Loop will generate a new
'coordinate for checking, and so on
Dim dist As Integer = Distance3D(centers(j)(0), centers(j)(1), centers(j)(2), x, y, z)
If dist <= minDistance Then
distanceOK = False
'exit the For loop and start the next iteration of the While Loop
Continue While
End If
Next
'If all previous points have been checked none are too close
'flag distanceOK as true
distanceOK = True
End If
End While
'ws1.Cells(i + 5, 2) = x
'ws1.Cells(i + 5, 3) = y
'ws1.Cells(i + 5, 4) = z
centers.Add({x, y, z})
Next
End Sub

Arithmetic operation resulted in an overflow..Error in below highlited code

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Compare(PictureBox1.Image, PictureBox2.Image)
End Sub
Public Function Compare(ByVal img1_ As Image, ByVal img2_ As Image) As Double
Dim pixelNb As Integer = img1_.Width * img1_.Height
Dim percent As Double = 100
Dim resized_img2_ As Bitmap = ResizeBitmap(CType(img2_, Bitmap), img1_.Width, img1_.Height)
For i As Integer = 0 To img1_.Width - 1
For j As Integer = 0 To img1_.Height - 1
percent -= ColorCompare((CType(img1_, Bitmap)).GetPixel(i, j), (CType(resized_img2_, Bitmap)).GetPixel(i, j)) / pixelNb
Next
Next
Return percent
End Function
Public Function ResizeBitmap(ByVal b As Bitmap, ByVal nWidth As Integer, ByVal nHeight As Integer) As Bitmap
Dim result As Bitmap = New Bitmap(nWidth, nHeight)
Using g As Graphics = Graphics.FromImage(CType(result, Image))
g.DrawImage(b, 0, 0, nWidth, nHeight)
End Using
Return result
End Function
Public Function ColorCompare(ByVal c1 As Color, ByVal c2 As Color) As Double
Return Double.Parse((Math.Abs(c1.B - c2.B) + Math.Abs(c1.R - c2.R) + Math.Abs(c1.G - c2.G)).ToString()) * 100 / (3 * 255)
End Function
Error Give in this line
Return Double.Parse((Math.Abs(c1.B - c2.B) + Math.Abs(c1.R - c2.R) +
Math.Abs(c1.G - c2.G)).ToString()) * 100 / (3 * 255)
c1.B returns a byte. A Byte has a value of 0-255 and is unsigned so it cannot hold a negative value.
Dim a As Byte = 200
Dim b As Byte = 201
Dim x = a - b
causes the same overflow error.
Changing to an integer avoids the error. A cast doesn't seem to be necessary as it is widening (no data loss).
Dim a As Byte = 200
Dim b As Byte = 201
Dim c As Integer = a
Dim d As Integer = b
Dim x = c - d
Change your color bytes to Integers and try again.
Dim g, h, i, j, k, l As Integer
g = c1.B
h = c2.B
i = c1.R
j = c1.R
k = c1.G
l = c1.G
Dim result As Double = CDbl(Math.Abs(g - h) + Math.Abs(i - j) + Math.Abs(k - l)) * 100 / (3 * 255)
Return result

ECDH Generating Public key causes the point to not be on the curve VB.net

I am not sure whether this question was relevant for stackoverflow or cryptography stackexchange, but I thought that I would ask it here as the question might go into programming.
I am trying to generate a public and private keypair using elliptic curve diffie-hellman, I successfully generate a private key that is smaller than the order of the curve but when I calculate the public key by multiplying the base point by the private key I calculate a point that is not on the curve.
The code I am using to generate the keys looks like this:
Public Shared Function generate_Keys(ByVal Param As Domain_Parameters) As Keys
Dim __PrivateKey As BigInteger
Dim __PublicKey As ECPoint
Dim d As BigInteger
Dim rng As New RNGCryptoServiceProvider
Dim bytes(Param.n.ToByteArray.Length) As Byte
Do
rng.GetBytes(bytes)
d = New BigInteger(bytes)
If d.Sign = -1 Then
d = d * -1
End If
Loop While d >= Param.n
__PrivateKey = d
__PublicKey = Point_Operations.Scalar_Mult(Param.Base, Param, d)
Dim Ret As Keys
Ret.PublicKey = __PublicKey
Ret.PrivateKey = __PrivateKey
__PrivateKey = BigInteger.Zero()
d = BigInteger.Zero()
bytes = {0}
Return Ret
End Function
And the code that I have tested and works fine to multiply the base point by the private key looks like this:
Public Class Point_Operations
''' <summary>
''' A structure that contains data returned from Extended_GCD function
''' </summary>
Friend Structure RetGCD
Public x As BigInteger
Public y As BigInteger
Public GCD As BigInteger
End Structure
''' <summary>
''' Perfomrs addition of two points
''' </summary>
Public Shared Function Addition(ByVal P1 As ECPoint, ByVal P2 As ECPoint) As ECPoint
'Details about the maths was found on https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
'Tested with the site http://christelbach.com/ECCalculator.aspx
If P1.IsPointInfinity() Then
Return P2
End If
If P2.IsPointInfinity() Then
Return P1
End If
If P1.p <> P2.p Then
Return New ECPoint(-99, -99, -99) 'Add custom errors with ENUM
End If
If P1.x = P2.x And P1.y = P2.y Then
Return New ECPoint(-99, -99, -99)
End If
Dim P3 As New ECPoint(P1)
Dim l, z As BigInteger
z = Inverse((P2.x - P1.x), P1.p)
l = ((P2.y - P1.y) * z) Mod P1.p
P3.x = ((l * l) Mod P1.p - P2.x - P1.x) Mod P1.p
P3.y = (l * (P1.x - P3.x) Mod P1.p - P1.y) Mod P1.p
If P3.x < 0 Then 'Tested the code without the peice below and found that the input (10,10,47) and (20,20,47) returned wrong values found out that the difference between each was the prime number so if its less than zero we add the prime whcih seems to work
P3.x += P1.p
End If
If P3.y < 0 Then
P3.y += P1.p
End If
Return P3
End Function
''' <summary>
''' A way of doubling a EC Point
''' </summary>
Public Shared Function PDouble(ByVal P As ECPoint, ByVal a As Domain_Parameters) As ECPoint
'Details about the maths was found on https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
'Tested with the site http://christelbach.com/ECCalculator.aspx
If P.p = 0 And a.Fp.p = 0 Then
Return New ECPoint(-99, -99, -99)
End If
'If a.a = 0 Then
' Return New ECPoint(-99, -99, -99)
'End If
If P.IsPointInfinity() Then
Return P
End If
Dim prime As BigInteger
If P.p = 0 Then
prime = a.Fp.p
Else
prime = P.p
End If
Dim Q As New ECPoint(P)
Dim l, z As BigInteger
z = Inverse(2 * P.y, P.p)
l = ((((3 * P.x * P.x) Mod P.p + a.a) Mod P.p) * z) Mod P.p
Q.x = ((l * l) Mod P.p - 2 * P.x) Mod P.p 'accidental set (2 * p.x) to (2 * P.p)
Q.y = (l * (P.x - Q.x) Mod P.p - P.y) Mod P.p
If Q.x < 0 Then 'This code was tested and the same problem again with negative values for x and y so we must add the prime to p to correct that
Q.x += P.p
End If
If Q.y < 0 Then
Q.y += P.p
End If
Return Q
End Function
''' <summary>
''' Performs point multiplication with a scalar
''' </summary>
Public Shared Function Scalar_Mult(ByVal P As ECPoint, ByVal a As Domain_Parameters, ByVal Scalar As BigInteger) As ECPoint
'Details about the maths was found on https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
'Tested with the site http://christelbach.com/ECCalculator.aspx
If P.p = 0 And a.Fp.p = 0 Then
Return New ECPoint(-99, -99, -99)
End If
'If a.a = 0 Then
' Return New ECPoint(-99, -99, -99)
'End If
If P.IsPointInfinity Then
Return P
End If
Dim prime As BigInteger
If P.p = 0 Then
prime = a.Fp.p
Else
prime = P.p
End If
'Dim k As New BigInteger(Scalar.ToByteArray)
Dim N, S As New ECPoint(P)
S = New ECPoint(0, 0, prime) 'Accidentally set S.y = 1 was causing a bad value
'Dim sc As New BigInteger(k.ToByteArray) 'Depreciated as now we can use bits.lenght
'Dim bitlenght As Integer
'While sc / 2 <> 0
' bitlenght += 1
' sc /= 2
'End While
Dim bits As New BitArray(Scalar.ToByteArray)
For i = 0 To bits.Length - 1
If bits(i) = True Then 'Fixed error where BitArray uses True/False instead of 1/0
S = Addition(S, N)
End If
N = PDouble(N, a)
Next
Return S
End Function
''' <summary>
''' Calcualtes the Greatest Common Divisor of two numbers
''' </summary>
Private Shared Function Extended_GCD(ByVal a As BigInteger, b As BigInteger) As RetGCD
'The pseudocode was found on https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode
'Tested with the site http://planetcalc.com/3298/
Dim r, o_r As BigInteger
Dim t, o_t As BigInteger
Dim s, o_s As BigInteger
Dim p, q As BigInteger
Dim ret As RetGCD
s = 0
t = 1
r = b
o_s = 1
o_t = 0
o_r = a
While r <> 0
q = o_r / r
p = r
r = o_r - q * p
o_r = p
p = s
s = o_s - q * p
o_s = p
p = t
t = o_t - q * p
o_t = p
End While
ret.x = o_s
ret.y = o_t
ret.GCD = o_r
Return ret
End Function
''' <summary>
''' Performs the modular multiplitcative inverse of a number so we can use multiplication instead of division in our arithmetic
''' </summary>
Public Shared Function Inverse(ByVal a As BigInteger, ByVal p As BigInteger) As BigInteger
'Not tested but works
Dim ret As RetGCD
ret = Extended_GCD(a, p)
If ret.GCD <> 1 Then
Return 0
End If
Return ret.x Mod p
End Function
I have a feeling that it is possibly the way I am generating a private key or that I am using the wrong operation when calculating G.d .
Any help would really be appreciated thanks.
===EDIT===
After spending some time check values I have found the problem to be caused by the scalar_mult function not returning the right value. Is this function written correctly because i am unsure I have tested it with values from a site and it has been adapted from the pseudocode on wikipedia. Is that the correct method for adding a point to itself x number of time?

Finding minimum point of a function

If I have a convex curve, and want to find the minimum point (x,y) using a for or while loop. I am thinking of something like
dim y as double
dim LastY as double = 0
for i = 0 to a large number
y=computefunction(i)
if lasty > y then exit for
next
how can I that minimum point? (x is always > 0 and integer)
Very Close
you just need to
dim y as double
dim smallestY as double = computefunction(0)
for i = 0 to aLargeNumber as integer
y=computefunction(i)
if smallestY > y then smallestY=y
next
'now that the loop has finished, smallestY should contain the lowest value of Y
If this code takes a long time to run, you could quite easily turn it into a multi-threaded loop using parallel.For - for example
dim y as Double
dim smallestY as double = computefunction(0)
Parallel.For(0, aLargeNumber, Sub(i As Integer)
y=computefunction(i)
if smallestY > y then smallestY=y
End Sub)
This would automatically create separate threads for each iteration of the loop.
For a sample function:
y = 0.01 * (x - 50) ^ 2 - 5
or properly written like this:
A minimum is mathematically obvious at x = 50 and y = -5, you can verify with google:
Below VB.NET console application, converted from python, finds a minimum at x=50.0000703584199, y=-4.9999999999505, which is correct for the specified tolerance of 0.0001:
Module Module1
Sub Main()
Dim result As Double = GoldenSectionSearch(AddressOf ComputeFunction, 0, 100)
Dim resultString As String = "x=" & result.ToString + ", y=" & ComputeFunction(result).ToString
Console.WriteLine(resultString) 'prints x=50.0000703584199, y=-4.9999999999505
End Sub
Function GoldenSectionSearch(f As Func(Of Double, Double), xStart As Double, xEnd As Double, Optional tol As Double = 0.0001) As Double
Dim gr As Double = (Math.Sqrt(5) - 1) / 2
Dim c As Double = xEnd - gr * (xEnd - xStart)
Dim d As Double = xStart + gr * (xEnd - xStart)
While Math.Abs(c - d) > tol
Dim fc As Double = f(c)
Dim fd As Double = f(d)
If fc < fd Then
xEnd = d
d = c
c = xEnd - gr * (xEnd - xStart)
Else
xStart = c
c = d
d = xStart + gr * (xEnd - xStart)
End If
End While
Return (xEnd + xStart) / 2
End Function
Function ComputeFunction(x As Double)
Return 0.01 * (x - 50) ^ 2 - 5
End Function
End Module
Side note: your initial attempt to find minimum is assuming a function is discrete, which is very unlikely in real life. What you would get with a simple for loop is a very rough estimate, and a long time to find it, as linear search is least efficient among other methods.

Trouble with VB.NET Liang-Barsky implementation

After some research, I've decided to use the Liang-Barsky line clipping algorithm in my 2D game. Google did not deliver on any VB.NET implementations of this algorithm but plenty C/++ ones. Therefore, as I have knowledge in C++, decided to port one found on Skytopia over to VB.Net. Unfortunately, it does not work with:
Public Class PhysicsObject
Public Function CollideRay(ByVal p0 As Point, ByVal p1 As Point, ByRef clip0 As Point, ByRef clip1 As Point) As Boolean
Dim t0 As Double = 0.0
Dim t1 As Double = 1.0
Dim xdelta As Double = p1.X - p0.X
Dim ydelta As Double = p1.Y - p0.Y
Dim p, q, r As Double
For edge = 0 To 3
' Traverse through left, right, bottom, top edges
If (edge = 0) Then
p = -xdelta
q = -(AABB.Left - p0.X)
ElseIf (edge = 1) Then
p = xdelta
q = (AABB.Right - p0.X)
ElseIf (edge = 2) Then
p = -ydelta
q = -(AABB.Bottom - p0.Y)
ElseIf (edge = 3) Then
p = ydelta
q = (AABB.Top - p0.Y)
End If
r = q / p
If p = 0 And q < 0 Then Return False ' Don't draw line at all. (parallel line outside)
If p < 0 Then
If r > t1 Then
Return False ' Don't draw line at all.
ElseIf r > t0 Then
t0 = r ' Line is clipped!
End If
ElseIf p > 0 Then
If r < t0 Then
Return False ' Don't draw line at all.
ElseIf r < t1 Then
t1 = r ' Line is clipped!
End If
End If
Next
clip0.X = p0.X + t0 * xdelta
clip0.Y = p0.Y + t0 * ydelta
clip1.X = p0.X + t1 * xdelta
clip1.Y = p0.Y + t1 * ydelta
Return True ' (clipped) line is drawn
End Function
Public AABB As Rectangle
End Class
I'm using the class/method like:
Dim testPhysics As PhysicsObject = New PhysicsObject
testPhysics.AABB = New Rectangle(30, 30, 20, 20)
Dim p0, p1 As Point
p0 = New Point(0, 0)
p1 = New Point(120, 120)
Dim clip0, clip1 As Point
clip0 = New Point(-1, -1)
clip1 = New Point(-1, -1)
GlobalRenderer.Graphics.DrawLine(Pens.LimeGreen, p0, p1)
If testPhysics.CollideRay(p0, p1, clip0, clip1) Then
GlobalRenderer.Graphics.DrawLine(Pens.Magenta, clip0, clip1)
End If
However, the CollideRay method fails on its 3rd edge iteration (edge = 3), r < t0, therefore the function returns false.
I'm wondering if anyone can spot some issue with my CollideRay function which would result in this behaviour, because I'm well and truly stumped.
Thanks in advance.
The code assumes a different coordinate system, note that topEdge is larger than bottomEdge in the linked web page. Your test works with normal graphics coordinates where Bottom is larger than Top. You have to swap the bottom and top arguments.