diff --git a/src/main/java/org/fhir/ucum/Converter.java b/src/main/java/org/fhir/ucum/Converter.java index 21e34cb..e600105 100644 --- a/src/main/java/org/fhir/ucum/Converter.java +++ b/src/main/java/org/fhir/ucum/Converter.java @@ -127,7 +127,7 @@ public int compare(final CanonicalUnit lhs, CanonicalUnit rhs) { } private Canonical normalise(String indent, Symbol sym) throws UcumException { - Canonical result = new Canonical(new Decimal(1)); + Canonical result = new Canonical(new Decimal("1.000000000000000000000000000000")); if (sym.getUnit() instanceof BaseUnit) { result.getUnits().add(new CanonicalUnit((BaseUnit) sym.getUnit(), sym.getExponent())); @@ -157,17 +157,25 @@ private Canonical normalise(String indent, Symbol sym) throws UcumException { private Canonical expandDefinedUnit(String indent, DefinedUnit unit) throws UcumException { String u = unit.getValue().getUnit(); + Decimal v = unit.getValue().getValue(); + if (unit.isSpecial()) { if (!handlers.exists(unit.getCode())) throw new UcumException("Not handled yet (special unit)"); - else + else { u = handlers.get(unit.getCode()).getUnits(); + v = handlers.get(unit.getCode()).getValue(); + if (handlers.get(unit.getCode()).hasOffset()) { + // the problem here is that supporting this requires a total rework of the architecture, because the actual value isn't available here (and don't know whether it's needed to do offset either) + throw new UcumException("Not handled yet (special unit with offset from 0 at intersect)"); + } + } } Term t = new ExpressionParser(model).parse(u); debug(indent, "now handle", t); Canonical result = normalise(indent+" ", t); - result.multiplyValue(unit.getValue().getValue()); + result.multiplyValue(v); return result; } diff --git a/src/main/java/org/fhir/ucum/UcumEssenceService.java b/src/main/java/org/fhir/ucum/UcumEssenceService.java index 941f03d..ddf3441 100644 --- a/src/main/java/org/fhir/ucum/UcumEssenceService.java +++ b/src/main/java/org/fhir/ucum/UcumEssenceService.java @@ -297,14 +297,12 @@ public Decimal convert(Decimal value, String sourceUnit, String destUnit) throws if (!s.equals(d)) throw new UcumException("Unable to convert between units "+sourceUnit+" and "+destUnit+" as they do not have matching canonical forms ("+s+" and "+d+" respectively)"); Decimal canValue = value.multiply(src.getValue()); - if (value.isWholeNumber()) { - // whole numbers are tricky - they have implied infinite precision, but we need to check for digit errors in the last couple of digits - canValue.checkForCouldBeWholeNumber(); - } -// System.out.println(value.toPlainString()+sourceUnit+" =("+src.getValue().toPlainString()+")= "+ -// canValue.toPlainString()+s+" =("+dst.getValue().toPlainString()+")= "+ -// canValue.divide(dst.getValue())+destUnit); - return canValue.divide(dst.getValue()); + Decimal res = canValue.divide(dst.getValue()); + if (value.isWholeNumber()) { + // whole numbers are tricky - they have implied infinite precision, but we need to check for digit errors in the last couple of digits + res.checkForCouldBeWholeNumber(); + } + return res; } @Override diff --git a/src/main/java/org/fhir/ucum/special/CelsiusHandler.java b/src/main/java/org/fhir/ucum/special/CelsiusHandler.java index 3e1407d..1cabf4d 100644 --- a/src/main/java/org/fhir/ucum/special/CelsiusHandler.java +++ b/src/main/java/org/fhir/ucum/special/CelsiusHandler.java @@ -34,6 +34,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.fhir.ucum.special; import org.fhir.ucum.Decimal; +import org.fhir.ucum.UcumException; public class CelsiusHandler extends SpecialUnitHandler { @@ -52,5 +53,18 @@ public Decimal getValue() { return Decimal.one(); } - + + + /* (non-Javadoc) + * @see org.eclipse.ohf.ucum.special.SpecialUnitHandler#getOffset() + */ + @Override + public Decimal getOffset() throws UcumException { + return new Decimal("-273.15", 24); + } + + @Override + public boolean hasOffset() { + return true; + } } diff --git a/src/main/java/org/fhir/ucum/special/FahrenheitHandler.java b/src/main/java/org/fhir/ucum/special/FahrenheitHandler.java index 020188d..ecbb130 100644 --- a/src/main/java/org/fhir/ucum/special/FahrenheitHandler.java +++ b/src/main/java/org/fhir/ucum/special/FahrenheitHandler.java @@ -34,6 +34,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.fhir.ucum.special; import org.fhir.ucum.Decimal; +import org.fhir.ucum.UcumException; public class FahrenheitHandler extends SpecialUnitHandler { @@ -59,5 +60,17 @@ public Decimal getValue() { return null; } } + + /* (non-Javadoc) + * @see org.eclipse.ohf.ucum.special.SpecialUnitHandler#getOffset() + */ + @Override + public Decimal getOffset() throws UcumException { + return new Decimal("32", 24); + } + @Override + public boolean hasOffset() { + return true; + } } diff --git a/src/main/java/org/fhir/ucum/special/HoldingHandler.java b/src/main/java/org/fhir/ucum/special/HoldingHandler.java index 6234c1c..f619f76 100644 --- a/src/main/java/org/fhir/ucum/special/HoldingHandler.java +++ b/src/main/java/org/fhir/ucum/special/HoldingHandler.java @@ -34,6 +34,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.fhir.ucum.special; import org.fhir.ucum.Decimal; +import org.fhir.ucum.UcumException; /** * If you want to actually use one of these units, then you'll @@ -84,4 +85,16 @@ public Decimal getValue() { return value; } + /* (non-Javadoc) + * @see org.eclipse.ohf.ucum.special.SpecialUnitHandler#getOffset() + */ + @Override + public Decimal getOffset() throws UcumException { + return new Decimal("0", 24); + } + + @Override + public boolean hasOffset() { + return false; + } } diff --git a/src/main/java/org/fhir/ucum/special/SpecialUnitHandler.java b/src/main/java/org/fhir/ucum/special/SpecialUnitHandler.java index 7ed97ef..0d37bd6 100644 --- a/src/main/java/org/fhir/ucum/special/SpecialUnitHandler.java +++ b/src/main/java/org/fhir/ucum/special/SpecialUnitHandler.java @@ -34,6 +34,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.fhir.ucum.special; import org.fhir.ucum.Decimal; +import org.fhir.ucum.UcumException; public abstract class SpecialUnitHandler { @@ -57,4 +58,20 @@ public abstract class SpecialUnitHandler { */ public abstract Decimal getValue(); + + /** + * return true if the conversion offset value != 0 + * + * @return + */ + public abstract boolean hasOffset(); + + /** + * get the conversion offset value + * + * @return + * @throws UcumException + */ + public abstract Decimal getOffset() throws UcumException; + } diff --git a/src/test/java/org/fhir/ucum/UcumTestsIssue21.java b/src/test/java/org/fhir/ucum/UcumTestsIssue21.java new file mode 100644 index 0000000..222eb2d --- /dev/null +++ b/src/test/java/org/fhir/ucum/UcumTestsIssue21.java @@ -0,0 +1,29 @@ +package org.fhir.ucum; + +import java.io.IOException; + +import static org.junit.Assert.assertThrows; + +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; + +import org.junit.Assert; +import org.junit.Test; + +public class UcumTestsIssue21 { + + @Test + public void testMileConversion() throws IOException, UcumException { + + String fileName = "ucum-essence.xml"; + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(fileName).getFile()); + InputStream inputStream = new FileInputStream(file); + UcumEssenceService ucumService = new UcumEssenceService(inputStream); + + Decimal m = ucumService.convert(new Decimal("1",15), "[mi_i]","m"); + Assert.assertEquals("1609", m.asDecimal()); // because UCUM value for cm is wrong precision + } + +} diff --git a/src/test/java/org/fhir/ucum/UcumTestsIssue22.java b/src/test/java/org/fhir/ucum/UcumTestsIssue22.java new file mode 100644 index 0000000..4099c93 --- /dev/null +++ b/src/test/java/org/fhir/ucum/UcumTestsIssue22.java @@ -0,0 +1,34 @@ +package org.fhir.ucum; + +import java.io.IOException; + +import static org.junit.Assert.assertThrows; + +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; + +import org.junit.Assert; +import org.junit.Test; + +public class UcumTestsIssue22 { + + @Test + public void testDegreeConversion() throws IOException, UcumException { + + String fileName = "ucum-essence.xml"; + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(fileName).getFile()); + InputStream inputStream = new FileInputStream(file); + UcumEssenceService ucumService = new UcumEssenceService(inputStream); + + assertThrows(UcumException.class, () -> { + ucumService.convert(new Decimal("100", 15), "Cel", "K"); + }); + + assertThrows(UcumException.class, () -> { + ucumService.convert(new Decimal("100", 15), "[degF]", "Cel"); + }); + } + +}