Angles (geometric), normalization and conversion: Difference between revisions

Content added Content deleted
(→‎{{header|J}}: simplify NAMES definition (also: the ,. was a no-op in the original))
(→‎{{header|Groovy}}: new solution)
Line 618: Line 618:
</pre>
</pre>



=={{header|Groovy}}==
This solution creates the concept of an angular quantity with subclasses for different units of measure. Rather than creating individual functions (d2d, r2m, etc.) this solution uses inheritance, polymorphism, and operator overloading to implement the conversions and comparisons in a relatively natural way for idiomatic Groovy.
<lang groovy>import java.lang.reflect.Constructor

abstract class Angle implements Comparable<? extends Angle> {
double value

Angle(double value = 0) { this.value = normalize(value) }

abstract Number unitCircle()
abstract String unitName()

Number normalize(double n) { n % this.unitCircle() }

def <B extends Angle> B asType(Class<B> bClass){
if (bClass == this.class) return this
bClass.getConstructor(Number.class).newInstance(0).tap {
value = this.value * unitCircle() / this.unitCircle()
}
}

String toString() {
"${String.format('%14.8f',value)}${this.unitName()}"
}

int hashCode() {
value.hashCode() + 17 * unit().hashCode()
}

int compareTo(Angle that) {
this.value * that.unitCircle() <=> that.value * this.unitCircle()
}

boolean equals(that) {
this.is(that) ? true
: that instanceof Angle ? (this <=> that) == 0
: that instanceof Number ? this.value == this.normalize(that)
: super.equals(that)
}
}

class Degrees extends Angle {
static final int UNIT_CIRCLE = 360
Number unitCircle() { UNIT_CIRCLE }
static final String UNIT = "º "
String unitName() { UNIT }
Degrees(Number value = 0) { super(value) }
}

class Gradians extends Angle {
static final int UNIT_CIRCLE = 400
Number unitCircle() { UNIT_CIRCLE }
static final String UNIT = " grad"
String unitName() { UNIT }
Gradians(Number value = 0) { super(value) }
}

class Mils extends Angle {
static final int UNIT_CIRCLE = 6400
Number unitCircle() { UNIT_CIRCLE }
static final String UNIT = " mil "
String unitName() { UNIT }
Mils(Number value = 0) { super(value) }
}

class Radians extends Angle {
static final double UNIT_CIRCLE = Math.PI*2
Number unitCircle() { UNIT_CIRCLE }
static final String UNIT = " rad "
String unitName() { UNIT }
Radians(Number value = 0) { super(value) }
}</lang>

This category class allows Angles to interoperate more easily with Numbers:
<lang groovy>class AngleCategory {
static Degrees getDeg(Number n) { new Degrees(n) }
static Gradians getGrad(Number n) { new Gradians(n) }
static Mils getMil(Number n) { new Mils(n) }
static Radians getRad(Number n) { new Radians(n) }
}</lang>

Test:
<lang groovy>Number.metaClass.mixin AngleCategory

[ -2, -1, 0, 1, 2, 6.2831853, 16, 57.2957795, 359, 399, 6399, 1000000 ].each { rawAngle ->
println "\n raw angle normalized ------------------------------ conversions ------------------------------"
[rawAngle.deg, rawAngle.grad, rawAngle.mil, rawAngle.rad].each { angle ->
printf("%10s %20s %s %s %s %s\n", rawAngle.toString(), angle,
angle as Degrees, angle as Gradians,
angle as Mils, angle as Radians
)
}
}

// some additional checks implied in the task statement
// but not requested for solution demonstration
assert 360.deg == 0.deg
assert 90.deg == 100.grad
assert Math.PI.rad == 3200.mil</lang>

{{out}}
<pre style="height:60ex;overflow:scroll;"> raw angle normalized ------------------------------ conversions ------------------------------
-2 -2.00000000º -2.00000000º -2.22222222 grad -35.55555556 mil -0.03490659 rad
-2 -2.00000000 grad -1.80000000º -2.00000000 grad -32.00000000 mil -0.03141593 rad
-2 -2.00000000 mil -0.11250000º -0.12500000 grad -2.00000000 mil -0.00196350 rad
-2 -2.00000000 rad -114.59155903º -127.32395447 grad -2037.18327158 mil -2.00000000 rad

raw angle normalized ------------------------------ conversions ------------------------------
-1 -1.00000000º -1.00000000º -1.11111111 grad -17.77777778 mil -0.01745329 rad
-1 -1.00000000 grad -0.90000000º -1.00000000 grad -16.00000000 mil -0.01570796 rad
-1 -1.00000000 mil -0.05625000º -0.06250000 grad -1.00000000 mil -0.00098175 rad
-1 -1.00000000 rad -57.29577951º -63.66197724 grad -1018.59163579 mil -1.00000000 rad

