diff --git a/src/common/CommonGraphics.ts b/src/common/CommonGraphics.ts new file mode 100644 index 0000000..56b97f4 --- /dev/null +++ b/src/common/CommonGraphics.ts @@ -0,0 +1,71 @@ +import { Graphics } from 'pixi.js'; +import { calculateMirrorPoint } from 'jl-graphic'; +/** + * + * @param polygon + * @param x 箭头顶点x坐标 + * @param y 箭头顶点y坐标 + * @param length 箭头长度 + * @param radius 箭头三角半径 + * @param lineWidth 箭头线宽 + * @param mirror 是否镜像翻转 (基于箭头顶点) + */ +export function drawArrow( + polygon: Graphics, + x: number, + y: number, + length: number, + radius: number, + lineWidth: number, + mirror: boolean +) { + const trianglAcme = { x, y }; + let triangleP1 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y + Math.cos(Math.PI / 6) * radius, + }; + let triangleP2 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y - Math.cos(Math.PI / 6) * radius, + }; + let lineP1 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y + lineWidth / 2, + }; + let lineP2 = { + x: x - length, + y: y + lineWidth / 2, + }; + let lineP3 = { + x: x - length, + y: y - lineWidth / 2, + }; + let lineP4 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y - lineWidth / 2, + }; + if (mirror) { + triangleP1 = calculateMirrorPoint(trianglAcme, triangleP1); + triangleP2 = calculateMirrorPoint(trianglAcme, triangleP2); + lineP1 = calculateMirrorPoint(trianglAcme, lineP1); + lineP2 = calculateMirrorPoint(trianglAcme, lineP2); + lineP3 = calculateMirrorPoint(trianglAcme, lineP3); + lineP4 = calculateMirrorPoint(trianglAcme, lineP4); + } + polygon.drawPolygon( + trianglAcme.x, + trianglAcme.y, + triangleP1.x, + triangleP1.y, + lineP1.x, + lineP1.y, + lineP2.x, + lineP2.y, + lineP3.x, + lineP3.y, + lineP4.x, + lineP4.y, + triangleP2.x, + triangleP2.y + ); +} diff --git a/src/common/common.ts b/src/common/common.ts index 2e1fddf..ea7a4b9 100644 --- a/src/common/common.ts +++ b/src/common/common.ts @@ -41,6 +41,13 @@ export interface KilometerSystem { set direction(v: Direction); } +export interface KilometerSystemNoDir { + get coordinateSystem(): string; + set coordinateSystem(v: string); + get kilometer(): number; + set kilometer(v: number); +} + export interface IRelatedRef { deviceType: DeviceType; //关联的设备类型 id: number; //关联的设备ID diff --git a/src/packages/Signal/FleetMode.ts b/src/packages/Signal/FleetMode.ts new file mode 100644 index 0000000..b726247 --- /dev/null +++ b/src/packages/Signal/FleetMode.ts @@ -0,0 +1,34 @@ +import { Graphics, Point, Container, ColorSource } from 'pixi.js'; +import { drawArrow } from './common/CommonGraphics'; + +interface FleetModeData { + lmp: Point; + fleetModeColor: ColorSource; + fleetModeLength: number; + fleetModeRadius: number; + fleetModeLineWidth: number; + mirror: boolean; +} + +export class FleetMode extends Container { + static Type = 'FleetMode'; + fleetMode: Graphics = new Graphics(); + + constructor() { + super(); + this.addChild(this.fleetMode); + } + paint(fleetModeData: FleetModeData) { + this.fleetMode.beginFill(fleetModeData.fleetModeColor, 1); + drawArrow( + this.fleetMode, + fleetModeData.lmp.x, + 0, + fleetModeData.fleetModeLength, + fleetModeData.fleetModeRadius, + fleetModeData.fleetModeLineWidth, + fleetModeData.mirror + ); + this.fleetMode.endFill(); + } +} diff --git a/src/packages/Signal/HumanControl.ts b/src/packages/Signal/HumanControl.ts new file mode 100644 index 0000000..d0091b9 --- /dev/null +++ b/src/packages/Signal/HumanControl.ts @@ -0,0 +1,31 @@ +import { Graphics, Point, Container, ColorSource } from 'pixi.js'; + +interface HumanControlData { + hmp: Point; + humanControlColor: ColorSource; + humanControlRadius: number; + angle: number; +} + +export class HumanControl extends Container { + static Type = 'HumanControl'; + humanControl: Graphics = new Graphics(); + + constructor() { + super(); + this.addChild(this.humanControl); + } + paint(humanControlData: HumanControlData) { + this.humanControl.beginFill(humanControlData.humanControlColor, 1); + if (this.humanControl.drawRegularPolygon) { + this.humanControl.drawRegularPolygon( + humanControlData.hmp.x, + humanControlData.hmp.y, + humanControlData.humanControlRadius, + 3, + humanControlData.angle + ); + } + this.humanControl.endFill(); + } +} diff --git a/src/packages/Signal/Lamp.ts b/src/packages/Signal/Lamp.ts new file mode 100644 index 0000000..ad4bddd --- /dev/null +++ b/src/packages/Signal/Lamp.ts @@ -0,0 +1,117 @@ +import { Container } from '@pixi/display'; +import { Graphics, ColorSource } from 'pixi.js'; + + +// lampBadColor: '0xFF0000', +// badStart: 10, +// badEnd: 15, +interface LampBadData { + lampBadColor: ColorSource; + badStart: number; + badEnd: number; +}; + +interface LampData { + lampLineColor: ColorSource; // 信号机圆灯描边颜色 + lampLineWidth: number; + lampRadius: number; + radiusX: number; + radiusY: number; +} + +interface LogicModeData { + logicModeColor: ColorSource; // 信号机圆灯逻辑点灯颜色 + logicModeDistance: number; + logicModeLineWidth: number; +} + +export class Lamp extends Container { + circleLamp: Graphics = new Graphics(); + logicMode: Graphics = new Graphics(); + lampData: LampData|null = null; + + constructor() { + super(); + this.addChild(this.circleLamp); + } + paint(lampData:LampData) { + this.lampData = lampData; + this.createLamp(); + } + + createLampBad(lampBadData: LampBadData) { + if(!this.lampData) { return }; + this.circleLamp.lineStyle(this.lampData.lampLineWidth, lampBadData.lampBadColor); + this.circleLamp.moveTo(this.lampData.radiusX + lampBadData.badStart, this.lampData.radiusY); + this.circleLamp.lineTo(this.lampData.radiusX + lampBadData.badEnd, this.lampData.radiusY); + this.circleLamp.moveTo(this.lampData.radiusX - lampBadData.badStart, this.lampData.radiusY); + this.circleLamp.lineTo(this.lampData.radiusX - lampBadData.badEnd, this.lampData.radiusY); + this.circleLamp.moveTo(this.lampData.radiusX, this.lampData.radiusY + lampBadData.badStart); + this.circleLamp.lineTo(this.lampData.radiusX, this.lampData.radiusY + lampBadData.badEnd); + this.circleLamp.moveTo(this.lampData.radiusX, this.lampData.radiusY - lampBadData.badStart); + this.circleLamp.lineTo(this.lampData.radiusX, this.lampData.radiusY - lampBadData.badEnd); + const xieStart = Math.sin(Math.PI / 4) * lampBadData.badStart; + const xieEnd = Math.sin(Math.PI / 4) * lampBadData.badEnd; + this.circleLamp.moveTo(this.lampData.radiusX + xieStart, this.lampData.radiusY + xieStart); + this.circleLamp.lineTo(this.lampData.radiusX + xieEnd, this.lampData.radiusY + xieEnd); + this.circleLamp.moveTo(this.lampData.radiusX + xieStart, this.lampData.radiusY - xieStart); + this.circleLamp.lineTo(this.lampData.radiusX + xieEnd, this.lampData.radiusY - xieEnd); + + this.circleLamp.moveTo(this.lampData.radiusX - xieStart, this.lampData.radiusY - xieStart); + this.circleLamp.lineTo(this.lampData.radiusX - xieEnd, this.lampData.radiusY - xieEnd); + this.circleLamp.moveTo(this.lampData.radiusX - xieStart, this.lampData.radiusY + xieStart); + this.circleLamp.lineTo(this.lampData.radiusX - xieEnd, this.lampData.radiusY + xieEnd); + } + + createLamp(color?: string) { + if(!this.lampData) { return }; + this.circleLamp.clear(); + this.circleLamp.lineStyle( + this.lampData.lampLineWidth, + this.lampData.lampLineColor + ); + if (!color) { + this.circleLamp.beginFill('0XFFFFFF', 0); + } else { + this.circleLamp.beginFill(color, 1); + } + this.circleLamp.drawCircle( + this.lampData.radiusX, + this.lampData.radiusY, + this.lampData.lampRadius + ); + this.circleLamp.endFill(); + } + createLogicMode(logicModeData: LogicModeData) { + if(!this.lampData) { return }; + this.addChild(this.logicMode); + this.logicMode + .clear() + .lineStyle( + logicModeData.logicModeLineWidth, + logicModeData.logicModeColor + ) + .moveTo( + this.lampData.radiusX - logicModeData.logicModeDistance, + this.lampData.radiusY + logicModeData.logicModeDistance + ) + .lineTo( + this.lampData.radiusX + logicModeData.logicModeDistance, + this.lampData.radiusY - logicModeData.logicModeDistance + ) + .moveTo( + this.lampData.radiusX - logicModeData.logicModeDistance, + this.lampData.radiusY - logicModeData.logicModeDistance + ) + .lineTo( + this.lampData.radiusX + logicModeData.logicModeDistance, + this.lampData.radiusY + logicModeData.logicModeDistance + ); + } + logicModeClear() { + this.logicMode.clear(); + } + lampClear() { + this.circleLamp.clear(); + } +} diff --git a/src/packages/Signal/LampPost.ts b/src/packages/Signal/LampPost.ts new file mode 100644 index 0000000..b57bc18 --- /dev/null +++ b/src/packages/Signal/LampPost.ts @@ -0,0 +1,31 @@ +import { Graphics, Point, Container, ColorSource } from 'pixi.js'; + +interface LampPostData { + lpp: Point; + lampPostColor: ColorSource; + postLineWidth: number; + verticalLampPostLength: number; +} + +export class LampPost extends Container { + static Type = 'LampPost'; + lampPost: Graphics = new Graphics(); + + constructor() { + super(); + this.addChild(this.lampPost); + } + paint(lampPostData: LampPostData) { + // let lpp = new Point(signalConsts.levelLampPostLength, 0); + // if (mirror) { + // lpp = calculateMirrorPoint(new Point(0, 0), lpp); + // } + this.lampPost.clear(); + this.lampPost + .lineStyle(lampPostData.postLineWidth, lampPostData.lampPostColor) + .moveTo(0, -lampPostData.verticalLampPostLength / 2) + .lineTo(0, lampPostData.verticalLampPostLength / 2) + .moveTo(0, 0) + .lineTo(lampPostData.lpp.x, lampPostData.lpp.y); + } +} diff --git a/src/packages/Signal/SignalCode.ts b/src/packages/Signal/SignalCode.ts new file mode 100644 index 0000000..f56416f --- /dev/null +++ b/src/packages/Signal/SignalCode.ts @@ -0,0 +1,46 @@ +import { Container, Graphics, Point, ColorSource, TextStyleFill } from 'pixi.js'; +import { VectorText } from 'jl-graphic'; + +interface CodeData { + code: string; + fontSize: number; + codeColor: TextStyleFill; +} +interface BlockedData { + blockedLineWidth: number; + blockedColor: ColorSource; +} + +export class SignalCode extends Container { + blockedMode: Graphics = new Graphics(); + codeGraph: VectorText = new VectorText(''); + name = 'signalCode'; + constructor() { + super(); + this.addChild(this.codeGraph); + } + paint(codeData: CodeData) { + this.codeGraph.text = codeData.code || '信号机编号'; + this.codeGraph.style.fill = codeData.codeColor; + this.codeGraph.setVectorFontSize(codeData.fontSize); + this.codeGraph.anchor.set(0.5); + this.codeGraph.position.set(0, 0); + this.blockedMode.clear(); + } + createBlockedMode(blockedData: BlockedData) { + this.addChild(this.blockedMode); + const codeRect = this.codeGraph.getBounds(); + const rectP = this.screenToLocalPoint(new Point(codeRect.x, codeRect.y)); + this.blockedMode.clear(); + this.blockedMode.lineStyle( + blockedData.blockedLineWidth, + blockedData.blockedColor + ); + this.blockedMode.drawRect( + rectP.x, + rectP.y, + codeRect.width, + codeRect.height + ); + } +} diff --git a/src/packages/Signal/SignalDrawAssistant.ts b/src/packages/Signal/SignalDrawAssistant.ts new file mode 100644 index 0000000..00cab77 --- /dev/null +++ b/src/packages/Signal/SignalDrawAssistant.ts @@ -0,0 +1,179 @@ +import { DisplayObject, FederatedPointerEvent, IHitArea, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + IDrawApp, + JlGraphic, + GraphicData, + GraphicState +} from 'jl-graphic'; + +import { SignalTemplate } from './SignalTemplate'; + +export class SignalDraw extends GraphicDrawAssistant< + SignalTemplate, + GraphicData +> { + _signal: G | null = null; + + constructor(app: IDrawApp, template: SignalTemplate) { + super( + app, + template, + 'svguse: ../../drawIcon.svg#icon-signal', + '信号机Signal' + ); + + SignalInteraction.init(app); + } + + public get signal(): G { + if (!this._signal) { + this._signal = this.graphicTemplate.new(); + this._signal.loadData(this.graphicTemplate.datas); + this.container.addChild(this._signal); + } + return this._signal; + } + + onLeftUp(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.signal.repaint(); + this.container.position.set(p.x, p.y); + } + prepareData(data: GraphicData): boolean { + data.transform = this.container.saveTransform(); + return true; + } +} + +export class SignalGraphicHitArea implements IHitArea { + signal: JlGraphic; + constructor(signal: JlGraphic) { + this.signal = signal; + } + contains(x: number, y: number): boolean { + const bound = this.signal.getLocalBounds(); + const maxX = bound.x + bound.width; + const minX = bound.x; + const maxY = bound.y + bound.height; + const minY = bound.y; + return maxX >= x && x >= minX && maxY >= y && y >= minY; + } +} + +/** + * 构建吸附线 + * @param signal + */ +function buildAbsorbablePositions(signal: Signal): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const signals = signal.queryStore.queryByType(Signal.Type); + const canvas = signal.getCanvas(); + signals.forEach((item: Signal) => { + if (item.id === signal.id) { + return; + } + const ala = new AbsorbableLine( + new Point(item.x, 0), + new Point(item.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, item.y), + new Point(canvas.width, item.y) + ); + aps.push(ala); + aps.push(alb); + }); + + return aps; +} +/** + * 信号机名称构建吸附线 + * @param signal + */ +function buildCodeAbsorbablePositions(signal: Signal): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const signals = signal.queryStore.queryByType(Signal.Type); + const canvas = signal.getCanvas(); + signals.forEach((item: Signal) => { + if (item.id === signal.id) { + return; + } + const codePoint = item.signalCode.getPositionOnCanvas(); + const ala = new AbsorbableLine( + new Point(codePoint.x, 0), + new Point(codePoint.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, codePoint.y), + new Point(canvas.width, codePoint.y) + ); + aps.push(ala); + aps.push(alb); + }); + return aps; +} + +export class SignalInteraction extends GraphicInteractionPlugin { + static Name = 'signal_transform'; + constructor(app: IDrawApp) { + super(SignalInteraction.Name, app); + } + static init(app: IDrawApp) { + return new SignalInteraction(app); + } + filter(...grahpics: JlGraphic[]): G[] | undefined { + return grahpics + .filter((g) => g.type === Signal.Type) + .map((g) => g as G); + } + bind(g: G): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.lampMainBody.hitArea = new SignalGraphicHitArea(g); + g.on('transformstart', this.transformstart, this); + g.signalCode.on('transformstart', this.codetransformstart, this); + g.signalCode.draggable = true; + g.signalCode.selectable = true; + g.signalCode.rotatable = true; + g.signalCode.transformSave = true; + g.signalCode.eventMode = 'static'; + } + + unbind(g: G): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('transformstart', this.transformstart, this); + g.signalCode.off('transformstart', this.codetransformstart, this); + g.signalCode.draggable = false; + g.signalCode.selectable = false; + g.signalCode.rotatable = false; + g.signalCode.transformSave = false; + g.signalCode.eventMode = 'none'; + } + transformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + signal.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(signal), + }); + } + codetransformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + signal.getGraphicApp().setOptions({ + absorbablePositions: buildCodeAbsorbablePositions(signal), + }); + } +} diff --git a/src/packages/Signal/SignalTemplate.ts b/src/packages/Signal/SignalTemplate.ts new file mode 100644 index 0000000..17305e1 --- /dev/null +++ b/src/packages/Signal/SignalTemplate.ts @@ -0,0 +1,19 @@ +import { JlGraphicTemplate, JlGraphic, GraphicData, GraphicState } from 'jl-graphic'; +import { Signal } from './th/Signal'; + +export class SignalTemplate extends JlGraphicTemplate { + graphic: G; + constructor( + dataTemplate: D, + stateTemplate: S, + graphic: G + ) { + super(Signal.Type, { dataTemplate, stateTemplate }); + this.graphic = graphic; + } + new(): G { + this.graphic.loadData(this.datas); + this.graphic.loadState(this.states); + return this.graphic; + } +} diff --git a/src/packages/Signal/th/LampMainBody.ts b/src/packages/Signal/th/LampMainBody.ts deleted file mode 100644 index d294a51..0000000 --- a/src/packages/Signal/th/LampMainBody.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Graphics, Point, Container } from 'pixi.js'; -import { - calculateMirrorPoint, - GraphicAnimation, -} from 'jl-graphic'; -import { Lamp } from '../common/Lamp'; -import { SignalColorEnum, signalConsts, Model } from './Signal'; - -export class LampMainBody extends Container { - static Type = 'LampMainBody'; - lampNum = 1; - lampPost: Graphics = new Graphics(); - lamps: Lamp[] = []; - mirror = false; - deltaTime = 0; - - constructor() { - super(); - } - paint(mt: Model, mirror: boolean) { - this.mirror = mirror; - if ( - mt === Model.HL || - mt === Model.AB - ) { - this.lampNum = 2; - } else { - this.lampNum = 3; - } - this.removeChildren(0); - this.lampPost = new Graphics(); - let lpp = new Point(signalConsts.levelLampPostLength, 0); - if (mirror) { - lpp = calculateMirrorPoint(new Point(0, 0), lpp); - } - this.lampPost - .lineStyle(signalConsts.postLineWidth, SignalColorEnum.lampPostColor) - .moveTo(0, -signalConsts.verticalLampPostLength / 2) - .lineTo(0, signalConsts.verticalLampPostLength / 2) - .moveTo(0, 0) - .lineTo(lpp.x, lpp.y); - this.addChild(this.lampPost); - - this.lamps = []; - for (let i = 0; i < this.lampNum; i++) { - const lamp = new Lamp(true); - this.addChild(lamp); - const radiusX = - (1 + i * 2) * signalConsts.lampRadius + - signalConsts.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); - } - } - - setStateBlueShow() { - this.lamps.forEach(lamp =>{ - lamp.createLamp(SignalColorEnum.blueLamp); - }) - } - - setStateLampBad() { - this.lamps.forEach(lamp => { - lamp.createLampBad(); - }) - } - - setStateLogic() { - this.lamps.forEach(lamp => { - lamp.createLogicMode(); - }) - } - - setStateH() { - this.lamps[0].createLamp(SignalColorEnum.redLamp); - this.lamps.forEach((lamp, index) => { - if (index !== 0) { - lamp.createLamp(SignalColorEnum.closeLamp); - } - }); - } - setStateL() { - this.lamps[1].createLamp(SignalColorEnum.greenLamp); - this.lamps.forEach((lamp, index) => { - if(index !==1) { - lamp.createLamp(SignalColorEnum.closeLamp); - } - }); - } - setStateU() { - this.lamps[2].createLamp(SignalColorEnum.yellowLamp); - this.lamps.forEach((lamp, index) => { - if (index !== 2) { - lamp.createLamp(SignalColorEnum.closeLamp); - } - }) - } - setStateHu() { - this.lamps[0].createLamp(SignalColorEnum.redLamp); - this.lamps[1].createLamp(SignalColorEnum.closeLamp); - this.lamps[2].createLamp(SignalColorEnum.yellowLamp); - } - setStateA() { - this.lamps[0].createLamp(SignalColorEnum.blueLamp); - this.lamps[1].createLamp(SignalColorEnum.closeLamp); - } - setStateB() { - this.lamps[0].createLamp(SignalColorEnum.whiteLamp); - this.lamps[1].createLamp(SignalColorEnum.closeLamp); - } - setStateOff() { - this.lamps.forEach((lamp) => - lamp.createLamp(SignalColorEnum.closeLamp) - ); - } - createFlashAnmiation( - name: string, - color: string, - lampIndex: number - ): GraphicAnimation { - const bgColor = '0X000000'; - const flashAnmiation = GraphicAnimation.init({ - name: name, - run: (dt: number) => { - this.deltaTime += dt; - if (this.deltaTime > 60) { - this.deltaTime = 0; - this.lamps[lampIndex].createLamp(color); - } else if (this.deltaTime > 30) { - this.lamps.forEach((lamp) => { - lamp.createLamp(bgColor); - }); - } - }, - }); - return flashAnmiation; - } -} diff --git a/src/packages/Signal/th/Signal.ts b/src/packages/Signal/th/Signal.ts index ee224f0..385e3c1 100644 --- a/src/packages/Signal/th/Signal.ts +++ b/src/packages/Signal/th/Signal.ts @@ -1,18 +1,12 @@ -import { GraphicData, calculateMirrorPoint, JlGraphic } from 'jl-graphic' +import { GraphicData, calculateMirrorPoint, JlGraphic, GraphicAnimation, GraphicState } from 'jl-graphic' import { Graphics, Point } from 'pixi.js'; -import { SignalCode } from '../common/SignalCode'; -import { LampMainBody } from './LampMainBody'; -/** 信号机类型 */ -export enum Model { - HL = 0, // 红绿灯 - HLU_FU = 1, // 红绿黄,封黄灯,无引导 - HLU_DU_YY = 2, // 红绿黄,不封灯,有单黄,带引导 - HLU_YY = 3, // 红绿黄,不封灯,无单黄,带引导 - HLU_FL_DU_YY = 4, // 红绿黄,封绿灯,有单黄,带引导 - HLU_DU = 5, // 红绿黄,不封灯,有单黄,无引导 - AB = 6, // 蓝白 - HBU_DU = 7, // 红白黄,不封灯,有单黄,无引导 -} +import { SignalCode } from '../SignalCode'; +import { FleetMode } from '../FleetMode'; +import { HumanControl } from '../HumanControl'; +import { Lamp } from '../Lamp'; +import { LampPost } from '../LampPost'; +import { KilometerSystemNoDir, IRelatedRef } from '../../../common/common' + /** 信号机颜色 */ export enum SignalColorEnum { humanControlColor = '0xffff00', @@ -28,6 +22,7 @@ export enum SignalColorEnum { closeLamp = '0X000000', logicModeColor = '0x000000', lampLineColor = '0x3149c3', + lampBadColor = '0xFF0000', } /** 信号机常量 */ export const signalConsts = { @@ -45,6 +40,9 @@ export const signalConsts = { logicModeLineWidth: 2, logicModeDistance: 5, lampLineWidth: 1, + lampNumber: 2, + badStart: 10, + badEnd: 15, }; /** 动画 */ const anmiationNameConst = { @@ -55,36 +53,90 @@ const anmiationNameConst = { signalBlueFlash: 'signal_blue_flash', }; -export interface ISignalData extends GraphicData { - code: string - mirror: boolean; - mt: Model +export interface ISignalState extends GraphicState { + redOpen: boolean; + redFlash: boolean; + greenOpen: boolean; + greenFlash: boolean; + yellowOpen: boolean; + yellowFlash: boolean; + whiteOpen: boolean; + whiteFlash: boolean; + blueOpen: boolean; + blueFlash: boolean; + fleetMode: boolean; + ctrlFleetMode: boolean; + autoMode: boolean; + ctrlAutoMode: boolean; + extinguish: boolean; + approachLock: boolean; + protectRoute: boolean; + autoRouteDisable: boolean; + callon: boolean; + yellowYellow: boolean; + yellowGreen: boolean; + blocked: boolean; + lampFailure: boolean; + rtuId: number; // 集中站站号 } +export interface ISignalData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get mirror(): boolean; + set mirror(v: boolean); + get kilometerSystem(): KilometerSystemNoDir; + set kilometerSystem(v: KilometerSystemNoDir); + get refDevice(): IRelatedRef | undefined; + set refDevice(v: IRelatedRef | undefined); + get centralizedStation(): number; //所属集中站 + set centralizedStation(v: number); + clone(): ISignalData; + copyFrom(data: ISignalData): void; + eq(other: ISignalData): boolean; +} + + export class Signal extends JlGraphic { static Type = 'signal'; - datas: ISignalData; signalCode: SignalCode = new SignalCode(); - humanControl: Graphics = new Graphics(); - fleetMode: Graphics = new Graphics(); - lampMainBody: LampMainBody = new LampMainBody(); - blockedMode: Graphics = new Graphics(); + humanControl: HumanControl = new HumanControl(); + fleetMode: FleetMode = new FleetMode(); + lampPost: LampPost = new LampPost(); + lamps: Lamp[] = []; + deltaTime = 0; - constructor(datas: ISignalData) { + constructor() { super(Signal.Type); - this.datas = datas; - this.addChild(this.humanControl); - this.addChild(this.fleetMode); - this.addChild(this.lampMainBody); + this.addChild(this.lampPost); this.addChild(this.signalCode); this.signalCode.name = 'signalCode'; } + get datas(): ISignalData { + return this.getDatas(); + } + + get states(): ISignalState { + return this.getStates(); + } + + get code(): string { + return this.datas.code; + } doRepaint(): void { + //移除除灯柱、code外元素 + this.removeChildren(2); + const mirror = this.datas.mirror; - this.lampMainBody.paint(this.datas.mt, mirror); - this.signalCode.paint(this.datas); + // 信号机编号 + this.signalCode.paint({ + code: this.datas.code, + fontSize: signalConsts.codeFontSize, + codeColor: SignalColorEnum.defaultCodeColor + }); + const codeTransform = this.datas?.childTransforms?.find( (item) => item.name === 'signalCode' ); @@ -96,8 +148,106 @@ export class Signal extends JlGraphic { } else { this.signalCode.position.set(0, signalConsts.codeOffset); } + // 信号机灯柱 + let lpp = new Point(signalConsts.levelLampPostLength, 0); + if (mirror) { + lpp = calculateMirrorPoint(new Point(0, 0), lpp); + } + this.lampPost.paint({ + lpp: lpp, + lampPostColor: SignalColorEnum.lampLineColor, + postLineWidth: signalConsts.postLineWidth, + verticalLampPostLength: signalConsts.verticalLampPostLength + }); + // 信号机圆灯 + this.lamps = []; + for (let i = 0; i < signalConsts.lampNumber; i++) { + const lamp = new Lamp(); + this.addChild(lamp); + const radiusX = + (1 + i * 2) * signalConsts.lampRadius + + signalConsts.levelLampPostLength; + let lrp = new Point(radiusX, 0); + if (mirror) { + lrp = calculateMirrorPoint(new Point(0, 0), lrp); + } + lamp.paint({ + radiusX: lrp.x, + radiusY: lrp.y, + lampLineColor: SignalColorEnum.lampLineColor, + lampLineWidth: signalConsts.lampLineWidth, + lampRadius: signalConsts.lampRadius + }); + this.lamps.push(lamp); + } } + handleState() { + if (this.states.extinguish) { + this.setStateLogic(); + } + if (this.states.fleetMode) { + this.setStateFleetMode(); + } + if (this.states.autoRouteDisable) { + this.setStateHumanControl(); + } + if (this.states.blocked) { + this.setStateBlocked(); + } + if (this.states.redOpen) { + this.setStateH(); + } else if (this.states.redFlash) { + this.setStateRedFlash(); + } else if (this.states.greenOpen) { + this.setStateL(); + } else if (this.states.greenFlash) { + this.setStateGreenFlash(); + } else if (this.states.yellowOpen) { + this.setStateU(); + } else if (this.states.yellowFlash) { + this.setStateYellowFlash(); + } else if (this.states.blueOpen) { + this.setStateBlueShow(); + } else if (this.states.blueFlash) { + this.setStateBlueFlash(); + } else if (this.states.whiteOpen) { + this.setStateA(); + } else if (this.states.whiteFlash) { + this.setStateWhiteFlash(); + } else if (this.states.callon) { + this.setStateHu(); + } else if (this.states.yellowYellow) { + this.setStateUu(); + } else if (this.states.yellowGreen) { + this.setStateUL(); + } else if (this.states.lampFailure) { + this.setStateH(); + } + } + + createFlashAnmiation( + name: string, + color: string, + lampIndex: number + ): GraphicAnimation { + const bgColor = '0X000000'; + const flashAnmiation = GraphicAnimation.init({ + name: name, + run: (dt: number) => { + this.deltaTime += dt; + if (this.deltaTime > 60) { + this.deltaTime = 0; + this.lamps[lampIndex].createLamp(color); + } else if (this.deltaTime > 30) { + this.lamps.forEach((lamp) => { + lamp.createLamp(bgColor); + }); + } + }, + }); + return flashAnmiation; + } stopAnmiation() { const redFlashA = this.animation(anmiationNameConst.signaRedFlash); @@ -125,93 +275,109 @@ export class Signal extends JlGraphic { /** 设置状态自动进路 */ setStateFleetMode(): void { const mirror = this.datas.mirror; - this.fleetMode.beginFill(SignalColorEnum.fleetModeColor, 1); + this.addChild(this.fleetMode); let lmp = new Point( - this.lampMainBody.width + signalConsts.fleetModeLength, + this.lampPost.width + (this.lamps[0].width * signalConsts.lampNumber) + signalConsts.fleetModeLength, 0 ); if (mirror) { lmp = calculateMirrorPoint(new Point(0, 0), lmp); } - drawArrow( - this.fleetMode, - lmp.x, - 0, - signalConsts.fleetModeLength, - signalConsts.fleetModeRadius, - signalConsts.fleetModeLineWidth, + this.fleetMode.paint({ + lmp: lmp, + fleetModeLength: signalConsts.fleetModeLength, + fleetModeLineWidth: signalConsts.fleetModeLineWidth, + fleetModeRadius: signalConsts.fleetModeRadius, + fleetModeColor: SignalColorEnum.fleetModeColor, mirror - ); - this.fleetMode.endFill(); + }) } /** 设置状态人工控 */ setStateHumanControl(): void { const mirror = this.datas.mirror; - this.humanControl.beginFill(SignalColorEnum.humanControlColor, 1); - if (this.humanControl.drawRegularPolygon) { - let hmp = new Point(-signalConsts.humanControlRadius, 0); - if (mirror) { - hmp = calculateMirrorPoint(new Point(0, 0), hmp); - } - this.humanControl.drawRegularPolygon( - hmp.x, - hmp.y, - signalConsts.humanControlRadius, - 3, - (Math.PI / 2) * (mirror ? -1 : 1) - ); + this.addChild(this.humanControl); + let hmp = new Point(-signalConsts.humanControlRadius, 0); + if (mirror) { + hmp = calculateMirrorPoint(new Point(0, 0), hmp); } - this.humanControl.endFill(); + this.humanControl.paint({ + hmp, + humanControlRadius: signalConsts.humanControlRadius, + humanControlColor: SignalColorEnum.humanControlColor, + angle: (Math.PI / 2) * (mirror ? -1 : 1) + }) } /** 设置状态封锁 */ setStateBlocked() { - this.signalCode.createBlockedMode(); + this.signalCode.createBlockedMode({ + blockedLineWidth: signalConsts.blockedLineWidth, + blockedColor: SignalColorEnum.blockedColor + }); } /** 设置状态蓝显 */ setStateBlueShow() { - this.lampMainBody.setStateBlueShow(); + this.lamps.forEach(lamp =>{ + lamp.createLamp(SignalColorEnum.blueLamp); + }) } /** 设置状态信号机损坏 */ setStateSignalBad() { - this.lampMainBody.setStateLampBad(); + // this.lampMainBody.setStateLampBad(); + this.lamps.forEach(lamp => { + lamp.createLampBad({ + lampBadColor: SignalColorEnum.lampBadColor, + badEnd: signalConsts.badEnd, + badStart: signalConsts.badStart + }); + }) } /** 设置状态逻辑点灯 */ setStateLogic() { - this.lampMainBody.setStateLogic(); + this.lamps.forEach(lamp => { + lamp.createLogicMode({ + logicModeColor: SignalColorEnum.logicModeColor, + logicModeDistance: signalConsts.logicModeDistance, + logicModeLineWidth: signalConsts.logicModeLineWidth + }); + }) } /** 设置状态红灯 */ setStateH() { - this.lampMainBody.setStateH(); + this.lamps[0].createLamp(SignalColorEnum.redLamp); } /** 设置状态绿灯 */ setStateL() { - this.lampMainBody.setStateL(); + this.lamps[1].createLamp(SignalColorEnum.greenLamp); } /** 设置状态黄灯 */ setStateU() { - this.lampMainBody.setStateU(); + this.lamps[1].createLamp(SignalColorEnum.yellowLamp); } /** 设置状态红黄灯 */ setStateHu() { - this.lampMainBody.setStateHu(); + this.lamps[0].createLamp(SignalColorEnum.redLamp); + this.lamps[1].createLamp(SignalColorEnum.yellowLamp); } /** 设置状态白灯 */ setStateA() { - this.lampMainBody.setStateA(); + this.lamps[0].createLamp(SignalColorEnum.whiteLamp); + this.lamps[1].visible = false; } - /** 设置状态蓝灯 */ - setStateB() { - this.lampMainBody.setStateB(); + /** 设置状态黄绿灯 */ + setStateUL() { + this.lamps[0].createLamp(SignalColorEnum.yellowLamp); + this.lamps[1].createLamp(SignalColorEnum.greenLamp); } - /** 设置状态灯位关闭 */ - setStateOff() { - this.lampMainBody.setStateOff(); + /** 设置状态双黄灯 */ + setStateUu() { + this.lamps[0].createLamp(SignalColorEnum.yellowLamp); + this.lamps[1].createLamp(SignalColorEnum.yellowLamp); } /** 设置状态红闪 */ setStateRedFlash() { let redFlashA = this.animation(anmiationNameConst.signaRedFlash); if (!redFlashA) { - redFlashA = this.lampMainBody.createFlashAnmiation( + redFlashA = this.createFlashAnmiation( anmiationNameConst.signaRedFlash, SignalColorEnum.redLamp, 0 @@ -224,7 +390,7 @@ export class Signal extends JlGraphic { setStateGreenFlash() { let greenFlashA = this.animation(anmiationNameConst.signalGreenFlash); if (!greenFlashA) { - greenFlashA = this.lampMainBody.createFlashAnmiation( + greenFlashA = this.createFlashAnmiation( anmiationNameConst.signalGreenFlash, SignalColorEnum.greenLamp, 1 @@ -237,7 +403,7 @@ export class Signal extends JlGraphic { setStateYellowFlash() { let yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash); if (!yellowFlashA) { - yellowFlashA = this.lampMainBody.createFlashAnmiation( + yellowFlashA = this.createFlashAnmiation( anmiationNameConst.signalYellowFlash, SignalColorEnum.yellowLamp, 2 @@ -250,7 +416,7 @@ export class Signal extends JlGraphic { setStateBlueFlash() { let blueFlashA = this.animation(anmiationNameConst.signalBlueFlash); if (!blueFlashA) { - blueFlashA = this.lampMainBody.createFlashAnmiation( + blueFlashA = this.createFlashAnmiation( anmiationNameConst.signalBlueFlash, SignalColorEnum.blueLamp, 0 @@ -263,7 +429,7 @@ export class Signal extends JlGraphic { setStateWhiteFlash() { let whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash); if (!whiteFlashA) { - whiteFlashA = this.lampMainBody.createFlashAnmiation( + whiteFlashA = this.createFlashAnmiation( anmiationNameConst.signalWhiteFlash, SignalColorEnum.whiteLamp, 0 @@ -273,74 +439,3 @@ export class Signal extends JlGraphic { whiteFlashA.resume(); } } - - -/** - * - * @param polygon - * @param x 箭头顶点x坐标 - * @param y 箭头顶点y坐标 - * @param length 箭头长度 - * @param radius 箭头三角半径 - * @param lineWidth 箭头线宽 - * @param mirror 是否镜像翻转 (基于箭头顶点) - */ -export function drawArrow( - polygon: Graphics, - x: number, - y: number, - length: number, - radius: number, - lineWidth: number, - mirror: boolean -) { - const trianglAcme = { x, y }; - let triangleP1 = { - x: x - radius - Math.sin(Math.PI / 6), - y: y + Math.cos(Math.PI / 6) * radius, - }; - let triangleP2 = { - x: x - radius - Math.sin(Math.PI / 6), - y: y - Math.cos(Math.PI / 6) * radius, - }; - let lineP1 = { - x: x - radius - Math.sin(Math.PI / 6), - y: y + lineWidth / 2, - }; - let lineP2 = { - x: x - length, - y: y + lineWidth / 2, - }; - let lineP3 = { - x: x - length, - y: y - lineWidth / 2, - }; - let lineP4 = { - x: x - radius - Math.sin(Math.PI / 6), - y: y - lineWidth / 2, - }; - if (mirror) { - triangleP1 = calculateMirrorPoint(trianglAcme, triangleP1); - triangleP2 = calculateMirrorPoint(trianglAcme, triangleP2); - lineP1 = calculateMirrorPoint(trianglAcme, lineP1); - lineP2 = calculateMirrorPoint(trianglAcme, lineP2); - lineP3 = calculateMirrorPoint(trianglAcme, lineP3); - lineP4 = calculateMirrorPoint(trianglAcme, lineP4); - } - polygon.drawPolygon( - trianglAcme.x, - trianglAcme.y, - triangleP1.x, - triangleP1.y, - lineP1.x, - lineP1.y, - lineP2.x, - lineP2.y, - lineP3.x, - lineP3.y, - lineP4.x, - lineP4.y, - triangleP2.x, - triangleP2.y - ); -}