Newer
Older
PureATN_M / src / main / java / cit / PureATN / ShortStroke.java
package cit.PureATN;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;

import org.piccolo2d.PNode;
import org.piccolo2d.activities.PActivity;
import org.piccolo2d.nodes.PPath;
import org.piccolo2d.util.PBounds;

import cit.PureATN.MultiNote.MultiNote;

/**
 * 生徒の筆記(1ストローク)モデル Zoom可能な画面に表示するためのクラス
 * @author miuramo
 *
 */
public class ShortStroke extends PPPath implements Serializable, Runnable {
	private static final long serialVersionUID = 5928762332664417016L;

	//TODO: 筆記解析をするならtrue
	// public transient static boolean doAssess = false;

	public float[] sx;
	public float[] sy;
	// public short[] penpress;
	public float width;
	public int color;
	public int penid;//ペンのID
	// public int paperid;//シートのID
	public long time;
	public boolean isRealPen = false; //マウス描画ならfalse
	// public int sbackid;

	public transient long id;
	public transient ArrayList<Point2D> tempPts;

	// public transient PNode ink;
	// public transient Point2D startp;
	public transient Shape full;

	// transient Event_onSS event_onss = null;
	
	public String toCsv(){
		SimpleDateFormat sdf = new SimpleDateFormat("\"yyyy/MM/dd HH:mm:ss\"");
		StringBuffer sb = new StringBuffer();
		sb.append(penid);
		sb.append(",");
		// sb.append(paperid);
		// sb.append(",");
		sb.append(String.valueOf(time));
		sb.append(",");
		sb.append(sdf.format(time));
		sb.append(",");
		sb.append(sx.length);
		sb.append(",");
		for(int i=0;i<sx.length;i++){
			sb.append(sx[i]);
			sb.append(",");
			sb.append(sy[i]);
			sb.append(",");
		}
		String s = sb.toString();
		return s.substring(0,s.length()-1);
	}

	// public transient int interval;
	// public transient Thread playthread;
	// public transient boolean playing;

	//for playing
	public transient ArrayList<Shape> shapel;
	public transient PBounds bounds;

	static Hashtable<String, BasicStroke> penStrokeHash;
	static Hashtable<Integer, Color> colorHash;

	static {
		penStrokeHash = new Hashtable<String, BasicStroke>();
		colorHash = new Hashtable<Integer, Color>();
	}

	public static BasicStroke getCachedBasicStroke(float f){ //f=太さ
		if (penStrokeHash.containsKey(java.lang.Float.valueOf(f).toString())){
			return penStrokeHash.get(java.lang.Float.valueOf(f).toString());
		} else {
			BasicStroke bs = new BasicStroke( f/2, BasicStroke.CAP_ROUND,
					BasicStroke.JOIN_ROUND, 90.0f);
			penStrokeHash.put( java.lang.Float.valueOf(f).toString(), bs);
			return bs;
		}
	}
	public static Color getColor(int f){
		if (colorHash.containsKey(f)){
			return colorHash.get(f);
		} else {
			Color opaqueC = new Color(f);
			Color cl = new Color(opaqueC.getRed(),
					opaqueC.getGreen(), opaqueC.getBlue(), 245); //TODO:ここで筆記の透明度を設定.以前は95
			colorHash.put(f, cl);
			return cl;
		}
	}

