电子地图绘制备用
This commit is contained in:
parent
c06acfd0b8
commit
5400acf7e3
@ -1 +1 @@
|
|||||||
Subproject commit 1f53057b3f87790ef27c91399a5bb7e890f05549
|
Subproject commit 64e48a0441eedd0b7bc926ca922b2fb58075467b
|
@ -7,7 +7,7 @@ const os = require('os');
|
|||||||
|
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
const messageDir = resolve(__dirname, '../rtss-proto-msg');
|
const messageDir = resolve(__dirname, '../rtsa-proto-msg');
|
||||||
const protoDir = resolve(messageDir, 'src');
|
const protoDir = resolve(messageDir, 'src');
|
||||||
const destDir = resolve(__dirname, '../src/protos');
|
const destDir = resolve(__dirname, '../src/protos');
|
||||||
|
|
||||||
|
49
src/components/draw-app/electronicMapDrawProperties.vue
Normal file
49
src/components/draw-app/electronicMapDrawProperties.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 绘制图形模板属性 -->
|
||||||
|
<div v-if="drawStore.drawMode">
|
||||||
|
<q-card flat>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">{{ drawStore.drawGraphicName + ' 模板' }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator inset></q-separator>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
<!-- 画布或图形对象属性 -->
|
||||||
|
<div v-else-if="drawStore.selectedGraphics !== null">
|
||||||
|
<q-card flat>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">{{ drawStore.selectedObjName + ' 属性' }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator inset></q-separator>
|
||||||
|
<template v-if="drawStore.selectedGraphics.length === 0">
|
||||||
|
<q-card-section>
|
||||||
|
<canvas-property></canvas-property>
|
||||||
|
</q-card-section>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="drawStore.selectedGraphics.length === 1">
|
||||||
|
<q-card-section>
|
||||||
|
<platform-property
|
||||||
|
v-if="drawStore.selectedGraphicType === Platform.Type"
|
||||||
|
></platform-property>
|
||||||
|
</q-card-section>
|
||||||
|
</template>
|
||||||
|
<!-- <template v-else-if="drawStore.selectedGraphics.length > 1">
|
||||||
|
<multiple-select-property></multiple-select-property>
|
||||||
|
</template> -->
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import CanvasProperty from './properties/CanvasElectronicMapProperty.vue';
|
||||||
|
import PlatformProperty from './properties/electronicMap/PlatformProperty.vue';
|
||||||
|
import { Platform } from 'src/graphics/electronicMap/platform/Platform';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
watch(
|
||||||
|
() => drawStore.selectedGraphics,
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
</script>
|
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<q-form>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model.number="canvas.width"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="画布宽 *"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => (val && val > 0) || '画布宽必须大于0']"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
type="number"
|
||||||
|
v-model.number="canvas.height"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="画布高 *"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => val > 0 || '画布高必须大于0']"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model="canvas.backgroundColor"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="画布背景色 *"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => (val && val.length > 0) || '画布背景色必须设置']"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="colorize" class="cursor-pointer">
|
||||||
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
|
<q-color
|
||||||
|
:model-value="canvas.backgroundColor"
|
||||||
|
@change="
|
||||||
|
(val) => {
|
||||||
|
canvas.backgroundColor = val;
|
||||||
|
onUpdate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import { onMounted, onUnmounted, reactive } from 'vue';
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
|
||||||
|
const canvas = reactive({
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// console.log('画布属性表单mounted');
|
||||||
|
const jc = drawStore.getJlCanvas();
|
||||||
|
canvas.width = jc.properties.width;
|
||||||
|
canvas.height = jc.properties.height;
|
||||||
|
canvas.backgroundColor = jc.properties.backgroundColor;
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// console.log('画布属性表单unmounted');
|
||||||
|
});
|
||||||
|
|
||||||
|
function onUpdate() {
|
||||||
|
// console.log('画布属性更新');
|
||||||
|
const app = drawStore.getDrawApp();
|
||||||
|
app.updateCanvasAndRecord({
|
||||||
|
...canvas,
|
||||||
|
viewportTransform: app.canvas.properties.viewportTransform,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<q-card class="q-gutter-sm q-pa-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">一键生成计轴配置</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-form ref="myForm">
|
||||||
|
<selectConfig-utils ref="selectConfigUtils" :drawStore="drawStore" />
|
||||||
|
<div class="q-mt-md q-gutter-md">
|
||||||
|
<q-btn label="确认修改" color="primary" @click="onSubmit" />
|
||||||
|
<q-btn label="返回" color="red" @click="goBack" />
|
||||||
|
<q-btn label="生成计轴" color="primary" @click="generateAxleCounting" />
|
||||||
|
</div>
|
||||||
|
<div class="q-mt-md q-gutter-md">
|
||||||
|
<q-btn
|
||||||
|
label="检查计轴"
|
||||||
|
color="primary"
|
||||||
|
@click="showErrorAxleCounting"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
v-if="showCheck"
|
||||||
|
label="上一个"
|
||||||
|
color="primary"
|
||||||
|
@click="clickSelectCenter(-1)"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
v-if="showCheck"
|
||||||
|
label="下一个"
|
||||||
|
color="primary"
|
||||||
|
@click="clickSelectCenter(1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref, provide } from 'vue';
|
||||||
|
import { QForm, useQuasar } from 'quasar';
|
||||||
|
import { JlGraphic } from 'jl-graphic';
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
import { Turnout } from 'src/graphics/electronicMap/turnout/Turnout';
|
||||||
|
import {
|
||||||
|
loadGenerateAxleCountingConfig,
|
||||||
|
setGenerateAxleCountingConfig,
|
||||||
|
} from 'src/drawApp/electronicMapApp';
|
||||||
|
import SelectConfigUtils from 'src/components/common/SelectConfigUtils.vue';
|
||||||
|
import { OneClickGenerate } from 'src/graphics/electronicMap/trainWindow/oneClickDrawAssistant';
|
||||||
|
import { AxleCounting } from 'src/graphics/electronicMap/axleCounting/AxleCounting';
|
||||||
|
|
||||||
|
//供公共选择组件使用
|
||||||
|
const filterSelect = (g: JlGraphic) => g instanceof Turnout;
|
||||||
|
const selectConfigUtils = ref<InstanceType<typeof SelectConfigUtils> | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
provide('filter', filterSelect);
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
selectConfigUtils.value.selectConfig = [
|
||||||
|
{
|
||||||
|
code: 'bb连接的道岔',
|
||||||
|
refDevices: [],
|
||||||
|
refDevicesCode: [],
|
||||||
|
expanded: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '不生成计轴的道岔组',
|
||||||
|
refDevices: [],
|
||||||
|
refDevicesCode: [],
|
||||||
|
expanded: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const generateAxleCountingConfig = loadGenerateAxleCountingConfig();
|
||||||
|
if (generateAxleCountingConfig !== undefined) {
|
||||||
|
selectConfigUtils.value.selectConfig.forEach(
|
||||||
|
(generate: {
|
||||||
|
code: string;
|
||||||
|
refDevices: number[];
|
||||||
|
refDevicesCode: string[];
|
||||||
|
}) => {
|
||||||
|
if (generate.code == 'bb连接的道岔') {
|
||||||
|
generate.refDevices = generateAxleCountingConfig.bbConnect;
|
||||||
|
generateAxleCountingConfig.bbConnect.forEach((id) => {
|
||||||
|
const g = drawStore.getDrawApp().queryStore.queryById(id);
|
||||||
|
generate.refDevicesCode.push(g.code);
|
||||||
|
});
|
||||||
|
} else if (generate.code == '不生成计轴的道岔组') {
|
||||||
|
generate.refDevices = generateAxleCountingConfig.noGenerateGroup;
|
||||||
|
generateAxleCountingConfig.noGenerateGroup.forEach((id) => {
|
||||||
|
const g = drawStore.getDrawApp().queryStore.queryById(id);
|
||||||
|
generate.refDevicesCode.push(g.code);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const myForm = ref<QForm | null>(null);
|
||||||
|
async function onSubmit() {
|
||||||
|
myForm.value?.validate().then(async (res) => {
|
||||||
|
if (res) {
|
||||||
|
try {
|
||||||
|
const generateAxleCountingConfig =
|
||||||
|
new electronicMapGraphicData.GenerateAxleCountingConfig();
|
||||||
|
selectConfigUtils.value.selectConfig.forEach(
|
||||||
|
(generate: { code: string; refDevices: number[] }) => {
|
||||||
|
if (generate.code == 'bb连接的道岔') {
|
||||||
|
generateAxleCountingConfig.bbConnect = generate.refDevices;
|
||||||
|
} else if (generate.code == '不生成计轴的道岔组') {
|
||||||
|
generateAxleCountingConfig.noGenerateGroup = generate.refDevices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setGenerateAxleCountingConfig(generateAxleCountingConfig);
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: '更新成功',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: '更新失败',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateAxleCounting() {
|
||||||
|
drawStore.oneClickType = 'AxleCounting';
|
||||||
|
drawStore.getDrawApp().interactionPlugin(OneClickGenerate.Type).resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectConfig = ref<
|
||||||
|
{
|
||||||
|
axleCountingId: number;
|
||||||
|
axleCountingCode: string;
|
||||||
|
}[]
|
||||||
|
>([]);
|
||||||
|
function showErrorAxleCounting() {
|
||||||
|
showCheck.value = true;
|
||||||
|
const axleCountings = drawStore
|
||||||
|
.getDrawApp()
|
||||||
|
.queryStore.queryByType<AxleCounting>(AxleCounting.Type);
|
||||||
|
const erroeAxleCountings = axleCountings
|
||||||
|
.filter(
|
||||||
|
(g) =>
|
||||||
|
g.datas.type ==
|
||||||
|
electronicMapGraphicData.AxleCounting.TypeDetectionPoint.AxleCounting &&
|
||||||
|
g.datas.axleCountingRef.length < 2
|
||||||
|
)
|
||||||
|
.sort((a, b) => a.position.x - b.position.x);
|
||||||
|
erroeAxleCountings.forEach((axleCounting) => {
|
||||||
|
selectConfig.value.push({
|
||||||
|
axleCountingId: axleCounting.id,
|
||||||
|
axleCountingCode: axleCounting.datas.code,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentIndex = ref(-1);
|
||||||
|
const showCheck = ref(false);
|
||||||
|
function clickSelectCenter(add: number) {
|
||||||
|
if (
|
||||||
|
currentIndex.value + add < 0 ||
|
||||||
|
currentIndex.value + add >= selectConfig.value.length
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
currentIndex.value = currentIndex.value + add;
|
||||||
|
const target = drawStore
|
||||||
|
.getDrawApp()
|
||||||
|
.queryStore.queryById(
|
||||||
|
selectConfig.value[currentIndex.value].axleCountingId
|
||||||
|
);
|
||||||
|
drawStore.getDrawApp().makeGraphicCenterShow(target);
|
||||||
|
drawStore.getDrawApp().updateSelected(target);
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<q-form class="q-gutter-sm">
|
||||||
|
<q-input outlined readonly v-model="platformModel.id" label="id" />
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
label="站台编号"
|
||||||
|
type="textarea"
|
||||||
|
@blur="onUpdate"
|
||||||
|
v-model="platformModel.code"
|
||||||
|
lazy-rules
|
||||||
|
autogrow
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
label="紧急停车继电器的编号"
|
||||||
|
type="textarea"
|
||||||
|
@blur="onUpdate"
|
||||||
|
v-model="platformModel.refEsbRelayCode"
|
||||||
|
lazy-rules
|
||||||
|
autogrow
|
||||||
|
/>
|
||||||
|
<q-select
|
||||||
|
outlined
|
||||||
|
v-model="platformModel.type"
|
||||||
|
:options="platformTypeOptions"
|
||||||
|
:map-options="true"
|
||||||
|
:emit-value="true"
|
||||||
|
label="站台类型"
|
||||||
|
@update:model-value="onUpdate"
|
||||||
|
/>
|
||||||
|
<q-list bordered separator class="rounded-borders">
|
||||||
|
<q-item>
|
||||||
|
<q-item-section no-wrap class="q-gutter-y-sm column">
|
||||||
|
<q-item-label> 关联的车站 </q-item-label>
|
||||||
|
<div class="q-gutter-sm row">
|
||||||
|
<q-chip square color="primary" text-color="white">
|
||||||
|
{{ stationRelation }}
|
||||||
|
</q-chip>
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section no-wrap class="q-gutter-y-sm column">
|
||||||
|
<q-item-label> 关联的物理区段 </q-item-label>
|
||||||
|
<div class="q-gutter-sm row">
|
||||||
|
<q-chip square color="primary" text-color="white">
|
||||||
|
{{ sectionRelation }}
|
||||||
|
</q-chip>
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PlatformData } from 'src/drawApp/graphics/electronicMap/PlatformInteraction';
|
||||||
|
import { useFormData } from 'src/components/DrawAppFormUtils';
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { Platform } from 'src/graphics/electronicMap/platform/Platform';
|
||||||
|
import { Station } from 'src/graphics/electronicMap/station/Station';
|
||||||
|
import { Section } from 'src/graphics/electronicMap/section/Section';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
const { data: platformModel, onUpdate } = useFormData(
|
||||||
|
new PlatformData(),
|
||||||
|
drawStore.getDrawApp()
|
||||||
|
);
|
||||||
|
const platformTypeOptions = [
|
||||||
|
{
|
||||||
|
label: '请选择',
|
||||||
|
value: electronicMapGraphicData.Platform.TypeOfPlatform.Unknown,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '上行站台',
|
||||||
|
value: electronicMapGraphicData.Platform.TypeOfPlatform.up,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '下行站台',
|
||||||
|
value: electronicMapGraphicData.Platform.TypeOfPlatform.down,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const stationRelation = computed(() => {
|
||||||
|
const platform = drawStore.selectedGraphic as Platform;
|
||||||
|
const refStations = platform?.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(platform, Station.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<Station>(platform).datas.code);
|
||||||
|
let refStation;
|
||||||
|
if (refStations) {
|
||||||
|
refStation = refStations[0];
|
||||||
|
}
|
||||||
|
return refStation;
|
||||||
|
});
|
||||||
|
const sectionRelation = computed(() => {
|
||||||
|
const platform = drawStore.selectedGraphic as Platform;
|
||||||
|
const refSections = platform?.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(platform, Section.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<Section>(platform).datas.code);
|
||||||
|
let refStation;
|
||||||
|
if (refSections) {
|
||||||
|
refStation = refSections[0];
|
||||||
|
}
|
||||||
|
return refStation;
|
||||||
|
});
|
||||||
|
</script>
|
76
src/drawApp/electronicMapApp.ts
Normal file
76
src/drawApp/electronicMapApp.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { toUint8Array } from 'js-base64';
|
||||||
|
import { GraphicData, IDrawApp, IGraphicStorage, newDrawApp } from 'jl-graphic';
|
||||||
|
import { getDraft } from 'src/api/DraftApi';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import { PlatformDraw } from 'src/graphics/electronicMap/platform/PlatformDrawAssistant';
|
||||||
|
import { PlatformTemplate } from 'src/graphics/electronicMap/platform/Platform';
|
||||||
|
import { PlatformData } from './graphics/electronicMap/PlatformInteraction';
|
||||||
|
|
||||||
|
let electronicMapDrawApp: IDrawApp | null = null;
|
||||||
|
|
||||||
|
export function getElectronicMapDrawApp(): IDrawApp | null {
|
||||||
|
return electronicMapDrawApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroyElectronicMapDrawApp(): void {
|
||||||
|
if (electronicMapDrawApp) {
|
||||||
|
electronicMapDrawApp.destroy();
|
||||||
|
electronicMapDrawApp = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initElectronicMapDrawApp(): IDrawApp {
|
||||||
|
electronicMapDrawApp = newDrawApp({
|
||||||
|
dataLoader: loadThDrawDatas,
|
||||||
|
});
|
||||||
|
const app = electronicMapDrawApp;
|
||||||
|
new PlatformDraw(
|
||||||
|
app,
|
||||||
|
new PlatformTemplate(new PlatformData())
|
||||||
|
);
|
||||||
|
return electronicMapDrawApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadThDrawDatas(): Promise<IGraphicStorage> {
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
const id = drawStore.draftId;
|
||||||
|
if (!id) {
|
||||||
|
throw new Error('获取数据异常:为获取到草稿地图ID');
|
||||||
|
}
|
||||||
|
const base64 = (await getDraft(id)).data;
|
||||||
|
if (base64) {
|
||||||
|
const storage =
|
||||||
|
electronicMapGraphicData.ElectronicMapGraphicStorage.deserialize(
|
||||||
|
toUint8Array(base64)
|
||||||
|
);
|
||||||
|
const datas: GraphicData[] = [];
|
||||||
|
generateAxleCountingConfig = storage.generateAxleCountingConfig;
|
||||||
|
console.log(storage, 'storage');
|
||||||
|
return Promise.resolve({
|
||||||
|
canvasProperty: storage.canvas,
|
||||||
|
datas: datas,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve({
|
||||||
|
datas: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveDrawDatas() {
|
||||||
|
console.log(111);
|
||||||
|
}
|
||||||
|
|
||||||
|
//一键生成计轴配置
|
||||||
|
let generateAxleCountingConfig =
|
||||||
|
new electronicMapGraphicData.GenerateAxleCountingConfig();
|
||||||
|
export function loadGenerateAxleCountingConfig() {
|
||||||
|
return generateAxleCountingConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setGenerateAxleCountingConfig(
|
||||||
|
newScreenDoorConfig: electronicMapGraphicData.GenerateAxleCountingConfig
|
||||||
|
) {
|
||||||
|
generateAxleCountingConfig = newScreenDoorConfig;
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import {
|
||||||
|
AxleCounting,
|
||||||
|
IAxleCountingData,
|
||||||
|
} from 'src/graphics/axleCounting/AxleCounting';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { GraphicDataBase } from './GraphicDataBase';
|
||||||
|
import { KilometerSystem } from 'src/graphics/signal/Signal';
|
||||||
|
|
||||||
|
export class AxleCountingData
|
||||||
|
extends GraphicDataBase
|
||||||
|
implements IAxleCountingData
|
||||||
|
{
|
||||||
|
constructor(data?: graphicData.AxleCounting) {
|
||||||
|
let axleCounting;
|
||||||
|
if (!data) {
|
||||||
|
axleCounting = new graphicData.AxleCounting({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(AxleCounting.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
axleCounting = data;
|
||||||
|
}
|
||||||
|
super(axleCounting);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data(): graphicData.AxleCounting {
|
||||||
|
return this.getData<graphicData.AxleCounting>();
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get kilometerSystem(): KilometerSystem {
|
||||||
|
if (!this.data.kilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem();
|
||||||
|
}
|
||||||
|
return this.data.kilometerSystem;
|
||||||
|
}
|
||||||
|
set kilometerSystem(v: KilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
|
||||||
|
}
|
||||||
|
get axleCountingRef(): graphicData.RelatedRef[] {
|
||||||
|
return this.data.axleCountingRef;
|
||||||
|
}
|
||||||
|
set axleCountingRef(points: graphicData.RelatedRef[]) {
|
||||||
|
this.data.axleCountingRef = points;
|
||||||
|
}
|
||||||
|
get type(): graphicData.AxleCounting.TypeDetectionPoint {
|
||||||
|
return this.data.type;
|
||||||
|
}
|
||||||
|
set type(type: graphicData.AxleCounting.TypeDetectionPoint) {
|
||||||
|
this.data.type = type;
|
||||||
|
}
|
||||||
|
get centralizedStations(): number[] {
|
||||||
|
return this.data.centralizedStations;
|
||||||
|
}
|
||||||
|
set centralizedStations(v: number[]) {
|
||||||
|
this.data.centralizedStations = v;
|
||||||
|
}
|
||||||
|
clone(): AxleCountingData {
|
||||||
|
return new AxleCountingData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: AxleCountingData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: AxleCountingData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
148
src/drawApp/graphics/electronicMap/PlatformInteraction.ts
Normal file
148
src/drawApp/graphics/electronicMap/PlatformInteraction.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import {
|
||||||
|
IPlatformData,
|
||||||
|
Platform,
|
||||||
|
} from 'src/graphics/electronicMap/platform/Platform';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
import { GraphicDataBase } from '../GraphicDataBase';
|
||||||
|
|
||||||
|
import { IGraphicScene, GraphicInteractionPlugin, JlGraphic } from 'jl-graphic';
|
||||||
|
|
||||||
|
export class PlatformData extends GraphicDataBase implements IPlatformData {
|
||||||
|
constructor(data?: electronicMapGraphicData.Platform) {
|
||||||
|
let platform;
|
||||||
|
if (!data) {
|
||||||
|
platform = new electronicMapGraphicData.Platform({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(Platform.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
platform = data;
|
||||||
|
}
|
||||||
|
super(platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data(): electronicMapGraphicData.Platform {
|
||||||
|
return this.getData<electronicMapGraphicData.Platform>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get refStation(): number {
|
||||||
|
return this.data.refStationId;
|
||||||
|
}
|
||||||
|
set refStation(v: number) {
|
||||||
|
this.data.refStationId = v;
|
||||||
|
}
|
||||||
|
get refSection(): number {
|
||||||
|
return this.data.refSectionId;
|
||||||
|
}
|
||||||
|
set refSection(v: number) {
|
||||||
|
this.data.refSectionId = v;
|
||||||
|
}
|
||||||
|
get refEsbRelayCode(): string {
|
||||||
|
return this.data.refEsbRelayCode;
|
||||||
|
}
|
||||||
|
set refEsbRelayCode(v: string) {
|
||||||
|
this.data.refEsbRelayCode = v;
|
||||||
|
}
|
||||||
|
get type(): electronicMapGraphicData.Platform.TypeOfPlatform {
|
||||||
|
return this.data.type;
|
||||||
|
}
|
||||||
|
set type(v: electronicMapGraphicData.Platform.TypeOfPlatform) {
|
||||||
|
this.data.type = v;
|
||||||
|
}
|
||||||
|
clone(): PlatformData {
|
||||||
|
return new PlatformData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: PlatformData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: PlatformData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* export class PlatformState extends GraphicStateBase implements IPlatformState {
|
||||||
|
constructor(proto?: state.PlatformState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.PlatformState();
|
||||||
|
}
|
||||||
|
super(states, Platform.Type);
|
||||||
|
}
|
||||||
|
get id(): number {
|
||||||
|
return this.states.id;
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
get states(): state.PlatformState {
|
||||||
|
return this.getState<state.PlatformState>();
|
||||||
|
}
|
||||||
|
get empj(): boolean {
|
||||||
|
return this.states.empj;
|
||||||
|
}
|
||||||
|
get spksState(): state.ReplyState[] {
|
||||||
|
if (!this.states.spksState) {
|
||||||
|
this.states.spksState = [new state.ReplyState()];
|
||||||
|
}
|
||||||
|
return this.states.spksState;
|
||||||
|
}
|
||||||
|
set spksState(v: state.ReplyState[]) {
|
||||||
|
this.states.spksState = v;
|
||||||
|
}
|
||||||
|
get mkxJState(): state.MkxJState {
|
||||||
|
if (!this.states.mkxJState) {
|
||||||
|
this.states.mkxJState = new state.MkxJState();
|
||||||
|
}
|
||||||
|
return this.states.mkxJState;
|
||||||
|
}
|
||||||
|
set mkxJState(v: state.MkxJState) {
|
||||||
|
this.states.mkxJState = v;
|
||||||
|
}
|
||||||
|
clone(): PlatformState {
|
||||||
|
return new PlatformState(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
export class PlatformOperateInteraction extends GraphicInteractionPlugin<Platform> {
|
||||||
|
static Name = 'platform_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(PlatformOperateInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new PlatformOperateInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Platform[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Platform.Type)
|
||||||
|
.map((g) => g as Platform);
|
||||||
|
}
|
||||||
|
bind(g: Platform): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.selectable = true;
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Platform): void {
|
||||||
|
g.selectable = false;
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
//useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
}
|
192
src/drawApp/graphics/electronicMap/ScreenDoorInteraction.ts
Normal file
192
src/drawApp/graphics/electronicMap/ScreenDoorInteraction.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import {
|
||||||
|
IScreenDoorData,
|
||||||
|
IScreenDoorState,
|
||||||
|
ScreenDoor,
|
||||||
|
} from 'src/graphics/screenDoor/ScreenDoor';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IGraphicScene,
|
||||||
|
JlGraphic,
|
||||||
|
MenuItemOptions,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { loadScreenDoorConfig } from '../commonApp';
|
||||||
|
import { Dialog } from 'quasar';
|
||||||
|
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
|
||||||
|
import ScreenDoorOperation from 'src/components/draw-app/dialogs/ScreenDoorOperation.vue';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
|
export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
|
||||||
|
constructor(data?: graphicData.ScreenDoor) {
|
||||||
|
let screenDoor;
|
||||||
|
if (!data) {
|
||||||
|
screenDoor = new graphicData.ScreenDoor({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(ScreenDoor.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
screenDoor = data;
|
||||||
|
}
|
||||||
|
super(screenDoor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data(): graphicData.ScreenDoor {
|
||||||
|
return this.getData<graphicData.ScreenDoor>();
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get refPlatform(): number {
|
||||||
|
return this.data.refPlatformId;
|
||||||
|
}
|
||||||
|
set refPlatform(v: number) {
|
||||||
|
this.data.refPlatformId = v;
|
||||||
|
}
|
||||||
|
get sonDoorAmount(): number {
|
||||||
|
return loadScreenDoorConfig()?.sonDoorAmount || 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone(): ScreenDoorData {
|
||||||
|
return new ScreenDoorData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: ScreenDoorData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: ScreenDoorData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScreenDoorState
|
||||||
|
extends GraphicStateBase
|
||||||
|
implements IScreenDoorState
|
||||||
|
{
|
||||||
|
constructor(proto?: state.PsdState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.PsdState();
|
||||||
|
}
|
||||||
|
super(states, ScreenDoor.Type);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
get id(): number {
|
||||||
|
return this.states.id;
|
||||||
|
}
|
||||||
|
set id(id: number) {
|
||||||
|
this.states.id = id;
|
||||||
|
}
|
||||||
|
get asdStates(): state.AsdState[] {
|
||||||
|
return this.states.asdStates;
|
||||||
|
}
|
||||||
|
set asdStates(v: state.AsdState[]) {
|
||||||
|
this.states.asdStates = v;
|
||||||
|
}
|
||||||
|
get mgj() {
|
||||||
|
return this.states.mgj;
|
||||||
|
}
|
||||||
|
set mgj(v: boolean) {
|
||||||
|
this.states.mgj = v;
|
||||||
|
}
|
||||||
|
get zaw() {
|
||||||
|
return this.states.zaw;
|
||||||
|
}
|
||||||
|
set zaw(v: boolean) {
|
||||||
|
this.states.zaw = v;
|
||||||
|
}
|
||||||
|
get param(): request.PsdParam {
|
||||||
|
return this.states.param;
|
||||||
|
}
|
||||||
|
set param(param: request.PsdParam) {
|
||||||
|
this.states.param = param;
|
||||||
|
}
|
||||||
|
get states(): state.PsdState {
|
||||||
|
return this.getState<state.PsdState>();
|
||||||
|
}
|
||||||
|
clone(): ScreenDoorState {
|
||||||
|
return new ScreenDoorState(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setSceenDoorParam: MenuItemOptions = { name: '设置参数' };
|
||||||
|
const sceenDoorOperateMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '屏蔽门操作菜单',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [setSceenDoorParam],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export class ScreenDoorOperateInteraction extends GraphicInteractionPlugin<ScreenDoor> {
|
||||||
|
static Name = 'screen_door_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(ScreenDoorOperateInteraction.Name, app);
|
||||||
|
app.registerMenu(sceenDoorOperateMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new ScreenDoorOperateInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): ScreenDoor[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === ScreenDoor.Type)
|
||||||
|
.map((g) => g as ScreenDoor);
|
||||||
|
}
|
||||||
|
bind(g: ScreenDoor): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.selectable = true;
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
g.on('rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: ScreenDoor): void {
|
||||||
|
g.selectable = false;
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
g.off('rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const screenDoor = target.getGraphic<ScreenDoor>();
|
||||||
|
if (!screenDoor) return;
|
||||||
|
this.app.updateSelected(screenDoor);
|
||||||
|
const lineStore = useLineStore();
|
||||||
|
setSceenDoorParam.handler = async () => {
|
||||||
|
if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
component: ScreenDoorOperation,
|
||||||
|
componentProps: {
|
||||||
|
id: screenDoor.id,
|
||||||
|
code: screenDoor.datas.code,
|
||||||
|
sonDoorAmount: screenDoor.datas.sonDoorAmount,
|
||||||
|
asdCodesProp: screenDoor.states.param.asdCodes,
|
||||||
|
screenDoorForceProp: screenDoor.states.param.force,
|
||||||
|
screenDoorFaultProp: screenDoor.states.param.fault,
|
||||||
|
},
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
sceenDoorOperateMenu.open(e.global);
|
||||||
|
}
|
||||||
|
}
|
317
src/drawApp/graphics/electronicMap/SectionInteraction.ts
Normal file
317
src/drawApp/graphics/electronicMap/SectionInteraction.ts
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
|
||||||
|
import {
|
||||||
|
ISectionData,
|
||||||
|
ISectionState,
|
||||||
|
Section,
|
||||||
|
SectionType,
|
||||||
|
} from 'src/graphics/section/Section';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IGraphicScene,
|
||||||
|
JlGraphic,
|
||||||
|
MenuItemOptions,
|
||||||
|
ContextMenu,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
|
import { SectionGraphicHitArea } from 'src/graphics/section/SectionDrawAssistant';
|
||||||
|
import { Dialog } from 'quasar';
|
||||||
|
import AddTrainDialog from '../../components/draw-app/dialogs/AddTrainDialog.vue';
|
||||||
|
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import { getKmDistance } from '../lineScene';
|
||||||
|
import SectionOperation from 'src/components/draw-app/dialogs/SectionOperation.vue';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
import { setAxleSectionState } from 'src/api/Simulation';
|
||||||
|
import { errorNotify } from 'src/utils/CommonNotify';
|
||||||
|
|
||||||
|
export class SectionData extends GraphicDataBase implements ISectionData {
|
||||||
|
constructor(data?: graphicData.Section) {
|
||||||
|
let section;
|
||||||
|
if (!data) {
|
||||||
|
section = new graphicData.Section({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(Section.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
section = data;
|
||||||
|
}
|
||||||
|
super(section);
|
||||||
|
}
|
||||||
|
public get data(): graphicData.Section {
|
||||||
|
return this.getData<graphicData.Section>();
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get points(): IPointData[] {
|
||||||
|
return this.data.points;
|
||||||
|
}
|
||||||
|
set points(points: IPointData[]) {
|
||||||
|
this.data.points = points.map(
|
||||||
|
(p) => new graphicData.Point({ x: p.x, y: p.y })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
get paRef(): graphicData.RelatedRef {
|
||||||
|
return this.data.paRef;
|
||||||
|
}
|
||||||
|
set paRef(ref: graphicData.RelatedRef) {
|
||||||
|
this.data.paRef = ref;
|
||||||
|
}
|
||||||
|
get pbRef(): graphicData.RelatedRef {
|
||||||
|
return this.data.pbRef;
|
||||||
|
}
|
||||||
|
set pbRef(ref: graphicData.RelatedRef) {
|
||||||
|
this.data.pbRef = ref;
|
||||||
|
}
|
||||||
|
get sectionType(): graphicData.Section.SectionType {
|
||||||
|
return this.data.sectionType;
|
||||||
|
}
|
||||||
|
set sectionType(type: graphicData.Section.SectionType) {
|
||||||
|
this.data.sectionType = type;
|
||||||
|
}
|
||||||
|
get axleCountings(): number[] {
|
||||||
|
return this.data.axleCountings;
|
||||||
|
}
|
||||||
|
set axleCountings(axleCountings: number[]) {
|
||||||
|
this.data.axleCountings = axleCountings;
|
||||||
|
}
|
||||||
|
get trackSectionId(): number {
|
||||||
|
return this.data.trackSectionId;
|
||||||
|
}
|
||||||
|
set trackSectionId(v: number) {
|
||||||
|
this.data.trackSectionId = v;
|
||||||
|
}
|
||||||
|
get isCurve(): boolean {
|
||||||
|
return this.data.isCurve;
|
||||||
|
}
|
||||||
|
set isCurve(v: boolean) {
|
||||||
|
this.data.isCurve = v;
|
||||||
|
}
|
||||||
|
get segmentsCount(): number {
|
||||||
|
return this.data.segmentsCount;
|
||||||
|
}
|
||||||
|
set segmentsCount(v: number) {
|
||||||
|
this.data.segmentsCount = v;
|
||||||
|
}
|
||||||
|
get centralizedStations(): number[] {
|
||||||
|
return this.data.centralizedStations;
|
||||||
|
}
|
||||||
|
set centralizedStations(v: number[]) {
|
||||||
|
this.data.centralizedStations = v;
|
||||||
|
}
|
||||||
|
get normalRunningDirection(): graphicData.Section.RunningDirection {
|
||||||
|
return this.data.normalRunningDirection;
|
||||||
|
}
|
||||||
|
set normalRunningDirection(v: graphicData.Section.RunningDirection) {
|
||||||
|
this.data.normalRunningDirection = v;
|
||||||
|
}
|
||||||
|
get isTurnBackZone(): boolean {
|
||||||
|
return this.data.isTurnBackZone;
|
||||||
|
}
|
||||||
|
set isTurnBackZone(v: boolean) {
|
||||||
|
this.data.isTurnBackZone = v;
|
||||||
|
}
|
||||||
|
get direction(): graphicData.Direction {
|
||||||
|
return this.data.direction;
|
||||||
|
}
|
||||||
|
set direction(v: graphicData.Direction) {
|
||||||
|
this.data.direction = v;
|
||||||
|
}
|
||||||
|
clone(): SectionData {
|
||||||
|
return new SectionData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: SectionData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: SectionData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SectionStates extends GraphicStateBase implements ISectionState {
|
||||||
|
constructor(proto?: state.SectionState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.SectionState();
|
||||||
|
}
|
||||||
|
super(states, Section.Type);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
get id(): number {
|
||||||
|
return this.states.id;
|
||||||
|
}
|
||||||
|
set id(id: number) {
|
||||||
|
this.states.id = id;
|
||||||
|
}
|
||||||
|
get occupied(): boolean {
|
||||||
|
return this.states.occupied;
|
||||||
|
}
|
||||||
|
set occupied(occupied: boolean) {
|
||||||
|
this.states.occupied = occupied;
|
||||||
|
}
|
||||||
|
get axleFault(): boolean {
|
||||||
|
return this.states.axleFault;
|
||||||
|
}
|
||||||
|
set axleFault(axleFault: boolean) {
|
||||||
|
this.states.axleFault = axleFault;
|
||||||
|
}
|
||||||
|
get axleDrst(): boolean {
|
||||||
|
return this.states.axleDrst;
|
||||||
|
}
|
||||||
|
set axleDrst(axleDrst: boolean) {
|
||||||
|
this.states.axleDrst = axleDrst;
|
||||||
|
}
|
||||||
|
get axlePdrst(): boolean {
|
||||||
|
return this.states.axlePdrst;
|
||||||
|
}
|
||||||
|
set axlePdrst(axlePdrst: boolean) {
|
||||||
|
this.states.axlePdrst = axlePdrst;
|
||||||
|
}
|
||||||
|
get states(): state.SectionState {
|
||||||
|
return this.getState<state.SectionState>();
|
||||||
|
}
|
||||||
|
clone(): SectionStates {
|
||||||
|
return new SectionStates(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addTrainConfig: MenuItemOptions = {
|
||||||
|
name: '添加列车',
|
||||||
|
};
|
||||||
|
const setSectionParam: MenuItemOptions = { name: '设置参数' };
|
||||||
|
const setFaultOcc: MenuItemOptions = { name: '设置故障占用' };
|
||||||
|
const SectionOperateMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '区段操作菜单',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [setSectionParam, setFaultOcc, addTrainConfig],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export class SectionOperateInteraction extends GraphicInteractionPlugin<Section> {
|
||||||
|
static Name = 'section_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(SectionOperateInteraction.Name, app);
|
||||||
|
app.registerMenu(SectionOperateMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new SectionOperateInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Section[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Section.Type)
|
||||||
|
.map((g) => g as Section);
|
||||||
|
}
|
||||||
|
bind(g: Section): void {
|
||||||
|
g.lineGraphic.eventMode = 'static';
|
||||||
|
g.lineGraphic.cursor = 'pointer';
|
||||||
|
g.lineGraphic.hitArea = new SectionGraphicHitArea(g);
|
||||||
|
g.lineGraphic.selectable = true;
|
||||||
|
g.selectable = true;
|
||||||
|
g.labelGraphic.eventMode = 'static';
|
||||||
|
g.labelGraphic.cursor = 'pointer';
|
||||||
|
g.labelGraphic.selectable = true;
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
g.on('rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Section): void {
|
||||||
|
g.lineGraphic.eventMode = 'none';
|
||||||
|
g.lineGraphic.scalable = false;
|
||||||
|
g.lineGraphic.selectable = false;
|
||||||
|
g.selectable = false;
|
||||||
|
g.labelGraphic.eventMode = 'none';
|
||||||
|
g.labelGraphic.selectable = false;
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
g.off('rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const section = target.getGraphic<Section>();
|
||||||
|
if (!section || section.datas.sectionType != SectionType.Physical) return;
|
||||||
|
this.app.updateSelected(section);
|
||||||
|
const lineStore = useLineStore();
|
||||||
|
setSectionParam.handler = async () => {
|
||||||
|
if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
component: SectionOperation,
|
||||||
|
componentProps: {
|
||||||
|
id: section.id,
|
||||||
|
code: section.datas.code,
|
||||||
|
axleDrst: section.states.axleDrst,
|
||||||
|
axlePdrst: section.states.axlePdrst,
|
||||||
|
},
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
setFaultOcc.handler = async () => {
|
||||||
|
const obj = {
|
||||||
|
simulationId: lineStore?.simulationId || '',
|
||||||
|
mapId: lineStore.mapId as number,
|
||||||
|
deviceId: section.id,
|
||||||
|
operation: request.Section.Operation.SetFaultOcc,
|
||||||
|
};
|
||||||
|
setAxleSectionState(obj).catch((e) =>
|
||||||
|
errorNotify('区段操作失败:' + e.title, e)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
addTrainConfig.disabled = !lineStore.trainConfigList;
|
||||||
|
addTrainConfig.handler = () => {
|
||||||
|
const relations =
|
||||||
|
section.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
section,
|
||||||
|
AxleCounting.Type
|
||||||
|
);
|
||||||
|
let AKm;
|
||||||
|
let BKm;
|
||||||
|
relations.forEach((item) => {
|
||||||
|
const rp = item.getRelationParam(section);
|
||||||
|
const other = item.getOtherGraphic(section) as AxleCounting;
|
||||||
|
if (
|
||||||
|
(other.datas.axleCountingRef.length > 1 &&
|
||||||
|
other.datas.type ==
|
||||||
|
graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
|
||||||
|
other.datas.axleCountingRef.length == 1
|
||||||
|
) {
|
||||||
|
if (rp.getParam() == 'A') {
|
||||||
|
AKm = other.datas.kilometerSystem;
|
||||||
|
}
|
||||||
|
if (rp.getParam() == 'B') {
|
||||||
|
BKm = other.datas.kilometerSystem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const d = getKmDistance(BKm, AKm);
|
||||||
|
if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
title: '创建列车',
|
||||||
|
message: '',
|
||||||
|
component: AddTrainDialog,
|
||||||
|
componentProps: { dev: section, kmLength: d },
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
SectionOperateMenu.open(e.global);
|
||||||
|
}
|
||||||
|
}
|
253
src/drawApp/graphics/electronicMap/SignalInteraction.ts
Normal file
253
src/drawApp/graphics/electronicMap/SignalInteraction.ts
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import {
|
||||||
|
ISignalData,
|
||||||
|
Signal,
|
||||||
|
ISignalState,
|
||||||
|
KilometerSystem,
|
||||||
|
} from 'src/graphics/signal/Signal';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
|
||||||
|
import {
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IGraphicScene,
|
||||||
|
JlGraphic,
|
||||||
|
MenuItemOptions,
|
||||||
|
ContextMenu,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { FederatedMouseEvent, DisplayObject } from 'pixi.js';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
|
import { SignalGraphicHitArea } from 'src/graphics/signal/SignalDrawAssistant';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
import { Dialog } from 'quasar';
|
||||||
|
import SignalOperation from 'src/components/draw-app/dialogs/SignalOperation.vue'
|
||||||
|
|
||||||
|
export class SignalData extends GraphicDataBase implements ISignalData {
|
||||||
|
constructor(data?: graphicData.Signal) {
|
||||||
|
let signal;
|
||||||
|
if (!data) {
|
||||||
|
signal = new graphicData.Signal({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(Signal.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
signal = data;
|
||||||
|
}
|
||||||
|
super(signal);
|
||||||
|
}
|
||||||
|
public get data(): graphicData.Signal {
|
||||||
|
return this.getData<graphicData.Signal>();
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get mirror(): boolean {
|
||||||
|
return this.data.mirror;
|
||||||
|
}
|
||||||
|
set mirror(v: boolean) {
|
||||||
|
this.data.mirror = v;
|
||||||
|
}
|
||||||
|
get kilometerSystem(): KilometerSystem {
|
||||||
|
if (!this.data.kilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem();
|
||||||
|
}
|
||||||
|
return this.data.kilometerSystem;
|
||||||
|
}
|
||||||
|
set kilometerSystem(v: KilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
|
||||||
|
}
|
||||||
|
get refDev(): graphicData.RelatedRef {
|
||||||
|
return this.data.refDev ?? new graphicData.RelatedRef();
|
||||||
|
}
|
||||||
|
set refDev(v: graphicData.RelatedRef) {
|
||||||
|
this.data.refDev = v;
|
||||||
|
}
|
||||||
|
get centralizedStations(): number[] {
|
||||||
|
return this.data.centralizedStations;
|
||||||
|
}
|
||||||
|
set centralizedStations(v: number[]) {
|
||||||
|
this.data.centralizedStations = v;
|
||||||
|
}
|
||||||
|
get mt(): graphicData.Signal.Model {
|
||||||
|
return this.data.mt;
|
||||||
|
}
|
||||||
|
set mt(v: graphicData.Signal.Model) {
|
||||||
|
this.data.mt = v;
|
||||||
|
}
|
||||||
|
get direction(): graphicData.Direction {
|
||||||
|
return this.data.direction;
|
||||||
|
}
|
||||||
|
set direction(v: graphicData.Direction) {
|
||||||
|
this.data.direction = v;
|
||||||
|
}
|
||||||
|
clone(): SignalData {
|
||||||
|
return new SignalData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: SignalData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: SignalData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalState extends GraphicStateBase implements ISignalState {
|
||||||
|
constructor(proto?: state.SignalState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.SignalState();
|
||||||
|
}
|
||||||
|
super(states, Signal.Type);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
get aspect(): number {
|
||||||
|
return this.states.aspect;
|
||||||
|
}
|
||||||
|
set aspect(v: number) {
|
||||||
|
this.states.aspect = v;
|
||||||
|
}
|
||||||
|
get param(): request.SignalParam {
|
||||||
|
return this.states.param;
|
||||||
|
}
|
||||||
|
set param(v: request.SignalParam) {
|
||||||
|
this.states.param = v;
|
||||||
|
}
|
||||||
|
get states(): state.SignalState {
|
||||||
|
return this.getState<state.SignalState>();
|
||||||
|
}
|
||||||
|
clone(): SignalState {
|
||||||
|
return new SignalState(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mirrorFlipConfig: MenuItemOptions = {
|
||||||
|
name: '镜像翻转',
|
||||||
|
};
|
||||||
|
const setSignalParam: MenuItemOptions = {
|
||||||
|
name: '设置参数'
|
||||||
|
}
|
||||||
|
const SignalEditMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '信号机编辑菜单',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [mirrorFlipConfig],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const SignalOperateMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '信号机操作菜单',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
setSignalParam
|
||||||
|
// signalRedConfig,
|
||||||
|
// signalGreenConfig,
|
||||||
|
// signalYellowConfig,
|
||||||
|
// signalGuideConfig,
|
||||||
|
// signalCloseConfig,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
export class DrawSignalInteraction extends GraphicInteractionPlugin<Signal> {
|
||||||
|
static Name = 'signal_draw_right_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(DrawSignalInteraction.Name, app);
|
||||||
|
app.registerMenu(SignalEditMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new DrawSignalInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Signal.Type)
|
||||||
|
.map((g) => g as Signal);
|
||||||
|
}
|
||||||
|
bind(g: Signal): void {
|
||||||
|
g.on('_rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Signal): void {
|
||||||
|
g.off('_rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const signal = target.getGraphic() as Signal;
|
||||||
|
this.app.updateSelected(signal);
|
||||||
|
mirrorFlipConfig.handler = () => {
|
||||||
|
signal.mirror = !signal.mirror;
|
||||||
|
};
|
||||||
|
SignalEditMenu.open(e.global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
|
||||||
|
static Name = 'signal_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(SignalOperateInteraction.Name, app);
|
||||||
|
app.registerMenu(SignalOperateMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new SignalOperateInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Signal.Type)
|
||||||
|
.map((g) => g as Signal);
|
||||||
|
}
|
||||||
|
bind(g: Signal): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.selectable = true;
|
||||||
|
g.lampMainBody.hitArea = new SignalGraphicHitArea(g);
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
g.on('rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Signal): void {
|
||||||
|
g.selectable = false;
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
g.off('rightclick', this.onContextMenu);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const signal = target.getGraphic() as Signal;
|
||||||
|
this.app.updateSelected(signal);
|
||||||
|
const lineStore = useLineStore();
|
||||||
|
|
||||||
|
setSignalParam.handler = () => {
|
||||||
|
if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
title: '信号机设置参数',
|
||||||
|
message: '',
|
||||||
|
component: SignalOperation,
|
||||||
|
componentProps: {
|
||||||
|
id: signal.datas.id,
|
||||||
|
code: signal.datas.code,
|
||||||
|
mt: signal.datas.mt,
|
||||||
|
param: signal.states.param,
|
||||||
|
},
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SignalOperateMenu.open(e.global);
|
||||||
|
}
|
||||||
|
}
|
168
src/drawApp/graphics/electronicMap/StationInteraction.ts
Normal file
168
src/drawApp/graphics/electronicMap/StationInteraction.ts
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import {
|
||||||
|
IStationData,
|
||||||
|
IStationState,
|
||||||
|
Station,
|
||||||
|
} from 'src/graphics/station/Station';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import { IGraphicScene, GraphicInteractionPlugin, JlGraphic } from 'jl-graphic';
|
||||||
|
import { KilometerSystem } from 'src/graphics/signal/Signal';
|
||||||
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
|
|
||||||
|
export class StationData extends GraphicDataBase implements IStationData {
|
||||||
|
constructor(data?: graphicData.Station) {
|
||||||
|
let station;
|
||||||
|
if (!data) {
|
||||||
|
station = new graphicData.Station({
|
||||||
|
common: GraphicDataBase.defaultCommonInfo(Station.Type),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
station = data;
|
||||||
|
}
|
||||||
|
super(station);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data(): graphicData.Station {
|
||||||
|
return this.getData<graphicData.Station>();
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get stationName(): string {
|
||||||
|
return this.data.stationName;
|
||||||
|
}
|
||||||
|
set stationName(v: string) {
|
||||||
|
this.data.stationName = v;
|
||||||
|
}
|
||||||
|
get stationNameAcronym(): string {
|
||||||
|
return this.data.stationNameAcronym;
|
||||||
|
}
|
||||||
|
set stationNameAcronym(v: string) {
|
||||||
|
this.data.stationNameAcronym = v;
|
||||||
|
}
|
||||||
|
get kilometerSystem(): KilometerSystem {
|
||||||
|
if (!this.data.kilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem();
|
||||||
|
}
|
||||||
|
return this.data.kilometerSystem;
|
||||||
|
}
|
||||||
|
set kilometerSystem(v: KilometerSystem) {
|
||||||
|
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
|
||||||
|
}
|
||||||
|
get concentrationStations(): boolean {
|
||||||
|
return this.data.concentrationStations;
|
||||||
|
}
|
||||||
|
set concentrationStations(v: boolean) {
|
||||||
|
this.data.concentrationStations = v;
|
||||||
|
}
|
||||||
|
get depots(): boolean {
|
||||||
|
return this.data.depots;
|
||||||
|
}
|
||||||
|
set depots(v: boolean) {
|
||||||
|
this.data.depots = v;
|
||||||
|
}
|
||||||
|
get manageStations(): number[] {
|
||||||
|
return this.data.manageStations;
|
||||||
|
}
|
||||||
|
set manageStations(v: number[]) {
|
||||||
|
this.data.manageStations = v;
|
||||||
|
}
|
||||||
|
clone(): StationData {
|
||||||
|
return new StationData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: StationData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: StationData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StationState extends GraphicStateBase implements IStationState {
|
||||||
|
constructor(proto?: state.StationState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.StationState();
|
||||||
|
}
|
||||||
|
super(states, Station.Type);
|
||||||
|
}
|
||||||
|
get id(): number {
|
||||||
|
return this.states.id;
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
// get ipRtuStusDown(): boolean {
|
||||||
|
// return this.states.ipRtuStusDown;
|
||||||
|
// }
|
||||||
|
// set ipRtuStusDown(v: boolean) {
|
||||||
|
// this.states.ipRtuStusDown = v;
|
||||||
|
// }
|
||||||
|
// get ipRtuStusInLocalCtrl(): boolean {
|
||||||
|
// return this.states.ipRtuStusInLocalCtrl;
|
||||||
|
// }
|
||||||
|
// set ipRtuStusInLocalCtrl(v: boolean) {
|
||||||
|
// this.states.ipRtuStusInLocalCtrl = v;
|
||||||
|
// }
|
||||||
|
// get ipRtuStusInCentralCtrl(): boolean {
|
||||||
|
// return this.states.ipRtuStusInCentralCtrl;
|
||||||
|
// }
|
||||||
|
// set ipRtuStusInCentralCtrl(v: boolean) {
|
||||||
|
// this.states.ipRtuStusInCentralCtrl = v;
|
||||||
|
// }
|
||||||
|
// get ipRtuStusInEmergencyCtrl(): boolean {
|
||||||
|
// return this.states.ipRtuStusInEmergencyCtrl;
|
||||||
|
// }
|
||||||
|
// set ipRtuStusInEmergencyCtrl(v: boolean) {
|
||||||
|
// this.states.ipRtuStusInEmergencyCtrl = v;
|
||||||
|
// }
|
||||||
|
get states(): state.StationState {
|
||||||
|
return this.getState<state.StationState>();
|
||||||
|
}
|
||||||
|
clone(): StationState {
|
||||||
|
return new StationState(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StationOperateInteraction extends GraphicInteractionPlugin<Station> {
|
||||||
|
static Name = 'station_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(StationOperateInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new StationOperateInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Station[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Station.Type)
|
||||||
|
.map((g) => g as Station);
|
||||||
|
}
|
||||||
|
bind(g: Station): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.selectable = true;
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Station): void {
|
||||||
|
g.selectable = false;
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
}
|
378
src/drawApp/graphics/electronicMap/TurnoutInteraction.ts
Normal file
378
src/drawApp/graphics/electronicMap/TurnoutInteraction.ts
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
import {
|
||||||
|
ITurnoutData,
|
||||||
|
ITurnoutState,
|
||||||
|
Turnout,
|
||||||
|
TurnoutSection,
|
||||||
|
} from 'src/graphics/turnout/Turnout';
|
||||||
|
import * as pb_1 from 'google-protobuf';
|
||||||
|
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
|
||||||
|
import { KilometerSystem } from 'src/graphics/signal/Signal';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import {
|
||||||
|
IGraphicScene,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
JlGraphic,
|
||||||
|
MenuItemOptions,
|
||||||
|
ContextMenu,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import {
|
||||||
|
ForkHitArea,
|
||||||
|
TurnoutSectionHitArea,
|
||||||
|
} from 'src/graphics/turnout/TurnoutDrawAssistant';
|
||||||
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
|
import { Dialog } from 'quasar';
|
||||||
|
// import AddTrainDialog from '../../components/draw-app/dialogs/AddTrainDialog.vue';
|
||||||
|
// import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
|
||||||
|
import TurnoutOperation from 'src/components/draw-app/dialogs/TurnoutOperation.vue';
|
||||||
|
// import { getKmDistance } from '../lineScene';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
|
function getDefaultEndPoint() {
|
||||||
|
return {
|
||||||
|
pointA: [new graphicData.Point([50, 0])],
|
||||||
|
pointB: [new graphicData.Point([-50, 0])],
|
||||||
|
pointC: [new graphicData.Point([-50, -50])],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTurnoutParam: MenuItemOptions = { name: '设置参数' };
|
||||||
|
|
||||||
|
// const addTrainConfig: MenuItemOptions = {
|
||||||
|
// name: '添加列车',
|
||||||
|
// };
|
||||||
|
|
||||||
|
const TurnoutOperationMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: 'Turnout操作',
|
||||||
|
groups: [{ items: [setTurnoutParam] }],
|
||||||
|
});
|
||||||
|
|
||||||
|
export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
|
||||||
|
static Name = 'turnout_operate_menu';
|
||||||
|
constructor(app: IGraphicScene) {
|
||||||
|
super(TurnoutOperationPlugin.Name, app);
|
||||||
|
app.registerMenu(TurnoutOperationMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicScene) {
|
||||||
|
return new TurnoutOperationPlugin(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Turnout[] | undefined {
|
||||||
|
return grahpics.filter<Turnout>((g): g is Turnout => g instanceof Turnout);
|
||||||
|
}
|
||||||
|
bind(g: Turnout): void {
|
||||||
|
g.graphics.fork.eventMode = 'static';
|
||||||
|
g.graphics.fork.cursor = 'pointer';
|
||||||
|
g.selectable = true;
|
||||||
|
g.graphics.fork.hitArea = new ForkHitArea(g);
|
||||||
|
g.graphics.sections.forEach((sectionGraphic) => {
|
||||||
|
sectionGraphic.eventMode = 'static';
|
||||||
|
sectionGraphic.cursor = 'pointer';
|
||||||
|
sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic);
|
||||||
|
});
|
||||||
|
g.on('rightclick', this.onContextMenu, this);
|
||||||
|
g.on('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
unbind(g: Turnout): void {
|
||||||
|
g.graphics.fork.eventMode = 'none';
|
||||||
|
g.selectable = false;
|
||||||
|
g.graphics.sections.forEach((sectionGraphic) => {
|
||||||
|
sectionGraphic.eventMode = 'none';
|
||||||
|
});
|
||||||
|
g.off('rightclick', this.onContextMenu);
|
||||||
|
g.off('_leftclick', this.onLeftClick, this);
|
||||||
|
}
|
||||||
|
onLeftClick() {
|
||||||
|
useLineStore().stateProCountIncrease();
|
||||||
|
}
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const turnout = target.getGraphic<Turnout>();
|
||||||
|
if (!turnout) return;
|
||||||
|
const lineStore = useLineStore();
|
||||||
|
this.app.updateSelected(turnout);
|
||||||
|
setTurnoutParam.handler = async () => {
|
||||||
|
if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
title: '道岔设置参数',
|
||||||
|
message: '',
|
||||||
|
component: TurnoutOperation,
|
||||||
|
componentProps: {
|
||||||
|
id: turnout.id,
|
||||||
|
code: turnout.datas.code,
|
||||||
|
force: turnout.states.param.forcePosition,
|
||||||
|
},
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// const port = (target as TurnoutSection).port;
|
||||||
|
// addTrainConfig.disabled = !port || !lineStore.trainConfigList;
|
||||||
|
// addTrainConfig.handler = () => {
|
||||||
|
// const relations =
|
||||||
|
// turnout.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
// turnout,
|
||||||
|
// AxleCounting.Type
|
||||||
|
// );
|
||||||
|
// const findAc = relations.find((item) => {
|
||||||
|
// const rp = item.getRelationParam(turnout);
|
||||||
|
// const orp = item.getOtherRelationParam(turnout as Turnout);
|
||||||
|
// const ac = orp.g as AxleCounting;
|
||||||
|
// return (
|
||||||
|
// rp.getParam() == port &&
|
||||||
|
// ((ac.datas.axleCountingRef.length > 1 &&
|
||||||
|
// ac.datas.type ==
|
||||||
|
// graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
|
||||||
|
// ac.datas.axleCountingRef.length == 1)
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// const oKm = turnout.datas.kilometerSystem;
|
||||||
|
// let pKm;
|
||||||
|
// if (findAc) {
|
||||||
|
// const other = findAc.getOtherGraphic(turnout) as AxleCounting;
|
||||||
|
// pKm = other.datas.kilometerSystem;
|
||||||
|
// } else {
|
||||||
|
// const relations =
|
||||||
|
// turnout.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
// turnout,
|
||||||
|
// Turnout.Type
|
||||||
|
// );
|
||||||
|
// const findT = relations.find((item) => {
|
||||||
|
// const rp = item.getRelationParam(turnout);
|
||||||
|
// return rp.getParam() == port;
|
||||||
|
// });
|
||||||
|
// if (findT) {
|
||||||
|
// const other = findT.getOtherGraphic(turnout) as Turnout;
|
||||||
|
// pKm = other.datas.kilometerSystem;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// const d = getKmDistance(pKm, oKm);
|
||||||
|
// if (lineStore.deviceOpreratDialogInstance) return;
|
||||||
|
// lineStore.deviceOpreratDialogInstance = Dialog.create({
|
||||||
|
// title: '创建列车',
|
||||||
|
// message: '',
|
||||||
|
// component: AddTrainDialog,
|
||||||
|
// componentProps: { dev: turnout, kmLength: d },
|
||||||
|
// cancel: true,
|
||||||
|
// persistent: true,
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
TurnoutOperationMenu.open(e.global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutData extends GraphicDataBase implements ITurnoutData {
|
||||||
|
constructor(data?: graphicData.Turnout) {
|
||||||
|
let turnout = new graphicData.Turnout();
|
||||||
|
if (!data) {
|
||||||
|
turnout.common = GraphicDataBase.defaultCommonInfo(Turnout.Type);
|
||||||
|
const p = getDefaultEndPoint();
|
||||||
|
turnout.pointA = p.pointA;
|
||||||
|
turnout.pointB = p.pointB;
|
||||||
|
turnout.pointC = p.pointC;
|
||||||
|
} else {
|
||||||
|
turnout = data;
|
||||||
|
}
|
||||||
|
super(turnout);
|
||||||
|
}
|
||||||
|
get data(): graphicData.Turnout {
|
||||||
|
return this.getData<graphicData.Turnout>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.data.code;
|
||||||
|
}
|
||||||
|
set code(v: string) {
|
||||||
|
this.data.code = v;
|
||||||
|
}
|
||||||
|
get pointA(): IPointData[] {
|
||||||
|
return this.data.pointA;
|
||||||
|
}
|
||||||
|
set pointA(v: IPointData[]) {
|
||||||
|
this.data.pointA = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
|
||||||
|
}
|
||||||
|
get pointB(): IPointData[] {
|
||||||
|
return this.data.pointB;
|
||||||
|
}
|
||||||
|
set pointB(v: IPointData[]) {
|
||||||
|
this.data.pointB = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
|
||||||
|
}
|
||||||
|
get pointC(): IPointData[] {
|
||||||
|
return this.data.pointC;
|
||||||
|
}
|
||||||
|
set pointC(v: IPointData[]) {
|
||||||
|
this.data.pointC = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
|
||||||
|
}
|
||||||
|
get paRef(): graphicData.RelatedRef {
|
||||||
|
return this.data.paRef;
|
||||||
|
}
|
||||||
|
set paRef(ref: graphicData.RelatedRef) {
|
||||||
|
this.data.paRef = ref;
|
||||||
|
}
|
||||||
|
get pbRef(): graphicData.RelatedRef {
|
||||||
|
return this.data.pbRef;
|
||||||
|
}
|
||||||
|
set pbRef(ref: graphicData.RelatedRef) {
|
||||||
|
this.data.pbRef = ref;
|
||||||
|
}
|
||||||
|
get pcRef(): graphicData.RelatedRef {
|
||||||
|
return this.data.pcRef;
|
||||||
|
}
|
||||||
|
set pcRef(ref: graphicData.RelatedRef) {
|
||||||
|
this.data.pcRef = ref;
|
||||||
|
}
|
||||||
|
get kilometerSystem(): KilometerSystem {
|
||||||
|
if (!this.data.kilometerSystem[0]) {
|
||||||
|
this.data.kilometerSystem = [new graphicData.KilometerSystem()];
|
||||||
|
}
|
||||||
|
return this.data.kilometerSystem[0];
|
||||||
|
}
|
||||||
|
set kilometerSystem(v: KilometerSystem) {
|
||||||
|
this.data.kilometerSystem = [new graphicData.KilometerSystem(v)];
|
||||||
|
}
|
||||||
|
get paTrackSectionId(): number {
|
||||||
|
return this.data.paTrackSectionId;
|
||||||
|
}
|
||||||
|
set paTrackSectionId(v: number) {
|
||||||
|
this.data.paTrackSectionId = v;
|
||||||
|
}
|
||||||
|
get pbTrackSectionId(): number {
|
||||||
|
return this.data.pbTrackSectionId;
|
||||||
|
}
|
||||||
|
set pbTrackSectionId(v: number) {
|
||||||
|
this.data.pbTrackSectionId = v;
|
||||||
|
}
|
||||||
|
get pcTrackSectionId(): number {
|
||||||
|
return this.data.pcTrackSectionId;
|
||||||
|
}
|
||||||
|
set pcTrackSectionId(v: number) {
|
||||||
|
this.data.pcTrackSectionId = v;
|
||||||
|
}
|
||||||
|
get switchMachineType(): graphicData.Turnout.SwitchMachineType {
|
||||||
|
return this.data.switchMachineType;
|
||||||
|
}
|
||||||
|
set switchMachineType(v: graphicData.Turnout.SwitchMachineType) {
|
||||||
|
this.data.switchMachineType = v;
|
||||||
|
}
|
||||||
|
get centralizedStations(): number[] {
|
||||||
|
return this.data.centralizedStations;
|
||||||
|
}
|
||||||
|
set centralizedStations(v: number[]) {
|
||||||
|
this.data.centralizedStations = v;
|
||||||
|
}
|
||||||
|
clone(): TurnoutData {
|
||||||
|
return new TurnoutData(this.data.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: TurnoutData): void {
|
||||||
|
pb_1.Message.copyInto(data.data, this.data);
|
||||||
|
}
|
||||||
|
eq(other: TurnoutData): boolean {
|
||||||
|
return pb_1.Message.equals(this.data, other.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutStates extends GraphicStateBase implements ITurnoutState {
|
||||||
|
constructor(proto?: state.SwitchState) {
|
||||||
|
let states;
|
||||||
|
if (proto) {
|
||||||
|
states = proto;
|
||||||
|
} else {
|
||||||
|
states = new state.SwitchState();
|
||||||
|
}
|
||||||
|
super(states, Turnout.Type);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.states.id + '';
|
||||||
|
}
|
||||||
|
get id(): number {
|
||||||
|
return this.states.id;
|
||||||
|
}
|
||||||
|
set id(id: number) {
|
||||||
|
this.states.id = id;
|
||||||
|
}
|
||||||
|
get normal(): boolean {
|
||||||
|
return this.states.normal;
|
||||||
|
}
|
||||||
|
set normal(normal: boolean) {
|
||||||
|
this.states.normal = normal;
|
||||||
|
}
|
||||||
|
get reverse(): boolean {
|
||||||
|
return this.states.reverse;
|
||||||
|
}
|
||||||
|
set reverse(reverse: boolean) {
|
||||||
|
this.states.reverse = reverse;
|
||||||
|
}
|
||||||
|
get dw(): boolean {
|
||||||
|
return this.states.dw;
|
||||||
|
}
|
||||||
|
set dw(dw: boolean) {
|
||||||
|
this.states.dw = dw;
|
||||||
|
}
|
||||||
|
get fw(): boolean {
|
||||||
|
return this.states.fw;
|
||||||
|
}
|
||||||
|
set fw(v: boolean) {
|
||||||
|
this.states.fw = v;
|
||||||
|
}
|
||||||
|
get param(): request.PointsParam {
|
||||||
|
return this.states.param;
|
||||||
|
}
|
||||||
|
set param(param: request.PointsParam) {
|
||||||
|
this.states.param = param;
|
||||||
|
}
|
||||||
|
get qdc(): boolean {
|
||||||
|
return this.states.qdc;
|
||||||
|
}
|
||||||
|
set qdc(v: boolean) {
|
||||||
|
this.states.qdc = v;
|
||||||
|
}
|
||||||
|
get qfc(): boolean {
|
||||||
|
return this.states.qfc;
|
||||||
|
}
|
||||||
|
set qfc(v: boolean) {
|
||||||
|
this.states.qfc = v;
|
||||||
|
}
|
||||||
|
get qyc(): boolean {
|
||||||
|
return this.states.qyc;
|
||||||
|
}
|
||||||
|
set qyc(v: boolean) {
|
||||||
|
this.states.qyc = v;
|
||||||
|
}
|
||||||
|
get dc(): boolean {
|
||||||
|
return this.states.dc;
|
||||||
|
}
|
||||||
|
set dc(v: boolean) {
|
||||||
|
this.states.dc = v;
|
||||||
|
}
|
||||||
|
get fc(): boolean {
|
||||||
|
return this.states.fc;
|
||||||
|
}
|
||||||
|
set fc(v: boolean) {
|
||||||
|
this.states.fc = v;
|
||||||
|
}
|
||||||
|
get yc(): boolean {
|
||||||
|
return this.states.yc;
|
||||||
|
}
|
||||||
|
set yc(v: boolean) {
|
||||||
|
this.states.yc = v;
|
||||||
|
}
|
||||||
|
get occupied(): boolean {
|
||||||
|
return this.states.occupied;
|
||||||
|
}
|
||||||
|
set occupied(v: boolean) {
|
||||||
|
this.states.occupied = v;
|
||||||
|
}
|
||||||
|
get states(): state.SwitchState {
|
||||||
|
return this.getState<state.SwitchState>();
|
||||||
|
}
|
||||||
|
clone(): TurnoutStates {
|
||||||
|
return new TurnoutStates(this.states.cloneMessage());
|
||||||
|
}
|
||||||
|
copyFrom(data: GraphicStateBase): void {
|
||||||
|
pb_1.Message.copyInto(data._state, this._state);
|
||||||
|
}
|
||||||
|
eq(data: GraphicStateBase): boolean {
|
||||||
|
return pb_1.Message.equals(this._state, data._state);
|
||||||
|
}
|
||||||
|
}
|
128
src/graphics/electronicMap/CommonGraphics.ts
Normal file
128
src/graphics/electronicMap/CommonGraphics.ts
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import { Graphics } from 'pixi.js';
|
||||||
|
import { calculateMirrorPoint } from 'jl-graphic';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
import { Turnout } from './turnout/Turnout';
|
||||||
|
import { Section, DevicePort } from './section/Section';
|
||||||
|
import { AxleCounting } from './axleCounting/AxleCounting';
|
||||||
|
import { Station } from './station/Station';
|
||||||
|
import { ScreenDoor } from './screenDoor/ScreenDoor';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param polygon
|
||||||
|
* @param x 箭头顶点x坐标
|
||||||
|
* @param y 箭头顶点y坐标
|
||||||
|
* @param length 箭头长度
|
||||||
|
* @param radius 箭头三角半径
|
||||||
|
* @param lineWidth 箭头线宽
|
||||||
|
* @param mirror 是否镜像翻转 (基于箭头顶点)
|
||||||
|
*/
|
||||||
|
export function drawArrow(
|
||||||
|
polygon: Graphics,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
length: number,
|
||||||
|
radius: number,
|
||||||
|
lineWidth: number,
|
||||||
|
mirror: boolean
|
||||||
|
) {
|
||||||
|
const trianglAcme = { x, y };
|
||||||
|
let triangleP1 = {
|
||||||
|
x: x - radius - Math.sin(Math.PI / 6),
|
||||||
|
y: y + Math.cos(Math.PI / 6) * radius,
|
||||||
|
};
|
||||||
|
let triangleP2 = {
|
||||||
|
x: x - radius - Math.sin(Math.PI / 6),
|
||||||
|
y: y - Math.cos(Math.PI / 6) * radius,
|
||||||
|
};
|
||||||
|
let lineP1 = {
|
||||||
|
x: x - radius - Math.sin(Math.PI / 6),
|
||||||
|
y: y + lineWidth / 2,
|
||||||
|
};
|
||||||
|
let lineP2 = {
|
||||||
|
x: x - length,
|
||||||
|
y: y + lineWidth / 2,
|
||||||
|
};
|
||||||
|
let lineP3 = {
|
||||||
|
x: x - length,
|
||||||
|
y: y - lineWidth / 2,
|
||||||
|
};
|
||||||
|
let lineP4 = {
|
||||||
|
x: x - radius - Math.sin(Math.PI / 6),
|
||||||
|
y: y - lineWidth / 2,
|
||||||
|
};
|
||||||
|
if (mirror) {
|
||||||
|
triangleP1 = calculateMirrorPoint(trianglAcme, triangleP1);
|
||||||
|
triangleP2 = calculateMirrorPoint(trianglAcme, triangleP2);
|
||||||
|
lineP1 = calculateMirrorPoint(trianglAcme, lineP1);
|
||||||
|
lineP2 = calculateMirrorPoint(trianglAcme, lineP2);
|
||||||
|
lineP3 = calculateMirrorPoint(trianglAcme, lineP3);
|
||||||
|
lineP4 = calculateMirrorPoint(trianglAcme, lineP4);
|
||||||
|
}
|
||||||
|
polygon.drawPolygon(
|
||||||
|
trianglAcme.x,
|
||||||
|
trianglAcme.y,
|
||||||
|
triangleP1.x,
|
||||||
|
triangleP1.y,
|
||||||
|
lineP1.x,
|
||||||
|
lineP1.y,
|
||||||
|
lineP2.x,
|
||||||
|
lineP2.y,
|
||||||
|
lineP3.x,
|
||||||
|
lineP3.y,
|
||||||
|
lineP4.x,
|
||||||
|
lineP4.y,
|
||||||
|
triangleP2.x,
|
||||||
|
triangleP2.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRelatedRefProto(
|
||||||
|
type: string,
|
||||||
|
id: number,
|
||||||
|
port?: DevicePort
|
||||||
|
) {
|
||||||
|
const typeMap = new Map([
|
||||||
|
[Section.Type, electronicMapGraphicData.RelatedRef.DeviceType.Section],
|
||||||
|
[Turnout.Type, electronicMapGraphicData.RelatedRef.DeviceType.Turnout],
|
||||||
|
[AxleCounting.Type, electronicMapGraphicData.RelatedRef.DeviceType.AxleCounting],
|
||||||
|
[Station.Type, electronicMapGraphicData.RelatedRef.DeviceType.station],
|
||||||
|
[ScreenDoor.Type, electronicMapGraphicData.RelatedRef.DeviceType.ScreenDoor],
|
||||||
|
]);
|
||||||
|
const protoDeviceType = typeMap.get(type);
|
||||||
|
if (protoDeviceType === undefined) throw Error(`输入的type有误: ${type}`);
|
||||||
|
const protoData = new electronicMapGraphicData.RelatedRef({
|
||||||
|
deviceType: protoDeviceType,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
if (port) {
|
||||||
|
if (port === DevicePort.A)
|
||||||
|
protoData.devicePort = electronicMapGraphicData.RelatedRef.DevicePort.A;
|
||||||
|
if (port === DevicePort.B)
|
||||||
|
protoData.devicePort = electronicMapGraphicData.RelatedRef.DevicePort.B;
|
||||||
|
if (port === DevicePort.C)
|
||||||
|
protoData.devicePort = electronicMapGraphicData.RelatedRef.DevicePort.C;
|
||||||
|
}
|
||||||
|
return protoData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function protoPort2Data(port: electronicMapGraphicData.RelatedRef.DevicePort) {
|
||||||
|
if (port === electronicMapGraphicData.RelatedRef.DevicePort.A) return 'A';
|
||||||
|
if (port === electronicMapGraphicData.RelatedRef.DevicePort.B) return 'B';
|
||||||
|
if (port === electronicMapGraphicData.RelatedRef.DevicePort.C) return 'C';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRelatedRefData {
|
||||||
|
deviceType: electronicMapGraphicData.RelatedRef.DeviceType; //关联的设备类型
|
||||||
|
id: number; //关联的设备ID
|
||||||
|
devicePort: electronicMapGraphicData.RelatedRef.DevicePort; //关联的设备端口
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISimpleRefData {
|
||||||
|
deviceType: electronicMapGraphicData.SimpleRef.DeviceType;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DevicePosition {
|
||||||
|
deviceId: number;
|
||||||
|
offset: number;
|
||||||
|
}
|
135
src/graphics/electronicMap/axleCounting/AxleCounting.ts
Normal file
135
src/graphics/electronicMap/axleCounting/AxleCounting.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import { Color, Container, Graphics } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicRelationParam,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
VectorText,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { IRelatedRefData, protoPort2Data } from '../CommonGraphics';
|
||||||
|
import { KilometerSystem } from '../signal/Signal';
|
||||||
|
|
||||||
|
enum TypeDetectionPoint {
|
||||||
|
AxleCounting = 0,
|
||||||
|
SectionBoundary = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAxleCountingData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
set code(v: string);
|
||||||
|
get kilometerSystem(): KilometerSystem;
|
||||||
|
set kilometerSystem(v: KilometerSystem);
|
||||||
|
get axleCountingRef(): IRelatedRefData[]; //关联的设备
|
||||||
|
set axleCountingRef(ref: IRelatedRefData[]);
|
||||||
|
get type(): TypeDetectionPoint; // 计轴、区段边界
|
||||||
|
set type(v: TypeDetectionPoint);
|
||||||
|
get centralizedStations(): number[];
|
||||||
|
set centralizedStations(v: number[]);
|
||||||
|
clone(): IAxleCountingData;
|
||||||
|
copyFrom(data: IAxleCountingData): void;
|
||||||
|
eq(other: IAxleCountingData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AxleCountingConsts = {
|
||||||
|
radius: 6,
|
||||||
|
borderWidth: 1,
|
||||||
|
circleColorBlue: '0x08F80D',
|
||||||
|
circleColorRed: '0xff0000',
|
||||||
|
codeFontSize: 22,
|
||||||
|
codeOffsetY: 30,
|
||||||
|
kilometerCodeColor: '0xFFFFFF',
|
||||||
|
kilometerCodeFontSize: 14,
|
||||||
|
kilometerCodeOffsetY: 95,
|
||||||
|
offsetSection: 50,
|
||||||
|
};
|
||||||
|
class TwoCircleGraphic extends Container {
|
||||||
|
circleA: Graphics = new Graphics();
|
||||||
|
circleB: Graphics = new Graphics();
|
||||||
|
line: Graphics = new Graphics();
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.addChild(this.circleA);
|
||||||
|
this.addChild(this.circleB);
|
||||||
|
this.addChild(this.line);
|
||||||
|
}
|
||||||
|
draw(data: IAxleCountingData): void {
|
||||||
|
this.drawCircle(this.circleA, data);
|
||||||
|
this.drawCircle(this.circleB, data);
|
||||||
|
this.circleA.position.set(-12, 0);
|
||||||
|
this.circleB.position.set(12, 0);
|
||||||
|
this.line.clear();
|
||||||
|
let color = AxleCountingConsts.circleColorBlue;
|
||||||
|
if (data.type == 1) {
|
||||||
|
color = AxleCountingConsts.circleColorRed;
|
||||||
|
}
|
||||||
|
this.line.lineStyle(1, new Color(color));
|
||||||
|
this.line.moveTo(-24, 0);
|
||||||
|
this.line.lineTo(24, 0);
|
||||||
|
}
|
||||||
|
drawCircle(circle: Graphics, data: IAxleCountingData): void {
|
||||||
|
circle.clear();
|
||||||
|
let color = AxleCountingConsts.circleColorBlue;
|
||||||
|
if (data.type == 1) {
|
||||||
|
color = AxleCountingConsts.circleColorRed;
|
||||||
|
}
|
||||||
|
circle.lineStyle(AxleCountingConsts.borderWidth, new Color(color));
|
||||||
|
circle.beginFill(color, 1);
|
||||||
|
circle.drawCircle(0, 0, AxleCountingConsts.radius);
|
||||||
|
circle.endFill;
|
||||||
|
}
|
||||||
|
clear(): void {
|
||||||
|
this.circleA.clear();
|
||||||
|
this.circleB.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class AxleCounting extends JlGraphic {
|
||||||
|
static Type = 'AxleCounting';
|
||||||
|
twoCircle: TwoCircleGraphic = new TwoCircleGraphic();
|
||||||
|
kilometerGraph: VectorText = new VectorText(''); //公里标
|
||||||
|
direction: number;
|
||||||
|
constructor(direction: number) {
|
||||||
|
super(AxleCounting.Type);
|
||||||
|
this.addChild(this.twoCircle);
|
||||||
|
this.addChild(this.kilometerGraph);
|
||||||
|
this.kilometerGraph.name = 'kilometer';
|
||||||
|
this.direction = direction;
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
get datas(): IAxleCountingData {
|
||||||
|
return this.getDatas<IAxleCountingData>();
|
||||||
|
}
|
||||||
|
doRepaint(): void {
|
||||||
|
this.twoCircle.draw(this.datas);
|
||||||
|
}
|
||||||
|
buildRelation(): void {
|
||||||
|
this.loadRelations();
|
||||||
|
}
|
||||||
|
loadRelations(): void {
|
||||||
|
if (this.datas.axleCountingRef.length) {
|
||||||
|
this.datas.axleCountingRef.forEach((device) => {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, 'A'),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(device.id),
|
||||||
|
protoPort2Data(device.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AxleCountingTemplate extends JlGraphicTemplate<AxleCounting> {
|
||||||
|
constructor(dataTemplate: IAxleCountingData) {
|
||||||
|
super(AxleCounting.Type, {
|
||||||
|
dataTemplate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
new(): AxleCounting {
|
||||||
|
const axleCounting = new AxleCounting(1);
|
||||||
|
axleCounting.loadData(this.datas);
|
||||||
|
return axleCounting;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,425 @@
|
|||||||
|
import { FederatedPointerEvent, IPoint, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicIdGenerator,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
distance2,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IAxleCountingData,
|
||||||
|
AxleCounting,
|
||||||
|
AxleCountingTemplate,
|
||||||
|
} from './AxleCounting';
|
||||||
|
import { Section, DevicePort, SectionType } from '../section/Section';
|
||||||
|
import { Turnout } from '../turnout/Turnout';
|
||||||
|
import { IRelatedRefData, createRelatedRefProto } from '../CommonGraphics';
|
||||||
|
import { Signal } from '../signal/Signal';
|
||||||
|
import { loadGenerateAxleCountingConfig } from 'src/drawApp/commonApp';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
|
||||||
|
export interface IAxleCountingDrawOptions {
|
||||||
|
newData: () => IAxleCountingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AxleCountingDraw extends GraphicDrawAssistant<
|
||||||
|
AxleCountingTemplate,
|
||||||
|
IAxleCountingData
|
||||||
|
> {
|
||||||
|
codeGraph: AxleCounting;
|
||||||
|
constructor(app: IDrawApp, template: AxleCountingTemplate) {
|
||||||
|
super(app, template, 'sym_o_circle', '区段检测点');
|
||||||
|
this.codeGraph = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.codeGraph);
|
||||||
|
AxleCountingInteraction.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.codeGraph.loadData(this.graphicTemplate.datas);
|
||||||
|
this.codeGraph.doRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache(): void {
|
||||||
|
//this.codeGraph.destroy();
|
||||||
|
}
|
||||||
|
onLeftDown(e: FederatedPointerEvent): void {
|
||||||
|
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.container.position.copyFrom(p);
|
||||||
|
}
|
||||||
|
prepareData(data: IAxleCountingData): boolean {
|
||||||
|
data.transform = this.container.saveTransform();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
draw(
|
||||||
|
ps: IPoint,
|
||||||
|
direction: number,
|
||||||
|
graphic: Section | Turnout,
|
||||||
|
port: DevicePort,
|
||||||
|
map: Map<string, number>,
|
||||||
|
reftype: string,
|
||||||
|
refGraphic: Section | Turnout,
|
||||||
|
refPort: DevicePort
|
||||||
|
) {
|
||||||
|
const generateAxleCountingConfig = loadGenerateAxleCountingConfig();
|
||||||
|
if (generateAxleCountingConfig?.noGenerateGroup !== undefined) {
|
||||||
|
const noGenerateGroup = generateAxleCountingConfig.noGenerateGroup;
|
||||||
|
for (let i = 0; i < noGenerateGroup.length; i++) {
|
||||||
|
if (
|
||||||
|
noGenerateGroup[i] == graphic.id &&
|
||||||
|
((i % 2 == 0 && refGraphic.id == noGenerateGroup[i + 1]) ||
|
||||||
|
(i % 2 == 1 && refGraphic.id == noGenerateGroup[i - 1]))
|
||||||
|
) {
|
||||||
|
map.set(`${graphic.id}-${port}`, 1);
|
||||||
|
map.set(`${refGraphic.id}-${refPort}`, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
graphic.type == 'Turnout' &&
|
||||||
|
reftype == 'Turnout' &&
|
||||||
|
port == DevicePort.B &&
|
||||||
|
refPort == DevicePort.B
|
||||||
|
) {
|
||||||
|
//查看生成计轴bb配置
|
||||||
|
let hasBB = false;
|
||||||
|
if (generateAxleCountingConfig !== undefined) {
|
||||||
|
const bbConnect = generateAxleCountingConfig.bbConnect;
|
||||||
|
if (
|
||||||
|
bbConnect.includes(graphic.id) ||
|
||||||
|
bbConnect.includes(refGraphic.id)
|
||||||
|
) {
|
||||||
|
hasBB = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//bb连接处有信号机需要生成
|
||||||
|
const points = (graphic as Turnout).getPortPoints();
|
||||||
|
const portPs = graphic.localToCanvasPoints(points[1][0])[0];
|
||||||
|
let hasSingle = false;
|
||||||
|
const singles = this.app.queryStore.queryByType<Signal>(Signal.Type);
|
||||||
|
singles.forEach((single) => {
|
||||||
|
if (distance2(portPs, single.position) < 50) {
|
||||||
|
hasSingle = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!hasSingle && !hasBB) {
|
||||||
|
map.set(`${graphic.id}-${port}`, 1);
|
||||||
|
map.set(`${refGraphic.id}-${refPort}`, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!map.has(`${refGraphic.id}-${refPort}`) &&
|
||||||
|
!map.has(`${graphic.id}-${port}`)
|
||||||
|
) {
|
||||||
|
map.set(`${graphic.id}-${port}`, 1);
|
||||||
|
map.set(`${refGraphic.id}-${refPort}`, 1);
|
||||||
|
const refData1 = createRelatedRefProto(reftype, refGraphic.id, refPort);
|
||||||
|
const refData2 = createRelatedRefProto(graphic.type, graphic.id, port);
|
||||||
|
const axleCounting = new AxleCounting(direction);
|
||||||
|
axleCounting.loadData(this.graphicTemplate.datas);
|
||||||
|
if (graphic.type == 'Turnout') {
|
||||||
|
axleCounting.position.set(ps.x, ps.y);
|
||||||
|
} else {
|
||||||
|
axleCounting.position.set(ps.x, ps.y);
|
||||||
|
}
|
||||||
|
axleCounting.id = GraphicIdGenerator.next();
|
||||||
|
axleCounting.datas.axleCountingRef = [refData2, refData1];
|
||||||
|
axleCounting.datas.code = `${graphic.datas.code}-${port}\\${refGraphic.datas.code}-${refPort}`;
|
||||||
|
this.storeGraphic(axleCounting);
|
||||||
|
axleCounting.loadRelations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drawAdd(
|
||||||
|
ps: IPoint,
|
||||||
|
direction: number,
|
||||||
|
graphic: Section | Turnout,
|
||||||
|
port: DevicePort,
|
||||||
|
map: Map<string, number>
|
||||||
|
) {
|
||||||
|
if (!map.has(`${graphic.id}-${port}`)) {
|
||||||
|
map.set(`${graphic.id}-${port}`, 1);
|
||||||
|
const refData = createRelatedRefProto(graphic.type, graphic.id, port);
|
||||||
|
const axleCounting = new AxleCounting(direction);
|
||||||
|
axleCounting.loadData(this.graphicTemplate.datas);
|
||||||
|
if (graphic.type == 'Turnout') {
|
||||||
|
axleCounting.position.set(ps.x, ps.y);
|
||||||
|
} else {
|
||||||
|
axleCounting.position.set(ps.x, ps.y);
|
||||||
|
}
|
||||||
|
axleCounting.id = GraphicIdGenerator.next();
|
||||||
|
axleCounting.datas.axleCountingRef = [refData];
|
||||||
|
axleCounting.datas.code = `${graphic.datas.code}-${port}`;
|
||||||
|
this.storeGraphic(axleCounting);
|
||||||
|
axleCounting.loadRelations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oneGenerates(height: Point) {
|
||||||
|
const map = new Map();
|
||||||
|
const needDelete: AxleCounting[] = [];
|
||||||
|
const axleCountings = this.app.queryStore
|
||||||
|
.queryByType<AxleCounting>(AxleCounting.Type)
|
||||||
|
.filter((axleCounting) => {
|
||||||
|
if (axleCounting.datas.axleCountingRef.length == 1) {
|
||||||
|
const refInfo = axleCounting.datas.axleCountingRef[0];
|
||||||
|
if (refInfo.deviceType == graphicData.RelatedRef.DeviceType.Section) {
|
||||||
|
const refSection = this.app.queryStore.queryById<Section>(
|
||||||
|
refInfo.id
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
refSection.datas.paRef != undefined &&
|
||||||
|
refSection.datas.pbRef != undefined
|
||||||
|
) {
|
||||||
|
needDelete.push(axleCounting);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
this.app.deleteGraphics(...needDelete);
|
||||||
|
const axleCountingRefs: IRelatedRefData[] = [];
|
||||||
|
axleCountings.forEach((axleCounting) => {
|
||||||
|
axleCountingRefs.push(...axleCounting.datas.axleCountingRef);
|
||||||
|
});
|
||||||
|
axleCountingRefs.forEach((axleCountingRef) => {
|
||||||
|
map.set(
|
||||||
|
`${axleCountingRef.id}-${
|
||||||
|
graphicData.RelatedRef.DevicePort[axleCountingRef.devicePort]
|
||||||
|
}`,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
//由区段生成计轴--区段和区段或区段和道岔
|
||||||
|
const sections = this.app.queryStore
|
||||||
|
.queryByType<Section>(Section.Type)
|
||||||
|
.filter((section) => {
|
||||||
|
return (
|
||||||
|
section.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
section,
|
||||||
|
AxleCounting.Type
|
||||||
|
).length < 2 && section.datas.sectionType == SectionType.Physical
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
sections.forEach((section) => {
|
||||||
|
const sectionRelations =
|
||||||
|
section.relationManage.getRelationsOfGraphic(section);
|
||||||
|
const ps = section.localToCanvasPoint(section.getStartPoint());
|
||||||
|
const pe = section.localToCanvasPoint(section.getEndPoint());
|
||||||
|
sectionRelations.forEach((relation) => {
|
||||||
|
const port = relation.getRelationParam(section).param;
|
||||||
|
const refDevice = relation.getOtherGraphic<Section>(section);
|
||||||
|
const refDevicePort = relation.getOtherRelationParam(section).param;
|
||||||
|
let direction = 1;
|
||||||
|
let axleCountingPs = ps;
|
||||||
|
if (port == 'B') {
|
||||||
|
axleCountingPs = pe;
|
||||||
|
}
|
||||||
|
if (axleCountingPs.y > height.y) {
|
||||||
|
direction = -1;
|
||||||
|
}
|
||||||
|
if (refDevice.type == Section.Type || refDevice.type == Turnout.Type)
|
||||||
|
this.draw(
|
||||||
|
axleCountingPs,
|
||||||
|
direction,
|
||||||
|
section,
|
||||||
|
port,
|
||||||
|
map,
|
||||||
|
refDevice.type,
|
||||||
|
refDevice,
|
||||||
|
refDevicePort
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//由区段生成计轴--单独区段
|
||||||
|
sections.forEach((section) => {
|
||||||
|
const axleCountingRelations =
|
||||||
|
section.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
section,
|
||||||
|
AxleCounting.Type
|
||||||
|
);
|
||||||
|
const ps = section.localToCanvasPoint(section.getStartPoint());
|
||||||
|
const pe = section.localToCanvasPoint(section.getEndPoint());
|
||||||
|
if (axleCountingRelations.length < 2) {
|
||||||
|
axleCountingRelations.forEach((relation) => {
|
||||||
|
const port = relation.getRelationParam(section).param;
|
||||||
|
let addPort = DevicePort.A;
|
||||||
|
let direction = 1;
|
||||||
|
let axleCountingPs = ps;
|
||||||
|
if (port == 'A') {
|
||||||
|
axleCountingPs = pe;
|
||||||
|
addPort = DevicePort.B;
|
||||||
|
}
|
||||||
|
if (axleCountingPs.y > height.y) {
|
||||||
|
direction = -1;
|
||||||
|
}
|
||||||
|
if (axleCountingPs.y > height.y) {
|
||||||
|
direction = -1;
|
||||||
|
}
|
||||||
|
this.drawAdd(axleCountingPs, direction, section, addPort, map);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//由道岔生成计轴--道岔和道岔
|
||||||
|
const turnouts = this.app.queryStore
|
||||||
|
.queryByType<Turnout>(Turnout.Type)
|
||||||
|
.filter((turnout) => {
|
||||||
|
return (
|
||||||
|
turnout.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
turnout,
|
||||||
|
AxleCounting.Type
|
||||||
|
).length < 3
|
||||||
|
);
|
||||||
|
});
|
||||||
|
turnouts.forEach((turnout) => {
|
||||||
|
const points = turnout.getPortPoints();
|
||||||
|
//道岔关联的道岔
|
||||||
|
const turnoutRelations =
|
||||||
|
turnout.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
turnout,
|
||||||
|
Turnout.Type
|
||||||
|
);
|
||||||
|
turnoutRelations.forEach((relation) => {
|
||||||
|
const port = relation.getRelationParam(turnout).getParam<DevicePort>();
|
||||||
|
const portIndex = Object.values(DevicePort).findIndex(
|
||||||
|
(p) => p === port
|
||||||
|
);
|
||||||
|
const refTurnout = relation.getOtherGraphic<Turnout>(turnout);
|
||||||
|
const refTurnoutPort = relation.getOtherRelationParam(turnout).param;
|
||||||
|
const portPs = turnout.localToCanvasPoints(...points[portIndex])[
|
||||||
|
points[portIndex].length - 1
|
||||||
|
];
|
||||||
|
this.draw(
|
||||||
|
portPs,
|
||||||
|
1,
|
||||||
|
turnout,
|
||||||
|
port,
|
||||||
|
map,
|
||||||
|
Turnout.Type,
|
||||||
|
refTurnout,
|
||||||
|
refTurnoutPort
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//由道岔生成计轴--单独道岔
|
||||||
|
turnouts.forEach((turnout) => {
|
||||||
|
const axleCountingRelations =
|
||||||
|
turnout.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
turnout,
|
||||||
|
AxleCounting.Type
|
||||||
|
);
|
||||||
|
const points = turnout.getPortPoints();
|
||||||
|
const turnoutPort = [DevicePort.A, DevicePort.B, DevicePort.C];
|
||||||
|
if (axleCountingRelations.length == 1) {
|
||||||
|
const port = axleCountingRelations[0].getRelationParam(turnout).param;
|
||||||
|
const otherPort = turnoutPort.filter((p) => {
|
||||||
|
return p !== port && p;
|
||||||
|
});
|
||||||
|
otherPort.forEach((port) => {
|
||||||
|
const portIndex = Object.values(DevicePort).findIndex(
|
||||||
|
(p) => p === port
|
||||||
|
);
|
||||||
|
const axleCountingPs1 = turnout.localToCanvasPoints(
|
||||||
|
...points[portIndex]
|
||||||
|
)[points[portIndex].length - 1];
|
||||||
|
this.drawAdd(axleCountingPs1, 1, turnout, port, map);
|
||||||
|
});
|
||||||
|
} else if (axleCountingRelations.length == 2) {
|
||||||
|
const port = axleCountingRelations.map(
|
||||||
|
(item) => item.getRelationParam(turnout).param
|
||||||
|
);
|
||||||
|
const otherPort = turnoutPort.filter((p) => {
|
||||||
|
return p !== port[0] && p !== port[1] && p;
|
||||||
|
});
|
||||||
|
if (otherPort.length) {
|
||||||
|
const portIndex = Object.values(DevicePort).findIndex(
|
||||||
|
(p) => p === otherPort[0]
|
||||||
|
);
|
||||||
|
const axleCountingPs1 = turnout.localToCanvasPoints(
|
||||||
|
...points[portIndex]
|
||||||
|
)[points[portIndex].length - 1];
|
||||||
|
this.drawAdd(axleCountingPs1, 1, turnout, otherPort[0], map);
|
||||||
|
}
|
||||||
|
} else if (axleCountingRelations.length == 0) {
|
||||||
|
const axleCountingPsA = turnout.localToCanvasPoints(points[0][0])[0];
|
||||||
|
const axleCountingPsC = turnout.localToCanvasPoints(points[2][0])[0];
|
||||||
|
this.drawAdd(axleCountingPsA, 1, turnout, DevicePort.A, map);
|
||||||
|
this.drawAdd(axleCountingPsC, 1, turnout, DevicePort.C, map);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(
|
||||||
|
axleCounting: AxleCounting
|
||||||
|
): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const axleCountings = axleCounting.queryStore.queryByType<AxleCounting>(
|
||||||
|
AxleCounting.Type
|
||||||
|
);
|
||||||
|
const { width } = axleCounting.getGraphicApp().canvas;
|
||||||
|
axleCountings.forEach((other) => {
|
||||||
|
if (other.id == axleCounting.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ps = other.datas.transform.position;
|
||||||
|
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
|
||||||
|
aps.push(xs);
|
||||||
|
});
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AxleCountingInteraction extends GraphicInteractionPlugin<AxleCounting> {
|
||||||
|
static Name = 'AxleCounting_transform';
|
||||||
|
constructor(app: IDrawApp) {
|
||||||
|
super(AxleCountingInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new AxleCountingInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): AxleCounting[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === AxleCounting.Type)
|
||||||
|
.map((g) => g as AxleCounting);
|
||||||
|
}
|
||||||
|
bind(g: AxleCounting): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.scalable = true;
|
||||||
|
g.rotatable = true;
|
||||||
|
g.kilometerGraph.eventMode = 'static';
|
||||||
|
g.kilometerGraph.cursor = 'pointer';
|
||||||
|
g.kilometerGraph.draggable = true;
|
||||||
|
g.kilometerGraph.selectable = true;
|
||||||
|
g.kilometerGraph.transformSave = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
unbind(g: AxleCounting): void {
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.scalable = false;
|
||||||
|
g.rotatable = false;
|
||||||
|
g.kilometerGraph.eventMode = 'none';
|
||||||
|
g.kilometerGraph.draggable = false;
|
||||||
|
g.kilometerGraph.selectable = false;
|
||||||
|
g.kilometerGraph.transformSave = false;
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
onSelected(): void {
|
||||||
|
const AxleCounting = this.app.selectedGraphics[0] as AxleCounting;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(AxleCounting),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
164
src/graphics/electronicMap/platform/Platform.ts
Normal file
164
src/graphics/electronicMap/platform/Platform.ts
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import { Color, Container, Graphics, Rectangle } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicState,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
distance2,
|
||||||
|
getRectangleCenter,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { Station } from '../station/Station';
|
||||||
|
import { Section } from '../section/Section';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
|
||||||
|
export interface IPlatformData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
set code(v: string);
|
||||||
|
get refStation(): number; // 关联的车站
|
||||||
|
set refStation(v: number);
|
||||||
|
get refSection(): number; // 关联的物理区段
|
||||||
|
set refSection(v: number);
|
||||||
|
get refEsbRelayCode(): string; // 关联的紧急停车继电器的编号
|
||||||
|
set refEsbRelayCode(v: string);
|
||||||
|
get type(): electronicMapGraphicData.Platform.TypeOfPlatform; //站台上下行
|
||||||
|
set type(v: electronicMapGraphicData.Platform.TypeOfPlatform);
|
||||||
|
clone(): IPlatformData;
|
||||||
|
copyFrom(data: IPlatformData): void;
|
||||||
|
eq(other: IPlatformData): boolean;
|
||||||
|
}
|
||||||
|
export interface IPlatformState extends GraphicState {
|
||||||
|
id?: number;
|
||||||
|
empj?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const platformConsts = {
|
||||||
|
width: 90,
|
||||||
|
height: 20,
|
||||||
|
lineWidth: 3,
|
||||||
|
white: '0xffffff', //站台颜色
|
||||||
|
};
|
||||||
|
|
||||||
|
//子元素--矩形
|
||||||
|
export class rectGraphic extends Container {
|
||||||
|
static Type = 'RectPlatForm';
|
||||||
|
rectGraphic: Graphics;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.rectGraphic = new Graphics();
|
||||||
|
this.addChild(this.rectGraphic);
|
||||||
|
}
|
||||||
|
draw(): void {
|
||||||
|
const rectGraphic = this.rectGraphic;
|
||||||
|
const fillColor = platformConsts.white;
|
||||||
|
rectGraphic
|
||||||
|
.clear()
|
||||||
|
.lineStyle(platformConsts.lineWidth, new Color(fillColor))
|
||||||
|
.beginFill(fillColor, 1)
|
||||||
|
.drawRect(0, 0, platformConsts.width, platformConsts.height)
|
||||||
|
.endFill();
|
||||||
|
rectGraphic.pivot = getRectangleCenter(
|
||||||
|
new Rectangle(0, 0, platformConsts.width, platformConsts.height)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
clear(): void {
|
||||||
|
this.rectGraphic.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class Platform extends JlGraphic {
|
||||||
|
static Type = 'Platform';
|
||||||
|
rectGraphic: rectGraphic = new rectGraphic();
|
||||||
|
constructor() {
|
||||||
|
super(Platform.Type);
|
||||||
|
this.addChild(this.rectGraphic);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
get datas(): IPlatformData {
|
||||||
|
return this.getDatas<IPlatformData>();
|
||||||
|
}
|
||||||
|
get states(): IPlatformState {
|
||||||
|
return this.getStates<IPlatformState>();
|
||||||
|
}
|
||||||
|
doRepaint(): void {
|
||||||
|
this.rectGraphic.draw();
|
||||||
|
}
|
||||||
|
buildRelation() {
|
||||||
|
const stationas = this.queryStore.queryByType<Station>(Station.Type);
|
||||||
|
for (let i = 0; i < stationas.length; i++) {
|
||||||
|
const sP = stationas[i].localBoundsToCanvasPoints();
|
||||||
|
if (this.x > sP[0].x && this.x < sP[1].x) {
|
||||||
|
this.relationManage.addRelation(this, stationas[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sections = this.queryStore.queryByType<Section>(Section.Type);
|
||||||
|
const minDistanceRefSections: Section[] = [];
|
||||||
|
sections.forEach((section) => {
|
||||||
|
const sP = section.localBoundsToCanvasPoints();
|
||||||
|
if (this.x > sP[0].x && this.x < sP[1].x) {
|
||||||
|
minDistanceRefSections.push(section);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (minDistanceRefSections) {
|
||||||
|
const refSection = minDistanceRefSections.reduce((prev, cur) => {
|
||||||
|
return distance2(
|
||||||
|
prev.localToCanvasPoint(getRectangleCenter(prev.getLocalBounds())),
|
||||||
|
this.position
|
||||||
|
) >
|
||||||
|
distance2(
|
||||||
|
cur.localToCanvasPoint(getRectangleCenter(cur.getLocalBounds())),
|
||||||
|
this.position
|
||||||
|
)
|
||||||
|
? cur
|
||||||
|
: prev;
|
||||||
|
});
|
||||||
|
this.relationManage.deleteRelationOfGraphicAndOtherType(
|
||||||
|
this,
|
||||||
|
Section.Type
|
||||||
|
);
|
||||||
|
this.relationManage.addRelation(this, refSection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveRelations() {
|
||||||
|
const refStation = this.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(this, Station.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<Station>(this).datas.id);
|
||||||
|
if (refStation.length) {
|
||||||
|
this.datas.refStation = refStation[0];
|
||||||
|
}
|
||||||
|
const refSection = this.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(this, Section.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<Section>(this).datas.id);
|
||||||
|
if (refSection.length) {
|
||||||
|
this.datas.refSection = refSection[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadRelations() {
|
||||||
|
if (this.datas.refStation) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
this,
|
||||||
|
this.queryStore.queryById<Platform>(this.datas.refStation)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.datas.refSection) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
this,
|
||||||
|
this.queryStore.queryById<Platform>(this.datas.refSection)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PlatformTemplate extends JlGraphicTemplate<Platform> {
|
||||||
|
constructor(dataTemplate: IPlatformData) {
|
||||||
|
super(Platform.Type, {
|
||||||
|
dataTemplate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
new(): Platform {
|
||||||
|
const platform = new Platform();
|
||||||
|
platform.loadData(this.datas);
|
||||||
|
return platform;
|
||||||
|
}
|
||||||
|
}
|
103
src/graphics/electronicMap/platform/PlatformDrawAssistant.ts
Normal file
103
src/graphics/electronicMap/platform/PlatformDrawAssistant.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { FederatedPointerEvent, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import { IPlatformData, Platform, PlatformTemplate } from './Platform';
|
||||||
|
|
||||||
|
export interface IPlatformDrawOptions {
|
||||||
|
newData: () => IPlatformData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PlatformDraw extends GraphicDrawAssistant<
|
||||||
|
PlatformTemplate,
|
||||||
|
IPlatformData
|
||||||
|
> {
|
||||||
|
platformGraphic: Platform;
|
||||||
|
constructor(app: IDrawApp, template: PlatformTemplate) {
|
||||||
|
super(
|
||||||
|
app,
|
||||||
|
template,
|
||||||
|
'svguse:../../drawIcon.svg#icon-platform',
|
||||||
|
'站台Platform'
|
||||||
|
);
|
||||||
|
this.platformGraphic = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.platformGraphic);
|
||||||
|
platformInteraction.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.platformGraphic.loadData(this.graphicTemplate.datas);
|
||||||
|
this.platformGraphic.doRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftDown(e: FederatedPointerEvent): void {
|
||||||
|
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.container.position.copyFrom(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareData(data: IPlatformData): boolean {
|
||||||
|
data.transform = this.container.saveTransform();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(platform: Platform): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const platforms = platform.queryStore.queryByType<Platform>(Platform.Type);
|
||||||
|
const { width, height } = platform.getGraphicApp().canvas;
|
||||||
|
platforms.forEach((other) => {
|
||||||
|
if (other.id == platform.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ps = other.datas.transform.position;
|
||||||
|
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
|
||||||
|
const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
|
||||||
|
aps.push(xs, ys);
|
||||||
|
});
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class platformInteraction extends GraphicInteractionPlugin<Platform> {
|
||||||
|
static Name = 'platform_transform';
|
||||||
|
constructor(app: IDrawApp) {
|
||||||
|
super(platformInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new platformInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Platform[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Platform.Type)
|
||||||
|
.map((g) => g as Platform);
|
||||||
|
}
|
||||||
|
bind(g: Platform): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.scalable = true;
|
||||||
|
g.rotatable = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
unbind(g: Platform): void {
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.scalable = false;
|
||||||
|
g.rotatable = false;
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
onSelected(): void {
|
||||||
|
const platform = this.app.selectedGraphics[0] as Platform;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(platform),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
219
src/graphics/electronicMap/screenDoor/ScreenDoor.ts
Normal file
219
src/graphics/electronicMap/screenDoor/ScreenDoor.ts
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
import { Color, Container, Graphics, Rectangle } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicState,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
VectorText,
|
||||||
|
distance2,
|
||||||
|
getRectangleCenter,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { Platform } from '../platform/Platform';
|
||||||
|
import { state } from 'src/protos/device_state';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
|
export interface IScreenDoorData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
set code(v: string);
|
||||||
|
get refPlatform(): number; // 关联的站台
|
||||||
|
set refPlatform(v: number);
|
||||||
|
get sonDoorAmount(): number; //子屏蔽门的数量
|
||||||
|
clone(): IScreenDoorData;
|
||||||
|
copyFrom(data: IScreenDoorData): void;
|
||||||
|
eq(other: IScreenDoorData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IScreenDoorState extends GraphicState {
|
||||||
|
get asdStates(): state.AsdState[]; //所有子门的状态
|
||||||
|
set asdStates(v: state.AsdState[]);
|
||||||
|
get mgj(): boolean; //屏蔽门整体的关闭(继电器)状态
|
||||||
|
set mgj(v: boolean);
|
||||||
|
get zaw(): boolean; //是否有障碍物
|
||||||
|
set zaw(v: boolean);
|
||||||
|
param: request.PsdParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
const screenDoorConsts = {
|
||||||
|
lineWidth: 3,
|
||||||
|
smallDoorWidth: 10,
|
||||||
|
doorClose: '0x00FF00', //屏蔽门的颜色
|
||||||
|
doorOpen: '0xff0000',
|
||||||
|
zawWidth: 3,
|
||||||
|
zawHeight: 3,
|
||||||
|
zawlineWidth: 3,
|
||||||
|
zawColor: '0xff0000',
|
||||||
|
forceWidth: 11,
|
||||||
|
forceHeight: 12,
|
||||||
|
forcelineWidth: 1,
|
||||||
|
forceColor: '0xff0000',
|
||||||
|
};
|
||||||
|
|
||||||
|
class smallDoorGraphic extends Container {
|
||||||
|
smallDoorGraphic: Graphics;
|
||||||
|
labelGraphic: VectorText;
|
||||||
|
zawGraphic: Graphics;
|
||||||
|
forceGraphic: Graphics;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.smallDoorGraphic = new Graphics();
|
||||||
|
this.zawGraphic = new Graphics();
|
||||||
|
this.forceGraphic = new Graphics();
|
||||||
|
this.labelGraphic = new VectorText();
|
||||||
|
this.labelGraphic.setVectorFontSize(12);
|
||||||
|
this.labelGraphic.anchor.set(0.5);
|
||||||
|
this.addChild(this.smallDoorGraphic);
|
||||||
|
this.addChild(this.labelGraphic);
|
||||||
|
this.addChild(this.zawGraphic);
|
||||||
|
this.addChild(this.forceGraphic);
|
||||||
|
this.drawZaw();
|
||||||
|
this.drawForce();
|
||||||
|
}
|
||||||
|
draw(data: IScreenDoorData, i: number, state: state.AsdState): void {
|
||||||
|
const start =
|
||||||
|
(-screenDoorConsts.smallDoorWidth * data.sonDoorAmount) / 2 +
|
||||||
|
screenDoorConsts.smallDoorWidth * i;
|
||||||
|
const smallDoorGraphic = this.smallDoorGraphic;
|
||||||
|
const lineColor = state?.mgj
|
||||||
|
? screenDoorConsts.doorClose
|
||||||
|
: screenDoorConsts.doorOpen;
|
||||||
|
smallDoorGraphic
|
||||||
|
.lineStyle(screenDoorConsts.lineWidth, new Color(lineColor))
|
||||||
|
.moveTo(start, 0)
|
||||||
|
.lineTo(start + screenDoorConsts.smallDoorWidth - 3, 0);
|
||||||
|
this.labelGraphic.text = i + 1;
|
||||||
|
this.labelGraphic.style.fill = 'red';
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
this.labelGraphic.position.set(start + 4, 9);
|
||||||
|
this.zawGraphic.position.set(start + 4, -9);
|
||||||
|
this.forceGraphic.position.set(start + 4, 9);
|
||||||
|
} else {
|
||||||
|
this.labelGraphic.position.set(start + 4, -9);
|
||||||
|
this.zawGraphic.position.set(start + 4, 9);
|
||||||
|
this.forceGraphic.position.set(start + 4, -9);
|
||||||
|
}
|
||||||
|
this.zawGraphic.visible = state?.zaw ? true : false;
|
||||||
|
this.forceGraphic.visible = state?.force ? true : false;
|
||||||
|
}
|
||||||
|
drawZaw() {
|
||||||
|
this.zawGraphic
|
||||||
|
.clear()
|
||||||
|
.lineStyle(
|
||||||
|
screenDoorConsts.zawlineWidth,
|
||||||
|
new Color(screenDoorConsts.zawColor)
|
||||||
|
)
|
||||||
|
.drawRect(0, 0, screenDoorConsts.zawWidth, screenDoorConsts.zawHeight);
|
||||||
|
this.zawGraphic.pivot = getRectangleCenter(
|
||||||
|
new Rectangle(0, 0, screenDoorConsts.zawWidth, screenDoorConsts.zawHeight)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
drawForce() {
|
||||||
|
this.forceGraphic
|
||||||
|
.clear()
|
||||||
|
.lineStyle(
|
||||||
|
screenDoorConsts.forcelineWidth,
|
||||||
|
new Color(screenDoorConsts.forceColor)
|
||||||
|
)
|
||||||
|
.drawRect(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
screenDoorConsts.forceWidth,
|
||||||
|
screenDoorConsts.forceHeight
|
||||||
|
);
|
||||||
|
this.forceGraphic.pivot = getRectangleCenter(
|
||||||
|
new Rectangle(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
screenDoorConsts.forceWidth,
|
||||||
|
screenDoorConsts.forceHeight
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScreenDoor extends JlGraphic {
|
||||||
|
static Type = 'ScreenDoor';
|
||||||
|
doorGraphic = new Container();
|
||||||
|
constructor() {
|
||||||
|
super(ScreenDoor.Type);
|
||||||
|
this.addChild(this.doorGraphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
get datas(): IScreenDoorData {
|
||||||
|
return this.getDatas<IScreenDoorData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get states(): IScreenDoorState {
|
||||||
|
return this.getStates<IScreenDoorState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint(): void {
|
||||||
|
const doorGraphic = this.doorGraphic;
|
||||||
|
doorGraphic.children.forEach((g) => {
|
||||||
|
(g as smallDoorGraphic).smallDoorGraphic.clear();
|
||||||
|
(g as smallDoorGraphic).zawGraphic.clear();
|
||||||
|
(g as smallDoorGraphic).forceGraphic.clear();
|
||||||
|
(g as smallDoorGraphic).labelGraphic.text = '';
|
||||||
|
});
|
||||||
|
for (let i = 0; i < this.datas.sonDoorAmount; i++) {
|
||||||
|
const smallDoor = new smallDoorGraphic();
|
||||||
|
const smallDoorState = this.states.asdStates.find(
|
||||||
|
(asdState) => +asdState.code == i + 1
|
||||||
|
);
|
||||||
|
smallDoor.draw(this.datas, i, smallDoorState as state.AsdState);
|
||||||
|
doorGraphic.addChild(smallDoor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildRelation() {
|
||||||
|
const platforms = this.queryStore.queryByType<Platform>(Platform.Type);
|
||||||
|
const minDistanceRefPlatform: Platform[] = [];
|
||||||
|
platforms.forEach((platform) => {
|
||||||
|
const sP = platform.localBoundsToCanvasPoints();
|
||||||
|
if (this.x > sP[0].x && this.x < sP[1].x) {
|
||||||
|
minDistanceRefPlatform.push(platform);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const refPlatform = minDistanceRefPlatform.reduce((prev, cur) => {
|
||||||
|
return distance2(prev.position, this.position) >
|
||||||
|
distance2(cur.position, this.position)
|
||||||
|
? cur
|
||||||
|
: prev;
|
||||||
|
});
|
||||||
|
if (refPlatform) {
|
||||||
|
this.relationManage.addRelation(this, refPlatform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveRelations() {
|
||||||
|
const refStation = this.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(this, Platform.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<Platform>(this).datas.id);
|
||||||
|
if (refStation.length) {
|
||||||
|
this.datas.refPlatform = refStation[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadRelations() {
|
||||||
|
if (this.datas.refPlatform) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
this,
|
||||||
|
this.queryStore.queryById<Platform>(this.datas.refPlatform)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScreenDoorTemplate extends JlGraphicTemplate<ScreenDoor> {
|
||||||
|
constructor(dataTemplate: IScreenDoorData, stateTemplate?: IScreenDoorState) {
|
||||||
|
super(ScreenDoor.Type, {
|
||||||
|
dataTemplate,
|
||||||
|
stateTemplate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
new(): ScreenDoor {
|
||||||
|
const screenDoor = new ScreenDoor();
|
||||||
|
screenDoor.loadData(this.datas);
|
||||||
|
screenDoor.loadState(this.states);
|
||||||
|
return screenDoor;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
import { FederatedPointerEvent, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import { IScreenDoorData, ScreenDoor, ScreenDoorTemplate } from './ScreenDoor';
|
||||||
|
import { Platform } from 'src/graphics/platform/Platform';
|
||||||
|
|
||||||
|
export interface IScreenDoorDrawOptions {
|
||||||
|
newData: () => IScreenDoorData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScreenDoorDraw extends GraphicDrawAssistant<
|
||||||
|
ScreenDoorTemplate,
|
||||||
|
IScreenDoorData
|
||||||
|
> {
|
||||||
|
screenDoorGraphic: ScreenDoor;
|
||||||
|
constructor(app: IDrawApp, template: ScreenDoorTemplate) {
|
||||||
|
super(app, template, 'door_sliding', '屏蔽门ScreenDoor');
|
||||||
|
this.screenDoorGraphic = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.screenDoorGraphic);
|
||||||
|
screenDoorInteraction.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.screenDoorGraphic.loadData(this.graphicTemplate.datas);
|
||||||
|
this.screenDoorGraphic.doRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftDown(e: FederatedPointerEvent): void {
|
||||||
|
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.container.position.copyFrom(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareData(data: IScreenDoorData): boolean {
|
||||||
|
data.transform = this.container.saveTransform();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(
|
||||||
|
screenDoor: ScreenDoor
|
||||||
|
): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const platforms = screenDoor.queryStore.queryByType<Platform>(Platform.Type);
|
||||||
|
const { height } = screenDoor.getGraphicApp().canvas;
|
||||||
|
platforms.forEach((platform) => {
|
||||||
|
const ps = platform.datas.transform.position;
|
||||||
|
const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
|
||||||
|
aps.push(ys);
|
||||||
|
});
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class screenDoorInteraction extends GraphicInteractionPlugin<ScreenDoor> {
|
||||||
|
static Name = 'screenDoor_transform';
|
||||||
|
constructor(app: IDrawApp) {
|
||||||
|
super(screenDoorInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new screenDoorInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): ScreenDoor[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === ScreenDoor.Type)
|
||||||
|
.map((g) => g as ScreenDoor);
|
||||||
|
}
|
||||||
|
bind(g: ScreenDoor): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.scalable = true;
|
||||||
|
g.rotatable = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
unbind(g: ScreenDoor): void {
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.scalable = false;
|
||||||
|
g.rotatable = false;
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
onSelected(): void {
|
||||||
|
const screenDoor = this.app.selectedGraphics[0] as ScreenDoor;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(screenDoor),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
407
src/graphics/electronicMap/section/Section.ts
Normal file
407
src/graphics/electronicMap/section/Section.ts
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
import { IPointData } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicRelationParam,
|
||||||
|
GraphicState,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
VectorText,
|
||||||
|
convertToBezierParams,
|
||||||
|
distance2,
|
||||||
|
splitLineEvenly,
|
||||||
|
ILineGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import { Vector2 } from 'jl-graphic';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IRelatedRefData,
|
||||||
|
createRelatedRefProto,
|
||||||
|
protoPort2Data,
|
||||||
|
} from '../CommonGraphics';
|
||||||
|
import { Turnout } from '../turnout/Turnout';
|
||||||
|
import { AxleCounting } from '../axleCounting/AxleCounting';
|
||||||
|
|
||||||
|
import { SectionGraphic } from '../sectionGraphic/SectionGraphic';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
|
||||||
|
const tolerance = 0.01;
|
||||||
|
|
||||||
|
export enum SectionType {
|
||||||
|
Physical = 0,
|
||||||
|
Logic = 1,
|
||||||
|
TurnoutPhysical = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISectionData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
set code(v: string);
|
||||||
|
get points(): IPointData[]; // 线坐标点
|
||||||
|
set points(points: IPointData[]);
|
||||||
|
get paRef(): IRelatedRefData | undefined;
|
||||||
|
set paRef(ref: IRelatedRefData | undefined);
|
||||||
|
get pbRef(): IRelatedRefData | undefined;
|
||||||
|
set pbRef(ref: IRelatedRefData | undefined);
|
||||||
|
get sectionType(): SectionType;
|
||||||
|
set sectionType(type: SectionType);
|
||||||
|
get axleCountings(): number[]; //计轴id列表
|
||||||
|
set axleCountings(axleCountings: number[]);
|
||||||
|
get trackSectionId(): number; // 轨道区段id
|
||||||
|
set trackSectionId(v: number);
|
||||||
|
get isCurve(): boolean; // 是否曲线
|
||||||
|
set isCurve(v: boolean);
|
||||||
|
get segmentsCount(): number; // 曲线分段数
|
||||||
|
set segmentsCount(v: number);
|
||||||
|
get centralizedStations(): number[];
|
||||||
|
set centralizedStations(v: number[]);
|
||||||
|
get normalRunningDirection(): electronicMapGraphicData.Section.RunningDirection;
|
||||||
|
set normalRunningDirection(v: electronicMapGraphicData.Section.RunningDirection);
|
||||||
|
get isTurnBackZone(): boolean;
|
||||||
|
set isTurnBackZone(v: boolean);
|
||||||
|
get direction(): electronicMapGraphicData.Direction;
|
||||||
|
set direction(v: electronicMapGraphicData.Direction);
|
||||||
|
clone(): ISectionData;
|
||||||
|
copyFrom(data: ISectionData): void;
|
||||||
|
eq(other: ISectionData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISectionState extends GraphicState {
|
||||||
|
id: number;
|
||||||
|
occupied?: boolean; //区段占用
|
||||||
|
axleFault?: boolean; //计轴故障
|
||||||
|
axleDrst: boolean; // 计轴复位
|
||||||
|
axlePdrst: boolean; // 计轴预复位
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SectionConsts = {
|
||||||
|
lineColor: '#5578b6',
|
||||||
|
occupiedColor: '#f00',
|
||||||
|
lineWidth: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum DevicePort {
|
||||||
|
A = 'A',
|
||||||
|
B = 'B',
|
||||||
|
C = 'C',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Section extends JlGraphic implements ILineGraphic {
|
||||||
|
static Type = 'Section';
|
||||||
|
lineGraphic: SectionGraphic;
|
||||||
|
labelGraphic: VectorText;
|
||||||
|
childSections: Section[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Section.Type);
|
||||||
|
this.lineGraphic = new SectionGraphic();
|
||||||
|
this.labelGraphic = new VectorText();
|
||||||
|
this.labelGraphic.setVectorFontSize(14);
|
||||||
|
this.labelGraphic.anchor.set(0.5);
|
||||||
|
this.labelGraphic.style.fill = '#0f0';
|
||||||
|
this.labelGraphic.transformSave = true;
|
||||||
|
this.labelGraphic.name = 'label';
|
||||||
|
this.transformSave = true;
|
||||||
|
this.addChild(this.lineGraphic);
|
||||||
|
this.addChild(this.labelGraphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint() {
|
||||||
|
if (
|
||||||
|
this.datas.sectionType === SectionType.Physical &&
|
||||||
|
this.datas.points.length < 2
|
||||||
|
) {
|
||||||
|
throw new Error('Link坐标数据异常');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lineGraphic.clear();
|
||||||
|
if (this.datas.sectionType === SectionType.Physical) {
|
||||||
|
this.lineGraphic.isCurve = this.datas.isCurve;
|
||||||
|
if (this.lineGraphic.isCurve) {
|
||||||
|
this.lineGraphic.segmentsCount = this.datas.segmentsCount;
|
||||||
|
}
|
||||||
|
this.lineGraphic.points = this.datas.points;
|
||||||
|
this.lineGraphic.lineStyle(
|
||||||
|
SectionConsts.lineWidth,
|
||||||
|
this.states.occupied
|
||||||
|
? SectionConsts.occupiedColor
|
||||||
|
: SectionConsts.lineColor
|
||||||
|
);
|
||||||
|
//FIXME 依赖location.path不合适
|
||||||
|
if (location.pathname.includes('painting')) {
|
||||||
|
if (
|
||||||
|
this.datas.normalRunningDirection ===
|
||||||
|
electronicMapGraphicData.Section.RunningDirection.BtoA
|
||||||
|
) {
|
||||||
|
this.lineGraphic.lineStyle(SectionConsts.lineWidth, '#f00');
|
||||||
|
} else if (
|
||||||
|
this.datas.normalRunningDirection ===
|
||||||
|
electronicMapGraphicData.Section.RunningDirection.AtoB
|
||||||
|
) {
|
||||||
|
this.lineGraphic.lineStyle(SectionConsts.lineWidth, '#0f0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lineGraphic.paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.labelGraphic.text = this.datas.code;
|
||||||
|
const labelPosition = this.datas.childTransforms?.find(
|
||||||
|
(t) => t.name === this.labelGraphic.name
|
||||||
|
)?.transform.position;
|
||||||
|
if (labelPosition) {
|
||||||
|
this.labelGraphic.position.set(labelPosition.x, labelPosition.y);
|
||||||
|
} else {
|
||||||
|
this.labelGraphic.position.set(
|
||||||
|
this.datas.points[0].x,
|
||||||
|
this.datas.points[0].y + 20
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getVerticesList(): IPointData[] {
|
||||||
|
if (this.datas.isCurve) {
|
||||||
|
return [
|
||||||
|
this.datas.points[0],
|
||||||
|
...convertToBezierParams(this.datas.points).map((param) => param.p2),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return this.datas.points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getStartPoint() {
|
||||||
|
return this.datas.points[0];
|
||||||
|
}
|
||||||
|
getEndPoint(): IPointData {
|
||||||
|
return this.datas.points[this.datas.points.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
get datas(): ISectionData {
|
||||||
|
return this.getDatas<ISectionData>();
|
||||||
|
}
|
||||||
|
get states(): ISectionState {
|
||||||
|
return this.getStates<ISectionState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get linePoints(): IPointData[] {
|
||||||
|
return this.datas.points;
|
||||||
|
}
|
||||||
|
set linePoints(points: IPointData[]) {
|
||||||
|
const old = this.datas.clone();
|
||||||
|
old.points = points;
|
||||||
|
this.updateData(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
getConnectElement(port: DevicePort) {
|
||||||
|
const relation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).getParam<DevicePort>() === port &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
if (!relation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
g: relation?.getOtherGraphic(this) as Section | Turnout,
|
||||||
|
port: relation?.getOtherRelationParam(this).getParam<DevicePort>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取拆分逻辑区段数据 */
|
||||||
|
getSplitPoints(count: number): IPointData[][] {
|
||||||
|
if (this.datas.points.length !== 2) {
|
||||||
|
let totalLen = 0;
|
||||||
|
const lengths: number[] = [];
|
||||||
|
for (let i = 1; i < this.datas.points.length; i++) {
|
||||||
|
const { x: x1, y: y1 } = this.datas.points[i - 1],
|
||||||
|
{ x: x2, y: y2 } = this.datas.points[i];
|
||||||
|
const len = new Vector2([x2 - x1, y2 - y1]).length();
|
||||||
|
totalLen += len;
|
||||||
|
lengths.push(len);
|
||||||
|
}
|
||||||
|
const counts = lengths.map((length) =>
|
||||||
|
Math.round((count * length) / totalLen)
|
||||||
|
);
|
||||||
|
if (counts.reduce((p, c) => p + c, 0) !== count) {
|
||||||
|
const intersection = counts.reduce((p, c) => p + c, 0) - count;
|
||||||
|
let maxCountIndex = 0,
|
||||||
|
maxCount = 0;
|
||||||
|
counts.forEach((c, i) => {
|
||||||
|
if (c > maxCount) {
|
||||||
|
maxCount = c;
|
||||||
|
maxCountIndex = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
counts[maxCountIndex] + intersection;
|
||||||
|
}
|
||||||
|
return counts
|
||||||
|
.map((count, i) => {
|
||||||
|
return splitLineEvenly(
|
||||||
|
this.localToCanvasPoint(this.datas.points[i]),
|
||||||
|
this.localToCanvasPoint(this.datas.points[i + 1]),
|
||||||
|
count
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
} else {
|
||||||
|
return splitLineEvenly(
|
||||||
|
this.localToCanvasPoint(this.datas.points[0]),
|
||||||
|
this.localToCanvasPoint(
|
||||||
|
this.datas.points[this.datas.points.length - 1]
|
||||||
|
),
|
||||||
|
count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRelation() {
|
||||||
|
this.relationManage.deleteRelationOfGraphicAndOtherType(this, Section.Type);
|
||||||
|
|
||||||
|
if (this.datas.sectionType === SectionType.Physical) {
|
||||||
|
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
|
||||||
|
if (section.id === this.id) return;
|
||||||
|
|
||||||
|
let param: DevicePort[] = [];
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
this.localToCanvasPoint(this.getStartPoint()),
|
||||||
|
section.localToCanvasPoint(section.getStartPoint())
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
param = [DevicePort.A, DevicePort.A];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
this.localToCanvasPoint(this.getEndPoint()),
|
||||||
|
section.localToCanvasPoint(section.getStartPoint())
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
param = [DevicePort.B, DevicePort.A];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
this.localToCanvasPoint(this.getStartPoint()),
|
||||||
|
section.localToCanvasPoint(section.getEndPoint())
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
param = [DevicePort.A, DevicePort.B];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
this.localToCanvasPoint(this.getEndPoint()),
|
||||||
|
section.localToCanvasPoint(section.getEndPoint())
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
param = [DevicePort.B, DevicePort.B];
|
||||||
|
}
|
||||||
|
if (param.length) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, param[0]),
|
||||||
|
new GraphicRelationParam(section, param[1])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRelations() {
|
||||||
|
const paRelation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).param === DevicePort.A &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
const paDevice = paRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||||
|
if (paDevice) {
|
||||||
|
this.datas.paRef = createRelatedRefProto(
|
||||||
|
paDevice.type,
|
||||||
|
paDevice.id,
|
||||||
|
paRelation?.getOtherRelationParam(this).param
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.datas.paRef = undefined;
|
||||||
|
}
|
||||||
|
const pbRelation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).param === DevicePort.B &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
const pbDevice = pbRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||||
|
if (pbDevice) {
|
||||||
|
this.datas.pbRef = createRelatedRefProto(
|
||||||
|
pbDevice.type,
|
||||||
|
pbDevice.id,
|
||||||
|
pbRelation?.getOtherRelationParam(this).param
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.datas.pbRef = undefined;
|
||||||
|
}
|
||||||
|
this.datas.axleCountings = this.relationManage
|
||||||
|
.getRelationsOfGraphicAndOtherType(this, AxleCounting.Type)
|
||||||
|
.map((relation) => relation.getOtherGraphic<AxleCounting>(this).datas.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRelations() {
|
||||||
|
if (this.datas?.paRef?.id) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, DevicePort.A),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.paRef.id),
|
||||||
|
protoPort2Data(this.datas.paRef.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.datas?.pbRef?.id) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, DevicePort.B),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.pbRef.id),
|
||||||
|
protoPort2Data(this.datas.pbRef.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.datas.sectionType === SectionType.TurnoutPhysical) {
|
||||||
|
if (this.datas.axleCountings) {
|
||||||
|
this.datas.axleCountings.forEach((id) => {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
this,
|
||||||
|
this.queryStore.queryById<AxleCounting>(id)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISectionTemplateProperty {
|
||||||
|
isCurve: boolean;
|
||||||
|
segmentsCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SectionTemplate
|
||||||
|
extends JlGraphicTemplate<Section>
|
||||||
|
implements ISectionTemplateProperty
|
||||||
|
{
|
||||||
|
isCurve = false;
|
||||||
|
segmentsCount = 10;
|
||||||
|
constructor(dataTemplate: ISectionData, stateTemplate?: ISectionState) {
|
||||||
|
super(Section.Type, { dataTemplate, stateTemplate });
|
||||||
|
}
|
||||||
|
new() {
|
||||||
|
const g = new Section();
|
||||||
|
g.loadData(this.datas);
|
||||||
|
g.loadState(this.states);
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
671
src/graphics/electronicMap/section/SectionDrawAssistant.ts
Normal file
671
src/graphics/electronicMap/section/SectionDrawAssistant.ts
Normal file
@ -0,0 +1,671 @@
|
|||||||
|
import {
|
||||||
|
DisplayObject,
|
||||||
|
FederatedMouseEvent,
|
||||||
|
Graphics,
|
||||||
|
IHitArea,
|
||||||
|
IPointData,
|
||||||
|
Point,
|
||||||
|
} from 'pixi.js';
|
||||||
|
import { Dialog } from 'quasar';
|
||||||
|
import SectionSplitDialog from 'src/components/draw-app/dialogs/SectionSplitDialog.vue';
|
||||||
|
import { LogicSectionData } from 'src/drawApp/graphics/LogicSectionInteraction';
|
||||||
|
import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
|
||||||
|
import {
|
||||||
|
AppConsts,
|
||||||
|
ChildTransform,
|
||||||
|
DraggablePoint,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
GraphicTransform,
|
||||||
|
GraphicTransformEvent,
|
||||||
|
IDrawApp,
|
||||||
|
IGraphicApp,
|
||||||
|
JlGraphic,
|
||||||
|
KeyListener,
|
||||||
|
VectorText,
|
||||||
|
calculateLineMidpoint,
|
||||||
|
calculateMirrorPoint,
|
||||||
|
convertToBezierParams,
|
||||||
|
linePoint,
|
||||||
|
pointPolygon,
|
||||||
|
BezierCurveEditPlugin,
|
||||||
|
IEditPointOptions,
|
||||||
|
ILineGraphic,
|
||||||
|
PolylineEditPlugin,
|
||||||
|
addWayPoint,
|
||||||
|
clearWayPoint,
|
||||||
|
getWaypointRangeIndex,
|
||||||
|
ContextMenu,
|
||||||
|
MenuItemOptions,
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
AbsorbablePoint,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||||
|
import { AxleCounting } from '../axleCounting/AxleCounting';
|
||||||
|
import { LogicSection } from '../logicSection/LogicSection';
|
||||||
|
import { LogicSectionDraw } from '../logicSection/LogicSectionDrawAssistant';
|
||||||
|
import { Turnout } from '../turnout/Turnout';
|
||||||
|
import {
|
||||||
|
ISectionData,
|
||||||
|
Section,
|
||||||
|
DevicePort,
|
||||||
|
SectionConsts,
|
||||||
|
SectionTemplate,
|
||||||
|
SectionType,
|
||||||
|
} from './Section';
|
||||||
|
import { ConcentrationDividingLine } from '../concentrationDividingLine/ConcentrationDividingLine';
|
||||||
|
import { buildDragMoveAbsorbablePositions } from '../turnout/TurnoutDrawAssistant';
|
||||||
|
|
||||||
|
export class SectionDraw extends GraphicDrawAssistant<
|
||||||
|
SectionTemplate,
|
||||||
|
ISectionData
|
||||||
|
> {
|
||||||
|
points: Point[] = [];
|
||||||
|
graphic = new Graphics();
|
||||||
|
|
||||||
|
keyQListener = new KeyListener({
|
||||||
|
value: 'KeyQ',
|
||||||
|
global: true,
|
||||||
|
onPress: () => {
|
||||||
|
if (this.points.length === 0) {
|
||||||
|
this.graphicTemplate.isCurve = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
keyZListener = new KeyListener({
|
||||||
|
value: 'KeyZ',
|
||||||
|
global: true,
|
||||||
|
onPress: () => {
|
||||||
|
if (this.points.length === 0) {
|
||||||
|
this.graphicTemplate.isCurve = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(app: IDrawApp, template: SectionTemplate) {
|
||||||
|
super(app, template, 'sym_o_timeline', '区段Section');
|
||||||
|
this.container.addChild(this.graphic);
|
||||||
|
|
||||||
|
SectionPointEditPlugin.init(app, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.app.addKeyboardListener(this.keyQListener, this.keyZListener);
|
||||||
|
}
|
||||||
|
unbind(): void {
|
||||||
|
super.unbind();
|
||||||
|
this.app.removeKeyboardListener(this.keyQListener, this.keyZListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftDown(e: FederatedMouseEvent): void {
|
||||||
|
const { x, y } = this.toCanvasCoordinates(e.global);
|
||||||
|
const p = new Point(x, y);
|
||||||
|
if (this.graphicTemplate.isCurve) {
|
||||||
|
if (this.points.length == 0) {
|
||||||
|
this.points.push(p);
|
||||||
|
} else {
|
||||||
|
this.points.push(p, p.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.points.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftUp(e: FederatedMouseEvent): void {
|
||||||
|
const template = this.graphicTemplate;
|
||||||
|
if (template.isCurve) {
|
||||||
|
const mp = this.toCanvasCoordinates(e.global);
|
||||||
|
if (this.points.length === 1) {
|
||||||
|
this.points.push(new Point(mp.x, mp.y));
|
||||||
|
} else if (this.points.length > 1) {
|
||||||
|
const cp2 = this.points[this.points.length - 2];
|
||||||
|
const p = this.points[this.points.length - 1];
|
||||||
|
cp2.copyFrom(calculateMirrorPoint(p, mp));
|
||||||
|
this.points.push(mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRightClick(): void {
|
||||||
|
if (this.points.length < 2) {
|
||||||
|
this.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEsc(): void {
|
||||||
|
if (this.points.length < 2) {
|
||||||
|
this.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
if (this.points.length < 1) return;
|
||||||
|
const template = this.graphicTemplate;
|
||||||
|
this.graphic.clear();
|
||||||
|
this.graphic.lineStyle(SectionConsts.lineWidth, SectionConsts.lineColor);
|
||||||
|
|
||||||
|
const ps = [...this.points];
|
||||||
|
if (template.isCurve) {
|
||||||
|
if (ps.length === 1) {
|
||||||
|
this.graphic.moveTo(ps[0].x, ps[0].y);
|
||||||
|
this.graphic.lineTo(p.x, p.y);
|
||||||
|
} else {
|
||||||
|
if ((ps.length + 1) % 3 === 0) {
|
||||||
|
ps.push(p.clone(), p.clone());
|
||||||
|
} else {
|
||||||
|
const cp = ps[ps.length - 2];
|
||||||
|
const p1 = ps[ps.length - 1];
|
||||||
|
const mp = calculateMirrorPoint(p1, p);
|
||||||
|
cp.copyFrom(mp);
|
||||||
|
}
|
||||||
|
const bps = convertToBezierParams(ps);
|
||||||
|
bps.forEach((bp) => {
|
||||||
|
this.graphic.drawBezierCurve(
|
||||||
|
bp.p1,
|
||||||
|
bp.p2,
|
||||||
|
bp.cp1,
|
||||||
|
bp.cp2,
|
||||||
|
template.segmentsCount
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ps.push(p);
|
||||||
|
ps.forEach((p, i) => {
|
||||||
|
if (i !== 0) {
|
||||||
|
this.graphic.lineTo(p.x, p.y);
|
||||||
|
} else {
|
||||||
|
this.graphic.moveTo(p.x, p.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareData(data: ISectionData): boolean {
|
||||||
|
const template = this.graphicTemplate;
|
||||||
|
if (
|
||||||
|
(!template.isCurve && this.points.length < 2) ||
|
||||||
|
(template.isCurve && this.points.length < 4)
|
||||||
|
) {
|
||||||
|
console.log('Section绘制因点不够取消绘制');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (template.isCurve) {
|
||||||
|
this.points.pop();
|
||||||
|
}
|
||||||
|
data.isCurve = template.isCurve;
|
||||||
|
data.segmentsCount = template.segmentsCount;
|
||||||
|
data.points = this.points;
|
||||||
|
data.code = 'G000';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache(): void {
|
||||||
|
this.points = [];
|
||||||
|
this.graphic.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
generateTurnoutSection() {
|
||||||
|
const turnoutIds: number[] = []; /* 已遍历的道岔id列表 */
|
||||||
|
const dfs = (turnout: Turnout) => {
|
||||||
|
const axleCountings: AxleCounting[] = [];
|
||||||
|
const turnouts: Turnout[] = [];
|
||||||
|
if (turnoutIds.includes(turnout.datas.id)) return;
|
||||||
|
turnoutIds.push(turnout.datas.id);
|
||||||
|
|
||||||
|
turnouts.push(turnout);
|
||||||
|
|
||||||
|
Object.values(DevicePort).forEach((port) => {
|
||||||
|
const currentPortRelated = turnout.getGraphicOfPort(port);
|
||||||
|
if (
|
||||||
|
currentPortRelated.some((graphic) => graphic instanceof AxleCounting)
|
||||||
|
) {
|
||||||
|
const axleCounting = currentPortRelated.find(
|
||||||
|
(graphic) => graphic instanceof AxleCounting
|
||||||
|
) as AxleCounting;
|
||||||
|
axleCountings.push(axleCounting);
|
||||||
|
} else {
|
||||||
|
const nextTurnout = currentPortRelated.find(
|
||||||
|
(graphic) => graphic instanceof Turnout
|
||||||
|
) as Turnout;
|
||||||
|
const result = dfs(nextTurnout);
|
||||||
|
if (result?.axleCountings) {
|
||||||
|
axleCountings.push(...result.axleCountings);
|
||||||
|
turnouts.push(...result.turnouts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { axleCountings, turnouts };
|
||||||
|
};
|
||||||
|
|
||||||
|
const graphics: Section[] = [];
|
||||||
|
this.app.queryStore
|
||||||
|
.queryByType<Turnout>(Turnout.Type)
|
||||||
|
.forEach((turnout) => {
|
||||||
|
const result = dfs(turnout);
|
||||||
|
if (!result || !result.axleCountings.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const turnoutSections = this.app.queryStore
|
||||||
|
.queryByType<Section>(Section.Type)
|
||||||
|
.filter((s) => s.datas.sectionType === SectionType.TurnoutPhysical);
|
||||||
|
//判重
|
||||||
|
const existed = turnoutSections.some((sec) =>
|
||||||
|
result.axleCountings.every((ac) =>
|
||||||
|
sec.datas.axleCountings.includes(ac.datas.id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (existed) return;
|
||||||
|
const turnoutPhysicalSectionData = new SectionData();
|
||||||
|
turnoutPhysicalSectionData.id = this.nextId();
|
||||||
|
turnoutPhysicalSectionData.sectionType =
|
||||||
|
graphicData.Section.SectionType.TurnoutPhysical;
|
||||||
|
turnoutPhysicalSectionData.points = result.axleCountings.map((ac) => {
|
||||||
|
return new Point(ac.position.x, ac.position.y);
|
||||||
|
});
|
||||||
|
turnoutPhysicalSectionData.axleCountings = result.axleCountings.map(
|
||||||
|
(ac) => ac.datas.id
|
||||||
|
);
|
||||||
|
turnoutPhysicalSectionData.code = result.turnouts
|
||||||
|
.map((t) => t.datas.code)
|
||||||
|
.join('-');
|
||||||
|
let labelPosition: IPointData;
|
||||||
|
if (result.turnouts.length === 2) {
|
||||||
|
labelPosition = calculateLineMidpoint(
|
||||||
|
result.turnouts[0].position,
|
||||||
|
result.turnouts[1].position
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
labelPosition = { x: result.turnouts[0].x, y: result.turnouts[0].y };
|
||||||
|
}
|
||||||
|
labelPosition.y += 20;
|
||||||
|
const labelTransform = GraphicTransform.default();
|
||||||
|
labelTransform.position = labelPosition;
|
||||||
|
turnoutPhysicalSectionData.childTransforms = [
|
||||||
|
new ChildTransform('label', labelTransform),
|
||||||
|
];
|
||||||
|
const g = this.graphicTemplate.new();
|
||||||
|
g.position.set(turnout.datas.pointC[0].x, turnout.datas.pointC[0].y);
|
||||||
|
g.loadData(turnoutPhysicalSectionData);
|
||||||
|
graphics.push(g);
|
||||||
|
});
|
||||||
|
this.storeGraphic(...graphics);
|
||||||
|
graphics.forEach((g) => {
|
||||||
|
g.loadRelations();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SectionGraphicHitArea implements IHitArea {
|
||||||
|
section: Section;
|
||||||
|
constructor(section: Section) {
|
||||||
|
this.section = section;
|
||||||
|
}
|
||||||
|
contains(x: number, y: number): boolean {
|
||||||
|
if (this.section.datas.sectionType === SectionType.TurnoutPhysical) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.section.datas.isCurve) {
|
||||||
|
const bps = convertToBezierParams(this.section.datas.points);
|
||||||
|
for (let i = 0; i < bps.length; i++) {
|
||||||
|
const bp = bps[i];
|
||||||
|
if (
|
||||||
|
pointPolygon(
|
||||||
|
{ x, y },
|
||||||
|
[bp.p1, bp.cp1, bp.cp2, bp.p2],
|
||||||
|
SectionConsts.lineWidth
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 1; i < this.section.datas.points.length; i++) {
|
||||||
|
const p1 = this.section.datas.points[i - 1];
|
||||||
|
const p2 = this.section.datas.points[i];
|
||||||
|
if (linePoint(p1, p2, { x, y }, SectionConsts.lineWidth)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(
|
||||||
|
section: Section | ConcentrationDividingLine,
|
||||||
|
dp: DraggablePoint
|
||||||
|
): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const changePoints = section.localToCanvasPoints(...section.datas.points);
|
||||||
|
for (let i = 0; i < changePoints.length; i++) {
|
||||||
|
if (changePoints[i].equals(dp)) {
|
||||||
|
const { width, height } = section.getGraphicApp().canvas;
|
||||||
|
if (i == 0 || i == changePoints.length - 1) {
|
||||||
|
const ps =
|
||||||
|
i == 0 ? changePoints[1] : changePoints[changePoints.length - 2];
|
||||||
|
const x = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
|
||||||
|
const y = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
|
||||||
|
aps.push(x, y);
|
||||||
|
} else {
|
||||||
|
const generateAxisPoint = [changePoints[i - 1], changePoints[i + 1]];
|
||||||
|
generateAxisPoint.forEach((point) => {
|
||||||
|
const x = new AbsorbableLine(
|
||||||
|
{ x: 0, y: point.y },
|
||||||
|
{ x: width, y: point.y }
|
||||||
|
);
|
||||||
|
const y = new AbsorbableLine(
|
||||||
|
{ x: point.x, y: 0 },
|
||||||
|
{ x: point.x, y: height }
|
||||||
|
);
|
||||||
|
aps.push(x, y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (section instanceof Section) {
|
||||||
|
const sections = section.queryStore
|
||||||
|
.queryByType<Section>(Section.Type)
|
||||||
|
.filter((g) => g.datas.sectionType == SectionType.Physical);
|
||||||
|
sections.forEach((item) => {
|
||||||
|
if (item.id !== section.id) {
|
||||||
|
item.localToCanvasPoints(...item.datas.points).forEach((p) => {
|
||||||
|
aps.push(new AbsorbablePoint(p));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const turnouts = section.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||||
|
turnouts.forEach((turnout) => {
|
||||||
|
turnout.getPortPoints().forEach((points) => {
|
||||||
|
turnout.localToCanvasPoints(...points).forEach((p) => {
|
||||||
|
aps.push(new AbsorbablePoint(p));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onEditPointCreate(g: ILineGraphic, dp: DraggablePoint): void {
|
||||||
|
const section = g as Section | ConcentrationDividingLine;
|
||||||
|
dp.on('transformstart', (e: GraphicTransformEvent) => {
|
||||||
|
if (e.isShift()) {
|
||||||
|
section.getGraphicApp().setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(section, dp),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SectionPolylineEditPlugin extends PolylineEditPlugin {
|
||||||
|
static Name = 'SectionPolylineEditPlugin';
|
||||||
|
labels: VectorText[] = [];
|
||||||
|
constructor(g: ILineGraphic, options?: IEditPointOptions) {
|
||||||
|
super(g, options);
|
||||||
|
this.name = SectionPolylineEditPlugin.Name;
|
||||||
|
this.initLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
initLabels() {
|
||||||
|
this.labels = ['A', 'B'].map((str) => {
|
||||||
|
const vc = new VectorText(str, { fill: AppConsts.assistantElementColor });
|
||||||
|
vc.setVectorFontSize(14);
|
||||||
|
vc.anchor.set(0.5);
|
||||||
|
return vc;
|
||||||
|
});
|
||||||
|
this.addChild(...this.labels);
|
||||||
|
this.updateEditedPointsPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEditedPointsPosition() {
|
||||||
|
super.updateEditedPointsPosition();
|
||||||
|
this.labels[0]?.position.set(
|
||||||
|
this.editedPoints[0].x,
|
||||||
|
this.editedPoints[0].y + 10
|
||||||
|
);
|
||||||
|
this.labels[1]?.position.set(
|
||||||
|
this.editedPoints[this.editedPoints.length - 1].x,
|
||||||
|
this.editedPoints[this.editedPoints.length - 1].y + 10
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SectionBazierCurveEditPlugin extends BezierCurveEditPlugin {
|
||||||
|
static Name = 'SectionBazierCurveEditPlugin';
|
||||||
|
labels: VectorText[] = [];
|
||||||
|
constructor(g: ILineGraphic, options?: IEditPointOptions) {
|
||||||
|
super(g, options);
|
||||||
|
this.name = SectionBazierCurveEditPlugin.Name;
|
||||||
|
this.initLabels();
|
||||||
|
}
|
||||||
|
initLabels() {
|
||||||
|
this.labels = [new VectorText('A'), new VectorText('B')];
|
||||||
|
this.labels.forEach((label) => {
|
||||||
|
label.setVectorFontSize(14);
|
||||||
|
this.addChild(label);
|
||||||
|
});
|
||||||
|
this.updateEditedPointsPosition();
|
||||||
|
}
|
||||||
|
updateEditedPointsPosition() {
|
||||||
|
super.updateEditedPointsPosition();
|
||||||
|
this.labels[0]?.position.set(
|
||||||
|
this.editedPoints[0].x,
|
||||||
|
this.editedPoints[0].y + 10
|
||||||
|
);
|
||||||
|
this.labels[1]?.position.set(
|
||||||
|
this.editedPoints[this.editedPoints.length - 1].x,
|
||||||
|
this.editedPoints[this.editedPoints.length - 1].y + 10
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addWaypointConfig: MenuItemOptions = {
|
||||||
|
name: '添加路径点',
|
||||||
|
};
|
||||||
|
export const clearWaypointsConfig: MenuItemOptions = {
|
||||||
|
name: '清除所有路径点',
|
||||||
|
};
|
||||||
|
export const splitSectionConfig: MenuItemOptions = {
|
||||||
|
name: '拆分',
|
||||||
|
// disabled: true,
|
||||||
|
};
|
||||||
|
const SectionEditMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '区段编辑菜单',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [addWaypointConfig, clearWaypointsConfig],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: [splitSectionConfig],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export class SectionPointEditPlugin extends GraphicInteractionPlugin<Section> {
|
||||||
|
static Name = 'SectionPointDrag';
|
||||||
|
drawAssistant: SectionDraw;
|
||||||
|
|
||||||
|
constructor(app: IGraphicApp, da: SectionDraw) {
|
||||||
|
super(SectionPointEditPlugin.Name, app);
|
||||||
|
this.drawAssistant = da;
|
||||||
|
app.registerMenu(SectionEditMenu);
|
||||||
|
}
|
||||||
|
static init(app: IGraphicApp, da: SectionDraw) {
|
||||||
|
return new SectionPointEditPlugin(app, da);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Section[] | undefined {
|
||||||
|
return grahpics.filter((g) => g.type == Section.Type) as Section[];
|
||||||
|
}
|
||||||
|
bind(g: Section): void {
|
||||||
|
g.lineGraphic.eventMode = 'static';
|
||||||
|
g.lineGraphic.cursor = 'pointer';
|
||||||
|
g.lineGraphic.hitArea = new SectionGraphicHitArea(g);
|
||||||
|
g.transformSave = true;
|
||||||
|
g.labelGraphic.eventMode = 'static';
|
||||||
|
g.labelGraphic.cursor = 'pointer';
|
||||||
|
g.labelGraphic.selectable = true;
|
||||||
|
g.labelGraphic.draggable = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
g.on('unselected', this.onUnselected, this);
|
||||||
|
g.on('transformstart', this.onDragMove, this);
|
||||||
|
// g.on('_rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
unbind(g: Section): void {
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
g.off('unselected', this.onUnselected, this);
|
||||||
|
g.off('transformstart', this.onDragMove, this);
|
||||||
|
// g.off('_rightclick', this.onContextMenu, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onContextMenu(e: FederatedMouseEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const section = target.getGraphic() as Section;
|
||||||
|
this.app.updateSelected(section);
|
||||||
|
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const p = section.screenToLocalPoint(e.global);
|
||||||
|
addWaypointConfig.handler = () => {
|
||||||
|
const linePoints = section.linePoints;
|
||||||
|
const { start, end } = getWaypointRangeIndex(
|
||||||
|
linePoints,
|
||||||
|
false,
|
||||||
|
p,
|
||||||
|
SectionConsts.lineWidth
|
||||||
|
);
|
||||||
|
addWayPoint(section, false, start, end, p);
|
||||||
|
};
|
||||||
|
clearWaypointsConfig.handler = () => {
|
||||||
|
clearWayPoint(section, false);
|
||||||
|
};
|
||||||
|
splitSectionConfig.disabled = false;
|
||||||
|
splitSectionConfig.handler = () => {
|
||||||
|
Dialog.create({
|
||||||
|
title: '拆分区段',
|
||||||
|
message: '请选择生成数量和方向',
|
||||||
|
component: SectionSplitDialog,
|
||||||
|
cancel: true,
|
||||||
|
persistent: true,
|
||||||
|
}).onOk((data: { num: number; dir: 'ltr' | 'rtl' }) => {
|
||||||
|
const { num, dir } = data;
|
||||||
|
const sectionData = section.datas;
|
||||||
|
const points = section.getSplitPoints(num);
|
||||||
|
const children: LogicSection[] = [];
|
||||||
|
let codeAppend = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.slice(0, num);
|
||||||
|
if (
|
||||||
|
(dir === 'ltr' &&
|
||||||
|
sectionData.points[0].x >
|
||||||
|
sectionData.points[sectionData.points.length - 1].x) ||
|
||||||
|
(dir === 'rtl' &&
|
||||||
|
sectionData.points[0].x <
|
||||||
|
sectionData.points[sectionData.points.length - 1].x)
|
||||||
|
) {
|
||||||
|
codeAppend = codeAppend.split('').reverse().join('');
|
||||||
|
}
|
||||||
|
points.forEach((ps, i) => {
|
||||||
|
const data = new LogicSectionData();
|
||||||
|
const logicSectionDraw =
|
||||||
|
this.drawAssistant.app.getDrawAssistant<LogicSectionDraw>(
|
||||||
|
LogicSection.Type
|
||||||
|
);
|
||||||
|
data.id = logicSectionDraw.nextId();
|
||||||
|
data.code = `${sectionData.code}-${codeAppend.charAt(i % 26)}`;
|
||||||
|
data.points = ps.map(
|
||||||
|
(p) => new graphicData.Point({ x: p.x, y: p.y })
|
||||||
|
);
|
||||||
|
data.id = this.drawAssistant.nextId();
|
||||||
|
data.childTransforms = [
|
||||||
|
new ChildTransform(
|
||||||
|
'label',
|
||||||
|
new GraphicTransform(
|
||||||
|
{
|
||||||
|
x:
|
||||||
|
data.points[0].x +
|
||||||
|
(data.points[1].x - data.points[0].x) / 2,
|
||||||
|
y:
|
||||||
|
data.points[0].y +
|
||||||
|
(data.points[1].y - data.points[0].y) / 2 +
|
||||||
|
20,
|
||||||
|
},
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
0,
|
||||||
|
{ x: 0, y: 0 }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
const g = logicSectionDraw.graphicTemplate.new();
|
||||||
|
g.loadData(data);
|
||||||
|
logicSectionDraw.storeGraphic(g);
|
||||||
|
children.push(g);
|
||||||
|
});
|
||||||
|
// sectionData.children = children.map((g) => g.datas.id);
|
||||||
|
section.repaint();
|
||||||
|
section.buildRelation();
|
||||||
|
section.draggable = false;
|
||||||
|
children.forEach((c) => c.buildRelation());
|
||||||
|
this.app.updateSelected(...children);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
SectionEditMenu.open(e.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelected(g: DisplayObject): void {
|
||||||
|
const section = g as Section;
|
||||||
|
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (section.datas.isCurve) {
|
||||||
|
let lep = section.getAssistantAppend<SectionBazierCurveEditPlugin>(
|
||||||
|
SectionBazierCurveEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (!lep) {
|
||||||
|
lep = new SectionBazierCurveEditPlugin(section, {
|
||||||
|
onEditPointCreate,
|
||||||
|
});
|
||||||
|
section.addAssistantAppend(lep);
|
||||||
|
}
|
||||||
|
lep.showAll();
|
||||||
|
} else {
|
||||||
|
let lep = section.getAssistantAppend<SectionPolylineEditPlugin>(
|
||||||
|
SectionPolylineEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (!lep) {
|
||||||
|
lep = new SectionPolylineEditPlugin(section, { onEditPointCreate });
|
||||||
|
section.addAssistantAppend(lep);
|
||||||
|
}
|
||||||
|
lep.showAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onUnselected(g: DisplayObject): void {
|
||||||
|
const section = g as Section;
|
||||||
|
if (section.datas.isCurve) {
|
||||||
|
const lep = section.getAssistantAppend<SectionBazierCurveEditPlugin>(
|
||||||
|
SectionBazierCurveEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (lep) {
|
||||||
|
lep.hideAll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const lep = section.getAssistantAppend<SectionPolylineEditPlugin>(
|
||||||
|
SectionPolylineEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (lep) {
|
||||||
|
lep.hideAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onDragMove(e: GraphicTransformEvent) {
|
||||||
|
const section = e.target as Section;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildDragMoveAbsorbablePositions(section),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
51
src/graphics/electronicMap/sectionGraphic/SectionGraphic.ts
Normal file
51
src/graphics/electronicMap/sectionGraphic/SectionGraphic.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Graphics, IPointData } from 'pixi.js';
|
||||||
|
import { assertBezierPoints, convertToBezierParams } from 'jl-graphic';
|
||||||
|
|
||||||
|
export class SectionGraphic extends Graphics {
|
||||||
|
static Type = 'SectionGraphic';
|
||||||
|
private _points: IPointData[] = [];
|
||||||
|
public get points(): IPointData[] {
|
||||||
|
return this._points;
|
||||||
|
}
|
||||||
|
public set points(value: IPointData[]) {
|
||||||
|
if (!this.isCurve) {
|
||||||
|
if (value.length < 2) {
|
||||||
|
throw Error('Polyline must have at least 2 points');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assertBezierPoints(value);
|
||||||
|
}
|
||||||
|
this._points = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _segmentsCount = 10;
|
||||||
|
public get segmentsCount(): number {
|
||||||
|
return this._segmentsCount;
|
||||||
|
}
|
||||||
|
public set segmentsCount(value: number) {
|
||||||
|
if (value < 1) {
|
||||||
|
throw Error('segmentsCount must be at least 1');
|
||||||
|
}
|
||||||
|
this._segmentsCount = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCurve = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
paint() {
|
||||||
|
if (this.isCurve) {
|
||||||
|
const bps = convertToBezierParams(this.points);
|
||||||
|
bps.forEach((bp) => {
|
||||||
|
this.drawBezierCurve(bp.p1, bp.p2, bp.cp1, bp.cp2, this.segmentsCount);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.moveTo(this.points[0].x, this.points[0].y);
|
||||||
|
for (let i = 1; i < this.points.length; i++) {
|
||||||
|
this.lineTo(this.points[i].x, this.points[i].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
141
src/graphics/electronicMap/signal/LampMainBody.ts
Normal file
141
src/graphics/electronicMap/signal/LampMainBody.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import { Graphics, Point } from 'pixi.js';
|
||||||
|
import { calculateMirrorPoint, GraphicAnimation, JlGraphic } from 'jl-graphic';
|
||||||
|
import { ISignalState, SignalColorEnum, signalConsts } from './Signal';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
|
||||||
|
// export enum LampEnum {
|
||||||
|
// lampPostColor = '0xFFFFFF',
|
||||||
|
// redLamp = '0XFF0000',
|
||||||
|
// greenLamp = '0X00FF00',
|
||||||
|
// yellowLamp = '0XFFFF00',
|
||||||
|
// whiteLamp = '0XFFFFFF',
|
||||||
|
// blueLamp = '0X0033FF',
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const lampConsts = {
|
||||||
|
// verticalLampPostLength: 16,
|
||||||
|
// levelLampPostLength: 4,
|
||||||
|
// postLineWidth: 3,
|
||||||
|
// lampRadius: 8,
|
||||||
|
// };
|
||||||
|
|
||||||
|
/* const anmiationNameConst = {
|
||||||
|
signaRedFlash: 'signal_red_flash',
|
||||||
|
signalGreenFlash: 'signal_green_flash',
|
||||||
|
signalYellowFlash: 'signal_yellow_flash',
|
||||||
|
signalWhiteFlash: 'signal_white_flash',
|
||||||
|
signalBlueFlash: 'signal_blue_flash',
|
||||||
|
}; */
|
||||||
|
|
||||||
|
export class LampMainBody extends JlGraphic {
|
||||||
|
static Type = 'LampMainBody';
|
||||||
|
lampNum = 1;
|
||||||
|
lampPost: Graphics = new Graphics();
|
||||||
|
lamps: Graphics = new Graphics();
|
||||||
|
redFlashAnimation: GraphicAnimation | null = null;
|
||||||
|
mirror = false;
|
||||||
|
deltaTime = 0;
|
||||||
|
states: ISignalState | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(LampMainBody.Type);
|
||||||
|
this.addChild(this.lampPost);
|
||||||
|
this.addChild(this.lamps);
|
||||||
|
}
|
||||||
|
paint(
|
||||||
|
mt: electronicMapGraphicData.Signal.Model,
|
||||||
|
mirror: boolean,
|
||||||
|
states: ISignalState
|
||||||
|
) {
|
||||||
|
this.lampPost.clear();
|
||||||
|
this.lamps.clear();
|
||||||
|
this.mirror = mirror;
|
||||||
|
this.states = states;
|
||||||
|
if (
|
||||||
|
mt === electronicMapGraphicData.Signal.Model.HL ||
|
||||||
|
mt === electronicMapGraphicData.Signal.Model.AB
|
||||||
|
) {
|
||||||
|
this.lampNum = 2;
|
||||||
|
} else {
|
||||||
|
this.lampNum = 3;
|
||||||
|
}
|
||||||
|
let lpp = new Point(signalConsts.levelLampPostLength, 0);
|
||||||
|
if (mirror) {
|
||||||
|
lpp = calculateMirrorPoint(new Point(0, 0), lpp);
|
||||||
|
}
|
||||||
|
this.lampPost
|
||||||
|
.lineStyle(signalConsts.postLineWidth, SignalColorEnum.lampPostColor)
|
||||||
|
.moveTo(0, -signalConsts.verticalLampPostLength / 2)
|
||||||
|
.lineTo(0, signalConsts.verticalLampPostLength / 2)
|
||||||
|
.moveTo(0, 0)
|
||||||
|
.lineTo(lpp.x, lpp.y);
|
||||||
|
this.chagneState(this.states);
|
||||||
|
}
|
||||||
|
doRepaint() {
|
||||||
|
// this.paint(this.lampNum, this.mirror, this.states);
|
||||||
|
}
|
||||||
|
// stopAnmiation() {
|
||||||
|
// const redFlashA = this.animation(anmiationNameConst.signaRedFlash);
|
||||||
|
// const greenFlashA = this.animation(anmiationNameConst.signalGreenFlash);
|
||||||
|
// const blueFlashA = this.animation(anmiationNameConst.signalBlueFlash);
|
||||||
|
// const yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash);
|
||||||
|
// const whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash);
|
||||||
|
// if (redFlashA) {
|
||||||
|
// redFlashA.pause();
|
||||||
|
// }
|
||||||
|
// if (greenFlashA) {
|
||||||
|
// greenFlashA.pause();
|
||||||
|
// }
|
||||||
|
// if (blueFlashA) {
|
||||||
|
// blueFlashA.pause();
|
||||||
|
// }
|
||||||
|
// if (yellowFlashA) {
|
||||||
|
// yellowFlashA.pause();
|
||||||
|
// }
|
||||||
|
// if (whiteFlashA) {
|
||||||
|
// whiteFlashA.pause();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
paintLamp(colors: string[]) {
|
||||||
|
this.lamps.lineStyle(
|
||||||
|
signalConsts.lampLineWidth,
|
||||||
|
SignalColorEnum.lampLineColor
|
||||||
|
);
|
||||||
|
for (let i = 0; i < this.lampNum; i++) {
|
||||||
|
const radiusX =
|
||||||
|
(1 + i * 2) * signalConsts.lampRadius +
|
||||||
|
signalConsts.levelLampPostLength;
|
||||||
|
let lrp = new Point(radiusX, 0);
|
||||||
|
if (this.mirror) {
|
||||||
|
lrp = calculateMirrorPoint(new Point(0, 0), lrp);
|
||||||
|
}
|
||||||
|
const color = colors[i] ? colors[i] : SignalColorEnum.closeLamp;
|
||||||
|
const alpha = color === SignalColorEnum.closeLamp ? 0 : 1;
|
||||||
|
this.lamps.beginFill(color, alpha);
|
||||||
|
this.lamps.drawCircle(lrp.x, lrp.y, signalConsts.lampRadius);
|
||||||
|
this.lamps.endFill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chagneState(states: ISignalState) {
|
||||||
|
console.log(states); //待之后处理
|
||||||
|
try {
|
||||||
|
/* if (states.aspect === state.Signal.Aspect.H) {
|
||||||
|
this.paintLamp([SignalColorEnum.redLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.L) {
|
||||||
|
this.paintLamp(['', SignalColorEnum.greenLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.U) {
|
||||||
|
this.paintLamp(['', '', SignalColorEnum.yellowLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.HU) {
|
||||||
|
this.paintLamp([SignalColorEnum.redLamp, '', SignalColorEnum.yellowLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.A) {
|
||||||
|
this.paintLamp([SignalColorEnum.blueLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.B) {
|
||||||
|
this.paintLamp([SignalColorEnum.whiteLamp]);
|
||||||
|
} else if (states.aspect === state.Signal.Aspect.OFF) {
|
||||||
|
this.paintLamp([]);
|
||||||
|
} */
|
||||||
|
} catch (error) {
|
||||||
|
console.error('信号机状态处理异常!', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
311
src/graphics/electronicMap/signal/Signal.ts
Normal file
311
src/graphics/electronicMap/signal/Signal.ts
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import { Graphics, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
calculateDistanceFromPointToLine,
|
||||||
|
calculateFootPointFromPointToLine,
|
||||||
|
GraphicData,
|
||||||
|
GraphicRelationParam,
|
||||||
|
GraphicState,
|
||||||
|
isPointOnLine,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { calculateMirrorPoint } from 'jl-graphic';
|
||||||
|
import { LampMainBody } from './LampMainBody';
|
||||||
|
import {
|
||||||
|
drawArrow,
|
||||||
|
IRelatedRefData,
|
||||||
|
createRelatedRefProto,
|
||||||
|
} from '../CommonGraphics';
|
||||||
|
import { SignalCode } from './SignalCode';
|
||||||
|
import { Section, DevicePort, SectionType } from '../section/Section';
|
||||||
|
import { Turnout } from '../turnout/Turnout';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
|
||||||
|
export enum Direction {
|
||||||
|
LEFT = 0,
|
||||||
|
RIGHT = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KilometerSystem {
|
||||||
|
get coordinateSystem(): string;
|
||||||
|
set coordinateSystem(v: string);
|
||||||
|
get kilometer(): number;
|
||||||
|
set kilometer(v: number);
|
||||||
|
get direction(): Direction;
|
||||||
|
set direction(v: Direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISignalData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
set code(v: string);
|
||||||
|
get mirror(): boolean;
|
||||||
|
set mirror(v: boolean);
|
||||||
|
get kilometerSystem(): KilometerSystem;
|
||||||
|
set kilometerSystem(v: KilometerSystem);
|
||||||
|
get refDev(): IRelatedRefData;
|
||||||
|
set refDev(v: IRelatedRefData);
|
||||||
|
get centralizedStations(): number[];
|
||||||
|
set centralizedStations(v: number[]);
|
||||||
|
get mt(): electronicMapGraphicData.Signal.Model;
|
||||||
|
set mt(v: electronicMapGraphicData.Signal.Model);
|
||||||
|
get direction(): electronicMapGraphicData.Direction;
|
||||||
|
set direction(v: electronicMapGraphicData.Direction);
|
||||||
|
clone(): ISignalData;
|
||||||
|
copyFrom(data: ISignalData): void;
|
||||||
|
eq(other: ISignalData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISignalState extends GraphicState {
|
||||||
|
id?: string;
|
||||||
|
get aspect(): number;
|
||||||
|
set aspect(v: number);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum SignalColorEnum {
|
||||||
|
humanControlColor = '0xffff00',
|
||||||
|
fleetModeColor = '0x00ff00',
|
||||||
|
blockedColor = '0XFF0000',
|
||||||
|
defaultCodeColor = '0XFFFFFF',
|
||||||
|
lampPostColor = '0xFFFFFF',
|
||||||
|
//redLamp = '0XFF0000',
|
||||||
|
greenLamp = '0X00FF00',
|
||||||
|
yellowLamp = '0XFFFF00',
|
||||||
|
//whiteLamp = '0XFFFFFF',
|
||||||
|
blueLamp = '0X0033FF',
|
||||||
|
closeLamp = '0X000000',
|
||||||
|
logicModeColor = '0x000000',
|
||||||
|
lampLineColor = '0x3149c3',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const signalConsts = {
|
||||||
|
fleetModeLength: 24,
|
||||||
|
fleetModeRadius: 8,
|
||||||
|
fleetModeLineWidth: 6,
|
||||||
|
humanControlRadius: 8,
|
||||||
|
codeOffset: 20,
|
||||||
|
codeFontSize: 11,
|
||||||
|
blockedLineWidth: 1,
|
||||||
|
verticalLampPostLength: 16,
|
||||||
|
levelLampPostLength: 4,
|
||||||
|
postLineWidth: 3,
|
||||||
|
lampRadius: 8,
|
||||||
|
logicModeLineWidth: 2,
|
||||||
|
logicModeDistance: 5,
|
||||||
|
lampLineWidth: 1,
|
||||||
|
};
|
||||||
|
export class Signal extends JlGraphic {
|
||||||
|
static Type = 'signal';
|
||||||
|
signalCode: SignalCode = new SignalCode();
|
||||||
|
humanControl: Graphics = new Graphics();
|
||||||
|
fleetMode: Graphics = new Graphics();
|
||||||
|
lampMainBody: LampMainBody = new LampMainBody();
|
||||||
|
blockedMode: Graphics = new Graphics();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Signal.Type);
|
||||||
|
this.addChild(this.humanControl);
|
||||||
|
this.addChild(this.fleetMode);
|
||||||
|
this.addChild(this.lampMainBody);
|
||||||
|
this.addChild(this.signalCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
get datas(): ISignalData {
|
||||||
|
return this.getDatas<ISignalData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get states(): ISignalState {
|
||||||
|
return this.getStates<ISignalState>();
|
||||||
|
}
|
||||||
|
get mirror(): boolean {
|
||||||
|
return this.datas.mirror;
|
||||||
|
}
|
||||||
|
set mirror(v: boolean) {
|
||||||
|
const old = this.datas.clone();
|
||||||
|
old.mirror = v;
|
||||||
|
this.updateData(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
paint(): void {
|
||||||
|
const mirror = this.datas.mirror;
|
||||||
|
this.lampMainBody.paint(this.datas.mt, mirror, this.states);
|
||||||
|
this.signalCode.paint(this.datas);
|
||||||
|
const codeTransform = this.datas?.childTransforms?.find(
|
||||||
|
(item) => item.name === 'signalCode'
|
||||||
|
);
|
||||||
|
if (codeTransform) {
|
||||||
|
const position = codeTransform?.transform.position;
|
||||||
|
const rotation = codeTransform?.transform?.rotation;
|
||||||
|
this.signalCode.position.set(position?.x, position?.y);
|
||||||
|
this.signalCode.rotation = rotation || 0;
|
||||||
|
} else {
|
||||||
|
this.signalCode.position.set(0, signalConsts.codeOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint(): void {
|
||||||
|
this.paint();
|
||||||
|
this.fleetMode.clear();
|
||||||
|
// if (this.states.fleetMode) {
|
||||||
|
// this.createFleetMode();
|
||||||
|
// }
|
||||||
|
// this.humanControl.clear();
|
||||||
|
// if (this.states.autoRouteDisable) {
|
||||||
|
// this.createHumanControl();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
createFleetMode(): void {
|
||||||
|
const mirror = this.datas.mirror;
|
||||||
|
this.fleetMode.beginFill(SignalColorEnum.fleetModeColor, 1);
|
||||||
|
let lmp = new Point(
|
||||||
|
this.lampMainBody.width + signalConsts.fleetModeLength,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (mirror) {
|
||||||
|
lmp = calculateMirrorPoint(new Point(0, 0), lmp);
|
||||||
|
}
|
||||||
|
drawArrow(
|
||||||
|
this.fleetMode,
|
||||||
|
lmp.x,
|
||||||
|
0,
|
||||||
|
signalConsts.fleetModeLength,
|
||||||
|
signalConsts.fleetModeRadius,
|
||||||
|
signalConsts.fleetModeLineWidth,
|
||||||
|
mirror
|
||||||
|
);
|
||||||
|
this.fleetMode.endFill();
|
||||||
|
}
|
||||||
|
createHumanControl(): void {
|
||||||
|
const mirror = this.datas.mirror;
|
||||||
|
this.humanControl.beginFill(SignalColorEnum.humanControlColor, 1);
|
||||||
|
if (this.humanControl.drawRegularPolygon) {
|
||||||
|
let hmp = new Point(-signalConsts.humanControlRadius, 0);
|
||||||
|
if (mirror) {
|
||||||
|
hmp = calculateMirrorPoint(new Point(0, 0), hmp);
|
||||||
|
}
|
||||||
|
this.humanControl.drawRegularPolygon(
|
||||||
|
hmp.x,
|
||||||
|
hmp.y,
|
||||||
|
signalConsts.humanControlRadius,
|
||||||
|
3,
|
||||||
|
(Math.PI / 2) * (mirror ? -1 : 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.humanControl.endFill();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRelation() {
|
||||||
|
const sections = this.queryStore
|
||||||
|
.queryByType<Section>(Section.Type)
|
||||||
|
.filter((s) => s.datas.sectionType === SectionType.Physical);
|
||||||
|
const turnouts = this.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||||
|
let deviceId = 0;
|
||||||
|
let deviceType = '';
|
||||||
|
let minD = Number.MAX_SAFE_INTEGER;
|
||||||
|
let port: DevicePort = DevicePort.A;
|
||||||
|
sections.forEach((sec: Section) => {
|
||||||
|
const verticesList = sec.getVerticesList();
|
||||||
|
for (let i = 0; i < verticesList.length - 1; i++) {
|
||||||
|
const d = calculateDistanceFromPointToLine(
|
||||||
|
sec.localToCanvasPoint(verticesList[i]),
|
||||||
|
sec.localToCanvasPoint(verticesList[i + 1]),
|
||||||
|
this.position
|
||||||
|
);
|
||||||
|
const p = calculateFootPointFromPointToLine(
|
||||||
|
sec.localToCanvasPoint(verticesList[i]),
|
||||||
|
sec.localToCanvasPoint(verticesList[i + 1]),
|
||||||
|
this.position
|
||||||
|
);
|
||||||
|
const onLine = isPointOnLine(
|
||||||
|
sec.localToCanvasPoint(verticesList[i]),
|
||||||
|
sec.localToCanvasPoint(verticesList[i + 1]),
|
||||||
|
p
|
||||||
|
);
|
||||||
|
if (onLine && d < minD) {
|
||||||
|
minD = d;
|
||||||
|
deviceId = sec.id;
|
||||||
|
deviceType = sec.type;
|
||||||
|
port = DevicePort.A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
turnouts.forEach((turnout: Turnout) => {
|
||||||
|
for (let i = 0; i < turnout.datas.pointA.length; i++) {
|
||||||
|
const p1 = turnout.localToCanvasPoint(
|
||||||
|
i === 0 ? new Point(0, 0) : turnout.datas.pointA[i - 1]
|
||||||
|
);
|
||||||
|
const p2 = turnout.localToCanvasPoint(turnout.datas.pointA[i]);
|
||||||
|
const d = calculateDistanceFromPointToLine(p1, p2, this.position);
|
||||||
|
const p = calculateFootPointFromPointToLine(p1, p2, this.position);
|
||||||
|
const onLine = isPointOnLine(p1, p2, p);
|
||||||
|
if (onLine && d < minD) {
|
||||||
|
minD = d;
|
||||||
|
deviceId = turnout.id;
|
||||||
|
deviceType = turnout.type;
|
||||||
|
port = DevicePort.A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < turnout.datas.pointB.length; i++) {
|
||||||
|
const p1 = turnout.localToCanvasPoint(
|
||||||
|
i === 0 ? new Point(0, 0) : turnout.datas.pointB[i - 1]
|
||||||
|
);
|
||||||
|
const p2 = turnout.localToCanvasPoint(turnout.datas.pointB[i]);
|
||||||
|
const d = calculateDistanceFromPointToLine(p1, p2, this.position);
|
||||||
|
const p = calculateFootPointFromPointToLine(p1, p2, this.position);
|
||||||
|
const onLine = isPointOnLine(p1, p2, p);
|
||||||
|
if (onLine && d < minD) {
|
||||||
|
minD = d;
|
||||||
|
deviceId = turnout.id;
|
||||||
|
deviceType = turnout.type;
|
||||||
|
port = DevicePort.B;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < turnout.datas.pointC.length; i++) {
|
||||||
|
const p1 = turnout.localToCanvasPoint(
|
||||||
|
i === 0 ? new Point(0, 0) : turnout.datas.pointC[i - 1]
|
||||||
|
);
|
||||||
|
const p2 = turnout.localToCanvasPoint(turnout.datas.pointC[i]);
|
||||||
|
const d = calculateDistanceFromPointToLine(p1, p2, this.position);
|
||||||
|
const p = calculateFootPointFromPointToLine(p1, p2, this.position);
|
||||||
|
const onLine = isPointOnLine(p1, p2, p);
|
||||||
|
if (onLine && d < minD) {
|
||||||
|
minD = d;
|
||||||
|
deviceId = turnout.id;
|
||||||
|
deviceType = turnout.type;
|
||||||
|
port = DevicePort.C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (deviceId) {
|
||||||
|
this.datas.refDev = createRelatedRefProto(deviceType, deviceId, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadRelations() {
|
||||||
|
if (this.datas.refDev) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, ''),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.refDev.id),
|
||||||
|
this.datas.refDev.devicePort
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalTemplate extends JlGraphicTemplate<Signal> {
|
||||||
|
constructor(dataTemplate: ISignalData, stateTemplate: ISignalState) {
|
||||||
|
super(Signal.Type, { dataTemplate, stateTemplate });
|
||||||
|
}
|
||||||
|
new(): Signal {
|
||||||
|
const g = new Signal();
|
||||||
|
g.loadData(this.datas);
|
||||||
|
g.loadState(this.states);
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
44
src/graphics/electronicMap/signal/SignalCode.ts
Normal file
44
src/graphics/electronicMap/signal/SignalCode.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Container, Graphics, Point } from 'pixi.js';
|
||||||
|
import { VectorText } from 'jl-graphic';
|
||||||
|
import {
|
||||||
|
ISignalData,
|
||||||
|
SignalColorEnum,
|
||||||
|
signalConsts,
|
||||||
|
} from './Signal';
|
||||||
|
|
||||||
|
export class SignalCode extends Container {
|
||||||
|
blockedMode: Graphics = new Graphics();
|
||||||
|
codeGraph: VectorText = new VectorText('');
|
||||||
|
name = 'signalCode';
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.addChild(this.blockedMode);
|
||||||
|
this.addChild(this.codeGraph);
|
||||||
|
}
|
||||||
|
paint(datas: ISignalData) {
|
||||||
|
this.codeGraph.text = datas?.code || '信号机编号';
|
||||||
|
this.codeGraph.style.fill = SignalColorEnum.defaultCodeColor;
|
||||||
|
this.codeGraph.setVectorFontSize(signalConsts.codeFontSize);
|
||||||
|
this.codeGraph.anchor.set(0.5);
|
||||||
|
this.codeGraph.position.set(0, 0);
|
||||||
|
this.blockedMode.clear();
|
||||||
|
// if (states.blocked) {
|
||||||
|
// this.createBlockedMode();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
createBlockedMode() {
|
||||||
|
const codeRect = this.codeGraph.getBounds();
|
||||||
|
const rectP = this.screenToLocalPoint(new Point(codeRect.x, codeRect.y));
|
||||||
|
this.blockedMode.clear();
|
||||||
|
this.blockedMode.lineStyle(
|
||||||
|
signalConsts.blockedLineWidth,
|
||||||
|
SignalColorEnum.blockedColor
|
||||||
|
);
|
||||||
|
this.blockedMode.drawRect(
|
||||||
|
rectP.x,
|
||||||
|
rectP.y,
|
||||||
|
codeRect.width,
|
||||||
|
codeRect.height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
181
src/graphics/electronicMap/signal/SignalDrawAssistant.ts
Normal file
181
src/graphics/electronicMap/signal/SignalDrawAssistant.ts
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import { DisplayObject, FederatedPointerEvent, IHitArea, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
GraphicTransformEvent,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import { ISignalData, Signal, SignalTemplate } from './Signal';
|
||||||
|
|
||||||
|
export interface ISignalDrawOptions {
|
||||||
|
newData: () => ISignalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalDraw extends GraphicDrawAssistant<
|
||||||
|
SignalTemplate,
|
||||||
|
ISignalData
|
||||||
|
> {
|
||||||
|
_signal: Signal | null = null;
|
||||||
|
|
||||||
|
constructor(app: IDrawApp, template: SignalTemplate) {
|
||||||
|
super(
|
||||||
|
app,
|
||||||
|
template,
|
||||||
|
'svguse: ../../drawIcon.svg#icon-signal',
|
||||||
|
'信号机Signal'
|
||||||
|
);
|
||||||
|
|
||||||
|
SignalInteraction.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get signal(): Signal {
|
||||||
|
if (!this._signal) {
|
||||||
|
this._signal = this.graphicTemplate.new();
|
||||||
|
this._signal.loadData(this.graphicTemplate.datas);
|
||||||
|
this.container.addChild(this._signal);
|
||||||
|
}
|
||||||
|
return this._signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftUp(e: FederatedPointerEvent): void {
|
||||||
|
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.signal.paint();
|
||||||
|
this.container.position.set(p.x, p.y);
|
||||||
|
}
|
||||||
|
prepareData(data: ISignalData): boolean {
|
||||||
|
data.transform = this.container.saveTransform();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalGraphicHitArea implements IHitArea {
|
||||||
|
signal: Signal;
|
||||||
|
constructor(signal: Signal) {
|
||||||
|
this.signal = signal;
|
||||||
|
}
|
||||||
|
contains(x: number, y: number): boolean {
|
||||||
|
const bound = this.signal.getLocalBounds();
|
||||||
|
const maxX = bound.x + bound.width;
|
||||||
|
const minX = bound.x;
|
||||||
|
const maxY = bound.y + bound.height;
|
||||||
|
const minY = bound.y;
|
||||||
|
return maxX >= x && x >= minX && maxY >= y && y >= minY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建吸附线
|
||||||
|
* @param signal
|
||||||
|
*/
|
||||||
|
function buildAbsorbablePositions(signal: Signal): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const signals = signal.queryStore.queryByType<Signal>(Signal.Type);
|
||||||
|
const canvas = signal.getCanvas();
|
||||||
|
signals.forEach((item) => {
|
||||||
|
if (item.id === signal.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ala = new AbsorbableLine(
|
||||||
|
new Point(item.x, 0),
|
||||||
|
new Point(item.x, canvas.height)
|
||||||
|
);
|
||||||
|
const alb = new AbsorbableLine(
|
||||||
|
new Point(0, item.y),
|
||||||
|
new Point(canvas.width, item.y)
|
||||||
|
);
|
||||||
|
aps.push(ala);
|
||||||
|
aps.push(alb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 信号机名称构建吸附线
|
||||||
|
* @param signal
|
||||||
|
*/
|
||||||
|
function buildCodeAbsorbablePositions(signal: Signal): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const signals = signal.queryStore.queryByType<Signal>(Signal.Type);
|
||||||
|
const canvas = signal.getCanvas();
|
||||||
|
signals.forEach((item) => {
|
||||||
|
if (item.id === signal.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const codePoint = item.signalCode.getPositionOnCanvas();
|
||||||
|
const ala = new AbsorbableLine(
|
||||||
|
new Point(codePoint.x, 0),
|
||||||
|
new Point(codePoint.x, canvas.height)
|
||||||
|
);
|
||||||
|
const alb = new AbsorbableLine(
|
||||||
|
new Point(0, codePoint.y),
|
||||||
|
new Point(canvas.width, codePoint.y)
|
||||||
|
);
|
||||||
|
aps.push(ala);
|
||||||
|
aps.push(alb);
|
||||||
|
});
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignalInteraction extends GraphicInteractionPlugin<Signal> {
|
||||||
|
static Name = 'signal_transform';
|
||||||
|
constructor(app: IDrawApp) {
|
||||||
|
super(SignalInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new SignalInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Signal.Type)
|
||||||
|
.map((g) => g as Signal);
|
||||||
|
}
|
||||||
|
bind(g: Signal): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.scalable = true;
|
||||||
|
g.rotatable = true;
|
||||||
|
g.lampMainBody.hitArea = new SignalGraphicHitArea(g);
|
||||||
|
g.on('transformstart', this.transformstart, this);
|
||||||
|
g.signalCode.on('transformstart', this.codetransformstart, this);
|
||||||
|
g.signalCode.draggable = true;
|
||||||
|
g.signalCode.selectable = true;
|
||||||
|
g.signalCode.rotatable = true;
|
||||||
|
g.signalCode.transformSave = true;
|
||||||
|
g.signalCode.eventMode = 'static';
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Signal): void {
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.scalable = false;
|
||||||
|
g.rotatable = false;
|
||||||
|
g.off('transformstart', this.transformstart, this);
|
||||||
|
g.signalCode.off('transformstart', this.codetransformstart, this);
|
||||||
|
g.signalCode.draggable = false;
|
||||||
|
g.signalCode.selectable = false;
|
||||||
|
g.signalCode.rotatable = false;
|
||||||
|
g.signalCode.transformSave = false;
|
||||||
|
g.signalCode.eventMode = 'none';
|
||||||
|
}
|
||||||
|
transformstart(e: GraphicTransformEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const signal = target.getGraphic() as Signal;
|
||||||
|
signal.getGraphicApp().setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(signal),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
codetransformstart(e: GraphicTransformEvent) {
|
||||||
|
const target = e.target as DisplayObject;
|
||||||
|
const signal = target.getGraphic() as Signal;
|
||||||
|
signal.getGraphicApp().setOptions({
|
||||||
|
absorbablePositions: buildCodeAbsorbablePositions(signal),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
111
src/graphics/electronicMap/station/Station.ts
Normal file
111
src/graphics/electronicMap/station/Station.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicState,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
VectorText,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { KilometerSystem } from '../signal/Signal';
|
||||||
|
import { Platform } from '../platform/Platform';
|
||||||
|
|
||||||
|
export interface IStationData extends GraphicData {
|
||||||
|
get code(): string; // 车站站名
|
||||||
|
set code(v: string);
|
||||||
|
get stationName(): string; // 车站名
|
||||||
|
set stationName(v: string);
|
||||||
|
get stationNameAcronym(): string; // 车站名拼音简写
|
||||||
|
set stationNameAcronym(v: string);
|
||||||
|
get kilometerSystem(): KilometerSystem;
|
||||||
|
set kilometerSystem(v: KilometerSystem);
|
||||||
|
get concentrationStations(): boolean; //是否集中站
|
||||||
|
set concentrationStations(v: boolean);
|
||||||
|
get depots(): boolean; //是否车辆段
|
||||||
|
set depots(v: boolean);
|
||||||
|
get manageStations(): number[]; //集中站管理的车站
|
||||||
|
set manageStations(v: number[]);
|
||||||
|
clone(): IStationData;
|
||||||
|
copyFrom(data: IStationData): void;
|
||||||
|
eq(other: IStationData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IStationState extends GraphicState {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stationConsts = {
|
||||||
|
codeColor: '0xF48815',
|
||||||
|
codeFontSize: 22,
|
||||||
|
kilometerCodeColor: '0xFFFFFF',
|
||||||
|
kilometerCodeFontSize: 8,
|
||||||
|
kilometerCodeOffsetY: -25,
|
||||||
|
};
|
||||||
|
export class Station extends JlGraphic {
|
||||||
|
static Type = 'station';
|
||||||
|
codeGraph: VectorText = new VectorText(''); //车站站名
|
||||||
|
kilometerGraph: VectorText = new VectorText(''); //公里标
|
||||||
|
constructor() {
|
||||||
|
super(Station.Type);
|
||||||
|
this.addChild(this.codeGraph);
|
||||||
|
this.addChild(this.kilometerGraph);
|
||||||
|
}
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
get datas(): IStationData {
|
||||||
|
return this.getDatas<IStationData>();
|
||||||
|
}
|
||||||
|
get states(): IStationState {
|
||||||
|
return this.getStates<IStationState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint(): void {
|
||||||
|
const codeGraph = this.codeGraph;
|
||||||
|
const kilometerGraph = this.kilometerGraph;
|
||||||
|
codeGraph.text = this.datas?.code || '车站Station';
|
||||||
|
codeGraph.style.fill = stationConsts.codeColor;
|
||||||
|
codeGraph.setVectorFontSize(stationConsts.codeFontSize);
|
||||||
|
codeGraph.anchor.set(0.5);
|
||||||
|
const kilometerCode = this.datas.kilometerSystem?.kilometer || 12345678;
|
||||||
|
if (Math.floor(kilometerCode * 1000).toString().length > 3) {
|
||||||
|
const kiloBit = Math.floor(Number(kilometerCode) / 1000000).toString();
|
||||||
|
kilometerGraph.text =
|
||||||
|
'K' +
|
||||||
|
kiloBit +
|
||||||
|
'+' +
|
||||||
|
(
|
||||||
|
Number(kilometerCode.toString().substring(kiloBit.length)) / 1000
|
||||||
|
).toFixed(3);
|
||||||
|
} else {
|
||||||
|
kilometerGraph.text = (kilometerCode * 1000).toFixed(3);
|
||||||
|
}
|
||||||
|
kilometerGraph.style.fill = stationConsts.kilometerCodeColor;
|
||||||
|
kilometerGraph.setVectorFontSize(stationConsts.kilometerCodeFontSize);
|
||||||
|
kilometerGraph.anchor.set(0.5);
|
||||||
|
kilometerGraph.position.set(0, stationConsts.kilometerCodeOffsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlatforms(): Platform[] {
|
||||||
|
const relations = this.relationManage.getRelationsOfGraphicAndOtherType(
|
||||||
|
this,
|
||||||
|
Platform.Type
|
||||||
|
);
|
||||||
|
return relations.map((r) => r.getOtherGraphic(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StationTemplate extends JlGraphicTemplate<Station> {
|
||||||
|
hasControl: boolean;
|
||||||
|
constructor(dataTemplate: IStationData, stateTemplate: IStationState) {
|
||||||
|
super(Station.Type, {
|
||||||
|
dataTemplate,
|
||||||
|
stateTemplate,
|
||||||
|
});
|
||||||
|
this.hasControl = true;
|
||||||
|
}
|
||||||
|
new(): Station {
|
||||||
|
const station = new Station();
|
||||||
|
station.loadData(this.datas);
|
||||||
|
station.loadState(this.states);
|
||||||
|
return station;
|
||||||
|
}
|
||||||
|
}
|
102
src/graphics/electronicMap/station/StationDrawAssistant.ts
Normal file
102
src/graphics/electronicMap/station/StationDrawAssistant.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import { FederatedPointerEvent, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
AbsorbableLine,
|
||||||
|
AbsorbablePosition,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
|
||||||
|
import { IStationData, Station, StationTemplate } from './Station';
|
||||||
|
|
||||||
|
export interface IStationDrawOptions {
|
||||||
|
newData: () => IStationData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StationDraw extends GraphicDrawAssistant<
|
||||||
|
StationTemplate,
|
||||||
|
IStationData
|
||||||
|
> {
|
||||||
|
codeGraph: Station;
|
||||||
|
constructor(app: IDrawApp, template: StationTemplate) {
|
||||||
|
super(
|
||||||
|
app,
|
||||||
|
template,
|
||||||
|
'svguse:../../drawIcon.svg#icon-station',
|
||||||
|
'车站Station'
|
||||||
|
);
|
||||||
|
this.codeGraph = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.codeGraph);
|
||||||
|
stationInteraction.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.codeGraph.loadData(this.graphicTemplate.datas);
|
||||||
|
this.codeGraph.doRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftDown(e: FederatedPointerEvent): void {
|
||||||
|
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.container.position.copyFrom(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareData(data: IStationData): boolean {
|
||||||
|
data.transform = this.container.saveTransform();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(station: Station): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
const stations = station.queryStore.queryByType<Station>(Station.Type);
|
||||||
|
const { width } = station.getGraphicApp().canvas;
|
||||||
|
stations.forEach((other) => {
|
||||||
|
if (other.id == station.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ps = other.datas.transform.position;
|
||||||
|
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
|
||||||
|
aps.push(xs);
|
||||||
|
});
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class stationInteraction extends GraphicInteractionPlugin<Station> {
|
||||||
|
static Name = 'station_transform';
|
||||||
|
constructor(app: IDrawApp) {
|
||||||
|
super(stationInteraction.Name, app);
|
||||||
|
}
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new stationInteraction(app);
|
||||||
|
}
|
||||||
|
filter(...grahpics: JlGraphic[]): Station[] | undefined {
|
||||||
|
return grahpics
|
||||||
|
.filter((g) => g.type === Station.Type)
|
||||||
|
.map((g) => g as Station);
|
||||||
|
}
|
||||||
|
bind(g: Station): void {
|
||||||
|
g.eventMode = 'static';
|
||||||
|
g.cursor = 'pointer';
|
||||||
|
g.scalable = true;
|
||||||
|
g.rotatable = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
unbind(g: Station): void {
|
||||||
|
g.eventMode = 'none';
|
||||||
|
g.scalable = false;
|
||||||
|
g.rotatable = false;
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
}
|
||||||
|
onSelected(): void {
|
||||||
|
const station = this.app.selectedGraphics[0] as Station;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(station),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
import { Color, FederatedPointerEvent, Graphics, Point } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicData,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { AxleCounting } from '../axleCounting/AxleCounting';
|
||||||
|
import { AxleCountingDraw } from '../axleCounting/AxleCountingDrawAssistant';
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
|
||||||
|
interface IOneClickData extends GraphicData {
|
||||||
|
get code(): string; // 编号
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OneClickGenerate extends JlGraphic {
|
||||||
|
static Type = 'OneClickGenerate';
|
||||||
|
lineGraphic: Graphics = new Graphics();
|
||||||
|
constructor() {
|
||||||
|
super(OneClickGenerate.Type);
|
||||||
|
this.addChild(this.lineGraphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint(): void {
|
||||||
|
this.lineGraphic.clear();
|
||||||
|
this.lineGraphic.lineStyle(1, new Color('0xff0000'));
|
||||||
|
this.lineGraphic.moveTo(-1920, 0);
|
||||||
|
this.lineGraphic.lineTo(1920, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OneClickGenerateTemplate extends JlGraphicTemplate<OneClickGenerate> {
|
||||||
|
constructor() {
|
||||||
|
super(OneClickGenerate.Type, {});
|
||||||
|
}
|
||||||
|
new(): OneClickGenerate {
|
||||||
|
return new OneClickGenerate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OneClickGenerateDraw extends GraphicDrawAssistant<
|
||||||
|
OneClickGenerateTemplate,
|
||||||
|
IOneClickData
|
||||||
|
> {
|
||||||
|
lineGraph: OneClickGenerate;
|
||||||
|
constructor(app: IDrawApp, template: OneClickGenerateTemplate) {
|
||||||
|
super(app, template, 'sym_o_square', '不展示');
|
||||||
|
this.lineGraph = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.lineGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(): void {
|
||||||
|
super.bind();
|
||||||
|
this.lineGraph.doRepaint();
|
||||||
|
}
|
||||||
|
onLeftDown(e: FederatedPointerEvent): void {
|
||||||
|
const type = useDrawStore().oneClickType;
|
||||||
|
if (type == 'AxleCounting') {
|
||||||
|
const axleCountingDraw = this.app.getDrawAssistant(
|
||||||
|
AxleCounting.Type
|
||||||
|
) as AxleCountingDraw;
|
||||||
|
axleCountingDraw.oneGenerates(this.toCanvasCoordinates(e.global));
|
||||||
|
}
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(p: Point): void {
|
||||||
|
this.container.position.copyFrom(p);
|
||||||
|
}
|
||||||
|
prepareData(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
463
src/graphics/electronicMap/turnout/Turnout.ts
Normal file
463
src/graphics/electronicMap/turnout/Turnout.ts
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
import { Graphics, IPointData } from 'pixi.js';
|
||||||
|
import {
|
||||||
|
GraphicAnimation,
|
||||||
|
GraphicData,
|
||||||
|
GraphicRelationParam,
|
||||||
|
GraphicState,
|
||||||
|
JlGraphic,
|
||||||
|
JlGraphicTemplate,
|
||||||
|
VectorText,
|
||||||
|
angleOfIncludedAngle,
|
||||||
|
distance2,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { Section, DevicePort, SectionType } from '../section/Section';
|
||||||
|
import {
|
||||||
|
IRelatedRefData,
|
||||||
|
createRelatedRefProto,
|
||||||
|
protoPort2Data,
|
||||||
|
} from '../CommonGraphics';
|
||||||
|
import { KilometerSystem } from '../signal/Signal';
|
||||||
|
import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data';
|
||||||
|
const tolerance = 0.01;
|
||||||
|
|
||||||
|
export interface ITurnoutData extends GraphicData {
|
||||||
|
get code(): string;
|
||||||
|
set code(code: string);
|
||||||
|
get pointA(): IPointData[]; //A端点列表(从岔心向外)
|
||||||
|
set pointA(point: IPointData[]);
|
||||||
|
get pointB(): IPointData[];
|
||||||
|
set pointB(point: IPointData[]);
|
||||||
|
get pointC(): IPointData[];
|
||||||
|
set pointC(point: IPointData[]);
|
||||||
|
get paRef(): IRelatedRefData | undefined;
|
||||||
|
set paRef(ref: IRelatedRefData | undefined);
|
||||||
|
get pbRef(): IRelatedRefData | undefined;
|
||||||
|
set pbRef(ref: IRelatedRefData | undefined);
|
||||||
|
get pcRef(): IRelatedRefData | undefined;
|
||||||
|
set pcRef(ref: IRelatedRefData | undefined);
|
||||||
|
get kilometerSystem(): KilometerSystem;
|
||||||
|
set kilometerSystem(v: KilometerSystem);
|
||||||
|
get paTrackSectionId(): number;
|
||||||
|
set paTrackSectionId(v: number);
|
||||||
|
get pbTrackSectionId(): number;
|
||||||
|
set pbTrackSectionId(v: number);
|
||||||
|
get pcTrackSectionId(): number;
|
||||||
|
set pcTrackSectionId(v: number);
|
||||||
|
get switchMachineType(): electronicMapGraphicData.Turnout.SwitchMachineType;
|
||||||
|
set switchMachineType(v: electronicMapGraphicData.Turnout.SwitchMachineType);
|
||||||
|
get centralizedStations(): number[];
|
||||||
|
set centralizedStations(v: number[]);
|
||||||
|
clone(): ITurnoutData;
|
||||||
|
copyFrom(data: ITurnoutData): void;
|
||||||
|
eq(other: ITurnoutData): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITurnoutState extends GraphicState {
|
||||||
|
id?: number;
|
||||||
|
normal?: boolean;
|
||||||
|
reverse?: boolean;
|
||||||
|
dw?: boolean;
|
||||||
|
fw?: boolean;
|
||||||
|
qdc?: boolean;
|
||||||
|
qfc?: boolean;
|
||||||
|
qyc?: boolean;
|
||||||
|
dc?: boolean;
|
||||||
|
fc?: boolean;
|
||||||
|
yc?: boolean;
|
||||||
|
occupied?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TurnoutConsts = {
|
||||||
|
lineColor: '#5578b6',
|
||||||
|
occupiedColor: '#f00',
|
||||||
|
lineWidth: 5,
|
||||||
|
forkLenth: 20,
|
||||||
|
labelFontSize: 12,
|
||||||
|
normalLabelColor: '#0f0',
|
||||||
|
reverseLabelColor: '#ff0',
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum TurnoutPosition {
|
||||||
|
NORMAL = 0,
|
||||||
|
REVERSE = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getForkPoint(r: number, p: IPointData): IPointData {
|
||||||
|
if (r === 0) return { x: 0, y: 0 };
|
||||||
|
const len = Math.sqrt((-p.x) ** 2 + (-p.y) ** 2);
|
||||||
|
const scale = r / len;
|
||||||
|
return { x: scale * p.x, y: scale * p.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutSection extends Graphics {
|
||||||
|
turnout: Turnout;
|
||||||
|
port: DevicePort;
|
||||||
|
constructor(turnout: Turnout, port: DevicePort) {
|
||||||
|
super();
|
||||||
|
this.turnout = turnout;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
paint() {
|
||||||
|
let pList: IPointData[] = [];
|
||||||
|
switch (this.port) {
|
||||||
|
case DevicePort.A:
|
||||||
|
pList = this.turnout.datas.pointA;
|
||||||
|
break;
|
||||||
|
case DevicePort.B:
|
||||||
|
pList = this.turnout.datas.pointB;
|
||||||
|
break;
|
||||||
|
case DevicePort.C:
|
||||||
|
pList = this.turnout.datas.pointC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const gap = this.port === DevicePort.A ? 0 : TurnoutConsts.forkLenth;
|
||||||
|
let color = TurnoutConsts.lineColor;
|
||||||
|
if (this.turnout.states.occupied) {
|
||||||
|
if (
|
||||||
|
this.port === DevicePort.A ||
|
||||||
|
(this.turnout.states.dw && this.port === DevicePort.B) ||
|
||||||
|
(this.turnout.states.fw && this.port === DevicePort.C)
|
||||||
|
) {
|
||||||
|
color = TurnoutConsts.occupiedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const start = getForkPoint(gap, pList[0]);
|
||||||
|
this.clear()
|
||||||
|
.lineStyle(TurnoutConsts.lineWidth, color)
|
||||||
|
.moveTo(start.x, start.y);
|
||||||
|
pList.forEach((p) => {
|
||||||
|
const { x, y } = p;
|
||||||
|
this.lineTo(x, y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ForkGraphic extends Graphics {
|
||||||
|
turnout: Turnout;
|
||||||
|
constructor(turnout: Turnout) {
|
||||||
|
super();
|
||||||
|
this.turnout = turnout;
|
||||||
|
}
|
||||||
|
|
||||||
|
paint(p: IPointData) {
|
||||||
|
const target = getForkPoint(TurnoutConsts.forkLenth, p);
|
||||||
|
const color = this.turnout.states.occupied
|
||||||
|
? TurnoutConsts.occupiedColor
|
||||||
|
: TurnoutConsts.lineColor;
|
||||||
|
this.clear()
|
||||||
|
.lineStyle(TurnoutConsts.lineWidth, color)
|
||||||
|
.moveTo(0, 0)
|
||||||
|
.lineTo(target.x, target.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Turnout extends JlGraphic {
|
||||||
|
static Type = 'Turnout';
|
||||||
|
graphics: {
|
||||||
|
fork: ForkGraphic;
|
||||||
|
sections: [TurnoutSection, TurnoutSection, TurnoutSection];
|
||||||
|
label: VectorText;
|
||||||
|
};
|
||||||
|
deltaTime: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Turnout.Type);
|
||||||
|
this.name = 'turnout';
|
||||||
|
this.graphics = {
|
||||||
|
fork: new ForkGraphic(this),
|
||||||
|
sections: [
|
||||||
|
new TurnoutSection(this, DevicePort.A),
|
||||||
|
new TurnoutSection(this, DevicePort.B),
|
||||||
|
new TurnoutSection(this, DevicePort.C),
|
||||||
|
],
|
||||||
|
label: new VectorText(),
|
||||||
|
};
|
||||||
|
this.deltaTime = 0;
|
||||||
|
this.addChild(this.graphics.fork);
|
||||||
|
// this.addChild(...this.graphics.sections);
|
||||||
|
this.addChild(this.graphics.sections[0]);
|
||||||
|
this.addChild(this.graphics.sections[1]);
|
||||||
|
this.addChild(this.graphics.sections[2]);
|
||||||
|
this.graphics.label.anchor.set(0.5);
|
||||||
|
this.graphics.label.style.fill = '#0f0';
|
||||||
|
this.graphics.label.setVectorFontSize(TurnoutConsts.labelFontSize);
|
||||||
|
this.graphics.label.position.set(20, 20);
|
||||||
|
this.graphics.label.transformSave = true;
|
||||||
|
this.graphics.label.name = 'label';
|
||||||
|
this.addChild(this.graphics.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
get code(): string {
|
||||||
|
return this.datas.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
get datas(): ITurnoutData {
|
||||||
|
return this.getDatas<ITurnoutData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
get states(): ITurnoutState {
|
||||||
|
return this.getStates<ITurnoutState>();
|
||||||
|
}
|
||||||
|
getPortPoints() {
|
||||||
|
return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
|
||||||
|
}
|
||||||
|
|
||||||
|
doRepaint(): void {
|
||||||
|
const { pointB, pointC } = this.datas;
|
||||||
|
if (this.states.dw) {
|
||||||
|
this.graphics.fork.paint(pointB[0]);
|
||||||
|
this.graphics.label.style.stroke = TurnoutConsts.normalLabelColor;
|
||||||
|
} else if (this.states.fw) {
|
||||||
|
this.graphics.fork.paint(pointC[0]);
|
||||||
|
this.graphics.label.style.stroke = TurnoutConsts.reverseLabelColor;
|
||||||
|
}
|
||||||
|
this.graphics.label.text = this.datas.code;
|
||||||
|
|
||||||
|
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
|
||||||
|
|
||||||
|
if (!this.states.dw && !this.states.fw) {
|
||||||
|
// 失表
|
||||||
|
this.graphics.fork.visible = false;
|
||||||
|
} else {
|
||||||
|
this.graphics.fork.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initTurnoutSplit() {
|
||||||
|
// 道岔失表
|
||||||
|
const name = `${this.datas.id}_turnout_split`;
|
||||||
|
let turnoutSplit = this.animation(name);
|
||||||
|
if (!turnoutSplit) {
|
||||||
|
turnoutSplit = GraphicAnimation.init({
|
||||||
|
name: name,
|
||||||
|
run: (dt: number) => {
|
||||||
|
this.deltaTime += dt;
|
||||||
|
this.deltaTime = this.deltaTime % 60;
|
||||||
|
this.graphics.fork.visible = this.deltaTime > 30;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.addAnimation(turnoutSplit);
|
||||||
|
}
|
||||||
|
turnoutSplit.resume();
|
||||||
|
}
|
||||||
|
stopTurnoutSplit() {
|
||||||
|
const name = `${this.datas.id}_turnout_split`;
|
||||||
|
const turnoutSplit = this.animation(name);
|
||||||
|
if (turnoutSplit) {
|
||||||
|
turnoutSplit.pause();
|
||||||
|
this.deltaTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getConnectElement(port: DevicePort) {
|
||||||
|
const relation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).getParam<DevicePort>() === port &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
if (!relation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
g: relation?.getOtherGraphic(this) as Section | Turnout,
|
||||||
|
port: relation?.getOtherRelationParam(this).getParam<DevicePort>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRelation(): void {
|
||||||
|
this.relationManage.deleteRelationOfGraphic(this);
|
||||||
|
|
||||||
|
/** 道岔和区段 */
|
||||||
|
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
|
||||||
|
if (section.datas.sectionType !== SectionType.Physical) return;
|
||||||
|
this.getPortPoints().forEach((port, i) => {
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
section.localToCanvasPoint(section.getStartPoint()),
|
||||||
|
this.localToCanvasPoint(port[port.length - 1])
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this,
|
||||||
|
[DevicePort.A, DevicePort.B, DevicePort.C][i]
|
||||||
|
),
|
||||||
|
new GraphicRelationParam(section, DevicePort.A)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
section.localToCanvasPoint(section.getEndPoint()),
|
||||||
|
this.localToCanvasPoint(port[port.length - 1])
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this,
|
||||||
|
[DevicePort.A, DevicePort.B, DevicePort.C][i]
|
||||||
|
),
|
||||||
|
new GraphicRelationParam(section, DevicePort.B)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 道岔和道岔 */
|
||||||
|
this.getPortPoints().forEach((thisPort, i) => {
|
||||||
|
let params: GraphicRelationParam[] = [],
|
||||||
|
deflection = 180;
|
||||||
|
this.queryStore.queryByType<Turnout>(Turnout.Type).forEach((turnout) => {
|
||||||
|
if (turnout.id === this.id) return;
|
||||||
|
turnout.getPortPoints().forEach((otherPort, j) => {
|
||||||
|
if (
|
||||||
|
distance2(
|
||||||
|
this.localToCanvasPoint(thisPort[thisPort.length - 1]),
|
||||||
|
turnout.localToCanvasPoint(otherPort[otherPort.length - 1])
|
||||||
|
) <= tolerance
|
||||||
|
) {
|
||||||
|
const angle = angleOfIncludedAngle(
|
||||||
|
this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */,
|
||||||
|
thisPort[thisPort.length - 2]
|
||||||
|
? this.localToCanvasPoint(thisPort[thisPort.length - 2])
|
||||||
|
: this.position,
|
||||||
|
otherPort[otherPort.length - 2]
|
||||||
|
? turnout.localToCanvasPoint(otherPort[otherPort.length - 2])
|
||||||
|
: turnout.position
|
||||||
|
);
|
||||||
|
if (180 - Math.abs(angle) <= deflection) {
|
||||||
|
deflection = 180 - Math.abs(angle);
|
||||||
|
params = [
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this,
|
||||||
|
[DevicePort.A, DevicePort.B, DevicePort.C][i]
|
||||||
|
),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
turnout,
|
||||||
|
[DevicePort.A, DevicePort.B, DevicePort.C][j]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (params.length === 2) {
|
||||||
|
this.relationManage.addRelation(params[0], params[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRelations() {
|
||||||
|
const paRelation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).param === DevicePort.A &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
const paDevice = paRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||||
|
if (paDevice) {
|
||||||
|
this.datas.paRef = createRelatedRefProto(
|
||||||
|
paDevice.type,
|
||||||
|
paDevice.id,
|
||||||
|
paRelation?.getOtherRelationParam(this).param
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.datas.paRef = undefined;
|
||||||
|
}
|
||||||
|
const pbRelation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).param === DevicePort.B &&
|
||||||
|
(relation.getOtherGraphic(this) instanceof Section ||
|
||||||
|
relation.getOtherGraphic(this) instanceof Turnout)
|
||||||
|
);
|
||||||
|
const pbDevice = pbRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||||
|
if (pbDevice) {
|
||||||
|
this.datas.pbRef = createRelatedRefProto(
|
||||||
|
pbDevice.type,
|
||||||
|
pbDevice.id,
|
||||||
|
pbRelation?.getOtherRelationParam(this).param
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.datas.pbRef = undefined;
|
||||||
|
}
|
||||||
|
const pcRelation = this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.find(
|
||||||
|
(relation) => relation.getRelationParam(this).param === DevicePort.C
|
||||||
|
);
|
||||||
|
const pcDevice = pcRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||||
|
if (pcDevice) {
|
||||||
|
this.datas.pcRef = createRelatedRefProto(
|
||||||
|
pcDevice.type,
|
||||||
|
pcDevice.id,
|
||||||
|
pcRelation?.getOtherRelationParam(this).param
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.datas.pcRef = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRelations() {
|
||||||
|
if (this.datas.paRef?.id) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, DevicePort.A),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.paRef.id),
|
||||||
|
protoPort2Data(this.datas.paRef.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.datas.pbRef?.id) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, DevicePort.B),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.pbRef.id),
|
||||||
|
protoPort2Data(this.datas.pbRef.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.datas.pcRef?.id) {
|
||||||
|
this.relationManage.addRelation(
|
||||||
|
new GraphicRelationParam(this, DevicePort.C),
|
||||||
|
new GraphicRelationParam(
|
||||||
|
this.queryStore.queryById(this.datas.pcRef.id),
|
||||||
|
protoPort2Data(this.datas.pcRef.devicePort)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getGraphicOfPort(port: DevicePort) {
|
||||||
|
return this.relationManage
|
||||||
|
.getRelationsOfGraphic(this)
|
||||||
|
.filter(
|
||||||
|
(relation) =>
|
||||||
|
relation.getRelationParam(this).getParam<DevicePort>() === port
|
||||||
|
)
|
||||||
|
.map((relation) => {
|
||||||
|
return relation.getOtherGraphic(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutTemplate extends JlGraphicTemplate<Turnout> {
|
||||||
|
constructor(dataTemplate: ITurnoutData, stateTemplate?: ITurnoutState) {
|
||||||
|
super(Turnout.Type, {
|
||||||
|
dataTemplate,
|
||||||
|
stateTemplate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
new() {
|
||||||
|
const g = new Turnout();
|
||||||
|
g.loadData(this.datas);
|
||||||
|
g.loadState(this.states);
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
567
src/graphics/electronicMap/turnout/TurnoutDrawAssistant.ts
Normal file
567
src/graphics/electronicMap/turnout/TurnoutDrawAssistant.ts
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
import {
|
||||||
|
AbsorbablePosition,
|
||||||
|
DraggablePoint,
|
||||||
|
IGraphicApp,
|
||||||
|
GraphicDrawAssistant,
|
||||||
|
GraphicInteractionPlugin,
|
||||||
|
GraphicTransformEvent,
|
||||||
|
IDrawApp,
|
||||||
|
JlGraphic,
|
||||||
|
VectorText,
|
||||||
|
linePoint,
|
||||||
|
polylinePoint,
|
||||||
|
AppConsts,
|
||||||
|
GraphicEditPlugin,
|
||||||
|
getWaypointRangeIndex,
|
||||||
|
ContextMenu,
|
||||||
|
MenuItemOptions,
|
||||||
|
AbsorbablePoint,
|
||||||
|
AbsorbableLine,
|
||||||
|
distance,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import {
|
||||||
|
ITurnoutData,
|
||||||
|
Turnout,
|
||||||
|
TurnoutConsts,
|
||||||
|
TurnoutSection,
|
||||||
|
TurnoutTemplate,
|
||||||
|
getForkPoint,
|
||||||
|
} from './Turnout';
|
||||||
|
import {
|
||||||
|
DisplayObject,
|
||||||
|
FederatedMouseEvent,
|
||||||
|
IHitArea,
|
||||||
|
IPointData,
|
||||||
|
Point,
|
||||||
|
} from 'pixi.js';
|
||||||
|
import { DevicePort, Section } from '../section/Section';
|
||||||
|
|
||||||
|
export class TurnoutDraw extends GraphicDrawAssistant<
|
||||||
|
TurnoutTemplate,
|
||||||
|
ITurnoutData
|
||||||
|
> {
|
||||||
|
turnout: Turnout;
|
||||||
|
constructor(app: IDrawApp, template: TurnoutTemplate) {
|
||||||
|
super(app, template, 'sym_o_ramp_left', '道岔Turnout');
|
||||||
|
|
||||||
|
this.turnout = this.graphicTemplate.new();
|
||||||
|
this.container.addChild(this.turnout);
|
||||||
|
|
||||||
|
TurnoutPointsInteractionPlugin.init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeftUp(e: FederatedMouseEvent): void {
|
||||||
|
this.turnout.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||||
|
this.createAndStore(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareData(data: ITurnoutData): boolean {
|
||||||
|
data.transform = this.turnout.saveTransform();
|
||||||
|
data.code = 'A000000';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(cp: Point): void {
|
||||||
|
this.turnout.position.copyFrom(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ForkHitArea implements IHitArea {
|
||||||
|
turnout: Turnout;
|
||||||
|
constructor(turnout: Turnout) {
|
||||||
|
this.turnout = turnout;
|
||||||
|
}
|
||||||
|
contains(x: number, y: number): boolean {
|
||||||
|
const intersectPointB = getForkPoint(
|
||||||
|
TurnoutConsts.forkLenth,
|
||||||
|
this.turnout.datas.pointB[0]
|
||||||
|
);
|
||||||
|
const intersectPointC = getForkPoint(
|
||||||
|
TurnoutConsts.forkLenth,
|
||||||
|
this.turnout.datas.pointC[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
linePoint(
|
||||||
|
intersectPointB,
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x, y },
|
||||||
|
TurnoutConsts.lineWidth
|
||||||
|
) ||
|
||||||
|
linePoint(
|
||||||
|
intersectPointC,
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x, y },
|
||||||
|
TurnoutConsts.lineWidth
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutSectionHitArea implements IHitArea {
|
||||||
|
section: TurnoutSection;
|
||||||
|
constructor(section: TurnoutSection) {
|
||||||
|
this.section = section;
|
||||||
|
}
|
||||||
|
contains(x: number, y: number): boolean {
|
||||||
|
let points: IPointData[];
|
||||||
|
let start: IPointData;
|
||||||
|
switch (this.section.port) {
|
||||||
|
case DevicePort.A:
|
||||||
|
points = this.section.turnout.datas.pointA;
|
||||||
|
start = { x: 0, y: 0 };
|
||||||
|
break;
|
||||||
|
case DevicePort.B:
|
||||||
|
points = this.section.turnout.datas.pointB;
|
||||||
|
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
|
||||||
|
break;
|
||||||
|
case DevicePort.C:
|
||||||
|
points = this.section.turnout.datas.pointC;
|
||||||
|
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return polylinePoint([start, ...points], { x, y }, TurnoutConsts.lineWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbsorbablePositions(turnout: Turnout): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
|
||||||
|
const sections = turnout.queryStore.queryByType<Section>(Section.Type);
|
||||||
|
sections.forEach((section) => {
|
||||||
|
const ps = new AbsorbablePoint(
|
||||||
|
section.localToCanvasPoint(section.getStartPoint())
|
||||||
|
);
|
||||||
|
const pe = new AbsorbablePoint(
|
||||||
|
section.localToCanvasPoint(section.getEndPoint())
|
||||||
|
);
|
||||||
|
aps.push(ps, pe); //区段端点
|
||||||
|
});
|
||||||
|
|
||||||
|
const turnouts = turnout.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||||
|
turnouts.forEach((otherTurnout) => {
|
||||||
|
const {
|
||||||
|
pointA: [A],
|
||||||
|
pointB: [B],
|
||||||
|
pointC: [C],
|
||||||
|
} = otherTurnout.datas;
|
||||||
|
|
||||||
|
[A, B, C].forEach((p) => {
|
||||||
|
aps.push(
|
||||||
|
new AbsorbablePoint(otherTurnout.localToCanvasPoint(p)), //道岔端点
|
||||||
|
new AbsorbableLine(
|
||||||
|
otherTurnout.localToCanvasPoint({ x: -5 * p.x, y: -5 * p.y }),
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 5 * p.x, y: 5 * p.y })
|
||||||
|
) //道岔延长线
|
||||||
|
);
|
||||||
|
});
|
||||||
|
aps.push(
|
||||||
|
new AbsorbableLine(
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 0, y: -500 }),
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 0, y: 500 })
|
||||||
|
), //岔心垂直线
|
||||||
|
new AbsorbableLine(
|
||||||
|
otherTurnout.localToCanvasPoint({ x: -500, y: 0 }),
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 500, y: 0 })
|
||||||
|
), //岔心水平线
|
||||||
|
new AbsorbableLine(
|
||||||
|
otherTurnout.localToCanvasPoint({ x: -500, y: 500 }),
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 500, y: -500 })
|
||||||
|
), //岔心/
|
||||||
|
new AbsorbableLine(
|
||||||
|
otherTurnout.localToCanvasPoint({ x: -500, y: -500 }),
|
||||||
|
otherTurnout.localToCanvasPoint({ x: 500, y: 500 })
|
||||||
|
) //岔心\
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
type dragType = Turnout | Section;
|
||||||
|
class DragMoveAbsorbablePoint extends AbsorbablePoint {
|
||||||
|
moveTarget:
|
||||||
|
| {
|
||||||
|
position: IPointData;
|
||||||
|
portPos: IPointData[];
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
constructor(point: IPointData, absorbRange = 15) {
|
||||||
|
super(point, absorbRange);
|
||||||
|
}
|
||||||
|
tryAbsorb(...dragTargets: dragType[]): void {
|
||||||
|
const dragTarget = dragTargets[0];
|
||||||
|
if (dragTarget instanceof Turnout) {
|
||||||
|
if (this.moveTarget == undefined) {
|
||||||
|
const {
|
||||||
|
pointA: [A],
|
||||||
|
pointB: [B],
|
||||||
|
pointC: [C],
|
||||||
|
} = dragTarget.datas;
|
||||||
|
this.moveTarget = {
|
||||||
|
position: dragTarget
|
||||||
|
.getGraphicApp()
|
||||||
|
.toCanvasCoordinates(dragTarget.getGlobalPosition()),
|
||||||
|
portPos: [
|
||||||
|
dragTarget.localToCanvasPoint(A),
|
||||||
|
dragTarget.localToCanvasPoint(B),
|
||||||
|
dragTarget.localToCanvasPoint(C),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
pointA: [A],
|
||||||
|
pointB: [B],
|
||||||
|
pointC: [C],
|
||||||
|
} = dragTarget.datas;
|
||||||
|
[A, B, C].forEach((p, i) => {
|
||||||
|
const changePos = dragTarget.localToCanvasPoint(p);
|
||||||
|
if (
|
||||||
|
distance(this._point.x, this._point.y, changePos.x, changePos.y) <
|
||||||
|
this.absorbRange &&
|
||||||
|
this.moveTarget
|
||||||
|
) {
|
||||||
|
dragTarget.updatePositionByCanvasPosition(
|
||||||
|
new Point(
|
||||||
|
this.moveTarget.position.x +
|
||||||
|
this._point.x -
|
||||||
|
this.moveTarget.portPos[i].x,
|
||||||
|
this.moveTarget.position.y +
|
||||||
|
this._point.y -
|
||||||
|
this.moveTarget.portPos[i].y
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this.moveTarget == undefined) {
|
||||||
|
this.moveTarget = {
|
||||||
|
position: dragTarget
|
||||||
|
.getGraphicApp()
|
||||||
|
.toCanvasCoordinates(dragTarget.getGlobalPosition()),
|
||||||
|
portPos: [
|
||||||
|
dragTarget.localToCanvasPoint(dragTarget.getStartPoint()),
|
||||||
|
dragTarget.localToCanvasPoint(dragTarget.getEndPoint()),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
dragTarget
|
||||||
|
.localToCanvasPoints(...dragTarget.datas.points)
|
||||||
|
.forEach((p, i) => {
|
||||||
|
if (
|
||||||
|
distance(this._point.x, this._point.y, p.x, p.y) <
|
||||||
|
this.absorbRange &&
|
||||||
|
this.moveTarget
|
||||||
|
) {
|
||||||
|
dragTarget.updatePositionByCanvasPosition(
|
||||||
|
new Point(
|
||||||
|
this.moveTarget.position.x +
|
||||||
|
this._point.x -
|
||||||
|
this.moveTarget.portPos[i].x,
|
||||||
|
this.moveTarget.position.y +
|
||||||
|
this._point.y -
|
||||||
|
this.moveTarget.portPos[i].y
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDragMoveAbsorbablePositions(
|
||||||
|
target: dragType
|
||||||
|
): AbsorbablePosition[] {
|
||||||
|
const aps: AbsorbablePosition[] = [];
|
||||||
|
|
||||||
|
const sections = target.queryStore.queryByType<Section>(Section.Type);
|
||||||
|
sections.forEach((section) => {
|
||||||
|
if (section.id !== target.id) {
|
||||||
|
section.localToCanvasPoints(...section.datas.points).forEach((p) => {
|
||||||
|
aps.push(new DragMoveAbsorbablePoint(p)); //区段端点
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const turnouts = target.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||||
|
turnouts.forEach((otherTurnout) => {
|
||||||
|
if (otherTurnout.id !== target.id) {
|
||||||
|
const {
|
||||||
|
pointA: [A],
|
||||||
|
pointB: [B],
|
||||||
|
pointC: [C],
|
||||||
|
} = otherTurnout.datas;
|
||||||
|
[A, B, C].forEach((p) => {
|
||||||
|
aps.push(
|
||||||
|
new DragMoveAbsorbablePoint(otherTurnout.localToCanvasPoint(p)) //道岔端点
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditPointCreate(turnout: Turnout, dp: DraggablePoint) {
|
||||||
|
dp.on('transformstart', (e: GraphicTransformEvent) => {
|
||||||
|
if (e.isShift()) {
|
||||||
|
turnout.getGraphicApp().setOptions({
|
||||||
|
absorbablePositions: buildAbsorbablePositions(turnout),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const addPointConfig: MenuItemOptions = { name: '添加路径点' };
|
||||||
|
const clearPointConfig: MenuItemOptions = { name: '清除路径点' };
|
||||||
|
|
||||||
|
const turnoutSectionEditMenu: ContextMenu = ContextMenu.init({
|
||||||
|
name: '道岔区段路径编辑',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
items: [addPointConfig, clearPointConfig],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Turnout> {
|
||||||
|
static Name = 'TurnoutPointsDrag';
|
||||||
|
static init(app: IDrawApp) {
|
||||||
|
return new TurnoutPointsInteractionPlugin(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(app: IGraphicApp) {
|
||||||
|
super(TurnoutPointsInteractionPlugin.Name, app);
|
||||||
|
app.registerMenu(turnoutSectionEditMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSectionContextMenu(e: FederatedMouseEvent, section: TurnoutSection) {
|
||||||
|
const p = section.turnout.screenToLocalPoint(e.global);
|
||||||
|
addPointConfig.handler = () => {
|
||||||
|
if (section.port === DevicePort.A) {
|
||||||
|
const { start } = getWaypointRangeIndex(
|
||||||
|
[{ x: 0, y: 0 }, ...section.turnout.datas.pointA],
|
||||||
|
false,
|
||||||
|
p,
|
||||||
|
TurnoutConsts.lineWidth
|
||||||
|
);
|
||||||
|
const points = section.turnout.datas.pointA;
|
||||||
|
const ps = points.slice(0, start);
|
||||||
|
ps.push(new Point(p.x, p.y));
|
||||||
|
ps.push(...points.slice(start));
|
||||||
|
section.turnout.datas.pointA = ps;
|
||||||
|
}
|
||||||
|
if (section.port === DevicePort.B) {
|
||||||
|
const { start } = getWaypointRangeIndex(
|
||||||
|
[{ x: 0, y: 0 }, ...section.turnout.datas.pointB],
|
||||||
|
false,
|
||||||
|
p,
|
||||||
|
TurnoutConsts.lineWidth
|
||||||
|
);
|
||||||
|
const points = section.turnout.datas.pointB;
|
||||||
|
const ps = points.slice(0, start);
|
||||||
|
ps.push(new Point(p.x, p.y));
|
||||||
|
ps.push(...points.slice(start));
|
||||||
|
section.turnout.datas.pointB = ps;
|
||||||
|
}
|
||||||
|
if (section.port === DevicePort.C) {
|
||||||
|
const { start } = getWaypointRangeIndex(
|
||||||
|
[{ x: 0, y: 0 }, ...section.turnout.datas.pointC],
|
||||||
|
false,
|
||||||
|
p,
|
||||||
|
TurnoutConsts.lineWidth
|
||||||
|
);
|
||||||
|
const points = section.turnout.datas.pointC;
|
||||||
|
const ps = points.slice(0, start);
|
||||||
|
ps.push(new Point(p.x, p.y));
|
||||||
|
ps.push(...points.slice(start));
|
||||||
|
section.turnout.datas.pointC = ps;
|
||||||
|
}
|
||||||
|
this.onSelected(section.turnout);
|
||||||
|
};
|
||||||
|
clearPointConfig.handler = () => {
|
||||||
|
if (section.port === DevicePort.A)
|
||||||
|
section.turnout.datas.pointA = [
|
||||||
|
section.turnout.datas.pointA[section.turnout.datas.pointA.length - 1],
|
||||||
|
];
|
||||||
|
if (section.port === DevicePort.B)
|
||||||
|
section.turnout.datas.pointB = [
|
||||||
|
section.turnout.datas.pointB[section.turnout.datas.pointB.length - 1],
|
||||||
|
];
|
||||||
|
if (section.port === DevicePort.C)
|
||||||
|
section.turnout.datas.pointC = [
|
||||||
|
section.turnout.datas.pointC[section.turnout.datas.pointC.length - 1],
|
||||||
|
];
|
||||||
|
const tep = section.turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||||
|
TurnoutEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (tep) {
|
||||||
|
tep.reset();
|
||||||
|
}
|
||||||
|
section.turnout.repaint();
|
||||||
|
};
|
||||||
|
turnoutSectionEditMenu.open(e.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(g: Turnout): void {
|
||||||
|
g.graphics.fork.eventMode = 'static';
|
||||||
|
g.graphics.fork.cursor = 'pointer';
|
||||||
|
g.graphics.fork.hitArea = new ForkHitArea(g);
|
||||||
|
g.graphics.sections.forEach((sectionGraphic) => {
|
||||||
|
sectionGraphic.eventMode = 'static';
|
||||||
|
sectionGraphic.cursor = 'pointer';
|
||||||
|
sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic);
|
||||||
|
sectionGraphic.on(
|
||||||
|
'rightclick',
|
||||||
|
(e) => this.onSectionContextMenu(e, sectionGraphic),
|
||||||
|
sectionGraphic
|
||||||
|
);
|
||||||
|
});
|
||||||
|
g.graphics.label.eventMode = 'static';
|
||||||
|
g.graphics.label.cursor = 'pointer';
|
||||||
|
g.graphics.label.draggable = true;
|
||||||
|
g.graphics.label.selectable = true;
|
||||||
|
g.graphics.label.name = 'label';
|
||||||
|
g.graphics.label.transformSave = true;
|
||||||
|
g.transformSave = true;
|
||||||
|
g.on('selected', this.onSelected, this);
|
||||||
|
g.on('unselected', this.onUnSelected, this);
|
||||||
|
g.on('transformstart', this.onDragMove, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(g: Turnout): void {
|
||||||
|
g.off('selected', this.onSelected, this);
|
||||||
|
g.off('unselected', this.onUnSelected, this);
|
||||||
|
g.graphics.sections.forEach((sectionGraphic) => {
|
||||||
|
sectionGraphic.off('rightclick');
|
||||||
|
});
|
||||||
|
g.off('transformstart', this.onDragMove, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelected(g: DisplayObject) {
|
||||||
|
const turnout = g as Turnout;
|
||||||
|
let tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||||
|
TurnoutEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (!tep) {
|
||||||
|
tep = new TurnoutEditPlugin(turnout, { onEditPointCreate });
|
||||||
|
turnout.addAssistantAppend(tep);
|
||||||
|
}
|
||||||
|
tep.editPoints = [[], [], []];
|
||||||
|
tep.removeChildren();
|
||||||
|
tep.initEditPoints();
|
||||||
|
//tep.reset();
|
||||||
|
tep.showAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnSelected(g: DisplayObject) {
|
||||||
|
const turnout = g as Turnout;
|
||||||
|
const tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||||
|
TurnoutEditPlugin.Name
|
||||||
|
);
|
||||||
|
if (tep) {
|
||||||
|
tep.hideAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(...grahpics: JlGraphic[]): Turnout[] | undefined {
|
||||||
|
return grahpics.filter((g) => g.type == Turnout.Type) as Turnout[];
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragMove(e: GraphicTransformEvent) {
|
||||||
|
const turnout = e.target as Turnout;
|
||||||
|
this.app.setOptions({
|
||||||
|
absorbablePositions: buildDragMoveAbsorbablePositions(turnout),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type onTurnoutEditPointCreate = (turnout: Turnout, dp: DraggablePoint) => void;
|
||||||
|
|
||||||
|
export interface ITurnoutEditOptions {
|
||||||
|
onEditPointCreate?: onTurnoutEditPointCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
|
||||||
|
static Name = 'TurnoutEdit';
|
||||||
|
options: ITurnoutEditOptions;
|
||||||
|
editPoints: DraggablePoint[][] = [[], [], []];
|
||||||
|
labels: VectorText[] = [];
|
||||||
|
|
||||||
|
constructor(graphic: Turnout, options?: ITurnoutEditOptions) {
|
||||||
|
super(graphic);
|
||||||
|
this.name = TurnoutEditPlugin.Name;
|
||||||
|
this.options = Object.assign({}, options);
|
||||||
|
this.initEditPoints();
|
||||||
|
}
|
||||||
|
reset(): void {
|
||||||
|
this.destoryEditPoints();
|
||||||
|
this.removeChildren();
|
||||||
|
this.initEditPoints();
|
||||||
|
}
|
||||||
|
hideAll(): void {
|
||||||
|
super.hideAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
initEditPoints() {
|
||||||
|
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
|
||||||
|
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
|
||||||
|
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
|
||||||
|
const cpMap: Map<Point[], IPointData[]> = new Map([
|
||||||
|
[cpA, this.graphic.datas.pointA],
|
||||||
|
[cpB, this.graphic.datas.pointB],
|
||||||
|
[cpC, this.graphic.datas.pointC],
|
||||||
|
]);
|
||||||
|
Array.from(cpMap.entries()).forEach(([cpDatas, dataPoints], i) => {
|
||||||
|
cpDatas.forEach((cpData, j) => {
|
||||||
|
const dp = new DraggablePoint(cpData);
|
||||||
|
dp.on('transforming', () => {
|
||||||
|
const localPoint = this.graphic.canvasToLocalPoint(dp.position);
|
||||||
|
dataPoints[j].x = localPoint.x;
|
||||||
|
dataPoints[j].y = localPoint.y;
|
||||||
|
|
||||||
|
this.graphic.repaint();
|
||||||
|
});
|
||||||
|
if (this.options.onEditPointCreate) {
|
||||||
|
this.options.onEditPointCreate(this.graphic, dp);
|
||||||
|
}
|
||||||
|
this.editPoints[i].push(dp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.editPoints.forEach((cps) => {
|
||||||
|
this.addChild(...cps);
|
||||||
|
});
|
||||||
|
this.labels = ['A', 'B', 'C'].map((str) => {
|
||||||
|
const vc = new VectorText(str, { fill: AppConsts.assistantElementColor });
|
||||||
|
vc.setVectorFontSize(14);
|
||||||
|
vc.anchor.set(0.5);
|
||||||
|
return vc;
|
||||||
|
});
|
||||||
|
this.addChild(...this.labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
destoryEditPoints() {
|
||||||
|
this.editPoints.forEach((dps) => {
|
||||||
|
dps.forEach((dp) => {
|
||||||
|
dp.off('transforming');
|
||||||
|
dp.destroy();
|
||||||
|
this.removeChild(dp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.editPoints = [[], [], []];
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEditedPointsPosition() {
|
||||||
|
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
|
||||||
|
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
|
||||||
|
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
|
||||||
|
[cpA, cpB, cpC].forEach((cps, i) => {
|
||||||
|
cps.forEach((cp, j) => {
|
||||||
|
this.editPoints[i][j].position.copyFrom(cp);
|
||||||
|
if (j === cps.length - 1) {
|
||||||
|
this.labels[i].position.copyFrom({ x: cp.x, y: cp.y + 12 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
311
src/layouts/electronicMapDrawLayout.vue
Normal file
311
src/layouts/electronicMapDrawLayout.vue
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
<template>
|
||||||
|
<q-layout view="hHh LpR fFf">
|
||||||
|
<q-header reveal class="bg-primary text-white">
|
||||||
|
<q-toolbar>
|
||||||
|
<q-toolbar-title class="q-gutter-sm">
|
||||||
|
<q-btn color="accent" label="功能菜单">
|
||||||
|
<q-menu>
|
||||||
|
<q-list style="min-width: 100px">
|
||||||
|
<q-item
|
||||||
|
v-for="item in leftMenuConfig"
|
||||||
|
:key="item.label"
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="item.click"
|
||||||
|
>
|
||||||
|
<q-item-section>{{ item.label }}</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn-toggle
|
||||||
|
v-model="selectUtil"
|
||||||
|
color="brown"
|
||||||
|
text-color="white"
|
||||||
|
toggle-color="orange"
|
||||||
|
toggle-text-color="black"
|
||||||
|
:options="utilsOption"
|
||||||
|
@update:model-value="drawSelect"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
v-for="(ctl, idx) in utilsOption"
|
||||||
|
:key="idx"
|
||||||
|
v-slot:[ctl.value]
|
||||||
|
>
|
||||||
|
<q-tooltip>{{ ctl.tip }}</q-tooltip>
|
||||||
|
</template>
|
||||||
|
</q-btn-toggle>
|
||||||
|
</q-toolbar-title>
|
||||||
|
<q-btn square color="purple" style="margin-right: 10px" icon="search">
|
||||||
|
<q-popup-edit
|
||||||
|
ref="popupEdit"
|
||||||
|
v-model="searchId"
|
||||||
|
:cover="false"
|
||||||
|
:offset="[0, 10]"
|
||||||
|
v-slot="scope"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
color="accent"
|
||||||
|
v-model="scope.value"
|
||||||
|
label="设备Id"
|
||||||
|
dense
|
||||||
|
autofocus
|
||||||
|
@keyup.enter="scope.set"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="search" color="accent" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn-dropdown
|
||||||
|
color="orange"
|
||||||
|
label="数据管理"
|
||||||
|
style="margin-right: 10px"
|
||||||
|
>
|
||||||
|
<q-list>
|
||||||
|
<q-item
|
||||||
|
v-for="item in dataManageConfig"
|
||||||
|
:key="item.label"
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="item.click"
|
||||||
|
>
|
||||||
|
<q-item-section>{{ item.label }}</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
<q-btn color="info" label="返回" @click="backConfirm" />
|
||||||
|
<q-btn dense flat round icon="menu" @click="toggleRightDrawer" />
|
||||||
|
</q-toolbar>
|
||||||
|
<q-resize-observer @resize="onHeaderResize" />
|
||||||
|
</q-header>
|
||||||
|
|
||||||
|
<q-drawer show-if-above bordered v-model="rightDrawerOpen" side="right">
|
||||||
|
<q-resize-observer @resize="onRightResize" />
|
||||||
|
<axleCounting-config
|
||||||
|
v-if="showGenerateAxleCountingConfig"
|
||||||
|
@close="closeGenerateAxleCountingConfig"
|
||||||
|
/>
|
||||||
|
<draw-properties v-else></draw-properties>
|
||||||
|
</q-drawer>
|
||||||
|
|
||||||
|
<q-page-container>
|
||||||
|
<div id="draw-app-container" class="overflow-hidden"></div>
|
||||||
|
</q-page-container>
|
||||||
|
|
||||||
|
<q-dialog
|
||||||
|
v-model="saveAsDialog"
|
||||||
|
persistent
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
>
|
||||||
|
<q-card style="width: 300px">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">另存为</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
label="草稿名称"
|
||||||
|
v-model="saveAsName"
|
||||||
|
:rules="[(val) => val.trim() != '' || '草稿名称不能为空']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn color="primary" label="提交" @click="saveAs(saveAsName)" />
|
||||||
|
<q-btn label="取消" v-close-popup />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
<q-resize-observer @resize="onResize" />
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import DrawProperties from 'src/components/draw-app/electronicMapDrawProperties.vue';
|
||||||
|
import { useDrawStore } from 'src/stores/electronicMap-draw-store';
|
||||||
|
import { onMounted, reactive, ref, watch } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import AxleCountingConfig from 'src/components/draw-app/properties/electronicMap/AxleCountingConfig.vue';
|
||||||
|
//import { Station } from 'src/graphics/electronicMap/station/Station';
|
||||||
|
import { Platform } from 'src/graphics/electronicMap/platform/Platform';
|
||||||
|
/* import { ScreenDoor } from 'src/graphics/electronicMap/screenDoor/ScreenDoor';
|
||||||
|
import { Section } from 'src/graphics/electronicMap/section/Section';
|
||||||
|
import { Turnout } from 'src/graphics/electronicMap/turnout/Turnout';
|
||||||
|
import { Signal } from 'src/graphics/electronicMap/signal/Signal'; */
|
||||||
|
import { saveDrawToServer } from 'src/drawApp/commonApp';
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const searchId = ref(0);
|
||||||
|
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => drawStore.drawMode,
|
||||||
|
(drawMode) => {
|
||||||
|
if (!drawMode) {
|
||||||
|
selectUtil.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => searchId.value,
|
||||||
|
() => {
|
||||||
|
try {
|
||||||
|
if (searchId.value) {
|
||||||
|
const device = drawStore
|
||||||
|
.getDrawApp()
|
||||||
|
.queryStore.queryById(searchId.value);
|
||||||
|
drawStore.getDrawApp().makeGraphicCenterShow(device);
|
||||||
|
drawStore.getDrawApp().updateSelected(device);
|
||||||
|
searchId.value = 0;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: `未查找到id为【${searchId.value}】的设备`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const rightDrawerOpen = ref(false);
|
||||||
|
function toggleRightDrawer() {
|
||||||
|
rightDrawerOpen.value = !rightDrawerOpen.value;
|
||||||
|
onResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
//工具栏所用
|
||||||
|
const selectUtil = ref();
|
||||||
|
const utilsOption: ControlItem[] = reactive([]);
|
||||||
|
const drawSelect = (item: string) => {
|
||||||
|
drawStore.getDrawApp().interactionPlugin(item).resume();
|
||||||
|
};
|
||||||
|
class ControlItem {
|
||||||
|
value: string;
|
||||||
|
slot: string;
|
||||||
|
icon: string;
|
||||||
|
tip: string;
|
||||||
|
show = true;
|
||||||
|
|
||||||
|
constructor(value: string, icon: string, tip: string, show?: boolean) {
|
||||||
|
this.value = value;
|
||||||
|
this.slot = value;
|
||||||
|
this.icon = icon;
|
||||||
|
this.tip = tip;
|
||||||
|
if (show != undefined) {
|
||||||
|
this.show = show;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//左侧功能按钮
|
||||||
|
const leftMenuConfig = [
|
||||||
|
{ label: '保存', click: saveAllDrawDatas },
|
||||||
|
{ label: '另存为', click: () => (saveAsDialog.value = true) },
|
||||||
|
{ label: '一键关联', click: buildRelations },
|
||||||
|
{ label: '一键生成计轴', click: oneClickAxleCounting },
|
||||||
|
];
|
||||||
|
|
||||||
|
//数据管理下拉按钮
|
||||||
|
const showScreenDoorConfig = ref(false);
|
||||||
|
const showGenerateAxleCountingConfig = ref(false);
|
||||||
|
const closeGenerateAxleCountingConfig = () => {
|
||||||
|
showGenerateAxleCountingConfig.value = false;
|
||||||
|
};
|
||||||
|
const dataManageConfig = [
|
||||||
|
{ label: '屏蔽门配置', click: () => (showScreenDoorConfig.value = true) },
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('绘制应用layout mounted');
|
||||||
|
drawStore.setDraftId(+route.params.id as number);
|
||||||
|
const dom = document.getElementById('draw-app-container');
|
||||||
|
if (dom) {
|
||||||
|
drawStore.setDraftId(+route.params.id as number);
|
||||||
|
const drawApp = drawStore.initDrawApp();
|
||||||
|
drawApp.bindDom(dom);
|
||||||
|
drawApp.reload();
|
||||||
|
onResize();
|
||||||
|
} else {
|
||||||
|
drawStore.setDraftId(null);
|
||||||
|
}
|
||||||
|
/* const drawAssistantsTypes = [
|
||||||
|
Station.Type,
|
||||||
|
Platform.Type,
|
||||||
|
ScreenDoor.Type,
|
||||||
|
Section.Type,
|
||||||
|
Turnout.Type,
|
||||||
|
Signal.Type,
|
||||||
|
]; */
|
||||||
|
const drawAssistantsTypes = [Platform.Type];
|
||||||
|
drawAssistantsTypes.forEach((type) => {
|
||||||
|
const drawAssistant = drawStore.getDrawApp().getDrawAssistant(type);
|
||||||
|
if (drawAssistant) {
|
||||||
|
utilsOption.push(
|
||||||
|
new ControlItem(
|
||||||
|
drawAssistant.name,
|
||||||
|
drawAssistant.icon,
|
||||||
|
drawAssistant.description || drawAssistant.name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const canvasWidth = ref(0);
|
||||||
|
const canvasHeight = ref(0);
|
||||||
|
const headerHeight = ref(0);
|
||||||
|
const rightWidth = ref(0);
|
||||||
|
|
||||||
|
function onHeaderResize(size: { height: number; width: number }) {
|
||||||
|
headerHeight.value = size.height;
|
||||||
|
onResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRightResize(size: { height: number; width: number }) {
|
||||||
|
rightWidth.value = size.width;
|
||||||
|
onResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResize() {
|
||||||
|
const clientWidth = document.documentElement.clientWidth;
|
||||||
|
const clientHeight = document.documentElement.clientHeight;
|
||||||
|
canvasWidth.value =
|
||||||
|
clientWidth - (rightDrawerOpen.value ? rightWidth.value : 0);
|
||||||
|
canvasHeight.value = clientHeight - headerHeight.value;
|
||||||
|
const dom = document.getElementById('draw-app-container');
|
||||||
|
if (dom) {
|
||||||
|
dom.style.width = canvasWidth.value + 'px';
|
||||||
|
dom.style.height = canvasHeight.value + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveAllDrawDatas() {
|
||||||
|
let base64 = '';
|
||||||
|
saveDrawToServer(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRelations() {
|
||||||
|
const app = drawStore.getDrawApp();
|
||||||
|
app?.detectRelations();
|
||||||
|
}
|
||||||
|
|
||||||
|
function oneClickAxleCounting() {
|
||||||
|
//一键生成计轴--先展示配置
|
||||||
|
drawStore.oneClickType;
|
||||||
|
showGenerateAxleCountingConfig.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function backConfirm() {
|
||||||
|
router.go(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveAsDialog = ref(false);
|
||||||
|
const saveAsName = ref('');
|
||||||
|
</script>
|
@ -72,6 +72,7 @@ const visible = ref(false);
|
|||||||
const loginInfo = reactive({
|
const loginInfo = reactive({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
|
orgId: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
let orgInfo;
|
let orgInfo;
|
||||||
@ -81,7 +82,7 @@ onMounted(async () => {
|
|||||||
} else {
|
} else {
|
||||||
orgInfo = await getDefaultOrg();
|
orgInfo = await getDefaultOrg();
|
||||||
}
|
}
|
||||||
console.log(orgInfo, 6666);
|
loginInfo.orgId = orgInfo.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
@ -8,13 +8,23 @@ export namespace common {
|
|||||||
export enum Role {
|
export enum Role {
|
||||||
Role_Unknown = 0,
|
Role_Unknown = 0,
|
||||||
Role_Admin = 1,
|
Role_Admin = 1,
|
||||||
Role_User = 2
|
Role_User = 2,
|
||||||
|
Role_OrgManager = 11,
|
||||||
|
Role_OrgTeacher = 12,
|
||||||
|
Role_OrgStudent = 13,
|
||||||
|
Role_OrgGuest = 14
|
||||||
}
|
}
|
||||||
export enum DataType {
|
export enum DataType {
|
||||||
DataType_Unknown = 0,
|
DataType_Unknown = 0,
|
||||||
DataType_Em = 1,
|
DataType_Em = 1,
|
||||||
DataType_Iscs = 4
|
DataType_Iscs = 4
|
||||||
}
|
}
|
||||||
|
export enum LineType {
|
||||||
|
LineType_Unknown = 0,
|
||||||
|
LineType_Ur = 1,
|
||||||
|
LineType_Ir = 2,
|
||||||
|
LineType_Cr = 3
|
||||||
|
}
|
||||||
export enum IscsStyle {
|
export enum IscsStyle {
|
||||||
IscsStyle_Unknown = 0,
|
IscsStyle_Unknown = 0,
|
||||||
IscsStyle_DaShiZhiNeng = 1
|
IscsStyle_DaShiZhiNeng = 1
|
||||||
|
2459
src/protos/electronicMap_graphic_data.ts
Normal file
2459
src/protos/electronicMap_graphic_data.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,426 +0,0 @@
|
|||||||
/**
|
|
||||||
* Generated by the protoc-gen-ts. DO NOT EDIT!
|
|
||||||
* compiler version: 5.27.4
|
|
||||||
* source: em_data.proto
|
|
||||||
* git: https://github.com/thesayyn/protoc-gen-ts */
|
|
||||||
import * as dependency_1 from "./common";
|
|
||||||
import * as pb_1 from "google-protobuf";
|
|
||||||
export namespace em_data {
|
|
||||||
export class Em extends pb_1.Message {
|
|
||||||
#one_of_decls: number[][] = [];
|
|
||||||
constructor(data?: any[] | {
|
|
||||||
canvas?: dependency_1.common.Canvas;
|
|
||||||
stations?: Station[];
|
|
||||||
}) {
|
|
||||||
super();
|
|
||||||
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2], this.#one_of_decls);
|
|
||||||
if (!Array.isArray(data) && typeof data == "object") {
|
|
||||||
if ("canvas" in data && data.canvas != undefined) {
|
|
||||||
this.canvas = data.canvas;
|
|
||||||
}
|
|
||||||
if ("stations" in data && data.stations != undefined) {
|
|
||||||
this.stations = data.stations;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get canvas() {
|
|
||||||
return pb_1.Message.getWrapperField(this, dependency_1.common.Canvas, 1) as dependency_1.common.Canvas;
|
|
||||||
}
|
|
||||||
set canvas(value: dependency_1.common.Canvas) {
|
|
||||||
pb_1.Message.setWrapperField(this, 1, value);
|
|
||||||
}
|
|
||||||
get has_canvas() {
|
|
||||||
return pb_1.Message.getField(this, 1) != null;
|
|
||||||
}
|
|
||||||
get stations() {
|
|
||||||
return pb_1.Message.getRepeatedWrapperField(this, Station, 2) as Station[];
|
|
||||||
}
|
|
||||||
set stations(value: Station[]) {
|
|
||||||
pb_1.Message.setRepeatedWrapperField(this, 2, value);
|
|
||||||
}
|
|
||||||
static fromObject(data: {
|
|
||||||
canvas?: ReturnType<typeof dependency_1.common.Canvas.prototype.toObject>;
|
|
||||||
stations?: ReturnType<typeof Station.prototype.toObject>[];
|
|
||||||
}): Em {
|
|
||||||
const message = new Em({});
|
|
||||||
if (data.canvas != null) {
|
|
||||||
message.canvas = dependency_1.common.Canvas.fromObject(data.canvas);
|
|
||||||
}
|
|
||||||
if (data.stations != null) {
|
|
||||||
message.stations = data.stations.map(item => Station.fromObject(item));
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
toObject() {
|
|
||||||
const data: {
|
|
||||||
canvas?: ReturnType<typeof dependency_1.common.Canvas.prototype.toObject>;
|
|
||||||
stations?: ReturnType<typeof Station.prototype.toObject>[];
|
|
||||||
} = {};
|
|
||||||
if (this.canvas != null) {
|
|
||||||
data.canvas = this.canvas.toObject();
|
|
||||||
}
|
|
||||||
if (this.stations != null) {
|
|
||||||
data.stations = this.stations.map((item: Station) => item.toObject());
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
serialize(): Uint8Array;
|
|
||||||
serialize(w: pb_1.BinaryWriter): void;
|
|
||||||
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
|
|
||||||
const writer = w || new pb_1.BinaryWriter();
|
|
||||||
if (this.has_canvas)
|
|
||||||
writer.writeMessage(1, this.canvas, () => this.canvas.serialize(writer));
|
|
||||||
if (this.stations.length)
|
|
||||||
writer.writeRepeatedMessage(2, this.stations, (item: Station) => item.serialize(writer));
|
|
||||||
if (!w)
|
|
||||||
return writer.getResultBuffer();
|
|
||||||
}
|
|
||||||
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Em {
|
|
||||||
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Em();
|
|
||||||
while (reader.nextField()) {
|
|
||||||
if (reader.isEndGroup())
|
|
||||||
break;
|
|
||||||
switch (reader.getFieldNumber()) {
|
|
||||||
case 1:
|
|
||||||
reader.readMessage(message.canvas, () => message.canvas = dependency_1.common.Canvas.deserialize(reader));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
reader.readMessage(message.stations, () => pb_1.Message.addToRepeatedWrapperField(message, 2, Station.deserialize(reader), Station));
|
|
||||||
break;
|
|
||||||
default: reader.skipField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
serializeBinary(): Uint8Array {
|
|
||||||
return this.serialize();
|
|
||||||
}
|
|
||||||
static deserializeBinary(bytes: Uint8Array): Em {
|
|
||||||
return Em.deserialize(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class KilometerMark extends pb_1.Message {
|
|
||||||
#one_of_decls: number[][] = [];
|
|
||||||
constructor(data?: any[] | {
|
|
||||||
coordinate?: string;
|
|
||||||
value?: number;
|
|
||||||
}) {
|
|
||||||
super();
|
|
||||||
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
|
|
||||||
if (!Array.isArray(data) && typeof data == "object") {
|
|
||||||
if ("coordinate" in data && data.coordinate != undefined) {
|
|
||||||
this.coordinate = data.coordinate;
|
|
||||||
}
|
|
||||||
if ("value" in data && data.value != undefined) {
|
|
||||||
this.value = data.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get coordinate() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 1, "") as string;
|
|
||||||
}
|
|
||||||
set coordinate(value: string) {
|
|
||||||
pb_1.Message.setField(this, 1, value);
|
|
||||||
}
|
|
||||||
get value() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 2, 0) as number;
|
|
||||||
}
|
|
||||||
set value(value: number) {
|
|
||||||
pb_1.Message.setField(this, 2, value);
|
|
||||||
}
|
|
||||||
static fromObject(data: {
|
|
||||||
coordinate?: string;
|
|
||||||
value?: number;
|
|
||||||
}): KilometerMark {
|
|
||||||
const message = new KilometerMark({});
|
|
||||||
if (data.coordinate != null) {
|
|
||||||
message.coordinate = data.coordinate;
|
|
||||||
}
|
|
||||||
if (data.value != null) {
|
|
||||||
message.value = data.value;
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
toObject() {
|
|
||||||
const data: {
|
|
||||||
coordinate?: string;
|
|
||||||
value?: number;
|
|
||||||
} = {};
|
|
||||||
if (this.coordinate != null) {
|
|
||||||
data.coordinate = this.coordinate;
|
|
||||||
}
|
|
||||||
if (this.value != null) {
|
|
||||||
data.value = this.value;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
serialize(): Uint8Array;
|
|
||||||
serialize(w: pb_1.BinaryWriter): void;
|
|
||||||
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
|
|
||||||
const writer = w || new pb_1.BinaryWriter();
|
|
||||||
if (this.coordinate.length)
|
|
||||||
writer.writeString(1, this.coordinate);
|
|
||||||
if (this.value != 0)
|
|
||||||
writer.writeInt64(2, this.value);
|
|
||||||
if (!w)
|
|
||||||
return writer.getResultBuffer();
|
|
||||||
}
|
|
||||||
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): KilometerMark {
|
|
||||||
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new KilometerMark();
|
|
||||||
while (reader.nextField()) {
|
|
||||||
if (reader.isEndGroup())
|
|
||||||
break;
|
|
||||||
switch (reader.getFieldNumber()) {
|
|
||||||
case 1:
|
|
||||||
message.coordinate = reader.readString();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
message.value = reader.readInt64();
|
|
||||||
break;
|
|
||||||
default: reader.skipField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
serializeBinary(): Uint8Array {
|
|
||||||
return this.serialize();
|
|
||||||
}
|
|
||||||
static deserializeBinary(bytes: Uint8Array): KilometerMark {
|
|
||||||
return KilometerMark.deserialize(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Station extends pb_1.Message {
|
|
||||||
#one_of_decls: number[][] = [];
|
|
||||||
constructor(data?: any[] | {
|
|
||||||
common?: dependency_1.common.CommonInfo;
|
|
||||||
name?: string;
|
|
||||||
zhanName?: string;
|
|
||||||
namePinyin?: string;
|
|
||||||
km?: KilometerMark;
|
|
||||||
concentration?: boolean;
|
|
||||||
depots?: boolean;
|
|
||||||
manageStationIds?: number[];
|
|
||||||
}) {
|
|
||||||
super();
|
|
||||||
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [13], this.#one_of_decls);
|
|
||||||
if (!Array.isArray(data) && typeof data == "object") {
|
|
||||||
if ("common" in data && data.common != undefined) {
|
|
||||||
this.common = data.common;
|
|
||||||
}
|
|
||||||
if ("name" in data && data.name != undefined) {
|
|
||||||
this.name = data.name;
|
|
||||||
}
|
|
||||||
if ("zhanName" in data && data.zhanName != undefined) {
|
|
||||||
this.zhanName = data.zhanName;
|
|
||||||
}
|
|
||||||
if ("namePinyin" in data && data.namePinyin != undefined) {
|
|
||||||
this.namePinyin = data.namePinyin;
|
|
||||||
}
|
|
||||||
if ("km" in data && data.km != undefined) {
|
|
||||||
this.km = data.km;
|
|
||||||
}
|
|
||||||
if ("concentration" in data && data.concentration != undefined) {
|
|
||||||
this.concentration = data.concentration;
|
|
||||||
}
|
|
||||||
if ("depots" in data && data.depots != undefined) {
|
|
||||||
this.depots = data.depots;
|
|
||||||
}
|
|
||||||
if ("manageStationIds" in data && data.manageStationIds != undefined) {
|
|
||||||
this.manageStationIds = data.manageStationIds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get common() {
|
|
||||||
return pb_1.Message.getWrapperField(this, dependency_1.common.CommonInfo, 1) as dependency_1.common.CommonInfo;
|
|
||||||
}
|
|
||||||
set common(value: dependency_1.common.CommonInfo) {
|
|
||||||
pb_1.Message.setWrapperField(this, 1, value);
|
|
||||||
}
|
|
||||||
get has_common() {
|
|
||||||
return pb_1.Message.getField(this, 1) != null;
|
|
||||||
}
|
|
||||||
get name() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 2, "") as string;
|
|
||||||
}
|
|
||||||
set name(value: string) {
|
|
||||||
pb_1.Message.setField(this, 2, value);
|
|
||||||
}
|
|
||||||
get zhanName() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 3, "") as string;
|
|
||||||
}
|
|
||||||
set zhanName(value: string) {
|
|
||||||
pb_1.Message.setField(this, 3, value);
|
|
||||||
}
|
|
||||||
get namePinyin() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 4, "") as string;
|
|
||||||
}
|
|
||||||
set namePinyin(value: string) {
|
|
||||||
pb_1.Message.setField(this, 4, value);
|
|
||||||
}
|
|
||||||
get km() {
|
|
||||||
return pb_1.Message.getWrapperField(this, KilometerMark, 6) as KilometerMark;
|
|
||||||
}
|
|
||||||
set km(value: KilometerMark) {
|
|
||||||
pb_1.Message.setWrapperField(this, 6, value);
|
|
||||||
}
|
|
||||||
get has_km() {
|
|
||||||
return pb_1.Message.getField(this, 6) != null;
|
|
||||||
}
|
|
||||||
get concentration() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean;
|
|
||||||
}
|
|
||||||
set concentration(value: boolean) {
|
|
||||||
pb_1.Message.setField(this, 10, value);
|
|
||||||
}
|
|
||||||
get depots() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean;
|
|
||||||
}
|
|
||||||
set depots(value: boolean) {
|
|
||||||
pb_1.Message.setField(this, 11, value);
|
|
||||||
}
|
|
||||||
get manageStationIds() {
|
|
||||||
return pb_1.Message.getFieldWithDefault(this, 13, []) as number[];
|
|
||||||
}
|
|
||||||
set manageStationIds(value: number[]) {
|
|
||||||
pb_1.Message.setField(this, 13, value);
|
|
||||||
}
|
|
||||||
static fromObject(data: {
|
|
||||||
common?: ReturnType<typeof dependency_1.common.CommonInfo.prototype.toObject>;
|
|
||||||
name?: string;
|
|
||||||
zhanName?: string;
|
|
||||||
namePinyin?: string;
|
|
||||||
km?: ReturnType<typeof KilometerMark.prototype.toObject>;
|
|
||||||
concentration?: boolean;
|
|
||||||
depots?: boolean;
|
|
||||||
manageStationIds?: number[];
|
|
||||||
}): Station {
|
|
||||||
const message = new Station({});
|
|
||||||
if (data.common != null) {
|
|
||||||
message.common = dependency_1.common.CommonInfo.fromObject(data.common);
|
|
||||||
}
|
|
||||||
if (data.name != null) {
|
|
||||||
message.name = data.name;
|
|
||||||
}
|
|
||||||
if (data.zhanName != null) {
|
|
||||||
message.zhanName = data.zhanName;
|
|
||||||
}
|
|
||||||
if (data.namePinyin != null) {
|
|
||||||
message.namePinyin = data.namePinyin;
|
|
||||||
}
|
|
||||||
if (data.km != null) {
|
|
||||||
message.km = KilometerMark.fromObject(data.km);
|
|
||||||
}
|
|
||||||
if (data.concentration != null) {
|
|
||||||
message.concentration = data.concentration;
|
|
||||||
}
|
|
||||||
if (data.depots != null) {
|
|
||||||
message.depots = data.depots;
|
|
||||||
}
|
|
||||||
if (data.manageStationIds != null) {
|
|
||||||
message.manageStationIds = data.manageStationIds;
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
toObject() {
|
|
||||||
const data: {
|
|
||||||
common?: ReturnType<typeof dependency_1.common.CommonInfo.prototype.toObject>;
|
|
||||||
name?: string;
|
|
||||||
zhanName?: string;
|
|
||||||
namePinyin?: string;
|
|
||||||
km?: ReturnType<typeof KilometerMark.prototype.toObject>;
|
|
||||||
concentration?: boolean;
|
|
||||||
depots?: boolean;
|
|
||||||
manageStationIds?: number[];
|
|
||||||
} = {};
|
|
||||||
if (this.common != null) {
|
|
||||||
data.common = this.common.toObject();
|
|
||||||
}
|
|
||||||
if (this.name != null) {
|
|
||||||
data.name = this.name;
|
|
||||||
}
|
|
||||||
if (this.zhanName != null) {
|
|
||||||
data.zhanName = this.zhanName;
|
|
||||||
}
|
|
||||||
if (this.namePinyin != null) {
|
|
||||||
data.namePinyin = this.namePinyin;
|
|
||||||
}
|
|
||||||
if (this.km != null) {
|
|
||||||
data.km = this.km.toObject();
|
|
||||||
}
|
|
||||||
if (this.concentration != null) {
|
|
||||||
data.concentration = this.concentration;
|
|
||||||
}
|
|
||||||
if (this.depots != null) {
|
|
||||||
data.depots = this.depots;
|
|
||||||
}
|
|
||||||
if (this.manageStationIds != null) {
|
|
||||||
data.manageStationIds = this.manageStationIds;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
serialize(): Uint8Array;
|
|
||||||
serialize(w: pb_1.BinaryWriter): void;
|
|
||||||
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
|
|
||||||
const writer = w || new pb_1.BinaryWriter();
|
|
||||||
if (this.has_common)
|
|
||||||
writer.writeMessage(1, this.common, () => this.common.serialize(writer));
|
|
||||||
if (this.name.length)
|
|
||||||
writer.writeString(2, this.name);
|
|
||||||
if (this.zhanName.length)
|
|
||||||
writer.writeString(3, this.zhanName);
|
|
||||||
if (this.namePinyin.length)
|
|
||||||
writer.writeString(4, this.namePinyin);
|
|
||||||
if (this.has_km)
|
|
||||||
writer.writeMessage(6, this.km, () => this.km.serialize(writer));
|
|
||||||
if (this.concentration != false)
|
|
||||||
writer.writeBool(10, this.concentration);
|
|
||||||
if (this.depots != false)
|
|
||||||
writer.writeBool(11, this.depots);
|
|
||||||
if (this.manageStationIds.length)
|
|
||||||
writer.writePackedUint32(13, this.manageStationIds);
|
|
||||||
if (!w)
|
|
||||||
return writer.getResultBuffer();
|
|
||||||
}
|
|
||||||
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Station {
|
|
||||||
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Station();
|
|
||||||
while (reader.nextField()) {
|
|
||||||
if (reader.isEndGroup())
|
|
||||||
break;
|
|
||||||
switch (reader.getFieldNumber()) {
|
|
||||||
case 1:
|
|
||||||
reader.readMessage(message.common, () => message.common = dependency_1.common.CommonInfo.deserialize(reader));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
message.name = reader.readString();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
message.zhanName = reader.readString();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
message.namePinyin = reader.readString();
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
reader.readMessage(message.km, () => message.km = KilometerMark.deserialize(reader));
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
message.concentration = reader.readBool();
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
message.depots = reader.readBool();
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
message.manageStationIds = reader.readPackedUint32();
|
|
||||||
break;
|
|
||||||
default: reader.skipField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
serializeBinary(): Uint8Array {
|
|
||||||
return this.serialize();
|
|
||||||
}
|
|
||||||
static deserializeBinary(bytes: Uint8Array): Station {
|
|
||||||
return Station.deserialize(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* Generated by the protoc-gen-ts. DO NOT EDIT!
|
|
||||||
* compiler version: 5.27.4
|
|
||||||
* source: picture.proto
|
|
||||||
* git: https://github.com/thesayyn/protoc-gen-ts */
|
|
||||||
import * as pb_1 from "google-protobuf";
|
|
||||||
export enum PictureType {
|
|
||||||
FireAlarm = 0,
|
|
||||||
Electromechanical = 1,
|
|
||||||
Broadcast = 2,
|
|
||||||
PassengerInformation = 3,
|
|
||||||
CCTV = 4,
|
|
||||||
PSD = 5,
|
|
||||||
TicketSalesAndChecking = 6,
|
|
||||||
AccessControl = 7,
|
|
||||||
FloodGate = 8,
|
|
||||||
NetworkStatus = 9
|
|
||||||
}
|
|
187
src/protos/simulation.ts
Normal file
187
src/protos/simulation.ts
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/**
|
||||||
|
* Generated by the protoc-gen-ts. DO NOT EDIT!
|
||||||
|
* compiler version: 5.27.4
|
||||||
|
* source: simulation.proto
|
||||||
|
* git: https://github.com/thesayyn/protoc-gen-ts */
|
||||||
|
import * as dependency_1 from "./google\\protobuf\\any";
|
||||||
|
import * as pb_1 from "google-protobuf";
|
||||||
|
export namespace simulation {
|
||||||
|
export enum OperationType {
|
||||||
|
Unknown = 0,
|
||||||
|
Pause = 1,
|
||||||
|
Unpause = 2,
|
||||||
|
Reset = 3,
|
||||||
|
SetSpeed = 4,
|
||||||
|
Destroy = 5
|
||||||
|
}
|
||||||
|
export class Operation extends pb_1.Message {
|
||||||
|
#one_of_decls: number[][] = [[2]];
|
||||||
|
constructor(data?: any[] | ({
|
||||||
|
otype?: OperationType;
|
||||||
|
} & (({
|
||||||
|
setSpeedParam?: SetSpeedParam;
|
||||||
|
})))) {
|
||||||
|
super();
|
||||||
|
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
|
||||||
|
if (!Array.isArray(data) && typeof data == "object") {
|
||||||
|
if ("otype" in data && data.otype != undefined) {
|
||||||
|
this.otype = data.otype;
|
||||||
|
}
|
||||||
|
if ("setSpeedParam" in data && data.setSpeedParam != undefined) {
|
||||||
|
this.setSpeedParam = data.setSpeedParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get otype() {
|
||||||
|
return pb_1.Message.getFieldWithDefault(this, 1, OperationType.Unknown) as OperationType;
|
||||||
|
}
|
||||||
|
set otype(value: OperationType) {
|
||||||
|
pb_1.Message.setField(this, 1, value);
|
||||||
|
}
|
||||||
|
get setSpeedParam() {
|
||||||
|
return pb_1.Message.getWrapperField(this, SetSpeedParam, 2) as SetSpeedParam;
|
||||||
|
}
|
||||||
|
set setSpeedParam(value: SetSpeedParam) {
|
||||||
|
pb_1.Message.setOneofWrapperField(this, 2, this.#one_of_decls[0], value);
|
||||||
|
}
|
||||||
|
get has_setSpeedParam() {
|
||||||
|
return pb_1.Message.getField(this, 2) != null;
|
||||||
|
}
|
||||||
|
get param() {
|
||||||
|
const cases: {
|
||||||
|
[index: number]: "none" | "setSpeedParam";
|
||||||
|
} = {
|
||||||
|
0: "none",
|
||||||
|
2: "setSpeedParam"
|
||||||
|
};
|
||||||
|
return cases[pb_1.Message.computeOneofCase(this, [2])];
|
||||||
|
}
|
||||||
|
static fromObject(data: {
|
||||||
|
otype?: OperationType;
|
||||||
|
setSpeedParam?: ReturnType<typeof SetSpeedParam.prototype.toObject>;
|
||||||
|
}): Operation {
|
||||||
|
const message = new Operation({});
|
||||||
|
if (data.otype != null) {
|
||||||
|
message.otype = data.otype;
|
||||||
|
}
|
||||||
|
if (data.setSpeedParam != null) {
|
||||||
|
message.setSpeedParam = SetSpeedParam.fromObject(data.setSpeedParam);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
toObject() {
|
||||||
|
const data: {
|
||||||
|
otype?: OperationType;
|
||||||
|
setSpeedParam?: ReturnType<typeof SetSpeedParam.prototype.toObject>;
|
||||||
|
} = {};
|
||||||
|
if (this.otype != null) {
|
||||||
|
data.otype = this.otype;
|
||||||
|
}
|
||||||
|
if (this.setSpeedParam != null) {
|
||||||
|
data.setSpeedParam = this.setSpeedParam.toObject();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
serialize(): Uint8Array;
|
||||||
|
serialize(w: pb_1.BinaryWriter): void;
|
||||||
|
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
|
||||||
|
const writer = w || new pb_1.BinaryWriter();
|
||||||
|
if (this.otype != OperationType.Unknown)
|
||||||
|
writer.writeEnum(1, this.otype);
|
||||||
|
if (this.has_setSpeedParam)
|
||||||
|
writer.writeMessage(2, this.setSpeedParam, () => this.setSpeedParam.serialize(writer));
|
||||||
|
if (!w)
|
||||||
|
return writer.getResultBuffer();
|
||||||
|
}
|
||||||
|
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Operation {
|
||||||
|
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Operation();
|
||||||
|
while (reader.nextField()) {
|
||||||
|
if (reader.isEndGroup())
|
||||||
|
break;
|
||||||
|
switch (reader.getFieldNumber()) {
|
||||||
|
case 1:
|
||||||
|
message.otype = reader.readEnum();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
reader.readMessage(message.setSpeedParam, () => message.setSpeedParam = SetSpeedParam.deserialize(reader));
|
||||||
|
break;
|
||||||
|
default: reader.skipField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
serializeBinary(): Uint8Array {
|
||||||
|
return this.serialize();
|
||||||
|
}
|
||||||
|
static deserializeBinary(bytes: Uint8Array): Operation {
|
||||||
|
return Operation.deserialize(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class SetSpeedParam extends pb_1.Message {
|
||||||
|
#one_of_decls: number[][] = [];
|
||||||
|
constructor(data?: any[] | {
|
||||||
|
speed?: number;
|
||||||
|
}) {
|
||||||
|
super();
|
||||||
|
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
|
||||||
|
if (!Array.isArray(data) && typeof data == "object") {
|
||||||
|
if ("speed" in data && data.speed != undefined) {
|
||||||
|
this.speed = data.speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get speed() {
|
||||||
|
return pb_1.Message.getFieldWithDefault(this, 1, 0) as number;
|
||||||
|
}
|
||||||
|
set speed(value: number) {
|
||||||
|
pb_1.Message.setField(this, 1, value);
|
||||||
|
}
|
||||||
|
static fromObject(data: {
|
||||||
|
speed?: number;
|
||||||
|
}): SetSpeedParam {
|
||||||
|
const message = new SetSpeedParam({});
|
||||||
|
if (data.speed != null) {
|
||||||
|
message.speed = data.speed;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
toObject() {
|
||||||
|
const data: {
|
||||||
|
speed?: number;
|
||||||
|
} = {};
|
||||||
|
if (this.speed != null) {
|
||||||
|
data.speed = this.speed;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
serialize(): Uint8Array;
|
||||||
|
serialize(w: pb_1.BinaryWriter): void;
|
||||||
|
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
|
||||||
|
const writer = w || new pb_1.BinaryWriter();
|
||||||
|
if (this.speed != 0)
|
||||||
|
writer.writeFloat(1, this.speed);
|
||||||
|
if (!w)
|
||||||
|
return writer.getResultBuffer();
|
||||||
|
}
|
||||||
|
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): SetSpeedParam {
|
||||||
|
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new SetSpeedParam();
|
||||||
|
while (reader.nextField()) {
|
||||||
|
if (reader.isEndGroup())
|
||||||
|
break;
|
||||||
|
switch (reader.getFieldNumber()) {
|
||||||
|
case 1:
|
||||||
|
message.speed = reader.readFloat();
|
||||||
|
break;
|
||||||
|
default: reader.skipField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
serializeBinary(): Uint8Array {
|
||||||
|
return this.serialize();
|
||||||
|
}
|
||||||
|
static deserializeBinary(bytes: Uint8Array): SetSpeedParam {
|
||||||
|
return SetSpeedParam.deserialize(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -94,6 +94,14 @@ const routes: RouteRecordRaw[] = [
|
|||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/electronicMapPainting/:id',
|
||||||
|
name: 'electronicMapPainting',
|
||||||
|
component: () => import('layouts/electronicMapDrawLayout.vue'),
|
||||||
|
meta: {
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/:catchAll(.*)*',
|
path: '/:catchAll(.*)*',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -12,14 +12,12 @@ import {
|
|||||||
JlGraphic,
|
JlGraphic,
|
||||||
} from 'jl-graphic';
|
} from 'jl-graphic';
|
||||||
import { markRaw } from 'vue';
|
import { markRaw } from 'vue';
|
||||||
import { PictureType } from 'src/protos/picture';
|
|
||||||
|
|
||||||
export const useDrawStore = defineStore('draw', {
|
export const useDrawStore = defineStore('draw', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
drawAssistant: null as DrawAssistant | null,
|
drawAssistant: null as DrawAssistant | null,
|
||||||
selectedGraphics: null as JlGraphic[] | null,
|
selectedGraphics: null as JlGraphic[] | null,
|
||||||
draftId: null as number | null,
|
draftId: null as number | null,
|
||||||
drawPictureType: null as PictureType | null,
|
|
||||||
selectSubmenuAndStation: { submenu: '', station: '', partition: '' },
|
selectSubmenuAndStation: { submenu: '', station: '', partition: '' },
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
107
src/stores/electronicMap-draw-store.ts
Normal file
107
src/stores/electronicMap-draw-store.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import {
|
||||||
|
initElectronicMapDrawApp,
|
||||||
|
destroyElectronicMapDrawApp,
|
||||||
|
getElectronicMapDrawApp,
|
||||||
|
} from 'src/drawApp/electronicMapApp';
|
||||||
|
import {
|
||||||
|
DrawAssistant,
|
||||||
|
GraphicData,
|
||||||
|
IDrawApp,
|
||||||
|
IJlCanvas,
|
||||||
|
JlGraphic,
|
||||||
|
} from 'jl-graphic';
|
||||||
|
import { markRaw } from 'vue';
|
||||||
|
|
||||||
|
export const useDrawStore = defineStore('draw', {
|
||||||
|
state: () => ({
|
||||||
|
drawAssistant: null as DrawAssistant | null,
|
||||||
|
selectedGraphics: null as JlGraphic[] | null,
|
||||||
|
draftId: null as number | null,
|
||||||
|
oneClickType: '',
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
drawMode: (state) => state.drawAssistant != null,
|
||||||
|
drawGraphicType: (state) => state.drawAssistant?.type,
|
||||||
|
drawGraphicName: (state) => state.drawAssistant?.description,
|
||||||
|
drawGraphicTemplate: (state) => state.drawAssistant?.graphicTemplate,
|
||||||
|
selectedGraphicType: (state) => {
|
||||||
|
if (state.selectedGraphics) {
|
||||||
|
if (state.selectedGraphics.length === 1) {
|
||||||
|
return state.selectedGraphics[0].type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedObjName(state): string {
|
||||||
|
if (state.selectedGraphics) {
|
||||||
|
if (state.selectedGraphics.length == 0) {
|
||||||
|
return '画布';
|
||||||
|
} else if (state.selectedGraphics.length == 1) {
|
||||||
|
const name = getElectronicMapDrawApp()?.getDrawAssistant(
|
||||||
|
state.selectedGraphics[0].type
|
||||||
|
).description;
|
||||||
|
return name || '';
|
||||||
|
}
|
||||||
|
return '批量设置';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
selectedGraphic: (state) => {
|
||||||
|
if (state.selectedGraphics) {
|
||||||
|
if (state.selectedGraphics.length === 1) {
|
||||||
|
return state.selectedGraphics[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
getDrawApp(): IDrawApp {
|
||||||
|
const app = getElectronicMapDrawApp();
|
||||||
|
if (app == null) {
|
||||||
|
throw new Error('未初始化app');
|
||||||
|
}
|
||||||
|
return app;
|
||||||
|
},
|
||||||
|
getJlCanvas(): IJlCanvas {
|
||||||
|
return this.getDrawApp().canvas;
|
||||||
|
},
|
||||||
|
bindFormData(form: GraphicData): void {
|
||||||
|
const app = this.getDrawApp();
|
||||||
|
app.bindFormData(form);
|
||||||
|
},
|
||||||
|
unbindFormData(form: GraphicData): void {
|
||||||
|
const app = this.getDrawApp();
|
||||||
|
app.unbindFormData(form);
|
||||||
|
},
|
||||||
|
initDrawApp() {
|
||||||
|
const app = initElectronicMapDrawApp();
|
||||||
|
if (app == null) {
|
||||||
|
throw new Error('未初始化app');
|
||||||
|
}
|
||||||
|
app.on('interaction-plugin-resume', (plugin) => {
|
||||||
|
if (plugin.isAppPlugin()) {
|
||||||
|
if (Object.hasOwn(plugin, '__GraphicDrawAssistant')) {
|
||||||
|
this.drawAssistant = plugin as DrawAssistant;
|
||||||
|
} else {
|
||||||
|
this.drawAssistant = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.on('graphicselected', (graphics) => {
|
||||||
|
this.selectedGraphics = markRaw(graphics);
|
||||||
|
});
|
||||||
|
this.selectedGraphics = [];
|
||||||
|
return app;
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
// console.log('绘制状态清空,绘制应用销毁');
|
||||||
|
this.drawAssistant = null;
|
||||||
|
this.selectedGraphics = null;
|
||||||
|
destroyElectronicMapDrawApp();
|
||||||
|
},
|
||||||
|
setDraftId(id: number | null) {
|
||||||
|
this.draftId = id;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user