Friday, 23 December 2016
Friday, 9 December 2016
Plots have I laid, inductions dangerous
Time to do some F#.
First I want a function that will tabulate a function f.
f is to be a function of two floats x and y returning a float. The table is to operate over an x-axis range and a y-axis range, each described by a tuple of floats. So here is a sample function of the type I mean:
let testfun (x:float) (y:float) =
let r = sqrt ((x * x) + (y * y))
if r < 2.0
then
if r < 1.0
then 7.0
else 4.0
else
0.0
My tabulate function is to return a two-dimensional array of floats. Here it is:
let tabulate funct (xrange : (float*float)) (yrange : (float*float)) : float[,]=
let x0 = fst xrange
let dx = (snd xrange - fst xrange) / 50.0
let y0 = fst yrange
let dy = (snd yrange - fst yrange) / 50.0
Array2D.init 51 51 (fun i j -> funct (x0+(float i * dx)) (y0+(float j * dy)))
The function Array2D.init takes the size of the two dimensions of the array and a function that will populate each element in the array, given the indices I and j. I'm breaking my ranges into 50 parts so I want 51 elements in each direction.
Now to project this table of values as in isometric type sheet: create a new array of the same size but here each element is a tuple of values p and q that represent screen coordinates. p works down from the top left and q works across. So p and q depend on the index i and j, and p also depends on the value of the array that I've passed through. I've scaled the value by 10.0 pixels quite arbitrarily. The grid is drawn by going right 5 pixels per cell and either up or down by 3.5 pixels for p and q axis, so:
let project (valueTable : float [,]) : (float * float)[,] =
Array2D.init 51 51
(fun (i:int) (j:int) ->
let p = (float i * 5.0) + (float j * 5.0) + 20.0
let q = (float i * 3.5) - (float j * 3.5) + 300.0 - (valueTable.[i,j] * 10.0)
(p,q))
Right, now I want to plot out the projected table as an SVG element. After some research it looks like this is the thing to do:
let plot (a:(float * float)[,]) : unit =
use file = System.IO.File.CreateText("plotout.svg")
fprintfn file """<svg xmlns="http://www.w3.org/2000/svg" version="1.1">"""
for j in 0..49 do
for i in 0..49 do
fprintf file """<polygon fill="#FFFFFF" """
fprintf file """stroke="#000000" stroke-width="1" points="""
fprintfn file "\"%.2f,%.2f %.2f,%.2f %.2f,%.2f %.2f,%.2f\" "
(fst a.[i,j]) (snd a.[i,j])
(fst a.[i,j+1]) (snd a.[i,j+1])
(fst a.[i+1,j+1]) (snd a.[i+1,j+1])
(fst a.[i+1,j]) (snd a.[i+1,j])
fprintfn file """/>"""
fprintfn file """</svg>"""
The SVG document contains a polygon element which has a fill colour and a stroke width and colour and a list of points - each point is represented by a two floats separated by a comma. For each element i, j I'm drawing a four sided shape with the points from i,j - i+1,j - i+1,j+1 - i,j+1.
So finally to tabulate and plot my test function in the range -3 to 3:
let main () =
(tabulate testfun (-3.0, 3.0) (-3.0, 3.0)) |> project |> plot
Then you can open the resulting file in the browser:
This looks a bit rough round the back of the raised area. Really I need to plot starting from the cells that are furthest away and then working forward, so get the hidden ones properly hidden. Still, nice first try.
First I want a function that will tabulate a function f.
f is to be a function of two floats x and y returning a float. The table is to operate over an x-axis range and a y-axis range, each described by a tuple of floats. So here is a sample function of the type I mean:
let testfun (x:float) (y:float) =
let r = sqrt ((x * x) + (y * y))
if r < 2.0
then
if r < 1.0
then 7.0
else 4.0
else
0.0
My tabulate function is to return a two-dimensional array of floats. Here it is:
let tabulate funct (xrange : (float*float)) (yrange : (float*float)) : float[,]=
let x0 = fst xrange
let dx = (snd xrange - fst xrange) / 50.0
let y0 = fst yrange
let dy = (snd yrange - fst yrange) / 50.0
Array2D.init 51 51 (fun i j -> funct (x0+(float i * dx)) (y0+(float j * dy)))
The function Array2D.init takes the size of the two dimensions of the array and a function that will populate each element in the array, given the indices I and j. I'm breaking my ranges into 50 parts so I want 51 elements in each direction.
Now to project this table of values as in isometric type sheet: create a new array of the same size but here each element is a tuple of values p and q that represent screen coordinates. p works down from the top left and q works across. So p and q depend on the index i and j, and p also depends on the value of the array that I've passed through. I've scaled the value by 10.0 pixels quite arbitrarily. The grid is drawn by going right 5 pixels per cell and either up or down by 3.5 pixels for p and q axis, so:
let project (valueTable : float [,]) : (float * float)[,] =
Array2D.init 51 51
(fun (i:int) (j:int) ->
let p = (float i * 5.0) + (float j * 5.0) + 20.0
let q = (float i * 3.5) - (float j * 3.5) + 300.0 - (valueTable.[i,j] * 10.0)
(p,q))
Right, now I want to plot out the projected table as an SVG element. After some research it looks like this is the thing to do:
let plot (a:(float * float)[,]) : unit =
use file = System.IO.File.CreateText("plotout.svg")
fprintfn file """<svg xmlns="http://www.w3.org/2000/svg" version="1.1">"""
for j in 0..49 do
for i in 0..49 do
fprintf file """<polygon fill="#FFFFFF" """
fprintf file """stroke="#000000" stroke-width="1" points="""
fprintfn file "\"%.2f,%.2f %.2f,%.2f %.2f,%.2f %.2f,%.2f\" "
(fst a.[i,j]) (snd a.[i,j])
(fst a.[i,j+1]) (snd a.[i,j+1])
(fst a.[i+1,j+1]) (snd a.[i+1,j+1])
(fst a.[i+1,j]) (snd a.[i+1,j])
fprintfn file """/>"""
fprintfn file """</svg>"""
The SVG document contains a polygon element which has a fill colour and a stroke width and colour and a list of points - each point is represented by a two floats separated by a comma. For each element i, j I'm drawing a four sided shape with the points from i,j - i+1,j - i+1,j+1 - i,j+1.
So finally to tabulate and plot my test function in the range -3 to 3:
let main () =
(tabulate testfun (-3.0, 3.0) (-3.0, 3.0)) |> project |> plot
Then you can open the resulting file in the browser:
This looks a bit rough round the back of the raised area. Really I need to plot starting from the cells that are furthest away and then working forward, so get the hidden ones properly hidden. Still, nice first try.
Subscribe to:
Posts (Atom)