Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds a constructor for regular polygons #148

Merged
merged 5 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions src/Polygon2d.elm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

module Polygon2d exposing
( Polygon2d
, singleLoop, withHoles, convexHull
, singleLoop, withHoles, convexHull, regular
, outerLoop, innerLoops, vertices, edges, perimeter, area, centroid, boundingBox
, contains
, scaleAbout, rotateAround, translateBy, translateIn, mirrorAcross
Expand All @@ -32,7 +32,7 @@ holes. This module contains a variety of polygon-related functionality, such as

# Constructors

@docs singleLoop, withHoles, convexHull
@docs singleLoop, withHoles, convexHull, regular


# Properties
Expand Down Expand Up @@ -261,6 +261,31 @@ convexHull points =
singleLoop (lower ++ upper)


{-| Constructs a regular convex polygon with the specified center point,
circumradius and number of sides. The polygon will be oriented so that the
bottom edge is horizontal (assuming a Y-up coordinate system; note that SVG
uses Y-down instead!).
-}
regular : { centerPoint : Point2d units coordinates, circumradius : Quantity Float units, numSides : Int } -> Polygon2d units coordinates
regular { centerPoint, circumradius, numSides } =
let
n =
toFloat numSides

angle =
Angle.turns 1 |> Quantity.divideBy n

startAngle =
Angle.degrees -90 |> Quantity.plus (Angle.degrees 180 |> Quantity.divideBy n)

point index =
Point2d.translateBy (Vector2d.rTheta circumradius (Quantity.plus startAngle (Quantity.multiplyBy index angle))) centerPoint
in
List.range 0 (numSides - 1)
|> List.map (toFloat >> point)
|> singleLoop


{-| Convert a polygon from one units type to another, by providing a conversion
factor given as a rate of change of destination units with respect to source
units.
Expand Down
48 changes: 47 additions & 1 deletion tests/Tests/Polygon2d.elm
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ module Tests.Polygon2d exposing
, convexHullContainsAllPoints
, convexHullIsConvex
, rectangleCentroidIsInTheCenter
, regularTest
, rotatingAroundCentroidKeepsCentroid
, triangulationHasCorrectArea
, triangulationHasCorrectNumberOfTriangles
, triangulationHasCorrectWeightedCentroid
)

import Area
import Angle
import Expect
import Fuzz
import Geometry.Expect as Expect
Expand All @@ -26,6 +27,51 @@ import TriangularMesh
import Vector2d


{-| Implements the formula for area of a regular polygon.
-}
areaOfRegularNGon : Quantity.Quantity Float units -> Float -> Quantity.Quantity Float (Quantity.Squared units)
areaOfRegularNGon radius sides =
Quantity.squared radius
|> Quantity.multiplyBy sides
|> Quantity.multiplyBy (Angle.sin (Angle.turns (1 / sides)))
|> Quantity.divideBy 2


regularTest : Test
regularTest =
Test.describe "regular"
[ Test.fuzz3 Fuzz.point2d
Fuzz.length
(Fuzz.intRange 3 300)
"A centroid of a regular polygon is in the center"
<|
\center radius sides ->
Polygon2d.regular { centerPoint = center, circumradius = radius, numSides = sides }
|> Polygon2d.centroid
|> Expect.just (Expect.point2d center)
, Test.fuzz3 Fuzz.point2d
Fuzz.length
(Fuzz.intRange 3 300)
"The area matches what we would expect from a regular polygon"
<|
\center radius sides ->
Polygon2d.regular { centerPoint = center, circumradius = radius, numSides = sides }
|> Polygon2d.area
|> Expect.quantity (areaOfRegularNGon radius (toFloat sides))
, Test.test "sanity check" <|
\() ->
Polygon2d.regular { centerPoint = Point2d.meters 0.5 0.5, circumradius = meters (sqrt 2 / 2), numSides = 4 }
|> Expect.polygon2d
(Polygon2d.singleLoop
[ Point2d.meters 1 0
, Point2d.meters 1 1
, Point2d.meters 0 1
, Point2d.meters 0 0
]
)
]


convexHullIsConvex : Test
convexHullIsConvex =
Test.fuzz (Fuzz.list Fuzz.point2d)
Expand Down