Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f2c40f2a78 | ||
|
c8eef1fb1c | ||
|
b25fee816a | ||
|
c4cb584853 | ||
|
224f8975f8 | ||
|
5488cbea12 | ||
|
bc0017057c | ||
|
8076e0bd6d | ||
|
e10f41ce32 |
@ -23,7 +23,8 @@
|
||||
"centrifuge": "^4.0.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"google-protobuf": "^3.21.2",
|
||||
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.3",
|
||||
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.8",
|
||||
"rt-graphic-component": "git+https://git.code.tencent.com/jl-framework/rt-graphic-component.git#5eecd80",
|
||||
"js-base64": "^3.7.5",
|
||||
"pinia": "^2.0.11",
|
||||
"quasar": "^2.6.0",
|
||||
|
@ -95,9 +95,9 @@ const stationName = computed(() => {
|
||||
});
|
||||
const sectionName = computed(() => {
|
||||
const platform = drawStore.selectedGraphic as Platform;
|
||||
if (platformModel.refSectionId) {
|
||||
if (platformModel.refSection) {
|
||||
const refSection = platform.queryStore.queryById<Section>(
|
||||
platformModel.refSectionId
|
||||
platformModel.refSection
|
||||
);
|
||||
return refSection.datas.code;
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ export class PlatformData extends GraphicDataBase implements IPlatformData {
|
||||
set refStation(v: number) {
|
||||
this.data.refStation = v;
|
||||
}
|
||||
get refSectionId(): number {
|
||||
get refSection(): number {
|
||||
return this.data.refSectionId;
|
||||
}
|
||||
set refSectionId(v: number) {
|
||||
set refSection(v: number) {
|
||||
this.data.refSectionId = v;
|
||||
}
|
||||
get centralizedStation(): number {
|
||||
|
@ -33,12 +33,19 @@ import { ConcentrationDividingLineDraw } from 'src/graphics/concentrationDividin
|
||||
import { Rect, RectTemplate } from 'src/graphics/rect/Rect';
|
||||
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
|
||||
import { RectData } from './graphics/RectInteraction';
|
||||
import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform';
|
||||
import {
|
||||
Platform,
|
||||
PlatformDraw,
|
||||
PlatformTemplate,
|
||||
} from 'src/graphics/platform/Platform';
|
||||
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
|
||||
import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant';
|
||||
import { Station, StationTemplate } from 'src/graphics/station/Station';
|
||||
import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
|
||||
import {
|
||||
Station,
|
||||
StationDraw,
|
||||
StationTemplate,
|
||||
} from 'src/graphics/station/Station';
|
||||
import { StationData, StationState } from './graphics/StationInteraction';
|
||||
import { StyleType } from 'rt-graphic-component/components/common/common';
|
||||
import {
|
||||
StationLine,
|
||||
StationLineTemplate,
|
||||
@ -67,8 +74,11 @@ import {
|
||||
} from 'src/graphics/axleCounting/AxleCounting';
|
||||
import { AxleCountingDraw } from 'src/graphics/axleCounting/AxleCountingDrawAssistant';
|
||||
import { AxleCountingData } from './graphics/AxleCountingInteraction';
|
||||
import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout';
|
||||
import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant';
|
||||
import {
|
||||
Turnout,
|
||||
TurnoutTemplate,
|
||||
TurnoutDraw,
|
||||
} from 'src/graphics/turnout/Turnout';
|
||||
import { TurnoutData, TurnoutStates } from './graphics/TurnoutInteraction';
|
||||
import { RunLine, RunLineTemplate } from 'src/graphics/runLine/RunLine';
|
||||
import { RunLineDraw } from 'src/graphics/runLine/RunLineDrawAssistant';
|
||||
@ -84,7 +94,8 @@ import { PathLineDraw } from 'src/graphics/pathLine/PathLineDrawAssistant';
|
||||
import { PathLineData } from './graphics/PathLineInteraction';
|
||||
import { toStorageTransform } from './graphics/GraphicDataBase';
|
||||
import { SeparatorDraw } from 'src/graphics/separator/SeparatorDrawAssistant';
|
||||
import { Separator, SeparatorTemplate } from 'src/graphics/separator/Separator';
|
||||
import { Separator } from 'src/graphics/separator/Separator';
|
||||
import { SeparatorTemplate } from 'rt-graphic-component/components/packages/Separator/Separator';
|
||||
import { SeparatorData } from './graphics/SeparatorInteraction';
|
||||
import { LogicSectionDraw } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
|
||||
import {
|
||||
@ -188,7 +199,7 @@ function constructMenu(app: IDrawApp): (e: FederatedMouseEvent) => void {
|
||||
const jumpStaitonItems: MenuItemOptions[] = [];
|
||||
stations.forEach((station) => {
|
||||
const item: MenuItemOptions = {
|
||||
name: station.datas.name,
|
||||
name: station.datas.name as string,
|
||||
handler: () => {
|
||||
app.makeGraphicCenterShow(station);
|
||||
},
|
||||
@ -233,11 +244,21 @@ export function initDrawApp(): IDrawApp {
|
||||
if (draftType === 'Line') {
|
||||
new PlatformDraw(
|
||||
app,
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState())
|
||||
new PlatformTemplate(
|
||||
new PlatformData(),
|
||||
new PlatformState(),
|
||||
StyleType.TH
|
||||
),
|
||||
'svguse:../../drawIcon.svg#icon-platform'
|
||||
),
|
||||
new StationDraw(
|
||||
app,
|
||||
new StationTemplate(new StationData(), new StationState())
|
||||
new StationTemplate(
|
||||
new StationData(),
|
||||
new StationState(),
|
||||
StyleType.TH
|
||||
),
|
||||
'svguse:../../drawIcon.svg#icon-station'
|
||||
),
|
||||
new SignalDraw(
|
||||
app,
|
||||
@ -254,7 +275,11 @@ export function initDrawApp(): IDrawApp {
|
||||
),
|
||||
new TurnoutDraw(
|
||||
app,
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates())
|
||||
new TurnoutTemplate(
|
||||
new TurnoutData(),
|
||||
new TurnoutStates(),
|
||||
StyleType.TH
|
||||
)
|
||||
),
|
||||
new TrainWindowDraw(app, new TrainWindowTemplate(new TrainWindowData())),
|
||||
new OneClickGenerateDraw(app, new OneClickGenerateTemplate()),
|
||||
@ -262,7 +287,12 @@ export function initDrawApp(): IDrawApp {
|
||||
app,
|
||||
new AxleCountingTemplate(new AxleCountingData())
|
||||
),
|
||||
new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData())),
|
||||
new SeparatorDraw(
|
||||
app,
|
||||
new SeparatorTemplate(new SeparatorData(), {
|
||||
lineColor: '0x617799',
|
||||
})
|
||||
),
|
||||
new ConcentrationDividingLineDraw(
|
||||
app,
|
||||
new ConcentrationDividingLineTemplate(
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
PlatformOperateInteraction,
|
||||
PlatformState,
|
||||
} from './graphics/PlatformInteraction';
|
||||
import { PlatformTemplate, Platform } from 'src/graphics/platform/Platform';
|
||||
import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform';
|
||||
import {
|
||||
StationData,
|
||||
StationOperateInteraction,
|
||||
@ -58,7 +58,7 @@ import {
|
||||
TrainWindowTemplate,
|
||||
} from 'src/graphics/trainWindow/TrainWindow';
|
||||
import { TrainWindowData } from './graphics/TrainWindowInteraction';
|
||||
import { SeparatorTemplate } from 'src/graphics/separator/Separator';
|
||||
import { SeparatorTemplate } from 'rt-graphic-component/components/packages/Separator/Separator';
|
||||
import { SeparatorData } from './graphics/SeparatorInteraction';
|
||||
import { ContextMenu, MenuItemOptions } from 'jl-graphic';
|
||||
import {
|
||||
@ -73,6 +73,7 @@ import {
|
||||
import { Notify, QNotifyUpdateOptions } from 'quasar';
|
||||
import { useLineNetStore } from 'src/stores/line-net-store';
|
||||
import { alert } from 'src/protos/alertInfo';
|
||||
import { StyleType } from 'rt-graphic-component/components/common/common';
|
||||
|
||||
let lineApp: IGraphicApp | null = null;
|
||||
|
||||
@ -111,12 +112,14 @@ export function initLineApp(): IGraphicApp {
|
||||
const graphicTemplate = [
|
||||
new TrainTemplate(new TrainData(), new TrainState()),
|
||||
new SignalTemplate(new SignalData(), new SignalState()),
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState()),
|
||||
new StationTemplate(new StationData(), new StationState()),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState(), StyleType.TH),
|
||||
new StationTemplate(new StationData(), new StationState(), StyleType.TH),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.TH),
|
||||
new SectionTemplate(new SectionData()),
|
||||
new LogicSectionTemplate(new LogicSectionData(), new LogicSectionState()),
|
||||
new SeparatorTemplate(new SeparatorData()),
|
||||
new SeparatorTemplate(new SeparatorData(), {
|
||||
lineColor: '0x617799',
|
||||
}),
|
||||
new AxleCountingTemplate(new AxleCountingData()),
|
||||
new TrainWindowTemplate(new TrainWindowData()),
|
||||
];
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
LogicSectionData,
|
||||
LogicSectionState,
|
||||
} from './graphics/LogicSectionInteraction';
|
||||
import { SeparatorTemplate } from 'src/graphics/separator/Separator';
|
||||
import { SeparatorTemplate } from 'rt-graphic-component/components/packages/Separator/Separator';
|
||||
import { AxleCountingTemplate } from 'src/graphics/axleCounting/AxleCounting';
|
||||
import { SignalData, SignalState } from './graphics/SignalInteraction';
|
||||
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
|
||||
@ -32,6 +32,7 @@ import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
|
||||
import { useRangeConfigStore } from 'src/stores/range-config-store';
|
||||
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||
import { toUint8Array } from 'js-base64';
|
||||
import { StyleType } from 'rt-graphic-component/components/common/common';
|
||||
|
||||
let rangeConfigApp: IGraphicApp;
|
||||
|
||||
@ -57,9 +58,9 @@ export function initRangeConfigApp(lineId: number) {
|
||||
});
|
||||
const graphicTemplate = [
|
||||
new SignalTemplate(new SignalData(), new SignalState()),
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState()),
|
||||
new StationTemplate(new StationData(), new StationState()),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState(), StyleType.TH),
|
||||
new StationTemplate(new StationData(), new StationState(), StyleType.TH),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.TH),
|
||||
new SectionTemplate(new SectionData()),
|
||||
new LogicSectionTemplate(new LogicSectionData(), new LogicSectionState()),
|
||||
new SeparatorTemplate(new SeparatorData()),
|
||||
|
@ -1,116 +1,9 @@
|
||||
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';
|
||||
AxleCounting,
|
||||
IAxleCountingData,
|
||||
AxleCountingTemplate,
|
||||
AxleCountingConsts,
|
||||
} from 'rt-graphic-component/components/packages/AxleCounting/AxleCounting';
|
||||
|
||||
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[]);
|
||||
clone(): IAxleCountingData;
|
||||
copyFrom(data: IAxleCountingData): void;
|
||||
eq(other: IAxleCountingData): boolean;
|
||||
}
|
||||
|
||||
export const AxleCountingConsts = {
|
||||
radius: 6,
|
||||
borderWidth: 1,
|
||||
circleColorBlue: '0x08F80D',
|
||||
codeColor: '0xF48815',
|
||||
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(): void {
|
||||
this.drawCircle(this.circleA);
|
||||
this.drawCircle(this.circleB);
|
||||
this.circleA.position.set(-12, 0);
|
||||
this.circleB.position.set(12, 0);
|
||||
this.line.clear();
|
||||
this.line.lineStyle(1, new Color(AxleCountingConsts.circleColorBlue));
|
||||
this.line.moveTo(-24, 0);
|
||||
this.line.lineTo(24, 0);
|
||||
}
|
||||
drawCircle(circle: Graphics): void {
|
||||
circle.clear();
|
||||
circle.lineStyle(
|
||||
AxleCountingConsts.borderWidth,
|
||||
new Color(AxleCountingConsts.circleColorBlue)
|
||||
);
|
||||
circle.beginFill(AxleCountingConsts.circleColorBlue, 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 datas(): IAxleCountingData {
|
||||
return this.getDatas<IAxleCountingData>();
|
||||
}
|
||||
doRepaint(): void {
|
||||
this.twoCircle.draw();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
export { AxleCounting, AxleCountingTemplate, AxleCountingConsts };
|
||||
export type { IAxleCountingData };
|
||||
|
@ -112,14 +112,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
|
||||
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 - AxleCountingConsts.offsetSection * direction
|
||||
);
|
||||
}
|
||||
axleCounting.id = GraphicIdGenerator.next();
|
||||
axleCounting.datas.axleCountingRef = [refData2, refData1];
|
||||
axleCounting.datas.code = `${graphic.datas.code}-${port}+${refGraphic.datas.code}-${refPort}`;
|
||||
@ -139,14 +132,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
|
||||
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 - AxleCountingConsts.offsetSection * direction
|
||||
);
|
||||
}
|
||||
axleCounting.id = GraphicIdGenerator.next();
|
||||
axleCounting.datas.axleCountingRef = [refData];
|
||||
axleCounting.datas.code = `${graphic.datas.code}-${port}`;
|
||||
@ -362,21 +348,12 @@ export class AxleCountingInteraction extends GraphicInteractionPlugin<AxleCounti
|
||||
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 {
|
||||
|
@ -1,487 +1,8 @@
|
||||
import { Color, Container, Graphics, Point, Rectangle } from 'pixi.js';
|
||||
import {
|
||||
GraphicData,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
VectorText,
|
||||
calculateMirrorPoint,
|
||||
distance2,
|
||||
getRectangleCenter,
|
||||
} from 'jl-graphic';
|
||||
import { Station } from '../station/Station';
|
||||
import { Section } from '../section/Section';
|
||||
import { THPlatform as Platform } from 'rt-graphic-component/components/packages/Platform/THPlatform';
|
||||
import { IPlatformData } from 'rt-graphic-component/components/packages/Platform/common/PlatformConfig';
|
||||
import { PlatformTemplate } from 'rt-graphic-component/components/packages/Platform/common/PlatformTemplate';
|
||||
import { ITHPlatformState as IPlatformState } from 'rt-graphic-component/components/packages/Platform/THPlatform';
|
||||
import { PlatformDraw } from 'rt-graphic-component/components/packages/Platform/common/PlatformDrawAssistant';
|
||||
|
||||
export interface IPlatformData extends GraphicData {
|
||||
get code(): string; // 编号
|
||||
set code(v: string);
|
||||
get hasdoor(): boolean; // 是否有屏蔽门
|
||||
set hasdoor(v: boolean);
|
||||
get direction(): string; // 屏蔽门上下
|
||||
set direction(v: string);
|
||||
get up(): boolean; // 站台上下行
|
||||
set up(v: boolean);
|
||||
get refStation(): number; // 关联的车站
|
||||
set refStation(v: number);
|
||||
get refSectionId(): number; // 关联的物理区段
|
||||
set refSectionId(v: number);
|
||||
get centralizedStation(): number; //所属集中站
|
||||
set centralizedStation(v: number);
|
||||
clone(): IPlatformData;
|
||||
copyFrom(data: IPlatformData): void;
|
||||
eq(other: IPlatformData): boolean;
|
||||
}
|
||||
export interface IPlatformState extends GraphicState {
|
||||
get emergstop(): boolean; //紧急关闭
|
||||
set emergstop(v: boolean);
|
||||
get trainberth(): boolean; //列车停站
|
||||
set trainberth(v: boolean);
|
||||
get close(): boolean; //站台关闭,清客
|
||||
set close(v: boolean);
|
||||
get upHold(): boolean; //上行方向车站扣车
|
||||
set upHold(v: boolean);
|
||||
get downHold(): boolean; //下行方向车站扣车
|
||||
set downHold(v: boolean);
|
||||
get upOccHold(): boolean; //上行方向中心扣车
|
||||
set upOccHold(v: boolean);
|
||||
get downOccHold(): boolean; //下行方向中心扣车
|
||||
set downOccHold(v: boolean);
|
||||
get psdOpen(): boolean; //屏蔽门开
|
||||
set psdOpen(v: boolean);
|
||||
get psdCut(): boolean; //屏蔽门切除
|
||||
set psdCut(v: boolean);
|
||||
get upSkipstop(): boolean; //上行方向跳停
|
||||
set upSkipstop(v: boolean);
|
||||
get downSkipstop(): boolean; //下行方向跳停
|
||||
set downSkipstop(v: boolean);
|
||||
get upTrainSkipstop(): boolean; //上行方向指定列车跳停
|
||||
set upTrainSkipstop(v: boolean);
|
||||
get downTrainSkipstop(): boolean; //下行方向指定列车跳停
|
||||
set downTrainSkipstop(v: boolean);
|
||||
get nextSectionRunTime(): number; //下一区间运行时间
|
||||
set nextSectionRunTime(v: number);
|
||||
get nextSectionRunLevel(): number; //下一区间运行等级
|
||||
set nextSectionRunLevel(v: number);
|
||||
get stopTime(): number; //停站时间
|
||||
set stopTime(v: number);
|
||||
get rtuId(): number; // 集中站站号
|
||||
set rtuId(v: number);
|
||||
}
|
||||
|
||||
//站台颜色
|
||||
export enum PlatformColorEnum {
|
||||
grey = '0x7F7F7F', //站台没有列车停站
|
||||
yellow = '0xfbff00', //列车在站台停站
|
||||
blue = '0xC0C0FE', //列车在站台跳停
|
||||
lozengeRed = '0xff0000', //站台旁的菱形图标
|
||||
whiteNumbers = '0xffffff', //站台旁白色数字
|
||||
whiteCircle = '0xffffff', //H字符旁的圆圈
|
||||
HCharYellow = '0xfbff00', //站台旁的H字符
|
||||
HCharWhite = '0xffffff',
|
||||
HCharRed = '0xff0000',
|
||||
doorGreen = '0x00FF00', //屏蔽门的颜色
|
||||
doorRed = '0xff0000',
|
||||
doorBlue = '0x4048C4',
|
||||
blueShowColor = '0x3149c3',
|
||||
}
|
||||
|
||||
const platformConsts = {
|
||||
width: 90,
|
||||
height: 20,
|
||||
lineWidth: 3,
|
||||
besideFontSize: 12,
|
||||
doorOpenSpacing: 15,
|
||||
doorPlatformSpacing: 10,
|
||||
besideSpacing: 10,
|
||||
circleRadius: 1,
|
||||
};
|
||||
|
||||
//子元素--矩形
|
||||
export class rectGraphic extends Container {
|
||||
static Type = 'RectPlatForm';
|
||||
rectGraphic: Graphics;
|
||||
constructor() {
|
||||
super();
|
||||
this.rectGraphic = new Graphics();
|
||||
this.addChild(this.rectGraphic);
|
||||
}
|
||||
draw(state: IPlatformState): void {
|
||||
const rectGraphic = this.rectGraphic;
|
||||
rectGraphic.clear();
|
||||
let fillColor = PlatformColorEnum.grey;
|
||||
if (state.trainberth) {
|
||||
fillColor = PlatformColorEnum.yellow;
|
||||
}
|
||||
if (state.upSkipstop || state.downSkipstop) {
|
||||
fillColor = PlatformColorEnum.blue;
|
||||
}
|
||||
rectGraphic.lineStyle(platformConsts.lineWidth, new Color(fillColor));
|
||||
rectGraphic.beginFill(fillColor, 1);
|
||||
rectGraphic.drawRect(0, 0, platformConsts.width, platformConsts.height);
|
||||
rectGraphic.endFill;
|
||||
const rectP = new Rectangle(
|
||||
0,
|
||||
0,
|
||||
platformConsts.width,
|
||||
platformConsts.height
|
||||
);
|
||||
rectGraphic.pivot = getRectangleCenter(rectP);
|
||||
}
|
||||
clear(): void {
|
||||
this.rectGraphic.clear();
|
||||
}
|
||||
}
|
||||
//子元素--门
|
||||
export class doorGraphic extends Container {
|
||||
static Type = 'Door';
|
||||
doorGraphic: Graphics;
|
||||
doorCloseGraphic: Graphics;
|
||||
constructor() {
|
||||
super();
|
||||
this.doorGraphic = new Graphics();
|
||||
this.doorCloseGraphic = new Graphics();
|
||||
this.addChild(this.doorGraphic);
|
||||
this.addChild(this.doorCloseGraphic);
|
||||
}
|
||||
draw(stateData: IPlatformState, ipRtuStusDown: boolean): void {
|
||||
const doorGraphic = this.doorGraphic;
|
||||
const doorCloseGraphic = this.doorCloseGraphic;
|
||||
doorGraphic.clear();
|
||||
doorCloseGraphic.clear();
|
||||
let lineColor = PlatformColorEnum.doorGreen;
|
||||
if (ipRtuStusDown) {
|
||||
lineColor = PlatformColorEnum.blueShowColor;
|
||||
} else if (stateData.psdCut) {
|
||||
lineColor = PlatformColorEnum.doorRed;
|
||||
}
|
||||
doorGraphic.lineStyle(platformConsts.lineWidth, new Color(lineColor));
|
||||
doorGraphic.moveTo(
|
||||
-platformConsts.width / 2 - platformConsts.lineWidth / 2,
|
||||
0
|
||||
);
|
||||
doorGraphic.lineTo(-platformConsts.doorOpenSpacing, 0);
|
||||
doorGraphic.moveTo(platformConsts.doorOpenSpacing, 0);
|
||||
doorGraphic.lineTo(
|
||||
platformConsts.width / 2 + platformConsts.lineWidth / 2,
|
||||
0
|
||||
);
|
||||
//屏蔽门闭合
|
||||
doorCloseGraphic.lineStyle(platformConsts.lineWidth, new Color(lineColor));
|
||||
doorCloseGraphic.moveTo(-platformConsts.doorOpenSpacing, 0);
|
||||
doorCloseGraphic.lineTo(platformConsts.doorOpenSpacing, 0);
|
||||
}
|
||||
clear(): void {
|
||||
this.doorGraphic.clear();
|
||||
this.doorCloseGraphic.clear();
|
||||
}
|
||||
changeState(stateData: IPlatformState): void {
|
||||
if (stateData.psdOpen) {
|
||||
this.doorCloseGraphic.visible = false;
|
||||
} else {
|
||||
this.doorCloseGraphic.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//子元素--字符
|
||||
class codeGraph extends Container {
|
||||
static Type = 'Code';
|
||||
character: VectorText = new VectorText(''); //扣车H
|
||||
runLevel: VectorText = new VectorText(''); //运行等级
|
||||
runTime: VectorText = new VectorText(''); //运行时间
|
||||
stopTime: VectorText = new VectorText(''); //停站时间
|
||||
circle: Graphics = new Graphics();
|
||||
constructor() {
|
||||
super();
|
||||
this.addChild(this.character);
|
||||
this.addChild(this.runLevel);
|
||||
this.addChild(this.circle);
|
||||
this.addChild(this.stopTime);
|
||||
this.addChild(this.runTime);
|
||||
this.character.setVectorFontSize(platformConsts.besideFontSize);
|
||||
this.runLevel.setVectorFontSize(platformConsts.besideFontSize);
|
||||
this.stopTime.setVectorFontSize(platformConsts.besideFontSize);
|
||||
this.runTime.setVectorFontSize(platformConsts.besideFontSize);
|
||||
}
|
||||
draw(): void {
|
||||
//扣车
|
||||
const character = this.character;
|
||||
character.text = 'H';
|
||||
character.anchor.set(0.5);
|
||||
character.position.set(
|
||||
-platformConsts.width / 2 -
|
||||
platformConsts.lineWidth / 2 -
|
||||
(platformConsts.besideSpacing * 2) / 3,
|
||||
(platformConsts.height * 3) / 4
|
||||
);
|
||||
character.style.fill = PlatformColorEnum.whiteNumbers;
|
||||
const circle = this.circle;
|
||||
circle.clear();
|
||||
circle.lineStyle(0.5, PlatformColorEnum.whiteCircle);
|
||||
circle.drawCircle(0, 0, platformConsts.circleRadius);
|
||||
circle.position.set(
|
||||
-platformConsts.width / 2 -
|
||||
platformConsts.lineWidth / 2 -
|
||||
(platformConsts.besideSpacing * 4) / 3,
|
||||
(platformConsts.height * 3) / 5
|
||||
);
|
||||
//区间运行等级状态
|
||||
const runLevel = this.runLevel;
|
||||
runLevel.anchor.set(0.5);
|
||||
runLevel.position.set(
|
||||
platformConsts.width / 2 +
|
||||
platformConsts.lineWidth / 2 +
|
||||
3 * platformConsts.besideSpacing,
|
||||
-platformConsts.besideSpacing
|
||||
);
|
||||
runLevel.style.fill = PlatformColorEnum.whiteNumbers;
|
||||
//区间运行时间
|
||||
const runTime = this.runTime;
|
||||
runTime.anchor.set(0.5);
|
||||
runTime.position.set(
|
||||
platformConsts.width / 2 +
|
||||
platformConsts.lineWidth / 2 +
|
||||
platformConsts.besideSpacing,
|
||||
-platformConsts.besideSpacing
|
||||
);
|
||||
runTime.style.fill = PlatformColorEnum.whiteNumbers;
|
||||
//停站时间
|
||||
const stopTime = this.stopTime;
|
||||
stopTime.anchor.set(0.5);
|
||||
stopTime.position.set(
|
||||
platformConsts.width / 2 +
|
||||
platformConsts.lineWidth / 2 +
|
||||
platformConsts.besideSpacing,
|
||||
platformConsts.besideSpacing
|
||||
);
|
||||
stopTime.style.fill = PlatformColorEnum.whiteNumbers;
|
||||
character.visible = false;
|
||||
circle.visible = false;
|
||||
runLevel.visible = false;
|
||||
stopTime.visible = false;
|
||||
runTime.visible = false;
|
||||
}
|
||||
clear(): void {
|
||||
this.character.destroy();
|
||||
}
|
||||
changeState(stateData: IPlatformState): void {
|
||||
if (
|
||||
stateData.upHold ||
|
||||
stateData.upOccHold ||
|
||||
stateData.downHold ||
|
||||
stateData.downOccHold
|
||||
) {
|
||||
this.character.text = 'H';
|
||||
this.character.visible = true;
|
||||
this.circle.visible = true;
|
||||
//上行扣车
|
||||
if (stateData.upHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharYellow;
|
||||
}
|
||||
if (stateData.upOccHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharWhite;
|
||||
}
|
||||
if (stateData.upHold && stateData.upOccHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharRed;
|
||||
}
|
||||
//下行扣车
|
||||
if (stateData.downHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharYellow;
|
||||
}
|
||||
if (stateData.downOccHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharWhite;
|
||||
}
|
||||
if (stateData.downHold && stateData.downOccHold) {
|
||||
this.character.style.fill = PlatformColorEnum.HCharRed;
|
||||
}
|
||||
}
|
||||
//运行等级
|
||||
if (stateData.nextSectionRunLevel) {
|
||||
this.runLevel.visible = false;
|
||||
this.runLevel.text = stateData.nextSectionRunLevel;
|
||||
}
|
||||
//运行时间
|
||||
if (stateData.nextSectionRunTime) {
|
||||
this.runTime.visible = true;
|
||||
this.runTime.text = stateData.nextSectionRunTime;
|
||||
}
|
||||
//停站时间
|
||||
if (stateData.stopTime) {
|
||||
this.stopTime.visible = true;
|
||||
this.stopTime.text = stateData.stopTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
//子元素--站台旁菱形图标
|
||||
class besideGraphic extends Container {
|
||||
static Type = 'BesideGraphic';
|
||||
besideGraphic: Graphics;
|
||||
constructor() {
|
||||
super();
|
||||
this.besideGraphic = new Graphics();
|
||||
this.addChild(this.besideGraphic);
|
||||
}
|
||||
draw(): void {
|
||||
const besideGraphic = this.besideGraphic;
|
||||
besideGraphic.clear();
|
||||
besideGraphic.lineStyle(1, new Color(PlatformColorEnum.lozengeRed));
|
||||
besideGraphic.beginFill(PlatformColorEnum.lozengeRed, 1);
|
||||
besideGraphic.drawRect(
|
||||
0,
|
||||
0,
|
||||
platformConsts.height / 4,
|
||||
platformConsts.height / 4
|
||||
);
|
||||
besideGraphic.endFill();
|
||||
const rect = new Rectangle(
|
||||
0,
|
||||
0,
|
||||
platformConsts.height / 4,
|
||||
platformConsts.height / 4
|
||||
);
|
||||
besideGraphic.pivot = getRectangleCenter(rect);
|
||||
besideGraphic.rotation = Math.PI / 4;
|
||||
besideGraphic.visible = false;
|
||||
}
|
||||
clear(): void {
|
||||
this.besideGraphic.clear();
|
||||
}
|
||||
changeState(stateData: IPlatformState): void {
|
||||
if (stateData.emergstop) {
|
||||
this.besideGraphic.visible = true;
|
||||
} else {
|
||||
this.besideGraphic.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Platform extends JlGraphic {
|
||||
static Type = 'Platform';
|
||||
platformGraphic: rectGraphic = new rectGraphic();
|
||||
doorGraphic: doorGraphic = new doorGraphic();
|
||||
besideGraphic: besideGraphic = new besideGraphic();
|
||||
codeGraph: codeGraph = new codeGraph();
|
||||
constructor() {
|
||||
super(Platform.Type);
|
||||
this.addChild(this.platformGraphic);
|
||||
this.addChild(this.doorGraphic);
|
||||
this.addChild(this.besideGraphic);
|
||||
this.addChild(this.codeGraph);
|
||||
}
|
||||
|
||||
get datas(): IPlatformData {
|
||||
return this.getDatas<IPlatformData>();
|
||||
}
|
||||
get states(): IPlatformState {
|
||||
return this.getStates<IPlatformState>();
|
||||
}
|
||||
get code(): string {
|
||||
return this.datas.code;
|
||||
}
|
||||
doRepaint(): void {
|
||||
const station = this.getGraphicApp().queryStore.queryByCodeAndType<Station>(
|
||||
this.states.rtuId > 9 ? '' + this.states.rtuId : '0' + this.states.rtuId,
|
||||
Station.Type
|
||||
);
|
||||
this.doorGraphic.clear();
|
||||
if (this.datas.hasdoor) {
|
||||
this.doorGraphic.draw(this.states, !!station?.states.ipRtuStusDown);
|
||||
}
|
||||
this.platformGraphic.draw(this.states);
|
||||
this.besideGraphic.draw();
|
||||
this.codeGraph.draw();
|
||||
|
||||
this.doorGraphic.position.set(
|
||||
0,
|
||||
-platformConsts.height / 2 - platformConsts.doorPlatformSpacing
|
||||
);
|
||||
this.besideGraphic.position.set(
|
||||
0,
|
||||
-platformConsts.height / 2 -
|
||||
platformConsts.doorPlatformSpacing -
|
||||
platformConsts.height / 3
|
||||
);
|
||||
this.codeGraph.position.set(0, 0);
|
||||
//站台方向
|
||||
if (this.datas.direction == 'down') {
|
||||
const psChange = [
|
||||
this.doorGraphic,
|
||||
this.besideGraphic,
|
||||
this.codeGraph.children[0],
|
||||
this.codeGraph.children[1],
|
||||
this.codeGraph.children[3],
|
||||
this.codeGraph.children[4],
|
||||
];
|
||||
psChange.forEach((g) => {
|
||||
g.position.copyFrom(calculateMirrorPoint(new Point(0, 0), g.position));
|
||||
});
|
||||
this.codeGraph.children[2].position.set(
|
||||
platformConsts.width / 2 +
|
||||
platformConsts.lineWidth / 2 +
|
||||
(platformConsts.besideSpacing * 4) / 3,
|
||||
(-platformConsts.height * 10) / 11
|
||||
);
|
||||
}
|
||||
|
||||
if (station?.states.ipRtuStusDown) {
|
||||
return;
|
||||
}
|
||||
this.changeState();
|
||||
}
|
||||
changeState(): void {
|
||||
this.doorGraphic.changeState(this.states);
|
||||
this.besideGraphic.changeState(this.states);
|
||||
this.codeGraph.changeState(this.states);
|
||||
}
|
||||
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.datas.refStation = stationas[i].id;
|
||||
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.datas.refSectionId = refSection.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PlatformTemplate extends JlGraphicTemplate<Platform> {
|
||||
hasdoor: boolean;
|
||||
direction: string;
|
||||
constructor(dataTemplate: IPlatformData, stateTemplate: IPlatformState) {
|
||||
super(Platform.Type, {
|
||||
dataTemplate,
|
||||
stateTemplate,
|
||||
});
|
||||
this.hasdoor = true;
|
||||
this.direction = 'up';
|
||||
}
|
||||
new(): Platform {
|
||||
const platform = new Platform();
|
||||
platform.loadData(this.datas);
|
||||
platform.loadState(this.states);
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
export { Platform, PlatformTemplate, PlatformDraw };
|
||||
export type { IPlatformState, IPlatformData };
|
||||
|
@ -1,109 +0,0 @@
|
||||
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();
|
||||
}
|
||||
|
||||
clearCache(): void {
|
||||
//this.platformGraphic.clear();
|
||||
}
|
||||
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 {
|
||||
const template = this.graphicTemplate;
|
||||
data.hasdoor = template.hasdoor;
|
||||
data.direction = template.direction;
|
||||
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),
|
||||
});
|
||||
}
|
||||
}
|
@ -244,9 +244,11 @@ export class SectionGraphicHitArea implements IHitArea {
|
||||
function buildAbsorbablePositions(section: Section): AbsorbablePosition[] {
|
||||
const aps: AbsorbablePosition[] = [];
|
||||
|
||||
const sections = section.queryStore.queryByType<Section>(Section.Type);
|
||||
sections.forEach((other) => {
|
||||
const [ps, pe] = [
|
||||
section.localToCanvasPoint(section.getStartPoint()),
|
||||
section.localToCanvasPoint(section.getEndPoint()),
|
||||
other.localToCanvasPoint(other.getStartPoint()),
|
||||
other.localToCanvasPoint(other.getEndPoint()),
|
||||
];
|
||||
const { width, height } = section.getGraphicApp().canvas;
|
||||
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
|
||||
@ -254,15 +256,6 @@ function buildAbsorbablePositions(section: Section): AbsorbablePosition[] {
|
||||
const xe = new AbsorbableLine({ x: 0, y: pe.y }, { x: width, y: pe.y });
|
||||
const ye = new AbsorbableLine({ x: pe.x, y: 0 }, { x: pe.x, y: height });
|
||||
aps.push(xs, ys, xe, ye);
|
||||
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);
|
||||
|
@ -1,94 +1,8 @@
|
||||
import { Color, Graphics } from 'pixi.js';
|
||||
import { GraphicData, JlGraphic, JlGraphicTemplate } from 'jl-graphic';
|
||||
import { Separator } from 'rt-graphic-component/components/packages/Separator/Separator';
|
||||
import {
|
||||
ISeparatorData,
|
||||
separatorTypeEnum,
|
||||
} from 'rt-graphic-component/components/packages/Separator/SeparatorConfig';
|
||||
|
||||
export interface ISeparatorData extends GraphicData {
|
||||
get code(): string; // 编号
|
||||
set code(v: string);
|
||||
get separatorType(): string; // 类型
|
||||
set separatorType(v: string);
|
||||
clone(): ISeparatorData;
|
||||
copyFrom(data: ISeparatorData): void;
|
||||
eq(other: ISeparatorData): boolean;
|
||||
}
|
||||
|
||||
export enum separatorTypeEnum {
|
||||
turnout = 'turnout', // 道岔分隔符
|
||||
endA = 'endA', // A端尽头分隔符
|
||||
endB = 'endB', // B端尽头分隔符
|
||||
section = 'section', // 区段分隔符
|
||||
}
|
||||
|
||||
export const SeparatorConsts = {
|
||||
height: 12,
|
||||
lineWidth: 2,
|
||||
lineColor: '0x617799',
|
||||
circleColor: '0xEF0200',
|
||||
radius: 5,
|
||||
};
|
||||
|
||||
export class Separator extends JlGraphic {
|
||||
static Type = 'Separator';
|
||||
rectGraphic: Graphics = new Graphics();
|
||||
circleGraphic: Graphics = new Graphics();
|
||||
constructor() {
|
||||
super(Separator.Type);
|
||||
this.addChild(this.rectGraphic);
|
||||
this.addChild(this.circleGraphic);
|
||||
}
|
||||
get datas(): ISeparatorData {
|
||||
return this.getDatas<ISeparatorData>();
|
||||
}
|
||||
clear() {
|
||||
this.rectGraphic.clear();
|
||||
this.circleGraphic.clear();
|
||||
}
|
||||
doRepaint(): void {
|
||||
this.clear();
|
||||
const rectGraphic = this.rectGraphic;
|
||||
if (!this.datas.separatorType) {
|
||||
this.datas.separatorType = separatorTypeEnum.endA;
|
||||
}
|
||||
const typeArr = ['section', 'turnout'];
|
||||
if (typeArr.includes(this.datas.separatorType)) {
|
||||
rectGraphic.lineStyle(
|
||||
SeparatorConsts.lineWidth,
|
||||
new Color(SeparatorConsts.lineColor)
|
||||
);
|
||||
rectGraphic.moveTo(0, -SeparatorConsts.height / 2);
|
||||
rectGraphic.lineTo(0, SeparatorConsts.height / 2);
|
||||
if (this.datas.separatorType == 'turnout') {
|
||||
this.circleGraphic.lineStyle(1, SeparatorConsts.circleColor);
|
||||
this.circleGraphic.drawCircle(0, 0, SeparatorConsts.radius);
|
||||
}
|
||||
}
|
||||
const endTypeArr = ['endA', 'endB'];
|
||||
if (endTypeArr.includes(this.datas.separatorType)) {
|
||||
let d = SeparatorConsts.radius;
|
||||
if (this.datas.separatorType == 'endB') {
|
||||
d = -d;
|
||||
}
|
||||
rectGraphic.lineStyle(
|
||||
SeparatorConsts.lineWidth,
|
||||
new Color(SeparatorConsts.lineColor)
|
||||
);
|
||||
rectGraphic.moveTo(0, 0);
|
||||
rectGraphic.lineTo(-d, 0);
|
||||
rectGraphic.lineTo(-d, -d);
|
||||
rectGraphic.lineTo(-d * 3, -d);
|
||||
rectGraphic.moveTo(-d, 0);
|
||||
rectGraphic.lineTo(-d, d);
|
||||
rectGraphic.lineTo(-d * 3, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SeparatorTemplate extends JlGraphicTemplate<Separator> {
|
||||
constructor(dataTemplate: ISeparatorData) {
|
||||
super(Separator.Type, {
|
||||
dataTemplate,
|
||||
});
|
||||
}
|
||||
new(): Separator {
|
||||
return new Separator();
|
||||
}
|
||||
}
|
||||
export { Separator, separatorTypeEnum };
|
||||
export type { ISeparatorData };
|
||||
|
@ -1,56 +1,18 @@
|
||||
import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js';
|
||||
import {
|
||||
GraphicDrawAssistant,
|
||||
GraphicIdGenerator,
|
||||
GraphicInteractionPlugin,
|
||||
GraphicRelationParam,
|
||||
IDrawApp,
|
||||
JlGraphic,
|
||||
linePoint,
|
||||
} from 'jl-graphic';
|
||||
import { Point } from 'pixi.js';
|
||||
import { GraphicIdGenerator, GraphicRelationParam, IDrawApp } from 'jl-graphic';
|
||||
import { Section, SectionType } from '../section/Section';
|
||||
import {
|
||||
ISeparatorData,
|
||||
Separator,
|
||||
SeparatorConsts,
|
||||
SeparatorTemplate,
|
||||
separatorTypeEnum,
|
||||
} from './Separator';
|
||||
import { Separator, separatorTypeEnum } from './Separator';
|
||||
import { SeparatorData } from 'src/drawApp/graphics/SeparatorInteraction';
|
||||
import { Turnout } from '../turnout/Turnout';
|
||||
import { LogicSection } from '../logicSection/LogicSection';
|
||||
import { SeparatorTemplate } from 'rt-graphic-component/components/packages/Separator/Separator';
|
||||
import { SeparatorDraw as XaSeparatorDraw } from 'rt-graphic-component/components/packages/Separator/SeparatorDrawAssistant';
|
||||
|
||||
export class SeparatorDraw extends GraphicDrawAssistant<
|
||||
SeparatorTemplate,
|
||||
ISeparatorData
|
||||
> {
|
||||
SeparatorGraph: Separator;
|
||||
export class SeparatorDraw extends XaSeparatorDraw {
|
||||
constructor(app: IDrawApp, template: SeparatorTemplate) {
|
||||
super(app, template, 'sym_o_square', '分隔符Separator');
|
||||
this.SeparatorGraph = this.graphicTemplate.new();
|
||||
this.container.addChild(this.SeparatorGraph);
|
||||
SeparatorInteraction.init(app);
|
||||
super(app, template);
|
||||
}
|
||||
|
||||
bind(): void {
|
||||
super.bind();
|
||||
this.SeparatorGraph.loadData(this.graphicTemplate.datas);
|
||||
this.SeparatorGraph.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: ISeparatorData): boolean {
|
||||
data.transform = this.container.saveTransform();
|
||||
return true;
|
||||
}
|
||||
oneGenerates() {
|
||||
const SeparatorAll = this.app.queryStore.queryByType<Separator>(
|
||||
Separator.Type
|
||||
@ -76,7 +38,7 @@ export class SeparatorDraw extends GraphicDrawAssistant<
|
||||
allR.forEach((relation, index) => {
|
||||
const r = relation.getRelationParam(section);
|
||||
const other = relation.getOtherRelationParam(section);
|
||||
if (!section.datas.children.includes(other.g.id + '')) {
|
||||
if (!section.datas.children.includes(other.g.id)) {
|
||||
// 排除物理区段和自身逻辑区段的关联关系
|
||||
port.push(r.param);
|
||||
}
|
||||
@ -216,69 +178,3 @@ export class SeparatorDraw extends GraphicDrawAssistant<
|
||||
this.storeGraphic(separator);
|
||||
}
|
||||
}
|
||||
|
||||
//碰撞检测
|
||||
export class SeparatorGraphicHitArea implements IHitArea {
|
||||
separator: Separator;
|
||||
constructor(separator: Separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
contains(x: number, y: number): boolean {
|
||||
let contains = false;
|
||||
const p = new Point(x, y);
|
||||
const typeArr = ['section', 'turnout'];
|
||||
const endTypeArr = ['endA', 'endB'];
|
||||
let d = SeparatorConsts.radius;
|
||||
if (typeArr.includes(this.separator.datas.separatorType)) {
|
||||
const tolerance = SeparatorConsts.lineWidth;
|
||||
const p1 = new Point(0, -SeparatorConsts.height / 2);
|
||||
const p2 = new Point(0, SeparatorConsts.height / 2);
|
||||
contains = contains || linePoint(p1, p2, p, tolerance);
|
||||
return contains;
|
||||
} else if (endTypeArr.includes(this.separator.datas.separatorType)) {
|
||||
if (this.separator.datas.separatorType == 'endB') {
|
||||
d = -d;
|
||||
}
|
||||
const tolerance = SeparatorConsts.lineWidth;
|
||||
const p1 = new Point(0, 0);
|
||||
const p2 = new Point(-d, 0);
|
||||
const p3 = new Point(-d, -d);
|
||||
const p4 = new Point(-d * 3, -d);
|
||||
const p5 = new Point(-d, d);
|
||||
const p6 = new Point(-d * 3, d);
|
||||
contains = contains || linePoint(p1, p2, p, tolerance);
|
||||
contains = contains || linePoint(p2, p3, p, tolerance);
|
||||
contains = contains || linePoint(p3, p4, p, tolerance);
|
||||
contains = contains || linePoint(p2, p5, p, tolerance);
|
||||
contains = contains || linePoint(p5, p6, p, tolerance);
|
||||
}
|
||||
return contains;
|
||||
}
|
||||
}
|
||||
|
||||
export class SeparatorInteraction extends GraphicInteractionPlugin<Separator> {
|
||||
static Name = 'Separator_transform';
|
||||
constructor(app: IDrawApp) {
|
||||
super(SeparatorInteraction.Name, app);
|
||||
}
|
||||
static init(app: IDrawApp) {
|
||||
return new SeparatorInteraction(app);
|
||||
}
|
||||
filter(...grahpics: JlGraphic[]): Separator[] | undefined {
|
||||
return grahpics
|
||||
.filter((g) => g.type === Separator.Type)
|
||||
.map((g) => g as Separator);
|
||||
}
|
||||
bind(g: Separator): void {
|
||||
g.eventMode = 'static';
|
||||
g.cursor = 'pointer';
|
||||
g.scalable = true;
|
||||
g.rotatable = true;
|
||||
g.rectGraphic.hitArea = new SeparatorGraphicHitArea(g);
|
||||
}
|
||||
unbind(g: Separator): void {
|
||||
g.eventMode = 'none';
|
||||
g.scalable = false;
|
||||
g.rotatable = false;
|
||||
}
|
||||
}
|
||||
|
101
src/graphics/signal/Lamp.ts
Normal file
101
src/graphics/signal/Lamp.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { Container } from '@pixi/display';
|
||||
import { Graphics } from 'pixi.js';
|
||||
|
||||
const lampConsts = {
|
||||
lampRadius: 8,
|
||||
logicModeLineWidth: 2,
|
||||
logicModeDistance: 5,
|
||||
logicModeColor: '0x000000',
|
||||
lampLineWidth: 1,
|
||||
lampLineColor: '0x3149c3',
|
||||
lampBadColor: '0xFF0000',
|
||||
badStart: 10,
|
||||
badEnd: 15,
|
||||
};
|
||||
|
||||
export class Lamp extends Container {
|
||||
circleLamp: Graphics = new Graphics();
|
||||
logicMode: Graphics = new Graphics();
|
||||
lampBad: Graphics = new Graphics();
|
||||
radiusX = 0;
|
||||
radiusY = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addChild(this.circleLamp);
|
||||
this.addChild(this.logicMode);
|
||||
this.addChild(this.lampBad);
|
||||
}
|
||||
paint(radiusX: number, radiusY: number) {
|
||||
this.radiusX = radiusX;
|
||||
this.radiusY = radiusY;
|
||||
this.createLamp();
|
||||
}
|
||||
createLampBad() {
|
||||
this.lampBad.clear();
|
||||
this.lampBad.lineStyle(lampConsts.lampLineWidth, lampConsts.lampBadColor);
|
||||
this.lampBad.moveTo(this.radiusX + lampConsts.badStart, this.radiusY);
|
||||
this.lampBad.lineTo(this.radiusX + lampConsts.badEnd, this.radiusY);
|
||||
this.lampBad.moveTo(this.radiusX - lampConsts.badStart, this.radiusY);
|
||||
this.lampBad.lineTo(this.radiusX - lampConsts.badEnd, this.radiusY);
|
||||
this.lampBad.moveTo(this.radiusX, this.radiusY + lampConsts.badStart);
|
||||
this.lampBad.lineTo(this.radiusX, this.radiusY + lampConsts.badEnd);
|
||||
this.lampBad.moveTo(this.radiusX, this.radiusY - lampConsts.badStart);
|
||||
this.lampBad.lineTo(this.radiusX, this.radiusY - lampConsts.badEnd);
|
||||
const xieStart = Math.sin(Math.PI / 4) * lampConsts.badStart;
|
||||
const xieEnd = Math.sin(Math.PI / 4) * lampConsts.badEnd;
|
||||
this.lampBad.moveTo(this.radiusX + xieStart, this.radiusY + xieStart);
|
||||
this.lampBad.lineTo(this.radiusX + xieEnd, this.radiusY + xieEnd);
|
||||
this.lampBad.moveTo(this.radiusX + xieStart, this.radiusY - xieStart);
|
||||
this.lampBad.lineTo(this.radiusX + xieEnd, this.radiusY - xieEnd);
|
||||
|
||||
this.lampBad.moveTo(this.radiusX - xieStart, this.radiusY - xieStart);
|
||||
this.lampBad.lineTo(this.radiusX - xieEnd, this.radiusY - xieEnd);
|
||||
this.lampBad.moveTo(this.radiusX - xieStart, this.radiusY + xieStart);
|
||||
this.lampBad.lineTo(this.radiusX - xieEnd, this.radiusY + xieEnd);
|
||||
}
|
||||
createLamp(color?: string) {
|
||||
this.circleLamp.clear();
|
||||
this.circleLamp.lineStyle(
|
||||
lampConsts.lampLineWidth,
|
||||
lampConsts.lampLineColor
|
||||
);
|
||||
if (!color) {
|
||||
color = '0X' + this.getCanvas().backgroundColor.substring(1);
|
||||
}
|
||||
this.circleLamp.beginFill(color, 1);
|
||||
this.circleLamp.drawCircle(
|
||||
this.radiusX,
|
||||
this.radiusY,
|
||||
lampConsts.lampRadius
|
||||
);
|
||||
this.circleLamp.endFill();
|
||||
}
|
||||
createLogicMode() {
|
||||
this.logicMode
|
||||
.clear()
|
||||
.lineStyle(lampConsts.logicModeLineWidth, lampConsts.logicModeColor)
|
||||
.moveTo(
|
||||
this.radiusX - lampConsts.logicModeDistance,
|
||||
this.radiusY + lampConsts.logicModeDistance
|
||||
)
|
||||
.lineTo(
|
||||
this.radiusX + lampConsts.logicModeDistance,
|
||||
this.radiusY - lampConsts.logicModeDistance
|
||||
)
|
||||
.moveTo(
|
||||
this.radiusX - lampConsts.logicModeDistance,
|
||||
this.radiusY - lampConsts.logicModeDistance
|
||||
)
|
||||
.lineTo(
|
||||
this.radiusX + lampConsts.logicModeDistance,
|
||||
this.radiusY + lampConsts.logicModeDistance
|
||||
);
|
||||
}
|
||||
logicModeClear() {
|
||||
this.logicMode.clear();
|
||||
}
|
||||
lampClear() {
|
||||
this.circleLamp.clear();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { Graphics, Point } from 'pixi.js';
|
||||
import { calculateMirrorPoint, GraphicAnimation, JlGraphic } from 'jl-graphic';
|
||||
import { Lamp } from './Lamp';
|
||||
import { ISignalState } from './Signal';
|
||||
|
||||
export enum LampEnum {
|
||||
@ -9,7 +10,6 @@ export enum LampEnum {
|
||||
yellowLamp = '0XFFFF00',
|
||||
whiteLamp = '0XFFFFFF',
|
||||
blueLamp = '0x3149c3',
|
||||
closeLamp = '0x000000',
|
||||
}
|
||||
|
||||
const lampConsts = {
|
||||
@ -17,14 +17,6 @@ const lampConsts = {
|
||||
levelLampPostLength: 4,
|
||||
postLineWidth: 3,
|
||||
lampRadius: 8,
|
||||
logicModeLineWidth: 2,
|
||||
logicModeDistance: 5,
|
||||
logicModeColor: '0x000000',
|
||||
lampLineWidth: 1,
|
||||
lampLineColor: '0x3149c3',
|
||||
lampBadColor: '0xFF0000',
|
||||
badStart: 10,
|
||||
badEnd: 15,
|
||||
};
|
||||
|
||||
const anmiationNameConst = {
|
||||
@ -39,31 +31,23 @@ export class LampMainBody extends JlGraphic {
|
||||
static Type = 'LampMainBody';
|
||||
lampNum = 1;
|
||||
lampPost: Graphics = new Graphics();
|
||||
// lamps: Lamp[] = [];
|
||||
lamps: Graphics = new Graphics();
|
||||
logicMode: Graphics = new Graphics();
|
||||
lamps: Lamp[] = [];
|
||||
mirror = false;
|
||||
deltaTime = 0;
|
||||
states: ISignalState | null = null;
|
||||
|
||||
constructor() {
|
||||
super(LampMainBody.Type);
|
||||
this.addChild(this.lampPost);
|
||||
this.addChild(this.lamps);
|
||||
this.addChild(this.logicMode);
|
||||
}
|
||||
paint(lampNum: number, mirror: boolean, states: ISignalState) {
|
||||
this.lampPost.clear();
|
||||
|
||||
this.logicMode.clear();
|
||||
this.mirror = mirror;
|
||||
this.states = states;
|
||||
if (lampNum < 1) {
|
||||
throw new Error('信号机灯数量异常');
|
||||
}
|
||||
this.lampNum = lampNum;
|
||||
// this.removeChildren(0);
|
||||
// this.lampPost = new Graphics();
|
||||
this.removeChildren(0);
|
||||
this.lampPost = new Graphics();
|
||||
let lpp = new Point(lampConsts.levelLampPostLength, 0);
|
||||
if (mirror) {
|
||||
lpp = calculateMirrorPoint(new Point(0, 0), lpp);
|
||||
@ -74,81 +58,39 @@ export class LampMainBody extends JlGraphic {
|
||||
.lineTo(0, lampConsts.verticalLampPostLength / 2)
|
||||
.moveTo(0, 0)
|
||||
.lineTo(lpp.x, lpp.y);
|
||||
// this.addChild(this.lampPost);
|
||||
this.addChild(this.lampPost);
|
||||
|
||||
// this.lamps = [];
|
||||
// for (let i = 0; i < this.lampNum; i++) {
|
||||
// const lamp = new Lamp();
|
||||
// // this.addChild(lamp);
|
||||
// const radiusX =
|
||||
// (1 + i * 2) * lampConsts.lampRadius + lampConsts.levelLampPostLength;
|
||||
// let lrp = new Point(radiusX, 0);
|
||||
// if (mirror) {
|
||||
// lrp = calculateMirrorPoint(new Point(0, 0), lrp);
|
||||
// }
|
||||
// lamp.paint(lrp.x, lrp.y);
|
||||
// // this.lamps.push(lamp);
|
||||
// }
|
||||
this.chagneState(this.states);
|
||||
}
|
||||
paintLamp(colors: string[], lampNum?: number) {
|
||||
this.lamps.clear();
|
||||
this.lamps.lineStyle(
|
||||
lampConsts.lampLineWidth,
|
||||
lampConsts.lampLineColor
|
||||
);
|
||||
const number = lampNum || this.lampNum
|
||||
for (let i = 0; i < number; i++) {
|
||||
this.lamps = [];
|
||||
for (let i = 0; i < this.lampNum; i++) {
|
||||
const lamp = new Lamp();
|
||||
this.addChild(lamp);
|
||||
const radiusX =
|
||||
(1 + i * 2) * lampConsts.lampRadius +
|
||||
lampConsts.levelLampPostLength;
|
||||
(1 + i * 2) * lampConsts.lampRadius + lampConsts.levelLampPostLength;
|
||||
let lrp = new Point(radiusX, 0);
|
||||
if (this.mirror) {
|
||||
if (mirror) {
|
||||
lrp = calculateMirrorPoint(new Point(0, 0), lrp);
|
||||
}
|
||||
const color = colors[i] ? colors[i] : LampEnum.closeLamp;
|
||||
this.lamps.beginFill(color, 1);
|
||||
this.lamps.drawCircle(
|
||||
lrp.x,
|
||||
lrp.y,
|
||||
lampConsts.lampRadius
|
||||
);
|
||||
this.lamps.endFill();
|
||||
if (this.states?.extinguish) {
|
||||
this.logicMode
|
||||
.lineStyle(lampConsts.logicModeLineWidth, lampConsts.logicModeColor)
|
||||
.moveTo(
|
||||
lrp.x - lampConsts.logicModeDistance,
|
||||
lrp.y + lampConsts.logicModeDistance
|
||||
)
|
||||
.lineTo(
|
||||
lrp.x + lampConsts.logicModeDistance,
|
||||
lrp.y - lampConsts.logicModeDistance
|
||||
)
|
||||
.moveTo(
|
||||
lrp.x - lampConsts.logicModeDistance,
|
||||
lrp.y - lampConsts.logicModeDistance
|
||||
)
|
||||
.lineTo(
|
||||
lrp.x + lampConsts.logicModeDistance,
|
||||
lrp.y + lampConsts.logicModeDistance
|
||||
);
|
||||
}
|
||||
lamp.paint(lrp.x, lrp.y);
|
||||
this.lamps.push(lamp);
|
||||
}
|
||||
this.chagneState(this.states);
|
||||
}
|
||||
setBlueShow() {
|
||||
this.stopAnmiation();
|
||||
this.paintLamp([LampEnum.blueLamp, LampEnum.blueLamp, LampEnum.blueLamp]);
|
||||
this.lamps.forEach((lamp) => {
|
||||
lamp.createLamp(LampEnum.blueLamp);
|
||||
lamp.logicModeClear();
|
||||
});
|
||||
}
|
||||
doRepaint() {
|
||||
// this.paint(this.lampNum, this.mirror, this.states);
|
||||
}
|
||||
stopAnmiation() {
|
||||
const redFlashA = this.animation(anmiationNameConst.signaRedFlash + this.states?.code);
|
||||
const greenFlashA = this.animation(anmiationNameConst.signalGreenFlash + this.states?.code);
|
||||
const blueFlashA = this.animation(anmiationNameConst.signalBlueFlash + this.states?.code);
|
||||
const yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash + this.states?.code);
|
||||
const whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash + this.states?.code);
|
||||
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();
|
||||
}
|
||||
@ -167,13 +109,18 @@ export class LampMainBody extends JlGraphic {
|
||||
}
|
||||
chagneState(states: ISignalState) {
|
||||
this.stopAnmiation();
|
||||
if (states.extinguish) {
|
||||
this.lamps.forEach((lamp) => lamp.createLogicMode());
|
||||
} else {
|
||||
this.lamps.forEach((lamp) => lamp.logicModeClear());
|
||||
}
|
||||
if (states.redOpen) {
|
||||
this.paintLamp([LampEnum.redLamp]);
|
||||
this.lamps[0].createLamp(LampEnum.redLamp);
|
||||
} else if (states.redFlash) {
|
||||
let redFlashA = this.animation(anmiationNameConst.signaRedFlash + states.code);
|
||||
let redFlashA = this.animation(anmiationNameConst.signaRedFlash);
|
||||
if (!redFlashA) {
|
||||
redFlashA = this.createFlashAnmiation(
|
||||
anmiationNameConst.signaRedFlash + states.code,
|
||||
anmiationNameConst.signaRedFlash,
|
||||
LampEnum.redLamp,
|
||||
0
|
||||
);
|
||||
@ -181,12 +128,12 @@ export class LampMainBody extends JlGraphic {
|
||||
this.addAnimation(redFlashA);
|
||||
redFlashA.resume();
|
||||
} else if (states.greenOpen) {
|
||||
this.paintLamp([LampEnum.closeLamp, LampEnum.greenLamp]);
|
||||
this.lamps[1].createLamp(LampEnum.greenLamp);
|
||||
} else if (states.greenFlash) {
|
||||
let greenFlashA = this.animation(anmiationNameConst.signalGreenFlash + states.code);
|
||||
let greenFlashA = this.animation(anmiationNameConst.signalGreenFlash);
|
||||
if (!greenFlashA) {
|
||||
greenFlashA = this.createFlashAnmiation(
|
||||
anmiationNameConst.signalGreenFlash + states.code,
|
||||
anmiationNameConst.signalGreenFlash,
|
||||
LampEnum.greenLamp,
|
||||
1
|
||||
);
|
||||
@ -194,12 +141,12 @@ export class LampMainBody extends JlGraphic {
|
||||
this.addAnimation(greenFlashA);
|
||||
greenFlashA.resume();
|
||||
} else if (states.yellowOpen) {
|
||||
this.paintLamp([LampEnum.closeLamp, LampEnum.yellowLamp]);
|
||||
this.lamps[1].createLamp(LampEnum.yellowLamp);
|
||||
} else if (states.yellowFlash) {
|
||||
let yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash + states.code);
|
||||
let yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash);
|
||||
if (!yellowFlashA) {
|
||||
yellowFlashA = this.createFlashAnmiation(
|
||||
anmiationNameConst.signalYellowFlash + states.code,
|
||||
anmiationNameConst.signalYellowFlash,
|
||||
LampEnum.yellowLamp,
|
||||
1
|
||||
);
|
||||
@ -207,12 +154,12 @@ export class LampMainBody extends JlGraphic {
|
||||
this.addAnimation(yellowFlashA);
|
||||
yellowFlashA.resume();
|
||||
} else if (states.blueOpen) {
|
||||
this.paintLamp([LampEnum.blueLamp, LampEnum.blueLamp, LampEnum.blueLamp]);
|
||||
this.lamps.forEach((lamp) => lamp.createLamp(LampEnum.blueLamp));
|
||||
} else if (states.blueFlash) {
|
||||
let blueFlashA = this.animation(anmiationNameConst.signalBlueFlash + states.code);
|
||||
let blueFlashA = this.animation(anmiationNameConst.signalBlueFlash);
|
||||
if (!blueFlashA) {
|
||||
blueFlashA = this.createFlashAnmiation(
|
||||
anmiationNameConst.signalBlueFlash + states.code,
|
||||
anmiationNameConst.signalBlueFlash,
|
||||
LampEnum.blueLamp,
|
||||
0
|
||||
);
|
||||
@ -220,12 +167,13 @@ export class LampMainBody extends JlGraphic {
|
||||
this.addAnimation(blueFlashA);
|
||||
blueFlashA.resume();
|
||||
} else if (states.whiteOpen) {
|
||||
this.paintLamp([LampEnum.whiteLamp], 1);
|
||||
this.lamps[0].createLamp(LampEnum.whiteLamp);
|
||||
this.lamps[1].visible = false;
|
||||
} else if (states.whiteFlash) {
|
||||
let whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash + states.code);
|
||||
let whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash);
|
||||
if (!whiteFlashA) {
|
||||
whiteFlashA = this.createFlashAnmiation(
|
||||
anmiationNameConst.signalWhiteFlash + states.code,
|
||||
anmiationNameConst.signalWhiteFlash,
|
||||
LampEnum.whiteLamp,
|
||||
0
|
||||
);
|
||||
@ -233,15 +181,16 @@ export class LampMainBody extends JlGraphic {
|
||||
this.addAnimation(whiteFlashA);
|
||||
whiteFlashA.resume();
|
||||
} else if (states.callon) {
|
||||
this.paintLamp([LampEnum.redLamp, LampEnum.yellowLamp]);
|
||||
this.lamps[0].createLamp(LampEnum.redLamp);
|
||||
this.lamps[1].createLamp(LampEnum.yellowLamp);
|
||||
} else if (states.yellowYellow) {
|
||||
this.paintLamp([LampEnum.yellowLamp, LampEnum.yellowLamp]);
|
||||
this.lamps[0].createLamp(LampEnum.yellowLamp);
|
||||
this.lamps[1].createLamp(LampEnum.yellowLamp);
|
||||
} else if (states.yellowGreen) {
|
||||
this.paintLamp([LampEnum.yellowLamp, LampEnum.greenLamp]);
|
||||
this.lamps[0].createLamp(LampEnum.yellowLamp);
|
||||
this.lamps[1].createLamp(LampEnum.greenLamp);
|
||||
} else if (states.lampFailure) {
|
||||
this.paintLamp([LampEnum.redLamp]);
|
||||
} else {
|
||||
this.paintLamp([]);
|
||||
this.lamps[0].createLamp(LampEnum.redLamp);
|
||||
}
|
||||
}
|
||||
createFlashAnmiation(
|
||||
@ -249,17 +198,18 @@ export class LampMainBody extends JlGraphic {
|
||||
color: string,
|
||||
lampIndex: number
|
||||
): GraphicAnimation {
|
||||
const bgColor = '0X' + this.getCanvas().backgroundColor.substring(1);
|
||||
const flashAnmiation = GraphicAnimation.init({
|
||||
name: name,
|
||||
run: (dt: number) => {
|
||||
this.deltaTime += dt;
|
||||
if (this.deltaTime > 60) {
|
||||
const colors = ['', '', ''];
|
||||
this.deltaTime = 0;
|
||||
colors[lampIndex] = color;
|
||||
this.paintLamp(colors);
|
||||
this.lamps[lampIndex].createLamp(color);
|
||||
} else if (this.deltaTime > 30) {
|
||||
this.paintLamp([]);
|
||||
this.lamps.forEach((lamp) => {
|
||||
lamp.createLamp(bgColor);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -1,280 +1,8 @@
|
||||
import { Color, Container, Graphics } from 'pixi.js';
|
||||
import {
|
||||
GraphicData,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
VectorText,
|
||||
} from 'jl-graphic';
|
||||
import { LogicSection } from '../logicSection/LogicSection';
|
||||
import { Platform } from '../platform/Platform';
|
||||
import { KilometerSystem, Signal } from '../signal/Signal';
|
||||
import { Train } from '../train/Train';
|
||||
import { Turnout } from '../turnout/Turnout';
|
||||
import { THStation as Station } from 'rt-graphic-component/components/packages/Station/THStation';
|
||||
import { IStationData } from 'rt-graphic-component/components/packages/Station/common/StationConfig';
|
||||
import { ITHStationState as IStationState } from 'rt-graphic-component/components/packages/Station/THStation';
|
||||
import { StationTemplate } from 'rt-graphic-component/components/packages/Station/common/StationTemplate';
|
||||
import { StationDraw } from 'rt-graphic-component/components/packages/Station/common/StationDrawAssistant';
|
||||
|
||||
export interface IStationData extends GraphicData {
|
||||
get code(): string; // 车站索引
|
||||
set code(v: string);
|
||||
get kilometerSystem(): KilometerSystem;
|
||||
set kilometerSystem(v: KilometerSystem);
|
||||
get hasControl(): boolean; //是否有控制
|
||||
set hasControl(v: boolean);
|
||||
get concentrationStations(): boolean; //是否集中站
|
||||
set concentrationStations(v: boolean);
|
||||
get name(): string; //车站名称
|
||||
set name(v: string);
|
||||
get manageStations(): number[]; //集中站管理的车站
|
||||
set manageStations(v: number[]);
|
||||
get depots(): boolean; //是否车辆段
|
||||
set depots(v: boolean);
|
||||
clone(): IStationData;
|
||||
copyFrom(data: IStationData): void;
|
||||
eq(other: IStationData): boolean;
|
||||
}
|
||||
|
||||
export interface IStationState extends GraphicState {
|
||||
get ipRtuStusDown(): boolean; //通信终端---是否允许转到中控
|
||||
set ipRtuStusDown(v: boolean);
|
||||
get ipRtuStusInLocalCtrl(): boolean; //站控
|
||||
set ipRtuStusInLocalCtrl(v: boolean);
|
||||
get ipRtuStusInCentralCtrl(): boolean; //遥控
|
||||
set ipRtuStusInCentralCtrl(v: boolean);
|
||||
get ipRtuStusInEmergencyCtrl(): boolean; //紧急站控
|
||||
set ipRtuStusInEmergencyCtrl(v: boolean);
|
||||
get rtuId(): number; // 集中站站号
|
||||
set rtuId(v: number);
|
||||
}
|
||||
|
||||
const stationConsts = {
|
||||
radius: 3,
|
||||
borderWidth: 1,
|
||||
circleColorGrey: '0x808080',
|
||||
circleColorBlue: '0x08F80D',
|
||||
circleColorYellow: '0xFFFA0C',
|
||||
codeColor: '0xF48815',
|
||||
codeFontSize: 22,
|
||||
codeControlFontSize: 12,
|
||||
codeOffsetY: 30,
|
||||
circleOffsetY: 20,
|
||||
circleBetweenOffset: 40,
|
||||
kilometerCodeColor: '0xFFFFFF',
|
||||
kilometerCodeFontSize: 8,
|
||||
kilometerCodeOffsetY: -25,
|
||||
};
|
||||
class constrolGraphic extends Container {
|
||||
circleA: Graphics = new Graphics();
|
||||
codeGraphA: VectorText = new VectorText(''); //控制名--站控
|
||||
circleB: Graphics = new Graphics();
|
||||
codeGraphB: VectorText = new VectorText(''); //控制名--中控
|
||||
arrow: Graphics = new Graphics();
|
||||
inArrow: Graphics = new Graphics();
|
||||
constructor() {
|
||||
super();
|
||||
this.addChild(this.circleA);
|
||||
this.addChild(this.codeGraphA);
|
||||
this.addChild(this.circleB);
|
||||
this.addChild(this.codeGraphB);
|
||||
this.addChild(this.arrow);
|
||||
this.addChild(this.inArrow);
|
||||
this.codeGraphA.setVectorFontSize(stationConsts.codeFontSize);
|
||||
this.codeGraphB.setVectorFontSize(stationConsts.codeFontSize);
|
||||
}
|
||||
draw(states: IStationState): void {
|
||||
let StationControlFillColor = stationConsts.circleColorGrey;
|
||||
let centralControlFillColor = stationConsts.circleColorBlue;
|
||||
let inArrowFillColor = stationConsts.circleColorGrey;
|
||||
if (states.ipRtuStusInLocalCtrl) {
|
||||
StationControlFillColor = stationConsts.circleColorYellow;
|
||||
centralControlFillColor = stationConsts.circleColorGrey;
|
||||
if (!states.ipRtuStusDown) {
|
||||
inArrowFillColor = stationConsts.circleColorBlue;
|
||||
}
|
||||
}
|
||||
this.drawCircleCode(
|
||||
this.circleA,
|
||||
this.codeGraphA,
|
||||
'站控',
|
||||
StationControlFillColor
|
||||
);
|
||||
this.circleA.position.set(
|
||||
stationConsts.circleBetweenOffset / 2,
|
||||
stationConsts.circleOffsetY
|
||||
);
|
||||
this.codeGraphA.position.set(
|
||||
stationConsts.circleBetweenOffset / 2,
|
||||
stationConsts.codeOffsetY
|
||||
);
|
||||
this.drawCircleCode(
|
||||
this.circleB,
|
||||
this.codeGraphB,
|
||||
'中控',
|
||||
centralControlFillColor
|
||||
);
|
||||
this.circleB.position.set(
|
||||
-stationConsts.circleBetweenOffset / 2,
|
||||
stationConsts.circleOffsetY
|
||||
);
|
||||
this.codeGraphB.position.set(
|
||||
-stationConsts.circleBetweenOffset / 2,
|
||||
stationConsts.codeOffsetY
|
||||
);
|
||||
const arrow = this.arrow;
|
||||
arrow.clear();
|
||||
arrow.lineStyle(stationConsts.borderWidth, new Color('0xFFFFFF'));
|
||||
const points = [0, 0, 2, 2, 2, 1, 14, 1, 14, -1, 2, -1, 2, -2];
|
||||
arrow.beginFill('0xFFFFFF');
|
||||
arrow.drawPolygon(points);
|
||||
arrow.endFill();
|
||||
arrow.scale.set(1.1, 1.1);
|
||||
arrow.position.set(-7, stationConsts.circleOffsetY);
|
||||
const inArrow = this.inArrow;
|
||||
inArrow.beginFill(inArrowFillColor);
|
||||
inArrow.drawPolygon(points);
|
||||
inArrow.endFill();
|
||||
inArrow.position.set(-6.5, stationConsts.circleOffsetY);
|
||||
}
|
||||
drawCircleCode(
|
||||
circle: Graphics,
|
||||
codeGraph: VectorText,
|
||||
code: string,
|
||||
fillcolor: string
|
||||
): void {
|
||||
circle.clear();
|
||||
circle.lineStyle(stationConsts.borderWidth, new Color(fillcolor));
|
||||
circle.beginFill(fillcolor, 1);
|
||||
circle.drawCircle(0, 0, stationConsts.radius);
|
||||
circle.endFill;
|
||||
codeGraph.text = code;
|
||||
codeGraph.style.fill = fillcolor;
|
||||
codeGraph.setVectorFontSize(stationConsts.codeControlFontSize);
|
||||
codeGraph.anchor.set(0.5);
|
||||
}
|
||||
clear(): void {
|
||||
this.circleA.clear();
|
||||
this.circleB.clear();
|
||||
this.codeGraphA.text = '';
|
||||
this.codeGraphB.text = '';
|
||||
this.arrow.clear();
|
||||
this.inArrow.clear();
|
||||
}
|
||||
}
|
||||
export class Station extends JlGraphic {
|
||||
static Type = 'station';
|
||||
codeGraph: VectorText = new VectorText(''); //车站名
|
||||
kilometerGraph: VectorText = new VectorText(''); //公里标
|
||||
controlGraphic: constrolGraphic = new constrolGraphic();
|
||||
_ipRtuStusDown = false;
|
||||
constructor() {
|
||||
super(Station.Type);
|
||||
this.addChild(this.codeGraph);
|
||||
this.addChild(this.kilometerGraph);
|
||||
this.addChild(this.controlGraphic);
|
||||
this.kilometerGraph.name = 'kilometer';
|
||||
this.controlGraphic.name = 'trainControl';
|
||||
}
|
||||
|
||||
get datas(): IStationData {
|
||||
return this.getDatas<IStationData>();
|
||||
}
|
||||
get states(): IStationState {
|
||||
return this.getStates<IStationState>();
|
||||
}
|
||||
get code(): string {
|
||||
return this.datas.code;
|
||||
}
|
||||
doRepaint(): void {
|
||||
const codeGraph = this.codeGraph;
|
||||
const kilometerGraph = this.kilometerGraph;
|
||||
const controlGraphic = this.controlGraphic;
|
||||
controlGraphic.clear();
|
||||
codeGraph.text = this.datas?.code
|
||||
? `${this.datas?.name}(${this.datas?.code})`
|
||||
: `${this.datas?.name}`;
|
||||
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);
|
||||
if (this.datas.childTransforms?.length) {
|
||||
this.datas.childTransforms.forEach((child) => {
|
||||
if (child.name == 'kilometer') {
|
||||
const pos = child.transform.position;
|
||||
kilometerGraph.position.set(pos.x, pos.y);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.datas.hasControl) {
|
||||
controlGraphic.draw(this.states);
|
||||
}
|
||||
if (this.states.ipRtuStusDown !== this._ipRtuStusDown) {
|
||||
this._ipRtuStusDown = this.states.ipRtuStusDown;
|
||||
this.handleBlueShow();
|
||||
}
|
||||
}
|
||||
handleBlueShow() {
|
||||
const signals = this.queryStore.queryByType<Signal>(Signal.Type);
|
||||
const logicSections = this.queryStore.queryByType<LogicSection>(
|
||||
LogicSection.Type
|
||||
);
|
||||
const turnouts = this.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||
const platfroms = this.queryStore.queryByType<Platform>(Platform.Type);
|
||||
const trains = this.queryStore.queryByType<Train>(Train.Type);
|
||||
signals.forEach((signal) => {
|
||||
if (signal.states.rtuId === this.states.rtuId) {
|
||||
signal.doRepaint();
|
||||
}
|
||||
});
|
||||
logicSections.forEach((logicSection) => {
|
||||
if (logicSection.states.rtuId === this.states.rtuId) {
|
||||
logicSection.doRepaint();
|
||||
}
|
||||
});
|
||||
turnouts.forEach((turnout) => {
|
||||
if (turnout.states.rtuId === this.states.rtuId) {
|
||||
turnout.doRepaint();
|
||||
}
|
||||
});
|
||||
platfroms.forEach((platform) => {
|
||||
if (platform.states.rtuId === this.states.rtuId) {
|
||||
platform.doRepaint();
|
||||
}
|
||||
});
|
||||
trains.forEach((train) => {
|
||||
if (train.states.rtuId === this.states.rtuId) {
|
||||
train.doRepaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
export { Station, StationTemplate, StationDraw };
|
||||
export type { IStationState, IStationData };
|
||||
|
@ -1,123 +0,0 @@
|
||||
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();
|
||||
}
|
||||
|
||||
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: IStationData): boolean {
|
||||
data.transform = this.container.saveTransform();
|
||||
data.hasControl = this.graphicTemplate.hasControl;
|
||||
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.controlGraphic.eventMode = 'static';
|
||||
g.controlGraphic.cursor = 'pointer';
|
||||
g.controlGraphic.draggable = true;
|
||||
g.controlGraphic.selectable = true;
|
||||
g.controlGraphic.transformSave = 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: Station): void {
|
||||
g.eventMode = 'none';
|
||||
g.scalable = false;
|
||||
g.rotatable = false;
|
||||
g.controlGraphic.eventMode = 'none';
|
||||
g.controlGraphic.draggable = false;
|
||||
g.controlGraphic.selectable = false;
|
||||
g.controlGraphic.transformSave = 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 station = this.app.selectedGraphics[0] as Station;
|
||||
this.app.setOptions({
|
||||
absorbablePositions: buildAbsorbablePositions(station),
|
||||
});
|
||||
}
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
import { Graphics, Container, Point } from 'pixi.js';
|
||||
import {
|
||||
GraphicData,
|
||||
GraphicIdGenerator,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
VectorText,
|
||||
calculateMirrorPoint,
|
||||
} from 'jl-graphic';
|
||||
import { train } from 'src/protos/train';
|
||||
import { state } from 'src/protos/device_status';
|
||||
@ -14,6 +10,13 @@ import { TrainWindow } from '../trainWindow/TrainWindow';
|
||||
import { LogicSection } from '../logicSection/LogicSection';
|
||||
import { Section } from '../section/Section';
|
||||
import { Station } from '../station/Station';
|
||||
import { Train as XaTrain } from 'rt-graphic-component/components/packages/Train/Train';
|
||||
import {
|
||||
EnumDiriveModel,
|
||||
EnumStatusText,
|
||||
EnumTrainType,
|
||||
UpdateTrainConsts,
|
||||
} from 'rt-graphic-component/components/packages/Train/TrainConfig';
|
||||
|
||||
export interface ITrainData extends GraphicData {
|
||||
get code(): string; // 车号
|
||||
@ -72,285 +75,13 @@ export interface ITrainState extends GraphicState {
|
||||
set record(v: train.TrainRecord);
|
||||
}
|
||||
|
||||
interface bodyWH {
|
||||
width: number; // 宽
|
||||
height: number; // 高
|
||||
}
|
||||
|
||||
// 列车颜色
|
||||
export enum TrainColorEnum {
|
||||
headColor = '0xFFCE4D', // 箭头颜色
|
||||
bodyColor = '0xA388B1', // 背景色
|
||||
codeColor = '0xffffff', // 车号颜色
|
||||
borderColor = '0xA3E198', // 边框的颜色
|
||||
directionColor = '0x00FF00', // 方向箭头颜色
|
||||
}
|
||||
|
||||
enum DiriveModelColorEnum { // 驾驶模式对应颜色
|
||||
AM = '0x00FF00', // ATO自动驾驶
|
||||
SM = '0xFFFF00', // ATP 监控下的人工驾驶模式
|
||||
RM = '0xFFC837', // 限制人工驾驶模式
|
||||
NRM = '0xA0522D', // 非限制人工驾驶模式
|
||||
red = '0xF80103', // 红色表示通信中断
|
||||
}
|
||||
enum BBBColorEnum { // 识别号颜色
|
||||
accuracy = '0xffffff', // 准点
|
||||
early = '0x00FF00', // 早点
|
||||
late = '0xFFFF00', // 晚点
|
||||
schedule = '0xffffff', // 计划车
|
||||
head = '0xE9FC01', // 头码车
|
||||
manual = '0xE9FC01', // 人工车
|
||||
special = '0xE9FC01', // 特殊车
|
||||
}
|
||||
|
||||
enum statusTextColor {
|
||||
H = '0xFFFF00', // H扣车
|
||||
S = '0x6260F3', // S跳停
|
||||
D = '0x00FF00', // D开门
|
||||
A = '0xFF0000', // A报警
|
||||
}
|
||||
|
||||
const deviceTypeString = new Map();
|
||||
deviceTypeString.set(state.DeviceType.TRACK, LogicSection.Type);
|
||||
deviceTypeString.set(state.DeviceType.SWITCH_TRACK, Section.Type);
|
||||
|
||||
export const trainConsts = {
|
||||
codeWidth: 120,
|
||||
codeHeight: 40,
|
||||
codePadding: 5,
|
||||
borderWidth: 1,
|
||||
codeFontSize: 22,
|
||||
textFontSize: 16, // 状态字母大小
|
||||
textMarginY: 10, // 状态字母与列车距离
|
||||
statusTextList: ['H', 'S', 'D', 'A'],
|
||||
marginX: 4, // 图形x轴边距
|
||||
pauseW: 4, // 停止框宽度
|
||||
};
|
||||
|
||||
export class TrainHead extends Container {
|
||||
arrow: Graphics; // 箭头
|
||||
pause: Graphics; // 停止
|
||||
constructor() {
|
||||
super();
|
||||
this.arrow = new Graphics();
|
||||
this.pause = new Graphics();
|
||||
this.addChild(this.arrow);
|
||||
this.addChild(this.pause);
|
||||
}
|
||||
clear() {
|
||||
this.arrow.clear();
|
||||
this.pause.clear();
|
||||
}
|
||||
doRepaint(states: ITrainState, bodyWH?: bodyWH) {
|
||||
let direction = '';
|
||||
if (states.mode?.ipModeTrainDirDown) {
|
||||
direction = 'left';
|
||||
}
|
||||
if (states.mode?.ipModeTrainDirUp) {
|
||||
direction = 'right';
|
||||
}
|
||||
this.clear();
|
||||
if (!direction) {
|
||||
return;
|
||||
}
|
||||
const marginX = trainConsts.marginX;
|
||||
const pauseW = trainConsts.pauseW;
|
||||
const codeWidth = bodyWH ? bodyWH.width : trainConsts.codeWidth;
|
||||
const codeHeight = bodyWH ? bodyWH.height : trainConsts.codeHeight;
|
||||
let arrowPoint = [
|
||||
-codeHeight * 0.4 - marginX - codeWidth / 2,
|
||||
0,
|
||||
-marginX - codeWidth / 2,
|
||||
codeHeight / 2,
|
||||
-marginX - codeWidth / 2,
|
||||
-codeHeight / 2,
|
||||
];
|
||||
let pausePoint = [
|
||||
-marginX - pauseW / 2 - codeWidth / 2,
|
||||
-codeHeight / 2,
|
||||
-marginX - pauseW / 2 - codeWidth / 2,
|
||||
codeHeight / 2,
|
||||
];
|
||||
if (direction != 'left') {
|
||||
const aP: Array<number> = [];
|
||||
arrowPoint.forEach((item, index) => {
|
||||
if (index % 2 == 1) {
|
||||
const p = new Point(arrowPoint[index - 1], item);
|
||||
const newP = calculateMirrorPoint(new Point(0, 0), p);
|
||||
aP.push(newP.x, newP.y);
|
||||
}
|
||||
});
|
||||
arrowPoint = aP;
|
||||
const pP: Array<number> = [];
|
||||
pausePoint.forEach((item, index) => {
|
||||
if (index % 2 == 1) {
|
||||
const p = new Point(pausePoint[index - 1], item);
|
||||
const newP = calculateMirrorPoint(new Point(0, 0), p);
|
||||
pP.push(newP.x, newP.y);
|
||||
}
|
||||
});
|
||||
pausePoint = pP;
|
||||
}
|
||||
let aColor = DiriveModelColorEnum.AM;
|
||||
let pColor = DiriveModelColorEnum.SM;
|
||||
if (states.mode?.ipModeTrainDriveModeCm) {
|
||||
aColor = DiriveModelColorEnum.SM;
|
||||
pColor = DiriveModelColorEnum.SM;
|
||||
} else if (
|
||||
states.mode?.ipModeTrainDriveModeRmf ||
|
||||
states.mode?.ipModeTrainDriveModeRmr
|
||||
) {
|
||||
aColor = DiriveModelColorEnum.RM;
|
||||
pColor = DiriveModelColorEnum.RM;
|
||||
}
|
||||
if (states.mode?.ipModeTrainStoped) {
|
||||
this.pause.lineStyle(pauseW, pColor, 1);
|
||||
this.pause.moveTo(pausePoint[0], pausePoint[1]);
|
||||
this.pause.lineTo(pausePoint[2], pausePoint[3]);
|
||||
} else {
|
||||
const arrow = this.arrow;
|
||||
arrow.beginFill(aColor, 1);
|
||||
arrow.drawPolygon(arrowPoint);
|
||||
arrow.endFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TrainBody extends Container {
|
||||
// codeRact: Graphics;
|
||||
codeAGraph: VectorText = new VectorText(''); //识别号AA
|
||||
codeBGraph: VectorText = new VectorText(''); //识别号BBB
|
||||
constructor() {
|
||||
super();
|
||||
// this.codeRact = new Graphics();
|
||||
// this.addChild(this.codeRact);
|
||||
this.addChild(this.codeAGraph);
|
||||
this.addChild(this.codeBGraph);
|
||||
this.codeAGraph.setVectorFontSize(trainConsts.codeFontSize);
|
||||
this.codeBGraph.setVectorFontSize(trainConsts.codeFontSize);
|
||||
}
|
||||
clear() {
|
||||
// this.codeRact.clear();
|
||||
this.codeAGraph.text = '';
|
||||
this.codeBGraph.text = '';
|
||||
}
|
||||
getBodyWH(): bodyWH {
|
||||
const bodyAWH = this.codeAGraph.localBoundsToCanvasPoints();
|
||||
const bodyBWH = this.codeBGraph.localBoundsToCanvasPoints();
|
||||
return {
|
||||
width: bodyAWH[1].x - bodyAWH[0].x + bodyBWH[1].x - bodyBWH[0].x,
|
||||
height: bodyAWH[2].y - bodyAWH[1].y,
|
||||
};
|
||||
}
|
||||
|
||||
doRepaint(states: ITrainState): void {
|
||||
this.clear();
|
||||
const codeAGraph = this.codeAGraph;
|
||||
const codeBGraph = this.codeBGraph;
|
||||
// const codeRact = this.codeRact;
|
||||
let codeA = states.trainId;
|
||||
// let codeA = states?.groupId;
|
||||
// const firstChar = codeA.substring(0, 1); // 获取首字符
|
||||
// if (+firstChar == states.lineId) {
|
||||
// codeA = codeA.substring(1); // 删除首字符是线路号的字符
|
||||
// }
|
||||
const fillAColor = BBBColorEnum.schedule;
|
||||
let fillBColor = BBBColorEnum.schedule;
|
||||
if (states.mode?.ipModeTrainTypeSchedule) {
|
||||
if (states.mode?.ipModeTrainSchdLate) {
|
||||
fillBColor = BBBColorEnum.late;
|
||||
} else if (states.mode?.ipModeTrainSchdEarly) {
|
||||
fillBColor = BBBColorEnum.early;
|
||||
}
|
||||
} else if (states.mode?.ipModeTrainTypeHead) {
|
||||
codeA = states?.destinationId + '';
|
||||
fillBColor = BBBColorEnum.head;
|
||||
} else if (states.mode?.ipModeTrainTypeManual) {
|
||||
codeA = 'MM';
|
||||
fillBColor = BBBColorEnum.manual;
|
||||
} else if (states.mode?.ipModeTrainTypeSpecial) {
|
||||
codeA = '';
|
||||
}
|
||||
const codeB = states?.globalId;
|
||||
codeAGraph.text = codeA || '01';
|
||||
codeBGraph.text = codeB || '222';
|
||||
codeAGraph.anchor.set(0.5);
|
||||
codeBGraph.anchor.set(0.5);
|
||||
const styleA = {
|
||||
fill: fillAColor,
|
||||
fontSize: trainConsts.codeFontSize,
|
||||
};
|
||||
const styleB = {
|
||||
fill: fillBColor,
|
||||
fontSize: trainConsts.codeFontSize,
|
||||
};
|
||||
codeAGraph.style = styleA;
|
||||
codeBGraph.style = styleB;
|
||||
const bodyAWH = codeAGraph.getLocalBounds();
|
||||
const bodyBWH = codeBGraph.getLocalBounds();
|
||||
codeAGraph.position.set(-bodyBWH.width / 2, 0);
|
||||
codeBGraph.position.set(bodyAWH.width / 2, 0);
|
||||
codeAGraph.updateOnScaled();
|
||||
codeBGraph.updateOnScaled();
|
||||
// const { width: codeWidth, height: codeHeight } = this.getBodyWH();
|
||||
// codeRact.beginFill(new Color(TrainColorEnum.bodyColor));
|
||||
// codeRact.drawRect(-codeWidth / 2, -codeHeight / 2, codeWidth, codeHeight);
|
||||
// codeRact.endFill();
|
||||
}
|
||||
}
|
||||
|
||||
class StatusText extends Container {
|
||||
sText: VectorText = new VectorText('');
|
||||
constructor() {
|
||||
super();
|
||||
this.addChild(this.sText);
|
||||
}
|
||||
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 style = {
|
||||
fill: c,
|
||||
fontSize: trainConsts.textFontSize,
|
||||
};
|
||||
this.sText.style = style;
|
||||
const { width: codeWidth, height: codeHeight } = bodyWH;
|
||||
const { width: textHWidth, height: textHeight } =
|
||||
this.sText.getLocalBounds();
|
||||
const num = trainConsts.statusTextList.length;
|
||||
let index = trainConsts.statusTextList.findIndex((item) => {
|
||||
return item == text;
|
||||
});
|
||||
if (index < 0) {
|
||||
index = (num - 1) / 2; // 中间
|
||||
}
|
||||
const textMargin = (codeWidth - textHWidth * num) / (num - 1);
|
||||
this.sText.position.set(
|
||||
-codeWidth / 2 + (textHWidth * (index * 2 + 1)) / 2 + textMargin * index,
|
||||
-codeHeight / 2 - textHeight / 2 - trainConsts.textMarginY
|
||||
);
|
||||
}
|
||||
clear(): void {
|
||||
this.sText.text = '';
|
||||
}
|
||||
}
|
||||
|
||||
export class Train extends JlGraphic {
|
||||
static Type = 'Train';
|
||||
|
||||
trainHead: TrainHead;
|
||||
trainbody: TrainBody;
|
||||
statusTextMap: Map<string, StatusText> = new Map();
|
||||
constructor() {
|
||||
super(Train.Type);
|
||||
this.trainbody = new TrainBody();
|
||||
this.trainHead = new TrainHead();
|
||||
this.addChild(this.trainHead);
|
||||
this.addChild(this.trainbody);
|
||||
}
|
||||
|
||||
get datas(): ITrainData {
|
||||
return this.getDatas<ITrainData>();
|
||||
export class Train extends XaTrain {
|
||||
constructor(data?: UpdateTrainConsts) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
get states(): ITrainState {
|
||||
@ -371,52 +102,78 @@ export class Train extends JlGraphic {
|
||||
this.trainbody.clear();
|
||||
return;
|
||||
}
|
||||
this.trainbody.doRepaint(this.states);
|
||||
const bodyWH = this.trainbody.getBodyWH();
|
||||
this.trainHead.doRepaint(this.states, bodyWH);
|
||||
if (this.states.mode?.ipModeTrainHolded) {
|
||||
this.showStatus('H');
|
||||
let direction = '';
|
||||
if (this.states.mode?.ipModeTrainDirDown) {
|
||||
direction = 'left';
|
||||
}
|
||||
if (this.states.mode?.ipModeTrainDirUp) {
|
||||
direction = 'right';
|
||||
}
|
||||
this.isRightRoTop = direction != 'left';
|
||||
if (!direction) {
|
||||
this.trainHead.clear();
|
||||
}
|
||||
let dModel = EnumDiriveModel.AM;
|
||||
if (this.states.mode?.ipModeTrainDriveModeCm) {
|
||||
dModel = EnumDiriveModel.SM;
|
||||
} else if (
|
||||
this.states.mode?.ipModeTrainDriveModeRmf ||
|
||||
this.states.mode?.ipModeTrainDriveModeRmr
|
||||
) {
|
||||
dModel = EnumDiriveModel.RM;
|
||||
}
|
||||
this.setDiriveModelColor(dModel);
|
||||
let codeA = this.states.trainId;
|
||||
let tType = EnumTrainType.schedule;
|
||||
if (this.states.mode?.ipModeTrainTypeSchedule) {
|
||||
if (this.states.mode?.ipModeTrainSchdLate) {
|
||||
tType = EnumTrainType.late;
|
||||
} else if (this.states.mode?.ipModeTrainSchdEarly) {
|
||||
tType = EnumTrainType.early;
|
||||
}
|
||||
} else if (this.states.mode?.ipModeTrainTypeHead) {
|
||||
codeA = this.states?.destinationId + '';
|
||||
tType = EnumTrainType.head;
|
||||
} else if (this.states.mode?.ipModeTrainTypeManual) {
|
||||
codeA = 'MM';
|
||||
tType = EnumTrainType.manual;
|
||||
} else if (this.states.mode?.ipModeTrainTypeSpecial) {
|
||||
codeA = '';
|
||||
}
|
||||
this.setTrainTypeColor(tType);
|
||||
const codeB = this.states?.globalId;
|
||||
this.setCodeAText(codeA);
|
||||
this.setCodeBText(codeB);
|
||||
this.trainbody.doRepaint();
|
||||
this.trainHead.doRepaint();
|
||||
if (this.states.mode?.ipModeTrainStoped) {
|
||||
this.stop();
|
||||
} else {
|
||||
this.hideStatus('H');
|
||||
this.run();
|
||||
}
|
||||
if (this.states.mode?.ipModeTrainHolded) {
|
||||
this.showStatus(EnumStatusText.H);
|
||||
} else {
|
||||
this.hideStatus(EnumStatusText.H);
|
||||
}
|
||||
if (this.states.mode?.ipModeTrainSkipstop) {
|
||||
this.showStatus('S');
|
||||
this.showStatus(EnumStatusText.S);
|
||||
} else {
|
||||
this.hideStatus('S');
|
||||
this.hideStatus(EnumStatusText.S);
|
||||
}
|
||||
if (this.states.mode?.ipModeTrainDoorOpen) {
|
||||
this.showStatus('D');
|
||||
this.showStatus(EnumStatusText.D);
|
||||
} else {
|
||||
this.hideStatus('D');
|
||||
this.hideStatus(EnumStatusText.D);
|
||||
}
|
||||
if (this.states.mode?.ipModeTrainRsAlarm) {
|
||||
this.showStatus('A');
|
||||
this.showStatus(EnumStatusText.A);
|
||||
} else {
|
||||
this.hideStatus('A');
|
||||
this.hideStatus(EnumStatusText.A);
|
||||
}
|
||||
this.setPosition();
|
||||
}
|
||||
|
||||
showStatus(s: string) {
|
||||
if (this.statusTextMap.has(s)) {
|
||||
return;
|
||||
}
|
||||
const bodyWH = this.trainbody.getBodyWH();
|
||||
const textD = new StatusText();
|
||||
textD.doRepaint(s, bodyWH);
|
||||
this.addChild(textD);
|
||||
this.statusTextMap.set(s, textD);
|
||||
}
|
||||
hideStatus(s: string) {
|
||||
if (!this.statusTextMap.has(s)) {
|
||||
return;
|
||||
}
|
||||
const textD = this.statusTextMap.get(s);
|
||||
if (textD) {
|
||||
textD.clear();
|
||||
this.statusTextMap.delete(s);
|
||||
}
|
||||
}
|
||||
setPosition(): void {
|
||||
if (deviceTypeString.get(this.states.devType)) {
|
||||
const dev = this.queryStore.queryByCodeAndType<LogicSection | Section>(
|
||||
@ -455,12 +212,22 @@ export class Train extends JlGraphic {
|
||||
}
|
||||
}
|
||||
|
||||
const updataConsts: UpdateTrainConsts = {
|
||||
arrowPauseOnlyOne: true,
|
||||
hasBodyRact: false,
|
||||
textMarginY: 10, // 状态字母与列车距离
|
||||
marginX: 4, // 图形x轴边距
|
||||
borderColor: '0xA3E198', // 边框的颜色
|
||||
arrowDefaultColor: '0x00FF00', // 箭头默认颜色
|
||||
pauseDefaultColor: '0xFFCE4D', // 停止默认颜色
|
||||
};
|
||||
|
||||
export class TrainTemplate extends JlGraphicTemplate<Train> {
|
||||
constructor(dataTemplate: ITrainData, stateTemplate: ITrainState) {
|
||||
super(Train.Type, { dataTemplate, stateTemplate });
|
||||
}
|
||||
new(): Train {
|
||||
const train = new Train();
|
||||
const train = new Train(updataConsts);
|
||||
train.id = GraphicIdGenerator.next();
|
||||
train.loadState(this.states);
|
||||
return train;
|
||||
|
@ -1,732 +1,15 @@
|
||||
import { Graphics, IPointData } from 'pixi.js';
|
||||
import {
|
||||
GraphicAnimation,
|
||||
GraphicData,
|
||||
GraphicRelationParam,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
VectorText,
|
||||
angleOfIncludedAngle,
|
||||
distance2,
|
||||
getParallelOfPolyline,
|
||||
epsilon,
|
||||
Vector2,
|
||||
} from 'jl-graphic';
|
||||
import { Section, SectionPort, SectionType } from '../section/Section';
|
||||
import {
|
||||
IRelatedRefData,
|
||||
createRelatedRefProto,
|
||||
protoPort2Data,
|
||||
} from '../CommonGraphics';
|
||||
import { KilometerSystem } from '../signal/Signal';
|
||||
import { Station } from '../station/Station';
|
||||
import { THTurnout as Turnout } from 'rt-graphic-component/components/packages/Turnout/THTurnout';
|
||||
|
||||
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 centralizedStation(): number; //所属集中站
|
||||
set centralizedStation(v: number);
|
||||
clone(): ITurnoutData;
|
||||
copyFrom(data: ITurnoutData): void;
|
||||
eq(other: ITurnoutData): boolean;
|
||||
}
|
||||
import { ITurnoutData } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutConfig';
|
||||
import { TurnoutTemplate } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutTemplate';
|
||||
import { ITHTurnoutState as ITurnoutState } from 'rt-graphic-component/components/packages/Turnout/THTurnout';
|
||||
import { TurnoutDraw } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
|
||||
|
||||
export const TurnoutConsts = {
|
||||
lineColor: '#5578b6',
|
||||
idleColor: '#888', //空闲
|
||||
jammedLineColor: '#f00', //挤岔
|
||||
ciOccupiedColor: '#f00', //非通信车占用
|
||||
cbtcOccupiedColor: '#f49', //通信车占用
|
||||
lockedColor: '#fff', //锁闭 && 故障锁闭
|
||||
atcInvalidColor: '#954', //atc报告失效
|
||||
overlapColor: '#ff0', //overlap
|
||||
blueShowColor: '0x3149c3',
|
||||
lineWidth: 5,
|
||||
forkLenth: 20,
|
||||
labelFontSize: 12,
|
||||
};
|
||||
|
||||
const TurnoutLabelColor = {
|
||||
GREEN: '#0f0',
|
||||
YELLOW: '#ff0',
|
||||
RED: '#f00',
|
||||
WHITE: '#fff',
|
||||
};
|
||||
|
||||
export enum TurnoutPosition {
|
||||
NORMAL = 0,
|
||||
REVERSE = 1,
|
||||
}
|
||||
export { Turnout, TurnoutTemplate, TurnoutDraw };
|
||||
export type { ITurnoutState, ITurnoutData };
|
||||
|
||||
export enum TurnoutPort {
|
||||
A = 'A',
|
||||
B = 'B',
|
||||
C = 'C',
|
||||
}
|
||||
|
||||
export interface ITurnoutState extends GraphicState {
|
||||
ipSingleSwitchStusCiOccupied: boolean;
|
||||
ipSingleSwitchStusCbtcOccupied: boolean;
|
||||
ipSingleSwitchStusLocked: boolean;
|
||||
ipSingleSwitchStusFailLocked: boolean;
|
||||
ipSingleSwitchStusNormal: boolean;
|
||||
ipSingleSwitchStusReverse: boolean;
|
||||
ipSingleSwitchStusBlocked1: boolean;
|
||||
ipSingleSwitchStusJammed: boolean;
|
||||
ipSingleSwitchStusCut: boolean;
|
||||
ipSingleSwitchStusAtcInvalid: boolean;
|
||||
ipSingleSwitchStusOverlap: boolean;
|
||||
ipSingleSwitchStusTsrCbtcMain: boolean;
|
||||
ipSingleSwitchStusTsrCbtcNormal: boolean;
|
||||
ipSingleSwitchStusTsrCbtcReverse: boolean;
|
||||
ipSingleSwitchStusTsrBmMain: boolean;
|
||||
ipSingleSwitchStusTsrBmNormal: boolean;
|
||||
ipSingleSwitchStusTsrBmReverse: boolean;
|
||||
ipSingleSwitchStusBlocked2: boolean;
|
||||
ipSingleSwitchStusLostIndication: boolean;
|
||||
id: string;
|
||||
speedLimit: number;
|
||||
rtuId: number;
|
||||
}
|
||||
|
||||
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: TurnoutPort;
|
||||
constructor(turnout: Turnout, port: TurnoutPort) {
|
||||
super();
|
||||
this.turnout = turnout;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
paint() {
|
||||
let pList: IPointData[] = [];
|
||||
let lineColor = this.turnout.lineColor;
|
||||
switch (this.port) {
|
||||
case TurnoutPort.A:
|
||||
pList = this.turnout.datas.pointA;
|
||||
break;
|
||||
case TurnoutPort.B:
|
||||
pList = this.turnout.datas.pointB;
|
||||
if (!this.turnout.states.ipSingleSwitchStusNormal) {
|
||||
lineColor = TurnoutConsts.idleColor;
|
||||
}
|
||||
break;
|
||||
case TurnoutPort.C:
|
||||
pList = this.turnout.datas.pointC;
|
||||
if (!this.turnout.states.ipSingleSwitchStusReverse) {
|
||||
lineColor = TurnoutConsts.idleColor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
const station = this.turnout.queryStore.queryByCodeAndType<Station>(
|
||||
this.turnout.states.rtuId > 9
|
||||
? '' + this.turnout.states.rtuId
|
||||
: '0' + this.turnout.states.rtuId,
|
||||
Station.Type
|
||||
);
|
||||
if (station?.states.ipRtuStusDown) {
|
||||
lineColor = TurnoutConsts.blueShowColor;
|
||||
}
|
||||
const gap = this.port === TurnoutPort.A ? 0 : TurnoutConsts.forkLenth;
|
||||
const start = getForkPoint(gap, pList[0]);
|
||||
this.clear()
|
||||
.lineStyle(TurnoutConsts.lineWidth, lineColor)
|
||||
.moveTo(start.x, start.y);
|
||||
|
||||
pList.forEach((p) => {
|
||||
const { x, y } = p;
|
||||
this.lineTo(x, y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ForkGraphic extends Graphics {
|
||||
turnout: Turnout;
|
||||
dt = 0;
|
||||
lostIndicationSquare: Graphics = new Graphics();
|
||||
constructor(turnout: Turnout) {
|
||||
super();
|
||||
this.turnout = turnout;
|
||||
this.addChild(this.lostIndicationSquare);
|
||||
}
|
||||
|
||||
paint() {
|
||||
this.clear();
|
||||
this.lostIndicationSquare.clear();
|
||||
if (
|
||||
this.turnout.states.ipSingleSwitchStusJammed /* ||
|
||||
this.turnout.states.ipSingleSwitchStusLostIndication */
|
||||
) {
|
||||
let x: number, y: number;
|
||||
const w = 24,
|
||||
h = 24;
|
||||
if (this.turnout.datas.pointA[0].x > this.turnout.datas.pointB[0].x) {
|
||||
x = -22;
|
||||
} else {
|
||||
x = -2;
|
||||
}
|
||||
if (this.turnout.datas.pointC[0].y > 0) {
|
||||
y = -2;
|
||||
} else {
|
||||
y = -20;
|
||||
}
|
||||
this.lostIndicationSquare.lineStyle(2, '#f00').drawRect(x, y, w, h);
|
||||
const flashAnimation = this.bindFlashAnimation(this.lostIndicationSquare);
|
||||
flashAnimation.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.turnout.states.ipSingleSwitchStusNormal) {
|
||||
this.paintForkLine('B');
|
||||
this.turnout.removeAllAnimation();
|
||||
} else if (this.turnout.states.ipSingleSwitchStusReverse) {
|
||||
this.paintForkLine('C');
|
||||
this.turnout.removeAllAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
paintForkLine(position: 'B' | 'C' | 'BOTH') {
|
||||
this.clear().lineStyle(TurnoutConsts.lineWidth, this.turnout.lineColor);
|
||||
|
||||
const targetB = getForkPoint(
|
||||
TurnoutConsts.forkLenth,
|
||||
this.turnout.datas.pointB[0]
|
||||
);
|
||||
const targetC = getForkPoint(
|
||||
TurnoutConsts.forkLenth,
|
||||
this.turnout.datas.pointC[0]
|
||||
);
|
||||
if (position === 'B') {
|
||||
this.moveTo(0, 0).lineTo(targetB.x, targetB.y);
|
||||
} else if (position === 'C') {
|
||||
this.moveTo(0, 0).lineTo(targetC.x, targetC.y);
|
||||
} else if (position === 'BOTH') {
|
||||
this.moveTo(targetB.x, targetB.y)
|
||||
.lineTo(0, 0)
|
||||
.lineTo(targetC.x, targetC.y);
|
||||
}
|
||||
}
|
||||
|
||||
bindFlashAnimation(g: Graphics) {
|
||||
const flashAnimation = GraphicAnimation.init({
|
||||
name: 'lostIndicationFlash',
|
||||
run: (dt: number) => {
|
||||
this.dt += dt;
|
||||
if (this.dt > 60) {
|
||||
this.dt = 0;
|
||||
g.visible = true;
|
||||
} else if (this.dt > 30) {
|
||||
g.visible = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
this.turnout.addAnimation(flashAnimation);
|
||||
return flashAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
export class Turnout extends JlGraphic {
|
||||
static Type = 'Turnout';
|
||||
graphics: {
|
||||
fork: ForkGraphic;
|
||||
sections: [TurnoutSection, TurnoutSection, TurnoutSection];
|
||||
label: VectorText;
|
||||
labelRect: Graphics;
|
||||
speedLimit: Graphics;
|
||||
};
|
||||
lineColor: string;
|
||||
dt = 0;
|
||||
|
||||
constructor() {
|
||||
super(Turnout.Type);
|
||||
this.name = 'turnout';
|
||||
this.lineColor = TurnoutConsts.lineColor;
|
||||
this.graphics = {
|
||||
fork: new ForkGraphic(this),
|
||||
sections: [
|
||||
new TurnoutSection(this, TurnoutPort.A),
|
||||
new TurnoutSection(this, TurnoutPort.B),
|
||||
new TurnoutSection(this, TurnoutPort.C),
|
||||
],
|
||||
label: new VectorText(),
|
||||
labelRect: new Graphics(),
|
||||
speedLimit: new Graphics(),
|
||||
};
|
||||
this.addChild(this.graphics.sections[0]);
|
||||
this.addChild(this.graphics.sections[1]);
|
||||
this.addChild(this.graphics.sections[2]);
|
||||
this.addChild(this.graphics.fork);
|
||||
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);
|
||||
this.addChild(this.graphics.labelRect);
|
||||
this.addChild(this.graphics.speedLimit);
|
||||
}
|
||||
|
||||
get code(): string {
|
||||
return this.datas.code;
|
||||
}
|
||||
|
||||
set code(code: string) {
|
||||
this.datas.code = code;
|
||||
}
|
||||
|
||||
get datas(): ITurnoutData {
|
||||
return this.getDatas<ITurnoutData>();
|
||||
}
|
||||
|
||||
get states(): ITurnoutState {
|
||||
return this.getStates<ITurnoutState>();
|
||||
}
|
||||
|
||||
getSpeedLimitLinePoints(conf: 'normal' | 'reverse' | 'main'): IPointData[][] {
|
||||
const [pa, pb, pc] = [
|
||||
this.datas.pointA[0],
|
||||
this.datas.pointB[0],
|
||||
this.datas.pointC[0],
|
||||
];
|
||||
const [va, vb, vc] = [
|
||||
new Vector2([pa.x, pa.y]),
|
||||
new Vector2([pb.x, pb.y]),
|
||||
new Vector2([pc.x, pc.y]),
|
||||
];
|
||||
const [vab, vbc] = [vb.subtract(va), vc.subtract(vb)];
|
||||
const cpd = vab.x * vbc.y - vab.y * vbc.x;
|
||||
const side = cpd > 0 ? 'L' : 'R'; //计算三个分支的手性
|
||||
|
||||
const offset = 10;
|
||||
if (conf === 'main') {
|
||||
return [
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
],
|
||||
offset,
|
||||
'L'
|
||||
),
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
],
|
||||
offset,
|
||||
'R'
|
||||
),
|
||||
];
|
||||
} else if (conf === 'normal') {
|
||||
return [
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
...this.datas.pointB.map((p) => ({ x: p.x, y: p.y })),
|
||||
],
|
||||
offset,
|
||||
'L'
|
||||
),
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
...this.datas.pointB.map((p) => ({ x: p.x, y: p.y })),
|
||||
],
|
||||
offset,
|
||||
'R'
|
||||
),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
...this.datas.pointC.map((p) => ({ x: p.x, y: p.y })),
|
||||
],
|
||||
offset,
|
||||
'L'
|
||||
),
|
||||
getParallelOfPolyline(
|
||||
[
|
||||
...this.datas.pointA.map((p) => ({ x: p.x, y: p.y })).reverse(),
|
||||
{ x: 0, y: 0 },
|
||||
...this.datas.pointC.map((p) => ({ x: p.x, y: p.y })),
|
||||
],
|
||||
offset,
|
||||
'R'
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
getPortPoints() {
|
||||
return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
|
||||
}
|
||||
|
||||
doRepaint(): void {
|
||||
//线条颜色
|
||||
const station = this.queryStore.queryByCodeAndType<Station>(
|
||||
this.states.rtuId > 9 ? '' + this.states.rtuId : '0' + this.states.rtuId,
|
||||
Station.Type
|
||||
);
|
||||
if (station?.states.ipRtuStusDown) {
|
||||
this.lineColor = TurnoutConsts.blueShowColor;
|
||||
} else if (this.states.ipSingleSwitchStusCbtcOccupied) {
|
||||
this.lineColor = TurnoutConsts.cbtcOccupiedColor;
|
||||
} else if (this.states.ipSingleSwitchStusCiOccupied) {
|
||||
this.lineColor = TurnoutConsts.ciOccupiedColor;
|
||||
} else if (
|
||||
this.states.ipSingleSwitchStusLocked ||
|
||||
this.states.ipSingleSwitchStusFailLocked
|
||||
) {
|
||||
this.lineColor = TurnoutConsts.lockedColor;
|
||||
} else if (this.states.ipSingleSwitchStusAtcInvalid) {
|
||||
this.lineColor = TurnoutConsts.atcInvalidColor;
|
||||
} else if (this.states.ipSingleSwitchStusOverlap) {
|
||||
this.lineColor = TurnoutConsts.overlapColor;
|
||||
} else {
|
||||
this.lineColor = TurnoutConsts.idleColor;
|
||||
}
|
||||
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
|
||||
|
||||
this.graphics.fork.paint();
|
||||
|
||||
this.graphics.label.text = this.datas.code;
|
||||
|
||||
//文字颜色
|
||||
if (this.states.ipSingleSwitchStusBlocked1) {
|
||||
this.graphics.label.style.fill = TurnoutLabelColor.RED;
|
||||
} else if (this.states.ipSingleSwitchStusNormal) {
|
||||
this.graphics.label.style.fill = TurnoutLabelColor.GREEN;
|
||||
} else if (this.states.ipSingleSwitchStusReverse) {
|
||||
this.graphics.label.style.fill = TurnoutLabelColor.YELLOW;
|
||||
} else if (
|
||||
this.states.ipSingleSwitchStusJammed ||
|
||||
this.states.ipSingleSwitchStusLostIndication
|
||||
) {
|
||||
this.graphics.label.style.fill = TurnoutLabelColor.WHITE;
|
||||
}
|
||||
|
||||
this.graphics.labelRect.clear();
|
||||
this.graphics.speedLimit.clear();
|
||||
this.graphics.fork.visible = true;
|
||||
this.graphics.sections.forEach((s) => (s.visible = true));
|
||||
this.removeAnimation('flash');
|
||||
|
||||
//文字框
|
||||
if (this.states.ipSingleSwitchStusBlocked2) {
|
||||
this.graphics.labelRect.clear().lineStyle(1, '#f00');
|
||||
const { width, height } = this.graphics.label.getLocalBounds();
|
||||
const { x, y } = this.graphics.label.transform.position;
|
||||
this.graphics.labelRect.drawRect(
|
||||
x - width / 2,
|
||||
y - height / 2,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
if (station?.states.ipRtuStusDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(this.states.speedLimit && this.states.speedLimit > 0) ||
|
||||
this.states.ipSingleSwitchStusTsrBmMain ||
|
||||
this.states.ipSingleSwitchStusTsrBmNormal ||
|
||||
this.states.ipSingleSwitchStusTsrBmReverse ||
|
||||
this.states.ipSingleSwitchStusTsrCbtcMain ||
|
||||
this.states.ipSingleSwitchStusTsrCbtcNormal ||
|
||||
this.states.ipSingleSwitchStusTsrCbtcReverse
|
||||
) {
|
||||
let limitConf: Parameters<
|
||||
typeof Turnout.prototype.getSpeedLimitLinePoints
|
||||
>[0];
|
||||
if (
|
||||
this.states.ipSingleSwitchStusTsrBmReverse ||
|
||||
this.states.ipSingleSwitchStusTsrCbtcReverse
|
||||
) {
|
||||
limitConf = 'reverse';
|
||||
} else if (
|
||||
this.states.ipSingleSwitchStusTsrBmNormal ||
|
||||
this.states.ipSingleSwitchStusTsrCbtcNormal
|
||||
) {
|
||||
limitConf = 'normal';
|
||||
} else {
|
||||
limitConf = 'main';
|
||||
}
|
||||
const points = this.getSpeedLimitLinePoints(limitConf);
|
||||
this.graphics.speedLimit.lineStyle(1, '#ff0');
|
||||
points.forEach((ps) => {
|
||||
this.graphics.speedLimit.moveTo(ps[0].x, ps[0].y);
|
||||
for (let i = 1; i < ps.length; i++) {
|
||||
this.graphics.speedLimit.lineTo(ps[i].x, ps[i].y);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.states.ipSingleSwitchStusCut) {
|
||||
if (this.states.ipSingleSwitchStusNormal) {
|
||||
this.bindFlashAnimation([
|
||||
this.graphics.fork,
|
||||
this.graphics.sections[0],
|
||||
this.graphics.sections[1],
|
||||
]);
|
||||
} else if (this.states.ipSingleSwitchStusReverse) {
|
||||
this.bindFlashAnimation([
|
||||
this.graphics.fork,
|
||||
this.graphics.sections[0],
|
||||
this.graphics.sections[2],
|
||||
]);
|
||||
}
|
||||
this.animation('flash')?.resume();
|
||||
}
|
||||
}
|
||||
|
||||
bindFlashAnimation(gList: Graphics[]) {
|
||||
const flashAnimation = GraphicAnimation.init({
|
||||
name: 'flash',
|
||||
run: (dt: number) => {
|
||||
this.dt += dt;
|
||||
if (this.dt > 60) {
|
||||
this.dt = 0;
|
||||
gList.forEach((g) => (g.visible = true));
|
||||
} else if (this.dt > 30) {
|
||||
gList.forEach((g) => (g.visible = false));
|
||||
}
|
||||
},
|
||||
});
|
||||
this.addAnimation(flashAnimation);
|
||||
return flashAnimation;
|
||||
}
|
||||
|
||||
getGraphicOfPort(port: TurnoutPort) {
|
||||
return this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.filter(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this).getParam<TurnoutPort>() === port
|
||||
)
|
||||
.map((relation) => {
|
||||
return relation.getOtherGraphic(this);
|
||||
});
|
||||
}
|
||||
|
||||
buildRelation(): void {
|
||||
this.relationManage.deleteRelationOfGraphic(this);
|
||||
|
||||
|
||||
/** 道岔和区段 */
|
||||
this.queryStore.queryByType<Section>(Section.Type)
|
||||
.forEach((section) => {
|
||||
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
|
||||
if (section.datas.children.includes(this.datas.id)) {
|
||||
this.relationManage.addRelation(this, section)
|
||||
}
|
||||
return
|
||||
}
|
||||
this.getPortPoints().forEach((port, i) => {
|
||||
if (
|
||||
distance2(
|
||||
section.localToCanvasPoint(section.getStartPoint()),
|
||||
this.localToCanvasPoint(port[port.length - 1])
|
||||
) <= epsilon
|
||||
) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(
|
||||
this,
|
||||
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
|
||||
),
|
||||
new GraphicRelationParam(section, SectionPort.A)
|
||||
);
|
||||
}
|
||||
if (
|
||||
distance2(
|
||||
section.localToCanvasPoint(section.getEndPoint()),
|
||||
this.localToCanvasPoint(port[port.length - 1])
|
||||
) <= epsilon
|
||||
) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(
|
||||
this,
|
||||
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
|
||||
),
|
||||
new GraphicRelationParam(section, SectionPort.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])
|
||||
) <= epsilon
|
||||
) {
|
||||
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,
|
||||
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
|
||||
),
|
||||
new GraphicRelationParam(
|
||||
turnout,
|
||||
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.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 === TurnoutPort.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 === TurnoutPort.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 === TurnoutPort.C
|
||||
&& (!(relation.getOtherGraphic(this) instanceof Section
|
||||
&& relation.getOtherGraphic<Section>(this).datas.sectionType !== SectionType.TurnoutPhysical))
|
||||
);
|
||||
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, TurnoutPort.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, TurnoutPort.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, TurnoutPort.C),
|
||||
new GraphicRelationParam(
|
||||
this.queryStore.queryById(this.datas.pcRef.id),
|
||||
protoPort2Data(this.datas.pcRef.devicePort)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
}
|
||||
|
@ -1,493 +1,6 @@
|
||||
import {
|
||||
AbsorbablePosition,
|
||||
DraggablePoint,
|
||||
IGraphicApp,
|
||||
GraphicDrawAssistant,
|
||||
GraphicInteractionPlugin,
|
||||
GraphicRelation,
|
||||
GraphicTransformEvent,
|
||||
IDrawApp,
|
||||
JlGraphic,
|
||||
VectorText,
|
||||
linePoint,
|
||||
polylinePoint,
|
||||
GraphicEditPlugin,
|
||||
getWaypointRangeIndex,
|
||||
AbsorbablePoint,
|
||||
AbsorbableLine,
|
||||
ContextMenu,
|
||||
MenuItemOptions,
|
||||
} from 'jl-graphic';
|
||||
import {
|
||||
ITurnoutData,
|
||||
Turnout,
|
||||
TurnoutConsts,
|
||||
TurnoutPort,
|
||||
TurnoutSection,
|
||||
TurnoutTemplate,
|
||||
getForkPoint,
|
||||
} from './Turnout';
|
||||
import {
|
||||
DisplayObject,
|
||||
FederatedMouseEvent,
|
||||
IHitArea,
|
||||
IPointData,
|
||||
Point,
|
||||
} from 'pixi.js';
|
||||
import { Section, SectionPort } from '../section/Section';
|
||||
ForkHitArea,
|
||||
TurnoutSectionHitArea,
|
||||
} from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
|
||||
|
||||
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 TurnoutPort.A:
|
||||
points = this.section.turnout.datas.pointA;
|
||||
start = { x: 0, y: 0 };
|
||||
break;
|
||||
case TurnoutPort.B:
|
||||
points = this.section.turnout.datas.pointB;
|
||||
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
|
||||
break;
|
||||
case TurnoutPort.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;
|
||||
}
|
||||
|
||||
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) {
|
||||
let points: IPointData[];
|
||||
if (section.port === TurnoutPort.A) points = section.turnout.datas.pointA;
|
||||
if (section.port === TurnoutPort.B) points = section.turnout.datas.pointB;
|
||||
if (section.port === TurnoutPort.C) points = section.turnout.datas.pointC;
|
||||
const p = section.turnout.screenToLocalPoint(e.global);
|
||||
addPointConfig.handler = () => {
|
||||
if (section.port === TurnoutPort.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 === TurnoutPort.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 === TurnoutPort.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 (points.length <= 1) return;
|
||||
points.splice(0, points.length - 1);
|
||||
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);
|
||||
}
|
||||
|
||||
unbind(g: Turnout): void {
|
||||
g.off('selected', this.onSelected, this);
|
||||
g.off('unselected', this.onUnSelected, this);
|
||||
g.graphics.sections.forEach((sectionGraphic) => {
|
||||
sectionGraphic.off('rightclick');
|
||||
});
|
||||
}
|
||||
|
||||
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.reset();
|
||||
tep.showAll();
|
||||
tep.setRelatedDrag();
|
||||
}
|
||||
|
||||
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[];
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
setRelatedDrag() {
|
||||
this.editPoints.forEach((eps, i) => {
|
||||
const ep = eps[eps.length - 1];
|
||||
let relations: GraphicRelation[];
|
||||
if (i === 0) {
|
||||
relations = this.graphic.relationManage
|
||||
.getRelationsOfGraphic(this.graphic)
|
||||
.filter(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this.graphic).param === TurnoutPort.A
|
||||
);
|
||||
} else if (i === 1) {
|
||||
relations = this.graphic.relationManage
|
||||
.getRelationsOfGraphic(this.graphic)
|
||||
.filter(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this.graphic).param === TurnoutPort.B
|
||||
);
|
||||
} else {
|
||||
relations = this.graphic.relationManage
|
||||
.getRelationsOfGraphic(this.graphic)
|
||||
.filter(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this.graphic).param === TurnoutPort.C
|
||||
);
|
||||
}
|
||||
if (!relations.length) return;
|
||||
const otherGraphics = relations.map((relation) =>
|
||||
relation.getOtherGraphic(this.graphic)
|
||||
);
|
||||
console.log(otherGraphics);
|
||||
const otherPorts = relations.map(
|
||||
(relation) => relation.getOtherRelationParam(this.graphic).param
|
||||
);
|
||||
|
||||
const point: IPointData[] = [];
|
||||
otherGraphics.map((otherGraphic, i) => {
|
||||
const otherPort = otherPorts[i];
|
||||
if (otherGraphic instanceof Turnout) {
|
||||
if (otherPort === TurnoutPort.A) {
|
||||
point.push(
|
||||
otherGraphic.datas.pointA[otherGraphic.datas.pointA.length - 1]
|
||||
);
|
||||
} else if (otherPort === TurnoutPort.B) {
|
||||
point.push(
|
||||
otherGraphic.datas.pointB[otherGraphic.datas.pointB.length - 1]
|
||||
);
|
||||
} else if (otherPort === TurnoutPort.C) {
|
||||
point.push(
|
||||
otherGraphic.datas.pointC[otherGraphic.datas.pointC.length - 1]
|
||||
);
|
||||
}
|
||||
} else if (otherGraphic instanceof Section) {
|
||||
if (otherPort === SectionPort.A) {
|
||||
point.push(otherGraphic.datas.points[0]);
|
||||
} else if (otherPort === SectionPort.B) {
|
||||
point.push(
|
||||
otherGraphic.datas.points[otherGraphic.datas.points.length - 1]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
const transformingHandler = () => {
|
||||
otherGraphics.forEach((otherGraphic, i) => {
|
||||
const p = otherGraphic.canvasToLocalPoint(ep);
|
||||
point[i].x = p.x;
|
||||
point[i].y = p.y;
|
||||
otherGraphic.repaint();
|
||||
});
|
||||
};
|
||||
ep.on('transforming', transformingHandler);
|
||||
});
|
||||
}
|
||||
|
||||
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', (e: GraphicTransformEvent) => {
|
||||
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);
|
||||
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 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export { ForkHitArea, TurnoutSectionHitArea };
|
||||
|
Loading…
Reference in New Issue
Block a user