package rui import ( "fmt" "math" "strconv" "strings" ) // AngleUnitType : type of enumerated constants for define a type of AngleUnit value. // Can take the following values: Radian, Degree, Gradian, and Turn type AngleUnitType uint8 const ( // Radian - angle in radians Radian AngleUnitType = 0 // Radian - angle in radians * π PiRadian AngleUnitType = 1 // Degree - angle in degrees Degree AngleUnitType = 2 // Gradian - angle in gradian (1⁄400 of a full circle) Gradian AngleUnitType = 3 // Turn - angle in turns (1 turn = 360 degree) Turn AngleUnitType = 4 ) // AngleUnit describe a size (Value field) and size unit (Type field). type AngleUnit struct { Type AngleUnitType Value float64 } // Deg creates AngleUnit with Degree type func Deg(value float64) AngleUnit { return AngleUnit{Type: Degree, Value: value} } // Rad create AngleUnit with Radian type func Rad(value float64) AngleUnit { return AngleUnit{Type: Radian, Value: value} } // PiRad create AngleUnit with PiRadian type func PiRad(value float64) AngleUnit { return AngleUnit{Type: PiRadian, Value: value} } // Grad create AngleUnit with Gradian type func Grad(value float64) AngleUnit { return AngleUnit{Type: Gradian, Value: value} } // Equal compare two AngleUnit. Return true if AngleUnit are equal func (angle AngleUnit) Equal(size2 AngleUnit) bool { return angle.Type == size2.Type && angle.Value == size2.Value } func angleUnitSuffixes() map[AngleUnitType]string { return map[AngleUnitType]string{ Degree: "deg", Radian: "rad", PiRadian: "pi", Gradian: "grad", Turn: "turn", } } // StringToAngleUnit converts the string argument to AngleUnit func StringToAngleUnit(value string) (AngleUnit, bool) { angle, err := stringToAngleUnit(value) if err != nil { ErrorLog(err.Error()) return angle, false } return angle, true } func stringToAngleUnit(value string) (AngleUnit, error) { value = strings.ToLower(strings.Trim(value, " \t\n\r")) setValue := func(suffix string, unitType AngleUnitType) (AngleUnit, error) { val, err := strconv.ParseFloat(value[:len(value)-len(suffix)], 64) if err != nil { return AngleUnit{}, err } return AngleUnit{Value: val, Type: unitType}, nil } if value == "π" { return AngleUnit{Value: 1, Type: PiRadian}, nil } if strings.HasSuffix(value, "π") { return setValue("π", PiRadian) } if strings.HasSuffix(value, "°") { return setValue("°", Degree) } for unitType, suffix := range angleUnitSuffixes() { if strings.HasSuffix(value, suffix) { return setValue(suffix, unitType) } } val, err := strconv.ParseFloat(value, 64) if err != nil { return AngleUnit{}, err } return AngleUnit{Value: val, Type: Radian}, nil } // String - convert AngleUnit to string func (angle AngleUnit) String() string { if suffix, ok := angleUnitSuffixes()[angle.Type]; ok { return fmt.Sprintf("%g%s", angle.Value, suffix) } return fmt.Sprintf("%g", angle.Value) } // cssString - convert AngleUnit to string func (angle AngleUnit) cssString() string { if angle.Type == PiRadian { return fmt.Sprintf("%grad", angle.Value*math.Pi) } return angle.String() } // ToDegree returns the angle in radians func (angle AngleUnit) ToRadian() AngleUnit { switch angle.Type { case PiRadian: return AngleUnit{Value: angle.Value * math.Pi, Type: Radian} case Degree: return AngleUnit{Value: angle.Value * math.Pi / 180, Type: Radian} case Gradian: return AngleUnit{Value: angle.Value * math.Pi / 200, Type: Radian} case Turn: return AngleUnit{Value: angle.Value * 2 * math.Pi, Type: Radian} } return angle } // ToDegree returns the angle in degrees func (angle AngleUnit) ToDegree() AngleUnit { switch angle.Type { case Radian: return AngleUnit{Value: angle.Value * 180 / math.Pi, Type: Degree} case PiRadian: return AngleUnit{Value: angle.Value * 180, Type: Degree} case Gradian: return AngleUnit{Value: angle.Value * 360 / 400, Type: Degree} case Turn: return AngleUnit{Value: angle.Value * 360, Type: Degree} } return angle } // ToGradian returns the angle in gradians (1⁄400 of a full circle) func (angle AngleUnit) ToGradian() AngleUnit { switch angle.Type { case Radian: return AngleUnit{Value: angle.Value * 200 / math.Pi, Type: Gradian} case PiRadian: return AngleUnit{Value: angle.Value * 200, Type: Gradian} case Degree: return AngleUnit{Value: angle.Value * 400 / 360, Type: Gradian} case Turn: return AngleUnit{Value: angle.Value * 400, Type: Gradian} } return angle } // ToTurn returns the angle in turns (1 turn = 360 degree) func (angle AngleUnit) ToTurn() AngleUnit { switch angle.Type { case Radian: return AngleUnit{Value: angle.Value / (2 * math.Pi), Type: Turn} case PiRadian: return AngleUnit{Value: angle.Value / 2, Type: Turn} case Degree: return AngleUnit{Value: angle.Value / 360, Type: Turn} case Gradian: return AngleUnit{Value: angle.Value / 400, Type: Turn} } return angle }