AppleWatch 自作アプリGPSブイ気兼ねなく使いたい

おもい

  • Apple Watchの設定でバッテリー容量を節約してみました
    1. 不必要なバックグランド更新オフ。
    2. 画面常時オフ。
    3. ディスプレイの明るさ調整。
    4. 必要な通知以外オフの設定
    5. 視覚効果を減らす

 

  • ワークアウトや自作GPSブイアプリを使うとすぐにバッテリーが減ります。上記の設定を試しましたが、あまり効果が出ませんでした。

 

  • PSブイを連続して6時間使いたいです。途中で1時間の昼食休憩の間に充電するのはどうでしょうか?

 

 

 

Ultra0を買いました

  • 昨夜、Apple Watch Series 9のオークションで競り負けてしまいました。少し落ち込んでいた時に、中古のUltra 0をメルカリで見つけ、衝動的に購入してしまいました。

   

  • 普段使いならば、Apple Watch Series 6で十分ですね。竿やリールと同額でしたので、魚釣りの道具の一つとして考えています。そう思いたいですね。
  • バッテリーを交換し、関連する充電器を購入して、これで大丈夫だと思っていました。今回は、期待に応えてくれることを願っています。また、結果を報告しますね
ここまで読んでいただき、ありがとうございます

 

 

 

キーボードのワイヤレス化【予告】

経緯

  • 2024年4月22日にメールが届きました。ワイヤレスキーボード用USBケーブル付きコンバーター,Bluetooth 2.4,5.3gが紹介されています

         

   

 

 

AppleWatch「GPSブイ」手動でGPS停止【備忘録】

経緯

  • アプリを使用しGPSを利用するとバッテリーがかなり消耗します
  • Apple Watchからは、GPSを単独で停止することができませんが、iPhoneの「Watch」アプリから手動で停止することができます。(どなたか、Swiftで出来る方法があれば、教えてください)

 

弱手手法

  • AppleWatch側
    • GPSブイが止まっている時は

     

    • 表示されるボタンと押すと、iPhoneでオンして下さいとメッセージを出す

    • OKアラートを記載
      • 全てのボタンに位置情報サービスを開始できるか確認し、場合によりアラートを表示させる
    • Button(action: {

          // No.2 GPSブイを登録する際、GPS情報入手不可能な時、isShowAlertでアラート発生

          //          manager.reloadRegion(bouyNo: 2)

          if false == manager.reloadRegion(bouyNo: 2){

              isShowAlert.toggle()

          }

      }) {

          Image(systemName: "mappin.circle.fill")

              .foregroundColor(.white)

              .font(.system(size: 12))

          Text("3")

              .foregroundColor(.white)

              .font(.system(size: 12))

      }

      .frame(width: 41, height: 23)

      .cornerRadius(30.0)

        

      //OkAlertを記載

      .alert("Error", isPresented: $isShowAlert) {

          // ダイアログ内で行うアクション処理...

      } message: {

          // アラートのメッセージ...

          Text("アプリの位置情報サービスを\niPhoneから\nオンにして下さい")

      }

       

    •  GPS情報入手可否確認

    • //位置情報サービスがデバイス上で有効になっているか?

      if CLLocationManager.locationServicesEnabled() {

          let status = manager.authorizationStatus

          switch status {

          case .authorizedAlways, .authorizedWhenInUse:

              //ユーザーは、アプリがいつでも位置情報サービスを開始することを許可している

              //ユーザーは、アプリの使用中に位置情報サービスを開始することを許可した

              //この時は

              //ユーザーの現在位置を報告するアップデートの生成を開始

              manager.startUpdatingLocation()

          case .notDetermined:

              //アプリの使用中に位置情報サービスを使用する許可をユーザーに要求

              manager.requestWhenInUseAuthorization()

          case .denied:

              //ユーザーがアプリの位置情報サービスの使用を拒否しているので、アラートで知らせ

              return false

          case .restricted:

              //このアプリは位置情報サービスを使用する権限がない

              break

          default:

              break

          }

      }else {

          //ユーザーがアプリの位置情報サービスの使用を拒否しているので、アラートで知らせる

          return false

      }

      return true

       

  • iPhone

     

    • プライバシーを選択

     

    • 「”設定”の”プライバシー”」(オレンジ文字)を選択

     

    • 位置情報サービスを選択

    • gpsBuoyを選択

     

    •  GPSを切る時は「しない」

     

    • GPSを使う時は「このアプリの使用中」を選択

     

 

 

