Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(charging): provide the charging stations within a certain area #446

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ buildNumber.properties
*.log
credentials.cached
*.lcs
.tiles
.tiles
/logs/
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.mosaic.fed.application.ambassador.simulation.TrafficLightGroupUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.TrafficManagementCenterUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.communication.ReceivedV2xMessage;
import org.eclipse.mosaic.fed.application.ambassador.simulation.electric.providers.ChargingStationIndex;
import org.eclipse.mosaic.fed.application.ambassador.simulation.navigation.CentralNavigationComponent;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.CentralPerceptionComponent;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.DefaultLidarSensorModule;
Expand Down Expand Up @@ -55,6 +56,7 @@
import org.eclipse.mosaic.interactions.traffic.VehicleUpdates;
import org.eclipse.mosaic.interactions.trafficsigns.VehicleSeenTrafficSignsUpdate;
import org.eclipse.mosaic.interactions.vehicle.VehicleRouteRegistration;
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.objects.electricity.ChargingStationData;
import org.eclipse.mosaic.lib.objects.environment.EnvironmentEvent;
import org.eclipse.mosaic.lib.objects.traffic.InductionLoopInfo;
Expand Down Expand Up @@ -158,6 +160,12 @@ public ApplicationAmbassador(AmbassadorParameter ambassadorParameter) {
SimulationKernel.SimulationKernel.setCentralPerceptionComponent(centralPerceptionComponent);
}

if (SimulationKernel.SimulationKernel.chargingStationIndex == null) {
// use same bucketsize as TrafficLightTree (see: CPercetion.java) (bucketsize := number of direct children per tree node)
ChargingStationIndex chargingStationIndex = new ChargingStationIndex(20);
SimulationKernel.SimulationKernel.setChargingStationIndex(chargingStationIndex);
}

