diff --git a/README.md b/README.md index bec107a..8371695 100644 --- a/README.md +++ b/README.md @@ -353,18 +353,18 @@ Distance reducedDistance2 = roadLength.log10(); // 2.0 ```java Angle exampleAngle = Angle.ofDegrees(90); -Angle sinResult = exampleAngle.sin(); // 1 -Angle cosResult = exampleAngle.cos(); // 0 +double sinResult = exampleAngle.sin(); // 1 +double cosResult = exampleAngle.cos(); // 0 Angle angle45 = exampleAngle.withValue(45); -Angle tanResult = angle45.tan(); // 1 -Angle cotResult = angle45.cot(); // 1 +double tanResult = angle45.tan(); // 1 +double cotResult = angle45.cot(); // 1 Angle angleRad1 = exampleAngle.toRadians().withValue(1); -Angle aSinResult = angleRad1.asin(); // 1.570796(..) -Angle aCosResult = angleRad1.acos(); // 0 -Angle aTanResult = angleRad1.atan(); // 0.785398(..) -Angle aCotResult = angleRad1.acot(); // 0.785398(..) +double aSinResult = angleRad1.asin(); // 1.570796(..) +double aCosResult = angleRad1.acos(); // 0 +double aTanResult = angleRad1.atan(); // 0.785398(..) +double aCotResult = angleRad1.acot(); // 0.785398(..) ``` Please keep in mind that not all values belong to the domain of a given trigonometric function. Some might throw an exception if they hold invalid value for a specific function. diff --git a/unitility-core/src/main/java/com/synerset/unitility/unitsystem/TrigonometricQuantity.java b/unitility-core/src/main/java/com/synerset/unitility/unitsystem/TrigonometricQuantity.java index 115988c..b8ecb68 100644 --- a/unitility-core/src/main/java/com/synerset/unitility/unitsystem/TrigonometricQuantity.java +++ b/unitility-core/src/main/java/com/synerset/unitility/unitsystem/TrigonometricQuantity.java @@ -7,40 +7,39 @@ import java.util.function.DoubleUnaryOperator; /** - * Interface representing a calculable quantity with operations for basic arithmetics. + * Interface representing a calculable quantity with operations for basic arithmetic and trigonometric functions. * * @param The type of {@link PhysicalQuantity} implementing this interface. */ public interface TrigonometricQuantity> extends CalculableQuantity { - // Trigonometric /** - * Calculate the sine of the physical quantity's value in a current unit.

