package cz.agents.dbtokmlexporter.kmlitem;
import com.vividsolutions.jts.geom.*;
import cz.agents.agentpolis.tools.geovisio.projection.ProjectionTransformer;
import cz.agents.alite.googleearth.updates.Kmz;
import cz.agents.dbtokmlexporter.factory.geometry.GeometryFactory;
import cz.agents.dbtokmlexporter.factory.style.StyleFactory;
import cz.agents.resultsvisio.kml.TimeKmlItem;
import cz.agents.resultsvisio.kml.util.TimeKmlFormater;
import de.micromata.opengis.kml.v_2_2_0.*;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.gx.Coord;
import de.micromata.opengis.kml.v_2_2_0.gx.Track;
import de.micromata.opengis.kml.v_2_2_0.gx.custom.TrackPoint;
import org.apache.log4j.Logger;
import java.util.*;
/**
*
* @author Marek Cuchy
*
*/
public class InterpolatedTimeKmlItem implements TimeKmlItem {
private static final Logger logger = Logger.getLogger(InterpolatedTimeKmlItem.class);
private final StyleFactory styleFactory;
private final ProjectionTransformer transformer;
private final long endTime;
/**
* Define if as end time of the last interval for some id is used
* {@code endTime} argument or {@code intervalDuration} argument.
*/
private final boolean useEndTime;
private final long intervalDuration;
public InterpolatedTimeKmlItem(ProjectionTransformer transformer, StyleFactory styleFactory,
GeometryFactory geometryFactory, long endTime,
boolean useEndTime, long intervalDuration) {
super();
this.styleFactory = styleFactory;
this.endTime = endTime;
this.useEndTime = useEndTime;
this.intervalDuration = intervalDuration;
this.transformer = transformer;
}
public InterpolatedTimeKmlItem(ProjectionTransformer transformer, StyleFactory styleFactory,
GeometryFactory geometryFactory, int endTime) {
this(transformer, styleFactory, geometryFactory, endTime, true, 0);
}
public InterpolatedTimeKmlItem(StyleFactory styleFactory,
GeometryFactory geometryFactory, int endTime) {
this(null, styleFactory, geometryFactory, endTime, true, 0);
}
public InterpolatedTimeKmlItem(StyleFactory styleFactory,
GeometryFactory geometryFactory, long endTime,
boolean useEndTime, long intervalDuration) {
this(null, styleFactory, geometryFactory, endTime, useEndTime, intervalDuration);
}
private Map<String, TimeRecords> recordMap = new HashMap<>();
@Override
public Folder initFeatureForKml(Kmz kmz) {
Folder folder = new Folder();
Style style = styleFactory.createStyle();
folder.addToStyleSelector(style);
// add LookAt KML tag to folder
Map.Entry<String, TimeRecords> firstRecord = recordMap.entrySet().iterator().next();
if (firstRecord != null) {
LookAt lookat = new LookAt();
lookat.setLatitude(firstRecord.getValue().getFinalRecords().get(0).coord.getLatitude());
lookat.setLongitude(firstRecord.getValue().getFinalRecords().get(0).coord.getLongitude());
lookat.setAltitude(3000);
lookat.setAltitudeMode(AltitudeMode.RELATIVE_TO_GROUND);
lookat.setRange(500);
lookat.setTilt(15);
lookat.setHeading(0);
folder.setAbstractView(lookat);
}
for (TimeRecords timeRecords : recordMap.values()) {
Placemark p = new Placemark();
p.setId(timeRecords.id);
p.setDescription(timeRecords.description);
p.withStyleUrl("#" + style.getId());
Track track = new Track();
List<Record> records = timeRecords.getFinalRecords();
for (int i = 0; i < records.size(); i++) {
Record record = records.get(i);
// long time = useEndTime ? Math.min(record.time, endTime) : record.time;
long time;
if (useEndTime) {
time = Math.min(record.time, endTime);
} else {
time = record.time;
}
TrackPoint trackPoint = new TrackPoint(TimeKmlFormater.getTimeForKML(time));
Coordinate tmpCoord = record.coord;
com.vividsolutions.jts.geom.Coordinate coordinate =
new com.vividsolutions.jts.geom.Coordinate(tmpCoord.getLongitude(), tmpCoord.getLatitude());
Coord kmlCoordinate = new Coord(coordinate.x, coordinate.y);
trackPoint.setCoord(kmlCoordinate);
track.withTrackPoint(trackPoint);
}
p.setGeometry(track);
folder.addToFeature(p);
}
return folder;
}
public void addTimeGeometry(String id, Coordinate[] coords, long time, String description) {
addToRecordMap(id, coords[0], time, description);
}
private void addToRecordMap(String id, Coordinate coord, long time, String description) {
TimeRecords timeRecords = recordMap.get(id);
if (timeRecords == null) {
timeRecords = new TimeRecords(id, description);
recordMap.put(id, timeRecords);
}
timeRecords.add(coord, time);
}
static int skipCounter = 0;
static int totalCounter = 0;
public class TimeRecords {
String id;
List<Record> records = new ArrayList<>();
Record lastRecord;
String description;
public TimeRecords(String id, String description) {
this.id = id;
this.description = description;
}
public List<Record> getFinalRecords() {
if (lastRecord == null) {
// logger.debug(id + " wut?");
// logger.debug(records);
} else {
// if (id.endsWith("Id244"))
// logger.debug(id + " Time - finished repeated: " + TimeKmlFormater.getTimeForKML(lastRecord
// .time) + " " + lastRecord.coord);
records.add(lastRecord);
}
return records;
}
public void add(Coordinate coord, long time) {
int lastIndex = records.size() - 1;
Record record = new Record(coord, time);
if (lastIndex >= 0 && records.get(lastIndex).equalsIgnoringTime(record)) {
// if (id.endsWith("Id244"))
// logger.debug(id + " Time - repeated: " + TimeKmlFormater.getTimeForKML(time) + " " + record.coord);
lastRecord = record;
skipCounter++;
} else {
if (lastRecord != null) {
// if (id.endsWith("Id244"))
// logger.debug(id + " Time - finished repeated: " + TimeKmlFormater.getTimeForKML(lastRecord
// .time) + " " + lastRecord.coord);
records.add(lastRecord);
}
// if (id.endsWith("Id244"))
// logger.debug(id + " Time: " + TimeKmlFormater.getTimeForKML(time) + " " + record.coord);
records.add(record);
lastRecord = null;
}
totalCounter++;
}
}
private class Record {
public final Coordinate coord;
public final long time;
public Record(Coordinate coord, long time) {
super();
this.coord = coord;
this.time = time;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + coord.hashCode();
return result;
}
public boolean equalsIgnoringTime(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Record other = (Record) obj;
if (coord != null && !coord.equals(other.coord)) return false;
if (other.coord != null && !other.coord.equals(coord)) return false;
return true;
}
}
}