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(),
|