电子地图绘制备用
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 messageDir = resolve(__dirname, '../rtss-proto-msg');
|
||||
const messageDir = resolve(__dirname, '../rtsa-proto-msg');
|
||||
const protoDir = resolve(messageDir, 'src');
|
||||
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({
|
||||
username: '',
|
||||
password: '',
|
||||
orgId: 0,
|
||||
});
|
||||
|
||||
let orgInfo;
|
||||
@ -81,7 +82,7 @@ onMounted(async () => {
|
||||
} else {
|
||||
orgInfo = await getDefaultOrg();
|
||||
}
|
||||
console.log(orgInfo, 6666);
|
||||
loginInfo.orgId = orgInfo.id;
|
||||
});
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
@ -8,13 +8,23 @@ export namespace common {
|
||||
export enum Role {
|
||||
Role_Unknown = 0,
|
||||
Role_Admin = 1,
|
||||
Role_User = 2
|
||||
Role_User = 2,
|
||||
Role_OrgManager = 11,
|
||||
Role_OrgTeacher = 12,
|
||||
Role_OrgStudent = 13,
|
||||
Role_OrgGuest = 14
|
||||
}
|
||||
export enum DataType {
|
||||
DataType_Unknown = 0,
|
||||
DataType_Em = 1,
|
||||
DataType_Iscs = 4
|
||||
}
|
||||
export enum LineType {
|
||||
LineType_Unknown = 0,
|
||||
LineType_Ur = 1,
|
||||
LineType_Ir = 2,
|
||||
LineType_Cr = 3
|
||||
}
|
||||
export enum IscsStyle {
|
||||
IscsStyle_Unknown = 0,
|
||||
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,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/electronicMapPainting/:id',
|
||||
name: 'electronicMapPainting',
|
||||
component: () => import('layouts/electronicMapDrawLayout.vue'),
|
||||
meta: {
|
||||
hidden: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)*',
|
||||
meta: {
|
||||
|
@ -12,14 +12,12 @@ import {
|
||||
JlGraphic,
|
||||
} from 'jl-graphic';
|
||||
import { markRaw } from 'vue';
|
||||
import { PictureType } from 'src/protos/picture';
|
||||
|
||||
export const useDrawStore = defineStore('draw', {
|
||||
state: () => ({
|
||||
drawAssistant: null as DrawAssistant | null,
|
||||
selectedGraphics: null as JlGraphic[] | null,
|
||||
draftId: null as number | null,
|
||||
drawPictureType: null as PictureType | null,
|
||||
selectSubmenuAndStation: { submenu: '', station: '', partition: '' },
|
||||
}),
|
||||
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