packages feed

FieldTrip-0.2: examples/src/Tablet.hs

{-# OPTIONS_GHC -Wall #-}
----------------------------------------------------------------------
-- |
-- Module      :  Tablet
-- Copyright   :  (c) Conal Elliott and Andy J Gill 2008
-- License     :  BSD3
-- 
-- Maintainer  :  conal@conal.net, andygill@ku.edu
-- Stability   :  experimental
-- 
-- Tablet shape with rounded corners
----------------------------------------------------------------------

module Tablet where

import Data.Monoid

import Graphics.FieldTrip.Misc
import Graphics.FieldTrip.Vector3
import Graphics.FieldTrip.Transform
import Graphics.FieldTrip.Transform2
import Graphics.FieldTrip.Geometry2
import Graphics.FieldTrip.Geometry3

--import Graphics.FieldTrip.QParamSurf as Q

-- 2D rectangle with rounded corners, having given width, height, and
-- rounding radius.
roundedRect :: R -> R -> R -> Geometry2
roundedRect width height radius = right `sandwich2` center
  -- Build out of left, center, right.
  -- The sides sandwich the center to make the whole; and
  -- the quarter-disks sandwich the edge strip to make the right side.
 where
   -- Trimmed dimensions
   width'  = width-2*radius
   height' = height-2*radius
   center = box2 width' height
   -- Quarter-disk at origin, angle ranges from 0 to pi/2 (3pm to noon)
   qdisk = uscale2 radius *% diskWedge (1/4)
   ne = move2Y (height'/2) qdisk
   se = move2Y (-height'/2) (rotate2 (-pi/2::Float) *% qdisk)
   right = move2X (width'/2) $
           ne `mappend` move2X (radius/2) (box2 radius height') `mappend` se

-- Sandwich @inside@ between @outside@ and a flipped version of @outside@
sandwich2 :: Geometry2 -> Filter2
outside `sandwich2` inside = andFlip2 outside `mappend` inside



-- 3D tablet shape, with flat top & bottom, using roundedRect.
-- Cylinders for the four corners.

tablet1 :: R -> R -> R -> R -> Geometry3
tablet1 width height depth radius = top `sandwichY` edging
 where
   width'  = width-2*radius
   height' = height-2*radius
   top = move3Z (depth/2) $ flatG (roundedRect width height radius)
   edging  = andFlip3 (zVector3::Vector3 Float) ell
   ell = capped height' (width'/2) `mappend`
         pivot3Z (capped width' (height'/2))
   capped len dx = ( move3X (dx+radius) $
                     pivot3Y $
                     flatG (box2 depth len) )
                   `mappend`
                   ( move3 dx (len/2) 0 $
                     cylinder radius depth )

-- Or with more rounding.
-- 3D tablet with half-cylinders for sides and quarter-sphere corners,
-- having given width, height, and depth.  Rounding radius is depth/2.
tablet2 :: R -> R -> R -> Geometry3
tablet2 width height depth = ell `sandwichZ` center
  -- Build out of two ell shapes sandwiching a center box.  Each ell has
  -- two cylinders and two spheres.  I can't yet make partial spheres or
  -- cylinders, so I'll make full ones, which will be partly hidden (half
  -- of each cylinder and 3/4 of each sphere).  Later, make the partial
  -- versions, to reduce computing and rendering.
 where
   radius   = depth/2
   width'   = width-2*radius
   height'  = height-2*radius
   center   = box3 width' height' depth
   right    = move3X (width'/2) $
              move3Y (height'/2) (sphere radius) `sandwichX` rightCyl
   ell      = move3Y (height'/2) topCyl `mappend` right
   rightCyl = cyl xVector3 height'
   topCyl   = cyl yVector3 width'
   cyl :: Vector3 Float -> R -> Geometry3
   cyl axis len = pivot3 axis $ cylinder radius len


---- utilities

-- Sandwich @inside@ between @outside@ and a flipped version of @outside@
sandwich3 :: Vector3 Float -> Geometry3 -> Filter3
sandwich3 axis outside inside = andFlip3 axis outside `mappend` inside

-- Specializations
sandwichX, sandwichY, sandwichZ :: Geometry3 -> Filter3
sandwichX = sandwich3 xVector3
sandwichY = sandwich3 yVector3
sandwichZ = sandwich3 zVector3