ここまで見てください、ありがとうございます

 

 

HHKB 魔改造

HHKBの魔改造

  • キーボードの中身を総入れ替えしました。

ハード

ソフト

  • 使い方 
  • 私のキー設定

    • LAYER 0

    • LAYER 1
    • LAYER 2(自作の親指シフトキーボードに合わせてみました)

       

最後に

ここまで見ていただき、ありがとうございます

 

 

親指シフトキーボード作成【備忘録】

経緯

  • 2021年4月5日

    • @sadaoikebeさんの記事をみて親指シフトキーボードを作って見ました。
    • 改良点は、キー配置を「HHKB」に合わせました
    • 非常に優秀なのは、OSがバージョンアップするたびに、ソフトがちゃんと動くか心配しなくて良いことです。キーボードソフト内で処理します
    • Facebookに記載しました        
    • 元記事    qiita.com
  • 2022年11月5日

    • コロナの影響で在宅勤務が増え、会社のPCにリモート接続するようになりました。
    • みんなが使うPCは「JISキーボード」で、自分用のPCは「USキーボード」です。これらをリモートから上手く切り替えることができませんでした。
  • 2023年3月3日

    • 作成できましたので、もう1台作成しました。自宅と会社で同じものを使っています
  • 2024年4月15日

    • そろそろ、購入できなくなるかと思い、もう1台作成しています。以前に作成したものを分解し、基盤とスイッチの位置を確認しながら作業を進めています
    • 手間がかかるのは、ハンダ付けする前にUSBで接続し、ソフトウェア(2023年3月に作成した完成したもの)をインストールし、ピンセットで導通に問題がないか確認することです。ハンダ付けを行うと不良品として交換できないため、慎重に作業を進めています。
    • 注)この作り方はかなり専門的なものであり、一般の方にはお勧めできません。特にソフトの改良には時間がかかりました

あるべき姿

  • キーボードの配列を変更できない場合は、キーボードから出力される文字コードをAppleUS、WinJIS、WinUSの3つのモードに切り替えることができれば良いでしょう
  • この方法で、親指シフト入力エミュレータ(たとえば、やまぶきRさんやDvorakJさんなど)を導入する必要がなく、便利に使えます

作ってみた

  • Fnキー併用押し
    • 英語は、KC_EISU。 日本語は、KC_KANA2 となっています(@sadaoikebeさんオリジナル)
    • AppleUSは、KC_YSMAC。 WinUSは、KC_YSWIN。 WinJISは、KC_YSUSJP。 (shiguが新規追加)
    • 注)KC_GRV(〜)は、物理キーボード上では右上になります。ソフト上では、KC_KANA2(右スペース)の横になっています (shiguがHHKBに合わすため追加)
    • Function Layer
 [_FUNC] = LAYOUT_62_ansi_2space( \
    KC_ESC,    KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,    KC_F7,   KC_F8,   KC_F9,    KC_F10,  KC_F11,  KC_F12,  KC_TRNS,  \
    KC_TRNS,   KC_F14, KC_F15, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME,  KC_PGDN, KC_PGUP, KC_END,   KC_PSCR, KC_TRNS, KC_BRK,  KC_DEL,            \
    KC_LCTL,   KC_YSMAC , KC_YSWIN, KC_YSUSJP, KC_TRNS, KC_TRNS, KC_LEFT,  KC_DOWN, KC_UP,KC_RIGHT, KC_INS,  KC_DEL,           KC_ENT,            \
    KC_LSFT,   RGB_TOG, RGB_HUI, RGB_HUD, KC_TRNS, KC_TRNS, KC_TRNS,  KC_TRNS, KC_TRNS, KC_TRNS,  KC_TRNS, KC_TRNS,                  \
    MO(_FUNC), KC_TRNS, KC_TRNS,                   KC_EISU, KC_KANA2,                   KC_GRV,   KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS )
  • モード設定
    • KC_YSMAC , KC_YSWIN, KC_YSUSJPを追加しました                  
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {
    case KC_EISU:
      if (record->event.pressed) {
        // NICOLA親指シフト
        //yseko
        if (ys_macwin == 0){
          send_string(SS_TAP(X_MHEN)); // Win
          send_string(SS_TAP(X_LANG2)); // Mac
        }else if(ys_macwin == 1){
          send_string(SS_LCTL("9"));    // Win
        }

        nicola_off();
        // NICOLA親指シフト
        rgblight_sethsv_at(170,255,40, RGBLED_NUM-1); // the last LED = BLUE (NICOLA off)
      }
      return false;
      break;
    case KC_KANA2:
      if (record->event.pressed) {
        // NICOLA親指シフト
        if (ys_macwin == 0){
          send_string(SS_TAP(X_HENK));  // Win
          send_string(SS_TAP(X_LANG1)); // Mac
        }else if(ys_macwin == 1){
          send_string(SS_LCTL("0"));   // Win
        }

        nicola_on();
        // NICOLA親指シフト
        rgblight_sethsv_at(85,255,40, RGBLED_NUM-1); // the last LED = GREEN (NICOLA on)
      }
      return false;
      break;

      //shiguが追加
      case KC_YSMAC:
        ys_macwin = 0;
        ys_Us_Jis = 0;
        return false;
        break;
      case KC_YSWIN:
        ys_macwin = 1;
        ys_Us_Jis = 0;
        return false;
        break;
      case KC_YSUSJP:
        ys_Us_Jis = 1;
        return false;
        break;

  }
  • JIS、USごとに変えるキー
