Skip to content

Commit

Permalink
マウスカーソル位置のメッシュコードを表示するパネル
Browse files Browse the repository at this point in the history
  • Loading branch information
ciscorn committed Jul 20, 2024
1 parent 24e5ea4 commit de30fbb
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 41 deletions.
66 changes: 65 additions & 1 deletion japanese_grids/algorithms/utils/gridsquare_to_box.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from typing import Optional, Tuple
from typing import Optional, Tuple, TypedDict

from .grid_square import AVAILABLE_PRIMARY_CODES

_VALID_LENGTH = (4, 6, 8, 9, 10, 11)
_VALID_QUAD = ("1", "2", "3", "4")

LngLatBox = Tuple[float, float, float, float]

_MULTIPLIER = 30 # 浮動小数点誤差を回避するために内部的な経緯度にかける係数


def grid_square_code_to_bbox( # noqa: C901
code: str,
Expand Down Expand Up @@ -77,3 +81,63 @@ def grid_square_code_to_bbox( # noqa: C901
lat2 = lat + (lat10 + 0.015625) / 10
lng2 = lng + (lng10 + 0.015625) / 10
return (lng1, lat1 / 1.5, lng2, lat2 / 1.5)


class Codes(TypedDict):
primary: str
secondary: str
standard: str
half: str
quarter: str
eighth: str


def lnglat_to_grid_square_code(lng: float, lat: float) -> Optional[Codes]:
lat *= 1.5
lat_r = int(lat)
lng_r = int(lng)
primary_code = f"{lat_r:02d}{lng_r-100:02d}"
if primary_code not in AVAILABLE_PRIMARY_CODES:
return None

lat = (lat - lat_r) * 8
lng = (lng - lng_r) * 8
lat_r = int(lat)
lng_r = int(lng)
secondary_code = primary_code + f"{lat_r}{lng_r}"

lat = (lat - lat_r) * 10
lng = (lng - lng_r) * 10
lat_r = int(lat)
lng_r = int(lng)
standard_code = secondary_code + f"{lat_r}{lng_r}"

lat = (lat - lat_r) * 2
lng = (lng - lng_r) * 2
lat_r = int(lat)
lng_r = int(lng)
suffix = 1 + lat_r * 2 + lng_r
half_code = standard_code + str(suffix)

lat = (lat - lat_r) * 2
lng = (lng - lng_r) * 2
lat_r = int(lat)
lng_r = int(lng)
suffix = 1 + lat_r * 2 + lng_r
quarter_code = half_code + str(suffix)

lat = (lat - lat_r) * 2
lng = (lng - lng_r) * 2
lat_r = int(lat)
lng_r = int(lng)
suffix = 1 + lat_r * 2 + lng_r
eighth_code = quarter_code + str(suffix)

return {
"primary": primary_code,
"secondary": secondary_code,
"standard": standard_code,
"half": half_code,
"quarter": quarter_code,
"eighth": eighth_code,
}
114 changes: 114 additions & 0 deletions japanese_grids/panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""Coordinate Panel"""

# Copyright (C) 2023 MIERUNE Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import re
from typing import Callable

from qgis.core import QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject
from qgis.gui import QgisInterface, QgsMapMouseEvent, QgsMapTool
from qgis.PyQt.QtCore import Qt, QTimer
from qgis.PyQt.QtWidgets import (
QDockWidget,
QHBoxLayout,
QLabel,
QLineEdit,
QVBoxLayout,
QWidget,
)

from japanese_grids.algorithms.utils.gridsquare_to_box import lnglat_to_grid_square_code


class MapMouseMoveTool(QgsMapTool):
def __init__(self, canvas, callback: Callable[[float, float], None]):
super().__init__(canvas)
self._canvas = canvas
self._callback = callback
self._pressed = False

def canvasPressEvent(self, event: QgsMapMouseEvent):
self._pressed = True

def canvasReleaseEvent(self, event: QgsMapMouseEvent):
self._pressed = False

def canvasMoveEvent(self, event: QgsMapMouseEvent):
if not self._pressed:
point = self.toMapCoordinates(event.pos())
self._callback(point.x(), point.y())


class CoordinatePanel:
def __init__(self, iface: QgisInterface):
self._iface = iface
self._setup()
self._current_coord = None

def _handle_mousemove(self, x: float, y: float):
canvas = self._iface.mapCanvas()
source_crs = canvas.mapSettings().destinationCrs()
dest_crs = QgsCoordinateReferenceSystem(4326) # WGS 84
transform = QgsCoordinateTransform(source_crs, dest_crs, QgsProject.instance())
geog_point = transform.transform(x, y)
self._current_coord = geog_point

(geog_lng, geog_lat) = (self._current_coord.x(), self._current_coord.y())
self._coordinate_label.setText(f"緯度: {geog_lat:.5f}°, 経度: {geog_lng:.5f}°")
if code := lnglat_to_grid_square_code(geog_lng, geog_lat):
if m := re.match(r"(\d{4})(\d{4})(\d)(\d)(\d)", code["eighth"]):
self._line_edit.setText(
f"{m.group(1)}-{m.group(2)}-{m.group(3)}-{m.group(4)}-{m.group(5)}"
)
else:
self._line_edit.setText("-")

def _setup(self):
self._dock_widget = QDockWidget("地域メッシュコード", self._iface.mainWindow())

self._coordinate_label = QLabel("緯度: -.-°, 経度: -.-°")
layout = QVBoxLayout()
layout.addWidget(self._coordinate_label)

self._line_edit = QLineEdit()

self._line_edit.focusInEvent = lambda a0: QTimer.singleShot(
1, self._line_edit.selectAll
)

h_layout = QHBoxLayout()
h_layout.addWidget(QLabel("コード:"))
h_layout.addWidget(self._line_edit)
layout.addLayout(h_layout)

container = QWidget()
container.setLayout(layout)
container.setMaximumHeight(layout.totalSizeHint().height())
self._dock_widget.setWidget(container)

self._iface.addDockWidget(Qt.RightDockWidgetArea, self._dock_widget)

canvas = self._iface.mapCanvas()
self._maptool = MapMouseMoveTool(
self._iface.mapCanvas(), self._handle_mousemove
)
canvas.setMapTool(self._maptool)

def teardown(self):
self._iface.removeDockWidget(self._dock_widget)
del self._dock_widget
del self._maptool
92 changes: 52 additions & 40 deletions japanese_grids/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from qgis.core import QgsApplication
from qgis.gui import QgisInterface

from .panel import CoordinatePanel
from .provider import JapanMeshProcessingProvider

with contextlib.suppress(ImportError):
Expand All @@ -39,47 +40,58 @@ def initGui(self):
QgsApplication.processingRegistry().addProvider(self.provider)

if self.iface:
# Add a button on the toolbar
tool_button = QToolButton()
icon = self.provider.icon()
default_action = QAction(
icon, "地域メッシュを作成", self.iface.mainWindow()
)
default_action.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:creategridsquare", {})
)
tool_button.setDefaultAction(default_action)

# ToolButton Menu
menu = QMenu()
tool_button.setMenu(menu)
tool_button.setPopupMode(QToolButton.MenuButtonPopup)

action_grid_square = QAction(
icon, "地域メッシュを作成", self.iface.mainWindow()
)
action_grid_square.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:creategridsquare", {})
)
menu.addAction(action_grid_square)

action_legacy = QAction(icon, "国土基本図郭を作成", self.iface.mainWindow())
action_legacy.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:createlegacygrid", {})
)
menu.addAction(action_legacy)

action_estat = QAction(
icon, "地域メッシュ統計を読み込む", self.iface.mainWindow()
)
action_estat.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:loadestatgridstats", {})
)
menu.addAction(action_estat)

self.toolButtonAction = self.iface.addToolBarWidget(tool_button)
self.setup_algorithms_tool_button()
self._coord_panel = CoordinatePanel(self.iface)

def unload(self):
if self.iface:
self.iface.removeToolBarIcon(self.toolButtonAction)
self.teardown_algorithms_tool_button()
self._coord_panel.teardown()

QgsApplication.processingRegistry().removeProvider(self.provider)

def setup_algorithms_tool_button(self):
"""ツールバー上にアルゴリズムの呼び出しボタンを追加する"""

# Add a button on the toolbar
tool_button = QToolButton()
icon = self.provider.icon()
default_action = QAction(icon, "地域メッシュを作成", self.iface.mainWindow())
default_action.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:creategridsquare", {})
)
tool_button.setDefaultAction(default_action)

# ToolButton Menu
menu = QMenu()
tool_button.setMenu(menu)
tool_button.setPopupMode(QToolButton.MenuButtonPopup)

action_grid_square = QAction(
icon, "地域メッシュを作成", self.iface.mainWindow()
)
action_grid_square.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:creategridsquare", {})
)
menu.addAction(action_grid_square)

action_legacy = QAction(icon, "国土基本図郭を作成", self.iface.mainWindow())
action_legacy.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:createlegacygrid", {})
)
menu.addAction(action_legacy)

action_estat = QAction(
icon, "地域メッシュ統計を読み込む", self.iface.mainWindow()
)
action_estat.triggered.connect(
lambda: execAlgorithmDialog("japanesegrid:loadestatgridstats", {})
)
menu.addAction(action_estat)

self.toolButtonAction = self.iface.addToolBarWidget(tool_button)

def teardown_algorithms_tool_button(self):
"""ツールバー上のアルゴリズムの呼び出しボタンを削除する"""

self.iface.removeToolBarIcon(self.toolButtonAction)

0 comments on commit de30fbb

Please sign in to comment.