Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
92 views
in Technique[技术] by (71.8m points)

java - Converting different unit types in JScience library

I'm looking for a way in the JScience library to convert from one unit type to another. Given a factor between the base units of each types I should be able to convert. But it seems that JScience isn't being very nice about the conversion, and only allowing the conversion between units of the same base type.

Basically, I'm writing a diet app, and I need to be able to convert between calories, joules, kilojoules, grams, pounds, kg, etc. It is complicated by the macronutrient values - carbohyrates, protein, and fat content.

Example:

Each 1g of carb = 4 Calorie. That's 4000 calorie, or 16.736 Kilojoules, or 16736 joules (the base unit of energy).

Carb_Unit is then defined as: 16736 joules/gram, or 16736000joules/kilogram

Given this base values, I should be able to convert from any mass unit to any energy unit. But again, JScience won't allow this. Is there a way to tell the converter to return a converter with the correct conversion factor without it giving out the ConversionException?

CustomUnits.java:

public class CustomUnits extends SystemOfUnits {

    /**
     * Holds collection of CustomUnits.
     */
    private static HashSet<Unit<?>> UNITS = new HashSet<Unit<?>>();

    private static <U extends Unit<?>> U customUnits(U unit) {
        UNITS.add(unit);
        return unit;
    }

    @Override
    public Set<Unit<?>> getUnits() {
        return Collections.unmodifiableSet(UNITS);
    }

    public static final Unit<Energy> KILOCALORIE = customUnits(SI.JOULE.times(4184));
    public static final Unit<Energy> KILOJOULE = customUnits(SI.JOULE.times(1000));

    // Food units expressed as energy
    public static final Unit<Energy> CARBOHYDRATE_ENERGY = customUnits(KILOCALORIE.times(4));
    public static final Unit<Energy> PROTEIN_ENERGY = customUnits(KILOCALORIE.times(4));
    public static final Unit<Energy> FAT_ENERGY = customUnits(KILOCALORIE.times(9));

    // Food units expressed as mass
    public static final Unit<Mass> CARBOHYDRATE_MASS = customUnits(SI.GRAM);
    public static final Unit<Mass> PROTEIN_MASS = customUnits(SI.GRAM);
    public static final Unit<Mass> FAT_MASS = customUnits(SI.GRAM);
}

Main.java:

public static void main(String[] args) {

    Amount<?> carbEnergyUnit = Amount.valueOf(1, CustomUnits.CARBOHYDRATE_ENERGY);
    Amount<?> carbEnergyCalorie = carbEnergyUnit.to(CustomUnits.KILOCALORIE);
    Amount<?> carbEnergyKJ = carbEnergyUnit.to(CustomUnits.KILOJOULE);
    Amount<?> carbEnergyJoules = carbEnergyUnit.to(SI.JOULE);

    System.out.println(carbEnergyUnit.getExactValue() + "g of carb");       // 1g of carb
    System.out.println(carbEnergyCalorie.getExactValue() + " Calorie");     // 4 Calorie
    System.out.println(carbEnergyKJ.getEstimatedValue() + " KiloJoules");   // 16.735999999999997 KiloJoules
    System.out.println(carbEnergyJoules.getExactValue() + " Joules");       // 16736 Joules

    // Exception in thread "main" javax.measure.converter.ConversionException: lb is not compatible with J*16736
    UnitConverter toCarb = NonSI.POUND.getConverterTo(CustomUnits.CARBOHYDRATE_ENERGY);
    double result = toCarb.convert(4);
    System.out.println(result);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It looks like JScience has caught you trying to convert a Unit<Mass> to a Unit<Energy>, which is forbidden in the default PhysicalModel.

One alternative approach would be to create a new Quantity for various units of FoodEnergy:

public static final Unit<Energy> KILOCALORIE = SI.JOULE.times(4184);

public interface FoodEnergy extends Quantity {

    public final static Unit<FoodEnergy> UNIT
        = (Unit<FoodEnergy>) SI.GRAM.times(KILOCALORIE);
}

private static final Unit<FoodEnergy> PROTEIN_ENERGY = FoodEnergy.UNIT.times(4);
private static final Unit<FoodEnergy> ETHANOL_ENERGY = FoodEnergy.UNIT.times(7);
…

You can then combine the contributions of particular energy sources:

Amount<FoodEnergy> beer =
    Amount.valueOf(2, PROTEIN_ENERGY).plus(
    Amount.valueOf(14, ETHANOL_ENERGY));
System.out.println(beer.to(FoodEnergy.UNIT).getEstimatedValue() + " Calories");

Which prints 105.99999999999997 Calories. You can find the calories in a pound of protein by converting a NonSI.POUND to SI.GRAM:

double grams = NonSI.POUND.getConverterTo(SI.GRAM).convert(1);
Amount<FoodEnergy> pound = Amount.valueOf(grams, PROTEIN_ENERGY);
System.out.println(pound.to(FoodEnergy.UNIT).getEstimatedValue() + " Calories");

Which prints 1814.3694799999998 Calories. Finally, you can recover the number of Joules from a FoodEnergy.UNIT:

System.out.println(FoodEnergy.UNIT.divide(SI.GRAM));

Which prints J*4184, or

System.out.println(FoodEnergy.UNIT.divide(SI.GRAM).toStandardUnit().convert(1));

Which prints 4184.0.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...