From 8bae1d064a016c16047d65a7b6630f7b5210a2ff Mon Sep 17 00:00:00 2001 From: Kaveh Hajinajaf Date: Sat, 10 May 2025 20:48:03 +0330 Subject: [PATCH] ADD: Utm Convert FIX: Features data not saving and not loading --- package-lock.json | 17 +++ package.json | 2 + src/utm.js | 78 ++++++++++++ src/views/pages/Belonging/CreateBelonging.vue | 111 +++++++++++++++--- .../pages/Belonging/TransactionDialog.vue | 68 ++++++++++- src/views/uikit/MapComponent.vue | 23 +++- 6 files changed, 272 insertions(+), 27 deletions(-) create mode 100644 src/utm.js diff --git a/package-lock.json b/package-lock.json index e5cbcce..b2d1b20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,8 @@ "photoswipe": "^5.4.4", "primeicons": "^7.0.0", "primevue": "^4.2.4", + "usng.js": "^0.4.5", + "utm-latlng": "^1.0.8", "v-mapbox": "^5.1.0", "vue": "^3.4.34", "vue-cookies": "^1.8.3", @@ -4794,12 +4796,27 @@ "punycode": "^2.1.0" } }, + "node_modules/usng.js": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/usng.js/-/usng.js-0.4.5.tgz", + "integrity": "sha512-JTJcFFDy/JqA5iiU8DqMOV5gJiL3ZdXH0hCKYaRMDbbredhFna5Ok4C1YDFU07mTGAgm+5FzHaaOzQnO/3BzWQ==", + "license": "MIT", + "bin": { + "usng-cli": "bin/cli.js" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/utm-latlng": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/utm-latlng/-/utm-latlng-1.0.8.tgz", + "integrity": "sha512-jQ5l1BNTzNgas7jXOIh0jU0m5PU5LtmjYvRiLwR4iymYYAhEhQ6N0MGCnLjv5iO958b9tLMMSmzdbIIhLtXqCg==", + "license": "MIT" + }, "node_modules/v-mapbox": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/v-mapbox/-/v-mapbox-5.1.0.tgz", diff --git a/package.json b/package.json index 0ecd677..ff2da84 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "photoswipe": "^5.4.4", "primeicons": "^7.0.0", "primevue": "^4.2.4", + "usng.js": "^0.4.5", + "utm-latlng": "^1.0.8", "v-mapbox": "^5.1.0", "vue": "^3.4.34", "vue-cookies": "^1.8.3", diff --git a/src/utm.js b/src/utm.js new file mode 100644 index 0000000..f129249 --- /dev/null +++ b/src/utm.js @@ -0,0 +1,78 @@ +// Converts UTM coordinates to latitude and longitude + +const a = 6378137.0; // WGS84 Major axis +const eccSquared = 0.00669438; // WGS84 eccentricity squared +const k0 = 0.9996; // Scale factor + +function UTMtoLatLon(UTMEasting, UTMNorthing, UTMZoneNumber, Hemisphere) { + const e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared)); + let x = UTMEasting - 500000.0; + let y = UTMNorthing; + + if (Hemisphere === 'S') { + y -= 10000000.0; + } + + const LongOrigin = (UTMZoneNumber - 1) * 6 - 180 + 3; + const eccPrimeSquared = eccSquared / (1 - eccSquared); + const M = y / k0; + const mu = M / (a * (1 - eccSquared / 4 - (3 * eccSquared ** 2) / 64 - (5 * eccSquared ** 3) / 256)); + + let phi1Rad = mu + ((3 * e1) / 2 - (27 * e1 ** 3) / 32) * Math.sin(2 * mu) + ((21 * e1 ** 2) / 16 - (55 * e1 ** 4) / 32) * Math.sin(4 * mu) + ((151 * e1 ** 3) / 96) * Math.sin(6 * mu); + + const N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) ** 2); + const T1 = Math.tan(phi1Rad) ** 2; + const C1 = eccPrimeSquared * Math.cos(phi1Rad) ** 2; + const R1 = (a * (1 - eccSquared)) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) ** 2, 1.5); + const D = x / (N1 * k0); + + let lat = phi1Rad - ((N1 * Math.tan(phi1Rad)) / R1) * (D ** 2 / 2 - ((5 + 3 * T1 + 10 * C1 - 4 * C1 ** 2 - 9 * eccPrimeSquared) * D ** 4) / 24 + ((61 + 90 * T1 + 298 * C1 + 45 * T1 ** 2 - 252 * eccPrimeSquared - 3 * C1 ** 2) * D ** 6) / 720); + lat *= 180 / Math.PI; + + let lon = (D - ((1 + 2 * T1 + C1) * D ** 3) / 6 + ((5 - 2 * C1 + 28 * T1 - 3 * C1 ** 2 + 8 * eccPrimeSquared + 24 * T1 ** 2) * D ** 5) / 120) / Math.cos(phi1Rad); + lon = LongOrigin + (lon * 180) / Math.PI; + + return { latitude: lat, longitude: lon }; +} + +// Converts latitude and longitude to UTM coordinates +function LatLontoUTM(lat, lon) { + const LatRad = (lat * Math.PI) / 180.0; + const LongRad = (lon * Math.PI) / 180.0; + + const ZoneNumber = Math.floor((lon + 180) / 6) + 1; + const LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; + const LongOriginRad = (LongOrigin * Math.PI) / 180.0; + + const eccPrimeSquared = eccSquared / (1 - eccSquared); + const N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) ** 2); + const T = Math.tan(LatRad) ** 2; + const C = eccPrimeSquared * Math.cos(LatRad) ** 2; + const A = Math.cos(LatRad) * (LongRad - LongOriginRad); + + const M = + a * + ((1 - eccSquared / 4 - (3 * eccSquared ** 2) / 64 - (5 * eccSquared ** 3) / 256) * LatRad - + ((3 * eccSquared) / 8 + (3 * eccSquared ** 2) / 32 + (45 * eccSquared ** 3) / 1024) * Math.sin(2 * LatRad) + + ((15 * eccSquared ** 2) / 256 + (45 * eccSquared ** 3) / 1024) * Math.sin(4 * LatRad) - + ((35 * eccSquared ** 3) / 3072) * Math.sin(6 * LatRad)); + + let UTMEasting = k0 * N * (A + ((1 - T + C) * A ** 3) / 6 + ((5 - 18 * T + T ** 2 + 72 * C - 58 * eccPrimeSquared) * A ** 5) / 120) + 500000.0; + + let UTMNorthing = k0 * (M + N * Math.tan(LatRad) * (A ** 2 / 2 + ((5 - T + 9 * C + 4 * C ** 2) * A ** 4) / 24 + ((61 - 58 * T + T ** 2 + 600 * C - 330 * eccPrimeSquared) * A ** 6) / 720)); + + const Hemisphere = lat < 0 ? 'S' : 'N'; + if (lat < 0) { + UTMNorthing += 10000000.0; + } + + return { + easting: UTMEasting, + northing: UTMNorthing, + zoneNumber: ZoneNumber, + hemisphere: Hemisphere + }; +} + +// Exporting functions as a module +export { UTMtoLatLon, LatLontoUTM }; diff --git a/src/views/pages/Belonging/CreateBelonging.vue b/src/views/pages/Belonging/CreateBelonging.vue index bf5b849..eb1010f 100644 --- a/src/views/pages/Belonging/CreateBelonging.vue +++ b/src/views/pages/Belonging/CreateBelonging.vue @@ -47,7 +47,6 @@ const route = useRoute(); const router = useRouter(); const mapKey = 'web.79abbab4970e401781f434da3e41cfa6'; const serviceKey = 'service.11d860f52c434bd29e5f84d0a0a41108'; -const mapRef = ref(); const transactions = ref([]); const stockData = ref({}); @@ -118,6 +117,7 @@ onBeforeMount(async () => { if (route.name === 'edit-belonging') { editMode.value = true; belonging.value = await BelongingService.getBelonging(route.params.belongingId); + featuresValues.value = extractFeaturesValues(belonging.value.features); transactions.value = await TransactionService.getTransactionsByBelongingId(route.params.belongingId); stockData.value = await TransactionService.getStockByBelongingId(route.params.belongingId); mainImageUrlsWithData.value = fillImagesArray(belonging.value?.mainImageUrls || []); @@ -126,6 +126,67 @@ onBeforeMount(async () => { }); const showTransactionDialog = ref(false); +import { UTMtoLatLon, LatLontoUTM } from '@/utm'; + +const easting = ref(); +const northing = ref(); +const zone = ref(); +const lat = ref(); +const long = ref(); + +const convertUTMtoLatLng = () => { + if (easting.value && northing.value && zone.value) { + try { + const result = UTMtoLatLon( + Number(easting.value), + Number(northing.value), + Number(zone.value), + 'N' // Change to 'S' if in Southern Hemisphere + ); + lat.value = result.latitude; + long.value = result.longitude; + console.log(lat.value, long.value); + searchLocation(lat.value, long.value); + } catch (error) { + console.error('Error converting UTM to Lat/Lng:', error); + } + } +}; + +// Watch nationalGeoCode to split and convert to Lat/Lng +watch( + () => belonging.value.nationalGeoCode, + (newCode) => { + if (newCode && newCode.length === 15) { + easting.value = newCode.substring(0, 6); // First 6 digits for easting + northing.value = newCode.substring(6, 13); // Next 6 digits for northing + zone.value = newCode.substring(13, 15); // Last 2 digits for zone + // Convert to Lat/Lng after splitting + convertUTMtoLatLng(); + } + } +); + +const mapRef = ref(); + +const searchLocation = (lat, lon) => { + if (mapRef.value) { + mapRef.value.searchByCoordinates(lat, lon); + } +}; + +watch( + () => belonging.value.category, + (newCategory) => { + if (editMode.value && newCategory) { + selectedCategory.value = categories.value.find((x) => x._id === newCategory); + if (selectedCategory.value) { + features.value = selectedCategory.value.features; + } + } + } +); + const fillImagesArray = (imageUrls) => { const images = []; for (let url of imageUrls) { @@ -161,12 +222,36 @@ const handleSelectCategory = ($event) => { } }; +const extractFeatures = (featuresValues) => { + const features = []; + + for (const [key, value] of Object.entries(featuresValues)) { + features.push({ + definition: key, + value: value + }); + } + + return features; +}; + +const extractFeaturesValues = (features) => { + const featuresValues = {}; + + for (let feature of features) { + featuresValues[feature.definition] = feature.value; + } + + return featuresValues; +}; + const saveBelonging = async () => { let status = 'failed'; console.log(belonging); if (belonging?.value._id?.trim()) { belonging.value.mainImageUrls = mainImageUrlsWithData.value.map((x) => x.url); belonging.value.documentUrls = documentUrlsWithData.value.map((x) => x.url); + belonging.value.features = extractFeatures(featuresValues.value); status = await BelongingService.updateBelonging(belonging.value._id, belonging.value); } else { status = await BelongingService.createBelonging(belonging.value); @@ -181,23 +266,6 @@ const saveBelonging = async () => { await router.push('/belonging/list-belongings'); }; -watch( - () => mapRef.value?.state.map, - (nv, ol) => { - if (ol) return; - setTimeout(() => { - mapRef.value?.state.map?.setMapType('standard-night'); - if (mapRef.value?.state.mapType) mapRef.value.state.mapType = 'standard-night'; - }, 2000); - setTimeout(() => { - mapRef.value?.search({ - term: 'ولی عصر', - coords: [51.36281969540723, 35.69672648316882] - }); - }, 3000); - } -); - const filters = ref({ global: { value: null, matchMode: FilterMatchMode.CONTAINS }, type: { value: null, matchMode: FilterMatchMode.EQUALS }, @@ -336,7 +404,7 @@ const formatDate = (dateString) => {
- +
@@ -447,6 +515,11 @@ const formatDate = (dateString) => { + +
+ + +
diff --git a/src/views/pages/Belonging/TransactionDialog.vue b/src/views/pages/Belonging/TransactionDialog.vue index 8e02683..da45ad0 100644 --- a/src/views/pages/Belonging/TransactionDialog.vue +++ b/src/views/pages/Belonging/TransactionDialog.vue @@ -1,5 +1,5 @@