/*
* Copyright (C) 2006 Steve Ratcliffe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program 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.
*
*
* Author: Steve Ratcliffe
* Create date: 18-Dec-2006
*/
package uk.me.parabola.mkgmap.general;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction;
import uk.me.parabola.imgfmt.app.net.RoadNetwork;
import uk.me.parabola.imgfmt.app.trergn.Overview;
import uk.me.parabola.imgfmt.app.trergn.PointOverview;
import uk.me.parabola.imgfmt.app.trergn.PolygonOverview;
import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.filters.ShapeMergeFilter;
import uk.me.parabola.mkgmap.reader.osm.GType;
import uk.me.parabola.util.EnhancedProperties;
/**
* The map features that we are going to map are collected here.
*
* @author Steve Ratcliffe
*/
public class MapDetails
implements MapCollector, MapDataSource
{
private static final Logger log =
Logger.
getLogger(MapDetails.
class);
private final List<MapLine
> lines =
new ArrayList<>();
private final List<MapShape
> shapes =
new ArrayList<>();
private final List<MapPoint
> points =
new ArrayList<>();
private int minLatHp =
Integer.
MAX_VALUE;
private int minLonHp =
Integer.
MAX_VALUE;
private int maxLatHp =
Integer.
MIN_VALUE;
private int maxLonHp =
Integer.
MIN_VALUE;
// Keep lists of all items that were used.
private final Map<Integer,
Integer> pointOverviews =
new HashMap<>();
private final Map<Integer,
Integer> lineOverviews =
new HashMap<>();
private final Map<Integer,
Integer> shapeOverviews =
new HashMap<>();
private final RoadNetwork roadNetwork =
new RoadNetwork
();
public void config
(EnhancedProperties props
) {
roadNetwork.
config(props
);
}
/**
* Add a point to the map.
*
* @param point Point to add.
*/
public void addPoint
(MapPoint point
) {
updateOverview
(pointOverviews, point.
getType(), point.
getMinResolution());
points.
add(point
);
}
/**
* Add a line to the map.
*
* @param line The line information.
*/
public void addLine
(MapLine line
) {
assert !(line
instanceof MapShape
);
if (line.
getPoints().
isEmpty())
return;
int type
;
if(line.
hasExtendedType())
type = line.
getType();
else
type = line.
getType() << 8;
updateOverview
(lineOverviews, type, line.
getMinResolution());
lines.
add(line
);
}
/**
* Add the given shape (polygon) to the map. A shape is very similar to a
* line but they are separate because they need to be put in different
* sections in the output map.
*
* @param shape The polygon to add.
*/
public void addShape
(MapShape shape
) {
if (shape.
getPoints().
size() < 4)
return;
if (ShapeMergeFilter.
calcAreaSizeTestVal(shape.
getPoints()) ==
0){
log.
info("ignoring shape with id", shape.
getOsmid(),
"and type",
GType.
formatType(shape.
getType()) +
", it",
(shape.
wasClipped() ? "was clipped to" :
"has"),
shape.
getPoints().
size(),
"points and has an empty area ");
return;
}
int type
;
if(shape.
hasExtendedType())
type = shape.
getType();
else
type = shape.
getType() << 8;
updateOverview
(shapeOverviews, type, shape.
getMinResolution());
shapes.
add(shape
);
}
public void addRoad
(MapRoad road
) {
roadNetwork.
addRoad(road.
getRoadDef(), road.
getPoints());
addLine
(road
);
}
public int addRestriction
(GeneralRouteRestriction grr
) {
return roadNetwork.
addRestriction(grr
);
}
/**
* Add the given point to the total bounds for the map.
*
* @param p The coordinates of the point to add.
*/
public void addToBounds
(Coord p
) {
int latHp = p.
getHighPrecLat();
int lonHp = p.
getHighPrecLon();
if (latHp
< minLatHp
)
minLatHp = latHp
;
if (latHp
> maxLatHp
)
maxLatHp = latHp
;
if (lonHp
< minLonHp
)
minLonHp = lonHp
;
if (lonHp
> maxLonHp
)
maxLonHp = lonHp
;
}
/**
* Get the bounds of this map.
*
* @return An area covering all the points in the map.
*/
public Area getBounds
() {
if (minLatHp ==
Integer.
MAX_VALUE) // nothing called addToBounds
return new Area(1,
1, -
1, -
1); // return invalid bbox that doesn't break signed 3 byte IO in img file
int minLat = minLatHp
>> Coord.
DELTA_SHIFT;
int maxLat = maxLatHp
>> Coord.
DELTA_SHIFT;
int minLon = minLonHp
>> Coord.
DELTA_SHIFT;
int maxLon = maxLonHp
>> Coord.
DELTA_SHIFT;
if ((maxLat
<< Coord.
DELTA_SHIFT) < maxLatHp
)
maxLat++
;
if ((maxLon
<< Coord.
DELTA_SHIFT) < maxLonHp
)
maxLon++
;
return new Area(minLat, minLon, maxLat, maxLon
);
}
public List<MapPoint
> getPoints
() {
return points
;
}
/**
* Get all the lines for this map.
*
* @return A list of all lines defined for this map.
*/
public List<MapLine
> getLines
() {
return lines
;
}
public List<MapShape
> getShapes
() {
return shapes
;
}
public RoadNetwork getRoadNetwork
() {
return roadNetwork
;
}
/**
* Get the overviews. We construct them at this point from the information
* that we have built up.
* Perhaps this could be a separate class rather than a list.
*
* @return A list of overviews.
*/
public List<Overview
> getOverviews
() {
List<Overview
> ovlist =
new ArrayList<>();
for (Map.Entry<Integer,
Integer> ent : pointOverviews.
entrySet()) {
Overview ov =
new PointOverview
(ent.
getKey(), ent.
getValue());
ovlist.
add(ov
);
}
for (Map.Entry<Integer,
Integer> ent : lineOverviews.
entrySet()) {
Overview ov =
new PolylineOverview
(ent.
getKey(), ent.
getValue());
ovlist.
add(ov
);
}
for (Map.Entry<Integer,
Integer> ent : shapeOverviews.
entrySet()) {
Overview ov =
new PolygonOverview
(ent.
getKey(), ent.
getValue());
ovlist.
add(ov
);
}
return ovlist
;
}
private static void updateOverview
(Map<Integer,
Integer> overviews,
int type,
int minResolution
) {
Integer prev = overviews.
get(type
);
if (prev ==
null || minResolution
< prev
)
overviews.
put(type, minResolution
);
}
}