Java Source Code: org.opensourcephysics.displayejs.InteractiveTrace


   1: /*
   2:  * The display package contains drawing classes and drawables
   3:  * Copyright (c) June 2002 F. Esquembre
   4:  * @author F. Esquembre (http://fem.um.es).
   5:  */
   6: 
   7: package org.opensourcephysics.displayejs;
   8: 
   9: 
  10: import java.awt.*;
  11: import java.util.*;
  12: import org.opensourcephysics.display.*;
  13: import java.awt.geom.*;
  14: 
  15:	  public class InteractiveTrace extends AbstractInteractiveElement {
  16:  // Configuration variables
  17:  protected boolean connected=true, ignore=false, active=true;
  18:  protected int maxPoints=0, skip=0, shapeSize;
  19:  private int shapeType = -1;  // Make sure an shape is created (if requested to)
  20:
  21:  // Implementation variables
  22:  private int counter=0;
  23://  private double xlast=Double.NaN, ylast=Double.NaN, zlast=Double.NaN;
  24:  private double point[] = new double[3];
  25:  protected ArrayList list, displayList;
  26:  private OnePoint lastPoint=new OnePoint(this,Double.NaN,Double.NaN,Double.NaN,false);
  27:  private Object3D[] minimalObjects = new Object3D[1];
  28:  DrawingPanel panelWithValidProjection = null;
  29:  private AffineTransform transform = new AffineTransform();
  30:
  31:  /**
  32:   * Default constructor
  33:   */
  34:	    public InteractiveTrace () {
  35:    list = new ArrayList();
  36:    setXYZ(0,0,0);
  37:    setSizeXYZ(1,1,1);
  38://    style.displayObject = new Ellipse2D.Float();
  39:  }
  40:
  41:	    public void copyFrom (InteractiveElement _element) {
  42:    super.copyFrom(_element);
  43:	      if (_element instanceof InteractiveTrace) {
  44:      setMaximumPoints(((InteractiveTrace)_element).getMaximumPoints());
  45:      setConnected(((InteractiveTrace)_element).isConnected());
  46:      setIgnoreEqualPoints(((InteractiveTrace)_element).isIgnoreEqualPoints());
  47:      setActive(((InteractiveTrace)_element).isActive());
  48:      setSkip(((InteractiveTrace)_element).getSkip());
  49:    }
  50:  }
  51:
  52:// -------------------------------------
  53:// New configuration methods
  54:// -------------------------------------
  55:
  56:	    public void setMaximumPoints (int _n) {
  57:    if (_n<0 || _n==maxPoints) return;
  58:    maxPoints = _n;
  59:    counter   = 0;
  60:    synchronized(list) { list.clear(); }
  61:    hasChanged = true;
  62:  }
  63:  public int getMaximumPoints () {  return maxPoints; }
  64:
  65:  public void setConnected (boolean connect) { this.connected = connect; }
  66:  public boolean isConnected () { return this.connected; }
  67:
  68:  public void setIgnoreEqualPoints (boolean ignoreEqual) { this.ignore = ignoreEqual; }
  69:  public boolean isIgnoreEqualPoints () { return this.ignore; }
  70:
  71:  public void setActive (boolean acceptInput) {  this.active = acceptInput; }
  72:  public boolean isActive () {  return this.active; }
  73:
  74:  public void setSkip (int howMany) { this.skip = howMany; counter = 0; }
  75:  public int  getSkip () { return this.skip; }
  76:
  77:  // Methods for operation
  78:
  79:  public void clear () { synchronized(list) { list.clear(); } }
  80:
  81:  public void addPoint (double xInput, double yInput) { addPoint (xInput,yInput,0.0); }
  82:
  83:	    public void addPoint (double xInput, double yInput, double zInput) {
  84:    if (!active) return;
  85://    System.out.println ("Adding "+xInput+","+yInput+" connected = "+connected);
  86:	      if (skip>0) {
  87:	        if (counter>0) {
  88:        counter++;
  89:        if (counter>=skip) counter = 0;
  90:        return;
  91:      }
  92:      counter++;
  93:    }
  94:    if (ignore && xInput==lastPoint.coordinates[0] && yInput==lastPoint.coordinates[1] && zInput==lastPoint.coordinates[2]) return;
  95:	      synchronized(list) {
  96:      if (maxPoints>0 && (list.size()>=maxPoints) ) list.remove(0);
  97:      list.add (lastPoint = new OnePoint (this,xInput,yInput,zInput,connected));
  98:    }
  99:    hasChanged = true;
 100:  }
 101:
 102:  /**
 103:   * Set the type of the marker
 104:   */
 105:	    public void setShapeType (int _type) {
 106:    if (shapeType==_type) return;
 107:    shapeType = _type;
 108:	      switch (shapeType) {
 109:      default :
 110:      case InteractiveParticle.NONE            : style.displayObject = null; break;
 111:      case InteractiveParticle.ELLIPSE         : style.displayObject = new Ellipse2D.Float(); break;
 112:      case InteractiveParticle.RECTANGLE       : style.displayObject = new Rectangle2D.Float(); break;
 113:      case InteractiveParticle.ROUND_RECTANGLE : style.displayObject = new RoundRectangle2D.Float(); break;
 114:    }
 115:  }
 116:
 117:  /**
 118:   * Set the size of the marker
 119:   */
 120:  public void setShapeSize (int _size) { shapeSize = _size; }
 121:
 122:// -------------------------------------
 123:// Implementation of Drawable3D
 124:// -------------------------------------
 125:
 126:	    public org.opensourcephysics.display.Interactive findInteractive (DrawingPanel _panel, int _xpix, int _ypix) {
 127:    if (!visible) return null;
 128:    if (hasChanged || _panel!=panelWithValidProjection) projectPoints (_panel);
 129://    if (sizeEnabled      && Math.abs(a2-_xpix)<SENSIBILITY               && Math.abs(b2-_ypix)<SENSIBILITY)               return sizeTarget;
 130:	      if (positionEnabled  && Math.abs(lastPoint.pixel[0]-_xpix)<SENSIBILITY && Math.abs(lastPoint.pixel[1]-_ypix)<SENSIBILITY) {
 131:      return new InteractionTargetTracePoint(this, new Point3D (lastPoint.coordinates[0],lastPoint.coordinates[1],lastPoint.coordinates[2]));
 132:    }
 133:    return null;
 134:  }
 135:
 136:	    public Object3D[] getObjects3D (DrawingPanel3D _panel) {
 137:    if (list.size()<=0 || !visible) return null;
 138:    if (hasChanged || _panel!=panelWithValidProjection) projectPoints(_panel);
 139:    return (Object3D[]) displayList.toArray(minimalObjects);
 140:  }
 141:
 142:	    public void draw (DrawingPanel3D _panel, Graphics2D _g, int _index) {
 143:	      try {
 144:      Graphics2D g2 = (Graphics2D) _g;
 145:      OnePoint point = (OnePoint) displayList.get(_index);
 146:      Color theColor = ( (DrawingPanel3D) _panel).projectColor(style.edgeColor, point.distance);
 147:	        if (_index>0 && point.connected) {
 148:        g2.setColor(theColor);
 149:        g2.setStroke(style.edgeStroke);
 150:        OnePoint pointPrev = (OnePoint) displayList.get(_index-1);
 151:        g2.drawLine((int)point.pixel[0],(int)point.pixel[1],(int)pointPrev.pixel[0],(int)pointPrev.pixel[1]);
 152:      }
 153:	        if (style.displayObject!=null) {
 154:        Paint theFillPattern = style.fillPattern;
 155:        if (theFillPattern instanceof Color) theFillPattern = ( (DrawingPanel3D) _panel).projectColor( (Color) theFillPattern, point.distance);
 156:        drawMarker (g2,point,theColor,theFillPattern);
 157:      }
 158:    } catch (Exception _e) { } //System.out.println ("Aha at drawing number "+_index +" / "+list.size()); } // Ignore it
 159:  }
 160:
 161:	    public void draw (DrawingPanel _panel, Graphics _g) {
 162:    if (list.size()<=0 || !visible) return;
 163://    if (hasChanged || _panel!=panelWithValidProjection)
 164:    projectPoints(_panel);
 165:    boolean notFirstTime=false;
 166:    int aprev=0, bprev=0;
 167:    Graphics2D g2 = (Graphics2D) _g;
 168:	      for (Iterator it=displayList.iterator(); it.hasNext(); ) { // Draw everything
 169:      OnePoint point = (OnePoint) it.next();
 170:      if (style.edgeColor==null) continue;
 171:      g2.setColor (style.edgeColor);
 172:      g2.setStroke(style.edgeStroke);
 173:      if (notFirstTime && point.connected) g2.drawLine ((int)point.pixel[0],(int)point.pixel[1],aprev,bprev);
 174:      if (style.displayObject!=null) drawMarker (g2,point,style.edgeColor,style.fillPattern);
 175:      aprev = (int)point.pixel[0];
 176:      bprev = (int)point.pixel[1];
 177:      notFirstTime = true;
 178:    }
 179:  }
 180:
 181:// -------------------------------------
 182:// Implementation of Measured3D
 183:// -------------------------------------
 184:
 185:  public boolean isMeasured () { return canBeMeasured && list.size()>0;  }
 186:
 187:	    public double getXMin () {
 188:    double min = Double.MAX_VALUE;
 189:	      synchronized(list) {
 190:      for (Iterator it = list.iterator(); it.hasNext(); ) min = Math.min(min,((OnePoint) it.next()).coordinates[0]);
 191:    }
 192:    if (group==null) return x + min*sizex;
 193:    else return group.x + (x + min*sizex)*group.sizex;
 194:  }
 195:	    public double getXMax () {
 196:    double max = -Double.MAX_VALUE;
 197:	      synchronized(list) {
 198:      for (Iterator it = list.iterator(); it.hasNext(); ) max = Math.max(max,((OnePoint) it.next()).coordinates[0]);
 199:    }
 200:    if (group==null) return x + max*sizex;
 201:    else return group.x + (x + max*sizex)*group.sizex;
 202:  }
 203:	    public double getYMin () {
 204:    double min = Double.MAX_VALUE;
 205:	      synchronized(list) {
 206:      for (Iterator it = list.iterator(); it.hasNext(); ) min = Math.min(min,((OnePoint) it.next()).coordinates[1]);
 207:    }
 208:    if (group==null) return y + min*sizey;
 209:    else return group.y + (y + min*sizey)*group.sizey;
 210:  }
 211:	    public double getYMax () {
 212:    double max = -Double.MAX_VALUE;
 213:	      synchronized(list) {
 214:      for (Iterator it = list.iterator(); it.hasNext(); ) max = Math.max(max,((OnePoint) it.next()).coordinates[1]);
 215:    }
 216:    if (group==null) return y + max*sizey;
 217:    else return group.y + (y + max*sizey)*group.sizey;
 218:  }
 219:	    public double getZMin () {
 220:    double min = Double.MAX_VALUE;
 221:	      synchronized(list) {
 222:      for (Iterator it = list.iterator(); it.hasNext(); ) min = Math.min(min,((OnePoint) it.next()).coordinates[2]);
 223:    }
 224:    if (group==null) return z + min*sizez;
 225:    else return group.z + (z + min*sizez)*group.sizez;
 226:  }
 227:	    public double getZMax () {
 228:    double max = -Double.MAX_VALUE;
 229:	      synchronized(list) {
 230:      for (Iterator it = list.iterator(); it.hasNext(); ) max = Math.max(max,((OnePoint) it.next()).coordinates[2]);
 231:    }
 232:    if (group==null) return z + max*sizez;
 233:    else return group.z + (z + max*sizez)*group.sizez;
 234:  }
 235:
 236:// -------------------------------------
 237://  Private methods and classes
 238:// -------------------------------------
 239:
 240:	    private void projectPoints (DrawingPanel _panel) {
 241:    synchronized(list)
 242:	      {
 243:      displayList = (ArrayList) list.clone(); // Or face synchronization problems!
 244:    }
 245:    for (int i=0, n=displayList.size(); i<n; i++) ((OnePoint) displayList.get(i)).project(_panel,i);
 246:    panelWithValidProjection = _panel;
 247:  }
 248:
 249:	    private void drawMarker (Graphics2D _g2, OnePoint _point, Color _color, Paint _fill) {
 250:	      if (! (style.displayObject instanceof RectangularShape) ) {
 251:      _g2.setColor (_color);
 252:      _g2.drawOval ((int) _point.pixel[0], (int) _point.pixel[1],1,1);  // draw a point
 253:      return;
 254:    }
 255:    RectangularShape shape = (RectangularShape) style.displayObject;
 256:    AffineTransform originalTransform = _g2.getTransform();
 257:    transform.setTransform(originalTransform);
 258:    transform.rotate(-style.angle,_point.pixel[0],_point.pixel[1]);
 259:    _g2.setTransform(transform);
 260:    shape.setFrame(_point.a1,_point.b1,shapeSize, shapeSize); // shape.getWidth(),shape.getHeight());
 261:	      if (_fill!=null) { // First fill the inside
 262:      _g2.setPaint(_fill);
 263:      _g2.fill(shape);
 264:    }
 265:    _g2.setColor (_color);
 266:    _g2.setStroke(style.edgeStroke);
 267:    _g2.draw(shape); // Second, draw the edge
 268:    _g2.setTransform(originalTransform);
 269:  }
 270:
 271:
 272:	  private class OnePoint extends Object3D {
 273:  boolean connected;
 274:  double[] coordinates = new double[3];
 275:  double[] pixel = new double[3];
 276:  int a1,b1;
 277:
 278:	    OnePoint (Drawable3D _drawable, double _x,double _y,double _z, boolean _c) {
 279:    super (_drawable,-1);
 280:    coordinates[0] = _x; coordinates[1] = _y;  coordinates[2] = _z;
 281:    connected = _c;
 282:    }
 283:
 284:	    protected void project (DrawingPanel _panel, int _index) {
 285:	      if (group==null) {
 286:      point[0] = x + coordinates[0]*sizex;
 287:      point[1] = y + coordinates[1]*sizey;
 288:      point[2] = z + coordinates[2]*sizez;
 289:    }
 290:	      else {
 291:      point[0] = group.x + (x + coordinates[0]*sizex)*group.sizex;
 292:      point[1] = group.y + (y + coordinates[1]*sizey)*group.sizey;
 293:      point[2] = group.z + (z + coordinates[2]*sizez)*group.sizez;
 294:    }
 295:    _panel.project(point,pixel);
 296:    distance = pixel[2];
 297:    index = _index;
 298:	      if (style.displayObject instanceof RectangularShape) {
 299:      RectangularShape shape = (RectangularShape) style.displayObject;
 300:      double dx, dy;
 301:	        switch (style.position) {
 302:        default :
 303:        case Style.CENTERED:   dx = shape.getWidth()/2.0; dy = shape.getHeight()/2.0; break;
 304:        case Style.NORTH:      dx = shape.getWidth()/2.0; dy = 0.0;                   break;
 305:        case Style.SOUTH:      dx = shape.getWidth()/2.0; dy = shape.getHeight();     break;
 306:        case Style.EAST:       dx = shape.getWidth();     dy = shape.getHeight()/2.0; break;
 307:        case Style.SOUTH_EAST: dx = shape.getWidth();     dy = shape.getHeight();     break;
 308:        case Style.NORTH_EAST: dx = shape.getWidth();     dy = 0.0;                   break;
 309:        case Style.WEST:       dx = 0.0;                  dy = shape.getHeight()/2.0; break;
 310:        case Style.SOUTH_WEST: dx = 0.0;                  dy = shape.getHeight();     break;
 311:        case Style.NORTH_WEST: dx = 0.0;                  dy = 0.0;                   break;
 312:      }
 313:      a1 = (int) (pixel[0] - dx);
 314:      b1 = (int) (pixel[1] - dy);
 315:    }
 316:  }
 317:
 318:}  // End of class OnePoint
 319:
 320:}  // End of main class