Section
This commit is contained in:
parent
574bce4b31
commit
a354c9f136
|
@ -0,0 +1,56 @@
|
|||
export enum DevicePort {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
}
|
||||
|
||||
export enum DeviceType {
|
||||
Section = 0,
|
||||
Turnout = 1,
|
||||
TrainWindow = 2,
|
||||
AxleCounting = 3,
|
||||
SectionLink = 4,
|
||||
Signal = 5,
|
||||
Station = 6,
|
||||
ScreenDoor = 7,
|
||||
SignalFaultAlarm = 8,
|
||||
Breakers = 9,
|
||||
PowerScreen = 10,
|
||||
}
|
||||
|
||||
export enum Direction {
|
||||
LEFT = 0,
|
||||
RIGHT = 1,
|
||||
}
|
||||
|
||||
export interface KilometerSystem {
|
||||
get coordinateSystem(): string;
|
||||
set coordinateSystem(v: string);
|
||||
get kilometer(): number;
|
||||
set kilometer(v: number);
|
||||
get direction(): Direction;
|
||||
set direction(v: Direction);
|
||||
}
|
||||
|
||||
export interface IRelatedRef {
|
||||
deviceType: DeviceType; //关联的设备类型
|
||||
id: number; //关联的设备ID
|
||||
devicePort: DevicePort; //关联的设备端口
|
||||
}
|
||||
|
||||
export namespace IRelatedRef {
|
||||
export function create(
|
||||
type: string,
|
||||
id: number,
|
||||
port: DevicePort,
|
||||
): IRelatedRef {
|
||||
const typeNum = Object.keys(DeviceType).indexOf(type);
|
||||
if (typeNum < 0) throw Error('Invalid device type');
|
||||
typeNum as DeviceType;
|
||||
return {
|
||||
deviceType: typeNum,
|
||||
id,
|
||||
devicePort: port,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { GraphicData, JlGraphic } from 'jl-graphic';
|
||||
import { IRelatedRef, KilometerSystem } from 'src/common/common';
|
||||
|
||||
enum TypeDetectionPoint {
|
||||
AxleCounting = 0,
|
||||
SectionBoundary = 1,
|
||||
}
|
||||
|
||||
export interface IAxleCountingData extends GraphicData {
|
||||
code: string;
|
||||
kilometerSystem: KilometerSystem;
|
||||
axleCountingRef: IRelatedRef[];
|
||||
type: TypeDetectionPoint;
|
||||
centralizedStations: number[];
|
||||
clone(): IAxleCountingData;
|
||||
copyFrom(data: IAxleCountingData): void;
|
||||
eq(other: IAxleCountingData): boolean;
|
||||
}
|
||||
|
||||
export class AxleCounting extends JlGraphic {
|
||||
static Type = 'axleCounting';
|
||||
|
||||
constructor() {
|
||||
super(AxleCounting.Type);
|
||||
}
|
||||
|
||||
doRepaint(): void {}
|
||||
|
||||
get datas(): IAxleCountingData {
|
||||
return this.getDatas<IAxleCountingData>();
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import { GraphicData, JlGraphic } from 'jl-graphic'
|
||||
import { IPointData } from 'pixi.js'
|
||||
import { SectionGraphic } from './SectionGraphic'
|
||||
|
||||
export interface ISectionData extends GraphicData {
|
||||
code: string
|
||||
points: IPointData[]
|
||||
|
||||
}
|
||||
|
||||
export interface SectionDisplayConfig {
|
||||
lineColor: string;
|
||||
lineWidth: number;
|
||||
}
|
||||
|
||||
export class Section extends JlGraphic {
|
||||
static Type = 'Section'
|
||||
lineGraphic: SectionGraphic
|
||||
|
||||
constructor() {
|
||||
super(Section.Type)
|
||||
this.lineGraphic = new SectionGraphic();
|
||||
// this.transformSave = true;
|
||||
this.addChild(this.lineGraphic);
|
||||
}
|
||||
|
||||
doRepaint(): void {
|
||||
console.log('repaint')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { Section as SectionBase, SectionDisplayConfig } from "../common/Section";
|
||||
|
||||
const displayConfig: SectionDisplayConfig = {
|
||||
lineColor: '#5578b6',
|
||||
occupiedColor: '#f00',
|
||||
lineWidth: 5
|
||||
}
|
||||
|
||||
export class Section extends SectionBase {
|
||||
constructor() {
|
||||
super();
|
||||
this.setDisplayConfig(displayConfig)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
import {
|
||||
GraphicData,
|
||||
GraphicRelationParam,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
Vector2,
|
||||
VectorText,
|
||||
convertToBezierParams,
|
||||
distance2,
|
||||
splitLineEvenly,
|
||||
} from 'jl-graphic';
|
||||
import { IPointData } from 'pixi.js';
|
||||
import { SectionGraphic } from './SectionGraphic';
|
||||
import { DevicePort, DeviceType, IRelatedRef } from 'src/common/common';
|
||||
import { Turnout } from 'src/packages/Turnout/Turnout';
|
||||
import { AxleCounting } from 'src/packages/AxleCounting/AxleCounting';
|
||||
|
||||
const tolerance = 0.01;
|
||||
|
||||
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;
|
||||
clone(): ISectionData;
|
||||
copyFrom(data: ISectionData): void;
|
||||
eq(other: ISectionData): boolean;
|
||||
}
|
||||
|
||||
export interface ISectionState extends GraphicState {
|
||||
id: number;
|
||||
occupied: boolean;
|
||||
}
|
||||
|
||||
export enum SectionType {
|
||||
Physical = 0, //物理区段
|
||||
Logic = 1, //逻辑区段
|
||||
TurnoutPhysical = 2, //道岔物理区段
|
||||
Track = 4, //轨道区段
|
||||
TrackLogic = 5, //轨道逻辑区段
|
||||
}
|
||||
|
||||
export interface SectionDisplayConfig {
|
||||
lineColor: string;
|
||||
occupiedColor: string;
|
||||
lineWidth: number;
|
||||
}
|
||||
|
||||
const defaultDisplayConfig: SectionDisplayConfig = {
|
||||
lineColor: '#5578b6',
|
||||
occupiedColor: '#f00',
|
||||
lineWidth: 5,
|
||||
};
|
||||
|
||||
export class Section extends JlGraphic {
|
||||
static Type = 'Section';
|
||||
lineGraphic: SectionGraphic;
|
||||
labelGraphic: VectorText;
|
||||
displayConfig = defaultDisplayConfig;
|
||||
|
||||
constructor() {
|
||||
super(Section.Type);
|
||||
this.lineGraphic = new SectionGraphic();
|
||||
this.labelGraphic = new VectorText('');
|
||||
this.labelGraphic.setVectorFontSize(14);
|
||||
this.labelGraphic.anchor.set(0.5);
|
||||
this.labelGraphic.style.fill = '#0f0';
|
||||
this.labelGraphic.transformSave = true;
|
||||
this.labelGraphic.name = 'label';
|
||||
this.transformSave = true;
|
||||
this.addChild(this.lineGraphic);
|
||||
this.addChild(this.labelGraphic);
|
||||
}
|
||||
|
||||
setDisplayConfig(config: SectionDisplayConfig) {
|
||||
this.displayConfig = config;
|
||||
}
|
||||
|
||||
getVerticesList(): IPointData[] {
|
||||
if (this.datas.isCurve) {
|
||||
return [
|
||||
this.datas.points[0],
|
||||
...convertToBezierParams(this.datas.points).map((param) => param.p2),
|
||||
];
|
||||
} else {
|
||||
return this.datas.points;
|
||||
}
|
||||
}
|
||||
getStartPoint() {
|
||||
return this.datas.points[0];
|
||||
}
|
||||
getEndPoint(): IPointData {
|
||||
return this.datas.points[this.datas.points.length - 1];
|
||||
}
|
||||
|
||||
doRepaint(): void {
|
||||
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(): ISectionData {
|
||||
return this.getDatas<ISectionData>();
|
||||
}
|
||||
get states(): ISectionState {
|
||||
return this.getStates<ISectionState>();
|
||||
}
|
||||
get linePoints(): IPointData[] {
|
||||
return this.datas.points;
|
||||
}
|
||||
set linePoints(points: IPointData[]) {
|
||||
const old = this.datas.clone();
|
||||
old.points = points;
|
||||
this.updateData(old);
|
||||
}
|
||||
|
||||
getConnectElement(port: DevicePort) {
|
||||
const relation = this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.find(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this).getParam<DevicePort>() === port &&
|
||||
(relation.getOtherGraphic(this) instanceof Section ||
|
||||
relation.getOtherGraphic(this) instanceof Turnout),
|
||||
);
|
||||
if (!relation) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
g: relation?.getOtherGraphic(this) as Section | Turnout,
|
||||
port: relation?.getOtherRelationParam(this).getParam<DevicePort>(),
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取拆分逻辑区段数据 */
|
||||
getSplitPoints(count: number): IPointData[][] {
|
||||
if (this.datas.points.length !== 2) {
|
||||
let totalLen = 0;
|
||||
const lengths: number[] = [];
|
||||
for (let i = 1; i < this.datas.points.length; i++) {
|
||||
const { x: x1, y: y1 } = this.datas.points[i - 1],
|
||||
{ x: x2, y: y2 } = this.datas.points[i];
|
||||
const len = new Vector2([x2 - x1, y2 - y1]).length();
|
||||
totalLen += len;
|
||||
lengths.push(len);
|
||||
}
|
||||
const counts = lengths.map((length) =>
|
||||
Math.round((count * length) / totalLen),
|
||||
);
|
||||
if (counts.reduce((p, c) => p + c, 0) !== count) {
|
||||
const intersection = counts.reduce((p, c) => p + c, 0) - count;
|
||||
let maxCountIndex = 0,
|
||||
maxCount = 0;
|
||||
counts.forEach((c, i) => {
|
||||
if (c > maxCount) {
|
||||
maxCount = c;
|
||||
maxCountIndex = i;
|
||||
}
|
||||
});
|
||||
counts[maxCountIndex] + intersection;
|
||||
}
|
||||
return counts
|
||||
.map((count, i) => {
|
||||
return splitLineEvenly(
|
||||
this.localToCanvasPoint(this.datas.points[i]),
|
||||
this.localToCanvasPoint(this.datas.points[i + 1]),
|
||||
count,
|
||||
);
|
||||
})
|
||||
.flat();
|
||||
} else {
|
||||
return splitLineEvenly(
|
||||
this.localToCanvasPoint(this.datas.points[0]),
|
||||
this.localToCanvasPoint(
|
||||
this.datas.points[this.datas.points.length - 1],
|
||||
),
|
||||
count,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
buildRelation() {
|
||||
this.relationManage.deleteRelationOfGraphicAndOtherType(this, Section.Type);
|
||||
|
||||
if (this.datas.sectionType === SectionType.Physical) {
|
||||
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
|
||||
if (section.id === this.id) return;
|
||||
|
||||
let param: DevicePort[] = [];
|
||||
if (
|
||||
distance2(
|
||||
this.localToCanvasPoint(this.getStartPoint()),
|
||||
section.localToCanvasPoint(section.getStartPoint()),
|
||||
) <= tolerance
|
||||
) {
|
||||
param = [DevicePort.A, DevicePort.A];
|
||||
}
|
||||
if (
|
||||
distance2(
|
||||
this.localToCanvasPoint(this.getEndPoint()),
|
||||
section.localToCanvasPoint(section.getStartPoint()),
|
||||
) <= tolerance
|
||||
) {
|
||||
param = [DevicePort.B, DevicePort.A];
|
||||
}
|
||||
if (
|
||||
distance2(
|
||||
this.localToCanvasPoint(this.getStartPoint()),
|
||||
section.localToCanvasPoint(section.getEndPoint()),
|
||||
) <= tolerance
|
||||
) {
|
||||
param = [DevicePort.A, DevicePort.B];
|
||||
}
|
||||
if (
|
||||
distance2(
|
||||
this.localToCanvasPoint(this.getEndPoint()),
|
||||
section.localToCanvasPoint(section.getEndPoint()),
|
||||
) <= tolerance
|
||||
) {
|
||||
param = [DevicePort.B, DevicePort.B];
|
||||
}
|
||||
if (param.length) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, param[0]),
|
||||
new GraphicRelationParam(section, param[1]),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
saveRelations() {
|
||||
const paRelation = this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.find(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this).param === DevicePort.A &&
|
||||
(relation.getOtherGraphic(this) instanceof Section ||
|
||||
relation.getOtherGraphic(this) instanceof Turnout),
|
||||
);
|
||||
const paDevice = paRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||
if (paDevice) {
|
||||
this.datas.paRef = 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 Section ||
|
||||
relation.getOtherGraphic(this) instanceof Turnout),
|
||||
);
|
||||
const pbDevice = pbRelation?.getOtherGraphic<Section | Turnout>(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<AxleCounting>(this).datas.id);
|
||||
}
|
||||
|
||||
loadRelations() {
|
||||
if (this.datas?.paRef?.id) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.A),
|
||||
new GraphicRelationParam(
|
||||
this.queryStore.queryById(this.datas.paRef.id),
|
||||
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.trackSectionId) {
|
||||
this.relationManage.addRelation(
|
||||
this,
|
||||
this.queryStore.queryById<Section>(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<AxleCounting>(id),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SectionTemplate extends JlGraphicTemplate<Section> {
|
||||
constructor(dataTemplate: ISectionData, stateTemplate?: ISectionState) {
|
||||
super(Section.Type, {
|
||||
dataTemplate,
|
||||
stateTemplate,
|
||||
});
|
||||
}
|
||||
new(): Section {
|
||||
const section = new Section();
|
||||
section.loadData(this.datas);
|
||||
section.loadState(this.states);
|
||||
return section;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue