Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Simonstrator
PeerfactSim.KOM
Commits
0c80da45
Commit
0c80da45
authored
Nov 06, 2015
by
Björn Richerzhagen
Browse files
Removed deprecated `Position`-Interface
parent
db566de9
Changes
64
Hide whitespace changes
Inline
Side-by-side
src/de/tud/kom/p2psim/impl/topology/waypoints/strong/OSMHotspotStrategy.java
View file @
0c80da45
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.topology.waypoints.strong
;
import
java.awt.Color
;
import
java.awt.Font
;
import
java.awt.Graphics
;
import
java.awt.Graphics2D
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Vector
;
import
javax.swing.JComponent
;
import
org.apache.commons.math.random.JDKRandomGenerator
;
import
org.apache.commons.math.random.RandomGenerator
;
import
com.vividsolutions.jts.geom.Coordinate
;
import
com.vividsolutions.jts.geom.Geometry
;
import
com.vividsolutions.jts.geom.GeometryFactory
;
import
de.tud.kom.p2psim.api.scenario.ConfigurationException
;
import
de.tud.kom.p2psim.api.topology.obstacles.Obstacle
;
import
de.tud.kom.p2psim.api.topology.waypoints.WaypointModel
;
import
de.tud.kom.p2psim.api.util.geo.maps.Node
;
import
de.tud.kom.p2psim.api.util.geo.maps.Way
;
import
de.tud.kom.p2psim.impl.simengine.Simulator
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector
;
import
de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector.DisplayString
;
import
de.tud.kom.p2psim.impl.topology.waypoints.StrongWaypointSupport
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.StrongWaypoint
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.WeakWaypoint
;
import
de.tud.kom.p2psim.impl.util.Tuple
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMMap
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMNode
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMObstacle
;
import
de.tudarmstadt.maki.simonstrator.api.Monitor
;
import
de.tudarmstadt.maki.simonstrator.api.Monitor.Level
;
public
class
OSMHotspotStrategy
extends
StrongWaypointStrategy
{
protected
ArrayList
<
HotspotDeplacmentInfo
>
hotspotMoveLerpPositions
=
new
ArrayList
<
HotspotDeplacmentInfo
>();
private
static
String
AMENITIES_FILENAME
=
"data/maps/valid_amenities.ordering"
;
private
RandomGenerator
rnd
;
protected
int
placementRetries
=
1000
;
// The number of strong waypoints that shall be added to the map
protected
int
noOfWaypoints
=
1000
;
// Holds the actually existing amenities in the map (given that they are
// valid)
ArrayList
<
String
>
existingAmenities
;
private
WaypointModel
model
=
null
;
/**
* A list of the most used amenities in open street map sorted by the
* likelihood of being hotspots where many people meet.
*/
private
static
ArrayList
<
String
>
validAmenities
=
new
ArrayList
<
String
>();
public
OSMHotspotStrategy
()
{
// The fresh random generator based on the configured seed
// ensures that the amount of waypoints and their positioning is
// reproducible
rnd
=
new
JDKRandomGenerator
();
rnd
.
setSeed
(
Simulator
.
getSeed
());
validAmenities
=
readAmenitiesFromFile
();
}
/**
* Reads the valid amenities from the file AMENETIES_FILENAME and returns
* them as a list of strings.
*
* @return
*/
private
ArrayList
<
String
>
readAmenitiesFromFile
()
{
File
ordering
=
new
File
(
AMENITIES_FILENAME
);
if
(!
ordering
.
exists
())
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
);
ArrayList
<
String
>
amenities
=
new
ArrayList
<
String
>();
BufferedReader
reader
=
null
;
try
{
reader
=
new
BufferedReader
(
new
FileReader
(
ordering
));
String
line
=
reader
.
readLine
();
while
(
line
!=
null
)
{
if
(!
line
.
equals
(
""
))
{
amenities
.
add
(
line
);
}
line
=
reader
.
readLine
();
}
reader
.
close
();
}
catch
(
FileNotFoundException
e
)
{
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
,
e
);
}
catch
(
IOException
e
)
{
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
,
e
);
}
finally
{
try
{
reader
.
close
();
}
catch
(
Exception
e
)
{
// ...
}
}
return
amenities
;
}
@Override
public
void
generateStrongWaypoints
(
WaypointModel
wpModel
)
{
this
.
model
=
wpModel
;
if
(!(
wpModel
instanceof
StrongWaypointSupport
))
throw
new
ConfigurationException
(
"OSMHotspotStrategy requires a waypoint model with strong waypoint support to work correctly."
);
if
(!(
model
.
getMap
()
instanceof
OSMMap
))
throw
new
ConfigurationException
(
"OSMHotspotStrategy requires a OSMMap to work correctly."
);
OSMMap
map
=
(
OSMMap
)
model
.
getMap
();
StrongWaypointSupport
sws
=
(
StrongWaypointSupport
)
wpModel
;
noOfWaypoints
=
sws
.
getNoOfWaypoints
();
// Find hotspots based on the validAmenities list
final
List
<
Hotspot
>
hotspots
=
findHotspots
(
map
);
// Filter the existing valid amenities
existingAmenities
=
existingAmenity
(
hotspots
);
// Assign radii based on the priority of the amenities
assignRadii
(
hotspots
,
map
);
// Move the hotspots if they are inside of an obstacle
if
(
obstacleModel
!=
null
)
{
moveWaypointsBasedOnObstacles
(
hotspots
);
}
// Add the number of specified way points distributed by the radius size
addStrongWaypoints
(
hotspots
);
// Inject the JComponent for displaying the hotspots
VisualizationInjector
.
injectComponent
(
"Hotspots"
,
0
,
new
ShowHotspots
(
hotspots
,
model
),
false
);
VisualizationInjector
.
addDisplayString
(
new
DisplayString
()
{
@Override
public
String
getDisplayString
()
{
int
distinctAmenities
=
0
;
if
(
existingAmenities
!=
null
)
distinctAmenities
=
existingAmenities
.
size
();
return
"OSM[Waypoints (strong/weak): "
+
model
.
getNumberOfWaypoints
(
StrongWaypoint
.
class
)
+
"/"
+
model
.
getNumberOfWaypoints
(
WeakWaypoint
.
class
)
+
", Hotspots: "
+
hotspots
.
size
()
+
", Distinct amenities: "
+
distinctAmenities
+
", Highest amenity: "
+
hotspots
.
get
(
0
).
amenity
+
"]"
;
}
});
}
/**
* Uses the information provided by the obstacle model to move the hotspots
* outside of the obstacles should the be completely covered.
*/
private
void
moveWaypointsBasedOnObstacles
(
List
<
Hotspot
>
hotspots
)
{
for
(
Hotspot
hotspot
:
hotspots
)
{
createHotspotGeometry
(
hotspot
);
Obstacle
obstacle
=
isHotspotInsideObstacle
(
hotspot
);
if
(
obstacle
==
null
)
continue
;
hotspot
.
wasHidden
=
true
;
Tuple
<
PositionVector
,
PositionVector
>
closestEdges
=
findClosestEdgest
(
hotspot
,
obstacle
);
double
t
=
rnd
.
nextDouble
();
PositionVector
a
=
closestEdges
.
getA
();
PositionVector
b
=
closestEdges
.
getB
();
PositionVector
newPosition
=
a
.
clone
();
PositionVector
p
=
b
.
minus
(
newPosition
);
p
.
multiplyScalar
(
t
);
newPosition
.
add
(
p
);
PositionVector
direction
=
a
.
clone
();
p
=
b
.
minus
(
direction
);
p
.
multiplyScalar
(
0.5
);
direction
.
add
(
p
);
direction
=
direction
.
minus
(
hotspot
.
position
);
direction
.
normalize
();
direction
.
multiplyScalar
(
hotspot
.
radius
/
2
);
newPosition
.
add
(
direction
);
HotspotDeplacmentInfo
lerpPos
=
new
HotspotDeplacmentInfo
(
closestEdges
.
getA
(),
closestEdges
.
getB
(),
newPosition
,
hotspot
.
position
);
hotspotMoveLerpPositions
.
add
(
lerpPos
);
hotspot
.
position
=
newPosition
;
}
}
private
Tuple
<
PositionVector
,
PositionVector
>
findClosestEdgest
(
Hotspot
hotspot
,
Obstacle
obstacle
)
{
Geometry
geometry
=
obstacle
.
getGeometry
();
Coordinate
[]
coordinates
=
geometry
.
getCoordinates
();
PositionVector
[]
positionCache
=
new
PositionVector
[
coordinates
.
length
];
double
closestDistance
=
-
1
;
int
closestIdx
=
-
1
;
for
(
int
i
=
0
;
i
<
coordinates
.
length
;
i
++)
{
positionCache
[
i
]
=
new
PositionVector
(
coordinates
[
i
].
x
,
coordinates
[
i
].
y
);
double
d
=
positionCache
[
i
].
getD
istance
(
hotspot
.
position
);
if
(
closestDistance
>
d
||
closestDistance
==
-
1
)
{
closestDistance
=
d
;
closestIdx
=
i
;
}
}
PositionVector
before
=
positionCache
[
closestIdx
-
1
==
-
1
?
coordinates
.
length
-
1
:
closestIdx
-
1
];
PositionVector
after
=
positionCache
[
closestIdx
+
1
==
coordinates
.
length
?
0
:
closestIdx
+
1
];
if
(
before
.
getD
istance
(
hotspot
.
position
)
<
after
.
getD
istance
(
hotspot
.
position
))
{
return
new
Tuple
<
PositionVector
,
PositionVector
>(
positionCache
[
closestIdx
].
clone
(),
before
);
}
else
{
return
new
Tuple
<
PositionVector
,
PositionVector
>(
positionCache
[
closestIdx
].
clone
(),
after
);
}
}
private
Obstacle
isHotspotInsideObstacle
(
Hotspot
hotspot
)
{
for
(
Obstacle
obstacle
:
obstacleModel
.
getObstacles
())
{
if
(
obstacle
.
contains
(
hotspot
.
geometry
))
{
return
obstacle
;
}
}
return
null
;
}
/**
* Uses the validAmenities list to find hotspots in the map and returns a
* list newly created Hotspots.
*
* @param map
* @return
*/
private
List
<
Hotspot
>
findHotspots
(
OSMMap
map
)
{
List
<
Hotspot
>
hotspots
=
new
ArrayList
<
Hotspot
>();
Collection
<
OSMNode
>
nodes
=
map
.
getNodes
();
Collection
<
Way
>
ways
=
map
.
getWays
();
List
<
Obstacle
>
obstacles
=
map
.
getObstacles
();
// Node and Way are currently the only retained
// information and also the most used
// TODO: Add a MovementStrategy that doesn't use waypoints but avoids
// obstacles
// TODO: Add a MovementStrategy that uses the waypoints but doesn't move
// in a straight line
// TODO: Add an option to assign StrongWaypoints based on the density of
// WeakWaypoints or convert some WeakWaypoints to StrongWaypoints
for
(
Obstacle
o
:
obstacles
)
{
OSMObstacle
obstacle
=
(
OSMObstacle
)
o
;
if
(
obstacle
.
containsAttribute
(
"amenity"
))
{
if
(
getAmenityIndex
(
obstacle
.
getAttribute
(
"amenity"
),
validAmenities
)
<
0
)
continue
;
Hotspot
hotspot
=
new
Hotspot
();
hotspot
.
position
=
obstacle
.
getVertices
().
get
(
0
);
hotspot
.
amenity
=
obstacle
.
getAttribute
(
"amenity"
);
hotspot
.
type
=
obstacle
.
getAttribute
(
"name"
);
hotspots
.
add
(
hotspot
);
}
}
/*
* for (Node n : nodes) { OSMNode node = (OSMNode)n; if
* (node.containsAttribute("amenity")) { if
* (getAmenityIndex(node.getAttribute("amenity"), validAmenities) < 0)
* continue;
*
* Hotspot hotspot = new Hotspot(); hotspot.position =
* node.getWorldPosition(); hotspot.amenity =
* node.getAttribute("amenity"); hotspot.type = "node";
*
* hotspots.add(hotspot); } }
*
* for (Way w : ways) { OSMWay way = (OSMWay)w; if
* (way.containsAttribute("amenity")) { if
* (getAmenityIndex(way.getAttribute("amenity"), validAmenities) < 0)
* continue;
*
* PositionVector center = getCenter(way.getNodes());
*
* Hotspot hotspot = new Hotspot(); hotspot.position = center;
* hotspot.amenity = way.getAttribute("amenity"); hotspot.type = "way";
*
* hotspots.add(hotspot); } }
*/
Collections
.
sort
(
hotspots
,
new
HotspotComparator
(
validAmenities
));
return
hotspots
;
}
/**
* Filters the existing amenities based on the validAmenities list
*
* @param hotspots
* Hotspots with amenities
* @return List of existing valid amenities
*/
public
ArrayList
<
String
>
existingAmenity
(
List
<
Hotspot
>
hotspots
)
{
ArrayList
<
String
>
list
=
new
ArrayList
<
String
>();
for
(
String
vh
:
validAmenities
)
{
for
(
Hotspot
h
:
hotspots
)
{
if
(
h
.
amenity
.
equals
(
vh
))
{
list
.
add
(
vh
);
break
;
}
}
}
return
list
;
}
/**
* Returns the center of a list of nodes
*
* @param points
* @return
*/
private
PositionVector
getCenter
(
Vector
<
Node
>
points
)
{
PositionVector
centroid
=
new
PositionVector
(
0
,
0
);
for
(
Node
n
:
points
)
{
centroid
.
add
(
n
.
getWorldPosition
());
}
centroid
.
multiplyScalar
(
1
/
(
double
)
points
.
size
());
return
centroid
;
}
/**
* Calculates the maximum radius size based on the map size and assigns the
* radii based on the hotspots amenities priority.
*
* The hotspot with the highest priority e.g. the first hotspot in the list
* receives the maximum radius.
*
* Note: This method also creates the Geometry object for the hotspot
*
* @param hotspots
* Hotspots whos radius shall be calculated
* @param map
* The current map
*/
private
void
assignRadii
(
List
<
Hotspot
>
hotspots
,
OSMMap
map
)
{
PositionVector
dimensions
=
map
.
getDimensions
();
double
llsqrt
=
Math
.
sqrt
(
dimensions
.
getX
()
+
dimensions
.
getY
());
double
defaultRadius
=
0.630
*
llsqrt
;
// 0.887
int
idx
;
for
(
Hotspot
h
:
hotspots
)
{
idx
=
getAmenityIndex
(
h
.
amenity
,
existingAmenities
);
h
.
radius
=
(
defaultRadius
/
(
idx
+
1
));
h
.
geometry
=
createHotspotGeometry
(
h
);
}
}
private
Geometry
createHotspotGeometry
(
Hotspot
h
)
{
int
points
=
20
;
double
slice
=
2
*
Math
.
PI
/
points
;
ArrayList
<
Coordinate
>
coordinates
=
new
ArrayList
<
Coordinate
>();
for
(
int
i
=
0
;
i
<
points
;
i
++)
{
double
angle
=
slice
*
i
;
int
newX
=
(
int
)
(
h
.
position
.
getX
()
+
h
.
radius
*
Math
.
cos
(
angle
));
int
newY
=
(
int
)
(
h
.
position
.
getY
()
+
h
.
radius
*
Math
.
sin
(
angle
));
coordinates
.
add
(
new
Coordinate
(
newX
,
newY
));
}
coordinates
.
add
(
coordinates
.
get
(
0
));
Coordinate
[]
coordinateArray
=
new
Coordinate
[
coordinates
.
size
()];
GeometryFactory
gf
=
new
GeometryFactory
();
return
gf
.
createLinearRing
(
coordinates
.
toArray
(
coordinateArray
));
}
/**
* Adds strong way points to the graph that are used for the navigation of
* AbstractWaypointMovementModel implementations.
*
* FIXME: Find a way to place all waypoints (currently only used x retries)
* FIXME: Remove hotspots that are fully contained in an obstacle!!
*
* @param hotspots
* Hotspots to whom the new way points shall be added
*/
private
void
addStrongWaypoints
(
List
<
Hotspot
>
hotspots
)
{
double
radiiSum
=
0.0
;
for
(
Hotspot
h
:
hotspots
)
{
radiiSum
+=
h
.
radius
;
}
double
wps
=
noOfWaypoints
/
radiiSum
;
int
wpCount
=
0
;
addHotspots:
{
for
(
Hotspot
h
:
hotspots
)
{
int
nrWps
=
(
int
)
(
Math
.
round
(
wps
*
h
.
radius
));
int
retries
=
0
;
for
(
int
i
=
0
;
i
<
nrWps
;
i
++)
{
PositionVector
loc
=
selectRandomLocation
(
h
);
if
(
obstacleModel
!=
null
)
{
if
(!
obstacleModel
.
contains
(
loc
))
{
model
.
addWaypoint
(
new
StrongWaypoint
<
Object
>(
loc
));
if
(++
wpCount
>=
noOfWaypoints
)
break
addHotspots
;
}
else
{
if
(!(
retries
++
>=
placementRetries
))
i
--;
}
}
else
{
model
.
addWaypoint
(
new
StrongWaypoint
<
Object
>(
loc
));
if
(++
wpCount
>=
noOfWaypoints
)
break
addHotspots
;
}
}
}
}
Monitor
.
log
(
OSMHotspotStrategy
.
class
,
Level
.
INFO
,
"Added "
+
wpCount
+
" strong waypoints."
);
}
/**
* Selects a random location inside the hotspots radius
*
* @param hotspot
* @return
*/
private
PositionVector
selectRandomLocation
(
Hotspot
hotspot
)
{
double
theta
=
rnd
.
nextDouble
()
*
Math
.
PI
*
2
;
double
length
=
Math
.
sqrt
(
rnd
.
nextDouble
());
double
x
=
Math
.
cos
(
theta
)
*
hotspot
.
radius
*
length
;
double
y
=
Math
.
sin
(
theta
)
*
hotspot
.
radius
*
length
;
return
new
PositionVector
(
hotspot
.
position
.
getX
()
+
x
,
hotspot
.
position
.
getY
()
+
y
);
}
/**
* Returns the position of the given amenity in the validHotspots list.
*
* @param amenity
* @param validHotspots
* @return
*/
private
static
int
getAmenityIndex
(
String
amenity
,
ArrayList
<
String
>
validHotspots
)
{
if
(
validHotspots
==
null
)
return
0
;
for
(
int
i
=
0
;
i
<
validHotspots
.
size
();
i
++)
{
if
(
validHotspots
.
get
(
i
).
equals
(
amenity
))
{
return
i
;
}
}
return
-
1
;
}
/**
* Bean for hotspots
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
static
class
Hotspot
{
public
Hotspot
()
{
//
}
public
double
weight
;
public
String
amenity
;
public
PositionVector
position
;
public
String
type
;
public
double
radius
;
public
Geometry
geometry
;
public
boolean
wasHidden
=
false
;
}
/**
* Compares hotspots based on their amenity and prioritizes ways over nodes.
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
static
class
HotspotComparator
implements
Comparator
<
Hotspot
>
{
private
ArrayList
<
String
>
validHotspots
;
public
HotspotComparator
(
ArrayList
<
String
>
validHotspots
)
{
this
.
validHotspots
=
validHotspots
;
}
@SuppressWarnings
(
"synthetic-access"
)
@Override
public
int
compare
(
Hotspot
h1
,
Hotspot
h2
)
{
int
idx1
=
getAmenityIndex
(
h1
.
amenity
,
validHotspots
);
int
idx2
=
getAmenityIndex
(
h2
.
amenity
,
validHotspots
);
int
diff
=
idx1
-
idx2
;
if
(
diff
!=
0
)
{
return
diff
;
}
else
{
if
(
"way"
.
equals
(
h1
)
&&
"node"
.
equals
(
h2
))
return
1
;
if
(
"node"
.
equals
(
h1
)
&&
"way"
.
equals
(
h2
))
return
-
1
;
return
0
;
}
}
}
private
class
HotspotDeplacmentInfo
{
public
PositionVector
edge1
;
public
PositionVector
edge2
;
public
PositionVector
newPosition
;
public
PositionVector
oldPosition
;
public
HotspotDeplacmentInfo
(
PositionVector
edge1
,
PositionVector
edge2
,
PositionVector
newPosition
,
PositionVector
oldPosition
)
{
this
.
edge1
=
edge1
;
this
.
edge2
=
edge2
;
this
.
newPosition
=
newPosition
;
this
.
oldPosition
=
oldPosition
;
}
}
/**
* Draws the hotspots on the map and displays some extra information
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
class
ShowHotspots
extends
JComponent
{
private
List
<
Hotspot
>
hotspots
;
private
WaypointModel
model
;
public
ShowHotspots
(
List
<
Hotspot
>
hotspots
,
WaypointModel
model
)
{
super
();
this
.
hotspots
=
hotspots
;
this
.
model
=
model
;
PositionVector
dimension
=
model
.
getMap
().
getDimensions
();
setBounds
(
0
,
0
,
(
int
)
dimension
.
getX
(),
(
int
)
dimension
.
getY
());
setOpaque
(
false
);
setVisible
(
true
);
}
@Override
protected
void
paintComponent
(
Graphics
g
)
{
super
.
paintComponent
(
g
);
Graphics2D
g2
=
(
Graphics2D
)
g
;
g2
.
setFont
(
new
Font
(
"SansSerif"
,
Font
.
PLAIN
,
9
));
int
i
=
0
;
for
(
Hotspot
h
:
hotspots
)
{
if
(!
h
.
wasHidden
)
{
g2
.
setColor
(
new
Color
(
255
,
255
,
0
,
100
));
}
else
{
g2
.
setColor
(
new
Color
(
0
,
0
,
255
,
100
));
}
g2
.
fillOval
((
int
)
(
h
.
position
.
getX
()
-
h
.
radius
),
(
int
)
(
h
.
position
.
getY
()
-
h
.
radius
),
(
int
)
h
.
radius
*
2
,
(
int
)
h
.
radius
*
2
);
g2
.
setColor
(
Color
.
BLACK
);
if
(
h
.
type
!=
null
)
{
g2
.
drawString
(
h
.
type
,
(
int
)
(
h
.
position
.
getX
()
-
h
.
amenity
.
length
()
*
1.5
),
(
int
)
h
.
position
.
getY
());
}
}
drawLerp
(
g2
);
}
protected
void
drawLerp
(
Graphics2D
g2
)
{
for
(
HotspotDeplacmentInfo
l
:
hotspotMoveLerpPositions
)
{
g2
.
setColor
(
new
Color
(
0
,
0
,
0
,
255
));
g2
.
drawLine
((
int
)
l
.
edge1
.
getX
(),
(
int
)
l
.
edge1
.
getY
(),
(
int
)
l
.
edge2
.
getX
(),
(
int
)
l
.
edge2
.
getY
());
g2
.
fillOval
((
int
)
l
.
edge1
.
getX
()
-
2
,
(
int
)
l
.
edge1
.
getY
()
-
2
,
4
,
4
);
g2
.
fillOval
((
int
)
l
.
edge2
.
getX
()
-
2
,
(
int
)
l
.
edge2
.
getY
()
-
2
,
4
,
4
);
g2
.
setColor
(
new
Color
(
238
,
232
,
170
,
100
));
g2
.
fillOval
((
int
)
l
.
newPosition
.
getX
()
-
2
,
(
int
)
l
.
newPosition
.
getY
()
-
2
,
4
,
4
);
g2
.
setColor
(
new
Color
(
238
,
232
,
170
,
100
));
g2
.
drawLine
((
int
)
l
.
oldPosition
.
getX
(),
(
int
)
l
.
oldPosition
.
getY
(),
(
int
)
l
.
newPosition
.
getX
(),
(
int
)
l
.
newPosition
.
getY
());
}
}
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.topology.waypoints.strong
;
import
java.awt.Color
;
import
java.awt.Font
;
import
java.awt.Graphics
;
import
java.awt.Graphics2D
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Vector
;
import
javax.swing.JComponent
;
import
org.apache.commons.math.random.JDKRandomGenerator
;
import
org.apache.commons.math.random.RandomGenerator
;
import
com.vividsolutions.jts.geom.Coordinate
;
import
com.vividsolutions.jts.geom.Geometry
;
import
com.vividsolutions.jts.geom.GeometryFactory
;
import
de.tud.kom.p2psim.api.scenario.ConfigurationException
;
import
de.tud.kom.p2psim.api.topology.obstacles.Obstacle
;
import
de.tud.kom.p2psim.api.topology.waypoints.WaypointModel
;
import
de.tud.kom.p2psim.api.util.geo.maps.Node
;
import
de.tud.kom.p2psim.api.util.geo.maps.Way
;
import
de.tud.kom.p2psim.impl.simengine.Simulator
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector
;
import
de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector.DisplayString
;
import
de.tud.kom.p2psim.impl.topology.waypoints.StrongWaypointSupport
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.StrongWaypoint
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.WeakWaypoint
;
import
de.tud.kom.p2psim.impl.util.Tuple
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMMap
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMNode
;
import
de.tud.kom.p2psim.impl.util.geo.maps.osm.OSMObstacle
;
import
de.tudarmstadt.maki.simonstrator.api.Monitor
;
import
de.tudarmstadt.maki.simonstrator.api.Monitor.Level
;
public
class
OSMHotspotStrategy
extends
StrongWaypointStrategy
{
protected
ArrayList
<
HotspotDeplacmentInfo
>
hotspotMoveLerpPositions
=
new
ArrayList
<
HotspotDeplacmentInfo
>();
private
static
String
AMENITIES_FILENAME
=
"data/maps/valid_amenities.ordering"
;
private
RandomGenerator
rnd
;
protected
int
placementRetries
=
1000
;
// The number of strong waypoints that shall be added to the map
protected
int
noOfWaypoints
=
1000
;
// Holds the actually existing amenities in the map (given that they are
// valid)
ArrayList
<
String
>
existingAmenities
;
private
WaypointModel
model
=
null
;
/**
* A list of the most used amenities in open street map sorted by the
* likelihood of being hotspots where many people meet.
*/
private
static
ArrayList
<
String
>
validAmenities
=
new
ArrayList
<
String
>();
public
OSMHotspotStrategy
()
{
// The fresh random generator based on the configured seed
// ensures that the amount of waypoints and their positioning is
// reproducible
rnd
=
new
JDKRandomGenerator
();
rnd
.
setSeed
(
Simulator
.
getSeed
());
validAmenities
=
readAmenitiesFromFile
();
}
/**
* Reads the valid amenities from the file AMENETIES_FILENAME and returns
* them as a list of strings.
*
* @return
*/
private
ArrayList
<
String
>
readAmenitiesFromFile
()
{
File
ordering
=
new
File
(
AMENITIES_FILENAME
);
if
(!
ordering
.
exists
())
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
);
ArrayList
<
String
>
amenities
=
new
ArrayList
<
String
>();
BufferedReader
reader
=
null
;
try
{
reader
=
new
BufferedReader
(
new
FileReader
(
ordering
));
String
line
=
reader
.
readLine
();
while
(
line
!=
null
)
{
if
(!
line
.
equals
(
""
))
{
amenities
.
add
(
line
);
}
line
=
reader
.
readLine
();
}
reader
.
close
();
}
catch
(
FileNotFoundException
e
)
{
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
,
e
);
}
catch
(
IOException
e
)
{
throw
new
ConfigurationException
(
"Unable to read the amenities file ("
+
AMENITIES_FILENAME
+
")"
,
e
);
}
finally
{
try
{
reader
.
close
();
}
catch
(
Exception
e
)
{
// ...
}
}
return
amenities
;
}
@Override
public
void
generateStrongWaypoints
(
WaypointModel
wpModel
)
{
this
.
model
=
wpModel
;
if
(!(
wpModel
instanceof
StrongWaypointSupport
))
throw
new
ConfigurationException
(
"OSMHotspotStrategy requires a waypoint model with strong waypoint support to work correctly."
);
if
(!(
model
.
getMap
()
instanceof
OSMMap
))
throw
new
ConfigurationException
(
"OSMHotspotStrategy requires a OSMMap to work correctly."
);
OSMMap
map
=
(
OSMMap
)
model
.
getMap
();
StrongWaypointSupport
sws
=
(
StrongWaypointSupport
)
wpModel
;
noOfWaypoints
=
sws
.
getNoOfWaypoints
();
// Find hotspots based on the validAmenities list
final
List
<
Hotspot
>
hotspots
=
findHotspots
(
map
);
// Filter the existing valid amenities
existingAmenities
=
existingAmenity
(
hotspots
);
// Assign radii based on the priority of the amenities
assignRadii
(
hotspots
,
map
);
// Move the hotspots if they are inside of an obstacle
if
(
obstacleModel
!=
null
)
{
moveWaypointsBasedOnObstacles
(
hotspots
);
}
// Add the number of specified way points distributed by the radius size
addStrongWaypoints
(
hotspots
);
// Inject the JComponent for displaying the hotspots
VisualizationInjector
.
injectComponent
(
"Hotspots"
,
0
,
new
ShowHotspots
(
hotspots
,
model
),
false
);
VisualizationInjector
.
addDisplayString
(
new
DisplayString
()
{
@Override
public
String
getDisplayString
()
{
int
distinctAmenities
=
0
;
if
(
existingAmenities
!=
null
)
distinctAmenities
=
existingAmenities
.
size
();
return
"OSM[Waypoints (strong/weak): "
+
model
.
getNumberOfWaypoints
(
StrongWaypoint
.
class
)
+
"/"
+
model
.
getNumberOfWaypoints
(
WeakWaypoint
.
class
)
+
", Hotspots: "
+
hotspots
.
size
()
+
", Distinct amenities: "
+
distinctAmenities
+
", Highest amenity: "
+
hotspots
.
get
(
0
).
amenity
+
"]"
;
}
});
}
/**
* Uses the information provided by the obstacle model to move the hotspots
* outside of the obstacles should the be completely covered.
*/
private
void
moveWaypointsBasedOnObstacles
(
List
<
Hotspot
>
hotspots
)
{
for
(
Hotspot
hotspot
:
hotspots
)
{
createHotspotGeometry
(
hotspot
);
Obstacle
obstacle
=
isHotspotInsideObstacle
(
hotspot
);
if
(
obstacle
==
null
)
continue
;
hotspot
.
wasHidden
=
true
;
Tuple
<
PositionVector
,
PositionVector
>
closestEdges
=
findClosestEdgest
(
hotspot
,
obstacle
);
double
t
=
rnd
.
nextDouble
();
PositionVector
a
=
closestEdges
.
getA
();
PositionVector
b
=
closestEdges
.
getB
();
PositionVector
newPosition
=
a
.
clone
();
PositionVector
p
=
b
.
minus
(
newPosition
);
p
.
multiplyScalar
(
t
);
newPosition
.
add
(
p
);
PositionVector
direction
=
a
.
clone
();
p
=
b
.
minus
(
direction
);
p
.
multiplyScalar
(
0.5
);
direction
.
add
(
p
);
direction
=
direction
.
minus
(
hotspot
.
position
);
direction
.
normalize
();
direction
.
multiplyScalar
(
hotspot
.
radius
/
2
);
newPosition
.
add
(
direction
);
HotspotDeplacmentInfo
lerpPos
=
new
HotspotDeplacmentInfo
(
closestEdges
.
getA
(),
closestEdges
.
getB
(),
newPosition
,
hotspot
.
position
);
hotspotMoveLerpPositions
.
add
(
lerpPos
);
hotspot
.
position
=
newPosition
;
}
}
private
Tuple
<
PositionVector
,
PositionVector
>
findClosestEdgest
(
Hotspot
hotspot
,
Obstacle
obstacle
)
{
Geometry
geometry
=
obstacle
.
getGeometry
();
Coordinate
[]
coordinates
=
geometry
.
getCoordinates
();
PositionVector
[]
positionCache
=
new
PositionVector
[
coordinates
.
length
];
double
closestDistance
=
-
1
;
int
closestIdx
=
-
1
;
for
(
int
i
=
0
;
i
<
coordinates
.
length
;
i
++)
{
positionCache
[
i
]
=
new
PositionVector
(
coordinates
[
i
].
x
,
coordinates
[
i
].
y
);
double
d
=
positionCache
[
i
].
d
istance
To
(
hotspot
.
position
);
if
(
closestDistance
>
d
||
closestDistance
==
-
1
)
{
closestDistance
=
d
;
closestIdx
=
i
;
}
}
PositionVector
before
=
positionCache
[
closestIdx
-
1
==
-
1
?
coordinates
.
length
-
1
:
closestIdx
-
1
];
PositionVector
after
=
positionCache
[
closestIdx
+
1
==
coordinates
.
length
?
0
:
closestIdx
+
1
];
if
(
before
.
d
istance
To
(
hotspot
.
position
)
<
after
.
d
istance
To
(
hotspot
.
position
))
{
return
new
Tuple
<
PositionVector
,
PositionVector
>(
positionCache
[
closestIdx
].
clone
(),
before
);
}
else
{
return
new
Tuple
<
PositionVector
,
PositionVector
>(
positionCache
[
closestIdx
].
clone
(),
after
);
}
}
private
Obstacle
isHotspotInsideObstacle
(
Hotspot
hotspot
)
{
for
(
Obstacle
obstacle
:
obstacleModel
.
getObstacles
())
{
if
(
obstacle
.
contains
(
hotspot
.
geometry
))
{
return
obstacle
;
}
}
return
null
;
}
/**
* Uses the validAmenities list to find hotspots in the map and returns a
* list newly created Hotspots.
*
* @param map
* @return
*/
private
List
<
Hotspot
>
findHotspots
(
OSMMap
map
)
{
List
<
Hotspot
>
hotspots
=
new
ArrayList
<
Hotspot
>();
Collection
<
OSMNode
>
nodes
=
map
.
getNodes
();
Collection
<
Way
>
ways
=
map
.
getWays
();
List
<
Obstacle
>
obstacles
=
map
.
getObstacles
();
// Node and Way are currently the only retained
// information and also the most used
// TODO: Add a MovementStrategy that doesn't use waypoints but avoids
// obstacles
// TODO: Add a MovementStrategy that uses the waypoints but doesn't move
// in a straight line
// TODO: Add an option to assign StrongWaypoints based on the density of
// WeakWaypoints or convert some WeakWaypoints to StrongWaypoints
for
(
Obstacle
o
:
obstacles
)
{
OSMObstacle
obstacle
=
(
OSMObstacle
)
o
;
if
(
obstacle
.
containsAttribute
(
"amenity"
))
{
if
(
getAmenityIndex
(
obstacle
.
getAttribute
(
"amenity"
),
validAmenities
)
<
0
)
continue
;
Hotspot
hotspot
=
new
Hotspot
();
hotspot
.
position
=
obstacle
.
getVertices
().
get
(
0
);
hotspot
.
amenity
=
obstacle
.
getAttribute
(
"amenity"
);
hotspot
.
type
=
obstacle
.
getAttribute
(
"name"
);
hotspots
.
add
(
hotspot
);
}
}
/*
* for (Node n : nodes) { OSMNode node = (OSMNode)n; if
* (node.containsAttribute("amenity")) { if
* (getAmenityIndex(node.getAttribute("amenity"), validAmenities) < 0)
* continue;
*
* Hotspot hotspot = new Hotspot(); hotspot.position =
* node.getWorldPosition(); hotspot.amenity =
* node.getAttribute("amenity"); hotspot.type = "node";
*
* hotspots.add(hotspot); } }
*
* for (Way w : ways) { OSMWay way = (OSMWay)w; if
* (way.containsAttribute("amenity")) { if
* (getAmenityIndex(way.getAttribute("amenity"), validAmenities) < 0)
* continue;
*
* PositionVector center = getCenter(way.getNodes());
*
* Hotspot hotspot = new Hotspot(); hotspot.position = center;
* hotspot.amenity = way.getAttribute("amenity"); hotspot.type = "way";
*
* hotspots.add(hotspot); } }
*/
Collections
.
sort
(
hotspots
,
new
HotspotComparator
(
validAmenities
));
return
hotspots
;
}
/**
* Filters the existing amenities based on the validAmenities list
*
* @param hotspots
* Hotspots with amenities
* @return List of existing valid amenities
*/
public
ArrayList
<
String
>
existingAmenity
(
List
<
Hotspot
>
hotspots
)
{
ArrayList
<
String
>
list
=
new
ArrayList
<
String
>();
for
(
String
vh
:
validAmenities
)
{
for
(
Hotspot
h
:
hotspots
)
{
if
(
h
.
amenity
.
equals
(
vh
))
{
list
.
add
(
vh
);
break
;
}
}
}
return
list
;
}
/**
* Returns the center of a list of nodes
*
* @param points
* @return
*/
private
PositionVector
getCenter
(
Vector
<
Node
>
points
)
{
PositionVector
centroid
=
new
PositionVector
(
0
,
0
);
for
(
Node
n
:
points
)
{
centroid
.
add
(
n
.
getWorldPosition
());
}
centroid
.
multiplyScalar
(
1
/
(
double
)
points
.
size
());
return
centroid
;
}
/**
* Calculates the maximum radius size based on the map size and assigns the
* radii based on the hotspots amenities priority.
*
* The hotspot with the highest priority e.g. the first hotspot in the list
* receives the maximum radius.
*
* Note: This method also creates the Geometry object for the hotspot
*
* @param hotspots
* Hotspots whos radius shall be calculated
* @param map
* The current map
*/
private
void
assignRadii
(
List
<
Hotspot
>
hotspots
,
OSMMap
map
)
{
PositionVector
dimensions
=
map
.
getDimensions
();
double
llsqrt
=
Math
.
sqrt
(
dimensions
.
getX
()
+
dimensions
.
getY
());
double
defaultRadius
=
0.630
*
llsqrt
;
// 0.887
int
idx
;
for
(
Hotspot
h
:
hotspots
)
{
idx
=
getAmenityIndex
(
h
.
amenity
,
existingAmenities
);
h
.
radius
=
(
defaultRadius
/
(
idx
+
1
));
h
.
geometry
=
createHotspotGeometry
(
h
);
}
}
private
Geometry
createHotspotGeometry
(
Hotspot
h
)
{
int
points
=
20
;
double
slice
=
2
*
Math
.
PI
/
points
;
ArrayList
<
Coordinate
>
coordinates
=
new
ArrayList
<
Coordinate
>();
for
(
int
i
=
0
;
i
<
points
;
i
++)
{
double
angle
=
slice
*
i
;
int
newX
=
(
int
)
(
h
.
position
.
getX
()
+
h
.
radius
*
Math
.
cos
(
angle
));
int
newY
=
(
int
)
(
h
.
position
.
getY
()
+
h
.
radius
*
Math
.
sin
(
angle
));
coordinates
.
add
(
new
Coordinate
(
newX
,
newY
));
}
coordinates
.
add
(
coordinates
.
get
(
0
));
Coordinate
[]
coordinateArray
=
new
Coordinate
[
coordinates
.
size
()];
GeometryFactory
gf
=
new
GeometryFactory
();
return
gf
.
createLinearRing
(
coordinates
.
toArray
(
coordinateArray
));
}
/**
* Adds strong way points to the graph that are used for the navigation of
* AbstractWaypointMovementModel implementations.
*
* FIXME: Find a way to place all waypoints (currently only used x retries)
* FIXME: Remove hotspots that are fully contained in an obstacle!!
*
* @param hotspots
* Hotspots to whom the new way points shall be added
*/
private
void
addStrongWaypoints
(
List
<
Hotspot
>
hotspots
)
{
double
radiiSum
=
0.0
;
for
(
Hotspot
h
:
hotspots
)
{
radiiSum
+=
h
.
radius
;
}
double
wps
=
noOfWaypoints
/
radiiSum
;
int
wpCount
=
0
;
addHotspots:
{
for
(
Hotspot
h
:
hotspots
)
{
int
nrWps
=
(
int
)
(
Math
.
round
(
wps
*
h
.
radius
));
int
retries
=
0
;
for
(
int
i
=
0
;
i
<
nrWps
;
i
++)
{
PositionVector
loc
=
selectRandomLocation
(
h
);
if
(
obstacleModel
!=
null
)
{
if
(!
obstacleModel
.
contains
(
loc
))
{
model
.
addWaypoint
(
new
StrongWaypoint
<
Object
>(
loc
));
if
(++
wpCount
>=
noOfWaypoints
)
break
addHotspots
;
}
else
{
if
(!(
retries
++
>=
placementRetries
))
i
--;
}
}
else
{
model
.
addWaypoint
(
new
StrongWaypoint
<
Object
>(
loc
));
if
(++
wpCount
>=
noOfWaypoints
)
break
addHotspots
;
}
}
}
}
Monitor
.
log
(
OSMHotspotStrategy
.
class
,
Level
.
INFO
,
"Added "
+
wpCount
+
" strong waypoints."
);
}
/**
* Selects a random location inside the hotspots radius
*
* @param hotspot
* @return
*/
private
PositionVector
selectRandomLocation
(
Hotspot
hotspot
)
{
double
theta
=
rnd
.
nextDouble
()
*
Math
.
PI
*
2
;
double
length
=
Math
.
sqrt
(
rnd
.
nextDouble
());
double
x
=
Math
.
cos
(
theta
)
*
hotspot
.
radius
*
length
;
double
y
=
Math
.
sin
(
theta
)
*
hotspot
.
radius
*
length
;
return
new
PositionVector
(
hotspot
.
position
.
getX
()
+
x
,
hotspot
.
position
.
getY
()
+
y
);
}
/**
* Returns the position of the given amenity in the validHotspots list.
*
* @param amenity
* @param validHotspots
* @return
*/
private
static
int
getAmenityIndex
(
String
amenity
,
ArrayList
<
String
>
validHotspots
)
{
if
(
validHotspots
==
null
)
return
0
;
for
(
int
i
=
0
;
i
<
validHotspots
.
size
();
i
++)
{
if
(
validHotspots
.
get
(
i
).
equals
(
amenity
))
{
return
i
;
}
}
return
-
1
;
}
/**
* Bean for hotspots
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
static
class
Hotspot
{
public
Hotspot
()
{
//
}
public
double
weight
;
public
String
amenity
;
public
PositionVector
position
;
public
String
type
;
public
double
radius
;
public
Geometry
geometry
;
public
boolean
wasHidden
=
false
;
}
/**
* Compares hotspots based on their amenity and prioritizes ways over nodes.
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
static
class
HotspotComparator
implements
Comparator
<
Hotspot
>
{
private
ArrayList
<
String
>
validHotspots
;
public
HotspotComparator
(
ArrayList
<
String
>
validHotspots
)
{
this
.
validHotspots
=
validHotspots
;
}
@SuppressWarnings
(
"synthetic-access"
)
@Override
public
int
compare
(
Hotspot
h1
,
Hotspot
h2
)
{
int
idx1
=
getAmenityIndex
(
h1
.
amenity
,
validHotspots
);
int
idx2
=
getAmenityIndex
(
h2
.
amenity
,
validHotspots
);
int
diff
=
idx1
-
idx2
;
if
(
diff
!=
0
)
{
return
diff
;
}
else
{
if
(
"way"
.
equals
(
h1
)
&&
"node"
.
equals
(
h2
))
return
1
;
if
(
"node"
.
equals
(
h1
)
&&
"way"
.
equals
(
h2
))
return
-
1
;
return
0
;
}
}
}
private
class
HotspotDeplacmentInfo
{
public
PositionVector
edge1
;
public
PositionVector
edge2
;
public
PositionVector
newPosition
;
public
PositionVector
oldPosition
;
public
HotspotDeplacmentInfo
(
PositionVector
edge1
,
PositionVector
edge2
,
PositionVector
newPosition
,
PositionVector
oldPosition
)
{
this
.
edge1
=
edge1
;
this
.
edge2
=
edge2
;
this
.
newPosition
=
newPosition
;
this
.
oldPosition
=
oldPosition
;
}
}
/**
* Draws the hotspots on the map and displays some extra information
*
* @author Fabio Zöllner
* @version 1.0, 08.04.2012
*/
private
class
ShowHotspots
extends
JComponent
{
private
List
<
Hotspot
>
hotspots
;
private
WaypointModel
model
;
public
ShowHotspots
(
List
<
Hotspot
>
hotspots
,
WaypointModel
model
)
{
super
();
this
.
hotspots
=
hotspots
;
this
.
model
=
model
;
PositionVector
dimension
=
model
.
getMap
().
getDimensions
();
setBounds
(
0
,
0
,
(
int
)
dimension
.
getX
(),
(
int
)
dimension
.
getY
());
setOpaque
(
false
);
setVisible
(
true
);
}
@Override
protected
void
paintComponent
(
Graphics
g
)
{
super
.
paintComponent
(
g
);
Graphics2D
g2
=
(
Graphics2D
)
g
;
g2
.
setFont
(
new
Font
(
"SansSerif"
,
Font
.
PLAIN
,
9
));
int
i
=
0
;
for
(
Hotspot
h
:
hotspots
)
{
if
(!
h
.
wasHidden
)
{
g2
.
setColor
(
new
Color
(
255
,
255
,
0
,
100
));
}
else
{
g2
.
setColor
(
new
Color
(
0
,
0
,
255
,
100
));
}
g2
.
fillOval
((
int
)
(
h
.
position
.
getX
()
-
h
.
radius
),
(
int
)
(
h
.
position
.
getY
()
-
h
.
radius
),
(
int
)
h
.
radius
*
2
,
(
int
)
h
.
radius
*
2
);
g2
.
setColor
(
Color
.
BLACK
);
if
(
h
.
type
!=
null
)
{
g2
.
drawString
(
h
.
type
,
(
int
)
(
h
.
position
.
getX
()
-
h
.
amenity
.
length
()
*
1.5
),
(
int
)
h
.
position
.
getY
());
}
}
drawLerp
(
g2
);
}
protected
void
drawLerp
(
Graphics2D
g2
)
{
for
(
HotspotDeplacmentInfo
l
:
hotspotMoveLerpPositions
)
{
g2
.
setColor
(
new
Color
(
0
,
0
,
0
,
255
));
g2
.
drawLine
((
int
)
l
.
edge1
.
getX
(),
(
int
)
l
.
edge1
.
getY
(),
(
int
)
l
.
edge2
.
getX
(),
(
int
)
l
.
edge2
.
getY
());
g2
.
fillOval
((
int
)
l
.
edge1
.
getX
()
-
2
,
(
int
)
l
.
edge1
.
getY
()
-
2
,
4
,
4
);
g2
.
fillOval
((
int
)
l
.
edge2
.
getX
()
-
2
,
(
int
)
l
.
edge2
.
getY
()
-
2
,
4
,
4
);
g2
.
setColor
(
new
Color
(
238
,
232
,
170
,
100
));
g2
.
fillOval
((
int
)
l
.
newPosition
.
getX
()
-
2
,
(
int
)
l
.
newPosition
.
getY
()
-
2
,
4
,
4
);
g2
.
setColor
(
new
Color
(
238
,
232
,
170
,
100
));
g2
.
drawLine
((
int
)
l
.
oldPosition
.
getX
(),
(
int
)
l
.
oldPosition
.
getY
(),
(
int
)
l
.
newPosition
.
getX
(),
(
int
)
l
.
newPosition
.
getY
());
}
}
}
}
src/de/tud/kom/p2psim/impl/util/geo/maps/AbstractMap.java
View file @
0c80da45
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.util.geo.maps
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.PriorityQueue
;
import
java.util.Queue
;
import
java.util.Set
;
import
org.jgrapht.alg.ConnectivityInspector
;
import
org.jgrapht.alg.DijkstraShortestPath
;
import
com.google.common.collect.ArrayListMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Sets
;
import
de.tud.kom.p2psim.api.scenario.ConfigurationException
;
import
de.tud.kom.p2psim.api.topology.obstacles.Obstacle
;
import
de.tud.kom.p2psim.api.util.geo.maps.Map
;
import
de.tud.kom.p2psim.api.util.geo.maps.Way
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.obstacles.PolygonObstacle
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.DefaultWeightedEdgeRetrievableGraph
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Path
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.PathEdgeFactory
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint
;
import
de.tud.kom.p2psim.impl.util.Tuple
;
import
de.tud.kom.p2psim.impl.util.geo.maps.MapChangeListener.MapEvent
;
public
abstract
class
AbstractMap
implements
Map
{
private
List
<
Obstacle
>
obstacles
=
Lists
.
newLinkedList
();
private
List
<
Path
>
paths
=
Lists
.
newLinkedList
();
protected
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>
graph
=
new
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>(
new
PathEdgeFactory
());
private
Multimap
<
Class
,
Waypoint
>
typeWaypointMap
=
ArrayListMultimap
.
create
();
protected
PositionVector
minPosition
=
new
PositionVector
(
2
);
protected
PositionVector
maxPosition
=
new
PositionVector
(
2
);
protected
List
<
Way
>
ways
=
Lists
.
newLinkedList
();
protected
boolean
[]
swapped
=
new
boolean
[
2
];
protected
String
filename
=
null
;
private
boolean
isLoaded
=
false
;
private
String
name
=
""
;
private
List
<
MapChangeListener
>
mapListeners
=
Lists
.
newLinkedList
();
// TEMP
protected
PositionVector
ppm
;
public
void
loadMap
()
{
if
(
filename
==
null
)
{
throw
new
ConfigurationException
(
"Unable to load map. Missing a filename, please make sure the configuration contains a file attribute."
);
}
doLoadMap
();
buildGraph
();
//forcefullyConnectGraphs();
removeNotConnectedGraphs
();
isLoaded
=
true
;
}
protected
abstract
void
doLoadMap
();
protected
String
getFilename
()
{
return
filename
;
}
public
void
setFile
(
String
filename
)
{
this
.
filename
=
filename
;
}
protected
void
buildGraph
()
{
graph
=
new
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>(
new
PathEdgeFactory
());
for
(
Path
path
:
paths
)
{
graph
.
addVertex
(
path
.
getSource
());
graph
.
addVertex
(
path
.
getTarget
());
typeWaypointMap
.
put
(
path
.
getSource
().
getClass
(),
path
.
getSource
());
typeWaypointMap
.
put
(
path
.
getTarget
().
getClass
(),
path
.
getTarget
());
graph
.
addEdge
(
path
.
getSource
(),
path
.
getTarget
(),
path
);
}
}
public
void
addObstacle
(
Obstacle
obstacle
)
{
obstacles
.
add
(
obstacle
);
raiseMapChanged
(
new
MapChangeListener
.
ObstacleEvent
(
obstacle
));
}
public
void
addPath
(
Path
path
)
{
paths
.
add
(
path
);
raiseMapChanged
(
new
MapChangeListener
.
PathEvent
(
path
));
}
public
List
<
Path
>
getPaths
()
{
return
paths
;
}
public
void
clearPaths
()
{
paths
.
clear
();
}
/**
* Scales the world based on the given vector: coordinate * (world /
* dimensions)
*
* @param world
*/
public
void
mapToWorld
(
PositionVector
world
)
{
PositionVector
pixelPerMeter
=
world
.
clone
();
pixelPerMeter
.
divide
(
getDimensions
());
this
.
ppm
=
pixelPerMeter
;
mapWaypoints
(
pixelPerMeter
);
mapObstacles
(
pixelPerMeter
);
raiseMapChanged
(
new
MapChangeListener
.
MapToWorldEvent
(
world
));
}
private
void
mapObstacles
(
PositionVector
pixelPerMeter
)
{
for
(
Obstacle
o
:
obstacles
)
{
PolygonObstacle
p
=
(
PolygonObstacle
)
o
;
List
<
PositionVector
>
vertices
=
p
.
getVertices
();
List
<
PositionVector
>
newVertices
=
Lists
.
newArrayList
();
for
(
PositionVector
v
:
vertices
)
{
newVertices
.
add
(
toPixelCoords
(
v
,
pixelPerMeter
));
}
p
.
rebuildPolygon
(
newVertices
);
}
}
private
void
mapWaypoints
(
PositionVector
pixelPerMeter
)
{
for
(
Waypoint
w
:
graph
.
vertexSet
())
{
w
.
setPosition
(
toPixelCoords
(
w
.
getPosition
(),
pixelPerMeter
));
}
}
protected
PositionVector
toPixelCoords
(
PositionVector
position
,
PositionVector
pixelPerMeter
)
{
PositionVector
clonedPosition
=
position
.
clone
();
PositionVector
relativePosition
=
clonedPosition
.
minus
(
getMinPosition
());
relativePosition
.
multiply
(
pixelPerMeter
);
return
relativePosition
;
}
public
List
<
Obstacle
>
getObstacles
()
{
return
obstacles
;
}
public
PositionVector
pos
(
double
x
,
double
y
)
{
return
new
PositionVector
(
x
,
y
);
}
protected
void
createPath
(
Waypoint
wp1
,
Waypoint
wp2
)
{
Path
path
=
new
Path
(
wp1
,
wp2
);
addPath
(
path
);
}
@SuppressWarnings
(
"unchecked"
)
public
DefaultWeightedEdgeRetrievableGraph
getGraph
()
{
return
graph
;
}
@Override
public
PositionVector
getMinPosition
()
{
return
cut
(
minPosition
);
}
@Override
public
PositionVector
getMaxPosition
()
{
return
cut
(
maxPosition
);
}
public
void
setMinPosition
(
PositionVector
minPosition
)
{
this
.
minPosition
=
minPosition
;
}
public
void
setMaxPosition
(
PositionVector
maxPosition
)
{
this
.
maxPosition
=
maxPosition
;
}
public
PositionVector
getDimensions
()
{
return
getMaxPosition
().
minus
(
getMinPosition
());
}
public
List
<
Way
>
getWays
()
{
return
ways
;
}
public
void
swapWorld
(
Axis
axis
,
double
max
)
{
for
(
Waypoint
w
:
graph
.
vertexSet
())
{
w
.
getPosition
().
setEntry
(
axis
.
ordinal
(),
max
-
w
.
getPosition
().
getEntry
(
axis
.
ordinal
()));
}
for
(
Obstacle
o
:
obstacles
)
{
PolygonObstacle
p
=
(
PolygonObstacle
)
o
;
List
<
PositionVector
>
vertices
=
p
.
getVertices
();
for
(
PositionVector
v
:
vertices
)
{
v
.
setEntry
(
axis
.
ordinal
(),
max
-
v
.
getEntry
(
axis
.
ordinal
()));
}
p
.
rebuildPolygon
(
vertices
);
}
swapped
[
axis
.
ordinal
()]
=
!
swapped
[
axis
.
ordinal
()];
raiseMapChanged
(
new
MapChangeListener
.
SwapMapEvent
(
axis
,
max
));
}
public
enum
Axis
{
X_AXIS
,
Y_AXIS
}
public
boolean
isSwapped
(
Axis
axis
)
{
return
swapped
[
axis
.
ordinal
()];
}
public
List
<
Path
>
getShortestPath
(
Waypoint
start
,
Waypoint
end
)
{
DijkstraShortestPath
<
Waypoint
,
Path
>
dijkstrashortestpath
=
new
DijkstraShortestPath
<
Waypoint
,
Path
>(
graph
,
start
,
end
);
return
dijkstrashortestpath
.
getPathEdgeList
();
}
public
void
addWaypoint
(
Waypoint
wp
)
{
graph
.
addVertex
(
wp
);
typeWaypointMap
.
put
(
wp
.
getClass
(),
wp
);
}
public
Collection
<
Waypoint
>
getWaypoints
(
Class
type
)
{
return
typeWaypointMap
.
get
(
type
);
}
public
boolean
isLoaded
()
{
return
this
.
isLoaded
;
}
@Override
public
String
getName
()
{
return
name
;
}
@Override
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
void
addMapChangeListener
(
MapChangeListener
listener
)
{
mapListeners
.
add
(
listener
);
}
public
void
removeMapChangeListener
(
MapChangeListener
listener
)
{
mapListeners
.
remove
(
listener
);
}
private
void
raiseMapChanged
(
MapEvent
event
)
{
for
(
MapChangeListener
l
:
mapListeners
)
{
l
.
mapChanged
(
event
);
}
}
/**
* Calculates all connected sets in the graph and removes
* all waypoints that aren't part of the largest connected set.
*/
private
void
removeNotConnectedGraphs
()
{
Queue
<
List
<
Waypoint
>>
queue
=
getConnectedComponents
();
if
(
queue
.
size
()
<=
1
)
return
;
// Remove the connected set with the highest number of
// waypoints so it won't be touched
queue
.
poll
();
List
<
Waypoint
>
waypoints
=
queue
.
poll
();
while
(
waypoints
!=
null
)
{
//removeWaypoints(waypoints, WeakWaypoint.class);
for
(
Waypoint
w
:
waypoints
)
{
Set
<
Path
>
edges
=
Sets
.
newHashSet
(
graph
.
edgesOf
(
w
));
for
(
Path
p
:
edges
)
{
graph
.
removeEdge
(
p
);
}
graph
.
removeVertex
(
w
);
}
waypoints
=
queue
.
poll
();
}
}
private
void
forcefullyConnectGraphs
()
{
Set
<
Waypoint
>
waypoints
=
graph
.
vertexSet
();
Queue
<
List
<
Waypoint
>>
queue
=
getConnectedComponents
();
if
(
queue
.
size
()
<=
1
)
return
;
queue
.
poll
();
List
<
Waypoint
>
connectedSet
=
queue
.
poll
();
while
(
connectedSet
!=
null
)
{
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>
shortestDistances
=
new
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>();
for
(
Waypoint
w
:
connectedSet
)
{
Waypoint
sd
=
findClosestWaypoint
(
w
,
waypoints
);
shortestDistances
.
add
(
new
Tuple
<
Waypoint
,
Waypoint
>(
w
,
sd
));
}
Tuple
<
Waypoint
,
Waypoint
>
shortestDistancePair
=
findClosestTuple
(
shortestDistances
);
try
{
createPath
(
shortestDistancePair
.
getA
(),
shortestDistancePair
.
getB
());
}
catch
(
IllegalArgumentException
e
)
{
//removeWaypoint(shortestDistancePair.getA());
Set
<
Path
>
edges
=
graph
.
outgoingEdgesOf
(
shortestDistancePair
.
getA
());
for
(
Path
p
:
edges
)
{
graph
.
removeEdge
(
p
);
}
graph
.
removeVertex
(
shortestDistancePair
.
getA
());
}
connectedSet
=
queue
.
poll
();
}
}
/**
* Searches for the waypoint in the set that is the closest
* to the target waypoint.
*
* @param target
* @param waypoints
* @return
*/
private
Waypoint
findClosestWaypoint
(
Waypoint
target
,
Collection
<
Waypoint
>
waypoints
)
{
double
d
=
-
1
;
Waypoint
wp
=
null
;
for
(
Waypoint
w
:
waypoints
)
{
double
ld
=
target
.
getPosition
().
getDistance
(
w
.
getPosition
());
if
(
ld
<
d
||
d
==
-
1
)
{
d
=
ld
;
wp
=
w
;
}
}
return
wp
;
}
/**
* Searches for the tuple whos two waypoints are the closest to each other.
*
* @param shortestDistances
* @return
*/
private
Tuple
<
Waypoint
,
Waypoint
>
findClosestTuple
(
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>
shortestDistances
)
{
Tuple
<
Waypoint
,
Waypoint
>
shortestDistance
=
null
;
double
d
=
-
1
;
for
(
Tuple
<
Waypoint
,
Waypoint
>
wpT
:
shortestDistances
)
{
double
ld
=
wpT
.
getA
().
getPosition
().
getDistance
(
wpT
.
getB
().
getPosition
());
if
(
ld
<
d
||
d
==
-
1
)
{
d
=
ld
;
shortestDistance
=
wpT
;
}
}
return
shortestDistance
;
}
private
Queue
<
List
<
Waypoint
>>
getConnectedComponents
()
{
ConnectivityInspector
ci
=
new
ConnectivityInspector
<
Waypoint
,
Path
>(
getGraph
());
@SuppressWarnings
(
"unchecked"
)
List
<
Set
<
Waypoint
>>
connectedSets
=
ci
.
connectedSets
();
PriorityQueue
<
List
<
Waypoint
>>
queue
=
new
PriorityQueue
<
List
<
Waypoint
>>(
1
,
new
Comparator
<
List
<
Waypoint
>>()
{
@Override
public
int
compare
(
List
<
Waypoint
>
o1
,
List
<
Waypoint
>
o2
)
{
return
o2
.
size
()
-
o1
.
size
();
}
});
for
(
Set
<
Waypoint
>
waypointSet
:
connectedSets
)
{
queue
.
add
(
new
ArrayList
<
Waypoint
>(
waypointSet
));
}
return
queue
;
}
private
PositionVector
cut
(
PositionVector
v1
)
{
int
x
=
(
int
)
v1
.
getX
();
int
y
=
(
int
)
v1
.
getY
();
PositionVector
v2
=
new
PositionVector
(
x
,
y
);
return
v2
;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.util.geo.maps
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.PriorityQueue
;
import
java.util.Queue
;
import
java.util.Set
;
import
org.jgrapht.alg.ConnectivityInspector
;
import
org.jgrapht.alg.DijkstraShortestPath
;
import
com.google.common.collect.ArrayListMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Sets
;
import
de.tud.kom.p2psim.api.scenario.ConfigurationException
;
import
de.tud.kom.p2psim.api.topology.obstacles.Obstacle
;
import
de.tud.kom.p2psim.api.util.geo.maps.Map
;
import
de.tud.kom.p2psim.api.util.geo.maps.Way
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.obstacles.PolygonObstacle
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.DefaultWeightedEdgeRetrievableGraph
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Path
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.PathEdgeFactory
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint
;
import
de.tud.kom.p2psim.impl.util.Tuple
;
import
de.tud.kom.p2psim.impl.util.geo.maps.MapChangeListener.MapEvent
;
public
abstract
class
AbstractMap
implements
Map
{
private
List
<
Obstacle
>
obstacles
=
Lists
.
newLinkedList
();
private
List
<
Path
>
paths
=
Lists
.
newLinkedList
();
protected
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>
graph
=
new
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>(
new
PathEdgeFactory
());
private
Multimap
<
Class
,
Waypoint
>
typeWaypointMap
=
ArrayListMultimap
.
create
();
protected
PositionVector
minPosition
=
new
PositionVector
(
2
);
protected
PositionVector
maxPosition
=
new
PositionVector
(
2
);
protected
List
<
Way
>
ways
=
Lists
.
newLinkedList
();
protected
boolean
[]
swapped
=
new
boolean
[
2
];
protected
String
filename
=
null
;
private
boolean
isLoaded
=
false
;
private
String
name
=
""
;
private
List
<
MapChangeListener
>
mapListeners
=
Lists
.
newLinkedList
();
// TEMP
protected
PositionVector
ppm
;
public
void
loadMap
()
{
if
(
filename
==
null
)
{
throw
new
ConfigurationException
(
"Unable to load map. Missing a filename, please make sure the configuration contains a file attribute."
);
}
doLoadMap
();
buildGraph
();
//forcefullyConnectGraphs();
removeNotConnectedGraphs
();
isLoaded
=
true
;
}
protected
abstract
void
doLoadMap
();
protected
String
getFilename
()
{
return
filename
;
}
public
void
setFile
(
String
filename
)
{
this
.
filename
=
filename
;
}
protected
void
buildGraph
()
{
graph
=
new
DefaultWeightedEdgeRetrievableGraph
<
Waypoint
,
Path
>(
new
PathEdgeFactory
());
for
(
Path
path
:
paths
)
{
graph
.
addVertex
(
path
.
getSource
());
graph
.
addVertex
(
path
.
getTarget
());
typeWaypointMap
.
put
(
path
.
getSource
().
getClass
(),
path
.
getSource
());
typeWaypointMap
.
put
(
path
.
getTarget
().
getClass
(),
path
.
getTarget
());
graph
.
addEdge
(
path
.
getSource
(),
path
.
getTarget
(),
path
);
}
}
public
void
addObstacle
(
Obstacle
obstacle
)
{
obstacles
.
add
(
obstacle
);
raiseMapChanged
(
new
MapChangeListener
.
ObstacleEvent
(
obstacle
));
}
public
void
addPath
(
Path
path
)
{
paths
.
add
(
path
);
raiseMapChanged
(
new
MapChangeListener
.
PathEvent
(
path
));
}
public
List
<
Path
>
getPaths
()
{
return
paths
;
}
public
void
clearPaths
()
{
paths
.
clear
();
}
/**
* Scales the world based on the given vector: coordinate * (world /
* dimensions)
*
* @param world
*/
public
void
mapToWorld
(
PositionVector
world
)
{
PositionVector
pixelPerMeter
=
world
.
clone
();
pixelPerMeter
.
divide
(
getDimensions
());
this
.
ppm
=
pixelPerMeter
;
mapWaypoints
(
pixelPerMeter
);
mapObstacles
(
pixelPerMeter
);
raiseMapChanged
(
new
MapChangeListener
.
MapToWorldEvent
(
world
));
}
private
void
mapObstacles
(
PositionVector
pixelPerMeter
)
{
for
(
Obstacle
o
:
obstacles
)
{
PolygonObstacle
p
=
(
PolygonObstacle
)
o
;
List
<
PositionVector
>
vertices
=
p
.
getVertices
();
List
<
PositionVector
>
newVertices
=
Lists
.
newArrayList
();
for
(
PositionVector
v
:
vertices
)
{
newVertices
.
add
(
toPixelCoords
(
v
,
pixelPerMeter
));
}
p
.
rebuildPolygon
(
newVertices
);
}
}
private
void
mapWaypoints
(
PositionVector
pixelPerMeter
)
{
for
(
Waypoint
w
:
graph
.
vertexSet
())
{
w
.
setPosition
(
toPixelCoords
(
w
.
getPosition
(),
pixelPerMeter
));
}
}
protected
PositionVector
toPixelCoords
(
PositionVector
position
,
PositionVector
pixelPerMeter
)
{
PositionVector
clonedPosition
=
position
.
clone
();
PositionVector
relativePosition
=
clonedPosition
.
minus
(
getMinPosition
());
relativePosition
.
multiply
(
pixelPerMeter
);
return
relativePosition
;
}
public
List
<
Obstacle
>
getObstacles
()
{
return
obstacles
;
}
public
PositionVector
pos
(
double
x
,
double
y
)
{
return
new
PositionVector
(
x
,
y
);
}
protected
void
createPath
(
Waypoint
wp1
,
Waypoint
wp2
)
{
Path
path
=
new
Path
(
wp1
,
wp2
);
addPath
(
path
);
}
@SuppressWarnings
(
"unchecked"
)
public
DefaultWeightedEdgeRetrievableGraph
getGraph
()
{
return
graph
;
}
@Override
public
PositionVector
getMinPosition
()
{
return
cut
(
minPosition
);
}
@Override
public
PositionVector
getMaxPosition
()
{
return
cut
(
maxPosition
);
}
public
void
setMinPosition
(
PositionVector
minPosition
)
{
this
.
minPosition
=
minPosition
;
}
public
void
setMaxPosition
(
PositionVector
maxPosition
)
{
this
.
maxPosition
=
maxPosition
;
}
public
PositionVector
getDimensions
()
{
return
getMaxPosition
().
minus
(
getMinPosition
());
}
public
List
<
Way
>
getWays
()
{
return
ways
;
}
public
void
swapWorld
(
Axis
axis
,
double
max
)
{
for
(
Waypoint
w
:
graph
.
vertexSet
())
{
w
.
getPosition
().
setEntry
(
axis
.
ordinal
(),
max
-
w
.
getPosition
().
getEntry
(
axis
.
ordinal
()));
}
for
(
Obstacle
o
:
obstacles
)
{
PolygonObstacle
p
=
(
PolygonObstacle
)
o
;
List
<
PositionVector
>
vertices
=
p
.
getVertices
();
for
(
PositionVector
v
:
vertices
)
{
v
.
setEntry
(
axis
.
ordinal
(),
max
-
v
.
getEntry
(
axis
.
ordinal
()));
}
p
.
rebuildPolygon
(
vertices
);
}
swapped
[
axis
.
ordinal
()]
=
!
swapped
[
axis
.
ordinal
()];
raiseMapChanged
(
new
MapChangeListener
.
SwapMapEvent
(
axis
,
max
));
}
public
enum
Axis
{
X_AXIS
,
Y_AXIS
}
public
boolean
isSwapped
(
Axis
axis
)
{
return
swapped
[
axis
.
ordinal
()];
}
public
List
<
Path
>
getShortestPath
(
Waypoint
start
,
Waypoint
end
)
{
DijkstraShortestPath
<
Waypoint
,
Path
>
dijkstrashortestpath
=
new
DijkstraShortestPath
<
Waypoint
,
Path
>(
graph
,
start
,
end
);
return
dijkstrashortestpath
.
getPathEdgeList
();
}
public
void
addWaypoint
(
Waypoint
wp
)
{
graph
.
addVertex
(
wp
);
typeWaypointMap
.
put
(
wp
.
getClass
(),
wp
);
}
public
Collection
<
Waypoint
>
getWaypoints
(
Class
type
)
{
return
typeWaypointMap
.
get
(
type
);
}
public
boolean
isLoaded
()
{
return
this
.
isLoaded
;
}
@Override
public
String
getName
()
{
return
name
;
}
@Override
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
void
addMapChangeListener
(
MapChangeListener
listener
)
{
mapListeners
.
add
(
listener
);
}
public
void
removeMapChangeListener
(
MapChangeListener
listener
)
{
mapListeners
.
remove
(
listener
);
}
private
void
raiseMapChanged
(
MapEvent
event
)
{
for
(
MapChangeListener
l
:
mapListeners
)
{
l
.
mapChanged
(
event
);
}
}
/**
* Calculates all connected sets in the graph and removes
* all waypoints that aren't part of the largest connected set.
*/
private
void
removeNotConnectedGraphs
()
{
Queue
<
List
<
Waypoint
>>
queue
=
getConnectedComponents
();
if
(
queue
.
size
()
<=
1
)
return
;
// Remove the connected set with the highest number of
// waypoints so it won't be touched
queue
.
poll
();
List
<
Waypoint
>
waypoints
=
queue
.
poll
();
while
(
waypoints
!=
null
)
{
//removeWaypoints(waypoints, WeakWaypoint.class);
for
(
Waypoint
w
:
waypoints
)
{
Set
<
Path
>
edges
=
Sets
.
newHashSet
(
graph
.
edgesOf
(
w
));
for
(
Path
p
:
edges
)
{
graph
.
removeEdge
(
p
);
}
graph
.
removeVertex
(
w
);
}
waypoints
=
queue
.
poll
();
}
}
private
void
forcefullyConnectGraphs
()
{
Set
<
Waypoint
>
waypoints
=
graph
.
vertexSet
();
Queue
<
List
<
Waypoint
>>
queue
=
getConnectedComponents
();
if
(
queue
.
size
()
<=
1
)
return
;
queue
.
poll
();
List
<
Waypoint
>
connectedSet
=
queue
.
poll
();
while
(
connectedSet
!=
null
)
{
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>
shortestDistances
=
new
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>();
for
(
Waypoint
w
:
connectedSet
)
{
Waypoint
sd
=
findClosestWaypoint
(
w
,
waypoints
);
shortestDistances
.
add
(
new
Tuple
<
Waypoint
,
Waypoint
>(
w
,
sd
));
}
Tuple
<
Waypoint
,
Waypoint
>
shortestDistancePair
=
findClosestTuple
(
shortestDistances
);
try
{
createPath
(
shortestDistancePair
.
getA
(),
shortestDistancePair
.
getB
());
}
catch
(
IllegalArgumentException
e
)
{
//removeWaypoint(shortestDistancePair.getA());
Set
<
Path
>
edges
=
graph
.
outgoingEdgesOf
(
shortestDistancePair
.
getA
());
for
(
Path
p
:
edges
)
{
graph
.
removeEdge
(
p
);
}
graph
.
removeVertex
(
shortestDistancePair
.
getA
());
}
connectedSet
=
queue
.
poll
();
}
}
/**
* Searches for the waypoint in the set that is the closest
* to the target waypoint.
*
* @param target
* @param waypoints
* @return
*/
private
Waypoint
findClosestWaypoint
(
Waypoint
target
,
Collection
<
Waypoint
>
waypoints
)
{
double
d
=
-
1
;
Waypoint
wp
=
null
;
for
(
Waypoint
w
:
waypoints
)
{
double
ld
=
target
.
getPosition
().
distanceTo
(
w
.
getPosition
());
if
(
ld
<
d
||
d
==
-
1
)
{
d
=
ld
;
wp
=
w
;
}
}
return
wp
;
}
/**
* Searches for the tuple whos two waypoints are the closest to each other.
*
* @param shortestDistances
* @return
*/
private
Tuple
<
Waypoint
,
Waypoint
>
findClosestTuple
(
ArrayList
<
Tuple
<
Waypoint
,
Waypoint
>>
shortestDistances
)
{
Tuple
<
Waypoint
,
Waypoint
>
shortestDistance
=
null
;
double
d
=
-
1
;
for
(
Tuple
<
Waypoint
,
Waypoint
>
wpT
:
shortestDistances
)
{
double
ld
=
wpT
.
getA
().
getPosition
()
.
distanceTo
(
wpT
.
getB
().
getPosition
());
if
(
ld
<
d
||
d
==
-
1
)
{
d
=
ld
;
shortestDistance
=
wpT
;
}
}
return
shortestDistance
;
}
private
Queue
<
List
<
Waypoint
>>
getConnectedComponents
()
{
ConnectivityInspector
ci
=
new
ConnectivityInspector
<
Waypoint
,
Path
>(
getGraph
());
@SuppressWarnings
(
"unchecked"
)
List
<
Set
<
Waypoint
>>
connectedSets
=
ci
.
connectedSets
();
PriorityQueue
<
List
<
Waypoint
>>
queue
=
new
PriorityQueue
<
List
<
Waypoint
>>(
1
,
new
Comparator
<
List
<
Waypoint
>>()
{
@Override
public
int
compare
(
List
<
Waypoint
>
o1
,
List
<
Waypoint
>
o2
)
{
return
o2
.
size
()
-
o1
.
size
();
}
});
for
(
Set
<
Waypoint
>
waypointSet
:
connectedSets
)
{
queue
.
add
(
new
ArrayList
<
Waypoint
>(
waypointSet
));
}
return
queue
;
}
private
PositionVector
cut
(
PositionVector
v1
)
{
int
x
=
(
int
)
v1
.
getX
();
int
y
=
(
int
)
v1
.
getY
();
PositionVector
v2
=
new
PositionVector
(
x
,
y
);
return
v2
;
}
}
src/de/tud/kom/p2psim/impl/util/positioning/GeoSpherePosition.java
View file @
0c80da45
...
...
@@ -4,7 +4,6 @@ import java.util.Map;
import
java.util.Random
;
import
java.util.WeakHashMap
;
import
de.tud.kom.p2psim.api.common.Position
;
import
de.tud.kom.p2psim.impl.network.modular.common.GeoToolkit
;
import
de.tudarmstadt.maki.simonstrator.api.Randoms
;
import
de.tudarmstadt.maki.simonstrator.api.common.Transmitable
;
...
...
@@ -17,7 +16,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
*
* @author Andreas Hemel
*/
public
class
GeoSpherePosition
implements
Transmitable
,
Posi
tion
{
public
class
GeoSpherePosition
implements
Transmitable
,
Loca
tion
{
/** Latitude in radians */
private
final
double
latitude
;
...
...
@@ -131,7 +130,7 @@ public class GeoSpherePosition implements Transmitable, Position {
* @return The distance in meters.
*/
@Override
public
double
getD
istance
(
Posi
tion
destination
)
{
public
double
d
istance
To
(
Loca
tion
destination
)
{
GeoSpherePosition
dest
=
(
GeoSpherePosition
)
destination
;
if
(
enableDistanceCache
)
{
Double
cached
=
checkDistanceCache
(
this
,
dest
);
...
...
@@ -163,8 +162,8 @@ public class GeoSpherePosition implements Transmitable, Position {
}
@Override
public
double
getAngle
(
Posi
tion
target
)
{
return
-
getBearing
(
target
)
+
180
;
public
float
bearingTo
(
Loca
tion
target
)
{
return
(
float
)
(
-
getBearing
(
target
)
+
180
)
;
}
/** Calculate the initial bearing to target on a great circle in degrees.
...
...
@@ -177,7 +176,7 @@ public class GeoSpherePosition implements Transmitable, Position {
*
* @return The initial bearing in degrees.
*/
public
double
getBearing
(
Posi
tion
target
)
{
public
double
getBearing
(
Loca
tion
target
)
{
return
Math
.
toDegrees
(
getBearingRad
(
target
));
}
...
...
@@ -188,7 +187,7 @@ public class GeoSpherePosition implements Transmitable, Position {
*
* @return The initial bearing in radians.
*/
public
double
getBearingRad
(
Posi
tion
destination
)
{
public
double
getBearingRad
(
Loca
tion
destination
)
{
GeoSpherePosition
dest
=
(
GeoSpherePosition
)
destination
;
if
(
enableBearingCache
)
{
Double
cached
=
checkBearingCache
(
this
,
dest
);
...
...
@@ -228,11 +227,6 @@ public class GeoSpherePosition implements Transmitable, Position {
return
getDestinationRad
(
Math
.
toRadians
(
bearing
),
distance
);
}
@Override
public
GeoSpherePosition
getTarget
(
double
distance
,
double
angle
)
{
return
getDestinationRad
(
angle
,
distance
);
}
/** Calculate the destination position given a bearing and a distance.
*
* The formulae used here assume a spherical Earth, so this calculation has
...
...
@@ -448,14 +442,4 @@ public class GeoSpherePosition implements Transmitable, Position {
public
long
getAgeOfLocation
()
{
throw
new
UnsupportedOperationException
();
}
@Override
public
double
distanceTo
(
Location
dest
)
{
return
getDistance
((
Position
)
dest
);
}
@Override
public
float
bearingTo
(
Location
dest
)
{
return
(
float
)
getBearing
((
Position
)
dest
);
}
}
src/de/tud/kom/p2psim/impl/util/structures/WaypointKdTree.java
View file @
0c80da45
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.util.structures
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint
;
public
class
WaypointKdTree
extends
KdTree
<
Waypoint
>
{
public
WaypointKdTree
(
int
dimensions
)
{
super
(
dimensions
,
null
);
}
@Override
protected
double
pointDist
(
double
[]
p1
,
double
[]
p2
)
{
return
new
PositionVector
(
p1
).
getD
istance
(
new
PositionVector
(
p2
));
}
@Override
protected
double
pointRegionDist
(
double
[]
point
,
double
[]
min
,
double
[]
max
)
{
// FIXME: Implement (if required)
return
0
;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package
de.tud.kom.p2psim.impl.util.structures
;
import
de.tud.kom.p2psim.impl.topology.PositionVector
;
import
de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint
;
public
class
WaypointKdTree
extends
KdTree
<
Waypoint
>
{
public
WaypointKdTree
(
int
dimensions
)
{
super
(
dimensions
,
null
);
}
@Override
protected
double
pointDist
(
double
[]
p1
,
double
[]
p2
)
{
return
new
PositionVector
(
p1
).
d
istance
To
(
new
PositionVector
(
p2
));
}
@Override
protected
double
pointRegionDist
(
double
[]
point
,
double
[]
min
,
double
[]
max
)
{
// FIXME: Implement (if required)
return
0
;
}
}
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment