This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new eef29ecb6c Make `AbstractConverter` public and add an
`Units.logarithm(Unit)` method. The intend is to make easier for users to
define their own "decibel watt" unit.
eef29ecb6c is described below
commit eef29ecb6c2f36f63267d117d33bcb4740e19203
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri May 10 17:58:11 2024 +0200
Make `AbstractConverter` public and add an `Units.logarithm(Unit)` method.
The intend is to make easier for users to define their own "decibel watt"
unit.
---
.../org/apache/sis/measure/AbstractConverter.java | 31 ++++++++++++++----
.../main/org/apache/sis/measure/AbstractUnit.java | 5 +--
.../org/apache/sis/measure/ConventionalUnit.java | 38 +++++++++++++++-------
.../main/org/apache/sis/measure/PowerOf10.java | 2 +-
.../main/org/apache/sis/measure/SystemUnit.java | 7 +++-
.../main/org/apache/sis/measure/UnitFormat.java | 6 ++--
.../main/org/apache/sis/measure/Units.java | 22 +++++++++++++
.../main/org/apache/sis/util/resources/Errors.java | 7 +---
.../apache/sis/util/resources/Errors.properties | 1 -
.../apache/sis/util/resources/Errors_fr.properties | 1 -
.../apache/sis/measure/ConventionalUnitTest.java | 17 ++++++++++
11 files changed, 104 insertions(+), 33 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractConverter.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractConverter.java
index 83d648276e..ec0761e16d 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractConverter.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractConverter.java
@@ -18,16 +18,30 @@ package org.apache.sis.measure;
import java.util.List;
import java.io.Serializable;
+import javax.measure.Unit;
import javax.measure.UnitConverter;
import org.apache.sis.math.DecimalFunctions;
/**
- * Base class of unit converters.
+ * Skeletal implementation of the {@code UnitConverter} interface for reducing
implementation effort.
+ * This class makes easier to define a non-linear conversion between two units
of measurement.
+ * Note that for linear conversions, the standard {@link Unit#shift(Number)},
{@link Unit#multiply(Number)}
+ * and {@link Unit#divide(Number)} methods should be used instead.
+ *
+ * <p>After a non-linear conversion has been created, a new unit of
measurement using that conversion
+ * can be defined by a call to {@link Unit#transform(UnitConverter)}.
+ * See {@link Units#logarithm(Unit)} for an example.</p>
*
* @author Martin Desruisseaux (Geomatys)
+ * @version 1.5
+ *
+ * @see Units#converter(Number, Number)
+ * @see Units#logarithm(Unit)
+ *
+ * @since 1.5
*/
-abstract class AbstractConverter implements UnitConverter, Serializable {
+public abstract class AbstractConverter implements UnitConverter, Serializable
{
/**
* For cross-version compatibility.
*/
@@ -36,7 +50,7 @@ abstract class AbstractConverter implements UnitConverter,
Serializable {
/**
* Creates a new converter.
*/
- AbstractConverter() {
+ protected AbstractConverter() {
}
/**
@@ -135,19 +149,24 @@ abstract class AbstractConverter implements
UnitConverter, Serializable {
* by the specified converter (right converter), and then converting by
this converter (left converter).
*
* <p>The default implementation is okay, but subclasses should override
if they can detect optimizations.</p>
+ *
+ * @param before the converter to concatenate before this converter.
+ * @return a conversion which applies {@code before} first, then {@code
this}.
*/
@Override
- public UnitConverter concatenate(final UnitConverter converter) {
- if (equals(converter.inverse())) {
+ public UnitConverter concatenate(final UnitConverter before) {
+ if (equals(before.inverse())) {
return IdentityConverter.INSTANCE;
}
- return new ConcatenatedConverter(converter, this);
+ return new ConcatenatedConverter(before, this);
}
/**
* Returns the steps of fundamental converters making up this converter.
The default implementation returns
* only {@code this} on the assumption that this conversion is not a
concatenation of other converters.
* Subclasses should override if this assumption does not hold.
+ *
+ * @return list of steps in the unit conversion represented by this
instance.
*/
@Override
public List<UnitConverter> getConversionSteps() {
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractUnit.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractUnit.java
index ac3cff03f7..c6a44cd1f6 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractUnit.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/AbstractUnit.java
@@ -266,9 +266,10 @@ abstract class AbstractUnit<Q extends Quantity<Q>>
implements Unit<Q>, LenientCo
*/
final <R extends Quantity<R>> Unit<R> inferSymbol(Unit<R> result, final
char operation, final Unit<?> other) {
if (result instanceof ConventionalUnit<?> && result.getSymbol() ==
null) {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final String symbol = inferSymbol(operation, other);
if (symbol != null) {
- result = ((ConventionalUnit<R>) result).forSymbol(symbol);
+ result = ((ConventionalUnit<R>) result).alternate(symbol);
}
}
return result;
@@ -597,7 +598,7 @@ abstract class AbstractUnit<Q extends Quantity<Q>>
implements Unit<Q>, LenientCo
* @see #getSymbol()
*/
@Override
- public final String toString() {
+ public String toString() {
if (symbol != null) {
return symbol;
} else {
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/ConventionalUnit.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/ConventionalUnit.java
index 8645d641c0..060331c964 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/ConventionalUnit.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/ConventionalUnit.java
@@ -358,26 +358,22 @@ final class ConventionalUnit<Q extends Quantity<Q>>
extends AbstractUnit<Q> {
* Returns a new unit identical to this unit except for the symbol, which
is set to the given value.
* This is used by {@link UnitFormat} mostly; we do not provide public API
for setting a unit symbol
* on a conventional unit.
- */
- final ConventionalUnit<Q> forSymbol(final String symbol) {
- if (symbol.equals(getSymbol())) {
- return this;
- }
- return new ConventionalUnit<>(target, toTarget, symbol, scope, epsg);
- }
-
- /**
- * Unsupported operation for conventional units, as required by JSR-385
specification.
+ *
+ * <h4>Departure from JSR-385 specification</h4>
+ * The JSR-385 specification requires that we throw a {@link
MeasurementException} because this unit
+ * is not an unscaled standard unit. This implementation relaxes that
restriction.
*
* @param symbol the new symbol for the alternate unit.
* @return the alternate unit.
- * @throws MeasurementException always thrown because this unit is not an
unscaled standard unit.
*
* @see SystemUnit#alternate(String)
*/
@Override
public Unit<Q> alternate(final String symbol) {
- throw new
MeasurementException(Errors.format(Errors.Keys.NonSystemUnit_1, this));
+ if (symbol.equals(getSymbol())) {
+ return this;
+ }
+ return new ConventionalUnit<>(target, toTarget, symbol, scope, epsg);
}
/**
@@ -506,4 +502,22 @@ final class ConventionalUnit<Q extends Quantity<Q>>
extends AbstractUnit<Q> {
public int hashCode() {
return super.hashCode() + 37 * (target.hashCode() + 31 *
toTarget.hashCode());
}
+
+ /**
+ * Returns a string representation of this unit of measurement.
+ *
+ * @return a string representation.
+ */
+ @Override
+ public String toString() {
+ if (toTarget instanceof LinearConverter || toTarget.isLinear()) {
+ return super.toString();
+ }
+ final String symbol = getSymbol();
+ if (symbol != null) {
+ return symbol;
+ } else {
+ return "f(" + target + ')';
+ }
+ }
}
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/PowerOf10.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/PowerOf10.java
index 9fbab44a76..7fc64313fa 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/PowerOf10.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/PowerOf10.java
@@ -40,7 +40,7 @@ final class PowerOf10 extends AbstractConverter {
/**
* The singleton instance. Can be used for conversion from neper units to
{@link Units#UNITY}.
*/
- private static final UnitConverter INSTANCE = new PowerOf10();
+ static final UnitConverter INSTANCE = new PowerOf10();
/**
* Returns the converter from bel unit (B) to dimensionless unit. ISO
80000-3:2006 defines
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/SystemUnit.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/SystemUnit.java
index bb7abf1421..062c74061e 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/SystemUnit.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/SystemUnit.java
@@ -57,6 +57,11 @@ final class SystemUnit<Q extends Quantity<Q>> extends
AbstractUnit<Q> implements
*/
static final String ONE = "1";
+ /**
+ * The symbol for unformattable units.
+ */
+ static final String UNFORMATTABLE = "?";
+
/**
* The type of quantity that uses this unit, or {@code null} if unknown.
* This field should be null only when this unit is the result of an
arithmetic
@@ -308,7 +313,7 @@ final class SystemUnit<Q extends Quantity<Q>> extends
AbstractUnit<Q> implements
}
if (!dimension.equals(unit.dimension)) {
throw new
ClassCastException(Errors.format(Errors.Keys.IncompatibleUnitDimension_5, new
Object[] {
- this, (quantity != null) ? quantity.getSimpleName() : "?",
dimension,
+ this, (quantity != null) ? quantity.getSimpleName() :
UNFORMATTABLE, dimension,
type.getSimpleName(), unit.dimension}));
}
return unit;
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/UnitFormat.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/UnitFormat.java
index f24097ec71..08c892c1de 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/UnitFormat.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/UnitFormat.java
@@ -427,7 +427,7 @@ public class UnitFormat extends Format implements
javax.measure.format.UnitForma
}
Unit<?> labeledUnit = unit;
if (labeledUnit instanceof ConventionalUnit<?>) {
- labeledUnit = ((ConventionalUnit<?>) labeledUnit).forSymbol(label);
+ labeledUnit = ((ConventionalUnit<?>) labeledUnit).alternate(label);
}
final Unit<?> unitForOldLabel =
labelToUnit.remove(unitToLabel.put(unit, label));
final Unit<?> oldUnitForLabel = labelToUnit.put(label, labeledUnit);
@@ -443,7 +443,7 @@ public class UnitFormat extends Format implements
javax.measure.format.UnitForma
* Assuming there is no bug in our algorithm, this exception
should never happen
* unless this UnitFormat has been modified concurrently in
another thread.
* We compared system units because the units may not be strictly
equal
- * as a result of the call to ConventionalUnit.forSymbol(label).
+ * as a result of the call to ConventionalUnit.alternate(label).
*/
throw new CorruptedObjectException("labelToUnit");
}
@@ -889,7 +889,7 @@ appPow: if (unit == null) {
return;
}
}
- toAppendTo.append('?');
+ toAppendTo.append(SystemUnit.UNFORMATTABLE);
}
/**
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/Units.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/Units.java
index d965d057d9..68954b7b64 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/Units.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/measure/Units.java
@@ -1621,6 +1621,28 @@ public final class Units extends Static {
return unit.transform(LinearConverter.scale(numerator, denominator));
}
+ /**
+ * Creates an unit for values computed by the logarithm in base 10 of
values in the given unit.
+ * Conversions from the given unit to the returned unit is done by {@link
Math#log10(double)}.
+ *
+ * <p><strong>The given unit should be dimensionless.</strong>
+ * However, this method does not enforce this constraint in order to allow
the creation of
+ * units such as <a
href="https://en.wikipedia.org/wiki/Decibel_watt">decibel watt</a>.
+ * For example:</p>
+ *
+ * {@snippet lang="java" :
+ * Unit<Power> dBW = Units.logarithm(Units.WATT).divide(10);
+ * }
+ *
+ * @param unit the unit from which to convert.
+ * @return an unit which is the logarithm in base 10 of the given unit.
+ *
+ * @since 1.5
+ */
+ public static <Q extends Quantity<Q>> Unit<Q> logarithm(final Unit<Q>
unit) {
+ return unit.transform(PowerOf10.INSTANCE);
+ }
+
/**
* Returns the factor by which to multiply the standard unit in order to
get the given unit.
* The "standard" unit is usually the SI unit on which the given unit is
based, as given by
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
index 257a3fdb13..74998ec8a3 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.java
@@ -166,7 +166,7 @@ public class Errors extends IndexedResourceBundle {
/**
* Cannot resolve “{0}” as an absolute path.
*/
- public static final short CanNotResolveAsAbsolutePath_1 = 205;
+ public static final short CanNotResolveAsAbsolutePath_1 = 106;
/**
* Cannot set a value for parameter “{0}”.
@@ -724,11 +724,6 @@ public class Errors extends IndexedResourceBundle {
*/
public static final short NonScaleUnit_1 = 105;
- /**
- * “{0}” is not a fundamental or derived unit.
- */
- public static final short NonSystemUnit_1 = 106;
-
/**
* “{0}” is not a time unit.
*/
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
index a8290bea8d..cf1ed4b216 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors.properties
@@ -155,7 +155,6 @@ NonAngularUnit_1 = \u201c{0}\u201d is not
an angular unit.
NonLinearUnit_1 = \u201c{0}\u201d is not a linear unit.
NonScaleUnit_1 = \u201c{0}\u201d is not a scale unit.
NonTemporalUnit_1 = \u201c{0}\u201d is not a time unit.
-NonSystemUnit_1 = \u201c{0}\u201d is not a fundamental or
derived unit.
NonRatioUnit_1 = The scale of measurement for
\u201c{0}\u201d unit is not a ratio scale.
NotABackwardReference_1 = No element for the \u201c{0}\u201d
identifier, or the identifier is a forward reference.
NotADivisorOrMultiple_4 = Value of \u2018{0}\u2019 shall be a
{1,choice,0#divisor|1#multiple} of {2} but the given value is {3}.
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
index 59f896eec0..46b4e9cdfb 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Errors_fr.properties
@@ -152,7 +152,6 @@ NonAngularUnit_1 =
\u00ab\u202f{0}\u202f\u00bb n\u2019est pas u
NonLinearUnit_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas
une unit\u00e9 de longueurs.
NonScaleUnit_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas
une unit\u00e9 d\u2019\u00e9chelles.
NonTemporalUnit_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas
une unit\u00e9 de temps.
-NonSystemUnit_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas
une unit\u00e9 fondamentale ou d\u00e9riv\u00e9e.
NonRatioUnit_1 = L\u2019\u00e9chelle de mesure de
l\u2019unit\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019est pas une \u00e9chelle
de rapports.
NotABackwardReference_1 = Il n\u2019y a pas d\u2019\u00e9l\u00e9ment
pour l\u2019identifiant \u201c{0}\u201d, ou l\u2019identifiant est une
r\u00e9f\u00e9rence vers l\u2019avant.
NotADivisorOrMultiple_4 = La valeur de \u2018{0}\u2019 doit
\u00eatre un {1,choice,0#diviseur|1#multiple} de {2}, mais la valeur
donn\u00e9e est {3}.
diff --git
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/measure/ConventionalUnitTest.java
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/measure/ConventionalUnitTest.java
index f5abf7c68d..8283be0b94 100644
---
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/measure/ConventionalUnitTest.java
+++
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/measure/ConventionalUnitTest.java
@@ -19,6 +19,7 @@ package org.apache.sis.measure;
import javax.measure.IncommensurableException;
import javax.measure.Unit;
import javax.measure.UnitConverter;
+import javax.measure.quantity.Power;
import javax.measure.quantity.Volume;
// Test dependencies
@@ -277,6 +278,22 @@ public final class ConventionalUnitTest extends TestCase {
assertEquals(40, cl.getConverterTo(cm3).convert(4), "4 cL to cm³");
}
+ /**
+ * Tests the creation of a unit of measurement defined by a logarithm.
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/DBm">Decibel-milliwatts on
Wikipedia</a>
+ */
+ @Test
+ public void testDecibelWatt() {
+ final Unit<Power> dBm =
Units.logarithm(Units.WATT.divide(1000)).divide(10);
+ final UnitConverter c = dBm.getConverterTo(Units.WATT);
+ assertEquals(100000, c.convert(80));
+ assertEquals( 1000, c.convert(60));
+ assertEquals( 10, c.convert(40));
+ assertEquals( 1, c.convert(30));
+ assertEquals(0.3162, c.convert(25), 0.0001);
+ }
+
/**
* Serializes some units, deserializes them and verifies that we get the
same instance.
*/