Get current tide height when previous and next tides are known - kotlin

I'm trying to calculate the current tide height based on the height of the previous tide, the height of the next tide, and the time difference of the two.
I've tried to use this formula as a start but I think I either have something wrong in the formula or the formula won't work based on only having the previous and next tides (or both, and I'm way off):
Found here: https://www.dummies.com/article/academics-the-arts/math/trigonometry/measure-tidal-change-using-a-trigonometry-graph-187108/
I'm trying to solve this in Kotlin but can translate from any other language if given a working example.
My code looks like this:
val previousTideHeight = 5.3
val nextTideHeight = -.3
val timeBetweenTides = 60 * 60 * 6 // 6 hours in seconds
val timeSincePrevTide = 60 * 60 * 3 // 3 hours in seconds
val tideHeightDifference = previousTideHeight - nextTideHeight
val averageTideHeight = tideHeightDifference / 2
val tideAmplitude = Math.max(Math.abs(averageTideHeight - previousTideHeight), Math.abs(averageTideHeight - nextTideHeight))
val currentHeight = (tideAmplitude * Math.sin(Math.PI / timeBetweenTides) * timeSincePrevTide) + averageTideHeight

After messing with everything for a little I ended up with a formula that seems to be working but would love any feedback on it as I'm not totally certain how it all works.
val previousTideHeight = -1.3
val nextTideHeight = 5.2
val hoursBetweenTides = 6
val hoursSincePrevTide = 0
val timeBetweenTides = 60 * 60 * hoursBetweenTides
val timeSincePrevTide = 60 * 60 * hoursSincePrevTide
// We need to shift the graph horizontally based on the time since the previous tide
// and we need to produce a negative number so that we can get a value below the equilibrium
val timeShift = (timeSincePrevTide - (timeBetweenTides / 2)) * 2
// If the tide is going down we need to shift the graph the
// other direction to catch the down slope
val tideDirectionMultiplier = if (previousTideHeight > nextTideHeight) -1 else 1
val tideHeightDifference = previousTideHeight + nextTideHeight
val averageTideHeight = tideHeightDifference / 2
val tideAmplitude = Math.max(Math.abs(averageTideHeight - previousTideHeight), Math.abs(averageTideHeight - nextTideHeight))
val currentHeight = (tideAmplitude * Math.sin((Math.PI / (timeBetweenTides * 2)) * (timeShift * tideDirectionMultiplier))) + averageTideHeight
return currentHeight

Related

Using groupBy/groupingBy/aggregate to sum into smaller buckets in parallel?

I've got a collection of "stuff", and I'd like to sum it into smaller buckets. (In my particular case, I'm downsampling a luma channel of an image by 8x.)
I'd like it to be as fast as possible on your average multi-core android device, which I think means coroutine-per-bucket. (because there isn't any reason to play with IntAdders if I don't have to)
The naive linear solution:
val SCALE = 8
image.planes[0].buffer.toByteArray().forEachIndexed { index, byte ->
val x1 = index % image.width
val y1 = index / image.width
val x2 = x1 / SCALE
val y2 = y1 / SCALE
val quadIdx = y2 * (image.width / SCALE) + x2
summedQuadLum[quadIdx] += (byte.toInt() and 0xFF)
}
That isn't great - needs to pre-declare the summedQuadLum collection, and doesn't have any chance of parallel work.
I'd love to use groupBy, or groupingBy? or aggregate?) but those all seem to use the values to determine the new keys, and I need to use the key to determine the new keys. I think the least overhead is withIndex which could be done as
val thumbSums = bufferArray.withIndex().groupingBy { (idx, _) ->
val x1 = idx % previewImageDimension.width
val y1 = idx / previewImageDimension.width
val x2 = x1 / SCALE
val y2 = y1 / SCALE
y2 * (previewImageDimension.width / SCALE) + x2
}.aggregate { _, acc: Int?, (_, lum), _ ->
(acc ?: 0) + (lum.toInt() and 0xFF)
}.values.toIntArray()
Much better, it is really close - if I could figure out how to sum each bucket in a coroutine, I think it would be as good as can be expected.
So after groupingBy we have a Grouping object, which we can use to aggregate values. It's important to notice the grouping itself has not been done yet, we basically have a description how to group the values and an iterator of the original array. From here we have a few options:
Create a Channel from the iterator and launch a few worker coroutines to consume it in parallel. Channels support fan-out, so every item in the source is processed by one worker only. The problem here is all the workers need to update different items in the resulting array, so synchronization is required and that's where it gets tricky and likely inefficient.
To avoid multiple workers to write to the same item, we need to tell each of them what items to process. That mean either each of the worker should process all the items, picking only suitable or we should precalculate the groups in advance and feed the workers with the groups. Both approaches have pretty much the same performance as the serial algorithm, so do not make any sense.
So to parallelize it efficiently we want to avoid having a shared mutable state, because it requires synchronization. Obviously we don't want to precalculate the groups also.
My suggestion here is to come from another side - instead of mapping original array to sampled one, let's map sampled array to the original. So we say
This approaches makes each value to be calculated independently by one worker, so no synchronization needed. Now we can implement it like this:
suspend fun sample() {
val asyncFactor = 8
val src = Image(bufferArray, width)
val dst = Image(src.width / SCALE, src.height / SCALE)
val chunkSize = dst.sizeBytes / asyncFactor
val jobs = Array(asyncFactor) { idx ->
async(Dispatchers.Default) {
val chunkStartIdx = chunkSize * idx
val chunkEndIdxExclusive = min(chunkStartIdx + chunkSize, dst.sizeBytes)
calculateSampledImageForIndexes(src, dst, chunkStartIdx, chunkEndIdxExclusive, SCALE)
}
}
awaitAll(*jobs)
}
private fun calculateSampledImageForIndexes(src: Image, dst: Image, startIdx: Int, exclusiveEndIdx: Int, scaleFactor: Int) {
for (i in startIdx until exclusiveEndIdx) {
val destX = i % dst.width
val destY = i / dst.width
val srcX = destX * scaleFactor
val srcY = destY * scaleFactor
var sum = 0
for (xi in 0 until scaleFactor) {
for (yi in 0 until scaleFactor) {
sum += src[srcX + xi, srcY + yi]
}
}
dst[destX, destY] = sum / (scaleFactor * scaleFactor)
}
}
Where Image is a convenient wrapper around the image data buffer:
class Image(val buffer: ByteArray, val width: Int) {
val height = buffer.size / width
val sizeBytes get() = buffer.size
constructor(w: Int, h: Int) : this(ByteArray(w * h), w)
operator fun get(x: Int, y: Int): Byte = buffer[clampX(x) * width + clampY(y)]
operator fun set(x: Int, y: Int, value: Int) {
buffer[x * width + y] = (value and 0xFF).toByte()
}
private fun clampX(x: Int) = max(min(x, width), 0)
private fun clampY(y: Int) = max(min(y, height), 0)
}
Also, with this approach you can easily implement many image processing functions, which based on convolution operation, like blur and edge detection.

Kotlin - same condition: multiple if statements or one if statement

In Kotlin you can use if statements kind of like ternary operators.
We have the option to do something like this:
val x = if (isOdd) 1 else 2
but if we have multiple variables that need to be set based on some condition is it more correct to do it the old fashioned way like so:
val x: Int
val y: Int
val z: Int
if (isOdd) {
x = 1
y = 3
z = 5
} else {
x = 2
y = 4
z = 6
}
or like this :
val x = if (isOdd) 1 else 2
val y = if (isOdd) 3 else 4
val z = if (isOdd) 5 else 6
the second way looks much cleaner to me, but I'd like to know if the first method would be computed faster since it only needs to calculate the condition once whereas the second way needs to check the condition 3 times.
Is the second way actually slower or will it be optimized by the compiler?
I'd prefer something like this, looks way more Kotlinesque:
data class Point3D(val x: Int, val y: Int, val z: Int)
fun foo(isOdd: Boolean): Point3D = if (isOdd) Point3D(1, 3, 5) else Point3D(2, 4, 6)
//or using destructureing see https://kotlinlang.org/docs/reference/multi-declarations.html)
val (x,y,z) = if (isOdd) Triple(1, 3, 5) else Triple(2, 4, 6)
Also it combines the best of both, using if as expression and only one if is needed. (At the cost of an additional object allocation).
But to answer your question. Do what you like and think is most readable. Performance wise I doubt you will make a difference.
if is an expression in Kotlin, not a statement: it returns a value, whereas it doesn't in Java's case.
I don't think here is such an optimization issue you should ever think about, honestly. Premature optimization is a common source of problems. If this boolean variable is thread-confined, then I think the compiler will perform all the optimizations that are possible in this context, so it will be almost no overhead at all (if not completely).
Wise choice in OO languages is to prefer clearness and flexibility over low-level optimization issues (especially when compilers are able to resolve them).
Okay, so just saw this question again and got curious... So I did some tests.
Turns out there is actually a HUGE difference, heres the results:
Code
fun main() {
for (i in 0 until 3) {
val t1_s = System.currentTimeMillis()
for (j in 0 until 100000) {
when (i){
0 -> a(j % 2 == 0)
1 -> b(j % 2 == 0)
2 -> c(j % 2 == 0)
}
}
val t1_e = System.currentTimeMillis()
println("Test $i - time ${t1_e - t1_s}")
}
}
fun a(isOdd: Boolean): Int {
val x: Int
val y: Int
val z: Int
if (isOdd) {
x = 1
y = 3
z = 5
} else {
x = 2
y = 4
z = 6
}
return x + y + z
}
fun b(isOdd: Boolean): Int {
val x = if (isOdd) 1 else 2
val y = if (isOdd) 3 else 4
val z = if (isOdd) 5 else 6
return x + y + z
}
fun c(isOdd: Boolean): Int {
val (x,y,z) = if (isOdd) Triple(1, 3, 5) else Triple(2, 4, 6)
return x + y + z
}
Output
Test 0 - time 3
Test 1 - time 1
Test 2 - time 8
It seems my second solution is the fastest, my first suggestion next, and the top answer as MUCH slower.
Does any one know why this might be? Obviously these are milliseconds so it almost always wouldn't matter, but it is neat to think that one method is 5-10 times faster
EDIT:
So tried bumptin the iterations up to 100000000 and the results were:
Test 0 - time 6
Test 1 - time 41
Test 2 - time 941
I Guess the first 2 options are getting optimized out but the third option is always creating a new object making it much slow
Try it online!

Answer to converting lat/long to x/y on mercator not working for me when changing location from Germany to US

I'm using an answer from Raphael from this post (https://stackoverflow.com/a/10401734/3321095) to convert lat/long to xy coordinates plotted on a mercator map. Raphael's example uses an area in Hamburg, Germany. I tested it and it does work. I then changed it to find a point within the United States but the coordinates are always beyond the size of the image. Can someone help?
<script type="text/javascript">
var mapWidth = 749; //1500;
var mapHeight = 462; //1577;
var mapLonLeft = 125; //9.8;
var mapLonRight = 65 //10.2;
var mapLonDelta = mapLonRight - mapLonLeft;
var mapLatBottom = 25 //53.45;
var mapLatBottomDegree = mapLatBottom * Math.PI / 180;
function convertGeoToPixel(lat, lon)
{
var position = new Array(2);
var x = (lon - mapLonLeft) * (mapWidth / mapLonDelta);
var lat = lat * Math.PI / 180;
var worldMapWidth = ((mapWidth / mapLonDelta) * 360) / (2 * Math.PI);
var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomDegree)) / (1 - Math.sin(mapLatBottomDegree))));
var y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat)))) - mapOffsetY);
position[0] = x;
position[1] = y;
return position;
}
var coordinates = convertGeoToPixel(30.274333164300643, -97.74064064025879); //convertGeoToPixel(53.7, 9.95);
alert("x: " + coordinates[0] + " y: " + coordinates[1]);
</script>
Hope you figured this out in the last year. Your code helped me with a similar project. Your code is missing a minus sign and should look like this:
var mapLonLeft = -125; //9.8;
var mapLonRight = -65 //10.2;
Longitude is negative in the USA.

