package com.kuxhausen.huemore.persistence;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
import com.kuxhausen.huemore.persistence.Definitions.MoodColumns;
import com.kuxhausen.huemore.state.Mood;
import com.kuxhausen.huemore.utils.DeferredLog;
import java.util.Calendar;
public class Utils {
public static
@Nullable
Mood getMoodFromDatabase(String moodName, Context ctx) {
String[] moodColumns = {MoodColumns.COL_MOOD_VALUE};
String[] mWhereClause = {moodName};
Cursor moodCursor =
ctx.getContentResolver().query(Definitions.MoodColumns.MOODS_URI, moodColumns,
MoodColumns.COL_MOOD_NAME + "=?", mWhereClause, null);
if (!moodCursor.moveToFirst()) {
moodCursor.close();
return null;
}
String encodedMood = moodCursor.getString(0);
moodCursor.close();
try {
return HueUrlEncoder.decode(encodedMood).second.first;
} catch (InvalidEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (FutureEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* Inspired by https://github.com/PhilipsHue/PhilipsHueSDK-iOS-OSX/blob/master/ApplicationDesignNotes
* /RGB%20to%20xy%20Color%20conversion.md
*
* @param h in 0 to 1 in the wide RGB D65 space
* @param s in 0 to 1 in the wide RGB D65 space
* @return CIE 1931 xy each ranging 0 to 1
*/
public static float[] hsTOxy(float[] input) {
float h = input[0];
float s = input[1];
h = Math.max(0f, Math.min(h, 1f));
s = Math.max(0f, Math.min(s, 1f));
float[] hsv = {h * 360, s, 1};
int rgb = Color.HSVToColor(hsv);
float red = ((rgb >>> 16) & 0xFF) / 255f;
float green = ((rgb >>> 8) & 0xFF) / 255f;
float blue = ((rgb) & 0xFF) / 255f;
red =
(float) ((red > 0.04045f) ? Math.pow((red + 0.055f) / (1.0f + 0.055f), 2.4f)
: (red / 12.92f));
green =
(float) ((green > 0.04045f) ? Math.pow((green + 0.055f) / (1.0f + 0.055f), 2.4f)
: (green / 12.92f));
blue =
(float) ((blue > 0.04045f) ? Math.pow((blue + 0.055f) / (1.0f + 0.055f), 2.4f)
: (blue / 12.92f));
float X = red * 0.649926f + green * 0.103455f + blue * 0.197109f;
float Y = red * 0.234327f + green * 0.743075f + blue * 0.022598f;
float Z = red * 0.0000000f + green * 0.053077f + blue * 1.035763f;
float x = X / (X + Y + Z);
float y = Y / (X + Y + Z);
float[] result = {x, y};
// Log.e("colorspace", "h"+h+" s"+s+" to x"+x+" y"+y);
return result;
}
/**
* Inspired by https://github.com/PhilipsHue/PhilipsHueSDK-iOS-OSX/blob/master/ApplicationDesignNotes
* /RGB%20to%20xy%20Color%20conversion.md
*
* @param x CIE 1931 x ranging from 0 to 1
* @param y CIE 1931 y ranging from 0 to 1
* @return h, s each ranging 0 to 1 in the wide RGB D65 space
*/
public static float[] xyTOhs(float[] input) {
float x = input[0];
float y = input[1];
float z = 1.0f - x - y;
float Y = 1f; // The given brightness value
float X = (Y / y) * x;
float Z = (Y / y) * z;
float r = X * 1.612f - Y * 0.203f - Z * 0.302f;
float g = -X * 0.509f + Y * 1.412f + Z * 0.066f;
float b = X * 0.026f - Y * 0.072f + Z * 0.962f;
r =
(float) (r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math.pow(r, (1.0f / 2.4f))
- 0.055f);
g =
(float) (g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math.pow(g, (1.0f / 2.4f))
- 0.055f);
b =
(float) (b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math.pow(b, (1.0f / 2.4f))
- 0.055f);
float max = Math.max(r, Math.max(g, b));
r = r / max;
g = g / max;
b = b / max;
r = Math.max(r, 0);
g = Math.max(g, 0);
b = Math.max(b, 0);
float[] hsv = new float[3];
Color.RGBToHSV((int) (r * 0xFF), (int) (g * 0xFF), (int) (b * 0xFF), hsv);
float h = hsv[0] / 360;
float s = hsv[1];
h = Math.max(0f, Math.min(h, 1f));
s = Math.max(0f, Math.min(s, 1f));
float[] result = {h, s};
// Log.e("colorspace", "h"+h+" s"+s+" from x"+x+" y"+y);
return result;
}
/**
* @param x CIE 1931 x ranging from 0 to 1
* @param y CIE 1931 y ranging from 0 to 1
* @return h, s each ranging 0 to 1 in the sRGB D65 space
*/
public static float[] xyTOsRGBhs(float[] input) {
float x = input[0];
float y = input[1];
float z = 1.0f - x - y;
float Y = 1f; // The given brightness value
float X = (Y / y) * x;
float Z = (Y / y) * z;
float r = X * 3.2404542f + Y * -1.5371385f + Z * -0.4985314f;
float g = X * -0.9692660f + Y * 1.8760108f + Z * 0.0415560f;
float b = X * 0.0556434f + Y * -0.2040259f + Z * 1.0572252f;
r =
(float) (r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math.pow(r, (1.0f / 2.4f))
- 0.055f);
g =
(float) (g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math.pow(g, (1.0f / 2.4f))
- 0.055f);
b =
(float) (b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math.pow(b, (1.0f / 2.4f))
- 0.055f);
float max = Math.max(r, Math.max(g, b));
r = r / max;
g = g / max;
b = b / max;
r = Math.max(r, 0);
g = Math.max(g, 0);
b = Math.max(b, 0);
float[] hsv = new float[3];
Color.RGBToHSV((int) (r * 0xFF), (int) (g * 0xFF), (int) (b * 0xFF), hsv);
float h = hsv[0] / 360;
float s = hsv[1];
h = Math.max(0f, Math.min(h, 1f));
s = Math.max(0f, Math.min(s, 1f));
float[] result = {h, s};
// Log.e("colorspace", "h"+h+" s"+s+" from x"+x+" y"+y);
return result;
}
/**
* Plankian locus cubic spline approximation by Kim et al inspired by
* http://en.wikipedia.org/wiki/Planckian_locus
*
* @param ct Planckian locus color temperature in Mirads
* @return x, y in CIE 1931 each ranging 0 to 1
*/
public static float[] ctTOxy(float ctMirads) {
double ct = 1000000 / ctMirads;
double xc = 0;
double yc = 0;
if (1667 <= ct && ct <= 4000) {
xc =
-0.2661239 * (Math.pow(10, 9) / Math.pow(ct, 3)) - 0.2343580
* (Math.pow(10, 6) / Math.pow(ct, 2))
+ 0.8776956 * (Math.pow(10, 3) / ct)
+ 0.179910d;
} else if (4000 < ct && ct < 25000) {
xc =
-3.0258469 * (Math.pow(10, 9) / Math.pow(ct, 3)) + 2.1070379
* (Math.pow(10, 6) / Math.pow(ct, 2))
+ 0.2226347 * (Math.pow(10, 3) / ct)
+ 0.240390d;
}
if (1667 <= ct && ct <= 2222) {
yc =
-1.1063814 * Math.pow(xc, 3) - 1.34811020 * Math.pow(xc, 2) + 2.18555832 * xc
- 0.20219683d;
} else if (2222 < ct && ct <= 4000) {
yc =
-0.9549476 * Math.pow(xc, 3) - 1.37418593 * Math.pow(xc, 2) + 2.09137015 * xc
- 0.16748867d;
} else if (4000 < ct && ct <= 25000) {
yc =
3.0817580 * Math.pow(xc, 3) - 5.87338670 * Math.pow(xc, 2) + 3.75112997 * xc
- 0.37001483d;
}
DeferredLog.e("ctConversion", "%f , %f , %f", ct, + xc, yc);
float[] result = {(float) xc, (float) yc};
return result;
}
/**
* @param gamutBounds list of xy coordinates of maximum reachable colors
* @param xy desired coordinates
* @return the desired coordinates, adjusted to be within bounds
*/
public static float[] toReachableXY(@Size(6) float[] gamutBounds, @Size(2) float[] xy) {
//TODO
return xy;
}
/**
* @return deciseconds
*/
public static int toDeciSeconds(long milliseconds) {
return (int) (milliseconds / 100l);
}
/**
* @return milliseconds
*/
public static long fromDeciSeconds(int deciseconds) {
return deciseconds * 100l;
}
public static int moodDailyTimeFromCalendarMillis(Calendar input) {
Calendar startOfDay = Calendar.getInstance();
startOfDay.set(Calendar.MILLISECOND, 0);
startOfDay.set(Calendar.SECOND, 0);
startOfDay.set(Calendar.MINUTE, 0);
startOfDay.set(Calendar.HOUR_OF_DAY, 0);
Calendar inputCopy = Calendar.getInstance();
inputCopy.setTimeInMillis(input.getTimeInMillis());
Long offsetWithinTheDayInMilis = inputCopy.getTimeInMillis() - startOfDay.getTimeInMillis();
return (int) (offsetWithinTheDayInMilis / 100);
}
public static Calendar calendarMillisFromMoodDailyTime(int dailyMoodDeciSeconds) {
Calendar startOfDay = Calendar.getInstance();
startOfDay.set(Calendar.MILLISECOND, 0);
startOfDay.set(Calendar.SECOND, 0);
startOfDay.set(Calendar.MINUTE, 0);
startOfDay.set(Calendar.HOUR_OF_DAY, 0);
startOfDay.getTime();
startOfDay.setTimeInMillis(startOfDay.getTimeInMillis() + (dailyMoodDeciSeconds * 100L));
return startOfDay;
}
/**
* @return the start of day measured in SystemClock.elapsedRealtime milliseconds (may be negative)
*/
public static long getDayStartElapsedRealTimeMillis() {
Calendar dayStart = Calendar.getInstance();
dayStart.set(Calendar.MILLISECOND, 0);
dayStart.set(Calendar.SECOND, 0);
dayStart.set(Calendar.MINUTE, 0);
dayStart.set(Calendar.HOUR_OF_DAY, 0);
dayStart.getTime();
Calendar current = Calendar.getInstance();
return SystemClock.elapsedRealtime() - (current.getTimeInMillis() - dayStart.getTimeInMillis());
}
}