/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see .
*
*/
package de.tud.kom.p2psim.impl.topology.movement.local;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint3D;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor.RouteSegmentListener;
/**
* This class contains one trajectory from a start to a destination. It saves
* the respective points (coordinates) along the path with a given movement
* speed and also (if enabled) the assigned IDs of the roads and walkways that
* are traversed.
*
* TODO add segment handling
*
* Segment handling is only done if there is a segment listener registered for
* the respective client.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 9, 2017
*/
public class RouteImpl implements Route {
private PositionVector start;
private PositionVector destination;
private PointList pointList;
private final List positionsList;
private final List routeSegments;
private final Set segmentListeners;
private int currentIndex;
private int currentSegmentIndex;
private int routeLength;
private int routeSegmentsLength;
/**
*
* @param start
* @param destination
* @param pointList
* @param segmentListeners
* @param routeSegments
*/
public RouteImpl(PositionVector start,
PositionVector destination, PointList pointList,
Set segmentListeners,
List routeSegments) {
this.start = start;
this.destination = destination;
this.pointList = pointList;
this.positionsList = new LinkedList<>();
// Create Position vectors ONCE
for (GHPoint3D temp : pointList) {
positionsList
.add(RealWorldStreetsMovement.transformGPSWindowToOwnWorld(
temp.getLat(), temp.getLon()));
}
routeLength = positionsList.size();
this.segmentListeners = segmentListeners;
this.routeSegments = routeSegments;
this.routeSegmentsLength = routeSegments.size();
}
/**
*
* @param start
* @param destination
* @param pointList
*/
public RouteImpl(PositionVector start,
PositionVector destination, PointList pointList) {
this(start, destination, pointList, Collections.emptySet(),
Collections.emptyList());
}
public PositionVector getStart() {
return start;
}
public PositionVector getDestination() {
return destination;
}
@Override
public Location getTargetLocation() {
return destination;
}
@Override
public boolean hasSegmentInformation() {
return routeSegmentsLength != 0;
}
@Override
public RouteSegment getCurrentSegment() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return routeSegments.get(currentSegmentIndex);
}
@Override
public List getSegmentsAhead() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return Collections.unmodifiableList(routeSegments
.subList(currentSegmentIndex, routeSegmentsLength));
}
@Override
public List getSegmentsBehind() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return Collections.unmodifiableList(routeSegments
.subList(0, currentSegmentIndex));
}
/**
* Update the internal location with the given movement speed
*
* @param speed
* @param realPosition
* @return
*/
public PositionVector updateCurrentLocation(SimLocationActuator comp,
double speed, double tolerance) {
List sublist = positionsList.subList(currentIndex,
routeLength);
PositionVector newPosition = null;
for (PositionVector candidate : sublist) {
newPosition = comp.getRealPosition().moveStep(candidate, speed);
if (candidate.distanceTo(comp.getRealPosition()) < tolerance) {
currentIndex++;
} else {
break;
}
}
/*
* TODO Segment handling (also inform listeners!)
*/
return newPosition;
}
@Override
public String toString() {
return "\n\tfrom " + start.toString() + " to " + destination.toString()
+ "\n\tstep: " + currentIndex + " length: " + routeLength;
}
public PointList getPointList() {
return pointList;
}
public int getCurrentIndex() {
return this.currentIndex;
}
}