道岔编辑吸附方式调整

This commit is contained in:
Yuan 2023-06-15 17:18:06 +08:00
parent 15b028e494
commit cbd43ac95a
6 changed files with 170 additions and 173 deletions

View File

@ -26,23 +26,23 @@ export class TurnoutData extends GraphicDataBase implements ITurnoutData {
set code(v: string) {
this.data.code = v;
}
get pointA(): IPointData {
get pointA(): IPointData[] {
return this.data.pointA;
}
set pointA(v: IPointData) {
this.data.pointA = new graphicData.Point({ x: v.x, y: v.y });
set pointA(v: IPointData[]) {
this.data.pointA = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
}
get pointB(): IPointData {
get pointB(): IPointData[] {
return this.data.pointB;
}
set pointB(v: IPointData) {
this.data.pointB = new graphicData.Point({ x: v.x, y: v.y });
set pointB(v: IPointData[]) {
this.data.pointB = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
}
get pointC(): IPointData {
get pointC(): IPointData[] {
return this.data.pointC;
}
set pointC(v: IPointData) {
this.data.pointC = new graphicData.Point({ x: v.x, y: v.y });
set pointC(v: IPointData[]) {
this.data.pointC = v.map((p) => new graphicData.Point({ x: p.x, y: p.y }));
}
clone(): TurnoutData {
return new TurnoutData(this.data.cloneMessage());

View File

@ -28,6 +28,7 @@ import {
PolylineEditPlugin,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import AbsorbablePoint, {
AbsorbableLine,
AbsorbablePosition,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
import { Turnout } from '../turnout/Turnout';
@ -112,16 +113,18 @@ function buildAbsorbablePositions(section: Section): AbsorbablePosition[] {
const sections = section.queryStore.queryByType<Section>(Section.Type);
sections.forEach((other) => {
if (other.id == section.id) {
return;
}
const apa = new AbsorbablePoint(
other.localToCanvasPoint(other.getStartPoint())
);
const apb = new AbsorbablePoint(
other.localToCanvasPoint(other.getEndPoint())
);
aps.push(apa, apb);
const [ps, pe] = [
other.localToCanvasPoint(other.getStartPoint()),
other.localToCanvasPoint(other.getEndPoint()),
];
const apa = new AbsorbablePoint(ps);
const apb = new AbsorbablePoint(pe);
const { width, height } = section.getGraphicApp().canvas;
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
const xe = new AbsorbableLine({ x: 0, y: pe.y }, { x: width, y: pe.y });
const ye = new AbsorbableLine({ x: pe.x, y: 0 }, { x: pe.x, y: height });
aps.push(apa, apb, xs, ys, xe, ye);
});
const turnouts = section.queryStore.queryByType<Turnout>(Turnout.Type);
@ -140,16 +143,13 @@ function onEditPointCreate(
index: number
): void {
const section = g as Section;
if (index === 0 || index == section.datas.points.length - 1) {
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
section.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(section),
});
}
});
}
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
section.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(section),
});
}
});
}
class SectionPolylineEditPlugin extends PolylineEditPlugin {

View File

@ -14,12 +14,12 @@ import { epsilon } from 'src/jl-graphic/math';
export interface ITurnoutData extends GraphicData {
get code(): string;
set code(code: string);
get pointA(): IPointData;
set pointA(point: IPointData);
get pointB(): IPointData;
set pointB(point: IPointData);
get pointC(): IPointData;
set pointC(point: IPointData);
get pointA(): IPointData[]; //A端点列表(从岔心向外)
set pointA(point: IPointData[]);
get pointB(): IPointData[];
set pointB(point: IPointData[]);
get pointC(): IPointData[];
set pointC(point: IPointData[]);
clone(): ITurnoutData;
copyFrom(data: ITurnoutData): void;
eq(other: ITurnoutData): boolean;
@ -47,12 +47,15 @@ function getIntersectionPoint(r: number, p: IPointData): IPointData {
}
class TurnoutSection extends Graphics {
paint(p: IPointData, gap: number) {
const { x, y } = getIntersectionPoint(gap, p);
paint(pList: IPointData[], gap: number) {
const start = getIntersectionPoint(gap, pList[0]);
this.clear()
.lineStyle(TurnoutConsts.lineWidth, TurnoutConsts.lineColor)
.moveTo(p.x, p.y)
.lineTo(x, y);
.moveTo(start.x, start.y);
pList.forEach((p) => {
const { x, y } = p;
this.lineTo(x, y);
});
}
}
@ -120,13 +123,12 @@ export class Turnout extends JlGraphic {
this.graphics.sections.B.paint(pointB, 20);
this.graphics.sections.C.paint(pointC, 20);
this.graphics.fork.paint(pointB);
this.graphics.fork.paint(pointB[0]);
this.graphics.label.text = this.datas.code;
}
buildRelation(): void {
console.log('turnout build relation');
/** 道岔和区段 */
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
this.getPortPoints().forEach((port, i) => {

View File

@ -8,8 +8,10 @@ import {
JlDrawApp,
JlGraphic,
VectorText,
calculateIntersectionPointOfCircleAndPoint,
linePoint,
pointBox,
polylinePoint,
} from 'src/jl-graphic';
import {
ITurnoutData,
@ -25,9 +27,10 @@ import {
Point,
} from 'pixi.js';
import { GraphicEditPlugin } from 'src/jl-graphic/plugins/GraphicEditPlugin';
import Vector2 from 'src/jl-graphic/math/Vector2';
import { Section } from '../section/Section';
import AbsorbablePoint from 'src/jl-graphic/graphic/AbsorbablePosition';
import AbsorbablePoint, {
AbsorbableLine,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
export class TurnoutDraw extends GraphicDrawAssistant<
TurnoutTemplate,
@ -66,9 +69,9 @@ export class TurnoutDraw extends GraphicDrawAssistant<
getDefaultEndPoint() {
return {
pointA: new Point(50, 0),
pointB: new Point(-50, 0),
pointC: new Point(-50, -50),
pointA: [new Point(50, 0)],
pointB: [new Point(-50, 0)],
pointC: [new Point(-50, -50)],
};
}
@ -89,9 +92,21 @@ export class TurnoutHitArea implements IHitArea {
labelRect.x = labelPosition.x;
labelRect.y = labelPosition.y;
return (
linePoint(pointA, { x: 0, y: 0 }, { x, y }, TurnoutConsts.lineWidth) ||
linePoint(pointB, { x: 0, y: 0 }, { x, y }, TurnoutConsts.lineWidth) ||
linePoint(pointC, { x: 0, y: 0 }, { x, y }, TurnoutConsts.lineWidth) ||
polylinePoint(
[...pointA, { x: 0, y: 0 }],
{ x, y },
TurnoutConsts.lineWidth
) ||
polylinePoint(
[...pointB, { x: 0, y: 0 }],
{ x, y },
TurnoutConsts.lineWidth
) ||
polylinePoint(
[...pointC, { x: 0, y: 0 }],
{ x, y },
TurnoutConsts.lineWidth
) ||
pointBox({ x, y }, labelRect)
);
}
@ -113,10 +128,38 @@ function buildAbsorbablePositions(turnout: Turnout): AbsorbablePosition[] {
const turnouts = turnout.queryStore.queryByType<Turnout>(Turnout.Type);
turnouts.forEach((otherTurnout) => {
if (turnout.id === otherTurnout.id) return;
otherTurnout.getPortPoints().forEach((portPoint) => {
aps.push(new AbsorbablePoint(otherTurnout.localToCanvasPoint(portPoint)));
const {
pointA: [A],
pointB: [B],
pointC: [C],
} = otherTurnout.datas;
[A, B, C].forEach((p) => {
aps.push(
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 })
)
);
if (turnout.id !== otherTurnout.id) {
otherTurnout.getPortPoints().forEach((portPoint) => {
aps.push(
new AbsorbablePoint(otherTurnout.localToCanvasPoint(portPoint))
);
});
}
});
return aps;
@ -199,7 +242,7 @@ export interface ITurnoutEditOptions {
export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
static Name = 'TurnoutEdit';
options: ITurnoutEditOptions;
editPoints: DraggablePoint[] = [];
editPoints: DraggablePoint[][] = [[], [], []];
labels: VectorText[] = [];
constructor(graphic: Turnout, options?: ITurnoutEditOptions) {
@ -215,51 +258,34 @@ export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
}
initEditPoints() {
const cpA = this.graphic.localToCanvasPoint(this.graphic.datas.pointA);
const cpB = this.graphic.localToCanvasPoint(this.graphic.datas.pointB);
const cpC = this.graphic.localToCanvasPoint(this.graphic.datas.pointC);
const cpMap: Map<Point, IPointData> = new Map([
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],
]);
cpMap.forEach((v, k) => {
const dp = new DraggablePoint(k);
dp.on('transforming', (e: GraphicTransformEvent) => {
if (k === cpA || k === cpB) {
const vecA = new Vector2([
this.graphic.datas.pointA.x,
this.graphic.datas.pointA.y,
]);
const vecB = new Vector2([
this.graphic.datas.pointB.x,
this.graphic.datas.pointB.y,
]);
Array.from(cpMap.entries()).forEach(([cpDatas, dataPoints], i) => {
cpDatas.forEach((cpData, j) => {
const dp = new DraggablePoint(cpData);
dp.on('transforming', (e: GraphicTransformEvent) => {
const localPoint = this.graphic.canvasToLocalPoint(dp.position);
dataPoints[j].x = localPoint.x;
dataPoints[j].y = localPoint.y;
if (k === cpA) {
const len = vecB.length();
const res = vecA.normalize().scale(-len);
this.graphic.datas.pointB.x = res.x;
this.graphic.datas.pointB.y = res.y;
} else if (k === cpB) {
const len = vecA.length();
const res = vecB.normalize().scale(-len);
this.graphic.datas.pointA.x = res.x;
this.graphic.datas.pointA.y = res.y;
}
this.graphic.repaint();
});
if (this.options.onEditPointCreate) {
this.options.onEditPointCreate(this.graphic, dp);
}
const localPoint = this.graphic.canvasToLocalPoint(dp.position);
v.x = localPoint.x;
v.y = localPoint.y;
this.graphic.repaint();
this.editPoints[i].push(dp);
});
if (this.options.onEditPointCreate) {
this.options.onEditPointCreate(this.graphic, dp);
}
this.editPoints.push(dp);
});
this.addChild(...this.editPoints);
console.log(this.editPoints);
this.editPoints.forEach((cps) => {
this.addChild(...cps);
});
this.labels = ['A', 'B', 'C'].map((str) => {
const vc = new VectorText(str);
vc.setVectorFontSize(14);
@ -270,23 +296,27 @@ export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
}
destoryEditPoints() {
this.editPoints.forEach((dp) => {
dp.off('transforming');
dp.destroy();
this.removeChild(dp);
this.editPoints.forEach((dps) => {
dps.forEach((dp) => {
dp.off('transforming');
dp.destroy();
this.removeChild(dp);
});
});
this.editPoints.splice(0, this.editPoints.length);
this.editPoints = [[], [], []];
}
updateEditedPointsPosition() {
const cps = this.graphic.localToCanvasPoints(
this.graphic.datas.pointA,
this.graphic.datas.pointB,
this.graphic.datas.pointC
);
cps.forEach((cp, i) => {
this.editPoints[i].position.copyFrom(cp);
this.labels[i].position.copyFrom({ x: cp.x, y: cp.y + 12 });
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 });
}
});
});
}
}

View File

@ -2308,13 +2308,12 @@ export namespace graphicData {
constructor(data?: any[] | {
common?: CommonInfo;
code?: string;
pointA?: Point;
pointB?: Point;
pointC?: Point;
labelOffset?: Point;
pointA?: Point[];
pointB?: Point[];
pointC?: Point[];
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [6, 7, 8], this.#one_of_decls);
if (!Array.isArray(data) && typeof data == "object") {
if ("common" in data && data.common != undefined) {
this.common = data.common;
@ -2331,9 +2330,6 @@ export namespace graphicData {
if ("pointC" in data && data.pointC != undefined) {
this.pointC = data.pointC;
}
if ("labelOffset" in data && data.labelOffset != undefined) {
this.labelOffset = data.labelOffset;
}
}
}
get common() {
@ -2352,48 +2348,29 @@ export namespace graphicData {
pb_1.Message.setField(this, 2, value);
}
get pointA() {
return pb_1.Message.getWrapperField(this, Point, 6) as Point;
return pb_1.Message.getRepeatedWrapperField(this, Point, 6) as Point[];
}
set pointA(value: Point) {
pb_1.Message.setWrapperField(this, 6, value);
}
get has_pointA() {
return pb_1.Message.getField(this, 6) != null;
set pointA(value: Point[]) {
pb_1.Message.setRepeatedWrapperField(this, 6, value);
}
get pointB() {
return pb_1.Message.getWrapperField(this, Point, 7) as Point;
return pb_1.Message.getRepeatedWrapperField(this, Point, 7) as Point[];
}
set pointB(value: Point) {
pb_1.Message.setWrapperField(this, 7, value);
}
get has_pointB() {
return pb_1.Message.getField(this, 7) != null;
set pointB(value: Point[]) {
pb_1.Message.setRepeatedWrapperField(this, 7, value);
}
get pointC() {
return pb_1.Message.getWrapperField(this, Point, 8) as Point;
return pb_1.Message.getRepeatedWrapperField(this, Point, 8) as Point[];
}
set pointC(value: Point) {
pb_1.Message.setWrapperField(this, 8, value);
}
get has_pointC() {
return pb_1.Message.getField(this, 8) != null;
}
get labelOffset() {
return pb_1.Message.getWrapperField(this, Point, 9) as Point;
}
set labelOffset(value: Point) {
pb_1.Message.setWrapperField(this, 9, value);
}
get has_labelOffset() {
return pb_1.Message.getField(this, 9) != null;
set pointC(value: Point[]) {
pb_1.Message.setRepeatedWrapperField(this, 8, value);
}
static fromObject(data: {
common?: ReturnType<typeof CommonInfo.prototype.toObject>;
code?: string;
pointA?: ReturnType<typeof Point.prototype.toObject>;
pointB?: ReturnType<typeof Point.prototype.toObject>;
pointC?: ReturnType<typeof Point.prototype.toObject>;
labelOffset?: ReturnType<typeof Point.prototype.toObject>;
pointA?: ReturnType<typeof Point.prototype.toObject>[];
pointB?: ReturnType<typeof Point.prototype.toObject>[];
pointC?: ReturnType<typeof Point.prototype.toObject>[];
}): Turnout {
const message = new Turnout({});
if (data.common != null) {
@ -2403,16 +2380,13 @@ export namespace graphicData {
message.code = data.code;
}
if (data.pointA != null) {
message.pointA = Point.fromObject(data.pointA);
message.pointA = data.pointA.map(item => Point.fromObject(item));
}
if (data.pointB != null) {
message.pointB = Point.fromObject(data.pointB);
message.pointB = data.pointB.map(item => Point.fromObject(item));
}
if (data.pointC != null) {
message.pointC = Point.fromObject(data.pointC);
}
if (data.labelOffset != null) {
message.labelOffset = Point.fromObject(data.labelOffset);
message.pointC = data.pointC.map(item => Point.fromObject(item));
}
return message;
}
@ -2420,10 +2394,9 @@ export namespace graphicData {
const data: {
common?: ReturnType<typeof CommonInfo.prototype.toObject>;
code?: string;
pointA?: ReturnType<typeof Point.prototype.toObject>;
pointB?: ReturnType<typeof Point.prototype.toObject>;
pointC?: ReturnType<typeof Point.prototype.toObject>;
labelOffset?: ReturnType<typeof Point.prototype.toObject>;
pointA?: ReturnType<typeof Point.prototype.toObject>[];
pointB?: ReturnType<typeof Point.prototype.toObject>[];
pointC?: ReturnType<typeof Point.prototype.toObject>[];
} = {};
if (this.common != null) {
data.common = this.common.toObject();
@ -2432,16 +2405,13 @@ export namespace graphicData {
data.code = this.code;
}
if (this.pointA != null) {
data.pointA = this.pointA.toObject();
data.pointA = this.pointA.map((item: Point) => item.toObject());
}
if (this.pointB != null) {
data.pointB = this.pointB.toObject();
data.pointB = this.pointB.map((item: Point) => item.toObject());
}
if (this.pointC != null) {
data.pointC = this.pointC.toObject();
}
if (this.labelOffset != null) {
data.labelOffset = this.labelOffset.toObject();
data.pointC = this.pointC.map((item: Point) => item.toObject());
}
return data;
}
@ -2453,14 +2423,12 @@ export namespace graphicData {
writer.writeMessage(1, this.common, () => this.common.serialize(writer));
if (this.code.length)
writer.writeString(2, this.code);
if (this.has_pointA)
writer.writeMessage(6, this.pointA, () => this.pointA.serialize(writer));
if (this.has_pointB)
writer.writeMessage(7, this.pointB, () => this.pointB.serialize(writer));
if (this.has_pointC)
writer.writeMessage(8, this.pointC, () => this.pointC.serialize(writer));
if (this.has_labelOffset)
writer.writeMessage(9, this.labelOffset, () => this.labelOffset.serialize(writer));
if (this.pointA.length)
writer.writeRepeatedMessage(6, this.pointA, (item: Point) => item.serialize(writer));
if (this.pointB.length)
writer.writeRepeatedMessage(7, this.pointB, (item: Point) => item.serialize(writer));
if (this.pointC.length)
writer.writeRepeatedMessage(8, this.pointC, (item: Point) => item.serialize(writer));
if (!w)
return writer.getResultBuffer();
}
@ -2477,16 +2445,13 @@ export namespace graphicData {
message.code = reader.readString();
break;
case 6:
reader.readMessage(message.pointA, () => message.pointA = Point.deserialize(reader));
reader.readMessage(message.pointA, () => pb_1.Message.addToRepeatedWrapperField(message, 6, Point.deserialize(reader), Point));
break;
case 7:
reader.readMessage(message.pointB, () => message.pointB = Point.deserialize(reader));
reader.readMessage(message.pointB, () => pb_1.Message.addToRepeatedWrapperField(message, 7, Point.deserialize(reader), Point));
break;
case 8:
reader.readMessage(message.pointC, () => message.pointC = Point.deserialize(reader));
break;
case 9:
reader.readMessage(message.labelOffset, () => message.labelOffset = Point.deserialize(reader));
reader.readMessage(message.pointC, () => pb_1.Message.addToRepeatedWrapperField(message, 8, Point.deserialize(reader), Point));
break;
default: reader.skipField();
}

@ -1 +1 @@
Subproject commit b0bc3b6100b9dbe5fd02a9e8cd2515c840ebf2a8
Subproject commit eec3d3f6eff222e69479abb5e0bd36f29f883382