public KerbulatorGUI(IGlue glue, bool inEditor, bool drawMainButton, KerbulatorOptions options) { this.glue = glue; this.inEditor = inEditor; this.drawMainButton = drawMainButton; this.options = options; ChangeState(false); // Use the game base directory + PluginData as base folder for plugin data functionDir = glue.GetFunctionDir(); functionDir = functionDir.Replace("\\", "/"); Debug.Log("Kerbulator function dir: " + functionDir); editFunctionContent = maneuverTemplate; if (!Directory.Exists(functionDir)) { Directory.CreateDirectory(functionDir); } // Load icons kerbulatorIcon = glue.GetTexture("kerbulator"); editIcon = glue.GetTexture("edit"); runIcon = glue.GetTexture("run"); repeatIcon = glue.GetTexture("repeat"); nodeIcon = glue.GetTexture("node"); alarmIcon = glue.GetTexture("alarm"); saveIcon = glue.GetTexture("save"); deleteIcon = glue.GetTexture("delete"); kalc = new Kerbulator(functionDir); }
// UNITY public static void AddOrbit(Kerbulator kalc, Orbit orbit, string prefix) { if (orbit == null) { return; } AddDouble(kalc, prefix + ".Ap", (double)orbit.ApA); AddDouble(kalc, prefix + ".Pe", (double)orbit.PeA); AddDouble(kalc, prefix + ".Inc", (double)orbit.inclination); AddDouble(kalc, prefix + ".Alt", (double)orbit.altitude); AddDouble(kalc, prefix + ".ArgPe", (double)orbit.argumentOfPeriapsis); AddDouble(kalc, prefix + ".ω", (double)orbit.argumentOfPeriapsis); AddDouble(kalc, prefix + ".LAN", (double)orbit.LAN); AddDouble(kalc, prefix + ".Ω", (double)orbit.LAN); AddDouble(kalc, prefix + ".TimeToAp", (double)orbit.timeToAp); AddDouble(kalc, prefix + ".TimeToPe", (double)orbit.timeToPe); AddDouble(kalc, prefix + ".Vel", (double)orbit.vel.magnitude); AddDouble(kalc, prefix + ".TrueAnomaly", (double)orbit.trueAnomaly); AddDouble(kalc, prefix + ".θ", (double)orbit.trueAnomaly); if (orbit.UTsoi > 0) { AddDouble(kalc, prefix + ".SOI.dt", (double)orbit.UTsoi - Planetarium.GetUniversalTime()); AddDouble(kalc, prefix + ".SOI.Δt", (double)orbit.UTsoi - Planetarium.GetUniversalTime()); AddDouble(kalc, prefix + ".SOI.TrueAnomaly", (double)orbit.TrueAnomalyAtUT(orbit.UTsoi)); AddDouble(kalc, prefix + ".SOI.θ", (double)orbit.TrueAnomalyAtUT(orbit.UTsoi)); } }
public static void AddCelestialBody(Kerbulator kalc, CelestialBody body, string prefix) { if (body == null) { return; } try { if (body.orbit != null) { AddOrbit(kalc, body.orbit, prefix); } } catch (Exception) { // Somehow, testing body.orbit != null is not enough. I don't know why... // Leave a pull request or file an issue if you can help me figure this out! } AddDouble(kalc, prefix + ".R", (double)body.Radius); AddDouble(kalc, prefix + ".M", (double)body.Mass); AddDouble(kalc, prefix + ".mu", (double)body.gravParameter); AddDouble(kalc, prefix + ".μ", (double)body.gravParameter); AddDouble(kalc, prefix + ".µ", (double)body.gravParameter); AddDouble(kalc, prefix + ".day", (double)body.rotationPeriod); AddDouble(kalc, prefix + ".SOI", (double)body.sphereOfInfluence); AddDouble(kalc, prefix + ".AtmosHeight", (double)body.maxAtmosphereAltitude); AddDouble(kalc, prefix + ".AtmosPress", (double)body.atmosphereMultiplier * 101325.0); }
private void HandleToken(Token t) { switch (t.type) { case TokenType.EMPTY: return; // Some identifiers are special case TokenType.IDENTIFIER: // These are actually operators if (t.val == "and" || t.val == "or") { t.type = TokenType.OPERATOR; } // These are actually conditionals else if (t.val == "if" || t.val == "otherwise") { t.type = TokenType.CONDITIONAL; } break; } Kerbulator.Debug(" " + t.ToString()); tokens.Enqueue(t); }
public JITExpression(string expression, Kerbulator kalc) : base("unnamed", expression, kalc) { Expression <Func <Object> > e = Expression.Lambda <Func <Object> >(ParseExpression()); expressionFunction = e.Compile(); }
private bool PossiblyValidExpression(Stack <Expression> expr, Stack <Operator> ops) { if (expr.Count == 0 && ops.Count == 0) { return(false); } int required = 0; int supplied = expr.Count; foreach (Operator op in ops) { Kerbulator.DebugLine(op.id); supplied++; if (op.arity == Arity.BINARY) { required += 2; } else { required += 1; } } Kerbulator.DebugLine("required: " + required + ", supplied: " + supplied); return(supplied == required + 1); }
private void PrintVertices(double[][] sim, double[] fsim) { Kerbulator.DebugLine("Verts:"); for (int i = 0; i < sim.Length; i++) { Kerbulator.Debug("\t" + i + ": " + PrintVert(sim[i]) + " = " + fsim[i] + "\n"); } }
public static JITFunction FromFile(string filename, Kerbulator kalc) { StreamReader file = File.OpenText(filename); string contents = file.ReadToEnd() + "\n"; file.Close(); JITFunction f = new JITFunction(Path.GetFileNameWithoutExtension(filename), contents, kalc); return(f); }
public static void AddDouble(Kerbulator kalc, string id, double v) { if (kalc.Globals.ContainsKey(id)) { kalc.Globals[id] = (System.Object)v; } else { kalc.Globals.Add(id, (System.Object)v); } }
private void ParseNumber(Stack <Expression> expr) { Token t = tokens.Dequeue(); Kerbulator.DebugLine("Pushing " + t.val); expr.Push( Expression.Convert( Expression.Constant(Double.Parse(t.val, System.Globalization.CultureInfo.InvariantCulture)), typeof(Object) ) ); }
private void HandleToken(Token t) { switch (t.type) { case TokenType.EMPTY: break; default: Kerbulator.Debug(" " + t.ToString()); tokens.Enqueue(t); break; } }
/// <summary>Provide a string representation of the output resulting from executing a function.</summary> public string FormatOutput(ExecutionEnvironment env) { if (env == null) { return(""); } if (env.InError) { return("ERROR: " + env.ErrorString); } if (env.Output == null) { return(""); } if (env.Output.Count == 0) { return("None."); } if (env.Output.Count != env.func.Outs.Count) { return("None."); } string desc = ""; for (int i = 0; i < env.Output.Count; i++) { if (i < env.func.OutputTypes.Count) { if (env.func.OutputTypes[i] == OutputType.Value) { desc += env.func.OutPrefixes[i] + Kerbulator.FormatVar(env.Output[i]) + env.func.OutPostfixes[i] + "\n"; } } else { desc += env.func.OutPrefixes[i] + Kerbulator.FormatVar(env.Output[i]) + env.func.OutPostfixes[i] + "\n"; } } return(desc); }
private void SortVertices(double[][] sim, double[] fsim) { int[] ind = Enumerable.Range(0, sim.Length).ToArray(); Array.Sort(fsim, ind); Kerbulator.DebugLine("Sorted idx:" + PrintVert(ind)); double[][] sim2 = new double[sim.Length][]; for (int i = 0; i < sim.Length; i++) { sim2[i] = sim[ind[i]]; } for (int i = 0; i < sim.Length; i++) { sim[i] = sim2[i]; } }
private void ParseOperator(Stack <Expression> expr, Stack <Operator> ops) { Token t = tokens.Dequeue(); if (!kalc.Operators.ContainsKey(t.val)) { throw new Exception(t.pos + " unknown operator: " + t.val); } Operator op = kalc.Operators[t.val]; // Handle ambiguous cases of arity if (op.arity == Arity.BOTH) { if (PossiblyValidExpression(expr, ops)) { op = new Operator(op.id, op.precidence, Arity.BINARY); Kerbulator.DebugLine(op.id + " is binary."); } else { op = new Operator(op.id, 3, Arity.UNARY); Kerbulator.DebugLine(op.id + " is unary."); } } // Handle operators with higher precidence while (ops.Count > 0) { Operator prevOp = ops.Peek(); if (op.arity != Arity.BINARY || prevOp.precidence < op.precidence) { // Leave for later break; } else { expr.Push(ExecuteOperator(ops.Pop(), expr, ops, t.pos)); } } // Push current operator on the stack Kerbulator.DebugLine("Pushing " + op.id); ops.Push(op); }
public static Object Any(Object a, string pos) { Kerbulator.DebugLine("Executing any()"); if(a.GetType() != typeof(Object[])) throw new Exception(pos +"function any() can only be called with a list as argument"); Object[] listA = (Object[]) a; double result = 0.0; for(int i=0; i<listA.Length; i++) { if(listA[i].GetType() != typeof(double)) throw new Exception(pos +"argument to function any() must be a list that contains only numbers"); if(((double) listA[i]) != 0) result = 1.0; } return (Object) result; }
public bool ParseList(Stack <Expression> expr) { if (tokens.Peek().val == "]") { return(true); } // Consume left brace Token t = Consume(); List <Expression> elements = new List <Expression>(); while (tokens.Peek().val != "]") { t = tokens.Peek(); Kerbulator.DebugLine("Starting subexpression"); Expression subexpr = ParseExpression(); Kerbulator.DebugLine("End of subexpression"); elements.Add(subexpr); if (tokens.Count == 0) { throw new Exception(t.pos + "missing closing ']'"); } if (tokens.Peek().val != "]") { Consume(TokenType.COMMA); } } // Consume right brace Consume(); if (elements.Count == 0) { throw new Exception(t.pos + "Empty lists are not allowed."); } expr.Push(Expression.NewArrayInit(typeof(Object), elements)); return(false); }
public KerbulatorGUI(IGlue glue, bool inEditor, bool drawMainButton) { this.glue = glue; this.inEditor = inEditor; this.drawMainButton = drawMainButton; ChangeState(false); functionDir = Application.persistentDataPath + "/Kerbulator"; // Sometimes, Application.persistentDataPath returns an empty string. // To not completely crash, create a KerbulatorFunctions directory in the users home dir if (functionDir == "/Kerbulator") { string homePath = (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) ? Environment.GetEnvironmentVariable("HOME") : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); functionDir = homePath + "/KerbulatorFunctions"; } Debug.Log("Kerbulator function dir: " + functionDir); editFunctionContent = maneuverTemplate; if (!Directory.Exists(functionDir)) { Directory.CreateDirectory(functionDir); } // Load icons kerbulatorIcon = glue.GetTexture("kerbulator"); editIcon = glue.GetTexture("edit"); runIcon = glue.GetTexture("run"); repeatIcon = glue.GetTexture("repeat"); nodeIcon = glue.GetTexture("node"); saveIcon = glue.GetTexture("save"); deleteIcon = glue.GetTexture("delete"); kalc = new Kerbulator(functionDir); }
/// <summary>Provide a string representation of the output resulting from executing a function.</summary> /// <param name="f">The function that was executed</param> /// <param name="output">The variables resuting from the execution</param> public string FormatOutput(ExecutionEnvironment env) { if (env == null) { return(""); } if (env.InError) { return("ERROR: " + env.ErrorString); } if (env.Output == null) { return(""); } string desc = ""; if (env.Output.Count == 0) { desc += "None."; } else { for (int i = 0; i < env.Output.Count - 1; i++) { desc += env.func.Outs[i] + " = " + Kerbulator.FormatVar(env.Output[i]) + "\n"; } if (env.Output.Count > 0) { desc += env.func.Outs[env.func.Outs.Count - 1] + " = " + Kerbulator.FormatVar(env.Output[env.Output.Count - 1]); } } return(desc); }
public JITFunction(string id, string expression, Kerbulator kalc) { this.id = id; this.ins = new List <string>(); this.outs = new List <string>(); this.inDescriptions = new List <string>(); this.outDescriptions = new List <string>(); this.locals = new Dictionary <string, Object>(); this.thisExpression = Expression.Constant(this); this.kalc = kalc; this.solv = new Solver(this); try { Tokenizer tok = new Tokenizer(id); tok.Tokenize(expression); tokens = tok.tokens; } catch (Exception e) { inError = true; error = e; } }
public void Compile() { if (compiledFunction != null) { return; // Already compiled } try { // Skip leading whitespace while (tokens.Count > 0 && tokens.Peek().type == TokenType.END) { Consume(); } // Parse in: statements while (tokens.Count > 0 && tokens.Peek().type == TokenType.IN) { Consume(); Token id = Consume(TokenType.IDENTIFIER); if (tokens.Count > 0 && tokens.Peek().type == TokenType.TEXT) { inDescriptions.Add(tokens.Dequeue().val); } Consume(TokenType.END); ins.Add(id.val); Kerbulator.DebugLine("Found IN statement for " + id.val); } // Skip whitespace while (tokens.Count > 0 && tokens.Peek().type == TokenType.END) { Consume(); } // Parse out: statements while (tokens.Count > 0 && tokens.Peek().type == TokenType.OUT) { Consume(); Token id = Consume(TokenType.IDENTIFIER); if (tokens.Count > 0 && tokens.Peek().type == TokenType.TEXT) { outDescriptions.Add(tokens.Dequeue().val); } else { outDescriptions.Add(""); } Consume(TokenType.END); outs.Add(id.val); Kerbulator.DebugLine("Found OUT statement for " + id.val); } Kerbulator.DebugLine(""); // Parse all other statements List <Expression> statements = new List <Expression>(); while (tokens.Count > 0) { Expression statement = ParseStatement(); if (statement != null) { statements.Add(statement); } Consume(TokenType.END); } if (statements.Count == 0) { throw new Exception("In function " + this.id + ": function does not contain any statements (it's empty)"); } // If no outputs are given, take last assigned variables as output if (outs.Count == 0) { outs = lastAssigned; outDescriptions = new List <string>(outs.Count); for (int i = 0; i < outs.Count; i++) { outDescriptions.Add(""); } } // Create expression that will execute all the statements Expression functionExpression = Expression.Call( thisExpression, typeof(JITFunction).GetMethod("ExecuteBlock"), Expression.NewArrayInit(typeof(Object), statements) ); compiledFunction = Expression.Lambda <Func <Object> >(functionExpression).Compile(); } catch (Exception e) { compiledFunction = null; inError = true; error = e; } }
public static void AddVector3d(Kerbulator kalc, string id, Vector3d v) { Variable x = new Variable("x", VarType.NUMBER, v.x); Variable y = new Variable("y", VarType.NUMBER, v.y); Variable z = new Variable("z", VarType.NUMBER, v.z); List<Variable> elements = new List<Variable>(3); elements.Add(x); elements.Add(y); elements.Add(z); Variable g = new Variable(id, VarType.LIST, elements); kalc.AddGlobal(g); }
public static void Scan(string dir, Kerbulator kalc) { // This function is called pretty often, so I went through some lengths to ensure that only new or updated functions are compiled. List <string> files = new List <string>(Directory.GetFiles(dir, "*.math")); List <string> compiledFunctions = new List <string>(kalc.Functions.Keys); files.Sort(); compiledFunctions.Sort(); int i = 0; int j = 0; while (i < files.Count || j < compiledFunctions.Count) { if (i >= files.Count) { // Deleted function kalc.Functions.Remove(compiledFunctions[j]); j++; } else if (j >= compiledFunctions.Count) { // Added function JITFunction f = FromFile(files[i], kalc); kalc.Functions[f.Id] = f; i++; } else if (string.Compare(Path.GetFileNameWithoutExtension(files[i]), compiledFunctions[j]) == 1) { // Deleted function kalc.Functions.Remove(compiledFunctions[j]); i++; } else if (string.Compare(Path.GetFileNameWithoutExtension(files[i]), compiledFunctions[j]) == -1) { // Added function JITFunction f = FromFile(files[i], kalc); kalc.Functions[f.Id] = f; j++; } else { // Function already exists // Reload only if file is newer DateTime dt = File.GetLastWriteTime(files[i]); if (dt > lastScan) { JITFunction f = FromFile(files[i], kalc); kalc.Functions[f.Id] = f; } i++; j++; } } foreach (JITFunction f in kalc.Functions.Values) { f.Compile(); } lastScan = DateTime.Now; }
public void AddGlobals(Kerbulator kalc) { }
public KerbulatorGUI(IGlue glue, bool inEditor, bool drawMainButton) { this.glue = glue; this.inEditor = inEditor; this.drawMainButton = drawMainButton; ChangeState(false); functionDir = Application.persistentDataPath + "/Kerbulator"; // Sometimes, Application.persistentDataPath returns an empty string. // To not completely crash, create a KerbulatorFunctions directory in the users home dir if(functionDir == "/Kerbulator") { string homePath = (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) ? Environment.GetEnvironmentVariable("HOME") : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); functionDir = homePath +"/KerbulatorFunctions"; } Debug.Log("Function dir: "+ functionDir); editFunctionContent = maneuverTemplate; if(!Directory.Exists(functionDir)) { Directory.CreateDirectory(functionDir); } // Load icons kerbulatorIcon = glue.GetTexture("kerbulator"); editIcon = glue.GetTexture("edit"); runIcon = glue.GetTexture("run"); nodeIcon = glue.GetTexture("node"); saveIcon = glue.GetTexture("save"); deleteIcon = glue.GetTexture("delete"); Scan(); kalc = new Kerbulator(functionDir); }
private bool ParseBrace(Stack <Expression> expr, Stack <Operator> ops) { Token t = tokens.Peek(); // Determine whether it's a left or right brace bool isLeft = false; switch (t.val) { case "(": case "{": case "⌊": case "⌈": isLeft = true; break; case "|": isLeft = !PossiblyValidExpression(expr, ops); if (isLeft) { Kerbulator.DebugLine("| is left brace"); } else { Kerbulator.DebugLine("| is right brace"); } break; } // If it's a left brace, start a sub-expression if (isLeft) { Consume(); // Execute sub-expression Kerbulator.DebugLine("Starting subexpression"); Expression subexpr = ParseExpression(); Kerbulator.DebugLine("End of subexpression"); expr.Push(subexpr); // Consume right brace. Execute operation if any switch (t.val) { case "(": Consume(")"); break; case "{": Consume("}"); break; case "⌊": Consume("⌋"); ops.Push(kalc.Operators[t.val]); break; case "⌈": Consume("⌉"); ops.Push(kalc.Operators[t.val]); break; case "|": Consume("|"); ops.Push(kalc.Operators[t.val]); break; } return(false); } else { return(true); } }
public static void Add(Kerbulator kalc) { // Planets foreach(CelestialBody b in FlightGlobals.Bodies) { if(b.name == "Sun") Globals.AddCelestialBody(kalc, b, "Kerbol"); else Globals.AddCelestialBody(kalc, b, b.name); } Vessel v = FlightGlobals.ActiveVessel; Orbit orbit1 = v.orbit; if(v != null) { // Current orbit Globals.AddOrbit(kalc, orbit1, "Craft"); // Navball (thank you MechJeb source) Vector3d CoM = v.findWorldCenterOfMass(); Vector3d up = (CoM - v.mainBody.position).normalized; Vector3d north = Vector3d.Exclude(up, (v.mainBody.position + v.mainBody.transform.up * (float)v.mainBody.Radius) - CoM).normalized; Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(v.GetTransform().rotation) * rotationSurface); Vector3d velocityVesselOrbit = v.orbit.GetVel(); Vector3d velocityVesselSurface = velocityVesselOrbit - v.mainBody.getRFrmVel(CoM); Globals.AddDouble(kalc, "Navball.Heading", rotationVesselSurface.eulerAngles.y); Globals.AddDouble(kalc, "Navball.Pitch", (rotationVesselSurface.eulerAngles.x > 180) ? (360.0 - rotationVesselSurface.eulerAngles.x) : -rotationVesselSurface.eulerAngles.x); Globals.AddDouble(kalc, "Navball.Roll", (rotationVesselSurface.eulerAngles.z > 180) ? (rotationVesselSurface.eulerAngles.z - 360.0) : rotationVesselSurface.eulerAngles.z); Globals.AddDouble(kalc, "Navball.OrbitalVelocity", velocityVesselOrbit.magnitude); Globals.AddDouble(kalc, "Navball.SurfaceVelocity", velocityVesselSurface.magnitude); Globals.AddDouble(kalc, "Navball.VerticalVelocity", Vector3d.Dot(velocityVesselSurface, up)); // Current time double UT = (double)Planetarium.GetUniversalTime(); Globals.AddDouble(kalc, "UT", UT); // Reference body Globals.AddCelestialBody(kalc, v.orbit.referenceBody, "Parent"); // Target if(FlightGlobals.fetch.VesselTarget != null) { ITargetable target = FlightGlobals.fetch.VesselTarget; Orbit orbit2 = target.GetOrbit(); // Target Orbit Globals.AddOrbit(kalc, orbit2, "Target"); // Intersection with target orbit double CD = 0.0; double CCD = 0.0; double FFp = 0.0; double FFs = 0.0; double SFp = 0.0; double SFs = 0.0; int iterationCount = 0; Orbit.FindClosestPoints(orbit1, orbit2, ref CD, ref CCD, ref FFp, ref FFs, ref SFp, ref SFs, 0.0, 100, ref iterationCount); double T1 = orbit1.GetDTforTrueAnomaly(FFp, 0.0); double T2 = orbit1.GetDTforTrueAnomaly(SFp, 0.0); Globals.AddDouble(kalc, "Craft.Inter1.dt", T1); Globals.AddDouble(kalc, "Craft.Inter1.Δt", T1); Globals.AddDouble(kalc, "Craft.Inter1.Sep", (orbit1.getPositionAtUT(T1+UT) - orbit2.getPositionAtUT(T1+UT)).magnitude); Globals.AddDouble(kalc, "Craft.Inter1.TrueAnomaly", orbit1.TrueAnomalyAtUT(T1+UT)); Globals.AddDouble(kalc, "Craft.Inter1.θ", orbit1.TrueAnomalyAtUT(T1+UT)); Globals.AddDouble(kalc, "Craft.Inter2.dt", T2); Globals.AddDouble(kalc, "Craft.Inter2.Δt", T2); Globals.AddDouble(kalc, "Craft.Inter2.Sep", (orbit1.getPositionAtUT(T2+UT) - orbit2.getPositionAtUT(T2+UT)).magnitude); Globals.AddDouble(kalc, "Craft.Inter2.TrueAnomaly", orbit2.TrueAnomalyAtUT(T2+UT)); Globals.AddDouble(kalc, "Craft.Inter2.θ", orbit2.TrueAnomalyAtUT(T2+UT)); } } }
public ExecutionEnvironment(JITFunction func, Kerbulator kalc) { this.func = func; this.kalc = kalc; inputExpressions = new List <JITExpression>(func.Ins.Count); }
/// <summary>Add/Update some useful globals</summary> public void AddGlobals(Kerbulator kalc) { Globals.Add(kalc); // UNITY }
public static void Main(string[] args) { Kerbulator k = new Kerbulator("./tests"); if(args[0].EndsWith(".test")) { Console.WriteLine("Running unit tests in "+ args[0]); StreamReader file = File.OpenText(args[0]); string line; while( (line = file.ReadLine()) != null ) { string[] parts = line.Split('>'); string expression = parts[0].Trim(); string expectedResult = parts[1].Trim(); try { string r = k.RunExpression(expression).ToString(); if(r.Equals(expectedResult)) Console.WriteLine(expression +" = "+ r +" [PASS]"); else Console.WriteLine(expression +" = "+ r +" [FAIL] "+ expectedResult); } catch(Exception e) { if(expectedResult == "ERROR") Console.WriteLine(expression +" = ERROR [PASS]"); else Console.WriteLine(expression +" = ERROR [FAIL] "+ e.Message); } } file.Close(); return; } else { List<Variable> result; if(args[0] == "-v") { Kerbulator.DEBUG = true; result = k.Run(args[1]); } else { Kerbulator.DEBUG = false; result = k.Run(args[0]); } foreach(Variable v in result) Console.Write(v.id +" = "+ v.ToString() +", "); Console.WriteLine("\n"); } }
public static void AddCelestialBody(Kerbulator kalc, CelestialBody body) { AddCelestialBody(kalc, body, body.name); }
public static void Add(Kerbulator kalc) { // Planets foreach (CelestialBody b in FlightGlobals.Bodies) { if (b.name == "Sun") { AddCelestialBody(kalc, b, "Kerbol"); } else { AddCelestialBody(kalc, b, b.name); } } Vessel v = FlightGlobals.ActiveVessel; Orbit orbit1 = v.orbit; if (v != null) { // Current orbit AddOrbit(kalc, orbit1, "Craft"); // Current position in carthesian coordinates AddVector3d(kalc, "Craft.Pos", v.GetWorldPos3D()); // Navball (thank you MechJeb source) Vector3d CoM = v.findWorldCenterOfMass(); Vector3d up = (CoM - v.mainBody.position).normalized; Vector3d north = Vector3d.Exclude(up, (v.mainBody.position + v.mainBody.transform.up * (float)v.mainBody.Radius) - CoM).normalized; Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(v.GetTransform().rotation) * rotationSurface); Vector3d velocityVesselOrbit = v.orbit.GetVel(); Vector3d velocityVesselSurface = velocityVesselOrbit - v.mainBody.getRFrmVel(CoM); AddDouble(kalc, "Navball.Heading", rotationVesselSurface.eulerAngles.y); AddDouble(kalc, "Navball.Pitch", (rotationVesselSurface.eulerAngles.x > 180) ? (360.0 - rotationVesselSurface.eulerAngles.x) : -rotationVesselSurface.eulerAngles.x); AddDouble(kalc, "Navball.Roll", (rotationVesselSurface.eulerAngles.z > 180) ? (rotationVesselSurface.eulerAngles.z - 360.0) : rotationVesselSurface.eulerAngles.z); AddDouble(kalc, "Navball.OrbitalVelocity", velocityVesselOrbit.magnitude); AddDouble(kalc, "Navball.SurfaceVelocity", velocityVesselSurface.magnitude); AddDouble(kalc, "Navball.VerticalVelocity", Vector3d.Dot(velocityVesselSurface, up)); // Current time double UT = (double)Planetarium.GetUniversalTime(); AddDouble(kalc, "UT", UT); // Reference body AddCelestialBody(kalc, v.orbit.referenceBody, "Parent"); // Target if (FlightGlobals.fetch.VesselTarget != null) { ITargetable target = FlightGlobals.fetch.VesselTarget; Orbit orbit2 = target.GetOrbit(); // Target Orbit AddOrbit(kalc, orbit2, "Target"); // Intersection with target orbit double CD = 0.0; double CCD = 0.0; double FFp = 0.0; double FFs = 0.0; double SFp = 0.0; double SFs = 0.0; int iterationCount = 0; Orbit.FindClosestPoints(orbit1, orbit2, ref CD, ref CCD, ref FFp, ref FFs, ref SFp, ref SFs, 0.0, 100, ref iterationCount); double T1 = orbit1.GetDTforTrueAnomaly(FFp, 0.0); double T2 = orbit1.GetDTforTrueAnomaly(SFp, 0.0); AddDouble(kalc, "Craft.Inter1.dt", T1); AddDouble(kalc, "Craft.Inter1.Δt", T1); AddDouble(kalc, "Craft.Inter1.Sep", (orbit1.getPositionAtUT(T1 + UT) - orbit2.getPositionAtUT(T1 + UT)).magnitude); AddDouble(kalc, "Craft.Inter1.TrueAnomaly", orbit1.TrueAnomalyAtUT(T1 + UT)); AddDouble(kalc, "Craft.Inter1.θ", orbit1.TrueAnomalyAtUT(T1 + UT)); AddDouble(kalc, "Craft.Inter2.dt", T2); AddDouble(kalc, "Craft.Inter2.Δt", T2); AddDouble(kalc, "Craft.Inter2.Sep", (orbit1.getPositionAtUT(T2 + UT) - orbit2.getPositionAtUT(T2 + UT)).magnitude); AddDouble(kalc, "Craft.Inter2.TrueAnomaly", orbit2.TrueAnomalyAtUT(T2 + UT)); AddDouble(kalc, "Craft.Inter2.θ", orbit2.TrueAnomalyAtUT(T2 + UT)); } } }
// UNITY public static void AddOrbit(Kerbulator kalc, Orbit orbit, string prefix) { if(orbit == null) return; kalc.AddGlobal(new Variable(prefix +".Ap", VarType.NUMBER, (double)orbit.ApA)); kalc.AddGlobal(new Variable(prefix +".Pe", VarType.NUMBER, (double)orbit.PeA)); kalc.AddGlobal(new Variable(prefix +".Inc", VarType.NUMBER, (double)orbit.inclination)); kalc.AddGlobal(new Variable(prefix +".Alt", VarType.NUMBER, (double)orbit.altitude)); kalc.AddGlobal(new Variable(prefix +".ArgPe", VarType.NUMBER, (double)orbit.argumentOfPeriapsis)); kalc.AddGlobal(new Variable(prefix +".ω", VarType.NUMBER, (double)orbit.argumentOfPeriapsis)); kalc.AddGlobal(new Variable(prefix +".LAN", VarType.NUMBER, (double)orbit.LAN)); kalc.AddGlobal(new Variable(prefix +".Ω", VarType.NUMBER, (double)orbit.LAN)); kalc.AddGlobal(new Variable(prefix +".TimeToAp", VarType.NUMBER, (double)orbit.timeToAp)); kalc.AddGlobal(new Variable(prefix +".TimeToPe", VarType.NUMBER, (double)orbit.timeToPe)); kalc.AddGlobal(new Variable(prefix +".Vel", VarType.NUMBER, (double)orbit.vel.magnitude)); kalc.AddGlobal(new Variable(prefix +".TrueAnomaly", VarType.NUMBER, (double)orbit.trueAnomaly)); kalc.AddGlobal(new Variable(prefix +".θ", VarType.NUMBER, (double)orbit.trueAnomaly)); if(orbit.UTsoi > 0) { kalc.AddGlobal(new Variable(prefix +".SOI.dt", VarType.NUMBER, (double)orbit.UTsoi-Planetarium.GetUniversalTime())); kalc.AddGlobal(new Variable(prefix +".SOI.Δt", VarType.NUMBER, (double)orbit.UTsoi-Planetarium.GetUniversalTime())); kalc.AddGlobal(new Variable(prefix +".SOI.TrueAnomaly", VarType.NUMBER, (double)orbit.TrueAnomalyAtUT(orbit.UTsoi))); kalc.AddGlobal(new Variable(prefix +".SOI.θ", VarType.NUMBER, (double)orbit.TrueAnomalyAtUT(orbit.UTsoi))); } }
public void Tokenize(string line) { int lineno = 1; int col = 1; Token tok = new Token(functionName, lineno, col); for (int i = 0; i < line.Length; i++, col++) { char c = line[i]; switch (c) { // Whitespace case ' ': case '\t': case '\r': if (tok.type != TokenType.SKIP_NEWLINE) { HandleToken(tok); tok = new Token(functionName, lineno, col + 1); } break; // End of statement case '\n': if (tok.type != TokenType.SKIP_NEWLINE) { HandleToken(tok); HandleToken(new Token(TokenType.END, "\\n", functionName, lineno, col)); } lineno++; col = 0; tok = new Token(functionName, lineno, col + 1); break; // Comments case '#': HandleToken(tok); // Skip to next newline int newI = line.IndexOf('\n', i + 1) - 1; if (newI < 0) { newI = line.Length - 1; } col += newI - i; i = newI; tok = new Token(functionName, lineno, col); break; // Quoted strings case '"': HandleToken(tok); tok = new Token(TokenType.TEXT, "", functionName, lineno, col); // Read until next unescaped " bool terminated = false; for (i = i + 1, col++; i < line.Length; i++, col++) { if (line[i] == '\\') { if (i >= line.Length - 1) { break; } tok.val += line[i + 1]; i += 2; col += 2; } else if (line[i] == '"') { terminated = true; break; } else { tok.val += line[i]; } } if (!terminated) { throw new Exception(tok.pos + "missing end quote (\") for string"); } HandleToken(tok); tok = new Token(functionName, lineno, col); break; // Numbers case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (tok.type == TokenType.EMPTY) { tok.type = TokenType.NUMBER; tok.val = c.ToString(); } else if (tok.type == TokenType.NUMBER || tok.type == TokenType.IDENTIFIER) { tok.val += c; } else { throw new Exception(tok.pos + c + " is invalid here"); } break; case 'e': case 'E': if (tok.type == TokenType.EMPTY) { tok.type = TokenType.IDENTIFIER; tok.val = c.ToString(); } else if (tok.type == TokenType.NUMBER || tok.type == TokenType.IDENTIFIER) { tok.val += c; if (i < line.Length - 1 && line[i + 1] == '-') { tok.val += line[i + 1].ToString(); i++; col++; } } else { throw new Exception(tok.pos + c + " is invalid here"); } break; case '.': if (tok.type == TokenType.EMPTY) { tok.type = TokenType.NUMBER; tok.val = c.ToString(); } else if (tok.type == TokenType.NUMBER) { if (tok.val.IndexOf(c) >= 0) { throw new Exception(tok.pos + "numbers can only have one decimal point (.) in them"); } tok.val += c; } else if (tok.type == TokenType.IDENTIFIER) { tok.val += c; } else { throw new Exception(tok.pos + "variable/function names cannot start with a dot (.)"); } break; // Operators case '-': case '+': case '/': case '÷': case '√': case '%': case '*': case '·': case '×': case '^': case '≤': case '≥': case '≠': case '¬': case '∧': case '∨': HandleToken(tok); HandleToken(new Token(TokenType.OPERATOR, c.ToString(), functionName, lineno, col)); tok = new Token(functionName, lineno, col + 1); break; // Operators that can possibly expand to two characters (<=, =>, ==, !=) case '<': HandleToken(tok); if (i < line.Length - 1 && line[i + 1] == '=') { HandleToken(new Token(TokenType.OPERATOR, "<=", functionName, lineno, col)); col++; i++; } else { HandleToken(new Token(TokenType.OPERATOR, "<", functionName, lineno, col)); } tok = new Token(functionName, lineno, col + 1); break; case '>': HandleToken(tok); if (i < line.Length - 1 && line[i + 1] == '=') { HandleToken(new Token(TokenType.OPERATOR, ">=", functionName, lineno, col)); col++; i++; } else { HandleToken(new Token(TokenType.OPERATOR, ">", functionName, lineno, col)); } tok = new Token(functionName, lineno, col + 1); break; case '!': HandleToken(tok); if (i < line.Length - 1 && line[i + 1] == '=') { HandleToken(new Token(TokenType.OPERATOR, "!=", functionName, lineno, col)); col++; i++; } else { HandleToken(new Token(TokenType.OPERATOR, "!", functionName, lineno, col)); } tok = new Token(functionName, lineno, col + 1); break; // The =, ==, ={ case case '=': HandleToken(tok); if (i < line.Length - 1 && line[i + 1] == '=') { HandleToken(new Token(TokenType.OPERATOR, "==", functionName, lineno, col)); col++; i++; } else if (i < line.Length - 1 && line[i + 1] == '{') { HandleToken(new Token(TokenType.PIECEWISE, "={", functionName, lineno, col)); col++; i++; } else { HandleToken(new Token(TokenType.ASSIGN, "=", functionName, lineno, col)); } tok = new Token(functionName, lineno, col + 1); break; // Brackets case '[': case ']': HandleToken(tok); HandleToken(new Token(TokenType.LIST, c.ToString(), functionName, lineno, col)); tok = new Token(functionName, lineno, col + 1); break; case '(': case ')': case '{': case '}': case '⌊': case '⌋': case '⌈': case '⌉': case '|': HandleToken(tok); HandleToken(new Token(TokenType.BRACE, c.ToString(), functionName, lineno, col)); tok = new Token(functionName, lineno, col + 1); break; // In: and Out: statements case ':': if (tok.val == "in") { HandleToken(new Token(TokenType.IN, tok.val, functionName, lineno, col)); } else if (tok.val == "out") { HandleToken(new Token(TokenType.OUT, tok.val, functionName, lineno, col)); } else { HandleToken(tok); HandleToken(new Token(TokenType.COLON, tok.val, functionName, lineno, col)); } tok = new Token(functionName, lineno, col + 1); break; // Others case ',': HandleToken(tok); HandleToken(new Token(TokenType.COMMA, c.ToString(), functionName, lineno, col)); tok = new Token(functionName, lineno, col + 1); break; case '\\': HandleToken(tok); tok = new Token(TokenType.SKIP_NEWLINE, c.ToString(), functionName, lineno, col); break; default: if (tok.type != TokenType.EMPTY && tok.type != TokenType.IDENTIFIER) { throw new Exception(tok.pos + "unexpected character: " + c); } tok.type = TokenType.IDENTIFIER; tok.val += c; break; } } HandleToken(tok); Kerbulator.Debug("\n"); }
public Expression ParseExpression() { Stack <Expression> expr = new Stack <Expression>(); Stack <Operator> ops = new Stack <Operator>(); bool end = false; // If ever set to true, this is the end of the expression if (tokens.Count == 0) { throw new Exception("empty expression"); } Token t = tokens.Peek(); while (!end && tokens.Count > 0 && tokens.Peek().type != TokenType.END) { t = tokens.Peek(); Kerbulator.DebugLine("Token: " + Enum.GetName(typeof(TokenType), t.type) + ": " + t.val); switch (t.type) { case TokenType.NUMBER: ParseNumber(expr); break; case TokenType.OPERATOR: ParseOperator(expr, ops); break; case TokenType.BRACE: end = ParseBrace(expr, ops); break; case TokenType.LIST: end = ParseList(expr); break; case TokenType.IDENTIFIER: ParseIdentifier(expr, ops); break; case TokenType.COMMA: end = true; break; case TokenType.EQUALS: end = true; break; default: Consume(); break; } } // Handle remaining ops while (ops.Count > 0) { Operator op = ops.Pop(); expr.Push(ExecuteOperator(op, expr, ops, t.pos)); } if (expr.Count > 1) { throw new Exception(t.pos + "malformed expression"); } return(expr.Pop()); }
public static void AddBool(Kerbulator kalc, string id, bool v) { double val = v ? 1.0 : 0.0; Variable g = new Variable(id, VarType.NUMBER, val); kalc.AddGlobal(g); }
public static void AddCelestialBody(Kerbulator kalc, CelestialBody body, string prefix) { if(body == null) return; try { if(body.orbit != null) { AddOrbit(kalc, body.orbit, prefix); } } catch(Exception) { // Somehow, testing body.orbit != null is not enough. I don't know why... // Leave a pull request or file an issue if you can help me figure this out! } kalc.AddGlobal(new Variable(prefix +".R", VarType.NUMBER, (double)body.Radius)); kalc.AddGlobal(new Variable(prefix +".M", VarType.NUMBER, (double)body.Mass)); kalc.AddGlobal(new Variable(prefix +".mu", VarType.NUMBER, (double)body.gravParameter)); kalc.AddGlobal(new Variable(prefix +".μ", VarType.NUMBER, (double)body.gravParameter)); kalc.AddGlobal(new Variable(prefix +".day", VarType.NUMBER, (double)body.rotationPeriod)); kalc.AddGlobal(new Variable(prefix +".SOI", VarType.NUMBER, (double)body.sphereOfInfluence)); kalc.AddGlobal(new Variable(prefix +".AtmosHeight", VarType.NUMBER, (double)body.maxAtmosphereAltitude)); kalc.AddGlobal(new Variable(prefix +".AtmosPress", VarType.NUMBER, (double)body.atmosphereMultiplier * 101325.0)); }
private Expression ExecuteOperator(Operator op, Stack <Expression> expr, Stack <Operator> ops, string pos) { Kerbulator.DebugLine("Executing: " + op.id); if (op.arity == Arity.BINARY && expr.Count < 2) { throw new Exception(pos + "operator " + op.id + " expects both a left and a right hand side to operate on."); } else if (op.arity == Arity.UNARY && expr.Count < 1) { throw new Exception(pos + "operator " + op.id + " expects a right hand side to operate on."); } else if (op.arity == Arity.BOTH) { throw new Exception(pos + "arity of " + op.id + " still undefined."); } Expression a, b; Expression opExpression; switch (op.id) { case "+": b = expr.Pop(); a = expr.Pop(); opExpression = CallBinaryLambda(op.id, (x, y) => x + y, a, b, pos); break; case "-": b = expr.Pop(); if (op.arity == Arity.UNARY) { opExpression = CallUnaryLambda(op.id, x => - x, b, pos); } else { a = expr.Pop(); opExpression = CallBinaryLambda(op.id, (x, y) => x - y, a, b, pos); } break; case "*": case "·": case "×": b = expr.Pop(); a = expr.Pop(); opExpression = CallBinaryLambda(op.id, (x, y) => x * y, a, b, pos); break; case "/": case "÷": b = expr.Pop(); a = expr.Pop(); opExpression = CallBinaryLambda(op.id, (x, y) => x / y, a, b, pos); break; case "%": b = expr.Pop(); a = expr.Pop(); opExpression = CallBinaryLambda(op.id, (x, y) => x % y, a, b, pos); break; case "^": b = expr.Pop(); a = expr.Pop(); opExpression = CallBinaryMathFunction(op.id, "Pow", a, b, pos); break; case "√": b = expr.Pop(); if (op.arity == Arity.UNARY) { opExpression = CallUnaryMathFunction(op.id, "Sqrt", b, pos); } else { a = expr.Pop(); opExpression = CallBinaryMathFunction(op.id, "Pow", b, CallUnaryLambda(op.id, x => 1 / x, a, pos), pos ); } break; case "⌊": b = expr.Pop(); opExpression = CallUnaryMathFunction(op.id, "Floor", b, pos); break; case "⌈": b = expr.Pop(); opExpression = CallUnaryMathFunction(op.id, "Ceiling", b, pos); break; case "|": b = expr.Pop(); opExpression = Expression.Condition( Expression.TypeIs(b, typeof(double)), CallUnaryMathFunction(op.id, "Abs", b, pos), Expression.Call( typeof(VectorMath).GetMethod("Mag"), b, Expression.Constant(pos) ) ); break; case "buildin-function": List <Expression> args = new List <Expression>(); args.Add(expr.Pop()); a = expr.Pop(); opExpression = ParseBuildInFunction(kalc.BuildInFunctions[(string)((ConstantExpression)a).Value], args, pos); break; case "user-function": List <Expression> args2 = new List <Expression>(); args2.Add(expr.Pop()); a = expr.Pop(); return(ParseUserFunction( (string)((ConstantExpression)a).Value, args2, pos )); default: throw new Exception(pos + "unknown operator: " + op.id); } return(Expression.Convert(opExpression, typeof(Object))); }
public static void AddBool(Kerbulator kalc, string id, bool v) { double val = v ? 1.0 : 0.0; AddDouble(kalc, id, val); }
public static void AddVector3(Kerbulator kalc, string prefix, Vector3 v) { AddDouble(kalc, prefix + ".x", (double)v.x); AddDouble(kalc, prefix + ".y", (double)v.y); AddDouble(kalc, prefix + ".z", (double)v.z); }
public static void AddDouble(Kerbulator kalc, string id, double v) { Variable g = new Variable(id, VarType.NUMBER, v); kalc.AddGlobal(g); }