InkSimplification.java

00001 package edu.stanford.hci.r3.pen.ink;
00002 
00003 import java.util.ArrayList;
00004 import java.util.LinkedList;
00005 import java.util.List;
00006 
00007 import edu.stanford.hci.r3.pen.PenSample;
00008 import edu.stanford.hci.r3.util.DebugUtils;
00009 import edu.stanford.hci.r3.util.MathUtils;
00010 
00032 public class InkSimplification {
00033 
00034         private int maxNumSamples = 3;
00035 
00036         private LinkedList<PenSample> recentSamples = new LinkedList<PenSample>();
00037 
00038         public InkSimplification() {
00039 
00040         }
00041 
00047         public boolean processNewSample(PenSample sample) {
00048                 recentSamples.add(sample);
00049                 if (recentSamples.size() <= maxNumSamples) {
00050                         // just return true, so we can collect more samples
00051                         return true;
00052                 } else {
00053                         // check the bounding box in r,theta space...
00054                         // if it's big enough, we return true
00055 
00056                         double maxDR = Double.MIN_VALUE;
00057                         double maxDT = Double.MIN_VALUE;
00058 
00059                         // this is the new "origin"
00060                         PenSample firstSample = recentSamples.getFirst();
00061                         double firstX = firstSample.x;
00062                         double firstY = firstSample.y;
00063 
00064                         double firstTS = firstSample.timestamp;
00065 
00066                         List<Double> dThetas = new ArrayList<Double>();
00067 
00068                         for (PenSample s : recentSamples) {
00069                                 // DebugUtils.println(s);
00070                                 if (s.equals(firstSample)) {
00071                                         continue;
00072                                 }
00073 
00074                                 double dX = s.getX() - firstX;
00075                                 double dY = s.getY() - firstY;
00076                                 double dT = s.getTimestamp() - firstTS;
00077 
00078                                 double dR = Math.sqrt(dX * dX + dY * dY);
00079                                 double dTheta = Math.atan2(dY, dX);
00080                                 dThetas.add(dTheta);
00081                                 // System.out.println(theta + " ");
00082                                 maxDR = Math.max(dR, maxDR); // min should be 0
00083                                 maxDT = Math.max(dT, maxDT);
00084                         }
00085 
00086                         // by default, keep the sample
00087                         boolean shouldKeepNewSample = true;
00088 
00089                         // if the samples are too close to each other, then throw them out...
00090                         // DebugUtils.println("maxR: " + maxR);
00091                         if (maxDR < 30) {
00092                                 shouldKeepNewSample = false;
00093                         }
00094 
00095                         // however, if we've turned enough, we should keep the new sample
00096                         double stdevTheta = MathUtils.standardDeviation(dThetas.toArray(new Double[0]));
00097                         // DebugUtils.println("stdevTheta: " + stdevTheta);
00098                         if (stdevTheta > 1) {
00099                                 shouldKeepNewSample = true;
00100                         }
00101 
00102                         // however, if the person is writing really slowly, then keep the sample
00103                         // DebugUtils.println("maxDT: " + maxDT);
00104                         if (maxDT > 100) {
00105                                 shouldKeepNewSample = true;
00106                         }
00107 
00108                         // yet, we should still throw away the samples that are WAY too close to each other... :)
00109                         if (maxDR < 5) {
00110                                 shouldKeepNewSample = false;
00111                         }
00112 
00113                         if (shouldKeepNewSample) {
00114                                 // remove the oldest sample
00115                                 recentSamples.removeFirst();
00116                         } else {
00117                                 // remove the newest sample
00118                                 recentSamples.removeLast();
00119                         }
00120 
00121                         return shouldKeepNewSample;
00122                 }
00123         }
00124 
00128         public void reset() {
00129                 recentSamples.clear();
00130         }
00131 
00135         public void simplifyStroke(InkStroke currentStroke) {
00136                 reset();
00137 
00138                 List<PenSample> samples = currentStroke.getSamples();
00139                 List<PenSample> newSamples = new ArrayList<PenSample>();
00140 
00141                 for (PenSample s : samples) {
00142                         boolean shouldKeep = processNewSample(s);
00143                         if (shouldKeep) {
00144                                 newSamples.add(s);
00145                         }
00146                 }
00147 
00148                 // we should ALWAYS keep the last sample
00149                 PenSample lastSample = samples.get(samples.size() - 1);
00150                 if (!newSamples.contains(lastSample)) {
00151                         newSamples.add(lastSample);
00152                 }
00153 
00154                 currentStroke.setSamples(newSamples);
00155         }
00156 }

Generated on Sat Apr 14 18:21:36 2007 for R3 Paper Toolkit by  doxygen 1.4.7