Skip to content

Instantly share code, notes, and snippets.

@bohdanszymanik
Created May 29, 2012 10:36
Show Gist options
  • Select an option

  • Save bohdanszymanik/2824858 to your computer and use it in GitHub Desktop.

Select an option

Save bohdanszymanik/2824858 to your computer and use it in GitHub Desktop.
MichLet file generator from Kayak Foundry export
open System
open System.IO
let cSs = File.ReadAllLines(@"C:\Extras\kfoundry1.6.4\520x50a.txt")
(*
Raw form data exported from kfoundry with baseline at the waterline looks like this:
Form Position, X (mm), Y (mm)
...
Form at 52 cm, 60, 39.3333
Form at 52 cm, 54.6667, 25
Form at 52 cm, 49, 11.6667
Form at 52 cm, 43, 0
Form at 52 cm, 36.6667, -10
Form at 52 cm, 33.3333, -14.6667
Form at 52 cm, 29.6667, -18.6667
Form at 52 cm, 28, -20.6667
...
Michlet only takes shape data for the below the waterline - so we only want the negative portion.
Michlet uses constant vertical intervals... so we need to treat y like x and interpolate a value for x
*)
let rawForms =
cSs
|> Seq.skip 1
|> Seq.filter (fun l -> not(l.StartsWith("Cockpit") ) )
|> Seq.filter (fun l -> not(l.StartsWith("Bow") ) )
|> Seq.filter (fun l -> not(l.StartsWith("Stern") ) )
|> Seq.filter ( String.IsNullOrEmpty >> not )
let parseRawForm (s:string) =
let values = s.Replace("0,", "0.").Replace(",", "").Split(' ' )
// and change to metres
(float values.[2])/100., (float values.[4])/1000., (float values.[5])/1000.
let forms =
rawForms
|> Seq.map parseRawForm
// z is Form Postion, the x and y are reversed from the file header
|> Seq.filter ( fun (_,_,y) -> y <= 0.)
|> Seq.groupBy ( fun (z, _, _) -> z)
|> Seq.map (fun (z,zxy) -> (z, zxy |> Seq.map (fun (z,x,y) -> (-1. * y, x) ) |> Seq.sortBy (fun (y, _) -> y ) ) ) // changed to a function of height
let inline interpolateY xys x =
let rec getX1Y1X2Y2' xys x =
//printfn "list: %A" xys
match xys with
| (_, _)::[] -> 0.
| [] -> 0. // if not found then michlet expects a 0 - also, that typed 0 is negating the benefit of the inline...
| (x1, y1)::t ->
let (x2, y2) = t.Head
if (x1 <= x) && (x < x2) then
//printfn "%A adjacent points: %A" x (x1, y1, x2, y2)
y1 + ( (y2 - y1) / (x2 - x1) * ( x - x1) )
else
getX1Y1X2Y2' t x
getX1Y1X2Y2' xys x
let _,maxX = forms |> Seq.map (fun (z, xys) -> z, xys |> Seq.maxBy (fun (x,_) -> x) |> fun (x,_) -> x ) |> Seq.maxBy (fun (z, x) -> x)
let divs = 10.
let xVals = [0. .. maxX/divs .. maxX ]
// for each station
// iterate through xs getting the intepolated ys - straight lines good enough after all chines can be discontinuous
// write out ys - one line per station
forms
|> Seq.iter ( fun (z, xys) ->
let interpolatedValues =
xVals
|> Seq.map (fun xv -> sprintf "%.4f" (interpolateY (Seq.toList xys) xv ) )
|> Seq.toList
|> List.rev
//printfn "%A - %A - %s" z (Seq.toList xys) ( String.Join(",", interpolatedValues) )
printfn "%s" ( String.Join(",", interpolatedValues) )
)
@bohdanszymanik

Copy link
Copy Markdown
Author

OK, gives the right interpolated offsets now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment