我有以下代码来画一个单位圆
open System
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Math
open System.Drawing
open System.Windows.Forms
let make_point (x:float) (y:float) = (fun bit -> if bit = 0.0 then x else y)
let x_of (point:float->float) = point 0.0
let y_of (point:float->float) = point 1.0
let unit_circle (t:float) =
make_point (sin <| 2.0 * Math.PI * t)
(cos <| 2.0 * Math.PI * t)
let draw_connected (curve:float->float->float) (values: float list)=
let form = new Form(Text = "Curve")
let drawCurve (g:Graphics) =
for t in values do
let p = curve t
g.DrawEllipse(Pens.Red,
float32 (x_of p * 50.0 + (float)form.ClientSize.Width / 2.0),
float32 (y_of p * 50.0 + (float)form.ClientSize.Height / 2.0),
float32 1,
float32 1)
form.Paint.Add(fun e -> drawCurve e.Graphics)
form.Show()
draw_connected unit_circle ([0.0 .. 0.01 .. 1.0])我并不完全满意,因为我必须手动将x和y坐标“缩放”50以使圆可见。有没有办法让F#自动伸缩?
谢谢。
发布于 2010-07-05 01:16:18
我认为代码将一个二维点表示为一个带有3个参数的函数--一个标志,x& y。该标志指示返回x和y中的哪一个。如果标志是布尔型而不是浮点型,对于开始来说(稍微)更有意义。我猜代码是从另一种只有浮点数的语言转换而来的?
下面是一个更容易理解的版本:
open System
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Math
open System.Drawing
open System.Windows.Forms
open System.Threading
type Point = {x : float; y : float}
let unit_circle (angle : float) =
{
x = (sin <| 2.0 * Math.PI * angle)
y = (cos <| 2.0 * Math.PI * angle)
}
let draw_connected (curve : float -> Point) (radius : float) (angles : float list) =
let form = new Form(Text = "Curve")
let drawCurve (gfx : Graphics) =
for angle in angles do
let p = curve angle
gfx.DrawEllipse(Pens.Red,
float32 (p.x * radius + (float)form.ClientSize.Width / 2.0),
float32 (p.y * radius + (float)form.ClientSize.Height / 2.0),
float32 1,
float32 1)
form.Paint.Add (fun pntEvntArgs -> drawCurve pntEvntArgs.Graphics)
form.Show ()
form
let form = draw_connected unit_circle 50.0 ([0.0 .. 0.01 .. 1.0])
while form.Created do
Thread.Sleep (1)
Application.DoEvents ()
done不确定为什么圆呈现为1个像素椭圆的集合。
在任何情况下,正如Tomas所说,要么圆必须缩放,要么坐标系缩放。否则你最终会得到一个1像素的圆圈。
发布于 2010-07-04 23:49:14
我并没有完全理解您的代码,但也许您可以使用可以指定给Graphics对象的scale转换。这会更改Graphics的坐标系,因此您执行的所有绘图(例如,使用DrawEllipse)都会自动缩放-您可以通过某种方式设置缩放,使单位圆显示为半径为50的圆。
ScaleTransfrom方法(请参见MSDN documentation of Graphics instance (代码中的值为g )。发布于 2010-07-05 07:23:23
正如Tomas所说,您可以使用缩放转换。如果要使用小曲线绘制圆,可以使用多个DrawCurve调用:)
为此,我对jon的代码做了一些修改:
System.Drawing.Point类型而不是System.Drawing.Point unit_circle,以便它返回表示坐标x和y的元组。NsplitRepeatEvery方法表示,例如:Seq.splitRepeatEvery 3 { 1 .. 10 }返回seq [seq [1; 2; 3]; seq [3; 4; 5]; seq [5; 6; 7]; seq [7; 8; 9]; seq [9; 10]]
代码如下:
module Seq =
/// Split a sequence into pieces, each n items long
/// repeating elements between start and end of subsequences.
let splitRepeatEvery (count : int) (source : seq<'T>) =
if not (count > 1) then failwith "count must be superior to 1"
seq { use e = source.GetEnumerator()
let hasNext = ref (e.MoveNext())
while !hasNext do
let (block:option<'T>[]) = Array.create count None
for i in 0 .. count - 1 do
do block.[i] <- if !hasNext then Some(e.Current) else None
if (i <> count - 1) then do hasNext := e.MoveNext()
yield seq { yield! block }
|> Seq.filter (fun x -> x.IsSome)
|> Seq.map (function Some(e) -> e | _ -> failwith "" ) }
let unit_circle (angle : float) =
(sin <| 2.0 * Math.PI * angle), (cos <| 2.0 * Math.PI * angle)
let draw_connected curve radius (seqOfAngles : float seq seq) knotsCount =
let form = new Form(Text = "Curve")
let computeBoundingBox points =
let search f acc array =
Array.fold (fun (x,y) (p:Point) -> f p.X x, f p.Y y) acc array
let minX, minY = search min (form.ClientSize.Width, form.ClientSize.Height) points
let maxX, maxY = search max (0,0) points
new Rectangle(minX, minY, abs(minX-maxX), abs(minY-maxY))
let drawCurves (gfx : Graphics) =
// Create a buffer for storing our knots
let buffer = Array.create knotsCount (new Point())
let mutable i = 0
for angles in seqOfAngles do
for angle in angles do
let x, y = curve angle
let X = int(x * radius + (float)form.ClientSize.Width / 2.0)
let Y = int(y * radius + (float)form.ClientSize.Height / 2.0)
let P = new Point(X, Y)
buffer.[i] <- P
i <- i + 1
let knots = buffer.[0..(i-1)]
// Draw spline only if we have one or more knots
if knots.Length <> 1 then
gfx.DrawCurve(Pens.Red, knots)
// For debug: compute BBox of an array of points and draw it
let debugRect = computeBoundingBox knots
gfx.DrawRectangle(Pens.Black, debugRect)
// Don't forget to reset position in buffer between each spline draw call
i <- 0
form.Paint.Add (fun pntEvntArgs -> drawCurves pntEvntArgs.Graphics)
form.Show ()
form
// Define constants
let STEP = 0.050
let N = 4
// Define a new sequence of sequence of angles
let s = {0.0 .. STEP .. 1.0} |> Seq.splitRepeatEvery N
let form = draw_connected unit_circle 120.0 s N
// For debug: print sequence of sequence of angles
s |> Seq.iter (fun s -> Seq.iter (fun x -> printf "%f " x) s; printfn "")
while form.Created do
Thread.Sleep (1)
Application.DoEvents ()
done您可以使用不同值的N (样条线的结数)和STEP (但请注意,应选择STEP,以便1.0f是STEP的倍数或浮点数,以便最后一个序列的最后一个元素足够接近1.0f,否则最后一个样条线将无法连接到第一个!)。瞧!
alt text http://img818.imageshack.us/img818/9765/circles3.png
https://stackoverflow.com/questions/3175198
复制相似问题