	// 新規作成
	public ShortStroke() {
		this(0, new Color(0,0,90), 3, new Date().getTime());
	}
	public ShortStroke(int _penid, Color _color, int _width, long _time){
		penid = _penid;
		color = _color.getRGB();
		this.setStrokePaint(_color);
		width = _width;
		setStroke(getCachedBasicStroke(width));
		time = _time;
		setTransparency(0.7f);
		// playing = false;
	}
	// startDragのまえに、layer.addChildしておく
	public void startDrag_on_draw(double px, double py){
		tempPts = new ArrayList<Point2D>();
		this.moveTo(px,py);
	}
	public void drag_on_draw(double px, double py){
		if (tempPts == null) return;
		tempPts.add(new Point2D.Double(px,py));
		this.lineTo(px,py);
	}
	public void endDrag_on_draw(){
		// 下敷きが用意されていれば、Layerから下敷きに移動する
		if (tempPts == null) return;
		applyTempPtsToAry();
		if (Note.theapp instanceof MultiNote){
			//下敷きを特定
			MultiNote mn = (MultiNote)Note.theapp;
			PPath theShitajiki = mn.shitajikiNodes[penid];
			if (theShitajiki != null){
				Point2D offset = theShitajiki.getOffset();
				if (!this.isRealPen) { //マウス描画のときは、下敷きのオフセットにあわせる
					move((float)-offset.getX(), (float)-offset.getY());
				}
				theShitajiki.addChild(this);
			}
		}
    }
	public void restore_on_load(){
		if (Note.theapp instanceof MultiNote){
			//下敷きを特定
			MultiNote mn = (MultiNote)Note.theapp;
			PPath theShitajiki = mn.shitajikiNodes[penid];
			if (theShitajiki != null){
				theShitajiki.addChild(this);
			}
		} else {
			PNode layer = Note.theapp.getCanvas().getLayer();
			layer.addChild(this);
		}
	}

	public void applyTempPtsToAry(){
		sx = new float[tempPts.size()];
		sy = new float[tempPts.size()];
		// penpress = new short[tempPts.size()]; 
		for(int i=0;i<tempPts.size();i++){
			sx[i] = (float)tempPts.get(i).getX();
			sy[i] = (float)tempPts.get(i).getY();
			// penpress[i] = 127;
		}
	}

	public Color getColor(){
		return ShortStroke.getColor(color);
	}
	public void setColor(Color c){
		setStrokePaint(c);
		//元のデータも書き換える
		color = c.getRGB();
	}
	public void animateToFlushColor(Color flushcolor, long duration, long startwait){
		PActivity a1 = this.animateToColor(flushcolor, duration);
		PActivity a2 = this.animateToColor(getColor(), duration);
		a1.setStartTime(System.currentTimeMillis()+startwait);
		a2.startAfter(a1);
	}

	public Point2D getPenPoint(int pos) {
		return new Point2D.Float(sx[pos], sy[pos]);
	}

	public Point2D getFirstPoint() {
		return new Point2D.Float(sx[0], sy[0]);
	}

	public Point2D getLastPoint() {
		return new Point2D.Float(sx[sx.length - 1], sy[sy.length - 1]);
	}

	public synchronized void run() {
		// playing = true;
		// reset();
		// ink.addChild(this);
		// moveTo(sx[0], sy[0]);
		// for (int i = 1; i < sx.length; i++) {
		// 	lineTo(sx[i], sy[i]);
		// 	ink.repaintFrom(getBoundsReference(), this);
		// 	try {
		// 		Thread.sleep(interval);
		// 	} catch (InterruptedException e) {
		// 		e.printStackTrace();
		// 	}
		// 	if (!playing)
		// 		return;
		// }

		// removeFromParent();
		// ink.addChild(this);
		// ink.repaintFrom(getBoundsReference(), this);

		// if (SnailServer.server.recognizeCB.isSelected())
		// note.recognize(this);
		// note.student.afterAddDBStroke(note, this);
		// stop();
	}


	// public void suspend() {
	// 	synchronized (playthread) {
	// 		try {
	// 			playthread.wait(); // プロセスを休止する
	// 		} catch (InterruptedException e) {
	// 		}
	// 	}
	// }

	// public synchronized void resume() {
	// 	playthread.notify();
	// }

	// public void stop() {
	// 	if (playing)
	// 		playing = false;
	// 	if (playthread != null)
	// 		playthread = null;
	// 	// ink.repaint();
	// }

	public synchronized PPath genStroke(String protocol, float inkscale) {
		return genStroke_old(protocol, inkscale);
		// return genStroke_besier(protocol);
	}

	// public PPath getStroke(){
	// if (stroke!=null) return stroke;
	// else return rebuildStroke();
	// }

