Merge branch 'master' of git.code.tencent.com:beijing-rtss-test/bj-rtss-client

This commit is contained in:
Yuan 2023-07-12 11:24:35 +08:00
commit 6bd8bf17b9
20 changed files with 1277 additions and 330 deletions

View File

@ -77,6 +77,10 @@
drawStore.selectedGraphicType === AxleCountingSection.Type
"
></axle-counting-section-property>
<LogicSectionProperty
v-else-if="drawStore.selectedGraphicType === LogicSection.Type"
>
</LogicSectionProperty>
<separator-property
v-else-if="drawStore.selectedGraphicType === Separator.Type"
></separator-property>
@ -104,6 +108,7 @@ import StationProperty from './properties/StationProperty.vue';
import TrainWindowProperty from './properties/TrainWindowProperty.vue';
import AxleCountingProperty from './properties/AxleCountingProperty.vue';
import AxleCountingSectionProperty from './properties/AxleCountingSectionProperty.vue';
import LogicSectionProperty from './properties/LogicSectionProperty.vue';
import SignalProperty from './properties/SignalProperty.vue';
import TurnoutProperty from './properties/TurnoutProperty.vue';
import SectionProperty from './properties/SectionProperty.vue';
@ -121,6 +126,7 @@ import { Section } from 'src/graphics/section/Section';
import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { AxleCountingSection } from 'src/graphics/axleCountingSection/AxleCountingSection';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { Separator } from 'src/graphics/separator/Separator';
import { SectionLink } from 'src/graphics/sectionLink/SectionLink';

View File

@ -6,6 +6,15 @@
v-model="axleCountingModel.id"
label="id"
hint=""
/>
<q-input
outlined
label="计轴索引编号"
type="textarea"
@blur="onUpdate"
v-model="axleCountingModel.indexNumber"
lazy-rules
autogrow
/>
<q-input
outlined

View File

