Android AR Compass Display
I am working on an Augmented Reality (AR) app for an Android phone. I would like to display my orientation data in the form of two rotating axes: one at the top of the screen to show the current azimuth (North, East, South, West), and one on the side to show the altitude/elevation. I'm new to Android programming, so I'm not really sure how to go about creating these axes visually.
My first thought was that I could use predefined images that somehow wrap around upon hitting the edges of the screen (as if the image was on the outside of a rotating cylinder). From here, it would be开发者_开发知识库 a simple matter of lining up the image with the information I'm pulling from the sensors.
Is there some way to wrap images so that they can be rotated in a virtual plane in this manner? Can anybody suggest a better solution to my original problem?
I'm pressed for time, so I've come up with a hard-coded solution that could probably be extended to a more general case without too much trouble. To create the axes, I'm programmatically generating a bunch of Path objects and then drawing them to my canvas. Then I simply translate the canvas back and forth based on the azimuth values I'm collecting.
Here is a copy of the class I use to generate the azimuth axis:
class AzimuthOverlay extends View {
// Values hardcoded for fullscreen landscape
// Width = 800 pixels
int tickPixels = 40; // Number of pixels between tick marks
final int MAJORTICKS = 36;
final int MINORTICKS = 36;
// Need additional 10 for proper wrapping
final int TOTALOBJECTS = MAJORTICKS + MINORTICKS + 10;
public double mAzimuth; // Set externally by a SensorEventListener class
private Paint ticPaint = new Paint();
private Paint numPaint = new Paint();
private ArrayList<Path> axis = new ArrayList<Path>(TOTALOBJECTS);
public AzimuthOverlay(Context context) {
super(context);
ticPaint.setAntiAlias(true);
ticPaint.setColor(Color.GREEN);
ticPaint.setStyle(Paint.Style.FILL);
numPaint.setColor(Color.GREEN);
numPaint.setStyle(Paint.Style.STROKE);
numPaint.setStrokeWidth(2);
// Extend to the left of the screen
for (int i = -10; i < 0; i++) {
if (i % 2 == 0) {
axis.add(getMajorTick(i * tickPixels));
}
else {
axis.add(getNumber(360 + 5*i, i * tickPixels));
}
}
// Create axis (numbers on minor ticks)
for (int i = 0; i < TOTALOBJECTS; i++) {
if (i % 2 == 0) {
axis.add(getMajorTick(i * tickPixels));
}
else {
axis.add(getNumber((5*i)%360, i * tickPixels));
}
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate((int)-mAzimuth * 8, 0); // 8 pixels per degree
boolean toggle = true; // Alternate between ticks and numbers
for (Path p : axis) {
if (toggle) {
canvas.drawPath(p, ticPaint);
}
else {
canvas.drawPath(p, numPaint);
}
toggle = (toggle == false) ? true : false;
}
super.onDraw(canvas);
}
// Create big tick marks as Path object
private Path getMajorTick(int offset) {
Path mypath = new Path();
mypath.moveTo(-2 + offset, 0);
mypath.lineTo(-2 + offset, 20);
mypath.lineTo(2 + offset, 20);
mypath.lineTo(2 + offset, 0);
mypath.close();
return mypath;
}
// Create small tick marks as Path object
private Path getMinorTick(int offset) {
Path mypath = new Path();
mypath.moveTo(-2 + offset, 0);
mypath.lineTo(-2 + offset, 10);
mypath.lineTo(2 + offset, 10);
mypath.lineTo(2 + offset, 0);
mypath.close();
return mypath;
}
// Create individual digits as Path object
private Path getDigit(int digit, int offset) {
Path mypath = new Path();
final int lx = -6;
final int mx = 0;
final int rx = 6;
final int ty = 0;
final int my = 6;
final int by = 12;
final int doffset = 2;
switch(digit) {
case 0:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, by + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.close();
break;
case 1:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(mx + offset, ty + doffset);
mypath.lineTo(mx + offset, by + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.lineTo(rx + offset, by + doffset);
break;
case 2:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, my + doffset);
mypath.lineTo(lx + offset, my + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.lineTo(rx + offset, by + doffset);
break;
case 3:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, by + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.moveTo(lx + offset, my + doffset);
mypath.lineTo(rx + offset, my + doffset);
break;
case 4:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(lx + offset, my + doffset);
mypath.lineTo(rx + offset, my + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, by + doffset);
break;
case 5:
mypath.moveTo(rx + offset, ty + doffset);
mypath.lineTo(lx + offset, ty + doffset);
mypath.lineTo(lx + offset, my + doffset);
mypath.lineTo(rx + offset, my + doffset);
mypath.lineTo(rx + offset, by + doffset);
mypath.lineTo(lx + offset, by + doffset);
break;
case 6:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.lineTo(rx + offset, by + doffset);
mypath.lineTo(rx + offset, my + doffset);
mypath.lineTo(lx + offset, my + doffset);
break;
case 7:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, by + doffset);
break;
case 8:
mypath.moveTo(lx + offset, ty + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(rx + offset, by + doffset);
mypath.lineTo(lx + offset, by + doffset);
mypath.lineTo(lx + offset, ty + doffset);
mypath.moveTo(lx + offset, my + doffset);
mypath.lineTo(rx + offset, my + doffset);
break;
case 9:
mypath.moveTo(rx + offset, by + doffset);
mypath.lineTo(rx + offset, ty + doffset);
mypath.lineTo(lx + offset, ty + doffset);
mypath.lineTo(lx + offset, my + doffset);
mypath.lineTo(rx + offset, my + doffset);
break;
}
return mypath;
}
// Create a number up to 3 digits as a Path object
private Path getNumber(int number, int offset) {
Path mypath = new Path();
final int digitoffset = 7;
int digit;
int temp;
if (number > 99) { // 3-digit number
digit = number / 100;
mypath = getDigit(digit, offset - 2*digitoffset);
temp = (number % 100);
digit = temp / 10;
mypath.addPath(getDigit(digit, offset));
digit = temp % 10;
mypath.addPath(getDigit(digit, offset + 2*digitoffset));
}
else if (number > 9) { // 2-digit number
digit = number / 10;
mypath = getDigit(digit, offset-digitoffset);
mypath.addPath(getDigit(number % 10, offset+digitoffset));
}
else { // 1-digit number
mypath = getDigit(number, offset);
}
return mypath;
}
protected void setAzimuth(double azimuth) {
mAzimuth = azimuth;
}
}
精彩评论