Skip to content

Instantly share code, notes, and snippets.

@bschwind
Created January 18, 2014 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bschwind/8495883 to your computer and use it in GitHub Desktop.
Save bschwind/8495883 to your computer and use it in GitHub Desktop.
Building a stroke tree for a particular character
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