clean up template leftovers in copyright file
[debian/openrocket] / src / net / sf / openrocket / motor / MotorDigest.java
1 package net.sf.openrocket.motor;
2
3 import java.io.UnsupportedEncodingException;
4 import java.security.MessageDigest;
5 import java.security.NoSuchAlgorithmException;
6
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.TextUtil;
9
10 public class MotorDigest {
11         
12         private static final double EPSILON = 0.00000000001;
13         
14         public enum DataType {
15                 /** An array of time points at which data is available (in ms) */
16                 TIME_ARRAY(0, 1000),
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) */
22                 CG_SPECIFIC(3, 1000),
23                 /** CG position per time (in mm) */
24                 CG_PER_TIME(4, 1000),
25                 /** Thrust force per time (in mN) */
26                 FORCE_PER_TIME(5, 1000);
27
28                 private final int order;
29                 private final int multiplier;
30                 DataType(int order, int multiplier) {
31                         this.order = order;
32                         this.multiplier = multiplier;
33                 }
34                 public int getOrder() {
35                         return order;
36                 }
37                 public int getMultiplier() {
38                         return multiplier;
39                 }
40         }
41         
42
43         private final MessageDigest digest;
44         private boolean used = false;
45         private int lastOrder = -1;
46         
47         
48         public MotorDigest() {
49                 try {
50                         digest = MessageDigest.getInstance("MD5");
51                 } catch (NoSuchAlgorithmException e) {
52                         throw new IllegalStateException("MD5 digest not supported by JRE", e);
53                 }
54         }
55         
56         
57         public void update(DataType type, int ... values) {
58
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);
63                 }
64                 lastOrder = type.getOrder();
65                 
66                 // Digest the type
67                 digest.update(bytes(type.getOrder()));
68                 
69                 // Digest the data length
70                 digest.update(bytes(values.length));
71                 
72                 // Digest the values
73                 for (int v: values) {
74                         digest.update(bytes(v));
75                 }
76                 
77         }
78         
79         
80         private void update(DataType type, int multiplier, double ... values) {
81
82                 int[] intValues = new int[values.length];
83                 for (int i=0; i<values.length; i++) {
84                         double v = values[i];
85                         v = next(v);
86                         v *= multiplier;
87                         v = next(v);
88                         intValues[i] = (int) Math.round(v);
89                 }
90                 update(type, intValues);
91         }
92         
93         public void update(DataType type, double ... values) {
94                 update(type, type.getMultiplier(), values);
95         }
96         
97         private static double next(double v) {
98                 return v + Math.signum(v) * EPSILON;
99         }
100         
101         
102         public String getDigest() {
103                 if (used) {
104                         throw new IllegalStateException("MotorDigest already used");
105                 }
106                 used = true;
107                 byte[] result = digest.digest();
108                 return TextUtil.hexString(result);
109         }
110
111         
112         
113         private byte[] bytes(int value) {
114                 return new byte[] {
115                                 (byte) ((value>>>24) & 0xFF), (byte) ((value>>>16) & 0xFF),
116                                 (byte) ((value>>>8) & 0xFF), (byte) (value & 0xFF) 
117                 };
118         }
119
120         
121         /**
122          * Digest the contents of a thrust curve motor.  The result is a string uniquely
123          * defining the functional aspects of the motor.
124          * 
125          * @param m             the motor to digest
126          * @return              the digest
127          */
128         public static String digestMotor(ThrustCurveMotor m) {
129
130                 // Create the motor digest from data available in RASP files
131                 MotorDigest motorDigest = new MotorDigest();
132                 motorDigest.update(DataType.TIME_ARRAY, m.getTimePoints());
133                 
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++) {
138                         cgx[i] = cg[i].x;
139                         mass[i] = cg[i].weight;
140                 }
141                 
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();
146                 
147         }
148         
149         public static String digestComment(String comment) {
150                 comment = comment.replaceAll("\\s+", " ").trim();
151                 
152                 MessageDigest digest;
153                 try {
154                         digest = MessageDigest.getInstance("MD5");
155                 } catch (NoSuchAlgorithmException e) {
156                         throw new IllegalStateException("MD5 digest not supported by JRE", e);
157                 }
158                 
159                 try {
160                         digest.update(comment.getBytes("UTF-8"));
161                 } catch (UnsupportedEncodingException e) {
162                         throw new IllegalStateException("UTF-8 encoding not supported by JRE", e);
163                 }
164
165                 return TextUtil.hexString(digest.digest());
166         }
167         
168 }