Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion java/bundles/org.eclipse.set.application.test/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes>
<attribute name="module" value="true"/>
Expand Down
15 changes: 13 additions & 2 deletions java/bundles/org.eclipse.set.application.test/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,16 @@ 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: net.bytebuddy;version="[1.17.0,2.0.0)",
net.bytebuddy.agent;version="[1.17.0,2.0.0)",
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)",
org.mockito;version="[5.18.0,6.0.0)",
org.mockito.plugins;version="[5.18.0,6.0.0)",
org.mockito.stubbing;version="[5.18.0,6.0.0)",
org.objenesis;version="[3.4.0,4.0.0)"
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/**
* 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.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.eclipse.set.application.cacheservice.CacheServiceImpl;
import org.eclipse.set.basis.constants.ContainerType;
import org.eclipse.set.basis.files.ToolboxFileRole;
import org.eclipse.set.basis.graph.TopPoint;
import org.eclipse.set.core.services.Services;
import org.eclipse.set.core.services.cache.CacheService;
import org.eclipse.set.core.services.graph.TopologicalGraphService;
import org.eclipse.set.model.planpro.Basisobjekte.Punkt_Objekt;
import org.eclipse.set.model.planpro.PlanPro.PlanPro_Schnittstelle;
import org.eclipse.set.ppmodel.extensions.PlanProSchnittstelleExtensions;
import org.eclipse.set.ppmodel.extensions.container.MultiContainer_AttributeGroup;
import org.eclipse.set.ppmodel.extensions.utils.TopGraph;
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.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import com.google.common.collect.Streams;

/**
* Test {@link TopologicalGraphServiceImpl} with PlanPro file
*
* @author truong
*/
@SuppressWarnings("nls")
public class TopologicalGraphServiceTest extends AbstractToolboxTest {

TopologicalGraphService testee;
TopGraph topGraph;
MultiContainer_AttributeGroup container;
CacheService cachService;

void givenTopologicalGraphService() throws Exception {
testee = new TopologicalGraphServiceImpl();
final Map<PlanPro_Schnittstelle, WeightedPseudograph<Node, Edge>> topGraphBase = new HashMap<>();
final WeightedPseudograph<Node, Edge> 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 multiContainer = PlanProSchnittstelleExtensions
.getContainer(planProSchnittstelle, type);
addContainerGraph.invoke(testee, pseudograph, multiContainer);
}
topGraphBase.put(planProSchnittstelle, pseudograph);
FieldUtils.writeField(testee, "topGraphBaseMap", topGraphBase, true);
}

void givenFinalContainer() {
container = PlanProSchnittstelleExtensions
.getContainer(planProSchnittstelle, ContainerType.FINAL);
}

void givenTopGraph() {
topGraph = new TopGraph(container.getTOPKante());
}

void givenCacheService() {
cachService = new CacheServiceImpl() {
@Override
protected ToolboxFileRole getSessionRole(
final PlanPro_Schnittstelle schnittStelle) {
return ToolboxFileRole.SESSION;
}
};
}

@Test
void testFindShortedDistanceInDirection() throws Exception {
try (MockedStatic<Services> mockServices = Mockito
.mockStatic(Services.class)) {
setupTest(mockServices);
// 60L113X -> 60ZU21
// Signal 60L113X is "gegen" topological direction
final Optional<BigDecimal> testDistance1 = testee
.findShortestDistanceInDirection(
getTopPoint("43634A33-76AD-441C-8585-838C8528E2E6"),
getTopPoint("BDB6CEAF-57F9-419D-8540-93B76EF686AD"),
false);

assertTrue(testDistance1.isPresent());
assertEquals(testDistance1.get(), BigDecimal.valueOf(844.465));

final Optional<BigDecimal> testDistance2 = testee
.findShortestDistanceInDirection(
getTopPoint("43634A33-76AD-441C-8585-838C8528E2E6"),
getTopPoint("BDB6CEAF-57F9-419D-8540-93B76EF686AD"),
true);
assertFalse(testDistance2.isPresent());

// 60AA -> 60P1
// Signal 60AA is "in" topological direction
final Optional<BigDecimal> testDistance3 = testee
.findShortestDistanceInDirection(
getTopPoint("67BE8406-9D49-437D-98FF-D878941DF2F4"),
getTopPoint("C10AB78B-EA5E-44BA-BAC3-AB3B3D6C503C"),
true);
// It given't relevant path from 60AA -> 60P1
assertFalse(testDistance3.isPresent());

}
}

private TopPoint getTopPoint(final String guid) {
final Punkt_Objekt punkObjekt = Streams
.stream(container.getPunktObjekts())
.filter(po -> po.getIdentitaet().getWert().equals(guid))
.findFirst()
.orElse(null);
if (punkObjekt == null) {
throw new NullPointerException();
}
return new TopPoint(punkObjekt);
}