case KC_LSHIFT:
case KC_RSHIFT:
case JU_2:
case JU_6:
case JU_7:
case JU_8:
case JU_9:
case JU_0:
case JU_MINS:
case JU_EQL:
case JU_LBRC:
case JU_RBRC:
case JU_BSLS:
case JU_SCLN:
case JU_QUOT:
case JU_GRV:
  • 例:「キー2」は下記のようにしました
    case JU_2:
      if(ys_Us_Jis == 1){
        if (record->event.pressed) {
          if (lshift || rshift) {    //シフトキーが押されていれば
            jtu_a_pressed_shift[JU_A_2] = true;
            UNREG_SHIFT();
            JTU_PRESS(LBRC);
          } else {             //シフトキーが押されていない
            jtu_a_pressed_nshift[JU_A_2] = true;
            CLOSE_REG_SHIFT();
            JTU_PRESS(2);
          }
        } else { 
          if(jtu_a_pressed_shift[JU_A_2]) {
            jtu_a_pressed_shift[JU_A_2] = false;
            JTU_RELEASE(LBRC);
            CLOSE_UNREG_SHIFT();
          }
          if(jtu_a_pressed_nshift[JU_A_2]) {
            jtu_a_pressed_nshift[JU_A_2] = false;
            JTU_RELEASE(2);
          }
        }
      }
      else {
        if (record->event.pressed) {
          if (lshift || rshift) {
            jtu_a_pressed_shift[JU_A_2] = true;
            CLOSE_UNREG_SHIFT();
            JTU_PRESS(2);
          } else {
            jtu_a_pressed_nshift[JU_A_2] = true;
            CLOSE_REG_SHIFT();
            JTU_PRESS(2);
          }
        } else {
          if(jtu_a_pressed_shift[JU_A_2]) {
            jtu_a_pressed_shift[JU_A_2] = false;
            JTU_RELEASE(2);
          }
          if(jtu_a_pressed_nshift[JU_A_2]) {
            jtu_a_pressed_nshift[JU_A_2] = false;
            JTU_RELEASE(2);
          }
        }
      }
      return false;

親指シフトを使わない時にキーボードから手を離さずIMEオンオフする方法

  • IME設定を変更する
    1. 以前のバージョンのMicrosoft IMEを使う
    2. 全般ー>変更
    3. Ctrl+0:IME-オン
    4. Ctrl+9:IME-オフ

AppleWatch GPSブイで潮流チェック♪

GPSブイの説明動画を作って見ました。 本来なら海で使うことを想定していますが、アップルさん本社付近でのテストになります

