From f1f51c946d9b965ed5c31624085cdb040ad615bc Mon Sep 17 00:00:00 2001 From: AmyangXYZ Date: Thu, 28 Dec 2023 12:33:46 -0500 Subject: [PATCH] draw endsystem links --- src/hooks/useDrawMiniMap.ts | 63 +++++++++++++++++++++-------- src/hooks/useDrawTopology.ts | 77 ++++++++++++++++++++++++++---------- src/networks/5G/network.ts | 13 +++--- src/networks/TSCH/network.ts | 10 +++-- src/networks/TSN/network.ts | 16 +++----- src/networks/common.ts | 63 +++++++++++++++-------------- 6 files changed, 155 insertions(+), 87 deletions(-) diff --git a/src/hooks/useDrawMiniMap.ts b/src/hooks/useDrawMiniMap.ts index 2d23da5..c42db5d 100644 --- a/src/hooks/useDrawMiniMap.ts +++ b/src/hooks/useDrawMiniMap.ts @@ -3,6 +3,7 @@ import * as echarts from 'echarts' import { Network } from './useStates' import { MiniMapMode } from './useStates' +import { LINK_TYPE } from '@/networks/common' export function useDrawMiniMap(chartDom: HTMLElement) { const chart = echarts.init(chartDom, { useDirtyRect: true }) @@ -98,23 +99,44 @@ export function useDrawMiniMap(chartDom: HTMLElement) { name: n.id, value: n.pos }) - for (const nn of n.neighbors) { - const linkName = n.id < nn ? `${n.id}-${nn}` : `${nn}-${n.id}` - if (drawnLinks[linkName] == undefined) { - drawnLinks[linkName] = true - option.series[0].markLine.data.push([ - { - name: linkName, - label: { - show: false - }, - coord: n.pos - }, - { - coord: Network.Nodes.value[nn].pos - } - ]) + } + for (const e of Network.EndSystems.value) { + option.series[0].data.push({ + name: e.id, + value: e.pos, + itemStyle: { color: 'green' } + }) + } + for (const l of Object.values(Network.Links.value)) { + if (drawnLinks[l.uid] == undefined) { + drawnLinks[l.uid] = true + let coord1: [number, number], coord2: [number, number] + if (l.v1 <= Network.TopoConfig.value.num_nodes) { + coord1 = Network.Nodes.value[l.v1].pos + } else { + coord1 = Network.EndSystems.value[l.v1 - Network.TopoConfig.value.num_nodes - 1].pos } + if (l.v2 <= Network.TopoConfig.value.num_nodes) { + coord2 = Network.Nodes.value[l.v2].pos + } else { + coord2 = Network.EndSystems.value[l.v2 - Network.TopoConfig.value.num_nodes - 1].pos + } + + option.series[0].markLine.data.push([ + { + name: l.uid, + label: { + show: false + }, + lineStyle: { + type: l.type == LINK_TYPE.WIRELESS ? 'dashed' : 'solid' + }, + coord: coord1 + }, + { + coord: coord2 + } + ]) } } } @@ -148,6 +170,15 @@ export function useDrawMiniMap(chartDom: HTMLElement) { }, { deep: true } ) + watch( + Network.EndSystems, + () => { + drawMinimapScatter() + drawMinimapTree() + chart.setOption(option) + }, + { deep: true } + ) watch(MiniMapMode, () => { if (MiniMapMode.value == 'scatter') { diff --git a/src/hooks/useDrawTopology.ts b/src/hooks/useDrawTopology.ts index 891a3fd..745a61a 100644 --- a/src/hooks/useDrawTopology.ts +++ b/src/hooks/useDrawTopology.ts @@ -8,7 +8,14 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import { DragControls } from 'three/examples/jsm/controls/DragControls.js' import Stats from 'three/examples/jsm/libs/stats.module' import * as TWEEN from '@tweenjs/tween.js' -import { NODE_TYPE, NETWORK_TYPE, type Packet, type LinkMeta, LINK_TYPE } from '@/networks/common' +import { + NODE_TYPE, + NETWORK_TYPE, + type Packet, + type LinkMeta, + LINK_TYPE, + END_SYSTEM_TYPE +} from '@/networks/common' export function useDrawTopology(dom: HTMLElement) { const scene = new THREE.Scene() @@ -303,7 +310,7 @@ export function useDrawTopology(dom: HTMLElement) { }) for (const node of Network.Nodes.value) { - if (node.id == 0 || node.type != NODE_TYPE.FiveGUE) continue + if (node.id == 0 || node.type != NODE_TYPE.FIVE_G_UE) continue let modelGroup: any = {} const model = modelTemplate.clone() @@ -374,19 +381,19 @@ export function useDrawTopology(dom: HTMLElement) { model.position.set(es.pos[0], positionY, es.pos[1]) model.traverse((object: any) => { if (object.isMesh) { - object.userData.type = NODE_TYPE[4] // EndSystem + object.userData.type = END_SYSTEM_TYPE[es.type] object.userData.node_id = es.id } }) scene.add(model) - const label = createLabel(`${NODE_TYPE[4]}-${es.id}`) + const label = createLabel(`${END_SYSTEM_TYPE[es.type]}-${es.id}`) label.position.set(model.position.x, labelY, model.position.z) scene.add(label) const { dragBox, dragBoxHelper } = createDragBox(es, model) - drawnNodes[`${NODE_TYPE[4]}-${es.id}`] = { + drawnNodes[`${END_SYSTEM_TYPE[es.type]}-${es.id}`] = { model, label, modelGroup: model, @@ -442,16 +449,37 @@ export function useDrawTopology(dom: HTMLElement) { } } const drawLink = (l: LinkMeta) => { - const p1 = new THREE.Vector3( - Network.Nodes.value[l.v1].pos[0], - 1.6, - Network.Nodes.value[l.v1].pos[1] - ) - const p3 = new THREE.Vector3( - Network.Nodes.value[l.v2].pos[0], - 1.6, - Network.Nodes.value[l.v2].pos[1] - ) + let p1: THREE.Vector3 + if (l.v1 <= Network.TopoConfig.value.num_nodes) { + p1 = new THREE.Vector3( + Network.Nodes.value[l.v1].pos[0], + 1.6, + Network.Nodes.value[l.v1].pos[1] + ) + } else { + // is an end system + p1 = new THREE.Vector3( + Network.EndSystems.value[l.v1 - Network.TopoConfig.value.num_nodes - 1].pos[0], + 1.6, + Network.EndSystems.value[l.v1 - Network.TopoConfig.value.num_nodes - 1].pos[1] + ) + } + + let p3: THREE.Vector3 + if (l.v2 <= Network.TopoConfig.value.num_nodes) { + p3 = new THREE.Vector3( + Network.Nodes.value[l.v2].pos[0], + 1.6, + Network.Nodes.value[l.v2].pos[1] + ) + } else { + // is an end system + p3 = new THREE.Vector3( + Network.EndSystems.value[l.v2 - Network.TopoConfig.value.num_nodes - 1].pos[0], + 1.6, + Network.EndSystems.value[l.v2 - Network.TopoConfig.value.num_nodes - 1].pos[1] + ) + } const x2 = (p1.x + p3.x) / 2 const z2 = (p1.z + p3.z) / 2 @@ -468,7 +496,7 @@ export function useDrawTopology(dom: HTMLElement) { color: 'white', scale: 2, dashSize: 1, - gapSize: 1, + gapSize: 1 }) ) mesh.computeLineDistances() @@ -761,7 +789,7 @@ export function useDrawTopology(dom: HTMLElement) { let relatedBeaconPacket: any = undefined dragControls.deactivate() dragControls.addEventListener('dragstart', function (event) { - if (event.object.userData.type == 'TSCH') { + if (NODE_TYPE[event.object.userData.type] != undefined) { const node = event.object.userData.node_id for (const l of Object.values(drawnLinks)) { if (l.link.v1 == node || l.link.v2 == node) { @@ -793,10 +821,17 @@ export function useDrawTopology(dom: HTMLElement) { event.object.position.y = 0 if (NODE_TYPE[event.object.userData.type] != undefined) { - Network.Nodes.value[event.object.userData.node_id].pos = [ - event.object.position.x, - event.object.position.z - ] + if (event.object.userData.node_id <= Network.TopoConfig.value.num_nodes) { + Network.Nodes.value[event.object.userData.node_id].pos = [ + event.object.position.x, + event.object.position.z + ] + } else { + // is an end system + Network.EndSystems.value[ + event.object.userData.node_id - Network.TopoConfig.value.num_nodes - 1 + ].pos = [event.object.position.x, event.object.position.z] + } for (const l of relatedLinks) { clearLink(l.link.uid) diff --git a/src/networks/5G/network.ts b/src/networks/5G/network.ts index 54b34cf..9b9984e 100644 --- a/src/networks/5G/network.ts +++ b/src/networks/5G/network.ts @@ -1,7 +1,7 @@ import { ref } from 'vue' import { LINK_TYPE, Network, NETWORK_TYPE, NODE_TYPE } from '../common' import type { ScheduleConfig, FiveGNodeMeta } from './typedefs' -import { SeededRandom } from '@/hooks/useSeed' +import { KDNode } from '../TSN/kdtree' export class FiveGNetwork extends Network { constructor() { @@ -15,7 +15,6 @@ export class FiveGNetwork extends Network { } createNodes = () => { this.Nodes = ref([]) - const rand = new SeededRandom(this.TopoConfig.value.seed) // clear old nodes and webworkers if (this.Nodes.value.length > 1) { @@ -28,7 +27,7 @@ export class FiveGNetwork extends Network { this.Nodes.value = [ { id: 0, - type: NODE_TYPE.FiveGBS, + type: NODE_TYPE.FIVE_G_BS, pos: [0, 0], neighbors: [], queueLen: 0, @@ -41,11 +40,11 @@ export class FiveGNetwork extends Network { for (let i = 1; i <= this.TopoConfig.value.num_nodes; i++) { const n = { id: i, - type: NODE_TYPE.FiveGUE, + type: NODE_TYPE.FIVE_G_UE, pos: [ - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2, - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2 ], neighbors: [], @@ -53,6 +52,8 @@ export class FiveGNetwork extends Network { rx_cnt: 0, w: new Worker(new URL('@/networks/5G/node.ts', import.meta.url), { type: 'module' }) } + this.KDTree.Insert(new KDNode(i, n.pos)) + // add links super.addLink(0, i, LINK_TYPE.WIRELESS) diff --git a/src/networks/TSCH/network.ts b/src/networks/TSCH/network.ts index 986be21..d257c51 100644 --- a/src/networks/TSCH/network.ts +++ b/src/networks/TSCH/network.ts @@ -8,9 +8,9 @@ import type { ASSOC_RSP_PKT_PAYLOAD } from './typedefs' import { ADDR, MSG_TYPES, PKT_TYPES, CELL_TYPES } from './typedefs' -import { SeededRandom } from '@/hooks/useSeed' import { LINK_TYPE, Network, NETWORK_TYPE, NODE_TYPE } from '../common' import type { Packet, Message, MsgHandler } from '../common' +import { KDNode } from '../TSN/kdtree' export class TSCHNetwork extends Network { doneCnt = 0 @@ -35,6 +35,7 @@ export class TSCHNetwork extends Network { this.registerMsgHandler(MSG_TYPES.ASSOC_REQ, this.assocReqMsgHandler) this.createNodes() + super.createEndSystems() this.createSchedule() watch(this.ASN, () => { @@ -117,7 +118,6 @@ export class TSCHNetwork extends Network { createNodes = () => { this.Nodes = ref([]) - const rand = new SeededRandom(this.TopoConfig.value.seed) // clear old nodes if (this.Nodes.value.length > 1) { @@ -148,9 +148,9 @@ export class TSCHNetwork extends Network { id: i, type: NODE_TYPE.TSCH, pos: [ - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2, - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2 ], joined: i == ADDR.ROOT, @@ -162,6 +162,8 @@ export class TSCHNetwork extends Network { rank: 0, w: new Worker(new URL('@/networks/TSCH/node.ts', import.meta.url), { type: 'module' }) } + this.KDTree.Insert(new KDNode(i, n.pos)) + // send init msg n.w!.postMessage({ type: MSG_TYPES.INIT, diff --git a/src/networks/TSN/network.ts b/src/networks/TSN/network.ts index d4d32c1..af4c96c 100644 --- a/src/networks/TSN/network.ts +++ b/src/networks/TSN/network.ts @@ -1,8 +1,7 @@ import { ref, toRaw } from 'vue' import { Network, NETWORK_TYPE, NODE_TYPE, type Message, LINK_TYPE } from '../common' import { MSG_TYPES, type INIT_MSG_PAYLOAD, type ScheduleConfig, type TSNNodeMeta } from './typedefs' -import { SeededRandom } from '@/hooks/useSeed' -import { KDNode, KDTree } from './kdtree' +import { KDNode } from './kdtree' export class TSNNetwork extends Network { InPorts: any @@ -16,10 +15,10 @@ export class TSNNetwork extends Network { num_slots: 40 }) this.createNodes() + super.createEndSystems() } createNodes = () => { this.Nodes = ref([]) - const rand = new SeededRandom(this.TopoConfig.value.seed) // clear old nodes and webworkers if (this.Nodes.value.length > 1) { @@ -42,17 +41,14 @@ export class TSNNetwork extends Network { } ] // placeholder - // to find neighbors - const tree = new KDTree() - for (let i = 1; i <= this.TopoConfig.value.num_nodes; i++) { const n = { id: i, type: NODE_TYPE.TSN, pos: [ - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2, - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2 ], neighbors: [], @@ -72,11 +68,11 @@ export class TSNNetwork extends Network { }) this.Nodes.value.push(n) - tree.Insert(new KDNode(i, this.Nodes.value[i].pos)) + this.KDTree.Insert(new KDNode(i, n.pos)) } for (let i = 1; i <= this.TopoConfig.value.num_nodes; i++) { - this.Nodes.value[i].neighbors = tree.FindKNearest( + this.Nodes.value[i].neighbors = this.KDTree.FindKNearest( this.Nodes.value[i].pos, 3, this.TopoConfig.value.tx_range diff --git a/src/networks/common.ts b/src/networks/common.ts index 99b19d6..a2c673f 100644 --- a/src/networks/common.ts +++ b/src/networks/common.ts @@ -1,5 +1,6 @@ import { ref, type Ref } from 'vue' import { SeededRandom } from '@/hooks/useSeed' +import { KDTree } from './TSN/kdtree' export enum NETWORK_TYPE { TSCH, @@ -10,9 +11,15 @@ export enum NETWORK_TYPE { export enum NODE_TYPE { TSCH, TSN, - FiveGBS, - FiveGUE, - EndSystem + FIVE_G_BS, + FIVE_G_UE +} + +export enum END_SYSTEM_TYPE { + Server, + RoboticArm, + Sensor + // add more and find the corresponding 3D models } export interface NodeMeta { @@ -38,20 +45,6 @@ export enum LINK_TYPE { WIRELESS } -export enum END_SYSTEM_TYPE { - Server, - RoboticArm, - Sensor - // add more and find the corresponding 3D models -} - -export interface EndSystemMeta { - id: number - type: number - pos: number[] - neighbor: number // an es only connects with one network node/switch/base-station -} - // Packet is transfered among nodes, at data-link layer export interface Packet { uid: number @@ -91,10 +84,11 @@ export interface TopologyConfig { export class Network { ID: number Type: number - Nodes: any - Links = ref<{ [uid: number]: LinkMeta }>([]) + Nodes: any // tsn bridges, tsch node or 5g ue/bs EndSystems: any + Links = ref<{ [uid: number]: LinkMeta }>([]) TopoConfig: Ref + KDTree: KDTree SchConfig: any Schedule: any Packets = ref([]) @@ -107,6 +101,8 @@ export class Network { Running = ref(false) SlotDuration = ref(750) + Rand: SeededRandom + constructor() { this.ID = 1 this.Type = -1 @@ -117,30 +113,37 @@ export class Network { grid_size: 80, tx_range: 25 }) - this.createEndSystems() + this.Rand = new SeededRandom(this.TopoConfig.value.seed) + this.KDTree = new KDTree() } - createEndSystems = () => { + // call after create nodes + createEndSystems() { // initialize ref array if it does not already exist - this.EndSystems = ref([]) - const rand = new SeededRandom(this.TopoConfig.value.seed) + this.EndSystems = ref([]) this.EndSystems.value = [] // clear any old end systems for (let i = 1; i <= this.TopoConfig.value.num_es; i++) { - const es = { - id: i, + const es = { + id: i + this.TopoConfig.value.num_nodes, type: Math.floor( - rand.next() * Object.keys(END_SYSTEM_TYPE).filter((key) => isNaN(Number(key))).length + this.Rand.next() * Object.keys(END_SYSTEM_TYPE).filter((key) => isNaN(Number(key))).length ), // Object.keys(...).filter(...) is used to count # of elements in enum pos: [ - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2, - Math.floor(rand.next() * this.TopoConfig.value.grid_size) - + Math.floor(this.Rand.next() * this.TopoConfig.value.grid_size) - this.TopoConfig.value.grid_size / 2 ], - neighbor: 1 + Math.floor(rand.next() * this.TopoConfig.value.num_nodes) // range from 1 to num_nodes inclusive + tx_cnt: 0, + rx_cnt: 0, + neighbors: [], + w: undefined + } + es.neighbors = this.KDTree.FindKNearest(es.pos, 1, this.TopoConfig.value.grid_size) + if (es.neighbors.length > 0) { + this.addLink(es.id, es.neighbors[0], LINK_TYPE.WIRED) } - this.EndSystems.value.push(es) } }