diff --git a/java/bundles/org.eclipse.set.application.test/META-INF/MANIFEST.MF b/java/bundles/org.eclipse.set.application.test/META-INF/MANIFEST.MF index 42559200d3..eaeaab6680 100644 --- a/java/bundles/org.eclipse.set.application.test/META-INF/MANIFEST.MF +++ b/java/bundles/org.eclipse.set.application.test/META-INF/MANIFEST.MF @@ -6,5 +6,10 @@ Bundle-Version: 2.6.0.qualifier Fragment-Host: org.eclipse.set.application Bundle-RequiredExecutionEnvironment: JavaSE-21 Bundle-Vendor: Eclipse Signalling Engineering Toolbox -Import-Package: org.junit, - org.junit.jupiter.api +Import-Package: org.apache.commons.lang3.reflect;version="[3.17.0,4.0.0)", + org.eclipse.set.unittest.utils, + org.jheaps.tree;version="[0.14.0,1.0.0)", + org.junit, + org.junit.jupiter.api, + org.junit.jupiter.params;version="[5.12.0,6.0.0)", + org.junit.jupiter.params.provider;version="[5.12.0,6.0.0)" diff --git a/java/bundles/org.eclipse.set.application.test/src/org/eclipse/set/application/graph/TopologicalGraphServiceTest.java b/java/bundles/org.eclipse.set.application.test/src/org/eclipse/set/application/graph/TopologicalGraphServiceTest.java new file mode 100644 index 0000000000..11013e59f6 --- /dev/null +++ b/java/bundles/org.eclipse.set.application.test/src/org/eclipse/set/application/graph/TopologicalGraphServiceTest.java @@ -0,0 +1,204 @@ +/** + * Copyright (c) 2025 DB InfraGO AG and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + */ +package org.eclipse.set.application.graph; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.lang3.reflect.FieldUtils; +import org.eclipse.set.basis.constants.ContainerType; +import org.eclipse.set.basis.graph.DirectedEdge; +import org.eclipse.set.basis.graph.DirectedEdgePath; +import org.eclipse.set.basis.graph.TopPath; +import org.eclipse.set.basis.graph.TopPoint; +import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt; +import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt_TOP_Kante_AttributeGroup; +import org.eclipse.set.model.planpro.Basisobjekte.Ur_Objekt; +import org.eclipse.set.model.planpro.Fahrstrasse.Fstr_Fahrweg; +import org.eclipse.set.model.planpro.Geodaten.TOP_Kante; +import org.eclipse.set.model.planpro.Geodaten.TOP_Knoten; +import org.eclipse.set.model.planpro.PlanPro.PlanPro_Schnittstelle; +import org.eclipse.set.model.planpro.Signale.Signal; +import org.eclipse.set.ppmodel.extensions.BereichObjektExtensions; +import org.eclipse.set.ppmodel.extensions.FahrwegExtensions; +import org.eclipse.set.ppmodel.extensions.PlanProSchnittstelleExtensions; +import org.eclipse.set.ppmodel.extensions.container.MultiContainer_AttributeGroup; +import org.eclipse.set.ppmodel.extensions.utils.CollectionExtensions; +import org.eclipse.set.unittest.utils.AbstractToolboxTest; +import org.eclipse.set.utils.graph.AsSplitTopGraph.Edge; +import org.eclipse.set.utils.graph.AsSplitTopGraph.Node; +import org.jgrapht.graph.WeightedPseudograph; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.collect.Streams; + +/** + * + */ +public class TopologicalGraphServiceTest extends AbstractToolboxTest { + + /** + * @return the siteplan reference files + */ + protected static Stream getReferenceFiles() { + return Stream.of(Arguments.of(NB_Test_Info_2025_10_16_16_35, "nbTest")); + } + + TopologicalGraphServiceImpl testee; + + @ParameterizedTest + @MethodSource("getReferenceFiles") + void testTopologicalGraphService(final String file) throws Exception { + givenPlanProFile(file); + givenTopologicalGraphService(); + doFindFtrsWegTopPath(); + } + + private void doFindFtrsWegTopPath() { + final List fstrFahrweg = getUrObjekts( + container -> container.getFstrFahrweg()); + fstrFahrweg.forEach(fstr -> { + try { + if (fstr.getIdentitaet() + .getWert() + .equals("264739AB-EE6C-4144-AE63-C57505E57769")) { + System.out.println("TEST"); + } + final DirectedEdgePath topGraphPath = FahrwegExtensions + .getPath(fstr); + final DirectedEdge startEdge = topGraphPath + .getEdgeList() + .getFirst(); + // final Set> paths = + // org.eclipse.set.utils.graph.DirectedEdgeExtensions + // .getPaths(startEdge, new TopRouting(), + // topGraphPath.getStart(), topGraphPath.getEnd()); + + final TopPath topPath = FahrwegExtensions.getPath(fstr, testee); + final List test = topGraphPath.getEdgeList() + .stream() + .map(edge -> edge.getElement()) + .toList(); + final List test2 = topPath.edges(); + final List topPaths = getFstrFarhWegPath(fstr); + assertEquals(1, topPaths.size(), () -> { + return fstr.getIdentitaet().getWert(); + }); + assertEquals(test, topPaths.getFirst().edges(), () -> { + return fstr.getIdentitaet().getWert(); + }); + } catch (final Exception e) { + + } + + }); + } + + private List getFstrFarhWegPath(final Fstr_Fahrweg fstr) { + final Signal startSignal = fstr.getIDStart().getValue(); + final Punkt_Objekt zielPunktObjekt = FahrwegExtensions + .getZielPunktObjekt(fstr); + final Punkt_Objekt_TOP_Kante_AttributeGroup signalPotk = CollectionExtensions + .getUnique(BereichObjektExtensions.intersection(fstr, + startSignal)); + final Punkt_Objekt_TOP_Kante_AttributeGroup zielPotk = CollectionExtensions + .getUnique(BereichObjektExtensions.intersection(fstr, + zielPunktObjekt)); + if (signalPotk.getIDTOPKante().getValue() == zielPotk.getIDTOPKante() + .getValue()) { + return List.of( + new TopPath(List.of(signalPotk.getIDTOPKante().getValue()), + signalPotk.getAbstand() + .getWert() + .subtract(zielPotk.getAbstand().getWert()) + .abs(), + new TopPoint(signalPotk))); + } + + final BigDecimal length = BereichObjektExtensions.getLength(fstr); + final TopPath testPath = testee.findShortestPathBetween( + new TopPoint(startSignal), new TopPoint(zielPunktObjekt), + length.intValue() + 100, topPath -> { + final int size = fstr.getBereichObjektTeilbereich().size(); + final List topkanten = fstr + .getBereichObjektTeilbereich() + .stream() + .map(botb -> botb.getIDTOPKante().getValue()) + .toList(); + return size == topPath.edges().size() + && topPath.edges().containsAll(topkanten); + }); + final List allPathsBetween = testee.findAllPathsBetween( + new TopPoint(signalPotk), new TopPoint(zielPotk), + length.intValue() + 100, false); + final List result = allPathsBetween.stream() + .filter(path -> path.edges() + .stream() + .collect(Collectors.toSet()) + .size() == fstr.getBereichObjektTeilbereich().size()) + .filter(path -> path.edges() + .stream() + .allMatch(edge -> fstr.getBereichObjektTeilbereich() + .stream() + .map(botb -> botb.getIDTOPKante().getValue()) + .anyMatch(topKante -> topKante == edge))) + .toList(); + if (result.size() != 1) { + + System.out.println("TEST"); + } + return result; + } + + void givenTopologicalGraphService() throws Exception { + testee = new TopologicalGraphServiceImpl(); + final Map> topGraphBase = new HashMap<>(); + final WeightedPseudograph pseudograph = new WeightedPseudograph<>( + Edge.class); + final Method addContainerGraph = TopologicalGraphServiceImpl.class + .getDeclaredMethod("addContainerToGraph", + WeightedPseudograph.class, + MultiContainer_AttributeGroup.class); + addContainerGraph.setAccessible(true); + + for (final ContainerType type : ContainerType.values()) { + final MultiContainer_AttributeGroup container = PlanProSchnittstelleExtensions + .getContainer(planProSchnittstelle, type); + addContainerGraph.invoke(testee, pseudograph, container); + } + topGraphBase.put(planProSchnittstelle, pseudograph); + FieldUtils.writeField(testee, "topGraphBaseMap", topGraphBase, true); + } + + private List getUrObjekts( + final Function> getObjFunc) { + return Arrays.stream(ContainerType.values()) + .map(type -> PlanProSchnittstelleExtensions + .getContainer(planProSchnittstelle, type)) + .filter(Objects::nonNull) + .flatMap(container -> Streams + .stream(getObjFunc.apply(container))) + .toList(); + } +} diff --git a/java/bundles/org.eclipse.set.application/META-INF/MANIFEST.MF b/java/bundles/org.eclipse.set.application/META-INF/MANIFEST.MF index a851f49ac4..724494f452 100644 --- a/java/bundles/org.eclipse.set.application/META-INF/MANIFEST.MF +++ b/java/bundles/org.eclipse.set.application/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-Vendor: Eclipse Signalling Engineering Toolbox Export-Package: org.eclipse.set.application, org.eclipse.set.application.controlarea, org.eclipse.set.application.geometry, + org.eclipse.set.application.graph, org.eclipse.set.application.handler, org.eclipse.set.application.nameservice Require-Bundle: org.eclipse.core.runtime, diff --git a/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/BankServiceImpl.java b/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/BankServiceImpl.java index 9b08c8f332..9d9156fe67 100644 --- a/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/BankServiceImpl.java +++ b/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/BankServiceImpl.java @@ -282,7 +282,7 @@ public BankingInformation findTOPBanking( .getTOPLaenge() .getWert(); return new BankingInformation(bankingLine, new TopPath( - List.of(beginEdge), pathLength, pathLength)); + List.of(beginEdge), pathLength, new TopPoint(begin))); } } @@ -299,7 +299,7 @@ public BankingInformation findTOPBanking( return diff.doubleValue() < ToolboxConfiguration .getBankLineTopOffsetLimit(); }; - final TopPath path = topGraph.findPathBetween(new TopPoint(begin), + final TopPath path = topGraph.findShortestPathBetween(new TopPoint(begin), new TopPoint(end), limit, predicate); if (path == null) { diff --git a/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/TopologicalGraphServiceImpl.java b/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/TopologicalGraphServiceImpl.java index c7f81b9982..8ab604b0fd 100644 --- a/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/TopologicalGraphServiceImpl.java +++ b/java/bundles/org.eclipse.set.application/src/org/eclipse/set/application/graph/TopologicalGraphServiceImpl.java @@ -15,9 +15,11 @@ import java.math.BigDecimal; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.function.Predicate; import org.eclipse.e4.core.services.events.IEventBroker; @@ -30,9 +32,12 @@ import org.eclipse.set.core.services.Services; import org.eclipse.set.core.services.graph.TopologicalGraphService; import org.eclipse.set.core.services.session.SessionService; +import org.eclipse.set.model.planpro.Geodaten.ENUMTOPAnschluss; import org.eclipse.set.model.planpro.Geodaten.TOP_Kante; +import org.eclipse.set.model.planpro.Geodaten.TOP_Knoten; import org.eclipse.set.model.planpro.PlanPro.PlanPro_Schnittstelle; import org.eclipse.set.ppmodel.extensions.PlanProSchnittstelleExtensions; +import org.eclipse.set.ppmodel.extensions.TopKanteExtensions; import org.eclipse.set.ppmodel.extensions.container.MultiContainer_AttributeGroup; import org.eclipse.set.utils.graph.AsDirectedTopGraph; import org.eclipse.set.utils.graph.AsSplitTopGraph; @@ -47,6 +52,8 @@ import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * TopologicalGraph service for finding distances in the topological model @@ -57,6 +64,8 @@ EventHandler.class, TopologicalGraphService.class }) public class TopologicalGraphServiceImpl implements TopologicalGraphService, EventHandler { + private static final Logger logger = LoggerFactory + .getLogger(TopologicalGraphServiceImpl.class); private final Map> topGraphBaseMap; @Reference @@ -137,23 +146,31 @@ private static void addEdge( @Override public List findAllPathsBetween(final TopPoint from, final TopPoint to, final int limit) { + return findAllPathsBetween(from, to, limit, true); + } + + @Override + public List findAllPathsBetween(final TopPoint from, + final TopPoint to, final int limit, + final boolean inCludeIncompletePath) { final MultiContainer_AttributeGroup container = getContainer( from.edge()); final PlanPro_Schnittstelle planProSchnittstelle = getPlanProSchnittstelle( container); return AsDirectedTopGraph.getAllPaths( new AsSplitTopGraph(getTopGraphBase(planProSchnittstelle)), - from, to, limit); + from, to, limit, inCludeIncompletePath); } @Override - public TopPath findPathBetween(final TopPoint from, final TopPoint to, - final int limit, final Predicate condition) { + public TopPath findShortestPathBetween(final TopPoint from, + final TopPoint to, final int limit, + final Predicate condition) { final MultiContainer_AttributeGroup container = getContainer( from.edge()); final PlanPro_Schnittstelle planProSchnittstelle = getPlanProSchnittstelle( container); - return AsDirectedTopGraph.getPath( + return AsDirectedTopGraph.getShortestPath( new AsSplitTopGraph(getTopGraphBase(planProSchnittstelle)), from, to, limit, condition); } @@ -262,4 +279,134 @@ public Optional findClosestPoint(final TopPoint from, return minPoint; } + + @Override + public Optional findShortesPathInDirection(final TopPoint from, + final TopPoint to, final boolean inTopDirection) { + // When two point lie on same edge + if (from.edge().equals(to.edge())) { + return whenThePointsAreSameEdge(from, to, inTopDirection); + } + final MultiContainer_AttributeGroup container = getContainer( + from.edge()); + final PlanPro_Schnittstelle planProSchnittstelle = getPlanProSchnittstelle( + container); + final AsSplitTopGraph graphView = new AsSplitTopGraph( + getTopGraphBase(planProSchnittstelle)); + final Node startNode = graphView.splitGraphAt(from, + Boolean.valueOf(inTopDirection)); + + final Node endNode = graphView.splitGraphAt(to); + return Optional.ofNullable(AsDirectedTopGraph.getShortestPath( + AsDirectedTopGraph.asDirectedTopGraph(graphView), startNode, + endNode, findShortestDistance(from, to).orElse(BigDecimal.ZERO) + .intValue() + 1, + path -> { + if (!isInDirectionPath(path, inTopDirection)) { + return false; + } + final LinkedList edgeList = new LinkedList( + path.edges()); + for (TOP_Kante current; (current = edgeList + .poll()) != null;) { + if (edgeList.isEmpty()) { + return true; + } + final TOP_Kante next = edgeList.getFirst(); + if (!isRelevantNextEdge(current, next)) { + return false; + } + } + return true; + + })); + } + + private static Optional whenThePointsAreSameEdge( + final TopPoint from, final TopPoint to, + final boolean inTopDirection) { + // When two point lie on same edge + final BigDecimal fromDistance = from.distance(); + final BigDecimal toDistance = to.distance(); + final BigDecimal distance = toDistance.subtract(fromDistance); + return inTopDirection == distance.compareTo(BigDecimal.ZERO) > 0 + ? Optional.of( + new TopPath(List.of(from.edge()), distance.abs(), from)) + : Optional.empty(); + } + + private static boolean isInDirectionPath(final TopPath path, + final boolean inTopDirection) { + final TOP_Kante firstEdge = path.edges().getFirst(); + final TOP_Kante secondEdge = path.edges().get(1); + final TOP_Knoten connectionNode = TopKanteExtensions + .connectionTo(firstEdge, secondEdge); + return inTopDirection == connectionNode + .equals(TopKanteExtensions.getTOPKnotenB(firstEdge)); + } + + /** + * The connect type between to edge must plausible + * + * @param current + * the current edge + * @param next + * the next edge + * @param connectNode + * the connect node + * @return whether connect relevant + */ + private static boolean isRelevantNextEdge(final TOP_Kante current, + final TOP_Kante next) { + if (current == next) { + return false; + } + + final TOP_Knoten connectionNode = TopKanteExtensions + .connectionTo(current, next); + if (connectionNode == null) { + return false; + } + final Function> getTopConnectType = edge -> { + try { + final TOP_Knoten topNodeA = edge.getIDTOPKnotenA().getValue(); + final TOP_Knoten topNodeB = edge.getIDTOPKnotenB().getValue(); + if (topNodeA == connectionNode) { + return Optional.ofNullable(edge.getTOPKanteAllg() + .getTOPAnschlussA() + .getWert()); + } + + if (topNodeB == connectionNode) { + return Optional.ofNullable(edge.getTOPKanteAllg() + .getTOPAnschlussB() + .getWert()); + } + throw new IllegalArgumentException(); + } catch (final Exception e) { + logger.error( + "Can't find TOP_Anschlus of TOP_Kanten: {} at TOP_Knoten: {}", //$NON-NLS-1$ + edge.getIdentitaet().getWert(), + connectionNode.getIdentitaet().getWert()); + return Optional.empty(); + } + }; + final ENUMTOPAnschluss currentConnectType = getTopConnectType + .apply(current) + .orElse(null); + final ENUMTOPAnschluss nextConnectType = getTopConnectType.apply(next) + .orElse(null); + if (currentConnectType == null || nextConnectType == null) { + return false; + } + + return switch (currentConnectType) { + case ENUMTOP_ANSCHLUSS_LINKS, ENUMTOP_ANSCHLUSS_RECHTS -> nextConnectType == ENUMTOPAnschluss.ENUMTOP_ANSCHLUSS_SPITZE; + case ENUMTOP_ANSCHLUSS_SPITZE -> nextConnectType == ENUMTOPAnschluss.ENUMTOP_ANSCHLUSS_LINKS + || nextConnectType == ENUMTOPAnschluss.ENUMTOP_ANSCHLUSS_RECHTS; + case ENUMTOP_ANSCHLUSS_MERIDIANSPRUNG -> nextConnectType == ENUMTOPAnschluss.ENUMTOP_ANSCHLUSS_MERIDIANSPRUNG; + case ENUMTOP_ANSCHLUSS_SCHNITT -> nextConnectType == ENUMTOPAnschluss.ENUMTOP_ANSCHLUSS_SCHNITT; + default -> false; + }; + } } diff --git a/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/constants/ToolboxConstants.java b/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/constants/ToolboxConstants.java index cc80344dad..269fea2618 100644 --- a/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/constants/ToolboxConstants.java +++ b/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/constants/ToolboxConstants.java @@ -9,351 +9,351 @@ package org.eclipse.set.basis.constants; import java.util.Comparator; - import org.eclipse.set.basis.MixedStringComparator; import org.eclipse.set.basis.NumericFirstComparatorDecorator; import org.eclipse.set.basis.ToolboxProperties; /** * Common toolbox constants. - * + * * @author Schaefer */ @SuppressWarnings("nls") // Constants are not translated public final class ToolboxConstants { - /** - * Nested part for cache ids. - */ - public interface CacheId { - - /** - * The id of the guid to object cache. - */ - public static final String GUID_TO_OBJECT = "toolbox.cache.guid-to-object"; - - /** - * The id of the Top-Kante to single point cache. - */ - public static final String TOPKANTE_TO_SINGLEPOINTS = "toolbox.cache.topkante-to-singlepoints"; - - /** - * The id of the Fahrweg key to single Fahrweg routes cache. - */ - public static final String FAHRWEG_TO_ROUTES = "toolbox.cache.fahrweg-key-to-fahrweg-routes"; - - /** - * The id of the edge to single single points cache. - */ - public static final String DIRECTED_EDGE_TO_SINGLEPOINTS = "toolbox.cache.directed-edge-to-singlepoints"; - - /** - * The id of the edge to subpath cache. - */ - public static final String DIRECTED_EDGE_TO_SUBPATH = "toolbox.cache.directed-edge-to-subpath"; - - /** - * The id of the Top-Kante to adjacent Top-Kanten cache. - */ - public static final String TOPKANTE_TO_ADJACENT_TOPKANTEN = "toolbox.cache.topkante-to-adjacent-topkanten"; - - /** - * The geometry of the GEO_Kante - */ - public static final String GEOKANTE_GEOMETRY = "toolbox.cache.geokante-geometry"; - - /** - * The id of the problem message cache. - */ - public static final String PROBLEM_MESSAGE = "toolbox.cache.problem-message"; - - /** - * The id of the table error cache of initial state. - */ - public static final String TABLE_ERRORS_INITIAL = "toolbox.cache.table-errors-initial"; - - /** - * The id of the table error cache of final state. - */ - public static final String TABLE_ERRORS_FINAL = "toolbox.cache.table-errors-final"; - - /** - * The id of the table error cache of single state. - */ - public static final String TABLE_ERRORS_SINGLE = "toolbox.cache.table-errors-single"; - - /** - * The id of the table error cache. - */ - public static final String TABLE_ERRORS = "toolbox.cache.table-errors"; - - /** - * The id of the siteplan - */ - public static final String SITEPLAN_CACHE_ID = "toolbox.cache.siteplan"; - } - - /** - * Extension category for all PlanPro files (PlanPro models + merge). - */ - public static final String EXTENSION_CATEGORY_PPALL = "ppall"; - - /** - * Extension category for PlanPro models. - */ - public static final String EXTENSION_CATEGORY_PPFILE = "ppfile"; - - /** - * Extension category for PlanPro models - */ - public static final String EXTENSION_CATEGORY_PPMERGE = "ppmerge"; - - /** - * mplanpro extension - */ - public static final String EXTENSION_MPLANPRO = "mplanpro"; - - /** - * planpro extension - */ - public static final String EXTENSION_PLANPRO = "planpro"; - - /** - * ppxml extension - */ - public static final String EXTENSION_PPXML = "ppxml"; - - /** - * xml extension - */ - public static final String EXTENSION_XML = "xml"; - - /** - * PID file name - */ - public static final String PID_FILE_NAME = ".pid"; - - /** - * File parameter. - */ - public static final String FILE_PARAMETER = "org.eclipse.set.application.commandparameter.file"; //$NON-NLS-1$ - - /** - * Compares LST object names - */ - public static final Comparator LST_OBJECT_NAME_COMPARATOR = new NumericFirstComparatorDecorator( - new MixedStringComparator( - "(?[0-9]{2})?(?[A-Za-zÄÖÜßäöü]*)(?[0-9]*)(?[.]*)(?[0-9]*)(?[A-Za-zÄÖÜßäöü]*)(?.*)")); - - /** - * The id of the no session part. - */ - public static final String NO_SESSION_PART_ID = "org.eclipse.set.application.part.nosessionpart"; - - /** - * Compares strings numerical. - */ - public static final MixedStringComparator NUMERIC_COMPARATOR = new MixedStringComparator( - "(?[0-9]+)"); - - /** - * The id of the attachment viewer part. - */ - public static final String ATTACHMENT_VIEWER_PART_ID = "org.eclipse.set.application.parts.AttachmentViewerPart"; - - /** - * The id of the project part. - */ - public static final String PROJECT_PART_ID = "org.eclipse.set.feature.projectdata.edit.ProjectPart"; - - /** - * The id of the project part. - */ - public static final String PROJECT_IMPORTPART_ID = "org.eclipse.set.feature.projectdata.ppimport.PlanProImportPart"; - - /** - * The id of the table key to table cache. - */ - public static final String SHORTCUT_TO_TABLE_CACHE_ID = "toolbox.cache.shortcut-to-table"; - - /** - * The base directory for temporary subdirectories. - */ - public static final String TMP_BASE_DIR; - - /** - * The name for the temporary directory of a toolbox file used to be - * exported. - */ - public static final String TOOLBOX_DIRECTORY_NAME_EXPORT = "exportfile"; - - /** - * The name for the temporary directory of a toolbox file used to be - * imported into the final state. - */ - public static final String TOOLBOX_DIRECTORY_NAME_IMPORT_FINAL_STATE = "importfinalfile"; - - /** - * The name for the temporary directory of a toolbox file used to be - * imported into the initial state. - */ - public static final String TOOLBOX_DIRECTORY_NAME_IMPORT_INITIAL_STATE = "importinitialfile"; - - /** - * The name for the temporary directory of a toolbox file used as a first - * planning to import. - */ - public static final String TOOLBOX_DIRECTORY_NAME_FIRST_PLANNING_TO_IMPORT = "firstimportplanningfile"; - - /** - * The name for the temporary directory of a toolbox file used as a second - * planning to import. - */ - public static final String TOOLBOX_DIRECTORY_NAME_SECOND_PLANNING_TO_IMPORT = "secondimportplanningfile"; - - /** - * The name for the temporary directory of a toolbox file used as a - * secondary planning. - */ - public static final String TOOLBOX_DIRECTORY_NAME_COMPARE_PLANNING = "compareplanning"; - - /** - * The name for the temporary directory of a toolbox file used to start a - * new session. - */ - public static final String TOOLBOX_DIRECTORY_NAME_SESSION = "toolboxfile"; - - /** - * The name for the temporary directory of a toolbox file used as a - * temporary integration. - */ - public static final String TOOLBOX_DIRECTORY_NAME_TEMPORARY_INTEGRATION = "tempintegrationfile"; - - /** - * The id of the validation part. - */ - public static final String VALIDATION_PART_ID = "org.eclipse.set.feature.validation.parts.ValidationPart"; - - /** - * The id of the plaz model part - */ - public static final String PLAZ_MODEL_PART_ID = "org.eclipse.set.feature.plazmodel.PlaZModelPart"; - - /** - * The id of the validation table part. - */ - public static final String VALIDATION_TABLE_PART_ID = "org.eclipse.set.feature.validation.parts.ValidationTablePart"; - - /** - * The id of the table overview part. - */ - public static final String TABLE_OVERVIEW_ID = "overview.TableOverviewPart"; - - private static final String DEFAULT_HOME_DIR; - - /** - * The id of the news part - */ - public static final String WEB_NEWS_PART_ID = "org.eclipse.set.application.nosessionpart.WebNewsPart"; - - /** - * The id of the about part - */ - public static final String ABOUT_PART_ID = "org.eclipse.set.application.about.AboutPart"; - - /** - * The id of the chromium credits part - */ - public static final String CHROMIUM_CREDITS_PART_ID = "org.eclipse.set.application.about.ChromiumCreditsPart"; - - /** - * The key for decide with view model should be renderer - */ - public static final String PLANING_GROUP_VIEW_DETAIL_KEY = "detail"; - - /** - * The prefix of ESTW table part - */ - public static final String ESTW_TABLE_PART_ID_PREFIX = "org.eclipse.set.feature.table.estw"; - - /** - * The prefix of ETCS table part - */ - public static final String ETCS_TABLE_PART_ID_PREFIX = "org.eclipse.set.feature.table.etcs"; - - /** - * The prefix of ESTW Supplement table part - */ - public static final String ESTW_SUPPLEMENT_PART_ID_PREFIX = "org.eclipse.set.feature.table.supplement-estw"; - - /** - * Rounding result of BigDecimal.divide to place after comma - */ - public static final int ROUNDING_TO_PLACE = 5; - - /** - * Labels for CompareTableCellContent cell - */ - public static final String TABLE_COMPARE_TABLE_CELL_LABEL = "tableCompareCell"; - - /** - * Labels for converter search cell - */ - public static final String SEARCH_CELL_DISPLAY_CONVERTER = "searchCellConverter"; - - /** - * Color of the compare table cell border - */ - public static final String TABLE_COMPARE_TABLE_CELL_BORDER_COLOR = "#0066FF"; - - /** - * The id of the web developer help part - */ - public static String WEB_DEVELOPER_HELP_PART_ID = "org.eclipse.set.application.ppt.nosessionpart.WebDeveloperHelpPart"; - - /** - * The name of compare project cell content - */ - public static final String XSL_PROJECT_COMPARE_CELL = "CompareProjectContent"; - - /** - * The attribute name for compare row - */ - public static final String XSL_COMPARE_ROW_TYPE_ATTRIBUTE = "compareType"; - - /** - * Label for cells of table row, which completely changed. - */ - public static final String TABLE_COMPARE_CHANGED_GUID_ROW_CELL_LABEL = "tableGuidChangeRowCell"; - - /** - * Label for first cell of table row, which completely changed. - */ - public static final String TABLE_COMPARE_TABLE_ROW_FIRST_CELL_LABEL = "tableCompareTableRowFirstCell"; - - /** - * Label for last cell of table row, which completely changed. - */ - public static final String TABLE_COMPARE_TABLE_ROW_LAST_CELL_LABEL = "tableCompareTableRowLastCell"; - - /** - * Label for cell of the table row, which completely changed. - */ - public static final String TABLE_COMPARE_TABLE_ROW_CELL_LABEL = "tableCompareTableRowCell"; - - /** - * Label for Topological Cell - */ - public static final String TABLE_TOPOLOGICAL_CELL = "topologicalCell"; - - /** - * The tolerance value between TOP_Kante length and the sum of GEO_Kanten - * length, which belong to this TOP_Kante (in Meter) - */ - public static final double TOP_GEO_LENGTH_TOLERANCE = 0.01; - static { - DEFAULT_HOME_DIR = "./"; - TMP_BASE_DIR = System.getProperty(ToolboxProperties.TMP_BASE_DIR, - DEFAULT_HOME_DIR); - } + /** + * Nested part for cache ids. + */ + public interface CacheId { + + /** + * The id of the guid to object cache. + */ + public static final String GUID_TO_OBJECT = "toolbox.cache.guid-to-object"; + + /** + * The id of the Top-Kante to single point cache. + */ + public static final String TOPKANTE_TO_SINGLEPOINTS = "toolbox.cache.topkante-to-singlepoints"; + + /** + * The id of the Fahrweg key to single Fahrweg routes cache. + */ + public static final String FAHRWEG_TO_ROUTES = "toolbox.cache.fahrweg-key-to-fahrweg-routes"; + + /** + * The id of the edge to single single points cache. + */ + public static final String DIRECTED_EDGE_TO_SINGLEPOINTS = "toolbox.cache.directed-edge-to-singlepoints"; + + /** + * The id of the edge to subpath cache. + */ + public static final String DIRECTED_EDGE_TO_SUBPATH = "toolbox.cache.directed-edge-to-subpath"; + + /** + * The id of the Top-Kante to adjacent Top-Kanten cache. + */ + public static final String TOPKANTE_TO_ADJACENT_TOPKANTEN = "toolbox.cache.topkante-to-adjacent-topkanten"; + + /** + * The geometry of the GEO_Kante + */ + public static final String GEOKANTE_GEOMETRY = "toolbox.cache.geokante-geometry"; + + /** + * The id of the problem message cache. + */ + public static final String PROBLEM_MESSAGE = "toolbox.cache.problem-message"; + + /** + * The id of the table error cache of initial state. + */ + public static final String TABLE_ERRORS_INITIAL = "toolbox.cache.table-errors-initial"; + + /** + * The id of the table error cache of final state. + */ + public static final String TABLE_ERRORS_FINAL = "toolbox.cache.table-errors-final"; + + /** + * The id of the table error cache of single state. + */ + public static final String TABLE_ERRORS_SINGLE = "toolbox.cache.table-errors-single"; + + /** + * The id of the table error cache. + */ + public static final String TABLE_ERRORS = "toolbox.cache.table-errors"; + + /** + * The id of the siteplan + */ + public static final String SITEPLAN_CACHE_ID = "toolbox.cache.siteplan"; + } + + /** + * Extension category for all PlanPro files (PlanPro models + merge). + */ + public static final String EXTENSION_CATEGORY_PPALL = "ppall"; + + /** + * Extension category for PlanPro models. + */ + public static final String EXTENSION_CATEGORY_PPFILE = "ppfile"; + + /** + * Extension category for PlanPro models + */ + public static final String EXTENSION_CATEGORY_PPMERGE = "ppmerge"; + + /** + * mplanpro extension + */ + public static final String EXTENSION_MPLANPRO = "mplanpro"; + + /** + * planpro extension + */ + public static final String EXTENSION_PLANPRO = "planpro"; + + /** + * ppxml extension + */ + public static final String EXTENSION_PPXML = "ppxml"; + + /** + * xml extension + */ + public static final String EXTENSION_XML = "xml"; + + /** + * PID file name + */ + public static final String PID_FILE_NAME = ".pid"; + + /** + * File parameter. + */ + public static final String FILE_PARAMETER = "org.eclipse.set.application.commandparameter.file"; //$NON-NLS-1$ + + /** + * Compares LST object names + */ + public static final Comparator LST_OBJECT_NAME_COMPARATOR = new NumericFirstComparatorDecorator( + new MixedStringComparator( + "(?[0-9]{2})?(?[A-Za-zÄÖÜßäöü]*)(?[0-9]*)(?[.]*)(?[0-9]*)(?[A-Za-zÄÖÜßäöü]*)(?.*)")); + + /** + * The id of the no session part. + */ + public static final String NO_SESSION_PART_ID = "org.eclipse.set.application.part.nosessionpart"; + + /** + * Compares strings numerical. + */ + public static final MixedStringComparator NUMERIC_COMPARATOR = new MixedStringComparator( + "(?[0-9]+)"); + + /** + * The id of the attachment viewer part. + */ + public static final String ATTACHMENT_VIEWER_PART_ID = "org.eclipse.set.application.parts.AttachmentViewerPart"; + + /** + * The id of the project part. + */ + public static final String PROJECT_PART_ID = "org.eclipse.set.feature.projectdata.edit.ProjectPart"; + + /** + * The id of the project part. + */ + public static final String PROJECT_IMPORTPART_ID = "org.eclipse.set.feature.projectdata.ppimport.PlanProImportPart"; + + /** + * The id of the table key to table cache. + */ + public static final String SHORTCUT_TO_TABLE_CACHE_ID = "toolbox.cache.shortcut-to-table"; + + /** + * The base directory for temporary subdirectories. + */ + public static final String TMP_BASE_DIR; + + /** + * The name for the temporary directory of a toolbox file used to be + * exported. + */ + public static final String TOOLBOX_DIRECTORY_NAME_EXPORT = "exportfile"; + + /** + * The name for the temporary directory of a toolbox file used to be + * imported into the final state. + */ + public static final String TOOLBOX_DIRECTORY_NAME_IMPORT_FINAL_STATE = "importfinalfile"; + + /** + * The name for the temporary directory of a toolbox file used to be + * imported into the initial state. + */ + public static final String TOOLBOX_DIRECTORY_NAME_IMPORT_INITIAL_STATE = "importinitialfile"; + + /** + * The name for the temporary directory of a toolbox file used as a first + * planning to import. + */ + public static final String TOOLBOX_DIRECTORY_NAME_FIRST_PLANNING_TO_IMPORT = "firstimportplanningfile"; + + /** + * The name for the temporary directory of a toolbox file used as a second + * planning to import. + */ + public static final String TOOLBOX_DIRECTORY_NAME_SECOND_PLANNING_TO_IMPORT = "secondimportplanningfile"; + + /** + * The name for the temporary directory of a toolbox file used as a + * secondary planning. + */ + public static final String TOOLBOX_DIRECTORY_NAME_COMPARE_PLANNING = "compareplanning"; + + /** + * The name for the temporary directory of a toolbox file used to start a + * new session. + */ + public static final String TOOLBOX_DIRECTORY_NAME_SESSION = "toolboxfile"; + + /** + * The name for the temporary directory of a toolbox file used as a + * temporary integration. + */ + public static final String TOOLBOX_DIRECTORY_NAME_TEMPORARY_INTEGRATION = "tempintegrationfile"; + + /** + * The id of the validation part. + */ + public static final String VALIDATION_PART_ID = "org.eclipse.set.feature.validation.parts.ValidationPart"; + + /** + * The id of the plaz model part + */ + public static final String PLAZ_MODEL_PART_ID = "org.eclipse.set.feature.plazmodel.PlaZModelPart"; + + /** + * The id of the validation table part. + */ + public static final String VALIDATION_TABLE_PART_ID = "org.eclipse.set.feature.validation.parts.ValidationTablePart"; + + /** + * The id of the table overview part. + */ + public static final String TABLE_OVERVIEW_ID = "overview.TableOverviewPart"; + + private static final String DEFAULT_HOME_DIR; + + /** + * The id of the news part + */ + public static final String WEB_NEWS_PART_ID = "org.eclipse.set.application.nosessionpart.WebNewsPart"; + + /** + * The id of the about part + */ + public static final String ABOUT_PART_ID = "org.eclipse.set.application.about.AboutPart"; + + /** + * The id of the chromium credits part + */ + public static final String CHROMIUM_CREDITS_PART_ID = "org.eclipse.set.application.about.ChromiumCreditsPart"; + + /** + * The key for decide with view model should be renderer + */ + public static final String PLANING_GROUP_VIEW_DETAIL_KEY = "detail"; + + /** + * The prefix of ESTW table part + */ + public static final String ESTW_TABLE_PART_ID_PREFIX = "org.eclipse.set.feature.table.estw"; + + /** + * The prefix of ETCS table part + */ + public static final String ETCS_TABLE_PART_ID_PREFIX = "org.eclipse.set.feature.table.etcs"; + + /** + * The prefix of ESTW Supplement table part + */ + public static final String ESTW_SUPPLEMENT_PART_ID_PREFIX = "org.eclipse.set.feature.table.supplement-estw"; + + /** + * Rounding result of BigDecimal.divide to place after comma + */ + public static final int ROUNDING_TO_PLACE = 5; + + /** + * Labels for CompareTableCellContent cell + */ + public static final String TABLE_COMPARE_TABLE_CELL_LABEL = "tableCompareCell"; + + /** + * Labels for converter search cell + */ + public static final String SEARCH_CELL_DISPLAY_CONVERTER = "searchCellConverter"; + + /** + * Color of the compare table cell border + */ + public static final String TABLE_COMPARE_TABLE_CELL_BORDER_COLOR = "#0066FF"; + + /** + * The id of the web developer help part + */ + public static String WEB_DEVELOPER_HELP_PART_ID = "org.eclipse.set.application.ppt.nosessionpart.WebDeveloperHelpPart"; + + /** + * The name of compare project cell content + */ + public static final String XSL_PROJECT_COMPARE_CELL = "CompareProjectContent"; + + /** + * The attribute name for compare row + */ + public static final String XSL_COMPARE_ROW_TYPE_ATTRIBUTE = "compareType"; + + /** + * Label for cells of table row, which completely changed. + */ + public static final String TABLE_COMPARE_CHANGED_GUID_ROW_CELL_LABEL = "tableGuidChangeRowCell"; + + /** + * Label for first cell of table row, which completely changed. + */ + public static final String TABLE_COMPARE_TABLE_ROW_FIRST_CELL_LABEL = "tableCompareTableRowFirstCell"; + + /** + * Label for last cell of table row, which completely changed. + */ + public static final String TABLE_COMPARE_TABLE_ROW_LAST_CELL_LABEL = "tableCompareTableRowLastCell"; + + /** + * Label for cell of the table row, which completely changed. + */ + public static final String TABLE_COMPARE_TABLE_ROW_CELL_LABEL = "tableCompareTableRowCell"; + + /** + * Label for Topological Cell + */ + public static final String TABLE_TOPOLOGICAL_CELL = "topologicalCell"; + + /** + * The tolerance value between TOP_Kante length and the sum of GEO_Kanten + * length, which belong to this TOP_Kante (in Meter) + */ + public static final double TOP_GEO_LENGTH_TOLERANCE = 0.01; + + static { + DEFAULT_HOME_DIR = "./"; + TMP_BASE_DIR = System.getProperty(ToolboxProperties.TMP_BASE_DIR, + DEFAULT_HOME_DIR); + } } diff --git a/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/graph/TopPath.java b/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/graph/TopPath.java index 184f7f0d99..7f6bed6587 100644 --- a/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/graph/TopPath.java +++ b/java/bundles/org.eclipse.set.basis/src/org/eclipse/set/basis/graph/TopPath.java @@ -13,6 +13,7 @@ import java.math.BigDecimal; import java.util.List; import java.util.Optional; +import java.util.stream.IntStream; import org.apache.commons.lang3.Range; import org.eclipse.set.model.planpro.Geodaten.TOP_Kante; @@ -28,24 +29,6 @@ public class TopPath { private final BigDecimal firstEdgeLength; private final TopPoint startNode; - /** - * @param edges - * ordered list of edges for this path - * @param length - * the total length of the path. may be less than the total - * length of the edges if the path does not cover the full extent - * of the edges - * @param firstEdgeLength - * the length of the first edge - */ - public TopPath(final List edges, final BigDecimal length, - final BigDecimal firstEdgeLength) { - this.edges = edges; - this.length = length; - this.firstEdgeLength = firstEdgeLength; - this.startNode = determineStartNode(); - } - /** * @param edges * ordered list of edges for this path @@ -64,39 +47,6 @@ public TopPath(final List edges, final BigDecimal length, this.firstEdgeLength = determintFirstEdgeLength(); } - private TopPoint determineStartNode() { - try { - final TOP_Kante firstEdge = edges.getFirst(); - final BigDecimal edgeLength = firstEdge.getTOPKanteAllg() - .getTOPLaenge() - .getWert(); - // When the first edge length is ZERO, then should the start node - // lie at TOP_Knoten_A or TOP_Knoten_B - if (firstEdgeLength.compareTo(BigDecimal.ZERO) == 0) { - if (edges.size() == 1) { - if (length.compareTo(firstEdgeLength) != 0) { - throw new IllegalArgumentException(); - } - - return new TopPoint(firstEdge, - edgeLength.subtract(firstEdgeLength)); - } - final TOP_Knoten connectTopKnoten = getConnectTopKnoten( - firstEdge, edges.get(1)); - final BigDecimal distance = firstEdge.getIDTOPKnotenA() - .getValue() == connectTopKnoten ? BigDecimal.ZERO - : edgeLength; - return new TopPoint(firstEdge, distance); - } - - return new TopPoint(firstEdge, - edgeLength.subtract(firstEdgeLength)); - } catch (final Exception e) { - throw new IllegalArgumentException( - "Can\'t find start node of TopPath"); //$NON-NLS-1$ - } - } - private BigDecimal determintFirstEdgeLength() { try { final TOP_Kante firstEdge = edges.getFirst(); @@ -108,15 +58,9 @@ private BigDecimal determintFirstEdgeLength() { } final TOP_Knoten connectTopKnoten = getConnectTopKnoten(firstEdge, edges.get(1)); - final BigDecimal connectTopKnotenDistance = connectTopKnoten == firstEdge - .getIDTOPKnotenA() - .getValue() ? BigDecimal.ZERO : edgeLength; - // When the start node lie at TOP_Knoten_A or TOP_Knoten_B, then the - // first edge length is ZERO - if (startNode.distance().compareTo(connectTopKnotenDistance) == 0) { - return BigDecimal.ZERO; - } - return edgeLength.subtract(startNode.distance()); + return connectTopKnoten == firstEdge.getIDTOPKnotenA().getValue() + ? startNode.distance() + : edgeLength.subtract(startNode.distance()); } catch (final Exception e) { throw new IllegalArgumentException( "Can\'t find first edge length of TopPath"); //$NON-NLS-1$ @@ -166,6 +110,20 @@ public BigDecimal firstEdgeLength() { return firstEdgeLength; } + /** + * @param another + * @return + */ + public boolean isSamePath(final TopPath another) { + return length.compareTo(another.length) == 0 + && firstEdgeLength.compareTo(another.firstEdgeLength) == 0 + && startNode == another.startNode + && edges().size() == another.edges().size() + && IntStream.range(0, edges.size()) + .allMatch(index -> edges.get(index) == another.edges + .get(index)); + } + /** * @param point * a point to find the distance for @@ -256,5 +214,4 @@ private Optional getDistanceOnFirstEdge(final TopPoint point, return Optional .of(point.distance().subtract(startNode.distance()).abs()); } - } diff --git a/java/bundles/org.eclipse.set.core.services/src/org/eclipse/set/core/services/graph/TopologicalGraphService.java b/java/bundles/org.eclipse.set.core.services/src/org/eclipse/set/core/services/graph/TopologicalGraphService.java index 67b60b5a60..cd622973e1 100644 --- a/java/bundles/org.eclipse.set.core.services/src/org/eclipse/set/core/services/graph/TopologicalGraphService.java +++ b/java/bundles/org.eclipse.set.core.services/src/org/eclipse/set/core/services/graph/TopologicalGraphService.java @@ -47,7 +47,7 @@ List findAllPathsBetween(final TopPoint from, final TopPoint to, * the condition * @return the path, which satisfy the condition */ - TopPath findPathBetween(final TopPoint from, final TopPoint to, int limit, + TopPath findShortestPathBetween(final TopPoint from, final TopPoint to, int limit, Predicate condition); /** @@ -98,4 +98,20 @@ Optional findShortestDistance(final TopPoint from, */ Optional findClosestPoint(final TopPoint from, final List points, final boolean searchInTopDirection); + + /** + * @param from + * the start point + * @param to + * the end point + * @param inTopDirection + * the direction + * @return the shortest in direction path between from and to or empty if no + * path is found + */ + Optional findShortesPathInDirection(final TopPoint from, + final TopPoint to, final boolean inTopDirection); + + List findAllPathsBetween(TopPoint from, TopPoint to, int limit, + boolean inCludeIncompletePath); } diff --git a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sskp/SskpTransformator.xtend b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sskp/SskpTransformator.xtend index bd56440098..166f68f8c2 100644 --- a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sskp/SskpTransformator.xtend +++ b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sskp/SskpTransformator.xtend @@ -14,6 +14,7 @@ import org.eclipse.set.core.services.enumtranslation.EnumTranslationService import org.eclipse.set.core.services.graph.TopologicalGraphService import org.eclipse.set.feature.table.pt1.AbstractPlanPro2TableModelTransformator import org.eclipse.set.model.planpro.Ansteuerung_Element.Stell_Bereich +import org.eclipse.set.model.planpro.BasisTypen.ENUMWirkrichtung import org.eclipse.set.model.planpro.Basisobjekte.Basis_Objekt import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt import org.eclipse.set.model.planpro.Fahrstrasse.Fstr_DWeg @@ -29,7 +30,6 @@ import org.eclipse.set.model.tablemodel.ColumnDescriptor import org.eclipse.set.model.tablemodel.TableRow import org.eclipse.set.ppmodel.extensions.container.MultiContainer_AttributeGroup import org.eclipse.set.ppmodel.extensions.utils.Case -import org.eclipse.set.ppmodel.extensions.utils.TopGraph import org.eclipse.set.utils.math.AgateRounding import org.eclipse.set.utils.table.TMFactory import org.osgi.service.event.EventAdmin @@ -64,8 +64,7 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { new(Set cols, EnumTranslationService enumTranslationService, - TopologicalGraphService topGraphService, - EventAdmin eventAdmin) { + TopologicalGraphService topGraphService, EventAdmin eventAdmin) { super(cols, enumTranslationService, eventAdmin) this.topGraphService = topGraphService } @@ -73,7 +72,6 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { override transformTableContent(MultiContainer_AttributeGroup container, TMFactory factory, Stell_Bereich controlArea) { - val topGraph = new TopGraph(container.TOPKante) for (PZB_Element pzb : container.PZBElement.filter[isPlanningObject]. filterObjectsInControlArea(controlArea).filter [ PZBElementGUE?.IDPZBElementMitnutzung?.value === null @@ -92,11 +90,11 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { if (!isPZB2000 || fstrDwegs.nullOrEmpty || pzb.PZBElementGM === null) { val instance = rg.newTableRow() - fillRowGroupContent(instance, pzb, null, topGraph) + fillRowGroupContent(instance, pzb, null) } else { pzb?.fstrDWegs?.forEach [ val instance = rg.newTableRow() - fillRowGroupContent(instance, pzb, it, topGraph) + fillRowGroupContent(instance, pzb, it) ] } } @@ -105,7 +103,7 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { } private def fillRowGroupContent(TableRow instance, PZB_Element pzb, - Fstr_DWeg dweg, TopGraph topGraph) { + Fstr_DWeg dweg) { // A: Sskp.Bezug.BezugsElement fillIterable( instance, @@ -311,7 +309,7 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { pzb, [ PZBElementBezugspunkt.filterNull.map [ - getDistanceSignalTrackSwitch(topGraph, pzb, it) + getDistanceSignalTrackSwitch(pzb, it) ] ], null @@ -610,26 +608,30 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { static dispatch def String fillBezugsElement(Signal object) { return object.signalReal.signalFunktion.wert === ENUMSignalFunktion.ENUM_SIGNAL_FUNKTION_BUE_UEBERWACHUNGSSIGNAL - ? '''BÜ-K «object?.bezeichnung?.bezeichnungTabelle?.wert»''' - : object?.bezeichnung?.bezeichnungTabelle?.wert + ? '''BÜ-K «object?.bezeichnung?.bezeichnungTabelle?.wert»''' : object?. + bezeichnung?.bezeichnungTabelle?.wert } - private dispatch def String getDistanceSignalTrackSwitch(TopGraph topGraph, + private dispatch def String getDistanceSignalTrackSwitch( PZB_Element pzb, Basis_Objekt object) { throw new IllegalArgumentException(object.class.simpleName) } - private dispatch def String getDistanceSignalTrackSwitch(TopGraph topGraph, + private dispatch def String getDistanceSignalTrackSwitch( PZB_Element pzb, Signal signal) { if (signal?.signalReal?.signalFunktion?.wert !== ENUMSignalFunktion.ENUM_SIGNAL_FUNKTION_BUE_UEBERWACHUNGSSIGNAL) { val distance = AgateRounding.roundDown( getPointsDistance(pzb, signal).min) - val directionSign = topGraph. - isInWirkrichtungOfSignal(signal, pzb) ? "+" : "-" - return distance == 0 - ? distance.toString - : '''«directionSign»«distance.toString»''' + val inDirectionPath = topGraphService.findShortesPathInDirection( + new TopPoint(signal), new TopPoint(pzb), + signal.singlePoint.wirkrichtung.wert == + ENUMWirkrichtung.ENUM_WIRKRICHTUNG_IN || + signal.singlePoint.wirkrichtung.wert == + ENUMWirkrichtung.ENUM_WIRKRICHTUNG_BEIDE) + val directionSign = inDirectionPath.isPresent ? "+" : "-" + return distance == 0 ? distance. + toString : '''«directionSign»«distance.toString»''' } val bueSpezifischesSignal = signal.container.BUESpezifischesSignal. @@ -654,7 +656,7 @@ class SskpTransformator extends AbstractPlanPro2TableModelTransformator { } - private dispatch def String getDistanceSignalTrackSwitch(TopGraph topGraph, + private dispatch def String getDistanceSignalTrackSwitch( PZB_Element pzb, W_Kr_Gsp_Element gspElement) { val gspKomponent = gspElement.WKrGspKomponenten.filter [ zungenpaar !== null diff --git a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/ssld/SsldTransformator.xtend b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/ssld/SsldTransformator.xtend index 562729d68b..d6832e10a8 100644 --- a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/ssld/SsldTransformator.xtend +++ b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/ssld/SsldTransformator.xtend @@ -17,13 +17,13 @@ import org.eclipse.set.core.services.enumtranslation.EnumTranslationService import org.eclipse.set.core.services.graph.TopologicalGraphService import org.eclipse.set.feature.table.pt1.AbstractPlanPro2TableModelTransformator import org.eclipse.set.model.planpro.Ansteuerung_Element.Stell_Bereich +import org.eclipse.set.model.planpro.BasisTypen.ENUMWirkrichtung import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt import org.eclipse.set.model.planpro.Fahrstrasse.Fstr_DWeg import org.eclipse.set.model.planpro.Signale.Signal import org.eclipse.set.model.tablemodel.ColumnDescriptor import org.eclipse.set.ppmodel.extensions.container.MultiContainer_AttributeGroup import org.eclipse.set.ppmodel.extensions.utils.Case -import org.eclipse.set.ppmodel.extensions.utils.TopGraph import org.eclipse.set.utils.table.TMFactory import org.osgi.service.event.EventAdmin @@ -68,14 +68,42 @@ class SsldTransformator extends AbstractPlanPro2TableModelTransformator { ].filter[present].map[get].minBy[length] } - def String getFreigemeldetLaenge(Fstr_DWeg dweg, TopGraph topGraph, - BigDecimal maxLength) { + def String getFreigemeldetLaenge(Fstr_DWeg dweg, BigDecimal maxLength) { val startSignal = dweg?.fstrFahrweg?.start - val fmas = dweg?.fmaAnlageFreimeldung?.map[fmaGrenzen]?.flatten.toSet. - filter[topGraph.isInWirkrichtungOfSignal(startSignal, it)].toList - val pathFromSignalToFMA = fmas?.map [ - it -> getShortestPath(dweg?.fstrFahrweg?.start, it) - ] + val startSignalTopPoint = new TopPoint(startSignal) + val signalDirection = startSignal.singlePoint?.wirkrichtung?.wert + val isInTopDirection = signalDirection === + ENUMWirkrichtung.ENUM_WIRKRICHTUNG_IN || + signalDirection === ENUMWirkrichtung.ENUM_WIRKRICHTUNG_BEIDE +// if (startSignal.identitaet.wert == +// "B843A0A5-C717-11ED-9412-8932A423E144") { +// +// val topGraph = new TopGraph(dweg.container.TOPKante) +// val test = dweg?.fmaAnlageFreimeldung?.map[fmaGrenzen].flatten.toSet +// val fmas = test.filter [ +// topGraph.isInWirkrichtungOfSignal(startSignal, it) +// ].toList +// val pathFromSignalToFma = fmas.map [ +// it -> getShortestPath(dweg.fstrFahrweg.start, it) +// ] +// val relevant = pathFromSignalToFma.filter[dweg.isRelevantFma(key, value)].toList +// +// val test1 = test.map [ +// it -> +// topGraphService. +// findShortesPathInDirection(startSignalTopPoint, +// new TopPoint(it), isInTopDirection) +// ].filter[value.isPresent].map[key -> value.get].toList +// val releavan = test1.filter[dweg.isRelevantFma(key, value)].toList +// println("TEST") +// } + val fmaGrenzen = dweg?.fmaAnlageFreimeldung?.map[fmaGrenzen].flatten. + toSet + val pathFromSignalToFMA = fmaGrenzen.map [ + it -> + topGraphService.findShortesPathInDirection(startSignalTopPoint, + new TopPoint(it), isInTopDirection) + ].filter[value.isPresent].map[key -> value.get].toList if (pathFromSignalToFMA.isEmpty) { return "" } @@ -111,7 +139,6 @@ class SsldTransformator extends AbstractPlanPro2TableModelTransformator { TMFactory factory, Stell_Bereich controlArea ) { - val topGraph = new TopGraph(container.TOPKante) val fstDwegList = container.fstrDWeg.filter[isPlanningObject]. filterObjectsInControlArea(controlArea) @@ -206,7 +233,7 @@ class SsldTransformator extends AbstractPlanPro2TableModelTransformator { instance, cols.getColumn(Freigemeldet), dweg, - [getFreigemeldetLaenge(topGraph, fstrFahrWegLength)] + [getFreigemeldetLaenge(fstrFahrWegLength)] ) // J: Ssld.Eigenschaften.massgebende_Neigung @@ -324,7 +351,7 @@ class SsldTransformator extends AbstractPlanPro2TableModelTransformator { dweg, [fstrDWegSpezifisch !== null], [ - getZielGleisAbschnittLength(topGraph) + getZielGleisAbschnittLength ] ) @@ -347,18 +374,25 @@ class SsldTransformator extends AbstractPlanPro2TableModelTransformator { return factory.table } - private def String getZielGleisAbschnittLength(Fstr_DWeg dweg, - TopGraph topGraph) { + private def String getZielGleisAbschnittLength(Fstr_DWeg dweg) { val startSignal = dweg?.fstrFahrweg?.start + val startSignalTopPoint = new TopPoint(startSignal) + val isInTopDirection = #[ENUMWirkrichtung.ENUM_WIRKRICHTUNG_IN, + ENUMWirkrichtung.ENUM_WIRKRICHTUNG_BEIDE].exists [ + it === startSignal.singlePoint?.wirkrichtung?.wert + ] val fmaAnlage = dweg.fstrDWegSpezifisch?.IDFMAAnlageZielgleis?.value // The relevant FMA shouldn't lie on direction of start signal - val fmaKomponenten = fmaAnlage.fmaGrenzen.filter [ - !topGraph.isInWirkrichtungOfSignal(startSignal, it) - ].toList - val pathsFromSignalToFMA = fmaKomponenten.map [ - startSignal.getShortestPath(it) - ] - +// val fmaKomponenten = fmaAnlage.fmaGrenzen.filter [ +// !topGraph.isInWirkrichtungOfSignal(startSignal, it) +// ].toList +// val pathsFromSignalToFMA = fmaKomponenten.map [ +// startSignal.getShortestPath(it) +// ] + val pathsFromSignalToFMA = fmaAnlage.fmaGrenzen.map [ + topGraphService.findShortesPathInDirection(startSignalTopPoint, + new TopPoint(it), isInTopDirection) + ].filter[isPresent].map[get] val fstrs = dweg.fstrZugRangier val relevantPaths = fstrs.empty // if no fstrs we take all paths to any of the fmaKomponenten diff --git a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sszs/SszsTransformator.xtend b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sszs/SszsTransformator.xtend index f3bc4a10fd..171d8d4a13 100644 --- a/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sszs/SszsTransformator.xtend +++ b/java/bundles/org.eclipse.set.feature.table.pt1/src/org/eclipse/set/feature/table/pt1/sszs/SszsTransformator.xtend @@ -743,7 +743,7 @@ class SszsTransformator extends AbstractPlanPro2TableModelTransformator { IDSignal?.value ].filterNull.filter [ signal | predicates.forall[apply(signal)] && - topGraph.isInWirkrichtungOfSignal(refSignal, signal) + topGraphService.isInWirkrichtungOfSignal(refSignal, signal) ].filter [ sourceSignal.distanceToSignal(it) < MAX_TOP_DISTANCE_IN_METER ].toList @@ -775,7 +775,7 @@ class SszsTransformator extends AbstractPlanPro2TableModelTransformator { if (distances.compareTo(BigDecimal.ZERO) == 0) { return fma -> 0.0 } - return topGraph.isInWirkrichtungOfSignal(signal, fma) + return topGraphService.isInWirkrichtungOfSignal(signal, fma) ? fma -> distances.doubleValue : fma -> -distances.doubleValue ].filterNull diff --git a/java/bundles/org.eclipse.set.feature.table.test/META-INF/MANIFEST.MF b/java/bundles/org.eclipse.set.feature.table.test/META-INF/MANIFEST.MF index 04f29936f0..608bebd9e3 100644 --- a/java/bundles/org.eclipse.set.feature.table.test/META-INF/MANIFEST.MF +++ b/java/bundles/org.eclipse.set.feature.table.test/META-INF/MANIFEST.MF @@ -10,9 +10,11 @@ Require-Bundle: org.hamcrest.core;bundle-version="1.3.0" Bundle-Vendor: Eclipse Signalling Engineering Toolbox Import-Package: net.bytebuddy.agent.builder;version="[1.17.0,2.0.0)", net.bytebuddy.agent.utility.nullability;version="[1.17.0,2.0.0)", + org.eclipse.set.unittest.utils, org.eclipse.set.utils.table.sorting, org.junit.jupiter.api, org.junit.jupiter.api.function, + org.junit.jupiter.params.provider;version="[5.12.0,6.0.0)", org.mockito;version="[5.18.0,6.0.0)", org.mockito.stubbing;version="[5.18.0,6.0.0)" Export-Package: org.eclipse.set.feature.table.diff, diff --git a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/BereichObjektExtensions.xtend b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/BereichObjektExtensions.xtend index 8748bc288a..a0240b6234 100644 --- a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/BereichObjektExtensions.xtend +++ b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/BereichObjektExtensions.xtend @@ -12,9 +12,15 @@ import java.math.BigDecimal import java.util.Collection import java.util.List import java.util.Set +import org.apache.commons.lang3.Range import org.eclipse.core.runtime.Assert +import org.eclipse.emf.ecore.util.EcoreUtil import org.eclipse.set.basis.graph.DirectedEdge import org.eclipse.set.basis.graph.DirectedEdgePath +import org.eclipse.set.basis.graph.TopPath +import org.eclipse.set.basis.graph.TopPoint +import org.eclipse.set.core.services.graph.TopologicalGraphService +import org.eclipse.set.model.planpro.Ansteuerung_Element.Stell_Bereich import org.eclipse.set.model.planpro.Basisobjekte.Bereich_Objekt import org.eclipse.set.model.planpro.Basisobjekte.Bereich_Objekt_Teilbereich_AttributeGroup import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt @@ -32,10 +38,6 @@ import static extension org.eclipse.set.ppmodel.extensions.TopKanteExtensions.* import static extension org.eclipse.set.ppmodel.extensions.TopKnotenExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.CollectionExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.Debug.* -import org.eclipse.emf.ecore.util.EcoreUtil -import org.apache.commons.lang3.Range -import org.eclipse.set.model.planpro.Ansteuerung_Element.Stell_Bereich -import org.eclipse.set.basis.graph.TopPoint /** * Extensions for {@link Bereich_Objekt}. @@ -149,6 +151,30 @@ class BereichObjektExtensions extends BasisObjektExtensions { return new TopKantePath(bereich, s.unique, e.unique) } + def static TopPath getPath(Bereich_Objekt bereich, Punkt_Objekt start, + Punkt_Objekt end, TopologicalGraphService topGraphService) { + val s = bereich.intersection(start) + val e = bereich.intersection(end) + if (s.empty) { + logger.error( + '''start: topKante=«start.topKanten.unique.identitaet.wert» abstand=«start.singlePoint.abstand.wert»''' + ) + logger. + error('''bereichObjektTeilbereich: «bereich.bereichObjektTeilbereich.debugString»''') + throw new IllegalArgumentException('''Startsignal «start.debugString» not in Bereich «bereich.debugName»''') + } + if (e.empty) { + throw new IllegalArgumentException('''Zielelement «end.debugString» not in Bereich «bereich.debugName»''') + } +// val maxLength = bereich.bereichObjektTeilbereich.map[length].reduce[p1, p2| p1 + p2] +// val allPaths = topGraphService.findAllPathsBetween(new TopPoint(start), new TopPoint(end), maxLength.intValue + 10).toList +// val test = allPaths.filter[edges.size == bereich.bereichObjektTeilbereich.size +// ].filter[topPath | +// topPath.edges.forall[edge| bereich.bereichObjektTeilbereich.exists[botb | botb.IDTOPKante.value == edge]] +// ].toList + return topGraphService.findShortestPath(new TopPoint(start), new TopPoint(end)).orElse(null) + } + /** * @param bereich this Bereichsobjekt * diff --git a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/DwegExtensions.xtend b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/DwegExtensions.xtend index bc816812fa..bc377d4386 100644 --- a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/DwegExtensions.xtend +++ b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/DwegExtensions.xtend @@ -88,7 +88,10 @@ class DwegExtensions extends BasisObjektExtensions { val fahrweg = dweg?.fstrFahrweg val endFarhwegPotk = fahrweg?.zielPunktObjekt.punktObjektTOPKante val topEndFahrweg = fahrweg?.zielPunktObjekt?.topKanten - + val test1 = fma.topKanten.exists[topEndFahrweg.contains(it)] + val test2 = endFarhwegPotk.exists [ + pathToFma.getDistance(new TopPoint(it)).isPresent + ] return fma.topKanten.exists[topEndFahrweg.contains(it)] || endFarhwegPotk.exists [ pathToFma.getDistance(new TopPoint(it)).isPresent diff --git a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/FahrwegExtensions.xtend b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/FahrwegExtensions.xtend index efef2ffe84..81ecc1f4ed 100644 --- a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/FahrwegExtensions.xtend +++ b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/FahrwegExtensions.xtend @@ -62,6 +62,9 @@ import static extension org.eclipse.set.ppmodel.extensions.utils.CacheUtils.* import static extension org.eclipse.set.ppmodel.extensions.utils.CollectionExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.Debug.* import static extension org.eclipse.set.utils.graph.DirectedEdgeExtensions.* +import org.eclipse.set.basis.graph.TopPath +import org.eclipse.set.core.services.graph.TopologicalGraphService +import org.eclipse.set.ppmodel.extensions.utils.TopGraph /** * Extensions for {@link Fstr_Fahrweg}. @@ -325,6 +328,17 @@ class FahrwegExtensions extends BereichObjektExtensions { Fstr_Fahrweg fahrweg) { return fahrweg.getPath(fahrweg.start, fahrweg.zielPunktObjekt) } + + /** + * @param fahrweg this Fahrweg + * + * @return the path of this Fahrweg + */ + def static TopPath getPath( + Fstr_Fahrweg fahrweg, TopologicalGraphService topGraphService) { + return fahrweg.getPath(fahrweg.start, fahrweg.zielPunktObjekt, topGraphService) + } + /** * @param fahrweg this Fahrweg diff --git a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/SignalExtensions.xtend b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/SignalExtensions.xtend index 5eae79ca36..5468723290 100644 --- a/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/SignalExtensions.xtend +++ b/java/bundles/org.eclipse.set.ppmodel.extensions/src/org/eclipse/set/ppmodel/extensions/SignalExtensions.xtend @@ -14,6 +14,8 @@ import java.util.List import java.util.Set import org.eclipse.core.runtime.Assert import org.eclipse.set.basis.graph.Digraphs +import org.eclipse.set.basis.graph.TopPoint +import org.eclipse.set.core.services.graph.TopologicalGraphService import org.eclipse.set.model.planpro.Ansteuerung_Element.Stell_Bereich import org.eclipse.set.model.planpro.Ansteuerung_Element.Stellelement import org.eclipse.set.model.planpro.Ansteuerung_Element.Unterbringung @@ -36,7 +38,6 @@ import org.eclipse.set.model.planpro.Signale.Signal_Rahmen import org.eclipse.set.model.planpro.Signale.Signal_Signalbegriff import org.eclipse.set.model.planpro.Weichen_und_Gleissperren.W_Kr_Gsp_Element import org.eclipse.set.ppmodel.extensions.utils.DirectedTopKante -import org.eclipse.set.ppmodel.extensions.utils.TopGraph import org.eclipse.set.ppmodel.extensions.utils.TopRouting import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -44,8 +45,8 @@ import org.slf4j.LoggerFactory import static org.eclipse.set.model.planpro.Ansteuerung_Element.ENUMAussenelementansteuerungArt.* import static org.eclipse.set.model.planpro.BasisTypen.ENUMWirkrichtung.* import static org.eclipse.set.model.planpro.Signale.ENUMSignalFunktion.* +import static org.eclipse.set.ppmodel.extensions.geometry.GEOKanteGeometryExtensions.* -import static extension org.eclipse.set.basis.graph.Digraphs.* import static extension org.eclipse.set.ppmodel.extensions.AussenelementansteuerungExtensions.* import static extension org.eclipse.set.ppmodel.extensions.BereichObjektExtensions.* import static extension org.eclipse.set.ppmodel.extensions.FahrwegExtensions.* @@ -59,7 +60,6 @@ import static extension org.eclipse.set.ppmodel.extensions.StellelementExtension import static extension org.eclipse.set.ppmodel.extensions.TopKanteExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.CollectionExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.Debug.* -import static extension org.eclipse.set.ppmodel.extensions.geometry.GEOKanteGeometryExtensions.* import static extension org.eclipse.set.utils.math.BigDecimalExtensions.* /** @@ -162,13 +162,16 @@ class SignalExtensions extends PunktObjektExtensions { signalbegriffe.containsSignalbegriffID(Zs3v) } - def static boolean isInWirkrichtungOfSignal(TopGraph topGraph, - Signal signal, Punkt_Objekt object) { - return topGraph.isInWirkrichtungOfSignal(signal, object.singlePoints) + def static boolean isInWirkrichtungOfSignal( + TopologicalGraphService topGraphService, Signal signal, + Punkt_Objekt object) { + return topGraphService.isInWirkrichtungOfSignal(signal, + object.singlePoints) } - def static boolean isInWirkrichtungOfSignal(TopGraph topGraph, - Signal signal, TOP_Kante topKante) { + def static boolean isInWirkrichtungOfSignal( + TopologicalGraphService topGraphService, Signal signal, + TOP_Kante topKante) { if (signal.topKanten.exists[it === topKante]) { return false } @@ -182,36 +185,22 @@ class SignalExtensions extends PunktObjektExtensions { topKante.getAbstand(topKante.TOPKnotenB, p1) < topKante.getAbstand(topKante.TOPKnotenB, p2) ? p1 : p2 ] - return topGraph.isInWirkrichtungOfSignal(signal, + return topGraphService.isInWirkrichtungOfSignal(signal, List.of(punktNearstA)) && - topGraph.isInWirkrichtungOfSignal(signal, List.of(punkNearstB)) + topGraphService.isInWirkrichtungOfSignal(signal, + List.of(punkNearstB)) } - def static boolean isInWirkrichtungOfSignal(TopGraph topGraph, - Signal signal, List potks) { + def static boolean isInWirkrichtungOfSignal( + TopologicalGraphService topGraphService, Signal signal, + List potks) { // Find path from the signal to point object - val relevantPaths = topGraph.getPaths(signal.singlePoints, potks). - flatMap[edges] - if (relevantPaths.isNullOrEmpty) { - return false - } - - // The path must start the TOP_Kante of the signal and have same direction like the signal - return relevantPaths.filter[signal.topKanten.contains(element)].forall [ - val wirkrichtung = signal.getWirkrichtung(element) - if (wirkrichtung === null) { - return isForwards - } - switch (wirkrichtung) { - case ENUM_WIRKRICHTUNG_IN: - return isForwards == true - case ENUM_WIRKRICHTUNG_BEIDE_VALUE: - return true - case ENUM_WIRKRICHTUNG_GEGEN: - return isForwards == false - default: - throw new IllegalArgumentException() - } + val isInTopDirection = #[ENUM_WIRKRICHTUNG_IN, ENUM_WIRKRICHTUNG_BEIDE]. + exists[it === signal.singlePoint?.wirkrichtung?.wert] + val startPoint = new TopPoint(signal) + return potks.forall [ + topGraphService.findShortesPathInDirection(startPoint, + new TopPoint(it), isInTopDirection).isPresent ] } @@ -463,7 +452,8 @@ class SignalExtensions extends PunktObjektExtensions { Stell_Bereich controlArea) { val stellElement = signal.stellelement if (stellElement?.IDEnergie?.value.isBelongToControlArea(controlArea) || - stellElement?.IDInformation?.value.isBelongToControlArea(controlArea)) { + stellElement?.IDInformation?.value. + isBelongToControlArea(controlArea)) { return true } val existsFiktivesSignalFAPStart = signal.signalFiktiv !== null && diff --git a/java/bundles/org.eclipse.set.unittest.utils/res/NB_Test_Info__2025-10-16_16-35.planpro b/java/bundles/org.eclipse.set.unittest.utils/res/NB_Test_Info__2025-10-16_16-35.planpro new file mode 100644 index 0000000000..373d2a52a3 Binary files /dev/null and b/java/bundles/org.eclipse.set.unittest.utils/res/NB_Test_Info__2025-10-16_16-35.planpro differ diff --git a/java/bundles/org.eclipse.set.unittest.utils/src/org/eclipse/set/unittest/utils/AbstractToolboxTest.java b/java/bundles/org.eclipse.set.unittest.utils/src/org/eclipse/set/unittest/utils/AbstractToolboxTest.java index 3200576910..b2314b735e 100644 --- a/java/bundles/org.eclipse.set.unittest.utils/src/org/eclipse/set/unittest/utils/AbstractToolboxTest.java +++ b/java/bundles/org.eclipse.set.unittest.utils/src/org/eclipse/set/unittest/utils/AbstractToolboxTest.java @@ -71,6 +71,10 @@ public class AbstractToolboxTest { public static String PPHN_1_10_0_1_20220517_PPXML = getModel( "PPHN_1.10.0.1_01-02_Ibn-Z._-_2._AeM_2022-05-17_13-44_tg2.ppxml"); //$NON-NLS-1$ + public static String NB_Test_Info_2025_10_16_16_35 = + + getModel("NB_Test_Info__2025-10-16_16-35.planpro"); + private static final String UNZIP_DIR = "res/toolbox"; //$NON-NLS-1$ private static final String CONTENT_MODEL = "content"; //$NON-NLS-1$ private static final String LAYOUT_MODEL = "layout"; //$NON-NLS-1$ diff --git a/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/AsDirectedTopGraph.java b/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/AsDirectedTopGraph.java index 820f616652..6603279046 100644 --- a/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/AsDirectedTopGraph.java +++ b/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/AsDirectedTopGraph.java @@ -13,7 +13,6 @@ import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.LinkedList; @@ -36,7 +35,6 @@ * Helper class to convert an undirected graph of top edges to a directed graph */ public class AsDirectedTopGraph { - /** * Helper record for providing a TOP_Kante with a direction * @@ -96,15 +94,15 @@ public static Graph> asDirectedTopGraph( * condition for the relevant path * @return the path */ - public static TopPath getPath(final AsSplitTopGraph graph, + public static TopPath getShortestPath(final AsSplitTopGraph graph, final TopPoint from, final TopPoint to, final int maxPathWeight, final Predicate relevantCondition) { final Node startNode = graph.splitGraphAt(from); final Node endNode = graph.splitGraphAt(to); final Graph> directedTopGraph = AsDirectedTopGraph .asDirectedTopGraph(graph); - return getPath(directedTopGraph, startNode, endNode, maxPathWeight, - relevantCondition); + return getShortestPath(directedTopGraph, startNode, endNode, + maxPathWeight, relevantCondition); } /** @@ -123,7 +121,7 @@ public static TopPath getPath(final AsSplitTopGraph graph, * condition for the relevant path * @return the path */ - public static TopPath getPath( + public static TopPath getShortestPath( final Graph> graph, final Node startNode, final Node endNode, final int maxPathWeight, final Predicate relevantCondition) { @@ -150,10 +148,10 @@ public static TopPath getPath( final DirectedPathSearch path = new DirectedPathSearch(graph, startNode, endNode, maxPathWeight); path.addEdge(edge); - final List topPaths = getPath(path, - relevantEdgesFromTarget, relevantCondition, false); - if (!topPaths.isEmpty()) { - return topPaths.getFirst(); + final TopPath topPath = getShortestPath(path, + relevantEdgesFromTarget, relevantCondition); + if (topPath != null) { + return topPath; } } return null; @@ -176,6 +174,28 @@ public static TopPath getPath( */ public static List getAllPaths(final AsSplitTopGraph graph, final TopPoint from, final TopPoint to, final int maxPathWeight) { + return getAllPaths(graph, from, to, maxPathWeight, true); + } + + /** + * Find all paths from two {@link Node}. When the path length greater than + * the max path weight, then break find process + * + * @param graph + * the graph + * @param from + * the start point + * @param to + * the end point + * @param maxPathWeight + * max weight of path + * @param includeIncompletePath + * should include incomplete path or not + * @return the list of path + */ + public static List getAllPaths(final AsSplitTopGraph graph, + final TopPoint from, final TopPoint to, final int maxPathWeight, + final boolean includeIncompletePath) { final Node startNode = graph.splitGraphAt(from); final Node endNode = graph.splitGraphAt(to); final Graph> directedTopGraph = AsDirectedTopGraph @@ -190,24 +210,30 @@ public static List getAllPaths(final AsSplitTopGraph graph, return List.of(topPath); } } + + final List> relevantEdgesFromTarget = findRelevantEdgesFromTarget( + directedTopGraph, endNode, maxPathWeight); final List result = new ArrayList<>(); for (final DirectedTOPEdge edge : directedTopGraph .outgoingEdgesOf(startNode)) { final DirectedPathSearch path = new DirectedPathSearch( directedTopGraph, startNode, endNode, maxPathWeight); path.addEdge(edge); - final List topPath = getPath(path, Collections.emptyList(), - null, true); - result.addAll(topPath); + final List topPath = getPaths(path, + relevantEdgesFromTarget, includeIncompletePath); + topPath.forEach(newPath -> { + if (result.stream().noneMatch(p -> p.isSamePath(newPath))) { + result.add(newPath); + } + }); } return result; } - private static List getPath( + private static List getPaths( final DirectedPathSearch incompletePath, final List> relevantEdgesFromTarget, - final Predicate relevantCondition, final boolean includeIncompletePath) { final List result = new ArrayList<>(); final Deque incompletePaths = new LinkedList<>(); @@ -220,15 +246,10 @@ private static List getPath( final Node lastNode = graph.getEdgeTarget(lastEdge); for (final DirectedTOPEdge edge : graph .outgoingEdgesOf(lastNode)) { - if (!includeIncompletePath) { - final TopPath shortesPath = getShortesPath(incompletePaths, - path, edge, relevantEdgesFromTarget, - relevantCondition); - if (shortesPath != null) { - return List.of(shortesPath); - } - } else { - getAllPaths(result, incompletePaths, path, edge); + if (relevantEdgesFromTarget.contains(edge) + && path.isRelevantPathWeight(edge.edge().getWeight())) { + getAllPaths(result, incompletePaths, path, edge, + includeIncompletePath); } } @@ -236,6 +257,30 @@ private static List getPath( return result; } + private static TopPath getShortestPath( + final DirectedPathSearch incompletePath, + final List> relevantEdgesFromTarget, + final Predicate relevantCondition) { + final Deque incompletePaths = new LinkedList<>(); + incompletePaths.add(incompletePath); + final Graph> graph = incompletePath.graph(); + // Walkthrough graph to find relevant path + for (DirectedPathSearch path; (path = incompletePaths + .poll()) != null;) { + final DirectedTOPEdge lastEdge = path.path().getLast(); + final Node lastNode = graph.getEdgeTarget(lastEdge); + for (final DirectedTOPEdge edge : graph + .outgoingEdgesOf(lastNode)) { + final TopPath shortesPath = getShortesPath(incompletePaths, + path, edge, relevantEdgesFromTarget, relevantCondition); + if (shortesPath != null) { + return shortesPath; + } + } + } + return null; + } + private static TopPath getShortesPath( final Deque incompletePaths, final DirectedPathSearch path, final DirectedTOPEdge edge, @@ -263,7 +308,8 @@ private static TopPath getShortesPath( private static void getAllPaths(final List result, final Deque incompletePaths, - final DirectedPathSearch path, final DirectedTOPEdge edge) { + final DirectedPathSearch path, final DirectedTOPEdge edge, + final boolean includeIncompletePath) { final DirectedPathSearch newPath = path.clonePath(); if (!newPath.addEdge(edge)) { return; @@ -275,7 +321,7 @@ private static void getAllPaths(final List result, } if (newPath.isRelevantPathLength()) { incompletePaths.addFirst(newPath); - } else { + } else if (includeIncompletePath) { result.add(newPath.getTopPath(null, true)); } } @@ -325,10 +371,13 @@ private static List> findRelevantEdgesFromTarget( // When another edge exists, which is shorter than found edge, // replace the weight - remainingWeigthFromEnd.computeIfPresent(edgeSource, - (k, v) -> remainingWeight.compareTo(v) > 0 - ? remainingWeight - : v); + remainingWeigthFromEnd.computeIfPresent(edgeSource, (k, v) -> { + if (remainingWeight.compareTo(v) > 0) { + nodesToProcess.add(edgeSource); + return remainingWeight; + } + return v; + }); } } assert nodesToProcess.isEmpty(); diff --git a/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/DirectedPathSearch.java b/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/DirectedPathSearch.java index 32f7cbd951..78927f3e99 100644 --- a/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/DirectedPathSearch.java +++ b/java/bundles/org.eclipse.set.utils/src/org/eclipse/set/utils/graph/DirectedPathSearch.java @@ -237,15 +237,15 @@ private static TopPath pathTransform( "Path not start from source node"); //$NON-NLS-1$ } - final BigDecimal firstEdgeLength = firstEdge.edge().getWeight(); return new TopPath( path.getEdgeList() .stream() .map(e -> e.edge()) .distinct() .map(Edge::edge) + .distinct() .toList(), - getDirectedPathWeight(path), firstEdgeLength); + getDirectedPathWeight(path), startNode.point()); } private static BigDecimal getDirectedPathWeight(