SOE ex.8.13


{-
  Affine Transformation:

  [ x']     [ A B C ] [ x ]     [ Ax+By+C ]
  [ y']  =  [ D E F ] [ y ]  =  [ Dx+Ey+F ]
  [ 1 ]     [ 0 0 1 ] [ 1 ]     [    1    ]

  If the affine transform matrix is not invertible,
  which means the determinant of the matrix is zero,
  than that means all points transform to a point or a line.

  Det == 0  <=>  A*E - B*D == 0
  (1) A == E == B == D == 0
      It transforms all (x,y) to point (C,F).  (x'==C, y'==F)
  (2) A*E == B*D  &&  not all A,E,B,D == 0
          x' = Ax+By+C
          y' = Dx+Ey+F
      <=> Dx' = ADx + BDy + CD
          Ay' = ADx + AEy + AF
      <=> Dx' - Ay' = CD - AF
      <=> so, it transforms all point (x,y) to the line
          Dx' - Ay' + AF - CD = 0
-}

type Coordinate = (Float, Float)
type AffineTransformMatrix = [Float]

data Region
  =  UnitCircle
  |  Polygon [Coordinate]
  |  Empty
  |  AffineTransform AffineTransformMatrix Region

containsR :: Region -> Coordinate -> Bool

UnitCircle `containsR` (x, y) = x*x + y*y <= 1

-- Polygon ps `containsR` p = <<< see ex.8.12 >>>

Empty `containsR` p = False

AffineTransform matrix region `containsR` (x, y)
  | matrix' == Nothing =
      let (a:b:c:d:e:f:_) = matrix
      in  if (a == 0 && b == 0 && d == 0 && e == 0)
          then (x == c && y == f)            -- transform to a point
          else (d*x - a*y + a*f - c*d == 0)  -- transform to a line
  | otherwise =
      let Just m' = matrix'
          x' = (m'!!0)*x + (m'!!1)*y + (m'!!2)
          y' = (m'!!3)*x + (m'!!4)*y + (m'!!5)
      in  region `containsR` (x', y')
  where
  matrix' = inverse3×3 $ take 6 matrix ++ [0, 0, 1]


-- http://mathworld.wolfram.com/MatrixInverse.html
inverse3×3 :: [Float] -> Maybe [Float]
inverse3×3 matrix@[a11, a12, a13,
                   a21, a22, a23,
                   a31, a32, a33]
  | det == 0  = Nothing
  | otherwise = Just $
      map (/ det)
      [ a22*a33 - a23*a32,  a13*a32 - a12*a33,  a12*a23 - a13*a22,
        a23*a31 - a21*a33,  a11*a33 - a13*a31,  a13*a21 - a11*a23,
        a21*a32 - a22*a31,  a12*a31 - a11*a32,  a11*a22 - a12*a21]
  where det = determinant3×3 matrix


-- http://mathworld.wolfram.com/Determinant.html
determinant3×3 :: [Float] -> Float
determinant3×3 [a11, a12, a13,
                a21, a22, a23,
                a31, a32, a33]
  = a11*a22*a33 + a12*a23*a31 + a13*a21*a32
  - a13*a22*a31 - a12*a21*a33 - a11*a23*a32


Leave a Reply