Conversion from float_time to float

As we all know that we can use float field for time with the help of widget="float_time".
Now, my question is that how this float_time value is calculated/converted into float value.
Ex:
I am giving value 00:10 in my form and when I look into the db it shows 0.16666667.
Thanks in advance.
This is the code in js for displaying value in float_time format:
case 'float_time':
var pattern = '%02d:%02d';
if (value < 0) {
value = Math.abs(value);
pattern = '-' + pattern;
}
var hour = Math.floor(value);
var min = Math.round((value % 1) * 60);
if (min == 60){
min = 0;
hour = hour + 1;
}
return _.str.sprintf(pattern, hour, min);
So in your case, in db it is stored as 0.16666667. So the min will be var min = Math.round((0.16666667 % 1) * 60); which will be 10 when rounded...
def float_time_convert(float_val):
factor = float_val < 0 and -1 or 1
val = abs(float_val)
return (factor * int(math.floor(val)), "{:0>2d}".format(int(round((val % 1) * 60))))
print "%i:%s" %(float_time_convert(3.61))

Vectors -> Perpendicular distance from vector to point in 2D space

I have a sprite that moves along a vector (-0.7,-0.3). I have another point whose coordinates I have - let's call them (xB|yB). Now, quite some time ago I learned to calculate the perpendicular distance from a vector to a point (first formula on this page http://en.wikipedia.org/wiki/Perpendicular_distance). However I tried it, and if I log it, it returns an unbelievably high value that is 100% false. So what do I do wrong ? Have a look at the image I provided.
incomingVector = (-0.7,-0.3) //this is the vector the sprite is moving along
bh.position is the point I want to calculate the distance to
Here is the code:
// first I am working out the c Value in the formula in the link given above
CGPoint pointFromVector = CGPointMake(bh.incomingVector.x*theSprite.position.x,bh.incomingVector.y*theSprite.position.y);
float result = pointFromVector.x + pointFromVector.y;
float result2 = (-1)*result;
//now I use the formula
float test = (bh.incomingVector.x * bh.position.x + bh.incomingVector.y * bh.position.y + result2)/sqrt(pow(bh.incomingVector.x, 2)+pow(bh.incomingVector.y, 2));
//the distance has to be positive, so I do the following
if(test < 0){
test *= (-1);
}
let us implement the formula again, according to the contents of your original link.
we have a vector for the line: V(a; b)
we have a point on the line (the centre of the sprite): P(x1, y1)
we have another point somewhere else: B(xB, yB)
for the testing here are two rows of random values:
a = -0.7; b = -0.3; x1 = 7; y1 = 7; xB = 5; yB = 5;
a = -0.7; b = -0.3; x1 = 7; y1 = 7; xB = 5.5; yB = 4;
the numerator is the following then: (it seems you are calculating the numerator an unknown way, I don't understand why you did it because this is the proper way to calculate the numerator for the linked formula, perhaps this is why you got totally wrong distances.)
float _numerator = abs((b * xB) - (a * yB) - (b * x1) + (a * y1));
// for the 1. test values: (-0.3 * 5) - (-0.7 * 5) - (-0.3 * 7) + (-0.7 * 7) = -1.5 + 3.5 + 2.1 - 4.9 = -0.8 => abs(-0.8) = 0.8
// for the 2. test values: (-0.3 * 5.5) - (-0.7 * 4) - (-0.3 * 7) + (-0.7 * 7) = -1.65 + 2.8 + 2.1 - 4.9 = -1.65 => abs(-1.65) = 1.65
the denominator is the following then:
float _denomimator = sqrt((a * a) + (b * b));
// for the 1. test values: (-0.7 * -0.7) + (-0.3 * -0.3) = 0.49 + 0.09 = 0.58 => sort(0.58) = 0.76
// for the 2. test values: (-0.7 * -0.7) + (-0.3 * -0.3) = 0.49 + 0.09 = 0.58 => sort(0.58) = 0.76
the distance is obvious now:
float _distance = _numerator / _denominator;
// for the 1. test values: 0.8 / 0.76 = 1.05
// for the 2. test values: 1.65 / 0.76 = 2.17
and these results (1.05 and 2.17) are the correct distances exactly for our random values, if you can draw the lines and the points on the paper you can measure the distance and you would get the same values, using standard ruler.