raw angle normalized ------------------------------ conversions ------------------------------
0 0.00000000º 0.00000000º 0.00000000 grad 0.00000000 mil 0.00000000 rad
0 0.00000000 grad 0.00000000º 0.00000000 grad 0.00000000 mil 0.00000000 rad
0 0.00000000 mil 0.00000000º 0.00000000 grad 0.00000000 mil 0.00000000 rad
0 0.00000000 rad 0.00000000º 0.00000000 grad 0.00000000 mil 0.00000000 rad

raw angle normalized ------------------------------ conversions ------------------------------
1 1.00000000º 1.00000000º 1.11111111 grad 17.77777778 mil 0.01745329 rad
1 1.00000000 grad 0.90000000º 1.00000000 grad 16.00000000 mil 0.01570796 rad
1 1.00000000 mil 0.05625000º 0.06250000 grad 1.00000000 mil 0.00098175 rad
1 1.00000000 rad 57.29577951º 63.66197724 grad 1018.59163579 mil 1.00000000 rad

raw angle normalized ------------------------------ conversions ------------------------------
2 2.00000000º 2.00000000º 2.22222222 grad 35.55555556 mil 0.03490659 rad
2 2.00000000 grad 1.80000000º 2.00000000 grad 32.00000000 mil 0.03141593 rad
2 2.00000000 mil 0.11250000º 0.12500000 grad 2.00000000 mil 0.00196350 rad
2 2.00000000 rad 114.59155903º 127.32395447 grad 2037.18327158 mil 2.00000000 rad

raw angle normalized ------------------------------ conversions ------------------------------
6.2831853 6.28318530º 6.28318530º 6.98131700 grad 111.70107200 mil 0.10966227 rad
6.2831853 6.28318530 grad 5.65486677º 6.28318530 grad 100.53096480 mil 0.09869604 rad
6.2831853 6.28318530 mil 0.35342917º 0.39269908 grad 6.28318530 mil 0.00616850 rad
6.2831853 6.28318530 rad 359.99999959º 399.99999954 grad 6399.99999269 mil 6.28318530 rad

raw angle normalized ------------------------------ conversions ------------------------------
16 16.00000000º 16.00000000º 17.77777778 grad 284.44444444 mil 0.27925268 rad
16 16.00000000 grad 14.40000000º 16.00000000 grad 256.00000000 mil 0.25132741 rad
16 16.00000000 mil 0.90000000º 1.00000000 grad 16.00000000 mil 0.01570796 rad
16 3.43362939 rad 196.73247221º 218.59163579 grad 3497.46617261 mil 3.43362939 rad

raw angle normalized ------------------------------ conversions ------------------------------
57.2957795 57.29577950º 57.29577950º 63.66197722 grad 1018.59163556 mil 1.00000000 rad
57.2957795 57.29577950 grad 51.56620155º 57.29577950 grad 916.73247200 mil 0.90000000 rad
57.2957795 57.29577950 mil 3.22288760º 3.58098622 grad 57.29577950 mil 0.05625000 rad
57.2957795 0.74711174 rad 42.80634926º 47.56261029 grad 761.00176466 mil 0.74711174 rad

raw angle normalized ------------------------------ conversions ------------------------------
359 359.00000000º 359.00000000º 398.88888889 grad 6382.22222222 mil 6.26573201 rad
359 359.00000000 grad 323.10000000º 359.00000000 grad 5744.00000000 mil 5.63915881 rad
359 359.00000000 mil 20.19375000º 22.43750000 grad 359.00000000 mil 0.35244743 rad
359 0.85843749 rad 49.18484520º 54.64982800 grad 874.39724794 mil 0.85843749 rad

raw angle normalized ------------------------------ conversions ------------------------------
399 39.00000000º 39.00000000º 43.33333333 grad 693.33333333 mil 0.68067841 rad
399 399.00000000 grad 359.10000000º 399.00000000 grad 6384.00000000 mil 6.26747734 rad
399 399.00000000 mil 22.44375000º 24.93750000 grad 399.00000000 mil 0.39171733 rad
399 3.15932565 rad 181.01602572º 201.12891747 grad 3218.06267946 mil 3.15932565 rad

raw angle normalized ------------------------------ conversions ------------------------------
6399 279.00000000º 279.00000000º 310.00000000 grad 4960.00000000 mil 4.86946861 rad
6399 399.00000000 grad 359.10000000º 399.00000000 grad 6384.00000000 mil 6.26747734 rad
6399 6399.00000000 mil 359.94375000º 399.93750000 grad 6399.00000000 mil 6.28220356 rad
6399 2.71735729 rad 155.69310421º 172.99233802 grad 2767.87740825 mil 2.71735729 rad

raw angle normalized ------------------------------ conversions ------------------------------
1000000 280.00000000º 280.00000000º 311.11111111 grad 4977.77777778 mil 4.88692191 rad
1000000 0.00000000 grad 0.00000000º 0.00000000 grad 0.00000000 mil 0.00000000 rad
1000000 1600.00000000 mil 90.00000000º 100.00000000 grad 1600.00000000 mil 1.57079633 rad
1000000 5.92562114 rad 339.51308232º 377.23675814 grad 6035.78813019 mil 5.92562114 rad</pre>


=={{header|J}}==
=={{header|J}}==