sqrt-based filled ellipse pixel drawing function - vb.net

I'm trying to make a function in Lua or VB based code to draw / plot 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 in VB or Lua for a filled one.
On a previous post on this site I did get an answer about how to draw a normal ellipse but nothing came up for a filled one, that's why i make a new topic for a filled one.
Here are a few websites I visited but I can't find a way to make a filled ellipse without redrawing already drawed pixels...
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
Here is the code I have for a normal ellipse (thanks to "Johnny Strings" for the VB version):
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))
if s >= 0 then
s = s + fw2 * (1 - y)
y = y - 1
end
s = s + h2 * ((4 * x) + 6)
x = x + 1
end
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
while w2 * y <= h2 * x 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))
if s >= 0 then
s = s + fh2 * (1 - x)
x = x - 1
end
s = s + w2 * ((4 * y) + 6)
y = y + 1
end
end

Here's what I came up with for my CPU renderer in the past. It's very efficient and very simple too.
It relies on the mathematical definition of the ellipse, so the ellipse is drawn centered at x,y and has the width and height defined from the center, not from the other side.
The draw point function draws a pixel at the x by y point specified.
local function drawaxisalignedellipse(x,y,w,h)
--n Defines the bounds of the horizontal lines which fill the ellipse.
local n=w
local w2=w*w
local h2=h*h
--draws the center horizontal line.
for i=x-w,x+w do
drawpoint(i,y)
end
for j=1,h do
--The current top and bottom rows.
local ra,rb=y+j,y-j
--This loop removes 1 from n until it is within the shape
while w2*(h2-j*j)<h2*n*n and n~=0 do n=n-1 end
--Draws horizontal line from -n to n across the ellipse
for i=x-n,x+n do
drawpoint(i,ra)
drawpoint(i,rb)
end
end
end

Related

How to determine whether base point of secp256k1 (G) lies on curve?

