diff --git a/graphic-pixi b/graphic-pixi
index 7e4eaed..1f30264 160000
--- a/graphic-pixi
+++ b/graphic-pixi
@@ -1 +1 @@
-Subproject commit 7e4eaed0cf06d68c75cb51c30329eff5fe4d1e3f
+Subproject commit 1f302648b5a71a82b798b77fe238c5fc6e3081b4
diff --git a/quasar.config.js b/quasar.config.js
index ee66d7a..bc1b766 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -110,6 +110,8 @@ module.exports = configure(function (/* ctx */) {
// components: [],
// directives: [],
+ autoImportComponentCase: 'combined',
+
// Quasar plugins
plugins: ['Notify', 'Dialog', 'Dark', 'AppFullscreen', 'Loading'],
},
diff --git a/src/components/draw-app/dialogs/SectionSplitDialog.vue b/src/components/draw-app/dialogs/SectionSplitDialog.vue
new file mode 100644
index 0000000..2dd83ee
--- /dev/null
+++ b/src/components/draw-app/dialogs/SectionSplitDialog.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+ 区段拆分
+ 请选择要拆分的数量和方向
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/draw-app/properties/SectionProperty.vue b/src/components/draw-app/properties/SectionProperty.vue
index 12695da..30ee676 100644
--- a/src/components/draw-app/properties/SectionProperty.vue
+++ b/src/components/draw-app/properties/SectionProperty.vue
@@ -31,16 +31,6 @@
>
-
-
- 拆分为逻辑区段
-
-
@@ -56,34 +46,6 @@ const drawStore = useDrawStore();
const sectionModel = shallowRef(new SectionData());
-const splitNum = ref(3);
-
-function splitSection() {
- const sectionData = toRaw(sectionModel.value);
- const section = toRaw(drawStore.selectedGraphic as Section);
- const app = drawStore.getDrawApp();
- const points = section.getSplitPoints(splitNum.value);
- const childIds: string[] = [];
-
- points.forEach((ps, i) => {
- const data = new SectionData();
- data.points = ps.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
- data.id = app.drawAssistants
- .find((as) => as.name === Section.name)!
- .nextId();
- data.code = `${sectionData.code}-${'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(
- i % 26
- )}`;
- data.sectionType = SectionType.Logic;
- const section = app.graphicTemplateMap.get(Section.name)!.new();
- section?.loadData(data);
- app.addGraphics(section);
- childIds.push(data.id);
- });
- sectionData.children = childIds;
- app.updateGraphicAndRecord(section, sectionData);
-}
-
const sectionRelations = computed(() => {
const section = drawStore.selectedGraphic as Section;
diff --git a/src/graphics/section/Section.ts b/src/graphics/section/Section.ts
index 99cb600..6ec80b6 100644
--- a/src/graphics/section/Section.ts
+++ b/src/graphics/section/Section.ts
@@ -17,6 +17,7 @@ import {
} from '../CommonGraphics';
import { Turnout } from '../turnout/Turnout';
import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
+import Vector2 from 'src/jl-graphic/math/Vector2';
export enum SectionType {
Physical = 0,
@@ -134,13 +135,49 @@ export class Section extends JlGraphic implements ILineGraphic {
/** 获取拆分逻辑区段数据 */
getSplitPoints(count: number): IPointData[][] {
if (this.datas.points.length !== 2) {
- throw Error('多段分割待实现');
+ // throw Error('多段分割待实现');
+ 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
+ );
}
- return splitLineEvenly(
- this.localToCanvasPoint(this.datas.points[0]),
- this.localToCanvasPoint(this.datas.points[this.datas.points.length - 1]),
- count
- );
}
buildRelation() {
diff --git a/src/graphics/section/SectionDrawAssistant.ts b/src/graphics/section/SectionDrawAssistant.ts
index c27d8da..049f3ea 100644
--- a/src/graphics/section/SectionDrawAssistant.ts
+++ b/src/graphics/section/SectionDrawAssistant.ts
@@ -4,6 +4,7 @@ import {
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
+ GraphicRelation,
GraphicTransform,
GraphicTransformEvent,
JlDrawApp,
@@ -15,25 +16,37 @@ import {
ISectionData,
Section,
SectionConsts,
+ SectionPort,
SectionTemplate,
+ SectionType,
} from './Section';
import {
DisplayObject,
FederatedMouseEvent,
Graphics,
IHitArea,
+ IPointData,
Point,
} from 'pixi.js';
import {
IEditPointOptions,
ILineGraphic,
PolylineEditPlugin,
+ addWayPoint,
+ clearWayPoint,
+ getWaypointRangeIndex,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import AbsorbablePoint, {
AbsorbableLine,
AbsorbablePosition,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
-import { Turnout } from '../turnout/Turnout';
+import { Turnout, TurnoutPort } from '../turnout/Turnout';
+import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
+import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
+import { Dialog } from 'quasar';
+import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import SectionSplitDialog from 'src/components/draw-app/dialogs/SectionSplitDialog.vue';
export class SectionDraw extends GraphicDrawAssistant<
SectionTemplate,
@@ -46,7 +59,7 @@ export class SectionDraw extends GraphicDrawAssistant<
super(app, template, 'sym_o_timeline', '区段Section');
this.container.addChild(this.graphic);
- SectionPointEditPlugin.init(app);
+ SectionPointEditPlugin.init(app, this);
}
onLeftDown(e: FederatedMouseEvent): void {
@@ -88,20 +101,23 @@ export class SectionDraw extends GraphicDrawAssistant<
prepareData(data: ISectionData): boolean {
data.points = this.points;
data.code = 'G000';
- data.childTransforms?.push(
+ console.log(data.points[1].x);
+ console.log(data.points[0].x);
+ data.childTransforms = [
new ChildTransform(
'label',
new GraphicTransform(
{
- x: data.points[1].x - data.points[0].x,
- y: data.points[1].y - data.points[0].y + 20,
+ x: data.points[0].x + (data.points[1].x - data.points[0].x) / 2,
+ y:
+ data.points[0].y + (data.points[1].y - data.points[0].y) / 2 + 20,
},
{ x: 0, y: 0 },
0,
{ x: 0, y: 0 }
)
- )
- );
+ ),
+ ];
return true;
}
@@ -191,9 +207,71 @@ class SectionPolylineEditPlugin extends PolylineEditPlugin {
this.updateEditedPointsPosition();
}
- reset(): void {
- super.reset();
- this.initLabels();
+ setRelatedDrag() {
+ const len = this.editedPoints.length;
+ this.editedPoints.forEach((ep, i) => {
+ if (i === 0 || i === len - 1) {
+ let relations: GraphicRelation[];
+ if (i === 0) {
+ relations = this.graphic.relationManage
+ .getRelationsOfGraphic(this.graphic)
+ .filter(
+ (relation) =>
+ relation.getRelationParam(this.graphic).param === SectionPort.A
+ );
+ } else {
+ relations = this.graphic.relationManage
+ .getRelationsOfGraphic(this.graphic)
+ .filter(
+ (relation) =>
+ relation.getRelationParam(this.graphic).param === SectionPort.B
+ );
+ }
+ if (!relations.length) return;
+ const points: IPointData[] = [];
+ const otherGraphics = relations.map((relation) =>
+ relation.getOtherGraphic(this.graphic)
+ );
+ const otherPorts = relations.map(
+ (relation) => relation.getOtherRelationParam(this.graphic).param
+ );
+ otherGraphics.forEach((otherGraphic, i) => {
+ const otherPort = otherPorts[i];
+ if (otherGraphic instanceof Turnout) {
+ if (otherPort === TurnoutPort.A) {
+ points.push(
+ otherGraphic.datas.pointA[otherGraphic.datas.pointA.length - 1]
+ );
+ } else if (otherPort === TurnoutPort.B) {
+ points.push(
+ otherGraphic.datas.pointB[otherGraphic.datas.pointB.length - 1]
+ );
+ } else if (otherPort === TurnoutPort.C) {
+ points.push(
+ otherGraphic.datas.pointC[otherGraphic.datas.pointC.length - 1]
+ );
+ }
+ } else if (otherGraphic instanceof Section) {
+ if (otherPort === SectionPort.A) {
+ points.push(otherGraphic.datas.points[0]);
+ } else if (otherPort === SectionPort.B) {
+ points.push(
+ otherGraphic.datas.points[otherGraphic.datas.points.length - 1]
+ );
+ }
+ }
+ });
+ const transformingHandler = () => {
+ otherGraphics.forEach((otherGraphic, i) => {
+ const p = otherGraphic.canvasToLocalPoint(ep);
+ points[i].x = p.x;
+ points[i].y = p.y;
+ otherGraphic.repaint();
+ });
+ };
+ ep.on('transforming', transformingHandler);
+ }
+ });
}
updateEditedPointsPosition() {
@@ -209,14 +287,39 @@ class SectionPolylineEditPlugin extends PolylineEditPlugin {
}
}
+export const addWaypointConfig: MenuItemOptions = {
+ name: '添加路径点',
+};
+export const clearWaypointsConfig: MenuItemOptions = {
+ name: '清除所有路径点',
+};
+export const splitSectionConfig: MenuItemOptions = {
+ name: '拆分',
+ // disabled: true,
+};
+const SectionEditMenu: ContextMenu = ContextMenu.init({
+ name: '区段编辑菜单',
+ groups: [
+ {
+ items: [addWaypointConfig, clearWaypointsConfig],
+ },
+ {
+ items: [splitSectionConfig],
+ },
+ ],
+});
+
export class SectionPointEditPlugin extends GraphicInteractionPlugin {
static Name = 'SectionPointDrag';
+ drawAssistant: SectionDraw;
- constructor(app: GraphicApp) {
+ constructor(app: GraphicApp, da: SectionDraw) {
super(SectionPointEditPlugin.Name, app);
+ this.drawAssistant = da;
+ app.registerMenu(SectionEditMenu);
}
- static init(app: GraphicApp) {
- return new SectionPointEditPlugin(app);
+ static init(app: GraphicApp, da: SectionDraw) {
+ return new SectionPointEditPlugin(app, da);
}
filter(...grahpics: JlGraphic[]): Section[] | undefined {
return grahpics.filter((g) => g.type == Section.Type) as Section[];
@@ -232,14 +335,99 @@ export class SectionPointEditPlugin extends GraphicInteractionPlugin {
g.labelGraphic.draggable = true;
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
+ g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: Section): 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 section = target.getGraphic() as Section;
+ this.app.updateSelected(section);
+ const p = section.screenToLocalPoint(e.global);
+
+ addWaypointConfig.handler = () => {
+ const linePoints = section.linePoints;
+ const { start, end } = getWaypointRangeIndex(
+ linePoints,
+ false,
+ p,
+ SectionConsts.lineWidth
+ );
+ addWayPoint(section, false, start, end, p);
+ };
+ clearWaypointsConfig.handler = () => {
+ clearWayPoint(section, false);
+ };
+
+ if (
+ section.datas.children &&
+ section.datas.sectionType === SectionType.Physical
+ ) {
+ splitSectionConfig.disabled = false;
+ splitSectionConfig.handler = () => {
+ Dialog.create({
+ title: '拆分区段',
+ message: '请选择生成数量和方向',
+ component: SectionSplitDialog,
+ cancel: true,
+ persistent: true,
+ }).onOk((data: { num: number; dir: 'ltr' | 'rtl' }) => {
+ const { num, dir } = data;
+ const sectionData = section.datas;
+ const points = section.getSplitPoints(num);
+ const children: Section[] = [];
+ let codeAppend = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.slice(0, num);
+ if (
+ (dir === 'ltr' &&
+ sectionData.points[0].x >
+ sectionData.points[sectionData.points.length - 1].x) ||
+ (dir === 'rtl' &&
+ sectionData.points[0].x <
+ sectionData.points[sectionData.points.length - 1].x)
+ ) {
+ codeAppend = codeAppend.split('').reverse().join('');
+ }
+ points.forEach((ps, i) => {
+ const data = new SectionData();
+ data.id = this.drawAssistant.nextId();
+ data.code = `${sectionData.code}-${codeAppend.charAt(i % 26)}`;
+ data.sectionType = SectionType.Logic;
+ data.points = ps.map(
+ (p) => new graphicData.Point({ x: p.x, y: p.y })
+ );
+ data.id = this.drawAssistant.nextId();
+ const g = this.drawAssistant.graphicTemplate.new();
+ g.loadData(data);
+ this.drawAssistant.storeGraphic(g);
+ children.push(g);
+ });
+ sectionData.children = children.map((g) => g.datas.id);
+ section.repaint();
+ section.buildRelation();
+ section.draggable = false;
+ children.forEach((c) => c.buildRelation());
+ this.app.updateSelected(...children);
+ });
+ };
+ } else {
+ splitSectionConfig.disabled = true;
+ }
+
+ SectionEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const section = g as Section;
+ if (
+ section.datas.children.length > 0 &&
+ section.datas.sectionType === SectionType.Physical
+ ) {
+ return;
+ }
let lep = section.getAssistantAppend(
SectionPolylineEditPlugin.Name
);
@@ -248,6 +436,7 @@ export class SectionPointEditPlugin extends GraphicInteractionPlugin {
section.addAssistantAppend(lep);
}
lep.showAll();
+ lep.setRelatedDrag();
}
onUnselected(g: DisplayObject): void {
const section = g as Section;
diff --git a/src/graphics/turnout/TurnoutDrawAssistant.ts b/src/graphics/turnout/TurnoutDrawAssistant.ts
index 9c22ebb..0c50121 100644
--- a/src/graphics/turnout/TurnoutDrawAssistant.ts
+++ b/src/graphics/turnout/TurnoutDrawAssistant.ts
@@ -4,6 +4,7 @@ import {
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
+ GraphicRelation,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
@@ -31,7 +32,7 @@ import {
GraphicEditPlugin,
getWaypointRangeIndex,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
-import { Section } from '../section/Section';
+import { Section, SectionPort } from '../section/Section';
import AbsorbablePoint, {
AbsorbableLine,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
@@ -338,8 +339,9 @@ export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin {
this.removeChildren();
this.initEditPoints();
}
+ hideAll(): void {
+ super.hideAll();
+ }
+ setRelatedDrag() {
+ this.editPoints.forEach((eps, i) => {
+ const ep = eps[eps.length - 1];
+ let relations: GraphicRelation[];
+ if (i === 0) {
+ relations = this.graphic.relationManage
+ .getRelationsOfGraphic(this.graphic)
+ .filter(
+ (relation) =>
+ relation.getRelationParam(this.graphic).param === TurnoutPort.A
+ );
+ } else if (i === 1) {
+ relations = this.graphic.relationManage
+ .getRelationsOfGraphic(this.graphic)
+ .filter(
+ (relation) =>
+ relation.getRelationParam(this.graphic).param === TurnoutPort.B
+ );
+ } else {
+ relations = this.graphic.relationManage
+ .getRelationsOfGraphic(this.graphic)
+ .filter(
+ (relation) =>
+ relation.getRelationParam(this.graphic).param === TurnoutPort.C
+ );
+ }
+ if (!relations.length) return;
+ const otherGraphics = relations.map((relation) =>
+ relation.getOtherGraphic(this.graphic)
+ );
+ console.log(otherGraphics);
+ const otherPorts = relations.map(
+ (relation) => relation.getOtherRelationParam(this.graphic).param
+ );
+
+ const point: IPointData[] = [];
+ otherGraphics.map((otherGraphic, i) => {
+ const otherPort = otherPorts[i];
+ if (otherGraphic instanceof Turnout) {
+ if (otherPort === TurnoutPort.A) {
+ point.push(
+ otherGraphic.datas.pointA[otherGraphic.datas.pointA.length - 1]
+ );
+ } else if (otherPort === TurnoutPort.B) {
+ point.push(
+ otherGraphic.datas.pointB[otherGraphic.datas.pointB.length - 1]
+ );
+ } else if (otherPort === TurnoutPort.C) {
+ point.push(
+ otherGraphic.datas.pointC[otherGraphic.datas.pointC.length - 1]
+ );
+ }
+ } else if (otherGraphic instanceof Section) {
+ if (otherPort === SectionPort.A) {
+ point.push(otherGraphic.datas.points[0]);
+ } else if (otherPort === SectionPort.B) {
+ point.push(
+ otherGraphic.datas.points[otherGraphic.datas.points.length - 1]
+ );
+ }
+ }
+ });
+ const transformingHandler = () => {
+ otherGraphics.forEach((otherGraphic, i) => {
+ const p = otherGraphic.canvasToLocalPoint(ep);
+ point[i].x = p.x;
+ point[i].y = p.y;
+ otherGraphic.repaint();
+ });
+ };
+ ep.on('transforming', transformingHandler);
+ });
+ }
initEditPoints() {
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
diff --git a/src/jl-graphic/plugins/GraphicEditPlugin.ts b/src/jl-graphic/plugins/GraphicEditPlugin.ts
index 9b1cc5b..c93631a 100644
--- a/src/jl-graphic/plugins/GraphicEditPlugin.ts
+++ b/src/jl-graphic/plugins/GraphicEditPlugin.ts
@@ -32,13 +32,13 @@ export abstract class GraphicEditPlugin<
this.sortableChildren = true;
this.graphic.on('transformstart', this.hideAll, this);
this.graphic.on('transformend', this.showAll, this);
- this.graphic.on('repaint', this.showAll, this);
+ this.graphic.on('repaint', this.updateEditedPointsPosition, this);
}
destroy(options?: boolean | IDestroyOptions | undefined): void {
this.graphic.off('transformstart', this.hideAll, this);
this.graphic.off('transformend', this.showAll, this);
- this.graphic.off('repaint', this.showAll, this);
+ this.graphic.off('repaint', this.updateEditedPointsPosition, this);
super.destroy(options);
}
diff --git a/src/protos/device_info.ts b/src/protos/device_info.ts
index baa1e88..af0fb8c 100644
--- a/src/protos/device_info.ts
+++ b/src/protos/device_info.ts
@@ -188,7 +188,7 @@ export namespace state {
return Section.deserialize(bytes);
}
}
- export class Switch extends pb_1.Message {
+ export class Turnout extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(data?: any[] | {
id?: string;
@@ -242,8 +242,8 @@ export namespace state {
code?: string;
kilometerSystem?: ReturnType[];
convertKilometer?: number[];
- }): Switch {
- const message = new Switch({});
+ }): Turnout {
+ const message = new Turnout({});
if (data.id != null) {
message.id = data.id;
}
@@ -294,8 +294,8 @@ export namespace state {
if (!w)
return writer.getResultBuffer();
}
- static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Switch {
- const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Switch();
+ static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Turnout {
+ const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Turnout();
while (reader.nextField()) {
if (reader.isEndGroup())
break;
@@ -320,8 +320,8 @@ export namespace state {
serializeBinary(): Uint8Array {
return this.serialize();
}
- static deserializeBinary(bytes: Uint8Array): Switch {
- return Switch.deserialize(bytes);
+ static deserializeBinary(bytes: Uint8Array): Turnout {
+ return Turnout.deserialize(bytes);
}
}
}
diff --git a/xian-ncc-da-message b/xian-ncc-da-message
index 549aa2e..8fd000d 160000
--- a/xian-ncc-da-message
+++ b/xian-ncc-da-message
@@ -1 +1 @@
-Subproject commit 549aa2ec10bffe292a1a68e278ae824a8502db0b
+Subproject commit 8fd000d45907f94410786c3bd6c1ab37edbe91e8