diff --git a/src/com/pesterenan/MechPeste.java b/src/com/pesterenan/MechPeste.java index 4f6fc12..71f917c 100644 --- a/src/com/pesterenan/MechPeste.java +++ b/src/com/pesterenan/MechPeste.java @@ -1,26 +1,30 @@ package com.pesterenan; +import static com.pesterenan.views.StatusJPanel.isBtnConnectVisible; +import static com.pesterenan.views.StatusJPanel.setStatusMessage; + +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.swing.*; + import com.pesterenan.model.ActiveVessel; import com.pesterenan.resources.Bundle; import com.pesterenan.utils.Vector; +import com.pesterenan.views.CreateManeuverJPanel; import com.pesterenan.views.FunctionsAndTelemetryJPanel; import com.pesterenan.views.MainGui; + import krpc.client.Connection; import krpc.client.RPCException; import krpc.client.services.KRPC; import krpc.client.services.SpaceCenter; +import krpc.client.services.SpaceCenter.Node; import krpc.client.services.SpaceCenter.Vessel; -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static com.pesterenan.views.StatusJPanel.isBtnConnectVisible; -import static com.pesterenan.views.StatusJPanel.setStatusMessage; - public class MechPeste { private static KRPC krpc; private static MechPeste mechPeste; @@ -70,6 +74,24 @@ public static ListModel getActiveVessels(String search) { return list; } + public static ListModel getCurrentManeuvers() { + DefaultListModel list = new DefaultListModel<>(); + try { + List maneuvers = getSpaceCenter().getActiveVessel().getControl().getNodes(); + maneuvers.forEach(m -> { + try { + String maneuverStr = String.format("%d - Dv: %.1f {P: %.1f, N: %.1f, R: %.1f} AP: %.1f, PE: %.1f", + maneuvers.indexOf(m) + 1, m.getDeltaV(), m.getPrograde(), m.getNormal(), m.getRadial(), + m.getOrbit().getApoapsisAltitude(), m.getOrbit().getPeriapsisAltitude()); + list.addElement(maneuverStr); + } catch (RPCException ignored) { + } + }); + } catch (RPCException | NullPointerException ignored) { + } + return list; + } + private static boolean filterVessels(Vessel vessel, String search) { if (search == "all") { return true; @@ -98,13 +120,13 @@ private static boolean filterVessels(Vessel vessel, String search) { public static String getVesselInfo(int selectedIndex) { try { - Vessel naveAtual = - spaceCenter.getVessels().stream().filter(v -> v.hashCode() == selectedIndex).findFirst().get(); + Vessel naveAtual = spaceCenter.getVessels().stream().filter(v -> v.hashCode() == selectedIndex).findFirst() + .get(); String name = naveAtual.getName().length() > 40 - ? naveAtual.getName().substring(0, 40) + "..." - : naveAtual.getName(); - String vesselInfo = - String.format("Nome: %s\t\t\t | Corpo: %s", name, naveAtual.getOrbit().getBody().getName()); + ? naveAtual.getName().substring(0, 40) + "..." + : naveAtual.getName(); + String vesselInfo = String.format("Nome: %s\t\t\t | Corpo: %s", name, + naveAtual.getOrbit().getBody().getName()); return vesselInfo; } catch (RPCException | NullPointerException ignored) { } @@ -113,8 +135,8 @@ public static String getVesselInfo(int selectedIndex) { public static void changeToVessel(int selectedIndex) { try { - Vessel naveAtual = - spaceCenter.getVessels().stream().filter(v -> v.hashCode() == selectedIndex).findFirst().get(); + Vessel naveAtual = spaceCenter.getVessels().stream().filter(v -> v.hashCode() == selectedIndex).findFirst() + .get(); spaceCenter.setActiveVessel(naveAtual); } catch (RPCException | NullPointerException e) { System.out.println(Bundle.getString("status_couldnt_switch_vessel")); @@ -140,10 +162,11 @@ private void checkActiveVessel() { } if (currentVesselId != -1) { currentVessel.recordTelemetryData(); - if (currentVessel.hasModuleRunning()){ + if (currentVessel.hasModuleRunning()) { setStatusMessage(currentVessel.getCurrentStatus()); } FunctionsAndTelemetryJPanel.updateTelemetry(currentVessel.getTelemetryData()); + CreateManeuverJPanel.updatePanel(getCurrentManeuvers()); } Thread.sleep(100); } catch (RPCException | InterruptedException ignored) { @@ -185,4 +208,4 @@ public void checkConnection() { public static void cancelControl(ActionEvent e) { currentVessel.cancelControl(); } -} \ No newline at end of file +} diff --git a/src/com/pesterenan/controllers/LiftoffController.java b/src/com/pesterenan/controllers/LiftoffController.java index 77a437f..4f5259e 100644 --- a/src/com/pesterenan/controllers/LiftoffController.java +++ b/src/com/pesterenan/controllers/LiftoffController.java @@ -126,7 +126,7 @@ private void finalizeCurve() throws RPCException, StreamException, InterruptedEx private void circularizeOrbitOnApoapsis() { setCurrentStatus(Bundle.getString("status_planning_orbit")); Map commands = new HashMap<>(); - commands.put(Modulos.MODULO.get(), Modulos.MODULO_EXEC_MANOBRAS.get()); + commands.put(Modulos.MODULO.get(), Modulos.MODULE_MANEUVER.get()); commands.put(Modulos.FUNCAO.get(), Modulos.APOASTRO.get()); commands.put(Modulos.AJUSTE_FINO.get(), String.valueOf(false)); MechPeste.newInstance().startModule(commands); diff --git a/src/com/pesterenan/controllers/ManeuverController.java b/src/com/pesterenan/controllers/ManeuverController.java index 745e24f..98449a5 100644 --- a/src/com/pesterenan/controllers/ManeuverController.java +++ b/src/com/pesterenan/controllers/ManeuverController.java @@ -1,9 +1,13 @@ package com.pesterenan.controllers; import com.pesterenan.resources.Bundle; +import com.pesterenan.utils.Attributes; import com.pesterenan.utils.ControlePID; import com.pesterenan.utils.Modulos; import com.pesterenan.utils.Navigation; +import com.pesterenan.utils.Vector; +import com.pesterenan.views.RunManeuverJPanel; + import krpc.client.RPCException; import krpc.client.Stream; import krpc.client.StreamException; @@ -11,6 +15,8 @@ import krpc.client.services.SpaceCenter.Node; import krpc.client.services.SpaceCenter.Orbit; import krpc.client.services.SpaceCenter.RCS; +import krpc.client.services.SpaceCenter.ReferenceFrame; +import krpc.client.services.SpaceCenter.Vessel; import krpc.client.services.SpaceCenter.VesselSituation; import org.javatuples.Triplet; @@ -39,30 +45,60 @@ public ManeuverController(Map commands) { private void initializeParameters() { ctrlRCS.adjustOutput(0.5, 1.0); fineAdjustment = canFineAdjust(commands.get(Modulos.AJUSTE_FINO.get())); - lowOrbitAltitude = calculateSafeLowOrbitAltitude(); + try { + lowOrbitAltitude = new Attributes().getLowOrbitAltitude(currentBody.getName()); + System.out.println("lowOrbitAltitude: " + lowOrbitAltitude); + } catch (RPCException e) { + } } @Override public void run() { calculateManeuver(); - executeNextManeuver(); + if (!(commands.get(Modulos.FUNCAO.get()).equals(Modulos.RENDEZVOUS.get()) + || commands.get(Modulos.FUNCAO.get()).equals(Modulos.ORBITA_BAIXA.get()) + || commands.get(Modulos.FUNCAO.get()).equals(Modulos.AJUSTAR.get()))) { + executeNextManeuver(); + } } - private double calculateSafeLowOrbitAltitude() { - final double safeAltitude = 20000; - double bodyRadius = 0, atmosphereDepth = 0; + private Node biEllipticTransferToOrbit(double targetAltitude, double timeToStart) { + double[] totalDv = { 0, 0, 0 }; try { - bodyRadius = currentBody.getEquatorialRadius(); - atmosphereDepth = currentBody.getAtmosphereDepth(); - } catch (RPCException ignored) { + Orbit currentOrbit = getNaveAtual().getOrbit(); + double startingRadius = currentOrbit.getApoapsis(); + double gravParameter = currentBody.getGravitationalParameter(); + + // Delta-v required to leave the current orbit + double deltaV1 = Math.sqrt(2 * gravParameter / startingRadius) - Math.sqrt(gravParameter / startingRadius); + + // Calculate the intermediate radius for the intermediate orbit + double intermediateRadius = currentBody.getEquatorialRadius() + targetAltitude; + + // Delta-v required to enter the intermediate orbit + double deltaV2 = Math.sqrt(gravParameter / intermediateRadius) + - Math.sqrt(2 * gravParameter / intermediateRadius); + + // Calculate the final radius for the target orbit + double targetRadius = currentBody.getEquatorialRadius() + targetAltitude; + + // Delta-v required to leave the intermediate orbit and enter the target orbit + double deltaV3 = Math.sqrt(2 * gravParameter / intermediateRadius) + - Math.sqrt(gravParameter / intermediateRadius); + double deltaV4 = Math.sqrt(gravParameter / targetRadius) - Math.sqrt(2 * gravParameter / targetRadius); + + // Total delta-v for the bi-elliptic transfer + totalDv[0] = deltaV1 + deltaV2 + deltaV3 + deltaV4; + } catch (RPCException e) { + // Handle the exception } - return bodyRadius + (atmosphereDepth > 0 ? atmosphereDepth + safeAltitude : safeAltitude); + return createManeuver(timeToStart, totalDv); } public void calculateManeuver() { try { tuneAutoPilot(); - System.out.println(commands); + System.out.println(commands + " calculate maneuvers"); if (commands.get(Modulos.FUNCAO.get()).equals(Modulos.EXECUTAR.get())) { return; } @@ -71,12 +107,15 @@ public void calculateManeuver() { throw new InterruptedException(); } if (commands.get(Modulos.FUNCAO.get()).equals(Modulos.AJUSTAR.get())) { - this.alignPlanes(); + this.alignPlanesWithTargetVessel(); + return; + } + if (commands.get(Modulos.FUNCAO.get()).equals(Modulos.RENDEZVOUS.get())) { + this.rendezvousWithTargetVessel(); return; } if (commands.get(Modulos.FUNCAO.get()).equals(Modulos.ORBITA_BAIXA.get())) { - hohmannTransferToOrbit(lowOrbitAltitude, getNaveAtual().getOrbit().getTimeToPeriapsis()); - hohmannTransferToOrbit(lowOrbitAltitude, getNaveAtual().getOrbit().getTimeToPeriapsis()); + biEllipticTransferToOrbit(lowOrbitAltitude, getNaveAtual().getOrbit().getTimeToPeriapsis()); return; } double gravParameter = currentBody.getGravitationalParameter(); @@ -105,7 +144,7 @@ public void matchOrbitApoapsis() { try { Orbit targetOrbit = getTargetOrbit(); System.out.println(targetOrbit.getApoapsis() + "-- APO"); - Node maneuver = hohmannTransferToOrbit(targetOrbit.getApoapsis(), + Node maneuver = biEllipticTransferToOrbit(targetOrbit.getApoapsis(), getNaveAtual().getOrbit().getTimeToPeriapsis()); while (true) { if (Thread.interrupted()) { @@ -128,27 +167,6 @@ public void matchOrbitApoapsis() { } } - private Node hohmannTransferToOrbit(double targetAltitude, double timeToStart) { - double[] totalDv = { 0, 0, 0 }; - try { - double startingRadius = Math.max(getNaveAtual().getOrbit().getApoapsis(), - getNaveAtual().getOrbit().getPeriapsis()); - System.out.println(startingRadius + " --- " + targetAltitude); - double gravParameter = currentBody.getGravitationalParameter(); - // Delta-v required to leave the current orbit - double deltaV1 = Math.sqrt(2 * gravParameter / startingRadius) - Math.sqrt(gravParameter / startingRadius); - // Delta-v required to enter the target orbit - double deltaV2 = Math.sqrt(gravParameter / targetAltitude) - Math.sqrt(2 * gravParameter / targetAltitude); - System.out.println(deltaV1); - System.out.println(deltaV2); - - // Dv taken between the two points - totalDv[0] = deltaV2 + deltaV1; - } catch (RPCException e) { - } - return createManeuver(timeToStart, totalDv); - } - private Node createManeuverAtClosestIncNode(Orbit targetOrbit) { double uTatClosestNode = 1; double[] dv = { 0, 0, 0 }; @@ -167,36 +185,121 @@ private double[] getTimeToIncNodes(Orbit targetOrbit) throws RPCException { return new double[] { vesselOrbit.uTAtTrueAnomaly(ascendingNode), vesselOrbit.uTAtTrueAnomaly(descendingNode) }; } - public void alignPlanes() { + private void alignPlanesWithTargetVessel() { try { - Orbit targetOrbit = getTargetOrbit(); - Node maneuver = createManeuverAtClosestIncNode(targetOrbit); - double[] incNodesUt = getTimeToIncNodes(targetOrbit); + Vessel vessel = getNaveAtual(); + Orbit vesselOrbit = getNaveAtual().getOrbit(); + Orbit targetVesselOrbit = getSpaceCenter().getTargetVessel().getOrbit(); + boolean hasManeuverNodes = vessel.getControl().getNodes().size() > 0; + System.out.println("hasManeuverNodes: " + hasManeuverNodes); + if (!hasManeuverNodes) { + RunManeuverJPanel.createManeuver(); + } + java.util.List currentManeuvers = vessel.getControl().getNodes(); + Node currentManeuver = currentManeuvers.get(0); + double[] incNodesUt = { + vesselOrbit.uTAtTrueAnomaly(vesselOrbit.trueAnomalyAtAN(targetVesselOrbit)), + vesselOrbit.uTAtTrueAnomaly(vesselOrbit.trueAnomalyAtDN(targetVesselOrbit)) + }; boolean closestIsAN = incNodesUt[0] < incNodesUt[1]; - double timeToExecute = 0; - while (timeToExecute < 5000) { - if (Thread.interrupted()) { - throw new InterruptedException(); + RunManeuverJPanel.positionManeuverAt(closestIsAN ? "ascending" : "descending"); + double currentInclination = Math + .toDegrees(currentManeuver.getOrbit().relativeInclination(targetVesselOrbit)); + while (currentInclination > 0.05) { + currentInclination = Math + .toDegrees(currentManeuver.getOrbit().relativeInclination(targetVesselOrbit)); + double ctrlOutput = ctrlManeuver.calcPID(currentInclination * 100, 0); + currentManeuver.setNormal(currentManeuver.getNormal() + (closestIsAN ? ctrlOutput : -ctrlOutput)); + Thread.sleep(25); + } + } catch (Exception err) { + System.err.println(err); + } + } + + private void rendezvousWithTargetVessel() { + try { + Orbit targetVesselOrbit = getSpaceCenter().getTargetVessel().getOrbit(); + boolean hasManeuverNodes = getNaveAtual().getControl().getNodes().size() > 0; + java.util.List currentManeuvers = getNaveAtual().getControl().getNodes(); + Node lastManeuverNode; + double lastManeuverNodeUT = 60; + if (hasManeuverNodes) { + currentManeuvers = getNaveAtual().getControl().getNodes(); + lastManeuverNode = currentManeuvers.get(currentManeuvers.size() - 1); + lastManeuverNodeUT += lastManeuverNode.getUT(); + RunManeuverJPanel.createManeuver(lastManeuverNodeUT); + } else { + RunManeuverJPanel.createManeuver(); + } + currentManeuvers = getNaveAtual().getControl().getNodes(); + lastManeuverNode = currentManeuvers.get(currentManeuvers.size() - 1); + double targetAP = targetVesselOrbit.getApoapsis(); + double targetPE = targetVesselOrbit.getPeriapsis(); + double maneuverAP = lastManeuverNode.getOrbit().getApoapsis(); + double maneuverPE = lastManeuverNode.getOrbit().getPeriapsis(); + double maneuverUT = lastManeuverNode.getUT(); + ctrlManeuver.adjustPID(0.25, 0.0, 0.01); + ctrlManeuver.adjustOutput(-100, 100); + if (targetAP < maneuverPE) { + while (Math.floor(targetAP) != Math.floor(maneuverPE)) { + lastManeuverNode.setPrograde( + lastManeuverNode.getPrograde() + + ctrlManeuver.calcPID(maneuverPE / targetAP * 1000, 1000)); + maneuverPE = lastManeuverNode.getOrbit().getPeriapsis(); + Thread.sleep(25); } - double currentDeltaInc = compareOrbitParameter(maneuver.getOrbit(), targetOrbit, Compare.INC); - String deltaIncFormatted = String.format("%.2f", currentDeltaInc); - System.out.println(deltaIncFormatted); - if (deltaIncFormatted.equals(String.format("%.2f", 10.00))) { - break; + } + if (targetPE > maneuverAP) { + while (Math.floor(targetPE) != Math.floor(maneuverAP)) { + lastManeuverNode.setPrograde( + lastManeuverNode.getPrograde() + + ctrlManeuver.calcPID(maneuverAP / targetPE * 1000, 1000)); + maneuverAP = lastManeuverNode.getOrbit().getApoapsis(); + Thread.sleep(25); } - double dvNormal = maneuver.getNormal(); - double ctrlOutput = ctrlManeuver.calcPID(currentDeltaInc, 10.0);// * limitPIDOutput(Math.abs - // (currentDeltaInc)); - if ((closestIsAN ? currentDeltaInc : -currentDeltaInc) > 0.0) { - maneuver.setNormal(dvNormal + (ctrlOutput)); + } + + double mu = currentBody.getGravitationalParameter(); + double time = 1000; + + double hohmannTransferDistance = lastManeuverNode.getOrbit().getSemiMajorAxis(); + double timeOfFlight = Math.PI * Math.sqrt(Math.pow(hohmannTransferDistance, 3) / mu); + double angle = getNaveAtual().getOrbit().getMeanAnomalyAtEpoch(); + double omegaInterceptor = Math + .sqrt(mu / Math.pow(getNaveAtual().getOrbit().radiusAt(getSpaceCenter().getUT()), 3)); // rad/s + double omegaTarget = Math.sqrt(mu / Math.pow(targetVesselOrbit.radiusAt(getSpaceCenter().getUT()), 3)); // rad/s + // double leadAngle = omegaTarget * timeOfFlight; // rad + double leadAngle = targetVesselOrbit.getMeanAnomalyAtEpoch(); // rad + double phaseAngle = Math.PI - leadAngle; // rad + double calcAngle = (phaseAngle - angle); + calcAngle = calcAngle < 0 ? calcAngle + (Math.PI * 2) : calcAngle; + double waitTime = calcAngle / (omegaTarget - omegaInterceptor); + time = waitTime; + + lastManeuverNode.setUT(getSpaceCenter().getUT() + time); + ctrlManeuver.adjustOutput(-100, 100); + ctrlManeuver.adjustPID(0.05, 0.1, 0.01); + double closestApproach = lastManeuverNode.getOrbit().distanceAtClosestApproach(targetVesselOrbit); + System.out.println(closestApproach); + System.out.println("Ajustando tempo de Rendezvous..."); + while (Math.round(closestApproach) > 100) { + if (closestApproach < 100000) { + ctrlManeuver.adjustOutput(-10, 10); + } else if (closestApproach < 10000) { + ctrlManeuver.adjustOutput(-1, 1); } else { - maneuver.setNormal(dvNormal - (ctrlOutput)); + ctrlManeuver.adjustOutput(-100, 100); } - timeToExecute += 25; + maneuverUT = ctrlManeuver.calcPID(-closestApproach, 0); + lastManeuverNode.setUT(lastManeuverNode.getUT() + maneuverUT); + System.out.println("Closest " + (closestApproach)); + closestApproach = targetVesselOrbit.distanceAtClosestApproach(lastManeuverNode.getOrbit()); Thread.sleep(25); } - } catch (Exception e) { - setCurrentStatus("Não foi possivel ajustar a inclinação"); + // lastManeuverNode.setUT(lastManeuverNode.getUT() - + // lastManeuverNode.getOrbit().getPeriod() / 2); + } catch (Exception err) { } } @@ -325,31 +428,33 @@ public void executeBurn(Node noDeManobra, double duracaoDaQueima) { Thread.sleep(100); } // Executar a manobra: - Stream> queimaRestante = getConnection().addStream(noDeManobra, + Stream> remainingBurn = getConnection().addStream(noDeManobra, "remainingBurnVector", noDeManobra.getReferenceFrame()); setCurrentStatus(Bundle.getString("status_maneuver_executing")); while (noDeManobra != null) { + double burnDvLeft = remainingBurn.get().getValue1(); if (Thread.interrupted()) { throw new InterruptedException(); } - if (queimaRestante.get().getValue1() < (fineAdjustment ? 2 : 0.5)) { + if (burnDvLeft < (fineAdjustment ? 2 : 0.5)) { throttle(0.0f); break; } navigation.aimAtManeuver(noDeManobra); - throttle(ctrlManeuver.calcPID((noDeManobra.getDeltaV() - Math.floor(queimaRestante.get().getValue1())) / - noDeManobra.getDeltaV() * 1000, 1000)); + float limitValue = burnDvLeft > 100 ? 1000 : 100; + throttle(ctrlManeuver.calcPID((noDeManobra.getDeltaV() - Math.floor(burnDvLeft)) / + noDeManobra.getDeltaV() * limitValue, limitValue)); Thread.sleep(50); } throttle(0.0f); if (fineAdjustment) { - adjustManeuverWithRCS(queimaRestante); + adjustManeuverWithRCS(remainingBurn); } ap.setReferenceFrame(surfaceReferenceFrame); ap.disengage(); getNaveAtual().getControl().setSAS(true); getNaveAtual().getControl().setRCS(false); - queimaRestante.remove(); + remainingBurn.remove(); noDeManobra.remove(); setCurrentStatus(Bundle.getString("status_ready")); } catch (StreamException | RPCException e) { diff --git a/src/com/pesterenan/model/ActiveVessel.java b/src/com/pesterenan/model/ActiveVessel.java index 2fd88d1..f01f206 100644 --- a/src/com/pesterenan/model/ActiveVessel.java +++ b/src/com/pesterenan/model/ActiveVessel.java @@ -182,7 +182,7 @@ public void startModule(Map commands) { controller = new LandingController(commands); runningModule = true; } - if (currentFunction.equals(Modulos.MODULO_EXEC_MANOBRAS.get())) { + if (currentFunction.equals(Modulos.MODULE_MANEUVER.get())) { controller = new ManeuverController(commands); runningModule = true; } diff --git a/src/com/pesterenan/resources/MechPesteBundle.properties b/src/com/pesterenan/resources/MechPesteBundle.properties index e3d7143..6035da3 100644 --- a/src/com/pesterenan/resources/MechPesteBundle.properties +++ b/src/com/pesterenan/resources/MechPesteBundle.properties @@ -1,7 +1,7 @@ btn_func_landing = Auto Landing btn_func_liftoff = Orbital Liftoff btn_func_create_maneuver = Create Maneuvers -btn_func_exec_maneuver = Exec. Maneuvers +btn_func_maneuver = Maneuvers btn_func_rover = Drive Rover btn_stat_connect = Connect installer_dialog_btn_browse = Browse... diff --git a/src/com/pesterenan/resources/MechPesteBundle_pt.properties b/src/com/pesterenan/resources/MechPesteBundle_pt.properties index 2aaf5da..fbace8b 100644 --- a/src/com/pesterenan/resources/MechPesteBundle_pt.properties +++ b/src/com/pesterenan/resources/MechPesteBundle_pt.properties @@ -1,7 +1,7 @@ btn_func_landing = Pouso Autom\u00E1tico btn_func_liftoff = Decolagem Orbital btn_func_create_maneuver = Criar Manobras -btn_func_exec_maneuver = Exec. Manobras +btn_func_maneuver = Manobras btn_func_rover = Pilotar Rover btn_stat_connect = Conectar installer_dialog_btn_browse = Escolher... diff --git a/src/com/pesterenan/utils/Attributes.java b/src/com/pesterenan/utils/Attributes.java new file mode 100644 index 0000000..1046b85 --- /dev/null +++ b/src/com/pesterenan/utils/Attributes.java @@ -0,0 +1,33 @@ +package com.pesterenan.utils; + +import java.util.HashMap; +import java.util.Map; + +public class Attributes { + + private static Map safeLowOrbitAltitudes = new HashMap(); + + public Attributes() { + safeLowOrbitAltitudes.put("Bop", 10_000.0); + safeLowOrbitAltitudes.put("Dres", 20_000.0); + safeLowOrbitAltitudes.put("Duna", 60_000.0); + safeLowOrbitAltitudes.put("Eeloo", 20_000.0); + safeLowOrbitAltitudes.put("Eve", 100_000.0); + safeLowOrbitAltitudes.put("Gilly", 10_000.0); + safeLowOrbitAltitudes.put("Ike", 20_000.0); + safeLowOrbitAltitudes.put("Jool", 220_000.0); + safeLowOrbitAltitudes.put("Kerbin", 80_000.0); + safeLowOrbitAltitudes.put("Laythe", 80_000.0); + safeLowOrbitAltitudes.put("Minmus", 10_000.0); + safeLowOrbitAltitudes.put("Moho", 35_000.0); + safeLowOrbitAltitudes.put("Mun", 10_000.0); + safeLowOrbitAltitudes.put("Pol", 10_000.0); + safeLowOrbitAltitudes.put("Sun", 350_000.0); + safeLowOrbitAltitudes.put("Tylo", 40_000.0); + safeLowOrbitAltitudes.put("Vall", 20_000.0); + } + + public double getLowOrbitAltitude(String celestialBody) { + return safeLowOrbitAltitudes.getOrDefault(celestialBody, 10_000.0); + }; +} diff --git a/src/com/pesterenan/utils/Modulos.java b/src/com/pesterenan/utils/Modulos.java index 85222ba..5bdf85c 100644 --- a/src/com/pesterenan/utils/Modulos.java +++ b/src/com/pesterenan/utils/Modulos.java @@ -18,7 +18,7 @@ public enum Modulos { MAX_TWR("Max_TWR"), MODULO_CRIAR_MANOBRAS("CRIAR_MANOBRAS"), MODULO_DECOLAGEM("LIFTOFF"), - MODULO_EXEC_MANOBRAS("MANEUVER"), + MODULE_MANEUVER("MANEUVER"), MODULO_POUSO_SOBREVOAR("HOVER"), MODULO_POUSO("LANDING"), MODULO_ROVER("ROVER"), @@ -30,6 +30,7 @@ public enum Modulos { PERIASTRO("Periastro"), POUSAR("Pousar nave"), QUADRATICA("Quadrática"), + RENDEZVOUS("Rendezvous"), ROLAGEM("Rolagem"), SINUSOIDAL("Sinusoidal"), SOBREVOO_POS_POUSO("SOBREVOO PÓS POUSO"), diff --git a/src/com/pesterenan/views/CreateManeuverJPanel.java b/src/com/pesterenan/views/CreateManeuverJPanel.java new file mode 100644 index 0000000..db253de --- /dev/null +++ b/src/com/pesterenan/views/CreateManeuverJPanel.java @@ -0,0 +1,442 @@ +package com.pesterenan.views; + +import com.pesterenan.MechPeste; +import com.pesterenan.resources.Bundle; +import com.pesterenan.utils.ControlePID; + +import krpc.client.RPCException; +import krpc.client.services.SpaceCenter.Node; +import krpc.client.services.SpaceCenter.Orbit; +import krpc.client.services.SpaceCenter.Vessel; +import krpc.client.services.SpaceCenter.VesselSituation; + +import javax.swing.*; +import javax.swing.border.TitledBorder; + +import org.javatuples.Pair; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; + +import static com.pesterenan.views.MainGui.PNL_DIMENSION; +import static com.pesterenan.views.MainGui.BTN_DIMENSION; + +public class CreateManeuverJPanel extends JPanel implements ActionListener, UIMethods { + + private static JLabel lblManeuverInfo; + private static JButton btnCreateManeuver, btnDeleteManeuver, btnBack, btnAp, btnPe, btnAN, btnDN; + private static JButton btnIncrease, btnDecrease, btnNextOrbit, btnPrevOrbit; + private static JSlider sldScale; + private static JList listCurrentManeuvers; + private static int selectedManeuverIndex = 0; + private static JRadioButton rbPrograde, rbNormal, rbRadial, rbTime; + private static ButtonGroup bgManeuverType; + private static Map sliderValues = new HashMap<>(); + private final ControlePID ctrlManeuver = new ControlePID(); + + public CreateManeuverJPanel() { + initComponents(); + setupComponents(); + layoutComponents(); + } + + @Override + public void initComponents() { + // Labels: + lblManeuverInfo = new JLabel(""); + + // Buttons: + btnCreateManeuver = new JButton("Criar"); + btnDeleteManeuver = new JButton("Apagar"); + btnAp = new JButton("AP"); + btnPe = new JButton("PE"); + btnAN = new JButton("NA"); + btnDN = new JButton("ND"); + btnBack = new JButton(Bundle.getString("pnl_mnv_btn_back")); + btnIncrease = new JButton("+"); + btnDecrease = new JButton("-"); + btnNextOrbit = new JButton(">"); + btnPrevOrbit = new JButton("<"); + + // Radio buttons: + rbPrograde = new JRadioButton("Pro"); + rbNormal = new JRadioButton("Nor"); + rbRadial = new JRadioButton("Rad"); + rbTime = new JRadioButton("Tmp"); + + // Misc: + listCurrentManeuvers = new JList<>(); + sldScale = new JSlider(JSlider.VERTICAL, 0, 5, 2); + bgManeuverType = new ButtonGroup(); + sliderValues.put(0, 0.01f); + sliderValues.put(1, 0.1f); + sliderValues.put(2, 1f); + sliderValues.put(3, 10f); + sliderValues.put(4, 100f); + sliderValues.put(5, 1000f); + + ctrlManeuver.adjustOutput(-100, 100); + } + + @Override + public void setupComponents() { + // Setting-up components: + btnCreateManeuver.addActionListener(this); + btnCreateManeuver.setMaximumSize(BTN_DIMENSION); + btnCreateManeuver.setPreferredSize(BTN_DIMENSION); + btnDeleteManeuver.addActionListener(this); + btnDeleteManeuver.setMaximumSize(BTN_DIMENSION); + btnDeleteManeuver.setPreferredSize(BTN_DIMENSION); + btnAp.addActionListener(this); + btnAp.setActionCommand("apoapsis"); + btnPe.addActionListener(this); + btnPe.setActionCommand("periapsis"); + btnAN.addActionListener(this); + btnAN.setActionCommand("ascending"); + btnDN.addActionListener(this); + btnDN.setActionCommand("descending"); + btnBack.addActionListener(this); + btnBack.setMaximumSize(BTN_DIMENSION); + btnBack.setPreferredSize(BTN_DIMENSION); + btnIncrease.setActionCommand("increase"); + btnIncrease.addActionListener(this); + btnIncrease.addMouseWheelListener(e -> { + int rotation = e.getWheelRotation(); + if (rotation > 0) { + changeManeuverDeltaV(btnDecrease.getActionCommand()); + } else { + changeManeuverDeltaV(btnIncrease.getActionCommand()); + } + }); + btnIncrease.setMaximumSize(new Dimension(70, 26)); + btnIncrease.setPreferredSize(new Dimension(70, 26)); + btnIncrease.setMargin(new Insets(0, 0, 0, 0)); + btnDecrease.setActionCommand("decrease"); + btnDecrease.addActionListener(this); + btnDecrease.addMouseWheelListener(e -> { + int rotation = e.getWheelRotation(); + if (rotation > 0) { + changeManeuverDeltaV(btnIncrease.getActionCommand()); + } else { + changeManeuverDeltaV(btnDecrease.getActionCommand()); + } + }); + btnDecrease.setMaximumSize(new Dimension(70, 26)); + btnDecrease.setPreferredSize(new Dimension(70, 26)); + btnDecrease.setMargin(new Insets(0, 0, 0, 0)); + btnNextOrbit.setActionCommand("next_orbit"); + btnNextOrbit.addActionListener(this); + btnNextOrbit.setMaximumSize(new Dimension(35, 26)); + btnNextOrbit.setPreferredSize(new Dimension(35, 26)); + btnNextOrbit.setMargin(new Insets(0, 0, 0, 0)); + btnPrevOrbit.setActionCommand("prev_orbit"); + btnPrevOrbit.addActionListener(this); + btnPrevOrbit.setMaximumSize(new Dimension(35, 26)); + btnPrevOrbit.setPreferredSize(new Dimension(35, 26)); + btnPrevOrbit.setMargin(new Insets(0, 0, 0, 0)); + + rbPrograde.setActionCommand("prograde"); + rbPrograde.addChangeListener(e -> handleChangeButtonText(sldScale.getValue())); + rbNormal.setActionCommand("normal"); + rbNormal.addChangeListener(e -> handleChangeButtonText(sldScale.getValue())); + rbRadial.setActionCommand("radial"); + rbRadial.addChangeListener(e -> handleChangeButtonText(sldScale.getValue())); + rbTime.setActionCommand("time"); + rbTime.addChangeListener(e -> handleChangeButtonText(sldScale.getValue())); + bgManeuverType.add(rbPrograde); + bgManeuverType.add(rbNormal); + bgManeuverType.add(rbRadial); + bgManeuverType.add(rbTime); + bgManeuverType.setSelected(rbPrograde.getModel(), true); + + listCurrentManeuvers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + listCurrentManeuvers.addListSelectionListener(e -> selectedManeuverIndex = e.getFirstIndex()); + + sldScale.setSnapToTicks(true); + sldScale.setPaintTicks(true); + sldScale.setMajorTickSpacing(1); + sldScale.setMinorTickSpacing(1); + sldScale.setPaintLabels(false); + sldScale.addChangeListener(e -> handleChangeButtonText(sldScale.getValue())); + sldScale.addMouseWheelListener(e -> { + int rotation = e.getWheelRotation(); + if (rotation < 0) { + sldScale.setValue(sldScale.getValue() + sldScale.getMinorTickSpacing()); + } else { + sldScale.setValue(sldScale.getValue() - sldScale.getMinorTickSpacing()); + } + }); + } + + @Override + public void layoutComponents() { + // Main Panel layout: + setPreferredSize(PNL_DIMENSION); + setSize(PNL_DIMENSION); + setLayout(new BorderLayout()); + + JPanel pnlPositionManeuver = new JPanel(); + pnlPositionManeuver.setLayout(new BoxLayout(pnlPositionManeuver, BoxLayout.X_AXIS)); + pnlPositionManeuver.setBorder(new TitledBorder("Posicionar manobra no:")); + pnlPositionManeuver.add(Box.createHorizontalGlue()); + pnlPositionManeuver.add(btnAp); + pnlPositionManeuver.add(btnPe); + pnlPositionManeuver.add(btnAN); + pnlPositionManeuver.add(btnDN); + pnlPositionManeuver.add(Box.createHorizontalGlue()); + + JPanel pnlRadioButtons = new JPanel(new GridLayout(4, 1)); + pnlRadioButtons.setMaximumSize(new Dimension(50, 100)); + pnlRadioButtons.add(rbPrograde); + pnlRadioButtons.add(rbNormal); + pnlRadioButtons.add(rbRadial); + pnlRadioButtons.add(rbTime); + + JPanel pnlSlider = new JPanel(); + pnlSlider.setLayout(new BoxLayout(pnlSlider, BoxLayout.Y_AXIS)); + pnlSlider.setAlignmentX(Component.LEFT_ALIGNMENT); + pnlSlider.setBorder(new TitledBorder("Escala:")); + pnlSlider.add(sldScale); + pnlSlider.add(Box.createHorizontalStrut(40)); + + JPanel pnlOrbitControl = new JPanel(); + pnlOrbitControl.setLayout(new BoxLayout(pnlOrbitControl, BoxLayout.X_AXIS)); + pnlOrbitControl.setAlignmentX(Component.LEFT_ALIGNMENT); + pnlOrbitControl.add(btnPrevOrbit); + pnlOrbitControl.add(btnNextOrbit); + + JPanel pnlManeuverButtons = new JPanel(); + pnlManeuverButtons.setLayout(new BoxLayout(pnlManeuverButtons, BoxLayout.Y_AXIS)); + pnlManeuverButtons.setAlignmentX(Component.LEFT_ALIGNMENT); + pnlManeuverButtons.add(btnIncrease); + pnlManeuverButtons.add(pnlOrbitControl); + pnlManeuverButtons.add(btnDecrease); + + JPanel pnlManeuverController = new JPanel(); + pnlManeuverController.setLayout(new BoxLayout(pnlManeuverController, BoxLayout.X_AXIS)); + pnlManeuverController.setBorder(new TitledBorder("Controlador de Manobra:")); + pnlManeuverController.setMaximumSize(new Dimension(180, 300)); + pnlManeuverController.add(pnlRadioButtons); + pnlManeuverController.add(pnlSlider); + pnlManeuverController.add(pnlManeuverButtons); + + JPanel pnlManeuverInfo = new JPanel(); + pnlManeuverInfo.setLayout(new BoxLayout(pnlManeuverInfo, BoxLayout.Y_AXIS)); + pnlManeuverInfo.setBorder(new TitledBorder("Info. Manobra:")); + pnlManeuverInfo.setMaximumSize(new Dimension(300, 300)); + + JPanel pnlMCpnlAP = new JPanel(); + pnlMCpnlAP.setLayout(new BoxLayout(pnlMCpnlAP, BoxLayout.X_AXIS)); + pnlMCpnlAP.add(pnlManeuverController); + pnlMCpnlAP.add(pnlManeuverInfo); + + JPanel pnlControls = new JPanel(); + pnlControls.setLayout(new BoxLayout(pnlControls, BoxLayout.Y_AXIS)); + pnlControls.add(pnlPositionManeuver); + pnlControls.add(pnlMCpnlAP); + + JPanel pnlManeuverList = new JPanel(); + pnlManeuverList.setLayout(new BoxLayout(pnlManeuverList, BoxLayout.Y_AXIS)); + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setViewportView(listCurrentManeuvers); + pnlManeuverList.add(scrollPane); + pnlManeuverList.add(btnCreateManeuver); + pnlManeuverList.add(btnDeleteManeuver); + + JPanel pnlOptions = new JPanel(); + pnlOptions.setLayout(new BoxLayout(pnlOptions, BoxLayout.Y_AXIS)); + pnlOptions.setBorder(new TitledBorder("Lista de Manobras:")); + pnlOptions.add(pnlManeuverList); + pnlOptions.setPreferredSize(new Dimension(110, 300)); + pnlOptions.setMaximumSize(new Dimension(110, 300)); + + JPanel pnlOptionsAndList = new JPanel(); + pnlOptionsAndList.setLayout(new BoxLayout(pnlOptionsAndList, BoxLayout.X_AXIS)); + pnlControls.setAlignmentY(TOP_ALIGNMENT); + pnlOptions.setAlignmentY(TOP_ALIGNMENT); + pnlOptionsAndList.add(pnlOptions); + pnlOptionsAndList.add(Box.createHorizontalStrut(5)); + pnlOptionsAndList.add(pnlControls); + + JPanel pnlBackButton = new JPanel(); + pnlBackButton.setLayout(new BoxLayout(pnlBackButton, BoxLayout.X_AXIS)); + pnlBackButton.add(lblManeuverInfo); + pnlBackButton.add(Box.createHorizontalGlue()); + pnlBackButton.add(btnBack); + + JPanel pnlMain = new JPanel(); + pnlMain.setLayout(new BoxLayout(pnlMain, BoxLayout.X_AXIS)); + pnlMain.add(pnlOptionsAndList); + + add(pnlMain, BorderLayout.CENTER); + add(pnlBackButton, BorderLayout.SOUTH); + } + + public static void updatePanel(ListModel list) { + try { + boolean hasManeuverNodes = list.getSize() > 0; + boolean hasTargetVessel = MechPeste.getSpaceCenter().getTargetVessel() != null; + listCurrentManeuvers.setModel(list); + listCurrentManeuvers.setSelectedIndex(selectedManeuverIndex); + btnDeleteManeuver.setEnabled(hasManeuverNodes); + btnAp.setEnabled(hasManeuverNodes); + btnPe.setEnabled(hasManeuverNodes); + btnAN.setEnabled(hasManeuverNodes && hasTargetVessel); + btnDN.setEnabled(hasManeuverNodes && hasTargetVessel); + btnIncrease.setEnabled(hasManeuverNodes); + btnDecrease.setEnabled(hasManeuverNodes); + btnNextOrbit.setEnabled(hasManeuverNodes); + btnPrevOrbit.setEnabled(hasManeuverNodes); + lblManeuverInfo.setText(listCurrentManeuvers.getSelectedValue()); + } catch (RPCException ignored) { + } + } + + private static void handleChangeButtonText(int value) { + String decimalPlaces = value > 1 ? "%.0f" : "%.2f"; + String formattedValue = String.format(Locale.ENGLISH, decimalPlaces, sliderValues.get(value)); + String suffix = bgManeuverType.getSelection() == rbTime.getModel() ? " s" : "m/s"; + btnIncrease.setText("+ " + formattedValue + suffix); + btnDecrease.setText("- " + formattedValue + suffix); + } + + private void createManeuver() { + try { + createManeuver(MechPeste.getSpaceCenter().getUT() + 60); + } catch (RPCException e) { + } + } + + private void createManeuver(double atFutureTime) { + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + + if (vessel.getSituation() != VesselSituation.ORBITING) { + StatusJPanel.setStatusMessage("Não é possível criar a manobra fora de órbita."); + return; + } + vessel.getControl().addNode(atFutureTime, 0, 0, 0); + } catch (Exception e) { + } + } + + private void deleteManeuver() { + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + Node currentManeuver = vessel.getControl().getNodes().get(selectedManeuverIndex); + currentManeuver.remove(); + } catch (Exception e) { + } + } + + private void positionManeuverAt(String node) { + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + Orbit orbit = vessel.getOrbit(); + Node currentManeuver = vessel.getControl().getNodes().get(selectedManeuverIndex); + double timeToNode = 0; + switch (node) { + case "apoapsis": + timeToNode = MechPeste.getSpaceCenter().getUT() + orbit.getTimeToApoapsis(); + break; + case "periapsis": + timeToNode = MechPeste.getSpaceCenter().getUT() + orbit.getTimeToPeriapsis(); + break; + case "ascending": + double ascendingAnomaly = orbit + .trueAnomalyAtAN(MechPeste.getSpaceCenter().getTargetVessel().getOrbit()); + timeToNode = orbit.uTAtTrueAnomaly(ascendingAnomaly); + break; + case "descending": + double descendingAnomaly = orbit + .trueAnomalyAtDN(MechPeste.getSpaceCenter().getTargetVessel().getOrbit()); + timeToNode = orbit.uTAtTrueAnomaly(descendingAnomaly); + break; + } + currentManeuver.setUT(timeToNode); + // Print the maneuver node information + System.out.println("Maneuver Node updated:"); + System.out.println(" Time to node: " + currentManeuver.getTimeTo() + " s"); + } catch (Exception e) { + } + } + + private void changeManeuverDeltaV(String command) { + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + Node currentManeuver = vessel.getControl().getNodes().get(selectedManeuverIndex); + String maneuverType = bgManeuverType.getSelection().getActionCommand(); + float currentSliderValue = sliderValues.get(sldScale.getValue()); + currentSliderValue = command == "decrease" ? -currentSliderValue : currentSliderValue; + + switch (maneuverType) { + case "prograde": + currentManeuver.setPrograde(currentManeuver.getPrograde() + currentSliderValue); + break; + case "normal": + currentManeuver.setNormal(currentManeuver.getNormal() + currentSliderValue); + break; + case "radial": + currentManeuver.setRadial(currentManeuver.getRadial() + currentSliderValue); + break; + case "time": + currentManeuver.setUT(currentManeuver.getUT() + currentSliderValue); + break; + } + } catch (RPCException e) { + System.err.println("Erro RPC ao mudar o delta-V da manobra: " + e.getMessage()); + } catch (Exception e) { + System.err.println("Erro ao mudar o delta-V da manobra: " + e.getMessage()); + } + + } + + private void changeOrbit(String command) { + try { + MechPeste.newInstance(); + Vessel vessel; + vessel = MechPeste.getSpaceCenter().getActiveVessel(); + Node currentManeuver = vessel.getControl().getNodes().get(selectedManeuverIndex); + double currentOrbitPeriod = vessel.getOrbit().getPeriod(); + if (command == "next_orbit") { + currentManeuver.setUT(currentManeuver.getUT() + currentOrbitPeriod); + } else { + double newUT = currentManeuver.getUT() - currentOrbitPeriod; + newUT = newUT < MechPeste.getSpaceCenter().getUT() ? MechPeste.getSpaceCenter().getUT() + 60 : newUT; + currentManeuver.setUT(newUT); + } + } catch (RPCException ignored) { + } + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == btnCreateManeuver) { + createManeuver(); + } + if (e.getSource() == btnDeleteManeuver) { + deleteManeuver(); + } + if (e.getSource() == btnIncrease || e.getSource() == btnDecrease) { + changeManeuverDeltaV(e.getActionCommand()); + } + if (e.getSource() == btnNextOrbit || e.getSource() == btnPrevOrbit) { + changeOrbit(e.getActionCommand()); + } + if (e.getSource() == btnAp || e.getSource() == btnPe || e.getSource() == btnAN || e.getSource() == btnDN) { + positionManeuverAt(e.getActionCommand()); + } + if (e.getSource() == btnBack) { + MainGui.backToTelemetry(e); + } + } +} diff --git a/src/com/pesterenan/views/FunctionsAndTelemetryJPanel.java b/src/com/pesterenan/views/FunctionsAndTelemetryJPanel.java index aadcb06..3f0d9ac 100644 --- a/src/com/pesterenan/views/FunctionsAndTelemetryJPanel.java +++ b/src/com/pesterenan/views/FunctionsAndTelemetryJPanel.java @@ -21,7 +21,7 @@ public class FunctionsAndTelemetryJPanel extends JPanel implements UIMethods { private static final long serialVersionUID = 0L; private final Dimension btnFuncDimension = new Dimension(140, 25); - private JButton btnLiftoff, btnLanding, btnExecManeuver, btnRover, btnCancel, btnCreateManeuver; + private JButton btnLiftoff, btnLanding, btnManeuvers, btnRover, btnCancel; private static JLabel lblAltitude, lblSurfaceAlt, lblApoapsis, lblPeriapsis, lblVertSpeed, lblHorzSpeed; private static JLabel lblAltitudeValue, lblSurfaceAltValue, lblApoapsisValue; private static JLabel lblPeriapsisValue, lblVertSpeedValue, lblHorzSpeedValue; @@ -51,8 +51,7 @@ public void initComponents() { // Buttons: btnLiftoff = new JButton(Bundle.getString("btn_func_liftoff")); btnLanding = new JButton(Bundle.getString("btn_func_landing")); - btnCreateManeuver = new JButton(Bundle.getString("btn_func_create_maneuver")); - btnExecManeuver = new JButton(Bundle.getString("btn_func_exec_maneuver")); + btnManeuvers = new JButton(Bundle.getString("btn_func_maneuver")); btnRover = new JButton(Bundle.getString("btn_func_rover")); btnCancel = new JButton(Bundle.getString("pnl_tel_btn_cancel")); } @@ -76,15 +75,10 @@ public void setupComponents() { btnLiftoff.setActionCommand(Modulos.MODULO_DECOLAGEM.get()); btnLiftoff.setMaximumSize(btnFuncDimension); btnLiftoff.setPreferredSize(btnFuncDimension); - btnCreateManeuver.addActionListener(this::changeFunctionPanel); - btnCreateManeuver.setActionCommand(Modulos.MODULO_CRIAR_MANOBRAS.get()); - btnCreateManeuver.setMaximumSize(btnFuncDimension); - btnCreateManeuver.setPreferredSize(btnFuncDimension); - btnCreateManeuver.setEnabled(false); - btnExecManeuver.addActionListener(this::changeFunctionPanel); - btnExecManeuver.setActionCommand(Modulos.MODULO_EXEC_MANOBRAS.get()); - btnExecManeuver.setMaximumSize(btnFuncDimension); - btnExecManeuver.setPreferredSize(btnFuncDimension); + btnManeuvers.addActionListener(this::changeFunctionPanel); + btnManeuvers.setActionCommand(Modulos.MODULE_MANEUVER.get()); + btnManeuvers.setMaximumSize(btnFuncDimension); + btnManeuvers.setPreferredSize(btnFuncDimension); btnRover.addActionListener(this::changeFunctionPanel); btnRover.setActionCommand(Modulos.MODULO_ROVER.get()); btnRover.setMaximumSize(btnFuncDimension); @@ -100,9 +94,7 @@ public void layoutComponents() { pnlFunctionControls.add(btnLiftoff); pnlFunctionControls.add(btnLanding); pnlFunctionControls.add(btnRover); - pnlFunctionControls.add(MainGui.createMarginComponent(0, 20)); - pnlFunctionControls.add(btnCreateManeuver); - pnlFunctionControls.add(btnExecManeuver); + pnlFunctionControls.add(btnManeuvers); pnlFunctionControls.add(Box.createVerticalGlue()); JPanel pnlLeftPanel = new JPanel(); diff --git a/src/com/pesterenan/views/MainGui.java b/src/com/pesterenan/views/MainGui.java index 04c903a..2eab916 100644 --- a/src/com/pesterenan/views/MainGui.java +++ b/src/com/pesterenan/views/MainGui.java @@ -9,13 +9,11 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; public class MainGui extends JFrame implements ActionListener, UIMethods { - + private static final long serialVersionUID = 1L; - + private final Dimension APP_DIMENSION = new Dimension(480, 300); public static final Dimension PNL_DIMENSION = new Dimension(464, 216); public static final Dimension BTN_DIMENSION = new Dimension(110, 25); @@ -28,11 +26,12 @@ public class MainGui extends JFrame implements ActionListener, UIMethods { private JMenuBar menuBar; private JMenu mnFile, mnOptions, mnHelp; private JMenuItem mntmInstallKrpc, mntmExit, mntmChangeVessels, mntmAbout; - + private final static CardLayout cardLayout = new CardLayout(0, 0); private LiftoffJPanel pnlLiftoff; private LandingJPanel pnlLanding; - private ManeuverJPanel pnlManeuver; + private CreateManeuverJPanel pnlCreateManeuvers; + private RunManeuverJPanel pnlRunManeuvers; private RoverJPanel pnlRover; private MainGui() { @@ -54,7 +53,7 @@ public void initComponents() { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ignored) { } - + // Menu bar menuBar = new JMenuBar(); @@ -62,7 +61,7 @@ public void initComponents() { mnFile = new JMenu(Bundle.getString("main_mn_file")); mnOptions = new JMenu(Bundle.getString("main_mn_options")); mnHelp = new JMenu(Bundle.getString("main_mn_help")); - + // Menu Items mntmInstallKrpc = new JMenuItem(Bundle.getString("main_mntm_install_krpc")); mntmChangeVessels = new JMenuItem(Bundle.getString("main_mntm_change_vessels")); @@ -73,7 +72,8 @@ public void initComponents() { pnlFunctionsAndTelemetry = new FunctionsAndTelemetryJPanel(); pnlLiftoff = new LiftoffJPanel(); pnlLanding = new LandingJPanel(); - pnlManeuver = new ManeuverJPanel(); + pnlCreateManeuvers = new CreateManeuverJPanel(); + pnlRunManeuvers = new RunManeuverJPanel(); pnlRover = new RoverJPanel(); pnlStatus = new StatusJPanel(); } @@ -88,7 +88,7 @@ public void setupComponents() { setLocation(100, 100); setContentPane(ctpMainGui); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - + // Setting-up components: mntmAbout.addActionListener(this); mntmChangeVessels.addActionListener(this); @@ -98,7 +98,7 @@ public void setupComponents() { cardJPanels.setPreferredSize(PNL_DIMENSION); cardJPanels.setSize(PNL_DIMENSION); } - + @Override public void layoutComponents() { // Main Panel layout: @@ -120,11 +120,15 @@ public void layoutComponents() { menuBar.add(mnOptions); menuBar.add(mnHelp); + JTabbedPane pnlManeuverJTabbedPane = new JTabbedPane(); + pnlManeuverJTabbedPane.addTab("Criar Manobras", pnlCreateManeuvers); + pnlManeuverJTabbedPane.addTab("Executar Manobras", pnlRunManeuvers); + cardJPanels.setLayout(cardLayout); cardJPanels.add(pnlFunctionsAndTelemetry, Modulos.MODULO_TELEMETRIA.get()); cardJPanels.add(pnlLiftoff, Modulos.MODULO_DECOLAGEM.get()); cardJPanels.add(pnlLanding, Modulos.MODULO_POUSO.get()); - cardJPanels.add(pnlManeuver, Modulos.MODULO_EXEC_MANOBRAS.get()); + cardJPanels.add(pnlManeuverJTabbedPane, Modulos.MODULE_MANEUVER.get()); cardJPanels.add(pnlRover, Modulos.MODULO_ROVER.get()); } @@ -172,7 +176,7 @@ public static JPanel getCardJPanels() { public static void changeToPage(ActionEvent e) { cardLayout.show(cardJPanels, e.getActionCommand()); } - + public static void backToTelemetry(ActionEvent e) { cardLayout.show(cardJPanels, Modulos.MODULO_TELEMETRIA.get()); } diff --git a/src/com/pesterenan/views/ManeuverJPanel.java b/src/com/pesterenan/views/RunManeuverJPanel.java similarity index 58% rename from src/com/pesterenan/views/ManeuverJPanel.java rename to src/com/pesterenan/views/RunManeuverJPanel.java index c0b80e9..ab2f7ee 100644 --- a/src/com/pesterenan/views/ManeuverJPanel.java +++ b/src/com/pesterenan/views/RunManeuverJPanel.java @@ -2,8 +2,17 @@ import com.pesterenan.MechPeste; import com.pesterenan.resources.Bundle; +import com.pesterenan.utils.ControlePID; +import com.pesterenan.utils.Vector; import com.pesterenan.utils.Modulos; +import krpc.client.RPCException; +import krpc.client.services.SpaceCenter.Node; +import krpc.client.services.SpaceCenter.Orbit; +import krpc.client.services.SpaceCenter.ReferenceFrame; +import krpc.client.services.SpaceCenter.Vessel; +import krpc.client.services.SpaceCenter.VesselSituation; + import javax.swing.*; import javax.swing.border.CompoundBorder; import javax.swing.border.TitledBorder; @@ -18,14 +27,15 @@ import static com.pesterenan.views.MainGui.MARGIN_BORDER_10_PX_LR; import static com.pesterenan.views.MainGui.PNL_DIMENSION; -public class ManeuverJPanel extends JPanel implements ActionListener, UIMethods { +public class RunManeuverJPanel extends JPanel implements ActionListener, UIMethods { private static final long serialVersionUID = 1L; - private JLabel lblExecute, lblAdjustInc; - private JButton btnLowerOrbit, btnApoapsis, btnPeriapsis, btnExecute, btnAdjustInc, btnBack; + private JLabel lblExecute; + private JButton btnLowerOrbit, btnApoapsis, btnPeriapsis, btnExecute, btnBack, btnAlignPlanes, btnRendezvous; private JCheckBox chkFineAdjusment; + private final ControlePID ctrlManeuver = new ControlePID(); - public ManeuverJPanel() { + public RunManeuverJPanel() { initComponents(); setupComponents(); layoutComponents(); @@ -33,35 +43,89 @@ public ManeuverJPanel() { public void initComponents() { // Labels: - lblAdjustInc = new JLabel(Bundle.getString("pnl_mnv_lbl_adj_inc")); lblExecute = new JLabel(Bundle.getString("pnl_mnv_lbl_exec_mnv")); // Buttons: - btnAdjustInc = new JButton(Bundle.getString("pnl_mnv_btn_adj_inc")); btnApoapsis = new JButton(Bundle.getString("pnl_mnv_btn_apoapsis")); btnBack = new JButton(Bundle.getString("pnl_mnv_btn_back")); btnExecute = new JButton(Bundle.getString("pnl_mnv_btn_exec_mnv")); btnLowerOrbit = new JButton(Bundle.getString("pnl_mnv_btn_lower_orbit")); btnPeriapsis = new JButton(Bundle.getString("pnl_mnv_btn_periapsis")); + btnAlignPlanes = new JButton("Alinhar planos"); + btnRendezvous = new JButton("Rendezvous"); // Misc: chkFineAdjusment = new JCheckBox(Bundle.getString("pnl_mnv_chk_adj_mnv_rcs")); } - public void setupComponents() { - // Main Panel setup: - setBorder(new TitledBorder(null, Bundle.getString("pnl_mnv_border"), TitledBorder.LEADING, TitledBorder.TOP, - null, null)); + public static void createManeuver() { + System.out.println("Create maneuver"); + try { + createManeuver(MechPeste.getSpaceCenter().getUT() + 60); + } catch (RPCException e) { + } + } + + public static void createManeuver(double atFutureTime) { + System.out.println("Create maneuver overloaded"); + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + System.out.println("vessel: " + vessel); + + if (vessel.getSituation() != VesselSituation.ORBITING) { + StatusJPanel.setStatusMessage("Não é possível criar a manobra fora de órbita."); + return; + } + vessel.getControl().addNode(atFutureTime, 0, 0, 0); + } catch (Exception e) { + } + } + public static void positionManeuverAt(String node) { + try { + MechPeste.newInstance(); + Vessel vessel = MechPeste.getSpaceCenter().getActiveVessel(); + Orbit orbit = vessel.getOrbit(); + Node currentManeuver = vessel.getControl().getNodes().get(0); + double timeToNode = 0; + switch (node) { + case "apoapsis": + timeToNode = MechPeste.getSpaceCenter().getUT() + orbit.getTimeToApoapsis(); + break; + case "periapsis": + timeToNode = MechPeste.getSpaceCenter().getUT() + orbit.getTimeToPeriapsis(); + break; + case "ascending": + double ascendingAnomaly = orbit + .trueAnomalyAtAN(MechPeste.getSpaceCenter().getTargetVessel().getOrbit()); + timeToNode = orbit.uTAtTrueAnomaly(ascendingAnomaly); + break; + case "descending": + double descendingAnomaly = orbit + .trueAnomalyAtDN(MechPeste.getSpaceCenter().getTargetVessel().getOrbit()); + timeToNode = orbit.uTAtTrueAnomaly(descendingAnomaly); + break; + } + currentManeuver.setUT(timeToNode); + // Print the maneuver node information + System.out.println("Maneuver Node updated:"); + System.out.println(" Time to node: " + currentManeuver.getTimeTo() + " s"); + } catch (Exception e) { + } + } + + public void setupComponents() { // Setting-up components: - btnAdjustInc.addActionListener(this); - btnAdjustInc.setActionCommand(Modulos.AJUSTAR.get()); - btnAdjustInc.setEnabled(false); - btnAdjustInc.setMaximumSize(BTN_DIMENSION); - btnAdjustInc.setPreferredSize(BTN_DIMENSION); + btnAlignPlanes.addActionListener(this); + btnAlignPlanes.setMaximumSize(BTN_DIMENSION); + btnAlignPlanes.setPreferredSize(BTN_DIMENSION); + + btnRendezvous.addActionListener(this); + btnRendezvous.setMaximumSize(BTN_DIMENSION); + btnRendezvous.setPreferredSize(BTN_DIMENSION); btnApoapsis.addActionListener(this); - btnApoapsis.setActionCommand(Modulos.APOASTRO.get()); btnApoapsis.setMaximumSize(BTN_DIMENSION); btnApoapsis.setPreferredSize(BTN_DIMENSION); @@ -70,17 +134,14 @@ public void setupComponents() { btnBack.setPreferredSize(BTN_DIMENSION); btnExecute.addActionListener(this); - btnExecute.setActionCommand(Modulos.EXECUTAR.get()); btnExecute.setMaximumSize(BTN_DIMENSION); btnExecute.setPreferredSize(BTN_DIMENSION); btnLowerOrbit.addActionListener(this); - btnLowerOrbit.setActionCommand(Modulos.ORBITA_BAIXA.get()); btnLowerOrbit.setMaximumSize(BTN_DIMENSION); btnLowerOrbit.setPreferredSize(BTN_DIMENSION); btnPeriapsis.addActionListener(this); - btnPeriapsis.setActionCommand(Modulos.PERIASTRO.get()); btnPeriapsis.setMaximumSize(BTN_DIMENSION); btnPeriapsis.setPreferredSize(BTN_DIMENSION); } @@ -98,12 +159,11 @@ public void layoutComponents() { pnlExecuteManeuver.add(MainGui.createMarginComponent(10, 0)); pnlExecuteManeuver.add(btnExecute); - JPanel pnlAdjustInclination = new JPanel(); - pnlAdjustInclination.setLayout(new BoxLayout(pnlAdjustInclination, BoxLayout.X_AXIS)); - pnlAdjustInclination.setBorder(MARGIN_BORDER_10_PX_LR); - pnlAdjustInclination.add(lblAdjustInc); - pnlAdjustInclination.add(Box.createHorizontalGlue()); - pnlAdjustInclination.add(btnAdjustInc); + JPanel pnlAutoPosition = new JPanel(); + pnlAutoPosition.setLayout(new BoxLayout(pnlAutoPosition, BoxLayout.X_AXIS)); + pnlAutoPosition.setBorder(new TitledBorder("Auto posição:")); + pnlAutoPosition.add(btnAlignPlanes); + pnlAutoPosition.add(btnRendezvous); JPanel pnlCircularize = new JPanel(); pnlCircularize.setLayout(new BoxLayout(pnlCircularize, BoxLayout.X_AXIS)); @@ -119,7 +179,7 @@ public void layoutComponents() { JPanel pnlSetup = new JPanel(); pnlSetup.setLayout(new BoxLayout(pnlSetup, BoxLayout.Y_AXIS)); pnlSetup.add(pnlExecuteManeuver); - pnlSetup.add(pnlAdjustInclination); + pnlSetup.add(pnlAutoPosition); JPanel pnlOptions = new JPanel(); pnlOptions.setLayout(new BoxLayout(pnlOptions, BoxLayout.Y_AXIS)); @@ -161,9 +221,12 @@ public void actionPerformed(ActionEvent e) { if (e.getSource() == btnPeriapsis) { handleManeuverFunction(Modulos.PERIASTRO.get()); } - if (e.getSource() == btnAdjustInc) { + if (e.getSource() == btnAlignPlanes) { handleManeuverFunction(Modulos.AJUSTAR.get()); } + if (e.getSource() == btnRendezvous) { + handleManeuverFunction(Modulos.RENDEZVOUS.get()); + } if (e.getSource() == btnBack) { MainGui.backToTelemetry(e); } @@ -171,8 +234,8 @@ public void actionPerformed(ActionEvent e) { protected void handleManeuverFunction(String maneuverFunction) { Map commands = new HashMap<>(); - commands.put(Modulos.MODULO.get(), Modulos.MODULO_EXEC_MANOBRAS.get()); - commands.put(Modulos.FUNCAO.get(), maneuverFunction); + commands.put(Modulos.MODULO.get(), Modulos.MODULE_MANEUVER.get()); + commands.put(Modulos.FUNCAO.get(), maneuverFunction.toString()); commands.put(Modulos.AJUSTE_FINO.get(), String.valueOf(chkFineAdjusment.isSelected())); MechPeste.newInstance().startModule(commands); }