chunky v0.13.0 Chunky.Geometry.Triangle View Source
Functions for working with triangles. For predicate functions related to Triangles, see Chunky.Geometry.Triangle.Predicates
.
Triangles in Chunky are represented as a tuple of three positive integers, with each integer greater than or equal to 1
. So {3, 4, 5}
is a triangle, as is {145, 7, 139}
. Not every 3-tuple of integers is a valid triangle - {3, 5, 10}
doesn't describe a realizable
triangle. You can test for a valid triangle with Chunky.Geometry.is_valid_triangle?/1
.
Some functions will raise argument errors for invalid triangles, while others will return an error tuple, where possible.
Triangle Functions
Measurements
These functions provide measurements of triangles, their angles, or their shape.
angles/1
- Find the interior angles of a trianglearea/1
- Find the area of any triangleheight/2
- Find the bisecting height of a triangleis_multiple_heronian_triangle?/2
- Is a triangle a heronian triange with an area that is a specific multiple of the perimeter?
Construction and Deconstructing Triangles
Create new triangles, break existing triangles into smaller triangles, or recombine smaller triangles:
compose/2
- Create a new triangle from two compatible right trianglesdecompose/1
- Break a triangle into two smaller right trianglesnormalize/1
- Normalize the ordering of sides of a triangletriangles_from_hypotenuse/2
- Generate integer triangles given a hypotenuse and optional filter
Meta-inspection of triangles
Metadata about triangles:
type/1
- Determine the basic type, or form, of a triangle
Finding Triangles
Finding specific shapes of triangles (like Heronian, m-heronian, scalenes, etc) can be useful. For instance, finding triangles that are decomposable or 19-heronian triangles. Constructing these by hand can be tedious - instead we can combine a series of functions from the Triangle and Predicates modules to help find what we're looking for.
The heart of searching for triangles is the triangles_from_hypotenuse/2
function, which generates the set of all valid triangles
for a given hypotenuse edge:
iex> Triangle.triangles_from_hypotenuse(3)
[{1, 3, 3}, {2, 2, 3}, {2, 3, 3}, {3, 3, 3}]
All of the valid triangles for the given hypotenuse are generated, without duplicates, edge order independent (so {3, 2, 3}
and {2, 3, 3}
would be the same, and only one included in the output). For a small hypotenuse this output by itself can be useful
for visual inspection, but the number of valid triangles grows fairly quickly. For a hypotenuse of 15
, there
are 64
valid triangles. For a hypotenuse of 100
, there are 2550
triangles. On to the next step: filter functions.
The second parameter of triangles_from_hypotenuse/2
is a predicate function - any function that takes a triangle
as it's only parameter, and returns a boolean. The output of triangles_from_hypotenuse/2
will be filtered to contain only
those triangles that pass the filter. For instance, we can filter our list of triangles with a hypotenuse of 3
to
only the equilateral triangles:
iex> Triangle.triangles_from_hypotenuse(3, filter: &Triangle.Predicates.is_equilateral?/1)
[{3, 3, 3}]
Let's look at the first example we cited, finding decomposable triangles. Constructing these by hand can be tedious. But using
the above technique, we can quickly find what we're looking for. How about triangles with a hypotenuse of 30
that are
decomposable:
iex> Triangle.triangles_from_hypotenuse(30, filter: &Triangle.Predicates.is_decomposable?/1)
[{8, 26, 30}, {11, 25, 30}, {17, 17, 30}, {25, 25, 30}, {26, 28, 30}]
If we want to tackle the second example we cited, finding 19-heronian triangles (these are triangles whose area is exactly 19 times their perimeter), we'll need to expand our search: we don't know exactly what the hypotenuse will be, so we check multiple:
150..250
|> Enum.map(
fn h ->
Triangle.triangles_from_hypotenuse(
h,
filter: fn t ->
Triangle.is_multiple_heronian_triangle?(t, 19)
end)
end
)
|> List.flatten()
Here we've take the range of 150
to 250
, and used each of those in order as the hypotenuse of triangles_from_hypotenuse/2
. The
filter function is an anonymous function, where we use the is_multiple_heronian?/2
function to filter down to only those triangles
that are an exact multiple of perimeter and area.
Link to this section Summary
Functions
Find the angles of a triangle.
Find the area of a triangle, returning either an integer, float, or fraction value.
Compose two pythagorean (right) triangles into a larger triangle, if possible.
Decompose an integer triangle into two smaller integer right triangles.
Find the height of a triangle from the hypotenuse.
Is a triangle a heronian triangle where the area is a specific multiple of the perimeter?
Normalize the order of edges of a triangle.
Generate all of the integer triangles from a given hypotenuse h
.
Determine the characteristic type of a triangle, like right, scalene, or isoceles.
Link to this section Functions
Find the angles of a triangle.
The resulting 3-tuple will be floats, in order such that each angle is opposite
it's edge. So for a triangle with sides {a, b, c}
, the resulting angles {θa, θb, θc}
are such that θa
is opposite edge a
, θb
opposite edge b
, and θc
opposite edge
c
:
Examples
iex> Triangle.angles({3, 4, 5})
{36.86989764584401, 53.13010235415599, 90.0}
iex> Triangle.angles({13, 13, 13})
{59.99999999999999, 59.99999999999999, 59.99999999999999}
iex> Triangle.angles({10, 5, 10})
{75.52248781407008, 28.95502437185985, 75.52248781407008}
iex> Triangle.angles({30, 16, 17})
{130.73591716163173, 23.83600707762401, 25.428075760744253}
Find the area of a triangle, returning either an integer, float, or fraction value.
This function uses the heronian formula for calculating the area of any triangle.
Examples
iex> Triangle.area({3, 4, 5})
{:integer, 6}
iex> Triangle.area({5, 15, 15})
{:float, 36.9754986443726}
iex> Triangle.area({5, 5, 5})
{:float, 10.825317547305483}
iex> Triangle.area({7, 11, 13})
{:float, 38.499188303131795}
iex> Triangle.area({5, 12, 13})
{:integer, 30}
iex> Triangle.area({5, 10, 20})
** (ArgumentError) Shape of the triangle is invalid
Compose two pythagorean (right) triangles into a larger triangle, if possible.
This is the inverse of decompose/1
- two compatible right triangles can be joined on
an equal, non-hypotenuse edge to form a new triangle.
The results of this function will either be a tuple of {:ok, _}
with a one or two new triangles,
or {:error, reason}
for not being composable.
Examples
iex> Triangle.compose({12, 5, 13}, {5, 13, 12})
{:ok, {10, 13, 13}, {13, 13, 24}}
iex> Triangle.compose({12, 5, 13}, {9, 15, 12})
{:ok, {13, 14, 15}}
iex> Triangle.compose({12, 5, 13}, {3, 4, 5})
{:error, :not_composable}
iex> Triangle.compose({12, 5, 13}, {5, 7, 24})
{:error, :not_pythagorean_triangles}
Decompose an integer triangle into two smaller integer right triangles.
Examples
iex> Triangle.decompose({3, 4, 5})
{:error, :indecomposable}
iex> Triangle.decompose({6, 6, 6})
{:error, :indecomposable}
iex> Triangle.decompose({10, 13, 13})
{:ok, {5, 12, 13}, {5, 12, 13}}
iex> Triangle.decompose({13, 14, 15})
{:ok, {5, 12, 13}, {9, 12, 15}}
iex> Triangle.decompose({13, 13, 24})
{:ok, {5, 12, 13}, {5, 12, 13}}
Find the height of a triangle from the hypotenuse.
This function will return an integer, fraction, or float.
Options
base
- Atom. Default:large
. One of:small
,:medium
, or:large
. Side to use when calculating height for a scalene triangle
Examples
iex> Triangle.height({5, 5, 5})
{:float, 4.330127018922193}
iex> Triangle.height({3, 4, 5})
{:fractional, %Fraction{num: 12, den: 5}}
iex> Triangle.height({5, 5, 8})
{:integer, 3}
iex> Triangle.height({10, 13, 13})
{:integer, 12}
iex> Triangle.height({13, 14, 15})
{:fractional, %Fraction{num: 56, den: 5}}
iex> Triangle.height({13, 14, 15}, base: :medium)
{:integer, 12}
iex> Triangle.height({3, 4, 9})
** (ArgumentError) Shape of the triangle is invalid
Is a triangle a heronian triangle where the area is a specific multiple of the perimeter?
A 2-heronian
triangle would have an area that is 2*perimeter
of the triangle, while a
3-heronian
would have an area that is 3*perimeter
. For each multiple size m
, there
are a finite number of multiple heronians triangles that are m-heronian
.
Examples
iex> Triangle.is_multiple_heronian_triangle?({13, 14, 15}, 2)
true
iex> Triangle.is_multiple_heronian_triangle?({11, 25, 30}, 2)
true
iex> Triangle.is_multiple_heronian_triangle?({25, 26, 17}, 3)
true
iex> Triangle.is_multiple_heronian_triangle?({25, 28, 17}, 3)
true
iex> Triangle.is_multiple_heronian_triangle?({25, 36, 29}, 4)
true
Normalize the order of edges of a triangle.
Examples
iex> Triangle.normalize({5, 13, 7})
{5, 7, 13}
iex> Triangle.normalize({12, 8, 5})
{5, 8, 12}
iex> Triangle.normalize({55, 13, 47})
{13, 47, 55}
iex> Triangle.normalize({3, 4, 5})
{3, 4, 5}
Generate all of the integer triangles from a given hypotenuse h
.
This will create a list of triangles with integer sides and hypotenuse h
, with
no duplicates, with order independent sides. So the triangle {3, 4, 5}
and {4, 3, 5}
would be considered the same, and only one of them would be included in the output.
An optional filter
function can be provided which will be used to pre
filter the result list during computation, which can significantly reduce
memory consumption.
Options
filter
- Predicate function of arity 1, which returns a boolean
Examples
iex> Triangle.triangles_from_hypotenuse(5)
[{1, 5, 5}, {2, 4, 5}, {2, 5, 5}, {3, 3, 5}, {3, 4, 5}, {3, 5, 5}, {4, 4, 5}, {4, 5, 5}, {5, 5, 5}]
iex> Triangle.triangles_from_hypotenuse(5, filter: &Triangle.Predicates.is_scalene?/1)
[{2, 4, 5}, {3, 4, 5}]
iex> Triangle.triangles_from_hypotenuse(5, filter: &Triangle.Predicates.is_pythagorean_triangle?/1)
[{3, 4, 5}]
iex> Triangle.triangles_from_hypotenuse(125, filter: &Triangle.Predicates.is_pythagorean_triangle?/1)
[{35, 120, 125}, {44, 117, 125}, {75, 100, 125}]
Determine the characteristic type of a triangle, like right, scalene, or isoceles.
The possible types returned by this function are:
:invalid
:right
:equilateral
:isoceles
:scalene
Examples
iex> Triangle.type({3, 4, 5})
:right
iex> Triangle.type({3, 4, 9})
:invalid
iex> Triangle.type({3, 4, 4})
:isoceles
iex> Triangle.type({13, 13, 13})
:equilateral
iex> Triangle.type({7, 13, 19})
:scalene