課題

  • 海の中で目印となる、GPSブイが欲しい

ニーズ

  • GPSを活用して、位置情報を記録できる機能が欲しい
  • 釣っている最中は釣り具以外何も持ちたくない

背景

釣行計画はスマートフォン

  • 釣りスポットの履歴をGPSで簡単に確認できることで、以前に釣った場所を特定しやすくなる。
  • 釣りスポットの情報を見ながら、新しい釣りスポットを開拓する楽しみが増す。
  • 潮の流れや季節の変化など環境情報をより正確に把握し、釣果向上につなげることができる。

現場まで航行は

GPS釣りスポット記録アプリを利用し目的地に行ける

船にGPS付き魚群探知機で目的地付近に行く

実釣

目印としてのGPSブイやマーキング装置を設定し、潮や風でどれだけ流れたか知りたい

ほしい機能

  • GPSブイの投入
    • ブイID、緯度経度記録
    • ○ブイIは3個
    • Xブイは3個
  • GPSブイからの距離計測
    • ○ブイから50m離れたら振動でお知ら
    • Xブイから50m以内に入ったら振動でお知らせ
  • ブイ使用履歴を作成
    • 記録は5個

最初の一歩 マップ表示  

import MapKit
struct ContentView: View {
      var body: some View {
         Map()
      }
}

   

場所指定

  • 緯度経度と表示エリアを設定
import SwiftUI
import MapKit
struct ContentView: View {
  var body: some View {
    //三重県南伊勢町五ケ所を指定
    @State  var region = MKCoordinateRegion(
      center : CLLocationCoordinate2D (
        latitude: 34.349// 緯度
        longitude: 136.697 // 経度
      ),
      latitudinalMeters: 500.0, // 南北の表示エリア(単位:メートル)
      longitudinalMeters: 500.0 // 東西の表示エリア(単位:メートル)
    )
    
    Map(coordinateRegion: $region)
  }
}

現在位置表示

  • 緯度経度取得 LocationManagerクラス作成
    • ググって、情報をまとめました。みなさんありがとうございます
import WatchKit
import MapKit

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    // CLLocationManagerをインスタンス化
    let manager = CLLocationManager()
    
    // 更新のたびに変化するので@Publishedを付与して観測
    @Published  var region =  MKCoordinateRegion()
    
    override init() {
        super.init()     // スーパクラスイニシャライズ
        manager.delegate = self     //自身をデリゲートプロパティに
        manager.requestWhenInUseAuthorization()  // 位置情報を利用許可を要求
        manager.desiredAccuracy = kCLLocationAccuracyBest   // 最高精度の位置情報を要求
        manager.distanceFilter = 3.0     // 更新距離(m)
        manager.startUpdatingLocation()  //現在位置アップデート生成開始
    }
    
    // 領域の更新をするデリゲートメソッド
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        // 配列の最後に最新のロケーションが格納される
        // map関数を使って全要素にアクセス map{ $0←要素に参照 }
        locations.last.map {
            let center = CLLocationCoordinate2D(
                latitude: $0.coordinate.latitude,
                longitude: $0.coordinate.longitude)
            
            // 地図を表示するための領域を再構築
            region = MKCoordinateRegion(
                center: center,
                latitudinalMeters: 100.0,
                longitudinalMeters: 100.0
            )
        }
    }
}
  • View改良
    • ググって、情報をまとめました。みなさんありがとうございます
import SwiftUI
import MapKit

struct ContentView: View {
    @ObservedObject  var manager = LocationManager()
    //ユーザートラッキングモードを追従モード変数 .follow ユーザーを追跡  .none ユーザーの追跡を停止
    @State  var trackingMode = MapUserTrackingMode.follow
    
 
 struct ContentView: View {
    @ObservedObject  var manager = LocationManager()
    @State  var trackingMode = MapUserTrackingMode.follow
    
    var body: some View {
        ZStack{
            Map(coordinateRegion: $manager.region,  //状態変数をバインディング指定
                showsUserLocation: true, // マップ上にユーザーの場所を表示するオプションをBool値で指定
                userTrackingMode: $trackingMode
            )
            .edgesIgnoringSafeArea(.bottom)
            .edgesIgnoringSafeArea(.top)
        }
    }
}

GPSブイ設置

