Skip to content

Instantly share code, notes, and snippets.

@clockfort
Created September 18, 2016 07:04
Show Gist options
  • Save clockfort/2cd26db9a5d69d2a304dbbe8735c41ad to your computer and use it in GitHub Desktop.
Save clockfort/2cd26db9a5d69d2a304dbbe8735c41ad to your computer and use it in GitHub Desktop.
BinaryReverseGrayCodeRotaryEncoderGenerator
package com.clockfort;
import com.google.common.base.Joiner;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/* This would all be much simpler if we didn't track "runs" of the neighboring values in a track being the same,
* but I suspect that many CAD programs will behave considerably better with the much simpler geometry this gets us.
*/
public class Main {
final private static int BIT_LENGTH = 11;
final private static int CENTER_BUFFER_RADIUS_MM = 12;
final private static double INTERTRACK_SPACING_MM = 0;
final private static double TRACK_WIDTH_MM = 10;
final private static int CENTER_X = 0, CENTER_Y = 0;
private static final double viewSize = 400;
final private static String svgHeader =
"<?xml version=\"1.0\" standalone=\"no\"?>\n" +
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" +
"\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" +
"<svg width=\"" + viewSize + "mm\" height=\"" + viewSize + "mm\" " +
"viewBox=\"" + (-viewSize/2) + " " + (-viewSize/2) +" " + (viewSize) +" " + (viewSize) +"\"\n" +
"xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n";
final private static String svgFooter = "</svg>";
public static void main(String[] args) throws IOException {
PrintWriter outputFile = new PrintWriter(new BufferedWriter(new FileWriter("encoder.svg")));
outputFile.append(svgHeader);
for (int k=0; k < BIT_LENGTH; k++) { // kth bit; for each track
int lastGray = 0, runStart = 0;
for (int n = 0; n <= (2 << BIT_LENGTH); n++) {
int gray = intToGray(n);
if( kthBitToBool(lastGray, k) ) { // we were doing a run
if (kthBitToBool(gray, k)) {
if (n == (2 << (BIT_LENGTH)) - 1) { // this is the first bit / edge case
outputFile.append(generateArc(k, runStart, n, true));
}
} else { // we ended a run, render the arc
outputFile.append(generateArc(k, runStart, n));
}
} else { // we were not in a run
if (kthBitToBool(gray, k)) { // start a new run
runStart = n;
}
}
lastGray = gray;
}
}
outputFile.append(svgFooter);
outputFile.close();
}
private static int intToGray(int n) {
return n ^ (n >> 1);
}
private static String binaryRepresentation(int n) {
return String.format("%" + BIT_LENGTH + "s", Integer.toBinaryString(n)).replace(' ', '0');
}
private static boolean kthBitToBool(int n, int k) {
return ((n >> (k + 1)) & 1) > 0;
}
private static String generateArc(int trackNumber, int startN, int endN) {
return generateArc(trackNumber, startN, endN, false);
}
private static String generateArc(int trackNumber, int startN, int endN, boolean reverseSweep) {
System.out.println("Generating arc on track k=" + trackNumber + " from " + startN + " to " + endN);
double startRadius = CENTER_BUFFER_RADIUS_MM
+ (BIT_LENGTH - trackNumber) * TRACK_WIDTH_MM
+ (BIT_LENGTH - trackNumber) * INTERTRACK_SPACING_MM;
double endRadius = startRadius + TRACK_WIDTH_MM;
double startAngleRadians = ((double) startN / (2 << (BIT_LENGTH))) * (2 * Math.PI);
double endAngleRadians = ((double) endN / (2 << (BIT_LENGTH))) * (2 * Math.PI);
double lowerStartX = CENTER_X + startRadius * Math.cos(startAngleRadians);
double lowerStartY = CENTER_Y + startRadius * Math.sin(startAngleRadians);
double lowerEndX = CENTER_X + startRadius * Math.cos(endAngleRadians);
double lowerEndY = CENTER_Y + startRadius * Math.sin(endAngleRadians);
double upperStartX = CENTER_X + endRadius * Math.cos(endAngleRadians);
double upperStartY = CENTER_Y + endRadius * Math.sin(endAngleRadians);
double upperEndX = CENTER_X + endRadius * Math.cos(startAngleRadians);
double upperEndY = CENTER_Y + endRadius * Math.sin(startAngleRadians);
int largeArcFlag = (endAngleRadians - startAngleRadians) <= Math.PI ? 0 : 1;
int xAxisRotation = 0;
return "<path d=\"" +
"M " + lowerStartX + " " + lowerStartY + "\n" +
"A " + args(
startRadius,
startRadius,
xAxisRotation,
largeArcFlag,
reverseSweep? 0 : 1,
lowerEndX,
lowerEndY) + "\n" +
"L " + args(upperStartX, upperStartY) + "\n" +
"A " + args(
endRadius,
endRadius,
xAxisRotation,
largeArcFlag,
reverseSweep? 1 : 0,
upperEndX,
upperEndY) +
"Z" + "\n" +
"\" \n" +
"stroke=\"black\" stroke-width=\"0.1\" \n" +
"fill=\"blue\"" +
"/>\n";
}
private static String args(Object... args) {
return Joiner.on(" ").join(args);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment