3 | import Derive.Prelude
5 | %language ElabReflection
23 | normalize : Double -> Double
26 | let f := ceiling (abs x / TwoPi) in x + f * TwoPi
27 | else if x >= TwoPi then
28 | let f := floor (x / TwoPi) in x - f * TwoPi
43 | {auto 0 prf : value === normalize org}
45 | %runElab derive "Angle" [Show,Eq,Ord]
52 | angle : Double -> Angle
53 | angle v = A (normalize v) v
57 | halfPi = angle (pi / 2)
61 | twoThirdPi = angle (TwoPi / 3)
65 | threeHalfPi = angle (3 * pi / 2)
76 | fullSteps : Nat -> Angle
78 | fullSteps n = angle (TwoPi / cast n)
86 | delta : Angle -> Angle -> Angle
87 | delta (A x _) (A y _) = angle (abs $
x - y)
91 | (+) : Angle -> Angle -> Angle
92 | A x _ + A y _ = angle $
x + y
96 | (-) : Angle -> Angle -> Angle
97 | A x _ - A y _ = angle $
x - y
102 | negate : Angle -> Angle
103 | negate (A x _) = angle $
TwoPi - x
107 | (*) : Double -> Angle -> Angle
108 | v * A x _ = angle $
v * x
114 | divide : Nat -> Angle -> Angle
116 | divide n (A x _) = angle (x / cast n)
125 | minDelta : Angle -> Angle -> Angle
126 | minDelta x y = min (delta x y) (negate (delta x y))
130 | toDegree : Angle -> Double
131 | toDegree a = a.value * 180 / pi
135 | fromDegree : Double -> Angle
136 | fromDegree = angle . (*) (pi/180)
140 | bisector : Angle -> Angle -> Angle
141 | bisector x y = x + 0.5 * (y - x)
145 | closestAngle : Angle -> List Angle -> Maybe Angle
146 | closestAngle = minBy . delta
148 | shiftZip : List a -> List (a,a)
150 | shiftZip (x :: xs) = zip (x::xs) (xs++[x])
160 | enclosingAngles : Angle -> List Angle -> Maybe (Angle,Angle)
161 | enclosingAngles x xs =
164 | a::as => case find (\(y,z) => y <= x && x <= z) (zip (a::as) as) of
165 | Nothing => Just (last $
a::as,a)
169 | largestBisector : List Angle -> Angle
170 | largestBisector xs =
171 | fromMaybe zero . map (uncurry bisector) . maxBy diff . pairs $
sort xs
173 | pairs : List a -> List (a,a)
175 | pairs (h::t) = zip (h::t) (t ++ [h])
177 | diff : (Angle, Angle) -> Angle
180 | maxBy : Ord b => (a -> b) -> List a -> Maybe a
181 | maxBy f [] = Nothing
182 | maxBy f (h::t) = Just $
foldl (\x,y => if f x >= f y then x else y) h t
207 | %runElab derive "Arc" [Show,Eq]
211 | ngonAngle : (n : Nat) -> (0 prf : LTE 3 n) => Angle
212 | ngonAngle n = pi - fullSteps n
219 | ngonRadius : (side : Double) -> (n : Nat) -> (0 prf : LTE 3 n) => Double
220 | ngonRadius side n = 0.5 * side / cos ((ngonAngle n).value / 2)
222 | segDist : Double -> Double -> Double
223 | segDist side rad = sqrt (pow rad 2 - pow (side / 2) 2)
228 | ngonDistance : (side : Double) -> (n : Nat) -> (0 prf : LTE 3 n) => Double
229 | ngonDistance side n = segDist side (ngonRadius side n)
233 | arcRadius : (d,phi : Double) -> Double
234 | arcRadius d phi = d / (2 * sin (phi / 2))
239 | segmentLength : Nat -> (d,phi : Double) -> Double
240 | segmentLength n d phi = 2 * (arcRadius d phi) * sin (phi / (2 * cast (S n)))
242 | mkArc : Nat -> (d,phi : Double) -> Arc
244 | let r := arcRadius d phi
246 | in MkArc a (divide (S n) a) r (segDist d r)
249 | ngon : (side : Double) -> (n : Nat) -> (0 prf : LTE 3 n) => Arc
251 | let a := fullSteps n
252 | in MkArc (negate a) a (ngonRadius side n) (ngonDistance side n)
268 | arc : (n : Nat) -> (0 prf : IsSucc n) => (len,d : Double) -> Arc
269 | arc n@(S k) len d =
270 | case abs (len-d) < Epsilon of
272 | True => ngon len (S $
S $
S k)
274 | False => find 64 Epsilon (2*pi - Epsilon)
276 | best : (l,u : Double) -> Arc
278 | let ll := segmentLength n d l
279 | lu := segmentLength n d u
280 | in if abs (lu-len) <= abs (ll-len) then mkArc n d u else mkArc n d l
284 | find : (iter : Nat) -> (l,u : Double) -> Arc
285 | find 0 l u = best l u
287 | case abs (u-l) <= Epsilon of
289 | False => case segmentLength n d ((l+u)/2.0) >= len of
290 | True => find k l ((l+u)/2.0)
291 | False => find k ((l+u)/2.0) u
300 | 0 DoubleEq : Double -> Double -> Type
301 | DoubleEq x y = (abs (x - y) < 0.0000000001) === True
303 | 0 Norm : Double -> Double
304 | Norm x = normalize x
306 | 0 normalize0 : DoubleEq (Norm 0) 0.0
309 | 0 normalize2pi : DoubleEq (Norm $
2 * PI) 0
310 | normalize2pi = Refl
312 | 0 normalizeAny : DoubleEq (Norm $
21.54 * PI) (1.54 * PI)
313 | normalizeAny = Refl
315 | 0 normalizeNeg : DoubleEq (Norm $
negate PI) PI
316 | normalizeNeg = Refl
318 | 0 normalizeAnyNeg : DoubleEq (Norm $
(-21.54) * PI) ((2 - 1.54) * PI)
319 | normalizeAnyNeg = Refl