RosettaCodeData/Task/Angles-geometric-normalization-and-conversion/Groovy/angles-geometric-normalization-and-conversion-1.groovy
2023-07-01 13:44:08 -04:00

70 lines
2 KiB
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) }
}