Commit 95aff94d authored by shigemi miura's avatar shigemi miura

NGA対応

parent 7f096f00
......@@ -62,12 +62,9 @@
02C3E5D12AFCC16800AF7837 /* ChatTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C3E5D02AFCC16800AF7837 /* ChatTitleView.swift */; };
02C3E6092AFDF30000AF7837 /* ChatMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C3E6082AFDF30000AF7837 /* ChatMemberView.swift */; };
02CD068F2AE6535F005F8D8F /* MapSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CD068E2AE6535F005F8D8F /* MapSource.swift */; };
02CD06912AE6536B005F8D8F /* LayerEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CD06902AE6536B005F8D8F /* LayerEnum.swift */; };
02CD06932AE88970005F8D8F /* ServerSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CD06922AE88970005F8D8F /* ServerSession.swift */; };
02CD06952AE895F5005F8D8F /* APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CD06942AE895F5005F8D8F /* APIError.swift */; };
02CE4D7F2ADE42A9002E79BC /* MenuContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4D7E2ADE42A9002E79BC /* MenuContentView.swift */; };
02CE4D832ADE672B002E79BC /* MapTaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4D822ADE672B002E79BC /* MapTaskView.swift */; };
02CE4D852ADF6295002E79BC /* TaskSwitchingMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4D842ADF6295002E79BC /* TaskSwitchingMenuView.swift */; };
02CE4D872ADF62A7002E79BC /* EcaListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4D862ADF62A7002E79BC /* EcaListView.swift */; };
02CE4D892ADF62E1002E79BC /* EcaSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4D882ADF62E1002E79BC /* EcaSettingView.swift */; };
02CE4DC82ADF97E8002E79BC /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CE4DC72ADF97E8002E79BC /* View+Extensions.swift */; };
......@@ -92,17 +89,21 @@
D52D213F2AEBB7D700324D58 /* RegisteredEca.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52D213E2AEBB7D700324D58 /* RegisteredEca.swift */; };
D52D21412AEDE18F00324D58 /* EcaCoordinatesTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52D21402AEDE18F00324D58 /* EcaCoordinatesTable.swift */; };
D536F6712B678D8900A5BCF9 /* ReqUploadImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D536F6702B678D8900A5BCF9 /* ReqUploadImage.swift */; };
D5384AFC2B306CEF006228C6 /* TermsView.html in Resources */ = {isa = PBXBuildFile; fileRef = D5384AFB2B306CEF006228C6 /* TermsView.html */; };
D5384AFE2B3121F2006228C6 /* PrivacyView.html in Resources */ = {isa = PBXBuildFile; fileRef = D5384AFD2B3121F2006228C6 /* PrivacyView.html */; };
D539F3302C1809790088E609 /* NgaTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = D539F32F2C1809790088E609 /* NgaTask.swift */; };
D53B97262B341867000B3D29 /* AboutAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53B97252B341867000B3D29 /* AboutAppView.swift */; };
D545FC742B09C74300F206D0 /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D545FC732B09C74300F206D0 /* AlertManager.swift */; };
D545FC762B09C81300F206D0 /* PushNotificationTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D545FC752B09C81300F206D0 /* PushNotificationTypes.swift */; };
D546B0132C197BB50058CD98 /* MapInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D546B0122C197BB50058CD98 /* MapInformation.swift */; };
D54A5FD72B8F10B500F3A9D6 /* StatusEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54A5FD62B8F10B500F3A9D6 /* StatusEnum.swift */; };
D54D174B2B35137A00A0EAA5 /* LocalWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54D174A2B35137A00A0EAA5 /* LocalWebView.swift */; };
D54D17512B35923400A0EAA5 /* GetManualUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54D17502B35923400A0EAA5 /* GetManualUrl.swift */; };
D55135202B15B030007B66B1 /* SetEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D551351F2B15B030007B66B1 /* SetEcaArea.swift */; };
D55135222B15C062007B66B1 /* GetEcaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55135212B15C062007B66B1 /* GetEcaList.swift */; };
D55135242B15C3BF007B66B1 /* DeleteEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55135232B15C3BF007B66B1 /* DeleteEcaArea.swift */; };
D57905FE2C1C069000AF797C /* SetNgaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57905FD2C1C069000AF797C /* SetNgaArea.swift */; };
D57906002C1C06F600AF797C /* SessionNgaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57905FF2C1C06F600AF797C /* SessionNgaList.swift */; };
D57906022C1C0CFB00AF797C /* ReqNgaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57906012C1C0CFB00AF797C /* ReqNgaList.swift */; };
D58E06D02C1D1AF20039F22C /* GetNgaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E06CF2C1D1AF20039F22C /* GetNgaList.swift */; };
D58E1F502B142A260092D8FE /* EcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1F4F2B142A260092D8FE /* EcaArea.swift */; };
D58E1F522B142A3F0092D8FE /* ResEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1F512B142A3F0092D8FE /* ResEcaArea.swift */; };
D58E1F542B142A510092D8FE /* SessionEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1F532B142A510092D8FE /* SessionEcaArea.swift */; };
......@@ -124,6 +125,12 @@
D5B493A12B48E930008B3620 /* privacy.html in Resources */ = {isa = PBXBuildFile; fileRef = D5B4939F2B48E930008B3620 /* privacy.html */; };
D5B493A42B48EE50008B3620 /* Manual in Resources */ = {isa = PBXBuildFile; fileRef = D5B493A32B48EE50008B3620 /* Manual */; };
D5B803282B3B988E003B32AD /* AppVersionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B803272B3B988E003B32AD /* AppVersionModel.swift */; };
D5C7822F2BF88755001EBB3A /* MenuTaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C7822E2BF88755001EBB3A /* MenuTaskView.swift */; };
D5C7823A2BFB4C2A001EBB3A /* NgaNotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C782392BFB4C2A001EBB3A /* NgaNotificationView.swift */; };
D5C7823C2BFB4CEF001EBB3A /* FuelSwitchingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C7823B2BFB4CEF001EBB3A /* FuelSwitchingView.swift */; };
D5C782462BFB55F0001EBB3A /* DeleteNgaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C782432BFB55F0001EBB3A /* DeleteNgaArea.swift */; };
D5C782472BFB55F0001EBB3A /* RegistereNga.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C782442BFB55F0001EBB3A /* RegistereNga.swift */; };
D5C782492BFC2DA2001EBB3A /* NgaSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C782482BFC2DA2001EBB3A /* NgaSettingView.swift */; };
D5CB6F992B02088C00EC2010 /* ResShipStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CB6F982B02088C00EC2010 /* ResShipStatus.swift */; };
D5CB6F9B2B021C4F00EC2010 /* LocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CB6F9A2B021C4F00EC2010 /* LocationViewModel.swift */; };
D5CB6F9F2B0220A700EC2010 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CB6F9E2B0220A700EC2010 /* ErrorView.swift */; };
......@@ -227,12 +234,9 @@
02C3E5D02AFCC16800AF7837 /* ChatTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ChatTitleView.swift; path = SailAssist/Chat/View/ChatTitleView.swift; sourceTree = SOURCE_ROOT; };
02C3E6082AFDF30000AF7837 /* ChatMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ChatMemberView.swift; path = Sailassist/Chat/View/ChatMemberView.swift; sourceTree = SOURCE_ROOT; };
02CD068E2AE6535F005F8D8F /* MapSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapSource.swift; sourceTree = "<group>"; };
02CD06902AE6536B005F8D8F /* LayerEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayerEnum.swift; sourceTree = "<group>"; };
02CD06922AE88970005F8D8F /* ServerSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSession.swift; sourceTree = "<group>"; };
02CD06942AE895F5005F8D8F /* APIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIError.swift; sourceTree = "<group>"; };
02CE4D7E2ADE42A9002E79BC /* MenuContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuContentView.swift; sourceTree = "<group>"; };
02CE4D822ADE672B002E79BC /* MapTaskView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTaskView.swift; sourceTree = "<group>"; };
02CE4D842ADF6295002E79BC /* TaskSwitchingMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskSwitchingMenuView.swift; sourceTree = "<group>"; };
02CE4D862ADF62A7002E79BC /* EcaListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcaListView.swift; sourceTree = "<group>"; };
02CE4D882ADF62E1002E79BC /* EcaSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcaSettingView.swift; sourceTree = "<group>"; };
02CE4DC72ADF97E8002E79BC /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
......@@ -265,18 +269,22 @@
D52D213E2AEBB7D700324D58 /* RegisteredEca.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RegisteredEca.swift; path = Sailassist/ECA/RegisteredEca.swift; sourceTree = SOURCE_ROOT; };
D52D21402AEDE18F00324D58 /* EcaCoordinatesTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = EcaCoordinatesTable.swift; path = Sailassist/ECA/EcaCoordinatesTable.swift; sourceTree = SOURCE_ROOT; };
D536F6702B678D8900A5BCF9 /* ReqUploadImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ReqUploadImage.swift; path = Sailassist/Json/ReqUploadImage.swift; sourceTree = SOURCE_ROOT; };
D5384AFB2B306CEF006228C6 /* TermsView.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = TermsView.html; path = SailAssist/html/TermsView.html; sourceTree = SOURCE_ROOT; };
D5384AFD2B3121F2006228C6 /* PrivacyView.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = PrivacyView.html; path = SailAssist/html/PrivacyView.html; sourceTree = SOURCE_ROOT; };
D539F32F2C1809790088E609 /* NgaTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NgaTask.swift; sourceTree = "<group>"; };
D53ACA752B0AECF8008DCB18 /* Sailassist.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Sailassist.entitlements; path = Sailassist/Sailassist.entitlements; sourceTree = "<group>"; };
D53B97252B341867000B3D29 /* AboutAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AboutAppView.swift; path = Sailassist/Login/AboutAppView.swift; sourceTree = SOURCE_ROOT; };
D545FC732B09C74300F206D0 /* AlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AlertManager.swift; path = Sailassist/VoiceManager/AlertManager.swift; sourceTree = SOURCE_ROOT; };
D545FC752B09C81300F206D0 /* PushNotificationTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PushNotificationTypes.swift; path = Sailassist/DataSource/PushNotificationTypes.swift; sourceTree = SOURCE_ROOT; };
D546B0122C197BB50058CD98 /* MapInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MapInformation.swift; path = Sailassist/Map/MapInformation.swift; sourceTree = SOURCE_ROOT; };
D54A5FD62B8F10B500F3A9D6 /* StatusEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StatusEnum.swift; path = Sailassist/SharingData/StatusEnum.swift; sourceTree = SOURCE_ROOT; };
D54D174A2B35137A00A0EAA5 /* LocalWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LocalWebView.swift; path = Sailassist/Menu/View/LocalWebView.swift; sourceTree = SOURCE_ROOT; };
D54D17502B35923400A0EAA5 /* GetManualUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetManualUrl.swift; path = Sailassist/Menu/GetManualUrl.swift; sourceTree = SOURCE_ROOT; };
D551351F2B15B030007B66B1 /* SetEcaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetEcaArea.swift; path = Sailassist/ECA/SetEcaArea.swift; sourceTree = SOURCE_ROOT; };
D55135212B15C062007B66B1 /* GetEcaList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetEcaList.swift; path = Sailassist/ECA/GetEcaList.swift; sourceTree = SOURCE_ROOT; };
D55135232B15C3BF007B66B1 /* DeleteEcaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeleteEcaArea.swift; path = Sailassist/ECA/DeleteEcaArea.swift; sourceTree = SOURCE_ROOT; };
D57905FD2C1C069000AF797C /* SetNgaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetNgaArea.swift; sourceTree = "<group>"; };
D57905FF2C1C06F600AF797C /* SessionNgaList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionNgaList.swift; path = Sailassist/ServerSession/SessionNgaList.swift; sourceTree = SOURCE_ROOT; };
D57906012C1C0CFB00AF797C /* ReqNgaList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ReqNgaList.swift; path = Sailassist/Json/ReqNgaList.swift; sourceTree = SOURCE_ROOT; };
D58E06CF2C1D1AF20039F22C /* GetNgaList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNgaList.swift; sourceTree = "<group>"; };
D58E1F4F2B142A260092D8FE /* EcaArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EcaArea.swift; path = Sailassist/ECA/EcaArea.swift; sourceTree = SOURCE_ROOT; };
D58E1F512B142A3F0092D8FE /* ResEcaArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ResEcaArea.swift; path = Sailassist/Json/ResEcaArea.swift; sourceTree = SOURCE_ROOT; };
D58E1F532B142A510092D8FE /* SessionEcaArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SessionEcaArea.swift; path = Sailassist/ServerSession/SessionEcaArea.swift; sourceTree = SOURCE_ROOT; };
......@@ -298,6 +306,12 @@
D5B4939F2B48E930008B3620 /* privacy.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = privacy.html; path = Sailassist/html/privacy.html; sourceTree = SOURCE_ROOT; };
D5B493A32B48EE50008B3620 /* Manual */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Manual; path = Sailassist/html/Manual; sourceTree = SOURCE_ROOT; };
D5B803272B3B988E003B32AD /* AppVersionModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppVersionModel.swift; path = Sailassist/AppVersionModel.swift; sourceTree = SOURCE_ROOT; };
D5C7822E2BF88755001EBB3A /* MenuTaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MenuTaskView.swift; path = Sailassist/Map/Task/View/MenuTaskView.swift; sourceTree = SOURCE_ROOT; };
D5C782392BFB4C2A001EBB3A /* NgaNotificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NgaNotificationView.swift; path = Sailassist/Map/Task/View/NgaNotificationView.swift; sourceTree = SOURCE_ROOT; };
D5C7823B2BFB4CEF001EBB3A /* FuelSwitchingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FuelSwitchingView.swift; path = Sailassist/Map/Task/View/FuelSwitchingView.swift; sourceTree = SOURCE_ROOT; };
D5C782432BFB55F0001EBB3A /* DeleteNgaArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteNgaArea.swift; sourceTree = "<group>"; };
D5C782442BFB55F0001EBB3A /* RegistereNga.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegistereNga.swift; sourceTree = "<group>"; };
D5C782482BFC2DA2001EBB3A /* NgaSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NgaSettingView.swift; path = Sailassist/Map/Task/View/NgaSettingView.swift; sourceTree = SOURCE_ROOT; };
D5CB6F982B02088C00EC2010 /* ResShipStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ResShipStatus.swift; path = Sailassist/Json/ResShipStatus.swift; sourceTree = SOURCE_ROOT; };
D5CB6F9A2B021C4F00EC2010 /* LocationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LocationViewModel.swift; path = Sailassist/LocationViewModel.swift; sourceTree = SOURCE_ROOT; };
D5CB6F9E2B0220A700EC2010 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ErrorView.swift; path = Sailassist/ErrorView.swift; sourceTree = SOURCE_ROOT; };
......@@ -371,6 +385,7 @@
020B98122AD8C3140029DE4C /* SailAssist */ = {
isa = PBXGroup;
children = (
D5C782452BFB55F0001EBB3A /* NGA */,
D5384AFF2B3121FA006228C6 /* html */,
D545FC722B09C6DA00F206D0 /* VoiceManager */,
D51AA4052B099F6D00EBBDD4 /* DataSource */,
......@@ -457,8 +472,8 @@
0227890F2AE6028000A87787 /* Task */,
02CE4DD92ADFBA72002E79BC /* MapRepresentable.swift */,
02CD068E2AE6535F005F8D8F /* MapSource.swift */,
02CD06902AE6536B005F8D8F /* LayerEnum.swift */,
D5258C9A2B03401E00365276 /* MonitoringRoute.swift */,
D546B0122C197BB50058CD98 /* MapInformation.swift */,
);
path = Map;
sourceTree = "<group>";
......@@ -563,10 +578,12 @@
022789102AE6028400A87787 /* View */ = {
isa = PBXGroup;
children = (
02CE4D822ADE672B002E79BC /* MapTaskView.swift */,
02CE4D842ADF6295002E79BC /* TaskSwitchingMenuView.swift */,
D5C7823B2BFB4CEF001EBB3A /* FuelSwitchingView.swift */,
D5C782392BFB4C2A001EBB3A /* NgaNotificationView.swift */,
D5C7822E2BF88755001EBB3A /* MenuTaskView.swift */,
02CE4D862ADF62A7002E79BC /* EcaListView.swift */,
02CE4D882ADF62E1002E79BC /* EcaSettingView.swift */,
D5C782482BFC2DA2001EBB3A /* NgaSettingView.swift */,
);
path = View;
sourceTree = "<group>";
......@@ -596,6 +613,7 @@
02F4DB662B2C173F00E86C41 /* SessionGetManualUrl.swift */,
D58EF2442B901D3900FB784C /* SessionInformation.swift */,
D58EF2482B90562B00FB784C /* GetInformation.swift */,
D57905FF2C1C06F600AF797C /* SessionNgaList.swift */,
);
path = ServerSession;
sourceTree = "<group>";
......@@ -774,10 +792,24 @@
D5FCEF562B4789A8009A81D0 /* ResAckMessage.swift */,
D5FCEF582B4789D2009A81D0 /* ResChatMode.swift */,
D536F6702B678D8900A5BCF9 /* ReqUploadImage.swift */,
D57906012C1C0CFB00AF797C /* ReqNgaList.swift */,
);
path = Json;
sourceTree = "<group>";
};
D5C782452BFB55F0001EBB3A /* NGA */ = {
isa = PBXGroup;
children = (
D5C782432BFB55F0001EBB3A /* DeleteNgaArea.swift */,
D5C782442BFB55F0001EBB3A /* RegistereNga.swift */,
D539F32F2C1809790088E609 /* NgaTask.swift */,
D57905FD2C1C069000AF797C /* SetNgaArea.swift */,
D58E06CF2C1D1AF20039F22C /* GetNgaList.swift */,
);
name = NGA;
path = Sailassist/NGA;
sourceTree = SOURCE_ROOT;
};
D5EA86482AF2139D0032E810 /* Location */ = {
isa = PBXGroup;
children = (
......@@ -992,7 +1024,7 @@
D55135222B15C062007B66B1 /* GetEcaList.swift in Sources */,
D52D21412AEDE18F00324D58 /* EcaCoordinatesTable.swift in Sources */,
02A1DE2F2AFB4AA0005BCF55 /* ChatInputView.swift in Sources */,
02CD06912AE6536B005F8D8F /* LayerEnum.swift in Sources */,
D57905FE2C1C069000AF797C /* SetNgaArea.swift in Sources */,
020B98532AD919180029DE4C /* LoginTypeSelectView.swift in Sources */,
D52D213F2AEBB7D700324D58 /* RegisteredEca.swift in Sources */,
02CD06952AE895F5005F8D8F /* APIError.swift in Sources */,
......@@ -1002,9 +1034,12 @@
022A98202AF8B8960079C55A /* LocationCalculation.swift in Sources */,
D5258CA72B03988600365276 /* ReqTaskList.swift in Sources */,
D5CB6F9B2B021C4F00EC2010 /* LocationViewModel.swift in Sources */,
D5C7823C2BFB4CEF001EBB3A /* FuelSwitchingView.swift in Sources */,
D58E06D02C1D1AF20039F22C /* GetNgaList.swift in Sources */,
02CE4DC82ADF97E8002E79BC /* View+Extensions.swift in Sources */,
025F99742B2C125900C9A18A /* ResGetManualUrl.swift in Sources */,
D58E1F542B142A510092D8FE /* SessionEcaArea.swift in Sources */,
D5C7823A2BFB4C2A001EBB3A /* NgaNotificationView.swift in Sources */,
025C28002B034A1900BADC49 /* PDFViewer.swift in Sources */,
02C3E6092AFDF30000AF7837 /* ChatMemberView.swift in Sources */,
020B98412AD8C3810029DE4C /* LoginView.swift in Sources */,
......@@ -1020,20 +1055,23 @@
02F4DB672B2C173F00E86C41 /* SessionGetManualUrl.swift in Sources */,
D5AE351B2AEBA66A00059889 /* ResLogin.swift in Sources */,
D592D5252B0F16CA00B91A1C /* ReqMessage.swift in Sources */,
02CE4D832ADE672B002E79BC /* MapTaskView.swift in Sources */,
D5C782472BFB55F0001EBB3A /* RegistereNga.swift in Sources */,
02CE4DCC2ADFA03F002E79BC /* SelectedTabModel.swift in Sources */,
D5258C9B2B03401E00365276 /* MonitoringRoute.swift in Sources */,
D57906022C1C0CFB00AF797C /* ReqNgaList.swift in Sources */,
020B98162AD8C3150029DE4C /* ContentView.swift in Sources */,
020B98632ADD14E50029DE4C /* ChatView.swift in Sources */,
02CE4DDA2ADFBA72002E79BC /* MapRepresentable.swift in Sources */,
020B985E2ADCFF130029DE4C /* PreferencesKey.swift in Sources */,
0227890C2AE22E0B00A87787 /* SharingData.swift in Sources */,
D57906002C1C06F600AF797C /* SessionNgaList.swift in Sources */,
020B984D2AD9178F0029DE4C /* ScannerViewModel.swift in Sources */,
020B98142AD8C3140029DE4C /* SailassistApp.swift in Sources */,
02CE4D852ADF6295002E79BC /* TaskSwitchingMenuView.swift in Sources */,
D546B0132C197BB50058CD98 /* MapInformation.swift in Sources */,
D5CB6F9F2B0220A700EC2010 /* ErrorView.swift in Sources */,
D5CB6F992B02088C00EC2010 /* ResShipStatus.swift in Sources */,
023DB8282B1429E400B351CF /* NotificationContentView.swift in Sources */,
D5C7822F2BF88755001EBB3A /* MenuTaskView.swift in Sources */,
027EF9F22B0D804C0079B825 /* WebView.swift in Sources */,
020B984B2AD915810029DE4C /* QRReadView.swift in Sources */,
02A1DE332AFB654A005BCF55 /* CustomCornerRadius.swift in Sources */,
......@@ -1050,6 +1088,7 @@
025C27FE2B0206D700BADC49 /* PDFDownloadManager.swift in Sources */,
D59908CA2B1AC381000E13DD /* GetPushHistory.swift in Sources */,
D54D174B2B35137A00A0EAA5 /* LocalWebView.swift in Sources */,
D539F3302C1809790088E609 /* NgaTask.swift in Sources */,
D5FCEF572B4789A8009A81D0 /* ResAckMessage.swift in Sources */,
025C27FC2AFE191A00BADC49 /* MenuManualView.swift in Sources */,
D58E1F502B142A260092D8FE /* EcaArea.swift in Sources */,
......@@ -1064,6 +1103,8 @@
D5E03A672B04484D00D65FCE /* SessionTaskList.swift in Sources */,
020B986E2ADD3E8D0029DE4C /* DateTextLib.swift in Sources */,
D5258C9D2B03507A00365276 /* ResMonitoringRoute.swift in Sources */,
D5C782462BFB55F0001EBB3A /* DeleteNgaArea.swift in Sources */,
D5C782492BFC2DA2001EBB3A /* NgaSettingView.swift in Sources */,
020B98672ADD15050029DE4C /* MenuView.swift in Sources */,
020B98572AD924F50029DE4C /* CameraPreview.swift in Sources */,
D5CB6FA12B023F7F00EC2010 /* EcaTask.swift in Sources */,
......@@ -1258,7 +1299,7 @@
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 25;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1282,7 +1323,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D CANARY -D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist.canary;
PRODUCT_NAME = "Sail Assist";
......@@ -1304,7 +1345,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 25;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1325,7 +1366,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist;
PRODUCT_NAME = "Sail Assist";
......@@ -1488,7 +1529,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 25;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1512,7 +1553,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.2;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D QC -D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist.qc;
PRODUCT_NAME = "Sail Assist";
......
{
"images" : [
{
"filename" : "plus.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "areaPoint.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "target.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -12,11 +12,13 @@ struct WarnRecord {
var body: String
}
enum SwitchingEca {
enum SwitchingAlert {
case Finish
case Start
case Notice
case NgaPassing
init() {
self = .Notice
}
......@@ -26,14 +28,21 @@ class AlertDB {
// シングルトン宣言
static let OnlyOne = AlertDB()
private var alertEca : [SwitchingEca: WarnRecord] = [
SwitchingEca.Finish: WarnRecord(title: NSLocalizedString("No Fuel Switching Finished", comment: ""), body: NSLocalizedString("Arrived at switching finished point.", comment: ""))
, SwitchingEca.Start: WarnRecord(title: NSLocalizedString("Eca Start", comment: ""), body: NSLocalizedString("Arrived at switching start point.", comment: ""))
, SwitchingEca.Notice: WarnRecord(title: NSLocalizedString("Eca Notice", comment: ""), body: NSLocalizedString("Arrived at advance notice point.", comment: ""))
private var alertEca : [SwitchingAlert: WarnRecord] = [
SwitchingAlert.Finish: WarnRecord(title: String("No Fuel Switching Finished"), body: String("Arrived at switching finished point.")),
SwitchingAlert.Start: WarnRecord(title: NSLocalizedString("Eca Start", comment: ""), body: NSLocalizedString("Arrived at switching start point.", comment: "")),
SwitchingAlert.Notice: WarnRecord(title: NSLocalizedString("Eca Notice", comment: ""), body: NSLocalizedString("Arrived at advance notice point.", comment: "")),
SwitchingAlert.NgaPassing: WarnRecord(title: String("Nga Notice "), body: String("Nga Passing."))
]
//Eca通知
func GetAlertEcaPoint(point : SwitchingEca) -> WarnRecord {
func GetAlertEcaPoint(point : SwitchingAlert) -> WarnRecord {
return alertEca[point]!
}
//Nga通知
func GetAlertNgaPoint(point : SwitchingAlert) -> WarnRecord {
return alertEca[point]!
}
}
......@@ -12,6 +12,7 @@ struct PushNotificationTypes {
enum SendType: Int32{
case Error = -1
case Eca = 0 // Eca
case Nga = 1 //Nga
init(){
self = .Error
......@@ -29,5 +30,6 @@ struct PushNotificationTypes {
enum LocalPushIdentifier: String{
case Reserve = "Reserve" // 予約(初期設定)
case EcaSwitching = "Eca" // Eca
case NgaAlert = "Nga" // Nga
}
}
......@@ -47,7 +47,7 @@ class EcaArea {
private func tableInit() {
for data in ecaDataTable {
if !ecaData.ecaArea.keys.contains(data.areaId) {
var reg = RegisteredEca(id: data.areaId, ecaName: data.name)!
var reg = RegisteredEca(id: data.areaId, areaName: data.name)!
reg.color = "0xFF0000" //ライン色(ARGB)
reg.centerPosition = data.centerPosition
reg.zoomLevel = data.zoomLevel
......
......@@ -20,7 +20,7 @@ class EcaTask {
/**
* Eca通知
*/
private func notificationEca(point: SwitchingEca) {
private func notificationEca(point: SwitchingAlert) {
let alertDB = AlertDB.OnlyOne
var wernrec = WarnRecord(title:"Eca", body:"")
......@@ -75,7 +75,7 @@ class EcaTask {
// }
if eca.swFinish >= Float(distance) && 0.0 < Float(distance) && SharingData.my.ecaStatus != EcaState.finishPass{
// notificationEca(point: SwitchingEca.Finish)
// notificationEca(point: SwitchingAlert.Finish)
SharingData.eca.isShowEcaAlert = true
SharingData.my.ecaStatus = EcaState.finishPass
......@@ -84,7 +84,7 @@ class EcaTask {
}
if eca.swStart >= Float(distance) && eca.swFinish < Float(distance) && SharingData.my.ecaStatus != EcaState.startPass{
notificationEca(point: SwitchingEca.Start)
notificationEca(point: SwitchingAlert.Start)
SharingData.eca.isShowEcaAlert = true
SharingData.my.ecaStatus = EcaState.startPass
......@@ -93,7 +93,7 @@ class EcaTask {
}
if eca.swNotice >= Float(distance) && eca.swStart < Float(distance) && SharingData.my.ecaStatus != EcaState.noticePass{
notificationEca(point: SwitchingEca.Notice)
notificationEca(point: SwitchingAlert.Notice)
SharingData.eca.isShowEcaAlert = true
SharingData.my.ecaStatus = EcaState.noticePass
......
......@@ -44,8 +44,8 @@ struct RegisteredEca {
var zoomLevel: CGFloat = 11.0
var points: [CLLocationCoordinate2D] = []
init?(id: Int, ecaName: String ) {
init?(id: Int, areaName: String ) {
self.areaId = id
self.name = ecaName
self.name = areaName
}
}
......@@ -16,6 +16,7 @@ enum HttpRequestType : String {
// case CookiePolicy = "https://ssv-canary-web.azurewebsites.net/cookiepolicy"
// case PrivacyPolicy = "https://ssv-canary-web.azurewebsites.net/inapp?" //+バージョン番号
case TaskList = "https://ssv-canary-web.azurewebsites.net/api/sailassist/tasklist/XXXXX"
case NgaList = "https://ssv-canary-web.azurewebsites.net/api/sailassist/nogoarea/XXXXX"
case EcaArea = "https://ssv-canary-web.azurewebsites.net/api/sailassist/ecaarea/XXXXX"
case ShipStatus = "https://ssv-canary-web.azurewebsites.net/api/sailassist/shipstatus/XXXXX"
case ShipMonitoringRoute = "https://ssv-canary-web.azurewebsites.net/api/sailassist/shipmonitoringroute/XXXXX"
......@@ -42,6 +43,7 @@ enum HttpRequestType : String {
// case CookiePolicy = "https://ssv-qc-web.azurewebsites.net/cookiepolicy"
// case PrivacyPolicy = "https://ssv-qc-web.azurewebsites.net/inapp?" //+バージョン番号
case TaskList = "https://ssv-qc-web.azurewebsites.net/api/sailassist/tasklist/XXXXX"
case NgaList = "https://ssv-qc-web.azurewebsites.net/api/sailassist/nogoarea/XXXXX"
case EcaArea = "https://ssv-qc-web.azurewebsites.net/api/sailassist/ecaarea/XXXXX"
case ShipStatus = "https://ssv-qc-web.azurewebsites.net/api/sailassist/shipstatus/XXXXX"
case ShipMonitoringRoute = "https://ssv-qc-web.azurewebsites.net/api/sailassist/shipmonitoringroute/XXXXX"
......@@ -69,6 +71,7 @@ enum HttpRequestType : String {
// case CookiePolicy = "https://ssv.jmarinecloud.com/cookiepolicy"
// case PrivacyPolicy = "https://ssv.jmarinecloud.com/inapp?" //+バージョン番号
case TaskList = "https://ssv.jmarinecloud.com/api/sailassist/tasklist/XXXXX"
case NgaList = "https://ssv.jmarinecloud.com/api/sailassist/nogoarea/XXXXX"
case EcaArea = "https://ssv.jmarinecloud.com/api/sailassist/ecaarea/XXXXX"
case ShipStatus = "https://ssv.jmarinecloud.com/api/sailassist/shipstatus/XXXXX"
case ShipMonitoringRoute = "https://ssv.jmarinecloud.com/api/sailassist/shipmonitoringroute/XXXXX"
......
//
// ReqNgaList.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/14.
//
import Foundation
struct ReqNgaList : Codable {
var id: String = ""
var lock: Bool = false
var enabled: Bool = false
var geometry: [points] = []
init(Id: String) {
self.id = Id
}
}
......@@ -8,8 +8,10 @@
import Foundation
struct ReqTaskList : Codable {
// var id: String = ""
var areaId: Int = 0
var taskName: String = ""
// var name: String = ""
var noticeRange: Float = 0.0
var startRange: Float = 0.0
var finishRange: Float = 0.0
......
......@@ -10,35 +10,45 @@ import Foundation
import CoreLocation
// import Mapbox
struct PointC {
var x: Int
var y: Int
}
class LocationCalculation{
static let nm = 1852.0 // 国際海里 1852.0[m]
static let DI_BIAS = 10000000.0 //計算精度を1/100000°(暫定的、多分今後のGPS測位精度から推測しても十分なはず
static let ACCY_ROOT = 0.0000001
static let ACCY_COORD = 0.001
static let ACCY_RAD = 0.000001
static let ACCY_DEG = 0.0001
/**
* NMをkmに変換
*/
static func nm2km(nm: Double) -> Double{
return nm * 1.852
}
/**
* kmをNMに変換
*/
static func km2nm(km: Double) -> Double{
return km / 1.852
}
static func kn2kmh(kn: Double) -> Double{
return kn * 1.852
}
static func deg2rad(deg: Double) -> Double {
return (deg / 180.0) * Double.pi
}
static func rad2deg(rad: Double) -> Double {
return (rad / Double.pi) * 180.0
}
/**
* 地理座標の確認
*/
......@@ -65,7 +75,7 @@ class LocationCalculation{
return rangeDegree
}
/// 2点間距離の算出
/// - Parameters:
/// - posAlat: 地点A緯度
......@@ -83,12 +93,12 @@ class LocationCalculation{
let lonDifference = deg2rad(deg: posAlon - posBlon)
let curRadiusTemp = 1 - 0.00669438 * pow(sin(latAvg), 2.0)
//子午線曲率半径
let meridianCurvatureRadius = 6335439.327 / sqrt(pow(curRadiusTemp, 3.0))
//卯酉線曲率半径
let primeVerticalCircleCurvatureRadius = 6378137 / sqrt(curRadiusTemp)
//2点間距離
let distanceTemp = pow(meridianCurvatureRadius * latDifference, 2.0) + pow(primeVerticalCircleCurvatureRadius * cos(latAvg) * lonDifference, 2.0)
return sqrt(distanceTemp) //メートル単位
......@@ -102,7 +112,7 @@ class LocationCalculation{
static func distance(posA: CLLocationCoordinate2D, posB: CLLocationCoordinate2D) -> Double {
return distance(posAlat: posA.latitude, posAlon: posA.longitude, posBlat: posB.latitude, posBlon: posB.longitude)
}
/// 地点Bから地点Aをみたときの方位角
/// - Parameters:
/// - posAlat: 地点A緯度
......@@ -116,7 +126,7 @@ class LocationCalculation{
let posA_lon = deg2rad(deg: posAlon)
let posB_lat = deg2rad(deg: posBlat)
let posB_lon = deg2rad(deg: posBlon)
//経度の中心地
let posC_lat = (posA_lat + posB_lat) / 2.0
let dx = 6378137 * (posB_lon - posA_lon) * cos(posC_lat)
......@@ -125,14 +135,14 @@ class LocationCalculation{
if(dx == dy){
return 0.0
}
//なぜか左向きが0度、反時計回りに増える
let deg = rad2deg(rad: atan2(dy, dx))
//それを修正
let deg_o = deg + 90
let deg_p = 360 - deg_o
if(deg_p >= 360) {
return deg_p - 360
} else{
......@@ -140,7 +150,6 @@ class LocationCalculation{
}
}
/// 起点から指定の距離方位分移動した地点の緯度経度
/// - Parameters:
/// - startPointLat: 起点緯度
......@@ -154,26 +163,26 @@ class LocationCalculation{
startPointLon:Double,
initialBearing:Double,
distanceKilometers:Double) -> CLLocationCoordinate2D {
let initialBearingRadians = initialBearing * 2.0 * Double.pi / 360.0
let radiusEarthKilometers = 6371.01
let distRatio = distanceKilometers / radiusEarthKilometers
let distRatioSine = sin(distRatio)
let distRatioCosine = cos(distRatio)
let startLatRad = deg2rad(deg: startPointLat)
let startLonRad = deg2rad(deg: startPointLon)
let initialBearingRadians = initialBearing * 2.0 * Double.pi / 360.0
let radiusEarthKilometers = 6371.01
let distRatio = distanceKilometers / radiusEarthKilometers
let distRatioSine = sin(distRatio)
let distRatioCosine = cos(distRatio)
let startLatCos = cos(startLatRad)
let startLatSin = sin(startLatRad)
let startLatRad = deg2rad(deg: startPointLat)
let startLonRad = deg2rad(deg: startPointLon)
let endLatRads = asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * cos(initialBearingRadians)))
let startLatCos = cos(startLatRad)
let startLatSin = sin(startLatRad)
let endLonRads = startLonRad + atan2(sin(initialBearingRadians) * distRatioSine * startLatCos, distRatioCosine - startLatSin * sin(endLatRads))
let endLatRads = asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * cos(initialBearingRadians)))
let endLonRads = startLonRad + atan2(sin(initialBearingRadians) * distRatioSine * startLatCos, distRatioCosine - startLatSin * sin(endLatRads))
return CLLocationCoordinate2D(latitude: rad2deg(rad: endLatRads), longitude: rad2deg(rad: endLonRads))
}
return CLLocationCoordinate2D(latitude: rad2deg(rad: endLatRads), longitude: rad2deg(rad: endLonRads))
}
/// 地点Aと地点Bをの間の位置
/// - Parameters:
/// - posAlat: 地点A緯度
......@@ -183,20 +192,23 @@ class LocationCalculation{
/// - Returns:
/// 2地点間の中間緯度経度
static func halfPoint(posAlat:Double, posAlon:Double, posBlat:Double, posBlon:Double) -> CLLocationCoordinate2D {
let lat = ( posAlat + posBlat ) / 2
let lon = ( posAlon + posBlon ) / 2
return CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
static func halfPoint(posA:CLLocationCoordinate2D, posB:CLLocationCoordinate2D) -> CLLocationCoordinate2D {
return CLLocationCoordinate2D(latitude: ((posA.latitude + posB.latitude) / 2), longitude: ((posA.longitude + posB.longitude) / 2))
}
/// Plygonの中心の位置
/// - Parameters:
/// - positions: 地点配列
/// - Returns:
/// Polygonの中間緯度経度
static func CenterPoint(positions : [CLLocationCoordinate2D]) -> CLLocationCoordinate2D {
var latMax : Double = 0
var latMin : Double = 360
var lonMax : Double = 0
......@@ -220,7 +232,36 @@ class LocationCalculation{
return CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
static func CenterPoint2(positions : [CLLocationCoordinate2D]) -> CLLocationCoordinate2D {
var Max: CLLocationCoordinate2D = .init(latitude: 0, longitude: 0)
var Min: CLLocationCoordinate2D = .init(latitude: 0, longitude: 0)
Max = positions[0]
Min = positions[0]
for position in positions {
if fabs(Max.latitude) < fabs(position.latitude) {
Max.latitude = position.latitude
}
if fabs(Min.latitude) > fabs(position.latitude) {
Min.latitude = position.latitude
}
if fabs(Max.longitude) < fabs(position.longitude) {
Max.longitude = position.longitude
}
if fabs(Min.longitude) > fabs(position.longitude) {
Min.longitude = position.longitude
}
}
var ret = CLLocationCoordinate2D()
ret.latitude = (Max.latitude + Min.latitude) / 2
ret.longitude = (Max.longitude + Min.longitude) / 2
return ret
}
/// 緯度を数値から文字列に変換
/// - Parameters:
/// - lat: 緯度数値
......@@ -233,20 +274,22 @@ class LocationCalculation{
} else {
latNS = "S"
}
let latNum : Double
if (lat >= 0) {
latNum = lat
}else{
latNum = -lat
}
let latDeg = Int32(latNum)
let latMin = (latNum - Double(latDeg)) * 60.0
return "\(latDeg)°\(String(format:"%06.3f", latMin))\(latNS)"
}
/// 経度を数値から文字列に変換
/// - Parameters:
/// - lon: 経度数値
......@@ -259,20 +302,61 @@ class LocationCalculation{
}else{
lonEW = "W"
}
let lonNum : Double
if (lon >= 0){
lonNum = lon
} else {
lonNum = -lon
}
let lonDeg = Int32(lonNum)
let lonMin = (lonNum - Double(lonDeg)) * 60.0
return "\(lonDeg)°\(String(format:"%06.3f", lonMin))\(lonEW)"
}
/**
* 緯度経度を数値から文字列に変換
*/
static func locationDegtoString(location: CLLocationCoordinate2D) -> String {
let latNS : String
if (location.latitude >= 0){
latNS = "N"
} else {
latNS = "S"
}
let latNum : CLLocationDegrees
if (location.latitude >= 0) {
latNum = location.latitude
}else{
latNum = -location.latitude
}
let latDeg = Int32(latNum)
let latMin = (latNum - CLLocationDegrees(latDeg)) * 60.0
let lonEW : String
if (location.longitude >= 0){
lonEW = "E"
}else{
lonEW = "W"
}
let lonNum : CLLocationDegrees
if (location.longitude >= 0){
lonNum = location.longitude
} else {
lonNum = -location.longitude
}
let lonDeg = Int32(lonNum)
let lonMin = (lonNum - CLLocationDegrees(lonDeg)) * 60.0
return "\(String(format:"%3d", latDeg))°\(String(format:"%06.3f", latMin))\(latNS)\n\(String(format:"%03d", lonDeg))°\(String(format:"%06.3f", lonMin))\(lonEW)"
}
/**
* 緯度の文字列を数値に変換
* NXX°XX.XX
......@@ -306,7 +390,6 @@ class LocationCalculation{
}else{
return nil
}
}
/**
......@@ -343,7 +426,115 @@ class LocationCalculation{
return nil
}
}
/// 緯度の数値を分解
/// - Parameters:
/// - lat: 緯度数値
/// - Returns
/// 分解した数値
static func latDegtoInt(lat: CLLocationDegrees) -> [Int] {
var disLat : [Int] = []
if (lat >= 0){
disLat.append(0) //N
} else {
disLat.append(1) //S
}
let latNum : Double
if (lat >= 0) {
latNum = lat
}else{
latNum = -lat
}
let latDeg = Int(latNum)
let latMin = (latNum - Double(latDeg)) * 60.0
let latM = Int(latMin)
let latL = Int((latMin - Double(latM)) * 1000.0)
disLat.append(latDeg)
disLat.append(latM)
disLat.append(latL)
return disLat
}
/// 経度の数値を分解
/// - Parameters:
/// - lon: 経度数値
/// - Returns
/// 分解した数値
static func lonDegtoInt(lon: CLLocationDegrees) -> [Int] {
var disLat : [Int] = []
if (lon >= 0){
disLat.append(0) //E
}else{
disLat.append(1) //W
}
let lonNum : Double
if (lon >= 0){
lonNum = lon
} else {
lonNum = -lon
}
let lonDeg = Int(lonNum)
let lonMin = (lonNum - Double(lonDeg)) * 60.0
let lonM = Int(lonMin)
let lonL = Int((lonMin - Double(lonM)) * 1000.0)
disLat.append(lonDeg)
disLat.append(lonM)
disLat.append(lonL)
return disLat
}
/**
* 緯度の配列を数値に変換
* NXX°XX.XX
*/
static func latInttoDouble(lat: [Int]) -> CLLocationDegrees? {
if lat.count != 4 {
return nil
}
var direction : CLLocationDegrees
if lat[0] == 0 { //N
direction = 1.0
} else {
direction = -1.0
}
let deg0 : CLLocationDegrees = CLLocationDegrees(lat[1])
let deg1 : CLLocationDegrees = CLLocationDegrees(lat[2])
let min1 : CLLocationDegrees = CLLocationDegrees(lat[3])
let decimal = (deg1 + min1 / 1000) / 60.0
return ((deg0 + decimal) * direction)
}
/**
* 経度の配列を数値に変換
* EXXX°XX.XX
*/
static func lonInttoDouble(lon: [Int]) -> CLLocationDegrees? {
if lon.count != 4 {
return nil
}
var direction : CLLocationDegrees
if lon[0] == 0 { //E
direction = 1.0
} else {
direction = -1.0
}
let deg0 : CLLocationDegrees = CLLocationDegrees(lon[1])
let deg1 : CLLocationDegrees = CLLocationDegrees(lon[2])
let min1 : CLLocationDegrees = CLLocationDegrees(lon[3])
let decimal = (deg1 + min1 / 1000) / 60.0
return ((deg0 + decimal) * direction)
}
///時計回りか
///return: 1 -> 時計回り
/// -1 -> 反時計回り
......@@ -366,7 +557,7 @@ class LocationCalculation{
}
}
}
/// 地点Bから地点Aをみたときの方位角文字列
/// - Parameters:
/// - posAlat: 地点A緯度
......@@ -380,7 +571,7 @@ class LocationCalculation{
return String(round(direction)) + "°"
}
///距離(NM)を文字列に変換
static func distance2Str(nm: Double) -> String{
var rtnStr = ""
......@@ -393,7 +584,7 @@ class LocationCalculation{
}
return rtnStr
}
static let rad45 = 0.785398163397448 // radで45°
static let rDeg = 57.295779513082323 // radからdegに変換する乗数
static let eEccentricity = 0.08181919 // 離心率
......@@ -403,10 +594,10 @@ class LocationCalculation{
static let errorRange = 0.00001 //誤差範囲
struct AreaLatLon {
var NorthLat: Double = 0.0
var SouthLat: Double = 0.0
var EastLon: Double = 0.0
var WestLon: Double = 0.0
var NorthLat: CLLocationDegrees = 0.0
var SouthLat: CLLocationDegrees = 0.0
var EastLon: CLLocationDegrees = 0.0
var WestLon: CLLocationDegrees = 0.0
}
/**
......@@ -423,7 +614,7 @@ class LocationCalculation{
objPos: Array<CLLocationCoordinate2D>,
minMax: AreaLatLon,
exceed180: Bool)
-> Bool
-> Bool
{
var lUpperCnt = 0
var lLowerCnt = 0
......@@ -525,8 +716,8 @@ class LocationCalculation{
//直線S-E Y=(Ey-Sy)/Ex-Sx)*X+(Sy*Ex-Sx*Ey)/(Ex-Sx)
//交点のY座標、Y
let Y = (lpEP.latitude - lpSP.latitude) / (lpEP.longitude - lpSP.longitude) * cx +
(lpSP.latitude * lpEP.longitude - lpSP.longitude * lpEP.latitude) /
(lpEP.longitude - lpSP.longitude)
(lpSP.latitude * lpEP.longitude - lpSP.longitude * lpEP.latitude) /
(lpEP.longitude - lpSP.longitude)
if lpSP.longitude == cx { //始点が中心線上にある場合
//終点がその前の線分の始点と同じ方向か?
if (lpEP.longitude == maxX && lBeforeLR == 1)
......@@ -561,7 +752,7 @@ class LocationCalculation{
}
}
if lUpperCnt % 2 == 1 && lLowerCnt % 2 == 1{
if lUpperCnt % 2 == 1 && lLowerCnt % 2 == 1 {
return true
} else {
return false
......@@ -578,7 +769,7 @@ class LocationCalculation{
minMax: AreaLatLon,
exceed180: Bool,
exceed180Search: Bool)
-> (first: CLLocationCoordinate2D, second: CLLocationCoordinate2D)
-> (first: CLLocationCoordinate2D, second: CLLocationCoordinate2D)
{
var maxRt = max
var minRt = min
......@@ -633,7 +824,7 @@ class LocationCalculation{
lastPos: CLLocationCoordinate2D, //レグ起点
nextPos: CLLocationCoordinate2D, //レグ終点
shipPos: CLLocationCoordinate2D) //自船位置
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
{
let deg1 = bearing(lastPos: lastPos, nextPos: nextPos) //レグ起点 → レグ終点
let deg2 = bearing(lastPos: lastPos, nextPos: shipPos) //レグ起点 → 自船位置
......@@ -669,7 +860,7 @@ class LocationCalculation{
lastPos: CLLocationCoordinate2D, //レグ起点
nextPos: CLLocationCoordinate2D, //レグ終点
shipPos: CLLocationCoordinate2D) //自船位置
-> Bool
-> Bool
{
var checkCross: Bool = false
......@@ -700,7 +891,7 @@ class LocationCalculation{
static func checkPolyline(
objPos: Array<CLLocationCoordinate2D>,
shipPos: CLLocationCoordinate2D)
-> Double?
-> Double?
{
var distance: Double?
let rtn = crossLineDistance(objPos: objPos, shipPos: shipPos)
......@@ -729,7 +920,7 @@ class LocationCalculation{
static func crossLineDistance(
objPos: Array<CLLocationCoordinate2D>,
shipPos: CLLocationCoordinate2D)
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
{
//Loopしているか確認
var isLoop = false
......@@ -776,7 +967,7 @@ class LocationCalculation{
static func pointsDistance(
objPos: Array<CLLocationCoordinate2D>,
shipPos: CLLocationCoordinate2D)
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
{
var distance = 10000000.0
var nearbyPoint = 0
......@@ -883,7 +1074,7 @@ class LocationCalculation{
lastPos: CLLocationCoordinate2D, //レグ起点
nextPos: CLLocationCoordinate2D, //レグ終点
shipPos: CLLocationCoordinate2D) //自船位置
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
-> (retCode: Bool, xte: Double) //正常終了:true 異常:false 距離[NM]
{
let rtn1 = eNvMrdc(lastPos: lastPos, nextPos: nextPos, type: Mrdc.E_NV_MRDC_NORMAL)
print(debug: "eNvXteRL1 \(rtn1)")
......@@ -910,7 +1101,7 @@ class LocationCalculation{
lastPos: CLLocationCoordinate2D, //前回位置
nextPos: CLLocationCoordinate2D, //次回位置
type: Mrdc) //手法 Normal:E_NV_MRDC_NORMAL forAutoSail:E_NV_MRDC_XTE_R
-> ShipPosInf
-> ShipPosInf
{
var bRng1 = 0.0
var bRng2 = 0.0
......@@ -945,7 +1136,7 @@ class LocationCalculation{
//同じ位置かチェック
//『前回位置』と『次回位置』の差が0.00001'以下なら同じ位置とみなす
if ((abs(lastPos.latitude - nextPos.latitude) <= errorRange) &&
(abs(lastLon - nextLon) <= errorRange)) {
(abs(lastLon - nextLon) <= errorRange)) {
ret = ShipPosInf(retCode: false, co1: 0.0, co2: 180.0, dist: 0.0)
return ret
}
......@@ -969,11 +1160,11 @@ class LocationCalculation{
var bCalc = false
switch type {
case Mrdc.E_NV_MRDC_XTE_R:
case Mrdc.E_NV_MRDC_XTE_R:
if (abs(rLat1 - rLat0) > 0.0000001) {
bCalc = true
}
default:
default:
if (abs((abs(bRng1) - pidDiv2)) >= (Double.pi / 180.0)) {
bCalc = true
}
......@@ -994,9 +1185,9 @@ class LocationCalculation{
//手法によってずれ量を変える
var dist01: Double
switch type {
case Mrdc.E_NV_MRDC_XTE_R:
case Mrdc.E_NV_MRDC_XTE_R:
dist01 = 0.00000011
default:
default:
//0.11度ずれた緯度の質を求める
dist01 = (tan(LocationCalculation.deg2rad(deg: 0.11)) * abs(LocationCalculation.rad2deg(rad: dist) * deg2NM)) / 60.0
}
......@@ -1026,7 +1217,7 @@ class LocationCalculation{
lastPos: CLLocationCoordinate2D, //前回位置
nextPos: CLLocationCoordinate2D, //次回位置
type: Mrdc) //手法 Normal:E_NV_MRDC_NORMAL forAutoSail:E_NV_MRDC_XTE_R
-> DistanceInf
-> DistanceInf
{
var bRng1 = 0.0
var dist = 0.0
......@@ -1060,7 +1251,7 @@ class LocationCalculation{
//同じ位置かチェック
//『前回位置』と『次回位置』の差が0.00001'以下なら同じ位置とみなす
if ((abs(lastPos.latitude - nextPos.latitude) <= errorRange) &&
(abs(lastLon - nextLon) <= errorRange)) {
(abs(lastLon - nextLon) <= errorRange)) {
ret = DistanceInf(retCode: false, dist: dist)
return ret
}
......@@ -1084,11 +1275,11 @@ class LocationCalculation{
var bCalc = false
switch type {
case Mrdc.E_NV_MRDC_XTE_R:
case Mrdc.E_NV_MRDC_XTE_R:
if (abs(rLat1 - rLat0) > 0.0000001) {
bCalc = true
}
default:
default:
if (abs((abs(bRng1) - pidDiv2)) >= (Double.pi / 180.0)) {
bCalc = true
}
......@@ -1109,9 +1300,9 @@ class LocationCalculation{
//手法によってずれ量を変える
var dist01: Double
switch type {
case Mrdc.E_NV_MRDC_XTE_R:
case Mrdc.E_NV_MRDC_XTE_R:
dist01 = 0.00000011
default:
default:
//0.11度ずれた緯度の質を求める
dist01 = (tan(LocationCalculation.deg2rad(deg: 0.11)) * abs(LocationCalculation.rad2deg(rad: dist) * deg2NM)) / 60.0
}
......@@ -1139,7 +1330,7 @@ class LocationCalculation{
static func bearing(
lastPos: CLLocationCoordinate2D, //前回位置
nextPos: CLLocationCoordinate2D) //次回位置
-> BearingInf
-> BearingInf
{
var bRng1 = 0.0
var bRng2 = 0.0
......@@ -1172,7 +1363,7 @@ class LocationCalculation{
//同じ位置かチェック
//『前回位置』と『次回位置』の差が0.00001'以下なら同じ位置とみなす
if ((abs(lastPos.latitude - nextPos.latitude) <= errorRange) &&
(abs(lastLon - nextLon) <= errorRange)) {
(abs(lastLon - nextLon) <= errorRange)) {
ret = BearingInf(retCode: false, co1: 0.0, co2: 180.0)
return ret
}
......@@ -1280,13 +1471,392 @@ class LocationCalculation{
return deg
}
/**
* ポイントがライン上にあるか
*
* build/src/EDrawChart/ECdgeometry.cpp ECdIsPointOnLine移植
*/
static func eCdIsPointOnLine(
pt: CLLocationCoordinate2D,
ptL: CLLocationCoordinate2D,
ptR: CLLocationCoordinate2D
) -> Bool {
var checkN = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
checkN.latitude = ptL.latitude - pt.latitude
checkN.longitude = ptL.longitude - pt.longitude
if checkN.latitude == 0 && checkN.longitude == 0 {
return true
}
var zero = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
zero.latitude = ptR.latitude - pt.latitude
zero.longitude = ptR.longitude - pt.longitude
if zero.latitude == 0 && zero.longitude == 0 {
return true
}
let inside = zero.latitude * checkN.latitude + zero.longitude * checkN.longitude
let outside = zero.latitude * checkN.longitude - checkN.latitude * zero.longitude
if fabs(outside) <= ACCY_ROOT {
if fabs(inside) <= ACCY_ROOT {
return true // 内積、外積が0ということは、点がポリゴンの頂点のどれかと一致しているということ
}
if inside < 0.0 {
return true // 内積が0ということは、点がポリゴンの線上にあるということ
}
}
return false
}
/**
* 自己交差チェック(32ビット正規化座標用)
*
* build/src/Chart/Stranding/EWc_Inner.cpp移植
*/
static func chkSelfIntersection(
wcPos: Array<CLLocationCoordinate2D>
) -> Bool {
let positionNum = wcPos.count
var point1: Array<CLLocationCoordinate2D> = [CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)]
var point2: Array<CLLocationCoordinate2D> = [CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)]
var idx1: Array<Int> = [0, 0]
var idx2: Array<Int> = [0, 0]
var bIntersect = false
for i in 0 ..< positionNum - 1 {
point1[0] = wcPos[i]
point1[1] = wcPos[i + 1]
if point1[0] == point1[1] {
continue
}
idx1[0] = i
idx1[1] = i + 1
for j in i + 1 ..< positionNum - 1 {
bIntersect = false
point2[0] = wcPos[j]
point2[1] = wcPos[j + 1]
if point2[0] == point2[1] {
continue
}
idx2[0] = j
idx2[1] = j + 1
if min(point1[0].longitude, point1[1].longitude) > max(point2[0].longitude, point2[1].longitude) {
continue
}
if max(point1[0].longitude, point1[1].longitude) < min(point2[0].longitude, point2[1].longitude) {
continue
}
if min(point1[0].latitude, point1[1].latitude) > max(point2[0].latitude, point2[1].latitude) {
continue
}
if max(point1[0].latitude, point1[1].latitude) < min(point2[0].latitude, point2[1].latitude) {
continue
}
let ret = eCdInterPointLL(pSp: point1, pEp: point2)
if ret.crossInf == 0 {
bIntersect = true // 交点あり
} else if ret.crossInf == 1 {
// 接線(頂点と頂点の接触、辺と頂点の接触)
if !(point1[1] == point2[0]) && (i + 1 == j) {
if !(i == 0 && ((j + 1) == (positionNum - 1)) && (point1[0] == point2[1])) {
bIntersect = true
}
}
} else if ret.crossInf == -2 {
// 平行
if point1[0].longitude != point1[1].longitude && point2[0].longitude != point2[1].longitude {
// 線分2の座標が線分1上に有るか調べる
var targetPt: CLLocationCoordinate2D
var ptR: CLLocationCoordinate2D
var ptL: CLLocationCoordinate2D
let minX = min(point1[0].longitude, point1[1].longitude)
let maxX = max(point1[0].longitude, point1[1].longitude)
if minX < point2[0].longitude && maxX > point2[0].longitude {
targetPt = point2[0]
} else {
targetPt = point2[1]
}
if point1[0].longitude < point1[1].longitude {
ptL = point1[0]
ptR = point1[1]
} else {
ptL = point1[1]
ptR = point1[0]
}
let ret = eCdIsPointOnLine(pt: targetPt, ptL: ptL, ptR: ptR)
if true == ret {
if (min(point1[0].longitude, point1[1].longitude) <= min(point2[0].longitude, point2[1].longitude) && max(point2[0].longitude, point2[1].longitude) <= max(point1[0].longitude, point1[1].longitude))
|| (min(point2[0].longitude, point2[1].longitude) <= min(point1[0].longitude, point1[1].longitude) && max(point1[0].longitude, point1[1].longitude) <= max(point2[0].longitude, point2[1].longitude)) {
bIntersect = true
} else if !((point1[1] == point2[0]) && (i + 1 == j)) {
if !((i == 0) && ((j + 1) == (positionNum - 1)) && (point1[0] == point2[1])) {
bIntersect = true
}
}
}
} else if point1[0].longitude == point2[0].longitude {
// 縦一線の場合
if point1[1].latitude == point2[1].latitude {
bIntersect = true
} else if (min(point1[0].latitude, point1[1].latitude) < point2[1].latitude && max(point1[0].latitude, point1[1].latitude) > point2[1].latitude)
&& (min(point2[0].latitude, point2[1].latitude) < point1[1].latitude && max(point2[0].latitude, point2[1].latitude) > point1[1].latitude) {
bIntersect = true
} else if (min(point1[0].latitude, point1[1].latitude) < point2[0].latitude && max(point1[0].latitude, point1[1].latitude) > point2[0].latitude)
&& (min(point2[0].latitude, point2[1].latitude) < point1[0].latitude && max(point2[0].latitude, point2[1].latitude) > point1[0].latitude) {
bIntersect = true
} else if min(point1[0].latitude, point1[1].latitude) < point2[1].latitude && max(point1[0].latitude, point1[1].latitude) > point2[1].latitude {
bIntersect = true
} else if min(point2[0].latitude, point2[1].latitude) < point1[1].latitude && max(point2[0].latitude, point2[1].latitude) > point1[1].latitude {
bIntersect = true
}
}
}
// 自己交差している
if true == bIntersect {
return true
}
}
}
return false
}
/**
* 2線分の交点を計算
* 0:交点有り 1:接線 -1:線分が存在しない
* -2:二線分が並行し交点がない
* -3:線分外で交点あり
*
* src/EDrawChart/ECdGeometry.cpp
*/
static func eCdInterPointLL(
pSp: Array<CLLocationCoordinate2D>,
pEp: Array<CLLocationCoordinate2D>
) -> (crossInf: Int, cross: CLLocationCoordinate2D) {
var resp: Int = 0
var sd = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var dd = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var cross = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
sd.longitude = pSp[1].longitude - pSp[0].longitude
sd.latitude = pSp[1].latitude - pSp[0].latitude
dd.longitude = pEp[1].longitude - pEp[0].longitude
dd.latitude = pEp[1].latitude - pEp[0].latitude
let rsqs = sd.longitude * sd.longitude + sd.latitude * sd.latitude
let rsqe = dd.longitude * dd.longitude + dd.latitude * dd.latitude
//引数の適切性をチェック
if (rsqe < ACCY_ROOT) || (rsqs < ACCY_ROOT) {
//引数が不適切のため、計算中止
resp = -1
} else {
// 2線分の始点差ベクトルを求める
var bd = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
bd.longitude = pEp[0].longitude - pSp[0].longitude
bd.latitude = pEp[0].latitude - pSp[0].latitude
// 2線分の外積が0に近い時は平行となる
let det = dd.longitude * sd.latitude - dd.latitude * sd.longitude
if fabs(det) < ACCY_ROOT {
resp = -2;
} else {
// 始点差ベクトルとの外積から(外積比によって)パラメータを計算
let detinv = 1.0 / det
let s = (dd.longitude * bd.latitude - dd.latitude * bd.longitude) * detinv
let t = (sd.longitude * bd.latitude - sd.latitude * bd.longitude) * detinv
let ns = s
let nt = t
// パラメータから交点を計算
var l = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
l.longitude = pSp[0].longitude + sd.longitude * s
l.latitude = pSp[0].latitude + sd.latitude * s
cross = l
// 交点が2線分の外にある?
if (ns + ACCY_ROOT < 0.0) || (ns - ACCY_ROOT > 1.0) || (nt + ACCY_ROOT < 0.0) || (nt - ACCY_ROOT > 1.0) {
resp = -3;
} else if (fabs(ns) <= ACCY_ROOT) || (fabs(ns - 1.0) <= ACCY_ROOT) || (fabs(nt) <= ACCY_ROOT) || (fabs(nt - 1.0) <= ACCY_ROOT) {
resp = 1
// 接線判定になっても算出された交点が
// ・線分がなす矩形に内包されていない場合は線分外とする
// ・各線分の始点と終点に合致しない場合は交点ありとする
repeat {
var lSp: Array<PointC> = [PointC(x: 0, y:0), PointC(x: 0, y:0)]
var lEp: Array<PointC> = [PointC(x: 0, y:0), PointC(x: 0, y:0)]
var ptCross = PointC(x: 0, y: 0)
lSp[0].x = Int(pSp[0].longitude)
lSp[0].y = Int(pSp[0].latitude)
lSp[1].x = Int(pSp[1].longitude)
lSp[1].y = Int(pSp[1].latitude)
lEp[0].x = Int(pEp[0].longitude)
lEp[0].y = Int(pEp[0].latitude)
lEp[1].x = Int(pEp[1].longitude)
lEp[1].y = Int(pEp[1].latitude)
ptCross.x = (Int)((cross.longitude < 0) ? (cross.longitude - 0.5) : (cross.longitude + 0.5))
ptCross.y = (Int)((cross.latitude < 0) ? (cross.latitude - 0.5) : (cross.latitude + 0.5))
// 線分がなす矩形に内包されていない場合は線分外とする
if lSp[0].x < lSp[1].x {
if ptCross.x < lSp[0].x || lSp[1].x < ptCross.x {
resp = -3
break
}
} else {
if ptCross.x < lSp[1].x || lSp[0].x < ptCross.x {
resp = -3
break
}
}
if lEp[0].x < lEp[1].x {
if ptCross.x < lEp[0].x || lEp[1].x < ptCross.x {
resp = -3
break
}
} else {
if ptCross.x < lEp[1].x || lEp[0].x < ptCross.x {
resp = -3
break
}
}
if lSp[0].y < lSp[1].y {
if ptCross.y < lSp[0].y || lSp[1].y < ptCross.y {
resp = -3
break
}
} else {
if ptCross.y < lSp[1].y || lSp[0].y < ptCross.y {
resp = -3
break
}
}
if lEp[0].y < lEp[1].y {
if ptCross.y < lEp[0].y || lEp[1].y < ptCross.y {
resp = -3
break
}
} else {
if ptCross.y < lEp[1].y || lEp[0].y < ptCross.y {
resp = -3
break
}
}
// 各線分の始点と終点に合致しない場合は交点ありとする
if !((lSp[0].x == ptCross.x) && (lSp[0].y == ptCross.y)) &&
!((lSp[1].x == ptCross.x) && (lSp[1].y == ptCross.y)) &&
!((lEp[0].x == ptCross.x) && (lEp[0].y == ptCross.y)) &&
!((lEp[1].x == ptCross.x) && (lEp[1].y == ptCross.y)) {
resp = 0
break
}
} while false
} else {
resp = 0
// 交差判定になっても算出された交点が
// 線分がなす矩形に内包されていない場合は線分外とする
repeat {
var lSp: Array<PointC> = [PointC(x: 0, y:0), PointC(x: 0, y:0)]
var lEp: Array<PointC> = [PointC(x: 0, y:0), PointC(x: 0, y:0)]
var ptCross = PointC(x: 0, y: 0)
lSp[0].x = Int(pSp[0].longitude)
lSp[0].y = Int(pSp[0].latitude)
lSp[1].x = Int(pSp[1].longitude)
lSp[1].y = Int(pSp[1].latitude)
lEp[0].x = Int(pEp[0].longitude)
lEp[0].y = Int(pEp[0].latitude)
lEp[1].x = Int(pEp[1].longitude)
lEp[1].y = Int(pEp[1].latitude)
ptCross.x = (Int)((cross.longitude < 0) ? (cross.longitude - 0.5) : (cross.longitude + 0.5))
ptCross.y = (Int)((cross.latitude < 0) ? (cross.latitude - 0.5) : (cross.latitude + 0.5))
if lSp[0].x < lSp[1].x {
if ptCross.x < lSp[0].x || lSp[1].x < ptCross.x {
resp = -3
break
}
} else {
if ptCross.x < lSp[1].x || lSp[0].x < ptCross.x {
resp = -3
break
}
}
if lEp[0].x < lEp[1].x {
if ptCross.x < lEp[0].x || lEp[1].x < ptCross.x {
resp = -3
break
}
} else {
if ptCross.x < lEp[1].x || lEp[0].x < ptCross.x {
resp = -3
break
}
}
if lSp[0].y < lSp[1].y {
if ptCross.y < lSp[0].y || lSp[1].y < ptCross.y {
resp = -3
break
}
} else {
if ptCross.y < lSp[1].y || lSp[0].y < ptCross.y {
resp = -3
break
}
}
if lEp[0].y < lEp[1].y {
if ptCross.y < lEp[0].y || lEp[1].y < ptCross.y {
resp = -3
break
}
} else {
if ptCross.y < lEp[1].y || lEp[0].y < ptCross.y {
resp = -3
break
}
}
// 各線分の始点と終点に合致しない場合は交点ありとする
if ((lSp[0].x == ptCross.x) && (lSp[0].y == ptCross.y)) ||
((lSp[1].x == ptCross.x) && (lSp[1].y == ptCross.y)) ||
((lEp[0].x == ptCross.x) && (lEp[0].y == ptCross.y)) ||
((lEp[1].x == ptCross.x) && (lEp[1].y == ptCross.y)) {
resp = 1
break
}
} while false
}
}
}
return (resp, cross)
}
/**
* 等角航法での推測位置計算
* 等角航法で始点座標とその方位から任意の距離における位置座標を求める
*
* build/src/ENv/ENv.cpp ENvMrnp移植
*/
static func eNvMrnp(
static func eNvMrnp(
startPos: CLLocationCoordinate2D,
course: Double,
distance: Double
......@@ -1321,4 +1891,195 @@ class LocationCalculation{
return drPos
}
/**
* 直線と直線の交点検索
*
* build/src/Chart/DecisionAlgorithm.cpp
* テストまだ
*/
static func checkCrossLine(
p1: CLLocationCoordinate2D,
p2: CLLocationCoordinate2D,
sp: CLLocationCoordinate2D,
ep: CLLocationCoordinate2D
) -> Int {
var Max = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var Min = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var crossp = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
//直線p1-p2(Y=AX+B)とsp-ep(Y=CX+D)の交点チェック
//同じ経度の垂直線
if ((p2.longitude == p1.longitude) && (p1.longitude == ep.longitude) && (ep.longitude == sp.longitude)) {
Max.latitude = p1.latitude < p2.latitude ? p1.latitude : p2.latitude
Min.latitude = p1.latitude > p2.latitude ? p1.latitude : p2.latitude
//開始点がp1-p2に含まれる場合
if ((sp.latitude >= Min.latitude) && (sp.latitude <= Max.latitude)) {
crossp.latitude = sp.latitude
crossp.longitude = sp.longitude
return 1
}
//終了点がp1-p2に含まれる場合
else if (ep.latitude >= Min.latitude) && (ep.latitude <= Max.latitude) {
crossp.latitude = ep.latitude
crossp.longitude = ep.longitude
return 1
}
Max.latitude = sp.latitude < ep.latitude ? sp.latitude : ep.latitude
Min.latitude = sp.latitude > ep.latitude ? sp.latitude : ep.latitude
//p1がsp-epに含まれる場合
if ((p1.latitude >= Min.latitude) && (p1.latitude <= Max.latitude)) {
crossp.latitude = p1.latitude
crossp.longitude = p1.longitude
return 1
}
//p2がsp-epに含まれる場合
if ((p2.latitude >= Min.latitude) && (p2.latitude <= Max.latitude)) {
crossp.latitude = p2.latitude
crossp.longitude = p2.longitude
return 1
}
return 0
}
//同じ緯度の水平線
if ((p2.latitude == p1.latitude) && (p1.latitude == ep.latitude) && (ep.latitude == sp.latitude)) {
Max.longitude = p1.longitude < p2.longitude ? p1.longitude : p2.longitude
Min.longitude = p1.longitude > p2.longitude ? p1.longitude : p2.longitude
//開始点がp1-p2に含まれる場合
if ((sp.longitude >= Min.longitude) && sp.longitude <= Max.longitude) {
crossp.latitude = sp.latitude
crossp.longitude = sp.longitude
return 1
}
//終了点がp1-p2に含まれる場合
if ((ep.longitude >= Min.longitude) && (ep.longitude <= Max.longitude)) {
crossp.latitude = ep.latitude
crossp.longitude = ep.longitude
return 1
}
Max.longitude = sp.longitude < ep.longitude ? sp.longitude : ep.longitude
Min.longitude = sp.longitude > ep.longitude ? sp.longitude : ep.longitude
//p1がsp-epに含まれる場合
if ((p1.longitude >= Min.longitude) && (p1.longitude <= Max.longitude)) {
crossp.latitude = p1.latitude
crossp.longitude = p1.longitude
return 1
}
//p2がwp-epに含まれる場合
if ((p2.longitude >= Min.longitude) && (p2.longitude <= Max.longitude)) {
crossp.latitude = p2.latitude
crossp.longitude = p2.longitude
return 1
}
return 0
}
//違う垂直線
if ((p2.longitude == p1.longitude) && (ep.longitude == sp.longitude)) {
return 0
}
//違う水平線
if ((p2.latitude == p1.latitude) && (ep.latitude == sp.latitude)) {
return 0
}
var a, b, c, d : Double
crossp.longitude = 400
if (p2.longitude == p1.longitude) {
//p1-p2だけ垂直線
crossp.longitude = p1.longitude
crossp.latitude = (ep.latitude - sp.latitude) / (ep.longitude - sp.longitude) * p1.longitude + (sp.latitude * ep.longitude - sp.longitude * ep.latitude) / (ep.longitude - sp.longitude)
} else if (ep.longitude == sp.longitude) {
//sp-epだけ垂直線
crossp.longitude = sp.longitude
crossp.latitude = (p2.latitude - p1.latitude) / (p2.longitude - p1.longitude) * sp.longitude + (p1.latitude * p2.longitude - p1.longitude * p2.latitude) / (p2.longitude - p1.longitude)
} else if (p2.latitude == p1.latitude) {
//p1-p2だけ水平線
crossp.latitude = p1.latitude
crossp.longitude = (p1.latitude * (ep.longitude - sp.longitude) - (sp.latitude * ep.longitude - sp.longitude * ep.latitude)) / (ep.latitude - sp.latitude)
} else if (sp.latitude == ep.latitude) {
//sp-epだけ水平線
crossp.latitude = sp.latitude
crossp.longitude = (sp.latitude * (p2.longitude - p1.longitude) - (p1.latitude * p2.longitude - p1.longitude * p2.latitude)) / (p2.latitude - p1.latitude)
} else if ((p2.latitude - p1.latitude) / (p2.longitude - p1.longitude) == (ep.latitude - sp.latitude) / (ep.longitude - sp.longitude)) {
//両方とも垂直線、平行線ではなく2本の線が平行である時
crossp.longitude = p1.longitude
crossp.latitude = (ep.latitude - sp.latitude) / (ep.longitude - sp.longitude) * p1.longitude + (sp.latitude * ep.longitude - sp.longitude * ep.latitude) / (ep.longitude - sp.longitude)
//p1がsp-ep上の点か?
if (crossp.latitude == p1.latitude) {
return 1
}
crossp.longitude = p2.longitude
crossp.latitude = (ep.latitude - sp.latitude) / (ep.longitude - sp.longitude) * p2.longitude + (sp.latitude * ep.longitude - sp.longitude * ep.latitude) / (ep.longitude - sp.longitude)
//p2がsp-ep上の点か?
if (crossp.latitude == p2.latitude) {
return 1
}
crossp.longitude = sp.longitude
crossp.latitude = (p2.latitude - p1.latitude) / (p2.longitude - p1.longitude) * sp.longitude + (p1.latitude * p2.longitude - p1.longitude * p2.latitude) / (p2.longitude - p1.longitude)
//spがp1-p2上の点か?
if (crossp.latitude == sp.latitude) {
return 1
}
crossp.longitude = ep.longitude
crossp.latitude = (p2.latitude - p1.latitude) / (p2.longitude - p1.longitude) * ep.longitude + (p1.latitude * p2.longitude - p1.longitude * p2.latitude) / (p2.longitude - p1.longitude)
//epがp1-p2上の点か?
if (crossp.latitude == ep.latitude) {
return 1
}
//それ以外--別の平行線
return 0
} else {
a = (p2.latitude - p1.latitude) / (p2.longitude - p1.longitude)
b = (p1.latitude * p2.longitude - p1.longitude * p2.latitude) / (p2.longitude - p1.longitude)
c = (ep.latitude - sp.latitude) / (ep.longitude - sp.longitude)
d = (sp.latitude * ep.longitude - sp.longitude * ep.latitude) / (ep.longitude - sp.longitude)
crossp.longitude = (d - b) / (a - c)
crossp.latitude = (c * b - a * d) / (c - a)
}
//@@@ 2000/10/13 交点がどの線分上に存在するか判定する部分は、交点そのものをDOUBLEで計算していることから
// その線分の性質に沿った判定をする必要がある。
// 例えば水平線と任意の傾きをもった線分が交差する場合その交点を計算式で求めてもY座標値は
// 水平線のY座標とは異なってしまうはず(論理的には正しくとも、倍精度計算の丸め誤差により
// 正確に一致はしない)よって計算結果の有効桁数を小数点以下6桁で計算する。
if (crossp.longitude != 400) {
var iMaxX, iMaxY, iMinX, iMinY, iCrosX, iCrosY: Int
//求めた交点が線分p1-p2, sp-ep上にあるか?
Min.longitude = p1.longitude < p2.longitude ? p1.longitude : p2.longitude
Max.longitude = p1.longitude > p2.longitude ? p1.longitude : p2.longitude
Min.latitude = p1.latitude < p2.latitude ? p1.latitude : p2.latitude
Max.latitude = p1.latitude > p2.latitude ? p1.latitude : p2.latitude
iMinX = Int(round(Min.longitude * DI_BIAS))
iMinY = Int(round(Min.latitude * DI_BIAS))
iMaxX = Int(round(Max.longitude * DI_BIAS))
iMaxY = Int(round(Max.latitude * DI_BIAS))
iCrosX = Int(round(crossp.longitude * DI_BIAS))
iCrosY = Int(round(crossp.latitude * DI_BIAS))
if ((iMinX <= iCrosX) && (iCrosX <= iMaxX) && (iMinY <= iCrosY) && (iCrosY <= iMaxY)) {
//領域内で交わる
Min.longitude = sp.longitude < ep.longitude ? sp.longitude : ep.longitude
Max.longitude = sp.longitude > ep.longitude ? sp.longitude : ep.longitude
Min.latitude = sp.latitude < ep.latitude ? sp.latitude : ep.latitude
Max.latitude = sp.latitude > ep.latitude ? sp.latitude : ep.latitude
iMinX = Int(round(Min.longitude * DI_BIAS))
iMinY = Int(round(Min.latitude * DI_BIAS))
iMaxX = Int(round(Max.longitude * DI_BIAS))
iMaxY = Int(round(Max.latitude * DI_BIAS))
if ((iMinX <= iCrosX) && (iCrosX <= iMaxX) && (iMinY <= iCrosY) && (iCrosY <= iMaxY)) {
//線分内で交わる
return 1
} else {
return 0
}
} else {
return 0
}
}
return 0
}
}
......@@ -14,6 +14,7 @@ class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager: CLLocationManager
let ecaTask = EcaTask()
let ngaTask = NgaTask()
override init() {
let ecaArea = EcaArea()
......@@ -84,6 +85,7 @@ class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
if Preferences.LocationType == 0 {
ecaTask.checkEca()
ngaTask.checkNga()
}
}
......@@ -91,8 +93,9 @@ class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
if serverLocationInterval <= DateTextLib.Date2UnixTime(date: Date()) {
let eca = EcaTask()
eca.start()
self.ecaTask.checkEca()
self.ngaTask.checkNga()
serverLocationInterval = DateTextLib.Date2UnixTime(date: Date()) + Int64(TimerInterval)
}
}
......
......@@ -221,6 +221,9 @@ struct LoginView: View {
let ecaList = GetEcaList()
ecaList.start()
let ngaList = GetNgaList()
ngaList.start()
let pushHistory = GetPushHistory()
pushHistory.start()
}
......
......@@ -127,6 +127,9 @@ struct InputUserNameView: View {
let ecaList = GetEcaList()
ecaList.start()
let ngaList = GetNgaList()
ngaList.start()
let pushHistory = GetPushHistory()
pushHistory.start()
}
......
//
// LayerEnum.swift
// forShip
//
// Created by Mamoru Sugita on 2023/10/23.
//
import Foundation
enum LayerEnum: String{
case OwnShip
case EcaLine
case SwitchingLine
case SwLineLabel
case WayPoints
case WakeLines
case OneTimeEca
}
//
// MapInformation.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/12.
//
import SwiftUI
struct MapInformation: View {
@ObservedObject var ship = SharingData.location
@ObservedObject var ngaData = SharingData.nga
var body: some View {
VStack {
VStack {
Text(presentLocation())
.font(Font(UIFont.monospacedSystemFont(ofSize: 12, weight: .regular)))
.foregroundColor(Color.black)
.padding(5)
.background(Color.white.opacity(0.7))
.cornerRadius(3)
}
.padding(.top, 100)
.padding(.trailing, 200)
VStack {
ForEach(ngaData.ngaArea.map{ $0.1 }.filter{ $0.passingCnt > 0 }, id: \.name) { nga in
Text("Entering NGA \(nga.name)")
.font(FontStyle.EmphasisText.font)
.foregroundColor(Color.white)
.padding(5)
.background(Color.red.opacity(0.7))
.cornerRadius(3)
}
}
Spacer()
}
}
func presentLocation() -> String {
var location = " 00°00.000'N\n000°00.000'E"
if let shipPos = ship.location {
location = LocationCalculation.locationDegtoString(location: shipPos)
}
return location
}
}
#Preview {
MapInformation()
}
......@@ -10,8 +10,9 @@ import SwiftUI
import MapboxMaps
import UIKit
struct MapRepresentable: UIViewControllerRepresentable{
struct MapRepresentable: UIViewControllerRepresentable {
@ObservedObject var ecaData = SharingData.eca
@ObservedObject var ngaData = SharingData.nga
@ObservedObject var location = SharingData.location
@ObservedObject var map = SharingData.map
@ObservedObject var pushHistory = SharingData.pushHistory
......@@ -21,18 +22,18 @@ struct MapRepresentable: UIViewControllerRepresentable{
func makeUIViewController(context: Context) -> some UIViewController {
mapVC
}
//Viewが更新された場合に必要な処理を実装
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
let ecaArea = ecaData.ecaArea.map{ $0.1 }.filter{ $0.isRunning }.first
if let ecaArea = ecaArea{
if let ecaArea = ecaArea {
mapVC.updateEcaLine(line: ecaArea.points)
} else {
mapVC.removeEcaLine()
}
//ECA領域を画面中央に表示
if let focusEcaAreaId = ecaData.focusEca, let focusEca = ecaData.ecaArea[focusEcaAreaId]{
if let focusEcaAreaId = ecaData.focusEca, let focusEca = ecaData.ecaArea[focusEcaAreaId] {
mapVC.updateCamera(location: focusEca.centerPosition, zoomlevel: focusEca.zoomLevel)
mapVC.updateOneTimeEca(eca: focusEca.points)
//10秒後削除
......@@ -40,25 +41,35 @@ struct MapRepresentable: UIViewControllerRepresentable{
mapVC.updateOneTimeEca(eca: nil)
}
}
//NGA領域を画面中央に表示
if let AreaId = ngaData.focusNga, let uuid = NSUUID(uuidString: AreaId) {
if let focusNga = ngaData.ngaArea[uuid as UUID] {
if focusNga.points.count > 0 {
let centerPos = LocationCalculation.CenterPoint2(positions: focusNga.points)
mapVC.updateCamera(location: centerPos, zoomlevel: 10.0)
}
}
}
//通知場所を画面中央に表示
if let focusPushHistoryId = pushHistory.focusPushHistory, let focusPushHistory = pushHistory.pushHistoryData[focusPushHistoryId]{
if let focusPushHistoryId = pushHistory.focusPushHistory, let focusPushHistory = pushHistory.pushHistoryData[focusPushHistoryId] {
if let position = focusPushHistory.position {
if let latitude = position.lat, let longitude = position.lon {
mapVC.updateCamera(location: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), zoomlevel: nil)
}
}
}
//自船を画面中央に表示
if location.focusOwnShip {
mapVC.updateCamera(location: location.location, zoomlevel: nil)
}
if let mylocation = location.location {
mapVC.updateOwnShip(location: mylocation, bearing: location.heading)
if let ecaArea = ecaArea{
mapVC.updateOwnShipSymbol(location: mylocation, bearing: location.heading)
if let ecaArea = ecaArea {
mapVC.updateEcaSwitchingLine(center: mylocation, notice: ecaArea.swNotice, start: ecaArea.swStart, finish: ecaArea.swFinish)
} else {
mapVC.removeEcaSwitchingLine()
......@@ -66,26 +77,45 @@ struct MapRepresentable: UIViewControllerRepresentable{
}
mapVC.updateWakeLines(legLine: map.legLine, portLine: map.portLine, starboardLine: map.starboardLine)
mapVC.updateWayPoints(points: map.wayPoints)
mapVC.updateEditTarget()
if SharingData.nga.editType == EditNgaType.addPoint || SharingData.nga.editType == EditNgaType.movePoint {
mapVC.updateEditArea(remove: false)
}
if SharingData.nga.editType == EditNgaType.registered {
mapVC.updateEditArea(remove: true)
SharingData.nga.editType = EditNgaType.nonEdit
}
if SharingData.nga.editType == EditNgaType.deletePoint {
mapVC.updateEditArea(remove: true)
if let no = SharingData.nga.selectPoint {
SharingData.nga.editNga?.points.remove(at: no)
SharingData.nga.selectPoint = nil
}
mapVC.updateEditArea(remove: false)
}
if SharingData.map.isMapFree == true {
mapVC.lockEditPoint(isLocked: true)
SharingData.map.isMapFree = false
}
mapVC.updateAlertArea()
}
}
class MapViewController : UIViewController{
class MapViewController : UIViewController {
internal var mapView: MapView!
var ownShipSymbol = MapSource(layer: .OwnShip)
var ecaLine = MapSource(layer: .EcaLine)
var ecaSwitchingLine = MapSource(layer: .SwitchingLine)
var ecaSwLineLabel = MapSource(layer: .SwLineLabel)
var wayPoints = MapSource(layer: .WayPoints)
var wakeLines = MapSource(layer: .WakeLines)
var oneTimeEca = MapSource(layer: .OneTimeEca)
internal var touchedFeatures: Feature? = nil
override func viewDidLoad() {
super.viewDidLoad()
let centerCoordinate = CLLocationCoordinate2D(latitude: 37.8, longitude: -96)
// let url = StyleURI(rawValue: "mapbox://styles/jmarinecloud/cltrwnk5i01j901ra3g4n7dtz")
// let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 2), styleURI: url)
// let url = StyleURI(rawValue: "mapbox://styles/jmarinecloud/cltrwnk5i01j901ra3g4n7dtz")K
// let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 2), styleURI: url)
let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 2))
mapView = MapView(frame: view.bounds, mapInitOptions: options)
......@@ -93,300 +123,394 @@ class MapViewController : UIViewController{
self.view.addSubview(mapView)
mapView.mapboxMap.onNext(event: .mapLoaded) { [self] _ in
self.addIconImage()
self.addLayers()
}
//地図上クリック
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleMapTap(sender:)))
singleTap.numberOfTapsRequired = 1
for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
singleTap.require(toFail: recognizer)
}
singleTap.numberOfTouchesRequired = 1
//下記処理を加えると動作しない
// for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
// singleTap.require(toFail: recognizer)
// }
mapView.addGestureRecognizer(singleTap)
//地図上ダブルクリック
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleMapTap(sender:)))
doubleTap.numberOfTapsRequired = 2
for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
doubleTap.require(toFail: recognizer)
}
mapView.addGestureRecognizer(doubleTap)
// 両方を有効にするために必要
singleTap.require(toFail: doubleTap)
//地図上長押し
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleMapLongPress(sender:)))
for recognizer in mapView.gestureRecognizers! where recognizer is UILongPressGestureRecognizer {
longPress.require(toFail: recognizer)
}
mapView.addGestureRecognizer(longPress)
//地図上ドラッグ
let drug = UIPanGestureRecognizer(target: self, action: #selector(handleMapDrug))
// if isRocked{
mapView.removeGestureRecognizer(drug)
for recognizer in mapView.gestureRecognizers!where recognizer is UIPanGestureRecognizer{
recognizer.isEnabled = true
}
// }else{
// for recognizer in mapView.gestureRecognizers!where recognizer is UIPanGestureRecognizer{
// recognizer.isEnabled = false
// drug.require(toFail: recognizer)
// }
// mapView.addGestureRecognizer(drug)
// }
// updateUserMark()
}
/**
* 地図上クリックアクション
*/
@objc func handleMapTap(sender: UITapGestureRecognizer) {
print(debug: "called")
// setTapObjInfoDisp(isHidden: true)
// SharingData.UserMark.selectedPointId = nil
// SharingData.UserMark.selectedPointInfo = nil
// SharingData.UserMark.movePointLocation = nil
// setUserMarkRock(isRocked: true)
//
let spot = sender.location(in: mapView)
// mapboxMapManager.targetInfo = nil
// guard let touchedFeature = mapboxMapManager?.mapClick(pos: spot) else { return }
// // print(debug: "touchedFeature OK")
// mapboxMapManager.targetInfo = touchedFeature
// guard let type = touchedFeature.attribute(forKey: MapboxMapManager.PropertyKey.ObjectType.rawValue) as? String else { return }
// print(debug: "type = \(type)")
//
// guard let id = touchedFeature.attribute(forKey: MapboxMapManager.PropertyKey.Id.rawValue) else { return }
// print(debug: "id = \(id)")
//
// if let dataType = MapboxMapManager.DataType(rawValue: type){
// updataDetailInfo(type: dataType, id: id)
// switch dataType{
// case .AroundPhone:
// if let id = id as? String{
// //行き先シェア#128
// shareCourceparam.destinationShip = id
// self.destinationShip = id
// performSegue(withIdentifier: ActivityMap.InterruptShareCourse, sender: self)
// }
// default:
// break
// }
// }
let coordinate = mapView.mapboxMap.coordinate(for: spot)
mapClick(point: spot, coordinate: coordinate)
}
/**
* 地図上長押しアクション
*/
@objc func handleMapLongPress(sender: UILongPressGestureRecognizer ){
print( debug: "calld")
// // AIS情報問い合わせ
// //if SharingData.Vessels.distantTimer <= 0 { // 現在表示中でない
// // 長押し位置の緯度経度を得る
// let spot = sender.location(in: mapView)
// let tapCoordinate: CLLocationCoordinate2D = mapView.convert(spot, toCoordinateFrom: nil)
//
// let semaphore = DispatchSemaphore(value: 0)
// SessionManager().prepareSession(semaphore: semaphore)
//
// DispatchQueue(label: "WebAppRequest").async {
// semaphore.wait()
// self.distantWorkVessel.ErrCnt = 0
// self.distantWorkVessel.RequestWorkVessel( around : false, ActivityMap.noticeWorkVesselDist, tapCoordinate )
// }
// //}
@objc func handleMapLongPress(sender: UILongPressGestureRecognizer ) {
let spot = sender.location(in: mapView)
let coordinate = mapView.mapboxMap.coordinate(for: spot)
mapLongClick(point: spot, coordinate: coordinate)
}
/**
* 地図上ドラッグアクション
*/
@objc func handleMapDrug(sender: UIPanGestureRecognizer){
print( debug: "calld")
// if let id = SharingData.UserMark.selectedPointId,
// let point = SharingData.UserMark.selectedPointInfo{
// let pos = sender.location(in: mapView)
// let newLocation = mapView.convert(pos, toCoordinateFrom: nil)
// if sender.state == .began{
// guard let touchedFeature = mapboxMapManager.mapClick(pos: pos) else { return }
// guard let type = touchedFeature.attribute(forKey: MapboxMapManager.PropertyKey.ObjectType.rawValue) as? String else { return }
// if let _ = touchedFeature.attribute(forKey: MapboxMapManager.PropertyKey.Id.rawValue) as? Int64,
// type == MapboxMapManager.DataType.UserMark.rawValue &&
// id == SharingData.UserMark.selectedPointId{
// SharingData.UserMark.movePointLocation = newLocation
// }
// }else if let _ = SharingData.UserMark.movePointLocation,
// let _ = SharingData.UserMark.selectedPointId{
// if sender.state == .changed{
// SharingData.UserMark.movePointLocation = newLocation
// }else if sender.state == .ended{
// let markManager = UserMarkManager()
// point.latitude = newLocation.latitude
// point.longitude = newLocation.longitude
// markManager.updatePoint(point: point)
// updateUserMarkDetail(point: point)
// SharingData.UserMark.movePointLocation = nil
// }
// }
// }
// updateUserMark()
// updateRootNavigation()
// mapboxMapManager.updateTarget()
}
/**
* 自船アイコンの状態表記
*/
func addImage(){
do{
if let image = UIImage(named: "ownShip_normal"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Normal.rawValue)
}
if let image = UIImage(named: "ownShip_alarm"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Alarm.rawValue)
}
if let image = UIImage(named: "ownShip_caution"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Caution.rawValue)
}
if let image = UIImage(named: "ownShip_emergency"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Emergency.rawValue)
}
if let image = UIImage(named: "ownShip_necstemergency"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_NeCST_Emergency.rawValue)
}
if let image = UIImage(named: "ownShip_offline"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Offline.rawValue)
}
if let image = UIImage(named: "ownShip_unknown"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Unknown.rawValue)
}
if let image = UIImage(named: "ownShip_warning"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.OwnShip_Warning.rawValue)
}
if let image = UIImage(named: "swNoticeBack"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.SwNoticeBack.rawValue)
}
if let image = UIImage(named: "swStartBack"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.SwStartBack.rawValue)
@objc func handleMapDrug(sender: UIPanGestureRecognizer) {
let spot = sender.location(in: mapView)
let coordinate = mapView.mapboxMap.coordinate(for: spot)
print(debug: "test: handleMapDrug \(coordinate)")
mapDrug(point: spot, coordinate: coordinate)
if SharingData.nga.editType == EditNgaType.movePoint {
if let nga = SharingData.nga.editNga, let no = SharingData.nga.selectPoint {
var ngaData = nga
ngaData.points[no] = coordinate
SharingData.nga.targetLocation = coordinate
SharingData.nga.editNga = ngaData
updateEditArea()
}
if let image = UIImage(named: "swFinishBack"){
try mapView.mapboxMap.style.addImage(image, id: IconImage.SwFinisheBack.rawValue)
}
}
/**
* アイコンの状態表記
*/
let IconImageList = [
IconImageData(name: "ownShip_normal", id: IconImage.OwnShip_Normal.rawValue),
IconImageData(name: "ownShip_alarm", id: IconImage.OwnShip_Alarm.rawValue),
IconImageData(name: "ownShip_caution", id: IconImage.OwnShip_Caution.rawValue),
IconImageData(name: "ownShip_emergency", id: IconImage.OwnShip_Emergency.rawValue),
IconImageData(name: "ownShip_necstemergency", id: IconImage.OwnShip_NeCST_Emergency.rawValue),
IconImageData(name: "ownShip_offline", id: IconImage.OwnShip_Offline.rawValue),
IconImageData(name: "ownShip_unknown", id: IconImage.OwnShip_Unknown.rawValue),
IconImageData(name: "ownShip_warning", id: IconImage.OwnShip_Warning.rawValue),
IconImageData(name: "swNoticeBack", id: IconImage.SwNoticeBack.rawValue),
IconImageData(name: "swStartBack", id: IconImage.SwStartBack.rawValue),
IconImageData(name: "swFinishBack", id: IconImage.SwFinisheBack.rawValue),
IconImageData(name: "areaPoint", id: IconImage.AreaPoint.rawValue),
IconImageData(name: "target", id: IconImage.Target.rawValue),
IconImageData(name: "addSymbol", id: IconImage.AddSymbol.rawValue)
]
enum IconImage: String, CaseIterable {
case OwnShip_Alarm
case OwnShip_Caution
case OwnShip_Emergency
case OwnShip_NeCST_Emergency
case OwnShip_Normal
case OwnShip_Offline
case OwnShip_Unknown
case OwnShip_Warning
case SwNoticeBack
case SwStartBack
case SwFinisheBack
case AreaPoint
case Target
case AddSymbol
}
struct IconImageData {
var name: String
var id: String
}
func addIconImage() {
do{
for iconData in IconImageList {
if let iconImage = UIImage(named: iconData.name) {
try mapView.mapboxMap.style.addImage(iconImage, id: iconData.id)
}
}
} catch {
print(debug: "called")
}
}
func addLayers(){
addImage()
//自船
/**
* レイヤー処理
*/
enum LayerEnum: String {
case OwnShipSymbol
case EcaLine
case SwitchingLine
case SwLineLabel
case WayPoints
case WakeLines
case OneTimeEca
case EditTargetSymbol
case EditAreaAddSymbol
case EditAreaSymbol
case EditAreaLine
case EditAreaFill
case AlertAreaLabel
case AlertAreaSymbol
case AlertAreaLine
case AlertAreaFill
}
var ownShipSymbol = MapSource(layer: .OwnShipSymbol)
var ecaLine = MapSource(layer: .EcaLine)
var ecaSwitchingLine = MapSource(layer: .SwitchingLine)
var ecaSwLineLabel = MapSource(layer: .SwLineLabel)
var wayPoints = MapSource(layer: .WayPoints)
var wakeLines = MapSource(layer: .WakeLines)
var oneTimeEca = MapSource(layer: .OneTimeEca)
var editTargetSymbol = MapSource(layer: .EditTargetSymbol)
var editAreaAddSymbol = MapSource(layer: .EditAreaAddSymbol)
var editAreaFill = MapSource(layer: .EditAreaFill)
var editAreaLine = MapSource(layer: .EditAreaLine)
var editAreaSymbol = MapSource(layer: .EditAreaSymbol)
var alertAreaLabel = MapSource(layer: .AlertAreaLabel)
var alertAreaFill = MapSource(layer: .AlertAreaFill)
var alertAreaLine = MapSource(layer: .AlertAreaLine)
var alertAreaSymbol = MapSource(layer: .AlertAreaSymbol)
/**
* レイヤー作成
*/
func addLayers() {
alertAreaFillLayer()
alertAreaLineLayer()
editAreaFillLayer()
editAreaLineLayer()
editAreaAddSymbolLayer()
editAreaSymbolLayer()
editTargetSymbolLayer()
wayPointsLayer()
wakeLineLayer() //航路ライン
ecaSwitchingLineLabelLayer()
ecaSwitchingLineLayer()
oneTimeEcaLineLayer()
ecaLineLayer() //ECAライン
ownShipSymbolLayer() //自船シンボル
}
/**
* 自船シンボル表示レイヤー
*/
private func ownShipSymbolLayer() {
let point = Point(LocationCoordinate2D(latitude: 0, longitude: 0))
ownShipSymbol.source.data = .feature(Feature(geometry: point))
try! mapView.mapboxMap.style.addSource(ownShipSymbol.source, id: ownShipSymbol.sourceId)
var ownShipSymbolLayer = SymbolLayer(id: ownShipSymbol.layerId)
ownShipSymbolLayer.source = ownShipSymbol.sourceId
ownShipSymbolLayer.iconImage = .expression(Exp(.get) {
PropertyKey.IconImage.rawValue
})
ownShipSymbolLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
ownShipSymbolLayer.iconRotationAlignment = .constant(.map)
ownShipSymbolLayer.iconAllowOverlap = .constant(true)
ownShipSymbolLayer.iconIgnorePlacement = .constant(true)
ownShipSymbolLayer.iconRotate = .expression(Exp(.get) {
PropertyKey.Bearing.rawValue
})
try! mapView.mapboxMap.style.addSource(ownShipSymbol.source, id: ownShipSymbol.sourceId)
ownShipSymbolLayer.iconRotate = .expression(Exp(.get) {PropertyKey.Bearing.rawValue})
try? mapView.mapboxMap.style.addLayer(ownShipSymbolLayer)
}
//ECA
/**
* ECAライン表示レイヤー
*/
private func ecaLineLayer() {
let ecaLineString = LineString([LocationCoordinate2D(latitude: 0, longitude: 0)])
let ecaLinefeature = Feature(geometry: ecaLineString)
ecaLine.source.data = .feature(ecaLinefeature)
try! mapView.mapboxMap.style.addSource(ecaLine.source, id: ecaLine.sourceId)
var ecaLineLayer = LineLayer(id: ecaLine.layerId)
ecaLineLayer.source = ecaLine.sourceId
ecaLineLayer.lineColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
ecaLineLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
ecaLineLayer.lineDasharray = .constant([2,1])
try! mapView.mapboxMap.style.addSource(ecaLine.source, id: ecaLine.sourceId)
try? mapView.mapboxMap.style.addLayer(ecaLineLayer)
//
_ = LineString([LocationCoordinate2D(latitude: 0, longitude: 0)])
}
/**
* ECAライン一時表示レイヤー
*/
private func oneTimeEcaLineLayer() {
let ecaLineString = LineString([LocationCoordinate2D(latitude: 0, longitude: 0)])
let oneTimeEcaLinefeature = Feature(geometry: ecaLineString)
oneTimeEca.source.data = .feature(oneTimeEcaLinefeature)
try! mapView.mapboxMap.style.addSource(oneTimeEca.source, id: oneTimeEca.sourceId)
var oneTimeEcaLayer = LineLayer(id: oneTimeEca.layerId)
oneTimeEcaLayer.source = oneTimeEca.sourceId
oneTimeEcaLayer.lineColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
oneTimeEcaLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
oneTimeEcaLayer.lineDasharray = .constant([2,1])
try! mapView.mapboxMap.style.addSource(oneTimeEca.source, id: oneTimeEca.sourceId)
try? mapView.mapboxMap.style.addLayer(oneTimeEcaLayer)
//
}
/**
* ECA切替ライン表示レイヤー
*/
private func ecaSwitchingLineLayer() {
ecaSwitchingLine.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(ecaSwitchingLine.source, id: ecaSwitchingLine.sourceId)
var ecaSwitchingLineLayer = LineLayer(id: ecaSwitchingLine.layerId)
ecaSwitchingLineLayer.source = ecaSwitchingLine.sourceId
ecaSwitchingLineLayer.lineColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
ecaSwitchingLineLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
ecaSwitchingLineLayer.lineDasharray = .constant([2,1])
try! mapView.mapboxMap.style.addSource(ecaSwitchingLine.source, id: ecaSwitchingLine.sourceId)
try? mapView.mapboxMap.style.addLayer(ecaSwitchingLineLayer)
//ECA ラベル
}
/**
* ECA切替ラインラベル表示レイヤー
*/
private func ecaSwitchingLineLabelLayer() {
ecaSwLineLabel.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(ecaSwLineLabel.source, id: ecaSwLineLabel.sourceId)
var ecaSwLabelLayer = SymbolLayer(id: ecaSwLineLabel.layerId)
ecaSwLabelLayer.source = ecaSwLineLabel.sourceId
ecaSwLabelLayer.textField = .expression(Exp(.get) {
PropertyKey.Text.rawValue
})
ecaSwLabelLayer.iconImage = .expression(Exp(.get) {
PropertyKey.IconImage.rawValue
})
ecaSwLabelLayer.iconColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
ecaSwLabelLayer.textField = .expression(Exp(.get) {PropertyKey.Text.rawValue})
ecaSwLabelLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
ecaSwLabelLayer.iconColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
ecaSwLabelLayer.iconTextFit = .constant(.both)
ecaSwLabelLayer.iconTextFitPadding = .constant([0,6,0,6])
try! mapView.mapboxMap.style.addSource(ecaSwLineLabel.source, id: ecaSwLineLabel.sourceId)
try? mapView.mapboxMap.style.addLayer(ecaSwLabelLayer)
//航路
}
/**
* 航跡ラインレイヤー
*/
private func wakeLineLayer() {
wakeLines.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(wakeLines.source, id: wakeLines.sourceId)
var wakeLineLayer = LineLayer(id: wakeLines.layerId)
wakeLineLayer.source = wakeLines.sourceId
wakeLineLayer.lineColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
try! mapView.mapboxMap.style.addSource(wakeLines.source, id: wakeLines.sourceId)
wakeLineLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
try? mapView.mapboxMap.style.addLayer(wakeLineLayer)
//WayPoint
}
/**
* wayポイントレイヤー
*/
private func wayPointsLayer() {
wayPoints.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(wayPoints.source, id: wayPoints.sourceId)
var wayPointsLayer = SymbolLayer(id: wayPoints.layerId)
wayPointsLayer.source = wayPoints.sourceId
wayPointsLayer.iconImage = .expression(Exp(.get) {
PropertyKey.IconImage.rawValue
})
wayPointsLayer.iconColor = .expression(Exp(.get) {
PropertyKey.Color.rawValue
})
try! mapView.mapboxMap.style.addSource(wayPoints.source, id: wayPoints.sourceId)
wayPointsLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
wayPointsLayer.iconColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
try? mapView.mapboxMap.style.addLayer(wayPointsLayer)
}
///自船
func updateOwnShip(location: CLLocationCoordinate2D, bearing: Double){
/**
* NGA Editターゲットレイヤー
*/
private func editTargetSymbolLayer() {
editTargetSymbol.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(editTargetSymbol.source, id: editTargetSymbol.sourceId)
var editTargetSymbolLayer = SymbolLayer(id: editTargetSymbol.layerId)
editTargetSymbolLayer.source = editTargetSymbol.sourceId
editTargetSymbolLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
editTargetSymbolLayer.iconColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
try? mapView.mapboxMap.style.addLayer(editTargetSymbolLayer)
}
/**
* NGA Edit追加シンボルレイヤー
*/
private func editAreaAddSymbolLayer() {
editAreaAddSymbol.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(editAreaAddSymbol.source, id: editAreaAddSymbol.sourceId)
var editAreaAddSymbolLayer = SymbolLayer(id: editAreaAddSymbol.layerId)
editAreaAddSymbolLayer.source = editAreaAddSymbol.sourceId
editAreaAddSymbolLayer.textField = .expression(Exp(.get) {PropertyKey.Text.rawValue})
editAreaAddSymbolLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
editAreaAddSymbolLayer.iconColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
// editAreaSymbolLayer.iconOffset
// editAreaSymbolLayer.textOffset
try? mapView.mapboxMap.style.addLayer(editAreaAddSymbolLayer)
}
/**
* NGA Editポイントレイヤー
*/
private func editAreaSymbolLayer() {
editAreaSymbol.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(editAreaSymbol.source, id: editAreaSymbol.sourceId)
var editAreaSymbolLayer = SymbolLayer(id: editAreaSymbol.layerId)
editAreaSymbolLayer.source = editAreaSymbol.sourceId
editAreaSymbolLayer.textField = .expression(Exp(.get) {PropertyKey.Text.rawValue})
editAreaSymbolLayer.iconImage = .expression(Exp(.get) {PropertyKey.IconImage.rawValue})
editAreaSymbolLayer.iconColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
// editAreaSymbolLayer.iconOffset
// editAreaSymbolLayer.textOffset
try? mapView.mapboxMap.style.addLayer(editAreaSymbolLayer)
}
/**
* NGA Editライン表示レイヤー
*/
private func editAreaLineLayer() {
editAreaLine.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(editAreaLine.source, id: editAreaLine.sourceId)
var editAreaLineLayer = LineLayer(id: editAreaLine.layerId)
editAreaLineLayer.source = editAreaLine.sourceId
editAreaLineLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
editAreaLineLayer.lineWidth = .expression(Exp(.get) {PropertyKey.LineWidth.rawValue})
try? mapView.mapboxMap.style.addLayer(editAreaLineLayer)
}
/**
* NGA Editエリアレイヤー
*/
private func editAreaFillLayer() {
editAreaFill.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(editAreaFill.source, id: editAreaFill.sourceId)
var editAreaFillLayer = FillLayer(id: editAreaFill.layerId)
editAreaFillLayer.source = editAreaFill.sourceId
editAreaFillLayer.fillColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
try? mapView.mapboxMap.style.addLayer(editAreaFillLayer)
}
/**
* NGAライン表示レイヤー
*/
private func alertAreaLineLayer() {
alertAreaLine.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(alertAreaLine.source, id: alertAreaLine.sourceId)
var alertAreaLineLayer = LineLayer(id: alertAreaLine.layerId)
alertAreaLineLayer.source = alertAreaLine.sourceId
alertAreaLineLayer.lineColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
alertAreaLineLayer.lineWidth = .expression(Exp(.get) {PropertyKey.LineWidth.rawValue})
try? mapView.mapboxMap.style.addLayer(alertAreaLineLayer)
}
/**
* NGA エリアレイヤー
*/
private func alertAreaFillLayer() {
alertAreaFill.source.data = .featureCollection(FeatureCollection(features: []))
try! mapView.mapboxMap.style.addSource(alertAreaFill.source, id: alertAreaFill.sourceId)
var alertAreaFillLayer = FillLayer(id: alertAreaFill.layerId)
alertAreaFillLayer.source = alertAreaFill.sourceId
alertAreaFillLayer.fillColor = .expression(Exp(.get) {PropertyKey.Color.rawValue})
alertAreaFillLayer.fillOpacity = .expression(Exp(.get) {PropertyKey.FillOpacity.rawValue})
try? mapView.mapboxMap.style.addLayer(alertAreaFillLayer)
}
/**
* 自船シンボル描画処理
*/
func updateOwnShipSymbol(location: CLLocationCoordinate2D, bearing: Double){
do {
var shipIcon = IconImage.OwnShip_Normal.rawValue
......@@ -417,31 +541,15 @@ class MapViewController : UIViewController{
print(debug: "called")
}
}
///カメラ
func updateCamera(location: CLLocationCoordinate2D?, zoomlevel: CGFloat?){
if let level = zoomlevel {
self.mapView.camera.ease(to: CameraOptions(center: location, zoom: level), duration: 1)
} else {
self.mapView.camera.ease(to: CameraOptions(center: location), duration: 1)
}
if SharingData.eca.focusEca != nil {
SharingData.eca.focusEca = nil
}
if SharingData.pushHistory.focusPushHistory != nil {
SharingData.pushHistory.focusPushHistory = nil
}
if SharingData.location.focusOwnShip {
SharingData.location.focusOwnShip = false
}
}
///Ecaの線3本
func updateEcaSwitchingLine(center: CLLocationCoordinate2D, notice: Float, start: Float, finish: Float){
/**
* ECA表示
*/
func updateEcaSwitchingLine(center: CLLocationCoordinate2D, notice: Float, start: Float, finish: Float) {
do{
var switchingLines : [Feature] = []
var switchingLabels : [Feature] = []
let circlePoints_notice = getCirclePoints(center: center, radiusKm: LocationCalculation.nm2km(nm: Double(notice)))
var noticeLine = Feature(geometry: LineString(circlePoints_notice))
noticeLine.properties = [PropertyKey.Color.rawValue: .string("#62AB28")]
......@@ -449,12 +557,11 @@ class MapViewController : UIViewController{
if let point = circlePoints_notice.first{
var label = Feature(geometry: Point(point))
label.properties = [PropertyKey.Text.rawValue: .string("Advance Notice"),
PropertyKey.IconImage.rawValue: .string(IconImage.SwNoticeBack.rawValue),
PropertyKey.Color.rawValue: .string("#62AB28")]
PropertyKey.IconImage.rawValue: .string(IconImage.SwNoticeBack.rawValue),
PropertyKey.Color.rawValue: .string("#62AB28")]
switchingLabels.append(label)
}
let circlePoints_start = getCirclePoints(center: center, radiusKm: LocationCalculation.nm2km(nm: Double(start)))
var startLine = Feature(geometry: LineString(circlePoints_start))
startLine.properties = [PropertyKey.Color.rawValue: .string("#ECD932")]
......@@ -462,11 +569,11 @@ class MapViewController : UIViewController{
if let point = circlePoints_start.first{
var label = Feature(geometry: Point(point))
label.properties = [PropertyKey.Text.rawValue: .string("Switching Start"),
PropertyKey.IconImage.rawValue: .string(IconImage.SwStartBack.rawValue),
PropertyKey.Color.rawValue: .string("#ECD932")]
PropertyKey.IconImage.rawValue: .string(IconImage.SwStartBack.rawValue),
PropertyKey.Color.rawValue: .string("#ECD932")]
switchingLabels.append(label)
}
let circlePoints_finish = getCirclePoints(center: center, radiusKm: LocationCalculation.nm2km(nm: Double(finish)))
var finishLine = Feature(geometry: LineString(circlePoints_finish))
finishLine.properties = [PropertyKey.Color.rawValue: .string("#EF6135")]
......@@ -474,19 +581,24 @@ class MapViewController : UIViewController{
if let point = circlePoints_finish.first{
var label = Feature(geometry: Point(point))
label.properties = [PropertyKey.Text.rawValue: .string("Switching Finish"),
PropertyKey.IconImage.rawValue: .string(IconImage.SwFinisheBack.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
PropertyKey.IconImage.rawValue: .string(IconImage.SwFinisheBack.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
switchingLabels.append(label)
}
let lineGeoJson = FeatureCollection(features: switchingLines)
let labelGeoJson = FeatureCollection(features: switchingLabels)
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwitchingLine.sourceId, geoJSON: .featureCollection(lineGeoJson))
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwLineLabel.sourceId, geoJSON: .featureCollection(labelGeoJson))
}catch{}
} catch {
print(debug: "called")
}
}
func removeEcaSwitchingLine(){
/**
* ECA消去
*/
func removeEcaSwitchingLine() {
do{
let switchingLines : [Feature] = []
let switchingLabels : [Feature] = []
......@@ -495,71 +607,419 @@ class MapViewController : UIViewController{
let labelGeoJson = FeatureCollection(features: switchingLabels)
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwitchingLine.sourceId, geoJSON: .featureCollection(lineGeoJson))
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwLineLabel.sourceId, geoJSON: .featureCollection(labelGeoJson))
}catch{}
}
///円の位置情報を返す
private func getCirclePoints(center: CLLocationCoordinate2D, radiusKm: Double) -> [CLLocationCoordinate2D]{
var circlePoints : [CLLocationCoordinate2D] = []
for deg in stride(from: 0, through: 360, by: 6) {
let point = LocationCalculation.findPointAtDistanceFrom(
startPointLat: center.latitude,
startPointLon: center.longitude,
initialBearing: Double(deg),
distanceKilometers: radiusKm
)
circlePoints.append(point)
} catch {
print(debug: "called")
}
return circlePoints
}
func updateEcaLine(line: [CLLocationCoordinate2D]){
/**
* ECAライン更新
*/
func updateEcaLine(line: [CLLocationCoordinate2D]) {
do{
var geoJson = Feature(geometry: LineString(line))
geoJson.properties = [PropertyKey.Color.rawValue: .string(Color.blue.description)]
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaLine.sourceId, geoJSON: .feature(geoJson))
}catch{}
} catch {
print(debug: "called")
}
}
/**
* ECAライン消去
*/
func removeEcaLine(){
do{
let line: [CLLocationCoordinate2D] = []
let geoJson = Feature(geometry: LineString(line))
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaLine.sourceId, geoJSON: .feature(geoJson))
}catch{}
} catch {
print(debug: "called")
}
}
///一時的に見たいEcaを表示
func updateOneTimeEca(eca: [CLLocationCoordinate2D]?){
do{
func updateOneTimeEca(eca: [CLLocationCoordinate2D]?) {
do {
let eca = eca ?? []
var geoJson = Feature(geometry: LineString(eca))
geoJson.properties = [PropertyKey.Color.rawValue: .string(Color.black.description)]
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: oneTimeEca.sourceId, geoJSON: .feature(geoJson))
}catch{
} catch {
print(debug: "called")
}
}
func updateWakeLines(legLine: [CLLocationCoordinate2D], portLine: [CLLocationCoordinate2D], starboardLine: [CLLocationCoordinate2D]){
/**
* 航跡ライン更新処理
*/
func updateWakeLines(legLine: [CLLocationCoordinate2D], portLine: [CLLocationCoordinate2D], starboardLine: [CLLocationCoordinate2D]) {
do{
var legLineFeature = Feature(geometry: LineString(legLine))
legLineFeature.properties = [PropertyKey.Color.rawValue: .string(Color.blue.description)]
var portLineFeature = Feature(geometry: LineString(portLine))
portLineFeature.properties = [PropertyKey.Color.rawValue: .string(Color.blue.description)]
var starboardLineFeature = Feature(geometry: LineString(starboardLine))
starboardLineFeature.properties = [PropertyKey.Color.rawValue: .string(Color.blue.description)]
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: wakeLines.sourceId, geoJSON: .featureCollection(FeatureCollection(features: [legLineFeature, portLineFeature, starboardLineFeature])))
}catch{}
} catch {
print(debug: "called")
}
}
/**
* wayポイント更新処理
*/
func updateWayPoints(points: [CLLocationCoordinate2D]) {
do {
var features : [Feature] = []
for point in points {
var feature = Feature(geometry: Point(point))
feature.properties = [PropertyKey.IconImage.rawValue: .string(IconImage.SwFinisheBack.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
features.append(feature)
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwLineLabel.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA Editターゲット更新処理
*/
private func updateEditTargetSymbol(point: CLLocationCoordinate2D, remove: Bool = false) {
do {
var features : [Feature] = []
if remove == false {
var feature = Feature(geometry: Point(point))
feature.properties = [PropertyKey.IconImage.rawValue: .string(IconImage.Target.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
features.append(feature)
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: editTargetSymbol.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA Edit更新処理
* remove:
* true:画面消去
* false:画面表示
*/
func updateEditArea(remove: Bool = false) {
if let area = SharingData.nga.editNga {
if remove {
updateEditAreaAddSymbol(points: area.points, remove: remove)
updateEditAreaSymbol(points: area.points, remove: remove)
updateEditAreaLine(points: area.points, remove: remove)
updateEditAreaFill(points: area.points, remove: remove)
} else {
if area.points.count != 0 {
// updateEditAreaLabel(points: points)
updateEditAreaSymbol(points: area.points, remove: remove)
}
if area.points.count >= 2 {
updateEditAreaLine(points: area.points, remove: remove)
}
var areaPoints: [CLLocationCoordinate2D] = []
if remove == true {
updateEditAreaFill(points: areaPoints, remove: remove)
updateEditAreaAddSymbol(points: areaPoints, remove: remove)
} else {
if area.points.count >= 3 {
areaPoints = area.points
areaPoints.append(area.points[0])
updateEditAreaFill(points: areaPoints, remove: true)
updateEditAreaFill(points: areaPoints, remove: false)
updateEditAreaAddSymbol(points: areaPoints, remove: false)
}
}
}
}
}
func updateEditTarget() {
if SharingData.nga.editType == EditNgaType.movePoint {
if let location = SharingData.nga.targetLocation {
updateEditTargetSymbol(point: location)
}
} else {
let location = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
updateEditTargetSymbol(point: location, remove: true)
}
}
/**
* NGA Edit 追加シンボル更新処理
*/
private func updateEditAreaAddSymbol(points: [CLLocationCoordinate2D], remove: Bool = false) {
do{
var features : [Feature] = []
var id = 1
var firstPass = false
if remove == false {
var pointA = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var pointB = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
for point in points {
if firstPass == true {
pointB = point
let harf = LocationCalculation.halfPoint(posA: pointA, posB: pointB)
var feature = Feature(geometry: Point(harf))
feature.properties = [PropertyKey.IconImage.rawValue: .string(IconImage.AddSymbol.rawValue),
PropertyKey.Id.rawValue: .string(String(id)),
PropertyKey.Dtype.rawValue: .string(DataType.add.rawValue),
PropertyKey.Color.rawValue: .string("#62AB28")]
features.append(feature)
id += 1
pointA = pointB
} else {
pointA = point
firstPass = true
}
}
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: editAreaAddSymbol.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA Editポイント更新処理
*/
private func updateEditAreaSymbol(points: [CLLocationCoordinate2D], remove: Bool = false) {
do {
var features : [Feature] = []
var id = 0
if remove == false {
for point in points {
var feature = Feature(geometry: Point(point))
feature.properties = [PropertyKey.Text.rawValue: .string(String(id)),
PropertyKey.IconImage.rawValue: .string(IconImage.AreaPoint.rawValue),
PropertyKey.Id.rawValue: .string(String(id)),
PropertyKey.Dtype.rawValue: .string(DataType.point.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
features.append(feature)
id += 1
}
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: editAreaSymbol.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA Editライン更新処理
*/
private func updateEditAreaLine(points: [CLLocationCoordinate2D], remove: Bool = false) {
do {
var features : [Feature] = []
var id = 0
if remove == false {
if points.count >= 3 {
for cnt in 0..<points.count {
var line : [CLLocationCoordinate2D] = []
line.append(points[cnt])
if cnt + 1 == points.count {
line.append(points[0])
} else {
line.append(points[cnt + 1])
}
var feature = Feature(geometry: LineString(line))
feature.properties = [PropertyKey.Color.rawValue: .string(Color.black.description),
PropertyKey.Id.rawValue: .string(String(id)),
PropertyKey.Dtype.rawValue: .string(DataType.line.rawValue),
PropertyKey.LineWidth.rawValue: 3.0]
features.append(feature)
id += 1
}
} else if points.count == 2 {
var line : [CLLocationCoordinate2D] = []
line.append(points[0])
line.append(points[1])
var feature = Feature(geometry: LineString(line))
feature.properties = [PropertyKey.Color.rawValue: .string(Color.black.description),
PropertyKey.Id.rawValue: .string(String(id)),
PropertyKey.Dtype.rawValue: .string(DataType.line.rawValue),
PropertyKey.LineWidth.rawValue: 1.0]
features.append(feature)
}
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: editAreaLine.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA Editエリア更新処理
*/
private func updateEditAreaFill(points: [CLLocationCoordinate2D], remove: Bool = false) {
do{
var features : [Feature] = []
if remove == false {
var cnvPoints: Array<Array<CLLocationCoordinate2D>> = []
var areaPoints = points
let firstPoint = points[0]
areaPoints.append(firstPoint)
cnvPoints.append(areaPoints)
var feature = Feature(geometry: Polygon(cnvPoints))
feature.properties = [PropertyKey.Color.rawValue: .string(Color.blue.description)]
features.append(feature)
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: editAreaFill.sourceId, geoJSON: .featureCollection(FeatureCollection(features: features)))
} catch {
print(debug: "called")
}
}
/**
* NGA 更新処理
*/
func updateAlertArea() {
updateAlertAreaLine(area: SharingData.nga.ngaArea)
updateAlertAreaFill(area: SharingData.nga.ngaArea)
}
/**
* NGA ポイント更新処理
*/
private func updateAlertAreaSymbol(area: Dictionary<UUID, RegisteredNga>) {
do{
var features : [Feature] = []
for (_, value) in area {
if value.points.count >= 3 {
for point in value.points {
var feature = Feature(geometry: Point(point))
feature.properties = [PropertyKey.IconImage.rawValue: .string(IconImage.AreaPoint.rawValue),
PropertyKey.Color.rawValue: .string(Color.black.description)]
features.append(feature)
}
}
}
let featureCollection = FeatureCollection(features: features)
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: alertAreaSymbol.sourceId, geoJSON: .featureCollection(featureCollection))
} catch {
print(debug: "called")
}
}
/**
* NGAライン更新処理
*/
private func updateAlertAreaLine(area: Dictionary<UUID, RegisteredNga>) {
do{
var features : [Feature] = []
for (_, value) in area {
if value.isRunning == true {
if value.points.count >= 3 {
var areaPoints = value.points
let firstPoint = value.points[0]
areaPoints.append(firstPoint)
var color = Color.white.description
if value.isRunning {
color = Color.red.description
}
var feature = Feature(geometry: LineString(areaPoints))
feature.properties = [PropertyKey.Color.rawValue: .string(color),
PropertyKey.LineWidth.rawValue: 1.0]
features.append(feature)
}
}
}
let featureCollection = FeatureCollection(features: features)
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: alertAreaLine.sourceId, geoJSON: .featureCollection(featureCollection))
} catch {
print(debug: "called")
}
}
/**
* NGA エリア更新処理
*/
private func updateAlertAreaFill(area: Dictionary<UUID, RegisteredNga>) {
do{
var features : [Feature] = []
for (_, value) in area {
if value.points.count >= 3 {
var cnvPoints: Array<Array<CLLocationCoordinate2D>> = []
var areaPoints = value.points
let firstPoint = value.points[0]
areaPoints.append(firstPoint)
cnvPoints.append(areaPoints)
var feature = Feature(geometry: Polygon(cnvPoints))
if value.isRunning {
feature.properties = [PropertyKey.Color.rawValue: .string(value.color),
PropertyKey.FillOpacity.rawValue: 1.0]
} else {
feature.properties = [PropertyKey.Color.rawValue: .string(value.color),
PropertyKey.FillOpacity.rawValue: 0.2]
}
features.append(feature)
}
}
let featureCollection = FeatureCollection(features: features)
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: alertAreaFill.sourceId, geoJSON: .featureCollection(featureCollection))
} catch {
print(debug: "called")
}
}
///子午線を跨ぐ位置情報をチェックして東経ベースに補正する。
static func checkStraddleMeridian(_ locations: [CLLocationCoordinate2D]) -> [CLLocationCoordinate2D]{
/**
* カメラ
*/
func updateCamera(location: CLLocationCoordinate2D?, zoomlevel: CGFloat?){
if let level = zoomlevel {
self.mapView.camera.ease(to: CameraOptions(center: location, zoom: level), duration: 1)
} else {
self.mapView.camera.ease(to: CameraOptions(center: location), duration: 1)
}
if SharingData.eca.focusEca != nil {
SharingData.eca.focusEca = nil
}
if SharingData.nga.focusNga != nil {
SharingData.nga.focusNga = nil
}
if SharingData.pushHistory.focusPushHistory != nil {
SharingData.pushHistory.focusPushHistory = nil
}
if SharingData.location.focusOwnShip {
SharingData.location.focusOwnShip = false
}
}
/**
* 子午線を跨ぐ位置情報をチェックして東経ベースに補正する。
*/
static func checkStraddleMeridian(_ locations: [CLLocationCoordinate2D]) -> [CLLocationCoordinate2D] {
let eastLon = FloatingPointSign.plus
var returnLocations : [CLLocationCoordinate2D] = []
for location in locations {
......@@ -571,44 +1031,237 @@ class MapViewController : UIViewController{
returnLocations.append(location)
}
}
return returnLocations
}
func updateWayPoints(points: [CLLocationCoordinate2D]){
do{
var wayPointsFeatures : [Feature] = []
for point in points{
var feature = Feature(geometry: Point(point))
feature.properties = [PropertyKey.IconImage.rawValue: .string(IconImage.SwFinisheBack.rawValue),
PropertyKey.Color.rawValue: .string("#EF6135")]
wayPointsFeatures.append(feature)
}
try self.mapView.mapboxMap.style.updateGeoJSONSource(withId: ecaSwLineLabel.sourceId, geoJSON: .featureCollection(FeatureCollection(features: wayPointsFeatures)))
}catch{}
/**
* 円の位置情報を返す
*/
private func getCirclePoints(center: CLLocationCoordinate2D, radiusKm: Double) -> [CLLocationCoordinate2D]{
var circlePoints : [CLLocationCoordinate2D] = []
for deg in stride(from: 0, through: 360, by: 6) {
let point = LocationCalculation.findPointAtDistanceFrom(
startPointLat: center.latitude,
startPointLon: center.longitude,
initialBearing: Double(deg),
distanceKilometers: radiusKm
)
circlePoints.append(point)
}
return circlePoints
}
enum PropertyKey : String {
case Id
case Dtype
case IconImage
case Bearing
case Color
case Text
case Size
case LineWidth
case FillOpacity
case FillOutlineColor
}
enum IconImage: String, CaseIterable {
case OwnShip_Alarm
case OwnShip_Caution
case OwnShip_Emergency
case OwnShip_NeCST_Emergency
case OwnShip_Normal
case OwnShip_Offline
case OwnShip_Unknown
case OwnShip_Warning
case SwNoticeBack
case SwStartBack
case SwFinisheBack
enum DataType : String {
case ownShip
case point
case line
case add
}
}
/**
* 地図上クリック
*/
func mapClick(point: CGPoint, coordinate: CLLocationCoordinate2D) {
let layers = [
ownShipSymbol.layerId,
editAreaSymbol.layerId,
editAreaAddSymbol.layerId
]
self.touchedFeatures = nil
var features : [Feature] = []
let option = RenderedQueryOptions(layerIds: layers, filter: nil)
mapView.mapboxMap.queryRenderedFeatures(with: point, options: option) { [self] result in
switch result {
case .success(let queriedFeature):
for feature in queriedFeature {
features.append(feature.feature)
}
if let feature = features.last {
self.touchedFeatures = feature
}
clickSymbolLayer(tatchPoint: point, coordinate: coordinate)
case .failure(let error):
print(error.localizedDescription)
}
}
}
/**
* ポイントクリック処理
*/
private func clickSymbolLayer(tatchPoint: CGPoint, coordinate: CLLocationCoordinate2D) {
if let targetFeature = self.touchedFeatures {
print(debug: "Test: clickSymbolLayer \(coordinate)")
guard let type = targetFeature.properties?[PropertyKey.Dtype.rawValue] else {return}
switch type! {
case Turf.JSONValue.string(DataType.point.rawValue):
guard let jsonData = targetFeature.properties?[PropertyKey.Id.rawValue] else {return}
guard let Id = jsonData?.rawValue else {return}
if let noStr = Id as? String {
if let no = Int(noStr) {
SharingData.nga.selectPoint = no
}
}
if SharingData.nga.editNga?.isLock == false {
SharingData.nga.editType = EditNgaType.movePoint
SharingData.nga.moveNga = SharingData.nga.editNga
lockEditPoint(isLocked: false) //地図を固定
updateEditTargetSymbol(point: coordinate)
}
case Turf.JSONValue.string(DataType.add.rawValue):
print(debug: "Test: clickSymbolLayer(add) \(coordinate)")
guard let jsonData = targetFeature.properties?[PropertyKey.Id.rawValue] else {return}
guard let Id = jsonData?.rawValue else {return}
if SharingData.nga.editNga?.isLock == false {
if let noStr = Id as? String {
if let no = Int(noStr) {
SharingData.nga.editNga?.points.insert(coordinate, at: no)
}
}
}
default:
if SharingData.nga.editType == EditNgaType.addPoint {
if let editNga = SharingData.nga.editNga {
if editNga.points.count < ngaAreaPointMax {
SharingData.nga.editNga?.points.append(coordinate)
}
}
}
}
} else {
if SharingData.nga.editType == EditNgaType.addPoint {
if let editNga = SharingData.nga.editNga {
if editNga.points.count < ngaAreaPointMax {
SharingData.nga.editNga?.points.append(coordinate)
}
}
}
if SharingData.nga.editType == EditNgaType.movePoint {
SharingData.nga.editType = EditNgaType.addPoint
SharingData.map.isMapFree = true
}
}
}
/**
* 地図上ロングクリック
*/
func mapLongClick(point: CGPoint, coordinate: CLLocationCoordinate2D) {
let layers = [
editAreaSymbol.layerId
]
self.touchedFeatures = nil
var features : [Feature] = []
let option = RenderedQueryOptions(layerIds: layers, filter: nil)
mapView.mapboxMap.queryRenderedFeatures(with: point, options: option) { [self] result in
switch result {
case .success(let queriedFeature):
for feature in queriedFeature {
features.append(feature.feature)
}
if let feature = features.last {
self.touchedFeatures = feature
}
longClickSymbolLayer(tatchPoint: point, coordinate: coordinate)
case .failure(let error):
print(error.localizedDescription)
}
}
}
/**
* ポイント削除
*/
private func longClickSymbolLayer(tatchPoint: CGPoint, coordinate: CLLocationCoordinate2D) {
if SharingData.nga.editType == EditNgaType.addPoint {
if let targetFeature = self.touchedFeatures {
print(debug: "Test: longClickSymbolLayer \(coordinate)")
guard let type = targetFeature.properties?[PropertyKey.Dtype.rawValue] else {return}
if type! == Turf.JSONValue.string(DataType.point.rawValue) {
guard let jsonData = targetFeature.properties?[PropertyKey.Id.rawValue] else {return}
guard let Id = jsonData?.rawValue else {return}
if let noStr = Id as? String {
if let no = Int(noStr) {
SharingData.nga.editType = EditNgaType.deletePoint
SharingData.nga.selectPoint = no
}
}
}
updateEditArea()
}
}
}
/**
* 地図上ドラッグ
*/
private func mapDrug(point: CGPoint, coordinate: CLLocationCoordinate2D) {
let layers = [
editAreaSymbol.layerId
]
self.touchedFeatures = nil
var features : [Feature] = []
let option = RenderedQueryOptions(layerIds: layers, filter: nil)
print(debug: "Test: (Drug) \(coordinate)")
mapView.mapboxMap.queryRenderedFeatures(with: point, options: option) { [self] result in
switch result {
case .success(let queriedFeature):
for feature in queriedFeature {
features.append(feature.feature)
}
if let feature = features.last {
self.touchedFeatures = feature
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
/**
* ポイントの選択状態の設定
* setUserMarkRock
*/
func lockEditPoint(isLocked: Bool){
let drug = UIPanGestureRecognizer(target: self, action: #selector(handleMapDrug))
if isLocked {
mapView.removeGestureRecognizer(drug)
for recognizer in mapView.gestureRecognizers!where recognizer is UIPanGestureRecognizer {
recognizer.isEnabled = true
}
} else {
for recognizer in mapView.gestureRecognizers!where recognizer is UIPanGestureRecognizer {
recognizer.isEnabled = false
drug.require(toFail: recognizer)
}
mapView.addGestureRecognizer(drug)
}
}
}
......@@ -13,7 +13,7 @@ struct MapSource {
let layerId : String
var source = GeoJSONSource()
init(layer : LayerEnum){
init(layer : MapViewController.LayerEnum) {
sourceId = layer.rawValue + "Source"
layerId = layer.rawValue + "Layer"
}
......
......@@ -26,9 +26,9 @@ struct EcaListView: View {
var newData = eca
newData.isEnable.toggle()
ecaData.editEcaArea(key: eca.areaId, value: newData, type: EcaOperation.Insert)
taskViewModel.viewMode = .SwitchingMenu
taskViewModel.viewMode = .FuelSwitching
taskViewModel.edittingEcaArea = eca
taskViewModel.isShowSettingView = true
taskViewModel.viewMode = .EcaSetting
}, label: {
Image("icon_plus")
.resizable()
......
......@@ -9,10 +9,9 @@ import SwiftUI
import UIKit
struct EcaSettingView: View {
// @ObservedObject var taskViewModel: TaskViewModel
@Binding var isShowSettingEca: Bool
@ObservedObject var taskViewModel: TaskViewModel
@State var edittingEca: RegisteredEca
var body: some View {
VStack(spacing: 0){
SwSliderView(data: $edittingEca, type: .Finish)
......@@ -40,7 +39,6 @@ struct EcaSettingView: View {
var ecaData = edittingEca
ecaData.isEnable = true
SharingData.eca.editEcaArea(key: edittingEca.areaId, value: ecaData, type: EcaOperation.Change)
isShowSettingEca = false
}, label: {
Text("Register")
.font(FontStyle.DefaultText.font)
......@@ -59,7 +57,7 @@ struct EcaSettingView: View {
let notice = edittingEca.swNotice
let start = edittingEca.swStart
let finish = edittingEca.swFinish
return notice > start && notice > finish && start > finish
}
......@@ -213,5 +211,5 @@ struct EcaSettingView: View {
}
#Preview {
EcaSettingView(isShowSettingEca: .constant(true), edittingEca: RegisteredEca(id: 0, ecaName: "eca")!)
EcaSettingView(taskViewModel: TaskViewModel(), edittingEca: RegisteredEca(id: 0, areaName: "Alert Area")!)
}
//
// TaskSwitchingMenuView.swift
// FuelSwitchingView.swift
// forShip
//
// Created by Mamoru Sugita on 2023/10/18.
......@@ -7,7 +7,7 @@
import SwiftUI
struct TaskSwitchingMenuView: View {
struct FuelSwitchingView: View {
@ObservedObject var taskViewModel: TaskViewModel
@ObservedObject var ecaData = SharingData.eca
@State var isDeleteAlert: Bool = false
......@@ -57,7 +57,7 @@ struct TaskSwitchingMenuView: View {
Button{
taskViewModel.edittingEcaArea = eca
taskViewModel.ecaName = eca.name
taskViewModel.isShowSettingView = true
taskViewModel.viewMode = .EcaSetting
} label: {
Text("Edit Notice Setting")
}
......@@ -102,15 +102,6 @@ struct TaskSwitchingMenuView: View {
taskViewModel.edittingEcaArea = nil
}
Button("No"){}
// Button("Cancel"){¥
// if let ecaArea = taskViewModel.edittingEcaArea {
// var newData = ecaArea
// newData.isRunning = false
// newData.status = EcaState.cancel
// ecaData.editEcaArea(key: ecaArea.name, value: newData, type: EcaOperation.Cancel)
// }
// taskViewModel.edittingEcaArea = nil
// }
} message: {
Text("Have you finished " + taskViewModel.ecaName + " fuel switching?")
}
......@@ -137,11 +128,10 @@ struct TaskSwitchingMenuView: View {
Spacer()
}
// .padding()
}
}
#Preview {
TaskSwitchingMenuView(taskViewModel: TaskViewModel())
FuelSwitchingView(taskViewModel: TaskViewModel())
}
//
// MapTaskView.swift
// forShip
//
// Created by Mamoru Sugita on 2023/10/17.
//
import SwiftUI
enum TaskViewMode{
case SwitchingMenu
case EcaList
var title: String{
switch self{
case .SwitchingMenu:
"Fuel Switching"
case .EcaList:
"ECA List"
}
}
}
struct MapTaskView: View {
@ObservedObject var taskViewModel = TaskViewModel()
@ObservedObject var eca = SharingData.eca
var body: some View {
VStack{
if UIDevice.current.userInterfaceIdiom == .phone {
Capsule()
.foregroundColor(ColorSet.ScrollBarColor.color)
.frame(width: 45, height: 3)
.padding(.top, 10)
}
//タイトルエリア
HStack{
Button(action: {
taskViewModel.viewMode = .SwitchingMenu
taskViewModel.isShowSettingView = false
}, label: {
if taskViewModel.viewMode != .SwitchingMenu || taskViewModel.isShowSettingView{
Image("ink_02")
}
})
.frame(width: 48, height: 48)
Spacer()
Text(taskViewModel.isShowSettingView ? taskViewModel.edittingEcaArea?.name ?? "" : taskViewModel.viewMode.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
switch taskViewModel.viewMode {
case .SwitchingMenu:
if let edittingEcaArea = taskViewModel.edittingEcaArea, taskViewModel.isShowSettingView{
EcaSettingView(isShowSettingEca: $taskViewModel.isShowSettingView, edittingEca: edittingEcaArea)
}else{
TaskSwitchingMenuView(taskViewModel: taskViewModel)
}
case .EcaList:
EcaListView(taskViewModel: taskViewModel)
}
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
// proxy.scrollTo("scroll", anchor: .top)
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
.onAppear{
let appVersionModel = AppVersionModel()
appVersionModel.start()
}
.alert("", isPresented: $eca.isShowEcaAlert) {
// if let ecaArea = eca.ecaArea.map({ $0.1 }).filter({ $0.isRunning }).first{
Button("OK"){
// let ecaTask = EcaTask()
// ecaTask.chengeEcaStatus(eca: ecaArea)
// if let status = SharingData.my.ecaStatus {
// if status == .finishPass {
// var newData = ecaArea
// newData.isRunning = false
// newData.status = EcaState.incomplete
// SharingData.eca.editEcaArea(key: ecaArea.name, value: newData, type: EcaOperation.Incomplete)
// }
// }
}
// }
} message: {
if let ecaArea = eca.ecaArea.map({ $0.1 }).filter({ $0.isRunning }).first{
if let status = SharingData.my.ecaStatus {
switch status {
case .noticePass:
Text("Arrived at advance notice point.")
case .startPass:
Text("Arrived at switching start point.")
case .finishPass:
Text("Have you finished \(ecaArea.name) fuel switching?\nIf you finish, you disable it.")
case .incomplete:
Text("Have you finished \(ecaArea.name) fuel switching?\nIf you finish, you disable it.")
default:
Text("")
}
}
}
}
}
}
#Preview {
MapTaskView()
}
//
// MenuTaskView.swift
// forShip
//
// Created by Mamoru Sugita on 2023/10/17.
//
import SwiftUI
enum TaskViewMode {
case MenuList
case FuelSwitching
case EcaList
case EcaSetting
case NgaNotification
case NgaSetting
var title: String {
switch self {
case .MenuList:
"Menu Functions"
case .FuelSwitching:
"Fuel Switching"
case .EcaList:
"ECA List"
case .EcaSetting:
"ECA Setting"
case .NgaNotification:
"NGA Notification"
case .NgaSetting:
"NGA Setting"
}
}
}
struct MenuTaskView: View {
@ObservedObject var taskViewModel = TaskViewModel()
@ObservedObject var eca = SharingData.eca
@ObservedObject var nga = SharingData.nga
var body: some View {
VStack{
if UIDevice.current.userInterfaceIdiom == .phone {
Capsule()
.foregroundColor(ColorSet.ScrollBarColor.color)
.frame(width: 45, height: 3)
.padding(.top, 10)
}
switch taskViewModel.viewMode {
case .MenuList:
MenuMain(taskViewModel: taskViewModel)
case .FuelSwitching:
FuelSwitchingMain(taskViewModel: taskViewModel)
case .EcaList:
EcaListMain(taskViewModel: taskViewModel)
case .EcaSetting:
EcaSettingMain(taskViewModel: taskViewModel)
case .NgaNotification:
NgaNotificationMain(taskViewModel: taskViewModel)
case .NgaSetting:
NgaSettingMain(taskViewModel: taskViewModel)
}
}
.onAppear{
let appVersionModel = AppVersionModel()
appVersionModel.start()
nga.editType = EditNgaType.registered
}
.alert("", isPresented: $eca.isShowEcaAlert) {
// if let ecaArea = eca.ecaArea.map({ $0.1 }).filter({ $0.isRunning }).first{
Button("OK"){
// let ecaTask = EcaTask()
// ecaTask.chengeEcaStatus(eca: ecaArea)
// if let status = SharingData.my.ecaStatus {
// if status == .finishPass {
// var newData = ecaArea
// newData.isRunning = false
// newData.status = EcaState.incomplete
// SharingData.eca.editEcaArea(key: ecaArea.name, value: newData, type: EcaOperation.Incomplete)
// }
// }
}
// }
} message: {
if let ecaArea = eca.ecaArea.map({ $0.1 }).filter({ $0.isRunning }).first{
if let status = SharingData.my.ecaStatus {
switch status {
case .noticePass:
Text("Arrived at advance notice point.")
case .startPass:
Text("Arrived at switching start point.")
case .finishPass:
Text("Have you finished \(ecaArea.name) fuel switching?\nIf you finish, you disable it.")
case .incomplete:
Text("Have you finished \(ecaArea.name) fuel switching?\nIf you finish, you disable it.")
default:
Text("")
}
}
}
}
}
}
/**
* Menu画面
*/
struct MenuMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
var body: some View {
//タイトルエリア
HStack{
Spacer()
Text(TaskViewMode.MenuList.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
Button(action: {
taskViewModel.viewMode = .FuelSwitching
}, label: {
Text(TaskViewMode.FuelSwitching.title)
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
Button(action: {
taskViewModel.viewMode = .NgaNotification
}, label: {
Text(TaskViewMode.NgaNotification.title)
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
/**
* Fuel Switching画面
*/
struct FuelSwitchingMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
var body: some View {
//タイトルエリア
HStack{
Button(action: {
taskViewModel.viewMode = .MenuList
}, label: {
Image("ink_02")
})
.frame(width: 48, height: 48)
Spacer()
Text(TaskViewMode.FuelSwitching.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
//ECAリスト
ScrollViewReader { proxy in
ScrollView(.vertical){
FuelSwitchingView(taskViewModel: taskViewModel)
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
/**
* ECA List画面
*/
struct EcaListMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
var body: some View {
//タイトルエリア
HStack{
Button(action: {
taskViewModel.viewMode = .FuelSwitching
}, label: {
Image("ink_02")
})
.frame(width: 48, height: 48)
Spacer()
Text(TaskViewMode.EcaList.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
EcaListView(taskViewModel: taskViewModel)
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
/**
* ECA Setting画面
*/
struct EcaSettingMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
var body: some View {
//タイトルエリア
HStack{
Button(action: {
taskViewModel.viewMode = .FuelSwitching
}, label: {
Image("ink_02")
})
.frame(width: 48, height: 48)
Spacer()
Text(TaskViewMode.EcaSetting.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
if let edittingEcaArea = taskViewModel.edittingEcaArea {
EcaSettingView(taskViewModel: taskViewModel, edittingEca: edittingEcaArea)
}
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
/**
* NGA Notification画面
*/
struct NgaNotificationMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
var body: some View {
//タイトルエリア
HStack{
Button(action: {
taskViewModel.viewMode = .MenuList
}, label: {
Image("ink_02")
})
.frame(width: 48, height: 48)
Spacer()
Text(TaskViewMode.NgaNotification.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
NgaNotificationView(taskViewModel: taskViewModel)
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
/**
* NGA設定画面
*/
struct NgaSettingMain: View {
@ObservedObject var taskViewModel = TaskViewModel()
@ObservedObject var nga = SharingData.nga
@ObservedObject var map = SharingData.map
var body: some View {
//タイトルエリア
HStack{
Button(action: {
if taskViewModel.viewMode == .NgaSetting && nga.editType == EditNgaType.movePoint {
nga.editNga = nga.moveNga
nga.editType = EditNgaType.addPoint
map.isMapFree = true
} else {
taskViewModel.viewMode = .NgaNotification
nga.editType = EditNgaType.registered
}
}, label: {
Image("ink_02")
})
.frame(width: 48, height: 48)
Spacer()
Text(TaskViewMode.NgaSetting.title)
.font(FontStyle.TitleL.font)
.frame(height: 20)
.padding(.vertical, 14)
Spacer()
Button(action: {
}, label: {
})
.frame(width: 48, height: 48)
}
.padding(EdgeInsets(top: 10, leading: 8, bottom: 13, trailing: 17))
Divider()
.background(ColorSet.LineColor03.color)
ScrollViewReader { proxy in
ScrollView(.vertical){
NgaSettingView(taskViewModel: taskViewModel)
}
.onChange(of: taskViewModel.viewMode){ newViewMode in
proxy.scrollTo(0, anchor: .top)
}
}
Spacer()
.frame(height: 55)
}
}
#Preview {
MenuTaskView()
}
#Preview {
MenuMain(taskViewModel: TaskViewModel())
}
#Preview {
FuelSwitchingMain(taskViewModel: TaskViewModel())
}
#Preview {
EcaListMain(taskViewModel: TaskViewModel())
}
#Preview {
EcaSettingMain(taskViewModel: TaskViewModel())
}
#Preview {
NgaNotificationMain(taskViewModel: TaskViewModel())
}
#Preview {
NgaSettingMain(taskViewModel: TaskViewModel())
}
//
// NgaNotificationView.swift
// forShip
//
// Created by Mamoru Sugita on 2023/10/18.
//
import SwiftUI
struct NgaNotificationView: View {
@ObservedObject var taskViewModel: TaskViewModel
@ObservedObject var ngaData = SharingData.nga
@State var isDelete: Bool = false
@State var isRunningStopNga: Bool = false
var body: some View {
VStack {
// ForEach(ngaData.ngaArea.map{ $0.1 }.sorted{ $0.name < $1.name }, id: \.areaId) { nga in
ForEach(ngaData.ngaArea.map{ $0.1 }, id: \.areaId) { nga in
VStack {
HStack {
//NGA開始・終了ボタン
Button {
var newData = nga
newData.isRunning.toggle()
newData.passingCnt = 0
if newData.isRunning {
ngaData.editNgaArea(value: newData, type: NgaOperation.Running)
} else {
ngaData.editNgaArea(value: newData, type: NgaOperation.Cancel)
}
} label: {
HStack {
Circle()
.frame(width: 14, height: 14)
.foregroundColor(nga.isRunning ? ColorSet.PrimaryActiveIcon.color : ColorSet.TaskStateIcon.color)
Spacer()
.frame(width: 10)
}
}
//NGA移動
Text(nga.name)
.font(FontStyle.DefaultText.font)
.foregroundColor(ColorSet.Body.color)
.onTapGesture {
ngaData.focusNga = nga.areaId.uuidString
}
Spacer()
Menu {
Text(nga.name)
Button{
ngaData.editNga = nga
taskViewModel.viewMode = .NgaSetting
ngaData.editType = EditNgaType.nonEdit
} label: {
Text("Edit Nga Setting")
}
//削除
Button{
ngaData.editNga = nga
isDelete = true
} label: {
Text("Delete NGA Notification")
}.disabled(nga.isLock)
} label: {
Image(systemName: "ellipsis")
.frame(width: 22, height: 22)
.foregroundColor(nga.isRunning ? ColorSet.Splash.color : ColorSet.Slidebar.color)
}
.disabled(nga.isRunning)
.alert("Delete", isPresented: $isDelete) {
Button("Yes") {
if let newData = ngaData.editNga {
ngaData.editNgaArea(value: newData, type: NgaOperation.Delete)
ngaData.editNga = nil
}
}
Button("No"){}
} message: {
Text("Delete " + nga.name + " ?")
}
.alert("NGA Switching", isPresented:$isRunningStopNga) {
Button("Yes") {
var newData = nga
newData.isRunning = false
ngaData.editNgaArea(value: newData, type: NgaOperation.Cancel)
}
Button("No"){}
} message: {
Text("Have you finished " + nga.name + "switching?")
}
}
.frame(height: 60)
.padding(.horizontal, 30)
Divider()
.background(.white)
}
}
//Add NGAボタン
let isAddNga = ngaData.ngaArea.count < ngaAreaMax
Button(action: {
if var ngaTmp = RegisteredNga(areaName: "") {
ngaTmp.isLock = false
ngaTmp.isRunning = false
ngaTmp.name = "NGA Area" + String(ngaData.ngaArea.count)
ngaData.editType = EditNgaType.nonEdit
ngaData.editNga = ngaTmp
taskViewModel.viewMode = .NgaSetting
}
}, label: {
Text("Add NGA Task")
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(!isAddNga ? ColorSet.SecondaryDisable.color : ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
.disabled(!isAddNga)
Spacer()
}
}
}
#Preview {
NgaNotificationView(taskViewModel: TaskViewModel())
}
//
// NgaSettingView.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/05/21.
//
import SwiftUI
import CoreLocation
import UIKit
struct NgaSettingView: View {
@ObservedObject var taskViewModel: TaskViewModel
@ObservedObject var nga = SharingData.nga
@ObservedObject var map = SharingData.map
var body: some View {
if nga.editType == EditNgaType.movePoint {
NgaPointSetting(taskViewModel: taskViewModel)
} else {
NgaSetting(taskViewModel: taskViewModel)
}
}
}
struct NgaSetting: View {
@ObservedObject var taskViewModel: TaskViewModel
@ObservedObject var nga = SharingData.nga
@ObservedObject var map = SharingData.map
var body: some View {
VStack(spacing: 0) {
HStack {
Text("Area Name").padding(.horizontal, 0)
.foregroundColor(nga.editNga!.isLock ? ColorSet.BodyDescriptiion.color : ColorSet.Body.color)
TextField("", text: $taskViewModel.ngaName)
.foregroundColor(nga.editNga!.isLock ? ColorSet.BodyDescriptiion.color : ColorSet.Body.color)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.emailAddress)
.frame(width: 150)
.disabled(nga.editNga!.isLock)
let stateLock = nga.editNga!.points.count < 3 || nga.editNga!.name.isEmpty
Button{
if var ngaData = nga.editNga {
ngaData.isLock.toggle()
nga.editNga = ngaData
nga.editType = EditNgaType.nonEdit
}
}label:{
if nga.editNga!.isLock {
Image(systemName: "lock.fill")
.foregroundColor(Color.white)
.scaledToFit()
.frame(height: 18)
} else {
Image(systemName: "lock.open.fill")
.foregroundColor(stateLock ? ColorSet.BodyDescriptiion.color : ColorSet.Body.color)
.scaledToFit()
.frame(height: 18)
}
}
.disabled(stateLock)
.padding(.horizontal, 30)
}
.onAppear(perform: {
if let name = nga.editNga?.name {
taskViewModel.ngaName = name
}
})
// HStack {
// Button{
// var ngaData = nga.editNga!
// ngaData.isRunning.toggle()
// ngaData.passingCnt = 0
// nga.editNga = ngaData
// }label:{
// HStack {
// Text("Watch")
// .font(FontStyle.EmphasisText.font)
// .foregroundColor(nga.editNga!.isLock ? ColorSet.BodyDescriptiion.color : ColorSet.Body.color)
//
// if nga.editNga!.isRunning {
// Image(systemName: "checkmark.square.fill")
// .resizable()
// .frame(width: 22, height: 22)
// } else {
// Image(systemName: "square")
// .resizable()
// .frame(width: 22, height: 22)
// }
// }
// .padding(.vertical, 17)
// .padding(.horizontal, 30)
// }
// .disabled(nga.editNga!.isLock)
//
// Button{
// var ngaData = nga.editNga!
// ngaData.isLock.toggle()
// nga.editNga = ngaData
// }label:{
// HStack {
// Text("Lock")
// .font(FontStyle.EmphasisText.font)
// .foregroundColor(ColorSet.Body.color)
//
// if nga.editNga!.isLock {
// Image(systemName: "checkmark.square.fill")
// .resizable()
// .frame(width: 22, height: 22)
// } else {
// Image(systemName: "square")
// .resizable()
// .frame(width: 22, height: 22)
// }
// }
// .padding(.horizontal, 30)
// }
// }
HStack {
let stateEdit = nga.editNga!.isLock ? true : nga.editType != EditNgaType.nonEdit
Button(action: {
nga.editType = EditNgaType.addPoint
}, label: {
Text("Edit polygon")
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(stateEdit ? ColorSet.SecondaryDisable.color : ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
.padding(.vertical, 20)
.disabled(stateEdit)
let stateRegister = nga.editNga!.points.count < 3 || nga.editNga!.name.isEmpty
Button(action: {
if var ngaData = nga.editNga {
ngaData.name = taskViewModel.ngaName
nga.editType = EditNgaType.registered
nga.editNgaArea(value: ngaData, type: NgaOperation.Change)
}
taskViewModel.viewMode = .NgaNotification
}, label: {
Text("Register")
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(stateRegister ? ColorSet.SecondaryDisable.color : ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
.padding(.vertical, 20)
.disabled(stateRegister)
}
}
}
}
/**
* ポイント位置移動
*/
struct NgaPointSetting: View {
@ObservedObject var taskViewModel: TaskViewModel
@State private var selectLat = Array(repeating: 0, count: 4)
@State private var selectLon = Array(repeating: 0, count: 4)
var body: some View {
ZStack {
VStack(spacing: 0) {
HStack {
Picker("", selection: $selectLat[0]) {
Text("N")
Text("S")
}.pickerStyle(.wheel)
Picker("", selection: $selectLat[1]) {
ForEach((0...89), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text("°").padding(.horizontal, 0)
Picker("", selection: $selectLat[2]) {
ForEach((0...59), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text(".").padding(.horizontal, 0)
Picker("", selection: $selectLat[3]) {
ForEach((0...999), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text("'").padding(.horizontal, 0)
}
.frame(width: 350, height: 60)
.onChange(of: selectLat) { value in
changeLocationDouble()
}
HStack {
Picker("", selection: $selectLon[0]) {
Text("E")
Text("W")
}.pickerStyle(.wheel)
Picker("", selection: $selectLon[1]) {
ForEach((0...179), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text("°").padding(.horizontal, 0)
Picker("", selection: $selectLon[2]) {
ForEach((0...59), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text(".").padding(.horizontal, 0)
Picker("", selection: $selectLon[3]) {
ForEach((0...999), id:\.self) { num in
Text("\(num)")
}
}.pickerStyle(.wheel)
Text("'").padding(.horizontal, 0)
}
.frame(width: 350, height: 60)
.onChange(of: selectLon) { value in
changeLocationDouble()
}
HStack {
Button(action: {
SharingData.nga.editType = EditNgaType.deletePoint
}, label: {
Text("Delete")
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
.padding(.vertical, 20)
Button(action: {
SharingData.nga.editType = EditNgaType.addPoint
}, label: {
Text("Set")
.font(FontStyle.DefaultText.font)
.padding()
})
.frame(width: 153, height: 42)
.foregroundColor(ColorSet.ButtonText.color)
.background(ColorSet.PrimaryActiveIcon.color)
.cornerRadius(30)
.padding(.vertical, 20)
}
}
}
.onAppear(perform: {
changeLocationArray()
})
.onChange(of: selectLat) { newValue in
changeLocationDouble()
}
}
/**
* Picker情報用に位置情報を分解
*/
func changeLocationArray() {
if let no = SharingData.nga.selectPoint {
if let location = SharingData.nga.editNga?.points[no] {
selectLat = LocationCalculation.latDegtoInt(lat: location.latitude)
selectLon = LocationCalculation.lonDegtoInt(lon: location.longitude)
}
}
}
/**
* Picker情報から位置情報に変換
*/
func changeLocationDouble() {
if let no = SharingData.nga.selectPoint {
var location = SharingData.nga.editNga!.points[no]
location.latitude = LocationCalculation.latInttoDouble(lat: selectLat)!
location.longitude = LocationCalculation.lonInttoDouble(lon: selectLon)!
SharingData.nga.editNga!.points[no] = location
SharingData.nga.targetLocation = location
}
}
}
#Preview {
NgaSettingView(taskViewModel: TaskViewModel())
}
#Preview {
NgaSetting(taskViewModel: TaskViewModel())
}
#Preview {
NgaPointSetting(taskViewModel: TaskViewModel())
}
......@@ -8,8 +8,8 @@
import Foundation
class TaskViewModel: ObservableObject{
@Published var viewMode: TaskViewMode = .SwitchingMenu
@Published var viewMode: TaskViewMode = .MenuList
@Published var edittingEcaArea: RegisteredEca? = nil
@Published var ecaName: String = ""
@Published var isShowSettingView : Bool = false
@Published var ngaName: String = ""
}
......@@ -10,7 +10,7 @@ import SwiftUI
struct MenuTitleView: View {
@Binding var path : [MenuPath]
var title = "Menu"
var title = "Menu Functions"
var body: some View {
VStack {
HStack{
......
//
// DeleteNgaArea.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/05/20.
//
import Foundation
class DeleteNgaArea {
var sessionNgaList = SessionNgaList()
func start(areaId : String) {
print(debug: "called")
sessionNgaList.RequestDeleteNgaList(areaId, completion: responseDeleteNgaList)
}
private func responseDeleteNgaList(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let resultData):
print(debug: resultData)
case .failure(let errorCode):
print(debug: errorCode)
break
}
}
}
//
// GetNgaList.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/15.
//
import Foundation
import SwiftUI
import CoreLocation
class GetNgaList {
@ObservedObject var ngaData = SharingData.nga
var sessionNgaList = SessionNgaList()
func start() {
print(debug: "called")
sessionNgaList.RequestGetNgaList(responseGetNgaList)
}
private func responseGetNgaList(result: Result<Data, APIError>) {
print(debug: "called")
print(debug: "Test: GetNgaList")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: [ReqNgaList].self)
if let res = resjson {
var ngaAreas = ngaData.ngaArea
for ngaList in res {
if let id = NSUUID(uuidString: ngaList.id) {
if var nga = ngaAreas[id as UUID] {
print(debug: "Test: 1\(nga)")
// nga.name = ngaList.name
nga.isLock = ngaList.lock
nga.points.removeAll()
for pos in ngaList.geometry{
let point = CLLocationCoordinate2D(latitude: pos.lat!, longitude: pos.lon!)
nga.points.append(point)
}
ngaAreas.updateValue(nga, forKey: nga.areaId)
print(debug: "Test: 2\(nga)")
} else {
if var nga = RegisteredNga(areaName: "test dammy") { //TODO: 名称はダミー
nga.areaId = id as UUID
nga.isLock = ngaList.lock
nga.isRunning = ngaList.enabled
if !ngaList.enabled {
nga.passingCnt = 0
}
nga.color = Color.green.description
for pos in ngaList.geometry{
let point = CLLocationCoordinate2D(latitude: pos.lat!, longitude: pos.lon!)
nga.points.append(point)
}
ngaAreas.updateValue(nga, forKey: nga.areaId)
}
}
}
for ares in ngaAreas {
ngaData.setNgaArea(key: ares.value.areaId, value: ares.value)
}
}
}
case .failure(let errorCode):
print(debug: errorCode)
break
}
}
}
//
// NgaTask.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/11.
//
import Foundation
class NgaTask {
var ngaData = SharingData.nga
/**
* Nga通知
*/
private func notificationNga(point: SwitchingAlert, name: String) {
let alertDB = AlertDB.OnlyOne
var wernrec = WarnRecord(title:"Nga", body:"")
wernrec = alertDB.GetAlertNgaPoint(point: point)
let formatstr = wernrec.title + name
wernrec.title = String(format: formatstr)
let voicemanager = AlertManager.OnlyOne
voicemanager.VocalizeAlert(alertrec: wernrec, identifier: .NgaAlert)
}
func checkNga() {
ngaData.ngaArea.forEach { nga in
if nga.value.isRunning {
if let location = SharingData.location.location {
var shipPos = LocationCalculation.AreaLatLon()
shipPos.NorthLat = location.latitude
shipPos.SouthLat = location.latitude
shipPos.EastLon = location.longitude
shipPos.WestLon = location.longitude
var areaPoints = nga.value.points
areaPoints.append(nga.value.points[0])
let isInside = LocationCalculation.checkBeset(objPos: areaPoints, minMax: shipPos, exceed180: false)
var area = nga.value
if isInside {
//通過中
area.passingCnt += 1
let test = area.passingCnt
print(debug: "Test: \(test)")
ngaData.editNgaArea(value: area, type: NgaOperation.Passing)
if area.passingCnt == 1 {
let areaName = nga.value.name
notificationNga(point: SwitchingAlert.NgaPassing, name: areaName)
}
} else {
if area.passingCnt > 0 {
//通過
area.passingCnt = 0
ngaData.editNgaArea(value: area, type: NgaOperation.Passing)
}
}
}
}
}
}
}
//
// RegistereNga.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/05/16.
//
import Foundation
import CoreLocation
import SwiftUI
let ngaAreaMax = 30
let ngaAreaPointMax = 50
enum EditNgaType {
case nonEdit
case addPoint
case movePoint
case deletePoint
case registered
}
struct RegisteredNga {
var areaId = UUID()
var isLock: Bool = false
var isRunning: Bool = false
var passingCnt: Int = 0 //1以上で通過中
var name: String = "" //Area名称
var datetime: String = "" //時刻(UTC ISO8601準拠)
var color = Color.green.description //ライン色(ARGB)
var width: Int = 1 //ライン幅
var points: [CLLocationCoordinate2D] = []
init?(areaName: String ) {
self.name = areaName
}
}
//
// SetNgaArea.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/14.
//
import Foundation
import SwiftUI
class SetNgaArea {
@ObservedObject var ngaData = SharingData.nga
var sessionNgaList = SessionNgaList()
func start(nga : ReqNgaList) {
print(debug: "called")
sessionNgaList.RequestPostNgaList(nga, completion: responsePostNgaList)
}
private func responsePostNgaList(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let errorCode):
print(debug: "success: \(errorCode)")
case .failure(let errorCode):
print(debug: "failure: \(errorCode)")
break
}
}
}
......@@ -211,32 +211,29 @@ class ServerSession{
func httpBody(boundary: String, _ uploadImage : ReqUploadImage) -> Data! {
var httpBody1 = "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"shipId\"\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"ShipId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.shipId)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"messageId\"\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"MessageId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.messageId)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"location\"\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"Location\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.location)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"from\"\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"From\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.from)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"fromId\"\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"FromId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.fromId)\r\n"
httpBody1 += "--\(boundary)\r\n"
// httpBody1 += "Content-Disposition: form-data; name=\"files\"; filename=\"\(uploadImage.files)\"\r\n"
httpBody1 += "Content-Type: image/jpeg\r\n"
httpBody1 += "\r\n"
// var tmp = httpBody1.data(using: .utf8)!
var httpBody = Data()
httpBody.append(httpBody1.data(using: .utf8)!)
httpBody.append(uploadImage.files)
......
//
// SessionNgaList.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/06/14.
//
import Foundation
import SwiftUI
class SessionNgaList : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionNgaList()
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
/**
* タスクリスト取得
*/
func RequestGetNgaList(_ completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = Preferences.shipId
if id != 0 {
var url_string : String = HttpRequestType.NgaList.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.getJson(req_url, completion: completion)
}
}
/**
* タスク保存
*/
func RequestPostNgaList(_ nga : ReqNgaList, completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = Preferences.shipId
if id != 0 {
var url_string : String = HttpRequestType.NgaList.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
if let postdata = serverSession.toJSON(nga) {
serverSession.postJson(req_url, postdata, completion: completion)
}
else {
Calling = false
return
}
}
}
/**
* NGAタスク削除
*/
func RequestDeleteNgaList(_ ngaId : String, completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = Preferences.shipId
if id != 0 {
let strId = String(id) + "/" + ngaId
var url_string : String = HttpRequestType.NgaList.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: strId)
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.deleteJson(req_url, completion: completion)
}
}
}
......@@ -33,8 +33,7 @@ class SessionUploadImage : ObservableObject {
return
}
// let boundary = "----------" + UUID().uuidString
let boundary = "----WebKitFormBoundaryZLdHZy8HNaBmUX0d"
let boundary = "----------" + uploadImage.messageId
if let postdata = serverSession.httpBody(boundary: boundary, uploadImage) {
serverSession.postForm(boundary: boundary, req_url, postdata, completion: completion)
}
......
......@@ -8,7 +8,7 @@ import Foundation
import CoreLocation
class SharingData{
static var my = My()
class My: ObservableObject {
@Published var id: Int = 0
......@@ -112,23 +112,7 @@ class SharingData{
@Published var legLine: [CLLocationCoordinate2D] = []
@Published var portLine: [CLLocationCoordinate2D] = []
@Published var starboardLine: [CLLocationCoordinate2D] = []
}
static var message = Message()
class Message: ObservableObject {
@Published var mode: Bool = false // false:通常 , true:Warning中
@Published var messages: [ChatMessage] = []
@Published var users: [ChatUser] = []
@Published var viewCnt: Int = 0 //未読数
func changeMode(){
self.mode.toggle()
}
}
static var information = Information()
class Information: ObservableObject {
@Published var content: [ResInformation] = []
@Published var isMapFree: Bool = false
}
/**
......@@ -139,7 +123,7 @@ class SharingData{
@Published var ecaArea: Dictionary<Int, RegisteredEca> = [:]
@Published var focusEca: Int? = nil
@Published var isShowEcaAlert: Bool = false
func setEcaArea(key: Int, value: RegisteredEca) {
ecaArea.updateValue(value, forKey: key)
}
......@@ -218,7 +202,7 @@ class SharingData{
task.status = setEcaStatus(eca: value)
}
setEcaArea.start(eca: task)
case EcaOperation.Cancel:
case EcaOperation.Cancel:
task.areaId = value.areaId
task.taskName = value.name
task.noticeRange = value.swNotice
......@@ -267,6 +251,91 @@ class SharingData{
}
}
/**
* Nga Area
*/
static var nga = Nga()
class Nga: ObservableObject {
@Published var ngaArea: Dictionary<UUID, RegisteredNga> = [:]
@Published var editType = EditNgaType.nonEdit
@Published var editNga: RegisteredNga? = nil
@Published var moveNga: RegisteredNga? = nil
@Published var focusNga: String? = nil
@Published var targetLocation: CLLocationCoordinate2D? = nil //UserMark.movePointLocation
@Published var selectPoint: Int?
func setNgaArea(key: UUID, value: RegisteredNga) {
ngaArea.updateValue(value, forKey: key)
}
func editNgaArea(value: RegisteredNga, type: NgaOperation) {
let setNgaArea = SetNgaArea()
var task = ReqNgaList(Id: value.areaId.uuidString)
switch type {
case NgaOperation.Change:
task.id = value.areaId.uuidString
task.enabled = value.isRunning
task.lock = value.isLock
for point in value.points {
let position = points(lat: point.latitude, lon: point.longitude)
task.geometry.append(position)
}
setNgaArea.start(nga: task)
ngaArea.updateValue(value, forKey: value.areaId)
break
case NgaOperation.Delete:
let deleteNgaArea = DeleteNgaArea()
deleteNgaArea.start(areaId: value.areaId.uuidString)
ngaArea.removeValue(forKey: value.areaId)
break
case NgaOperation.Running:
task.id = value.areaId.uuidString
task.enabled = value.isRunning
task.lock = value.isLock
for point in value.points {
let position = points(lat: point.latitude, lon: point.longitude)
task.geometry.append(position)
}
setNgaArea.start(nga: task)
ngaArea.updateValue(value, forKey: value.areaId)
break
case NgaOperation.Passing:
ngaArea.updateValue(value, forKey: value.areaId)
break
case NgaOperation.Cancel:
task.id = value.areaId.uuidString
task.enabled = value.isRunning
task.lock = value.isLock
for point in value.points {
let position = points(lat: point.latitude, lon: point.longitude)
task.geometry.append(position)
}
setNgaArea.start(nga: task)
ngaArea.updateValue(value, forKey: value.areaId)
break
}
}
}
static var message = Message()
class Message: ObservableObject {
@Published var mode: Bool = false // false:通常 , true:Warning中
@Published var messages: [ChatMessage] = []
@Published var users: [ChatUser] = []
@Published var viewCnt: Int = 0 //未読数
func changeMode(){
self.mode.toggle()
}
}
static var information = Information()
class Information: ObservableObject {
@Published var content: [ResInformation] = []
}
static var pushHistory = PushHistory()
class PushHistory: ObservableObject{
@Published var pushHistoryData: Dictionary<Int, ResPushHistory> = [:]
......
......@@ -20,6 +20,14 @@ enum EcaOperation {
case Cancel
}
enum NgaOperation {
case Change
case Delete
case Running
case Cancel
case Passing
}
enum ShipAlert {
case Offline
case Unknown
......
......@@ -8,8 +8,8 @@
import SwiftUI
enum Tab: String, CaseIterable{
case chat = "tab_chat"
case task = "tab_task"
case chat = "tab_chat"
case alert = "tab_notification"
case menu = "tab_menu"
......@@ -41,9 +41,12 @@ struct MainTabView: View {
ChatView()
.tag(Tab.chat)
MapRepresentable()
.ignoresSafeArea()
.tag(Tab.task)
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea()
.tag(Tab.task)
NotificationView()
.tag(Tab.alert)
......@@ -53,7 +56,7 @@ struct MainTabView: View {
}
.hideNativeTabBar()
.sheet(isPresented: .constant(isTaskSel && isTabShow && SharingData.my.isFuelSwitchTask), content: {
MapTaskView()
MenuTaskView()
.zIndex(0)
.presentationDragIndicator(.hidden)
.presentationDetents([.height(150), .medium, .fraction(0.99)])
......@@ -81,7 +84,7 @@ struct MainTabView: View {
}
.hideNativeTabBar()
.popover(isPresented: .constant(isPopover && SharingData.my.isFuelSwitchTask), attachmentAnchor: .point(.bottom)) {
MapTaskView()
MenuTaskView()
.presentationCompactAdaptation(.none)
.zIndex(0)
.frame(minWidth: 300, maxHeight: 500)
......
......@@ -19,10 +19,6 @@ class AlertManager {
var lastSpeech: String = ""
// 警報を鳴らす。引数の型定義はAlertDB.swift
func VocalizeAlert( alertrec : WarnRecord ) {
VocalizeAlert( alertrec: alertrec, identifier: .EcaSwitching)
}
func VocalizeAlert( alertrec : WarnRecord, identifier : PushNotificationTypes.LocalPushIdentifier ) {
print(debug: "alertrec = \(alertrec)")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment