This commit is contained in:
joylink_zhaoerwei 2024-01-18 10:10:20 +08:00
parent b5d778ea24
commit 3850aa64cb
23 changed files with 1423 additions and 46 deletions

View File

@ -1,6 +1,6 @@
import { calculateMirrorPoint, VectorText, getRectangleCenter, JlGraphic, distance2 } from 'jl-graphic'; import { calculateMirrorPoint, VectorText, getRectangleCenter, JlGraphic, distance2 } from 'jl-graphic';
import { Container, Graphics, Color, Point, Rectangle } from 'pixi.js'; import { Container, Graphics, Color, Point, Rectangle } from 'pixi.js';
import { JlSection } from '../../Section/common/Section.js'; import { JlSection } from '../../Section/common/JlSection.js';
import { JlStation } from '../../Station/common/JlStation.js'; import { JlStation } from '../../Station/common/JlStation.js';
//子元素--矩形 //子元素--矩形

View File

@ -1,5 +1,5 @@
import { JlSection as SectionBase } from './common/Section'; import { JlSection as SectionBase } from './common/JlSection';
export declare class Section extends SectionBase { export declare class Section extends SectionBase {
constructor(); constructor();
} }
export { SectionTemplate } from './common/Section'; export { SectionTemplate } from './common/JlSection';

View File

@ -1,5 +1,5 @@
import { JlSection } from './common/Section.js'; import { JlSection } from './common/JlSection.js';
export { SectionTemplate } from './common/Section.js'; export { SectionTemplate } from './common/JlSection.js';
const displayConfig = { const displayConfig = {
lineColor: '#5578b6', lineColor: '#5578b6',

View File

@ -0,0 +1,74 @@
import { GraphicData, GraphicState, JlGraphic, JlGraphicTemplate, VectorText } from 'jl-graphic';
import { IPointData } from 'pixi.js';
import { SectionGraphic } from './SectionGraphic';
import { DevicePort, IRelatedRef } from 'common/common';
import { JlTurnout } from 'src/packages/Turnout/common/JlTurnout';
export interface ISectionData extends GraphicData {
code: string;
isCurve: boolean;
segmentsCount: number;
points: IPointData[];
sectionType: SectionType;
paRef?: IRelatedRef;
pbRef?: IRelatedRef;
axleCountings?: number[];
centralizedStations?: number[];
trackSectionId?: number;
children?: number[];
clone(): ISectionData;
copyFrom(data: ISectionData): void;
eq(other: ISectionData): boolean;
}
export interface ISectionState extends GraphicState {
id: number;
occupied: boolean;
}
export declare enum SectionType {
Physical = 0,//物理区段
Logic = 1,//逻辑区段
TurnoutPhysical = 2,//道岔物理区段
Track = 4,//轨道区段
TrackLogic = 5
}
export interface SectionDisplayConfig {
lineColor: string;
occupiedColor: string;
lineWidth: number;
}
export declare const defaultDisplayConfig: SectionDisplayConfig;
export declare class JlSection extends JlGraphic {
static Type: string;
lineGraphic: SectionGraphic;
labelGraphic: VectorText;
displayConfig: SectionDisplayConfig;
constructor();
setDisplayConfig(config: SectionDisplayConfig): void;
getVerticesList(): IPointData[];
getStartPoint(): IPointData;
getEndPoint(): IPointData;
doRepaint(): void;
get datas(): ISectionData;
get states(): ISectionState;
get linePoints(): IPointData[];
set linePoints(points: IPointData[]);
getConnectElement(port: DevicePort): {
g: JlTurnout | JlSection;
port: DevicePort;
} | undefined;
/** 获取拆分逻辑区段数据 */
getSplitPoints(count: number): IPointData[][];
/**
* * Relation处理考虑按不同区段类型分别处理或交子类处理后导出子类
*
*
*/
buildRelation(): void;
saveRelations(): void;
loadRelations(): void;
}
export declare class SectionTemplate extends JlGraphicTemplate<JlSection> {
isCurve: boolean;
segmentsCount: number;
constructor(dataTemplate: ISectionData, stateTemplate?: ISectionState);
new(): JlSection;
}

View File

@ -0,0 +1,240 @@
import { JlGraphic, VectorText, convertToBezierParams, Vector2, splitLineEvenly, distance2, GraphicRelationParam, JlGraphicTemplate } from 'jl-graphic';
import { SectionGraphic } from './SectionGraphic.js';
import { DevicePort, IRelatedRef } from '../../../common/common.js';
import { JlTurnout } from '../../Turnout/common/JlTurnout.js';
import { AxleCounting } from '../../AxleCounting/AxleCounting.js';
const tolerance = 0.01;
var SectionType;
(function (SectionType) {
SectionType[SectionType["Physical"] = 0] = "Physical";
SectionType[SectionType["Logic"] = 1] = "Logic";
SectionType[SectionType["TurnoutPhysical"] = 2] = "TurnoutPhysical";
SectionType[SectionType["Track"] = 4] = "Track";
SectionType[SectionType["TrackLogic"] = 5] = "TrackLogic";
})(SectionType || (SectionType = {}));
const defaultDisplayConfig = {
lineColor: '#5578b6',
occupiedColor: '#f00',
lineWidth: 5,
};
class JlSection extends JlGraphic {
static Type = 'Section';
lineGraphic;
labelGraphic;
displayConfig = defaultDisplayConfig;
constructor() {
super(JlSection.Type);
this.lineGraphic = new SectionGraphic();
this.labelGraphic = new VectorText('');
this.labelGraphic.setVectorFontSize(14);
this.labelGraphic.anchor.set(0.5);
this.labelGraphic.style.fill = '#0f0';
this.labelGraphic.transformSave = true;
this.labelGraphic.name = 'label';
this.transformSave = true;
this.addChild(this.lineGraphic);
this.addChild(this.labelGraphic);
}
setDisplayConfig(config) {
this.displayConfig = config;
}
getVerticesList() {
if (this.datas.isCurve) {
return [
this.datas.points[0],
...convertToBezierParams(this.datas.points).map((param) => param.p2),
];
}
else {
return this.datas.points;
}
}
getStartPoint() {
return this.datas.points[0];
}
getEndPoint() {
return this.datas.points[this.datas.points.length - 1];
}
doRepaint() {
this.lineGraphic.clear();
if (this.datas.sectionType === SectionType.TurnoutPhysical) {
return;
}
this.lineGraphic.isCurve = this.datas.isCurve;
if (this.lineGraphic.isCurve) {
this.lineGraphic.segmentsCount = this.datas.segmentsCount;
}
this.lineGraphic.points = this.datas.points;
this.lineGraphic.lineStyle(this.displayConfig.lineWidth, this.states.occupied
? this.displayConfig.occupiedColor
: this.displayConfig.lineColor);
this.labelGraphic.text = this.datas.code;
const labelPosition = this.datas.childTransforms?.find((t) => t.name === this.labelGraphic.name)?.transform.position;
if (labelPosition) {
this.labelGraphic.position.set(labelPosition.x, labelPosition.y);
}
else {
this.labelGraphic.position.set(this.datas.points[0].x, this.datas.points[0].y + 20);
}
}
get datas() {
return this.getDatas();
}
get states() {
return this.getStates();
}
get linePoints() {
return this.datas.points;
}
set linePoints(points) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
getConnectElement(port) {
const relation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).getParam() === port &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
if (!relation) {
return;
}
return {
g: relation?.getOtherGraphic(this),
port: relation?.getOtherRelationParam(this).getParam(),
};
}
/** 获取拆分逻辑区段数据 */
getSplitPoints(count) {
if (this.datas.points.length !== 2) {
let totalLen = 0;
const lengths = [];
for (let i = 1; i < this.datas.points.length; i++) {
const { x: x1, y: y1 } = this.datas.points[i - 1], { x: x2, y: y2 } = this.datas.points[i];
const len = new Vector2([x2 - x1, y2 - y1]).length();
totalLen += len;
lengths.push(len);
}
const counts = lengths.map((length) => Math.round((count * length) / totalLen));
if (counts.reduce((p, c) => p + c, 0) !== count) {
const intersection = counts.reduce((p, c) => p + c, 0) - count;
let maxCountIndex = 0, maxCount = 0;
counts.forEach((c, i) => {
if (c > maxCount) {
maxCount = c;
maxCountIndex = i;
}
});
counts[maxCountIndex] + intersection;
}
return counts
.map((count, i) => {
return splitLineEvenly(this.localToCanvasPoint(this.datas.points[i]), this.localToCanvasPoint(this.datas.points[i + 1]), count);
})
.flat();
}
else {
return splitLineEvenly(this.localToCanvasPoint(this.datas.points[0]), this.localToCanvasPoint(this.datas.points[this.datas.points.length - 1]), count);
}
}
//TODO
/**
* * Relation处理考虑按不同区段类型分别处理或交子类处理后导出子类
*
*
*/
buildRelation() {
this.relationManage.deleteRelationOfGraphicAndOtherType(this, JlSection.Type);
if (this.datas.sectionType === SectionType.Physical) {
this.queryStore
.queryByType(JlSection.Type)
.forEach((section) => {
if (section.id === this.id)
return;
let param = [];
if (distance2(this.localToCanvasPoint(this.getStartPoint()), section.localToCanvasPoint(section.getStartPoint())) <= tolerance) {
param = [DevicePort.A, DevicePort.A];
}
if (distance2(this.localToCanvasPoint(this.getEndPoint()), section.localToCanvasPoint(section.getStartPoint())) <= tolerance) {
param = [DevicePort.B, DevicePort.A];
}
if (distance2(this.localToCanvasPoint(this.getStartPoint()), section.localToCanvasPoint(section.getEndPoint())) <= tolerance) {
param = [DevicePort.A, DevicePort.B];
}
if (distance2(this.localToCanvasPoint(this.getEndPoint()), section.localToCanvasPoint(section.getEndPoint())) <= tolerance) {
param = [DevicePort.B, DevicePort.B];
}
if (param.length) {
this.relationManage.addRelation(new GraphicRelationParam(this, param[0]), new GraphicRelationParam(section, param[1]));
}
});
}
}
saveRelations() {
const paRelation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).param === DevicePort.A &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
const paDevice = paRelation?.getOtherGraphic(this);
if (paDevice) {
this.datas.paRef = IRelatedRef.create(paDevice.type, paDevice.id, paRelation.getOtherRelationParam(this).getParam());
}
else {
this.datas.paRef = undefined;
}
const pbRelation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).param === DevicePort.B &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
const pbDevice = pbRelation?.getOtherGraphic(this);
if (pbDevice) {
this.datas.pbRef = IRelatedRef.create(pbDevice.type, pbDevice.id, pbRelation?.getOtherRelationParam(this).param);
}
else {
this.datas.pbRef = undefined;
}
this.datas.axleCountings = this.relationManage
.getRelationsOfGraphicAndOtherType(this, AxleCounting.Type)
.map((relation) => relation.getOtherGraphic(this).datas.id);
}
loadRelations() {
if (this.datas?.paRef?.id) {
this.relationManage.addRelation(new GraphicRelationParam(this, DevicePort.A), new GraphicRelationParam(this.queryStore.queryById(this.datas.paRef.id), this.datas.paRef.devicePort));
}
if (this.datas?.pbRef?.id) {
this.relationManage.addRelation(new GraphicRelationParam(this, DevicePort.B), new GraphicRelationParam(this.queryStore.queryById(this.datas.pbRef.id), this.datas.pbRef.devicePort));
}
if (this.datas.trackSectionId) {
this.relationManage.addRelation(this, this.queryStore.queryById(this.datas.trackSectionId));
}
if (this.datas.sectionType === SectionType.TurnoutPhysical) {
if (this.datas.axleCountings) {
this.datas.axleCountings.forEach((id) => {
this.relationManage.addRelation(this, this.queryStore.queryById(id));
});
}
}
}
}
class SectionTemplate extends JlGraphicTemplate {
isCurve = false;
segmentsCount = 10;
constructor(dataTemplate, stateTemplate) {
super(JlSection.Type, {
dataTemplate,
stateTemplate,
});
}
new() {
const section = new JlSection();
section.loadData(this.datas);
section.loadState(this.states);
return section;
}
}
export { JlSection, SectionTemplate, SectionType, defaultDisplayConfig };

View File

