00001 package edu.stanford.hci.r3.components;
00002
00003 import java.awt.BasicStroke;
00004 import java.awt.Color;
00005 import java.awt.Dimension;
00006 import java.awt.geom.AffineTransform;
00007 import java.util.LinkedList;
00008 import java.util.List;
00009
00010 import edu.stanford.hci.r3.pen.ink.Ink;
00011 import edu.stanford.hci.r3.pen.ink.InkStroke;
00012 import edu.stanford.hci.r3.util.geometry.CatmullRomSpline;
00013 import edu.umd.cs.piccolo.PCanvas;
00014 import edu.umd.cs.piccolo.PNode;
00015 import edu.umd.cs.piccolo.nodes.PPath;
00016
00028 public class InkPCanvas extends PCanvas {
00029
00030 public static final Color DARK_THEMED_INK_COLOR = new Color(0.85f, 0.85f, .95f, 0.8f);
00031
00032 public static final Color DEFAULT_INK_COLOR = new Color(0.1f, 0.1f, .1f, 0.9f);
00033
00037 private static final BasicStroke DEFAULT_STROKE = new BasicStroke(2.0f, BasicStroke.CAP_ROUND,
00038 BasicStroke.JOIN_ROUND);
00039
00040 private Color defaultInkColor;
00041
00045 private LinkedList<Ink> inkWell = new LinkedList<Ink>();
00046
00047 private double pageOffsetX = 0;
00048
00049 private double pageOffsetY = 0;
00050
00051 private PNode strokesContainer;
00052
00056 public InkPCanvas() {
00057 setPreferredSize(new Dimension(320, 240));
00058 setMinimumSize(new Dimension(320, 240));
00059 strokesContainer = new PNode();
00060 getLayer().addChild(strokesContainer);
00061 useDefaultTheme();
00062 }
00063
00069 public void addInk(Ink ink) {
00070 inkWell.add(ink);
00071 addInkPaths(ink.getStrokes(), ink.getColor());
00072 getLayer().repaint();
00073 }
00074
00080 @SuppressWarnings("unused")
00081 private void addInkBezierPaths(List<InkStroke> strokes, Color inkColor) {
00082
00083
00084 for (final InkStroke s : strokes) {
00085
00086 final double[] xArr = s.getXSamples();
00087 final double[] yArr = s.getYSamples();
00088
00089 final PPath strokePath = new PPath();
00090
00091 strokePath.setStroke(DEFAULT_STROKE);
00092
00093 strokePath.setStrokePaint(inkColor);
00094 strokePath.addAttribute("timestamp", new Long(s.getFirstTimestamp()));
00095 strokesContainer.addChild(strokePath);
00096
00097 final int len = xArr.length;
00098 if (len > 0) {
00099 strokePath.moveTo((float) (xArr[0] + pageOffsetX), (float) (yArr[0] + pageOffsetY));
00100 }
00101
00102
00103 double lastGoodX = xArr[0];
00104 double lastGoodY = yArr[0];
00105
00106
00107 int numPointsCollected = 0;
00108 for (int i = 0; i < len; i++) {
00109 final double currX = xArr[i];
00110 final double currY = yArr[i];
00111
00112 numPointsCollected++;
00113
00114 final double diffFromLastX = currX - lastGoodX;
00115 final double diffFromLastY = currY - lastGoodY;
00116
00117 if (Math.abs(diffFromLastX) > 500 || Math.abs(diffFromLastY) > 500) {
00118
00119 strokePath.lineTo((float) (lastGoodX + pageOffsetX), (float) (lastGoodY + pageOffsetY));
00120 } else {
00121
00122 if (numPointsCollected == 2) {
00123 numPointsCollected = 0;
00124
00125
00126 strokePath.quadTo((float) (lastGoodX + pageOffsetX),
00127 (float) (lastGoodY + pageOffsetY), (float) (currX + pageOffsetX),
00128 (float) (currY + pageOffsetY));
00129 }
00130
00131
00132 lastGoodX = currX;
00133 lastGoodY = currY;
00134 }
00135 }
00136
00137
00138 if (numPointsCollected == 1) {
00139 strokePath.lineTo((float) (lastGoodX + pageOffsetX), (float) (lastGoodY + pageOffsetY));
00140 }
00141
00142 }
00143
00144 strokesContainer.repaint();
00145 }
00146
00152 private void addInkPaths(List<InkStroke> strokes, Color inkColor) {
00153
00154 for (final InkStroke s : strokes) {
00155 final CatmullRomSpline crspline = new CatmullRomSpline();
00156 final double[] x = s.getXSamples();
00157 final double[] y = s.getYSamples();
00158 crspline.setPoints(x, y);
00159
00160 final PPath strokePath = new PPath(crspline.getShape());
00161
00162
00163 strokePath.setStroke(DEFAULT_STROKE);
00164
00165
00166 strokePath.setStrokePaint(inkColor);
00167 strokePath.addAttribute("timestamp", new Long(s.getFirstTimestamp()));
00168 strokesContainer.addChild(strokePath);
00169 }
00170 strokesContainer.repaint();
00171 }
00172
00178 public void addInkWithDefaultColor(Ink ink) {
00179 inkWell.add(ink);
00180 addInkPaths(ink.getStrokes(), defaultInkColor);
00181 getLayer().repaint();
00182 }
00183
00187 public void resetViewOffsetAndScale() {
00188 getCamera().setViewTransform(new AffineTransform());
00189 }
00190
00194 public void setInk(Ink ink) {
00195 inkWell.clear();
00196 inkWell.add(ink);
00197 strokesContainer.removeAllChildren();
00198 addInkPaths(ink.getStrokes(), ink.getColor());
00199 getLayer().repaint();
00200 }
00201
00205 public void setStrokesScale(double scaleFactor) {
00206 strokesContainer.setScale(scaleFactor);
00207 }
00208
00212 public void useDarkTheme() {
00213 setBackground(new Color(40, 40, 40));
00214 defaultInkColor = DARK_THEMED_INK_COLOR;
00215 }
00216
00217 public void useDefaultTheme() {
00218 setBackground(new Color(240, 240, 240));
00219 defaultInkColor = DEFAULT_INK_COLOR;
00220 }
00221 }