changed README.md
 
@@ -47,6 +47,10 @@ The Math module adds many useful functions that extend Elixir's standard library
47
47
- `Math.acosh(x)` The inverse hyperbolic cosine of *x*.
48
48
- `Math.atanh(x)` The inverse hyperbolic tangent of *x*.
49
49
50
+ - Interpolation
51
+ - `Math.linear_interpolation(t,p0,p1)` Returns {x,y} of t in a linear interpolation
52
+ - `Math.bezier_curve(t,[p0,p1 ...])` Returns {x,y} of t in a bezier_curve
53
+
50
54
- Working with Collections
51
55
- `Math.Enum.product(collection)` The result of multiplying all elements in the passed collection.
52
56
- `Math.Enum.mean(collection)` the mean of the numbers in the collection.
 
@@ -82,6 +86,7 @@ import Math
82
86
(Importing allows usage of the `<~>` operator)
83
87
84
88
## Changelog
89
+ - 0.7.0 adds `Math.linear_interpolation/3` and `Math.bezier_curve/2`. Thank you, @pcarvsilva !
85
90
- 0.6.0 Adds `Math.Enum.variance/1` and `Math.Enum.stdev/1`. Thank you, @TenTakano !
86
91
- 0.5.0 Adds `Math.mod_inv`, `Math.mod_inv!` and `Math.egcd`
87
92
- 0.4.0 Adds `Math.Enum.mode/1`.
changed hex_metadata.config
 
@@ -10,4 +10,4 @@
10
10
{<<"links">>,[{<<"GitHub">>,<<"https://github.com/folz/math">>}]}.
11
11
{<<"name">>,<<"math">>}.
12
12
{<<"requirements">>,[]}.
13
- {<<"version">>,<<"0.6.0">>}.
13
+ {<<"version">>,<<"0.7.0">>}.
changed lib/math.ex
 
@@ -563,4 +563,130 @@ defmodule Math do
563
563
_ -> raise ArithmeticError, "Inputs are not coprime!"
564
564
end
565
565
end
566
+
567
+ # Interpolation
568
+
569
+ @doc """
570
+ Computes the y value of a given t point on a bezier_curve
571
+
572
+ If t is not in range [0,1] returns the interpolated point outside control points bounding box
573
+
574
+ ## Examples
575
+
576
+ iex> Math.bezier_curve(0.5, [{0,0}, {1,1}])
577
+ {0.5,0.5}
578
+
579
+ """
580
+ @spec bezier_curve(t :: number, control_points :: maybe_improper_list) :: tuple
581
+ def bezier_curve(t, control_points) when is_list(control_points) and is_number(t) do
582
+
583
+ new_points =
584
+ control_points
585
+ |> Enum.with_index()
586
+ |> Enum.slice(0..-2)
587
+ |> Enum.map(
588
+ fn {p0, index} ->
589
+ next_index = index + 1
590
+ p1 = Enum.at(control_points, next_index)
591
+ linear_interpolation(t, p0, p1)
592
+ end
593
+ )
594
+
595
+ if Enum.count(new_points) == 1 do
596
+ Enum.at(new_points, 0)
597
+ else
598
+ bezier_curve(t, new_points)
599
+ end
600
+ end
601
+
602
+ @doc """
603
+ Computes the y value of a given t point on a bezier_curve
604
+
605
+ Similar to `bezier_curve/2`, but raises an error if not on range [0,1].
606
+
607
+ ## Examples
608
+
609
+ iex> Math.bezier_curve!(0.5, [{0,0}, {1,1}])
610
+ {0.5,0.5}
611
+
612
+ iex> Math.bezier_curve!(1.5, [{0,0}, {1,1}])
613
+ ** (ArgumentError) t is not beetween 0 and 1
614
+ """
615
+ @spec bezier_curve!(t :: number, control_points :: maybe_improper_list) :: tuple
616
+ def bezier_curve!(t, control_points)
617
+ when is_number(t)
618
+ and 0.0 <= t
619
+ and t <= 1.0
620
+ and is_list(control_points) do
621
+ bezier_curve(t, control_points)
622
+ end
623
+
624
+ def bezier_curve!(t, control_points)
625
+ when is_number(t)
626
+ and is_list(control_points) do
627
+ raise ArgumentError, "t is not beetween 0 and 1"
628
+ end
629
+
630
+ @doc """
631
+ Computes the y value of a given t point on a linear_interpolation between 2 points
632
+
633
+ If t is not in range [0,1] returns the interpolated point outside control points bounding box
634
+
635
+ ## Examples
636
+
637
+ iex> Math.linear_interpolation(0.5, {0,0}, {1,1})
638
+ {0.5, 0.5}
639
+ """
640
+ @spec linear_interpolation(t :: number, p0 :: tuple, p1 :: tuple) :: tuple
641
+ def linear_interpolation(t, p0, p1)
642
+ when is_number(t)
643
+ and is_tuple(p0)
644
+ and is_tuple(p1) do
645
+
646
+ last = tuple_size(p0) - 1
647
+
648
+ 0..last
649
+ |> Enum.reduce({},
650
+ fn index, tuple ->
651
+ first_elem = p0 |> elem(index)
652
+ second_elem = p1 |> elem(index)
653
+
654
+ tuple
655
+ |> Tuple.append(
656
+ (1 - t) * first_elem + t * second_elem
657
+ )
658
+ end
659
+ )
660
+ end
661
+
662
+ @doc """
663
+ Computes the point of a given t on a linear_interpolation between 2 points
664
+
665
+ Similar to `linear_interpolation/3`, but raises an error if not on range [0,1].
666
+
667
+ ## Examples
668
+
669
+ iex> Math.linear_interpolation!(0.5, {0,0}, {1,1})
670
+ {0.5,0.5}
671
+
672
+ iex> Math.linear_interpolation!(1.5, {0,0}, {1,1})
673
+ ** (ArgumentError) t is not beetween 0 and 1
674
+ """
675
+ @spec linear_interpolation!(t :: number, p0 :: tuple, p1 :: tuple) :: tuple
676
+ def linear_interpolation!(t, p0, p1)
677
+ when is_number(t)
678
+ and 0.0 <= t
679
+ and t <= 1.0
680
+ and is_tuple(p0)
681
+ and is_tuple(p1) do
682
+ linear_interpolation(t, p0, p1)
683
+ end
684
+
685
+ def linear_interpolation!(t, p0, p1)
686
+ when is_number(t)
687
+ and is_tuple(p0)
688
+ and is_tuple(p1) do
689
+ raise ArgumentError, "t is not beetween 0 and 1"
690
+ end
691
+
566
692
end
changed mix.exs
 
@@ -6,7 +6,7 @@ defmodule Math.Mixfile do
6
6
def project do
7
7
[
8
8
app: :math,
9
- version: "0.6.0",
9
+ version: "0.7.0",
10
10
elixir: "~> 1.4",
11
11
description: description(),
12
12
package: package(),