@ -1,5 +1,5 @@
import { GraphicDrawAssistant, GraphicInteractionPlugin, IDrawApp, IGraphicApp, JlGraphic, KeyListener, MenuItemOptions } from 'jl-graphic'; import { GraphicDrawAssistant, GraphicInteractionPlugin, IDrawApp, IGraphicApp, JlGraphic, KeyListener, MenuItemOptions } from 'jl-graphic';
import { ISectionData, SectionTemplate } from './Section'; import { ISectionData, SectionTemplate } from './JlSection';
import { Point, Graphics, type FederatedMouseEvent, type IHitArea, type DisplayObject } from 'pixi.js'; import { Point, Graphics, type FederatedMouseEvent, type IHitArea, type DisplayObject } from 'pixi.js';
import { Section } from '../GPSection'; import { Section } from '../GPSection';
export declare class SectionDraw extends GraphicDrawAssistant<SectionTemplate, ISectionData> { export declare class SectionDraw extends GraphicDrawAssistant<SectionTemplate, ISectionData> {

View File

@ -1,5 +1,5 @@
import { ContextMenu, GraphicDrawAssistant, KeyListener, calculateMirrorPoint, convertToBezierParams, pointPolygon, linePoint, GraphicInteractionPlugin, getWaypointRangeIndex, addWayPoint, clearWayPoint, PolylineEditPlugin, VectorText, AppConsts, BezierCurveEditPlugin, AbsorbableLine, AbsorbablePoint } from 'jl-graphic'; import { ContextMenu, GraphicDrawAssistant, KeyListener, calculateMirrorPoint, convertToBezierParams, pointPolygon, linePoint, GraphicInteractionPlugin, getWaypointRangeIndex, addWayPoint, clearWayPoint, PolylineEditPlugin, VectorText, AppConsts, BezierCurveEditPlugin, AbsorbableLine, AbsorbablePoint } from 'jl-graphic';
import { SectionType, defaultDisplayConfig } from './Section.js'; import { SectionType, defaultDisplayConfig } from './JlSection.js';
import { Graphics, Point } from 'pixi.js'; import { Graphics, Point } from 'pixi.js';
import { JlTurnout } from '../../Turnout/common/JlTurnout.js'; import { JlTurnout } from '../../Turnout/common/JlTurnout.js';
import { Section } from '../GPSection.js'; import { Section } from '../GPSection.js';

View File

@ -1,5 +1,29 @@
import { GraphicState } from 'jl-graphic';
import { JlTurnout } from './common/JlTurnout'; import { JlTurnout } from './common/JlTurnout';
export interface IGPTurnoutState extends GraphicState {
id?: number;
normal?: boolean;
reverse?: boolean;
dw?: boolean;
fw?: boolean;
force?: boolean;
sb?: boolean;
dwsb?: boolean;
fwsb?: boolean;
jc?: boolean;
qdc?: boolean;
qfc?: boolean;
qyc?: boolean;
dc?: boolean;
fc?: boolean;
yc?: boolean;
occupied?: boolean;
}
export declare class GPTurnout extends JlTurnout { export declare class GPTurnout extends JlTurnout {
constructor(); constructor();
get states(): IGPTurnoutState;
doRepaint(): void; doRepaint(): void;
buildRelation(): void;
saveRelations(): void;
loadRelations(): void;
} }

View File

@ -5,8 +5,36 @@ class GPTurnout extends JlTurnout {
constructor() { constructor() {
super(GPConsts); super(GPConsts);
} }
get states() {
return this.getStates();
}
doRepaint() { doRepaint() {
const { pointB, pointC } = this.datas;
if (this.states.dw) {
this.graphics.fork.paint(pointB[0]);
this.graphics.label.style.stroke = GPConsts.normalLabelColor;
}
else if (this.states.fw) {
this.graphics.fork.paint(pointC[0]);
this.graphics.label.style.stroke = GPConsts.reverseLabelColor;
}
super.draw(); super.draw();
if (!this.states.dw && !this.states.fw) {
// 失表
this.graphics.fork.visible = false;
}
else {
this.graphics.fork.visible = true;
}
}
buildRelation() {
super.buildCommonRelation();
}
saveRelations() {
super.saveCommonRelations();
}
loadRelations() {
super.loadCommonRelations();
} }
} }

View File

@ -0,0 +1,40 @@
import { Graphics, IPointData } from 'pixi.js';
import { JlTurnout } from './common/JlTurnout';
import { GraphicAnimation, GraphicState } from 'jl-graphic';
export interface ITHTurnoutState 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 declare class THTurnout extends JlTurnout {
labelRect: Graphics;
speedLimit: Graphics;
deltaTime: number;
constructor();
get states(): ITHTurnoutState;
doRepaint(): void;
getSpeedLimitLinePoints(conf: 'normal' | 'reverse' | 'main'): IPointData[][];
bindFlashAnimation(gList: Graphics[]): GraphicAnimation;
buildRelation(): void;
saveRelations(): void;
loadRelations(): void;
}

View File

@ -0,0 +1,227 @@
import { Graphics } from 'pixi.js';
import { JlTurnout } from './common/JlTurnout.js';
import { THConsts } from './common/TurnoutConfig.js';
import { Vector2, getParallelOfPolyline, GraphicAnimation } from 'jl-graphic';
import { JlSection, SectionType } from '../Section/common/JlSection.js';
import { THStation } from '../Station/THStation.js';
const TurnoutLabelColor = {
GREEN: '#0f0',
YELLOW: '#ff0',
RED: '#f00',
WHITE: '#fff',
};
//ForkGraphic单独处理
class THTurnout extends JlTurnout {
labelRect;
speedLimit;
deltaTime;
constructor() {
super(THConsts);
this.name = 'turnout';
this.labelRect = new Graphics();
this.speedLimit = new Graphics();
this.addChild(this.labelRect);
this.addChild(this.speedLimit);
this.deltaTime = 0;
}
get states() {
return this.getStates();
}
doRepaint() {
//线条颜色
const station = this.queryStore.queryByCodeAndType(this.states.rtuId > 9 ? '' + this.states.rtuId : '0' + this.states.rtuId, THStation.Type);
if (station?.states.ipRtuStusDown) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.blueShowColor));
}
else if (this.states.ipSingleSwitchStusCbtcOccupied) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.cbtcOccupiedColor));
}
else if (this.states.ipSingleSwitchStusCiOccupied) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.ciOccupiedColor));
}
else if (this.states.ipSingleSwitchStusLocked ||
this.states.ipSingleSwitchStusFailLocked) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.lockedColor));
}
else if (this.states.ipSingleSwitchStusAtcInvalid) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.atcInvalidColor));
}
else if (this.states.ipSingleSwitchStusOverlap) {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.overlapColor));
}
else {
this.graphics.sections.forEach((g) => (g.stateFillColor = THConsts.idleColor));
}
super.draw();
const { pointB, pointC } = this.datas;
this.graphics.fork.paint(pointB[0]);
this.graphics.fork.paint(pointC[0]);
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;
}
super.draw();
this.labelRect.clear();
this.speedLimit.clear();
this.graphics.fork.visible = true;
this.removeAnimation('flash');
//文字框
if (this.states.ipSingleSwitchStusBlocked2) {
this.labelRect.clear().lineStyle(1, '#f00');
const { width, height } = this.graphics.label.getLocalBounds();
const { x, y } = this.graphics.label.transform.position;
this.labelRect.drawRect(x - width / 2, y - height / 2, width, height);
}
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;
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.speedLimit.lineStyle(1, '#ff0');
points.forEach((ps) => {
this.speedLimit.moveTo(ps[0].x, ps[0].y);
for (let i = 1; i < ps.length; i++) {
this.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();
}
}
getSpeedLimitLinePoints(conf) {
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)];
vab.x * vbc.y - vab.y * vbc.x;
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'),
];
}
}
bindFlashAnimation(gList) {
const flashAnimation = GraphicAnimation.init({
name: 'flash',
run: (dt) => {
this.deltaTime += dt;
if (this.deltaTime > 60) {
this.deltaTime = 0;
gList.forEach((g) => (g.visible = true));
}
else if (this.deltaTime > 30) {
gList.forEach((g) => (g.visible = false));
}
},
});
this.addAnimation(flashAnimation);
return flashAnimation;
}
buildRelation() {
super.buildCommonRelation();
this.queryStore
.queryByType(JlSection.Type)
.forEach((section) => {
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
if (section.datas.children &&
section.datas.children.includes(this.datas.id)) {
this.relationManage.addRelation(this, section);
}
return;
}
});
}
saveRelations() {
super.saveCommonRelations();
}
loadRelations() {
super.loadCommonRelations();
}
}
export { THTurnout };

