From 5c6dc6796148e5eeaaa321fa7a6ecfa5bb7f0ce9 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 28 Mar 2023 22:11:20 +0200 Subject: [PATCH] Implement RASAero recovery device exporting --- .../rasaero/export/BodyTubeDTOAdapter.java | 3 + .../file/rasaero/export/RASAeroSaver.java | 12 + .../file/rasaero/export/RecoveryDTO.java | 229 ++++++++++++++++++ 3 files changed, 244 insertions(+) diff --git a/core/src/net/sf/openrocket/file/rasaero/export/BodyTubeDTOAdapter.java b/core/src/net/sf/openrocket/file/rasaero/export/BodyTubeDTOAdapter.java index 8d6d4a960..392fc8fc6 100644 --- a/core/src/net/sf/openrocket/file/rasaero/export/BodyTubeDTOAdapter.java +++ b/core/src/net/sf/openrocket/file/rasaero/export/BodyTubeDTOAdapter.java @@ -5,6 +5,7 @@ import net.sf.openrocket.logging.ErrorSet; import net.sf.openrocket.logging.WarningSet; import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.LaunchLug; +import net.sf.openrocket.rocketcomponent.Parachute; import net.sf.openrocket.rocketcomponent.RailButton; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; @@ -54,6 +55,8 @@ public interface BodyTubeDTOAdapter { warnings.add(String.format("Instance count of '%s' equals %d, defaulting to 2.", button.getName(), button.getInstanceCount())); } + } else if (child instanceof Parachute) { + // Do nothing, is handled by RecoveryDTO } else { warnings.add(String.format("Unsupported component '%s', ignoring.", child.getComponentName())); } diff --git a/core/src/net/sf/openrocket/file/rasaero/export/RASAeroSaver.java b/core/src/net/sf/openrocket/file/rasaero/export/RASAeroSaver.java index a2b372c93..ae3c1584c 100644 --- a/core/src/net/sf/openrocket/file/rasaero/export/RASAeroSaver.java +++ b/core/src/net/sf/openrocket/file/rasaero/export/RASAeroSaver.java @@ -82,6 +82,7 @@ public class RASAeroSaver extends RocketSaver { RASAeroDocumentDTO rad = new RASAeroDocumentDTO(); rad.setDesign(toRocketDesignDTO(doc.getRocket(), warnings, errors)); rad.setLaunchSite(toLaunchSiteDTO(doc, warnings, errors)); + rad.setRecovery(toRecoveryDTO(doc.getRocket(), warnings, errors)); rad.setSimulationList(toSimulationListDTO(doc, warnings, errors)); return rad; @@ -107,6 +108,17 @@ public class RASAeroSaver extends RocketSaver { return new LaunchSiteDTO(document, warnings, errors); } + /** + * Create RASAero recovery settings. + * @param rocket rocket to fetch the recovery devices from + * @param warnings list to add export warnings to + * @param errors list to add export errors to + * @return the RASAero launch site settings + */ + private RecoveryDTO toRecoveryDTO(Rocket rocket, WarningSet warnings, ErrorSet errors) { + return new RecoveryDTO(rocket, warnings, errors); + } + /** * Create a list of simulations. * @param document document that contains simulations diff --git a/core/src/net/sf/openrocket/file/rasaero/export/RecoveryDTO.java b/core/src/net/sf/openrocket/file/rasaero/export/RecoveryDTO.java index ba79f415b..f0ffed438 100644 --- a/core/src/net/sf/openrocket/file/rasaero/export/RecoveryDTO.java +++ b/core/src/net/sf/openrocket/file/rasaero/export/RecoveryDTO.java @@ -1,12 +1,241 @@ package net.sf.openrocket.file.rasaero.export; +import net.sf.openrocket.file.rasaero.CustomBooleanAdapter; +import net.sf.openrocket.file.rasaero.CustomDoubleAdapter; import net.sf.openrocket.file.rasaero.RASAeroCommonConstants; +import net.sf.openrocket.logging.ErrorSet; +import net.sf.openrocket.logging.WarningSet; +import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; +import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.LinkedList; +import java.util.List; @XmlRootElement(name = RASAeroCommonConstants.RECOVERY) @XmlAccessorType(XmlAccessType.FIELD) public class RecoveryDTO { + @XmlElement(name = RASAeroCommonConstants.RECOVERY_ALTITUDE + 1) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double altitude1 = 0d; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_ALTITUDE + 2) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double altitude2 = 0d; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_DEVICE_TYPE + 1) + private String deviceType1 = "None"; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_DEVICE_TYPE + 2) + private String deviceType2 = "None"; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_EVENT + 1) + @XmlJavaTypeAdapter(CustomBooleanAdapter.class) + private Boolean event1 = false; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_EVENT + 2) + @XmlJavaTypeAdapter(CustomBooleanAdapter.class) + private Boolean event2 = false; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_SIZE + 1) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double size1 = 0d; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_SIZE + 2) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double size2 = 0d; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_EVENT_TYPE + 1) + private String eventType1 = "None"; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_EVENT_TYPE + 2) + private String eventType2 = "None"; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_CD + 1) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double CD1 = 0d; + @XmlElement(name = RASAeroCommonConstants.RECOVERY_CD + 2) + @XmlJavaTypeAdapter(CustomDoubleAdapter.class) + private Double CD2 = 0d; + + + @XmlTransient + private static final Logger log = LoggerFactory.getLogger(RecoveryDTO.class); + + /** + * We need a default, no-args constructor. + */ + public RecoveryDTO() { + } + + public RecoveryDTO(Rocket rocket, WarningSet warnings, ErrorSet errors) { + List parachutes = getParachutesFromRocket(rocket); + + switch (parachutes.size()) { + case 0: + log.debug("No parachutes present"); + break; + case 1: + configureRecoveryDevice1(parachutes.get(0), errors); + break; + case 2: + configureRecoveryDevice1(parachutes.get(0), errors); + configureRecoveryDevice2(parachutes.get(1), errors); + break; + } + } + + private List getParachutesFromRocket(Rocket rocket) { + List parachutes = new LinkedList<>(); + + for (int i = 0; i < Math.min(rocket.getChildCount(), 3); i++) { + AxialStage stage = (AxialStage) rocket.getChild(i); + + for (RocketComponent stageChild : stage.getChildren()) { + if (stageChild instanceof BodyTube) { + for (RocketComponent child : stageChild) { + if (child instanceof Parachute) { + parachutes.add((Parachute) child); + if (parachutes.size() == 2) { + return parachutes; + } + } + } + } + } + } + + return parachutes; + } + + private void configureRecoveryDevice1(Parachute device1, ErrorSet errors) { + setCD1(device1.getCD()); + setDeviceType1("Parachute"); + DeploymentConfiguration deployConfig = device1.getDeploymentConfigurations().getDefault(); + setAltitude1(deployConfig.getDeployAltitude() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_ALTITUDE); + if (deployConfig.getDeployEvent() == DeploymentConfiguration.DeployEvent.APOGEE) { + setEventType1(RASAeroCommonConstants.DEPLOYMENT_APOGEE); + } else if (deployConfig.getDeployEvent() == DeploymentConfiguration.DeployEvent.ALTITUDE) { + setEventType1(RASAeroCommonConstants.RECOVERY_ALTITUDE); + } else { + errors.add(String.format("RASAero only supports apogee and altitude deployment events for parachute '%s', not '%s'", + device1.getName(), deployConfig.getDeployEvent().toString())); + } + setEvent1(true); + setSize1(device1.getDiameter() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH); + } + + private void configureRecoveryDevice2(Parachute device2, ErrorSet errors) { + setCD1(device2.getCD()); + setDeviceType2("Parachute"); + DeploymentConfiguration deployConfig = device2.getDeploymentConfigurations().getDefault(); + setAltitude2(deployConfig.getDeployAltitude() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_ALTITUDE); + if (deployConfig.getDeployEvent() == DeploymentConfiguration.DeployEvent.APOGEE) { + setEventType2(RASAeroCommonConstants.DEPLOYMENT_APOGEE); + } else if (deployConfig.getDeployEvent() == DeploymentConfiguration.DeployEvent.ALTITUDE) { + setEventType2(RASAeroCommonConstants.RECOVERY_ALTITUDE); + } else { + errors.add(String.format("RASAero only supports apogee and altitude deployment events for parachute '%s', not '%s'", + device2.getName(), deployConfig.getDeployEvent().toString())); + } + setEvent2(true); + setSize2(device2.getDiameter() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH); + } + + public Double getAltitude1() { + return altitude1; + } + + public void setAltitude1(Double altitude1) { + this.altitude1 = altitude1; + } + + public Double getAltitude2() { + return altitude2; + } + + public void setAltitude2(Double altitude2) { + this.altitude2 = altitude2; + } + + public String getDeviceType1() { + return deviceType1; + } + + public void setDeviceType1(String deviceType1) { + this.deviceType1 = deviceType1; + } + + public String getDeviceType2() { + return deviceType2; + } + + public void setDeviceType2(String deviceType2) { + this.deviceType2 = deviceType2; + } + + public Boolean getEvent1() { + return event1; + } + + public void setEvent1(Boolean event1) { + this.event1 = event1; + } + + public Boolean getEvent2() { + return event2; + } + + public void setEvent2(Boolean event2) { + this.event2 = event2; + } + + public Double getSize1() { + return size1; + } + + public void setSize1(Double size1) { + this.size1 = size1; + } + + public Double getSize2() { + return size2; + } + + public void setSize2(Double size2) { + this.size2 = size2; + } + + public String getEventType1() { + return eventType1; + } + + public void setEventType1(String eventType1) { + this.eventType1 = eventType1; + } + + public String getEventType2() { + return eventType2; + } + + public void setEventType2(String eventType2) { + this.eventType2 = eventType2; + } + + public Double getCD1() { + return CD1; + } + + public void setCD1(Double CD1) { + this.CD1 = CD1; + } + + public Double getCD2() { + return CD2; + } + + public void setCD2(Double CD2) { + this.CD2 = CD2; + } }