	public synchronized PPath genStroke_besier(String protocol, float inkscale) {
		StringTokenizer st = new StringTokenizer(protocol);
		Vector<double[]> v = new Vector<double[]>();

		int c = st.countTokens();
		int p = 0;
		sx = new float[c / 2];
		sy = new float[c / 2];

		float tsx = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
		float tsy = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
		float ttx, tty; // previous values;
		sx[p] = tsx;
		sy[p] = tsy;
		// System.out.println("tsx: "+ tsx + " tsy: "+tsy);
		double[] t = new double[2];
		t[0] = tsx;
		t[1] = tsy;
		v.add(t);
		ttx = tsx;
		tty = tsy;
		while (st.hasMoreElements()) {
			p++;
			float x = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			float y = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			sx[p] = x;
			sy[p] = y;
			if (x != ttx && y != tty) {
				double[] tt = new double[2];
				tt[0] = x;
				tt[1] = y;
				v.add(tt);
			}
		}
		//		FitCurves fc = new FitCurves();
		//		try {
		//			fc.getBezier(v, 4.0);
		//		} catch (ArrayIndexOutOfBoundsException aioobe) {
		//			genStroke_old(protocol, inkscale);
		//		}
		return this;
	}

	public synchronized PPath genStroke_old(String protocol, float inkscale) {
		try {
			StringTokenizer st = new StringTokenizer(protocol);
			time = new Date().getTime();
			// System.out.println(time);

			int c = st.countTokens();
			int p = 0;
			sx = new float[c / 2];
			sy = new float[c / 2];
			// stroke = new MyPPath(this);
			reset();
			float tsx = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			float tsy = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			moveTo((float) tsx, (float) tsy);
			sx[p] = tsx;
			sy[p] = tsy;
			while (st.hasMoreElements()) {
				p++;
				float x = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
				float y = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
				lineTo((float) x, (float) y);
				sx[p] = x;
				sy[p] = y;
			}
			return this;
		} catch (NoSuchElementException ex) {
			System.out.println(ex.toString());
			return null;
		}
	}

	public synchronized PPath rebuildStroke_old() {
		// stroke = new MyPPath(this);

		reset();
		if (sx.length == 0 || sy.length == 0) {
			System.out.println("長さ0のストロークデータ " + time);
			return this;
		}
		moveTo((float) sx[0], (float) sy[0]);
		for (int i = 0; i < sx.length; i++) {
			lineTo((float) sx[i], (float) sy[i]);
		}
		full = new GeneralPath(this.getPathReference()); // 最後までの筆記を記録

//		removeAllChildren();
//		for(int i=0;i<sx.length;i++){
//			PPath a = PPath.createEllipse(sx[i]-0.3f, sy[i]-0.3f, 0.3f, 0.3f);
//			a.setPaint(getColor(3000000));
//			a.setStrokePaint(getColor(3000000));
//			addChild(a);
//		}
		return this;
		
//		return this;
	}
	// public void calcMetrics(){
	// 	// if (dist < 0){ //初期値は-1なので。はじめてかどうかのチェック
	// 	// 	// lengthInPixel();		
	// 	// 	// maxspeedInPixel();
	// 	// 	// varspeedInPixel();		
	// 	// 	// angle();		
	// 	// 	// ramer();
	// 	// 	// log();
	// 	// }
	// }
	// public void exportBySieve(){ //TODO:
	// 	calcMetrics();
	// 	FileReadWriter.buffer.add(var_ramer+","+num_choten+","+num_choten2+","+ramer+","+penid+","+time+","+ppd+","+pts+","+dist);
	// 	/*
	// 	 * FileReadWriter.buffer.add(id+","+time+","+sbackid+","+penid+","+paperid+","+
	// 			sx.length+","+length+","+avgspeed+","+varspeed+","+varspeed2+","+maxspeed+","+timediff+","+timed+","+
	// 		num_choten+","+num_choten2+","+numrammer);//研究用
	// 	 */		
	// 	//		FileReadWriter.buffer.add(timed+","+num_choten+","+num_choten2+","+numrammer+","+
	// 	//											varspeed+","+varspeed2+","+avgspeed+","+avgspeed2);//分析1用



