{-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Core.FontSize -- Copyright : (c) Stephen Tetley 2009 -- License : BSD3 -- -- Maintainer : stephen.tetley@gmail.com -- Stability : unstable -- Portability : GHC with TypeFamilies and more -- -- Font size calculation for Label\'s bounding boxes. -- -- Calculations are based on metrics derived from Courier at 48 -- pt. As Courier is a monospaced font, bounding boxes calculated -- for other font families will usually have longer width than is -- necessary for the printed text. -- -- This is a deficiency of Wumpus, but alternatives would have -- significant implementation complexity. -- -------------------------------------------------------------------------------- module Wumpus.Core.FontSize ( -- * Type synonyms FontSize , CharCount -- * Courier metrics at 48 point , courier48_width , courier48_body_height , courier48_height , courier48_descender_depth , courier48_spacer_width -- * Metrics calculation , widthAt48pt , textWidth , textHeight , descenderDepth , textBounds ) where import Wumpus.Core.BoundingBox import Wumpus.Core.Geometry import Data.AffineSpace -- vector-space type CharCount = Int type FontSize = Int -- | The width of a letter in Courier at 48 pt. -- -- The value is not entirely accurate but it is satisfactory. courier48_width :: Num u => u courier48_width = 26 -- | The height of a letter without accents, ascenders or -- descenders in Courier at 48 pt . -- -- The value is not entirely accurate but it is satisfactory - -- some letters are taller than others (e.g. numbers are taller -- then capitals). courier48_body_height :: Num u => u courier48_body_height = 30 -- | The /common maximum/ height of a letter in Courier at 48pt. -- -- By common maximum the letter is allowed to have both an accent -- or ascender and a descender. -- -- Naturally the height is 48.0. -- courier48_height :: Num u => u courier48_height = 48 -- | The depth of a descender in Courier at 48 pt. -- -- Also the height of an ascender. courier48_descender_depth :: Num u => u courier48_descender_depth = 9 -- | The spacing between letters printed directly with -- PostScript\'s show command for Courier at 48 pt. -- -- The value is not entirely accurate but it is satisfactory. courier48_spacer_width :: Num u => u courier48_spacer_width = 3 -- | Width of the supplied string when printed at 48pt. widthAt48pt :: Fractional u => CharCount -> u widthAt48pt n = courier48_width * len + courier48_spacer_width * len_sub where len = fromIntegral n len_sub = len - 1.0 --- | Text width at @sz@ point size of the string @s@. All -- characters are counted literally - special chars may cause -- problems (this a current deficiency of Wumpus). textWidth :: Fractional u => FontSize -> CharCount -> u textWidth sz n = (fromIntegral sz)/48 * widthAt48pt n -- | Text height is just identity/double-coercion, i.e. -- @18 == 18.0@. The /size/ of a font is the maximum height: -- -- > body + descender max + ascender max -- textHeight :: Num u => FontSize -> u textHeight = fromIntegral -- | Descender depth for font size @sz@. -- descenderDepth :: Fractional u => FontSize -> u descenderDepth sz = (fromIntegral sz) / 48 * courier48_descender_depth -- | Find the bounding box for the character count at the -- supplied font-size. -- -- The supplied point represents the bottom left corner of the -- a regular upper-case letter (that is without descenders). -- The bounding box will always be /dropped/ to accommodate -- ascenders - no interpretation of the string takes place to -- see if it actually contains ascenders or descenders. -- -- The metrics used are derived from Courier - a monospaced font. -- For variable width fonts the calculated bounding box will -- usually be too long. -- textBounds :: (Fractional u, Ord u) => FontSize -> Point2 u -> CharCount -> BoundingBox u textBounds sz body_bl n = bbox bl tr where h = textHeight sz w = textWidth sz n dd = descenderDepth sz bl = body_bl .-^ V2 0 dd tr = bl .+^ V2 w h