{-# LANGUAGE UnicodeSyntax #-}
module GraphRewriting.Layout.Rotation
	(module GraphRewriting.Layout.Rotation,
	 module Data.View)
where

import Prelude.Unicode
import Data.Vector.Class
import Data.Vector.V2
import Data.View
import GraphRewriting.Layout.Geometry


newtype Rotation = Rotation {rotation  Angle}

type Angle = Double -- ∊ [-π,π]
type Impulse = Angle  Angle
type Momentum = Impulse  Rotation  Rotation

v01 = Vector2 0 1

meanAngle  [Angle]  Angle
meanAngle as = angle v01 $ focalPoint [rotate a $ v01 | a  as]

momSum  [Momentum]  Momentum
momSum [] impulse r = r
momSum as impulse r = Rotation $ meanAngle [rotation (a impulse r) | a  as]

approach  Rotation  Momentum
approach target impulse current = momentum (angle currentV targetV) impulse current where
	targetV = rotate (rotation target) v01
	currentV = rotate (rotation current) v01

momentum  Angle  Momentum
momentum a impulse = Rotation . (+) (signum a * impulse (abs a)) . rotation

angle  Vector2  Vector2  Angle
angle u v = sign  (acos $ bound $ vdot a b) where
	sign = signum $ v2y b  v2x a - v2y a  v2x b
	a = vnormalise u
	b = vnormalise v
	bound x = max (-1) (min 1 x) -- due to a rounding error in (vdot a b), acos might yield NaN

rotate  Angle  Vector2  Vector2
rotate a (Vector2 x y) = Vector2 (x  cos a - y  sin a) (x  sin a + y  cos a)