View File

@ -2,8 +2,9 @@ import { JlGraphic, VectorText } from 'jl-graphic';
import { IPointData, Graphics } from 'pixi.js'; import { IPointData, Graphics } from 'pixi.js';
import { DevicePort } from 'common/common'; import { DevicePort } from 'common/common';
import { ITurnoutData, TurnoutConstsConfig } from './TurnoutConfig'; import { ITurnoutData, TurnoutConstsConfig } from './TurnoutConfig';
import { JlSection } from 'src/packages/Section/common/JlSection';
export declare function getForkPoint(r: number, p: IPointData): IPointData; export declare function getForkPoint(r: number, p: IPointData): IPointData;
export declare class TurnoutSection extends Graphics { declare class TurnoutSection extends Graphics {
turnoutConsts: TurnoutConstsConfig; turnoutConsts: TurnoutConstsConfig;
turnout: JlTurnout; turnout: JlTurnout;
port: DevicePort; port: DevicePort;
@ -26,9 +27,18 @@ export declare abstract class JlTurnout extends JlGraphic {
label: VectorText; label: VectorText;
}; };
constructor(turnoutConsts: TurnoutConstsConfig); constructor(turnoutConsts: TurnoutConstsConfig);
draw(): void;
get datas(): ITurnoutData; get datas(): ITurnoutData;
get code(): string;
set code(code: string);
draw(): void;
getPortPoints(): IPointData[][]; getPortPoints(): IPointData[][];
getGraphicOfPort(port: DevicePort): JlGraphic[]; getGraphicOfPort(port: DevicePort): JlGraphic[];
getConnectElement(port: DevicePort): {
g: JlTurnout | JlSection;
port: DevicePort;
} | undefined;
buildCommonRelation(): void;
saveCommonRelations(): void;
loadCommonRelations(): void;
} }
export {}; export {};

View File

