diff --git a/src/components/draw-app/DrawProperties.vue b/src/components/draw-app/DrawProperties.vue
index b8b0662..ffeaaba 100644
--- a/src/components/draw-app/DrawProperties.vue
+++ b/src/components/draw-app/DrawProperties.vue
@@ -81,6 +81,11 @@
+
@@ -90,6 +95,8 @@
diff --git a/src/components/draw-app/properties/PlatformProperty.vue b/src/components/draw-app/properties/PlatformProperty.vue
index f94a60e..dd0984b 100644
--- a/src/components/draw-app/properties/PlatformProperty.vue
+++ b/src/components/draw-app/properties/PlatformProperty.vue
@@ -1,6 +1,6 @@
-
+
+
@@ -69,7 +78,7 @@ import { Platform } from 'src/graphics/platform/Platform';
import { Section } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { useDrawStore } from 'src/stores/draw-store';
-import { computed, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: platformModel, onUpdate } = useFormData(
@@ -108,4 +117,20 @@ const optionsUpAndDown = [
{ label: '上行', value: true },
{ label: '下行', value: false },
];
+const centralizedStations = ref<{ label: string; value: number }[]>([]);
+
+onMounted(() => {
+ const stations = drawStore
+ .getDrawApp()
+ .queryStore.queryByType(Station.Type);
+ centralizedStations.value = [{ label: '', value: 0 }];
+ stations.forEach((station) => {
+ if (station.datas.concentrationStations) {
+ centralizedStations.value.push({
+ label: station.datas.name,
+ value: station.datas.id,
+ });
+ }
+ });
+});
diff --git a/src/components/draw-app/properties/SectionProperty.vue b/src/components/draw-app/properties/SectionProperty.vue
index 19ab547..3ce3c50 100644
--- a/src/components/draw-app/properties/SectionProperty.vue
+++ b/src/components/draw-app/properties/SectionProperty.vue
@@ -1,6 +1,6 @@
-
-
+
+
+
@@ -77,9 +83,10 @@ import { useFormData } from 'src/components/DrawAppFormUtils';
import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Section, SectionType } from 'src/graphics/section/Section';
+import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
-import { computed } from 'vue';
+import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: sectionModel, onUpdate } = useFormData(
@@ -140,4 +147,21 @@ const axleCountingRelations = computed(() => {
(relation) => relation.getOtherGraphic(section).datas.code
);
});
+
+const centralizedStations = ref<{ label: string; value: number }[]>([]);
+
+onMounted(() => {
+ const stations = drawStore
+ .getDrawApp()
+ .queryStore.queryByType(Station.Type);
+ centralizedStations.value = [{ label: '', value: 0 }];
+ stations.forEach((station) => {
+ if (station.datas.concentrationStations) {
+ centralizedStations.value.push({
+ label: station.datas.name,
+ value: station.datas.id,
+ });
+ }
+ });
+});
diff --git a/src/components/draw-app/properties/SignalProperty.vue b/src/components/draw-app/properties/SignalProperty.vue
index a9abedd..d7614c6 100644
--- a/src/components/draw-app/properties/SignalProperty.vue
+++ b/src/components/draw-app/properties/SignalProperty.vue
@@ -1,6 +1,6 @@
-
-
+
+
+
@@ -61,10 +65,11 @@
import { useFormData } from 'src/components/DrawAppFormUtils';
import { SignalData } from 'src/drawApp/graphics/SignalInteraction';
import { Section } from 'src/graphics/section/Section';
+import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useDrawStore } from 'src/stores/draw-store';
-import { computed } from 'vue';
+import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: signalModel, onUpdate } = useFormData(
@@ -107,4 +112,20 @@ const CoordinateSystemOptions = [
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
+const centralizedStations = ref<{ label: string; value: number }[]>([]);
+
+onMounted(() => {
+ const stations = drawStore
+ .getDrawApp()
+ .queryStore.queryByType(Station.Type);
+ centralizedStations.value = [{ label: '', value: 0 }];
+ stations.forEach((station) => {
+ if (station.datas.concentrationStations) {
+ centralizedStations.value.push({
+ label: station.datas.name,
+ value: station.datas.id,
+ });
+ }
+ });
+});
diff --git a/src/components/draw-app/properties/StationProperty.vue b/src/components/draw-app/properties/StationProperty.vue
index e834499..91c546c 100644
--- a/src/components/draw-app/properties/StationProperty.vue
+++ b/src/components/draw-app/properties/StationProperty.vue
@@ -38,22 +38,27 @@
label="公里标(mm):"
/>
-
+
@@ -61,17 +66,16 @@
diff --git a/src/components/draw-app/properties/TurnoutProperty.vue b/src/components/draw-app/properties/TurnoutProperty.vue
index 4cdd50e..ebd7858 100644
--- a/src/components/draw-app/properties/TurnoutProperty.vue
+++ b/src/components/draw-app/properties/TurnoutProperty.vue
@@ -1,6 +1,6 @@
-
-
+
+
+
@@ -74,9 +79,10 @@
import { useFormData } from 'src/components/DrawAppFormUtils';
import { TurnoutData } from 'src/drawApp/graphics/TurnoutInteraction';
import { Section } from 'src/graphics/section/Section';
+import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
-import { computed } from 'vue';
+import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: turnoutModel, onUpdate } = useFormData(
@@ -124,4 +130,21 @@ const turnoutRelations = computed(() => {
}(${relation.getOtherRelationParam(turnout).param})`
);
});
+
+const centralizedStations = ref<{ label: string; value: number }[]>([]);
+
+onMounted(() => {
+ const stations = drawStore
+ .getDrawApp()
+ .queryStore.queryByType(Station.Type);
+ centralizedStations.value = [{ label: '', value: 0 }];
+ stations.forEach((station) => {
+ if (station.datas.concentrationStations) {
+ centralizedStations.value.push({
+ label: station.datas.name,
+ value: station.datas.id,
+ });
+ }
+ });
+});
diff --git a/src/drawApp/graphics/ConcentrationDividingLineInteraction.ts b/src/drawApp/graphics/ConcentrationDividingLineInteraction.ts
new file mode 100644
index 0000000..b6bd21b
--- /dev/null
+++ b/src/drawApp/graphics/ConcentrationDividingLineInteraction.ts
@@ -0,0 +1,77 @@
+import * as pb_1 from 'google-protobuf';
+import { GraphicDataBase } from './GraphicDataBase';
+import {
+ IConcentrationDividingLineData,
+ ConcentrationDividingLine,
+} from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { IPointData } from 'pixi.js';
+
+export class ConcentrationDividingLineData
+ extends GraphicDataBase
+ implements IConcentrationDividingLineData
+{
+ constructor(data?: graphicData.ConcentrationDividingLine) {
+ let concentrationDividingLine;
+ if (!data) {
+ concentrationDividingLine = new graphicData.ConcentrationDividingLine({
+ common: GraphicDataBase.defaultCommonInfo(
+ ConcentrationDividingLine.Type
+ ),
+ });
+ } else {
+ concentrationDividingLine = data;
+ }
+ super(concentrationDividingLine);
+ }
+ public get data(): graphicData.ConcentrationDividingLine {
+ return this.getData();
+ }
+ get code(): string {
+ return this.data.code;
+ }
+ set code(v: string) {
+ this.data.code = v;
+ }
+ get points(): IPointData[] {
+ return this.data.points;
+ }
+ set points(points: IPointData[]) {
+ this.data.points = points.map(
+ (p) => new graphicData.Point({ x: p.x, y: p.y })
+ );
+ }
+ get refLeftStationId(): number {
+ return this.data.refLeftStationId;
+ }
+ set refLeftStationId(v: number) {
+ this.data.refLeftStationId = v;
+ }
+ get refRightStationId(): number {
+ return this.data.refRightStationId;
+ }
+ set refRightStationId(v: number) {
+ this.data.refRightStationId = v;
+ }
+ get nodeConWithSecs(): graphicData.NodeConWithSec[] {
+ return this.data.nodeConWithSecs;
+ }
+ set nodeConWithSecs(nodes: graphicData.NodeConWithSec[]) {
+ this.data.nodeConWithSecs = nodes;
+ }
+ get isOtherLineConcentrationDividingLine(): boolean {
+ return this.data.isOtherLineConcentrationDividingLine;
+ }
+ set isOtherLineConcentrationDividingLine(v: boolean) {
+ this.data.isOtherLineConcentrationDividingLine = v;
+ }
+ clone(): ConcentrationDividingLineData {
+ return new ConcentrationDividingLineData(this.data.cloneMessage());
+ }
+ copyFrom(data: ConcentrationDividingLineData): void {
+ pb_1.Message.copyInto(data.data, this.data);
+ }
+ eq(other: ConcentrationDividingLineData): boolean {
+ return pb_1.Message.equals(this.data, other.data);
+ }
+}
diff --git a/src/drawApp/graphics/PlatformInteraction.ts b/src/drawApp/graphics/PlatformInteraction.ts
index 4fc37d6..19e0cdc 100644
--- a/src/drawApp/graphics/PlatformInteraction.ts
+++ b/src/drawApp/graphics/PlatformInteraction.ts
@@ -71,6 +71,12 @@ export class PlatformData extends GraphicDataBase implements IPlatformData {
set refSectionId(v: number) {
this.data.refSectionId = v;
}
+ get centralizedStation(): number {
+ return this.data.centralizedStationId;
+ }
+ set centralizedStation(v: number) {
+ this.data.centralizedStationId = v;
+ }
clone(): PlatformData {
return new PlatformData(this.data.cloneMessage());
diff --git a/src/drawApp/graphics/SectionInteraction.ts b/src/drawApp/graphics/SectionInteraction.ts
index 852978b..2906369 100644
--- a/src/drawApp/graphics/SectionInteraction.ts
+++ b/src/drawApp/graphics/SectionInteraction.ts
@@ -77,6 +77,12 @@ export class SectionData extends GraphicDataBase implements ISectionData {
set turning(v: boolean) {
this.data.turning = v;
}
+ get centralizedStation(): number {
+ return this.data.centralizedStationId;
+ }
+ set centralizedStation(v: number) {
+ this.data.centralizedStationId = v;
+ }
clone(): SectionData {
return new SectionData(this.data.cloneMessage());
}
diff --git a/src/drawApp/graphics/SignalInteraction.ts b/src/drawApp/graphics/SignalInteraction.ts
index a5e6a0f..402a84d 100644
--- a/src/drawApp/graphics/SignalInteraction.ts
+++ b/src/drawApp/graphics/SignalInteraction.ts
@@ -62,6 +62,12 @@ export class SignalData extends GraphicDataBase implements ISignalData {
set kilometerSystem(v: KilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
}
+ get centralizedStation(): number {
+ return this.data.centralizedStationId;
+ }
+ set centralizedStation(v: number) {
+ this.data.centralizedStationId = v;
+ }
clone(): SignalData {
return new SignalData(this.data.cloneMessage());
}
diff --git a/src/drawApp/graphics/StationInteraction.ts b/src/drawApp/graphics/StationInteraction.ts
index 95fc6c1..b72d1b7 100644
--- a/src/drawApp/graphics/StationInteraction.ts
+++ b/src/drawApp/graphics/StationInteraction.ts
@@ -68,6 +68,12 @@ export class StationData extends GraphicDataBase implements IStationData {
set name(v: string) {
this.data.name = v;
}
+ get manageStations(): number[] {
+ return this.data.manageStations;
+ }
+ set manageStations(v: number[]) {
+ this.data.manageStations = v;
+ }
clone(): StationData {
return new StationData(this.data.cloneMessage());
}
diff --git a/src/drawApp/graphics/TurnoutInteraction.ts b/src/drawApp/graphics/TurnoutInteraction.ts
index 8e0fd4c..2a1b808 100644
--- a/src/drawApp/graphics/TurnoutInteraction.ts
+++ b/src/drawApp/graphics/TurnoutInteraction.ts
@@ -333,6 +333,12 @@ export class TurnoutData extends GraphicDataBase implements ITurnoutData {
(v) => new graphicData.KilometerSystem(v)
);
}
+ get centralizedStation(): number {
+ return this.data.centralizedStationId;
+ }
+ set centralizedStation(v: number) {
+ this.data.centralizedStationId = v;
+ }
clone(): TurnoutData {
return new TurnoutData(this.data.cloneMessage());
}
diff --git a/src/drawApp/index.ts b/src/drawApp/index.ts
index efeb577..2592cde 100644
--- a/src/drawApp/index.ts
+++ b/src/drawApp/index.ts
@@ -24,6 +24,12 @@ import {
SignalState,
} from './graphics/SignalInteraction';
import { graphicData } from 'src/protos/stationLayoutGraphics';
+import {
+ ConcentrationDividingLine,
+ ConcentrationDividingLineTemplate,
+} from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
+import { ConcentrationDividingLineData } from './graphics/ConcentrationDividingLineInteraction';
+import { ConcentrationDividingLineDraw } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLineDrawAssistant';
import { Rect, RectTemplate } from 'src/graphics/rect/Rect';
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
import { RectData } from './graphics/RectInteraction';
@@ -257,7 +263,13 @@ export function initDrawApp(): IDrawApp {
new AxleCountingTemplate(new AxleCountingData())
),
new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData())),
- DrawSignalInteraction.init(app);
+ new ConcentrationDividingLineDraw(
+ app,
+ new ConcentrationDividingLineTemplate(
+ new ConcentrationDividingLineData()
+ )
+ );
+ DrawSignalInteraction.init(app);
} else {
new StationLineDraw(app, new StationLineTemplate(new StationLineData())),
new RectDraw(app, new RectTemplate(new RectData())),
@@ -364,6 +376,11 @@ export function saveDrawDatas(app: IDrawApp) {
} else if (LogicSection.Type === g.type) {
const logicSectionData = (g as LogicSection).saveData();
storage.logicSections.push((logicSectionData as LogicSectionData).data);
+ } else if (g instanceof ConcentrationDividingLine) {
+ const concentrationDividingLineData = g.saveData();
+ storage.concentrationDividingLines.push(
+ (concentrationDividingLineData as ConcentrationDividingLineData).data
+ );
}
});
// storage.Platforms.forEach((item) => {
@@ -517,6 +534,9 @@ export async function loadDrawDatas(): Promise {
storage.trainWindows.forEach((trainWindow) => {
datas.push(new TrainWindowData(trainWindow));
});
+ storage.concentrationDividingLines.forEach((concentrationDividingLine) => {
+ datas.push(new ConcentrationDividingLineData(concentrationDividingLine));
+ });
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
diff --git a/src/graphics/axleCounting/AxleCountingDrawAssistant.ts b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts
index 42b2f94..519a30d 100644
--- a/src/graphics/axleCounting/AxleCountingDrawAssistant.ts
+++ b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts
@@ -43,7 +43,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
> {
codeGraph: AxleCounting;
constructor(app: IDrawApp, template: AxleCountingTemplate) {
- super(app, template, 'sym_o_circle', '不展示');
+ super(app, template, 'sym_o_circle', '计轴');
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
AxleCountingInteraction.init(app);
diff --git a/src/graphics/concentrationDividingLine/ConcentrationDividingLine.ts b/src/graphics/concentrationDividingLine/ConcentrationDividingLine.ts
new file mode 100644
index 0000000..eb38268
--- /dev/null
+++ b/src/graphics/concentrationDividingLine/ConcentrationDividingLine.ts
@@ -0,0 +1,224 @@
+import { IPointData } from 'pixi.js';
+import {
+ GraphicData,
+ JlGraphic,
+ JlGraphicTemplate,
+ calculateDistanceFromPointToLine,
+ getRectangleCenter,
+ ILineGraphic,
+} from 'jl-graphic';
+import { SectionGraphic } from './SectionGraphic';
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { Section, SectionType } from '../section/Section';
+import { arePolylinesIntersect } from './ConcentrationDividingLineUtils';
+import { createRelatedRefProto } from '../CommonGraphics';
+import { Turnout,TurnoutPort } from '../turnout/Turnout';
+
+export interface IConcentrationDividingLineData extends GraphicData {
+ get code(): string; // 编号
+ set code(v: string);
+ get points(): IPointData[]; // 线坐标点
+ set points(points: IPointData[]);
+ get refLeftStationId(): number; //左边关联的集中站id
+ set refLeftStationId(v: number);
+ get refRightStationId(): number; //右边关联的集中站id
+ set refRightStationId(v: number);
+ get nodeConWithSecs(): graphicData.NodeConWithSec[]; // 集中区分割线与区段的交点
+ set nodeConWithSecs(nodes: graphicData.NodeConWithSec[]);
+ get isOtherLineConcentrationDividingLine(): boolean; //集中区分割线绘制在其它线的边界处
+ set isOtherLineConcentrationDividingLine(v: boolean);
+ clone(): IConcentrationDividingLineData;
+ copyFrom(data: IConcentrationDividingLineData): void;
+ eq(other: IConcentrationDividingLineData): boolean;
+}
+
+export const ConcentrationDividingLineConsts = {
+ lineColor: '#f00',
+ lineWidth: 2,
+};
+
+enum devicePort {
+ 'A',
+ 'B',
+ 'C',
+}
+
+export class ConcentrationDividingLine
+ extends JlGraphic
+ implements ILineGraphic
+{
+ static Type = 'ConcentrationDividingLine';
+ lineGraphic: SectionGraphic;
+
+ constructor() {
+ super(ConcentrationDividingLine.Type);
+ this.lineGraphic = new SectionGraphic();
+ this.transformSave = true;
+ this.addChild(this.lineGraphic);
+ }
+
+ get datas(): IConcentrationDividingLineData {
+ return this.getDatas();
+ }
+
+ get linePoints(): IPointData[] {
+ return this.datas.points;
+ }
+ set linePoints(points: IPointData[]) {
+ const old = this.datas.clone();
+ old.points = points;
+ this.updateData(old);
+ }
+
+ doRepaint() {
+ if (this.datas.points.length < 2) {
+ throw new Error('Link坐标数据异常');
+ }
+ this.lineGraphic.clear();
+ this.lineGraphic.points = this.datas.points;
+ this.lineGraphic.lineStyle(
+ ConcentrationDividingLineConsts.lineWidth,
+ ConcentrationDividingLineConsts.lineColor
+ );
+ this.lineGraphic.paint();
+ }
+ buildRelation() {
+ const nodeConWithSecs: graphicData.NodeConWithSec[] = [];
+ const sections = this.queryStore
+ .queryByType(Section.Type)
+ .filter((g) => g.datas.sectionType == SectionType.Physical);
+ const hasNodeSection = new Map();
+ sections.forEach((section) => {
+ const changeSectionData = section.datas.points.map((point) =>
+ section.localToCanvasPoint(point)
+ );
+ const changeConcentrationDividingLineData = this.datas.points.map(
+ (point) => this.localToCanvasPoint(point)
+ );
+ const hasNode = arePolylinesIntersect(
+ changeSectionData,
+ changeConcentrationDividingLineData
+ );
+ if (hasNode) {
+ const minA = calculateDistanceFromPointToLine(
+ hasNode.segment2[0],
+ hasNode.segment2[1],
+ section.localToCanvasPoint(section.getStartPoint())
+ );
+ const minB = calculateDistanceFromPointToLine(
+ hasNode.segment2[0],
+ hasNode.segment2[1],
+ section.localToCanvasPoint(section.getEndPoint())
+ );
+ const relationParam = minA > minB ? TurnoutPort.B : TurnoutPort.A;
+ const portRefOtherDevice =
+ relationParam == 'A' ? section.datas.paRef : section.datas.pbRef;
+ if (
+ portRefOtherDevice?.id &&
+ !hasNodeSection.get(section.id) &&
+ !hasNodeSection.get(portRefOtherDevice.id)
+ ) {
+ const refDevice = this.queryStore.queryById(
+ portRefOtherDevice?.id
+ );
+ const [leftDevice, rightDevice] =
+ refDevice.localToCanvasPoint(
+ getRectangleCenter(refDevice.getLocalBounds())
+ ).x <
+ section.localToCanvasPoint(
+ getRectangleCenter(section.getLocalBounds())
+ ).x
+ ? [
+ {
+ device: refDevice,
+ port: devicePort[
+ portRefOtherDevice.devicePort
+ ] as TurnoutPort,
+ },
+ { device: section, port: relationParam },
+ ]
+ : [
+ { device: section, port: relationParam },
+ {
+ device: refDevice,
+ port: devicePort[
+ portRefOtherDevice.devicePort
+ ] as TurnoutPort,
+ },
+ ];
+ hasNodeSection.set(leftDevice.device.id, '1');
+ hasNodeSection.set(rightDevice.device.id, '1');
+ nodeConWithSecs.push(
+ new graphicData.NodeConWithSec({
+ leftSection: createRelatedRefProto(
+ leftDevice.device.type,
+ leftDevice.device.id,
+ leftDevice.port
+ ),
+ rightSection: createRelatedRefProto(
+ rightDevice.device.type,
+ rightDevice.device.id,
+ rightDevice.port
+ ),
+ })
+ );
+ } else if (!hasNodeSection.get(section.id) && !portRefOtherDevice?.id) {
+ const [leftSectionId, rightSectionId] =
+ relationParam === 'A'
+ ? [undefined, section.id]
+ : [section.id, undefined];
+ hasNodeSection.set(section.id, '1');
+ if (leftSectionId == undefined) {
+ nodeConWithSecs.push(
+ new graphicData.NodeConWithSec({
+ leftSection: undefined,
+ rightSection: createRelatedRefProto(
+ Section.Type,
+ rightSectionId,
+ TurnoutPort.A
+ ),
+ })
+ );
+ } else {
+ nodeConWithSecs.push(
+ new graphicData.NodeConWithSec({
+ leftSection: createRelatedRefProto(
+ Section.Type,
+ leftSectionId,
+ TurnoutPort.B
+ ),
+ rightSection: undefined,
+ })
+ );
+ }
+ }
+ }
+ });
+ nodeConWithSecs.sort((a, b) => {
+ const sectionAId = a.leftSection ? a.leftSection.id : a.rightSection.id;
+ const sectionA = this.queryStore.queryById(sectionAId);
+ const sectionBId = b.leftSection ? b.leftSection.id : b.rightSection.id;
+ const sectionB = this.queryStore.queryById(sectionBId);
+ return (
+ sectionA.localToCanvasPoint(
+ getRectangleCenter(sectionA.getLocalBounds())
+ ).y -
+ sectionB.localToCanvasPoint(
+ getRectangleCenter(sectionB.getLocalBounds())
+ ).y
+ );
+ });
+ this.datas.nodeConWithSecs = nodeConWithSecs;
+ }
+}
+
+export class ConcentrationDividingLineTemplate extends JlGraphicTemplate {
+ constructor(dataTemplate: IConcentrationDividingLineData) {
+ super(ConcentrationDividingLine.Type, { dataTemplate });
+ }
+ new() {
+ const g = new ConcentrationDividingLine();
+ g.loadData(this.datas);
+ return g;
+ }
+}
diff --git a/src/graphics/concentrationDividingLine/ConcentrationDividingLineDrawAssistant.ts b/src/graphics/concentrationDividingLine/ConcentrationDividingLineDrawAssistant.ts
new file mode 100644
index 0000000..2245a2d
--- /dev/null
+++ b/src/graphics/concentrationDividingLine/ConcentrationDividingLineDrawAssistant.ts
@@ -0,0 +1,212 @@
+import {
+ IGraphicApp,
+ GraphicDrawAssistant,
+ GraphicInteractionPlugin,
+ IDrawApp,
+ JlGraphic,
+ linePoint,
+ PolylineEditPlugin,
+ addWayPoint,
+ clearWayPoint,
+ MenuItemOptions,
+ ContextMenu
+} from 'jl-graphic';
+import {
+ IConcentrationDividingLineData,
+ ConcentrationDividingLine,
+ ConcentrationDividingLineConsts,
+ ConcentrationDividingLineTemplate,
+} from './ConcentrationDividingLine';
+import {
+ DisplayObject,
+ FederatedMouseEvent,
+ Graphics,
+ IHitArea,
+ Point,
+} from 'pixi.js';
+import { getWayLineIndex } from '../polygon/PolygonUtils';
+
+export class ConcentrationDividingLineDraw extends GraphicDrawAssistant<
+ ConcentrationDividingLineTemplate,
+ IConcentrationDividingLineData
+> {
+ points: Point[] = [];
+ graphic = new Graphics();
+
+ constructor(app: IDrawApp, template: ConcentrationDividingLineTemplate) {
+ super(app, template, 'sym_o_timeline', '集中区分割线');
+ this.container.addChild(this.graphic);
+
+ ConcentrationDividingLinePointEditPlugin.init(app, this);
+ }
+
+ bind(): void {
+ super.bind();
+ }
+ unbind(): void {
+ super.unbind();
+ }
+
+ onLeftDown(e: FederatedMouseEvent): void {
+ const { x, y } = this.toCanvasCoordinates(e.global);
+ const p = new Point(x, y);
+ this.points.push(p);
+ }
+
+ onRightClick(): void {
+ if (this.points.length < 2) {
+ this.finish();
+ return;
+ }
+ this.createAndStore(true);
+ }
+
+ onEsc(): void {
+ if (this.points.length < 2) {
+ this.finish();
+ return;
+ }
+ this.createAndStore(true);
+ }
+
+ redraw(p: Point): void {
+ if (this.points.length < 1) return;
+ this.graphic.clear();
+ this.graphic.lineStyle(
+ ConcentrationDividingLineConsts.lineWidth,
+ ConcentrationDividingLineConsts.lineColor
+ );
+
+ const ps = [...this.points];
+ ps.push(p);
+ ps.forEach((p, i) => {
+ if (i !== 0) {
+ this.graphic.lineTo(p.x, p.y);
+ } else {
+ this.graphic.moveTo(p.x, p.y);
+ }
+ });
+ }
+
+ prepareData(data: IConcentrationDividingLineData): boolean {
+ if (this.points.length < 2) {
+ console.log('ConcentrationDividingLine绘制因点不够取消绘制');
+ return false;
+ }
+ data.points = this.points;
+ return true;
+ }
+
+ clearCache(): void {
+ this.points = [];
+ this.graphic.clear();
+ }
+}
+
+export class ConcentrationDividingLineGraphicHitArea implements IHitArea {
+ concentrationDividingLine: ConcentrationDividingLine;
+ constructor(concentrationDividingLine: ConcentrationDividingLine) {
+ this.concentrationDividingLine = concentrationDividingLine;
+ }
+ contains(x: number, y: number): boolean {
+ for (
+ let i = 1;
+ i < this.concentrationDividingLine.datas.points.length;
+ i++
+ ) {
+ const p1 = this.concentrationDividingLine.datas.points[i - 1];
+ const p2 = this.concentrationDividingLine.datas.points[i];
+ if (
+ linePoint(p1, p2, { x, y }, ConcentrationDividingLineConsts.lineWidth)
+ ) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+const addWaypointConfig: MenuItemOptions = {
+ name: '添加路径点',
+};
+const clearWaypointsConfig: MenuItemOptions = {
+ name: '清除所有路径点',
+};
+const ConcentrationDividingLineEditMenu: ContextMenu = ContextMenu.init({
+ name: '集中区分割线编辑菜单',
+ groups: [
+ {
+ items: [addWaypointConfig, clearWaypointsConfig],
+ },
+ ],
+});
+
+export class ConcentrationDividingLinePointEditPlugin extends GraphicInteractionPlugin {
+ static Name = 'ConcentrationDividingLinePointDrag';
+ drawAssistant: ConcentrationDividingLineDraw;
+
+ constructor(app: IGraphicApp, da: ConcentrationDividingLineDraw) {
+ super(ConcentrationDividingLinePointEditPlugin.Name, app);
+ this.drawAssistant = da;
+ app.registerMenu(ConcentrationDividingLineEditMenu);
+ }
+ static init(app: IGraphicApp, da: ConcentrationDividingLineDraw) {
+ return new ConcentrationDividingLinePointEditPlugin(app, da);
+ }
+ filter(...grahpics: JlGraphic[]): ConcentrationDividingLine[] | undefined {
+ return grahpics.filter(
+ (g) => g.type == ConcentrationDividingLine.Type
+ ) as ConcentrationDividingLine[];
+ }
+ bind(g: ConcentrationDividingLine): void {
+ g.lineGraphic.eventMode = 'static';
+ g.lineGraphic.cursor = 'pointer';
+ g.lineGraphic.hitArea = new ConcentrationDividingLineGraphicHitArea(g);
+ g.transformSave = true;
+ g.on('selected', this.onSelected, this);
+ g.on('unselected', this.onUnselected, this);
+ g.on('_rightclick', this.onContextMenu, this);
+ }
+ unbind(g: ConcentrationDividingLine): void {
+ g.off('selected', this.onSelected, this);
+ g.off('unselected', this.onUnselected, this);
+ g.off('_rightclick', this.onContextMenu, this);
+ }
+ onContextMenu(e: FederatedMouseEvent) {
+ const target = e.target as DisplayObject;
+ const concentrationDividingLine =
+ target.getGraphic() as ConcentrationDividingLine;
+ this.app.updateSelected(concentrationDividingLine);
+ const p = concentrationDividingLine.screenToLocalPoint(e.global);
+ addWaypointConfig.handler = () => {
+ const linePoints = concentrationDividingLine.linePoints;
+ const { start, end } = getWayLineIndex(linePoints, p);
+ addWayPoint(concentrationDividingLine, false, start, end, p);
+ };
+ clearWaypointsConfig.handler = () => {
+ clearWayPoint(concentrationDividingLine, false);
+ };
+ ConcentrationDividingLineEditMenu.open(e.global);
+ }
+ onSelected(g: DisplayObject): void {
+ const concentrationDividingLine = g as ConcentrationDividingLine;
+ let lep = concentrationDividingLine.getAssistantAppend(
+ PolylineEditPlugin.Name
+ );
+ if (!lep) {
+ lep = new PolylineEditPlugin(concentrationDividingLine);
+ concentrationDividingLine.addAssistantAppend(lep);
+ }
+ lep.showAll();
+ }
+ onUnselected(g: DisplayObject): void {
+ const concentrationDividingLine = g as ConcentrationDividingLine;
+ const lep =
+ concentrationDividingLine.getAssistantAppend(
+ PolylineEditPlugin.Name
+ );
+ if (lep) {
+ lep.hideAll();
+ }
+ }
+}
diff --git a/src/graphics/concentrationDividingLine/ConcentrationDividingLineUtils.ts b/src/graphics/concentrationDividingLine/ConcentrationDividingLineUtils.ts
new file mode 100644
index 0000000..bf6da02
--- /dev/null
+++ b/src/graphics/concentrationDividingLine/ConcentrationDividingLineUtils.ts
@@ -0,0 +1,192 @@
+import { IPointData } from 'pixi.js';
+import { Section } from '../section/Section';
+import { Turnout } from '../turnout/Turnout';
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { IDrawApp, JlGraphic } from 'jl-graphic';
+import { GraphicDataBase } from 'src/drawApp/graphics/GraphicDataBase';
+import { TurnoutData } from 'src/drawApp/graphics/TurnoutInteraction';
+import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
+import { SignalData } from 'src/drawApp/graphics/SignalInteraction';
+import { Signal } from '../signal/Signal';
+
+//判断线段与线段有木有交点
+export function isSegmentsIntersect(
+ segment1: IPointData[],
+ segment2: IPointData[]
+) {
+ const [p1, p2] = segment1;
+ const [p3, p4] = segment2;
+ // 判断包围盒是否相交
+ if (
+ Math.max(p1.x, p2.x) < Math.min(p3.x, p4.x) ||
+ Math.min(p1.x, p2.x) > Math.max(p3.x, p4.x) ||
+ Math.max(p1.y, p2.y) < Math.min(p3.y, p4.y) ||
+ Math.min(p1.y, p2.y) > Math.max(p3.y, p4.y)
+ ) {
+ return false;
+ }
+ // 计算向量叉积
+ const cross1 = crossProduct(p3, p1, p4);
+ const cross2 = crossProduct(p3, p2, p4);
+ const cross3 = crossProduct(p1, p3, p2);
+ const cross4 = crossProduct(p1, p4, p2);
+ if (cross1 * cross2 < 0 && cross3 * cross4 < 0) {
+ return true;
+ }
+
+ return false;
+}
+
+function crossProduct(p1: IPointData, p2: IPointData, p3: IPointData) {
+ return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
+}
+
+export function getSegmentsFromPolyline(polyline: IPointData[]) {
+ const segments = [];
+
+ for (let i = 0; i < polyline.length - 1; i++) {
+ const segment = [polyline[i], polyline[i + 1]];
+ segments.push(segment);
+ }
+
+ return segments;
+}
+
+//判断折线与折线有木有交点
+export function arePolylinesIntersect(
+ polyline1: IPointData[],
+ polyline2: IPointData[]
+) {
+ const segments1 = getSegmentsFromPolyline(polyline1);
+ const segments2 = getSegmentsFromPolyline(polyline2);
+
+ for (const segment1 of segments1) {
+ for (const segment2 of segments2) {
+ if (isSegmentsIntersect(segment1, segment2)) {
+ return { hasnode: true, segment1, segment2 };
+ }
+ }
+ }
+
+ return false;
+}
+
+//获取指定区间内的物理区段和道岔
+export function findContainDevice(
+ refDevice: Section | Turnout,
+ refDevicePort: graphicData.RelatedRef.DevicePort,
+ containDeviceIds: number[],
+ drawApp: IDrawApp
+) {
+ const devicePort = graphicData.RelatedRef.DevicePort;
+ containDeviceIds.push(refDevice.id);
+ switch (true) {
+ case refDevice instanceof Section:
+ const sectionPaorbRef =
+ refDevicePort == devicePort.B
+ ? refDevice.datas.paRef
+ : refDevice.datas.pbRef;
+ if (sectionPaorbRef && !containDeviceIds.includes(sectionPaorbRef.id)) {
+ const pbRefDevice = drawApp.queryStore.queryById(
+ sectionPaorbRef.id
+ );
+ findContainDevice(
+ pbRefDevice,
+ sectionPaorbRef.devicePort,
+ containDeviceIds,
+ drawApp
+ );
+ }
+ break;
+ //道岔需要分路--实际的走向
+ case refDevice instanceof Turnout:
+ const otherPorts = [devicePort.A, devicePort.B, devicePort.C].filter(
+ (port) => port !== refDevicePort
+ );
+ otherPorts.forEach((port) => {
+ switch (port) {
+ case devicePort.A:
+ const turnoutPaRef = refDevice.datas.paRef;
+ if (turnoutPaRef && !containDeviceIds.includes(turnoutPaRef.id)) {
+ const paRefDevice = drawApp.queryStore.queryById<
+ Section | Turnout
+ >(turnoutPaRef.id);
+ findContainDevice(
+ paRefDevice,
+ turnoutPaRef.devicePort,
+ containDeviceIds,
+ drawApp
+ );
+ }
+ break;
+ case devicePort.B:
+ const turnoutPbRef = refDevice.datas.pbRef;
+ if (turnoutPbRef && !containDeviceIds.includes(turnoutPbRef.id)) {
+ const pbRefDevice = drawApp.queryStore.queryById<
+ Section | Turnout
+ >(turnoutPbRef.id);
+ findContainDevice(
+ pbRefDevice,
+ turnoutPbRef.devicePort,
+ containDeviceIds,
+ drawApp
+ );
+ }
+ break;
+ case devicePort.C:
+ const turnoutPcRef = (refDevice as Turnout).datas.pcRef;
+ if (turnoutPcRef && !containDeviceIds.includes(turnoutPcRef.id)) {
+ const pcRefDevice = drawApp.queryStore.queryById<
+ Section | Turnout
+ >(turnoutPcRef.id);
+ findContainDevice(
+ pcRefDevice,
+ turnoutPcRef.devicePort,
+ containDeviceIds,
+ drawApp
+ );
+ }
+ break;
+ }
+ });
+ break;
+ }
+}
+
+export function handleCentralizedStationsData(
+ devices: JlGraphic[],
+ centralizedStations: number[]
+) {
+ interface GraphicData {
+ centralizedStations: number[];
+ }
+ const dataMap = new Map([
+ [Turnout.Type, new TurnoutData()],
+ [Section.Type, new SectionData()],
+ [Signal.Type, new SignalData()],
+ ]);
+ devices.forEach((device) => {
+ const data = dataMap.get(device.type);
+ if (data) {
+ data.copyFrom(device.saveData());
+ const dataCopy = data as GraphicDataBase & GraphicData;
+ dataCopy.centralizedStations = centralizedStations;
+ device.updateData(data);
+ }
+ });
+}
+
+//找到公共的元素
+type findType = string | number;
+export function findCommonElements(arrays: findType[][]) {
+ if (arrays.length === 0) {
+ return [];
+ }
+ const commonElements: findType[] = [];
+ arrays[0].forEach((element) => {
+ if (arrays.every((arr) => arr.includes(element))) {
+ commonElements.push(element);
+ }
+ });
+ return commonElements;
+}
diff --git a/src/graphics/concentrationDividingLine/SectionGraphic.ts b/src/graphics/concentrationDividingLine/SectionGraphic.ts
new file mode 100644
index 0000000..c0b13e0
--- /dev/null
+++ b/src/graphics/concentrationDividingLine/SectionGraphic.ts
@@ -0,0 +1,57 @@
+import { Graphics, IPointData } from 'pixi.js';
+import { assertBezierPoints, convertToBezierParams } from 'jl-graphic';
+
+export enum DevicePort {
+ A = 'A',
+ B = 'B',
+ C = 'C',
+}
+
+export class SectionGraphic extends Graphics {
+ static Type = 'SectionGraphic';
+ private _points: IPointData[] = [];
+ public get points(): IPointData[] {
+ return this._points;
+ }
+ public set points(value: IPointData[]) {
+ if (!this.isCurve) {
+ if (value.length < 2) {
+ throw Error('Polyline must have at least 2 points');
+ }
+ } else {
+ assertBezierPoints(value);
+ }
+ this._points = value;
+ }
+
+ private _segmentsCount = 10;
+ public get segmentsCount(): number {
+ return this._segmentsCount;
+ }
+ public set segmentsCount(value: number) {
+ if (value < 1) {
+ throw Error('segmentsCount must be at least 1');
+ }
+ this._segmentsCount = value;
+ }
+
+ isCurve = false;
+
+ constructor() {
+ super();
+ }
+
+ paint() {
+ if (this.isCurve) {
+ const bps = convertToBezierParams(this.points);
+ bps.forEach((bp) => {
+ this.drawBezierCurve(bp.p1, bp.p2, bp.cp1, bp.cp2, this.segmentsCount);
+ });
+ } else {
+ this.moveTo(this.points[0].x, this.points[0].y);
+ for (let i = 1; i < this.points.length; i++) {
+ this.lineTo(this.points[i].x, this.points[i].y);
+ }
+ }
+ }
+}
diff --git a/src/graphics/logicSection/LogicSectionDrawAssistant.ts b/src/graphics/logicSection/LogicSectionDrawAssistant.ts
index 1320f8c..88f70d6 100644
--- a/src/graphics/logicSection/LogicSectionDrawAssistant.ts
+++ b/src/graphics/logicSection/LogicSectionDrawAssistant.ts
@@ -18,7 +18,7 @@ export class LogicSectionDraw extends GraphicDrawAssistant<
points: Point[] = [];
graphic = new Graphics();
constructor(app: IDrawApp, template: LogicSectionTemplate) {
- super(app, template, 'sym_o_timeline', '不展示');
+ super(app, template, 'sym_o_timeline', '逻辑区段');
this.container.addChild(this.graphic);
LogicSectionEditPlugin.init(app);
}
diff --git a/src/graphics/pathLine/PathLineDrawAssistant.ts b/src/graphics/pathLine/PathLineDrawAssistant.ts
index 12e8f6f..9ea384b 100644
--- a/src/graphics/pathLine/PathLineDrawAssistant.ts
+++ b/src/graphics/pathLine/PathLineDrawAssistant.ts
@@ -38,7 +38,7 @@ export class PathLineDraw extends GraphicDrawAssistant<
graphic: Graphics = new Graphics();
constructor(app: IDrawApp, template: PathLineTemplate) {
- super(app, template, 'sym_o_horizontal_rule', '不展示');
+ super(app, template, 'sym_o_horizontal_rule', 'PathLine');
this.container.addChild(this.graphic);
PathLinePointsEditPlugin.init(app);
}
diff --git a/src/graphics/platform/Platform.ts b/src/graphics/platform/Platform.ts
index b2b9d80..2311a5d 100644
--- a/src/graphics/platform/Platform.ts
+++ b/src/graphics/platform/Platform.ts
@@ -25,6 +25,8 @@ export interface IPlatformData extends GraphicData {
set refStation(v: number);
get refSectionId(): number; // 关联的物理区段
set refSectionId(v: number);
+ get centralizedStation(): number; //所属集中站
+ set centralizedStation(v: number);
clone(): IPlatformData;
copyFrom(data: IPlatformData): void;
eq(other: IPlatformData): boolean;
diff --git a/src/graphics/section/Section.ts b/src/graphics/section/Section.ts
index 5cfcc9f..499121d 100644
--- a/src/graphics/section/Section.ts
+++ b/src/graphics/section/Section.ts
@@ -48,6 +48,8 @@ export interface ISectionData extends GraphicData {
set destinationCode(destinationCode: string);
get turning(): boolean;
set turning(v: boolean);
+ get centralizedStation(): number; //所属集中站
+ set centralizedStation(v: number);
clone(): ISectionData;
copyFrom(data: ISectionData): void;
eq(other: ISectionData): boolean;
diff --git a/src/graphics/separator/SeparatorDrawAssistant.ts b/src/graphics/separator/SeparatorDrawAssistant.ts
index c477f42..0d0fd65 100644
--- a/src/graphics/separator/SeparatorDrawAssistant.ts
+++ b/src/graphics/separator/SeparatorDrawAssistant.ts
@@ -26,7 +26,7 @@ export class SeparatorDraw extends GraphicDrawAssistant<
> {
SeparatorGraph: Separator;
constructor(app: IDrawApp, template: SeparatorTemplate) {
- super(app, template, 'sym_o_square', '不展示');
+ super(app, template, 'sym_o_square', '分隔符Separator');
this.SeparatorGraph = this.graphicTemplate.new();
this.container.addChild(this.SeparatorGraph);
SeparatorInteraction.init(app);
diff --git a/src/graphics/signal/Signal.ts b/src/graphics/signal/Signal.ts
index 2cd20a6..dc28c48 100644
--- a/src/graphics/signal/Signal.ts
+++ b/src/graphics/signal/Signal.ts
@@ -36,6 +36,8 @@ export interface ISignalData extends GraphicData {
set kilometerSystem(v: KilometerSystem);
get refDevice(): IRelatedRefData | undefined;
set refDevice(v: IRelatedRefData | undefined);
+ get centralizedStation(): number; //所属集中站
+ set centralizedStation(v: number);
clone(): ISignalData;
copyFrom(data: ISignalData): void;
eq(other: ISignalData): boolean;
diff --git a/src/graphics/station/Station.ts b/src/graphics/station/Station.ts
index e6935fe..3952e05 100644
--- a/src/graphics/station/Station.ts
+++ b/src/graphics/station/Station.ts
@@ -23,6 +23,8 @@ export interface IStationData extends GraphicData {
set concentrationStations(v: boolean);
get name(): string; //车站名称
set name(v: string);
+ get manageStations(): number[]; //集中站管理的车站
+ set manageStations(v: number[]);
clone(): IStationData;
copyFrom(data: IStationData): void;
eq(other: IStationData): boolean;
diff --git a/src/graphics/train/TrainDrawAssistant.ts b/src/graphics/train/TrainDrawAssistant.ts
index 16f42ef..a569c3c 100644
--- a/src/graphics/train/TrainDrawAssistant.ts
+++ b/src/graphics/train/TrainDrawAssistant.ts
@@ -16,7 +16,7 @@ export class TrainDraw extends GraphicDrawAssistant {
_Train: Train | null = null;
constructor(app: IDrawApp, template: TrainTemplate) {
- super(app, template, 'directions_bus_filled', '不展示');
+ super(app, template, 'directions_bus_filled', '车Train');
trainInteraction.init(app);
}
diff --git a/src/graphics/trainWindow/TrainWindowDrawAssistant.ts b/src/graphics/trainWindow/TrainWindowDrawAssistant.ts
index 105a72c..c82cb7d 100644
--- a/src/graphics/trainWindow/TrainWindowDrawAssistant.ts
+++ b/src/graphics/trainWindow/TrainWindowDrawAssistant.ts
@@ -70,7 +70,7 @@ export class TrainWindowDraw extends GraphicDrawAssistant<
> {
trainWindowGraph: TrainWindow;
constructor(app: IDrawApp, template: TrainWindowTemplate) {
- super(app, template, 'sym_o_square', '不展示');
+ super(app, template, 'sym_o_square', '车次窗');
this.trainWindowGraph = this.graphicTemplate.new();
this.container.addChild(this.trainWindowGraph);
TrainWindowInteraction.init(app);
diff --git a/src/graphics/trainWindow/oneClickDrawAssistant.ts b/src/graphics/trainWindow/oneClickDrawAssistant.ts
index 9019a50..48ccda4 100644
--- a/src/graphics/trainWindow/oneClickDrawAssistant.ts
+++ b/src/graphics/trainWindow/oneClickDrawAssistant.ts
@@ -47,7 +47,7 @@ export class OneClickGenerateDraw extends GraphicDrawAssistant<
> {
lineGraph: OneClickGenerate;
constructor(app: JlDrawApp, template: OneClickGenerateTemplate) {
- super(app, template, 'sym_o_square', '不展示');
+ super(app, template, 'sym_o_square', '辅助线');
this.lineGraph = this.graphicTemplate.new();
this.container.addChild(this.lineGraph);
}
diff --git a/src/graphics/turnout/Turnout.ts b/src/graphics/turnout/Turnout.ts
index 6971f89..c938cb0 100644
--- a/src/graphics/turnout/Turnout.ts
+++ b/src/graphics/turnout/Turnout.ts
@@ -39,6 +39,8 @@ export interface ITurnoutData extends GraphicData {
set pcRef(ref: IRelatedRefData | undefined);
get kilometerSystem(): KilometerSystem[];
set kilometerSystem(v: KilometerSystem[]);
+ get centralizedStation(): number; //所属集中站
+ set centralizedStation(v: number);
clone(): ITurnoutData;
copyFrom(data: ITurnoutData): void;
eq(other: ITurnoutData): boolean;
diff --git a/src/layouts/DrawLayout.vue b/src/layouts/DrawLayout.vue
index 4bb7d19..95fc9fa 100644
--- a/src/layouts/DrawLayout.vue
+++ b/src/layouts/DrawLayout.vue
@@ -6,26 +6,14 @@
-
- 保存
-
-
- 另存为
-
-
- 一键关联
-
-
- 一键生成车次窗
-
-
- 一键生成分隔符
-
-
- 一键生成计轴
-
-
- 一键生成道岔区段
+
+ {{ item.label }}
@@ -174,7 +162,7 @@