00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package ikayaki;
00024
00025 import org.w3c.dom.Document;
00026 import org.w3c.dom.Element;
00027 import org.w3c.dom.NodeList;
00028
00029 import javax.vecmath.Matrix3d;
00030 import javax.vecmath.Vector3d;
00031 import java.util.ArrayList;
00032 import java.util.Date;
00033 import java.util.Iterator;
00034 import java.util.List;
00035
00036 import static ikayaki.MeasurementStep.State.*;
00037
00048 public class MeasurementStep implements Iterable<MeasurementResult> {
00049
00053 private final Project project;
00054
00058 private State state = State.READY;
00059
00064 private Date timestamp = null;
00065
00070 private double stepValue = -1.0;
00071
00075 private double mass = -1.0;
00076
00080 private double volume = -1.0;
00081
00086 private double susceptibility = -1.0;
00087
00091 private final List<MeasurementResult> results = new ArrayList<MeasurementResult>();
00092
00096 public MeasurementStep() {
00097 project = null;
00098 }
00099
00105 public MeasurementStep(Project project) {
00106 this.project = project;
00107 }
00108
00116 public MeasurementStep(Element element) {
00117 this(element, null);
00118 }
00119
00128 public MeasurementStep(Element element, Project project) {
00129 if (element == null) {
00130 throw new NullPointerException();
00131 }
00132 this.project = project;
00133 String s;
00134
00135
00136 if (!element.getTagName().equals("step")) {
00137 throw new IllegalArgumentException("Invalid tag name: " + element.getTagName());
00138 }
00139
00140
00141 s = element.getAttribute("stepvalue");
00142 try {
00143 double stepValue = Double.parseDouble(s);
00144 if (element.getAttribute("done").equals("1")) {
00145 if (stepValue < 0.0) {
00146 stepValue = -1.0;
00147 }
00148 this.stepValue = stepValue;
00149 } else {
00150 setStepValue(stepValue);
00151 }
00152 } catch (NumberFormatException e) {
00153 throw new IllegalArgumentException("Invalid stepvalue: " + s, e);
00154 }
00155 s = element.getAttribute("mass");
00156 try {
00157 setMass(Double.parseDouble(s));
00158 } catch (NumberFormatException e) {
00159 throw new IllegalArgumentException("Invalid mass: " + s, e);
00160 }
00161 s = element.getAttribute("volume");
00162 try {
00163 setVolume(Double.parseDouble(s));
00164 } catch (NumberFormatException e) {
00165 throw new IllegalArgumentException("Invalid volume: " + s, e);
00166 }
00167 s = element.getAttribute("susceptibility");
00168 try {
00169 setSusceptibility(Double.parseDouble(s));
00170 } catch (NumberFormatException e) {
00171 throw new IllegalArgumentException("Invalid susceptibility: " + s, e);
00172 }
00173
00174
00175 NodeList results = element.getElementsByTagName("result");
00176 for (int i = 0; i < results.getLength(); i++) {
00177 Element result = (Element) results.item(i);
00178 this.results.add(new MeasurementResult(result));
00179 }
00180
00181
00182 if (element.getAttribute("done").equals("1")) {
00183 state = DONE;
00184 } else {
00185 state = READY;
00186 }
00187
00188
00189 s = element.getAttribute("timestamp");
00190 if (s.equals("")) {
00191 timestamp = null;
00192 } else {
00193 try {
00194 timestamp = new Date(Long.parseLong(s));
00195 } catch (NumberFormatException e) {
00196 throw new IllegalArgumentException("Invalid timestamp: " + s, e);
00197 }
00198 }
00199
00200
00201 if (state.isDone()) {
00202 if (timestamp == null || this.results.size() == 0) {
00203 throw new IllegalArgumentException("Inconsistent state");
00204 }
00205 } else {
00206 if (timestamp != null || this.results.size() > 0) {
00207 throw new IllegalArgumentException("Inconsistent state");
00208 }
00209 }
00210
00211
00212 updateTransforms();
00213 }
00214
00220 public synchronized Element getElement(Document document) {
00221 Element element = document.createElement("step");
00222
00223 if (results.size() == 0) {
00224 element.setAttribute("done", "0");
00225 element.setAttribute("timestamp", "");
00226 } else {
00227 element.setAttribute("done", "1");
00228 element.setAttribute("timestamp", Long.toString(timestamp.getTime()));
00229 }
00230 element.setAttribute("stepvalue", Double.toString(stepValue));
00231 element.setAttribute("mass", Double.toString(mass));
00232 element.setAttribute("volume", Double.toString(volume));
00233 element.setAttribute("susceptibility", Double.toString(susceptibility));
00234
00235 for (MeasurementResult result : results) {
00236 element.appendChild(result.getElement(document));
00237 }
00238
00239 return element;
00240 }
00241
00245 public void save() {
00246 if (project != null) {
00247 project.save();
00248 }
00249 }
00250
00254 public synchronized Project getProject() {
00255 return project;
00256 }
00257
00261 public synchronized State getState() {
00262 return state;
00263 }
00264
00268 public synchronized Date getTimestamp() {
00269 if (!state.isDone()) {
00270 return null;
00271 }
00272 if (timestamp == null) {
00273 return null;
00274 } else {
00275 return (Date) timestamp.clone();
00276 }
00277 }
00278
00283 public synchronized double getStepValue() {
00284 return stepValue;
00285 }
00286
00295 public synchronized void setStepValue(double stepValue) {
00296 if (state != READY) {
00297 throw new IllegalStateException("Unable to set stepValue, state is: " + state);
00298 }
00299 if (stepValue < 0.0) {
00300 stepValue = -1.0;
00301 }
00302 if (getProject() != null && getProject().getType() == Project.Type.AF) {
00303
00304
00305 if (stepValue > 0.0 && stepValue < Settings.getDegausserMinimumField()) {
00306 stepValue = Settings.getDegausserMinimumField();
00307 }
00308
00309
00310 if (stepValue > 0.0) {
00311 double inc = Settings.getDegausserMinimumFieldIncrement();
00312 stepValue = stepValue / inc;
00313 stepValue = (int) (Math.round(stepValue)) * inc;
00314 }
00315
00316
00317 stepValue = Math.min(stepValue, Settings.getDegausserMaximumField());
00318 }
00319 this.stepValue = stepValue;
00320 save();
00321 }
00322
00327 public synchronized double getMass() {
00328 return mass;
00329 }
00330
00334 public synchronized void setMass(double mass) {
00335 if (mass < 0.0) {
00336 mass = -1.0;
00337 }
00338 this.mass = mass;
00339 save();
00340 }
00341
00346 public synchronized double getVolume() {
00347 return volume;
00348 }
00349
00353 public synchronized void setVolume(double volume) {
00354 if (volume < 0.0) {
00355 volume = -1.0;
00356 }
00357 this.volume = volume;
00358 save();
00359 }
00360
00365 public synchronized double getSusceptibility() {
00366 return susceptibility;
00367 }
00368
00372 public synchronized void setSusceptibility(double susceptibility) {
00373 if (susceptibility < 0.0) {
00374 susceptibility = -1.0;
00375 }
00376 this.susceptibility = susceptibility;
00377 save();
00378 }
00379
00384 protected synchronized void updateTransforms() {
00385 Matrix3d transform = null;
00386 if (project != null) {
00387 transform = project.getTransform();
00388 }
00389 for (MeasurementResult result : results) {
00390 result.applyFixes(this);
00391 result.setTransform(transform);
00392 }
00393 }
00394
00398 public synchronized int getResults() {
00399 return results.size();
00400 }
00401
00409 public synchronized MeasurementResult getResult(int index) {
00410 return results.get(index);
00411 }
00412
00424 public synchronized void addResult(MeasurementResult result) {
00425 if (result == null) {
00426 throw new NullPointerException();
00427 }
00428 if (state.isDone()) {
00429 throw new IllegalStateException("Unable to add results, state is: " + state);
00430 }
00431
00432 setMeasuring();
00433 if (results.size() == 0 && (getProject() == null || !getProject().isHolderCalibration())) {
00434
00435 MeasurementResult holder = Settings.getHolderCalibration();
00436 if (holder != null) {
00437 results.add(holder);
00438 }
00439 }
00440 results.add(result);
00441 timestamp = new Date();
00442 updateTransforms();
00443 save();
00444 }
00445
00451 public synchronized void setMeasuring() {
00452 if (state.isDone()) {
00453 throw new IllegalStateException("Unable set state to MEASURING, state is: " + state);
00454 }
00455 state = MEASURING;
00456 save();
00457 }
00458
00464 public synchronized void setDone() {
00465 if (!state.isDone()) {
00466
00467 if (getResults() == 0) {
00468 state = READY;
00469 } else {
00470 state = DONE_RECENTLY;
00471 }
00472 updateTransforms();
00473 save();
00474 }
00475 }
00476
00481 public synchronized Vector3d getHolder() {
00482 Vector3d v = new Vector3d();
00483 int count = 0;
00484 if (getProject() != null && getProject().isHolderCalibration()) {
00485 return v;
00486 }
00487 for (MeasurementResult result : results) {
00488 if (result.getType() != MeasurementResult.Type.HOLDER) {
00489 continue;
00490 }
00491
00492 v.add(result.getRawVector());
00493 count++;
00494 }
00495 if (count > 0) {
00496 v.scale(1.0 / count);
00497 }
00498 return v;
00499 }
00500
00505 public synchronized Vector3d getNoise() {
00506 Vector3d v = new Vector3d();
00507 int count = 0;
00508 for (MeasurementResult result : results) {
00509 if (result.getType() != MeasurementResult.Type.NOISE) {
00510 continue;
00511 }
00512
00513 v.add(result.getRawVector());
00514 count++;
00515 }
00516 if (count > 0) {
00517 v.scale(1.0 / count);
00518 }
00519 return v;
00520 }
00521
00525 public Iterator<MeasurementResult> iterator() {
00526 final MeasurementStep step = this;
00527
00528 return new Iterator<MeasurementResult>() {
00529
00530 private int next = 0;
00531
00532 public boolean hasNext() {
00533 return next < step.getResults();
00534 }
00535
00536 public MeasurementResult next() {
00537 return step.getResult(next++);
00538 }
00539
00540 public void remove() {
00541 throw new UnsupportedOperationException();
00542 }
00543 };
00544 }
00545
00549 public enum State {
00550 READY(false), MEASURING(false), DONE_RECENTLY(true), DONE(true);
00551
00552 private boolean done;
00553
00554 private State(boolean done) {
00555 this.done = done;
00556 }
00557
00561 public boolean isDone() {
00562 return done;
00563 }
00564 }
00565 }