/** Copyright 2015 Tim Engler, Rareventure LLC This file is part of Tiny Travel Tracker. Tiny Travel Tracker 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 (at your option) any later version. Tiny Travel Tracker 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 Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>. */ package com.rareventure.gps2.database; import java.util.ArrayList; import java.util.Collections; import com.rareventure.android.Util; /** * Keeps track of data set of lonm values. Finds the largest gap between points and ranges of lonm data, * so that a continuous block of lonm data that is narrowest can be found * @author tim * */ public class LonmDataSet { private ArrayList<LonmData> data = new ArrayList<LonmData>(); private boolean calcFinished; private int start; private int end; private boolean isInfinite; public LonmDataSet() { } public void addPoint(int lonm) { calcFinished = false; data.add(new LonmData(lonm,lonm)); } /** * Note this must be in order from left to right. If it over extends +/- 180M, that's alright. * @param lonm1 * @param lonm2 */ public void addRange(int lonm1, int lonm2) { calcFinished = false; data.add(new LonmData(Util.normalizeLonm(lonm1),Util.normalizeLonm(lonm2))); } /** * Adds a range using doubles. Items will be rounded to a range that includes the specified one * and is composed of ints */ public void addRangeWithWidth(double lonm1, double width) { if(width < 0) addRange((int)Math.floor(lonm1+width), (int)Math.ceil(lonm1)); else addRange((int)Math.floor(lonm1), (int)Math.ceil(lonm1+width)); } /** * Add a range using a starting position and width * @param lonm1 * @param width */ public void addRangeWithWidth(int lonm1, int width) { int lonm2; if(width < 0) { lonm2 = lonm1; lonm1 = lonm2 + width; } else { lonm2 = lonm1 + width; } addRange(lonm1, lonm2); } private void finishCalc() { if(!calcFinished) { calcFinished = true; if(isInfinite) return; //we need to find the maximum distance between points, which will determine where we don't //want the center of this guy to be Collections.sort(data); int largestGapEndPos = 0; //the end position of the largest gap in the data int largestGapSize = 0; // the size of the largest gap in data //first we need to find the maximum end value, and subtract 360 degrees. //This becomes the end of the last range when we are evaluating the first point int lastRangeEnd = Util.MIN_LONM; for(int i = 0; i < data.size(); i++) { int currRangeEnd = data.get(i).v2; if(data.get(i).v2 < data.get(i).v1) // if we wrapped around the end currRangeEnd += Util.LONM_PER_WORLD; //by adding 360 degrees, //we are making the guys the wrap around have a later range end then the guys that don't, //which is what should be correct if(lastRangeEnd < currRangeEnd) lastRangeEnd = currRangeEnd; } lastRangeEnd -= Util.LONM_PER_WORLD; for(int i = 0; i < data.size(); i++) { LonmData llsd = data.get(i); //if the current gap is greater than the max if(llsd.v1 - lastRangeEnd > largestGapSize) { largestGapSize = llsd.v1 - lastRangeEnd; largestGapEndPos = llsd.v1; } //since the point may extend past 179.9999M we need to make sure we have a range end //that is beyond 180M so that when we compare it, it won't be negative int currRangeEnd = Util.makeContinuousFromStartLonm(llsd.v1, llsd.v2); //if the range end of the current point extends past the range of the last if(lastRangeEnd < currRangeEnd) lastRangeEnd = currRangeEnd; } if(largestGapSize == 0) { isInfinite = true; } else { end = Util.normalizeLonm(largestGapEndPos - largestGapSize); start = largestGapEndPos; } } } public int getStartLonm() { finishCalc(); return start; } public int getWidth() { finishCalc(); if(start == Integer.MIN_VALUE) return Util.LONM_PER_WORLD; return Util.makeContinuousFromStartLonm(start, end) - start; } private static class LonmData implements Comparable<LonmData> { public LonmData(int lonm1, int lonm2) { this.v1 = lonm1; this.v2 = lonm2; } public int v1,v2; @Override public int compareTo(LonmData another) { return this.v1 - another.v1; } } public boolean isInfinite() { return isInfinite; } public void addInfiniteRange() { isInfinite = true; } }