Refactored the rocksim csv component parser system to allow for more flexible column definitions. Pulled each type of file parser into its own file. Use template pattern in the RocksimComponentFileLoader hierarchy. Change the OpenRocketComponentSaver (Jaxb driver code) to throw exceptions instead of trying to handle them on its own.

This commit is contained in:
Kevin Ruland 2012-04-26 21:10:34 +00:00
parent 42df7deb5b
commit 2827046b15
21 changed files with 968 additions and 617 deletions

View File

@ -0,0 +1,42 @@
package net.sf.openrocket.preset.loader;
import java.util.Locale;
import net.sf.openrocket.preset.TypedPropertyMap;
public abstract class BaseColumnParser implements RocksimComponentFileColumnParser {
protected String columnHeader;
protected boolean isConfigured = false;
protected int columnIndex;
public BaseColumnParser(String columnHeader) {
super();
this.columnHeader = columnHeader.toLowerCase(Locale.US);
}
@Override
public void configure(String[] headers) {
if ( headers == null ) {
return;
}
for( int i =0; i< headers.length; i++ ) {
if ( columnHeader.equals(headers[i].toLowerCase(Locale.US))) {
columnIndex = i;
isConfigured = true;
return;
}
}
}
@Override
final public void parse(String[] data, TypedPropertyMap props) {
if ( isConfigured ) {
doParse(data[columnIndex], data, props);
}
}
protected abstract void doParse(String columnData, String[] data, TypedPropertyMap props );
}

View File

@ -0,0 +1,47 @@
package net.sf.openrocket.preset.loader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPresetFactory;
import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.preset.TypedPropertyMap;
public abstract class BaseComponentLoader extends RocksimComponentFileLoader {
List<ComponentPreset> presets;
public BaseComponentLoader(Map<String, Material> materials) {
super();
presets = new ArrayList<ComponentPreset>();
fileColumns.add( new ManufacturerColumnParser() );
fileColumns.add( new StringColumnParser("Part No.", ComponentPreset.PARTNO));
fileColumns.add( new StringColumnParser("Desc.", ComponentPreset.DESCRIPTION));
fileColumns.add(new MaterialColumnParser(materials));
fileColumns.add(new DoubleUnitColumnParser("Mass","Mass units",ComponentPreset.MASS));
}
protected abstract ComponentPreset.Type getComponentPresetType();
public List<ComponentPreset> getPresets() {
return presets;
}
@Override
protected void postProcess(TypedPropertyMap props) {
try {
props.put(ComponentPreset.TYPE, getComponentPresetType());
ComponentPreset preset = ComponentPresetFactory.create(props);
presets.add(preset);
} catch ( InvalidComponentPresetException ex ) {
System.err.println(ex.getMessage());
System.err.println(props);
}
}
}

View File

@ -0,0 +1,53 @@
package net.sf.openrocket.preset.loader;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
public abstract class BaseUnitColumnParser extends BaseColumnParser {
protected String unitHeader;
protected int unitIndex;
protected boolean unitConfigured;
protected static Map<String,Unit> rocksimUnits;
static {
rocksimUnits = new HashMap<String,Unit>();
rocksimUnits.put("0", UnitGroup.UNITS_LENGTH.getUnit("in"));
rocksimUnits.put("1", UnitGroup.UNITS_LENGTH.getUnit("mm"));
}
protected String mungeUnitNameString( String name ) {
String newString = name.toLowerCase(Locale.US);
return newString.replace(".", "");
}
public BaseUnitColumnParser(String columnHeader, String unitHeader) {
super(columnHeader);
this.unitHeader = unitHeader.toLowerCase(Locale.US);
}
@Override
public void configure(String[] headers) {
// super configure will set columnIndex;
super.configure(headers);
// This indicates the actual dimension column was found.
if ( isConfigured ) {
// Look for the unit column proceeding it
for( int i=columnIndex-1; i>=0; i-- ) {
if ( unitHeader.equals(headers[i].toLowerCase(Locale.US))) {
unitConfigured = true;
unitIndex = i;
return;
}
}
}
}
}

View File