@ -1,7 +1,9 @@
import { JlGraphic, VectorText } from 'jl-graphic'; import { JlGraphic, VectorText, distance2, GraphicRelationParam, angleOfIncludedAngle } from 'jl-graphic';
import { Graphics } from 'pixi.js'; import { Graphics } from 'pixi.js';
import { DevicePort } from '../../../common/common.js'; import { DevicePort, IRelatedRef } from '../../../common/common.js';
import { JlSection, SectionType } from '../../Section/common/JlSection.js';
const tolerance = 0.01;
function getForkPoint(r, p) { function getForkPoint(r, p) {
if (r === 0) if (r === 0)
return { x: 0, y: 0 }; return { x: 0, y: 0 };
@ -64,7 +66,7 @@ class ForkGraphic extends Graphics {
} }
} }
class JlTurnout extends JlGraphic { class JlTurnout extends JlGraphic {
static Type = 'Turnout'; static Type = 'JlTurnout';
graphics; graphics;
constructor(turnoutConsts) { constructor(turnoutConsts) {
super(JlTurnout.Type); super(JlTurnout.Type);
@ -90,16 +92,23 @@ class JlTurnout extends JlGraphic {
this.graphics.label.name = 'label'; this.graphics.label.name = 'label';
this.addChild(this.graphics.label); this.addChild(this.graphics.label);
} }
get datas() {
return this.getDatas();
}
get code() {
return this.datas.code;
}
set code(code) {
this.datas.code = code;
}
draw() { draw() {
this.graphics.label.text = this.datas.code; this.graphics.label.text = this.datas.code;
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint()); this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
} }
get datas() {
return this.getDatas();
}
getPortPoints() { getPortPoints() {
return [this.datas.pointA, this.datas.pointB, this.datas.pointC]; return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
} }
//端口关联的设备
getGraphicOfPort(port) { getGraphicOfPort(port) {
return this.relationManage return this.relationManage
.getRelationsOfGraphic(this) .getRelationsOfGraphic(this)
@ -108,6 +117,118 @@ class JlTurnout extends JlGraphic {
return relation.getOtherGraphic(this); return relation.getOtherGraphic(this);
}); });
} }
//端口关联的区段或道岔
getConnectElement(port) {
const relation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).getParam() === port &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
if (!relation) {
return;
}
return {
g: relation?.getOtherGraphic(this),
port: relation?.getOtherRelationParam(this).getParam(),
};
}
buildCommonRelation() {
this.relationManage.deleteRelationOfGraphic(this);
/** 道岔和区段 */
this.queryStore
.queryByType(JlSection.Type)
.forEach((section) => {
if (section.datas.sectionType !== SectionType.Physical)
return;
this.getPortPoints().forEach((port, i) => {
if (distance2(section.localToCanvasPoint(section.getStartPoint()), this.localToCanvasPoint(port[port.length - 1])) <= tolerance) {
this.relationManage.addRelation(new GraphicRelationParam(this, [DevicePort.A, DevicePort.B, DevicePort.C][i]), new GraphicRelationParam(section, DevicePort.A));
}
if (distance2(section.localToCanvasPoint(section.getEndPoint()), this.localToCanvasPoint(port[port.length - 1])) <= tolerance) {
this.relationManage.addRelation(new GraphicRelationParam(this, [DevicePort.A, DevicePort.B, DevicePort.C][i]), new GraphicRelationParam(section, DevicePort.B));
}
});
});
/** 道岔和道岔 */
this.getPortPoints().forEach((thisPort, i) => {
let params = [], deflection = 180;
this.queryStore
.queryByType(JlTurnout.Type)
.forEach((turnout) => {
if (turnout.id === this.id)
return;
turnout.getPortPoints().forEach((otherPort, j) => {
if (distance2(this.localToCanvasPoint(thisPort[thisPort.length - 1]), turnout.localToCanvasPoint(otherPort[otherPort.length - 1])) <= tolerance) {
const angle = angleOfIncludedAngle(this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */, thisPort[thisPort.length - 2]
? this.localToCanvasPoint(thisPort[thisPort.length - 2])
: this.position, otherPort[otherPort.length - 2]
? turnout.localToCanvasPoint(otherPort[otherPort.length - 2])
: turnout.position);
if (180 - Math.abs(angle) <= deflection) {
deflection = 180 - Math.abs(angle);
params = [
new GraphicRelationParam(this, [DevicePort.A, DevicePort.B, DevicePort.C][i]),
new GraphicRelationParam(turnout, [DevicePort.A, DevicePort.B, DevicePort.C][j]),
];
}
}
});
});
if (params.length === 2) {
this.relationManage.addRelation(params[0], params[1]);
}
});
}
saveCommonRelations() {
const paRelation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).param === DevicePort.A &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
const paDevice = paRelation?.getOtherGraphic(this);
if (paDevice) {
this.datas.paRef = IRelatedRef.create(paDevice.type, paDevice.id, paRelation.getOtherRelationParam(this).getParam());
}
else {
this.datas.paRef = undefined;
}
const pbRelation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).param === DevicePort.B &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout));
const pbDevice = pbRelation?.getOtherGraphic(this);
if (pbDevice) {
this.datas.pbRef = IRelatedRef.create(pbDevice.type, pbDevice.id, pbRelation.getOtherRelationParam(this).getParam());
}
else {
this.datas.pbRef = undefined;
}
const pcRelation = this.relationManage
.getRelationsOfGraphic(this)
.find((relation) => relation.getRelationParam(this).param === DevicePort.C &&
!(relation.getOtherGraphic(this) instanceof JlSection &&
relation.getOtherGraphic(this).datas.sectionType !==
SectionType.TurnoutPhysical));
const pcDevice = pcRelation?.getOtherGraphic(this);
if (pcDevice) {
this.datas.pcRef = IRelatedRef.create(pcDevice.type, pcDevice.id, pcRelation.getOtherRelationParam(this).getParam());
}
else {
this.datas.pcRef = undefined;
}
}
loadCommonRelations() {
if (this.datas.paRef?.id) {
this.relationManage.addRelation(new GraphicRelationParam(this, DevicePort.A), new GraphicRelationParam(this.queryStore.queryById(this.datas.paRef.id), DevicePort[this.datas.paRef.devicePort]));
}
if (this.datas.pbRef?.id) {
this.relationManage.addRelation(new GraphicRelationParam(this, DevicePort.B), new GraphicRelationParam(this.queryStore.queryById(this.datas.pbRef.id), DevicePort[this.datas.pbRef.devicePort]));
}
if (this.datas.pcRef?.id) {
this.relationManage.addRelation(new GraphicRelationParam(this, DevicePort.C), new GraphicRelationParam(this.queryStore.queryById(this.datas.pcRef.id), DevicePort[this.datas.pcRef.devicePort]));
}
}
} }
export { JlTurnout, TurnoutSection, getForkPoint }; export { JlTurnout, getForkPoint };

View File

