diagrams-lib-1.3: src/Diagrams/ThreeD/Projection.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
-----------------------------------------------------------------------------
-- |
-- Module : Diagrams.ThreeD.Projection
-- Copyright : (c) 2014 diagrams team (see LICENSE)
-- License : BSD-style (see LICENSE)
-- Maintainer : diagrams-discuss@googlegroups.com
--
-- 3D projections are a way of viewing a three-dimensional objects on a
-- two-dimensional plane.
--
-- This module can be used with the functions in "Linear.Projection".
--
-- Disclaimer: This module should be considered experimental and is
-- likely to change.
--
-----------------------------------------------------------------------------
module Diagrams.ThreeD.Projection
( -- * Orthographic projections
-- $orthographic
-- ** Parallel projections
facingXY
, facingXZ
, facingYZ
-- ** axonometric
-- $axonometric
-- *** Isometric projections
-- $isometric
, isometricApply
, isometric
, lookingAt
-- ** Affine maps
, m44AffineApply
, m44AffineMap
, m33AffineApply
, m33AffineMap
-- * Perspective projections
-- $perspective
-- ** Perspective deformations
, m44Deformation
, module Linear.Projection
) where
import Control.Lens hiding (transform)
import Data.Functor.Rep
import Diagrams.Core
import Diagrams.Deform
import Diagrams.Direction
import Diagrams.LinearMap
import Diagrams.ThreeD.Types (P3)
import Diagrams.ThreeD.Vector
import Linear as L
import Linear.Affine
import Linear.Projection
------------------------------------------------------------------------
-- Orthographic projections
------------------------------------------------------------------------
-- $orthographic
-- Orthographic projections are a form of parallel projections where are
-- projection lines are orthogonal to the projection plane.
-- Parallel projections
-- | Look at the xy-plane with y as the up direction.
facingXY :: (Epsilon n, Floating n) => AffineMap V3 V2 n
facingXY = lookingAt unitZ origin yDir
-- | Look at the xz-plane with z as the up direction.
facingXZ :: (Epsilon n, Floating n) => AffineMap V3 V2 n
facingXZ = lookingAt unitY origin zDir
-- | Look at the yz-plane with z as the up direction.
facingYZ :: (Epsilon n, Floating n) => AffineMap V3 V2 n
facingYZ = lookingAt unitX origin zDir
-- $axonometric
-- Axonometric projections are a type of orthographic projection where
-- the object is rotated along one or more of its axes relative to the
-- plane of projection.
-- $isometric
-- Isometric projections are when the scale along each axis of the
-- projection is the same and the angle between any axis is 120
-- degrees.
-- | Apply an isometric projection given the up direction
isometricApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b, Floating n, Epsilon n)
=> Direction V3 n -> a -> b
isometricApply up = amap (isometric up)
-- | Make an isometric affine map with the given up direction.
isometric :: (Floating n, Epsilon n) => Direction V3 n -> AffineMap V3 V2 n
isometric up = m44AffineMap m
where
m = lookAt (V3 1 1 1) zero (fromDirection up)
lookingAt :: (Epsilon n, Floating n)
=> P3 n -- ^ Eye
-> P3 n -- ^ Center
-> Direction V3 n -- ^ Up
-> AffineMap V3 V2 n
lookingAt (P cam) (P center) d = m44AffineMap m
where
m = lookAt cam center (d^._Dir)
-- | Apply the affine part of a homogeneous matrix.
m44AffineApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b)
=> M44 n -> a -> b
m44AffineApply = amap . m44AffineMap
-- | Create an 'AffineMap' from a 4x4 homogeneous matrix, ignoring any
-- perspective transforms.
m44AffineMap :: Num n => M44 n -> AffineMap V3 V2 n
m44AffineMap m = AffineMap (LinearMap f) (f v)
where
f = view _xy . (m' !*)
m' = m ^. linearTransform
v = m ^. L.translation
-- | Apply a transformation matrix and translation.
m33AffineApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b)
=> M33 n -> V2 n -> a -> b
m33AffineApply m = amap . m33AffineMap m
-- | Create an 'AffineMap' from a 3x3 transformation matrix and a
-- translation vector.
m33AffineMap :: Num n => M33 n -> V2 n -> AffineMap V3 V2 n
m33AffineMap m = AffineMap (LinearMap f)
where
f = view _xy . (m !*)
-- | Extract the linear transform part of a homogeneous matrix.
linearTransform :: (Representable u, R3 v, R3 u) => Lens' (u (v n)) (M33 n)
linearTransform = column _xyz . _xyz
------------------------------------------------------------------------
-- Perspective transforms
------------------------------------------------------------------------
-- For the time being projective transforms use the deformable class.
-- Eventually we would like to replace this with a more specialised
-- method.
-- $perspective
-- Perspective projections are when closer objects appear bigger.
-- | Make a deformation from a 4x4 homogeneous matrix.
m44Deformation :: Fractional n => M44 n -> Deformation V3 V2 n
m44Deformation m =
Deformation (P . view _xy . normalizePoint . (m !*) . point . view _Point)