@ -0,0 +1,31 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
public class BodyTubeLoader extends BaseComponentLoader {
public BodyTubeLoader(Map<String, Material> materials) {
super(materials);
fileColumns.add(new DoubleUnitColumnParser("ID","Units",ComponentPreset.INNER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.BODY_TUBE;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.BODY_TUBE;
}
}

View File

@ -0,0 +1,37 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
import net.sf.openrocket.preset.TypedPropertyMap;
public class BulkHeadLoader extends BaseComponentLoader {
public BulkHeadLoader(Map<String, Material> materials) {
super(materials);
fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.BULK_HEAD;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.BULKHEAD;
}
@Override
protected void postProcess(TypedPropertyMap props) {
props.put(ComponentPreset.FILLED, true);
super.postProcess(props);
}
}

View File

@ -0,0 +1,25 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
public class CenteringRingLoader extends BodyTubeLoader {
public CenteringRingLoader(Map<String, Material> materials) {
super(materials);
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.CENTERING_RING;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.CENTERING_RING;
}
}

View File

@ -0,0 +1,21 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.preset.TypedPropertyMap;
public class DoubleColumnParser extends BaseColumnParser {
private TypedKey<Double> propKey;
public DoubleColumnParser(String columnHeader, TypedKey<Double> propKey) {
super(columnHeader);
this.propKey = propKey;
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
double value = Double.valueOf(columnData);
props.put(propKey, value);
}
}

View File

@ -0,0 +1,55 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
public class DoubleUnitColumnParser extends BaseUnitColumnParser {
private TypedKey<Double> propKey;
public DoubleUnitColumnParser(String columnHeader, String unitHeader,
TypedKey<Double> propKey) {
super(columnHeader, unitHeader);
this.propKey = propKey;
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
try {
if (columnData == null || "".equals(columnData) ) {
return;
}
double value = Double.valueOf(columnData);
if ( unitConfigured ) {
String unitName = data[unitIndex];
Unit unit = rocksimUnits.get(unitName);
if ( unit == null ) {
if ( unitName == null || "" .equals(unitName) ) {
// Hmm no data... Lets assume SI
if ( propKey.getUnitGroup() == UnitGroup.UNITS_LENGTH ) {
unit = UnitGroup.UNITS_LENGTH.getUnit("in");
} else {
unit= UnitGroup.UNITS_MASS.getUnit("oz");
}
} else {
unitName = super.mungeUnitNameString(unitName);
UnitGroup group = propKey.getUnitGroup();
unit = group.getUnit(unitName);
}
}
value = unit.fromUnit(value);
}
props.put(propKey, value);
}
catch ( NumberFormatException nex) {
}
}
}

View File

@ -0,0 +1,25 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
public class EngineBlockLoader extends BodyTubeLoader {
public EngineBlockLoader(Map<String, Material> materials) {
super(materials);
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.ENGINE_BLOCK;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.ENGINE_BLOCK;
}
}

View File

@ -0,0 +1,20 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.motor.Manufacturer;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.TypedPropertyMap;
public class ManufacturerColumnParser extends BaseColumnParser {
public ManufacturerColumnParser() {
super("Mfg.");
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
Manufacturer m = Manufacturer.getManufacturer(columnData);
props.put(ComponentPreset.MANUFACTURER, m);
}
}

View File

@ -0,0 +1,31 @@
package net.sf.openrocket.preset.loader;
import java.util.Collections;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.TypedPropertyMap;
public class MaterialColumnParser extends BaseColumnParser {
private Map<String,Material> materialMap = Collections.<String,Material>emptyMap();
// FIXME - BULK vs other types.
public MaterialColumnParser(Map<String,Material> materialMap) {
super("Material");
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
Material m = materialMap.get(columnData);
if ( m == null ) {
m = new Material.Bulk(columnData, 0.0, true);
}
props.put(ComponentPreset.MATERIAL, m);
}
}

View File

@ -0,0 +1,62 @@
package net.sf.openrocket.preset.loader;
import java.util.HashMap;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.util.BugException;
public class MaterialLoader extends RocksimComponentFileLoader {
private Map<String,Material> materialMap = new HashMap<String,Material>();
private final static TypedKey<String> MATERIALNAME = new TypedKey<String>("MaterialName", String.class);
private final static TypedKey<String> UNITS = new TypedKey<String>("Units", String.class);
private final static TypedKey<Double> DENSITY = new TypedKey<Double>("Density", Double.class);
public MaterialLoader() {
super();
fileColumns.add( new StringColumnParser("Material Name", MATERIALNAME) );
fileColumns.add( new StringColumnParser("Units", UNITS));
fileColumns.add( new DoubleColumnParser("Density", DENSITY));
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.MATERIAL;
}
public Map<String, Material> getMaterialMap() {
return materialMap;
}
@Override
protected void postProcess(TypedPropertyMap props) {
String name = props.get(MATERIALNAME);
String unit = props.get(UNITS);
double density = props.get(DENSITY);
String cleanedMaterialName = stripAll(name, '"').trim();
if ( "g/cm".equals( unit ) ) {
materialMap.put( cleanedMaterialName, new Material.Line(cleanedMaterialName, 0.1d * density, true));
} else if ( "g/cm2".equals(unit) ) {
materialMap.put( cleanedMaterialName, new Material.Surface(cleanedMaterialName, 10.0d * density, true));
} else if ( "g/cm3".equals(unit) ) {
materialMap.put( cleanedMaterialName, new Material.Bulk(cleanedMaterialName, 1000.0d * density, true));
} else if ( "kg/m3".equals(unit) ) {
materialMap.put( cleanedMaterialName, new Material.Bulk(cleanedMaterialName, density, true));
} else if ( "lb/ft3".equals(unit) ) {
materialMap.put( cleanedMaterialName, new Material.Bulk(cleanedMaterialName, 16.0184634d * density, true));
} else if ( "oz/in".equals(unit) ) {
materialMap.put( cleanedMaterialName, new Material.Line(cleanedMaterialName, 1.11612296d * density, true));
} else if ( "oz/in2".equals(unit ) ) {
materialMap.put( cleanedMaterialName, new Material.Surface(cleanedMaterialName, 43.94184876d * density, true));
} else {
throw new BugException("Unknown unit in Materials file: " + unit);
}
}
}

View File

@ -0,0 +1,45 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
import net.sf.openrocket.preset.TypedPropertyMap;
public class NoseConeLoader extends BaseComponentLoader {
public NoseConeLoader(Map<String, Material> materials) {
super(materials);
fileColumns.add(new DoubleUnitColumnParser("Outer Dia","Units",ComponentPreset.AFT_OUTER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
fileColumns.add(new DoubleUnitColumnParser("Insert Length","Units",ComponentPreset.AFT_SHOULDER_LENGTH));
fileColumns.add(new DoubleUnitColumnParser("Insert OD","Units",ComponentPreset.AFT_SHOULDER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Thickness","Units",ComponentPreset.THICKNESS));
fileColumns.add(new ShapeColumnParser() );
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.NOSE_CONE;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.NOSE_CONE;
}
@Override
protected void postProcess(TypedPropertyMap props) {
if ( props.containsKey( ComponentPreset.THICKNESS )) {
double thickness = props.get(ComponentPreset.THICKNESS);
if ( thickness == 0d ) {
props.remove( ComponentPreset.THICKNESS );
props.put(ComponentPreset.FILLED, true);
}
}
super.postProcess(props);
}
}

View File

@ -0,0 +1,22 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.preset.TypedPropertyMap;
public interface RocksimComponentFileColumnParser {
/**
* Examine the array of column headers and configure parsing for this type.
*
* @param headers
*/
public void configure( String[] headers );
/**
* Examine the data array, parse the appropriate data and push into props.
*
* @param data
* @param props
*/
public void parse( String[] data, TypedPropertyMap props );
}

View File

@ -1,47 +1,40 @@
package net.sf.openrocket.preset.loader;
import au.com.bytecode.opencsv.CSVReader;
import net.sf.openrocket.database.Databases;
import net.sf.openrocket.file.preset.ColumnDefinition;
import net.sf.openrocket.file.rocksim.RocksimNoseConeCode;
import net.sf.openrocket.gui.print.PrintUnit;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPresetFactory;
import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.BugException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.openrocket.gui.print.PrintUnit;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.ArrayList;
import au.com.bytecode.opencsv.CSVReader;
/**
* Primary entry point for parsing component CSV files that are in Rocksim format.
*/
public class RocksimComponentFileLoader {
public abstract class RocksimComponentFileLoader {
/**
* Common unit of measure key. Rocksim format allows different types of units.
*/
public final static TypedKey<String> UNITS_OF_MEASURE = new TypedKey<String>("Units", String.class);
public static String basePath = "";
protected List<RocksimComponentFileColumnParser> fileColumns;
public RocksimComponentFileLoader() {
super();
fileColumns = new ArrayList<RocksimComponentFileColumnParser>();
}
/**
protected abstract RocksimComponentFileType getFileType();
public void load() {
load( getFileType() );
}
/**
* Read a comma separated component file and return the parsed contents as a list of string arrays. Not for
* production use - just here for smoke testing.
*
@ -50,8 +43,23 @@ public class RocksimComponentFileLoader {
* component data file; the element in the list itself is an array of String, where each item in the array
* is a column (cell) in the row. The string array is in sequential order as it appeared in the file.
*/
public static List<String[]> load(RocksimComponentFileType type) {
return load(RocksimComponentFileLoader.class.getResourceAsStream("/giantleaprocketry/" + type.getDefaultFileName()));
private void load(RocksimComponentFileType type) {
File dir = new File(basePath);
if ( !dir.exists() ) {
throw new IllegalArgumentException( basePath + " does not exist" );
}
if ( !dir.isDirectory() ) {
throw new IllegalArgumentException( basePath + " is not directory" );
}
if ( !dir.canRead() ) {
throw new IllegalArgumentException ( basePath + " is not readable" );
}
try {
FileInputStream fis = new FileInputStream( new File(dir, type.getDefaultFileName()));
load(fis);
} catch (FileNotFoundException ex) {
// FIXME?
}
}
/**
@ -62,8 +70,8 @@ public class RocksimComponentFileLoader {
* component data file; the element in the list itself is an array of String, where each item in the array
* is a column (cell) in the row. The string array is in sequential order as it appeared in the file.
*/
public static List<String[]> load(File file) throws FileNotFoundException {
return load(new FileInputStream(file));
private void load(File file) throws FileNotFoundException {
load(new FileInputStream(file));
}
/**
@ -74,9 +82,9 @@ public class RocksimComponentFileLoader {
* component data file; the element in the list itself is an array of String, where each item in the array
* is a column (cell) in the row. The string array is in sequential order as it appeared in the file.
*/
public static List<String[]> load(InputStream is) {
private void load(InputStream is) {
if (is == null) {
return new ArrayList<String[]>();
return;
}
InputStreamReader r = null;
try {
@ -86,10 +94,21 @@ public class RocksimComponentFileLoader {
CSVReader reader = new CSVReader(r, ',', '\'', '\\');
//Read and throw away the header row.
reader.readNext();
parseHeaders(reader.readNext());
String[] data = null;
while( (data = reader.readNext()) != null ) {
// detect empty lines and skip:
if ( data.length == 0 ) {
continue;
}
if ( data.length == 1 && "".equals(data[0].trim())) {
continue;
}
parseData(data);
}
//Read the rest of the file as data rows.
return reader.readAll();
return;
}
catch (IOException e) {
}
@ -103,9 +122,43 @@ public class RocksimComponentFileLoader {
}
}
return new ArrayList<String[]>();
}
protected void parseHeaders( String[] headers ) {
for( RocksimComponentFileColumnParser column : fileColumns ) {
column.configure(headers);
}
}
protected void parseData( String[] data ) {
if ( data == null || data.length == 0 ) {
return;
}
TypedPropertyMap props = new TypedPropertyMap();
preProcess( data );
for( RocksimComponentFileColumnParser column : fileColumns ) {
column.parse(data, props);
}
postProcess( props );
}
protected void preProcess( String[] data ) {
for( int i = 0; i< data.length; i++ ) {
String d = data[i];
if (d == null) {
continue;
}
d = d.trim();
d = stripAll(d, '"');
data[i] = d;
}
}
protected abstract void postProcess( TypedPropertyMap props );
/**
* Rocksim CSV units are either inches or mm. A value of 0 or "in." indicate inches. A value of 1 or "mm" indicate
* millimeters.
@ -113,7 +166,7 @@ public class RocksimComponentFileLoader {
* @param units the value from the file
* @return true if it's inches
*/
private static boolean isInches(String units) {
protected static boolean isInches(String units) {
String tmp = units.trim().toLowerCase();
return "0".equals(tmp) || tmp.startsWith("in");
}
@ -125,7 +178,7 @@ public class RocksimComponentFileLoader {
* @param value the original value within the CSV file
* @return the value in meters
*/
private static double convertLength(String units, double value) {
protected static double convertLength(String units, double value) {
if (isInches(units)) {
return PrintUnit.INCHES.toMeters(value);
}
@ -133,6 +186,14 @@ public class RocksimComponentFileLoader {
return PrintUnit.MILLIMETERS.toMeters(value);
}
}
protected static double convertMass(String units, double value ) {
if ( "oz".equals(units) ) {
Unit u = UnitGroup.UNITS_MASS.getUnit(2);
return u.fromUnit(value);
}
return value;
}
/**
* Remove all occurrences of the given character. Note: this is done because some manufacturers embed double
@ -143,7 +204,7 @@ public class RocksimComponentFileLoader {
* @param toBeRemoved the character to remove
* @return target, minus every occurrence of toBeRemoved
*/
private static String stripAll(String target, Character toBeRemoved) {
protected static String stripAll(String target, Character toBeRemoved) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < target.length(); i++) {
Character c = target.charAt(i);
@ -163,7 +224,7 @@ public class RocksimComponentFileLoader {
* @param target the target string to be operated upon
* @return target, with the first letter of each word in uppercase
*/
private static String toCamelCase(String target) {
protected static String toCamelCase(String target) {
StringBuilder sb = new StringBuilder();
String[] t = target.split("[ ]");
if (t != null && t.length > 0) {
@ -179,447 +240,6 @@ public class RocksimComponentFileLoader {
}
}
/**
* The core loading method, shared by all component types.
*
* @param theData the data as read from the CSV file
* @param keyMap the list of typed keys that specify the preset's expected columns
* @param materialMap a map of material name to OR Material; this is sourced from a MATERIAL.CSV file that must
* accompany the component CSV file.
* @param type the kind of component
* @return a collection of preset's
*/
private static Collection<ComponentPreset> commonLoader(final List<String[]> theData,
final List<TypedKey<?>> keyMap,
final Map<String, Material> materialMap,
final ComponentPreset.Type type) {
Collection<ComponentPreset> result = new ArrayList<ComponentPreset>();
List<TypedPropertyMap> templates = new java.util.ArrayList<TypedPropertyMap>();
Set<String> favorites = Application.getPreferences().getComponentFavorites();
Integer uom = null;
ColumnDefinition[] columns = new ColumnDefinition[keyMap.size()];
for (int i = 0; i < keyMap.size(); i++) {
TypedKey key = keyMap.get(i);
if (key != null) {
columns[i] = new ColumnDefinition(key);
if (key.getName().equals("Units")) {
uom = i;
}
}
}
for (int i = 0; i < theData.size(); i++) {
String[] item = theData.get(i);
TypedPropertyMap preset = new TypedPropertyMap();
for (int j = 0; j < columns.length; j++) {
if (j < item.length) {
String value = item[j];
if (value == null) {
continue;
}
value = value.trim();
value = stripAll(value, '"');
if (value.length() == 0) {
continue;
}
final TypedKey typedKey = columns[j].getKey();
//If it's the material, then pull it out of our internal map. The map references the
//data from the associated MATERIAL.CSV file that is mandatory.
if (typedKey.equals(ComponentPreset.MATERIAL)) {
preset.put(ComponentPreset.MATERIAL, materialMap.get(value));
}
//The shape of a nosecone or transition must get mapped from Rocksim to OR.
else if (typedKey.equals(ComponentPreset.SHAPE)) {
preset.put(ComponentPreset.SHAPE, RocksimNoseConeCode.fromShapeNameOrCode(value).asOpenRocket());
}
else {
//Rocksim allows different types of length units. They must be converted and normalized to OR.
final UnitGroup unitGroup = typedKey.getUnitGroup();
if (unitGroup != null && unitGroup.equals(UnitGroup.UNITS_LENGTH)) {
columns[j].setProperty(preset, convertLength(item[uom], Double.valueOf(value)));
}
else {
columns[j].setProperty(preset, value);
}
}
}
}
//Set what kind of component this is.
preset.put(ComponentPreset.TYPE, type);
//Add to the collection.
templates.add(preset);
}
for (TypedPropertyMap o : templates) {
try {
ComponentPreset preset = ComponentPresetFactory.create(o);
if (favorites.contains(preset.preferenceKey())) {
preset.setFavorite(true);
}
result.add(preset);
}
catch (InvalidComponentPresetException ex) {
throw new BugException(ex);
}
}
return result;
}
static class BodyTubeLoader {
private final static int MFG_INDEX = 0;
private final static int PART_NO_INDEX = 1;
private final static int DESCRIPTION_INDEX = 2;
private final static int UNITS_INDEX = 3;
private final static int ID_INDEX = 4;
private final static int OD_INDEX = 5;
private final static int LENGTH_INDEX = 6;
private final static int MATERIAL_INDEX = 7;
public final static List<TypedKey<?>> keyMap = new ArrayList<TypedKey<?>>(8);
static {
keyMap.add(MFG_INDEX, ComponentPreset.MANUFACTURER);
keyMap.add(PART_NO_INDEX, ComponentPreset.PARTNO);
keyMap.add(DESCRIPTION_INDEX, ComponentPreset.DESCRIPTION);
keyMap.add(UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(ID_INDEX, ComponentPreset.INNER_DIAMETER);
keyMap.add(OD_INDEX, ComponentPreset.OUTER_DIAMETER);
keyMap.add(LENGTH_INDEX, ComponentPreset.LENGTH);
keyMap.add(MATERIAL_INDEX, ComponentPreset.MATERIAL);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.BODY_TUBE);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.BODY_TUBE);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.BODY_TUBE);
}
}
/**
* Tube coupler parser. Although there are additional fields in the file, they are not used by
* most (any?) manufacturers so we ignore them entirely.
*/
static class TubeCouplerLoader extends BodyTubeLoader {
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.TUBE_COUPLER);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.TUBE_COUPLER);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.TUBE_COUPLER);
}
}
/**
* Engine block parser. Although there are additional fields in the file, they are not used by
* most (any?) manufacturers so we ignore them entirely.
*/
static class EngineBlockLoader extends BodyTubeLoader {
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.ENGINE_BLOCK);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.ENGINE_BLOCK);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.ENGINE_BLOCK);
}
}
static class BulkheadLoader extends BodyTubeLoader {
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.BULKHEAD);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.BULK_HEAD);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.BULK_HEAD);
}
}
static class CenteringRingLoader extends BodyTubeLoader {
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.CENTERING_RING);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.CENTERING_RING);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.CENTERING_RING);
}
}
static class NoseConeLoader {
public static final int MFG_INDEX = 0;
public static final int PART_NO_INDEX = 1;
public static final int DESCRIPTION_INDEX = 2;
public static final int UNITS_INDEX = 3;
public static final int LENGTH_INDEX = 4;
public static final int OUTER_DIA_INDEX = 5;
public static final int LD_RATIO_INDEX = 6;
public static final int INSERT_LENGTH_INDEX = 7;
public static final int INSERT_OD_INDEX = 8;
public static final int THICKNESS_INDEX = 9;
public static final int SHAPE_INDEX = 10;
public static final int CONFIG_INDEX = 11;
public static final int MATERIAL_INDEX = 12;
public static final int CG_LOC_INDEX = 13;
public static final int MASS_UNITS_INDEX = 14;
public static final int MASS_INDEX = 15;
public static final int BASE_EXT_LEN_INDEX = 16;
public final static TypedKey<Double> LD_RATIO = new TypedKey<Double>("Len/Dia Ratio", Double.class);
public final static TypedKey<Double> BASE_EXT_LEN = new TypedKey<Double>("Base Ext Len", Double.class, UnitGroup.UNITS_LENGTH);
public final static TypedKey<String> CONFIG = new TypedKey<String>("Config", String.class);
public final static TypedKey<Double> CG_LOC = new TypedKey<Double>("CG Loc", Double.class, UnitGroup.UNITS_LENGTH);
public final static List<TypedKey<?>> keyMap = new ArrayList<TypedKey<?>>(17);
static {
keyMap.add(MFG_INDEX, ComponentPreset.MANUFACTURER);
keyMap.add(PART_NO_INDEX, ComponentPreset.PARTNO);
keyMap.add(DESCRIPTION_INDEX, ComponentPreset.DESCRIPTION);
keyMap.add(UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(LENGTH_INDEX, ComponentPreset.LENGTH);
keyMap.add(OUTER_DIA_INDEX, ComponentPreset.AFT_OUTER_DIAMETER);
keyMap.add(LD_RATIO_INDEX, LD_RATIO);
keyMap.add(INSERT_LENGTH_INDEX, ComponentPreset.AFT_SHOULDER_LENGTH);
keyMap.add(INSERT_OD_INDEX, ComponentPreset.AFT_SHOULDER_DIAMETER);
keyMap.add(THICKNESS_INDEX, ComponentPreset.THICKNESS);
keyMap.add(SHAPE_INDEX, ComponentPreset.SHAPE);
keyMap.add(CONFIG_INDEX, CONFIG);
keyMap.add(MATERIAL_INDEX, ComponentPreset.MATERIAL);
keyMap.add(CG_LOC_INDEX, CG_LOC);
keyMap.add(MASS_UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(MASS_INDEX, ComponentPreset.MASS);
keyMap.add(BASE_EXT_LEN_INDEX, BASE_EXT_LEN);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.NOSE_CONE);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.NOSE_CONE);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.NOSE_CONE);
}
}
static class TransitionLoader {
public static final int MFG_INDEX = 0;
public static final int PART_NO_INDEX = 1;
public static final int DESCRIPTION_INDEX = 2;
public static final int UNITS_INDEX = 3;
public static final int FRONT_INSERT_LENGTH_INDEX = 4;
public static final int FRONT_INSERT_OD_INDEX = 5;
public static final int FRONT_OD_INDEX = 6;
public static final int LENGTH_INDEX = 7;
public static final int REAR_OD_INDEX = 8;
public static final int CORE_DIA_INDEX = 9;
public static final int REAR_INSERT_LENGTH_INDEX = 10;
public static final int REAR_INSERT_OD_INDEX = 11;
public static final int THICKNESS_INDEX = 12;
public static final int CONFIG_INDEX = 13;
public static final int MATERIAL_INDEX = 14;
public static final int CG_LOC_INDEX = 15;
public static final int MASS_UNITS_INDEX = 16;
public static final int MASS_INDEX = 17;
public static final int SHAPE_INDEX = 18;
public final static TypedKey<String> CONFIG = new TypedKey<String>("Config", String.class);
public final static TypedKey<String> IGNORE = new TypedKey<String>("Ignore", String.class);
public final static TypedKey<Double> CG_LOC = new TypedKey<Double>("CG Loc", Double.class, UnitGroup.UNITS_LENGTH);
public final static List<TypedKey<?>> keyMap = new ArrayList<TypedKey<?>>(19);
static {
keyMap.add(MFG_INDEX, ComponentPreset.MANUFACTURER);
keyMap.add(PART_NO_INDEX, ComponentPreset.PARTNO);
keyMap.add(DESCRIPTION_INDEX, ComponentPreset.DESCRIPTION);
keyMap.add(UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(FRONT_INSERT_LENGTH_INDEX, ComponentPreset.FORE_SHOULDER_LENGTH);
keyMap.add(FRONT_INSERT_OD_INDEX, ComponentPreset.FORE_SHOULDER_DIAMETER);
keyMap.add(FRONT_OD_INDEX, ComponentPreset.FORE_OUTER_DIAMETER);
keyMap.add(LENGTH_INDEX, ComponentPreset.LENGTH);
keyMap.add(REAR_OD_INDEX, ComponentPreset.AFT_OUTER_DIAMETER);
keyMap.add(CORE_DIA_INDEX, IGNORE);
keyMap.add(REAR_INSERT_LENGTH_INDEX, ComponentPreset.AFT_SHOULDER_LENGTH);
keyMap.add(REAR_INSERT_OD_INDEX, ComponentPreset.AFT_SHOULDER_DIAMETER);
keyMap.add(THICKNESS_INDEX, ComponentPreset.THICKNESS);
keyMap.add(CONFIG_INDEX, CONFIG);
keyMap.add(MATERIAL_INDEX, ComponentPreset.MATERIAL);
keyMap.add(CG_LOC_INDEX, CG_LOC);
keyMap.add(MASS_UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(MASS_INDEX, ComponentPreset.MASS);
keyMap.add(SHAPE_INDEX, ComponentPreset.SHAPE);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap) {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.TRANSITION);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.TRANSITION);
}
public Collection<ComponentPreset> load(Map<String, Material> materialMap, File file) throws
FileNotFoundException {
List<String[]> data = RocksimComponentFileLoader.load(file);
return commonLoader(data, keyMap, materialMap, ComponentPreset.Type.TRANSITION);
}
}
static class MaterialLoader {
private final static int MATERIAL_INDEX = 0;
private final static int UNITS_INDEX = 1;
private final static int DENSITY_INDEX = 2;
private final static int LOW_INDEX = 3;
private final static int HIGH_INDEX = 4;
private final static int CLASS_INDEX = 5;
private final static int ROCKETRY_USE_INDEX = 6;
private final static int BODY_TUBES_INDEX = 7;
public static final int FIN_SETS_INDEX = 8;
public static final int LAUNCH_LUGS_INDEX = 9;
public static final int CORDS_INDEX = 10;
public static final int NOSE_INDEX = 11;
public static final int PARACHUTE_INDEX = 12;
public static final int STREAMER_INDEX = 13;
public static final int TRANSITION_INDEX = 14;
public static final int RING_INDEX = 15;
public static final int BULKHEAD_INDEX = 16;
public static final int ENGINE_BLOCK_INDEX = 17;
public static final int SLEEVE_INDEX = 18;
public static final int TUBE_COUPLER_INDEX = 19;
public static final int KNOWN_DIM_TYPE_INDEX = 27;
public static final int KNOWN_DIM_UNITS_INDEX = 28;
public static final int KNOWN_DIM_VALUE_INDEX = 29;
public final static List<TypedKey<?>> keyMap = new ArrayList<TypedKey<?>>(8);
public final static TypedKey<String> MATERIAL_NAME = new TypedKey<String>("Material Name", String.class);
public final static TypedKey<Double> DENSITY = new TypedKey<Double>("Density", Double.class);
static class MaterialAdapter {
Material.Type type;
double conversionFactor;
MaterialAdapter(Material.Type theType, double cf) {
type = theType;
conversionFactor = cf;
}
}
private final static Map<String, MaterialAdapter> materialAdapterMap = new HashMap<String, MaterialAdapter>();
static {
materialAdapterMap.put("g/cm", new MaterialAdapter(Material.Type.LINE, 0.1d));
materialAdapterMap.put("g/cm2", new MaterialAdapter(Material.Type.SURFACE, 10.0d));
materialAdapterMap.put("g/cm3", new MaterialAdapter(Material.Type.BULK, 1000.0d));
materialAdapterMap.put("kg/m3", new MaterialAdapter(Material.Type.BULK, 1d));
materialAdapterMap.put("lb/ft3", new MaterialAdapter(Material.Type.BULK, 16.0184634d));
materialAdapterMap.put("oz/in", new MaterialAdapter(Material.Type.LINE, 1.11612296d));
materialAdapterMap.put("oz/in2", new MaterialAdapter(Material.Type.SURFACE, 43.9418487));
keyMap.add(MATERIAL_INDEX, MATERIAL_NAME);
keyMap.add(UNITS_INDEX, UNITS_OF_MEASURE);
keyMap.add(DENSITY_INDEX, DENSITY);
}
static Map<String, Material> load() {
List<String[]> data = RocksimComponentFileLoader.load(RocksimComponentFileType.MATERIAL);
Map<String, Material> materialMap = new HashMap<String, Material>();
for (int i = 0; i < data.size(); i++) {
try {
String[] strings = data.get(i);
MaterialAdapter ma = materialAdapterMap.get(strings[UNITS_INDEX]);
double metricDensity = ma.conversionFactor * Double.parseDouble(strings[DENSITY_INDEX]);
final String cleanedMaterialName = stripAll(strings[MATERIAL_INDEX], '"').trim();
final Material material = Databases.findMaterial(ma.type, cleanedMaterialName,
metricDensity, true);
materialMap.put(cleanedMaterialName, material);
materialMap.put(cleanedMaterialName.toLowerCase(), material);
materialMap.put(toCamelCase(cleanedMaterialName), material);
}
catch (Exception e) {
//Trap a bad row and move on
//TODO: log it? Display to user?
}
}
return materialMap;
}
}
public static void main(String[] args) {
Application.setPreferences(new SwingPreferences());
Map<String, Material> materialMap = MaterialLoader.load();
Collection<ComponentPreset> presetNC = new NoseConeLoader().load(materialMap);
Collection<ComponentPreset> presetBC = new BodyTubeLoader().load(materialMap);
Collection<ComponentPreset> presetBH = new BulkheadLoader().load(materialMap);
Collection<ComponentPreset> presetCR = new CenteringRingLoader().load(materialMap);
Collection<ComponentPreset> presetTC = new TubeCouplerLoader().load(materialMap);
Collection<ComponentPreset> presetTR = new TransitionLoader().load(materialMap);
Collection<ComponentPreset> presetEB = new EngineBlockLoader().load(materialMap);
/*
for (Iterator<ComponentPreset> iterator = presetNC.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetBC.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetBH.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetCR.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetTC.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetTR.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
for (Iterator<ComponentPreset> iterator = presetEB.iterator(); iterator.hasNext(); ) {
ComponentPreset next = iterator.next();
System.err.println(next);
}
*/
List<ComponentPreset> allPresets = new ArrayList<ComponentPreset>();
allPresets.addAll(presetBC);
allPresets.addAll(presetBH);
allPresets.addAll(presetCR);
allPresets.addAll(presetEB);
allPresets.addAll(presetNC);
allPresets.addAll(presetTC);
allPresets.addAll(presetTR);
String xml = new OpenRocketComponentSaver().marshalToOpenRocketComponent(new ArrayList<Material>(materialMap.values()), allPresets);
System.err.println(xml);
try {
List<ComponentPreset> presets = new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new StringReader(xml));
}
catch (InvalidComponentPresetException e) {
e.printStackTrace();
}
}
}
//Errata:

