| @@ -19,6 +19,8 @@ var ( | |||||
| // ErrRelativePointRecursion is returned when a points are relative to itself. | // ErrRelativePointRecursion is returned when a points are relative to itself. | ||||
| ErrRelativePointRecursion = errors.New("point cannot be relative to itself") | ErrRelativePointRecursion = errors.New("point cannot be relative to itself") | ||||
| ErrInvalidArguments = errors.New("invalid arguments to call function") | |||||
| ) | ) | ||||
| // Points contains a map with points. | // Points contains a map with points. | ||||
| @@ -40,52 +42,50 @@ var ErrInvalidPointID = errors.New("type cannot be converted to a PointID") | |||||
| func (p Points) Functions(pat *pattern.Pattern) map[string]govaluate.ExpressionFunction { | func (p Points) Functions(pat *pattern.Pattern) map[string]govaluate.ExpressionFunction { | ||||
| return map[string]govaluate.ExpressionFunction{ | return map[string]govaluate.ExpressionFunction{ | ||||
| "DistanceBetween": func(args ...interface{}) (interface{}, error) { | "DistanceBetween": func(args ...interface{}) (interface{}, error) { | ||||
| id0, err := toPointID(args[0]) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("parsing args[0] to pointID: %w", err) | |||||
| } | |||||
| id1, err := toPointID(args[1]) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("parsing args[0] to pointID: %w", err) | |||||
| } | |||||
| p0, err := p.getOrCreate(id0, pat, 0) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("get or create point %q: %w", id0, err) | |||||
| if len(args) != 2 { | |||||
| return nil, fmt.Errorf("function DistanceBetween() requires 2 arguments: %w", | |||||
| ErrInvalidArguments) | |||||
| } | } | ||||
| p1, err := p.getOrCreate(id1, pat, 0) | |||||
| points, err := p.getOrCreateFromArgs(pat, args...) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("get or create point %q: %w", id1, err) | |||||
| return nil, err | |||||
| } | } | ||||
| return p0.Position().Distance(p1.Position()), nil | |||||
| return points[0].Position().Distance(points[1].Position()), nil | |||||
| }, | }, | ||||
| "AngleBetween": func(args ...interface{}) (interface{}, error) { | "AngleBetween": func(args ...interface{}) (interface{}, error) { | ||||
| id0, err := toPointID(args[0]) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("parsing args[0] to pointID: %w", err) | |||||
| if len(args) != 2 { | |||||
| return nil, fmt.Errorf("function AngleBetween() requires 2 arguments: %w", | |||||
| ErrInvalidArguments) | |||||
| } | } | ||||
| id1, err := toPointID(args[1]) | |||||
| points, err := p.getOrCreateFromArgs(pat, args...) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("parsing args[0] to pointID: %w", err) | |||||
| return nil, err | |||||
| } | } | ||||
| p0, err := p.getOrCreate(id0, pat, 0) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("get or create point %q: %w", id0, err) | |||||
| } | |||||
| return points[0].Vector().AngleBetween(points[1].Vector()), nil | |||||
| }, | |||||
| } | |||||
| } | |||||
| p1, err := p.getOrCreate(id1, pat, 0) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("get or create point %q: %w", id1, err) | |||||
| } | |||||
| func (p Points) getOrCreateFromArgs(pat *pattern.Pattern, args ...interface{}) ([]point.Point, error) { | |||||
| points := make([]point.Point, 0, len(args)) | |||||
| for i, arg := range args { | |||||
| id, err := toPointID(arg) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("parsing args[%d] to pointID: %w", i, err) | |||||
| } | |||||
| return p0.Vector().AngleBetween(p1.Vector()), nil | |||||
| }, | |||||
| newPoint, err := p.getOrCreate(id, pat, 0) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("get or create point %q: %w", id, err) | |||||
| } | |||||
| points = append(points, newPoint) | |||||
| } | } | ||||
| return points, nil | |||||
| } | } | ||||
| func toPointID(arg interface{}) (point.ID, error) { | func toPointID(arg interface{}) (point.ID, error) { | ||||
| @@ -111,9 +111,19 @@ type BetweenPoint struct { | |||||
| func (p Points) evaluationFunctions() map[string]govaluate.ExpressionFunction { | func (p Points) evaluationFunctions() map[string]govaluate.ExpressionFunction { | ||||
| return map[string]govaluate.ExpressionFunction{ | return map[string]govaluate.ExpressionFunction{ | ||||
| "acos": func(args ...interface{}) (interface{}, error) { | "acos": func(args ...interface{}) (interface{}, error) { | ||||
| if len(args) != 1 { | |||||
| return nil, fmt.Errorf("function acos() requires 1 argument: %w", | |||||
| ErrInvalidArguments) | |||||
| } | |||||
| return math.Acos(args[0].(float64)), nil | return math.Acos(args[0].(float64)), nil | ||||
| }, | }, | ||||
| "atan2": func(args ...interface{}) (interface{}, error) { | "atan2": func(args ...interface{}) (interface{}, error) { | ||||
| if len(args) != 2 { | |||||
| return nil, fmt.Errorf("function atan2() requires 2 arguments: %w", | |||||
| ErrInvalidArguments) | |||||
| } | |||||
| return math.Atan2(args[0].(float64), args[1].(float64)), nil | return math.Atan2(args[0].(float64), args[1].(float64)), nil | ||||
| }, | }, | ||||
| } | } | ||||