道岔
This commit is contained in:
parent
fdf2a9c00e
commit
d1f03f2cfc
@ -22,8 +22,8 @@
|
||||
"default-passive-events": "^2.0.0",
|
||||
"echarts": "^5.4.3",
|
||||
"google-protobuf": "^3.21.2",
|
||||
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.3",
|
||||
"rt-graphic-component": "git+https://git.code.tencent.com/jl-framework/rt-graphic-component.git#3c81ca8",
|
||||
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.8",
|
||||
"rt-graphic-component": "git+https://git.code.tencent.com/jl-framework/rt-graphic-component.git#5eecd80",
|
||||
"js-base64": "^3.7.5",
|
||||
"pinia": "^2.0.11",
|
||||
"quasar": "^2.6.0",
|
||||
|
@ -21,7 +21,11 @@ import { Polygon, PolygonTemplate } from 'src/graphics/polygon/Polygon';
|
||||
import { PolygonData } from './graphics/PolygonInteraction';
|
||||
import { PolygonDraw } from 'src/graphics/polygon/PolygonDrawAssistant';
|
||||
import { StyleType } from 'rt-graphic-component/components/common/common';
|
||||
import { Platform, PlatformDraw, PlatformTemplate } from 'src/graphics/platform/Platform';
|
||||
import {
|
||||
Platform,
|
||||
PlatformDraw,
|
||||
PlatformTemplate,
|
||||
} from 'src/graphics/platform/Platform';
|
||||
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
|
||||
import {
|
||||
ScreenDoor,
|
||||
@ -32,7 +36,11 @@ import {
|
||||
ScreenDoorState,
|
||||
} from './graphics/ScreenDoorInteraction';
|
||||
import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant';
|
||||
import { Station, StationDraw, StationTemplate } from 'src/graphics/station/Station';
|
||||
import {
|
||||
Station,
|
||||
StationDraw,
|
||||
StationTemplate,
|
||||
} from 'src/graphics/station/Station';
|
||||
import { StationData, StationState } from './graphics/StationInteraction';
|
||||
import {
|
||||
OneClickGenerateDraw,
|
||||
@ -50,8 +58,11 @@ import {
|
||||
} from 'src/graphics/axleCounting/AxleCounting';
|
||||
import { AxleCountingDraw } from 'src/graphics/axleCounting/AxleCountingDrawAssistant';
|
||||
import { AxleCountingData } from './graphics/AxleCountingInteraction';
|
||||
import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout';
|
||||
import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant';
|
||||
import {
|
||||
Turnout,
|
||||
TurnoutTemplate,
|
||||
TurnoutDraw,
|
||||
} from 'src/graphics/turnout/Turnout';
|
||||
import { TurnoutData, TurnoutStates } from './graphics/TurnoutInteraction';
|
||||
import { Section, SectionTemplate } from 'src/graphics/section/Section';
|
||||
import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
|
||||
@ -176,7 +187,7 @@ export function initCommonDrawApp(app: IDrawApp) {
|
||||
new SignalDraw(app, new SignalTemplate(new SignalData(), new SignalState()));
|
||||
new TurnoutDraw(
|
||||
app,
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates())
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.GP)
|
||||
);
|
||||
new TrainWindowDraw(app, new TrainWindowTemplate(new TrainWindowData()));
|
||||
new OneClickGenerateDraw(app, new OneClickGenerateTemplate());
|
||||
|
@ -237,7 +237,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
|
||||
new PlatformTemplate(new PlatformData(), new PlatformState(), StyleType.GP),
|
||||
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState()),
|
||||
new StationTemplate(new StationData(), new StationState(), StyleType.GP),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
|
||||
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.GP),
|
||||
new SectionTemplate(new SectionData(), new SectionStates()),
|
||||
new AxleCountingTemplate(new AxleCountingData()),
|
||||
new TrainWindowTemplate(new TrainWindowData()),
|
||||
|
@ -1,484 +1,18 @@
|
||||
import { Graphics, IPointData } from 'pixi.js';
|
||||
import { GPTurnout as Turnout } from 'rt-graphic-component/components/packages/Turnout/GPTurnout';
|
||||
import { TurnoutSection } from 'rt-graphic-component/components/packages/Turnout/common/JlTurnout';
|
||||
import {
|
||||
GraphicAnimation,
|
||||
GraphicData,
|
||||
GraphicRelationParam,
|
||||
GraphicState,
|
||||
JlGraphic,
|
||||
JlGraphicTemplate,
|
||||
VectorText,
|
||||
angleOfIncludedAngle,
|
||||
distance2,
|
||||
} from 'jl-graphic';
|
||||
import { Section, DevicePort, SectionType } from '../section/Section';
|
||||
import {
|
||||
IRelatedRefData,
|
||||
createRelatedRefProto,
|
||||
protoPort2Data,
|
||||
} from '../CommonGraphics';
|
||||
import { KilometerSystem } from '../signal/Signal';
|
||||
import { TrackSection } from '../trackSection/TrackSection';
|
||||
import { graphicData } from 'src/protos/stationLayoutGraphics';
|
||||
ITurnoutData,
|
||||
GPConsts as TurnoutConsts,
|
||||
} from 'rt-graphic-component/components/packages/Turnout/common/TurnoutConfig';
|
||||
import { TurnoutTemplate } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutTemplate';
|
||||
import { IGPTurnoutState as ITurnoutState } from 'rt-graphic-component/components/packages/Turnout/GPTurnout';
|
||||
import { TurnoutDraw } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
|
||||
|
||||
const tolerance = 0.01;
|
||||
export { Turnout, TurnoutTemplate, TurnoutDraw, TurnoutConsts };
|
||||
export type { ITurnoutState, ITurnoutData, TurnoutSection };
|
||||
|
||||
export interface ITurnoutData extends GraphicData {
|
||||
get code(): string;
|
||||
set code(code: string);
|
||||
get pointA(): IPointData[]; //A端点列表(从岔心向外)
|
||||
set pointA(point: IPointData[]);
|
||||
get pointB(): IPointData[];
|
||||
set pointB(point: IPointData[]);
|
||||
get pointC(): IPointData[];
|
||||
set pointC(point: IPointData[]);
|
||||
get paRef(): IRelatedRefData | undefined;
|
||||
set paRef(ref: IRelatedRefData | undefined);
|
||||
get pbRef(): IRelatedRefData | undefined;
|
||||
set pbRef(ref: IRelatedRefData | undefined);
|
||||
get pcRef(): IRelatedRefData | undefined;
|
||||
set pcRef(ref: IRelatedRefData | undefined);
|
||||
get kilometerSystem(): KilometerSystem;
|
||||
set kilometerSystem(v: KilometerSystem);
|
||||
get paTrackSectionId(): number;
|
||||
set paTrackSectionId(v: number);
|
||||
get pbTrackSectionId(): number;
|
||||
set pbTrackSectionId(v: number);
|
||||
get pcTrackSectionId(): number;
|
||||
set pcTrackSectionId(v: number);
|
||||
get switchMachineType(): graphicData.Turnout.SwitchMachineType;
|
||||
set switchMachineType(v: graphicData.Turnout.SwitchMachineType);
|
||||
get centralizedStations(): number[];
|
||||
set centralizedStations(v: number[]);
|
||||
clone(): ITurnoutData;
|
||||
copyFrom(data: ITurnoutData): void;
|
||||
eq(other: ITurnoutData): boolean;
|
||||
}
|
||||
|
||||
export interface ITurnoutState 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 const TurnoutConsts = {
|
||||
lineColor: '#5578b6',
|
||||
occupiedColor: '#f00',
|
||||
lineWidth: 5,
|
||||
forkLenth: 20,
|
||||
labelFontSize: 12,
|
||||
normalLabelColor: '#0f0',
|
||||
reverseLabelColor: '#ff0',
|
||||
};
|
||||
|
||||
export enum TurnoutPosition {
|
||||
NORMAL = 0,
|
||||
REVERSE = 1,
|
||||
}
|
||||
|
||||
export function getForkPoint(r: number, p: IPointData): IPointData {
|
||||
if (r === 0) return { x: 0, y: 0 };
|
||||
const len = Math.sqrt((-p.x) ** 2 + (-p.y) ** 2);
|
||||
const scale = r / len;
|
||||
return { x: scale * p.x, y: scale * p.y };
|
||||
}
|
||||
|
||||
export class TurnoutSection extends Graphics {
|
||||
turnout: Turnout;
|
||||
port: DevicePort;
|
||||
constructor(turnout: Turnout, port: DevicePort) {
|
||||
super();
|
||||
this.turnout = turnout;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
paint() {
|
||||
let pList: IPointData[] = [];
|
||||
switch (this.port) {
|
||||
case DevicePort.A:
|
||||
pList = this.turnout.datas.pointA;
|
||||
break;
|
||||
case DevicePort.B:
|
||||
pList = this.turnout.datas.pointB;
|
||||
break;
|
||||
case DevicePort.C:
|
||||
pList = this.turnout.datas.pointC;
|
||||
break;
|
||||
}
|
||||
const gap = this.port === DevicePort.A ? 0 : TurnoutConsts.forkLenth;
|
||||
let color = TurnoutConsts.lineColor;
|
||||
if (this.turnout.states.occupied) {
|
||||
if (
|
||||
this.port === DevicePort.A ||
|
||||
(this.turnout.states.dw && this.port === DevicePort.B) ||
|
||||
(this.turnout.states.fw && this.port === DevicePort.C)
|
||||
) {
|
||||
color = TurnoutConsts.occupiedColor;
|
||||
}
|
||||
}
|
||||
const start = getForkPoint(gap, pList[0]);
|
||||
this.clear()
|
||||
.lineStyle(TurnoutConsts.lineWidth, color)
|
||||
.moveTo(start.x, start.y);
|
||||
pList.forEach((p) => {
|
||||
const { x, y } = p;
|
||||
this.lineTo(x, y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ForkGraphic extends Graphics {
|
||||
turnout: Turnout;
|
||||
constructor(turnout: Turnout) {
|
||||
super();
|
||||
this.turnout = turnout;
|
||||
}
|
||||
|
||||
paint(p: IPointData) {
|
||||
const target = getForkPoint(TurnoutConsts.forkLenth, p);
|
||||
const color = this.turnout.states.occupied
|
||||
? TurnoutConsts.occupiedColor
|
||||
: TurnoutConsts.lineColor;
|
||||
this.clear()
|
||||
.lineStyle(TurnoutConsts.lineWidth, color)
|
||||
.moveTo(0, 0)
|
||||
.lineTo(target.x, target.y);
|
||||
}
|
||||
}
|
||||
|
||||
export class Turnout extends JlGraphic {
|
||||
static Type = 'Turnout';
|
||||
graphics: {
|
||||
fork: ForkGraphic;
|
||||
sections: [TurnoutSection, TurnoutSection, TurnoutSection];
|
||||
label: VectorText;
|
||||
};
|
||||
deltaTime: number;
|
||||
|
||||
constructor() {
|
||||
super(Turnout.Type);
|
||||
this.name = 'turnout';
|
||||
this.graphics = {
|
||||
fork: new ForkGraphic(this),
|
||||
sections: [
|
||||
new TurnoutSection(this, DevicePort.A),
|
||||
new TurnoutSection(this, DevicePort.B),
|
||||
new TurnoutSection(this, DevicePort.C),
|
||||
],
|
||||
label: new VectorText(),
|
||||
};
|
||||
this.deltaTime = 0;
|
||||
this.addChild(this.graphics.fork);
|
||||
// this.addChild(...this.graphics.sections);
|
||||
this.addChild(this.graphics.sections[0]);
|
||||
this.addChild(this.graphics.sections[1]);
|
||||
this.addChild(this.graphics.sections[2]);
|
||||
this.graphics.label.anchor.set(0.5);
|
||||
this.graphics.label.style.fill = '#0f0';
|
||||
this.graphics.label.setVectorFontSize(TurnoutConsts.labelFontSize);
|
||||
this.graphics.label.position.set(20, 20);
|
||||
this.graphics.label.transformSave = true;
|
||||
this.graphics.label.name = 'label';
|
||||
this.addChild(this.graphics.label);
|
||||
}
|
||||
|
||||
get datas(): ITurnoutData {
|
||||
return this.getDatas<ITurnoutData>();
|
||||
}
|
||||
|
||||
get states(): ITurnoutState {
|
||||
return this.getStates<ITurnoutState>();
|
||||
}
|
||||
getPortPoints() {
|
||||
return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
|
||||
}
|
||||
|
||||
doRepaint(): void {
|
||||
const { pointB, pointC } = this.datas;
|
||||
if (this.states.dw) {
|
||||
this.graphics.fork.paint(pointB[0]);
|
||||
this.graphics.label.style.stroke = TurnoutConsts.normalLabelColor;
|
||||
} else if (this.states.fw) {
|
||||
this.graphics.fork.paint(pointC[0]);
|
||||
this.graphics.label.style.stroke = TurnoutConsts.reverseLabelColor;
|
||||
}
|
||||
this.graphics.label.text = this.datas.code;
|
||||
|
||||
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
|
||||
|
||||
if (!this.states.dw && !this.states.fw) {
|
||||
// 失表
|
||||
this.graphics.fork.visible = false;
|
||||
} else {
|
||||
this.graphics.fork.visible = true;
|
||||
}
|
||||
}
|
||||
initTurnoutSplit() {
|
||||
// 道岔失表
|
||||
const name = `${this.datas.id}_turnout_split`;
|
||||
let turnoutSplit = this.animation(name);
|
||||
if (!turnoutSplit) {
|
||||
turnoutSplit = GraphicAnimation.init({
|
||||
name: name,
|
||||
run: (dt: number) => {
|
||||
this.deltaTime += dt;
|
||||
this.deltaTime = this.deltaTime % 60;
|
||||
this.graphics.fork.visible = this.deltaTime > 30;
|
||||
},
|
||||
});
|
||||
this.addAnimation(turnoutSplit);
|
||||
}
|
||||
turnoutSplit.resume();
|
||||
}
|
||||
stopTurnoutSplit() {
|
||||
const name = `${this.datas.id}_turnout_split`;
|
||||
const turnoutSplit = this.animation(name);
|
||||
if (turnoutSplit) {
|
||||
turnoutSplit.pause();
|
||||
this.deltaTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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>(),
|
||||
};
|
||||
}
|
||||
|
||||
buildRelation(): void {
|
||||
this.relationManage.deleteRelationOfGraphic(this);
|
||||
|
||||
/** 道岔和区段 */
|
||||
this.queryStore.queryByType<Section>(Section.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<Turnout>(Turnout.Type).forEach((turnout) => {
|
||||
if (turnout.id === this.id) return;
|
||||
turnout.getPortPoints().forEach((otherPort, j) => {
|
||||
if (
|
||||
distance2(
|
||||
this.localToCanvasPoint(thisPort[thisPort.length - 1]),
|
||||
turnout.localToCanvasPoint(otherPort[otherPort.length - 1])
|
||||
) <= 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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 = createRelatedRefProto(
|
||||
paDevice.type,
|
||||
paDevice.id,
|
||||
paRelation?.getOtherRelationParam(this).param
|
||||
);
|
||||
} else {
|
||||
this.datas.paRef = undefined;
|
||||
}
|
||||
const pbRelation = this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.find(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this).param === DevicePort.B &&
|
||||
(relation.getOtherGraphic(this) instanceof Section ||
|
||||
relation.getOtherGraphic(this) instanceof Turnout)
|
||||
);
|
||||
const pbDevice = pbRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||
if (pbDevice) {
|
||||
this.datas.pbRef = createRelatedRefProto(
|
||||
pbDevice.type,
|
||||
pbDevice.id,
|
||||
pbRelation?.getOtherRelationParam(this).param
|
||||
);
|
||||
} else {
|
||||
this.datas.pbRef = undefined;
|
||||
}
|
||||
const pcRelation = this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.find(
|
||||
(relation) => relation.getRelationParam(this).param === DevicePort.C
|
||||
);
|
||||
const pcDevice = pcRelation?.getOtherGraphic<Section | Turnout>(this);
|
||||
if (pcDevice) {
|
||||
this.datas.pcRef = createRelatedRefProto(
|
||||
pcDevice.type,
|
||||
pcDevice.id,
|
||||
pcRelation?.getOtherRelationParam(this).param
|
||||
);
|
||||
} else {
|
||||
this.datas.pcRef = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
loadRelations() {
|
||||
if (this.datas.paRef?.id) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.A),
|
||||
new GraphicRelationParam(
|
||||
this.queryStore.queryById(this.datas.paRef.id),
|
||||
protoPort2Data(this.datas.paRef.devicePort)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (this.datas.pbRef?.id) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.B),
|
||||
new GraphicRelationParam(
|
||||
this.queryStore.queryById(this.datas.pbRef.id),
|
||||
protoPort2Data(this.datas.pbRef.devicePort)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (this.datas.pcRef?.id) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.C),
|
||||
new GraphicRelationParam(
|
||||
this.queryStore.queryById(this.datas.pcRef.id),
|
||||
protoPort2Data(this.datas.pcRef.devicePort)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (this.datas.paTrackSectionId) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.A),
|
||||
this.queryStore.queryById<TrackSection>(this.datas.paTrackSectionId)
|
||||
);
|
||||
}
|
||||
if (this.datas.pbTrackSectionId) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.B),
|
||||
this.queryStore.queryById<TrackSection>(this.datas.pbTrackSectionId)
|
||||
);
|
||||
}
|
||||
if (this.datas.paTrackSectionId) {
|
||||
this.relationManage.addRelation(
|
||||
new GraphicRelationParam(this, DevicePort.C),
|
||||
this.queryStore.queryById<TrackSection>(this.datas.pcTrackSectionId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getGraphicOfPort(port: DevicePort) {
|
||||
return this.relationManage
|
||||
.getRelationsOfGraphic(this)
|
||||
.filter(
|
||||
(relation) =>
|
||||
relation.getRelationParam(this).getParam<DevicePort>() === port
|
||||
)
|
||||
.map((relation) => {
|
||||
return relation.getOtherGraphic(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class TurnoutTemplate extends JlGraphicTemplate<Turnout> {
|
||||
constructor(dataTemplate: ITurnoutData, stateTemplate?: ITurnoutState) {
|
||||
super(Turnout.Type, {
|
||||
dataTemplate,
|
||||
stateTemplate,
|
||||
});
|
||||
}
|
||||
|
||||
new() {
|
||||
const g = new Turnout();
|
||||
g.loadData(this.datas);
|
||||
g.loadState(this.states);
|
||||
return g;
|
||||
}
|
||||
export enum TurnoutPort {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
}
|
||||
|
@ -1,430 +1,6 @@
|
||||
import {
|
||||
AbsorbablePosition,
|
||||
DraggablePoint,
|
||||
IGraphicApp,
|
||||
GraphicDrawAssistant,
|
||||
GraphicInteractionPlugin,
|
||||
GraphicTransformEvent,
|
||||
IDrawApp,
|
||||
JlGraphic,
|
||||
VectorText,
|
||||
linePoint,
|
||||
polylinePoint,
|
||||
AppConsts,
|
||||
GraphicEditPlugin,
|
||||
getWaypointRangeIndex,
|
||||
ContextMenu,
|
||||
MenuItemOptions,
|
||||
AbsorbablePoint,
|
||||
AbsorbableLine,
|
||||
} from 'jl-graphic';
|
||||
import {
|
||||
ITurnoutData,
|
||||
Turnout,
|
||||
TurnoutConsts,
|
||||
TurnoutSection,
|
||||
TurnoutTemplate,
|
||||
getForkPoint,
|
||||
} from './Turnout';
|
||||
import {
|
||||
DisplayObject,
|
||||
FederatedMouseEvent,
|
||||
IHitArea,
|
||||
IPointData,
|
||||
Point,
|
||||
} from 'pixi.js';
|
||||
import { DevicePort, Section } from '../section/Section';
|
||||
ForkHitArea,
|
||||
TurnoutSectionHitArea,
|
||||
} from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
|
||||
|
||||
export class TurnoutDraw extends GraphicDrawAssistant<
|
||||
TurnoutTemplate,
|
||||
ITurnoutData
|
||||
> {
|
||||
turnout: Turnout;
|
||||
constructor(app: IDrawApp, template: TurnoutTemplate) {
|
||||
super(app, template, 'sym_o_ramp_left', '道岔Turnout');
|
||||
|
||||
this.turnout = this.graphicTemplate.new();
|
||||
this.container.addChild(this.turnout);
|
||||
|
||||
TurnoutPointsInteractionPlugin.init(app);
|
||||
}
|
||||
|
||||
onLeftUp(e: FederatedMouseEvent): void {
|
||||
this.turnout.position.copyFrom(this.toCanvasCoordinates(e.global));
|
||||
this.createAndStore(true);
|
||||
}
|
||||
|
||||
prepareData(data: ITurnoutData): boolean {
|
||||
data.transform = this.turnout.saveTransform();
|
||||
data.code = 'A000000';
|
||||
return true;
|
||||
}
|
||||
|
||||
redraw(cp: Point): void {
|
||||
this.turnout.position.copyFrom(cp);
|
||||
}
|
||||
}
|
||||
|
||||
export class ForkHitArea implements IHitArea {
|
||||
turnout: Turnout;
|
||||
constructor(turnout: Turnout) {
|
||||
this.turnout = turnout;
|
||||
}
|
||||
contains(x: number, y: number): boolean {
|
||||
const intersectPointB = getForkPoint(
|
||||
TurnoutConsts.forkLenth,
|
||||
this.turnout.datas.pointB[0]
|
||||
);
|
||||
const intersectPointC = getForkPoint(
|
||||
TurnoutConsts.forkLenth,
|
||||
this.turnout.datas.pointC[0]
|
||||
);
|
||||
|
||||
return (
|
||||
linePoint(
|
||||
intersectPointB,
|
||||
{ x: 0, y: 0 },
|
||||
{ x, y },
|
||||
TurnoutConsts.lineWidth
|
||||
) ||
|
||||
linePoint(
|
||||
intersectPointC,
|
||||
{ x: 0, y: 0 },
|
||||
{ x, y },
|
||||
TurnoutConsts.lineWidth
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TurnoutSectionHitArea implements IHitArea {
|
||||
section: TurnoutSection;
|
||||
constructor(section: TurnoutSection) {
|
||||
this.section = section;
|
||||
}
|
||||
contains(x: number, y: number): boolean {
|
||||
let points: IPointData[];
|
||||
let start: IPointData;
|
||||
switch (this.section.port) {
|
||||
case DevicePort.A:
|
||||
points = this.section.turnout.datas.pointA;
|
||||
start = { x: 0, y: 0 };
|
||||
break;
|
||||
case DevicePort.B:
|
||||
points = this.section.turnout.datas.pointB;
|
||||
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
|
||||
break;
|
||||
case DevicePort.C:
|
||||
points = this.section.turnout.datas.pointC;
|
||||
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
|
||||
break;
|
||||
}
|
||||
return polylinePoint([start, ...points], { x, y }, TurnoutConsts.lineWidth);
|
||||
}
|
||||
}
|
||||
|
||||
function buildAbsorbablePositions(turnout: Turnout): AbsorbablePosition[] {
|
||||
const aps: AbsorbablePosition[] = [];
|
||||
|
||||
const sections = turnout.queryStore.queryByType<Section>(Section.Type);
|
||||
sections.forEach((section) => {
|
||||
const ps = new AbsorbablePoint(
|
||||
section.localToCanvasPoint(section.getStartPoint())
|
||||
);
|
||||
const pe = new AbsorbablePoint(
|
||||
section.localToCanvasPoint(section.getEndPoint())
|
||||
);
|
||||
aps.push(ps, pe); //区段端点
|
||||
});
|
||||
|
||||
const turnouts = turnout.queryStore.queryByType<Turnout>(Turnout.Type);
|
||||
turnouts.forEach((otherTurnout) => {
|
||||
const {
|
||||
pointA: [A],
|
||||
pointB: [B],
|
||||
pointC: [C],
|
||||
} = otherTurnout.datas;
|
||||
|
||||
[A, B, C].forEach((p) => {
|
||||
aps.push(
|
||||
new AbsorbablePoint(otherTurnout.localToCanvasPoint(p)), //道岔端点
|
||||
new AbsorbableLine(
|
||||
otherTurnout.localToCanvasPoint({ x: -5 * p.x, y: -5 * p.y }),
|
||||
otherTurnout.localToCanvasPoint({ x: 5 * p.x, y: 5 * p.y })
|
||||
) //道岔延长线
|
||||
);
|
||||
});
|
||||
aps.push(
|
||||
new AbsorbableLine(
|
||||
otherTurnout.localToCanvasPoint({ x: 0, y: -500 }),
|
||||
otherTurnout.localToCanvasPoint({ x: 0, y: 500 })
|
||||
), //岔心垂直线
|
||||
new AbsorbableLine(
|
||||
otherTurnout.localToCanvasPoint({ x: -500, y: 0 }),
|
||||
otherTurnout.localToCanvasPoint({ x: 500, y: 0 })
|
||||
), //岔心水平线
|
||||
new AbsorbableLine(
|
||||
otherTurnout.localToCanvasPoint({ x: -500, y: 500 }),
|
||||
otherTurnout.localToCanvasPoint({ x: 500, y: -500 })
|
||||
), //岔心/
|
||||
new AbsorbableLine(
|
||||
otherTurnout.localToCanvasPoint({ x: -500, y: -500 }),
|
||||
otherTurnout.localToCanvasPoint({ x: 500, y: 500 })
|
||||
) //岔心\
|
||||
);
|
||||
});
|
||||
|
||||
return aps;
|
||||
}
|
||||
|
||||
function onEditPointCreate(turnout: Turnout, dp: DraggablePoint) {
|
||||
dp.on('transformstart', (e: GraphicTransformEvent) => {
|
||||
if (e.isShift()) {
|
||||
turnout.getGraphicApp().setOptions({
|
||||
absorbablePositions: buildAbsorbablePositions(turnout),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const addPointConfig: MenuItemOptions = { name: '添加路径点' };
|
||||
const clearPointConfig: MenuItemOptions = { name: '清除路径点' };
|
||||
|
||||
const turnoutSectionEditMenu: ContextMenu = ContextMenu.init({
|
||||
name: '道岔区段路径编辑',
|
||||
groups: [
|
||||
{
|
||||
items: [addPointConfig, clearPointConfig],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Turnout> {
|
||||
static Name = 'TurnoutPointsDrag';
|
||||
static init(app: IDrawApp) {
|
||||
return new TurnoutPointsInteractionPlugin(app);
|
||||
}
|
||||
|
||||
constructor(app: IGraphicApp) {
|
||||
super(TurnoutPointsInteractionPlugin.Name, app);
|
||||
app.registerMenu(turnoutSectionEditMenu);
|
||||
}
|
||||
|
||||
onSectionContextMenu(e: FederatedMouseEvent, section: TurnoutSection) {
|
||||
const p = section.turnout.screenToLocalPoint(e.global);
|
||||
addPointConfig.handler = () => {
|
||||
if (section.port === DevicePort.A) {
|
||||
const { start } = getWaypointRangeIndex(
|
||||
[{ x: 0, y: 0 }, ...section.turnout.datas.pointA],
|
||||
false,
|
||||
p,
|
||||
TurnoutConsts.lineWidth
|
||||
);
|
||||
const points = section.turnout.datas.pointA;
|
||||
const ps = points.slice(0, start);
|
||||
ps.push(new Point(p.x, p.y));
|
||||
ps.push(...points.slice(start));
|
||||
section.turnout.datas.pointA = ps;
|
||||
}
|
||||
if (section.port === DevicePort.B) {
|
||||
const { start } = getWaypointRangeIndex(
|
||||
[{ x: 0, y: 0 }, ...section.turnout.datas.pointB],
|
||||
false,
|
||||
p,
|
||||
TurnoutConsts.lineWidth
|
||||
);
|
||||
const points = section.turnout.datas.pointB;
|
||||
const ps = points.slice(0, start);
|
||||
ps.push(new Point(p.x, p.y));
|
||||
ps.push(...points.slice(start));
|
||||
section.turnout.datas.pointB = ps;
|
||||
}
|
||||
if (section.port === DevicePort.C) {
|
||||
const { start } = getWaypointRangeIndex(
|
||||
[{ x: 0, y: 0 }, ...section.turnout.datas.pointC],
|
||||
false,
|
||||
p,
|
||||
TurnoutConsts.lineWidth
|
||||
);
|
||||
const points = section.turnout.datas.pointC;
|
||||
const ps = points.slice(0, start);
|
||||
ps.push(new Point(p.x, p.y));
|
||||
ps.push(...points.slice(start));
|
||||
section.turnout.datas.pointC = ps;
|
||||
}
|
||||
this.onSelected(section.turnout);
|
||||
};
|
||||
clearPointConfig.handler = () => {
|
||||
if (section.port === DevicePort.A)
|
||||
section.turnout.datas.pointA = [
|
||||
section.turnout.datas.pointA[section.turnout.datas.pointA.length - 1],
|
||||
];
|
||||
if (section.port === DevicePort.B)
|
||||
section.turnout.datas.pointB = [
|
||||
section.turnout.datas.pointB[section.turnout.datas.pointB.length - 1],
|
||||
];
|
||||
if (section.port === DevicePort.C)
|
||||
section.turnout.datas.pointC = [
|
||||
section.turnout.datas.pointC[section.turnout.datas.pointC.length - 1],
|
||||
];
|
||||
const tep = section.turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||
TurnoutEditPlugin.Name
|
||||
);
|
||||
if (tep) {
|
||||
tep.reset();
|
||||
}
|
||||
section.turnout.repaint();
|
||||
};
|
||||
turnoutSectionEditMenu.open(e.global);
|
||||
}
|
||||
|
||||
bind(g: Turnout): void {
|
||||
g.graphics.fork.eventMode = 'static';
|
||||
g.graphics.fork.cursor = 'pointer';
|
||||
g.graphics.fork.hitArea = new ForkHitArea(g);
|
||||
g.graphics.sections.forEach((sectionGraphic) => {
|
||||
sectionGraphic.eventMode = 'static';
|
||||
sectionGraphic.cursor = 'pointer';
|
||||
sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic);
|
||||
sectionGraphic.on(
|
||||
'rightclick',
|
||||
(e) => this.onSectionContextMenu(e, sectionGraphic),
|
||||
sectionGraphic
|
||||
);
|
||||
});
|
||||
g.graphics.label.eventMode = 'static';
|
||||
g.graphics.label.cursor = 'pointer';
|
||||
g.graphics.label.draggable = true;
|
||||
g.graphics.label.selectable = true;
|
||||
g.graphics.label.name = 'label';
|
||||
g.graphics.label.transformSave = true;
|
||||
g.transformSave = true;
|
||||
g.on('selected', this.onSelected, this);
|
||||
g.on('unselected', this.onUnSelected, this);
|
||||
}
|
||||
|
||||
unbind(g: Turnout): void {
|
||||
g.off('selected', this.onSelected, this);
|
||||
g.off('unselected', this.onUnSelected, this);
|
||||
g.graphics.sections.forEach((sectionGraphic) => {
|
||||
sectionGraphic.off('rightclick');
|
||||
});
|
||||
}
|
||||
|
||||
onSelected(g: DisplayObject) {
|
||||
const turnout = g as Turnout;
|
||||
let tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||
TurnoutEditPlugin.Name
|
||||
);
|
||||
if (!tep) {
|
||||
tep = new TurnoutEditPlugin(turnout, { onEditPointCreate });
|
||||
turnout.addAssistantAppend(tep);
|
||||
}
|
||||
tep.reset();
|
||||
tep.showAll();
|
||||
}
|
||||
|
||||
onUnSelected(g: DisplayObject) {
|
||||
const turnout = g as Turnout;
|
||||
const tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
|
||||
TurnoutEditPlugin.Name
|
||||
);
|
||||
if (tep) {
|
||||
tep.hideAll();
|
||||
}
|
||||
}
|
||||
|
||||
filter(...grahpics: JlGraphic[]): Turnout[] | undefined {
|
||||
return grahpics.filter((g) => g.type == Turnout.Type) as Turnout[];
|
||||
}
|
||||
}
|
||||
|
||||
type onTurnoutEditPointCreate = (turnout: Turnout, dp: DraggablePoint) => void;
|
||||
|
||||
export interface ITurnoutEditOptions {
|
||||
onEditPointCreate?: onTurnoutEditPointCreate;
|
||||
}
|
||||
|
||||
export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
|
||||
static Name = 'TurnoutEdit';
|
||||
options: ITurnoutEditOptions;
|
||||
editPoints: DraggablePoint[][] = [[], [], []];
|
||||
labels: VectorText[] = [];
|
||||
|
||||
constructor(graphic: Turnout, options?: ITurnoutEditOptions) {
|
||||
super(graphic);
|
||||
this.name = TurnoutEditPlugin.Name;
|
||||
this.options = Object.assign({}, options);
|
||||
this.initEditPoints();
|
||||
}
|
||||
reset(): void {
|
||||
this.destoryEditPoints();
|
||||
this.removeChildren();
|
||||
this.initEditPoints();
|
||||
}
|
||||
hideAll(): void {
|
||||
super.hideAll();
|
||||
}
|
||||
|
||||
initEditPoints() {
|
||||
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
|
||||
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
|
||||
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
|
||||
const cpMap: Map<Point[], IPointData[]> = new Map([
|
||||
[cpA, this.graphic.datas.pointA],
|
||||
[cpB, this.graphic.datas.pointB],
|
||||
[cpC, this.graphic.datas.pointC],
|
||||
]);
|
||||
Array.from(cpMap.entries()).forEach(([cpDatas, dataPoints], i) => {
|
||||
cpDatas.forEach((cpData, j) => {
|
||||
const dp = new DraggablePoint(cpData);
|
||||
dp.on('transforming', () => {
|
||||
const localPoint = this.graphic.canvasToLocalPoint(dp.position);
|
||||
dataPoints[j].x = localPoint.x;
|
||||
dataPoints[j].y = localPoint.y;
|
||||
|
||||
this.graphic.repaint();
|
||||
});
|
||||
if (this.options.onEditPointCreate) {
|
||||
this.options.onEditPointCreate(this.graphic, dp);
|
||||
}
|
||||
this.editPoints[i].push(dp);
|
||||
});
|
||||
});
|
||||
this.editPoints.forEach((cps) => {
|
||||
this.addChild(...cps);
|
||||
});
|
||||
this.labels = ['A', 'B', 'C'].map((str) => {
|
||||
const vc = new VectorText(str, { fill: AppConsts.assistantElementColor });
|
||||
vc.setVectorFontSize(14);
|
||||
vc.anchor.set(0.5);
|
||||
return vc;
|
||||
});
|
||||
this.addChild(...this.labels);
|
||||
}
|
||||
|
||||
destoryEditPoints() {
|
||||
this.editPoints.forEach((dps) => {
|
||||
dps.forEach((dp) => {
|
||||
dp.off('transforming');
|
||||
dp.destroy();
|
||||
this.removeChild(dp);
|
||||
});
|
||||
});
|
||||
this.editPoints = [[], [], []];
|
||||
}
|
||||
|
||||
updateEditedPointsPosition() {
|
||||
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
|
||||
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
|
||||
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
|
||||
[cpA, cpB, cpC].forEach((cps, i) => {
|
||||
cps.forEach((cp, j) => {
|
||||
this.editPoints[i][j].position.copyFrom(cp);
|
||||
if (j === cps.length - 1) {
|
||||
this.labels[i].position.copyFrom({ x: cp.x, y: cp.y + 12 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export { ForkHitArea, TurnoutSectionHitArea };
|
||||
|
Loading…
Reference in New Issue
Block a user