From cee979fec856e1ad3d85bf23d5e1066d1af41c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kv=C3=A1=C4=8Dek?= Date: Mon, 15 Apr 2024 18:13:22 +0200 Subject: [PATCH] Zakladni verze planovace --- public/mapIcons/airport.png | Bin 0 -> 797 bytes .../flightPlans/FlightPlanRoute.vue | 23 + .../flightPlans/FlightPlansList.vue | 2 +- .../pokusy_o_chytre_vlozeni_markeru.js | 104 +++++ src/components/map/MapWrapper.vue | 67 +-- src/composables/flightPlan.js | 13 + src/graphql/fragments/flightPlan.js | 32 +- src/graphql/fragments/vectorUtilities.js | 46 ++ src/graphql/mutations/flightPlan.js | 6 +- src/graphql/queries/flightPlan.js | 12 +- src/pages/profile/flight/EditFlightPage.vue | 6 +- .../flightPlanner/FlightPlanEditPage.vue | 442 +++++++++++++++--- .../flightPlanner/NewFlightPlanPage.vue | 203 +------- src/router/routes.js | 2 +- src/stores/FlightPlans.js | 18 +- 15 files changed, 672 insertions(+), 304 deletions(-) create mode 100644 public/mapIcons/airport.png create mode 100644 src/components/flightPlans/FlightPlanRoute.vue create mode 100644 src/components/flightPlans/pokusy_o_chytre_vlozeni_markeru.js create mode 100644 src/composables/flightPlan.js create mode 100644 src/graphql/fragments/vectorUtilities.js diff --git a/public/mapIcons/airport.png b/public/mapIcons/airport.png new file mode 100644 index 0000000000000000000000000000000000000000..27053493ce44a27d5d905d919f8d258fe2b77e49 GIT binary patch literal 797 zcmV+&1LFLNP)EX>4Tx04R}tkvmAkP!xv$KBOX*4t5Z6$WRr;E-K-UJ*ouY7FBNGxa%9Ov7`1-NVQCyExDCzW3+qR|+Nrd;)QT>4rtTK|Hf* z>74h8qpU0`#OK5l1~o|h$aUG}H_j!8{X8>jWHa-`QDULg#c~(3vY`@B6UP))qkMnP zWrgz=XSG^q?LPSn!v$?+nd?-;NMR965FtQD9TikzAx^tSiir%JCq4W_j$b5~Os)zT zITlcZ3d!+<|H1Fsn#HL}Hz}M1dR}b%V+0880jVfq16NwdUuy!hpQJZB zTI>jjYy%h99ZlW?E_Z;zCtWfmM+#8+i$&o5jJ_!k4BP^JYwq0I=Qw=;vNWso4RCM> zjFu>S-Q(T8-E;f*PJ4bop-XbPpQ1|$00006VoOIv0RI600RN!9r;`8x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=mZZ2F)bV~qO1S_02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{008w#L_t(I%dOMPN&`UfqgS9_YuYE2;?E>4_ zO!j&an5h9r97miKjnY_ bObd@M*8fRvY?XRy00000NkvXXu0mjf)ND*5 literal 0 HcmV?d00001 diff --git a/src/components/flightPlans/FlightPlanRoute.vue b/src/components/flightPlans/FlightPlanRoute.vue new file mode 100644 index 0000000..ba8e482 --- /dev/null +++ b/src/components/flightPlans/FlightPlanRoute.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/components/flightPlans/FlightPlansList.vue b/src/components/flightPlans/FlightPlansList.vue index faf07ce..a4a1510 100644 --- a/src/components/flightPlans/FlightPlansList.vue +++ b/src/components/flightPlans/FlightPlansList.vue @@ -13,7 +13,7 @@ const props = defineProps({ diff --git a/src/components/flightPlans/pokusy_o_chytre_vlozeni_markeru.js b/src/components/flightPlans/pokusy_o_chytre_vlozeni_markeru.js new file mode 100644 index 0000000..a6b9cb3 --- /dev/null +++ b/src/components/flightPlans/pokusy_o_chytre_vlozeni_markeru.js @@ -0,0 +1,104 @@ +import {computed} from "vue"; + + + +const markersCenter = computed(() => { + if (markers.value.length === 0) return null; + + return { + gpsLatitude: markers.value.map(m => m.gpsLatitude).reduce((a, b) => a + b) / markers.value.length, + gpsLongitude: markers.value.map(m => m.gpsLongitude).reduce((a, b) => a + b) / markers.value.length, + } +}); + + +const calcAngleFromCenter = (pointA, pointB) => { + if (!markersCenter.value) return 0; + + const u = vector(markersCenter.value, pointA); + const v = vector(markersCenter.value, pointB); + + return Math.acos( + (u[0] * v[0] + u[1] * v[1]) + / + (vectorSize(u) * vectorSize(v)) + ) +} + +let targetPosition = null; +let minAngleDiff = Infinity; +let mapPoints = 1; + +const handleMapClickNefunkcni = (position) => { + const clickPoint = {gpsLatitude: position.lat, gpsLongitude: position.lng}; + + const clickAngle = calcAngleFromCenter(clickPoint, markers.value[0]); + + for (let i = 1; i < markers.value.length - 1; i++) { + const marker = markers.value[i]; + const angle = calcAngleFromCenter(marker, markers.value[0]); + + const angleDiff = clickAngle - angle; + console.log("click", i, marker.name, angleDiff); + if (angleDiff < minAngleDiff) { + console.log(" update => ", minAngleDiff, " > ", Math.abs(angleDiff), marker.name, " -> ", markers.value[i + 1].name); + minAngleDiff = angleDiff + targetPosition = Math.max(1, angleDiff < 0 ? i - 1 : i + 1); + } + + // console.log(marker.name, angle); + } + + console.log("click", clickAngle); + console.log("insert at position", targetPosition); + console.log("---------------") + markers.value.splice(targetPosition, 0, {name: `Bod v mape ${mapPoints}`, type: "mapPoint", ...clickPoint}); + mapPoints++; +} + +const handleMapClickNefunkcni2 = (position) => { + const clickPoint = {gpsLatitude: position.lat, gpsLongitude: position.lng} + + const markersToSort = markers.value.slice(1, -1); + markersToSort.push({name: `Bod v mape ${mapPoints}`, type: "mapPoint", ...clickPoint}); + + markersToSort.sort( + (a, b) => calcAngleFromCenter(a, markers.value[0]) - calcAngleFromCenter(b, markers.value[0]) + ); + + for (const marker of markersToSort) { + console.log(marker.name, calcAngleFromCenter(marker, markers.value[0])); + } + + markers.value = [markers.value[0], ...markersToSort, markers.value[markers.value.length - 1]]; + mapPoints++; +} + +const calcTotalDistance = (points) => { + let distance = 0; + for (let i = 1; i < points.length; i++) { + distance += vectorDistance(points[i-1], points[i]) + } + return distance +} + +let minDistance = Infinity; +const handleMapClick = (position) => { + const clickPoint = {gpsLatitude: position.lat, gpsLongitude: position.lng}; + const newMarker = {name: `Bod v mape ${mapPoints}`, type: "mapPoint", ...clickPoint} + markers.value.push(newMarker) + + for (let i = 1; i < markers.value.length - 1; i++) { + console.log(markers.value[i], clickPoint); + const dist = vectorDistance(markers.value[i], clickPoint); + + if (dist < minDistance) { + minDistance = dist; + targetPosition = i; + } + } + + targetPosition = Math.min(markers.value.length - 1, Math.max(1, targetPosition)); + markers.value.splice(targetPosition, 0, {name: `Bod v mape ${mapPoints}`, type: "mapPoint", ...clickPoint}); + mapPoints++; +} diff --git a/src/components/map/MapWrapper.vue b/src/components/map/MapWrapper.vue index 8088c54..984330a 100644 --- a/src/components/map/MapWrapper.vue +++ b/src/components/map/MapWrapper.vue @@ -1,6 +1,7 @@ diff --git a/src/composables/flightPlan.js b/src/composables/flightPlan.js new file mode 100644 index 0000000..e7b5bc0 --- /dev/null +++ b/src/composables/flightPlan.js @@ -0,0 +1,13 @@ +export const useFlightPlanUtils = () => { + const getIcon = (type) => { + const icons = { + "poi": "pin_drop", + "geocode": "travel_explore", + "airport": "local_airport" + }; + + return icons[type] || "place" + } + + return { getIcon } +} diff --git a/src/graphql/fragments/flightPlan.js b/src/graphql/fragments/flightPlan.js index 8874cb1..462865b 100644 --- a/src/graphql/fragments/flightPlan.js +++ b/src/graphql/fragments/flightPlan.js @@ -1,20 +1,36 @@ import gql from "graphql-tag"; +export const FRAGMENT_FLIGHT_PLAN_MARKER = gql` +fragment flightPlanMarker on FlightPlanMarker { + name + position + type + gpsLatitude + gpsLongitude +} +` + export const FRAGMENT_FLIGHT_PLAN_FULL_INFO = gql` fragment flightPlanFullInfo on FlightPlan { id name - markers { - name - position - type - gpsLatitude - gpsLongitude + track { + bearing + distance + from { + ...flightPlanMarker + } + to { + ...flightPlanMarker + } } -}`; +} + +${FRAGMENT_FLIGHT_PLAN_MARKER} +`; export const FRAGMENT_FLIGHT_PLAN_LIST_INFO = gql` -fragment flightPlanListInfo on FlightPlanListInfo { +fragment flightPlanListInfo on FlightPlan { id name } diff --git a/src/graphql/fragments/vectorUtilities.js b/src/graphql/fragments/vectorUtilities.js new file mode 100644 index 0000000..f8da0e2 --- /dev/null +++ b/src/graphql/fragments/vectorUtilities.js @@ -0,0 +1,46 @@ +export const useBasicVectorOperations = () => { + const vectorSize = (a) => { + return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2)); + } + + const vector = (pointA, pointB) => { + return [pointA.gpsLatitude - pointB.gpsLatitude, pointA.gpsLongitude - pointB.gpsLongitude]; + } + + const vectorDistance = (pointA, pointB) => { + console.log("pointA", pointA, "pointB", pointB); + + const u = [pointA.gpsLatitude, pointA.gpsLongitude]; + const v = [pointB.gpsLatitude, pointB.gpsLongitude]; + // const v = vector(pointB); + + return Math.sqrt( + Math.pow(u[0] - v[0], 2) + Math.pow(u[1] - v[1], 2) + ); + } + + return {vector, vectorSize, vectorDistance} +} + +export const useVectorUtities = () => { + + + function isPointInPolygon(clickPoint, polygonCoords) { + let count = 0; + const x = clickPoint.lng, y = clickPoint.lat; + + for (let i = 0; i < polygonCoords.length; i++) { + const iNext = (i + 1) % polygonCoords.length; + + const xi = polygonCoords[i].lng, yi = polygonCoords[i].lat; + const xiNext = polygonCoords[iNext].lng, yiNext = polygonCoords[iNext].lat; + + const test = ((yi > y) !== (yiNext > y)) && (x < (xiNext - xi) * (y - yi) / (yiNext - yi) + xi); + if (test) count++; + } + + return count % 2 === 1; // Lichý počet průsečíků = bod uvnitř + } + + return {isPointInPolygon} +} diff --git a/src/graphql/mutations/flightPlan.js b/src/graphql/mutations/flightPlan.js index a3a65fa..73335cd 100644 --- a/src/graphql/mutations/flightPlan.js +++ b/src/graphql/mutations/flightPlan.js @@ -2,7 +2,7 @@ import gql from "graphql-tag"; import {FRAGMENT_FLIGHT_PLAN_FULL_INFO} from "src/graphql/fragments/flightPlan"; export const CREATE_FLIGHT_PLAN = gql` - mutation createFlight_Plan($input: CreateFlightPlanInput!) { + mutation createFlightPlan($input: CreateFlightPlanInput!) { createFlightPlan(input: $input) { ...flightPlanFullInfo } @@ -13,8 +13,8 @@ export const CREATE_FLIGHT_PLAN = gql` export const EDIT_FLIGHT_PLAN = gql` mutation editFlightPlan($id: Int!, $input: EditFlightPlanInput!) { - editFlight_Plan(id: $id, input: $input) { - ...flight_planFullInfo + editFlightPlan(id: $id, input: $input) { + ...flightPlanFullInfo } } ${FRAGMENT_FLIGHT_PLAN_FULL_INFO} diff --git a/src/graphql/queries/flightPlan.js b/src/graphql/queries/flightPlan.js index f10e73e..280a9b5 100644 --- a/src/graphql/queries/flightPlan.js +++ b/src/graphql/queries/flightPlan.js @@ -1,5 +1,5 @@ import gql from "graphql-tag"; -import {FRAGMENT_FLIGHT_PLAN_LIST_INFO} from "src/graphql/fragments/flightPlan"; +import {FRAGMENT_FLIGHT_PLAN_FULL_INFO, FRAGMENT_FLIGHT_PLAN_LIST_INFO} from "src/graphql/fragments/flightPlan"; export const FLIGHT_PLANS_LIST = gql` query flightPlansList { @@ -10,3 +10,13 @@ query flightPlansList { ${FRAGMENT_FLIGHT_PLAN_LIST_INFO} `; + +export const FLIGHT_PLAN_DETAIL = gql` +query flightPlansDetail($id: Int!) { + flightPlan(id: $id) { + ...flightPlanFullInfo + } +} + +${FRAGMENT_FLIGHT_PLAN_FULL_INFO} +`; diff --git a/src/pages/profile/flight/EditFlightPage.vue b/src/pages/profile/flight/EditFlightPage.vue index 2df4981..5408228 100644 --- a/src/pages/profile/flight/EditFlightPage.vue +++ b/src/pages/profile/flight/EditFlightPage.vue @@ -34,6 +34,8 @@ import {useEventsStore} from "stores/Events"; import FlightEditCopilotSkeleton from "components/flights/skeletons/FlightEditCopilotSkeleton.vue"; import {useBasicPhotoOperations} from "src/composables/photos/basicOperations"; import {usePhotosStore} from "stores/Photos"; +import {flightName} from "src/composables/flight"; +import {useAppStore} from "stores/App"; const $q = useQuasar(); const $route = useRoute(); @@ -47,12 +49,10 @@ const {events} = storeToRefs(useEventsStore()); const {photos} = storeToRefs(usePhotosStore()); const {flight, isQueryRunning, isRequestPending: isMutationRunning} = storeToRefs(useFlightsStore()); + const formStep = ref("basic"); watch(() => $route.params.step, (val) => formStep.value = val); -import {flightName} from "src/composables/flight"; -import {useAppStore} from "stores/App"; - const flightNameFormatted = flightName(flight.value); useAppStore().setPageTitle(`Editace - ${flightNameFormatted}`); useAppStore().setBreadcrumbs([ diff --git a/src/pages/profile/flightPlanner/FlightPlanEditPage.vue b/src/pages/profile/flightPlanner/FlightPlanEditPage.vue index 41692d2..421951c 100644 --- a/src/pages/profile/flightPlanner/FlightPlanEditPage.vue +++ b/src/pages/profile/flightPlanner/FlightPlanEditPage.vue @@ -1,76 +1,402 @@ + + diff --git a/src/pages/profile/flightPlanner/NewFlightPlanPage.vue b/src/pages/profile/flightPlanner/NewFlightPlanPage.vue index d0d11ff..371a865 100644 --- a/src/pages/profile/flightPlanner/NewFlightPlanPage.vue +++ b/src/pages/profile/flightPlanner/NewFlightPlanPage.vue @@ -1,202 +1,21 @@ diff --git a/src/router/routes.js b/src/router/routes.js index 2e049a6..68c7fb4 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -50,7 +50,7 @@ const routes = [ {path: 'plany', name: "flightPlans", component: () => import('pages/profile/flightPlanner/FlightPlansPage.vue')}, {path: 'plany/novy', name: "newFlightPlan", component: () => import('pages/profile/flightPlanner/NewFlightPlanPage.vue')}, - {path: 'plany/:id', name: "flightPlan", component: () => import('pages/profile/flightPlanner/FlightPlanEditPage.vue')}, + {path: 'plany/:id', name: "editFlightPlan", component: () => import('pages/profile/flightPlanner/FlightPlanEditPage.vue')}, {path: 'poi', name: "poi", component: () => import('pages/profile/poi/PointsOfInterestPage.vue')}, {path: 'poi/novy', name: "addPOI", component: () => import('pages/profile/poi/NewPointOfInterestPage.vue')}, diff --git a/src/stores/FlightPlans.js b/src/stores/FlightPlans.js index 5b53de6..cca00ec 100644 --- a/src/stores/FlightPlans.js +++ b/src/stores/FlightPlans.js @@ -1,5 +1,5 @@ import {defineStore} from 'pinia' -import {FLIGHT_PLANS_LIST} from "src/graphql/queries/flightPlan"; +import {FLIGHT_PLAN_DETAIL, FLIGHT_PLANS_LIST} from "src/graphql/queries/flightPlan"; import {CREATE_FLIGHT_PLAN, EDIT_FLIGHT_PLAN} from "src/graphql/mutations/flightPlan"; import {mutate, query, updateInItems} from "stores/helpers"; import {ref} from "vue"; @@ -10,13 +10,13 @@ export const useFlightPlansStore = defineStore('FlightPlans', () => { const isMutationRunning = ref(false); const isQueryRunning = ref(false); - // const fetchDetail = (id) => { - // return query({ - // isQueryRunning, - // query: FLIGHT_PLAN_DETAIL, - // variables: {id}, - // }).then(item => flightPlan.value = item); - // }; + const fetchDetail = (id) => { + return query({ + isQueryRunning, + query: FLIGHT_PLAN_DETAIL, + variables: {id}, + }).then(item => flightPlan.value = item); + }; const fetch = () => { return query({ @@ -50,6 +50,6 @@ export const useFlightPlansStore = defineStore('FlightPlans', () => { return { flightPlan, flightPlans, isMutationRunning, isQueryRunning, - fetch, create, update + fetch, fetchDetail, create, update } })