mirror of
https://github.com/Krafpy/KSP-MGA-Planner.git
synced 2025-12-12 07:40:41 -08:00
Merge pull request #20 from Krafpy/converter-stock-combine
Combine with stock checkbox
This commit is contained in:
@@ -7,8 +7,8 @@
|
||||
# mass: kg
|
||||
# stdGravParam: m^3/s^2
|
||||
# soi: m
|
||||
# apoapsis: m
|
||||
# periapsis: m
|
||||
# apoapsis: m - optional
|
||||
# periapsis: m - optional
|
||||
# eccentricity: None
|
||||
# inclination: ° (degrees)
|
||||
# argOfPeriapsis: °
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
# EDIT NOTES FOR CUSTOM SOLAR SYSTEMS
|
||||
|
||||
# If your solar system uses Kopernicus' configuration files, you can directly convert them
|
||||
# into a `bodies.yml` file on this page : https://krafpy.github.io/KSP-MGA-Planner/tools/cfg-to-yml/
|
||||
|
||||
# For custom solar systems, the following rules apply to all `bodies.yml`:
|
||||
# - Follow the exact same format (names, indentations) as used in this file
|
||||
# - Numerical data must follow the units described above
|
||||
# - Each body has a unique ID, it must be an integer between 0 and N-1, where N is the number of bodies
|
||||
|
||||
19
dist/tools/cfg-to-yml/body-data.js
vendored
19
dist/tools/cfg-to-yml/body-data.js
vendored
@@ -58,6 +58,25 @@ export function parseToBodyConfig(bodyConfig, templateBodies) {
|
||||
},
|
||||
};
|
||||
}
|
||||
export function completeBodytoUnorderedData(body) {
|
||||
return {
|
||||
name: body.name,
|
||||
radius: body.radius,
|
||||
mass: body.mass,
|
||||
stdGravParam: body.stdGravParam,
|
||||
soi: body.soi,
|
||||
orbit: {
|
||||
semiMajorAxis: body.orbit.semiMajorAxis,
|
||||
eccentricity: body.orbit.eccentricity,
|
||||
inclination: body.orbit.inclination,
|
||||
argOfPeriapsis: body.orbit.argOfPeriapsis,
|
||||
ascNodeLongitude: body.orbit.ascNodeLongitude,
|
||||
},
|
||||
meanAnomaly0: body.meanAnomaly0,
|
||||
epoch: body.epoch,
|
||||
color: body.color,
|
||||
};
|
||||
}
|
||||
function deduceStdGravParamAndMass(bodyConfig, radius, template) {
|
||||
let stdGravParam = 0, mass = 0;
|
||||
if (bodyConfig.Properties.gravParameter !== undefined) {
|
||||
|
||||
45
dist/tools/cfg-to-yml/main.js
vendored
45
dist/tools/cfg-to-yml/main.js
vendored
@@ -1,5 +1,5 @@
|
||||
import { loadBodiesData } from "../../main/utilities/data.js";
|
||||
import { orderOrbitingBodies, parseToBodyConfig, parseToSunConfig, recomputeSOIs } from "./body-data.js";
|
||||
import { completeBodytoUnorderedData, orderOrbitingBodies, parseToBodyConfig, parseToSunConfig, recomputeSOIs } from "./body-data.js";
|
||||
import { parseConfigNodes } from "./cfg-parser.js";
|
||||
import { dumpBodyToYaml, dumpSunToYaml, joinYamlBlocks } from "./dump.js";
|
||||
import { readFilesFromInput } from "./file-reader.js";
|
||||
@@ -16,6 +16,7 @@ async function main() {
|
||||
const convertBtn = document.getElementById("convert-btn");
|
||||
const downloadBtn = document.getElementById("download-btn");
|
||||
const filesInput = document.getElementById("files-input");
|
||||
const combineChkBox = document.getElementById("combine-checkbox");
|
||||
const convert = async () => {
|
||||
var _a;
|
||||
if (!((_a = filesInput.files) === null || _a === void 0 ? void 0 : _a.length))
|
||||
@@ -30,12 +31,18 @@ async function main() {
|
||||
configs.push(parseConfigNodes(content));
|
||||
}
|
||||
const sunConfig = configs.find(c => { var _a; return ((_a = c.Orbit) === null || _a === void 0 ? void 0 : _a.referenceBody) === undefined; });
|
||||
if (sunConfig === undefined) {
|
||||
throw new Error("Sun configuration not found.");
|
||||
let sun;
|
||||
if (sunConfig !== undefined) {
|
||||
const unorderedSun = parseToSunConfig(sunConfig, template);
|
||||
sun = { id: 0, ...unorderedSun };
|
||||
}
|
||||
else {
|
||||
if (!combineChkBox.checked) {
|
||||
throw new Error("Sun configuration not found.");
|
||||
}
|
||||
TextareaLogger.log("Using stock Sun");
|
||||
sun = template.get("Sun");
|
||||
}
|
||||
const unorderedSun = parseToSunConfig(sunConfig, template);
|
||||
const sun = { id: 0, ...unorderedSun };
|
||||
TextareaLogger.log(`Ordering...`);
|
||||
const orbitingUnordered = [];
|
||||
for (const config of configs) {
|
||||
if (config.Orbit) {
|
||||
@@ -43,6 +50,10 @@ async function main() {
|
||||
orbitingUnordered.push(orbiting);
|
||||
}
|
||||
}
|
||||
if (combineChkBox.checked) {
|
||||
completeWithStock(orbitingUnordered, stockBodies.bodies, sun.name);
|
||||
}
|
||||
TextareaLogger.log(`Ordering...`);
|
||||
const orbiting = orderOrbitingBodies(orbitingUnordered, sun.name);
|
||||
TextareaLogger.log("Recomputing SOIs...");
|
||||
recomputeSOIs(orbiting, sun);
|
||||
@@ -50,14 +61,34 @@ async function main() {
|
||||
const sunYml = dumpSunToYaml(sun);
|
||||
const orbitingYml = orbiting.map(body => dumpBodyToYaml(body));
|
||||
const yml = joinYamlBlocks([sunYml, ...orbitingYml]);
|
||||
TextareaLogger.log(`\nSuccessfully converted solar system data.`);
|
||||
downloadBtn.onclick = () => download("bodies.yml", yml);
|
||||
TextareaLogger.log(`\nSuccessfully converted solar system data.`);
|
||||
TextareaLogger.log(`Click to download \`bodies.yml\``);
|
||||
};
|
||||
convertBtn.onclick = () => {
|
||||
convert().catch(reason => TextareaLogger.error(reason));
|
||||
};
|
||||
}
|
||||
function completeWithStock(unorderedOrbiting, stockOrbiting, sunName) {
|
||||
const definedOrbiting = new Set();
|
||||
for (const { data } of unorderedOrbiting) {
|
||||
definedOrbiting.add(data.name);
|
||||
}
|
||||
for (const body of stockOrbiting) {
|
||||
if (definedOrbiting.has(body.name))
|
||||
continue;
|
||||
TextareaLogger.log(`Using stock ${body.name}`);
|
||||
let referenceBody = sunName;
|
||||
if (body.orbiting != 0) {
|
||||
const idx = body.orbiting - 1;
|
||||
referenceBody = stockOrbiting[idx].name;
|
||||
}
|
||||
unorderedOrbiting.push({
|
||||
referenceBody,
|
||||
data: completeBodytoUnorderedData(body)
|
||||
});
|
||||
}
|
||||
}
|
||||
function download(filename, text) {
|
||||
const element = document.createElement('a');
|
||||
const encoded = encodeURIComponent(text);
|
||||
|
||||
@@ -76,6 +76,27 @@ export function parseToBodyConfig(bodyConfig: any, templateBodies: Map<string, I
|
||||
};
|
||||
}
|
||||
|
||||
export function completeBodytoUnorderedData(body: IOrbitingBody): IOrbitingBody_Unordered {
|
||||
return {
|
||||
name: body.name,
|
||||
radius: body.radius,
|
||||
mass: body.mass,
|
||||
stdGravParam: body.stdGravParam,
|
||||
soi: body.soi,
|
||||
orbit:
|
||||
{
|
||||
semiMajorAxis: body.orbit.semiMajorAxis,
|
||||
eccentricity: body.orbit.eccentricity,
|
||||
inclination: body.orbit.inclination,
|
||||
argOfPeriapsis: body.orbit.argOfPeriapsis,
|
||||
ascNodeLongitude: body.orbit.ascNodeLongitude,
|
||||
},
|
||||
meanAnomaly0: body.meanAnomaly0,
|
||||
epoch: body.epoch,
|
||||
color: body.color,
|
||||
};
|
||||
}
|
||||
|
||||
function deduceStdGravParamAndMass(bodyConfig: any, radius: number, template?: ICelestialBody){
|
||||
let stdGravParam = 0, mass = 0;
|
||||
|
||||
@@ -93,7 +114,6 @@ function deduceStdGravParamAndMass(bodyConfig: any, radius: number, template?: I
|
||||
} else {
|
||||
stdGravParam = template?.stdGravParam as number;
|
||||
}
|
||||
|
||||
return {stdGravParam, mass: mass != 0 ? mass : stdGravParam / GRAVITY_CONSTANT};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { loadBodiesData } from "../../main/utilities/data.js";
|
||||
import { orderOrbitingBodies, parseToBodyConfig, parseToSunConfig, recomputeSOIs } from "./body-data.js";
|
||||
import { completeBodytoUnorderedData, orderOrbitingBodies, parseToBodyConfig, parseToSunConfig, recomputeSOIs } from "./body-data.js";
|
||||
import { parseConfigNodes } from "./cfg-parser.js";
|
||||
import { dumpBodyToYaml, dumpSunToYaml, joinYamlBlocks } from "./dump.js";
|
||||
import { readFilesFromInput } from "./file-reader.js";
|
||||
@@ -20,6 +20,7 @@ async function main(){
|
||||
const convertBtn = document.getElementById("convert-btn") as HTMLButtonElement;
|
||||
const downloadBtn = document.getElementById("download-btn") as HTMLButtonElement;
|
||||
const filesInput = document.getElementById("files-input") as HTMLInputElement;
|
||||
const combineChkBox = document.getElementById("combine-checkbox") as HTMLInputElement;
|
||||
|
||||
const convert = async () => {
|
||||
if(!filesInput.files?.length) return;
|
||||
@@ -39,13 +40,17 @@ async function main(){
|
||||
|
||||
// extract ICelestiaBody data for the sun
|
||||
const sunConfig = configs.find(c => c.Orbit?.referenceBody === undefined);
|
||||
if(sunConfig === undefined){
|
||||
throw new Error("Sun configuration not found.");
|
||||
let sun: ICelestialBody;
|
||||
if(sunConfig !== undefined){
|
||||
const unorderedSun = parseToSunConfig(sunConfig, template);
|
||||
sun = {id: 0, ...unorderedSun};
|
||||
} else {
|
||||
if(!combineChkBox.checked){
|
||||
throw new Error("Sun configuration not found.");
|
||||
}
|
||||
TextareaLogger.log("Using stock Sun");
|
||||
sun = template.get("Sun") as ICelestialBody;
|
||||
}
|
||||
const unorderedSun = parseToSunConfig(sunConfig, template);
|
||||
const sun: ICelestialBody = {id: 0, ...unorderedSun};
|
||||
|
||||
TextareaLogger.log(`Ordering...`);
|
||||
|
||||
// extract IOribitingBody_Unordered (without id and orbiting)
|
||||
// data for other bodies
|
||||
@@ -57,6 +62,14 @@ async function main(){
|
||||
}
|
||||
}
|
||||
|
||||
// Combine with stock bodies, only add ones that have not been redefined
|
||||
// in a cfg file
|
||||
if(combineChkBox.checked){
|
||||
completeWithStock(orbitingUnordered, stockBodies.bodies, sun.name);
|
||||
}
|
||||
|
||||
TextareaLogger.log(`Ordering...`);
|
||||
|
||||
// Compute bodies's ids and sort them in the correct order
|
||||
const orbiting = orderOrbitingBodies(orbitingUnordered, sun.name);
|
||||
|
||||
@@ -71,10 +84,9 @@ async function main(){
|
||||
const orbitingYml = orbiting.map(body => dumpBodyToYaml(body));
|
||||
const yml = joinYamlBlocks([sunYml, ...orbitingYml]);
|
||||
|
||||
TextareaLogger.log(`\nSuccessfully converted solar system data.`);
|
||||
|
||||
downloadBtn.onclick = () => download("bodies.yml", yml);
|
||||
|
||||
TextareaLogger.log(`\nSuccessfully converted solar system data.`);
|
||||
TextareaLogger.log(`Click to download \`bodies.yml\``);
|
||||
};
|
||||
|
||||
@@ -83,14 +95,37 @@ async function main(){
|
||||
};
|
||||
}
|
||||
|
||||
function completeWithStock(unorderedOrbiting: ParsedUnorderedOrbitingData[], stockOrbiting: IOrbitingBody[], sunName: string){
|
||||
const definedOrbiting = new Set<string>();
|
||||
for(const {data} of unorderedOrbiting) {
|
||||
definedOrbiting.add(data.name);
|
||||
}
|
||||
|
||||
for(const body of stockOrbiting){
|
||||
if(definedOrbiting.has(body.name)) continue;
|
||||
|
||||
TextareaLogger.log(`Using stock ${body.name}`);
|
||||
|
||||
let referenceBody = sunName;
|
||||
if(body.orbiting != 0){
|
||||
const idx = body.orbiting - 1;
|
||||
referenceBody = stockOrbiting[idx].name;
|
||||
}
|
||||
unorderedOrbiting.push({
|
||||
referenceBody,
|
||||
data: completeBodytoUnorderedData(body)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function download(filename: string, text: string) {
|
||||
const element = document.createElement('a');
|
||||
const encoded = encodeURIComponent(text);
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encoded);
|
||||
element.setAttribute('download', filename);
|
||||
|
||||
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" href="#">
|
||||
<link rel="stylesheet" type="text/css" href="./../../style.css">
|
||||
<!--<link rel="stylesheet" type="text/css" href="./../../style.css">-->
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<title>CFG converter for MGA Planner</title>
|
||||
</head>
|
||||
@@ -15,21 +15,30 @@
|
||||
<h2>Kopernicus .CFG converter for <a href="https://krafpy.github.io/KSP-MGA-Planner/">KSP MGA Planner</a></h2>
|
||||
<p>
|
||||
Use this page to quickly convert Kopernicus' configuration files (.cfg) of solar systems to the `bodies.yml`
|
||||
file used by the MGA planner tool.
|
||||
file used by MGA planner.
|
||||
</p>
|
||||
<p>
|
||||
Select all .cfg files describing the solar system's bodies <em>only</em>, including the sun.
|
||||
Select all .cfg files describing the solar system's bodies <em>only</em>.
|
||||
Check the "Combine with stock" checkbox if the solar system is an extension to the stock one: missing configuration
|
||||
files for stock bodies will be added automatically.
|
||||
<p>
|
||||
Follow then <strong><a href="https://github.com/Krafpy/KSP-MGA-Planner#solar-systems-support">these steps</a></strong> to
|
||||
add the new solar system to the tool by contributing to the repository.
|
||||
Follow then <strong><a href="https://github.com/Krafpy/KSP-MGA-Planner#solar-systems-support">these steps</a></strong>
|
||||
to add the new solar system to the tool by contributing to the repository.
|
||||
</p>
|
||||
<div id="inputs">
|
||||
<input id="files-input" type="file" multiple>
|
||||
<div id="btns-div">
|
||||
<div id="controls">
|
||||
<div id="inputs">
|
||||
<input id="files-input" type="file" multiple>
|
||||
<div id="checkbox-container">
|
||||
<input id="combine-checkbox" name="combine-checkbox" type="checkbox">
|
||||
<label for="combine-checkbox">Combine with stock</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<button id="convert-btn">Convert</button>
|
||||
<button id="download-btn">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea name="log-box" id="log-box" rows="7" readonly></textarea>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,58 @@
|
||||
body
|
||||
{
|
||||
font-family: "Helvetica Neue", Helvetica;
|
||||
/*background-color: #222425;*/
|
||||
background: #1c1e1f;
|
||||
color: rgb(200, 195, 188);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
p
|
||||
{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
a:link
|
||||
{
|
||||
color: rgb(86, 169, 224);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover
|
||||
{
|
||||
color: rgb(116, 190, 240);
|
||||
}
|
||||
|
||||
#container
|
||||
{
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 50px;
|
||||
width: 570px;
|
||||
}
|
||||
|
||||
#inputs
|
||||
#controls
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#files-input
|
||||
{
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#combine-checkbox
|
||||
{
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#checkbox-container label
|
||||
{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#log-box
|
||||
{
|
||||
width: 100%;
|
||||
@@ -38,9 +75,4 @@
|
||||
button
|
||||
{
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
/*p, button, input
|
||||
{
|
||||
font-size: 0.85em;
|
||||
}*/
|
||||
}
|
||||
Reference in New Issue
Block a user