Created
January 18, 2014 20:32
-
-
Save bschwind/8495883 to your computer and use it in GitHub Desktop.
Building a stroke tree for a particular character
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.skritter.utils; | |
import com.skritter.models.Param; | |
import com.skritter.models.Stroke; | |
import com.skritter.models.StrokeData; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
public class StrokeTree { | |
private class StrokeNode { | |
public int strokeID; | |
public int strokeRank; | |
private List<StrokeNode> children; | |
public StrokeNode(int strokeID, int strokeRank) { | |
this.strokeID = strokeID; | |
this.strokeRank = strokeRank; | |
children = new ArrayList<StrokeNode>(); | |
} | |
public void addChild(StrokeNode strokeNode) { | |
children.add(strokeNode); | |
} | |
public boolean hasChild(int strokeID) { | |
for (StrokeNode strokeNode : children) { | |
if (strokeNode.strokeID == strokeID) { | |
return true; | |
} | |
} | |
return false; | |
} | |
public StrokeNode getChildWithStrokeID(int strokeID) { | |
for (StrokeNode strokeNode : children) { | |
if (strokeNode.strokeID == strokeID) { | |
return strokeNode; | |
} | |
} | |
return null; | |
} | |
public boolean equals(StrokeNode other) { | |
return this.strokeID == other.strokeID && this.strokeRank == other.strokeRank; | |
} | |
public int hashCode() { | |
return toString().hashCode(); | |
} | |
public String toString() { | |
return "\"" + this.strokeID + "-" + this.strokeRank + "\""; | |
} | |
} | |
private StrokeNode sentinel; | |
private Map<Integer, List<StrokeNode>> strokeRankMap; | |
public StrokeTree(StrokeData strokeData) { | |
sentinel = new StrokeNode(-1, 0); | |
strokeRankMap = new HashMap<Integer, List<StrokeNode>>(); | |
for (int i = 0; i < strokeData.getStrokes().length; i++) { | |
Stroke[] variation = strokeData.getStrokes()[i]; | |
StrokeNode parent = sentinel; | |
for (int j = 0; j < variation.length; j++) { | |
Stroke stroke = variation[j]; | |
int newStrokeRank = parent.strokeRank + getStrokeCountFromStrokeID(stroke.strokeID); | |
int nextRank = parent.strokeRank + 1; | |
StrokeNode potentialNextStrokeNode = parent.getChildWithStrokeID(stroke.strokeID); | |
if (potentialNextStrokeNode == null) { | |
potentialNextStrokeNode = getStrokeNodeFromRank(nextRank, stroke.strokeID); | |
if (potentialNextStrokeNode != null) { | |
parent.addChild(potentialNextStrokeNode); | |
} | |
} | |
if (potentialNextStrokeNode != null) { | |
parent = potentialNextStrokeNode; | |
continue; | |
} else { | |
StrokeNode newStrokeNode = new StrokeNode(stroke.strokeID, newStrokeRank); | |
parent.addChild(newStrokeNode); | |
insertNewStrokeRank(newStrokeNode, parent.strokeRank); | |
parent = newStrokeNode; | |
} | |
} | |
} | |
} | |
private int getStrokeCountFromStrokeID(int strokeID) { | |
for (Param param : Param.params) { | |
if (strokeID == param.bitmapID) { | |
if (param.containedStrokes != null) { | |
return param.containedStrokes.length; | |
} else { | |
return 1; | |
} | |
} | |
} | |
return 1; | |
} | |
private StrokeNode getStrokeNodeFromRank(int rank, int strokeID) { | |
List<StrokeNode> strokeNodes = strokeRankMap.get(rank); | |
if (strokeNodes == null || strokeNodes.isEmpty()) { | |
return null; | |
} | |
for (StrokeNode strokeNode : strokeNodes) { | |
if (strokeID == strokeNode.strokeID) { | |
return strokeNode; | |
} | |
} | |
return null; | |
} | |
private void insertNewStrokeRank(StrokeNode strokeNode, int parentStrokeRank) { | |
int numRanksToInsert = strokeNode.strokeRank - parentStrokeRank; | |
for (int i = 0; i < numRanksToInsert; i++) { | |
int newRank = parentStrokeRank + i + 1; | |
List<StrokeNode> nodes = strokeRankMap.get(newRank); | |
if (nodes != null) { | |
nodes.add(strokeNode); | |
} else { | |
List<StrokeNode> newStrokeNodes = new ArrayList<StrokeNode>(); | |
newStrokeNodes.add(strokeNode); | |
strokeRankMap.put(newRank, newStrokeNodes); | |
} | |
} | |
} | |
public String buildStrokeDotFile() { | |
StringBuilder sb = new StringBuilder(); | |
sb.append("digraph StrokeTree {\n\trankdir=LR;\n"); | |
Set<StrokeNode> nodes = new HashSet<StrokeNode>(); | |
for (List<StrokeNode> nodeList : strokeRankMap.values()) { | |
nodes.addAll(nodeList); | |
} | |
for (StrokeNode node : nodes) { | |
sb.append("\t" + node.toString() + ";\n"); | |
} | |
sb.append("\n\n"); | |
for (StrokeNode node : nodes) { | |
for (StrokeNode child : node.children) { | |
sb.append(node.toString() + "->" + child.toString() + ";\n"); | |
} | |
} | |
sb.append("\n}\n"); | |
return sb.toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment