{- ORMOLU_DISABLE -}
-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
-- Copyright 2016, Julia Longtin (julial@turinglace.com)
-- Released under the GNU AGPLV3+, see LICENSE

module Graphics.Implicit.ObjectUtil.GetBox2 (getBox2, getBox2R) where

import Prelude(pure, fmap, Eq, (==), (.), (<$>), (||), unzip, minimum, maximum, ($), (/), (-), (+), (*), cos, sin, sqrt, min, max, (<), (<>), pi, atan2, (==), (>), show, (&&), otherwise, error)

import Graphics.Implicit.Definitions
    ( SymbolicObj2(Square, Circle, Polygon, Rotate2, Transform2, Shared2),
      SharedObj(IntersectR, Complement, UnionR, DifferenceR),
      Box2,
      ℝ2,
      ,
      minℝ )

import Data.Fixed (mod')

import Graphics.Implicit.ObjectUtil.GetBoxShared (emptyBox, corners, outsetBox, intersectBoxes, pointsBox, getBoxShared, unionBoxes)

-- To construct vectors of ℝs.
import Linear (V2(V2), V3(V3))
import qualified Linear

-- Get a Box2 around the given object.
getBox2 :: SymbolicObj2 -> Box2
-- Primitives
getBox2 :: SymbolicObj2 -> Box2
getBox2 (Square V2 ℝ
size) = (forall (f :: * -> *) a. Applicative f => a -> f a
pure 0, V2 ℝ
size)
getBox2 (Circle r) = (forall (f :: * -> *) a. Applicative f => a -> f a
pure (-r), forall (f :: * -> *) a. Applicative f => a -> f a
pure r)
getBox2 (Polygon [V2 ℝ]
points) = forall (f :: * -> *) a.
(Applicative f, Num a, VectorStuff (f a)) =>
[f a] -> (f a, f a)
pointsBox [V2 ℝ]
points
-- (Rounded) CSG
-- Simple transforms
getBox2 (Rotate2 θ SymbolicObj2
symbObj) =
    let rotate :: V2 ℝ -> V2 ℝ
rotate (V2 x y) = forall a. a -> a -> V2 a
V2 (xforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos θ forall a. Num a => a -> a -> a
- yforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin θ) (xforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin θ forall a. Num a => a -> a -> a
+ yforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos θ)
     in forall (f :: * -> *) a.
(Applicative f, Num a, VectorStuff (f a)) =>
[f a] -> (f a, f a)
pointsBox forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap V2 ℝ -> V2 ℝ
rotate forall a b. (a -> b) -> a -> b
$ forall vec. VectorStuff vec => (vec, vec) -> [vec]
corners forall a b. (a -> b) -> a -> b
$ SymbolicObj2 -> Box2
getBox2 SymbolicObj2
symbObj
getBox2 (Transform2 M33 ℝ
m SymbolicObj2
symbObj) =
    let box :: Box2
box = SymbolicObj2 -> Box2
getBox2 SymbolicObj2
symbObj
        augment :: V2 a -> V3 a
augment (V2 a
x a
y) = forall a. a -> a -> a -> V3 a
V3 a
x a
y a
1
        normalize :: V3 a -> V2 a
normalize (V3 a
x a
y a
w) = forall a. a -> a -> V2 a
V2 (a
xforall a. Fractional a => a -> a -> a
/a
w) (a
yforall a. Fractional a => a -> a -> a
/a
w)
     in forall (f :: * -> *) a.
(Applicative f, Num a, VectorStuff (f a)) =>
[f a] -> (f a, f a)
pointsBox forall a b. (a -> b) -> a -> b
$ forall {a}. Fractional a => V3 a -> V2 a
normalize forall b c a. (b -> c) -> (a -> b) -> a -> c
. (M33 ℝ
m forall (m :: * -> *) (r :: * -> *) a.
(Functor m, Foldable r, Additive r, Num a) =>
m (r a) -> r a -> m a
Linear.!*) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}. Num a => V2 a -> V3 a
augment forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall vec. VectorStuff vec => (vec, vec) -> [vec]
corners Box2
box
getBox2 (Shared2 SharedObj SymbolicObj2 V2 ℝ
obj) = forall obj (f :: * -> *) a.
(Object obj f a, VectorStuff (f a), ComponentWiseMultable (f a),
 Fractional a, Metric f) =>
SharedObj obj f a -> (f a, f a)
getBoxShared SharedObj SymbolicObj2 V2 ℝ
obj

-- | Define a Box2 around the given object, and the space it occupies while rotating about the center point.
--   Note: No implementations for Square, Translate2, or Scale2 as they would be identical to the fallthrough.
getBox2R :: SymbolicObj2 ->  -> Box2
getBox2R :: SymbolicObj2 -> ℝ -> Box2
getBox2R (Circle r) _ = SymbolicObj2 -> Box2
getBox2 forall a b. (a -> b) -> a -> b
$ ℝ -> SymbolicObj2
Circle r
getBox2R (Polygon [V2 ℝ]
points) deg =
  let
    pointRBoxes :: [Box2]
pointRBoxes = [ V2 ℝ -> ℝ -> Box2
pointRBox V2 ℝ
point deg | V2 ℝ
point <- [V2 ℝ]
points ]
    ([V2 ℝ]
pointValsMin, [V2 ℝ]
pointValsMax) = forall a b. [(a, b)] -> ([a], [b])
unzip [Box2]
pointRBoxes
    unbox :: ℝ2 -> (, )
    unbox :: V2 ℝ -> (ℝ, ℝ)
unbox (V2 x y) = (x, y)
    ([ℝ]
pointValsX, [ℝ]
pointValsY) = forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap V2 ℝ -> (ℝ, ℝ)
unbox forall a b. (a -> b) -> a -> b
$ [V2 ℝ]
pointValsMin forall a. Semigroup a => a -> a -> a
<> [V2 ℝ]
pointValsMax
  in
    (forall a. a -> a -> V2 a
V2 (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
pointValsX)( forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
pointValsY), forall a. a -> a -> V2 a
V2 (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
pointValsX) (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
pointValsY))
getBox2R (Shared2 (Complement SymbolicObj2
symObj)) _ = SymbolicObj2 -> Box2
getBox2 forall a b. (a -> b) -> a -> b
$ SharedObj SymbolicObj2 V2 ℝ -> SymbolicObj2
Shared2 (forall obj (f :: * -> *) a. obj -> SharedObj obj f a
Complement SymbolicObj2
symObj)
getBox2R (Shared2 (UnionR r [SymbolicObj2]
symObjs)) deg =
    forall (f :: * -> *) a.
(VectorStuff (f a), Applicative f, Eq (f a), Num a, Num (f a)) =>
ℝ -> [(f a, f a)] -> (f a, f a)
unionBoxes r forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SymbolicObj2 -> ℝ -> Box2
`getBox2R` deg) [SymbolicObj2]
symObjs
getBox2R (Shared2 (DifferenceR _ SymbolicObj2
symObj [SymbolicObj2]
_)) deg = SymbolicObj2 -> ℝ -> Box2
getBox2R SymbolicObj2
symObj deg
getBox2R (Shared2 (IntersectR r [SymbolicObj2]
symObjs)) deg =
  let
    boxes :: [Box2]
boxes = [ SymbolicObj2 -> ℝ -> Box2
getBox2R SymbolicObj2
obj deg| SymbolicObj2
obj <- [SymbolicObj2]
symObjs ]
  in
    forall a. (VectorStuff a, Num a) => ℝ -> (a, a) -> (a, a)
outsetBox r forall a b. (a -> b) -> a -> b
$ forall a. VectorStuff a => [(a, a)] -> (a, a)
intersectBoxes [Box2]
boxes
-- FIXME: implement Rotate2.
-- Fallthrough: rotate the points of the containing box. no rounding.
getBox2R SymbolicObj2
symObj deg =
  let
    origBox :: Box2
origBox = SymbolicObj2 -> Box2
getBox2 SymbolicObj2
symObj
    points :: [V2 ℝ]
points  = forall vec. VectorStuff vec => (vec, vec) -> [vec]
corners Box2
origBox
  in
    SymbolicObj2 -> ℝ -> Box2
getBox2R ([V2 ℝ] -> SymbolicObj2
Polygon [V2 ℝ]
points) deg

data Quadrant  = UpperRight | UpperLeft | LowerRight | LowerLeft
  deriving Quadrant -> Quadrant -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Quadrant -> Quadrant -> Bool
$c/= :: Quadrant -> Quadrant -> Bool
== :: Quadrant -> Quadrant -> Bool
$c== :: Quadrant -> Quadrant -> Bool
Eq
data Axis      = PosX | PosY | NegX | NegY
  deriving Axis -> Axis -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Axis -> Axis -> Bool
$c/= :: Axis -> Axis -> Bool
== :: Axis -> Axis -> Bool
$c== :: Axis -> Axis -> Bool
Eq
data Position  = OnAxis Axis | InQuadrant Quadrant | CenterPoint
data HasRotation = Rotation Direction | None
  deriving HasRotation -> HasRotation -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HasRotation -> HasRotation -> Bool
$c/= :: HasRotation -> HasRotation -> Bool
== :: HasRotation -> HasRotation -> Bool
$c== :: HasRotation -> HasRotation -> Bool
Eq
data Direction = Clockwise | CounterClockwise
  deriving Direction -> Direction -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Direction -> Direction -> Bool
$c/= :: Direction -> Direction -> Bool
== :: Direction -> Direction -> Bool
$c== :: Direction -> Direction -> Bool
Eq

-- | put a box around a point, and all of the locations it will be at during an x degree arc around (0,0).
pointRBox :: ℝ2 ->  -> Box2
pointRBox :: V2 ℝ -> ℝ -> Box2
pointRBox (V2 xStart yStart) travel =
  let
    k :: 
    k :: ℝ
k = forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/180
    -- determine the distance of our input point from from the axis of rotation.
    distance :: ℝ
distance = forall a. Floating a => a -> a
sqrt forall a b. (a -> b) -> a -> b
$ xStartforall a. Num a => a -> a -> a
*xStart forall a. Num a => a -> a -> a
+ yStartforall a. Num a => a -> a -> a
*yStart
    -- radian starting position.
    θstart :: ℝ
θstart = forall a. RealFloat a => a -> a -> a
atan2 yStart xStart
    -- logical starting position
    startPosition :: Position
startPosition = ℝ -> ℝ -> Position
positionOf distance forall a b. (a -> b) -> a -> b
$ ℝ -> ℝ
absrad θstart

    -- take the input point. rotate it. see where it stops.

    -- how far we should rotate our point.
    rotationAmount :: ℝ
rotationAmount = travel forall a. Num a => a -> a -> a
* k
    -- what direction are we rotating.
    rotationDirection :: HasRotation
rotationDirection = case travel of
      polarity | polarity forall a. Ord a => a -> a -> Bool
> 0  -> Direction -> HasRotation
Rotation Direction
CounterClockwise
               | polarity forall a. Eq a => a -> a -> Bool
== 0 -> HasRotation
None
      _                        -> Direction -> HasRotation
Rotation Direction
Clockwise
    -- stopping position of our point.
    θstop :: ℝ
θstop = ℝ -> ℝ
absrad forall a b. (a -> b) -> a -> b
$ θstart forall a. Num a => a -> a -> a
+ rotationAmount
    stopPosition :: Position
stopPosition = ℝ -> ℝ -> Position
positionOf distance θstop
    (xStop, yStop) =
      case ℝ -> ℝ -> Position
positionOf distance θstop of
        Position
CenterPoint -> (0,0)
        OnAxis Axis
PosX -> (distance,0)
        OnAxis Axis
PosY -> (0,distance)
        OnAxis Axis
NegX -> (-distance,0)
        OnAxis Axis
NegY -> (0,-distance)
        InQuadrant Quadrant
_ -> ( distanceforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos θstop, distanceforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin θstop)

    -- observe what the initial position was, and what the end position is.
    -- check which quadrants they're in, and what direction the rotation was.

    (minX, minY, maxX, maxY) = (forall a. Ord a => a -> a -> a
min xStart xStop, forall a. Ord a => a -> a -> a
min yStart yStop, forall a. Ord a => a -> a -> a
max xStart xStop, forall a. Ord a => a -> a -> a
max yStart yStop)
    positionOf ::  ->  -> Position
    positionOf :: ℝ -> ℝ -> Position
positionOf d θpos
      | d forall a. Ord a => a -> a -> Bool
< minℝ                      = Position
CenterPoint
      | θpos forall a. Eq a => a -> a -> Bool
== 0 Bool -> Bool -> Bool
|| θpos forall a. Eq a => a -> a -> Bool
== 360forall a. Num a => a -> a -> a
*k    = Axis -> Position
OnAxis Axis
PosX
      | θpos forall a. Eq a => a -> a -> Bool
== 90forall a. Num a => a -> a -> a
*k                  = Axis -> Position
OnAxis Axis
PosY
      | θpos forall a. Eq a => a -> a -> Bool
== 180forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
|| θpos forall a. Eq a => a -> a -> Bool
== -0   = Axis -> Position
OnAxis Axis
NegX
      | θpos forall a. Eq a => a -> a -> Bool
== 270forall a. Num a => a -> a -> a
*k                 = Axis -> Position
OnAxis Axis
NegY
      | θpos forall a. Ord a => a -> a -> Bool
> 0 Bool -> Bool -> Bool
&& θpos forall a. Ord a => a -> a -> Bool
< 90forall a. Num a => a -> a -> a
*k       = Quadrant -> Position
InQuadrant Quadrant
UpperRight
      | θpos forall a. Ord a => a -> a -> Bool
> 90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& θpos forall a. Ord a => a -> a -> Bool
< 180forall a. Num a => a -> a -> a
*k   = Quadrant -> Position
InQuadrant Quadrant
UpperLeft
      | θpos forall a. Ord a => a -> a -> Bool
> 180forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& θpos forall a. Ord a => a -> a -> Bool
< 270forall a. Num a => a -> a -> a
*k  = Quadrant -> Position
InQuadrant Quadrant
LowerLeft
      | θpos forall a. Ord a => a -> a -> Bool
> 270forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& θpos forall a. Ord a => a -> a -> Bool
< 360forall a. Num a => a -> a -> a
*k  = Quadrant -> Position
InQuadrant Quadrant
LowerRight
      | Bool
otherwise                     = forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"illegal position in positionOf: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show (θposforall a. Num a => a -> a -> a
*k) forall a. Semigroup a => a -> a -> a
<> [Char]
" pos: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show θpos forall a. Semigroup a => a -> a -> a
<> [Char]
" d: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show d
    -- returns position around a circle in radians, from 0 to 2pi.
    absrad ::  -> 
    absrad :: ℝ -> ℝ
absrad rad
      | rad forall a. Ord a => a -> a -> Bool
> (360forall a. Num a => a -> a -> a
*k) = rad forall a. Real a => a -> a -> a
`mod'` (360forall a. Num a => a -> a -> a
*k)
      | rad forall a. Ord a => a -> a -> Bool
< 0       = ℝ -> ℝ
absrad (360forall a. Num a => a -> a -> a
*k)forall a. Num a => a -> a -> a
+rad
      | Bool
otherwise     = rad

    -- now, if you passed through an axis, then the box must be expanded to include distance from axis of rotation in that direction.
    -- otherwise, put a box around the start and stop positions.

    distanceBox :: Box2
    distanceBox :: Box2
distanceBox = (forall (f :: * -> *) a. Applicative f => a -> f a
pure (-distance), forall (f :: * -> *) a. Applicative f => a -> f a
pure distance)

    noAxis :: Quadrant -> Quadrant -> Direction ->  -> Box2
    noAxis :: Quadrant -> Quadrant -> Direction -> ℝ -> Box2
noAxis Quadrant
q1 Quadrant
q2 Direction
dir amount
      | Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
q2 Bool -> Bool -> Bool
&& amount forall a. Ord a => a -> a -> Bool
< 90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& amount forall a. Ord a => a -> a -> Bool
> -90forall a. Num a => a -> a -> a
*k = (forall a. a -> a -> V2 a
V2 minX  minY, forall a. a -> a -> V2 a
V2 maxX maxY)
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft  = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
PosY Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
PosX Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft  = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
NegY Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
NegX Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
PosX Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft  = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
PosY Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft  = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
NegX Quadrant
q2 Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&& Quadrant
q1 forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight = Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
NegY Quadrant
q2 Direction
dir amount
    noAxis Quadrant
_ Quadrant
_ Direction
_ _ = Box2
distanceBox
    oneAxis :: Axis -> Quadrant -> Direction ->  -> Box2
    oneAxis :: Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
axis Quadrant
quadrant Direction
dir amount
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&&
        amount forall a. Ord a => a -> a -> Bool
< 90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& amount forall a. Ord a => a -> a -> Bool
> -90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight))  = (forall a. a -> a -> V2 a
V2 minX minY, forall a. a -> a -> V2 a
V2 maxX maxY)
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&&
        amount forall a. Ord a => a -> a -> Bool
< 90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& amount forall a. Ord a => a -> a -> Bool
> -90forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight))  = (forall a. a -> a -> V2 a
V2 minX minY, forall a. a -> a -> V2 a
V2 maxX maxY)
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight))  = Axis -> Direction -> Box2
crossOne Axis
axis Direction
dir
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight))  = Axis -> Direction -> Box2
crossOne Axis
axis Direction
dir
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight))  = Axis -> Direction -> Box2
crossTwo Axis
axis Direction
dir
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight))  = Axis -> Direction -> Box2
crossTwo Axis
axis Direction
dir
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight))  = Axis -> Box2
crossThree Axis
axis
      | Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise Bool -> Bool -> Bool
&&
        ((Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerRight) Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
LowerLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperLeft)  Bool -> Bool -> Bool
||
         (Axis
axis forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Quadrant
quadrant forall a. Eq a => a -> a -> Bool
== Quadrant
UpperRight))  = Axis -> Box2
crossThree Axis
axis
      | Bool
otherwise = Box2
distanceBox
    twoAxis :: Axis -> Axis -> Direction -> Box2
    twoAxis :: Axis -> Axis -> Direction -> Box2
twoAxis Axis
start Axis
stop Direction
dir
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegX) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegY) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosX) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosY)  = Axis -> Direction -> Box2
crossOne Axis
start Direction
dir
    twoAxis Axis
start Axis
stop Direction
dir
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegY) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegX) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosY) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosX)  = if Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise
                                           then (forall a. a -> a -> V2 a
V2 minX minY, forall a. a -> a -> V2 a
V2 maxX maxY)
                                           else Axis -> Direction -> Box2
crossTwo Axis
start Direction
dir
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosY) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegX) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
NegY) Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Axis
stop forall a. Eq a => a -> a -> Bool
== Axis
PosX)  = if Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise
                                           then (forall a. a -> a -> V2 a
V2 minX minY, forall a. a -> a -> V2 a
V2 maxX maxY)
                                           else Axis -> Direction -> Box2
crossTwo Axis
start Direction
dir
    twoAxis Axis
_ Axis
_ Direction
_ = Box2
distanceBox
    crossOne :: Axis -> Direction -> Box2
    crossOne :: Axis -> Direction -> Box2
crossOne Axis
start Direction
dir
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [(0,-distance)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [(-distance, 0)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [(0, distance)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [( distance, 0)]
      | Bool
otherwise = Box2
distanceBox
    crossTwo :: Axis -> Direction -> Box2
    crossTwo :: Axis -> Direction -> Box2
crossTwo Axis
start Direction
dir
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [(-distance, 0), ( 0,-distance)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [( distance, 0), ( 0,-distance)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [( distance, 0), ( 0, distance)]
      | (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
NegY Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
Clockwise)        Bool -> Bool -> Bool
||
        (Axis
start forall a. Eq a => a -> a -> Bool
== Axis
PosX Bool -> Bool -> Bool
&& Direction
dir forall a. Eq a => a -> a -> Bool
== Direction
CounterClockwise)  = [(ℝ, ℝ)] -> Box2
mixWith [(-distance, 0), ( 0, distance)]
      | Bool
otherwise = Box2
distanceBox
    crossThree :: Axis -> Box2
    crossThree :: Axis -> Box2
crossThree Axis
PosX = [(ℝ, ℝ)] -> Box2
mixWith [( 0, distance), (-distance, 0), ( 0,-distance)]
    crossThree Axis
PosY = [(ℝ, ℝ)] -> Box2
mixWith [(-distance, 0), ( 0,-distance), ( distance, 0)]
    crossThree Axis
NegX = [(ℝ, ℝ)] -> Box2
mixWith [( 0,-distance), ( distance, 0), ( 0, distance)]
    crossThree Axis
NegY = [(ℝ, ℝ)] -> Box2
mixWith [( distance, 0), ( 0, distance), (-distance, 0)]
    -- TODO(sandy): clean me up to not use pairs
    mixWith :: [(,)] -> Box2
    mixWith :: [(ℝ, ℝ)] -> Box2
mixWith [(ℝ, ℝ)]
points = (forall a. a -> a -> V2 a
V2 (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
xPoints) (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
yPoints), forall a. a -> a -> V2 a
V2 (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
xPoints) (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
yPoints))
                     where
                       ([ℝ]
xPoints, [ℝ]
yPoints) = forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ [(ℝ, ℝ)]
points forall a. Semigroup a => a -> a -> a
<> [(xStart, yStart), (xStop, yStop)]
    invertRotation :: Direction -> Direction
    invertRotation :: Direction -> Direction
invertRotation Direction
Clockwise = Direction
CounterClockwise
    invertRotation Direction
CounterClockwise = Direction
Clockwise
  in
    case HasRotation
rotationDirection of
      HasRotation
None -> (forall a. a -> a -> V2 a
V2 xStart yStart, forall a. a -> a -> V2 a
V2 xStart  yStart)
      Rotation Direction
dir -> case rotationAmount of
                 amount | amount forall a. Ord a => a -> a -> Bool
< 360forall a. Num a => a -> a -> a
*k Bool -> Bool -> Bool
&& amount forall a. Ord a => a -> a -> Bool
> -360forall a. Num a => a -> a -> a
*k ->
                          case Position
startPosition of
                            Position
CenterPoint -> forall (f :: * -> *) a. (Applicative f, Num a) => (f a, f a)
emptyBox
                            OnAxis Axis
axis -> case Position
stopPosition of
                                             OnAxis Axis
stopaxis         -> Axis -> Axis -> Direction -> Box2
twoAxis Axis
axis Axis
stopaxis Direction
dir
                                             InQuadrant Quadrant
stopquadrant -> Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
axis Quadrant
stopquadrant Direction
dir amount
                                             Position
CenterPoint -> forall (f :: * -> *) a. (Applicative f, Num a) => (f a, f a)
emptyBox
                            InQuadrant Quadrant
quadrant -> case Position
stopPosition of
                                             OnAxis Axis
stopaxis         -> Axis -> Quadrant -> Direction -> ℝ -> Box2
oneAxis Axis
stopaxis Quadrant
quadrant (Direction -> Direction
invertRotation Direction
dir) (-amount)
                                             InQuadrant Quadrant
stopquadrant -> Quadrant -> Quadrant -> Direction -> ℝ -> Box2
noAxis Quadrant
quadrant Quadrant
stopquadrant Direction
dir travel
                                             Position
CenterPoint -> forall (f :: * -> *) a. (Applicative f, Num a) => (f a, f a)
emptyBox
                 _                         ->
                            (forall (f :: * -> *) a. Applicative f => a -> f a
pure (-distance), forall (f :: * -> *) a. Applicative f => a -> f a
pure distance)