  • 緯度経度取得 LocationManagerクラスに、記録機能追加
    func reloadRegion (bouyNo: Int){
        // オプショナルバインディング
        if let location = manager.location {
            
            let center = CLLocationCoordinate2D(
                latitude: location.coordinate.latitude,
                longitude: location.coordinate.longitude
            )

            if bouyNo == 0 || bouyNo == 1 || bouyNo == 2 {
                //GPSブイ投下を記録
                pointList[bouyNo] = Point(
                    name: "No.\(bouyNo + 1)",
                    latitude: location.coordinate.latitude ,
                    longitude: location.coordinate.longitude
                )
                region = MKCoordinateRegion(
                    center: center,
                    latitudinalMeters: 50.0,
                    longitudinalMeters: 50.0
                )
            } else {
                //ロケーションボタン
                region = MKCoordinateRegion(
                    center: center,
                    latitudinalMeters: 200.0,
                    longitudinalMeters: 200.0
                )
            }
        }
    }
  • View改良し
    • ブイ投下ボタン追加
    • ブイ番号表示
struct Point: Identifiable {
    let id = UUID()         //ユニークID
    let name: String
    let latitude: Double    // 緯度
    let longitude: Double   // 経度
    // 座標
    var coordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }
}

var pointList = [
    Point(name: "1", latitude: 35.709152712026265, longitude: 139.80771829999996),
    Point(name: "2", latitude: 35.711554715026265, longitude: 139.81371829999996),
    Point(name: "3", latitude: 35.712527719026265, longitude: 139.81071829999996)
]

struct ContentView: View {
    @ObservedObject  var manager = LocationManager()
    
    //ユーザートラッキングモードを追従モード変数 .follow ユーザーを追跡  .none ユーザーの追跡を停止
    @State  var trackingMode = MapUserTrackingMode.follow
    
    var body: some View {
        ZStack{
            Map(coordinateRegion: $manager.region,  //状態変数をバインディング指定
                showsUserLocation: true, //ユーザーの場所を表示するオプションをBool値で指定
                userTrackingMode: $trackingMode,
                annotationItems: pointList,
                annotationContent: { (pointList) in
                    MapAnnotation(coordinate: pointList.coordinate) {
                        VStack {
                            Image(systemName: "mappin")
                                .foregroundColor(.orange)
                                .font(.system(size: 20))
                            Text(pointList.name)
                                .foregroundColor(.orange)
                                .font(.system(size: 12))
                        }
                    }
                }
            )
            .edgesIgnoringSafeArea(.all)
            .edgesIgnoringSafeArea(.bottom)
            .edgesIgnoringSafeArea(.top)
            VStack{
                Spacer()
                HStack{
                     Button(action: {
                        manager.reloadRegion(bouyNo: 0)
                    }) {
                        Image(systemName: "mappin.circle.fill")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                        Text("1")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                    }
                    .frame(width: 41, height: 25)
                    .cornerRadius(30.0)
                    
                    Button(action: {
                        manager.reloadRegion(bouyNo: 1)
                    }) {
                        Image(systemName: "mappin.circle.fill")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                        Text("2")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                    }
                    .frame(width: 41, height: 25)
                    .cornerRadius(30.0)
                    
                    Button(action: {
                        manager.reloadRegion(bouyNo: 2)
                    }) {
                        Image(systemName: "mappin.circle.fill")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                        Text("3")
                            .foregroundColor(.white)
                            .font(.system(size: 12))
                    }
                    .frame(width: 41, height: 25)
                    .cornerRadius(30.0)
                    
                    
                    Button(action: {
                        manager.reloadRegion(bouyNo: 3)
                    }) {
                        Image(systemName: "location.fill")
                            .foregroundColor(.white)
                            .font(.system(size: 16))
                    }
                    .frame(width: 32, height: 25)
                    .cornerRadius(30.0)
                    
                }
                .background(Color(red: 0.4, green: 0.5, blue: 0.2))   //背景色
                .cornerRadius(30.0)
            }
        }
    }
}
  • 出来たもの
    • ボタン群、左から
      • GPSブイNo.1 投下ボタン
      • GPSブイNo.2 投下ボタン
      • GPSブイNo.3 投下ボタン
      • 現在位置にマップを移動
    • ブイ投下すると、ブイマークとナンバーが表示

      

