/*
* 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.obstacles;
import java.awt.Color;
import java.util.List;
import com.google.common.collect.Lists;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.geom.Polygon;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
/**
* This Obstacle is build from a list of coordinates that form a Polygon. The
* coordinates have to be specified in clockwise direction.
*
* @author Bjoern Richerzhagen
* @version 1.0, 20.03.2012
*/
public class PolygonObstacle extends AbstractObstacle {
private final GeometryFactory factory = new GeometryFactory();
private Polygon poly;
private double damping = 1.0;
int[] xpoints;
int[] ypoints;
double minX = Double.POSITIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY;
double maxX = Double.NEGATIVE_INFINITY;
double maxY = Double.NEGATIVE_INFINITY;
private Color customColor;
private List vertices;
/**
* A Polygon that is damping the signal (no link through this obstacle is
* possible)
*
* @param vertices
*/
public PolygonObstacle(List vertices) {
this(vertices, 1.0);
}
public PolygonObstacle(List vertices, double damping) {
if (damping > 1)
damping = 1;
if (damping < 0)
damping = 0;
this.damping = damping;
rebuildPolygon(vertices);
}
/**
* Returns the vertices this polygon was build with. Modifications
* to this list won't affect the obstacle. Use rebuildPolygon() to
* restructure the obstacle.
*
* @return
*/
public List getVertices() {
return Lists.newArrayList(vertices);
}
public void rebuildPolygon(List vertices) {
assert vertices.size() > 2 : "You have to specify at least 3 Points";
this.vertices = vertices;
this.minX = Double.POSITIVE_INFINITY;
this.minY = Double.POSITIVE_INFINITY;
this.maxX = Double.NEGATIVE_INFINITY;
this.maxY = Double.NEGATIVE_INFINITY;
Coordinate[] coordinates = new Coordinate[vertices.size()+ 1];
xpoints = new int[vertices.size()];
ypoints = new int[vertices.size()];
PositionVector firstVertex = vertices.get(0);
coordinates[coordinates.length - 1] = new Coordinate(firstVertex.getX(), firstVertex.getY());
int i = 0;
for (PositionVector vertex : vertices) {
coordinates[i] = new Coordinate(vertex.getX(), vertex.getY());
xpoints[i] = (int) vertex.getX();
ypoints[i] = (int) vertex.getY();
if (xpoints[i] < minX) {
minX = xpoints[i];
}
if (ypoints[i] < minY) {
minY = ypoints[i];
}
if (xpoints[i] > maxX) {
maxX = xpoints[i];
}
if (ypoints[i] > maxY) {
maxY = ypoints[i];
}
i++;
}
poly = factory.createPolygon(factory.createLinearRing(coordinates),
null);
}
public int[] getXPoints() {
return this.xpoints;
}
public int[] getYPoints() {
return this.ypoints;
}
@Override
public boolean intersectsWith(PositionVector a, PositionVector b) {
/*
* Adding a bit of greedy decisions, to not always use the poly-methods
*/
double dist = a.distanceTo(b);
if (a.getX() + dist < minX || a.getX() - dist > maxX
|| a.getY() + dist < minY || a.getY() - dist > maxY) {
return false;
}
Coordinate[] lineCoords = new Coordinate[]{new Coordinate(a.getX(), a.getY()), new Coordinate(b.getX(), b.getY())};
return poly.intersects(factory.createLineString(lineCoords));
}
@Override
public boolean contains(Geometry g) {
return poly.contains(g);
}
@Override
public double totalIntersectionLength(PositionVector a, PositionVector b) {
Coordinate[] lineCoords = new Coordinate[] {
new Coordinate(a.getX(), a.getY()),
new Coordinate(b.getX(), b.getY()) };
Geometry testLine = factory.createLineString(lineCoords);
double fullLength = testLine.getLength();
testLine = testLine.difference(poly);
if (testLine instanceof MultiLineString) { // some intersections
MultiLineString resultLines = (MultiLineString) testLine;
return fullLength - resultLines.getLength();
}
if (testLine instanceof GeometryCollection) { // all is intersected
GeometryCollection geocol = (GeometryCollection) testLine;
if (geocol.isEmpty())
return fullLength;
assert (false) : "Geometry collection is not empty";
return fullLength;
} else { // no intersection
assert (testLine instanceof LineString);
LineString resultLine = (LineString) testLine;
return fullLength - resultLine.getLength();
}
}
@Override
public double dampingFactor() {
return damping;
}
public java.awt.Polygon getAwtPolygon(double scale) {
int[] xScaled = new int[xpoints.length];
int[] yScaled = new int[ypoints.length];
for (int i = 0; i < yScaled.length; i++) {
xScaled[i] = (int) (xpoints[i] / scale);
yScaled[i] = (int) (ypoints[i] / scale);
}
return new java.awt.Polygon(xScaled, yScaled, yScaled.length);
}
@Override
public Geometry getGeometry() {
return this.poly;
}
public PositionVector getCentroid() {
double xCenter = 0;
double yCenter = 0;
for (int i = 0; i < xpoints.length; i++) {
xCenter += xpoints[i];
yCenter += ypoints[i];
}
return new PositionVector(xCenter * (1/xpoints.length), yCenter * (1/ypoints.length));
}
public void setDampeningFactor(double dampeningFactor) {
this.damping = dampeningFactor;
}
public void setCustomColor(Color color) {
this.customColor = color;
}
public Color getCustomColor() {
return this.customColor;
}
}