- * If the quantity is an instance of {@link AngleUnit} its value will be automatically - * converted to radians before calculating resulting value. + * Calculates the sine of the physical quantity's value in its current unit. + * If the quantity is an instance of {@link AngleUnit}, its value will be automatically + * converted to radians before calculating the resulting value. * - * @return A new physical quantity with the sine of the current value in a current unit. + * @return The sine of the current value. */ - default Q sin() { + default double sin() { return applyTrigonometricFunction(Math::sin); } /** - * Calculate the hyperbolic sine of the physical quantity's value. + * Calculates the hyperbolic sine of the physical quantity's value. * - * @return A new physical quantity with the hyperbolic sine of the current value. + * @return The hyperbolic sine of the current value. */ - default Q sinh() { + default double sinh() { return applyTrigonometricFunction(Math::sinh); } /** - * Calculate the arcsine of the physical quantity's value. + * Calculates the arcsine of the physical quantity's value. * - * @return A new physical quantity with the arcsine of the current value. + * @return The arcsine of the current value. * @throws UnitSystemArgumentException if the value is out of the range [-1, 1]. */ - default Q asin() { + default double asin() { double value = getValueInRadians(); if (value < -1 || value > 1) { throw new UnitSystemArgumentException("Value out of range for arcsine. Valid range is [-1, 1]."); @@ -49,33 +48,30 @@ default Q asin() { } /** - * Calculate the cosine of the physical quantity's value in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the cosine of the physical quantity's value in its current unit. * - * @return A new physical quantity with the cosine of the current value. + * @return The cosine of the current value. */ - default Q cos() { + default double cos() { return applyTrigonometricFunction(Math::cos); } /** - * Calculate the hyperbolic cosine of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the hyperbolic cosine of the physical quantity's value in its current unit. * - * @return A new physical quantity with the hyperbolic cosine of the current value. + * @return The hyperbolic cosine of the current value. */ - default Q cosh() { + default double cosh() { return applyTrigonometricFunction(Math::cosh); } /** - * Calculate the arccosine of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the arccosine of the physical quantity's value in its current unit. * - * @return A new physical quantity with the arccosine of the current value. + * @return The arccosine of the current value. * @throws UnitSystemArgumentException if the value is out of the range [-1, 1]. */ - default Q acos() { + default double acos() { double value = getValueInRadians(); if (value < -1 || value > 1) { throw new UnitSystemArgumentException("Value out of range for arccosine. Valid range is [-1, 1]."); @@ -84,13 +80,12 @@ default Q acos() { } /** - * Calculate the tangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the tangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the tangent of the current value. + * @return The tangent of the current value. * @throws UnitSystemArgumentException if the value is an odd multiple of π/2. */ - default Q tan() { + default double tan() { double value = getValueInRadians(); if (isMultipleOfPiOverTwo(value)) { throw new UnitSystemArgumentException("Tangent is undefined for odd multiples of π/2."); @@ -99,81 +94,98 @@ default Q tan() { } /** - * Calculate the hyperbolic tangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the hyperbolic tangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the hyperbolic tangent of the current value. + * @return The hyperbolic tangent of the current value. */ - default Q tanh() { + default double tanh() { return applyTrigonometricFunction(Math::tanh); } /** - * Calculate the arctangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the arctangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the arctangent of the current value. + * @return The arctangent of the current value. */ - default Q atan() { + default double atan() { return applyTrigonometricFunction(Math::atan); } /** - * Calculate the cotangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the cotangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the cotangent of the current value. + * @return The cotangent of the current value. * @throws UnitSystemArgumentException if the value is a multiple of π. */ - default Q cot() { + default double cot() { double value = getValueInRadians(); if (isMultipleOfPi(value)) { throw new UnitSystemArgumentException("Cotangent is undefined for multiples of π."); } - return withValue(1 / tan().getValue()); + return 1 / tan(); } /** - * Calculate the hyperbolic cotangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the hyperbolic cotangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the hyperbolic cotangent of the current value. + * @return The hyperbolic cotangent of the current value. * @throws UnitSystemArgumentException if the value is 0. */ - default Q coth() { + default double coth() { double value = getValueInRadians(); if (value == 0) { throw new UnitSystemArgumentException("Hyperbolic cotangent is undefined for 0."); } - return withValue(1 / tanh().getValue()); + return 1 / tanh(); } /** - * Calculate the arccotangent of the physical quantity's in a current unit. - * Use toUnit(Unit) if intended to convert value in other supported unit. + * Calculates the arccotangent of the physical quantity's value in its current unit. * - * @return A new physical quantity with the arccotangent of the current value. + * @return The arccotangent of the current value. */ - default Q acot() { - return withValue(1 / atan().getValue()); + default double acot() { + return 1 / atan(); } - @SuppressWarnings("unchecked") - private Q applyTrigonometricFunction(DoubleUnaryOperator unaryOperator) { - PhysicalQuantity unitInRadians = toUnit(AngleUnits.RADIANS); - double resultingValue = unaryOperator.applyAsDouble(unitInRadians.getValue()); - return (Q) unitInRadians.withValue(resultingValue).toUnit(getUnitType()); + /** + * Applies a trigonometric function to the physical quantity's value. + * + * @param unaryOperator the trigonometric function to apply. + * @return The result of the trigonometric function. + */ + private double applyTrigonometricFunction(DoubleUnaryOperator unaryOperator) { + double unitInRadians = getValueInRadians(); + return unaryOperator.applyAsDouble(unitInRadians); } + /** + * Gets the value of the physical quantity in radians. + * + * @return The value in radians. + */ private double getValueInRadians() { return toUnit(AngleUnits.RADIANS).getValue(); } + /** + * Checks if the value is a multiple of π/2. + * + * @param value the value to check. + * @return True if the value is a multiple of π/2, false otherwise. + */ private boolean isMultipleOfPiOverTwo(double value) { return Math.abs((value / (Math.PI / 2)) % 1) < 1e-10; } + /** + * Checks if the value is a multiple of π. + * + * @param value the value to check. + * @return True if the value is a multiple of π, false otherwise. + */ private boolean isMultipleOfPi(double value) { return Math.abs((value / Math.PI) % 1) < 1e-10; } + } diff --git a/unitility-core/src/test/java/com/synerset/unitility/unitsystem/TrigonometricQuantityTest.java b/unitility-core/src/test/java/com/synerset/unitility/unitsystem/TrigonometricQuantityTest.java index 81f8871..06e2e79 100644 --- a/unitility-core/src/test/java/com/synerset/unitility/unitsystem/TrigonometricQuantityTest.java +++ b/unitility-core/src/test/java/com/synerset/unitility/unitsystem/TrigonometricQuantityTest.java @@ -17,10 +17,10 @@ void sin_shouldCalculateSine() { Angle angle = Angle.ofRadians(Math.PI / 2); // When - Angle sinAngle = angle.sin(); + double sinAngle = angle.sin(); // Then - Angle expectedAngle = Angle.ofRadians(Math.sin(Math.PI / 2)); + double expectedAngle = Angle.ofRadians(Math.sin(Math.PI / 2)).getValue(); assertThat(sinAngle).isEqualTo(expectedAngle); } @@ -31,10 +31,10 @@ void cos_shouldCalculateCosine() { Angle angle = Angle.ofRadians(0); // When - Angle cosAngle = angle.cos(); + double cosAngle = angle.cos(); // Then - Angle expectedAngle = Angle.ofRadians(Math.cos(0)); + double expectedAngle = Angle.ofRadians(Math.cos(0)).getValue(); assertThat(cosAngle).isEqualTo(expectedAngle); } @@ -45,10 +45,10 @@ void tan_shouldCalculateTangent() { Angle angle = Angle.ofRadians(Math.PI / 4); // When - Angle tanAngle = angle.tan(); + double tanAngle = angle.tan(); // Then - Angle expectedAngle = Angle.ofRadians(Math.tan(Math.PI / 4)); + double expectedAngle = Angle.ofRadians(Math.tan(Math.PI / 4)).getValue(); assertThat(tanAngle).isEqualTo(expectedAngle); } @@ -59,10 +59,10 @@ void asin_shouldCalculateArcsine() { Angle angle = Angle.ofRadians(Math.sin(Math.PI / 6)); // When - Angle asinAngle = angle.asin(); + double asinAngle = angle.asin(); // Then - Angle expectedAngle = Angle.ofRadians(Math.asin(Math.sin(Math.PI / 6))); + double expectedAngle = Angle.ofRadians(Math.asin(Math.sin(Math.PI / 6))).getValue(); assertThat(asinAngle).isEqualTo(expectedAngle); } @@ -84,10 +84,10 @@ void sinh_shouldCalculateHyperbolicSine() { Angle angle = Angle.ofRadians(1); // When - Angle sinhAngle = angle.sinh(); + double sinhAngle = angle.sinh(); // Then - Angle expectedAngle = Angle.ofRadians(Math.sinh(1)); + double expectedAngle = Angle.ofRadians(Math.sinh(1)).getValue(); assertThat(sinhAngle).isEqualTo(expectedAngle); } @@ -98,10 +98,10 @@ void cosh_shouldCalculateHyperbolicCosine() { Angle angle = Angle.ofRadians(1); // When - Angle coshAngle = angle.cosh(); + double coshAngle = angle.cosh(); // Then - Angle expectedAngle = Angle.ofRadians(Math.cosh(1)); + double expectedAngle = Angle.ofRadians(Math.cosh(1)).getValue(); assertThat(coshAngle).isEqualTo(expectedAngle); } @@ -112,10 +112,10 @@ void cot_shouldCalculateCotangent() { Angle angle = Angle.ofRadians(Math.PI / 4); // When - Angle ctgAngle = angle.cot(); + double ctgAngle = angle.cot(); // Then - Angle expectedAngle = Angle.ofRadians(1 / Math.tan(Math.PI / 4)); + double expectedAngle = Angle.ofRadians(1 / Math.tan(Math.PI / 4)).getValue(); assertThat(ctgAngle).isEqualTo(expectedAngle); } @@ -126,10 +126,10 @@ void coth_shouldCalculateHyperbolicCotangent() { Angle angle = Angle.ofRadians(1); // When - Angle ctghAngle = angle.coth(); + double ctghAngle = angle.coth(); // Then - Angle expectedAngle = Angle.ofRadians(1 / Math.tanh(1)); + double expectedAngle = Angle.ofRadians(1 / Math.tanh(1)).getValue(); assertThat(ctghAngle).isEqualTo(expectedAngle); } @@ -140,10 +140,10 @@ void acos_shouldCalculateArccosine() { Angle angle = Angle.ofRadians(Math.cos(Math.PI / 3)); // When - Angle acosAngle = angle.acos(); + double acosAngle = angle.acos(); // Then - Angle expectedAngle = Angle.ofRadians(Math.acos(Math.cos(Math.PI / 3))); + double expectedAngle = Angle.ofRadians(Math.acos(Math.cos(Math.PI / 3))).getValue(); assertThat(acosAngle).isEqualTo(expectedAngle); } @@ -154,10 +154,10 @@ void atan_shouldCalculateArctangent() { Angle angle = Angle.ofRadians(Math.tan(Math.PI / 4)); // When - Angle atanAngle = angle.atan(); + double atanAngle = angle.atan(); // Then - Angle expectedAngle = Angle.ofRadians(Math.atan(Math.tan(Math.PI / 4))); + double expectedAngle = Angle.ofRadians(Math.atan(Math.tan(Math.PI / 4))).getValue(); assertThat(atanAngle).isEqualTo(expectedAngle); } @@ -168,10 +168,10 @@ void acot_shouldCalculateArccotangent() { Angle angle = Angle.ofRadians(Math.tan(Math.PI / 4)); // When - Angle actgAngle = angle.acot(); + double actgAngle = angle.acot(); // Then - Angle expectedAngle = Angle.ofRadians(1 / Math.atan(Math.tan(Math.PI / 4))); + double expectedAngle = Angle.ofRadians(1 / Math.atan(Math.tan(Math.PI / 4))).getValue(); assertThat(actgAngle).isEqualTo(expectedAngle); } }