	// 	//		FileReadWriter.buffer.add(num_choten+","+varspeed+","+avgspeed);//分析2-1用
	// 	//				FileReadWriter.buffer.add(num_choten2+","+varspeed2+","+avgspeed2);//分析2-2用
	// 	//						FileReadWriter.buffer.add(numrammer+","+varspeed+","+avgspeed);//分析2-3用
	// 	//							FileReadWriter.buffer.add(numrammer+","+varspeed2+","+avgspeed2);//分析2-4用
	// 	//
	// 	//System.out.println(penid+" "+paperid+" count "+sx.length+" len "+length+" avg "+avgspeed+" var "+varspeed+" max "+maxspeed+" td "+timediff);
	// 	//太さと色を設定
	// }
	// public void exportBySieveAverage(){ //TODO:
	// 	calcMetrics();
		/*
		 * FileReadWriter.buffer.add(id+","+time+","+sbackid+","+penid+","+paperid+","+
				sx.length+","+length+","+avgspeed+","+varspeed+","+varspeed2+","+maxspeed+","+timediff+","+timed+","+
			num_choten+","+num_choten2+","+numrammer);//研究用
		 */		
		//		FileReadWriter.buffer.add(timed+","+num_choten+","+num_choten2+","+numrammer+","+
		//											varspeed+","+varspeed2+","+avgspeed+","+avgspeed2);//分析1用



		//		FileReadWriter.buffer.add(num_choten+","+varspeed+","+avgspeed);//分析2-1用
		//				FileReadWriter.buffer.add(num_choten2+","+varspeed2+","+avgspeed2);//分析2-2用
		//						FileReadWriter.buffer.add(numrammer+","+varspeed+","+avgspeed);//分析2-3用
		//							FileReadWriter.buffer.add(numrammer+","+varspeed2+","+avgspeed2);//分析2-4用
		//
		//System.out.println(penid+" "+paperid+" count "+sx.length+" len "+length+" avg "+avgspeed+" var "+varspeed+" max "+maxspeed+" td "+timediff);
		//太さと色を設定
	// }

	public synchronized PPath rebuildStroke() {
		setStroke(getCachedBasicStroke(width));
		setStrokePaint(getColor(color));

//			float h = (float)(avgspeed/3);
//			if (h>1.0) h=1.0f;
//			float b = (float)(Math.log(varspeed+0.01)+0.2);
//			if (b>1.0) b=1.0f;
//			int hh = (int)(h*205)+50;
//			if (hh>255) hh=255;
			//		setStrokePaint(new Color(Color.HSBtoRGB(h, 0.7f, 0.7f)));
			//		if (hh>60) setStrokePaint(new Color(hh,hh,hh));
			//		else setStrokePaint(new Color(255-hh*2,0,0));
		return rebuildStroke_old();
		// return rebuildStroke_besier();
	}

	public synchronized PPath rebuildStroke_besier() { // bezier version
		// float ttx2 = -1, tty2 = 0;
		float ttx1 = 0, tty1 = 0;
		Vector<double[]> v = new Vector<double[]>();
		for (int i = 0; i < sx.length; i++) {
			float x = sx[i];
			float y = sy[i];
			if (x != ttx1 && y != tty1) {
				double[] tt = new double[2];
				double[] tmid = new double[2];
				if (ttx1 != 0 && tty1 != 0) {
					tmid[0] = (x + ttx1) / 2.0;
					tmid[1] = (y + tty1) / 2.0;
					v.add(tmid);
				}
				tt[0] = x;
				tt[1] = y;
				v.add(tt);
			}
			ttx1 = x;
			tty1 = y;
		}
		//		FitCurves fc = new FitCurves();
		//		fc.getBezier(v, 4.0);
		// ((MyPPath)stroke).setSS(this);
		return this;
	}

	//自分の最後と、otherの最初の距離をみる
	public float distance(ShortStroke other){
		if (sx.length==0) return 99999f;
		float tx = sx[sx.length-1];
		float ty = sy[sy.length-1];
		if (other.sx.length==0) return 99999f;
		float ox = other.sx[0];
		float oy = other.sy[0];
		return (float) Math.sqrt((ox-tx)*(ox-tx)+(oy-ty)*(oy-ty));

	}
	public void move(float dx, float dy){//移動
		for(int i=0;i<sx.length;i++){
			sx[i] = sx[i]+dx;
		}
		for(int i=0;i<sy.length;i++){
			sy[i] = sy[i]+dy;
		}

		rebuildStroke();
	}

