diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2022-05-27 22:39:03 -0230 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2022-05-27 22:39:03 -0230 |
| commit | 31605150d3e10b08dad2086005c64664f5648a51 (patch) | |
| tree | 7419f90e7b30d3de52595f25852e9ef87094718c | |
| parent | 585fbf852c1e76470df42ebe99ede62440ce19d9 (diff) | |
| download | volute-31605150d3e10b08dad2086005c64664f5648a51.zip | |
prepare to switch ui library
| -rw-r--r-- | app.go | 128 | ||||
| -rw-r--r-- | compressor/compressor.go | 24 | ||||
| -rw-r--r-- | go.mod | 20 | ||||
| -rw-r--r-- | go.sum | 37 | ||||
| -rw-r--r-- | main.go | 143 | ||||
| -rw-r--r-- | mass/mass.go | 21 | ||||
| -rw-r--r-- | pressure/pressure.go | 38 | ||||
| -rw-r--r-- | temperature/temperature.go | 47 | ||||
| -rw-r--r-- | ui.go | 372 | ||||
| -rw-r--r-- | util/util.go | 31 | ||||
| -rw-r--r-- | volume/volume.go | 34 |
11 files changed, 167 insertions, 728 deletions
@@ -0,0 +1,128 @@ +package main + +import ( + "errors" + "fmt" + "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/volume" +) + +type App struct { + Displacement volume.Volume + VolumeUnit volume.Volume + + Rpm []int + + Ve []float32 + + Iat []temperature.Temperature + TemperatureUnit temperature.Unit + + Map []pressure.Pressure + PressureUnit pressure.Pressure + + Pr []float32 + + Flow []mass.FlowRate + FlowUnit mass.FlowRate + + Comp compressor.Compressor + CompImg image.Image +} + +func NewApp() (App, error) { + a := App{ + Displacement: 2 * volume.Litre, + VolumeUnit: volume.Litre, + + Rpm: []int{2000}, + + Ve: []float32{0.80}, + + Iat: []temperature.Temperature{temperature.New( + 30.0, temperature.Celcius)}, + TemperatureUnit: temperature.Celcius, + + Map: []pressure.Pressure{pressure.Bar}, + PressureUnit: pressure.Kilopascal, + + Pr: []float32{0.0}, + + Flow: []mass.FlowRate{mass.FlowRate(0.0)}, + FlowUnit: mass.KilogramPerSecond, + } + + manufacturer, series, model := "borgwarner", "efr", "6258" + c, ok := compressor.Compressors[manufacturer][series][model] + if !ok { + return App{}, errors.New(fmt.Sprintf( + "Invalid compressor: %s %s %s", + manufacturer, series, model, + )) + } + if err := a.SetCompressor(c); err != nil { + return App{}, err + } + + a.SetPr() + a.SetFlow() + + return a, nil +} + +func (a *App) SetCompressor(c compressor.Compressor) error { + f, err := os.Open(c.FileName) + if err != nil { + return err + } + defer f.Close() + + j, _, err := image.Decode(f) + if err != nil { + return 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) + + a.Comp = c + a.CompImg = m + + return nil +} + +func (a *App) SetPr() { + for i := 0; i < len(a.Rpm); i++ { + a.Pr[i] = float32(a.Map[i] / pressure.Atmospheric) + } +} + +func (a *App) SetFlow() error { + for i := 0; i < len(a.Rpm); i++ { + rpm := a.Rpm[i] + disp := a.Displacement.As(volume.CubicMetre) + ve := a.Ve[i] + cubicMetresPerMin := float32(rpm/2) * disp * ve + + iat, err := a.Iat[i].As(temperature.Kelvin) + if err != nil { + return err + } + manPres := a.Map[i].As(pressure.Pascal) + molsPerMin := (manPres * cubicMetresPerMin) / (gasConstant * iat) + + kgPerMin := molsPerMin * airMolarMass + + a.Flow[i] = mass.FlowRate(kgPerMin/60.0) * mass.KilogramPerSecond + } + return nil +} diff --git a/compressor/compressor.go b/compressor/compressor.go index efe792e..0b9af90 100644 --- a/compressor/compressor.go +++ b/compressor/compressor.go @@ -1,12 +1,13 @@ package compressor import ( + "fmt" "github.com/BurntSushi/toml" "io/fs" + "os" fp "path/filepath" "github.com/sam-anthony/volute/mass" - "github.com/sam-anthony/volute/util" ) const root = "compressor/res/" @@ -32,7 +33,7 @@ type Compressor struct { } // [manufacturer][series][model] -var compressors = make(map[string]map[string]map[string]Compressor) +var Compressors = make(map[string]map[string]map[string]Compressor) func init() { // Walk root, looking for .toml files describing a compressor. @@ -57,13 +58,13 @@ func init() { man = fp.Clean(man) // Clean trailing slash var exists bool - _, exists = compressors[man] + _, exists = Compressors[man] if !exists { - compressors[man] = make(map[string]map[string]Compressor) + Compressors[man] = make(map[string]map[string]Compressor) } - _, exists = compressors[man][ser] + _, exists = Compressors[man][ser] if !exists { - compressors[man][ser] = make(map[string]Compressor) + Compressors[man][ser] = make(map[string]Compressor) } tomlFile := fp.Join(root, path) @@ -95,13 +96,12 @@ func init() { } c.MaxFlow = mass.FlowRate(flow.FlowVal) * u - compressors[man][ser][mod] = c + Compressors[man][ser][mod] = c return nil }) - util.Check(err) -} - -func Compressors() map[string]map[string]map[string]Compressor { - return compressors + if err != nil { + fmt.Println(err) + os.Exit(1) + } } @@ -1,21 +1,5 @@ module github.com/sam-anthony/volute -go 1.18 +go 1.17 -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 -) +require github.com/BurntSushi/toml v1.1.0 @@ -1,39 +1,2 @@ -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= @@ -2,18 +2,7 @@ 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 ( @@ -21,134 +10,10 @@ const ( 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, - ) +func main() { + _, err := NewApp() + if err != nil { + fmt.Println(err) 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 index 46ce33e..c66e94d 100644 --- a/mass/mass.go +++ b/mass/mass.go @@ -16,30 +16,17 @@ const ( 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 + KilogramPerSecond FlowRate = 1 + PoundPerMinute FlowRate = 0.007_559_872_833 ) func FlowRateUnitFromString(s string) (FlowRate, error) { // Each case corresponds to a value in FlowRateUnitStrings(). switch s { case "kg/s": - return KilogramsPerSecond, nil + return KilogramPerSecond, nil case "lb/min": - return PoundsPerMinute, nil + return PoundPerMinute, 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 index da1ab1e..820a8cf 100644 --- a/pressure/pressure.go +++ b/pressure/pressure.go @@ -1,10 +1,5 @@ package pressure -import ( - "errors" - "fmt" -) - type Pressure float32 const ( @@ -14,35 +9,8 @@ const ( 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 (p Pressure) As(unit Pressure) float32 { + return float32(p / unit) } -func Atmospheric() Pressure { - return 1 * Bar -} +const Atmospheric = Bar diff --git a/temperature/temperature.go b/temperature/temperature.go index 2a135df..6588ee6 100644 --- a/temperature/temperature.go +++ b/temperature/temperature.go @@ -5,56 +5,33 @@ import ( "fmt" ) -type unit int +type Unit int const ( - Celcius unit = iota + 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 } -type Temperature struct { - Val float32 - Unit unit +func New(i float32, u Unit) Temperature { + return Temperature{i, u} } -func (t Temperature) AsUnit(u unit) (float32, error) { +func (t Temperature) As(u Unit) (float32, error) { // Convert to celcius var c float32 - switch t.Unit { + switch t.unit { case Celcius: - c = t.Val + c = t.val case Kelvin: - c = t.Val - 272.15 + c = t.val - 272.15 case Fahrenheit: - c = (t.Val - 32.0) * (5.0 / 9.0) + c = (t.val - 32.0) * (5.0 / 9.0) } // Convert to desired unit @@ -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 index 48330df..e634b5d 100644 --- a/volume/volume.go +++ b/volume/volume.go @@ -1,10 +1,5 @@ package volume -import ( - "errors" - "fmt" -) - type Volume float32 const ( @@ -14,31 +9,6 @@ const ( 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)) - } +func (v Volume) As(unit Volume) float32 { + return float32(v / unit) } |