@ -2,23 +2,38 @@ import { IRelatedRef, KilometerSystem } from 'common/common';
import { GraphicData } from 'jl-graphic'; import { GraphicData } from 'jl-graphic';
import { IPointData } from 'pixi.js'; import { IPointData } from 'pixi.js';
export interface TurnoutConstsConfig { export interface TurnoutConstsConfig {
lineColor: string;
occupiedColor: string;
lineWidth: number; lineWidth: number;
lineColor: string;
forkLenth: number; forkLenth: number;
labelFontSize: number; labelFontSize: number;
normalLabelColor: string;
reverseLabelColor: string;
} }
export declare const GPConsts: { export declare const GPConsts: {
lineColor: string;
occupiedColor: string;
lineWidth: number; lineWidth: number;
lineColor: string;
forkLenth: number; forkLenth: number;
labelFontSize: number; labelFontSize: number;
occupiedColor: string;
normalLabelColor: string; normalLabelColor: string;
reverseLabelColor: string; reverseLabelColor: string;
}; };
export declare const THConsts: {
lineWidth: number;
lineColor: string;
forkLenth: number;
labelFontSize: number;
idleColor: string;
jammedLineColor: string;
ciOccupiedColor: string;
cbtcOccupiedColor: string;
lockedColor: string;
atcInvalidColor: string;
overlapColor: string;
blueShowColor: string;
labelGREEN: string;
labelYELLOW: string;
labelRED: string;
labelWHITE: string;
};
export declare enum SwitchMachineType { export declare enum SwitchMachineType {
Unknown = 0, Unknown = 0,
ZDJ9_Single = 1, ZDJ9_Single = 1,
@ -38,6 +53,7 @@ export interface ITurnoutData extends GraphicData {
pcTrackSectionId?: number; pcTrackSectionId?: number;
switchMachineType?: SwitchMachineType; switchMachineType?: SwitchMachineType;
centralizedStations?: number[]; centralizedStations?: number[];
centralizedStation?: number[];
clone(): ITurnoutData; clone(): ITurnoutData;
copyFrom(data: ITurnoutData): void; copyFrom(data: ITurnoutData): void;
eq(other: ITurnoutData): boolean; eq(other: ITurnoutData): boolean;

View File

@ -1,12 +1,30 @@
const GPConsts = { const GPConsts = {
lineColor: '#5578b6',
occupiedColor: '#f00',
lineWidth: 5, lineWidth: 5,
lineColor: '#5578b6',
forkLenth: 20, forkLenth: 20,
labelFontSize: 12, labelFontSize: 12,
occupiedColor: '#f00',
normalLabelColor: '#0f0', normalLabelColor: '#0f0',
reverseLabelColor: '#ff0', reverseLabelColor: '#ff0',
}; };
const THConsts = {
lineWidth: 5,
lineColor: '#5578b6',
forkLenth: 20,
labelFontSize: 12,
idleColor: '#888', //空闲
jammedLineColor: '#f00', //挤岔
ciOccupiedColor: '#f00', //非通信车占用
cbtcOccupiedColor: '#f49', //通信车占用
lockedColor: '#fff', //锁闭 && 故障锁闭
atcInvalidColor: '#954', //atc报告失效
overlapColor: '#ff0', //overlap
blueShowColor: '0x3149c3',
labelGREEN: '#0f0',
labelYELLOW: '#ff0',
labelRED: '#f00',
labelWHITE: '#fff',
};
var SwitchMachineType; var SwitchMachineType;
(function (SwitchMachineType) { (function (SwitchMachineType) {
SwitchMachineType[SwitchMachineType["Unknown"] = 0] = "Unknown"; SwitchMachineType[SwitchMachineType["Unknown"] = 0] = "Unknown";
@ -14,4 +32,4 @@ var SwitchMachineType;
SwitchMachineType[SwitchMachineType["ZDJ9_Double"] = 2] = "ZDJ9_Double"; SwitchMachineType[SwitchMachineType["ZDJ9_Double"] = 2] = "ZDJ9_Double";
})(SwitchMachineType || (SwitchMachineType = {})); })(SwitchMachineType || (SwitchMachineType = {}));
export { GPConsts, SwitchMachineType }; export { GPConsts, SwitchMachineType, THConsts };

View File

@ -19,7 +19,7 @@ import {
LozengeConstsConfig, LozengeConstsConfig,
PlatformConstsConfig, PlatformConstsConfig,
} from './PlatformConfig'; } from './PlatformConfig';
import { JlSection } from '../../Section/common/Section'; import { JlSection } from '../../Section/common/JlSection';
import { JlStation } from '../../Station/common/JlStation'; import { JlStation } from '../../Station/common/JlStation';
//子元素--矩形 //子元素--矩形

View File

@ -1,7 +1,7 @@
import { import {
JlSection as SectionBase, JlSection as SectionBase,
SectionDisplayConfig, SectionDisplayConfig,
} from './common/Section'; } from './common/JlSection';
const displayConfig: SectionDisplayConfig = { const displayConfig: SectionDisplayConfig = {
lineColor: '#5578b6', lineColor: '#5578b6',
@ -16,4 +16,4 @@ export class Section extends SectionBase {
} }
} }
export { SectionTemplate } from './common/Section'; export { SectionTemplate } from './common/JlSection';

View File

@ -12,7 +12,7 @@ import {
} from 'jl-graphic'; } from 'jl-graphic';
import { IPointData } from 'pixi.js'; import { IPointData } from 'pixi.js';
import { SectionGraphic } from './SectionGraphic'; import { SectionGraphic } from './SectionGraphic';
import { DevicePort, DeviceType, IRelatedRef } from 'common/common'; import { DevicePort, IRelatedRef } from 'common/common';
import { JlTurnout } from 'src/packages/Turnout/common/JlTurnout'; import { JlTurnout } from 'src/packages/Turnout/common/JlTurnout';
import { AxleCounting } from 'src/packages/AxleCounting/AxleCounting'; import { AxleCounting } from 'src/packages/AxleCounting/AxleCounting';
@ -29,6 +29,7 @@ export interface ISectionData extends GraphicData {
axleCountings?: number[]; axleCountings?: number[];
centralizedStations?: number[]; centralizedStations?: number[];
trackSectionId?: number; trackSectionId?: number;
children?: number[];
clone(): ISectionData; clone(): ISectionData;
copyFrom(data: ISectionData): void; copyFrom(data: ISectionData): void;
eq(other: ISectionData): boolean; eq(other: ISectionData): boolean;

View File

@ -34,7 +34,7 @@ import {
SectionTemplate, SectionTemplate,
SectionType, SectionType,
defaultDisplayConfig, defaultDisplayConfig,
} from './Section'; } from './JlSection';
import { import {
Point, Point,
Graphics, Graphics,

View File

@ -1,11 +1,60 @@
import { GraphicState } from 'jl-graphic';
import { JlTurnout } from './common/JlTurnout'; import { JlTurnout } from './common/JlTurnout';
import { GPConsts } from './common/TurnoutConfig'; import { GPConsts } from './common/TurnoutConfig';
export interface IGPTurnoutState extends GraphicState {
id?: number;
normal?: boolean;
reverse?: boolean;
dw?: boolean;
fw?: boolean;
force?: boolean;
sb?: boolean;
dwsb?: boolean;
fwsb?: boolean;
jc?: boolean;
qdc?: boolean;
qfc?: boolean;
qyc?: boolean;
dc?: boolean;
fc?: boolean;
yc?: boolean;
occupied?: boolean;
}
export class GPTurnout extends JlTurnout { export class GPTurnout extends JlTurnout {
constructor() { constructor() {
super(GPConsts); super(GPConsts);
} }
get states(): IGPTurnoutState {
return this.getStates<IGPTurnoutState>();
}
doRepaint(): void { doRepaint(): void {
const { pointB, pointC } = this.datas;
if (this.states.dw) {
this.graphics.fork.paint(pointB[0]);
this.graphics.label.style.stroke = GPConsts.normalLabelColor;
} else if (this.states.fw) {
this.graphics.fork.paint(pointC[0]);
this.graphics.label.style.stroke = GPConsts.reverseLabelColor;
}
super.draw(); super.draw();
if (!this.states.dw && !this.states.fw) {
// 失表
this.graphics.fork.visible = false;
} else {
this.graphics.fork.visible = true;
}
}
buildRelation() {
super.buildCommonRelation();
}
saveRelations() {
super.saveCommonRelations();
}
loadRelations() {
super.loadCommonRelations();
} }
} }

View File

@ -0,0 +1,304 @@
import { Graphics, IPointData } from 'pixi.js';
import { JlTurnout } from './common/JlTurnout';
import { THConsts } from './common/TurnoutConfig';
import {
GraphicAnimation,
GraphicState,
Vector2,
getParallelOfPolyline,
} from 'jl-graphic';
import { JlSection, SectionType } from '../Section/common/JlSection';
import { THStation } from '../Station/THStation';
const TurnoutLabelColor = {
GREEN: '#0f0',
YELLOW: '#ff0',
RED: '#f00',
WHITE: '#fff',
};
export interface ITHTurnoutState 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;
}
//ForkGraphic单独处理
export class THTurnout extends JlTurnout {
labelRect: Graphics;
speedLimit: Graphics;
deltaTime: number;
constructor() {
super(THConsts);
this.name = 'turnout';
this.labelRect = new Graphics();
this.speedLimit = new Graphics();
this.addChild(this.labelRect);
this.addChild(this.speedLimit);
this.deltaTime = 0;
}
get states(): ITHTurnoutState {
return this.getStates<ITHTurnoutState>();
}
doRepaint(): void {
//线条颜色
const station = this.queryStore.queryByCodeAndType<THStation>(
this.states.rtuId > 9 ? '' + this.states.rtuId : '0' + this.states.rtuId,
THStation.Type,
);
if (station?.states.ipRtuStusDown) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.blueShowColor),
);
} else if (this.states.ipSingleSwitchStusCbtcOccupied) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.cbtcOccupiedColor),
);
} else if (this.states.ipSingleSwitchStusCiOccupied) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.ciOccupiedColor),
);
} else if (
this.states.ipSingleSwitchStusLocked ||
this.states.ipSingleSwitchStusFailLocked
) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.lockedColor),
);
} else if (this.states.ipSingleSwitchStusAtcInvalid) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.atcInvalidColor),
);
} else if (this.states.ipSingleSwitchStusOverlap) {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.overlapColor),
);
} else {
this.graphics.sections.forEach(
(g) => (g.stateFillColor = THConsts.idleColor),
);
}
super.draw();
const { pointB, pointC } = this.datas;
this.graphics.fork.paint(pointB[0]);
this.graphics.fork.paint(pointC[0]);
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;
}
super.draw();
this.labelRect.clear();
this.speedLimit.clear();
this.graphics.fork.visible = true;
this.removeAnimation('flash');
//文字框
if (this.states.ipSingleSwitchStusBlocked2) {
this.labelRect.clear().lineStyle(1, '#f00');
const { width, height } = this.graphics.label.getLocalBounds();
const { x, y } = this.graphics.label.transform.position;
this.labelRect.drawRect(x - width / 2, y - height / 2, width, height);
}
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 THTurnout.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.speedLimit.lineStyle(1, '#ff0');
points.forEach((ps) => {
this.speedLimit.moveTo(ps[0].x, ps[0].y);
for (let i = 1; i < ps.length; i++) {
this.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();
}
}
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',
),
];
}
}
bindFlashAnimation(gList: Graphics[]) {
const flashAnimation = GraphicAnimation.init({
name: 'flash',
run: (dt: number) => {
this.deltaTime += dt;
if (this.deltaTime > 60) {
this.deltaTime = 0;
gList.forEach((g) => (g.visible = true));
} else if (this.deltaTime > 30) {
gList.forEach((g) => (g.visible = false));
}
},
});
this.addAnimation(flashAnimation);
return flashAnimation;
}
buildRelation() {
super.buildCommonRelation();
this.queryStore
.queryByType<JlSection>(JlSection.Type)
.forEach((section) => {
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
if (
section.datas.children &&
section.datas.children.includes(this.datas.id)
) {
this.relationManage.addRelation(this, section);
}
return;
}
});
}
saveRelations() {
super.saveCommonRelations();
}
loadRelations() {
super.loadCommonRelations();
}
}

