diff --git a/cmd/flightlog2kml/main.go b/cmd/flightlog2kml/main.go index 2d245b5..2efe4d0 100644 --- a/cmd/flightlog2kml/main.go +++ b/cmd/flightlog2kml/main.go @@ -28,7 +28,13 @@ func main() { dump_log := os.Getenv("DUMP_LOG") != "" files, _ := options.ParseCLI(getVersion) if len(files) == 0 { - options.Usage() + if len(options.Config.Mission) > 0 { + outms := kmlgen.GenKmlName(options.Config.Mission, options.Config.MissionIndex) + kmlgen.GenerateMissionOnly(outms) + show_output(outms) + } else { + options.Usage() + } os.Exit(1) } @@ -92,14 +98,7 @@ func main() { if !res { fmt.Fprintf(os.Stderr, "*** skipping KML/Z for log with no valid geospatial data\n") } else { - if outfn != "" { - rp, err := realpath.Realpath(outfn) - if err != nil || rp == "" { - fmt.Printf("%-8.8s : <%s> <%s>\n", "RealPath", rp, err) - rp = outfn - } - fmt.Printf("%-8.8s : %s\n", "Output", rp) - } + show_output(outfn) } fmt.Println() } @@ -109,3 +108,14 @@ func main() { } } } + +func show_output(outfn string) { + if outfn != "" { + rp, err := realpath.Realpath(outfn) + if err != nil || rp == "" { + fmt.Printf("%-8.8s : <%s> <%s>\n", "RealPath", rp, err) + rp = outfn + } + fmt.Printf("%-8.8s : %s\n", "Output", rp) + } +} diff --git a/cmd/mission2kml/main.go b/cmd/mission2kml/main.go index 8cde87e..d25b94b 100644 --- a/cmd/mission2kml/main.go +++ b/cmd/mission2kml/main.go @@ -3,7 +3,9 @@ package main import ( "flag" "fmt" + types "github.com/stronnag/bbl2kml/pkg/api/types" mission "github.com/stronnag/bbl2kml/pkg/mission" + kml "github.com/twpayne/go-kml" "log" "os" "path/filepath" @@ -68,7 +70,7 @@ Examples: flag.BoolVar(&dms, "dms", dms, "Show positions as DMS (vice decimal degrees)") flag.StringVar(&homepos, "home", homepos, "Use home location") - flag.IntVar(&idx, "mission-index", 1, "Mission Index") + flag.IntVar(&idx, "mission-index", 0, "Mission Index") flag.Parse() files := flag.Args() if len(files) == 0 { @@ -99,18 +101,44 @@ Examples: } } } + err := generateKML(files[0], idx, dms, home) + if err != nil { + log.Fatalf("mission2kmk: %+v\n", err) + } +} - _, m, err := mission.Read_Mission_File_Index(files[0], idx) - if m != nil && err == nil { - if len(home) == 0 { - if m.Metadata.Homey != 0 && m.Metadata.Homex != 0 { - home = append(home, m.Metadata.Homey, m.Metadata.Homex) +func generateKML(mfile string, idx int, dms bool, homep []float64) error { + kname := filepath.Base(mfile) + d := kml.Folder(kml.Name(kname)).Add(kml.Open(true)) + _, mm, err := mission.Read_Mission_File(mfile) + if err == nil { + isviz := true + for nm, _ := range mm.Segment { + nmx := nm + 1 + if idx == 0 || nmx == idx { + ms := mm.To_mission(nmx) + if len(homep) == 0 { + if ms.Metadata.Homey != 0 && ms.Metadata.Homex != 0 { + homep = append(homep, ms.Metadata.Homey, ms.Metadata.Homex) + } + } + var hpos types.HomeRec + if len(homep) == 2 { + hpos.HomeLat = homep[0] + hpos.HomeLon = homep[1] + hpos.Flags = types.HOME_ARM + } + if len(homep) > 2 { + hpos.HomeAlt = homep[2] + hpos.Flags |= types.HOME_ALT + } + mf := ms.To_kml(hpos, dms, false, nmx, isviz) + d.Add(mf) + isviz = false } } - - m.Dump(dms, home...) - } - if err != nil { - log.Fatalf("mission2kmk: %+v\n", err) + k := kml.KML(d) + k.WriteIndent(os.Stdout, "", " ") } + return err } diff --git a/meson.build b/meson.build index 556945b..f55bdde 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('flightlog2kml', version : '1.0.3-rc1') +project('flightlog2kml', version : '1.0.4-rc1') meson.add_install_script('meson/post_install.py') version = get_option('version') commit = get_option('commit') diff --git a/pkg/kmlgen/kmlbuilder.go b/pkg/kmlgen/kmlbuilder.go index a46d458..1a777fe 100644 --- a/pkg/kmlgen/kmlbuilder.go +++ b/pkg/kmlgen/kmlbuilder.go @@ -13,6 +13,7 @@ import ( "image/color" "log" "os" + "path/filepath" "strings" ) @@ -470,6 +471,39 @@ func add_ground_track(rec types.LogRec) kml.Element { return f } +func GenerateMissionOnly(outfn string) { + kname := filepath.Base(options.Config.Mission) + d := kml.Folder(kml.Name(kname)).Add(kml.Open(true)) + _, mm, err := mission.Read_Mission_File(options.Config.Mission) + if err == nil { + isviz := true + for nm, _ := range mm.Segment { + nmx := nm + 1 + if options.Config.MissionIndex == 0 || nmx == options.Config.MissionIndex { + ms := mm.To_mission(nmx) + if geo.Getfrobnication() { + for k, mi := range ms.MissionItems { + if mi.Is_GeoPoint() { + ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, _ = geo.Frobnicate_move(ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, 0) + } + } + } + var hpos types.HomeRec + + if ms.Metadata.Homey != 0 && ms.Metadata.Homex != 0 { + hpos.HomeLat = ms.Metadata.Homey + hpos.HomeLon = ms.Metadata.Homex + hpos.Flags = types.HOME_ARM + } + mf := ms.To_kml(hpos, options.Config.Dms, false, nmx, isviz) + d.Add(mf) + isviz = false + } + } + write_kml(outfn, d) + } +} + func GenerateKML(hpos types.HomeRec, rec types.LogRec, outfn string, meta types.FlightMeta, smap types.MapRec) { @@ -485,20 +519,42 @@ func GenerateKML(hpos types.HomeRec, rec types.LogRec, outfn string, d.Add(add_ground_track(rec)) if len(options.Config.Mission) > 0 { - _, ms, err := mission.Read_Mission_File_Index(options.Config.Mission, options.Config.MissionIndex) + _, mm, err := mission.Read_Mission_File(options.Config.Mission) if err == nil { - if geo.Getfrobnication() { - for k, mi := range ms.MissionItems { - if mi.Is_GeoPoint() { - ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, _ = geo.Frobnicate_move(ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, 0) + isviz := true + for nm, _ := range mm.Segment { + nmx := nm + 1 + if options.Config.MissionIndex == 0 || nmx == options.Config.MissionIndex { + ms := mm.To_mission(nmx) + if geo.Getfrobnication() { + for k, mi := range ms.MissionItems { + if mi.Is_GeoPoint() { + ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, _ = geo.Frobnicate_move(ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, 0) + } + } } + mf := ms.To_kml(hpos, options.Config.Dms, false, nmx, isviz) + d.Add(mf) + isviz = false } } - mf := ms.To_kml(hpos, options.Config.Dms, false) - d.Add(mf) - } else { - fmt.Fprintf(os.Stderr, "* Failed to read mission file %s\n", options.Config.Mission) } + /** + _, ms, err := mission.Read_Mission_File_Index(options.Config.Mission, options.Config.MissionIndex) + if err == nil { + if geo.Getfrobnication() { + for k, mi := range ms.MissionItems { + if mi.Is_GeoPoint() { + ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, _ = geo.Frobnicate_move(ms.MissionItems[k].Lat, ms.MissionItems[k].Lon, 0) + } + } + } + mf := ms.To_kml(hpos, options.Config.Dms, false) + d.Add(mf) + } else { + fmt.Fprintf(os.Stderr, "* Failed to read mission file %s\n", options.Config.Mission) + } + **/ } e := kml.ExtendedData(kml.Data(kml.Name("Log"), kml.Value(meta.LogName()))) @@ -558,7 +614,10 @@ func GenerateKML(hpos types.HomeRec, rec types.LogRec, outfn string, d.Add(f1) } } + write_kml(outfn, d) +} +func write_kml(outfn string, d *kml.CompoundElement) { var err error if strings.HasSuffix(outfn, ".kmz") { z := kmz.NewKMZ(d) diff --git a/pkg/mission/mission-read.go b/pkg/mission/mission-read.go index 89e96cc..fb2c425 100644 --- a/pkg/mission/mission-read.go +++ b/pkg/mission/mission-read.go @@ -6,7 +6,7 @@ import ( "os" ) -func (mm *MultiMission) to_mission(mi int) *Mission { +func (mm *MultiMission) To_mission(mi int) *Mission { m := &Mission{} if mi > len(mm.Segment) { mi = len(mm.Segment) @@ -20,7 +20,7 @@ func (mm *MultiMission) to_mission(mi int) *Mission { return m } -func Read_Mission_File_Index(path string, idx int) (string, *Mission, error) { +func Read_Mission_File(path string) (string, *MultiMission, error) { var dat []byte r, err := os.Open(path) if err == nil { @@ -33,9 +33,17 @@ func Read_Mission_File_Index(path string, idx int) (string, *Mission, error) { mtype, mm := handle_mission_data(dat, path) if mm == nil { fmt.Fprintf(os.Stderr, "Note: Mission fails verification %s\n", mtype) - return mtype, nil, nil } - m := mm.to_mission(idx) + return mtype, mm, nil + } +} + +func Read_Mission_File_Index(path string, idx int) (string, *Mission, error) { + mtype, mm, err := Read_Mission_File(path) + if err == nil { + m := mm.To_mission(idx) return mtype, m, nil + } else { + return mtype, nil, err } } diff --git a/pkg/mission/mission.go b/pkg/mission/mission.go index 3a11caa..578467d 100644 --- a/pkg/mission/mission.go +++ b/pkg/mission/mission.go @@ -220,7 +220,7 @@ func (m *Mission) Dump(dms bool, homep ...float64) { hpos.HomeAlt = homep[2] hpos.Flags |= types.HOME_ALT } - k := kml.KML(m.To_kml(hpos, dms, true)) + k := kml.KML(m.To_kml(hpos, dms, true, 1, true)) k.WriteIndent(os.Stdout, "", " ") } diff --git a/pkg/mission/to_kml.go b/pkg/mission/to_kml.go index a319be3..e475457 100644 --- a/pkg/mission/to_kml.go +++ b/pkg/mission/to_kml.go @@ -2,16 +2,16 @@ package mission import ( "fmt" + types "github.com/stronnag/bbl2kml/pkg/api/types" + geo "github.com/stronnag/bbl2kml/pkg/geo" kml "github.com/twpayne/go-kml" "github.com/twpayne/go-kml/icon" "image/color" - geo "github.com/stronnag/bbl2kml/pkg/geo" - types "github.com/stronnag/bbl2kml/pkg/api/types" ) -func (m *Mission) get_fly_points (addAlt int32) ([]kml.Coordinate, bool) { +func (m *Mission) get_fly_points(addAlt int32) ([]kml.Coordinate, bool) { var points []kml.Coordinate - nsize := len(m.MissionItems) + nsize := len(m.MissionItems) ret := false jumpC := make([]int16, nsize) @@ -64,9 +64,9 @@ func (m *Mission) get_fly_points (addAlt int32) ([]kml.Coordinate, bool) { return points, ret } -func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { +func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool, mmidx int, isvis bool) kml.Element { var points []kml.Coordinate - var wps []kml.Element + var wps []kml.Element llat := 0.0 llon := 0.0 lalt := int32(0) @@ -78,7 +78,7 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { if (hpos.Flags & types.HOME_ALT) == types.HOME_ALT { addAlt = int32(hpos.HomeAlt) } else { - bingelev, err := geo.GetElevation(hpos.HomeLat, hpos.HomeLon) + bingelev, err := geo.GetElevation(hpos.HomeLat, hpos.HomeLon) if err == nil { addAlt = int32(bingelev) hpos.Flags |= types.HOME_ALT @@ -97,7 +97,7 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { var alt int32 for _, mi := range m.MissionItems { - if mi.Action == "JUMP" || mi.Action == "SET_HEAD" || mi.Action == "RTH" { + if mi.Action == "JUMP" || mi.Action == "SET_HEAD" || mi.Action == "RTH" { lat = llat lon = llon alt = lalt @@ -127,7 +127,7 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { default: bname = mi.Action } - name:= fmt.Sprintf("%s %d", bname, mi.No) + name := fmt.Sprintf("%s %d", bname, mi.No) p := kml.Placemark( kml.Name(name), kml.Description(fmt.Sprintf("Action: %s
Position: %s
Elevation: %dm
GPS Altitude: %dm
", @@ -138,6 +138,7 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { kml.Coordinates(kml.Coordinate{Lon: lon, Lat: lat, Alt: float64(alt)}), ), ) + p.Add(kml.Visibility(isvis)) wps = append(wps, p) } @@ -164,7 +165,7 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { pts, rth := m.get_fly_points(addAlt) points = append(points, pts...) - if rth && (hpos.Flags & types.HOME_ALT) == types.HOME_ALT { + if rth && (hpos.Flags&types.HOME_ALT) == types.HOME_ALT { points = append(points, kml.Coordinate{Lon: hpos.HomeLon, Lat: hpos.HomeLat, Alt: float64(addAlt)}) } @@ -179,8 +180,10 @@ func (m *Mission) To_kml(hpos types.HomeRec, dms bool, fake bool) kml.Element { ), ) - return kml.Folder(kml.Name("Mission File")).Add(kml.Description(desc)). - Add(kml.Visibility(true)).Add(mission_styles()...).Add(track).Add(wps...) + track.Add(kml.Visibility(isvis)) + fldnam := fmt.Sprintf("Mission #%d", mmidx) + return kml.Folder(kml.Name(fldnam)).Add(kml.Description(desc)). + Add(kml.Visibility(isvis)).Add(mission_styles()...).Add(track).Add(wps...) } func mission_styles() []kml.Element { @@ -190,8 +193,7 @@ func mission_styles() []kml.Element { kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("ylw-diamond"), - ), + kml.Href(icon.PaddleHref("ylw-diamond")), ), ), kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), @@ -202,45 +204,40 @@ func mission_styles() []kml.Element { kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("red-diamond"), - ), + kml.Href(icon.PaddleHref("red-diamond")), ), ), - kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), - kml.Text(`$[name]

$[description]
`)), + kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), + kml.Text(`$[name]

$[description]
`)), ), kml.SharedStyle( "styleSET_HEAD", kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("ylw-diamond"), - ), + kml.Href(icon.PaddleHref("ylw-diamond")), ), ), - kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), - kml.Text(`$[name]

$[description]
`)), + kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), + kml.Text(`$[name]

$[description]
`)), ), kml.SharedStyle( "styleWAYPOINT", kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("ltblu-circle"), - ), + kml.Href(icon.PaddleHref("ltblu-circle")), ), ), kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), kml.Text(`$[name]

$[description]
`)), - ), kml.SharedStyle( "stylePOSHOLD_UNLIM", kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("grn-diamond"), - ), + kml.Href(icon.PaddleHref("grn-diamond")), ), ), kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), @@ -251,20 +248,18 @@ func mission_styles() []kml.Element { kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("grn-circle"), - ), + kml.Href(icon.PaddleHref("grn-circle")), ), ), - kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), - kml.Text(`$[name]

$[description]
`)), + kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), + kml.Text(`$[name]

$[description]
`)), ), kml.SharedStyle( "styleJUMP", kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("purple-circle"), - ), + kml.Href(icon.PaddleHref("purple-circle")), ), ), kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), @@ -275,24 +270,22 @@ func mission_styles() []kml.Element { kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("pink-stars"), - ), + kml.Href(icon.PaddleHref("pink-stars")), ), ), - kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), - kml.Text(`$[name]

$[description]
`)), + kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), + kml.Text(`$[name]

$[description]
`)), ), kml.SharedStyle( "styleFakeHome", kml.IconStyle( kml.Scale(0.8), kml.Icon( - kml.Href(icon.PaddleHref("orange-stars"), - ), + kml.Href(icon.PaddleHref("orange-stars")), ), ), - kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), - kml.Text(`$[name]

$[description]
`)), + kml.BalloonStyle(kml.BgColor(color.RGBA{R: 0xde, G: 0xde, B: 0xde, A: 0x40}), + kml.Text(`$[name]

$[description]
`)), ), kml.SharedStyle( "styleWPTrack", diff --git a/pkg/options/options.go b/pkg/options/options.go index 79677b5..a15e2d3 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -166,7 +166,7 @@ func ParseCLI(gv func() string) ([]string, string) { flag.IntVar(&Config.HomeAlt, "home-alt", Config.HomeAlt, "[OTX] home altitude") flag.BoolVar(&Config.Dump, "dump", false, "Dump log headers and exit") flag.StringVar(&Config.Mission, "mission", "", "Optional mission file name") - flag.IntVar(&Config.MissionIndex, "mission-index", 1, "Optional mission file index") + flag.IntVar(&Config.MissionIndex, "mission-index", 0, "Optional mission file index") } if strings.HasPrefix(app, "fl2mqtt") { flag.StringVar(&Config.Mqttopts, "broker", "", "Mqtt URI (mqtt://[user[:pass]@]broker[:port]/topic[?cafile=file]") @@ -217,15 +217,13 @@ func ParseCLI(gv func() string) ([]string, string) { Config.HomeAlt = -999999 // sentinel } /* - if Config.Idx == 0 { - Config.Idx = 1 + if Config.Idx == 0 { + Config.Idx = 1 + } + if Config.MissionIndex == 0 { + Config.MissionIndex = 1 } */ - - if Config.MissionIndex == 0 { - Config.MissionIndex = 1 - } - if err != nil { fmt.Fprintf(os.Stderr, "Warning: config file ignored due to error: %v\n", err) }