packages feed

keid-geometry-0.1.0.0: src/Geometry/Icosphere.hs

module Geometry.Icosphere where

import RIO

import Data.List (iterate, (!!))
import RIO.Vector.Partial ((!))

import RIO.Vector qualified as Vector
import Geomancy.Vec3 (Vec3, vec3)
import Geomancy.Vec3 qualified as Vec3

import Resource.Model qualified as Model

icosphere :: (Vec3 -> attrs) -> Int -> [Model.Vertex Vec3.Packed attrs]
icosphere mkAttrs n = do
  v <- reverse . concat $ subNormal n icotris_v1
  pure Model.Vertex
    { vPosition = Vec3.Packed v
    , vAttrs    = mkAttrs v
    }

subNormal :: Int -> [[Vec3]] -> [[Vec3]]
subNormal nu tris = map (map Vec3.normalize) $ subdivide nu tris

subdivide :: Int -> [[Vec3]] -> [[Vec3]]
subdivide frequency tris =
  iterate (concatMap subdivideTri) tris !! (frequency - 1)
  where
    subdivideTri = \case
      [v1, v2, v3] ->
        let
          a = midpoint v1 v2
          b = midpoint v2 v3
          c = midpoint v3 v1
        in
          [ [ v1, a, c ]
          , [ v2, b, a ]
          , [ v3, c, b ]
          , [  a, b, c ]
          ]
      _ ->
        error "subdivideTri: not a triangle somehow"

    midpoint a b = (a + b) / 2

icopoints :: Vector Vec3
icopoints = Vector.fromList
  [ vec3 (-1) 0   t
  , vec3   1  0   t
  , vec3 (-1) 0 (-t)
  , vec3   1  0 (-t)

  , vec3   0 (-t) (-1)
  , vec3   0 (-t)   1
  , vec3   0   t  (-1)
  , vec3   0   t    1

  , vec3   t     1  0
  , vec3   t   (-1) 0
  , vec3 (-t)    1  0
  , vec3 (-t)  (-1) 0
  ]
  where
    t = (1.0 + sqrt 5.0) / 2.0

icotris_v1 :: [[Vec3]]
icotris_v1 =
  [ -- faces around point 0
    [ icopoints ! 0
    , icopoints ! 11
    , icopoints ! 5
    ]

  , [ icopoints ! 0
    , icopoints ! 5
    , icopoints ! 1
    ]

  , [ icopoints ! 0
    , icopoints ! 1
    , icopoints ! 7
    ]
{-
  , [ icopoints ! 0
    , icopoints ! 1
    , icopoints ! 7
    ]
-}
  , [ icopoints ! 0
    , icopoints ! 7
    , icopoints ! 10
    ]

  , [ icopoints ! 0
    , icopoints ! 10
    , icopoints ! 11
    ]

    -- 5 adjacent faces

  , [ icopoints ! 1
    , icopoints ! 5
    , icopoints ! 9
    ]

  , [ icopoints ! 5
    , icopoints ! 11
    , icopoints ! 4
    ]

  , [ icopoints ! 11
    , icopoints ! 10
    , icopoints ! 2
    ]

  , [ icopoints ! 10
    , icopoints ! 7
    , icopoints ! 6
    ]

  , [ icopoints ! 7
    , icopoints ! 1
    , icopoints ! 8
    ]

    -- 5 adjacent faces around point 3

  , [ icopoints ! 3
    , icopoints ! 9
    , icopoints ! 4
    ]

  , [ icopoints ! 3
    , icopoints ! 4
    , icopoints ! 2
    ]

  , [ icopoints ! 3
    , icopoints ! 2
    , icopoints ! 6
    ]

  , [ icopoints ! 3
    , icopoints ! 6
    , icopoints ! 8
    ]

  , [ icopoints ! 3
    , icopoints ! 8
    , icopoints ! 9
    ]

    -- 5 adjacent faces

  , [ icopoints ! 4
    , icopoints ! 9
    , icopoints ! 5
    ]

  , [ icopoints ! 2
    , icopoints ! 4
    , icopoints ! 11
    ]

  , [ icopoints ! 6
    , icopoints ! 2
    , icopoints ! 10
    ]

  , [ icopoints ! 8
    , icopoints ! 6
    , icopoints ! 7
    ]

  , [ icopoints ! 9
    , icopoints ! 8
    , icopoints ! 1
    ]
  ]