content: /* amodeus - Copyright (c) 2018, ETH Zurich, Institute for Dynamic Systems and Control */
  package amodeus.amodeus.prep;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.matsim.api.core.v01.network.Link;
  import org.matsim.api.core.v01.network.Network;
  import org.matsim.api.core.v01.network.Node;
  import org.matsim.api.core.v01.population.Population;
  import org.matsim.core.network.NetworkUtils;
  import org.matsim.core.utils.collections.QuadTree;
  
  import amodeus.amodeus.dispatcher.util.TensorLocation;
  import amodeus.amodeus.util.geo.FastQuadTree;
  import amodeus.amodeus.util.math.GlobalAssert;
  import amodeus.amodeus.util.network.NodeAdjacencyMap;
  import amodeus.amodeus.virtualnetwork.CentroidVirtualNetworkCreator;
  import amodeus.amodeus.virtualnetwork.core.VirtualNetwork;
  
  /** This is a demo of functionality for the centroid virtual network creator, centroid locations
   * are placed on a half ring structure... */
  public class MatsimRingCentroidVirtualNetworkCreator {
  
      public static VirtualNetwork<Link> createVirtualNetwork(Population population, Network network, int numVNodes, //
              boolean completeGraph) {
          @SuppressWarnings("unchecked")
          Collection<Link> elements = (Collection<Link>) network.getLinks().values();
          Map<Node, Set<Link>> uElements = NodeAdjacencyMap.of(network);
  
          /** generating centroids on a ring */
          List<Link> centroids = getRingCentroids(network, numVNodes);
  
          /** create the virtual network using the centroidvirtualNetworkCreator */
          CentroidVirtualNetworkCreator<Link, Node> vnc = new CentroidVirtualNetworkCreator<>(//
                  elements, centroids, TensorLocation::of, NetworkCreatorUtils::linkToID, uElements, completeGraph);
          return vnc.getVirtualNetwork();
      }
  
      private static List<Link> getRingCentroids(Network network, int numVNodes) {
          List<Link> centroids = new ArrayList<>();
          double[] bounds = NetworkUtils.getBoundingBox(network.getNodes().values()); // minX, minY, maxX, maxY
          QuadTree<Link> quadTree = FastQuadTree.of(network);
  
          // center location
          double centerX = bounds[0] + 0.5 * (bounds[2] - bounds[0]);
          double centerY = bounds[1] + 0.5 * (bounds[3] - bounds[1]);
  
          double radius = 0.5 * Math.min(bounds[2] - bounds[0], bounds[3] - bounds[1]);
          centroids.add(quadTree.getClosest(centerX, centerY));
  
          for (int count = 1; count < numVNodes; ++count) {
              double arg = count / (numVNodes - 1.0) * 2 * Math.PI;
              double posX = centerX + radius * Math.cos(arg);
              double posY = centerY + radius * Math.sin(arg);
              Link closest = quadTree.getClosest(posX, posY);
              centroids.add(closest);
          }
          GlobalAssert.that(centroids.size() == numVNodes);
          return centroids;
      }
  }
  