/* * RestCycle.java - Copyright(c) 2013, 2014 Joe Pasqua * Provided under the MIT License. See the LICENSE file for details. * Created: Nov 25, 2014 */ package org.noroomattheinn.visibletesla.data; import java.util.Calendar; import java.util.List; import java.util.Locale; /** * Object that represents a single rest cycle. A rest cycle is a period where * the car is sitting parked and not charging for greater than a minimum period. * Rest cycles are interesting for determining the rate of vampire loss. * * @author Joe Pasqua <joe at NoRoomAtTheInn dot org> */ public class RestCycle extends BaseCycle { /*============================================================================== * ------- ------- * ------- Public Interface To This Class ------- * ------- ------- *============================================================================*/ public double startRange, endRange; public double startSOC, endSOC; public RestCycle() { } public RestCycle(RestCycle basis) { this.startTime = basis.startTime; this.endTime = basis.endTime; this.startRange = basis.startRange; this.endRange = basis.endRange; this.startSOC = basis.startSOC; this.endSOC = basis.endSOC; this.lat = basis.lat; this.lng = basis.lng; } @Override public String toJSONString() { return String.format(Locale.US, // Get the correct decimal point char "{ " + " \"startTime\": %d, " + " \"endTime\": %d, " + " \"startRange\": %.1f, " + " \"endRange\": %.1f, " + " \"startSOC\": %.1f, " + " \"endSOC\": %.1f, " + " \"lat\": %.6f, " + " \"lng\": %.6f " + " }", startTime, endTime, startRange, endRange, startSOC, endSOC, lat, lng); } /** * Return the loss in range over this RestCycle * @return The loss in range. Always given in miles. */ public double loss() { return startRange - endRange; } /** * Return the average loss in range per hour over this RestCycle. * @return The average loss/hour. Always given in miles/hour. */ public double avgLoss() { return loss() / hours(endTime - startTime); } /** * This RestCycle may span multiple days, split it into a List of RestCycles * that each covers at most one day. * @param splitList A list of RestCycles with at least one element. */ public void splitIntoDays(List<RestCycle> splitList) { int startDay = dayOf(startTime); int endDay = dayOf(endTime); if (startDay != endDay) { long endOfDay = endOfDay(startTime); double ratio = ((double)(endOfDay - startTime))/ ((double)(endTime - startTime)); double newEndRange = startRange - ((startRange - endRange) * ratio); double newEndSOC = startSOC - ((startSOC - endSOC) * ratio); RestCycle first = new RestCycle(this); first.endTime = endOfDay; first.endRange = newEndRange; first.endSOC = newEndSOC; splitList.add(first); RestCycle remainder = new RestCycle(this); remainder.startTime = endOfDay + 2000; // Inch into the next day remainder.startRange = newEndRange; remainder.endSOC = newEndSOC; remainder.splitIntoDays(splitList); } else { splitList.add(this); } } /*------------------------------------------------------------------------------ * * PRIVATE Utility Methods * *----------------------------------------------------------------------------*/ private double hours(long millis) {return ((double)(millis))/(60 * 60 * 1000); } private int dayOf(long time) { Calendar c = Calendar.getInstance(); c.setTimeInMillis(time); return c.get(Calendar.DAY_OF_YEAR); } private long endOfDay(long time) { Calendar c = Calendar.getInstance(); c.setTimeInMillis(time); c.set(Calendar.HOUR_OF_DAY, 23); c.set(Calendar.MINUTE, 59); c.set(Calendar.SECOND, 59); return c.getTimeInMillis(); } }