All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rinde.rinsim.examples.demo.swarm.SwarmDemo Maven / Gradle / Ivy

/*
 * Copyright (C) 2011-2017 Rinde van Lon, imec-DistriNet, KU Leuven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.rinde.rinsim.examples.demo.swarm;

import java.util.List;

import javax.measure.unit.NonSI;
import javax.measure.unit.SI;

import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.RandomGenerator;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;

import com.github.rinde.rinsim.core.Simulator;
import com.github.rinde.rinsim.core.model.road.MovingRoadUser;
import com.github.rinde.rinsim.core.model.road.RoadModel;
import com.github.rinde.rinsim.core.model.road.RoadModelBuilders;
import com.github.rinde.rinsim.core.model.time.TickListener;
import com.github.rinde.rinsim.core.model.time.TimeLapse;
import com.github.rinde.rinsim.geom.Point;
import com.github.rinde.rinsim.ui.View;
import com.github.rinde.rinsim.ui.renderers.PlaneRoadModelRenderer;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;

/**
 * @author Rinde van Lon
 *
 */
public final class SwarmDemo {

  static final int FONT_SIZE = 24;
  static final double FONT_SPACING = 30d;
  static final long RANDOM_SEED = 123L;
  static final int SPEED_UP = 8;
  static final Point MIN_POINT = new Point(0, 0);
  static final Point MAX_POINT = new Point(6000, 1000);
  static final double MAX_SPEED = 1000d;
  static final int WHITE_THRESHOLD = (int) Math.pow(2, 24) / 2 - 1;

  static final Rectangle MEASURE_RECT = new Rectangle(0, 0, 100, 10);

  private SwarmDemo() {}

  /**
   * Starts the demo.
   * @param args No args.
   */
  public static void main(String[] args) {
    final String string =
      "KU Leuven Computer Science\nimec-DistriNet AgentWise";
    final List points =
      measureString(string, FONT_SIZE, FONT_SPACING, 0);

    double maxX = MAX_POINT.x;
    double maxY = MAX_POINT.y;

    for (final Point p : points) {
      maxX = Math.max(p.x, maxX);
      maxY = Math.max(p.y, maxY);
    }
    final Point max = new Point(maxX, maxY);

    final RandomGenerator rng = new MersenneTwister(RANDOM_SEED);
    final Simulator sim = Simulator.builder()
      .addModel(RoadModelBuilders.plane()
        .withMinPoint(MIN_POINT)
        .withMaxPoint(max)
        .withDistanceUnit(SI.METER)
        .withSpeedUnit(NonSI.KILOMETERS_PER_HOUR)
        .withMaxSpeed(MAX_SPEED))
      .addModel(
        View.builder()
          .with(PlaneRoadModelRenderer.builder())
          .with(VehicleRenderer.builder())
          .with(DemoPanel.builder(string))
          .withSpeedUp(SPEED_UP))
      .build();

    for (final Point p : points) {
      sim.register(new Vehicle(p, rng));
    }
    sim.start();
  }

  /**
   * Measures the specified string using the specified font size.
   * @param string The string to measure.
   * @param fontSize The fontsize to use.
   * @param spacing The spacing between the points.
   * @param vCorrection The vertical correction for all the points.
   * @return A list of points, each point represents a pixel in the measured
   *         string.
   */
  public static ImmutableList measureString(String string, int fontSize,
      double spacing, int vCorrection) {
    if (string.trim().isEmpty()) {
      return ImmutableList.of();
    }
    final String stringToDraw = string;

    Display display = Display.getDefault();
    boolean haveToDispose = false;
    if (display == null) {
      display = new Display();
      haveToDispose = true;
    }

    final GC measureGC = new GC(new Image(display, MEASURE_RECT));
    final Font initialFont = measureGC.getFont();
    final FontData[] fontData = initialFont.getFontData();
    for (int i = 0; i < fontData.length; i++) {
      fontData[i].setHeight(fontSize);
    }
    final Font newFont = new Font(display, fontData);
    measureGC.setFont(newFont);

    final org.eclipse.swt.graphics.Point extent = measureGC
      .textExtent(stringToDraw);
    measureGC.dispose();

    final Image image = new Image(display, extent.x, extent.y);
    final GC gc = new GC(image);
    gc.setFont(newFont);

    gc.setForeground(new Color(display, new RGB(0, 0, 0)));
    gc.drawText(stringToDraw, 0, 0);

    final ImmutableList.Builder coordinateBuilder = ImmutableList
      .builder();
    for (int i = 0; i < image.getBounds().width; i++) {
      for (int j = vCorrection; j < image.getBounds().height; j++) {
        final int color = image.getImageData().getPixel(i, j);
        if (color < WHITE_THRESHOLD) {
          coordinateBuilder.add(new Point(i * spacing, (j - vCorrection)
            * spacing));
        }
      }
    }
    final ImmutableList points = coordinateBuilder.build();

    image.dispose();
    if (haveToDispose) {
      display.dispose();
    }
    return points;
  }

  static final class Vehicle implements MovingRoadUser, TickListener {
    static final int LB = 30;
    static final double MUL = 40;

    Point destPos;
    RandomGenerator rng;

    double speed;
    boolean active;
    private Optional rm;

    Vehicle(Point p, RandomGenerator r) {
      destPos = p;
      rng = r;
      active = true;
      rm = Optional.absent();
    }

    @Override
    public void initRoadUser(RoadModel model) {
      final Point startPos = model.getRandomPosition(rng);
      model.addObjectAt(this, startPos);

      rm = Optional.of(model);
      setDestination(destPos);
    }

    @Override
    public double getSpeed() {
      return speed;
    }

    @Override
    public void tick(TimeLapse timeLapse) {
      rm.get().moveTo(this, destPos, timeLapse);
    }

    @Override
    public void afterTick(TimeLapse timeLapse) {}

    /**
     * Change the destination of the vehicle.
     * @param dest The new destination.
     */
    public void setDestination(Point dest) {
      active = true;
      doSetDestination(dest);
    }

    private void doSetDestination(Point dest) {
      destPos = dest;
      speed = Point.distance(rm.get().getPosition(this), destPos)
        / (LB + MUL * rng.nextDouble());
    }

    /**
     * Moves the vehicle to a point on the border of the plane.
     */
    public void setInactive() {
      if (active) {
        active = false;
        final List bounds = rm.get().getBounds();
        final Point p = rm.get().getRandomPosition(rng);
        if (rng.nextBoolean()) {
          doSetDestination(new Point(bounds.get(rng.nextInt(2)).x, p.y));
        } else {
          doSetDestination(new Point(p.x, bounds.get(rng.nextInt(2)).y));
        }
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy