1 package net.sf.openrocket.motor;
3 import java.io.UnsupportedEncodingException;
4 import java.security.MessageDigest;
5 import java.security.NoSuchAlgorithmException;
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.TextUtil;
10 public class MotorDigest {
12 private static final double EPSILON = 0.00000000001;
14 public enum DataType {
15 /** An array of time points at which data is available (in ms) */
17 /** Mass data for a few specific points (normally initial and empty mass) (in 0.1g) */
18 MASS_SPECIFIC(1, 10000),
19 /** Mass per time (in 0.1g) */
20 MASS_PER_TIME(2, 10000),
21 /** CG position for a few specific points (normally initial and final CG) (in mm) */
23 /** CG position per time (in mm) */
25 /** Thrust force per time (in mN) */
26 FORCE_PER_TIME(5, 1000);
28 private final int order;
29 private final int multiplier;
30 DataType(int order, int multiplier) {
32 this.multiplier = multiplier;
34 public int getOrder() {
37 public int getMultiplier() {
43 private final MessageDigest digest;
44 private boolean used = false;
45 private int lastOrder = -1;
48 public MotorDigest() {
50 digest = MessageDigest.getInstance("MD5");
51 } catch (NoSuchAlgorithmException e) {
52 throw new IllegalStateException("MD5 digest not supported by JRE", e);
57 public void update(DataType type, int ... values) {
59 // Check for correct order
60 if (lastOrder >= type.getOrder()) {
61 throw new IllegalArgumentException("Called with type="+type+" order="+type.getOrder()+
62 " while lastOrder=" + lastOrder);
64 lastOrder = type.getOrder();
67 digest.update(bytes(type.getOrder()));
69 // Digest the data length
70 digest.update(bytes(values.length));
74 digest.update(bytes(v));
80 private void update(DataType type, int multiplier, double ... values) {
82 int[] intValues = new int[values.length];
83 for (int i=0; i<values.length; i++) {
88 intValues[i] = (int) Math.round(v);
90 update(type, intValues);
93 public void update(DataType type, double ... values) {
94 update(type, type.getMultiplier(), values);
97 private static double next(double v) {
98 return v + Math.signum(v) * EPSILON;
102 public String getDigest() {
104 throw new IllegalStateException("MotorDigest already used");
107 byte[] result = digest.digest();
108 return TextUtil.hexString(result);
113 private byte[] bytes(int value) {
115 (byte) ((value>>>24) & 0xFF), (byte) ((value>>>16) & 0xFF),
116 (byte) ((value>>>8) & 0xFF), (byte) (value & 0xFF)
122 * Digest the contents of a thrust curve motor. The result is a string uniquely
123 * defining the functional aspects of the motor.
125 * @param m the motor to digest
128 public static String digestMotor(ThrustCurveMotor m) {
130 // Create the motor digest from data available in RASP files
131 MotorDigest motorDigest = new MotorDigest();
132 motorDigest.update(DataType.TIME_ARRAY, m.getTimePoints());
134 Coordinate[] cg = m.getCGPoints();
135 double[] cgx = new double[cg.length];
136 double[] mass = new double[cg.length];
137 for (int i=0; i<cg.length; i++) {
139 mass[i] = cg[i].weight;
142 motorDigest.update(DataType.MASS_PER_TIME, mass);
143 motorDigest.update(DataType.CG_PER_TIME, cgx);
144 motorDigest.update(DataType.FORCE_PER_TIME, m.getThrustPoints());
145 return motorDigest.getDigest();
149 public static String digestComment(String comment) {
150 comment = comment.replaceAll("\\s+", " ").trim();
152 MessageDigest digest;
154 digest = MessageDigest.getInstance("MD5");
155 } catch (NoSuchAlgorithmException e) {
156 throw new IllegalStateException("MD5 digest not supported by JRE", e);
160 digest.update(comment.getBytes("UTF-8"));
161 } catch (UnsupportedEncodingException e) {
162 throw new IllegalStateException("UTF-8 encoding not supported by JRE", e);
165 return TextUtil.hexString(digest.digest());