From 95dc5a25d1896e02baa2cd84a3a5f4dbdfc8fcff Mon Sep 17 00:00:00 2001
From: Kai Brassel <mail@khbrassel.de>
Date: Mon, 31 May 2021 12:40:48 +0200
Subject: [PATCH] =?UTF-8?q?New=20data=20type=20for=20fraction=20and=20new?=
 =?UTF-8?q?=20unit=20for=20CO=E2=82=82=20equivalent?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../model/Quantities.ecore                    |  6 +++
 .../cityunits/model/UrbanSimulationUnits.java | 19 ++++-----
 .../model/quantities/QuantitiesPackage.java   | 33 +++++++++++++++
 .../impl/QuantitiesFactoryImpl.java           | 22 ++++++++++
 .../impl/QuantitiesPackageImpl.java           | 40 +++++++++++++++++++
 .../cityunits/tests/QuantityTest.java         | 26 +++++++-----
 6 files changed, 128 insertions(+), 18 deletions(-)

diff --git a/de.hftstuttgart.cityunits.model/model/Quantities.ecore b/de.hftstuttgart.cityunits.model/model/Quantities.ecore
index 9d54c0d..4bb2f9a 100644
--- a/de.hftstuttgart.cityunits.model/model/Quantities.ecore
+++ b/de.hftstuttgart.cityunits.model/model/Quantities.ecore
@@ -3,4 +3,10 @@
     xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="quantities" nsURI="https://www.hftstuttgart.de/quantities" nsPrefix="quant">
   <eClassifiers xsi:type="ecore:EDataType" name="QuantityDouble" instanceClassName="de.hftstuttgart.cityunits.model.NullableQuantity"/>
   <eClassifiers xsi:type="ecore:EDataType" name="QuantityLong" instanceClassName="de.hftstuttgart.cityunits.model.NullableQuantity"/>
+  <eClassifiers xsi:type="ecore:EDataType" name="Fraction" instanceClassName="java.lang.Double">
+    <eAnnotations source="https:///org/eclipse/emf/ecore/util/ExtendedMetaData">
+      <details key="minInclusive" value="0.0"/>
+      <details key="maxInclusive" value="1.0"/>
+    </eAnnotations>
+  </eClassifiers>
 </ecore:EPackage>
diff --git a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/UrbanSimulationUnits.java b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/UrbanSimulationUnits.java
index a23ca50..ea6f2f1 100644
--- a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/UrbanSimulationUnits.java
+++ b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/UrbanSimulationUnits.java
@@ -20,31 +20,33 @@ import tech.units.indriya.unit.TransformedUnit;
 import tech.units.indriya.unit.UnitDimension;
 import tech.units.indriya.unit.Units;
 
-public class UrbanSimulationUnits extends AbstractSystemOfUnits
-{
+public class UrbanSimulationUnits extends AbstractSystemOfUnits {
 	private static final UrbanSimulationUnits INSTANCE = new UrbanSimulationUnits();
-	
+
 	@Override
 	public String getName() {
 		return getClass().getSimpleName();
 	}
 
+	public static final Unit<Dimensionless> CO2EQ = addUnit(AbstractUnit.ONE);
+	public static final Unit<Mass> TON = addUnit(Units.KILOGRAM.multiply(1000));
 	public static final Unit<Dimensionless> PARTS_PER_MILLION = addUnit(new TransformedUnit<>(AbstractUnit.ONE,
 			MultiplyConverter.ofRational(BigInteger.ONE, BigInteger.valueOf(1000000))));
 	public static final Unit<Dimensionless> DECIBEL = addUnit(AbstractUnit.ONE.transform(
 			new LogConverter(10).inverse().concatenate(MultiplyConverter.ofRational(BigInteger.ONE, BigInteger.TEN))));
-	public static final Unit<Mass> TON = addUnit(Units.KILOGRAM.multiply(1000));
-
 	public static final Unit<Intensity> IRRADIANCE = addUnit(
-			new AlternateUnit<Intensity>(Units.WATT.divide(Units.SQUARE_METRE), "W/m2"));
+			new AlternateUnit<Intensity>(Units.WATT.divide(Units.SQUARE_METRE), "W/m²"));
 
-	// To model costs I added monetary units quick and dirty as SI base units. According to JavaDoc of AbstractUnit,
-	// monetary units should rather be implemented in an extra type hierarchy below ComparableUnit.
+	// To model costs I added monetary units quick and dirty as SI base units.
+	// According to JavaDoc of AbstractUnit,
+	// monetary units should rather be implemented in an extra type hierarchy below
+	// ComparableUnit.
 	public final static Dimension MONEY_DIMENSION = UnitDimension.parse('M');
 	public final static Unit<Euro> EURO = new BaseUnit<Euro>("€", MONEY_DIMENSION);
 	public final static Unit<Dollar> DOLLAR = new BaseUnit<Dollar>("$", MONEY_DIMENSION);
 
 	static {
+		SimpleUnitFormat.getInstance().label(CO2EQ, "COâ‚‚eq");
 		SimpleUnitFormat.getInstance().label(TON, "t");
 		SimpleUnitFormat.getInstance().label(DECIBEL, "dB");
 		SimpleUnitFormat.getInstance().label(PARTS_PER_MILLION, "ppm");
@@ -52,7 +54,6 @@ public class UrbanSimulationUnits extends AbstractSystemOfUnits
 		SimpleUnitFormat.getInstance().label(DOLLAR, "$");
 	}
 
-
 	/**
 	 * Returns the unique instance of this class.
 	 *
diff --git a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/QuantitiesPackage.java b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/QuantitiesPackage.java
index 0ff58da..054ca1f 100644
--- a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/QuantitiesPackage.java
+++ b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/QuantitiesPackage.java
@@ -75,6 +75,17 @@ public interface QuantitiesPackage extends EPackage {
 	int QUANTITY_LONG = 1;
 
 
+	/**
+	 * The meta object id for the '<em>Fraction</em>' data type.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @see java.lang.Double
+	 * @see de.hftstuttgart.cityunits.model.quantities.impl.QuantitiesPackageImpl#getFraction()
+	 * @generated
+	 */
+	int FRACTION = 2;
+
+
 	/**
 	 * Returns the meta object for data type '{@link de.hftstuttgart.cityunits.model.NullableQuantity <em>Quantity Double</em>}'.
 	 * <!-- begin-user-doc -->
@@ -97,6 +108,18 @@ public interface QuantitiesPackage extends EPackage {
 	 */
 	EDataType getQuantityLong();
 
+	/**
+	 * Returns the meta object for data type '{@link java.lang.Double <em>Fraction</em>}'.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @return the meta object for data type '<em>Fraction</em>'.
+	 * @see java.lang.Double
+	 * @model instanceClass="java.lang.Double"
+	 *        annotation="https:///org/eclipse/emf/ecore/util/ExtendedMetaData minInclusive='0.0' maxInclusive='1.0'"
+	 * @generated
+	 */
+	EDataType getFraction();
+
 	/**
 	 * Returns the factory that creates the instances of the model.
 	 * <!-- begin-user-doc -->
@@ -140,6 +163,16 @@ public interface QuantitiesPackage extends EPackage {
 		 */
 		EDataType QUANTITY_LONG = eINSTANCE.getQuantityLong();
 
+		/**
+		 * The meta object literal for the '<em>Fraction</em>' data type.
+		 * <!-- begin-user-doc -->
+		 * <!-- end-user-doc -->
+		 * @see java.lang.Double
+		 * @see de.hftstuttgart.cityunits.model.quantities.impl.QuantitiesPackageImpl#getFraction()
+		 * @generated
+		 */
+		EDataType FRACTION = eINSTANCE.getFraction();
+
 	}
 
 } //QuantitiesPackage
diff --git a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesFactoryImpl.java b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesFactoryImpl.java
index d19f76b..77208bf 100644
--- a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesFactoryImpl.java
+++ b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesFactoryImpl.java
@@ -75,6 +75,8 @@ public class QuantitiesFactoryImpl extends EFactoryImpl implements QuantitiesFac
 				return createQuantityDoubleFromString(eDataType, initialValue);
 			case QuantitiesPackage.QUANTITY_LONG:
 				return createQuantityLongFromString(eDataType, initialValue);
+			case QuantitiesPackage.FRACTION:
+				return createFractionFromString(eDataType, initialValue);
 			default:
 				throw new IllegalArgumentException("The datatype '" + eDataType.getName() + "' is not a valid classifier");
 		}
@@ -92,6 +94,8 @@ public class QuantitiesFactoryImpl extends EFactoryImpl implements QuantitiesFac
 				return convertQuantityDoubleToString(eDataType, instanceValue);
 			case QuantitiesPackage.QUANTITY_LONG:
 				return convertQuantityLongToString(eDataType, instanceValue);
+			case QuantitiesPackage.FRACTION:
+				return convertFractionToString(eDataType, instanceValue);
 			default:
 				throw new IllegalArgumentException("The datatype '" + eDataType.getName() + "' is not a valid classifier");
 		}
@@ -169,6 +173,24 @@ public class QuantitiesFactoryImpl extends EFactoryImpl implements QuantitiesFac
 		return convertQuantityLong((NullableQuantity)instanceValue);
 	}
 
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public Double createFractionFromString(EDataType eDataType, String initialValue) {
+		return (Double)super.createFromString(eDataType, initialValue);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public String convertFractionToString(EDataType eDataType, Object instanceValue) {
+		return super.convertToString(eDataType, instanceValue);
+	}
+
 	/**
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
diff --git a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesPackageImpl.java b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesPackageImpl.java
index fdee812..fe0fe48 100644
--- a/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesPackageImpl.java
+++ b/de.hftstuttgart.cityunits.model/src/de/hftstuttgart/cityunits/model/quantities/impl/QuantitiesPackageImpl.java
@@ -32,6 +32,13 @@ public class QuantitiesPackageImpl extends EPackageImpl implements QuantitiesPac
 	 */
 	private EDataType quantityLongEDataType = null;
 
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	private EDataType fractionEDataType = null;
+
 	/**
 	 * Creates an instance of the model <b>Package</b>, registered with
 	 * {@link org.eclipse.emf.ecore.EPackage.Registry EPackage.Registry} by the package
@@ -113,6 +120,16 @@ public class QuantitiesPackageImpl extends EPackageImpl implements QuantitiesPac
 		return quantityLongEDataType;
 	}
 
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public EDataType getFraction() {
+		return fractionEDataType;
+	}
+
 	/**
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
@@ -144,6 +161,7 @@ public class QuantitiesPackageImpl extends EPackageImpl implements QuantitiesPac
 		// Create data types
 		quantityDoubleEDataType = createEDataType(QUANTITY_DOUBLE);
 		quantityLongEDataType = createEDataType(QUANTITY_LONG);
+		fractionEDataType = createEDataType(FRACTION);
 	}
 
 	/**
@@ -172,9 +190,31 @@ public class QuantitiesPackageImpl extends EPackageImpl implements QuantitiesPac
 		// Initialize data types
 		initEDataType(quantityDoubleEDataType, NullableQuantity.class, "QuantityDouble", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS);
 		initEDataType(quantityLongEDataType, NullableQuantity.class, "QuantityLong", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS);
+		initEDataType(fractionEDataType, Double.class, "Fraction", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS);
 
 		// Create resource
 		createResource(eNS_URI);
+
+		// Create annotations
+		// https:///org/eclipse/emf/ecore/util/ExtendedMetaData
+		createExtendedMetaDataAnnotations();
+	}
+
+	/**
+	 * Initializes the annotations for <b>https:///org/eclipse/emf/ecore/util/ExtendedMetaData</b>.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void createExtendedMetaDataAnnotations() {
+		String source = "https:///org/eclipse/emf/ecore/util/ExtendedMetaData";
+		addAnnotation
+		  (fractionEDataType,
+		   source,
+		   new String[] {
+			   "minInclusive", "0.0",
+			   "maxInclusive", "1.0"
+		   });
 	}
 
 } //QuantitiesPackageImpl
diff --git a/de.hftstuttgart.cityunits.tests/src/de/hftstuttgart/cityunits/tests/QuantityTest.java b/de.hftstuttgart.cityunits.tests/src/de/hftstuttgart/cityunits/tests/QuantityTest.java
index 0f2c70a..3d8f3f2 100644
--- a/de.hftstuttgart.cityunits.tests/src/de/hftstuttgart/cityunits/tests/QuantityTest.java
+++ b/de.hftstuttgart.cityunits.tests/src/de/hftstuttgart/cityunits/tests/QuantityTest.java
@@ -1,6 +1,6 @@
 package de.hftstuttgart.cityunits.tests;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.*;
 
 import java.util.Locale;
 import java.util.Locale.Category;
@@ -9,6 +9,7 @@ import javax.measure.Quantity;
 import javax.measure.Unit;
 import javax.measure.quantity.Area;
 import javax.measure.quantity.Length;
+import javax.measure.quantity.Mass;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
@@ -17,8 +18,7 @@ import tech.units.indriya.quantity.Quantities;
 import tech.units.indriya.unit.Units;
 
 // Quantities.getQuantity("1.50 €"); does not compile in Maven without cast to String ???
-class QuantityTest
-{
+class QuantityTest {
 	@BeforeAll
 	static void init() {
 		// Initialize additional units like metric ton, $ and € with their labels
@@ -29,31 +29,31 @@ class QuantityTest
 
 	@Test
 	void testTemperature() {
-		Quantity<?> q = Quantities.getQuantity((String)"5 °C");
+		Quantity<?> q = Quantities.getQuantity((String) "5 °C");
 
 		assertEquals("[Θ]", q.getUnit().getDimension().toString(), "Wrong dimension!");
 		assertEquals("278.15 K", q.toSystemUnit().toString(), "Wrong calculation of Celsius to Kelvin!");
 	}
-	
+
 	@Test
 	void testMetreAndArea() {
 		Unit<Area> sqm = Units.METRE.multiply(Units.METRE).asType(Area.class);
 		Quantity<Length> line = Quantities.getQuantity(2, Units.METRE);
 		Quantity<Area> area = line.multiply(line).asType(Area.class);
-		
+
 		assertEquals(sqm, area.getUnit(), "Wrong unit computation!");
 		assertEquals(4, area.getValue(), "Wrong calculation of area!");
 	}
 
 	@Test
 	void testUrbanSimulationUnitMoney() {
-		Quantity<?> cost = Quantities.getQuantity((String)"1.50 €");
+		Quantity<?> cost = Quantities.getQuantity((String) "1.50 €");
 		assertEquals(cost.getUnit(), UrbanSimulationUnits.EURO, "Wrong currency!");
 	}
 
 	@Test
 	void testUrbanSimulationUnitPPMAndTon() {
-		Quantity<?> q = Quantities.getQuantity((String)"20 ppm").multiply(Quantities.getQuantity((String)"10 t"));
+		Quantity<?> q = Quantities.getQuantity((String) "20 ppm").multiply(Quantities.getQuantity((String) "10 t"));
 		assertEquals("[M]", q.getUnit().getDimension().toString());
 		assertEquals(UrbanSimulationUnits.PARTS_PER_MILLION.multiply(UrbanSimulationUnits.TON), q.getUnit());
 		assertEquals(200, q.getValue());
@@ -61,9 +61,17 @@ class QuantityTest
 
 	@Test
 	void testkWhPerCubicMeter() {
-		Quantity<?> q = Quantities.getQuantity((String)"5.2 kW*h/m³");
+		Quantity<?> q = Quantities.getQuantity((String) "5.2 kW*h/m³");
 		assertEquals("[M]/([L]·[T]²)", q.getUnit().getDimension().toString(), "Wrong dimension!");
 		assertEquals("18720000 W·s/m³", q.toSystemUnit().toString());
 	}
 
+	@Test
+	void testCO2eq() {
+		Quantity<Mass> q = Quantities.getQuantity("5200.5 kg·CO₂eq").asType(Mass.class);
+		assertEquals("[M]", q.getUnit().getDimension().toString(), "Wrong dimension!");
+		assertTrue(q.isEquivalentTo(Quantities.getQuantity("5.2005 t·CO₂eq").asType(Mass.class)),
+				"Wrong conversion from kg of COâ‚‚eq to ton of COâ‚‚eq!");
+	}
+
 }
-- 
GitLab