/** * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.android.healthconnect.controller.dataentries.units import kotlin.math.roundToInt object WeightConverter { private const val POUNDS_PER_STONE = 14 private const val KG_PER_POUND = 0.453592 private const val KG_PER_STONE = 6.35029 private const val POUND_PER_KG = 2.20462 private const val STONE_PER_KG = 0.157473 private const val MAX_STONE_TO_KG_INPUT = Double.MAX_VALUE / KG_PER_STONE private const val MAX_KG_TO_POUND_INPUT = Double.MAX_VALUE / POUND_PER_KG /** * Converts from kilograms to the provided units * * @param toUnit the units type to convert the passed in sourceKilograms (kg) to * @param sourceKilograms the kg weight to convert to toUnit weight * @return the sourceKilograms in toUnit weight units */ fun convertFromKilograms(toUnit: WeightUnit, sourceKilograms: Double): Double { return when (toUnit) { WeightUnit.KILOGRAM -> keepOneDecimal(sourceKilograms) WeightUnit.POUND -> { require( !(sourceKilograms > MAX_KG_TO_POUND_INPUT || sourceKilograms < -MAX_KG_TO_POUND_INPUT)) { "Kilogram input out of range: $sourceKilograms" } keepOneDecimal(sourceKilograms * POUND_PER_KG) } WeightUnit.STONE -> keepOneDecimal(sourceKilograms * STONE_PER_KG) } } /** * Converts from grams to the provided units * * @param toUnit the units type to convert the passed in sourceGrams (g) to * @param sourceGrams the gram weight to convert to toUnit weight * @return the sourceGrams in toUnit weight units */ fun convertFromGrams(toUnit: WeightUnit, sourceGrams: Double): Double { return convertFromKilograms(toUnit, sourceGrams / 1000) } /** * Converts from pounds to stones and pounds. * * @param weight the weight in pounds to convert * @param significantDigits the number of significant digits to round the pounds to */ fun stonePoundsFromPounds(weight: Double, significantDigits: Int): StonePounds { var stone = (weight / POUNDS_PER_STONE).toInt() val pow = Math.pow(10.0, significantDigits.toDouble()) var pound = keepOneDecimal((weight % POUNDS_PER_STONE * pow).roundToInt() / pow) if (pound == POUNDS_PER_STONE.toDouble()) { pound = 0.0 stone++ } return StonePounds(stone, pound) } private fun keepOneDecimal(weight: Double): Double { return (weight * 10).roundToInt() / 10.0 } } /** * Encapsulates the result of a conversion to UK imperial units; whole stones and fractional pounds. * * @param stone Stone value (14 pounds). * @param pounds Pounds (between zero and 14). */ data class StonePounds(val stone: Int, val pounds: Double)