View File

@ -1,7 +1,16 @@
import { JlGraphic, VectorText } from 'jl-graphic'; import {
GraphicRelationParam,
JlGraphic,
VectorText,
angleOfIncludedAngle,
distance2,
} from 'jl-graphic';
import { IPointData, Graphics } from 'pixi.js'; import { IPointData, Graphics } from 'pixi.js';
import { DevicePort } from 'common/common'; import { DevicePort, IRelatedRef } from 'common/common';
import { ITurnoutData, TurnoutConstsConfig } from './TurnoutConfig'; import { ITurnoutData, TurnoutConstsConfig } from './TurnoutConfig';
import { JlSection, SectionType } from 'src/packages/Section/common/JlSection';
const tolerance = 0.01;
export function getForkPoint(r: number, p: IPointData): IPointData { export function getForkPoint(r: number, p: IPointData): IPointData {
if (r === 0) return { x: 0, y: 0 }; if (r === 0) return { x: 0, y: 0 };
@ -10,7 +19,7 @@ export function getForkPoint(r: number, p: IPointData): IPointData {
return { x: scale * p.x, y: scale * p.y }; return { x: scale * p.x, y: scale * p.y };
} }
export class TurnoutSection extends Graphics { class TurnoutSection extends Graphics {
turnoutConsts: TurnoutConstsConfig; turnoutConsts: TurnoutConstsConfig;
turnout: JlTurnout; turnout: JlTurnout;
port: DevicePort; port: DevicePort;
@ -73,7 +82,7 @@ class ForkGraphic extends Graphics {
} }
export abstract class JlTurnout extends JlGraphic { export abstract class JlTurnout extends JlGraphic {
static Type = 'Turnout'; static Type = 'JlTurnout';
graphics: { graphics: {
fork: ForkGraphic; fork: ForkGraphic;
sections: [TurnoutSection, TurnoutSection, TurnoutSection]; sections: [TurnoutSection, TurnoutSection, TurnoutSection];
@ -104,18 +113,23 @@ export abstract class JlTurnout extends JlGraphic {
this.graphics.label.name = 'label'; this.graphics.label.name = 'label';
this.addChild(this.graphics.label); this.addChild(this.graphics.label);
} }
get datas(): ITurnoutData {
return this.getDatas<ITurnoutData>();
}
get code(): string {
return this.datas.code;
}
set code(code: string) {
this.datas.code = code;
}
draw(): void { draw(): void {
this.graphics.label.text = this.datas.code; this.graphics.label.text = this.datas.code;
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint()); this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
} }
get datas(): ITurnoutData {
return this.getDatas<ITurnoutData>();
}
getPortPoints() { getPortPoints() {
return [this.datas.pointA, this.datas.pointB, this.datas.pointC]; return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
} }
//端口关联的设备
getGraphicOfPort(port: DevicePort) { getGraphicOfPort(port: DevicePort) {
return this.relationManage return this.relationManage
.getRelationsOfGraphic(this) .getRelationsOfGraphic(this)
@ -127,4 +141,198 @@ export abstract class JlTurnout extends JlGraphic {
return relation.getOtherGraphic(this); return relation.getOtherGraphic(this);
}); });
} }
//端口关联的区段或道岔
getConnectElement(port: DevicePort) {
const relation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).getParam<DevicePort>() === port &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout),
);
if (!relation) {
return;
}
return {
g: relation?.getOtherGraphic(this) as JlSection | JlTurnout,
port: relation?.getOtherRelationParam(this).getParam<DevicePort>(),
};
}
buildCommonRelation(): void {
this.relationManage.deleteRelationOfGraphic(this);
/** 道岔和区段 */
this.queryStore
.queryByType<JlSection>(JlSection.Type)
.forEach((section) => {
if (section.datas.sectionType !== SectionType.Physical) return;
this.getPortPoints().forEach((port, i) => {
if (
distance2(
section.localToCanvasPoint(section.getStartPoint()),
this.localToCanvasPoint(port[port.length - 1]),
) <= tolerance
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i],
),
new GraphicRelationParam(section, DevicePort.A),
);
}
if (
distance2(
section.localToCanvasPoint(section.getEndPoint()),
this.localToCanvasPoint(port[port.length - 1]),
) <= tolerance
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i],
),
new GraphicRelationParam(section, DevicePort.B),
);
}
});
});
/** 道岔和道岔 */
this.getPortPoints().forEach((thisPort, i) => {
let params: GraphicRelationParam[] = [],
deflection = 180;
this.queryStore
.queryByType<JlTurnout>(JlTurnout.Type)
.forEach((turnout) => {
if (turnout.id === this.id) return;
turnout.getPortPoints().forEach((otherPort, j) => {
if (
distance2(
this.localToCanvasPoint(thisPort[thisPort.length - 1]),
turnout.localToCanvasPoint(otherPort[otherPort.length - 1]),
) <= tolerance
) {
const angle = angleOfIncludedAngle(
this.localToCanvasPoint(
thisPort[thisPort.length - 1],
) /* 交点 */,
thisPort[thisPort.length - 2]
? this.localToCanvasPoint(thisPort[thisPort.length - 2])
: this.position,
otherPort[otherPort.length - 2]
? turnout.localToCanvasPoint(otherPort[otherPort.length - 2])
: turnout.position,
);
if (180 - Math.abs(angle) <= deflection) {
deflection = 180 - Math.abs(angle);
params = [
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i],
),
new GraphicRelationParam(
turnout,
[DevicePort.A, DevicePort.B, DevicePort.C][j],
),
];
}
}
});
});
if (params.length === 2) {
this.relationManage.addRelation(params[0], params[1]);
}
});
}
saveCommonRelations() {
const paRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).param === DevicePort.A &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout),
);
const paDevice = paRelation?.getOtherGraphic<JlSection | JlTurnout>(this);
if (paDevice) {
this.datas.paRef = IRelatedRef.create(
paDevice.type,
paDevice.id,
paRelation!.getOtherRelationParam(this).getParam(),
);
} else {
this.datas.paRef = undefined;
}
const pbRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).param === DevicePort.B &&
(relation.getOtherGraphic(this) instanceof JlSection ||
relation.getOtherGraphic(this) instanceof JlTurnout),
);
const pbDevice = pbRelation?.getOtherGraphic<JlSection | JlTurnout>(this);
if (pbDevice) {
this.datas.pbRef = IRelatedRef.create(
pbDevice.type,
pbDevice.id,
pbRelation!.getOtherRelationParam(this).getParam(),
);
} else {
this.datas.pbRef = undefined;
}
const pcRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).param === DevicePort.C &&
!(
relation.getOtherGraphic(this) instanceof JlSection &&
relation.getOtherGraphic<JlSection>(this).datas.sectionType !==
SectionType.TurnoutPhysical
),
);
const pcDevice = pcRelation?.getOtherGraphic<JlSection | JlTurnout>(this);
if (pcDevice) {
this.datas.pcRef = IRelatedRef.create(
pcDevice.type,
pcDevice.id,
pcRelation!.getOtherRelationParam(this).getParam(),
);
} else {
this.datas.pcRef = undefined;
}
}
loadCommonRelations() {
if (this.datas.paRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.A),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.paRef.id),
DevicePort[this.datas.paRef.devicePort],
),
);
}
if (this.datas.pbRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.B),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.pbRef.id),
DevicePort[this.datas.pbRef.devicePort],
),
);
}
if (this.datas.pcRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.C),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.pcRef.id),
DevicePort[this.datas.pcRef.devicePort],
),
);
}
}
} }

