package cz.agents.dbtokmlexporter.kmlitem; 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.dbtokmlexporter.kmlitem.InterpolatedTimeKmlItem.TimeRecords; import cz.agents.resultsvisio.kml.TimeKmlItem; import cz.agents.resultsvisio.kml.util.TimeKmlFormater; import de.micromata.opengis.kml.v_2_2_0.*; import org.apache.log4j.Logger; import java.util.*; /** * * @author Marek Cuchy * */ public class NonInterpolatedTimeKmlItem implements TimeKmlItem { private static final Logger logger = Logger.getLogger(NonInterpolatedTimeKmlItem.class); private final StyleFactory styleFactory; private final GeometryFactory geometryFactory; 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 NonInterpolatedTimeKmlItem(ProjectionTransformer transformer, StyleFactory styleFactory, GeometryFactory geometryFactory, long endTime, boolean useEndTime, long intervalDuration) { super(); this.styleFactory = styleFactory; this.geometryFactory = geometryFactory; this.endTime = endTime; this.useEndTime = useEndTime; this.intervalDuration = intervalDuration; } public NonInterpolatedTimeKmlItem(StyleFactory styleFactory, GeometryFactory geometryFactory, long endTime, boolean useEndTime, long intervalDuration) { super(); this.styleFactory = styleFactory; this.geometryFactory = geometryFactory; this.endTime = endTime; this.useEndTime = useEndTime; this.intervalDuration = intervalDuration; } public NonInterpolatedTimeKmlItem(ProjectionTransformer transformer, StyleFactory styleFactory, GeometryFactory geometryFactory, int endTime) { this(transformer, styleFactory, geometryFactory, endTime, true, 0); } public NonInterpolatedTimeKmlItem(StyleFactory styleFactory, GeometryFactory geometryFactory, int endTime) { this(styleFactory, geometryFactory, endTime, true, 0); } private Map<String, TimeRecords> recordMap = new HashMap<>(); @Override public Folder initFeatureForKml(Kmz kmz) { Folder folder = new Folder(); Style style = styleFactory.createStyle(); folder.addToStyleSelector(style); for (TimeRecords timeRecords : recordMap.values()) { List<Record> records = timeRecords.getFinalRecords(); for (int i = 0; i < records.size(); i++) { Record record = records.get(i); Placemark p = new Placemark(); p.setId(record.id); p.setDescription(record.description); p.setGeometry(geometryFactory.createGeometry(record.coords)); p.withStyleUrl("#" + style.getId()); TimeSpan timeSpan = new TimeSpan(); timeSpan.setBegin(TimeKmlFormater.getTimeForKML(record.time)); long timeSpanEnd; if (i >= records.size() - 1) { if (useEndTime) { timeSpanEnd = endTime; } else { timeSpanEnd = record.time + intervalDuration - 1000; } } else { Record r = records.get(i + 1); if (r == null) { records.remove(i + 1); timeSpanEnd = record.time + intervalDuration - 1000; } else { timeSpanEnd = records.get(i + 1).time - 1000; } } timeSpan.setEnd(TimeKmlFormater.getTimeForKML(timeSpanEnd)); p.withTimePrimitive(timeSpan); folder.addToFeature(p); } } // 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().iterator().next().coords[0].getLatitude()); lookat.setLongitude(firstRecord.getValue().getFinalRecords().iterator().next().coords[0].getLongitude()); lookat.setAltitude(3000); lookat.setAltitudeMode(AltitudeMode.RELATIVE_TO_GROUND); lookat.setRange(500); lookat.setTilt(15); lookat.setHeading(0); folder.setAbstractView(lookat); } return folder; } public void addTimeGeometry(String id, Coordinate[] coords, long time, String description) { addToRecordMap(id, coords, time, description); } private void addToRecordMap(String id, Coordinate[] coords, long time, String description) { TimeRecords timeRecords = recordMap.get(id); if (timeRecords == null) { timeRecords = new TimeRecords(id); recordMap.put(id, timeRecords); } timeRecords.add(coords, time, description); } static int skipCounter = 0; static int totalCounter = 0; private class TimeRecords { String id; List<Record> records = new ArrayList<>(); Record lastRecord; public TimeRecords(String id) { this.id = id; } public List<Record> getFinalRecords() { if (lastRecord == null) { // logger.debug(records); } records.add(lastRecord); return records; } public void add(Coordinate[] coords, long time, String description) { int lastIndex = records.size() - 1; Record record = new Record(id, coords, time, description); if (lastIndex >= 0 && records.get(lastIndex).equalsIgnoringTime(record)) { lastRecord = record; skipCounter++; } else { records.add(record); } totalCounter++; } } private class Record { public final String id; public final Coordinate[] coords; public final long time; public final String description; public Record(String id, Coordinate[] coords, long time, String description) { super(); this.id = id; this.coords = coords; this.time = time; this.description = description; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(coords); result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } public boolean equalsIgnoringTime(Object obj) { return false; // if (this == obj) return true; // if (obj == null) return false; // if (getClass() != obj.getClass()) return false; // Record other = (Record) obj; // if (!Arrays.equals(coords, other.coords)) return false; // if (description == null) { // if (other.description != null) return false; // } else if (!description.equals(other.description)) return false; // if (id == null) { // if (other.id != null) return false; // } else if (!id.equals(other.id)) return false; // return true; } } }