package jp.ac.kyutech.mns.ist; import java.awt.BasicStroke; import java.awt.Color; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; import jp.ac.kyutech.mns.ist.filter.AvgVarCalc2; import jp.ac.kyutech.mns.ist.util.FadeTimerForNotify; import jp.ac.kyutech.mns.ist.util.FileReadWriter; import org.josql.Query; import org.josql.QueryExecutionException; import org.josql.QueryParseException; import org.josql.QueryResults; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.nodes.PPath; import edu.umd.cs.piccolo.nodes.PText; import edu.umd.cs.piccolo.util.PBounds; /** * 1つのペンに対応するデータ=ノート * ノート内に,6つのシートを保有する */ public class Note extends PPath implements LayoutContent { private static final long serialVersionUID = 3941932778256401748L; public static int width = 700; public static int height = 990; SimpleATN satn; Hashtable<Integer,Sheet> sheets; MyRect numPT; // PText numPT; public int penid; private ArrayList<ShortStroke> all; //保存用,および,グルーピング用 ArrayList<SSGroup> group;//ノート(ペン1本、6シート)全体が含むSSGroupのリスト Hashtable<Sheet,ArrayList<SSGroup>> sheet2ssgrouplist; boolean isLandscapeMode = false; //横画面モード public ArrayList<ShortStroke> getAll(){ return all; } public int getNum(){ return penid; } public Rectangle2D mysize(){ return getFullBounds(); } public int drawingAmount(){ return all.size(); } @SuppressWarnings("unchecked") public void grouping(float r){ sheet2ssgrouplist = new Hashtable<Sheet, ArrayList<SSGroup>>(); group = new ArrayList<SSGroup>(); // for(ShortStroke ss : all){ // } SSGroup target = new SSGroup(); group.add(target); for(int i=0;i<all.size()-1; i++){ ShortStroke ss = all.get(i); ShortStroke ss2 = all.get(i+1); if (ss.distance(ss2) < r){ //距離を測って target.add(ss); } else { target.add(ss); target = new SSGroup(); group.add(target); } } for(SSGroup ssg: group){ ssg.rebuild(); ShortStroke temp = ssg.get(0);//グループに含まれる、最初の線をピックアップ if (temp == null) continue; Sheet sheet = getSheet(temp.paperid);//最初の線が含まれているシートに、 sheet.addChild(ssg);//SSGroupを追加=表示 ssg.setSheet(sheet); } for(Sheet sheet : sheets.values()){ Collection<PNode> c = sheet.getAllNodes(); for(PNode pn : c){ if (pn instanceof SSGroup){ SSGroup thessg = (SSGroup)pn; ArrayList<SSGroup> sheetgroups = sheet2ssgrouplist.get(sheet); if (sheetgroups == null) { sheetgroups = new ArrayList<SSGroup>(); sheet2ssgrouplist.put(sheet, sheetgroups); } sheetgroups.add(thessg); } } // if (sheet2ssgrouplist.get(sheet) != null) System.out.println("num of ssgroup "+ sheet2ssgrouplist.get(sheet).size()); } } public Note(int _penid, SimpleATN _satn) { this.penid = _penid; satn = _satn; // numPT = new PText(String.valueOf(penid)); // numPT.setTextPaint(Color.black); numPT = new MyRect(String.valueOf(penid), (int)(Note.height), Note.height); addChild(numPT); numPT.innerText.setTextPaint(Color.lightGray); numPT.addInputEventListener(new Event_onSheetNum(numPT, this)); // numPT.setScale(50); // numPT.setOffset(-numPT.getWidth()*numPT.getScale()-50, 50); // setBounds(0,0,width*6+numPT.getWidth(),height); setStrokePaint(Color.black); setPaint(null); all = new ArrayList<ShortStroke>(); sheets = new Hashtable<Integer, Sheet>(); // addSheet(1); // addSheet(2); // addSheet(3); // addSheet(4); // addSheet(5); // addSheet(6); } public Sheet addSheet(int pagenum){ // PPath s = PPath.createRectangle(0, 0, width, height); Sheet s = new Sheet(this, pagenum); sheets.put(pagenum, s); s.setPathToRectangle(0, 0, width, height); // s.setPaint(Color.white); setStrokePaint(Color.black); // s.offset(numPT.getWidth()+10+(width+10)*(pagenum-1), 0); // to be refined // s.scale(1); // to be refined addChild(s); if (isLandscapeMode) s.rotate(Math.PI/2); if (satn.sheetVisibleMode[pagenum]>0){ s.setVisible(true); layoutVisibleSheets(); } else { s.setVisible(false); } return s; } public boolean hasContent() { if (getBounds().width*getBounds().height > 10){ return true; } return false; } public void layoutVisibleSheets(){ PBounds pb = new PBounds(); if (numPT.getVisible()) pb.add(numPT.getBounds()); int rotatedWidth = width; if (isLandscapeMode) { rotatedWidth = height; //rotateOffsetX = height; // pos++; } int x = 10; //default GAP if (numPT.getVisible()) x += numPT.getWidth(); if (isLandscapeMode) x+= rotatedWidth; if (!numPT.getVisible() && isLandscapeMode) x = rotatedWidth; for(int sn=1; sn<=6;sn++){ Sheet sht = sheets.get(sn); if (sht == null) continue; if (sht.getVisible()){ sht.setOffset(x, 0); x = x + rotatedWidth; pb.add(sht.getFullBounds()); addChild(sht); } else { sht.removeFromParent(); } } setBounds(pb); } public Sheet getSheet(int pagenum){ Sheet ret = sheets.get(pagenum); if (ret == null){ return addSheet(pagenum); //なければ登録しちゃいます } else return ret; } //TODO:共通の認識器,フィルタ public static ArrayList<SSHandler> sshandler; static { sshandler = new ArrayList<SSHandler>(); } public static void handleSS(ShortStroke ss){ for(SSHandler ssh: sshandler){ ssh.process(ss); } } public static void addSSHandler(SSHandler ssh){ //既存の筆記を処理 for(Note n: SimpleATN.theapp.notes.values()){ for(ShortStroke ss : n.all){ ssh.processPrevious(ss); } } sshandler.add(ssh); } //TODO:筆記の画面出力 public void addStroke(ShortStroke ss) { addStroke(ss,false); } public void addStroke(ShortStroke ss, boolean handled) { if (!handled) Note.handleSS(ss); ss.rebuildStroke(); //シートに貼付け Sheet sheet = getSheet(ss.paperid); sheet.addChild(ss); if (satn.menutoolbar.getAction("NotifyOnNew").isSelected()) sheet.notifySheet(); ss.setPickable(false); // sheet.showFadingSheetNum(5000); //TODO: all必要?>保存時のみ必要 all.add(ss); // ss.debugPrint(); } static Hashtable<Float, BasicStroke> penStrokeHash; static Hashtable<Integer, Color> colorHash; static { penStrokeHash = new Hashtable<Float, BasicStroke>(); colorHash = new Hashtable<Integer, Color>(); } public static BasicStroke getCachedBasicStroke(float f){ //f=太さ if (penStrokeHash.containsKey(f)){ return penStrokeHash.get(f); } else { BasicStroke bs = new BasicStroke( f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 90.0f); penStrokeHash.put(f, bs); return bs; } } public static Color getColor(int f){ if (colorHash.containsKey(f)){ return colorHash.get(f); } else { Color cl = new Color(f); colorHash.put(f, cl); return cl; } } // sheet num, visible mode (0:hide, 1: show with data, 2: show all) public void toggleVisible(int sn, int i) { if (sn == 0){ if (i==0) { numPT.removeFromParent(); numPT.setVisible(false); } else { this.addChild(numPT); numPT.setVisible(true); } } else { if (i==0){ Sheet sht = sheets.get(sn); if (sht != null) sht.setVisible(false); } else if (i==2){ Sheet sht = sheets.get(sn); if (sht == null) sht = getSheet(sn); sht.setVisible(true); } else if (i==1){ Sheet sht = sheets.get(sn); if (sht != null){ sht.setVisible(sht.getSSSize() > 0); } } } layoutVisibleSheets(); } public void applySheetVisible(){ for(int sn=0;sn<7;sn++){ toggleVisible(sn, satn.sheetVisibleMode[sn]); } } public void focus() { //フォーカス Rectangle2D globalb = getGlobalFullBounds(); satn.zoomToBounds(globalb, 1000, "Note.focus"); } public void prepare_for_print(boolean isBefore) { if (isBefore){ for(Sheet s: sheets.values()) s.setStrokePaint(null); } else { for(Sheet s: sheets.values()) s.setStrokePaint(Color.black); } } public void queueNotifyMessage(int num) { PText pt = new PText(String.valueOf(penid)+"-"+String.valueOf(num)); pt.setScale(2.0f); pt.setTransparency(0.7f); pt.setPaint(Color.yellow); pt.setTextPaint(Color.black); satn.canvas.getCamera().addChild(pt); new FadeTimerForNotify(pt, 2000, 1000, true); } public void setLandscapeMode(boolean b) { if (isLandscapeMode && b) return; //DBからの読み込み毎に,applyが有効化を図るため isLandscapeMode = b; if (b){ for(Sheet s: sheets.values()){ s.rotate(Math.PI/2); } } else { for(Sheet s: sheets.values()){ s.setRotation(0); } } layoutVisibleSheets(); } public void applyDrawingMode() { for(Sheet s: sheets.values()){ s.setDrawMode(satn.menutoolbar.getAction("Draw").isSelected()); } } public void exportToCSV(ArrayList<String> buffer) { for(ShortStroke ss: all){ buffer.add(ss.toCsv()); } } public void exportToCSVTeinei(ArrayList<String> buffer) { ArrayList<Point2D> sheetRegionCenter = new ArrayList<Point2D>(); sheetRegionCenter.add(new Point2D.Double(548,65));//名前 sheetRegionCenter.add(new Point2D.Double(207,260));//番号 sheetRegionCenter.add(new Point2D.Double(490,240));//番号の右 sheetRegionCenter.add(new Point2D.Double(211,452));//1 sheetRegionCenter.add(new Point2D.Double(502,456));//2 sheetRegionCenter.add(new Point2D.Double(200,630));//3 sheetRegionCenter.add(new Point2D.Double(506,630));//4 sheetRegionCenter.add(new Point2D.Double(184,827));//5 sheetRegionCenter.add(new Point2D.Double(506,827));//6 ArrayList<Point2D> sheetRegionCenter2 = new ArrayList<Point2D>(); sheetRegionCenter2.add(new Point2D.Double(517,68));//2名前 sheetRegionCenter2.add(new Point2D.Double(191,234));//7 sheetRegionCenter2.add(new Point2D.Double(498,236));//8 sheetRegionCenter2.add(new Point2D.Double(193,441));//9 sheetRegionCenter2.add(new Point2D.Double(500,441));//10 sheetRegionCenter2.add(new Point2D.Double(193,626));//11 sheetRegionCenter2.add(new Point2D.Double(500,626));//12 sheetRegionCenter2.add(new Point2D.Double(193,840));//13 sheetRegionCenter2.add(new Point2D.Double(500,840));//14 // System.out.println("size of all "+all.size()); if (all.size()==0) return; long beginT = all.get(0).time; //最初の時刻 long endT = all.get(all.size()-1).time;//最後の時刻 long duration = endT - beginT; LinkedList<ShortStroke> sec10 = new LinkedList<ShortStroke>(); LinkedList<ShortStroke> sec30 = new LinkedList<ShortStroke>(); LinkedList<ShortStroke> sec60 = new LinkedList<ShortStroke>(); long current; for(ShortStroke ss: all){ ss.calcMetrics(); sec10.offer(ss); sec30.offer(ss); sec60.offer(ss); //追加 current = ss.time; while(current - sec10.peek().time > 10000) sec10.poll(); while(current - sec30.peek().time > 30000) sec30.poll(); while(current - sec60.peek().time > 60000) sec60.poll(); if (ss.dist==0) continue;//長さが0だと,points/distがInfinityになってしまうため。筆記点1 StringBuffer sb = new StringBuffer(); sb.append(ss.penid); sb.append(","); sb.append(ss.paperid); sb.append(","); sb.append(current-beginT); // 経過秒 ss.current_begin = current-beginT; sb.append(","); sb.append(((double)(current-beginT))/duration);//経過秒数の全体に対する割合 ss.current_begin_duration = ((double)(current-beginT))/duration; sb.append(","); sb.append(sec10.size());//10秒以内の筆記数 ss.sec10size = sec10.size(); sb.append(","); sb.append(sec30.size());//30秒以内の筆記数 ss.sec30size = sec30.size(); sb.append(","); sb.append(sec60.size());//60秒以内の筆記数 ss.sec60size = sec60.size(); sb.append(","); sb.append(ss.timed); sb.append(","); sb.append(ss.ramer); sb.append(","); sb.append(ss.var_ramer);//varspeed/log10(ramer) sb.append(","); sb.append(ss.ppd);//pts/length(dist) sb.append(","); sb.append(ss.pts); sb.append(","); sb.append(ss.dist); sb.append(","); sb.append(ss.sx[0]); sb.append(","); sb.append(ss.sy[0]); int pos = -1; double min = Double.MAX_VALUE; if (ss.paperid==1){ int ii=0; for(Point2D ppp: sheetRegionCenter){ if (ppp.distance(ss.sx[0],ss.sy[0])<min){ min = ppp.distance(ss.sx[0],ss.sy[0]); pos = ii; } ii++; } } else { int ii=9; for(Point2D ppp: sheetRegionCenter2){ if (ppp.distance(ss.sx[0],ss.sy[0])<min){ min = ppp.distance(ss.sx[0],ss.sy[0]); pos = ii; } ii++; } } sb.append(","); sb.append(pos); ss.pos = pos; if (ss.pts > 30) { ss.setStrokePaint(Color.cyan); continue; //書き損じなどのぐちゅぐちゅなので,飛ばす } if (ss.dist >= 78) { ss.setStrokePaint(Color.green); continue; } buffer.add(sb.toString()); } } public void exportToCSVVarppdr(ArrayList<String> buffer) { if (all.size()==0) return; double[][][] score = new double[11][18][6]; ArrayList<String> sc = FileReadWriter.getLinesList("score.csv"); String[][] lines = new String[6][36]; for(int i=0;i<6;i++){ lines[i] = sc.get(i).split("\t"); } for(int j=0;j<36;j++){ int pen = Integer.parseInt(lines[0][j]); int pos = Integer.parseInt(lines[1][j]); for(int i=2;i<6;i++){ double scd = Double.parseDouble(lines[i][j]); score[pen][pos][i] = scd; } } Query q = new Query(); try { // q.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer>3;"); q.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer>-1 and pts<=30 and dist<=77 group by pos group by order pos"); // q.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer>-1 group by pos, ramer group by order pos, ramer"); } catch (QueryParseException e) { e.printStackTrace(); } QueryResults qr=null; List<Integer> res; try { qr = q.execute(all); // ArrayList<ShortStroke> res = new ArrayList<ShortStroke>(qr.getResults()); Map<ArrayList<Integer>, ArrayList<ShortStroke>> map = qr.getGroupByResults(); for(ArrayList<ShortStroke> ass: map.values()){ ShortStroke fss = ass.get(0); //System.out.println(fss.penid+" pos:"+fss.pos+" ram:"+fss.ramer+" size:"+ass.size()); if (ass.size()<4) continue; //3以下は出さない StringBuffer sb = new StringBuffer(); sb.append(fss.penid); sb.append(","); sb.append(fss.pos); sb.append(","); AvgVarCalc2 calc = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, ass); //calc.printAll(); sb.append(calc.getavg("pts")); sb.append(","); sb.append(calc.getavg("dist")); sb.append(","); sb.append(calc.getavg("var_ramer")); sb.append(","); sb.append(calc.getvar("var_ramer")); sb.append(","); sb.append(calc.getavg("ppd")); sb.append(","); sb.append(calc.getvar("ppd")); sb.append(","); Query q0 = new Query(); try { q0.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=0 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr0=null; qr0 = q0.execute(ass); AvgVarCalc2<ShortStroke> calc0 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr0.getResults()); Query q1 = new Query(); try { q1.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=1 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr1=null; qr1 = q1.execute(ass); AvgVarCalc2<ShortStroke> calc1 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr1.getResults()); Query q2 = new Query(); try { q2.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=2 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr2=null; qr2 = q2.execute(ass); AvgVarCalc2<ShortStroke> calc2 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr2.getResults()); Query q3 = new Query(); try { q3.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=3 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr3=null; qr3 = q3.execute(ass); AvgVarCalc2<ShortStroke> calc3 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr3.getResults()); Query q4 = new Query(); try { q4.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=4 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr4=null; qr4 = q4.execute(ass); AvgVarCalc2<ShortStroke> calc4 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr4.getResults()); Query q5 = new Query(); try { q5.parse("select * from jp.ac.kyutech.mns.ist.ShortStroke where ramer=5 and pos = "+fss.pos); } catch (QueryParseException e) { e.printStackTrace();} QueryResults qr5=null; qr5 = q5.execute(ass); AvgVarCalc2<ShortStroke> calc5 = new AvgVarCalc2<ShortStroke>(new String[]{"pts","ppd","var_ramer","dist","ramer"}, (ArrayList<ShortStroke>)qr5.getResults()); double varppd0 = calc0.getvar("ppd"); double varppd1 = calc1.getvar("ppd"); double varppd2 = calc2.getvar("ppd"); double varppd3 = calc3.getvar("ppd"); double varppd4 = calc4.getvar("ppd"); double varppd5 = calc5.getvar("ppd"); if (calc0.getcnt("ppd")<4) varppd0 = 0; if (calc1.getcnt("ppd")<4) varppd1 = 0; if (calc2.getcnt("ppd")<4) varppd2 = 0; if (calc3.getcnt("ppd")<4) varppd3 = 0; if (calc4.getcnt("ppd")<4) varppd4 = 0; if (calc5.getcnt("ppd")<4) varppd5 = 0; sb.append(varppd0); sb.append(","); sb.append(varppd1); sb.append(","); sb.append(varppd2); sb.append(","); sb.append(varppd3); sb.append(","); sb.append(varppd4); sb.append(","); sb.append(varppd5); sb.append(","); sb.append(calc.getcnt("ppd")); sb.append(","); sb.append(calc0.getcnt("ppd")); sb.append(","); sb.append(calc1.getcnt("ppd")); sb.append(","); sb.append(calc2.getcnt("ppd")); sb.append(","); sb.append(calc3.getcnt("ppd")); sb.append(","); sb.append(calc4.getcnt("ppd")); sb.append(","); sb.append(calc5.getcnt("ppd")); sb.append(","); sb.append(calc.getavg("ramer")); sb.append(","); sb.append(calc.getvar("ramer")); if (score[fss.penid][fss.pos][2]>0){ for(int i=2;i<6;i++){ sb.append(","); sb.append(score[fss.penid][fss.pos][i]); } buffer.add(sb.toString()); } } } catch (QueryExecutionException e) { e.printStackTrace(); } } @Override public double teineiLevel() { // TODO Auto-generated method stub return 0; } }