View File

@ -0,0 +1,105 @@
package net.sf.openrocket.preset.loader;
import java.io.File;
import java.io.FileWriter;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.ArrayList;
public class RocksimComponentFileTranslator {
private static void printUsage() {
System.err.println("RocksimComponentFileLoader <dir> <file>");
System.err.println("<dir> is base directory for a set of Rocksim component csv files");
System.err.println("<file> is where the orc file is written");
}
public static void main(String[] args) throws Exception {
// How to control logging?
if ( args.length < 2 || args.length > 2 ) {
printUsage();
throw new IllegalArgumentException("Invalid Command Line Params");
}
List<ComponentPreset> allPresets = new ArrayList<ComponentPreset>();
RocksimComponentFileLoader.basePath = args[0];
System.err.println("Loading csv files from directory " + args[0]);
Application.setPreferences(new SwingPreferences());
MaterialLoader mats = new MaterialLoader();
mats.load();
Map<String, Material> materialMap = mats.getMaterialMap();
System.err.println("\tMaterial types loaded: " + materialMap.size());
{
BodyTubeLoader bts = new BodyTubeLoader(materialMap);
bts.load();
allPresets.addAll(bts.getPresets());
System.err.println("\tBody Tubes loaded: " + bts.getPresets().size());
}
{
BulkHeadLoader bhs = new BulkHeadLoader(materialMap);
bhs.load();
allPresets.addAll(bhs.getPresets());
System.err.println("\tBody Tubes loaded: " + bhs.getPresets().size());
}
{
CenteringRingLoader crs = new CenteringRingLoader(materialMap);
crs.load();
allPresets.addAll(crs.getPresets());
System.err.println("\tCentering Rings loaded: " + crs.getPresets().size());
}
{
TubeCouplerLoader tcs = new TubeCouplerLoader(materialMap);
tcs.load();
allPresets.addAll(tcs.getPresets());
System.err.println("\tTube Couplers loaded: " + tcs.getPresets().size());
}
{
EngineBlockLoader ebs = new EngineBlockLoader(materialMap);
ebs.load();
allPresets.addAll(ebs.getPresets());
System.err.println("\tEngine Blocks loaded: " + ebs.getPresets().size());
}
{
NoseConeLoader ncs = new NoseConeLoader(materialMap);
ncs.load();
allPresets.addAll(ncs.getPresets());
System.err.println("\tNose Cones loaded: " + ncs.getPresets().size());
}
{
TransitionLoader trs = new TransitionLoader(materialMap);
trs.load();
allPresets.addAll(trs.getPresets());
System.err.println("\tTransitions loaded: " + trs.getPresets().size());
}
System.err.println("\tMarshalling to XML");
String xml = new OpenRocketComponentSaver().marshalToOpenRocketComponent(new ArrayList<Material>(materialMap.values()), allPresets);
// Try parsing the file
System.err.println("\tValidating XML");
List<ComponentPreset> presets = new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new StringReader(xml));
System.err.println("\tWriting to file " + args[1]);
File outfile = new File(args[1]);
FileWriter fos = new FileWriter(outfile);
fos.write(xml);
fos.flush();
fos.close();
}
}