GPSブイとの距離

  • 距離の計算方法は、Hubenyの公式を採用します
    • 主に日本の計算サイトなどで用いられている公式で,これもざっくり下図を用いて説明すると,まず,2地点A,Bの中点Rにおける回転楕円体の子午線方向と卯酉線方向のそれぞれの曲がり具合を円で近似します.次に2地点A,Bの経度差をΔx,緯度差をΔyとし,回転楕円体の近似円の子午線方向の曲率半径をM,卯酉線方向の曲率半径をNとします.点Aと経度が等しく,点Bと緯度が等しい点Hをつくって直角三角形をつくります.角AOH=Δyと書けるのでAH≒MΔyと近似でき,Rの緯度をμとすると線分BHもBH≒NcosμΔxと近似できます.この線分AHと線分BHを利用して求める距離である線分ABを3平方の定理で導きます
    • 下記C言語プログラムをSwift言語に書き換え、GPSブイNo.1との距離を表示します。単位はメートルとします
func deg2rad(_ deg:CGFloat ) -> CGFloat {
    return CGFloat.pi / 180.0 * deg
}

func cal_distance(x1: Double, y1: Double, x2: Double, y2: Double)->(Double) {
    let dx = x2 - x1
    let dy = y2 - y1
    let mu = (y1 + y2) / 2.0 // μ
    let RX = 6378.137; // 回転楕円体の長半径(赤道半径)[km]
    let RY = 6356.752; // 回転楕円体の短半径(極半径) [km]
    let E = sqrt(1 - pow(RY / RX, 2.0)) // 離心率
    let W = sqrt(1 - pow(E * sin(mu), 2.0))
    let M = RX * (1 - pow(E, 2.0)) / pow(W, 3.0) // 子午線曲率半径
    let N = RX / W // 卯酉線曲率半径
    return sqrt(pow(M * dy, 2.0) + pow(N * dx * cos(mu), 2.0)) // 距離[km]
}

    func locationDistance() -> Int {
        if let location = manager.location {
            let a = deg2rad( pointList[0].latitude )
            let b = deg2rad( pointList[0].longitude )
            let c = deg2rad( location.coordinate.latitude )
            let d = deg2rad( location.coordinate.longitude )
            let e = Int( cal_distance(x1: a, y1: b, x2: c, y2: d) * 1000.0 ) % 10000
            return( e )

        }else{
            return( 0 )
        }
    }
 
  • 表示
    • 4桁のメートルとしています
    • 「Off」にすると、拡大、縮小、移動が自由に出来ます。「On」場合は縮率が600mでGPSで測定した位置が画面中心になります

    • 下ボタン群、左から

      • GPSブイNo.1 投下ボタン
      • GPSブイNo.2 投下ボタン
      • GPSブイNo.3 投下ボタン
      • 現在位置にマップを移動 ー> 拡大鏡に変更

GPSの動きを手動で止める

  • AppleWatchの「設定」>「ブライバシーとセキュリティー」>「位置情報サービス」>「gpsBuoy」>「しない」とする
  • 止まって、地図が表示されなくなる

  • どなたか、プログラムを使った止めかたをご教授して頂けると幸いです

AppleWatch GPSブイで潮流チェック♪ 【開発経過】

課題

  • 海の中で目印となる、GPSブイが欲しい

ニーズ

  • GPSを活用して、位置情報を記録できる機能が欲しい
  • 釣っている最中は釣り具以外何も持ちたくない

背景

釣行計画はスマートフォン

  • 釣りスポットの履歴をGPSで簡単に確認できることで、以前に釣った場所を特定しやすくなる。
  • 釣りスポットの情報を見ながら、新しい釣りスポットを開拓する楽しみが増す。
  • 潮の流れや季節の変化など環境情報をより正確に把握し、釣果向上につなげることができる。

現場まで航行は

GPS釣りスポット記録アプリの利用し目的地に行ける

船にGPS付き魚群探知機があれば便利

実釣