private void setupTest(final MockedStatic<Services> mockServices)
throws Exception {
givenCacheService();
mockServices.when(Services::getCacheService).thenReturn(cachService);
givenPlanProFile(getTestFile());
givenTopologicalGraphService();
mockServices.when(Services::getTopGraphService).thenReturn(testee);
givenFinalContainer();
givenTopGraph();
}

private static String getTestFile() {
return PPHN_1_10_0_3_20220517_PLANPRO;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Boolean existCache(final PlanPro_Schnittstelle schnittstelle,
return existCache(getSessionRole(schnittstelle), cacheID);
}

private ToolboxFileRole getSessionRole(
protected ToolboxFileRole getSessionRole(
final PlanPro_Schnittstelle schnittStelle) {
final Map<ToolboxFileRole, IModelSession> loadedSessions = sessionService
.getLoadedSessions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
import static org.eclipse.set.ppmodel.extensions.MultiContainer_AttributeGroupExtensions.getPlanProSchnittstelle;

import java.math.BigDecimal;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -33,6 +35,7 @@
import org.eclipse.set.model.planpro.Geodaten.TOP_Kante;
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;
Expand Down Expand Up @@ -162,19 +165,8 @@ public TopPath findPathBetween(final TopPoint from, final TopPoint to,
public Optional<BigDecimal> findShortestDistanceInDirection(
final TopPoint from, final TopPoint to,
final boolean searchInTopDirection) {
final MultiContainer_AttributeGroup container = getContainer(
from.edge());
final PlanPro_Schnittstelle planProSchnittstelle = getPlanProSchnittstelle(
container);
final AsSplitTopGraph graphView = new AsSplitTopGraph(
getTopGraphBase(planProSchnittstelle));
final Node fromNode = graphView.splitGraphAt(from,
Boolean.valueOf(searchInTopDirection));
final Node toNode = graphView.splitGraphAt(to);

return Optional.ofNullable( //
findPathBetween(graphView, fromNode, toNode))
.map(p -> getPathWeight(p));
return findShortestPathInDirection(from, to, searchInTopDirection)
.map(TopPath::length);
}

@Override
Expand All @@ -199,12 +191,60 @@ public Optional<TopPath> findShortestPath(final TopPoint from,
.toList(), getPathWeight(p), from));
}

@Override
public Optional<TopPath> findShortestPathInDirection(final TopPoint from,
final TopPoint to, final boolean inTopDirection) {
// Fall the both of point lie on same TOP_Kante
if (from.edge() == to.edge()) {
final BigDecimal distance = from.distance().subtract(to.distance());
return distance.doubleValue() < 0 == inTopDirection
? Optional.of(new TopPath(List.of(from.edge()),
distance.abs(), distance.abs()))
: Optional.empty();
}
final MultiContainer_AttributeGroup container = getContainer(
from.edge());
final PlanPro_Schnittstelle planProSchnittstelle = getPlanProSchnittstelle(
container);
final AsSplitTopGraph graphView = new AsSplitTopGraph(
getTopGraphBase(planProSchnittstelle));

final Node fromNode = graphView.splitGraphAt(from,
Boolean.valueOf(inTopDirection));
final Node toNode = graphView.splitGraphAt(to);
final Optional<BigDecimal> shortestDistance = findShortestDistance(from,
to);

if (shortestDistance.isEmpty()) {
return Optional.empty();
}

final TopPath path = AsDirectedTopGraph.getPath(
AsDirectedTopGraph.asDirectedTopGraph(graphView), fromNode,
toNode, shortestDistance.get().intValue() + 500, topPath -> {
final Deque<TOP_Kante> edges = new LinkedList<>(
topPath.edges());
TOP_Kante current = edges.poll();
while (!edges.isEmpty()) {
final TOP_Kante next = edges.poll();

if (!TopKanteExtensions.isRoute(next, current)) {
return false;
}
current = next;
}
return true;
});
return Optional.ofNullable(path);
}

private static GraphPath<AsSplitTopGraph.Node, AsSplitTopGraph.Edge> findPathBetween(
final AsSplitTopGraph graphView, final Node fromNode,
final Node toNode) {
try {
return DijkstraShortestPath.findPathBetween(graphView, fromNode,
toNode);

} catch (final IllegalArgumentException ex) {
if (ex.getMessage().equals("Negative edge weight not allowed")) { //$NON-NLS-1$
throw new IllegalArgumentException("Invalid spot location", ex); //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ Optional<BigDecimal> findShortestDistance(final TopPoint from,
*/
Optional<TopPath> findShortestPath(final TopPoint from, final TopPoint to);

/**
* @param from
* starting point to search from
* @param to
* end point to search toward
* @param inTopDirection
* is in topological direction
* @return the optional of {@link TopPath} in direction of start point
*/
Optional<TopPath> findShortestPathInDirection(TopPoint from, TopPoint to,
boolean inTopDirection);

/**
* Finds the closest point of a set
*
Expand Down
Loading
Loading