I am a beginner in VB. I wrote a little program to simulate dosing regimens of antibiotics using some exponential equations and pharmacokinetic data.
The problem I have is that I want to display on a graph the following mathematical function:
That simulates the concentration variation at different intervals of time:
Where:
b(t) is the concentration at time t that will be plotted as Y axis, t is time (plotted on the x-axis).
b(0) is the concentration at time 0 and it is a known variable.
u(t-a1) is a function that has the value u(t-a1)=b(o) if t=a1 or 0 if t<>a1
a1 is the time at which a next dose is given.
alpha is the elimination rate constant, a variable that is known.
What I have so far:
Dim y, x As Double
For x = 0 To 24 Step 1
For n As Double = 1 To 24 / tau
y = (1 - test_condition(n * tau, x)) * css * Math.Exp(-ke * x) + test_condition(n * tau, x) * css * Math.Exp(-ke * (x - n * tau))
Chart1.Series("Concentratie1").Points.AddXY(x, y)
Next
Next
The test_condition:
if x=tau then test_condition= 1 else 0
It is close but I don't get an exponential decay after a dose ... don't know how to make that happen.
This works!! for tau (dosing interval) every 4 hours. Can it be rearranged somehow because the tau (dosing interval) will vary (sometimes 4 hours, sometimes every 6 hours)?:
Dim y, x, y2, x2, y3, x3, y4, x4, x5, x6, y5, y6 As Double
For x = 0 To tau Step 1
y = exponential_decay(css, ke, x) + test_condition(tau, x) * (css - Val(mic))
Chart1.Series("Bolus 1").Points.AddXY(x, y)
Next
For x2 = tau To 2 * tau Step 1
y2 = exponential_decay(css, ke, x2 - tau) + test_condition(2 * tau, x2) * (css - Val(mic))
Chart1.Series("Bolus 2").Points.AddXY(x2, y2)
Next
For x3 = 2 * tau To 3 * tau Step 1
y3 = exponential_decay(css, ke, x3 - 2 * tau) + test_condition(3 * tau, x3) * (css - Val(mic))
Chart1.Series("Bolus 3").Points.AddXY(x3, y3)
Next
For x4 = 3 * tau To 4 * tau Step 1
y4 = exponential_decay(css, ke, x4 - 3 * tau) + test_condition(4 * tau, x4) * (css - Val(mic))
Chart1.Series("Bolus 4").Points.AddXY(x4, y4)
Next
For x5 = 4 * tau To 5 * tau Step 1
y5 = exponential_decay(css, ke, x5 - 4 * tau) + test_condition(5 * tau, x5) * (css - Val(mic))
Chart1.Series("Bolus 4").Points.AddXY(x5, y5)
Next
For x6 = 5 * tau To 32 Step 1
y6 = exponential_decay(css, ke, x6 - 5 * tau)
Chart1.Series("Bolus 4").Points.AddXY(x6, y6)
Next
End Sub
I managed to solve the problem:
this function f relates time (t) to dosing interval (tau)
Private Function f(ByVal t As Double, ByVal tau As Double)
Dim n As Integer
For n = 0 To 24 / tau
If t = n * tau Then
f = n * tau
ElseIf t < tau Then
f = 0
ElseIf t > n * tau And t < (n + 1) * tau Then
f = n * tau
ElseIf t >= (n + 1) * tau Then
f = n * tau
End If
Next
End Function
And this is what I draw on the chart:
For x = 0 To 36 Step 0.5
y = exponential_decay(css, ke, x - f(x, tau))
Chart1.Series("Intermitent Dosage").Points.AddXY(x, y)
Next
Related
I have two lines - the first one is straight horizontal line with x1y1 as start point and x2y2 as end point. There is another line with start point as x1y1 and end point as x3y3.
Is there any way that I can fix the coordinate x1y1 of the lines so that if I rotate the second line the point x1y1 is not detached?
I tried grouping the lines but it didn't work.
Set p1 = ActiveSheet.Shapes.AddConnector(msoConnectorStraight, x1, y1, x2, y2)
p1.Select
Selection.ShapeRange.Line.BeginArrowheadStyle = msoArrowheadOval
Selection.ShapeRange.Line.EndArrowheadStyle = msoArrowheadOval
Set p2 = ActiveSheet.Shapes.AddConnector(msoConnectorStraight, x1, y1, x3, y3)
p2.Select
Selection.ShapeRange.Line.BeginArrowheadStyle = msoArrowheadOval
Selection.ShapeRange.Line.EndArrowheadStyle = msoArrowheadOval
Dim R As Variant
Set R = ActiveSheet.Shapes.Range(Array(p1.Name, p2.Name))
R.Group
Problem and code
If I understood correctly, you want to input an angle and to obtain the coordinates of the point (x3,y3) to redraw a line.
The solution can be done on the coordinates x3 and y3, since, as #SJR said "Rotation is around the midpoint of the line". So you need to use geometry to do it.
Using the Law of Sines code on Math.Stackexchange answered by Jean Marie, the following code can be done:
'Initial Values
x1 = 100
y1 = 100
x2 = 300
y2 = 100
DesiredAngle = 45
'Find coordinates
Angle1 = Application.WorksheetFunction.Radians(DesiredAngle)
Angle2 = Application.WorksheetFunction.Radians((180 - DesiredAngle) / 2)
Deltax = x2 - x1
Deltay = y2 - y1
a3 = Sqr(Deltax ^ 2 + Deltay ^ 2)
Angle3 = Application.WorksheetFunction.Pi() - Angle1 - Angle2
a2 = a3 * Sin(Angle2) / Sin(Angle3)
RHS1 = x1 * Deltax + y1 * Deltay + a2 * a3 * Cos(Angle1)
RHS2 = y2 * Deltax - x2 * Deltay + a2 * a3 * Sin(Angle1)
x3 = (1 / a3 ^ 2) * (Deltax * RHS1 - Deltay * RHS2)
y3 = (1 / a3 ^ 2) * (Deltay * RHS1 + Deltax * RHS2)
Debug.Print x3 & " " & y3
'Draw Lines
Set Line1 = ActiveSheet.Shapes.AddLine(x1, y1, x2, y2)
Set Line2 = ActiveSheet.Shapes.AddLine(x1, y1, x3, y3)
'Verify angle to know if it worked
'Method1 to obtain angle of 3 points
alpha = Application.WorksheetFunction.Atan2((y2 - y1), (x2 - x1))
beta = Application.WorksheetFunction.Atan2((y3 - y1), (x3 - x1))
Debug.Print Application.WorksheetFunction.Degrees(beta - alpha)
'Method2
m1 = (y2 - y1) / (x2 - x1)
m2 = (y3 - y1) / (x3 - x1)
Debug.Print Application.WorksheetFunction.Degrees(Atn((m1 - m2) / (1 + m1 * m2)))
'Check Length
Debug.Print Sqr((x3 - x1) ^ 2 + (y3 - y1) ^ 2)
On the code, the example is that the initial value is a line as you drew and after inputting the DesiredAngle, a line is drawn with this angle, with the new x3 and y3 coordinates.
Result
On the Result, the example uses a DesiredAngle of 45°.
Further References
You can refer to many questions about this on Math.Stackexchange, like this, this, this.
EDIT:
To test it, you can make a simple For loop and check that a circle is made, i.e., the circle radius is the same length:
'Initial Values
x1 = 500
y1 = 300
x2 = 700
y2 = 300
For i = 1 To 360
On Error Resume Next
DesiredAngle = i
'Find coordinates
Angle1 = Application.WorksheetFunction.Radians(DesiredAngle)
Angle2 = Application.WorksheetFunction.Radians((180 - DesiredAngle) / 2)
Deltax = x2 - x1
Deltay = y2 - y1
a3 = Sqr(Deltax ^ 2 + Deltay ^ 2)
Angle3 = Application.WorksheetFunction.Pi() - Angle1 - Angle2
a2 = a3 * Sin(Angle2) / Sin(Angle3)
RHS1 = x1 * Deltax + y1 * Deltay + a2 * a3 * Cos(Angle1)
RHS2 = y2 * Deltax - x2 * Deltay + a2 * a3 * Sin(Angle1)
x3 = (1 / a3 ^ 2) * (Deltax * RHS1 - Deltay * RHS2)
y3 = (1 / a3 ^ 2) * (Deltay * RHS1 + Deltax * RHS2)
Debug.Print x3 & " " & y3
'Draw Lines
Set Line1 = ActiveSheet.Shapes.AddLine(x1, y1, x2, y2)
Set Line2 = ActiveSheet.Shapes.AddLine(x1, y1, x3, y3)
Next i
So I have a "main" function (SolveSixODES) that calls a secondary function (AllODEs). And when it does this, the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable.
Here is the code, my inputs I used are as follows:
x=0, xmax=3, y=0-6, h=0.1, error=0.1
Public Function SolveSixODE(x As Double, xmax As Double, Y As Range, h As Double, error As Double) 'Weird bug: You must leave the first y4 value blank
Dim i As Integer, k(7, 7) As Double, j As Integer, m As Integer 'k(Order #, equation #)
Dim Y5(7) As Double, Y4(7) As Double, Y4Old(7) As Double
Dim delta0(7) As Double, delta1(7) As Double, delRatio(7) As Double, Rmin As Double
For i = 1 To 6 'Moving the input data so it can acutally be used
Y4(i) = Y(i)
Next i
While x < xmax
If x + h < xmax Then
x = x + h
Else
h = xmax - x
x = xmax
End If
For j = 1 To 6 'j is the order i is equation number
For i = 1 To 6 'Calculating all of the k(1) values for eq 1 to 6
k(j, i) = AllODES(x, Y4, i, j, k, h) '!!!!!SOME HOW THIS LOOP MAKES X negative...!!!!!!!
Next i
Next j
For i = 1 To 6
Y4Old(i) = Y4(i) 'Saving old y4 value to calc delta0
Y4(i) = Y4(i) + h * (k(1, i) * (37 / 378) + k(3, i) * (250 / 621) + k(4, i) * (125 / 594) + k(6, i) * (512 / 1771))
Y5(i) = Y4(i) + h * (k(1, i) * (2825 / 27648) + k(3, i) * (18575 / 48384) + k(4, i) * (13525 / 55296) + k(5, i) * (277 / 14336) + k(6, i) * (0.25))
delta0(i) = error * (Abs(Y4Old(i)) + Abs(h * AllODES(x, Y4Old, i, 1, k, h))) 'First order because we don't want to use the k vals
delta1(i) = Abs(Y5(i) - Y4(i))
delRatio(i) = Abs(delta0(i) / delta1(i)) 'Ratio of errors
Next i
Rmin = delRatio(1)
For i = 2 To 6
If delRatio(i) < Rmin Then
Rmin = delRatio(i) 'Determine the smallest error ratio
End If
Next i
If Rmin < 1 Then 'If this is true then the step size was too big must repeat step
x = x - h 'Set x and y's back to previous values
For i = 1 To 6
Y4(i) = Y4Old(i)
Next i
h = 0.9 * h * Rmin ^ 0.25 'adjust h value; 0.9 is a safety factor
Else
h = 0.9 * h * Rmin ^ 0.2 'Otherwise, we march on
End If
m = m + 1
Wend
SolveSixODE = Y4
End Function
Public Function AllODES(x As Double, Y() As Double, EqNumber As Integer, order As Integer, k() As Double, h As Double) As Double
Dim conc(7) As Double, i As Integer, j As Integer
If order = 1 Then
x = x - h
For i = 1 To 6 'Movin the data so I can use it
conc(i) = Y(i) 'also adjusting the x and y values for RK4 (Cash Karp values)
Next i
ElseIf order = 2 Then
x = x - h + h * 0.2
For i = 1 To 6
conc(i) = Y(i) + h * k(1, i) * 0.2
Next i
ElseIf order = 3 Then
x = x - h + 0.3 * h
For i = 1 To 6
conc(i) = Y(i) + h * (0.075 * k(1, i) + 0.225 * k(2, i))
Next i
ElseIf order = 4 Then
x = x - h + 0.6 * h
For i = 1 To 6
conc(i) = Y(i) + h * (0.3 * k(1, i) - 0.9 * k(2, i) + 1.2 * k(3, i))
Next i
ElseIf order = 5 Then
x = x - h + h
For i = 1 To 6
conc(i) = Y(i) + h * ((-11 / 54) * k(1, i) + 2.5 * k(2, i) - (70 / 27) * k(3, i) + (35 / 27) * k(4, i))
Next i
ElseIf order = 6 Then
x = x - h + 0.875 * h
For i = 1 To 6
conc(i) = Y(i) + h * ((1631 / 55296) * k(1, i) + (175 / 512) * k(2, i) + (575 / 13824) * k(3, i) + (44275 / (110592) * k(4, i) + (253 / 4096) * k(5, i)))
Next i
Else
MsgBox ("error")
End If
If EqNumber = 1 Then 'These are the actual equations
AllODES = x + Y(1)
ElseIf EqNumber = 2 Then
AllODES = x
ElseIf EqNumber = 3 Then
AllODES = Y(3)
ElseIf EqNumber = 4 Then
AllODES = 2 * x
ElseIf EqNumber = 5 Then
AllODES = 2 * Y(2)
ElseIf EqNumber = 6 Then
AllODES = 3 * x
Else
MsgBox ("You entered an Eq Number that was dumb")
End If
End Function
It's possible that it is something really trivial that I missed but this seems to contradict my knowledge of how variables work. So if you understand how the function is able to manipulate a variable from another function in this case, I would appreciate any advice and/or explanation!
Thanks in advance!
the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable
This is normal because you are passing x by reference to the function AllODES and you do change it there. When the keyword ByVal is not explicitly specified in the function/sub prototype, the default passing mechanism is ByRef, that is, by reference.
Public Function AllODES(x As Double, ...
means
Public Function AllODES(ByRef x As Double, ....
We observe that x is manipulated in this function, so the change will appear in the caller. If you want that the change of x does not report back in the caller's scope, pass x by value:
Public Function AllODES(ByVal x As Double, ....
' ^^^^^
Only in this case the x of the caller and the x of the callee will be two different variables.
I'm trying to create a a program that will draw hypotrochoids (spirograph). The program below compiles fine. But when I run it I only get a portion of the drawing.. I'm not sure what I'm doing wrong. I'm fairly new to VB.. Any help is appreciated. Thanks.
Here is the screenshot http://imgur.com/a/KxFWk
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
Dim x As Integer
Dim y As Integer
Dim p As Integer
Dim x1 As Integer
Dim y1 As Integer
Dim x2 As Integer
Dim y2 As Integer
x = 75
y = 15
p = 15
x1 = (x + y) * Math.Cos(0) + p * Math.Cos(0)
y1 = (x + y) * Math.Sin(0) + p * Math.Sin(0)
For t = 0 To 500 Step 0.1
x2 = (x + y) * Math.Cos(t) + p * Math.Cos((x + y) * t / y)
y2 = (x + y) * Math.Sin(t) + p * Math.Sin((x + y) * t / y)
e.Graphics.DrawLine(Pens.Blue, x1, y1, x2, y2)
x1 = x2
y1 = y2
Next
End Sub
End Class
The results of the Sin and Cos calculations result in negative numbers where the parameter is greater than 90 for cos and greater than 180 for sin.
To see the whole image, you need to change the offset for x2 and y2 - see the code below. Alter the number 200 in each of the four lines to a value appropriate for your picturebox
x1 = 200 + CInt((x + y) * Math.Cos(0) + p * Math.Cos(0))
y1 = 200 + CInt((x + y) * Math.Sin(0) + p * Math.Sin(0))
For t As Double = 0 To 500 Step 0.1
x2 = 200 + CInt((x + y) * Math.Cos(t) + p * Math.Cos((x + y) * t / y))
y2 = 200 + CInt((x + y) * Math.Sin(t) + p * Math.Sin((x + y) * t / y))
e.Graphics.DrawLine(Pens.Blue, x1, y1, x2, y2)
x1 = x2
y1 = y2
Next
I'm trying to make a function in Lua or VB based code to
draw / plot an ellipse and also a filled ellipse.
I don't have much knowledge about this math and I can use some help.
I googled everything there is to google about drawing ellipses with code but I can't find a good simple working example that i can code into my Lua / VB code.
here are a few websites i visited but couldn't make the code work or couldn't convert the code to Lua or VB properly...
https://sites.google.com/site/ruslancray/lab/projects/bresenhamscircleellipsedrawingalgorithm/bresenham-s-circle-ellipse-drawing-algorithm
http://groups.csail.mit.edu/graphics/classes/6.837/F98/Lecture6/circle.html
http://www.blitzbasic.com/codearcs/codearcs.php?code=2817
http://hackipedia.org/Algorithms/Graphics/pdf/A%20Fast%20Bresenham%20Type%20Algorithm%20For%20Drawing%20Ellipses%20by%20John%20Kennedy.pdf
https://scratch.mit.edu/projects/49873666/
http://www.sourcecodesworld.com/source/show.asp?ScriptID=112
How do I draw an ellipse with arbitrary orientation pixel by pixel?
Can anyone help me make code that can draw an ellipse and a filled ellipse?
here is some code I tried to convert to Lua from here:
https://gist.github.com/Wollw/3291916
this code has some problems (missing pixels) and I think it's not converted properly but I don't know how to do it otherwise.
function plotEllipseRect(x0, y0, x1, y1)
-- values of diameter
a = math.abs(x1-x0)
b = math.abs(y1-y0)
b1 = 2.5
-- error increment
dx = 4*(1-a)*b*b
dy = 4*(b1+1)*a*a
-- error of 1.step
err = dx+dy+b1*a*a
-- e2 = 0
if (x0 > x1) then -- if called with swapped points
x0 = x1
x1 = x1 + a
end
if (y0 > y1) then -- .. exchange them
y0 = y1
end
-- starting pixel
y0 = y0 + (b+1)/2
y1 = y0-b1
a = a * 8*a
b1 = 8*b*b
repeat
dot(x1, y0) -- I. Quadrant
dot(x0, y0) -- II. Quadrant
dot(x0, y1) -- III. Quadrant
dot(x1, y1) -- IV. Quadrant
e2 = 2*err
if (e2 <= dy) then -- y step
y0 = y0 + 1
y1 = y1 - 1
dy = dy + a
err = err + dy
end
if (e2 >= dx or 2*err > dy) then -- x step
x0 = x0 + 1
x1 = x1 - 1
dx = dx + b1
err = err + dx
end
until (x0 >= x1)
while (y0-y1 < b) do -- too early stop of flat ellipses a=1
dot(x0-1, y0) -- -> finish tip of ellipse
y0 = y0 + 1
dot(x1+1, y0)
dot(x0-1, y1)
y1 = y1 - 1
dot(x1+1, y1)
end
end
[EDIT:]
I almost got it for the filled one!
see the comments in this code below to know what the problem is...
I use EGSL to test this Lua code:
http://www.egsl.retrogamecoding.org//pages/downloads.php
function DrawEllipse(xc,yc,w,h)
local w2 = w * w
local h2 = h * h
local fw2 = 4 * w2
local fh2 = 4 * h2
xc = xc + w
yc = yc + h
local x = 0
local y = h
local s = 2 * h2 + w2 * (1 - h)
while h2 * x <= w2 * y do
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255)) --random color to see changes
if s >= 0 then
s = s + fw2 * (1 - y)
y = y - 1
color(255,0,255)
line(xc + x, yc + y, xc - x, yc + y)
line(xc + x, yc - y, xc - x, yc - y)
end
s = s + h2 * ((4 * x) + 6)
x = x + 1
end
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
line(xc + x, yc + y, xc - x, yc + y) --to prevent the first line to be drawn twice
redraw()
inkey()
s = s + w2 * ((4 * y) + 6)
y = y + 1
while w2 * y < h2 * (x-2) do
line(xc + x, yc + y, xc - x, yc + y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
line(xc + x, yc - y, xc - x, yc - y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
if s >= 0 then
s = s + fh2 * (1 - x)
x = x - 1
end
s = s + w2 * ((4 * y) + 6)
y = y + 1
end
dot(xc + x, yc + y)
dot(xc - x, yc + y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()
inkey()
end
openwindow (70,70,32,"Resize Window")
color(255,255,0)
DrawEllipse(10,10,20,20) --works perfect!
inkey()
cls()
DrawEllipse(10,10,10,20) --problems with last 2 horizontal lines between the pixels!
inkey()
cls()
DrawEllipse(10,10,20,10) --works perfect to!
closewindow()
The following VB works for me, based on the first link provided; the only difference between mine here and the code at your link is I move xc and yc over, since you cannot can't have negative x or y values for the pixels in a bitmap.
Public Shared Function DrawEllipse(ByVal xc As Integer, ByVal yc As Integer, ByVal w As Integer, ByVal h As Integer, ByVal doFill As Boolean) As Drawing.Bitmap
Dim w2 As Integer = w * w
Dim h2 As Integer = h * h
Dim fw2 As Integer = 4 * w2
Dim fh2 As Integer = 4 * h2
// cheat by moving xc and yc so that we can handle quadrants
xc = w
yc = h
Dim bm As New Drawing.Bitmap(w2, h2)
// first half
Dim x As Integer = 0
Dim y As Integer = h
Dim s As Integer = 2 * h2 + w2 * (1 - h)
While h2 * x <= w2 * y
If doFill Then
For i As Integer = -y To y
bm.SetPixel(xc + x, yc + i, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + i, Drawing.Color.Red)
Next
Else
bm.SetPixel(xc + x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + x, yc - y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc - y, Drawing.Color.Red)
End If
If s >= 0 Then
s += fw2 * (1 - y)
y -= 1
End If
s += h2 * ((4 * x) + 6)
x += 1
End While
// second half
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
While w2 * y <= h2 * x
If doFill Then
For i As Integer = -x To x
bm.SetPixel(xc + i, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + i, yc - y, Drawing.Color.Red)
Next
Else
bm.SetPixel(xc + x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + x, yc - y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc - y, Drawing.Color.Red)
End If
If s >= 0 Then
s += fh2 * (1 - x)
x -= 1
End If
s += w2 * ((4 * y) + 6)
y += 1
End While
Return bm
End Function
(Aside: I used // instead of ' for the comments... just for readability here. If you copy to Visual Studio you'll have to fix that)
Ok, I managed to find a solution for the filled ellipse by checking
if the pixel from the second half is gonna be drawn in the x-range of the first half of the ellipse.
function drawellipse(xc, yc, w, h, dofill)
--trouble with the size, 1 pixel to large on x and y to...
w=w/2 --good solution for making it the right size?
h=h/2 --good solution for making it the right size?
local w2 = w * w
local h2 = h * h
local fw2 = 4 * w2
local fh2 = 4 * h2
-- cheat by moving xc and yc so that we can handle quadrants
xc = xc + w
yc = yc + h
-- first half
local x = 0
local y = h
local s = 2 * h2 + w2 * (1 - h)
while h2 * x <= w2 * y do
if dofill then
for i = -y , y do
color(0,255,0)
dot(xc + x, yc + i)
dot(xc - x, yc + i)
--redraw()inkey()
end
else
color(255,0,255)
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
--redraw()inkey()
end
if s >= 0 then
s =s+ fw2 * (1 - y)
y =y- 1
end
s =s+ h2 * ((4 * x) + 6)
x =x+ 1
end
color(255,0,255)
line(xc + x,0,xc - x,0)
test1 = xc + x
test2 = xc - x
print(test1 .. '/' .. test2)
redraw()inkey()
-- second half
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
while w2 * y <= h2 * x do
if dofill then
for i = -x , x do
if not(xc + i > test2 and xc + i < test1) then
color(255,255,0)
dot(xc + i, yc + y)
dot(xc + i, yc - y)
redraw()inkey()
end
end
else
color(0,255,255)
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()inkey()
end
if s >= 0 then
s =s+ fh2 * (1 - x)
x =x- 1
end
s =s+ w2 * ((4 * y) + 6)
y =y+ 1
end
end
In vb.net you have both Graphics.DrawEllipse and Graphics.DrawArc. In Lua you may be able to use Cairo which I know has a arc function.
If you where to make a ellipse in a GraphicsPath in .Net and where to reverse engineer how it is stored in memory, you would find out that it is stored as four bezier curves. I implemented my own graphics library in vb.net once, and that was how I did it. The best resource I found at the time where a implementation in Actionscript, that I unfortunately was unable to locate aswell as that graphics library I was talking about.
TLDR; You should have a look at bezier curves.
A completely different, and very simple take on this, although the ellipse doesn't seem as "pretty" as the other algorithms; this just uses the mathematical definition of an ellipse and, looping over x calculates the y coordinate given x, w, and h.
Public Shared Function DrawEllipse2(ByVal xc As Integer, ByVal yc As Integer, ByVal w As Integer, ByVal h As Integer, ByVal doFill As Boolean) As Drawing.Bitmap
Dim bm As New Drawing.Bitmap(w * w, h * h)
For x As Integer = xc - w To xc + w
Dim y As Integer = CInt((Math.Sqrt(1 - ((x * x) / (w * w)))) * h)
If doFill Then
For j As Integer = -y To y
bm.SetPixel(w + x, h + j, Drawing.Color.Red)
Next
Else
bm.SetPixel(w + x, h + y, Drawing.Color.Red)
bm.SetPixel(w + x, h - y, Drawing.Color.Red)
End If
Next
Return bm
End Function
I am getting a compile error in Excel VBA which says Expected Sub, Function or Property. The function I am using is given below which is trying to copy the rate function in Excel.
Thanks for your help.
Function rate_m(nper As Double, pmt As Double, pv As Double, fv As Double, types As Double, guess As Double) As Variant
Dim y, y0, y1, x0, x1, f, i As Double
Dim FINANCIAL_MAX_ITERATIONS As Double
Dim FINANCIAL_PRECISION As Double
If IsNull(guess) Then guess = 0.01
If IsNull(fv) Then fv = 0
If IsNull(types) Then types = 0
FINANCIAL_MAX_ITERATIONS = 128 'Bet accuracy with 128
FINANCIAL_PRECISION = 0.0000001 '1.0e-8
y , y0, y1, x0, x1, f, i = 0
rate_m = guess
If Abs(rate_m) < FINANCIAL_PRECISION Then
y = pv * (1 + nper * rate_m) + pmt * (1 + rate_m * types) * nper + fv
Else
f = Exp(nper * Log(1 + rate_m))
y = pv * f + pmt * (1 / rate_m + types) * (f - 1) + fv
y0 = pv + pmt * nper + fv
y1 = pv * f + pmt * (1 / rate_m + types) * (f - 1) + fv
End If
'find root by Newton secant method
i , x0 = 0
x1 = rate_m
While Abs(y0 - y1) > FINANCIAL_PRECISION & i < FINANCIAL_MAX_ITERATIONS
rate_m = (y1 * x0 - y0 * x1) / (y1 - y0)
x0 = x1
x1 = rate_m
If Abs(rate_m) < FINANCIAL_PRECISION Then
y = pv * (1 + nper * rate_m) + pmt * (1 + rate_m * types) * nper + fv
Else
f = Exp(nper * Log(1 + rate_m))
y = pv * f + pmt * (1 / rate_m + types) * (f - 1) + fv
End If
y0 = y1
y1 = y
i = i + 1
Wend
End Function
A couple things...
First, you have to assign each variable individually...like this:
y = 0
y0 = 0
y1 = 0
x0 = 0
x1 = 0
f = 0
i = 0
Second, you probably want to DIM your variables all as Double. Unfortunately, this line:
Dim y, y0, y1, x0, x1, f, i As Double
Only declares i as a Double, all the others will be a Variant. You need to declare each one individually, like this:
Dim y As Double
Dim y0 As Double
Dim y1 As Double
Dim x0 As Double
Dim x1 As Double
Dim f As Double
Dim i As Double
Every IF ends with a End If (unless in a single line) and While...loop. You might want to take a look at VBA's syntax:
http://msdn.microsoft.com/en-us/library/office/ee814737(v=office.14).aspx
EDIT: You have to declare variable individually, instead of:
y , y0, y1, x0, x1, f, i = 0
you could do:
y = 0
y0 = 0
y1 = 0
x0 = 0
x1 = 0
f = 0
i = 0