I am doing some research on elliptic curves. If I understood correctly there is a G base point that was set as a large prime point on the curve. As an example, I pick the infamous secp256k1 curve with G.
G = (0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
I wanted to test if a G lies on the curve. So I written a small piece of python code.
# y^2 = x^3 + 7
def curveEq(G):
x, y = G
left = (y * y)
right = (x * x * x) + 7
print("L: " + str(left))
print("R: " + str(right))
but I get left != right. What am I missing?
The point for me was as Mr. Polk said in the comment - the secpk1 curve contains in definition mod p. I totally misunderstood that this curve is defined with mod p (I was thinking that curve is just an equation without the mod and that mod was used only in point doubling and adding). After correcting my code with modulus everything works and I am able to verify the point.
# y^2 = x^3 + 7 mod P for secp256k1
P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
def curveEqMod(p):
x, y = p
x = int(x)
y = int(y)
left = (y * y) % P
right = ((x * x * x) + 7) % P
print("L: " + str(left))
print("R: " + str(right))
Also as Mr. kelalaka said there is a similar example: Proof that user public key corresponds the curve equation (secp256r1)

Rotate camera axis by mouse - Open GL

So I have successfully managed to rotate, move, etc with keyboard keys my camera through my environment. I do this by multiplying my view matrix by rotational matrices:
ViewMatrix = ViewMatrix X Z_Rotational_Matrix(yaw_increment) X X_Rotational_Matrix(pitch_increment) X Y_Rotational_Matrix(roll_increment)
I can do so with inputs of yaw, pitch, and roll. So I am next trying to do these rotations with the mouse. I believe I have all of the heavy lifting done and should just need to supply the yaw, and pitch to my rotational matrix. Correct me if this is the wrong thought process.
I can capture the mouse world coordinate when I click and when I move so supposedly it should just be math based on initial_mouse_click_coordinates and current_mouse_click_coordinates. My thought is to project two vectors, one from the initial_mouse_click_coordinate and the other from current_mouse_click_coordinates. Both vectors are parallel to the vector created from my camera location and my camera lookat point. Then I can calculate the XY planar angle and the XZ planar angle. Once these are determined I pass these as the yaw and pitch to my rotational matrices.
Determining two angles between my two lines:
The problem I have is that these values appear to be really small so on the screen nothing really happens. Am I going about this the wrong way completely?
If this is the right method to try, am I messing up on my math somewhere?
'we have initial_mouse_world_coordinates and mouse_world_coordinates. These are the points on the x screen in world coordinates.
'Two lines must be constructed going through these points, parallel with our lookat vector.
'The two angles between these two vectors are the angles to use on our lookat vector
'X = X0 + Rx*T
'Y = Y0 + Ry*T
'Z = Z0 + Rz*T
'therefore T = (Z-Z0)/Rz
'at Z = 0: T = -Z0/Rz
Dim t As Decimal = -initial_mouse_world_coordinates.Z / cam.lookat.Z
Dim y As Decimal = initial_mouse_world_coordinates.Y + (cam.lookat.Y * t)
Dim x As Decimal = initial_mouse_world_coordinates.X + (cam.lookat.X * t)
Dim z As Decimal = 0
'new point = x,y,z => translate to new vector
Dim startline As New Vector3(initial_mouse_world_coordinates.X - x, initial_mouse_world_coordinates.Y - y, initial_mouse_world_coordinates.Z - z)
t = -mouse_world_coordinates.Z / cam.lookat.Z
y = mouse_world_coordinates.Y + (cam.lookat.Y * t)
x = mouse_world_coordinates.X + (cam.lookat.X * t)
z = 0
Dim endline As New Vector3(mouse_world_coordinates.X - x, mouse_world_coordinates.Y - y, mouse_world_coordinates.Z - z)
'now simply find the two angles between these two lines
'cos(theida) = ((Ai,Ak) ⋅ (Bi,Bk)) / (||Ai,Ak|| * ||Bi,Bk||)
Try
theida = Acos(((startline.X * endline.X) + (startline.Z * endline.Z)) / (Sqrt(startline.X ^ 2 + startline.Z ^ 2) * Sqrt(endline.X ^ 2 + endline.Z ^ 2)))
Catch
theida = 0
End Try
Try
phi = Acos(((startline.X * endline.X) + (startline.Y * endline.Y)) / (Sqrt(startline.X ^ 2 + startline.Y ^ 2) * Sqrt(endline.X ^ 2 + endline.Y ^ 2)))
Catch
phi = 0
End Try
theida = theida * (180 / PI)
phi = phi * (180 / PI)
Any help or guidance is appreciated. Again I may be going at this with the wrong idea in the first place.

Scaling up a tile-map smoothly?

I'm making a mod for some game, and I'm using a base tile-map that I want to be scaleable to a bigger map. However, when I just use a "nearest-neighbour" kind of scaling the map will have hard square edges. I want to prevent this.
So I have a tilemap, something like this:
- - X -
- X X X
X X X X
X X - -
With my current scaling I get something like:
- - - - X X - -
- - - - X X - -
- - X X X X X X
- - X X X X X X
X X X X X X X X
X X X X X X X X
X X X X - - - -
X X X X - - - -
Which has some hard edges as you can see. I would like them to be more smooth:
- - - - X X - -
- - - X X X X -
- - X X X X X X
- X X X X X X X
X X X X X X X X
X X X X X X X X
X X X X X X - -
X X X X - - - -
I wasn't sure what to call this, so my search didn't turn up much.
How can I do something like this?
Note that there are several different kinds of tiles, and no in-between tile types.
So I played around a bit myself, and found something that seems to work quite well.
Here's what I do (Lua):
--First get the cells you're between (x and y are real numbers, not ints)
local top = math.floor(y)
local bottom = (top + 1)
local left = math.floor(x)
local right = (left + 1)
--Then calculate weights. These are basically 1 - the distance. The distance is scaled to be between 0 and 1.
local sqrt2 = math.sqrt(2)
local w_top_left = 1 - math.sqrt((top - y)*(top - y) + (left - x)*(left - x)) / sqrt2
local w_top_right = 1 - math.sqrt((top - y)*(top - y) + (right - x)*(right - x)) / sqrt2
local w_bottom_left = 1 - math.sqrt((bottom - y)*(bottom - y) + (left - x)*(left - x)) / sqrt2
local w_bottom_right = 1 - math.sqrt((bottom - y)*(bottom - y) + (right - x)*(right - x)) / sqrt2
--Then square these weights, which makes it look better
w_top_left = w_top_left * w_top_left
w_top_right = w_top_right * w_top_right
w_bottom_left = w_bottom_left * w_bottom_left
w_bottom_right = w_bottom_right * w_bottom_right
--Now get the codes (or types) of the surrounding tiles
local c_top_left = decompressed_map_data[top % height][left % width]
local c_top_right = decompressed_map_data[top % height][right % width]
local c_bottom_left = decompressed_map_data[bottom % height][left % width]
local c_bottom_right = decompressed_map_data[bottom % height][right % width]
--Next calculate total weights for codes
-- So add together the weights of surrounding tiles if they have the same type
local totals = {}
add_to_total(totals, w_top_left, c_top_left) --see below for this helper func
add_to_total(totals, w_top_right, c_top_right)
add_to_total(totals, w_bottom_left, c_bottom_left)
add_to_total(totals, w_bottom_right, c_bottom_right)
--Lastly choose final code, which is the tile-type with the highest weight
local code = nil
local weight = 0
for _, total in pairs(totals) do
if total.weight > weight then
code = total.code
weight = total.weight
end
end
return terrain_codes[code]
-- Helper function
local function add_to_total(totals, weight, code)
if totals[code] == nil then
totals[code] = {code=code, weight=weight}
else
totals[code].weight = totals[code].weight + weight
end
end
And voila. This select an exact tile-type for any x/y value even when they are not integers, thus making it possible to scale your grid. I'm not sure if there are better ways, but it works and looks good. In the end I also added some random number to the weights, to make the edges a little less straight which looks better in Factorio when scaling very high.

VBA CODE CORRECTION

I am using VBA for the first time. I started with a very basic code using Runga Kutta Method. I am not able to run it. Can I know where I am going wrong? Can you also post some solutions for this type of differential equation solvers?
Option Explicit
Dim K1 As Double
Dim K2 As Double
Dim K3 As Double
Dim K4 As Double
Dim y As Double
Dim x As Double
Dim dx As Double
Dim x0 As Integer
Dim y0 As Integer
Function f(x, y) As Double
f = 0.5 * x - 0.5 * y
End Function
Sub RK(x, y, dx)
Dim i As Integer
Dim ynew As Double
dx = 0.5
x0 = 0
y0 = 1
K1 = dx * f(x, y)
K2 = dx * f(x + dx / 2, y + K1 / 2)
K3 = dx * f(x + dx / 2, y + K2 / 2)
K4 = dx * f(x + dx, y + K3)
RK = y + ((K1 + 2 * (K2 + K3 + K4)) / 6)
For i = 0 To 6
ynew = RK(x, y, dx)
x = x + dx
y = ynew
Next i
For j = 1 To 6
Call RK(x, y, dx, ynew)
ActiveCell.Offset(i - 1, 1).Value = x
ActiveCell.Offset(i - 1, 2).Value = y
x = x + dx
y = ynew
Next
End Sub
You need to execute the RK procedure and give it the starting values of x, y and dx.
To do this from within the VBE (Visual Basic Editor) open the Immediate window. If it's not visible press Ctrl+G and it should appear at the bottom of the VBE.
In the Immediate window type something like RK 1, 3, 2 and the results will appear in the two columns to the right of the active cell and take up 6 rows.
If you want the procedure to execute on the press of a button, or when a value is updated you'll need to add an extra bit of code for that.
Edit:
Just noticed these lines - RK = y + ((K1 + 2 * (K2 + K3 + K4)) / 6) and ynew = RK(x, y, dx).
The RK procedure won't return a value and you can't set it as a value either.
This link may help explain it: http://what-when-how.com/excel-vba/vba-sub-and-function-procedures/

Draw an ellipse sqrt-based function

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