Created
September 18, 2016 07:04
-
-
Save clockfort/2cd26db9a5d69d2a304dbbe8735c41ad to your computer and use it in GitHub Desktop.
BinaryReverseGrayCodeRotaryEncoderGenerator
This file contains 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.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