View File

@ -0,0 +1,54 @@
package net.sf.openrocket.preset.loader;
import java.util.Locale;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.rocketcomponent.Transition.Shape;
import net.sf.openrocket.util.BugException;
public class ShapeColumnParser extends BaseColumnParser {
public ShapeColumnParser() {
super("Shape");
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
Transition.Shape shape = null;
String lc = columnData.toLowerCase(Locale.US);
if ( "ogive".equals(lc) ) {
shape = Shape.OGIVE;
}
if ( "conical".equals(lc) ) {
shape = Shape.CONICAL;
}
if ( "cone".equals(lc) ) {
shape = Shape.CONICAL;
}
if ( "elliptical".equals(lc) ) {
shape = Shape.ELLIPSOID;
}
if ( "parabolic".equals(lc) ) {
shape = Shape.PARABOLIC;
}
if ( "sears-haack".equals(lc) ) {
shape = Shape.HAACK;
}
if ( "power-series".equals(lc) ) {
shape = Shape.POWER;
}
if ( "1".equals(lc) ) {
shape = Shape.OGIVE;
}
if( "0". equals(lc) ) {
shape = Shape.CONICAL;
}
if ( shape == null ) {
throw new BugException("Invalid shape parameter: " + columnData);
}
props.put(ComponentPreset.SHAPE, shape);
}
}