	public void addPoint(Point2D p) {
		tempPts.add(p);
	}
	/**
	 * 生徒PDAからの生筆記データからDB用データを生成
	 *
	 * @param sx X座標配列
	 * @param sy Y座標配列
	 * @return DB格納用バイトデータ
	 */
// 	public byte[] getXYBytes() {
// 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 		BufferedOutputStream bos;
// 		DataOutputStream dos;
// 		try {
// 			bos = new BufferedOutputStream(baos);
// 			dos = new DataOutputStream(bos);

// 			dos.writeInt(sx.length);
// 			for (int i = 0; i < sx.length; i++) {
// 				dos.writeFloat(sx[i]);
// 			}
// 			for (int i = 0; i < sy.length; i++) {
// 				dos.writeFloat(sy[i]);
// 			}
// 			dos.close();
// 			bos.close();
// 			baos.close();
// 		} catch (FileNotFoundException e) {
// 			e.printStackTrace();
// 		} catch (IOException e) {
// 			e.printStackTrace();
// 		}
// 		return baos.toByteArray();
// 	}
// 	public byte[] getPseudoPPBytes() {
// 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 		BufferedOutputStream bos;
// 		DataOutputStream dos;
// 		try {
// 			bos = new BufferedOutputStream(baos);
// 			dos = new DataOutputStream(bos);

// 			dos.writeInt(sx.length);
// 			for (int i = 0; i < sx.length; i++) {
// 				dos.writeShort(128);
// 			}
// 			dos.close();
// 			bos.close();
// 			baos.close();
// 		} catch (FileNotFoundException e) {
// 			e.printStackTrace();
// 		} catch (IOException e) {
// 			e.printStackTrace();
// 		}
// 		return baos.toByteArray();
// 	}
// 	public void debugPrint() {
// //		System.out.println("SSDebug "+penid+" "+paperid+" "+new Date(time));
// 	}

	public ShortStroke clone(){
		ShortStroke newss = new ShortStroke();
		newss.sx = new float[this.sx.length];
		newss.sy = new float[this.sy.length];
		for(int i=0;i<this.sx.length;i++){
			newss.sx[i] = this.sx[i];
		}
		for(int i=0;i<this.sy.length;i++){
			newss.sy[i] = this.sy[i];
		}
		// if (this.penpress != null){
		// 	newss.penpress = new short[this.penpress.length];
		// 	for(int i=0;i<this.penpress.length;i++){
		// 		newss.penpress[i] = this.penpress[i];
		// 	}
		// }
		newss.time = this.time;
		newss.penid = this.penid;
		newss.color = this.color;
		newss.width = this.width;
		// newss.paperid = this.paperid;
		newss.id = this.id;
		return newss;

	}

	public void play(int _interval /* PNode _ink, PNode _redink, Note n*/) {
		// if (playing) return;
		// this.prepareStrokeList(_ink);
		// for(TimePlayPath tpp: strokelist){
		// // tpp.snip.setTransparency(0.0f);
		// tpp.snip.setVisible(false);
		// }
		// ink = _ink;
		// redink = _redink;
		// note = n;
		// interval = _interval;
		// playthread = new Thread(this);

		// playthread.start();
		// try {
		// 	playthread.join();
		// } catch (InterruptedException e) {
		// 	e.printStackTrace();
		// }
	}

	// 現在の形状をリストに追加
	public void restoreShape() {
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		Shape shape = this.getPathReference();
		shapel.add(new GeneralPath(shape));
	}

	// リセット
	public void resetShapes() {
		if (full == null) {
			rebuildStroke();
		}
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		setPathTo(full);
		shapel.clear();
	}

	// 形状を保存
	public void prepareShapes() {
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		shapel.clear();
		GeneralPath gp = new GeneralPath();
		gp.moveTo(sx[0], sy[0]);
		shapel.add(new GeneralPath(gp));
		for (int i = 1; i < sx.length; i++) {
			gp.lineTo(sx[i], sy[i]);
			shapel.add(new GeneralPath(gp));
		}
	}