View File

@ -3,25 +3,41 @@ import { GraphicData } from 'jl-graphic';
import { IPointData } from 'pixi.js'; import { IPointData } from 'pixi.js';
export interface TurnoutConstsConfig { export interface TurnoutConstsConfig {
lineColor: string;
occupiedColor: string;
lineWidth: number; lineWidth: number;
lineColor: string;
forkLenth: number; forkLenth: number;
labelFontSize: number; labelFontSize: number;
normalLabelColor: string;
reverseLabelColor: string;
} }
export const GPConsts = { export const GPConsts = {
lineColor: '#5578b6',
occupiedColor: '#f00',
lineWidth: 5, lineWidth: 5,
lineColor: '#5578b6',
forkLenth: 20, forkLenth: 20,
labelFontSize: 12, labelFontSize: 12,
occupiedColor: '#f00',
normalLabelColor: '#0f0', normalLabelColor: '#0f0',
reverseLabelColor: '#ff0', reverseLabelColor: '#ff0',
}; };
export const THConsts = {
lineWidth: 5,
lineColor: '#5578b6',
forkLenth: 20,
labelFontSize: 12,
idleColor: '#888', //空闲
jammedLineColor: '#f00', //挤岔
ciOccupiedColor: '#f00', //非通信车占用
cbtcOccupiedColor: '#f49', //通信车占用
lockedColor: '#fff', //锁闭 && 故障锁闭
atcInvalidColor: '#954', //atc报告失效
overlapColor: '#ff0', //overlap
blueShowColor: '0x3149c3',
labelGREEN: '#0f0',
labelYELLOW: '#ff0',
labelRED: '#f00',
labelWHITE: '#fff',
};
export enum SwitchMachineType { export enum SwitchMachineType {
Unknown = 0, Unknown = 0,
ZDJ9_Single = 1, ZDJ9_Single = 1,
@ -40,8 +56,9 @@ export interface ITurnoutData extends GraphicData {
paTrackSectionId?: number; // A端轨道区段id paTrackSectionId?: number; // A端轨道区段id
pbTrackSectionId?: number; pbTrackSectionId?: number;
pcTrackSectionId?: number; pcTrackSectionId?: number;
switchMachineType?: SwitchMachineType; // 转辙机类型 switchMachineType?: SwitchMachineType; // 转辙机类型--北京
centralizedStations?: number[]; // 集中站Id列表--北京 centralizedStations?: number[]; // 集中站Id列表--北京
centralizedStation?: number[]; // 所属集中站--西安
clone(): ITurnoutData; clone(): ITurnoutData;
copyFrom(data: ITurnoutData): void; copyFrom(data: ITurnoutData): void;
eq(other: ITurnoutData): boolean; eq(other: ITurnoutData): boolean;