View File

@ -0,0 +1,20 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.preset.TypedPropertyMap;
public class StringColumnParser extends BaseColumnParser {
private TypedKey<String> propKey;
public StringColumnParser(String columnHeader, TypedKey<String> propKey) {
super(columnHeader);
this.propKey = propKey;
}
@Override
protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
props.put(propKey, columnData);
}
}

View File

@ -0,0 +1,31 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
public class TransitionLoader extends NoseConeLoader {
public TransitionLoader(Map<String, Material> materials) {
super(materials);
fileColumns.add(new DoubleUnitColumnParser("Front Insert Len","Units",ComponentPreset.FORE_SHOULDER_LENGTH));
fileColumns.add(new DoubleUnitColumnParser("Front Insert OD","Units",ComponentPreset.FORE_SHOULDER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Front OD","Units",ComponentPreset.FORE_OUTER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Rear Insert Len","Units",ComponentPreset.AFT_SHOULDER_LENGTH));
fileColumns.add(new DoubleUnitColumnParser("Rear Insert OD","Units",ComponentPreset.AFT_SHOULDER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Rear OD","Units",ComponentPreset.AFT_OUTER_DIAMETER));
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.TRANSITION;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.TRANSITION;
}
}

View File

@ -0,0 +1,25 @@
package net.sf.openrocket.preset.loader;
import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
public class TubeCouplerLoader extends BodyTubeLoader {
public TubeCouplerLoader(Map<String, Material> materials) {
super(materials);
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.TUBE_COUPLER;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.TUBE_COUPLER;
}
}

View File

@ -1,15 +1,5 @@
package net.sf.openrocket.preset.xml;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.startup.Application;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
@ -18,144 +8,134 @@ import java.io.Reader;
import java.io.StringWriter;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.InvalidComponentPresetException;
/**
* The active manager class that is the entry point for writing *.orc files.
*/
public class OpenRocketComponentSaver {
/**
* The logger.
*/
private static final LogHelper log = Application.getLogger();
/**
* This method marshals an OpenRocketDocument (OR design) to Rocksim-compliant XML.
*
* @param theMaterialList the list of materials to be included
* @param thePresetList the list of presets to be included
*
* @return ORC-compliant XML
* @throws JAXBException
*/
public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws JAXBException {
/**
* This method marshals an OpenRocketDocument (OR design) to Rocksim-compliant XML.
*
* @param theMaterialList the list of materials to be included
* @param thePresetList the list of presets to be included
*
* @return ORC-compliant XML
*/
public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
JAXBContext binder = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Marshaller marshaller = binder.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
try {
JAXBContext binder = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Marshaller marshaller = binder.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
return sw.toString();
marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
return sw.toString();
}
catch (Exception e) {
log.error("Could not marshal a preset list. " + e.getMessage());
}
}
return null;
}
/**
* This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
*
* @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle
* UTF characters correctly
*
* @return a list of ComponentPresets
*
* @throws InvalidComponentPresetException
*
*/
public List<ComponentPreset> unmarshalFromOpenRocketComponent(Reader is) throws JAXBException, InvalidComponentPresetException {
return fromOpenRocketComponent(is).asComponentPresets();
}
/**
* This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
*
* @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle
* UTF characters correctly
*
* @return a list of ComponentPresets
*
* @throws InvalidComponentPresetException
*
*/
public List<ComponentPreset> unmarshalFromOpenRocketComponent(Reader is) throws InvalidComponentPresetException {
return fromOpenRocketComponent(is).asComponentPresets();
}
/**
* Write an XML representation of a list of presets.
*
* @param dest the stream to write the data to
* @param theMaterialList the list of materials to be included
* @param thePresetList the list of presets to be included
* @throws JAXBException
* @throws IOException thrown if the stream could not be written
*/
public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws IOException, JAXBException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
writer.flush();
writer.close();
}
/**
* Write an XML representation of a list of presets.
*
* @param dest the stream to write the data to
* @param theMaterialList the list of materials to be included
* @param thePresetList the list of presets to be included
*
* @throws IOException thrown if the stream could not be written
*/
public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
IOException {
log.info("Saving .orc file");
/**
* Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
*
* @param is an open Reader; assumed to be opened on a file of XML in .orc format
*
* @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read
* or was in an invalid format
*/
private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
JAXBContext bind = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Unmarshaller unmarshaller = bind.createUnmarshaller();
return (OpenRocketComponentDTO) unmarshaller.unmarshal(is);
}
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
writer.flush();
writer.close();
}
/**
* Root conversion method. It iterates over all subcomponents.
*
* @return a corresponding ORC representation
*/
private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
/**
* Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
*
* @param is an open Reader; assumed to be opened on a file of XML in .orc format
*
* @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read
* or was in an invalid format
*/
private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) {
try {
JAXBContext bind = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Unmarshaller unmarshaller = bind.createUnmarshaller();
return (OpenRocketComponentDTO) unmarshaller.unmarshal(is);
}
catch (JAXBException e) {
log.error("Could not unmarshal the .orc file. ", e);
}
return null;
}
if (theMaterialList != null) {
for (Material material : theMaterialList) {
rsd.addMaterial(new MaterialDTO(material));
}
}
/**
* Root conversion method. It iterates over all subcomponents.
*
* @return a corresponding ORC representation
*/
private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
if (thePresetList != null) {
for (ComponentPreset componentPreset : thePresetList) {
rsd.addComponent(toComponentDTO(componentPreset));
}
}
return rsd;
}
if (theMaterialList != null) {
for (Material material : theMaterialList) {
rsd.addMaterial(new MaterialDTO(material));
}
}
/**
* Factory method that maps a preset to the corresponding DTO handler.
*
* @param thePreset the preset for which a handler will be found
*
* @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
* for the preset type
*/
private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
switch (thePreset.getType()) {
case BODY_TUBE:
return new BodyTubeDTO(thePreset);
case TUBE_COUPLER:
return new TubeCouplerDTO(thePreset);
case NOSE_CONE:
return new NoseConeDTO(thePreset);
case TRANSITION:
return new TransitionDTO(thePreset);
case BULK_HEAD:
return new BulkHeadDTO(thePreset);
case CENTERING_RING:
return new CenteringRingDTO(thePreset);
case ENGINE_BLOCK:
return new EngineBlockDTO(thePreset);
}
if (thePresetList != null) {
for (ComponentPreset componentPreset : thePresetList) {
rsd.addComponent(toComponentDTO(componentPreset));
}
}
return rsd;
}
/**
* Factory method that maps a preset to the corresponding DTO handler.
*
* @param thePreset the preset for which a handler will be found
*
* @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
* for the preset type
*/
private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
switch (thePreset.getType()) {
case BODY_TUBE:
return new BodyTubeDTO(thePreset);
case TUBE_COUPLER:
return new TubeCouplerDTO(thePreset);
case NOSE_CONE:
return new NoseConeDTO(thePreset);
case TRANSITION:
return new TransitionDTO(thePreset);
case BULK_HEAD:
return new BulkHeadDTO(thePreset);
case CENTERING_RING:
return new CenteringRingDTO(thePreset);
case ENGINE_BLOCK:
return new EngineBlockDTO(thePreset);
}
return null;
}
return null;
}
}