Hello
Le 2024-05-10 à 12 h 31, 张浩 a écrit :
Recently, I have encountered many doubts in the process of developing
using the org.apache.sis.measure package. I found that many useful
classes, such as AbstractConverter and its subclasses, as well as the
UnitRegistry class, are not public. Therefore, I cannot reuse existing
converters like LinearConverter class, nor can I extend based on
AbstractConverter, let alone use UnitRegistry to register some special
units that cannot be derived from SI units.
In principle, in should not be necessary to make those classes public
for allowing custom unit definitions. However, I understand that
creating a custom UnitConverter is a bit tedious, so I just made
AbstractConverter public (for SIS 1.5) for reducing user's
implementation effort.
For example, I now hope to implement two units representing power -
dBm and dBw - and realize mutual conversion with WATT; also to achieve
mutual mapping between symbols and unit instances. But after much
thought, I still don't know how to use the classes under
org.apache.sis.measure package to construct these two units.
With the current SIS release (1.4), the following should work, were
DBWConverter is a custom converter given later:
static final Unit<Power> dBW = Units.WATT.transform(DBWConverter.FORWARD);
static final Unit<Power> dBm =
Units.WATT.divide(1000).transform(DBWConverter.FORWARD);
static final UnitFormat FORMAT = new UnitFormat(Locale.US);
static {
FORMAT.label(dBW, "dBW");
FORMAT.label(dBm, "dBm");
}
It should be all needed. Unit conversions between dBW or dBm and other
units of power should work (I tried a few). For getting a unit from a
symbol, or printing a unit, it would be necessary to use
FORMAT.parse("dBW") and FORMAT.format(dBW) instead of Units.parse("dBW")
and dBW.toString(). If the latter is anoying, it is possible to cheat as
below:
Unit<Power> dBW = Units.WATT.transform(DBWConverter.FORWARD);
FORMAT.label(dBW, "dBW");
dBW = FORMAT.parse("dbW");
For the upcoming SIS release (1.5), I made the task a bit easier (the
call to alternate(String) will not work with SIS 1.4 because JSR-385
specification said that it should not be allowed if the unit is not an
unscaled unit. For SIS 1.5, I relaxed this restriction):
static final Unit<Power> dBW =
Units.logarithm(Units.WATT).divide(10).alternate("dBW");
Unit converter is below (reminder: should not be needed anymore with SIS
1.5):
class DBWConverter implements UnitConverter {
static final DBWConverter FORWARD = new DBWConverter(false);
static final DBWConverter INVERSE = new DBWConverter(true);
private final boolean inverse;
private DBWConverter(boolean inverse) {
this.inverse = inverse;
}
@Override public boolean isIdentity() {return false;}
@Override public boolean isLinear() {return false;}
@Override
public UnitConverter inverse() {
return inverse ? FORWARD : INVERSE;
}
@Override
public Number convert(Number value) {
return convert(value.doubleValue());
}
@Override
public double convert(double value) {
return inverse ? Math.log10(value)*10 : Math.pow(10, value/10);
}
@Override
public UnitConverter concatenate(UnitConverter uc) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public List<? extends UnitConverter> getConversionSteps() {
return List.of(this);
}
}
Martin