// add all application jar files
addJarFiles();
}
Expand Down Expand Up @@ -368,6 +376,9 @@ private void process(final ServerRegistration serverRegistration) {

private void process(final ChargingStationRegistration chargingStationRegistration) {
UnitSimulator.UnitSimulator.registerChargingStation(chargingStationRegistration);
String id = chargingStationRegistration.getMapping().getName();
GeoPoint position = chargingStationRegistration.getMapping().getPosition();
SimulationKernel.SimulationKernel.chargingStationIndex.addChargingStation(id, position);
}

private void process(final TrafficLightRegistration trafficLightRegistration) {
Expand Down Expand Up @@ -449,6 +460,8 @@ private void process(final ChargingStationUpdate chargingStationUpdate) {
final AbstractSimulationUnit simulationUnit =
UnitSimulator.UnitSimulator.getUnitFromId(chargingStationData.getName());

SimulationKernel.SimulationKernel.chargingStationIndex.updateChargingStation(chargingStationUpdate.getUpdatedChargingStation());

if (simulationUnit == null) {
return;
}
Expand All @@ -458,6 +471,7 @@ private void process(final ChargingStationUpdate chargingStationUpdate) {
chargingStationData,
EventNicenessPriorityRegister.UPDATE_CHARGING_STATION
);

addEvent(event);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public enum ErrorRegister {
SIMULATION_KERNEL_CentralNavigationComponentAlreadySet(0x01000029, "The CentralNavigationComponent was already set."),
SIMULATION_KERNEL_CentralPerceptionComponentNotSet(0x01000200, "The CentralPerceptionComponent was not set."),
SIMULATION_KERNEL_CentralPerceptionComponentAlreadySet(0x01000201, "The CentralPerceptionComponent was already set."),
SIMULATION_KERNEL_ChargingStationIndexAlreadySet(0x01000202, "The ChargingStationIndex was already set"),
SIMULATION_KERNEL_ChargingStationIndexNotSet(0x01000203, "The ChargingStationIndex was not set"),

// 0x01000030 to 0x0100003F unit simulator
UNIT_SIMULATOR_IdAlreadyAssigned(0x01000030, "The id is already assigned."),
UNIT_SIMULATOR_IdFromUnitIsNotInMap(0x01000031, "The unit with the id couldn't be found."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.eclipse.mosaic.fed.application.ambassador;

import org.eclipse.mosaic.fed.application.ambassador.simulation.AbstractSimulationUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.electric.providers.ChargingStationIndex;
import org.eclipse.mosaic.fed.application.ambassador.simulation.navigation.CentralNavigationComponent;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.CentralPerceptionComponent;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.EnvironmentBasicSensorModule;
Expand Down Expand Up @@ -94,6 +95,8 @@ public enum SimulationKernel {
*/
transient CentralPerceptionComponent centralPerceptionComponent;

transient ChargingStationIndex chargingStationIndex;

/**
* Map containing all the routes with the corresponding edge-id's.
*/
Expand Down Expand Up @@ -259,6 +262,21 @@ public void setCentralPerceptionComponent(CentralPerceptionComponent centralPerc
this.centralPerceptionComponent = centralPerceptionComponent;
}

public void setChargingStationIndex(ChargingStationIndex chargingStationIndex) {
if (this.chargingStationIndex != null) {
throw new RuntimeException(ErrorRegister.SIMULATION_KERNEL_ChargingStationIndexAlreadySet.toString());
}

this.chargingStationIndex = chargingStationIndex;
}

public ChargingStationIndex getChargingStationIndex() {
if (this.chargingStationIndex == null) {
throw new RuntimeException(ErrorRegister.SIMULATION_KERNEL_ChargingStationIndexNotSet.toString());
}

return this.chargingStationIndex;
}
public CentralPerceptionComponent getCentralPerceptionComponent() {
if (centralPerceptionComponent == null) {
throw new RuntimeException(ErrorRegister.SIMULATION_KERNEL_CentralPerceptionComponentNotSet.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@
package org.eclipse.mosaic.fed.application.ambassador.simulation;

import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.ambassador.simulation.electric.objects.ChargingStationObject;
import org.eclipse.mosaic.fed.application.app.api.ElectricVehicleApplication;
import org.eclipse.mosaic.fed.application.app.api.os.ElectricVehicleOperatingSystem;
import org.eclipse.mosaic.interactions.electricity.VehicleChargingDenial;
import org.eclipse.mosaic.interactions.electricity.VehicleChargingStartRequest;
import org.eclipse.mosaic.interactions.electricity.VehicleChargingStopRequest;
import org.eclipse.mosaic.lib.geo.GeoCircle;
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.objects.electricity.ChargingStationData;
import org.eclipse.mosaic.lib.objects.vehicle.BatteryData;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleType;

import java.util.List;
import java.util.stream.Collectors;

/**
* This class represents an electric vehicle in the application simulator. It extends {@link VehicleUnit}
* with further functionality.
Expand Down Expand Up @@ -103,4 +109,10 @@ public void sendChargingStopRequest() {
);
sendInteractionToRti(vehicleChargingStopRequest);
}

public List<ChargingStationData> getChargingStationsInArea(GeoCircle searchArea) {
return SimulationKernel.SimulationKernel.getChargingStationIndex().getChargingStationsInCircle(searchArea)
.stream().map(ChargingStationObject::getChargingStationData)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2025 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: mosaic@fokus.fraunhofer.de
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.electric.objects;

import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.PointBoundingBox;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObjectBoundingBox;
import org.eclipse.mosaic.lib.geo.CartesianPoint;
import org.eclipse.mosaic.lib.objects.electricity.ChargingStationData;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class ChargingStationObject extends SpatialObject<ChargingStationObject> {
/**
* The data object that stores all static and dynamic information of the charging station.
*/
private ChargingStationData chargingStationData;

/**
* The bounding box of a charging station is represented by a single point.
*/
private transient PointBoundingBox boundingBox;

public ChargingStationObject(String id) {
super(id);
}

public ChargingStationObject setChargingStationData(ChargingStationData chargingStationData) {
this.chargingStationData = chargingStationData;
return this;
}

public ChargingStationData getChargingStationData() {
return chargingStationData;
}

@Override
public ChargingStationObject setPosition(CartesianPoint position) {
cartesianPosition.set(position);
position.toVector3d(this);
return this;
}

@Override
public SpatialObjectBoundingBox getBoundingBox() {
if (boundingBox == null) {
boundingBox = new PointBoundingBox(this);
}
return boundingBox;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}

if (o == null || getClass() != o.getClass()) {
return false;
}

ChargingStationObject that = (ChargingStationObject) o;

return new EqualsBuilder()
.appendSuper(super.equals(o))
.append(chargingStationData, that.chargingStationData)
.append(boundingBox, that.boundingBox)
.isEquals();
}

@Override
public int hashCode() {
return new HashCodeBuilder(5, 11)
.appendSuper(super.hashCode())
.append(chargingStationData)
.toHashCode();
}

/**
* Returns a hard copy of the {@link ChargingStationObject}, this should be used
* when the data of a perceived traffic light is to be altered or stored in memory.
*
* @return a copy of the {@link ChargingStationObject}
*/
@Override
public ChargingStationObject copy() {
return new ChargingStationObject(getId())
.setChargingStationData(chargingStationData)
.setPosition(getProjectedPosition());

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2025 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: mosaic@fokus.fraunhofer.de
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.electric.providers;

import org.eclipse.mosaic.fed.application.ambassador.simulation.electric.objects.ChargingStationObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObjectAdapter;
import org.eclipse.mosaic.lib.geo.GeoCircle;
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.objects.electricity.ChargingStationData;
import org.eclipse.mosaic.lib.spatial.KdTree;
import org.eclipse.mosaic.lib.spatial.SpatialTreeTraverser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ChargingStationIndex {

private final int bucketSize;

/**
* Stores {@link ChargingStationObject}s for fast removal and position update.
*/
final Map<String, ChargingStationObject> indexedChargingStations = new HashMap<>();

private KdTree<ChargingStationObject> chargingStationTree;

private SpatialTreeTraverser.InRadius<ChargingStationObject> treeTraverser;

public ChargingStationIndex(int bucketSize) {
this.bucketSize = bucketSize;
}

/**
* Method called to initialize index after configuration has been read.
*/
public void initialize() {
// initialization at first update
}

public void addChargingStation(String id, GeoPoint position) {
indexedChargingStations.computeIfAbsent(id, ChargingStationObject::new)
.setPosition(position.toCartesian());
}

/**
* Perform action before an update of the {@link ChargingStationIndex} takes place.
*/
public void updateChargingStation(ChargingStationData chargingStationData) {
onChargingStationUpdate();
indexedChargingStations.get(chargingStationData.getName())
.setChargingStationData(chargingStationData);
}

public List<ChargingStationObject>getChargingStationsInCircle(GeoCircle circle) {
treeTraverser.setup(circle.getCenter().toVector3d(), circle.getRadius());
treeTraverser.traverse(chargingStationTree);
return treeTraverser.getResult();
}

public void onChargingStationUpdate() {
if (chargingStationTree == null) { // initialize before first update is called
List<ChargingStationObject> allChargingStations = new ArrayList<>(indexedChargingStations.values());
chargingStationTree = new KdTree<>(new SpatialObjectAdapter<>(), allChargingStations, bucketSize);
treeTraverser = new SpatialTreeTraverser.InRadius<>();
}
}

public int getNumberOfChargingStations() {
return chargingStationTree.getRoot().size();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@

package org.eclipse.mosaic.fed.application.app.api.os;

import org.eclipse.mosaic.lib.geo.GeoCircle;
import org.eclipse.mosaic.lib.objects.electricity.ChargingStationData;
import org.eclipse.mosaic.lib.objects.vehicle.BatteryData;

import java.util.List;
import javax.annotation.Nullable;

/**
Expand Down Expand Up @@ -45,4 +48,11 @@ public interface ElectricVehicleOperatingSystem extends VehicleOperatingSystem {
* Sends a request to stop charging the battery of the vehicle.
*/
void sendChargingStopRequest();

/**
* Locate all charging stations in the provided area.
*
* @param searchArea The area where the charging stations are searched
*/
List<ChargingStationData> getChargingStationsInArea(GeoCircle searchArea);
}
Loading
Loading