首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

定位 API 開發指南:實作 CompassUI 類別繪製電子羅盤 (第 6 部分)

     編輯:J2ME

4.4.8 CompassUI 類別:電子羅盤視覺化

CompassUI 繼承 Canvas,實作 CommandListener 與 Runnable,負責:

  • 載入羅盤背景圖片(依螢幕尺寸切換大小圖)
  • 週期性讀取 Orientation 感測器取得方位角
  • 繪製旋轉指標指向磁北或真北
  • 提供切換至 RouteUI、PitchRollUI 的指令

類別結構與常數

package com.nokia.example.location.tourist.ui;

import java.io.IOException;
import javax.microedition.lcdui.*;
import javax.microedition.location.Orientation;
import com.nokia.example.location.tourist.TouristMIDlet;
import com.nokia.example.location.tourist.model.ConfigurationProvider;

public class CompassUI extends Canvas implements CommandListener, Runnable {
    private final int X = 0, Y = 1;
    private int centerX, centerY;
    private final float degree = (float) (2 * Math.PI / 360.0);
    private float azimuth = 0.0f;
    private boolean isMagnetic;
    private boolean threadActive = false;
    private final long SLEEPTIME = 1000;
    private Displayable route, pitchrollUI;
    private Command routeCmd = new Command("Route", Command.BACK, 1);
    private Command prCmd = new Command("Pitch and Roll", Command.OK, 1);
    private Image compassImage = null;
    // ...

建構子與圖片載入

public CompassUI(Displayable route) {
    this.route = route;
    pitchrollUI = new PitchRollUI(this);
    loadCompassImage();
    centerX = getWidth() / 2;
    centerY = getHeight() / 2;
    addCommand(routeCmd);
    addCommand(prCmd);
    setCommandListener(this);
}

private void loadCompassImage() {
    String imageName = "/compass_small.gif";
    if (getWidth() > 160) imageName = "/compass_large.gif";
    try {
        compassImage = Image.createImage(getClass().getResourceAsStream(imageName));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

生命週期控制執行緒

protected void showNotify() {
    threadActive = true;
    new Thread(this).start();
}

protected void hideNotify() {
    threadActive = false;
}

繪製畫面

清除畫布、繪製背景圖、根據 azimuth 旋轉繪製指標、顯示方位類型(磁北/真北):

protected void paint(Graphics g) {
    g.setColor(255, 255, 255);
    g.fillRect(0, 0, getWidth(), getHeight());

    int spikeLen = 5;
    int len = (compassImage.getWidth() / 2) - spikeLen;

    g.drawImage(compassImage,
        (getWidth() - compassImage.getWidth()) / 2,
        centerY, Graphics.LEFT | Graphics.VCENTER);

    g.setColor(0, 0, 255);
    drawArrow(g, degree * azimuth, len, spikeLen);

    g.setColor(0, 0, 255);
    String otext = isMagnetic ? "Magnetic Field" : "True North";
    g.drawString("Orientation: " + otext, 0, getHeight(),
        Graphics.BOTTOM | Graphics.LEFT);
}

向量旋轉繪製指標

使用 2x2 旋轉矩陣計算指標四個端點座標:

private void drawArrow(Graphics g, float angle, int len, int spikeLen) {
    int a[] = rotate(angle, 0, -(len - spikeLen));
    int b[] = rotate(angle, -spikeLen, -(len - spikeLen));
    int c[] = rotate(angle, 0, -len);
    int d[] = rotate(angle, spikeLen, -(len - spikeLen));
    int e[] = rotate(angle + (degree * 180.0), 0, -len);

    g.setColor(255, 0, 0); // 紅色指標
    g.drawLine(centerX, centerY, centerX + a[X], centerY + a[Y]);
    g.drawLine(centerX + b[X], centerY + b[Y], centerX + d[X], centerY + d[Y]);
    g.drawLine(centerX + b[X], centerY + b[Y], centerX + c[X], centerY + c[Y]);
    g.drawLine(centerX + c[X], centerY + c[Y], centerX + d[X], centerY + d[Y]);

    g.setColor(0, 0, 0); // 黑色反向指標
    g.drawLine(centerX, centerY, centerX + e[X], centerY + e[Y]);
}

private int[] rotate(double angle, int x, int y) {
    int rotated[] = new int[2];
    rotated[X] = (int) (Math.cos(angle) * x + Math.sin(angle) * y);
    rotated[Y] = (int) (-Math.sin(angle) * x + Math.cos(angle) * y);
    return rotated;
}

背景執行緒更新方位角

public void run() {
    while (threadActive) {
        Orientation orientation = ConfigurationProvider.getInstance().getOrientation();
        if (orientation != null) {
            isMagnetic = orientation.isOrientationMagnetic();
            azimuth = orientation.getCompassAzimuth();
        }
        repaint();
        try { Thread.sleep(SLEEPTIME); }
        catch (InterruptedException e) {}
    }
}

指令事件處理

public void commandAction(Command command, Displayable d) {
    if (command == routeCmd) {
        TouristMIDlet.getDisplay().setCurrent(route);
    } else if (command == prCmd) {
        TouristMIDlet.getDisplay().setCurrent(pitchrollUI);
    }
}
}

技術亮點: 採用雙緩衝繪製(Canvas 內建)、旋轉矩陣運算指標幾何、背景執行緒輪詢感測器,實現流暢的電子羅盤體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved