diff --git a/Aircraft/ufo/ufo-set.xml b/Aircraft/ufo/ufo-set.xml index a78faf2eb..2b73ad073 100644 --- a/Aircraft/ufo/ufo-set.xml +++ b/Aircraft/ufo/ufo-set.xml @@ -35,7 +35,15 @@ mouse click - set cursor + add model to scenery + + + space bar + mouse click + select nearest model (blinks twice) + + + backspace + remove selected model tab @@ -43,47 +51,83 @@ d - dump coordinates + dump model data to terminal + + e + export model data + + + m + open/close model select dialog + + + pre-select model (path relative to $FG_ROOT): + --prop:model=Model/path.xml + + set directories that are scanned for models (comma separated and + relative to $FG_ROOT; default: Models): + --prop:source=Models,Scenery/Objects/w130n30/w123n37 + + exported data are written to $FG_HOME/ufo-model-export.xml - - d - Dump cursor/UFO coordinates + + Backspace + Remove selected model nasal - + Ctrl-I - Show cursor dialog + Show adjustment dialog nasal - + + + + + + d + Dump coordinates + + nasal + + + + + + e + Export model data XML file + + nasal + + + + + + m + Show model select dialog + + nasal + + Aircraft/ufo/Models/cursor.ac - - - cursor - - /cursor-data/longitude-deg - /cursor-data/latitude-deg - /cursor-data/elevation-ft - /cursor-data/heading-deg - /cursor-data/pitch-deg - /cursor-data/roll-deg - - + + Models diff --git a/Aircraft/ufo/ufo.nas b/Aircraft/ufo/ufo.nas index 946ec14da..b03ca4fcb 100644 --- a/Aircraft/ufo/ufo.nas +++ b/Aircraft/ufo/ufo.nas @@ -1,5 +1,7 @@ + # maximum speed ----------------------------------------------------------------------------------- + var maxspeed = props.globals.getNode("engines/engine/speed-max-mps"); var speed = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000]; var current = 7; @@ -15,20 +17,120 @@ controls.flapsDown = func(x) { } var s = speed[current]; maxspeed.setDoubleValue(s); - gui.popupTip("MaxSpeed " ~ s ~ " m/s"); + gui.popupTip("Max. Speed " ~ s ~ " m/s"); } -# cursor ------------------------------------------------------------------------------------------ + +# library stuff ----------------------------------------------------------------------------------- + +var ERAD = 6378138.12; # Earth radius +var D2R = math.pi / 180; +var R2D = 180 / math.pi; ft2m = func { arg[0] * 0.3048 } m2ft = func { arg[0] / 0.3048 } -floor = func { arg[0] < 0.0 ? -int(-arg[0]) - 1 : int(arg[0]) } +floor = func(v) { v < 0.0 ? -int(-v) - 1 : int(v) } +printf = func(_...) { print(call(sprintf, _)) } + +# convert [lon, lat] to [x, y, z] +# +lonlat2xyz = func(lonlat) { + var lonr = lonlat[0] * D2R; + var latr = lonlat[1] * D2R; + var cosphi = math.cos(latr); + var x = cosphi * math.cos(lonr); + var y = cosphi * math.sin(lonr); + var z = math.sin(latr); + return [x, y, z]; +} + + +# convert [x, y, z] to [lon, lat] +# +xyz2lonlat = func(xyz) { + var x = xyz[0]; + var y = xyz[1]; + var z = xyz[2]; + var aux = x * x + y * y; + var lat = math.atan2(z, math.sqrt(aux)) * R2D; + var lon = math.atan2(y, x) * R2D; + return [lon, lat]; +} + + +# return squared distance between two [x, y, z] +# +coord_dist_sq = func(xyz0, xyz1) { + var x = xyz0[0] - xyz1[0]; + var y = xyz0[1] - xyz1[1]; + var z = xyz0[2] - xyz1[2]; + return x * x + y * y + z * z; +} + + +# sort vector of strings (bubblesort) +# +sort = func(list) { + var l = list; + while (1) { + var n = 0; + for (var i = 0; i < size(l) - 1; i += 1) { + if (cmp(l[i], l[i + 1]) > 0) { + var t = l[i + 1]; + l[i + 1] = l[i]; + l[i] = t; + n += 1; + } + } + if (!n) { + return l; + } + } +} + + +# scan all objects in subdir of $FG_ROOT. (Prefer *.xml files to *.ac files.) +# +scan_models = func(base) { + var result = []; + var list = directory(getprop("/sim/fg-root") ~ "/" ~ base); + if (list == nil) { + return result; + } + var xml = {}; + var ac = {}; + foreach (var d; list) { + if (d[0] != `.` and d != "CVS") { + if (substr(d, size(d) - 4) == ".xml") { + xml[base ~ "/" ~ d] = 1; + } elsif (substr(d, size(d) - 3) == ".ac") { + ac[base ~ "/" ~ d] = 1; + } else { + foreach (var s; scan_models(base ~ "/" ~ d)) { + append(result, s); + } + } + } + } + foreach (var m; keys(xml)) { + append(result, m); + delete(ac, var x = substr(m, 0, size(m) - 3) ~ "ac"); + } + foreach (var m; keys(ac)) { + append(result, m); + } + return result; +} + + +# normalize degree to 0 <= angle < 360 +# normdeg = func(angle) { while (angle < 0) { angle += 360; @@ -117,23 +219,41 @@ tile_path = func(lon, lat) { } + + + + + + +# cursor ------------------------------------------------------------------------------------------ + + +var DATA = {}; # FIXME +var modellist = nil; +var modelmgr = nil; +var adjust = nil; + + + Value = { new : func(baseN, name, init) { - m = { parents : [Value] }; + var m = { parents: [Value] }; m.lastOffs = 0; m.init = init; + # offset node; fed by the dialog slider m.inOffsN = baseN.getNode("offsets/" ~ name, 1); m.inOffsN.setValue(m.lastOffs); - m.outN = baseN.getNode(name, 1); - m.outN.setValue(m.init); + # live number property + m.outN = baseN.getNode("adjust/" ~ name, 1); + m.outN.setDoubleValue(init); - m.lst = setlistener(m.inOffsN, func { m.update() }); + m.listener = setlistener(m.inOffsN, func { m.update() }); return m; }, del : func { - removelistener(me.lst); + removelistener(m.listener); }, reset : func { me.center(); @@ -162,78 +282,418 @@ Value = { }; -Object = { - new : func { - m = { parents : [Object] }; - baseN = props.globals.getNode("/cursor-data", 1); - m.values = { - lon: Value.new(baseN, "longitude-deg", 0), - lat: Value.new(baseN, "latitude-deg", 0), - alt: Value.new(baseN, "elevation-ft", -1000), +Adjust = { + new : func(prop) { + var m = { parents: [Adjust] }; + m.node = props.globals.getNode(prop, 1); + m.val = { + lon: Value.new(m.node, "longitude-deg", 0), + lat: Value.new(m.node, "latitude-deg", 0), + elev: Value.new(m.node, "elevation-ft", -10000), - hdg: Value.new(baseN, "heading-deg", 0), - pitch: Value.new(baseN, "pitch-deg", 0), - roll: Value.new(baseN, "roll-deg", 0), + hdg: Value.new(m.node, "heading-deg", 0), + pitch: Value.new(m.node, "pitch-deg", 0), + roll: Value.new(m.node, "roll-deg", 0), }; return m; }, + del : func { + foreach (var v; keys(me.val)) { + me.val[v].del(); + } + }, + offsetNode : func(which) { + me.val[which].inOffsN; + }, + outNode : func(which) { + me.val[which].outN; + }, + get : func(which) { + me.val[which].get(); + }, + set : func(which, value) { + me.val[which].set(value); + }, + setall : func(lon, lat, elev, hdg, pitch, roll) { + me.val["lon"].set(lon); + me.val["lat"].set(lat); + me.val["elev"].set(elev); + me.val["hdg"].set(hdg); + me.val["pitch"].set(pitch); + me.val["roll"].set(roll); + }, reset : func { - foreach (v; keys(me.values)) { me.values[v].reset() } + foreach (var v; keys(me.val)) { + me.val[v].reset(); + } }, - center : func { - foreach (v; keys(me.values)) { me.values[v].center() } - }, - update : func { - foreach (v; keys(me.values)) { me.valuse[v].update() } + step : func(which, step) { + me.val[which].add(step); }, upright : func { - me.values["pitch"].set(0); - me.values["roll"].set(0); + me.val["pitch"].set(0); + me.val["roll"].set(0); + }, + center : func { + foreach (var v; keys(me.val)) { + me.val[v].center(); + } }, }; -var cursor = Object.new(); -setlistener("/sim/input/click/longitude-deg", func { cursor.values["lon"].set(cmdarg().getValue())}); -setlistener("/sim/input/click/latitude-deg", func { cursor.values["lat"].set(cmdarg().getValue())}); -setlistener("/sim/input/click/elevation-ft", func { cursor.values["alt"].set(cmdarg().getValue())}); +Model = { + # searches first free slot and sets path + new : func(path) { + var m = { parents: [Model] }; + var models = props.globals.getNode("/models", 1); + + for (var i = 0; 42; i += 1) { + if (models.getChild("model", i, 0) == nil) { + m.node = models.getChild("model", i, 1); + break; + } + } + m.path = path; + m.node.getNode("path", 1).setValue(m.path); + return m; + }, + # signal modelmgr.cxx to load model + load : func { + me.node.getNode("load", 1).setValue(1); + me.node.removeChildren("load"); + }, + add_derived_props : func(node) { + var path = node.getNode("path").getValue(); + var lon = node.getNode("longitude-deg").getValue(); + var lat = node.getNode("latitude-deg").getValue(); + var elev = node.getNode("elevation-ft").getValue(); + var hdg = node.getNode("heading-deg").getValue(); + + var type = "OBJECT_" ~ ((path != nil and split("/", path)[0] == "Models") + ? "SHARED" : "STATIC"); + var stg_hdg = normdeg(360 - hdg); + var stg_path = tile_path(lon, lat); + var abs_path = getprop("/sim/fg-root") ~ "/" ~ path; + var obj_line = sprintf("%s %s %.6f %.6f %.4f %.1f", type, path, lon, lat, + ft2m(elev), stg_hdg); + + node.getNode("absolute-path", 1).setValue(abs_path); + node.getNode("stg-path", 1).setValue(stg_path); + node.getNode("stg-heading-deg", 1).setDoubleValue(stg_hdg); + node.getNode("object-line", 1).setValue(obj_line) + } +}; -var DATA = {}; +Static = { + new : func(path, lon, lat, elev, hdg, pitch, roll) { + var m = Model.new(path); + m.parents = [Static, Model]; + + m.node.getNode("type", 1).setValue("static"); + m.node.getNode("longitude-deg", 1).setDoubleValue(m.lon = lon); + m.node.getNode("latitude-deg", 1).setDoubleValue(m.lat = lat); + m.node.getNode("elevation-ft", 1).setDoubleValue(m.elev = elev); + m.node.getNode("heading-deg", 1).setDoubleValue(m.hdg = hdg); + m.node.getNode("pitch-deg", 1).setDoubleValue(m.pitch = pitch); + m.node.getNode("roll-deg", 1).setDoubleValue(m.roll = roll); + m.load(); + return m; + }, + del : func { + var parent = me.node.getParent(); + if (parent != nil) { + parent.removeChild(me.node.getName(), me.node.getIndex()); + } + }, + distance_from : func(xyz) { + return math.sqrt(coord_dist_sq(xyz, lonlat2xyz([me.lon, me.lat]))) * ERAD; + }, + get_data : func { + var n = props.Node.new(); + props.copy(me.node, n); + me.add_derived_props(n); + n.removeChildren("type"); + return n; + }, +}; -var dialog = nil; +Dynamic = { + new : func(path, lon, lat, elev, hdg, pitch, roll) { + var m = Model.new(path); + m.parents = [Dynamic, Model]; -showDialog = func { - name = "ufo-cursor-dialog"; - if (dialog != nil) { - fgcommand("dialog-close", props.Node.new({ "dialog-name" : name })); - dialog = nil; + adjust.setall(lon, lat, elev, hdg, pitch, roll); + m.node.getNode("type", 1).setValue("dynamic"); + m.node.getNode("longitude-deg-prop", 1).setValue(adjust.outNode("lon").getPath()); + m.node.getNode("latitude-deg-prop", 1).setValue(adjust.outNode("lat").getPath()); + m.node.getNode("elevation-ft-prop", 1).setValue(adjust.outNode("elev").getPath()); + m.node.getNode("heading-deg-prop", 1).setValue(adjust.outNode("hdg").getPath()); + m.node.getNode("pitch-deg-prop", 1).setValue(adjust.outNode("pitch").getPath()); + m.node.getNode("roll-deg-prop", 1).setValue(adjust.outNode("roll").getPath()); + m.load(); + return m; + }, + del : func { + var parent = me.node.getParent(); + if (parent != nil) { + parent.removeChild(me.node.getName(), me.node.getIndex()); + } + }, + make_static : func { + var static = Static.new(me.path, + adjust.get("lon"), adjust.get("lat"), adjust.get("elev"), + adjust.get("hdg"), adjust.get("pitch"), adjust.get("roll")); + me.del(); + return static; + }, + distance_from : func(xyz) { + var lon = adjust.get("lon"); + var lat = adjust.get("lat"); + return math.sqrt(coord_dist_sq(xyz, lonlat2xyz([lon, lat]))) * ERAD; + }, + get_data : func { + var n = props.Node.new(); + n.getNode("path", 1).setValue(me.path); + props.copy(props.globals.getNode("/data/adjust"), n); + me.add_derived_props(n); + n.removeChildren("type"); + return n; + }, +}; + + +Static.make_dynamic = func { + me.del(); + return Dynamic.new(me.path, me.lon, me.lat, me.elev, me.hdg, me.pitch, me.roll); +}; + + +ModelMgr = { + new : func(path) { + var m = { parents: [ModelMgr] }; + + var click = props.globals.getNode("/sim/input/click", 1); + m.lonN = click.getNode("longitude-deg", 1); + m.latN = click.getNode("latitude-deg", 1); + m.elevN = click.getNode("elevation-ft", 1); + + m.spacebarN = props.globals.getNode("/controls/engines/engine/starter", 1); + m.modelpath = path; + + m.dynamic = nil; + m.static = []; + m.block = 0; + return m; + }, + click : func { + if (me.block) { + return; + } + if (me.spacebarN.getBoolValue()) { + me.select(); + } else { + me.add_instance(); + } + }, + add_instance : func { + if (me.dynamic != nil) { + append(me.static, me.dynamic.make_static()); + } + me.dynamic = Dynamic.new(me.modelpath, me.lonN.getValue(), me.latN.getValue(), + me.elevN.getValue(), 0, 0, 0); + }, + select : func { + var click_xyz = lonlat2xyz([me.lonN.getValue(), me.latN.getValue()]); + var min_dist = me.dynamic != nil ? me.dynamic.distance_from(click_xyz) : 1000000; + var nearest = nil; + + # find nearest static object + forindex (var i; me.static) { + var dist = me.static[i].distance_from(click_xyz); + if (dist < min_dist) { + min_dist = dist; + nearest = i; + } + } + if (nearest != nil) { + # swap dynamic with nearest static + if (me.dynamic != nil) { + var st = me.dynamic.make_static(); + me.dynamic = me.static[nearest].make_dynamic(); + me.static[nearest] = st; + } else { + me.dynamic = me.static[nearest].make_dynamic(); + + var left = subvec(me.static, 0, nearest); + if (nearest + 1 < size(me.static)) { + foreach (var v; subvec(me.static, nearest + 1)) { + append(left, v); + } + } + me.static = left; + } + } + if (me.dynamic == nil) { # last one removed + return; + } + + # blink + me.block = 1; + settimer(func { adjust.set("elev", adjust.get("elev") - 10000) }, 0.33); + settimer(func { adjust.set("elev", adjust.get("elev") + 10000) }, 0.66); + settimer(func { adjust.set("elev", adjust.get("elev") - 10000) }, 1.00); + settimer(func { adjust.set("elev", adjust.get("elev") + 10000) }, 1.33); + settimer(func { me.block = 0 }, 1.34); + }, + remove_selected : func { + if (me.block) { + return; + } + if (me.dynamic != nil) { + me.dynamic.del(); + me.dynamic = nil; + } + me.select(); + }, + setmodelpath : func(path) { + me.modelpath = path; + }, + get_data : func { + var n = props.Node.new(); + if (me.dynamic != nil) { + props.copy(me.dynamic.get_data(), n.getChild("model", 0, 1)); + } + forindex (var i; me.static) { + props.copy(me.static[i].get_data(), n.getChild("model", i + 1, 1)); + } + return n; + }, +}; + + + + + +# what to do on terrain clicks + +#var lastXYZ = lonlat2xyz([getprop("/position/longitude-deg"), getprop("/position/latitude-deg")]); +#var lastElev = 0; + +# # print distance to last cursor coordinates (horizontal distance +# # doesn't consider elevation and is rather imprecise) +# newXYZ = lonlat2xyz([lon, lat]); +# var hdist = math.sqrt(coord_dist_sq(lastXYZ, newXYZ) * ERAD); +# var vdist = ft2m(elev - lastElev); +# var s = hdist < 4 ? sprintf("%.1f m HOR, %.1f m VERT", hdist * 1000, vdist) +# : sprintf("%.1f km HOR, %.1f m VERT", hdist, vdist); +# screen.log.write(s); + +# lastXYZ = newXYZ; +# lastElev = elev; + + + + + +scanDirs = func(csv) { + var list = []; + foreach(var dir; split(",", csv)) { + foreach(var m; scan_models(dir)) { + append(list, m); + } + } + return sort(list); +} + + +printData = func { + var rule = "------------------------------------------------------------------"; + var data = modelmgr.get_data(); + var bucket = {}; + # group all objects of a bucket + foreach (var m; data.getChildren("model")) { + var stg = m.getNode("stg-path").getValue(); + var obj = m.getNode("object-line").getValue(); + if (contains(bucket, stg)) { + append(bucket[stg], obj); + } else { + bucket[stg] = [obj]; + } + } + print(rule); + foreach (var key; keys(bucket)) { + print("\n# ", key); + foreach (var obj; bucket[key]) { + print(obj); + } + } + print(); + print(rule); +} + + +exportData = func { + savexml = func(name, node) { + fgcommand("savexml", props.Node.new({"filename": name, "sourcenode": node})); + } + var tmp = "save-ufo-data"; + save = props.globals.getNode(tmp, 1); + props.copy(modelmgr.get_data(), save); + savexml(getprop("/sim/fg-home") ~ "/ufo-model-export.xml", save.getPath()); + props.globals.removeChild(tmp); +} + + +removeSelectedModel = func { modelmgr.remove_selected() } + + +settimer(func { + modellist = scanDirs(getprop("/source")); + modelmgr = ModelMgr.new(getprop("/model")); + adjust = Adjust.new("/data"); + setlistener("/sim/signals/click", func { modelmgr.click() }); +}, 0); + + + + + + + + + + +# dialogs ----------------------------------------------------------------------------------------- + + +var dialog = {}; + +showModelSelectDialog = func { + name = "ufo-model-select-dialog"; + + if (contains(dialog, name)) { + closeModelSelectDialog(); return; } - var name = pop(split("/", getprop("cursor"))); - var ext = find(".", name); - if (ext >= 0) { - name = substr(name, 0, ext); - } - var title = 'Position "' ~ name ~ '"'; - cursor.center(); + var title = 'Select Model'; - dialog = gui.Widget.new(); - dialog.set("layout", "vbox"); - dialog.set("name", name); - dialog.set("x", -40); - dialog.set("y", -40); + dialog[name] = gui.Widget.new(); + dialog[name].set("layout", "vbox"); + dialog[name].set("name", name); + dialog[name].set("pref-width", 600); # "window" titlebar - titlebar = dialog.addChild("group"); + titlebar = dialog[name].addChild("group"); titlebar.set("layout", "hbox"); titlebar.addChild("empty").set("stretch", 1); titlebar.addChild("text").set("label", title); titlebar.addChild("empty").set("stretch", 1); - dialog.addChild("hrule").addChild("dummy"); + dialog[name].addChild("hrule").addChild("dummy"); w = titlebar.addChild("button"); w.set("pref-width", 16); @@ -243,13 +703,85 @@ showDialog = func { w.set("keynum", 27); w.set("border", 1); w.prop().getNode("binding[0]/command", 1).setValue("nasal"); - w.prop().getNode("binding[0]/script", 1).setValue("ufo.dialog = nil"); + w.prop().getNode("binding[0]/script", 1).setValue("ufo.closeModelSelectDialog()"); + + w = dialog[name].addChild("list"); + w.set("halign", "fill"); + w.set("pref-height", 300); + #w.set("live", 1); # FIXME + w.set("property", "/model"); + forindex (var i; modellist) { + w.prop().getChild("value", i, 1).setValue(modellist[i]); + } + w.prop().getNode("binding[0]/command", 1).setValue("dialog-apply"); # FIXME + #w.prop().getNode("binding[1]/command", 1).setValue("nasal"); + #w.prop().getNode("binding[1]/script", 1).setValue("print('foo');ufo.modelmgr.setmodelpath(getprop('/model'))"); + + #w = dialog[name].addChild("button"); # FIXME + #w.set("legend", "OK"); + #w.set("default", 1); + #w.prop().getNode("binding[0]/command", 1).setValue("nasal"); + #w.prop().getNode("binding[0]/script", 1).setValue("ufo.closeModelSelectDialog()"); + + fgcommand("dialog-new", dialog[name].prop()); + gui.showDialog(name); +} + + +closeModelSelectDialog = func { + var name = "ufo-model-select-dialog"; + var dlg = props.Node.new({"dialog-name": name}); + fgcommand("dialog-apply", dlg); + fgcommand("dialog-close", dlg); + delete(dialog, name); + print(getprop("/model")); + modelmgr.setmodelpath(getprop("/model")); +} + + +showAdjustDialog = func { + name = "ufo-cursor-dialog"; + + if (contains(dialog, name)) { + fgcommand("dialog-close", props.Node.new({ "dialog-name" : name })); + delete(dialog, name); + return; + } + + var title = 'Adjust model'; + adjust.center(); + + dialog[name] = gui.Widget.new(); + dialog[name].set("layout", "vbox"); + dialog[name].set("name", name); + dialog[name].set("x", -40); + dialog[name].set("y", -40); + + # "window" titlebar + titlebar = dialog[name].addChild("group"); + titlebar.set("layout", "hbox"); + titlebar.addChild("empty").set("stretch", 1); + titlebar.addChild("text").set("label", title); + titlebar.addChild("empty").set("stretch", 1); + + dialog[name].addChild("hrule").addChild("dummy"); + + w = titlebar.addChild("button"); + w.set("pref-width", 16); + w.set("pref-height", 16); + w.set("legend", ""); + w.set("default", 1); + w.set("keynum", 27); + w.set("border", 1); + w.prop().getNode("binding[0]/command", 1).setValue("nasal"); + w.prop().getNode("binding[0]/script", 1).setValue("delete(ufo.dialog, \"" ~ name ~ "\")"); w.prop().getNode("binding[1]/command", 1).setValue("dialog-close"); - slider = func(p, legend, col, coarse, fine) { - group = dialog.addChild("group"); + slider = func(legend, col, coarse, fine) { + group = dialog[name].addChild("group"); group.set("layout", "hbox"); group.set("default-padding", 0); + button = func(leg, step) { b = group.addChild("button"); b.set("legend", leg); @@ -257,8 +789,7 @@ showDialog = func { b.set("pref-height", 22); b.set("live", 1); b.prop().getNode("binding[0]/command", 1).setValue("nasal"); - b.prop().getNode("binding[0]/script", 1).setValue - ('ufo.cursor.values["'~legend~'"].add('~step~');ufo.cursor.center()'); + b.prop().getNode("binding[0]/script", 1).setValue('ufo.adjust.step("'~legend~'", '~step~')'); return b; } @@ -266,7 +797,7 @@ showDialog = func { fl = button("<", -fine); s = group.addChild("slider"); - s.set("property", p.getPath()); + s.set("property", adjust.offsetNode(legend).getPath()); s.set("legend", legend); s.set("pref-width", 250); s.set("live", 1); @@ -279,15 +810,15 @@ showDialog = func { cr = button(">>", coarse); } - slider(cursor.values["lon"].inOffsN, "lon", [1.0, 0.6, 0.6], 0.0002, 0.00002); - slider(cursor.values["lat"].inOffsN, "lat", [0.6, 1.0, 0.6], 0.0002, 0.00002); - slider(cursor.values["alt"].inOffsN, "alt", [0.6, 0.6, 1.0], 10, 2); + slider("lon", [1.0, 0.6, 0.6], 0.0002, 0.00002); + slider("lat", [0.6, 1.0, 0.6], 0.0002, 0.00002); + slider("elev", [0.6, 0.6, 1.0], 10, 2); - slider(cursor.values["hdg"].inOffsN, "hdg", [1.0, 1.0, 0.6], 36, 6); - slider(cursor.values["pitch"].inOffsN, "pitch", [1.0, 0.6, 1.0], 36, 6); - slider(cursor.values["roll"].inOffsN, "roll", [0.6, 1.0, 1.0], 36, 6); + slider("hdg", [1.0, 1.0, 0.6], 36, 6); + slider("pitch", [1.0, 0.6, 1.0], 36, 6); + slider("roll", [0.6, 1.0, 1.0], 36, 6); - g = dialog.addChild("group"); + g = dialog[name].addChild("group"); g.set("layout", "hbox"); w = g.addChild("button"); @@ -296,7 +827,7 @@ showDialog = func { w.set("pref-height", 22); w.set("pref-width", 50); w.prop().getNode("binding[0]/command", 1).setValue("nasal"); - w.prop().getNode("binding[0]/script", 1).setValue("ufo.cursor.upright()"); + w.prop().getNode("binding[0]/script", 1).setValue("ufo.adjust.upright()"); w = g.addChild("button"); w.set("halign", "center"); @@ -304,7 +835,7 @@ showDialog = func { w.set("pref-height", 22); w.set("pref-width", 50); w.prop().getNode("binding[0]/command", 1).setValue("nasal"); - w.prop().getNode("binding[0]/script", 1).setValue("ufo.cursor.center()"); + w.prop().getNode("binding[0]/script", 1).setValue("ufo.adjust.center()"); w = g.addChild("button"); w.set("halign", "right"); @@ -312,13 +843,21 @@ showDialog = func { w.set("pref-height", 22); w.set("pref-width", 50); w.prop().getNode("binding[0]/command", 1).setValue("nasal"); - w.prop().getNode("binding[0]/script", 1).setValue("ufo.dumpCoords()"); + w.prop().getNode("binding[0]/script", 1).setValue("ufo.printData()"); - fgcommand("dialog-new", dialog.prop()); + fgcommand("dialog-new", dialog[name].prop()); gui.showDialog(name); } + + + +##### + + + + dumpCoords = func { print("\n---------------------------- UFO -----------------------------"); @@ -329,15 +868,15 @@ dumpCoords = func { var heading = getprop("/orientation/heading-deg"); var agl_ft = alt_ft - m2ft(elev_m); - print(sprintf("Longitude: %.6f deg", lon)); - print(sprintf("Latitude: %.6f deg", lat)); - print(sprintf("Altitude ASL: %.4f m (%.4f ft)", ft2m(alt_ft), alt_ft)); - print(sprintf("Altitude AGL: %.4f m (%.4f ft)", ft2m(agl_ft), agl_ft)); - print(sprintf("Heading: %.1f deg", normdeg(heading))); - print(sprintf("Ground Elev: %.4f m (%.4f ft)", elev_m, m2ft(elev_m))); + printf("Longitude: %.6f deg", lon); + printf("Latitude: %.6f deg", lat); + printf("Altitude ASL: %.4f m (%.4f ft)", ft2m(alt_ft), alt_ft); + printf("Altitude AGL: %.4f m (%.4f ft)", ft2m(agl_ft), agl_ft); + printf("Heading: %.1f deg", normdeg(heading)); + printf("Ground Elev: %.4f m (%.4f ft)", elev_m, m2ft(elev_m)); print(""); print(tile_path(lon, lat)); - print(sprintf("OBJECT_STATIC %.6f %.6f %.4f %.1f", lon, lat, elev_m, normdeg(360 - heading))); + printf("OBJECT_STATIC %.6f %.6f %.4f %.1f", lon, lat, elev_m, normdeg(360 - heading)); print(""); var hdg = normdeg(heading + getprop("/sim/current-view/goal-pitch-offset-deg")); @@ -348,13 +887,13 @@ dumpCoords = func { print("\n\n--------------------------- Cursor ---------------------------"); - var alt = cursor.values["alt"].get(); - print(sprintf("Longitude: %.6f deg", var clon = cursor.values["lon"].get())); - print(sprintf("Latitude: %.6f deg", var clat = cursor.values["lat"].get())); - print(sprintf("Altitude ASL: %.4f m (%.4f ft)", var celev = ft2m(alt), alt)); - print(sprintf("Heading: %.1f deg", var chdg = normdeg(cursor.values["hdg"].get()))); - print(sprintf("Pitch: %.1f deg", normdeg(cursor.values["pitch"].get()))); - print(sprintf("Roll: %.1f deg", normdeg(cursor.values["roll"].get()))); + var alt = cursor.val["alt"].get(); + printf("Longitude: %.6f deg", var clon = cursor.val["lon"].get()); + printf("Latitude: %.6f deg", var clat = cursor.val["lat"].get()); + printf("Altitude ASL: %.4f m (%.4f ft)", var celev = ft2m(alt), alt); + printf("Heading: %.1f deg", var chdg = normdeg(cursor.val["hdg"].get())); + printf("Pitch: %.1f deg", normdeg(cursor.val["pitch"].get())); + printf("Roll: %.1f deg", normdeg(cursor.val["roll"].get())); print(""); print(DATA["stg"] = tile_path(clon, clat)); print(DATA["object"] = sprintf("%s %s %.6f %.6f %.4f %.1f", DATA["type"], DATA["model"], clon, clat, celev, normdeg(360 - chdg))); @@ -363,43 +902,3 @@ dumpCoords = func { } - -saveData = func { - savexml = func(name, node) { - fgcommand("savexml", props.Node.new({"filename": name, "sourcenode": node})); - } - var tmp = "save-ufo-data"; - save = props.globals.getNode(tmp, 1); - model = props.globals.getNode("/cursor-data"); - props.copy(model, save); - foreach (var p; keys(DATA)) { - save.getNode(p, 1).setValue(DATA[p]); - } - save.removeChildren("offsets"); - savexml(getprop("/sim/fg-home") ~ "/ufo-cursor.xml", save.getPath()); - props.globals.removeChild(tmp); -} - - -getCursorData = func { - var model = getprop("cursor"); - if (model == "") { - die("No such model: ", model); - } - - if (model == "Aircraft/ufo/Models/cursor.ac") { - DATA["type"] = "OBJECT_STATIC"; - DATA["path"] = ""; - DATA["model"] = ""; - } else { - DATA["type"] = split("/", model)[0] == "Models" ? "OBJECT_SHARED" : "OBJECT_STATIC"; - DATA["path"] = getprop("/sim/fg-root") ~ "/" ~ model; - DATA["model"] = model; - } -} - - -# INIT - -settimer(func { getCursorData() }, 0); -