/*
* Copyright (c) 2005-2015 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.modularosm;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
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.movement.local.AbstractLocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionProvider;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.NodeVisInteractionListener;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
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.Route.RouteSegment;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/**
* Visualization Component of the Attraction Points in the Modular Movement
* Model.
*
*
* @author Martin Hellwig, Bjoern Richerzhagen
* @version 1.0, 02.07.2015
*/
public class ModularMovementModelViz extends JComponent
implements VisualizationComponent, NodeVisInteractionListener {
protected ModularMovementModel movementModel;
protected boolean showAttractionPoints = true;
protected boolean showNodePositions = false;
protected boolean showTrajectories = false;
protected boolean setupCalculatesTrajectories = false;
private JMenu menu;
private Map trajectoryVisualizations = new LinkedHashMap<>();
private final static int NODE_SIZE = 2;
private final static int ATTR_SIZE = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public ModularMovementModelViz() {
init();
}
protected void init() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
VisualizationInjector.addInteractionListener(this);
setOpaque(true);
setVisible(true);
menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions());
menu.add(createCheckboxTrajectories());
}
public ModularMovementModelViz(ModularMovementModel model) {
init();
this.movementModel = model;
}
private JCheckBoxMenuItem createCheckboxAp() {
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show attraction points", showAttractionPoints);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showAttractionPoints = checkBox.isSelected();
VisualizationInjector.invalidate();
}
});
return checkBox;
}
private JCheckBoxMenuItem createCheckboxNodePositions() {
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show node positions", showNodePositions);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showNodePositions = checkBox.isSelected();
VisualizationInjector.invalidate();
}
});
return checkBox;
}
private JCheckBoxMenuItem createCheckboxTrajectories() {
setupCalculatesTrajectories = AbstractLocalMovementStrategy.isCalculatingRouteSegments();
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show node trajectories", showTrajectories);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showTrajectories = checkBox.isSelected();
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
VisualizationInjector.invalidate();
}
});
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
return checkBox;
}
public static LinkedList paths = new LinkedList();
@Override
public void paint(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints) {
drawAttractionPoints(g2);
}
if (showNodePositions) {
for (SimLocationActuator comp : movementModel
.getAllLocationActuators()) {
drawNodePosition(g2, comp);
}
}
if (showTrajectories) {
for (TrajectoryVis tVis : trajectoryVisualizations.values()) {
tVis.drawTrajectory(g2);
}
}
if(this.movementModel.getLocalMovementStrategy() instanceof RealWorldStreetsMovement) {
RealWorldStreetsMovement mov = (RealWorldStreetsMovement) this.movementModel.getLocalMovementStrategy();
if(mov.getBlockedAreas() != null && !mov.getBlockedAreas().isEmpty()) {
g2.setColor(new Color(1f, 0f, 0f, 0.5f));
String[] split = mov.getBlockedAreas().split(";");
for (String s : split) {
String[] vals = s.split(",");
PositionVector p1 = GPSCalculation.transformGPSWindowToOwnWorld(Double.parseDouble(vals[0]), Double.parseDouble(vals[1]));
PositionVector p2 = GPSCalculation.transformGPSWindowToOwnWorld(Double.parseDouble(vals[2]), Double.parseDouble(vals[3]));
g2.fillRect(VisualizationInjector.scaleValue(p1.getX()), VisualizationInjector.scaleValue(p1.getY()),
VisualizationInjector.scaleValue(p2.getX()) - VisualizationInjector.scaleValue(p1.getX()),
VisualizationInjector.scaleValue(p2.getY())- VisualizationInjector.scaleValue(p1.getY()));
}
}
}
}
@Override
public void onHostClick(long hostID, boolean isActive) {
if (isActive) {
Host h = Oracle.getHostByID(INodeID.get(hostID));
try {
RouteSensor routeSensor = h.getComponent(RouteSensor.class);
trajectoryVisualizations.put(hostID,
new TrajectoryVis(routeSensor));
} catch (ComponentNotAvailableException e) {
// ignore.
}
} else {
trajectoryVisualizations.remove(hostID);
}
}
/**
* Visualizes the movement trajectory of a given node.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
private class TrajectoryVis {
private final RouteSensor routeSensor;
public TrajectoryVis(RouteSensor routeSensor) {
this.routeSensor = routeSensor;
}
public void drawTrajectory(Graphics2D g2) {
Route rt = routeSensor.getRoute();
if (!rt.hasSegmentInformation()) {
return;
}
boolean alt = false;
for (RouteSegment segment : rt.getSegmentsAhead()) {
Location lastLoc = null;
g2.setColor(Color.MAGENTA);
if (alt) {
g2.setColor(Color.ORANGE);
}
alt = !alt;
for (Location loc : segment.getSegmentLocations()) {
if (lastLoc == null) {
lastLoc = loc;
g2.drawString(segment.getSegmentId(),
VisualizationInjector
.scaleValue(lastLoc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(lastLoc.getLatitudeOrY()));
continue;
}
g2.setStroke(new BasicStroke(3.0f));
g2.drawLine(
VisualizationInjector
.scaleValue(lastLoc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(lastLoc.getLatitudeOrY()),
VisualizationInjector
.scaleValue(loc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(loc.getLatitudeOrY()));
lastLoc = loc;
}
}
}
}
/**
* Provides access super.paintComponent() for extending classes.
* @param g the Graphics object for painting.
*/
protected void paintSuper(Graphics g)
{
super.paintComponent(g);
}
/**
* Draws the attraction points. This method has been extracted from paint()
* to make it possible for extending class to override only this bit while leaving everything
* else untouched.
* @param g2 the Graphics2D object for painting.
*/
protected void drawAttractionPoints(Graphics2D g2)
{
Composite gc = g2.getComposite();
for (IAttractionPoint aPoint : movementModel.getAttractionPoints()) {
Point point = ((PositionVector) aPoint).asPoint();
// draw border
g2.setColor(Color.BLACK);
g2.setFont(VisualizationTopologyView.FONT_MEDIUM);
g2.drawString(aPoint.getName(),
VisualizationInjector.scaleValue(point.x) - g2.getFontMetrics().stringWidth(aPoint.getName()) / 2,
VisualizationInjector.scaleValue(point.y - aPoint.getRadius() - 5) - ATTR_SIZE);
// g2.setColor(COLOR_ATTR_POINT);
// float alpha = 0.25f + (float) (aPoint.getWeight() / 2);
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// g2.fillOval(
// VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
// VisualizationInjector.scaleValue(point.y) - ATTR_PAD,
// ATTR_PAD * 2 + 1, ATTR_PAD * 2 + 1);
g2.setColor(COLOR_ATTR_POINT);
int radius = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_SIZE;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
g2.setComposite(gc);
}
}
/**
* Draws the position of the node. This method has been extracted from paint()
* to make it possible for extending class to override only this bit while leaving everything
* else untouched. Instead of painting all of the nodes, only a specific one gets painted. This allows
* extending class to fall back to this implementation if one specific node could not be drawn for whatever reason.
* @param g2 the Graphics2D object for painting.
*/
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{
Point2D pt = comp.getRealPosition().asPoint();
g2.setColor(Color.GRAY);
g2.fillOval(VisualizationInjector.scaleValue(pt.getX()) - NODE_SIZE,
VisualizationInjector.scaleValue(pt.getY()) - NODE_SIZE,
NODE_SIZE * 2, NODE_SIZE * 2);
}
protected void setMovementModel(ModularMovementModel model)
{
movementModel = model;
}
@Override
public String getDisplayName() {
return "Mobility Model";
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public JMenu getCustomMenu() {
return menu;
}
@Override
public boolean isHidden() {
return false;
}
}