Android Open Source - android-rotation-sensor-sample Attitude Indicator






From Project

Back to project page android-rotation-sensor-sample.

License

The source code is released under:

Copyright (c) 2013 Keith Platfoot Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Sof...

If you think the Android project android-rotation-sensor-sample listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.kviation.android.sample.orientation;
/*  ww w .  j a v  a2  s.  c o  m*/
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

public class AttitudeIndicator extends View {

  private static final boolean LOG_FPS = false;

  private static final int SKY_COLOR = Color.parseColor("#36B4DD");
  private static final int EARTH_COLOR = Color.parseColor("#865B4B");
  private static final int MIN_PLANE_COLOR = Color.parseColor("#E8D4BB");
  private static final float TOTAL_VISIBLE_PITCH_DEGREES = 45 * 2; // ? 45?

  private final PorterDuffXfermode mXfermode;
  private final Paint mBitmapPaint;
  private final Paint mEarthPaint;
  private final Paint mPitchLadderPaint;
  private final Paint mMinPlanePaint;
  private final Paint mBottomPitchLadderPaint;

  // These are created once and reused in subsequent onDraw calls.
  private Bitmap mSrcBitmap;
  private Canvas mSrcCanvas;
  private Bitmap mDstBitmap;

  private int mWidth;
  private int mHeight;

  private float mPitch = 0; // Degrees
  private float mRoll = 0; // Degrees, left roll is positive

  public AttitudeIndicator(Context context) {
    this(context, null);
  }

  public AttitudeIndicator(Context context, AttributeSet attrs) {
    super(context, attrs);

    mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    mBitmapPaint = new Paint();
    mBitmapPaint.setFilterBitmap(false);

    mEarthPaint = new Paint();
    mEarthPaint.setAntiAlias(true);
    mEarthPaint.setColor(EARTH_COLOR);

    mPitchLadderPaint = new Paint();
    mPitchLadderPaint.setAntiAlias(true);
    mPitchLadderPaint.setColor(Color.WHITE);
    mPitchLadderPaint.setStrokeWidth(3);

    mBottomPitchLadderPaint = new Paint();
    mBottomPitchLadderPaint.setAntiAlias(true);
    mBottomPitchLadderPaint.setColor(Color.WHITE);
    mBottomPitchLadderPaint.setStrokeWidth(3);
    mBottomPitchLadderPaint.setAlpha(128);

    mMinPlanePaint = new Paint();
    mMinPlanePaint.setAntiAlias(true);
    mMinPlanePaint.setColor(MIN_PLANE_COLOR);
    mMinPlanePaint.setStrokeWidth(5);
    mMinPlanePaint.setStyle(Paint.Style.STROKE);
  }

  public float getPitch() {
    return mPitch;
  }

  public float getRoll() {
    return mRoll;
  }

  public void setAttitude(float pitch, float roll) {
    mPitch = pitch;
    mRoll = roll;
    invalidate();
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w;
    mHeight = h;
  }

  private Bitmap getSrc() {
    if (mSrcBitmap == null) {
      mSrcBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
      mSrcCanvas = new Canvas(mSrcBitmap);
    }
    Canvas canvas = mSrcCanvas;

    float centerX = mWidth / 2;
    float centerY = mHeight / 2;

    // Background
    canvas.drawColor(SKY_COLOR);

    // Save the state without any rotation/translation so
    // we can revert back to it to draw the fixed components.
    canvas.save();

    // Orient the earth to reflect the pitch and roll angles
    canvas.rotate(mRoll, centerX, centerY);
    canvas.translate(0, (mPitch / TOTAL_VISIBLE_PITCH_DEGREES) * mHeight);

    // Draw the earth as a rectangle, well beyond the view bounds
    // to account for large nose-down pitch.
    canvas.drawRect(-mWidth, centerY, mWidth * 2, mHeight * 2, mEarthPaint);

    // Draw white horizon and top pitch ladder
    float ladderStepY = mHeight / 12;
    canvas.drawLine(-mWidth, centerY, mWidth * 2, centerY, mPitchLadderPaint);
    for (int i = 1; i <= 4; i++) {
      float y = centerY - ladderStepY * i;
      float width = mWidth / 8;
      canvas.drawLine(centerX - width / 2, y, centerX + width / 2, y, mPitchLadderPaint);
    }

    // Draw the bottom pitch ladder
    float bottomLadderStepX = mWidth / 12;
    float bottomLadderStepY = mWidth / 12;
    canvas.drawLine(centerX, centerY, centerX - bottomLadderStepX * 3.5f, centerY
        + bottomLadderStepY * 3.5f, mBottomPitchLadderPaint);
    canvas.drawLine(centerX, centerY, centerX + bottomLadderStepX * 3.5f, centerY
        + bottomLadderStepY * 3.5f, mBottomPitchLadderPaint);
    for (int i = 1; i <= 3; i++) {
      float y = centerY + bottomLadderStepY * i;
      canvas.drawLine(centerX - bottomLadderStepX * i, y, centerX + bottomLadderStepX * i, y,
          mBottomPitchLadderPaint);
    }

    // Return to normal to draw the miniature plane
    canvas.restore();

    // Draw the nose dot
    canvas.drawPoint(centerX, centerY, mMinPlanePaint);

    // Half-circle of miniature plane
    float minPlaneCircleRadiusX = mWidth / 6;
    float minPlaneCircleRadiusY = mHeight / 6;
    RectF wingsCircleBounds = new RectF(centerX - minPlaneCircleRadiusX, centerY
        - minPlaneCircleRadiusY, centerX + minPlaneCircleRadiusX, centerY + minPlaneCircleRadiusY);
    canvas.drawArc(wingsCircleBounds, 0, 180, false, mMinPlanePaint);

    // Wings of miniature plane
    float wingLength = mWidth / 6;
    canvas.drawLine(centerX - minPlaneCircleRadiusX - wingLength, centerY, centerX
        - minPlaneCircleRadiusX, centerY, mMinPlanePaint);
    canvas.drawLine(centerX + minPlaneCircleRadiusX, centerY, centerX + minPlaneCircleRadiusX
        + wingLength, centerY, mMinPlanePaint);

    // Draw vertical post
    canvas.drawLine(centerX, centerY + minPlaneCircleRadiusY, centerX, centerY
        + minPlaneCircleRadiusY + mHeight / 3, mMinPlanePaint);

    return mSrcBitmap;
  }

  private Bitmap getDst() {
    if (mDstBitmap == null) {
      mDstBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
      Canvas c = new Canvas(mDstBitmap);
      c.drawColor(Color.TRANSPARENT);

      Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
      p.setColor(Color.RED);
      c.drawOval(new RectF(0, 0, mWidth, mHeight), p);
    }
    return mDstBitmap;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    if (LOG_FPS) {
      countFps();
    }

    Bitmap src = getSrc();
    Bitmap dst = getDst();

    int sc = canvas.saveLayer(0, 0, mWidth, mHeight, null, Canvas.MATRIX_SAVE_FLAG
        | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
        | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);

    canvas.drawBitmap(dst, 0, 0, mBitmapPaint);
    mBitmapPaint.setXfermode(mXfermode);
    canvas.drawBitmap(src, 0, 0, mBitmapPaint);
    mBitmapPaint.setXfermode(null);

    canvas.restoreToCount(sc);
  }

  private long frameCountStartedAt = 0;
  private long frameCount = 0;

  private void countFps() {
    frameCount++;
    if (frameCountStartedAt == 0) {
      frameCountStartedAt = System.currentTimeMillis();
    }
    long elapsed = System.currentTimeMillis() - frameCountStartedAt;
    if (elapsed >= 1000) {
      Log.i("FPS: " + frameCount);
      frameCount = 0;
      frameCountStartedAt = System.currentTimeMillis();
    }
  }
}




Java Source Code List

com.kviation.android.sample.orientation.AttitudeIndicator.java
com.kviation.android.sample.orientation.Log.java
com.kviation.android.sample.orientation.MainActivity.java
com.kviation.android.sample.orientation.Orientation.java