--------------------------------------------------------------------------------
-- |
-- Module      :  HGeometry.Duality
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--
-- Standard duality between points and non-vertical hyperplanes (or lines in R^2)
--
--------------------------------------------------------------------------------
module HGeometry.Duality
  ( dualPoint
  , dualHyperPlane
  , dualLine

  , liftPointToPlane
  ) where

import Control.Lens
import GHC.TypeNats
import HGeometry.HyperPlane.Class
import HGeometry.HyperPlane.NonVertical
import HGeometry.Line.LineEQ
import HGeometry.Point
import HGeometry.Vector

--------------------------------------------------------------------------------

-- | Compute the point dual to a non-vertical hyperplane
--
-- >>> dualPoint (LineEQ 10 20)
-- Point2 10 (-20)
dualPoint :: forall hyperPlane d r. (NonVerticalHyperPlane_ hyperPlane d r, Num r, 1 <= d
                                    , KnownNat (d-1)
                                    )
          => hyperPlane -> Point d r
dualPoint :: forall hyperPlane (d :: Natural) r.
(NonVerticalHyperPlane_ hyperPlane d r, Num r, 1 <= d,
 KnownNat (d - 1)) =>
hyperPlane -> Point d r
dualPoint = Vector d r -> PointF (Vector d r)
forall v. v -> PointF v
Point (Vector d r -> PointF (Vector d r))
-> (hyperPlane -> Vector d r) -> hyperPlane -> PointF (Vector d r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Vector d r) (Vector d r) r r
-> (r -> r) -> Vector d r -> Vector d r
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over (forall (i :: Natural) vector r (d :: Natural).
(i <= (d - 1), KnownNat i, Vector_ vector d r) =>
IndexedLens' Int vector r
component @(d-1)) r -> r
forall a. Num a => a -> a
negate (Vector d r -> Vector d r)
-> (hyperPlane -> Vector d r) -> hyperPlane -> Vector d r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Vector d r) hyperPlane (Vector d r)
-> hyperPlane -> Vector d r
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Vector d r) hyperPlane (Vector d r)
forall hyperPlane (d :: Natural) r.
NonVerticalHyperPlane_ hyperPlane d r =>
Lens' hyperPlane (Vector d r)
Lens' hyperPlane (Vector d r)
hyperPlaneCoefficients

-- | Compute the dual of a hyperplane
--
-- >>> dualHyperPlane (Point2 10 (-20))
-- NonVerticalHyperPlane [10,20]
dualHyperPlane :: forall point d r. (Point_ point d r, Num r, 1 <= d, KnownNat (d-1))
               => point -> NonVerticalHyperPlane d r
dualHyperPlane :: forall point (d :: Natural) r.
(Point_ point d r, Num r, 1 <= d, KnownNat (d - 1)) =>
point -> NonVerticalHyperPlane d r
dualHyperPlane = Vector d r -> NonVerticalHyperPlane d r
forall (d :: Natural) r. Vector d r -> NonVerticalHyperPlane d r
NonVerticalHyperPlane (Vector d r -> NonVerticalHyperPlane d r)
-> (point -> Vector d r) -> point -> NonVerticalHyperPlane d r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Vector d r) (Vector d r) r r
-> (r -> r) -> Vector d r -> Vector d r
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over (forall (i :: Natural) vector r (d :: Natural).
(i <= (d - 1), KnownNat i, Vector_ vector d r) =>
IndexedLens' Int vector r
component @(d-1)) r -> r
forall a. Num a => a -> a
negate (Vector d r -> Vector d r)
-> (point -> Vector d r) -> point -> Vector d r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Vector d r) point (Vector d r) -> point -> Vector d r
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Vector d r) point (Vector d r)
forall (d :: Natural) r s.
(Dimension point ~ d, NumType point ~ r, Dimension point ~ d,
 NumType point ~ s) =>
Lens point point (Vector d r) (Vector d s)
forall point point' (d :: Natural) r s.
(HasVector point point', Dimension point ~ d, NumType point ~ r,
 Dimension point' ~ d, NumType point' ~ s) =>
Lens point point' (Vector d r) (Vector d s)
Lens point point (Vector d r) (Vector d r)
vector

-- | Compute the line dual to a point
--
-- >>> dualLine (Point2 10 (-20))
-- LineEQ 10 20
dualLine :: (Point_ point 2 r, Num r) => point -> LineEQ r
dualLine :: forall point r. (Point_ point 2 r, Num r) => point -> LineEQ r
dualLine = NonVerticalHyperPlane 2 r -> LineEQ r
forall r. NonVerticalHyperPlane 2 r -> LineEQ r
MkLineEQ (NonVerticalHyperPlane 2 r -> LineEQ r)
-> (point -> NonVerticalHyperPlane 2 r) -> point -> LineEQ r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. point -> NonVerticalHyperPlane 2 r
forall point (d :: Natural) r.
(Point_ point d r, Num r, 1 <= d, KnownNat (d - 1)) =>
point -> NonVerticalHyperPlane d r
dualHyperPlane


--------------------------------------------------------------------------------

-- | The standard lifting transform, that lifts a point to the plane
-- tangent to the unit hyperboloid.
liftPointToPlane               :: (Point_ point 2 r, Num r) => point -> NonVerticalHyperPlane 3 r
liftPointToPlane :: forall point r.
(Point_ point 2 r, Num r) =>
point -> NonVerticalHyperPlane 3 r
liftPointToPlane (Point2_ r
x r
y) = r -> r -> r -> Plane r
forall r. r -> r -> r -> Plane r
Plane (r
2r -> r -> r
forall a. Num a => a -> a -> a
*r
x) (r
2r -> r -> r
forall a. Num a => a -> a -> a
*r
y) (r -> r
forall a. Num a => a -> a
negate (r -> r) -> r -> r
forall a b. (a -> b) -> a -> b
$ r
xr -> r -> r
forall a. Num a => a -> a -> a
*r
x r -> r -> r
forall a. Num a => a -> a -> a
+ r
yr -> r -> r
forall a. Num a => a -> a -> a
*r
y)


--------------------------------------------------------------------------------


--------------------------------------------------------------------------------
-- we could define a newtype for the duality instead of using Ext as well

-- newtype DualHyperPlane point = DualHyperPlane point
--   deriving (Show,Read,Eq,Ord)

-- instance (Point_ point d r, 1 <= d, Num r) => HyperPlane_ (DualHyperPlane point) d r where


-- instance (Point_ point d r, 1 <= d, Num r) => NonVerticalHyperPlane_ (DualHyperPlane point) d r where