From e4033ca5fce56b957be309fe7cff6533a7be7435 Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Tue, 27 Feb 2024 10:32:01 +0100 Subject: [PATCH] Ensure we do not return an invalid anchor point during edge routing Fixes https://github.com/eclipse-glsp/glsp/issues/1270 --- .../routing/glsp-bezier-edge-router.ts | 32 ++++++++++++++++++ .../routing/glsp-manhattan-edge-router.ts | 22 ++++++++++++- .../routing/glsp-polyline-edge-router.ts | 32 ++++++++++++++++++ packages/client/src/features/routing/index.ts | 1 + .../src/features/routing/routing-module.ts | 8 ++--- packages/protocol/src/index.ts | 1 + .../protocol/src/sprotty-geometry-point.ts | 33 +++++++++++++++++++ 7 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 packages/client/src/features/routing/glsp-bezier-edge-router.ts create mode 100644 packages/client/src/features/routing/glsp-polyline-edge-router.ts create mode 100644 packages/protocol/src/sprotty-geometry-point.ts diff --git a/packages/client/src/features/routing/glsp-bezier-edge-router.ts b/packages/client/src/features/routing/glsp-bezier-edge-router.ts new file mode 100644 index 00000000..9ee41249 --- /dev/null +++ b/packages/client/src/features/routing/glsp-bezier-edge-router.ts @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2024 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { BezierEdgeRouter, GConnectableElement, GParentElement, GRoutableElement, Point } from '@eclipse-glsp/sprotty'; +import { injectable } from 'inversify'; + +@injectable() +export class GLSPBezierEdgeRouter extends BezierEdgeRouter { + override getTranslatedAnchor( + connectable: GConnectableElement, + refPoint: Point, + refContainer: GParentElement, + edge: GRoutableElement, + anchorCorrection?: number | undefined + ): Point { + // users may define all kinds of anchors and anchor computers, we want to make sure we return a valid one in any case + const anchor = super.getTranslatedAnchor(connectable, refPoint, refContainer, edge, anchorCorrection); + return Point.isValid(anchor) ? anchor : refPoint; + } +} diff --git a/packages/client/src/features/routing/glsp-manhattan-edge-router.ts b/packages/client/src/features/routing/glsp-manhattan-edge-router.ts index 7d9d379e..62b2c8fa 100644 --- a/packages/client/src/features/routing/glsp-manhattan-edge-router.ts +++ b/packages/client/src/features/routing/glsp-manhattan-edge-router.ts @@ -14,7 +14,15 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { ManhattanEdgeRouter, ResolvedHandleMove, GRoutableElement, almostEquals } from '@eclipse-glsp/sprotty'; +import { + GConnectableElement, + GParentElement, + GRoutableElement, + ManhattanEdgeRouter, + Point, + ResolvedHandleMove, + almostEquals +} from '@eclipse-glsp/sprotty'; export class GLSPManhattanEdgeRouter extends ManhattanEdgeRouter { protected override applyInnerHandleMoves(edge: GRoutableElement, moves: ResolvedHandleMove[]): void { @@ -56,4 +64,16 @@ export class GLSPManhattanEdgeRouter extends ManhattanEdgeRouter { } }); } + + override getTranslatedAnchor( + connectable: GConnectableElement, + refPoint: Point, + refContainer: GParentElement, + edge: GRoutableElement, + anchorCorrection?: number | undefined + ): Point { + // users may define all kinds of anchors and anchor computers, we want to make sure we return a valid one in any case + const anchor = super.getTranslatedAnchor(connectable, refPoint, refContainer, edge, anchorCorrection); + return Point.isValid(anchor) ? anchor : refPoint; + } } diff --git a/packages/client/src/features/routing/glsp-polyline-edge-router.ts b/packages/client/src/features/routing/glsp-polyline-edge-router.ts new file mode 100644 index 00000000..97a83c5e --- /dev/null +++ b/packages/client/src/features/routing/glsp-polyline-edge-router.ts @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2024 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { GConnectableElement, GParentElement, GRoutableElement, Point, PolylineEdgeRouter } from '@eclipse-glsp/sprotty'; +import { injectable } from 'inversify'; + +@injectable() +export class GLSPPolylineEdgeRouter extends PolylineEdgeRouter { + override getTranslatedAnchor( + connectable: GConnectableElement, + refPoint: Point, + refContainer: GParentElement, + edge: GRoutableElement, + anchorCorrection?: number | undefined + ): Point { + // users may define all kinds of anchors and anchor computers, we want to make sure we return a valid one in any case + const anchor = super.getTranslatedAnchor(connectable, refPoint, refContainer, edge, anchorCorrection); + return Point.isValid(anchor) ? anchor : refPoint; + } +} diff --git a/packages/client/src/features/routing/index.ts b/packages/client/src/features/routing/index.ts index 452038f5..b8acc9e7 100644 --- a/packages/client/src/features/routing/index.ts +++ b/packages/client/src/features/routing/index.ts @@ -14,4 +14,5 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ export * from './glsp-manhattan-edge-router'; +export * from './glsp-polyline-edge-router'; export * from './routing-module'; diff --git a/packages/client/src/features/routing/routing-module.ts b/packages/client/src/features/routing/routing-module.ts index 7fb859c7..18e46a57 100644 --- a/packages/client/src/features/routing/routing-module.ts +++ b/packages/client/src/features/routing/routing-module.ts @@ -17,7 +17,6 @@ import { AddRemoveBezierSegmentCommand, AnchorComputerRegistry, BezierDiamondAnchor, - BezierEdgeRouter, BezierEllipseAnchor, BezierRectangleAnchor, DiamondAnchor, @@ -27,13 +26,14 @@ import { ManhattanDiamondAnchor, ManhattanEllipticAnchor, ManhattanRectangularAnchor, - PolylineEdgeRouter, RectangleAnchor, TYPES, bindAsService, configureCommand } from '@eclipse-glsp/sprotty'; import { GLSPManhattanEdgeRouter } from './glsp-manhattan-edge-router'; +import { GLSPPolylineEdgeRouter } from './glsp-polyline-edge-router'; +import { GLSPBezierEdgeRouter } from './glsp-bezier-edge-router'; export const routingModule = new FeatureModule((bind, unbind, isBound, rebind) => { const context = { bind, unbind, isBound, rebind }; @@ -45,12 +45,12 @@ export const routingModule = new FeatureModule((bind, unbind, isBound, rebind) = bindAsService(context, TYPES.IAnchorComputer, ManhattanRectangularAnchor); bindAsService(context, TYPES.IAnchorComputer, ManhattanDiamondAnchor); - bindAsService(context, TYPES.IEdgeRouter, PolylineEdgeRouter); + bindAsService(context, TYPES.IEdgeRouter, GLSPPolylineEdgeRouter); bindAsService(context, TYPES.IAnchorComputer, EllipseAnchor); bindAsService(context, TYPES.IAnchorComputer, RectangleAnchor); bindAsService(context, TYPES.IAnchorComputer, DiamondAnchor); - bindAsService(context, TYPES.IEdgeRouter, BezierEdgeRouter); + bindAsService(context, TYPES.IEdgeRouter, GLSPBezierEdgeRouter); bindAsService(context, TYPES.IAnchorComputer, BezierEllipseAnchor); bindAsService(context, TYPES.IAnchorComputer, BezierRectangleAnchor); bindAsService(context, TYPES.IAnchorComputer, BezierDiamondAnchor); diff --git a/packages/protocol/src/index.ts b/packages/protocol/src/index.ts index 8dc607af..f3c0e229 100644 --- a/packages/protocol/src/index.ts +++ b/packages/protocol/src/index.ts @@ -18,4 +18,5 @@ export * from './client-server-protocol'; export * from './model'; export * from './re-exports'; export * from './sprotty-actions'; +export * from './sprotty-geometry-point'; export * from './utils'; diff --git a/packages/protocol/src/sprotty-geometry-point.ts b/packages/protocol/src/sprotty-geometry-point.ts new file mode 100644 index 00000000..e1090b77 --- /dev/null +++ b/packages/protocol/src/sprotty-geometry-point.ts @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2024 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +/* eslint-disable @typescript-eslint/no-shadow */ + +import { Point } from 'sprotty-protocol/lib/utils/geometry'; + +declare module 'sprotty-protocol/lib/utils/geometry' { + namespace Point { + /** + * Type guard to check if a point is valid. For a point to be valid it needs to be defined and have valid x and y coordinates. + * + * @param point the point to be checked for validity + */ + function isValid(point?: Point): point is Point; + } +} + +Point.isValid = (point?: Point): point is Point => point !== undefined && !isNaN(point.x) && !isNaN(point.y); + +export { Point };