目印としてのGPSブイやマーキング装置を設定し、潮でどれだけ流れたか知りたい

 

ほしい機能

  • GPSブイの投入
    • ブイID、緯度経度記録
    • ○ブイIは3個
    • Xブイは3個
  • GPSブイからの距離計測
    • ○ブイから50m離れたら振動でお知ら
    • Xブイから50m以内に入ったら振動でお知らせ
  • ブイ使用履歴を作成
    • 記録は5個
    •  

最初の一歩 マップ表示  

  • >|Swift|
  • import SwiftUI

    import MapKit

  • struct ContentView: View {

      var body: some View {

         Map()

      }

    }

  • ||<

  


場所指定

  • 緯度経度と表示エリアを設定

>|Swift|

import SwiftUI

import MapKit

struct ContentView: View {

  var body: some View {

    //三重県南伊勢町五ケ所を指定

    @State  var region = MKCoordinateRegion(

      center : CLLocationCoordinate2D (

        latitude: 34.349,  // 緯度

        longitude: 136.697 // 経度

      ),

      latitudinalMeters: 500.0, // 南北の表示エリア(単位:メートル)

      longitudinalMeters: 500.0 // 東西の表示エリア(単位:メートル)

    )

    

    Map(coordinateRegion: $region)

  }

}

||<

 

現在位置表示

  • 緯度経度取得 LocationManagerクラス作成
    • ググって、情報をまとめました。みなさんありがとうございます

>|Swift|

import WatchKit

import MapKit

 

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {

    // CLLocationManagerをインスタンス

    let manager = CLLocationManager()

    

    // 更新のたびに変化するので@Publishedを付与して観測

    @Published  var region =  MKCoordinateRegion()

    

    

    override init() {

        super.init()                                        // スーパクラスイニシャライズ

        manager.delegate = self                             //自身をデリゲートプロパティに

        manager.requestWhenInUseAuthorization()             // 位置情報を利用許可を要求

        manager.desiredAccuracy = kCLLocationAccuracyBest   // 最高精度の位置情報を要求

        manager.distanceFilter = 3.0                        // 更新距離(m)

        manager.startUpdatingLocation()                    //現在位置アップデート生成開始

    }

    

    // 領域の更新をするデリゲートメソッド

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        

        // 配列の最後に最新のロケーションが格納される

        // map関数を使って全要素にアクセス map{ $0←要素に参照 }

        locations.last.map {

            let center = CLLocationCoordinate2D(

                latitude: $0.coordinate.latitude,

                longitude: $0.coordinate.longitude)

            

            // 地図を表示するための領域を再構築

            region = MKCoordinateRegion(

                center: center,

                latitudinalMeters: 100.0,

                longitudinalMeters: 100.0

            )

        }

    }

}

||<

  • View改良
    • ググって、情報をまとめました。みなさんありがとうございます

>|Swift|

import SwiftUI

import MapKit

 

struct ContentView: View {

    @ObservedObject  var manager = LocationManager()

    

    //ユーザートラッキングモードを追従モード変数 .follow ユーザーを追跡  .none ユーザーの追跡を停止

    @State  var trackingMode = MapUserTrackingMode.follow

    

 

 struct ContentView: View {

    @ObservedObject  var manager = LocationManager()

    

    //ユーザートラッキングモードを追従モード変数 .follow ユーザーを追跡  .none ユーザーの追跡を停止

    @State  var trackingMode = MapUserTrackingMode.follow

    

    var body: some View {

        ZStack{

            Map(coordinateRegion: $manager.region,  //状態変数をバインディング指定

                showsUserLocation: true, // マップ上にユーザーの場所を表示するオプションをBool値で指定

                userTrackingMode: $trackingMode

            )

            .edgesIgnoringSafeArea(.bottom)

            .edgesIgnoringSafeArea(.top)

        }

    }

}

  • ||<

GPSブイ設置

  • 緯度経度取得 LocationManagerクラスに、記録機能追加

>|Swift|