	public int getSteps() {
		return sx.length;
	}
	//TODO:
	// public transient double[] speedary;
	// public transient double[] speedary2;
	// public transient double dist = -1;
	// public transient double length2;
	// public transient double avgspeed;
	// public transient double avgspeed2;
	// public transient double varspeed;
	// public transient double varspeed2;
	// public transient double maxspeed;
	// public transient ShortStroke previous;
	// public transient long timediff;
	// public transient long timed;
	// public transient double[] angleary ;
	// public transient double[] angleary2 ;
	// public transient double[] angleary3 ;
	// public transient int num_choten = 0;//90度以上の点の数
	// public transient int num_choten2 = 0;//90度以上の点の数 ノイズ除去ver
	// public transient double sumangle, avgangle;
	// public transient double varangle;
	// public transient int ramer;
	// public transient double choten1_var;
	// public transient double choten1_avg;
	// public transient double choten2_var;	
	// public transient double choten2_avg;
	// public transient int kukan2;
	// public transient double var_oreten;
	// public transient double var_ramer;
	// public transient double ramerthre;
	// public transient double ppd, pps,ppr;
	// public transient double pts, dbltime;
	
	// public int pos; //水井筆記のpos
	// public String tag;

// 	public void print_metrics2(){
// 		String a[] = new String[]{"var_ramer","ppd","pts","length", "current_begin"};
// 		for(String fn: a){
// 			Field f = null;
// 			try {
// 				f = ShortStroke.class.getField(fn);
// 			} catch (NoSuchFieldException e) {
// 				e.printStackTrace();
// 			} catch (SecurityException e) {
// 				e.printStackTrace();
// 			}
			
// 			try {
// 				System.out.println(fn+" : "+f.get(this));
// 			} catch (IllegalArgumentException e) {
// 				e.printStackTrace();
// 			} catch (IllegalAccessException e) {
// 				e.printStackTrace();
// 			}
// 		}
// 		System.out.println("");
// 	}
// 	public void print_metrics(){
// 		ShortStroke clone = this.clone();
// 		clone.calcMetrics();
// 		String a[] = new String[]{"ramerthre","varspeed2","numrammer","var_ramer", "length"};
// 		for(String fn: a){
// 			Field f = null;
// 			try {
// 				f = ShortStroke.class.getField(fn);
// 			} catch (NoSuchFieldException e) {
// 				e.printStackTrace();
// 			} catch (SecurityException e) {
// 				e.printStackTrace();
// 			}
			
// 			try {
// 				System.out.println(fn+" : "+f.get(clone));
// 			} catch (IllegalArgumentException e) {
// 				e.printStackTrace();
// 			} catch (IllegalAccessException e) {
// 				e.printStackTrace();
// 			}
// 		}
// 		System.out.println("size : "+clone.sx.length);
// 		for(double d: clone.speedary) System.out.print(d+" ");
// 		System.out.println("");
// 	}
// 	private void log() {
// 		var_oreten = varspeed /( Math.log10(num_choten2+2));
// 		var_ramer = varspeed / (Math.log10(ramer+2));
// 		ppd = sx.length/dist;
// 		pps = sx.length/(ramerthre*5);
// 		ppr = sx.length/(ramer+1);
// 		pts = sx.length;
// 		dbltime = (double)(time - 1360901083972L)/1000;
// //		System.out.println("Math.log10 = "+Math.log10(numrammer+2));
// 	}

// 	private void ramer() {
// 		float minx=java.lang.Float.MAX_VALUE,maxx=java.lang.Float.MIN_VALUE,miny=java.lang.Float.MAX_VALUE,maxy=java.lang.Float.MIN_VALUE;
// 		for(int i=0;i<sx.length;i++){
// 			if (sx[i] < minx) minx = sx[i];
// 			if (sx[i] > maxx) maxx = sx[i];
// 			if (sy[i] < miny) miny = sy[i];
// 			if (sy[i] > maxy) maxy = sy[i];
// 		}
// 		double w = maxx-minx;
// 		double h = maxy-miny;
// 		ramerthre = (w > h) ? w/5 : h/5; 
// 		//TODO: ramer = Rammer.getRammerPoints(sx, sy, (float)ramerthre).size()-2;
// 	}

// 	private void angle() {
// 		if (sx.length > 2) {
// 			angleary = new double[sx.length-2];
// 			num_choten = 0;
// 			//1または2か所の合計で80以上曲がっている折れ点の数を数える。
// 			double prev_angle = -1.0;
// 			boolean isprev_choten = false;
// 			for(int i=0;i<sx.length-2;i++){
// 				double cos = getAngle(new Point2D.Float(sx[i],sy[i]), new Point2D.Float(sx[i+1],sy[i+1]), new Point2D.Float(sx[i+2],sy[i+2]));
// 				angleary[i] = cos;
// 				if (cos > -0.17) {
// 					num_choten++;
// 					isprev_choten = true;
// 				}
// 				else if ((cos + prev_angle > -1.53) && isprev_choten==false) {//(cos > -0.8) && (prev_angle > -0.8)
// 					num_choten++;
// 					isprev_choten = true;
// 				} else {
// 					isprev_choten = false;
// 				}
// 				sumangle += cos;
// 				prev_angle = cos;
// 			}
// 		}	
// 		// 初めの二つの角度について除外
// 		if(sx.length > 4){
// 			angleary2 = new double[sx.length-4];
// 			double prev_angle2 = -1.0;
// 			boolean isprev_choten2 = false;
// 			num_choten2 = 0;
// 			for(int i=0;i<sx.length-4;i++){
// 				double cos2 = getAngle(new Point2D.Float(sx[i+2],sy[i+2]), new Point2D.Float(sx[i+3],sy[i+3]), new Point2D.Float(sx[i+4],sy[i+4]));
// 				angleary2[i] = cos2;
// 				if (cos2 > -0.17) {
// 					num_choten2++;
// 					isprev_choten2 = true;
// 				}
// 				else if ((cos2 + prev_angle2 > -1.53) && isprev_choten2==false) {//(cos > -0.8) && (prev_angle > -0.8)
// 					num_choten2++;
// 					isprev_choten2 = true;
// 				} else {
// 					isprev_choten2 = false;
// 				}
// 				prev_angle2 = cos2;
// 			}
// 			//折れ点の数をノイズ分ひく
// 			if(angleary2.length > 0){
// 				if(angleary2[angleary2.length-1] > -0.17  && speedary[speedary.length-1] < 1.0){
// 					num_choten2--;
// 				}
// 			}	
// 			if(angleary2.length > 1){
// 				if(angleary2[angleary2.length-2] > -0.17  && (speedary[speedary.length-1]+speedary[speedary.length-2]) < 2.0){
// 					num_choten2--;
// 				}
// 			}
// 		}	
// 	}

// 	public void setPreviousSS(ShortStroke pre){
// 		if (pre == null) return;
// 		if (pre.penid != this.penid) return;
// 		// if (pre.paperid != this.paperid) return; 
// 		if (pre.id == this.id-1) {
// 			previous = pre;
// 			timediff = this.time - previous.time;
// 			long pretime = ((previous.sx.length-1)*1000)/75;
// 			timed =  timediff - pretime;
// 		}
// 	}
// 	//筆記のパスの長さ(これをgetSteps()で割ったら平均速度になる)
// 	public double lengthInPixel(){
// 		double len = 0;
// 		double len2 = 0;
// 		if (sx.length>1){
// 			speedary = new double[sx.length-1];							
// 			for(int i=1;i<sx.length;i++){
// 				speedary[i-1] = Math.sqrt((sx[i]-sx[i-1])*(sx[i]-sx[i-1])+(sy[i]-sy[i-1])*(sy[i]-sy[i-1]));
// 				len = len + speedary[i-1];
// 				//	System.out.println(i+"len1 :"+speedary[i-1]);		
// 			}
// 		}
// //		System.out.println("");
// 		if (sx.length > 3) {
// 			speedary2 = new double[sx.length-3];
// 			for(int i=3;i<sx.length;i++){
// 				speedary2[i-3] = Math.sqrt((sx[i]-sx[i-1])*(sx[i]-sx[i-1])+(sy[i]-sy[i-1])*(sy[i]-sy[i-1]));
// 				//System.out.println("speedary : "+speedary[i-1]);			
// 				len2 = len2 + speedary2[i-3];
// 				//System.out.println(i+"len2 :"+speedary2[i-3]);
// 			}
// 			kukan2 = speedary2.length;
// 		}
// //		System.out.println("");
// 		if (sx.length > 4 ) {
// 			for(int i=0;i<sx.length;i++){
// 			}
// //			System.out.println("");
// 			angleary3 = new double[sx.length-4];
// 			//			num_choten = 0;
// 			//1または2か所の合計で90以上曲がっている折れ点の数を数える。 但し初めの二つの角度については除外
// 			for(int i=0;i<sx.length-4;i++){
// 				double cos = getAngle(new Point2D.Float(sx[i+2],sy[i+2]), new Point2D.Float(sx[i+3],sy[i+3]), new Point2D.Float(sx[i+4],sy[i+4]));
// 				angleary3[i] = cos;
// 			}	
// //			System.out.println("同じ"+angleary3.length+speedary.length+sx.length);
// 			if(angleary3.length > 1){

// 				if(angleary3[angleary3.length-1] > -0.17  && speedary[speedary.length-1] < 1.0){
// //					System.out.println("ts");
// 					len2 = len2 - speedary2[speedary2.length-1];
// 					kukan2 = kukan2 - 1;
// 				}
// 			}	
// 			if(angleary3.length > 2){
// 				if(angleary3[angleary3.length-2] > -0.17  && (speedary[speedary.length-1]+speedary[speedary.length-2]) < 2.0){			
// 					len2 = len2 - speedary2[speedary2.length-1] - speedary2[speedary2.length-2];
// 					kukan2 = kukan2 - 2;					
// 				}	
// 			}
// 		}	
// 		dist = len;
// 		length2 = len2;
// 		return len;
// 	}

// 	public double maxspeedInPixel(){ //最大瞬間速度
// 		double len = 0;
// 		double tmp = 0;
// 		if (sx.length >1){
// 			if (speedary == null) lengthInPixel();
// 			for(int i=0;i<speedary.length;i++){
// 				tmp = speedary[i];
// 				if (len < tmp) len = tmp;		
// 			}
// 		}
// 		maxspeed = len;
// 		return len;
// 	}

// 	public double varspeedInPixel(){//速度の分散
// 		double var = 0;
// 		double var2 = 0;

// 		if (sx.length >1){
// 			if (speedary == null) lengthInPixel();
// 			avgspeed = dist/speedary.length; //平均速度
// 			for(int i=0;i<speedary.length;i++){
// 				double tmp = speedary[i]-avgspeed;
// 				var = var + (tmp*tmp);
// 			}
// 			var = var / speedary.length;
// 			varspeed = var;
// 		}
// 		if (sx.length >3){

// 			if (speedary2 == null) lengthInPixel();
// 			avgspeed2 = length2/kukan2;//平均速度
// 			for(int i=0;i<speedary2.length;i++){
// 				double tmp2 = speedary2[i]-avgspeed2;
// 				var2 = var2 + (tmp2*tmp2);
// 			}
// 			var2 = var2 / kukan2;
// 			varspeed2 = var2;
// 		}
// 		return var;
// 	}

// 	//なす角のcosを求める.1なら反復,-1なら直進
// 	public static double getAngle(Point2D m1, Point2D m2, Point2D m3){
// 		double a = m1.distance(m2);
// 		double b = m2.distance(m3);
// 		double c = m3.distance(m1);
// 		double cosC = (a*a+b*b-c*c)/(2*a*b);
// 		//          System.out.println("a "+a+"  b "+b+"  c "+c+"  cosC "+cosC);
// 		return cosC;
// 	}

	/**
	 * 途中までの線を構築する
	 */
	public void showSubpath(int pos) {
		reset();
		setPathTo(shapel.get(pos));
	}

	public String getDateTime() {
		SimpleDateFormat sdf = new SimpleDateFormat("\"yyyy/MM/dd HH:mm:ss\"");
		return sdf.format(time);
	}
	//ストローク終了時刻とストローク開始時刻の差
	public String toCsvTeinei() {
		
		return null;
	}
	
	public long current_begin;
	public double current_begin_duration;
	public int sec10size;
	public int sec30size;
	public int sec60size;

	
}



/*
 * for(int i=0;i<sx.length;i++){ float x = sx[i]; float y = sy[i]; if (x !=
 * ttx1 && y != tty1){ if (((tty1-tty2)*(x-ttx1))!=((ttx1-ttx2)*(y-tty1))){
 * double[] tt = new double[2]; tt[0] = x; tt[1] = y; v.add(tt); } ttx2 = ttx1;
 * tty2 = tty1; } ttx1 = x; tty1 = y; }
 */