aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2023-01-15 22:40:41 -0330
committerSam Anthony <sam@samanthony.xyz>2023-01-15 22:40:41 -0330
commitb6247a8372eb18a19c35a924316941d6c1e585d2 (patch)
treeeb7c1db8ff7f4524f3ac093d6f445ee52c747302
parent585fbf852c1e76470df42ebe99ede62440ce19d9 (diff)
downloadvolute-b6247a8372eb18a19c35a924316941d6c1e585d2.zip
volume
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml8
-rw-r--r--Makefile17
-rw-r--r--go.mod21
-rw-r--r--go.sum39
-rw-r--r--main.go154
-rw-r--r--mass/mass.go47
-rw-r--r--pressure/pressure.go48
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs3
-rw-r--r--src/volume.rs53
-rw-r--r--temperature/temperature.go71
-rw-r--r--ui.go372
-rw-r--r--util/util.go31
-rw-r--r--volume/volume.go44
16 files changed, 84 insertions, 836 deletions
diff --git a/.gitignore b/.gitignore
index 72e62a2..ea8c4bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-/volute
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..66f37b7
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "volute"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..00b728c
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "volute"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/Makefile b/Makefile
index d92c5fa..1250725 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,11 @@
-build: tidy format
- go build
-run: tidy format
- go run .
+build: test format
+ cargo build --workspace
-format:
- gofmt -s -w .
+doc: test format
+ cargo doc --workspace --open
+
+test: format
+ cargo test --workspace
-tidy:
- go mod tidy
+format:
+ cargo fmt --all
diff --git a/go.mod b/go.mod
deleted file mode 100644
index ca90545..0000000
--- a/go.mod
+++ /dev/null
@@ -1,21 +0,0 @@
-module github.com/sam-anthony/volute
-
-go 1.18
-
-require (
- github.com/AllenDang/giu v0.6.2
- github.com/BurntSushi/toml v1.1.0
-)
-
-require (
- github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8 // indirect
- github.com/AllenDang/imgui-go v1.12.1-0.20220322114136-499bbf6a42ad // indirect
- github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 // indirect
- github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
- github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220320163800-277f93cfa958 // indirect
- github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
- github.com/sahilm/fuzzy v0.1.0 // indirect
- golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
- golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect
- gopkg.in/eapache/queue.v1 v1.1.0 // indirect
-)
diff --git a/go.sum b/go.sum
deleted file mode 100644
index 074e02e..0000000
--- a/go.sum
+++ /dev/null
@@ -1,39 +0,0 @@
-github.com/AllenDang/giu v0.6.2 h1:CFIHSQxDqEFNsNnTO9LXBVZ8zlInV71H3M6V3BNagmI=
-github.com/AllenDang/giu v0.6.2/go.mod h1:9hCQh0l0wbBzOqe9cr02EB9EsNOy9AwFIjG4xVsR6TI=
-github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8 h1:dKZMqib/yUDoCFigmz2agG8geZ/e3iRq304/KJXqKyw=
-github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8/go.mod h1:b4uuDd0s6KRIPa84cEEchdQ9ICh7K0OryZHbSzMca9k=
-github.com/AllenDang/imgui-go v1.12.1-0.20220322114136-499bbf6a42ad h1:Kr961C2uEEAklK+jBRiZVnQH0AgS7o6pXrIgUTUUGiM=
-github.com/AllenDang/imgui-go v1.12.1-0.20220322114136-499bbf6a42ad/go.mod h1:kuPs9RWleaUuK7D49bE6HPxyRA36Lp4ICKGp+5OnnbY=
-github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
-github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
-github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
-github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
-github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220320163800-277f93cfa958 h1:TL70PMkdPCt9cRhKTqsm+giRpgrd0IGEj763nNr2VFY=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220320163800-277f93cfa958/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
-github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
-github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
-golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4=
-golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
-golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
-golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc=
-gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
deleted file mode 100644
index 377d4ac..0000000
--- a/main.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package main
-
-import (
- "fmt"
- g "github.com/AllenDang/giu"
- "image"
- "image/draw"
- _ "image/jpeg"
- "os"
-
- "github.com/sam-anthony/volute/compressor"
- "github.com/sam-anthony/volute/mass"
- "github.com/sam-anthony/volute/pressure"
- "github.com/sam-anthony/volute/temperature"
- "github.com/sam-anthony/volute/util"
- "github.com/sam-anthony/volute/volume"
-)
-
-const (
- gasConstant = 8.314472
- airMolarMass = 0.0289647 // kg/mol
-)
-
-// numPoints is the number of datapoints on the compressor map.
-var numPoints = 1
-
-var (
- displacement = 2000 * volume.CubicCentimetre
- // volumeUnitIndex is used to index volume.UnitStrings().
- volumeUnitIndex = volume.DefaultUnitIndex
-
- engineSpeed = []int32{2000}
-
- volumetricEfficiency = []int32{80}
-
- intakeAirTemperature = []temperature.Temperature{{25, temperature.Celcius}}
- // temperatureUnitIndex is used to index temperature.UnitStrings().
- temperatureUnitIndex = temperature.DefaultUnitIndex
-
- manifoldPressure = []pressure.Pressure{pressure.Atmospheric()}
- // pressureUnitIndex is used to index pressure.UnitStrings().
- pressureUnitIndex = pressure.DefaultUnitIndex
-)
-
-var pressureRatio []float32
-
-func pressureRatioAt(point int) float32 {
- u := pressure.Pascal
- m := manifoldPressure[point] / u
- a := pressure.Atmospheric() / u
- return float32(m / a)
-}
-func init() {
- pressureRatio = append(pressureRatio, pressureRatioAt(0))
-}
-
-var (
- engineMassFlowRate []mass.FlowRate
- // selectedMassFlowRateUnit is used to index mass.FlowRateUnitStrings().
- selectedMassFlowRateUnit = mass.DefaultFlowRateUnitIndex
-)
-
-func massFlowRateAt(point int) mass.FlowRate {
- rpm := float32(engineSpeed[point])
- disp := float32(displacement / volume.CubicMetre)
- ve := float32(volumetricEfficiency[point]) / 100.0
- cubicMetresPerMin := (rpm / 2.0) * disp * ve
-
- iat, err := intakeAirTemperature[point].AsUnit(temperature.Kelvin)
- util.Check(err)
- pres := manifoldPressure[point] / pressure.Pascal
- molsPerMin := (float32(pres) * cubicMetresPerMin) / (gasConstant * iat)
-
- kgPerMin := molsPerMin * airMolarMass
-
- mfr := mass.FlowRate(kgPerMin/60.0) * mass.KilogramsPerSecond
- return mfr
-}
-func init() {
- engineMassFlowRate = append(engineMassFlowRate, massFlowRateAt(0))
-}
-
-func loop() {
- g.SingleWindow().Layout(
- engineDisplacementRow(),
- g.Table().
- Size(g.Auto, 190).
- Rows(
- engineSpeedRow(),
- volumetricEfficiencyRow(),
- intakeAirTemperatureRow(),
- manifoldPressureRow(),
- pressureRatioRow(),
- massFlowRateRow(),
- duplicateDeleteRow(),
- ).
- Columns(
- columns()...,
- ),
- selectCompressor(),
- g.Custom(compressorWidget),
- )
-}
-
-var (
- compressorImage *image.RGBA
- compressorTexture *g.Texture
- selectedCompressor compressor.Compressor
-)
-
-func setCompressor(c compressor.Compressor) {
- f, err := os.Open(c.FileName)
- util.Check(err)
- defer f.Close()
-
- j, _, err := image.Decode(f)
- util.Check(err)
-
- b := j.Bounds()
- m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
- draw.Draw(m, m.Bounds(), j, b.Min, draw.Src)
-
- selectedCompressor = c
- compressorImage = m
-
- go updateCompImg()
-}
-
-func init() {
- manufacturer := "garrett"
- series := "g"
- model := "25-660"
- c, ok := compressor.Compressors()[manufacturer][series][model]
- if !ok {
- fmt.Printf("compressor.Compressors()[\"%s\"][\"%s\"][\"%s\"] does not exist.\n",
- manufacturer, series, model,
- )
- os.Exit(1)
- }
-
- setCompressor(c)
-}
-
-func main() {
- wnd := g.NewMasterWindow("volute", 400, 200, 0)
-
- go updateCompImg()
- m := <-updatedCompImg
- g.EnqueueNewTextureFromRgba(m, func(tex *g.Texture) {
- compressorTexture = tex
- })
-
- wnd.Run(loop)
-}
diff --git a/mass/mass.go b/mass/mass.go
deleted file mode 100644
index 46ce33e..0000000
--- a/mass/mass.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package mass
-
-import (
- "errors"
- "fmt"
-)
-
-type Mass float32
-
-const (
- Gram Mass = 1
- Kilogram Mass = 1_000
- Pound Mass = 453.5924
-)
-
-type FlowRate float32
-
-const (
- KilogramsPerSecond FlowRate = 1
- PoundsPerMinute FlowRate = 0.007_559_872_833
-)
-
-// FlowRateUnitStrings returns a slice of strings, each representing a
-// flowRate unit.
-// This is necessary because giu.Combo only works with strings.
-func FlowRateUnitStrings() []string {
- return []string{"kg/s", "lb/min"}
-}
-
-const (
- DefaultFlowRateUnit FlowRate = KilogramsPerSecond
- // DefaultFlowRateUnitIndex is used to index FlowRateUnitStrings()
- DefaultFlowRateUnitIndex int32 = 0 // kg/s
-)
-
-func FlowRateUnitFromString(s string) (FlowRate, error) {
- // Each case corresponds to a value in FlowRateUnitStrings().
- switch s {
- case "kg/s":
- return KilogramsPerSecond, nil
- case "lb/min":
- return PoundsPerMinute, nil
- default:
- return *new(FlowRate), errors.New(
- fmt.Sprintf("invalid mass flow rate unit: '%s'", s))
- }
-}
diff --git a/pressure/pressure.go b/pressure/pressure.go
deleted file mode 100644
index da1ab1e..0000000
--- a/pressure/pressure.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package pressure
-
-import (
- "errors"
- "fmt"
-)
-
-type Pressure float32
-
-const (
- Pascal Pressure = 1
- Kilopascal Pressure = 1_000
- Bar Pressure = 100_000
- PoundsPerSquareInch Pressure = 6_894.757
-)
-
-// UnitStrings returns a slice of strings, each representing a
-// unit.
-// This is necessary because giu.Combo only works with strings.
-func UnitStrings() []string {
- return []string{"Pa", "kPa", "bar", "psi"}
-}
-
-const (
- DefaultUnit Pressure = Kilopascal
- // DefaultUnitIndex is used to index UnitStrings().
- DefaultUnitIndex int32 = 1 // kPa
-)
-
-func UnitFromString(s string) (Pressure, error) {
- // Each case corresponds to a value in UnitStrings().
- switch s {
- case "Pa":
- return Pascal, nil
- case "kPa":
- return Kilopascal, nil
- case "bar":
- return Bar, nil
- case "psi":
- return PoundsPerSquareInch, nil
- default:
- return *new(Pressure), errors.New(fmt.Sprintf("invalid unit: '%s'", s))
- }
-}
-
-func Atmospheric() Pressure {
- return 1 * Bar
-}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..0e68f71
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,3 @@
+mod volume;
+
+type Percent = u8;
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/volume.rs b/src/volume.rs
new file mode 100644
index 0000000..ea78938
--- /dev/null
+++ b/src/volume.rs
@@ -0,0 +1,53 @@
+use std::ops::Mul;
+
+trait Volume {
+ /// Returns the volume in SI units (cubic metres).
+ fn si(self) -> CubicMetre;
+}
+
+#[derive(Debug, PartialEq)]
+struct CubicMetre(f64);
+
+#[derive(Debug, PartialEq)]
+struct Litre(f64);
+
+impl Volume for Litre {
+ fn si(self) -> CubicMetre {
+ CubicMetre(self.0 * 10_f64.powf(-3.))
+ }
+}
+
+impl From<i32> for Litre {
+ fn from(value: i32) -> Self {
+ Self(value as f64)
+ }
+}
+
+impl From<CubicMetre> for Litre {
+ fn from(value: CubicMetre) -> Self {
+ Self(value.0 * 10_f64.powf(3.))
+ }
+}
+
+impl Mul<f64> for Litre {
+ type Output = Self;
+
+ fn mul(self, rhs: f64) -> Self::Output {
+ Self(self.0 * rhs)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::volume::{CubicMetre, Litre, Volume};
+
+ #[test]
+ fn litre_to_cubic_metre() {
+ assert_eq!(Litre(1000.).si(), CubicMetre(1.))
+ }
+
+ #[test]
+ fn cubic_metre_to_litre() {
+ assert_eq!(Litre::from(CubicMetre(1.)), Litre(1000.))
+ }
+}
diff --git a/temperature/temperature.go b/temperature/temperature.go
deleted file mode 100644
index 2a135df..0000000
--- a/temperature/temperature.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package temperature
-
-import (
- "errors"
- "fmt"
-)
-
-type unit int
-
-const (
- Celcius unit = iota
- Kelvin
- Fahrenheit
-)
-
-// UnitStrings returns a slice of strings, each representing a
-// unit.
-// This is necessary because giu.Combo only works with strings.
-func UnitStrings() []string {
- return []string{"°C", "°K", "°F"}
-}
-
-const (
- DefaultUnit unit = Celcius
- // DefaultUnitIndex is used to index UnitStrings().
- DefaultUnitIndex int32 = 0 // celcius
-)
-
-func UnitFromString(s string) (unit, error) {
- // Each case corresponds to a value in UnitStrings().
- switch s {
- case "°C":
- return Celcius, nil
- case "°K":
- return Kelvin, nil
- case "°F":
- return Fahrenheit, nil
- default:
- return *new(unit), errors.New(fmt.Sprintf("invalid unit: '%s'", s))
- }
-}
-
-type Temperature struct {
- Val float32
- Unit unit
-}
-
-func (t Temperature) AsUnit(u unit) (float32, error) {
- // Convert to celcius
- var c float32
- switch t.Unit {
- case Celcius:
- c = t.Val
- case Kelvin:
- c = t.Val - 272.15
- case Fahrenheit:
- c = (t.Val - 32.0) * (5.0 / 9.0)
- }
-
- // Convert to desired unit
- switch u {
- case Celcius:
- return c, nil
- case Kelvin:
- return c + 272.15, nil
- case Fahrenheit:
- return c*(9.0/5.0) + 32.0, nil
- default:
- return 0, errors.New(fmt.Sprintf("invalid unit: '%v'", u))
- }
-}
diff --git a/ui.go b/ui.go
deleted file mode 100644
index c116b8e..0000000
--- a/ui.go
+++ /dev/null
@@ -1,372 +0,0 @@
-package main
-
-import (
- "fmt"
- g "github.com/AllenDang/giu"
- "image"
- "image/color"
- "image/draw"
- "strconv"
-
- "github.com/sam-anthony/volute/compressor"
- "github.com/sam-anthony/volute/mass"
- "github.com/sam-anthony/volute/pressure"
- "github.com/sam-anthony/volute/temperature"
- "github.com/sam-anthony/volute/util"
- "github.com/sam-anthony/volute/volume"
-)
-
-func red() color.RGBA {
- return color.RGBA{255, 0, 0, 255}
-}
-
-func engineDisplacementRow() *g.RowWidget {
- s := volume.UnitStrings()[volumeUnitIndex]
- unit, err := volume.UnitFromString(s)
- util.Check(err)
- engDisp := float32(displacement / unit)
- return g.Row(
- g.Label("Engine Displacement"),
- g.InputFloat(&engDisp).Format("%.2f").OnChange(func() {
- displacement = volume.Volume(engDisp) * unit
- for i := 0; i < numPoints; i++ {
- engineMassFlowRate[i] = massFlowRateAt(i)
- go updateCompImg()
- }
- }),
- g.Combo(
- "",
- volume.UnitStrings()[volumeUnitIndex],
- volume.UnitStrings(),
- &volumeUnitIndex,
- ),
- )
-}
-
-func engineSpeedRow() *g.TableRowWidget {
- widgets := []g.Widget{
- g.Label("Engine Speed"),
- g.Label("rpm"),
- }
- for i := 0; i < numPoints; i++ {
- i := i
- widgets = append(
- widgets,
- g.InputInt(&engineSpeed[i]).OnChange(func() {
- engineMassFlowRate[i] = massFlowRateAt(i)
- go updateCompImg()
- }),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func volumetricEfficiencyRow() *g.TableRowWidget {
- widgets := []g.Widget{
- g.Label("Volumetric Efficiency"),
- g.Label("%"),
- }
- for i := 0; i < numPoints; i++ {
- i := i
- widgets = append(
- widgets,
- g.InputInt(&volumetricEfficiency[i]).OnChange(func() {
- engineMassFlowRate[i] = massFlowRateAt(i)
- go updateCompImg()
- }),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func intakeAirTemperatureRow() *g.TableRowWidget {
- widgets := []g.Widget{
- g.Label("Intake Air Temperature"),
- g.Combo(
- "",
- temperature.UnitStrings()[temperatureUnitIndex],
- temperature.UnitStrings(),
- &temperatureUnitIndex,
- ).OnChange(func() {
- s := temperature.UnitStrings()[temperatureUnitIndex]
- u, err := temperature.UnitFromString(s)
- util.Check(err)
-
- for i := range intakeAirTemperature {
- t, err := intakeAirTemperature[i].AsUnit(u)
- util.Check(err)
- intakeAirTemperature[i] = temperature.Temperature{t, u}
- }
- }),
- }
- for i := 0; i < numPoints; i++ {
- i := i
- widgets = append(
- widgets,
- g.InputFloat(&intakeAirTemperature[i].Val).
- Format("%.2f").
- OnChange(func() {
- engineMassFlowRate[i] = massFlowRateAt(i)
- go updateCompImg()
- }),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func manifoldPressureRow() *g.TableRowWidget {
- s := pressure.UnitStrings()[pressureUnitIndex]
- unit, err := pressure.UnitFromString(s)
- util.Check(err)
-
- widgets := []g.Widget{
- g.Label("Manifold Absolute Pressure"),
- g.Combo(
- "",
- pressure.UnitStrings()[pressureUnitIndex],
- pressure.UnitStrings(),
- &pressureUnitIndex,
- ),
- }
- for i := 0; i < numPoints; i++ {
- i := i
- manPres := float32(manifoldPressure[i] / unit)
- widgets = append(
- widgets,
- g.InputFloat(&manPres).Format("%.2f").
- OnChange(func() {
- manifoldPressure[i] = pressure.Pressure(manPres * float32(unit))
- pressureRatio[i] = pressureRatioAt(i)
- engineMassFlowRate[i] = massFlowRateAt(i)
- go updateCompImg()
- }),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func pressureRatioRow() *g.TableRowWidget {
- widgets := []g.Widget{
- g.Label("Pressure Ratio"),
- g.Label(""),
- }
- for i := 0; i < numPoints; i++ {
- pr := strconv.FormatFloat(float64(pressureRatio[i]), 'f', 1, 32)
- widgets = append(
- widgets,
- g.Label(pr),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func massFlowRateRow() *g.TableRowWidget {
- s := mass.FlowRateUnitStrings()[selectedMassFlowRateUnit]
- mfrUnit, err := mass.FlowRateUnitFromString(s)
- util.Check(err)
-
- widgets := []g.Widget{
- g.Label("Mass Flow Rate"),
- g.Combo(
- "",
- mass.FlowRateUnitStrings()[selectedMassFlowRateUnit],
- mass.FlowRateUnitStrings(),
- &selectedMassFlowRateUnit,
- ),
- }
- for i := 0; i < numPoints; i++ {
- mfr := strconv.FormatFloat(
- float64(engineMassFlowRate[i]/mfrUnit),
- 'f',
- 3,
- 32,
- )
- widgets = append(
- widgets,
- g.Label(mfr),
- )
- }
- return g.TableRow(widgets...)
-}
-
-func duplicateDeleteRow() *g.TableRowWidget {
- widgets := []g.Widget{g.Label(""), g.Label("")}
- for i := 0; i < numPoints; i++ {
- i := i
- widgets = append(widgets, g.Row(
- g.Button("Duplicate").OnClick(func() {
- numPoints++
- engineSpeed = util.Insert(
- engineSpeed,
- engineSpeed[i],
- i,
- )
- volumetricEfficiency = util.Insert(
- volumetricEfficiency,
- volumetricEfficiency[i],
- i,
- )
- intakeAirTemperature = util.Insert(
- intakeAirTemperature,
- intakeAirTemperature[i],
- i,
- )
- manifoldPressure = util.Insert(
- manifoldPressure,
- manifoldPressure[i],
- i,
- )
- pressureRatio = util.Insert(
- pressureRatio,
- pressureRatio[i],
- i,
- )
- engineMassFlowRate = util.Insert(
- engineMassFlowRate,
- engineMassFlowRate[i],
- i,
- )
- go updateCompImg()
- }),
- g.Button("Delete").OnClick(func() {
- if numPoints < 2 {
- return
- }
- numPoints--
- engineSpeed = util.Remove(engineSpeed, i)
- volumetricEfficiency = util.Remove(volumetricEfficiency, i)
- intakeAirTemperature = util.Remove(intakeAirTemperature, i)
- manifoldPressure = util.Remove(manifoldPressure, i)
- pressureRatio = util.Remove(pressureRatio, i)
- engineMassFlowRate = util.Remove(engineMassFlowRate, i)
- go updateCompImg()
- }),
- ))
- }
- return g.TableRow(widgets...)
-}
-
-func columns() []*g.TableColumnWidget {
- widgets := []*g.TableColumnWidget{
- g.TableColumn("Parameter"),
- g.TableColumn("Unit"),
- }
- for i := 0; i < numPoints; i++ {
- widgets = append(
- widgets,
- g.TableColumn(fmt.Sprintf("Point %d", i+1)),
- )
- }
- return widgets
-}
-
-var compressorTree []g.Widget
-
-func init() {
- compressors := compressor.Compressors()
- for man := range compressors {
- man := man // Manufacturer
- var serNodes []g.Widget
- for ser := range compressors[man] {
- ser := ser // Series
- var modNodes []g.Widget
- for mod, c := range compressors[man][ser] {
- mod := mod // Model
- c := c // Compressor
- modNodes = append(
- modNodes,
- g.Selectable(mod).OnClick(func() {
- go setCompressor(c)
- }),
- )
- }
- serNodes = append(
- serNodes,
- g.TreeNode(ser).Layout(modNodes...),
- )
- }
- manNode := g.TreeNode(man).Layout(serNodes...)
- compressorTree = append(compressorTree, manNode)
- }
-}
-
-func selectCompressor() g.Widget {
- return g.ComboCustom("Compressor", selectedCompressor.Name).
- Layout(compressorTree...)
-}
-
-var updatedCompImg = make(chan image.Image)
-
-func updateCompImg() {
- // Copy compressorImage
- b := compressorImage.Bounds()
- m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
- draw.Draw(m, m.Bounds(), compressorImage, b.Min, draw.Src)
-
- for i := 0; i < numPoints; i++ {
- min := selectedCompressor.MinX
- max := selectedCompressor.MaxX
-
- unit := mass.KilogramsPerSecond
- mfr := engineMassFlowRate[i] / unit
- maxMfr := selectedCompressor.MaxFlow / unit
-
- x := min + int(float32(max-min)*float32(mfr/maxMfr))
-
- min = selectedCompressor.MinY
- max = selectedCompressor.MaxY
-
- pr := pressureRatio[i]
- maxPr := selectedCompressor.MaxPR
-
- y := min - int(float32((min-max))*((pr-1.0)/(maxPr-1.0)))
-
- ps := m.Bounds().Dx() / 100 // Point size
-
- draw.Draw(m,
- image.Rect(x-ps/2, y-ps/2, x+ps/2, y+ps/2),
- &image.Uniform{red()},
- image.ZP,
- draw.Src,
- )
- }
-
- updatedCompImg <- m
-}
-
-func compressorWidget() {
- select {
- case m := <-updatedCompImg:
- g.EnqueueNewTextureFromRgba(m, func(tex *g.Texture) {
- compressorTexture = tex
- })
- default:
- }
-
- canvas := g.GetCanvas()
- if compressorTexture != nil {
- winWidth, winHeight := g.GetAvailableRegion()
-
- bounds := compressorImage.Bounds()
- imWidth := float32(bounds.Dx())
- imHeight := float32(bounds.Dy())
-
- var ratio, xratio, yratio float32
- xratio = winWidth / imWidth
- yratio = winHeight / imHeight
- if xratio < yratio {
- ratio = xratio
- } else {
- ratio = yratio
- }
-
- x := int(imWidth * ratio)
- y := int(imHeight * ratio)
-
- canvas.AddImage(
- compressorTexture,
- image.Pt(0, 250),
- image.Pt(x, y),
- )
- }
-}
diff --git a/util/util.go b/util/util.go
deleted file mode 100644
index 5812ee1..0000000
--- a/util/util.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package util
-
-import (
- "fmt"
- "os"
-
- "github.com/sam-anthony/volute/mass"
- "github.com/sam-anthony/volute/pressure"
- "github.com/sam-anthony/volute/temperature"
-)
-
-func Check(err error) {
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-}
-
-func Insert[T int32 | float32 | temperature.Temperature | pressure.Pressure | mass.FlowRate](slice []T, elem T, i int) []T {
- return append(
- slice[:i],
- append(
- []T{elem},
- slice[i:]...,
- )...,
- )
-}
-
-func Remove[T int32 | float32 | temperature.Temperature | pressure.Pressure | mass.FlowRate](slice []T, i int) []T {
- return append(slice[:i], slice[i+1:]...)
-}
diff --git a/volume/volume.go b/volume/volume.go
deleted file mode 100644
index 48330df..0000000
--- a/volume/volume.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package volume
-
-import (
- "errors"
- "fmt"
-)
-
-type Volume float32
-
-const (
- CubicCentimetre Volume = 1
- Litre Volume = 1_000
- CubicMetre Volume = 1_000_000
- CubicInch Volume = 16.38706
-)
-
-// UnitStrings returns a slice of strings, each representing a
-// unit.
-// This is necessary because giu.Combo only works with strings.
-func UnitStrings() []string {
- return []string{"cc", "L", "m³", "in³"}
-}
-
-const (
- DefaultUnit Volume = CubicCentimetre
- // DefaulUnitIndex is used to index UnitStrings().
- DefaultUnitIndex int32 = 0 // cc
-)
-
-func UnitFromString(s string) (Volume, error) {
- // Each case corresponds to a value in UnitStrings().
- switch s {
- case "cc":
- return CubicCentimetre, nil
- case "L":
- return Litre, nil
- case "m³":
- return CubicMetre, nil
- case "in³":
- return CubicInch, nil
- default:
- return *new(Volume), errors.New(fmt.Sprintf("invalid volume unit: '%s'", s))
- }
-}