@ -7,6 +7,15 @@
label="id"
hint=""
/>
<q-input
outlined
label="计轴区段索引编号"
type="textarea"
@blur="onUpdate"
v-model="axleCountingSectionModel.indexNumber"
lazy-rules
autogrow
/>
<q-input
outlined
label="计轴区段名称"
@ -16,31 +25,30 @@
lazy-rules
autogrow
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
<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
v-for="item in sectionRelations"
v-for="item in axleCountingRelations"
:key="item"
square
color="primary"
text-color="white"
>
{{ item }}
</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
v-for="item in turnoutRelations"
:key="item"
square
color="primary"
@ -59,19 +67,17 @@
import { AxleCountingSectionData } from 'src/drawApp/graphics/AxleCountingSectionInteraction';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { AxleCountingSection } from 'src/graphics/axleCountingSection/AxleCountingSection';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const axleCountingSectionModel = reactive(new AxleCountingSectionData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
enum turoutPos {
'定位',
'反位',
}
drawStore.$subscribe;
watch(
@ -101,7 +107,7 @@ function onUpdate() {
}
}
const sectionRelations = computed(() => {
const axleCountingRelations = computed(() => {
const axleCountingSection = drawStore.selectedGraphic as AxleCountingSection;
const sectionRelations =
axleCountingSection?.relationManage.getRelationsOfGraphicAndOtherType(
@ -112,7 +118,22 @@ const sectionRelations = computed(() => {
(relation) =>
`${
relation.getOtherGraphic<AxleCounting>(axleCountingSection).datas.code
}(${relation.getOtherRelationParam(axleCountingSection).param})`
}`
);
return Array.from(new Set(ref));
});
const turnoutRelations = computed(() => {
const axleCountingSection = drawStore.selectedGraphic as AxleCountingSection;
const refTurnoutAndPos: { turnout: Turnout; pos: number }[] = [];
axleCountingSection?.datas.turnoutPosRef.forEach((ref) => {
const refTurout = axleCountingSection.queryStore.queryById(
ref.id
) as Turnout;
refTurnoutAndPos.push({ turnout: refTurout, pos: ref.position });
});
const ref = refTurnoutAndPos.map(
(ref) => `${ref.turnout.datas.code}:${turoutPos[ref.pos]}`
);
return Array.from(new Set(ref));
});

View File

@ -0,0 +1,92 @@
<template>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
v-model="logicSectionModel.id"
label="id"
hint=""
/>
<q-input
outlined
label="索引编号"
type="textarea"
@blur="onUpdate"
v-model="logicSectionModel.indexNumber"
lazy-rules
autogrow
/>
<q-input
outlined
label="逻辑区段名称"
type="textarea"
@blur="onUpdate"
v-model="logicSectionModel.code"
lazy-rules
autogrow
/>
<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
v-for="item in logicSectionRelations"
:key="item"
square
color="primary"
text-color="white"
>
{{ item }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
<script setup lang="ts">
import { LogicSectionData } from 'src/drawApp/graphics/LogicSectionInteraction';
import { AxleCountingSection } from 'src/graphics/axleCountingSection/AxleCountingSection';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const logicSectionModel = reactive(new LogicSectionData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == LogicSection.Type) {
logicSectionModel.copyFrom(val.saveData() as LogicSectionData);
}
}
);
onMounted(() => {
const logicSection = drawStore.selectedGraphic as LogicSection;
if (logicSection) {
logicSectionModel.copyFrom(logicSection.saveData());
}
});
function onUpdate() {
const logicSection = drawStore.selectedGraphic as LogicSection;
if (logicSection) {
drawStore
.getDrawApp()
.updateGraphicAndRecord(logicSection, logicSectionModel);
}
}
const logicSectionRelations = computed(() => {
const logicSection = drawStore.selectedGraphic as LogicSection;
const axleCountingSection = logicSection.queryStore.queryById(
logicSection.datas.axleSectionId
) as AxleCountingSection;
return [axleCountingSection.datas.code];
});
</script>

View File

@ -44,6 +44,12 @@ export class AxleCountingData
set axleCountingRef(points: graphicData.RelatedRef[]) {
this.data.axleCountingRef = points;
}
get indexNumber(): number {
return this.data.indexNumber;
}
set indexNumber(v: number) {
this.data.indexNumber = v;
}
clone(): AxleCountingData {
return new AxleCountingData(this.data.cloneMessage());
}

View File

@ -3,6 +3,7 @@ import { GraphicDataBase } from './GraphicDataBase';
import {
IAxleCountingSectionData,
AxleCountingSection,
ITurnoutPosRefData,
} from 'src/graphics/axleCountingSection/AxleCountingSection';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
@ -51,6 +52,18 @@ export class AxleCountingSectionData
set pbRef(ref: graphicData.RelatedRef) {
this.data.pbRef = ref;
}
get turnoutPosRef(): ITurnoutPosRefData[] {
return this.data.turnoutPos;
}
set turnoutPosRef(points: ITurnoutPosRefData[]) {
this.data.turnoutPos = points.map((p) => new graphicData.TurnoutPosRef(p));
}
get indexNumber(): number {
return this.data.indexNumber;
}
set indexNumber(v: number) {
this.data.indexNumber = v;
}
clone(): AxleCountingSectionData {
return new AxleCountingSectionData(this.data.cloneMessage());
}

View File

@ -0,0 +1,63 @@
import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase';
import {
ILogicSectionData,
LogicSection,
} from 'src/graphics/logicSection/LogicSection';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
export class LogicSectionData
extends GraphicDataBase
implements ILogicSectionData
{
constructor(data?: graphicData.LogicSection) {
let logicSection;
if (!data) {
logicSection = new graphicData.AxleCountingSection({
common: GraphicDataBase.defaultCommonInfo(LogicSection.Type),
});
} else {
logicSection = data;
}
super(logicSection);
}
public get data(): graphicData.LogicSection {
return this.getData<graphicData.LogicSection>();
}
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 axleSectionId(): string {
return this.data.axleSectionId;
}
set axleSectionId(v: string) {
this.data.axleSectionId = v;
}
get indexNumber(): number {
return this.data.indexNumber;
}
set indexNumber(v: number) {
this.data.indexNumber = v;
}
clone(): LogicSectionData {
return new LogicSectionData(this.data.cloneMessage());
}
copyFrom(data: LogicSectionData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: LogicSectionData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -47,18 +47,22 @@ export class TrainData extends GraphicDataBase implements ITrainData {
}
export class TrainState extends GraphicStateBase implements ITrainState {
constructor(proto?: StateTrain) {
constructor(proto?: train.TrainInfo) {
let states;
if (proto) {
states = proto;
} else {
states = new StateTrain();
states = new train.TrainInfo();
}
super(states, Train.Type);
}
get states(): StateTrain {
return this.getState<StateTrain>();
get code(): string {
return this.states.trainIndex;
}
get states(): train.TrainInfo {
return this.getState<train.TrainInfo>();
}
get lineId(): number {
@ -94,11 +98,11 @@ export class TrainState extends GraphicStateBase implements ITrainState {
set devName(v: string) {
this.states.devName = v;
}
get id(): string {
return this.states.id;
get trainIndex(): string {
return this.states.trainIndex;
}
set id(v: string) {
this.states.id = v;
set trainIndex(v: string) {
this.states.trainIndex = v;
}
get groupId(): string {
return this.states.groupId;
@ -169,12 +173,6 @@ export class TrainState extends GraphicStateBase implements ITrainState {
set speed(v: number) {
this.states.speed = v;
}
get show(): boolean {
return this.states.show;
}
set show(v: boolean) {
this.states.show = v;
}
get type(): boolean {
return this.states.type;
}
@ -193,27 +191,48 @@ export class TrainState extends GraphicStateBase implements ITrainState {
set rate(v: number) {
this.states.rate = v;
}
get remove(): train.TrainRemove {
return this.states.remove;
}
set remove(v: train.TrainRemove) {
this.states.remove = v;
}
get block(): train.TrainBlock {
return this.states.block;
}
set block(v: train.TrainBlock) {
this.states.block = v;
}
get record(): train.TrainRecord {
return this.states.record;
}
set record(v: train.TrainRecord) {
this.states.record = v;
}
clone(): TrainState {
return new TrainState(this.states.cloneMessage());
}
}
class StateTrain extends train.TrainInfo {
id: string;
constructor(data?: train.TrainInfo) {
super(data);
if (data?.trainIndex) {
this.id = data?.trainIndex;
} else {
this.id = '';
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 negativeDirectionConfig: MenuItemOptions = {
name: '反方向运行',
};
const runStopConfig: MenuItemOptions = {
name: '前进/停止',
};
const diriveModelConfig: MenuItemOptions = {
name: '驾驶模式',
};
const accuracyConfig: MenuItemOptions = {
name: '正常/早点/晚点',
};
const HoldTrainConfig: MenuItemOptions = {
name: '扣车',
};
@ -229,6 +248,9 @@ const TrainOperateMenu: ContextMenu = ContextMenu.init({
{
items: [
negativeDirectionConfig,
runStopConfig,
diriveModelConfig,
accuracyConfig,
HoldTrainConfig,
openDoorConfig,
editGroupConfig,
@ -275,20 +297,73 @@ export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
mode.ipModeTrainDirUp = false;
mode.ipModeTrainDirDown = true;
}
train.chagneDirection();
train.doRepaint();
};
runStopConfig.handler = () => {
train.states.mode.ipModeTrainStoped =
!train.states.mode.ipModeTrainStoped;
train.doRepaint();
};
diriveModelConfig.handler = () => {
const arr: Array<keyof state.TrainMode> = [
'ipModeTrainDriveModeAm',
'ipModeTrainDriveModeCm',
'ipModeTrainDriveBlockAm',
'ipModeTrainDriveBlockCm',
'ipModeTrainDriveModeRmf',
];
let findIndex = arr.findIndex((key) => {
return train.states.mode[key];
});
if (findIndex == arr.length - 1) {
findIndex = -1;
}
arr.forEach((key) => {
(train.states.mode[key] as boolean) = false;
});
(train.states.mode[arr[findIndex + 1]] as boolean) = true;
train.doRepaint();
};
HoldTrainConfig.handler = () => {
train.states.mode.ipModeTrainHolded =
!train.states.mode.ipModeTrainHolded;
train.chagneState();
train.doRepaint();
};
accuracyConfig.handler = () => {
const arr: Array<keyof state.TrainMode> = [
'ipModeTrainTypeSchedule',
'ipModeTrainSchdEarly',
'ipModeTrainSchdLate',
];
let findIndex = -1;
arr.forEach((key, index) => {
if (train.states.mode[key]) {
findIndex = index;
}
});
arr.forEach((key, index) => {
if (index != 0) {
(train.states.mode[key] as boolean) = false;
}
});
if (findIndex != arr.length - 1) {
train.states.mode.ipModeTrainTypeSchedule = true;
}
if (findIndex == arr.length - 1) {
train.states.mode.ipModeTrainTypeSchedule = false;
} else {
(train.states.mode[arr[findIndex + 1]] as boolean) = true;
}
train.doRepaint();
};
openDoorConfig.handler = () => {
train.states.mode.ipModeTrainDoorOpen =
!train.states.mode.ipModeTrainDoorOpen;
train.chagneState();
train.doRepaint();
};
editGroupConfig.handler = () => {
train.states.trainId = '022';
train.states.trainId = '02';
train.states.destinationId = 123;
train.doRepaint();
};
TrainOperateMenu.open(e.global);

View File

@ -71,6 +71,12 @@ import {
} from 'src/graphics/sectionLink/SectionLink';
import { SectionLinkDraw } from 'src/graphics/sectionLink/SectionLinkDrawAssistant';
import { SectionLinkData } from './graphics/SectionLinkInteraction';
import { LogicSectionDraw } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
import {
LogicSection,
LogicSectionTemplate,
} from 'src/graphics/logicSection/LogicSection';
import { LogicSectionData } from './graphics/LogicSectionInteraction';
// export function fromStoragePoint(p: graphicData.Point): Point {
// return new Point(p.x, p.y);
@ -111,14 +117,17 @@ const RedoOptions: MenuItemOptions = {
const SelectAllOptions: MenuItemOptions = {
name: '全选',
};
const oneLayerOptions: MenuItemOptions = {
name: '图层',
const AllOptions: MenuItemOptions = {
name: '全部图层',
};
const twoLayerOptions: MenuItemOptions = {
name: '图层',
const linkOptions: MenuItemOptions = {
name: '图层-Link',
};
const threeLayerOptions: MenuItemOptions = {
name: '图层三',
const axleCountingSectionOptions: MenuItemOptions = {
name: '图层-计轴区段',
};
const LogicSectionOptions: MenuItemOptions = {
name: '图层-逻辑区段',
};
const layerOptions: MenuItemOptions = {
@ -126,7 +135,12 @@ const layerOptions: MenuItemOptions = {
subMenu: [
{
name: '图层菜单',
items: [oneLayerOptions, twoLayerOptions, threeLayerOptions],
items: [
AllOptions,
linkOptions,
axleCountingSectionOptions,
LogicSectionOptions,
],
},
],
};
@ -178,6 +192,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
| SeparatorDraw
| SectionLinkDraw
| AxleCountingSectionDraw
| LogicSectionDraw
)[] = [];
if (draftType === 'Line') {
drawAssistants = [
@ -211,6 +226,10 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
app,
new AxleCountingSectionTemplate(new AxleCountingSectionData())
),
new LogicSectionDraw(
app,
new LogicSectionTemplate(new LogicSectionData())
),
];
DrawSignalInteraction.init(app);
}
@ -223,17 +242,23 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
if (app._drawing) return;
UndoOptions.disabled = !app.opRecord.hasUndo;
RedoOptions.disabled = !app.opRecord.hasRedo;
const axleCountings = app.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
const trainWindows = app.queryStore.queryByType<TrainWindow>(
TrainWindow.Type
const axleCountingSections =
app.queryStore.queryByType<AxleCountingSection>(AxleCountingSection.Type);
const logicSections = app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
const sections = app.queryStore.queryByType<Section>(Section.Type);
const sectionLinks = app.queryStore.queryByType<SectionLink>(
SectionLink.Type
);
const turnouts = app.queryStore.queryByType<Turnout>(Turnout.Type);
const disvisibleGraphics = [
...sections,
...turnouts,
...sectionLinks,
...axleCountingSections,
...logicSections,
];
UndoOptions.handler = () => {
app.opRecord.undo();
};
@ -243,31 +268,33 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
SelectAllOptions.handler = () => {
app.selectAllGraphics();
};
oneLayerOptions.handler = () => {
axleCountings.forEach((axleCounting) => {
axleCounting.visible = false;
});
sections.forEach((section) => {
section.visible = false;
});
sectionLinks.forEach((sectionLink) => {
sectionLink.visible = true;
});
turnouts.forEach((turnout) => {
turnout.visible = false;
AllOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = true;
});
};
twoLayerOptions.handler = () => {
trainWindows.forEach((trainWindow) => {
trainWindow.visible = false;
linkOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
sectionLinks.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
};
threeLayerOptions.handler = () => {
axleCountings.forEach((axleCounting) => {
axleCounting.visible = true;
axleCountingSectionOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
trainWindows.forEach((trainWindow) => {
trainWindow.visible = true;
axleCountingSections.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
};
LogicSectionOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
logicSections.forEach((logicSection) => {
logicSection.visible = true;
});
};
DefaultCanvasMenu.open(e.global);
@ -352,6 +379,9 @@ export function saveDrawDatas(app: JlDrawApp) {
storage.axleCountingSections.push(
(axleCountingSectionData as AxleCountingSectionData).data
);
} else if (LogicSection.Type === g.type) {
const logicSectionData = (g as LogicSection).saveData();
storage.logicSections.push((logicSectionData as LogicSectionData).data);
}
});
const base64 = fromUint8Array(storage.serialize());
@ -416,8 +446,30 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.axleCountingSections.forEach((axleCountingSection) => {
datas.push(new AxleCountingSectionData(axleCountingSection));
});
app.loadGraphic(datas);
storage.logicSections.forEach((logicSection) => {
datas.push(new LogicSectionData(logicSection));
});
await app.loadGraphic(datas);
} else {
app.loadGraphic([]);
}
//隐藏计轴区段--Link
const axleCountingSections = app.queryStore.queryByType<AxleCountingSection>(
AxleCountingSection.Type
);
axleCountingSections.forEach((axleCountingSection) => {
axleCountingSection.visible = false;
});
const sectionLinks = app.queryStore.queryByType<SectionLink>(
SectionLink.Type
);
sectionLinks.forEach((sectionLink) => {
sectionLink.visible = false;
});
const logicSections = app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
logicSections.forEach((logicSection) => {
logicSection.visible = false;
});
}

View File

@ -16,6 +16,8 @@ export interface IAxleCountingData extends GraphicData {
set kilometerSystem(v: KilometerSystem);
get axleCountingRef(): IRelatedRefData[]; //关联的设备
set axleCountingRef(ref: IRelatedRefData[]);
get indexNumber(): number; // 索引编号
set indexNumber(v: number);
clone(): IAxleCountingData;
copyFrom(data: IAxleCountingData): void;
eq(other: IAxleCountingData): boolean;

View File

@ -14,7 +14,6 @@ import {
IAxleCountingData,
AxleCounting,
AxleCountingTemplate,
AxleCountingConsts,
} from './AxleCounting';
import { Section, SectionPort, SectionType } from '../section/Section';
import { Turnout, TurnoutPort } from '../turnout/Turnout';
@ -119,7 +118,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
}
axleCounting.id = GraphicIdGenerator.next();
axleCounting.datas.axleCountingRef = [refData2, refData1];
axleCounting.datas.code = `${graphic.datas.code}-${port}+${refGraphic.datas.code}-${refPort}`;
axleCounting.datas.code = `${graphic.datas.code}-${port}\\${refGraphic.datas.code}-${refPort}`;
this.storeGraphic(axleCounting);
axleCounting.loadRelations();
}

View File

@ -9,15 +9,26 @@ import {
import { IRelatedRefData, protoPort2Data } from '../CommonGraphics';
import { SectionPort } from '../section/Section';
export interface ITurnoutPosRefData {
get id(): string; //道岔的ID
set id(v: string);
get position(): number; //道岔的正反为0是正位1是反位
set position(v: number);
}
export interface IAxleCountingSectionData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get paRef(): IRelatedRefData | undefined;
get paRef(): IRelatedRefData | undefined; //区段A端关联的设备
set paRef(ref: IRelatedRefData | undefined);
get pbRef(): IRelatedRefData | undefined;
get pbRef(): IRelatedRefData | undefined; //区段B端关联的设备
set pbRef(ref: IRelatedRefData | undefined);
get turnoutPosRef(): ITurnoutPosRefData[]; //关联道岔的定反位--0是定位1是反位
set turnoutPosRef(ref: ITurnoutPosRefData[]);
get indexNumber(): number; // 索引编号
set indexNumber(v: number);
clone(): IAxleCountingSectionData;
copyFrom(data: IAxleCountingSectionData): void;
eq(other: IAxleCountingSectionData): boolean;
@ -105,6 +116,17 @@ export class AxleCountingSection extends JlGraphic {
)
);
}
if (this.datas?.turnoutPosRef.length) {
this.datas.turnoutPosRef.forEach((ref) => {
this.relationManage.addRelation(
this,
new GraphicRelationParam(
this.queryStore.queryById(ref.id),
ref.position
)
);
});
}
}
}

View File

@ -1,19 +1,19 @@
import {
DisplayObject,
FederatedMouseEvent,
FederatedPointerEvent,
IHitArea,
IPoint,
IPointData,
Point,
} from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicIdGenerator,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
linePoint,
splitLineEvenly,
} from 'src/jl-graphic';
import {
@ -21,16 +21,23 @@ import {
AxleCountingSection,
AxleCountingSectionTemplate,
AxleCountingSectionConsts,
ITurnoutPosRefData,
} from './AxleCountingSection';
import { AxleCounting } from '../axleCounting/AxleCounting';
import { Section } from '../section/Section';
import { Turnout } from '../turnout/Turnout';
import { createRelatedRefProto } from '../CommonGraphics';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { Dialog } from 'quasar';
import { LogicSection } from '../logicSection/LogicSection';
import { LogicSectionData } from 'src/drawApp/graphics/LogicSectionInteraction';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import SectionSplitDialog from 'src/components/draw-app/dialogs/SectionSplitDialog.vue';
function hasCommonElements(arr1: string[], arr2: string[]): boolean {
function hasCommonElements(arr1: string[], arr2: string[]) {
for (let i = 0; i < arr1.length; i++) {
if (arr2.includes(arr1[i])) {
return true;
return arr1[i];
}
}
return false;
@ -59,7 +66,7 @@ export class AxleCountingSectionDraw extends GraphicDrawAssistant<
super(app, template, 'sym_o_circle', '不展示');
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
AxleCountingSectionInteraction.init(app);
AxleCountingSectionInteraction.init(app, this);
}
bind(): void {
@ -83,13 +90,17 @@ export class AxleCountingSectionDraw extends GraphicDrawAssistant<
data.transform = this.container.saveTransform();
return true;
}
draw(graphics: AxleCounting[]) {
/* const paRefPs = this.app.queryStore.queryById(
graphics[0].datas.axleCountingRef[0].id
);
const RepbRefPs = this.app.queryStore.queryById(
graphics[1].datas.axleCountingRef[0].id
); */
draw(
graphics: AxleCounting[],
commonElement: JlGraphic[],
map: Map<string, number>,
turoutPos?: number
) {
if (
map.has(`${graphics[0].id}+${graphics[1].id}`) ||
map.has(`${graphics[1].id}+${graphics[0].id}`)
)
return;
const axleCountingSection = new AxleCountingSection();
axleCountingSection.loadData(this.graphicTemplate.datas);
axleCountingSection.datas.points = [
@ -99,18 +110,48 @@ export class AxleCountingSectionDraw extends GraphicDrawAssistant<
axleCountingSection.id = GraphicIdGenerator.next();
const paRef = createRelatedRefProto(graphics[0].type, graphics[0].id);
const pbRef = createRelatedRefProto(graphics[1].type, graphics[1].id);
const turnoutPosData: ITurnoutPosRefData[] = [];
if (commonElement[0].type == 'Turnout') {
commonElement.forEach((Turnout) => {
if (commonElement.length > 1) {
turnoutPosData.push({
id: Turnout.id,
position: 0,
});
} else {
if (turoutPos == 0) {
turnoutPosData.push({
id: Turnout.id,
position: 0,
});
} else {
turnoutPosData.push({
id: Turnout.id,
position: 1,
});
}
}
});
}
axleCountingSection.datas.paRef = paRef;
axleCountingSection.datas.pbRef = pbRef;
axleCountingSection.datas.turnoutPosRef = turnoutPosData;
this.storeGraphic(axleCountingSection);
axleCountingSection.loadRelations();
}
oneGenerates() {
const axleCountingSectionAll =
const map = new Map();
const axleCountingSections =
this.app.queryStore.queryByType<AxleCountingSection>(
AxleCountingSection.Type
);
this.app.deleteGraphics(...axleCountingSectionAll);
axleCountingSections.forEach((axleCountingSection) => {
map.set(
`${axleCountingSection.datas.paRef?.id}+${axleCountingSection.datas.pbRef?.id}`,
1
);
});
const axleCountings = this.app.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
@ -124,80 +165,128 @@ export class AxleCountingSectionDraw extends GraphicDrawAssistant<
const refDevice = axleCountings[i].datas.axleCountingRef.map(
(ref) => ref.id
);
if (hasCommonElements(refDeviceTarget, refDevice)) {
this.draw([axleCounting, axleCountings[i]]);
const commonElementId = hasCommonElements(refDeviceTarget, refDevice);
if (commonElementId) {
const commonElement = this.app.queryStore.queryById(commonElementId);
let draw = true;
let turoutPos = 0;
//道岔BC端处的计轴不构成计轴区段
if (commonElement.type == 'Turnout') {
let targetPort, port;
axleCounting.datas.axleCountingRef.forEach((ref) => {
if (ref.id == commonElementId) {
targetPort = ref.devicePort;
}
});
axleCountings[i].datas.axleCountingRef.forEach((ref) => {
if (ref.id == commonElementId) {
port = ref.devicePort;
}
});
if (
(targetPort == 1 && port == 2) ||
(targetPort == 2 && port == 1)
) {
draw = false;
}
if (targetPort == 2 || port == 2) {
turoutPos = 1;
}
}
if (draw) {
this.draw(
[axleCounting, axleCountings[i]],
[commonElement],
map,
turoutPos
);
}
}
if (hasSamePosition(axleCounting, axleCountings[i])) {
hasfourTurnout.push([axleCounting, axleCountings[i]]);
}
}
});
const fourTurnout: Turnout[] = [];
//补4个道岔处的BB连接处的计轴区段
const fourAxleCounting: {
axleCounting: AxleCounting;
refTurout: Turnout;
}[] = [];
hasfourTurnout.forEach((axleCountings) => {
axleCountings.forEach((axleCounting) => {
//计轴关联的道岔
const axleCountingRelations =
axleCountings[0].relationManage.getRelationsOfGraphicAndOtherType(
axleCountings[0],
axleCounting.relationManage.getRelationsOfGraphicAndOtherType(
axleCounting,
Turnout.Type
);
axleCountingRelations.forEach((relation) => {
const refDevice = relation.getOtherGraphic<Section>(axleCountings[0]);
fourTurnout;
});
});
/* axleCountings.sort((a, b) => a.x - b.x);
const downAxleCountings = axleCountings.filter((point) => {
return point.y > 350;
});
for (let i = 0; i < downAxleCountings.length - 1; i++) {
const firstRef = downAxleCountings[i].datas.axleCountingRef.map(
(ref) => ref.id
const refTurnout = relation.getOtherGraphic<Turnout>(axleCounting);
//道岔关联的计轴
const turnoutRelations =
refTurnout.relationManage.getRelationsOfGraphicAndOtherType(
refTurnout,
AxleCounting.Type
);
const nextRef = downAxleCountings[i + 1].datas.axleCountingRef.map(
(ref) => ref.id
);
let nextNextRef: string[] = [];
if (i + 2 < downAxleCountings.length) {
nextNextRef = downAxleCountings[i + 2].datas.axleCountingRef.map(
(ref) => ref.id
);
}
if (hasCommonElements(firstRef, nextRef)) {
this.draw([downAxleCountings[i], downAxleCountings[i + 1]]);
} else if (
hasSamePosition(
downAxleCountings[i + 1].position,
downAxleCountings[i + 2].position
) &&
hasCommonElements(firstRef, nextNextRef)
turnoutRelations.forEach((relation) => {
const refAxleCounting =
relation.getOtherGraphic<AxleCounting>(refTurnout);
if (
refAxleCounting.id !== axleCountings[0].id &&
refAxleCounting.id !== axleCountings[1].id
) {
this.draw([downAxleCountings[i], downAxleCountings[i + 2]]);
i += 2;
}
} */
}
}
function buildAbsorbablePositions(
axleCountingSection: AxleCountingSection
): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const axleCountingSections =
axleCountingSection.queryStore.queryByType<AxleCountingSection>(
AxleCountingSection.Type
);
const { width } = axleCountingSection.getGraphicApp().canvas;
axleCountingSections.forEach((other) => {
if (other.id == axleCountingSection.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);
fourAxleCounting.push({
axleCounting: refAxleCounting,
refTurout: refTurnout,
});
return aps;
}
});
});
});
});
for (let x = 0; x < fourAxleCounting.length; x += 4) {
const AxleCountings = fourAxleCounting.slice(x, x + 4);
for (let y = 0; y < 4; y++) {
if (
fourAxleCounting[x].axleCounting.id ==
AxleCountings[y].axleCounting.id
)
continue;
if (
fourAxleCounting[x].axleCounting.y == AxleCountings[y].axleCounting.y
) {
this.draw(
[fourAxleCounting[x].axleCounting, AxleCountings[y].axleCounting],
[fourAxleCounting[x].refTurout, AxleCountings[y].refTurout],
map
);
break;
}
}
for (let y = 0; y < 4; y++) {
if (
fourAxleCounting[x + 1].axleCounting.id ==
AxleCountings[y].axleCounting.id
)
continue;
if (
fourAxleCounting[x + 1].axleCounting.y ==
AxleCountings[y].axleCounting.y
) {
this.draw(
[
fourAxleCounting[x + 1].axleCounting,
AxleCountings[y].axleCounting,
],
[fourAxleCounting[x + 1].refTurout, AxleCountings[y].refTurout],
map
);
break;
}
}
}
}
}
class AxleCountingSectionGraphicHitArea implements IHitArea {
axleCountingSection: AxleCountingSection;
constructor(axleCountingSection: AxleCountingSection) {
@ -215,13 +304,28 @@ class AxleCountingSectionGraphicHitArea implements IHitArea {
}
}
export const splitSectionConfig: MenuItemOptions = {
name: '拆分计轴区段',
};
const SectionEditMenu: ContextMenu = ContextMenu.init({
name: '区段编辑菜单',
groups: [
{
items: [splitSectionConfig],
},
],
});
export class AxleCountingSectionInteraction extends GraphicInteractionPlugin<AxleCountingSection> {
static Name = 'AxleCountingSection_transform';
constructor(app: JlDrawApp) {
drawAssistant: AxleCountingSectionDraw;
constructor(app: JlDrawApp, da: AxleCountingSectionDraw) {
super(AxleCountingSectionInteraction.Name, app);
this.drawAssistant = da;
app.registerMenu(SectionEditMenu);
}
static init(app: JlDrawApp) {
return new AxleCountingSectionInteraction(app);
static init(app: JlDrawApp, da: AxleCountingSectionDraw) {
return new AxleCountingSectionInteraction(app, da);
}
filter(...grahpics: JlGraphic[]): AxleCountingSection[] | undefined {
return grahpics
@ -240,7 +344,7 @@ export class AxleCountingSectionInteraction extends GraphicInteractionPlugin<Axl
g.labelGraphic.cursor = 'pointer';
g.labelGraphic.selectable = true;
g.labelGraphic.draggable = true;
g.on('selected', this.onSelected, this);
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: AxleCountingSection): void {
g.eventMode = 'none';
@ -254,13 +358,71 @@ export class AxleCountingSectionInteraction extends GraphicInteractionPlugin<Axl
g.labelGraphic.draggable = false;
g.labelGraphic.selectable = false;
g.labelGraphic.transformSave = false;
g.off('selected', this.onSelected, this);
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const axleCountingSection = target.getGraphic() as AxleCountingSection;
this.app.updateSelected(axleCountingSection);
splitSectionConfig.handler = () => {
Dialog.create({
title: '拆分逻辑区段',
message: '请选择生成数量和方向',
component: SectionSplitDialog,
cancel: true,
persistent: true,
}).onOk((data: { num: number; dir: 'ltr' | 'rtl' }) => {
const logicSections = this.app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
logicSections.forEach((logicSection) => {
if (logicSection.datas.axleSectionId == axleCountingSection.id) {
this.app.deleteGraphics(logicSection);
}
onSelected(): void {
const AxleCountingSection = this.app
.selectedGraphics[0] as AxleCountingSection;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(AxleCountingSection),
});
const { num, dir } = data;
const axleCountingSectionData = axleCountingSection.datas;
const points = splitLineEvenly(
axleCountingSection.localToCanvasPoint(
axleCountingSectionData.points[0]
),
axleCountingSection.localToCanvasPoint(
axleCountingSectionData.points[
axleCountingSectionData.points.length - 1
]
),
num
);
// let codeAppend = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.slice(0, num);
if (
(dir === 'ltr' &&
axleCountingSectionData.points[0].x >
axleCountingSectionData.points[
axleCountingSectionData.points.length - 1
].x) ||
(dir === 'rtl' &&
axleCountingSectionData.points[0].x <
axleCountingSectionData.points[
axleCountingSectionData.points.length - 1
].x)
) {
// codeAppend = codeAppend.split('').reverse().join('');
}
points.forEach((ps, i) => {
const data = new LogicSectionData();
data.id = GraphicIdGenerator.next();
data.axleSectionId = axleCountingSection.id;
// data.code = `${codeAppend.charAt(i % 26)}`;
data.points = ps.map(
(p) => new graphicData.Point({ x: p.x, y: p.y })
);
const g = new LogicSection();
g.loadData(data);
this.drawAssistant.storeGraphic(g);
});
});
};
SectionEditMenu.open(e.global);
}
}

View File

@ -0,0 +1,110 @@
import { Graphics, IPointData } from 'pixi.js';
import {
GraphicData,
GraphicRelationParam,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
export interface ILogicSectionData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get axleSectionId(): string; // 计轴区段ID
set axleSectionId(v: string);
get indexNumber(): number; // 索引编号
set indexNumber(v: number);
clone(): ILogicSectionData;
copyFrom(data: ILogicSectionData): void;
eq(other: ILogicSectionData): boolean;
}
export const LogicSectionConsts = {
lineColor: '0xff0000',
lineWidth: 2,
};
export class LogicSection extends JlGraphic {
static Type = 'LogicSection';
lineGraphic: Graphics;
labelGraphic: VectorText;
constructor() {
super(LogicSection.Type);
this.lineGraphic = new Graphics();
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);
}
get datas(): ILogicSectionData {
return this.getDatas<ILogicSectionData>();
}
doRepaint(): void {
if (this.datas.points.length < 2) {
throw new Error('LogicSection坐标数据异常');
}
this.lineGraphic.clear();
this.lineGraphic.lineStyle(
LogicSectionConsts.lineWidth,
LogicSectionConsts.lineColor
);
this.datas.points.forEach((p, i) => {
if (i !== 0) {
this.lineGraphic.lineTo(p.x, p.y);
} else {
this.lineGraphic.moveTo(p.x, p.y);
}
});
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
);
}
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
loadRelations() {
if (this.datas?.axleSectionId) {
const axleSection = this.queryStore.queryById(this.datas.axleSectionId);
axleSection &&
this.relationManage.addRelation(
new GraphicRelationParam(this),
new GraphicRelationParam(axleSection)
);
}
}
}
export class LogicSectionTemplate extends JlGraphicTemplate<LogicSection> {
constructor(dataTemplate: ILogicSectionData) {
super(LogicSection.Type, {
dataTemplate,
});
}
new(): LogicSection {
const logicSection = new LogicSection();
logicSection.loadData(this.datas);
return logicSection;
}
}

View File

@ -0,0 +1,163 @@
import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicIdGenerator,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jl-graphic';
import {
ILogicSectionData,
LogicSection,
LogicSectionTemplate,
LogicSectionConsts,
} from './LogicSection';
import { Turnout } from '../turnout/Turnout';
import { LogicSectionData } from 'src/drawApp/graphics/LogicSectionInteraction';
import { AxleCountingSection } from '../axleCountingSection/AxleCountingSection';
export interface ILogicSectionDrawOptions {
newData: () => ILogicSectionData;
}
export class LogicSectionDraw extends GraphicDrawAssistant<
LogicSectionTemplate,
ILogicSectionData
> {
codeGraph: LogicSection;
constructor(app: JlDrawApp, template: LogicSectionTemplate) {
super(app, template, 'sym_o_circle', '不展示');
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
LogicSectionInteraction.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: ILogicSectionData): boolean {
data.transform = this.container.saveTransform();
return true;
}
draw(data: ILogicSectionData) {
const logicSection = new LogicSection();
logicSection.loadData(data);
logicSection.id = GraphicIdGenerator.next();
this.storeGraphic(logicSection);
logicSection.loadRelations();
}
oneGenerates() {
const map = new Map();
const logicSections = this.app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
// this.app.deleteGraphics(...logicSections);
// return;
logicSections.forEach((logicSection) => {
map.set(`${logicSection.datas.axleSectionId}`, 1);
});
const axleCountingSections =
this.app.queryStore.queryByType<AxleCountingSection>(
AxleCountingSection.Type
);
axleCountingSections.forEach((axleCountingSection) => {
const turnoutPosRef = axleCountingSection.datas.turnoutPosRef;
if (turnoutPosRef.length > 0) {
turnoutPosRef.forEach((turnout) => {
if (turnout.position == 1 && !map.has(`${turnout.id}`)) {
map.set(`${turnout.id}`, 1);
const t = this.app.queryStore.queryById(turnout.id) as Turnout;
const data = new LogicSectionData();
data.points = [
t.position,
...t.localToCanvasPoints(...t.datas.pointC),
];
data.axleSectionId = axleCountingSection.id;
this.draw(data);
}
});
}
if (!map.has(`${axleCountingSection.id}`)) {
map.set(`${axleCountingSection.id}`, 1);
const data = new LogicSectionData();
data.points = axleCountingSection.datas.points;
data.axleSectionId = axleCountingSection.id;
this.draw(data);
}
});
}
}
class LogicSectionGraphicHitArea implements IHitArea {
logicSection: LogicSection;
constructor(logicSection: LogicSection) {
this.logicSection = logicSection;
}
contains(x: number, y: number): boolean {
for (let i = 1; i < this.logicSection.datas.points.length; i++) {
const p1 = this.logicSection.datas.points[i - 1];
const p2 = this.logicSection.datas.points[i];
if (linePoint(p1, p2, { x, y }, LogicSectionConsts.lineWidth)) {
return true;
}
}
return false;
}
}
export class LogicSectionInteraction extends GraphicInteractionPlugin<LogicSection> {
static Name = 'LogicSection_transform';
constructor(app: JlDrawApp) {
super(LogicSectionInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new LogicSectionInteraction(app);
}
filter(...grahpics: JlGraphic[]): LogicSection[] | undefined {
return grahpics
.filter((g) => g.type === LogicSection.Type)
.map((g) => g as LogicSection);
}
bind(g: LogicSection): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.transformSave = true;
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new LogicSectionGraphicHitArea(g);
g.labelGraphic.eventMode = 'static';
g.labelGraphic.cursor = 'pointer';
g.labelGraphic.selectable = true;
g.labelGraphic.draggable = true;
}
unbind(g: LogicSection): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.lineGraphic.eventMode = 'none';
g.lineGraphic.draggable = false;
g.lineGraphic.selectable = false;
g.lineGraphic.transformSave = false;
g.labelGraphic.eventMode = 'none';
g.labelGraphic.draggable = false;
g.labelGraphic.selectable = false;
g.labelGraphic.transformSave = false;
}
}

View File

@ -5,6 +5,8 @@ import {
JlGraphicTemplate,
VectorText,
IChildTransform,
getNormalVector,
movePointAlongNormal,
} from 'src/jl-graphic';
import { ILineGraphic } from 'src/jl-graphic/plugins/GraphicEditPlugin';
@ -23,12 +25,15 @@ export interface ISectionLinkData extends GraphicData {
export const SectionLinkConsts = {
lineColor: 0x5578b6,
lineWidth: 5,
divisionColor: 0xff0000,
divisionWidth: 2,
};
export class SectionLink extends JlGraphic implements ILineGraphic {
static Type = 'SectionLink';
lineGraphic: Graphics;
labelGraphic: VectorText;
divisionGraphic: Graphics = new Graphics();
constructor() {
super(SectionLink.Type);
@ -42,6 +47,7 @@ export class SectionLink extends JlGraphic implements ILineGraphic {
this.transformSave = true;
this.addChild(this.lineGraphic);
this.addChild(this.labelGraphic);
this.addChild(this.divisionGraphic);
}
doRepaint() {
@ -61,6 +67,36 @@ export class SectionLink extends JlGraphic implements ILineGraphic {
this.lineGraphic.moveTo(p.x, p.y);
}
});
const normalVector = getNormalVector(
this.datas.points[0],
this.datas.points[1]
);
this.divisionGraphic.clear();
this.divisionGraphic.lineStyle(
SectionLinkConsts.divisionWidth,
SectionLinkConsts.divisionColor
);
const nextP = movePointAlongNormal(this.datas.points[0], normalVector, 5);
const nextP1 = movePointAlongNormal(this.datas.points[0], normalVector, -5);
this.divisionGraphic.moveTo(nextP1.x, nextP1.y);
this.divisionGraphic.lineTo(nextP.x, nextP.y);
const normalVector2 = getNormalVector(
this.datas.points[this.datas.points.length - 2],
this.datas.points[this.datas.points.length - 1]
);
const nextP2 = movePointAlongNormal(
this.datas.points[this.datas.points.length - 1],
normalVector2,
5
);
const nextP3 = movePointAlongNormal(
this.datas.points[this.datas.points.length - 1],
normalVector2,
-5
);
this.divisionGraphic.moveTo(nextP3.x, nextP3.y);
this.divisionGraphic.lineTo(nextP2.x, nextP2.y);
this.labelGraphic.text = this.datas.code;
const labelPosition = this.datas?.childTransforms?.find(
(item: IChildTransform) => item.name === this.labelGraphic.name

View File

@ -23,6 +23,8 @@ import {
} from 'pixi.js';
import { Section } from '../section/Section';
import { Turnout } from '../turnout/Turnout';
import { AxleCounting } from '../axleCounting/AxleCounting';
import { IRelatedRefData } from '../CommonGraphics';
export class SectionLinkDraw extends GraphicDrawAssistant<
SectionLinkTemplate,
@ -65,12 +67,7 @@ export class SectionLinkDraw extends GraphicDrawAssistant<
data.points = this.points;
return true;
}
oneGenerates() {
// localToCanvasPoints
const sectionList = this.app.queryStore.queryByType<Section>(Section.Type);
const turnoutList = this.app.queryStore.queryByType<Turnout>(Turnout.Type);
console.log(sectionList.length, turnoutList.length);
sectionList.forEach((section: Section) => {
generateBySection(section: Section) {
const sectionLink = new SectionLink();
sectionLink.loadData(this.graphicTemplate.datas);
sectionLink.id = GraphicIdGenerator.next();
@ -80,36 +77,138 @@ export class SectionLinkDraw extends GraphicDrawAssistant<
});
sectionLink.datas.points = points;
this.storeGraphic(sectionLink);
});
turnoutList.forEach((turnout: Turnout) => {
const sectionLinkA = new SectionLink();
const sectionLinkB = new SectionLink();
const sectionLinkC = new SectionLink();
sectionLinkA.loadData(this.graphicTemplate.datas);
sectionLinkB.loadData(this.graphicTemplate.datas);
sectionLinkC.loadData(this.graphicTemplate.datas);
}
generateByTurnoutAxle(turnout: Turnout, port: number) {
const sectionLink = new SectionLink();
sectionLink.loadData(this.graphicTemplate.datas);
sectionLink.id = GraphicIdGenerator.next();
const forkP = new Point(turnout.position.x, turnout.position.y);
const pointA = [forkP];
const pointB = [forkP];
const pointC = [forkP];
const points: IPointData[] = [forkP];
if (port === 0) {
turnout.datas.pointA.forEach((p) => {
pointA.push(turnout.localToCanvasPoint(p));
points.push(turnout.localToCanvasPoint(p));
});
} else if (port === 1) {
turnout.datas.pointB.forEach((p) => {
pointB.push(turnout.localToCanvasPoint(p));
points.push(turnout.localToCanvasPoint(p));
});
} else if (port === 2) {
turnout.datas.pointC.forEach((p) => {
pointC.push(turnout.localToCanvasPoint(p));
points.push(turnout.localToCanvasPoint(p));
});
sectionLinkA.id = GraphicIdGenerator.next();
sectionLinkB.id = GraphicIdGenerator.next();
sectionLinkC.id = GraphicIdGenerator.next();
sectionLinkA.datas.points = pointA;
sectionLinkB.datas.points = pointB;
sectionLinkC.datas.points = pointC;
this.storeGraphic(sectionLinkA);
this.storeGraphic(sectionLinkB);
this.storeGraphic(sectionLinkC);
}
sectionLink.datas.points = points;
this.storeGraphic(sectionLink);
}
generateByTurnout(turnout: Turnout, port: number, pRef: IRelatedRefData) {
const refg = this.app.queryStore.queryById(pRef.id) as Turnout;
const sectionLink = new SectionLink();
sectionLink.loadData(this.graphicTemplate.datas);
sectionLink.id = GraphicIdGenerator.next();
const forkP1 = new Point(refg.position.x, refg.position.y);
const forkP2 = new Point(turnout.position.x, turnout.position.y);
const points: IPointData[] = [forkP1];
if (pRef.devicePort === 0) {
refg.datas.pointA.forEach((p) => {
points.push(refg.localToCanvasPoint(p));
});
} else if (pRef.devicePort === 1) {
refg.datas.pointB.forEach((p) => {
points.push(refg.localToCanvasPoint(p));
});
} else if (pRef.devicePort === 2) {
refg.datas.pointC.forEach((p) => {
points.push(refg.localToCanvasPoint(p));
});
}
let dataPoint: IPointData[] = [];
if (port === 0) {
dataPoint = turnout.datas.pointA;
} else if (port === 1) {
dataPoint = turnout.datas.pointB;
} else if (port === 2) {
dataPoint = turnout.datas.pointC;
}
const pLength = dataPoint.length;
for (let i = 1; i < pLength + 1; i++) {
points.push(turnout.localToCanvasPoint(dataPoint[pLength - i]));
}
points.push(forkP2);
sectionLink.datas.points = points;
this.storeGraphic(sectionLink);
}
oneGenerates() {
const axleCountingList = this.app.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
const turnoutList = this.app.queryStore.queryByType<Turnout>(Turnout.Type);
const generated = new Map();
axleCountingList.forEach((axleCounting) => {
axleCounting.datas.axleCountingRef.forEach((device) => {
const g = this.app.queryStore.queryById(device.id);
if (g.type === Section.Type && !generated.get(device.id)) {
const g1 = axleCountingList.find((axleCounting) => {
const s = axleCounting.datas.axleCountingRef.find(
(ref) => ref.id === device.id
);
return s;
});
if (g1) {
this.generateBySection(g as Section);
generated.set(g.id, ['A', 'B']);
}
} else if (g.type === Turnout.Type) {
this.generateByTurnoutAxle(g as Turnout, device.devicePort);
if (generated.get(g.id)) {
const pList = generated.get(g.id);
pList.push(device.devicePort);
generated.set(g.id, pList);
} else {
generated.set(g.id, [device.devicePort]);
}
}
});
});
turnoutList.forEach((turnout) => {
const pList = generated.get(turnout.id);
if (!pList) {
return;
}
let pRef = null;
if (
!pList.includes(0) &&
turnout.datas.paRef &&
turnout.datas.paRef.deviceType === 1
) {
pRef = turnout.datas.paRef;
this.generateByTurnout(turnout, 0, pRef);
}
if (
!pList.includes(1) &&
turnout.datas.pbRef &&
turnout.datas.pbRef.deviceType === 1
) {
pRef = turnout.datas.pbRef;
this.generateByTurnout(turnout, 1, pRef);
}
if (
!pList.includes(2) &&
turnout.datas.pcRef &&
turnout.datas.pcRef.deviceType === 1
) {
pRef = turnout.datas.pcRef;
this.generateByTurnout(turnout, 2, pRef);
}
generated.set(turnout.id, [0, 1, 2]);
if (pRef) {
if (generated.get(pRef.id)) {
const pListn = generated.get(pRef.id);
pListn.push(pRef.devicePort);
generated.set(pRef.id, pListn);
} else {
generated.set(pRef.id, [pRef.devicePort]);
}
}
});
}
clearCache(): void {
@ -153,31 +252,8 @@ export class SectionLinkEditPlugin extends GraphicInteractionPlugin<SectionLink>
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new SectionLinkGraphicHitArea(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('_rightclick', this.onContextMenu, this);
}
unbind(g: SectionLink): void {
// g.off('selected', this.onSelected, this);
// g.off('unselected', this.onUnselected, this);
// g.off('_rightclick', this.onContextMenu, this);
// console.log
}
// onContextMenu(e: FederatedMouseEvent) {
// const target = e.target as DisplayObject;
// const section = target.getGraphic() as SectionLink;
// this.app.updateSelected(section);
// }
// onSelected(g: DisplayObject): void {
// const sectionLink = g as SectionLink;
// }
// onUnselected(g: DisplayObject): void {
// const sectionLink = g as SectionLink;
// }
}

View File

@ -19,9 +19,9 @@ export enum separatorTypeEnum {
}
export const SeparatorConsts = {
height: 15,
height: 12,
lineWidth: 2,
lineColor: '0x617799',
lineColor: '0xFFFFFF',
circleColor: '0xEF0200',
radius: 5,
};

View File

@ -1,6 +1,7 @@
import { Color, Graphics, Container, Point } from 'pixi.js';
import {
GraphicData,
GraphicIdGenerator,
GraphicState,
JlGraphic,
JlGraphicTemplate,
@ -29,8 +30,8 @@ export interface ITrainState extends GraphicState {
set devType(v: state.DeviceType);
get devName(): string; // 所在设备名称
set devName(v: string);
get id(): string; // 设备唯一
set id(v: string);
get trainIndex(): string; // 设备唯一与trainIndex相同
set trainIndex(v: string);
get groupId(): string; // 列车车组号
set groupId(v: string);
get trainId(): string; // 列车表号
@ -53,14 +54,18 @@ export interface ITrainState extends GraphicState {
set departTime(v: number);
get speed(): number; // 速度
set speed(v: number);
get show(): boolean; // 是否显示
set show(v: boolean);
get type(): boolean; // 车次号变化状态
set type(v: boolean);
get routeId(): number; // 运行路径号
set routeId(v: number);
get rate(): number; // 满载率
set rate(v: number);
get remove(): train.TrainRemove;
set remove(v: train.TrainRemove);
get block(): train.TrainBlock;
set block(v: train.TrainBlock);
get record(): train.TrainRecord;
set record(v: train.TrainRecord);
}
interface bodyWH {
@ -71,36 +76,36 @@ interface bodyWH {
// 列车颜色
export enum TrainColorEnum {
headColor = '0xFFCE4D', // 箭头颜色
bodyColor = '0xA388B1', // 背景色
bodyColor = '0x1F3D99', // 背景色
ITCbodyColor = '0x737373', // 点式背景色
codeColor = '0xffffff', // 车号颜色
borderColor = '0xA3E198', // 边框的颜色
borderColor = '0xffffff', // 边框的颜色
directionColor = '0x00FF00', // 方向箭头颜色
}
enum diriveModelColorEnum { // 驾驶模式对应颜色
AM = '0x00FF00', // ATO自动驾驶
enum DiriveModelColorEnum { // 驾驶模式对应颜色
AM = '0xFF8000', // ATO自动驾驶
SM = '0xFFFF00', // ATP 监控下的人工驾驶模式
RM = '0xFFC837', // 限制人工驾驶模式
NRM = '0xA0522D', // 非限制人工驾驶模式
RM = '0xC2C2C2', // 限制人工驾驶模式
NRM = '0xFF0000', // 非限制人工驾驶模式
red = '0xF80103', // 红色表示通信中断
}
enum AAColorEnum { // 识别号AA颜色
accuracy = '0xffffff', // 准点
early = '0x00FF00', // 早点
late = '0xA0522D', // 晚点
}
enum typeColorEnum { // 识别号BBB颜色
accuracy = '0x11EF3D', // 准点
early = '0x82F6FF', // 早点
late = '0xE00D02', // 晚点
schedule = '0xffffff', // 计划车
head = '0xE9FC01', // 头码车
manual = '0xE9FC01', // 人工车
special = '0xE9FC01', // 特殊车
head = '0xffffff', // 头码车
manual = '0xffffff', // 人工车
special = '0xFFFF73', // 特殊车
}
enum statusTextColor {
H = '0xFFFF00', // H扣车
S = '0x6260F3', // S跳停
D = '0x00FF00', // D开门
A = '0xFF0000', // A报警
= '0xFFFF00', // H扣车
= '0x00CCFF', // S跳停
= '0x00FF00', // D开门
= '0xDA0000', // A报警
'>>' = '0xFFFF00', // 列车重叠,点击可切换列车
}
export const trainConsts = {
@ -110,10 +115,10 @@ export const trainConsts = {
borderWidth: 1,
codeFontSize: 22,
textFontSize: 16, // 状态字母大小
textMarginY: 10, // 状态字母与列车距离
statusTextList: ['H', 'S', 'D', 'A'],
textMarginY: 5, // 状态字母与列车距离
statusTextList: ['扣', '跳', '门', '警', '>>'],
marginX: 2, // 图形x轴边距
pauseW: 2, // 停止框宽度
pauseW: 4, // 停止框宽度
};
export class TrainHead extends Container {
@ -132,10 +137,10 @@ export class TrainHead extends Container {
}
doRepaint(states: ITrainState, bodyWH?: bodyWH) {
let direction = '';
if (states.mode?.ipModeTrainDirUp) {
if (states.mode?.ipModeTrainDirDown) {
direction = 'left';
}
if (states.mode?.ipModeTrainDirDown) {
if (states.mode?.ipModeTrainDirUp) {
direction = 'right';
}
this.clear();
@ -180,22 +185,34 @@ export class TrainHead extends Container {
});
pausePoint = pP;
}
const arrow = this.arrow;
arrow.beginFill(TrainColorEnum.headColor, 1);
arrow.drawPolygon(arrowPoint);
arrow.endFill();
this.pause.lineStyle(pauseW, TrainColorEnum.headColor, 1);
let aColor = DiriveModelColorEnum.AM;
let pColor = DiriveModelColorEnum.AM;
if (
states.mode?.ipModeTrainDriveModeCm ||
states.mode?.ipModeTrainDriveBlockCm
) {
aColor = DiriveModelColorEnum.SM;
pColor = DiriveModelColorEnum.SM;
} else if (
states.mode?.ipModeTrainDriveModeRmf ||
states.mode?.ipModeTrainDriveModeRmr
) {
aColor = DiriveModelColorEnum.RM;
pColor = DiriveModelColorEnum.RM;
}
this.pause.lineStyle(pauseW, pColor, 1);
this.pause.moveTo(pausePoint[0], pausePoint[1]);
this.pause.lineTo(pausePoint[2], pausePoint[3]);
}
stop() {
this.pause.visible = true;
const arrow = this.arrow;
arrow.beginFill(aColor, 1);
arrow.drawPolygon(arrowPoint);
arrow.endFill();
if (states.mode?.ipModeTrainStoped) {
this.arrow.visible = false;
}
run() {
this.pause.visible = false;
} else {
this.arrow.visible = true;
}
}
}
export class TrainBody extends Container {
@ -228,28 +245,33 @@ export class TrainBody extends Container {
const codeAGraph = this.codeAGraph;
const codeBGraph = this.codeBGraph;
const codeRact = this.codeRact;
let codeA = states?.trainId;
let fillAColor = AAColorEnum.accuracy;
if (states.mode?.ipModeTrainTypeSchedule) {
if (states?.otpTime > 0) {
fillAColor = AAColorEnum.late;
} else if (states?.otpTime < 0) {
fillAColor = AAColorEnum.early;
}
}
const codeA = states?.groupId;
let codeB = states?.destinationId ? states?.destinationId + '' : '';
const fillAColor = typeColorEnum.schedule;
let fillBColor = typeColorEnum.schedule;
if (states.mode?.ipModeTrainTypeHead) {
codeA = states?.destinationId + '';
fillBColor = typeColorEnum.head;
} else if (states.mode?.ipModeTrainTypeManual) {
codeA = 'MM';
fillBColor = typeColorEnum.manual;
} else if (states.mode?.ipModeTrainTypeSpecial) {
codeA = '';
if (states.mode?.ipModeTrainTypeSchedule) {
fillBColor = typeColorEnum.accuracy;
if (states.mode?.ipModeTrainSchdLate) {
fillBColor = typeColorEnum.late;
} else if (states.mode?.ipModeTrainSchdEarly) {
fillBColor = typeColorEnum.early;
}
} else if (states.mode?.ipModeTrainTypeHead) {
codeB = states?.destinationId ? states?.destinationId + '' : '';
} else if (states.mode?.ipModeTrainTypeManual) {
codeB = '---';
} else if (states.mode?.ipModeTrainTypeSpecial) {
codeB = 'MM';
}
let bgColor = TrainColorEnum.ITCbodyColor;
if (
states.mode?.ipModeTrainDriveModeAm ||
states.mode?.ipModeTrainDriveModeCm
) {
bgColor = TrainColorEnum.bodyColor;
}
const codeB = states?.globalId;
codeAGraph.text = codeA || '01';
codeBGraph.text = codeB || '2222';
codeBGraph.text = codeB || '222';
codeAGraph.anchor.set(0.5);
codeBGraph.anchor.set(0.5);
const styleA = {
@ -273,7 +295,7 @@ export class TrainBody extends Container {
trainConsts.borderWidth,
new Color(TrainColorEnum.borderColor)
);
codeRact.beginFill(new Color(TrainColorEnum.bodyColor));
codeRact.beginFill(new Color(bgColor));
codeRact.drawRect(-codeWidth / 2, -codeHeight / 2, codeWidth, codeHeight);
codeRact.endFill();
}
@ -288,7 +310,7 @@ class StatusText extends Container {
doRepaint(text: string, bodyWH: bodyWH): void {
this.sText.text = text;
this.sText.anchor.set(0.5);
const c = (statusTextColor as never)[text] || statusTextColor.D;
const c = (statusTextColor as never)[text] || statusTextColor.;
const style = {
fill: c,
fontSize: trainConsts.textFontSize,
@ -302,7 +324,7 @@ class StatusText extends Container {
return item == text;
});
if (index < 0) {
index = 1.5; // 中间
index = (num - 1) / 2; // 中间
}
const textMargin = (codeWidth - textHWidth * num) / (num - 1);
this.sText.position.set(
@ -337,17 +359,34 @@ export class Train extends JlGraphic {
return this.getStates<ITrainState>();
}
get code(): string {
return this.states.code;
}
doRepaint(): void {
this.trainbody.doRepaint(this.states);
const bodyWH = this.trainbody.getBodyWH();
this.trainHead.doRepaint(this.states, bodyWH);
if (this.states.mode?.ipModeTrainHolded) {
this.showStatus('扣');
} else {
this.hideStatus('扣');
}
stop() {
this.trainHead.stop();
if (this.states.mode?.ipModeTrainSkipstop) {
this.showStatus('跳');
} else {
this.hideStatus('跳');
}
if (this.states.mode?.ipModeTrainDoorOpen) {
this.showStatus('门');
} else {
this.hideStatus('门');
}
if (this.states.mode?.ipModeTrainRsAlarm) {
this.showStatus('警');
} else {
this.hideStatus('警');
}
run() {
this.trainHead.run();
}
showStatus(s: string) {
@ -370,22 +409,6 @@ export class Train extends JlGraphic {
this.statusTextMap.delete(s);
}
}
chagneDirection(): void {
const bodyWH = this.trainbody.getBodyWH();
this.trainHead.doRepaint(this.states, bodyWH);
}
chagneState(): void {
if (this.states.mode?.ipModeTrainHolded) {
this.showStatus('H');
} else {
this.hideStatus('H');
}
if (this.states.mode?.ipModeTrainDoorOpen) {
this.showStatus('D');
} else {
this.hideStatus('D');
}
}
}
export class TrainTemplate extends JlGraphicTemplate<Train> {
@ -394,7 +417,7 @@ export class TrainTemplate extends JlGraphicTemplate<Train> {
}
new(): Train {
const train = new Train();
train.loadData(this.datas);
train.id = GraphicIdGenerator.next();
train.loadState(this.states);
return train;
}

View File

@ -37,6 +37,9 @@
>
<q-item-section>一键生成计轴区段</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="oneClickLogicSection">
<q-item-section>一键生成逻辑区段</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
@ -201,10 +204,13 @@ import { Separator } from 'src/graphics/separator/Separator';
import { SeparatorDraw } from 'src/graphics/separator/SeparatorDrawAssistant';
import { SectionLink } from 'src/graphics/sectionLink/SectionLink';
import { SectionLinkDraw } from 'src/graphics/sectionLink/SectionLinkDrawAssistant';
import { store } from 'quasar/wrappers';
import { AxleCountingSection } from 'src/graphics/axleCountingSection/AxleCountingSection';
import { AxleCountingSectionDraw } from 'src/graphics/axleCountingSection/AxleCountingSectionAssistant';
import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
import { Section } from 'src/graphics/section/Section';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { LogicSectionDraw } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
const route = useRoute();
const router = useRouter();
@ -354,8 +360,19 @@ function oneClickAxleCountingSection() {
.getDrawAssistant(AxleCountingSection.Type) as AxleCountingSectionDraw;
axleCountingSectionDraw.oneGenerates();
}
function oneClickLogicSection() {
//
const logicSectionDraw = drawStore
.getDrawApp()
.getDrawAssistant(LogicSection.Type) as LogicSectionDraw;
logicSectionDraw.oneGenerates();
}
function oneClickLink() {
drawStore.oneClickType = 'SectionLink';
const linkList = drawStore
.getDrawApp()
.queryStore.queryByType(SectionLink.Type);
drawStore.getDrawApp().deleteGraphics(...linkList);
const draw = drawStore
.getDrawApp()
.getDrawAssistant<SectionLinkDraw>(SectionLink.Type);