    func reloadRegion (bouyNo: Int){

        // オプショナルバインディング

        if let location = manager.location {

            

            let center = CLLocationCoordinate2D(

                latitude: location.coordinate.latitude,

                longitude: location.coordinate.longitude

            )

 

            if bouyNo == 0 || bouyNo == 1 || bouyNo == 2 {

                //GPSブイ投下を記録

                pointList[bouyNo] = Point(

                    name: "No.\(bouyNo + 1)",

                    latitude: location.coordinate.latitude ,

                    longitude: location.coordinate.longitude

                )

                region = MKCoordinateRegion(

                    center: center,

                    latitudinalMeters: 50.0,

                    longitudinalMeters: 50.0

                )

            } else {

                //ロケーションボタン

                region = MKCoordinateRegion(

                    center: center,

                    latitudinalMeters: 200.0,

                    longitudinalMeters: 200.0

                )

            }

        }

    }

||<

  • View改良し
    • ブイ投下ボタン追加
    • ブイ番号表示

>|Swift|

struct Point: Identifiable {

    let id = UUID()         //ユニークID

    let name: String

    let latitude: Double    // 緯度

    let longitude: Double   // 経度

    // 座標

    var coordinate: CLLocationCoordinate2D {

        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

    }

}

 

var pointList = [

    Point(name: "1", latitude: 35.709152712026265, longitude: 139.80771829999996),

    Point(name: "2", latitude: 35.711554715026265, longitude: 139.81371829999996),

    Point(name: "3", latitude: 35.712527719026265, longitude: 139.81071829999996)

]

 

struct ContentView: View {

    @ObservedObject  var manager = LocationManager()

    

    //ユーザートラッキングモードを追従モード変数 .follow ユーザーを追跡  .none ユーザーの追跡を停止

    @State  var trackingMode = MapUserTrackingMode.follow

    

    var body: some View {

        ZStack{

            Map(coordinateRegion: $manager.region,  //状態変数をバインディング指定

                showsUserLocation: true, //ユーザーの場所を表示するオプションをBool値で指定

                userTrackingMode: $trackingMode,

                annotationItems: pointList,

                annotationContent: { (pointList) in

                    MapAnnotation(coordinate: pointList.coordinate) {

                        VStack {

                            Image(systemName: "mappin")

                                .foregroundColor(.orange)

                                .font(.system(size: 20))

                            Text(pointList.name)

                                .foregroundColor(.orange)

                                .font(.system(size: 12))

                        }

                    }

                }

            )

            .edgesIgnoringSafeArea(.all)

            .edgesIgnoringSafeArea(.bottom)

            .edgesIgnoringSafeArea(.top)

            VStack{

                Spacer()

                HStack{

                     Button(action: {

                        manager.reloadRegion(bouyNo: 0)

                    }) {

                        Image(systemName: "mappin.circle.fill")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                        Text("1")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                    }

                    .frame(width: 41, height: 25)

                    .cornerRadius(30.0)

                    

                    Button(action: {

                        manager.reloadRegion(bouyNo: 1)

                    }) {

                        Image(systemName: "mappin.circle.fill")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                        Text("2")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                    }

                    .frame(width: 41, height: 25)

                    .cornerRadius(30.0)

                    

                    Button(action: {

                        manager.reloadRegion(bouyNo: 2)

                    }) {

                        Image(systemName: "mappin.circle.fill")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                        Text("3")

                            .foregroundColor(.white)

                            .font(.system(size: 12))

                    }

                    .frame(width: 41, height: 25)

                    .cornerRadius(30.0)

                    

                    

                    Button(action: {

                        manager.reloadRegion(bouyNo: 3)

                    }) {

                        Image(systemName: "location.fill")

                            .foregroundColor(.white)

                            .font(.system(size: 16))

                    }

                    .frame(width: 32, height: 25)

                    .cornerRadius(30.0)

                    

                }

                .background(Color(red: 0.4, green: 0.5, blue: 0.2))   //背景色

                .cornerRadius(30.0)

            }

        }

    }

}

||<

  • 出来たもの
    • ボタン群、左から
      • GPSブイNo.1 投下ボタン
      • GPSブイNo.2 投下ボタン
      • GPSブイNo.3 投下ボタン
      • 現在位置にマップを移動
    • ブイ投下すると、ブイマークとナンバーが表示

      

    • 動画は下記を参照

GPSブイとの距離

  • 次回、記載します

 

 

 

 

 

 

`