Add a DPI calculator to help to find the correct image resolution.
[master-thesis.git] / Parasitemia / ParasitemiaUI / DPICalculator.fs
diff --git a/Parasitemia/ParasitemiaUI/DPICalculator.fs b/Parasitemia/ParasitemiaUI/DPICalculator.fs
new file mode 100644 (file)
index 0000000..dbd7251
--- /dev/null
@@ -0,0 +1,75 @@
+module ParasitemiaUI.DPICalculator
+
+open System
+open System.Windows
+open System.Windows.Media
+open System.Windows.Markup
+open System.Windows.Shapes
+open System.Windows.Controls
+open System.Diagnostics
+
+open ParasitemiaCore.UnitsOfMeasure
+open ParasitemiaCore.Types
+
+type SensorSize = {
+    w: float<mm>
+    h: float<mm>
+    txt: string } with
+    override this.ToString () =
+        sprintf "%g mm × %g mm%s" this.w this.h (if this.txt = "" then "" else " (" + this.txt + ")")
+
+let showWindow (parent: Window) : int option =
+    let win = Views.DPICalculatorWindow()
+    win.Root.Owner <- parent
+    win.Root.Left <- parent.Left + parent.ActualWidth / 2. - win.Root.Width / 2.
+    win.Root.Top <- parent.Top + parent.ActualHeight / 2. - win.Root.Height / 2.
+
+    let sensorSizes = [
+        { w = 5.76<mm>; h = 4.29<mm>; txt = "1/2.5″" }
+        { w = 7.6<mm>;  h = 5.7<mm>;  txt = "1/1.7″" }
+        { w = 8.6<mm>;  h = 6.6<mm>;  txt = "2/3″" }
+        { w = 13.2<mm>; h = 8.8<mm>;  txt = "1″" }
+        { w = 17.3<mm>; h = 13.<mm>;  txt = "" }
+        { w = 20.7<mm>; h = 13.8<mm>; txt = "" }
+        { w = 22.2<mm>; h = 14.8<mm>; txt = "" }
+        { w = 23.6<mm>; h = 15.7<mm>; txt = "" }
+        { w = 28.7<mm>; h = 19.<mm>;  txt = "" }
+        { w = 28.7<mm>; h = 19.<mm>;  txt = "" } ]
+
+    for size in sensorSizes do
+        win.cmbSensorSize.Items.Add(size) |> ignore
+    win.cmbSensorSize.SelectedIndex <- 0
+
+    let resolution (w_p: float<px>) (w_mm: float<mm>) (zoom: float) : float<ppi> =
+        w_p * zoom / mmToInch w_mm
+
+    let updateCurrentResolution () =
+        let { w = w; h = h } = win.cmbSensorSize.SelectedValue :?> SensorSize
+        let ratio = h / w
+
+        let parseDouble txt errorMess = match Double.TryParse(txt) with true, value -> Success value | _ -> Fail errorMess
+
+        match result
+            { let! sensorResolution = parseDouble win.txtSensorResolution.Text "The sensor resolution is not valid"
+              let! zoom = parseDouble win.txtZoom.Text "The zoom is not valid"
+              let wPixel = 1.<px> * sqrt (sensorResolution * 1e6 / ratio)
+              return! Success (float <| resolution wPixel w zoom) } with
+        | Success res -> win.txtImageResolution.Text <- (int (res / 1000.) * 1000).ToString()
+        | Fail mess -> win.txtImageResolution.Text <- mess
+
+    win.butCancel.Click.AddHandler(fun obj args -> win.Root.DialogResult <- Nullable<bool>(false); win.Root.Close())
+    win.butOK.Click.AddHandler(fun obj args -> win.Root.DialogResult <- Nullable<bool>(true); win.Root.Close())
+
+    win.cmbSensorSize.SelectionChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
+    win.txtSensorResolution.TextChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
+    win.txtZoom.TextChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
+
+    let result = win.Root.ShowDialog()
+    if result.HasValue && result.Value
+    then
+        match Int32.TryParse win.txtImageResolution.Text with
+        | true, res -> Some res
+        | _ -> None
+    else
+        None
+