strictly formatting changes

This commit is contained in:
Jack Wines 2024-04-18 02:54:07 -07:00
parent b5ae16ac59
commit b4ee69cd7f
No known key found for this signature in database
GPG key ID: 25B20640600571E6
8 changed files with 55 additions and 82 deletions

View file

@ -1,5 +1,6 @@
packages: packages:
./ ./
profiling: True
-- package repa -- package repa
-- ghc-options: -fincomplete-uni-patterns -- ghc-options: -fincomplete-uni-patterns

16
flake.lock generated
View file

@ -91,7 +91,6 @@
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"haskell-flake": "haskell-flake", "haskell-flake": "haskell-flake",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"systems": "systems_2",
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
} }
}, },
@ -110,21 +109,6 @@
"type": "github" "type": "github"
} }
}, },
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [

View file

@ -2,7 +2,6 @@
description = "srid/haskell-template: Nix template for Haskell projects"; description = "srid/haskell-template: Nix template for Haskell projects";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
systems.url = "github:nix-systems/default";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.url = "github:hercules-ci/flake-parts";
haskell-flake.url = "github:srid/haskell-flake"; haskell-flake.url = "github:srid/haskell-flake";

View file

@ -1,17 +1,16 @@
# Generated from web app, for more information, see: https://fourmolu.github.io/config/ # Generated from web app, for more information, see: https://fourmolu.github.io/config/
indentation: 4 indentation: 4
column-limit: none column-limit: none
function-arrows: trailing function-arrows: leading
comma-style: leading comma-style: trailing
import-export-style: diff-friendly import-export-style: diff-friendly
indent-wheres: false indent-wheres: false
record-brace-space: false record-brace-space: true
newlines-between-decls: 1 newlines-between-decls: 1
haddock-style: multi-line haddock-style: multi-line
haddock-style-module: null haddock-style-module: single-line
let-style: auto let-style: auto
in-style: right-align in-style: right-align
single-constraint-parens: always single-constraint-parens: always
unicode: never unicode: never
respectful: true respectful: false
single-deriving-parens: always

View file

@ -101,8 +101,8 @@ executable image-triangles
-- Base language which the package is written in. -- Base language which the package is written in.
default-language: Haskell2010 default-language: Haskell2010
ghc-options: ghc-options:
-- "-fprof-auto" -fprof-auto
-threaded -- -threaded
"-with-rtsopts= -N" "-with-rtsopts=-p"
-- -prof -- -prof
-- -fexternal-interpreter -- -fexternal-interpreter

View file

@ -40,7 +40,7 @@ import System.Random.SplitMix
import Triangles (getTriangleAverageRGB) import Triangles (getTriangleAverageRGB)
import qualified Triangles as Tri import qualified Triangles as Tri
toColour :: Fractional a => Co.Color (Co.SRGB Co.Linear) a -> Colour a toColour :: (Fractional a) => Co.Color (Co.SRGB Co.Linear) a -> Colour a
toColour (Co.ColorSRGB r g b) = CL.rgb r g b toColour (Co.ColorSRGB r g b) = CL.rgb r g b
corners :: [(Double, Double)] corners :: [(Double, Double)]
@ -57,7 +57,7 @@ genImage image dimensionsVec minDistance gen =
. mconcat . mconcat
. map drawVoroniRegion . map drawVoroniRegion
. sortOn shapeCircumference . sortOn shapeCircumference
. withStrategy (parListChunk 50 rdeepseq) . withStrategy (parListChunk 200 rdeepseq)
. map (uncurry Tri.voroniDiagramCorners) . map (uncurry Tri.voroniDiagramCorners)
$ voroni $ voroni
where where
@ -95,21 +95,25 @@ genImage image dimensionsVec minDistance gen =
padding = (/ 10) <$> V2 1 1 padding = (/ 10) <$> V2 1 1
corners' :: [P2 Double] corners' :: [P2 Double]
corners' = map (p2 . Bi.first (/ widthHeightRatio) . unp2 . (.-^ ((/ 2) <$> padding))) . MDS.randomPoints ((mkP2 widthHeightRatio 1) .+^ padding) (minDistance * widthHeightRatio) $ gen corners' =
map (p2 . Bi.first (/ widthHeightRatio) . unp2 . (.-^ ((/ 2) <$> padding)))
. MDS.randomPoints ((mkP2 widthHeightRatio 1) .+^ padding) (minDistance * widthHeightRatio)
$ gen
deriving instance Generic (CL.RGB a) deriving instance Generic (CL.RGB a)
deriving instance NFData a => NFData (CL.RGB a)
deriving instance (NFData a) => NFData (CL.RGB a)
toDimensionVector :: (Ma.Size r, Fractional a) => Ma.Array r Ma.Ix2 e -> V2 a toDimensionVector :: (Ma.Size r, Fractional a) => Ma.Array r Ma.Ix2 e -> V2 a
toDimensionVector image = toDimensionVector image =
p2 (fromIntegral $ cols, fromIntegral $ rows) .-. p2 (0.0, 0.0) p2 (fromIntegral cols, fromIntegral rows) .-. p2 (0.0, 0.0)
where where
(M.Sz2 rows cols) = Ma.size image (M.Sz2 rows cols) = Ma.size image
data CLIOptions = CLIOptions data CLIOptions = CLIOptions
{ input :: FilePath { input :: FilePath,
, output :: FilePath output :: FilePath,
, minDistance :: Double minDistance :: Double
} }
deriving (Generic) deriving (Generic)
@ -117,7 +121,7 @@ instance ParseRecord CLIOptions
main :: IO () main :: IO ()
main = do main = do
CLIOptions{..} <- getRecord "image options" CLIOptions {..} <- getRecord "image options"
gen' <- getStdGen -- for consistency, swap with something like: pure . mkStdGen $ 2344 gen' <- getStdGen -- for consistency, swap with something like: pure . mkStdGen $ 2344
print gen' print gen'
image :: M.Image M.S (Co.SRGB 'Co.Linear) Double <- M.readImageAuto input image :: M.Image M.S (Co.SRGB 'Co.Linear) Double <- M.readImageAuto input

View file

@ -21,7 +21,7 @@ randomPolarCoord gen = do
distance <- uniformRM (1, 2) gen distance <- uniformRM (1, 2) gen
pure $ view (from r2PolarIso) (distance, angle @@ turn) pure $ view (from r2PolarIso) (distance, angle @@ turn)
randomPoints :: RandomGen r => Point V2 Double -> Double -> r -> [Point V2 Double] randomPoints :: (RandomGen r) => Point V2 Double -> Double -> r -> [Point V2 Double]
randomPoints dims minDistance gen' = runStateGen_ gen' randomPointsM randomPoints dims minDistance gen' = runStateGen_ gen' randomPointsM
where where
randomPointsM gen = do randomPointsM gen = do
@ -37,7 +37,7 @@ randomPoints dims minDistance gen' = runStateGen_ gen' randomPointsM
bucketSize :: Double bucketSize :: Double
bucketSize = minDistance / (sqrt 2) bucketSize = minDistance / (sqrt 2)
addPointToGrid grid p = M.insert (floor <$> p) (p) grid addPointToGrid grid p = M.insert (floor <$> p) p grid
randomValueFrom xs = (xs NE.!!) <$> uniformRM (0, pred . length $ xs) gen randomValueFrom xs = (xs NE.!!) <$> uniformRM (0, pred . length $ xs) gen
@ -45,13 +45,10 @@ randomPoints dims minDistance gen' = runStateGen_ gen' randomPointsM
randomPointsRec (x : xs') grid = do randomPointsRec (x : xs') grid = do
startingPoint <- randomValueFrom xs startingPoint <- randomValueFrom xs
newPoint <- L.find isValidPoint <$> candidates startingPoint newPoint <- L.find isValidPoint <$> candidates startingPoint
randomPointsRec (prependIfJust newPoint $ (if My.isJust newPoint then x : xs' else xsWithout startingPoint)) . gridPlus $ newPoint case newPoint of
Just newPoint' -> randomPointsRec (newPoint' : x : xs') (addPointToGrid grid newPoint')
Nothing -> randomPointsRec (xsWithout startingPoint) grid
where where
prependIfJust (Just a) xs = a : xs
prependIfJust Nothing xs = xs
gridPlus = maybe grid (addPointToGrid grid)
xs :: NE.NonEmpty (Point V2 Double) xs :: NE.NonEmpty (Point V2 Double)
xs = x NE.:| xs' xs = x NE.:| xs'
@ -68,7 +65,7 @@ randomPoints dims minDistance gen' = runStateGen_ gen' randomPointsM
isValidPoint :: Point V2 Double -> Bool isValidPoint :: Point V2 Double -> Bool
isValidPoint p = isValidPoint p =
(Ix.inRange gridBounds (floor <$> p)) (Ix.inRange gridBounds . fmap floor $ p)
&& ( all ((>= 1) . abs . norm . (p .-.)) && ( all ((>= 1) . abs . norm . (p .-.))
. My.mapMaybe ((grid M.!?) . fmap floor . (p .-^)) . My.mapMaybe ((grid M.!?) . fmap floor . (p .-^))
$ unitVectorsAround $ unitVectorsAround

View file

@ -34,7 +34,7 @@ import Diagrams.TwoD.Segment.Bernstein (listToBernstein)
import qualified Graphics.Color.Space as Co import qualified Graphics.Color.Space as Co
import System.Random import System.Random
toColour :: Fractional a => Co.Color (Co.SRGB Co.Linear) a -> Colour a toColour :: (Fractional a) => Co.Color (Co.SRGB Co.Linear) a -> Colour a
toColour (Co.ColorSRGB r g b) = CL.rgb r g b toColour (Co.ColorSRGB r g b) = CL.rgb r g b
-- from -0.05 to 1.05 so there aren't missing/elongated triangles at the edges -- from -0.05 to 1.05 so there aren't missing/elongated triangles at the edges
@ -48,7 +48,7 @@ randomPoints = map (bimap toZeroToOneTuple toZeroToOneTuple) . randomRs ((0 :: W
toZeroToOneTuple x = ((fromIntegral x / (fromIntegral (maxBound :: Word))) * (1 + (2 * borderSize))) - borderSize toZeroToOneTuple x = ((fromIntegral x / (fromIntegral (maxBound :: Word))) * (1 + (2 * borderSize))) - borderSize
combinations :: (Ord b, Floating b, NFData b) => [P2 b] -> [(P2 b, P2 b)] combinations :: (Ord b, Floating b, NFData b) => [P2 b] -> [(P2 b, P2 b)]
combinations xs = combinations =
sortOn (abs . uncurry distanceA) sortOn (abs . uncurry distanceA)
. S.toList -- deduplicate . S.toList -- deduplicate
. S.fromList . S.fromList
@ -58,19 +58,13 @@ combinations xs =
. map (\(x : xs) -> take 10 . sortOn (abs . uncurry distanceA) . map (x,) $ xs) . map (\(x : xs) -> take 10 . sortOn (abs . uncurry distanceA) . map (x,) $ xs)
. init -- last output of tails is empty list . init -- last output of tails is empty list
. tails . tails
$ xs
where
xsLen = length xs
toPlanarGraph :: forall n. (NFData n, Floating n, Ord n) => [P2 n] -> [(Point V2 n, Point V2 n)] toPlanarGraph :: forall n. (NFData n, Floating n, Ord n) => [P2 n] -> [(Point V2 n, Point V2 n)]
toPlanarGraph points = toPlanarGraph =
removeIntersections removeIntersections
. sortOn (abs . uncurry distanceA) . sortOn (abs . uncurry distanceA)
. combinations . combinations
$ points
where where
numPoints = length points
removeIntersections :: [(Point V2 n, Point V2 n)] -> [(Point V2 n, Point V2 n)] removeIntersections :: [(Point V2 n, Point V2 n)] -> [(Point V2 n, Point V2 n)]
removeIntersections = foldl' addIfNoIntersection [] removeIntersections = foldl' addIfNoIntersection []
@ -82,17 +76,17 @@ toPlanarGraph points =
where where
sharedEndPoint = (< 4) . length . nub $ [fst l1, snd l1, fst l2, snd l2] sharedEndPoint = (< 4) . length . nub $ [fst l1, snd l1, fst l2, snd l2]
toLocatedTrail :: TrailLike a => Point (V a) (N a) -> Point (V a) (N a) -> Located a toLocatedTrail :: (TrailLike a) => Point (V a) (N a) -> Point (V a) (N a) -> Located a
toLocatedTrail p1 p2 = fromVertices [p1, p2] `at` p1 toLocatedTrail p1 p2 = fromVertices [p1, p2] `at` p1
withinShape :: RealFloat v => Point V2 v -> [Point V2 v] -> Point V2 v -> Bool withinShape :: (RealFloat v) => Point V2 v -> [Point V2 v] -> Point V2 v -> Bool
withinShape pointInShape verticies candidate = all ((< quarterTurn) . fmap abs . uncurry signedAngleBetweenDirs) $ zip (shapeDirections pointInShape) (shapeDirections candidate) withinShape pointInShape verticies candidate = all ((< quarterTurn) . fmap abs . uncurry signedAngleBetweenDirs) $ zip (shapeDirections pointInShape) (shapeDirections candidate)
where where
shapeDirections p = map (dirBetween p) verticies shapeDirections p = map (dirBetween p) verticies
sortOnAngle center = sortOn (normalizeAngle . signedAngleBetweenDirs xDir . dirBetween center) sortOnAngle center = sortOn (normalizeAngle . signedAngleBetweenDirs xDir . dirBetween center)
voroniDiagramCorners :: RealFloat n => Point V2 n -> [Point V2 n] -> [Point V2 n] voroniDiagramCorners :: (RealFloat n) => Point V2 n -> [Point V2 n] -> [Point V2 n]
voroniDiagramCorners center midpoints = voroniDiagramCorners center midpoints =
sortOnAngle center sortOnAngle center
. filter isValidMidpoint . filter isValidMidpoint
@ -119,8 +113,8 @@ voroniDiagramCorners center midpoints =
. rotateBy (1 / 4) . rotateBy (1 / 4)
$ dirBetween midpoint center $ dirBetween midpoint center
findVoroniDiagram :: RealFloat n => [(Point V2 n, Point V2 n)] -> [(Point V2 n, [Point V2 n])] findVoroniDiagram :: (RealFloat n) => [(Point V2 n, Point V2 n)] -> [(Point V2 n, [Point V2 n])]
findVoroniDiagram edges = findVoroniDiagram =
M.toList M.toList
. M.mapWithKey . M.mapWithKey
( \key -> ( \key ->
@ -128,13 +122,11 @@ findVoroniDiagram edges =
. map (pointBetween key) . map (pointBetween key)
. S.toList . S.toList
) )
$ adjacencyMap . adjacencyMapOf
where where
adjacencyMap = adjacencyMapOf edges
pointBetween p0 p1 = p0 .+^ ((p1 .-. p0) ^/ 2) pointBetween p0 p1 = p0 .+^ ((p1 .-. p0) ^/ 2)
findTriangles :: Ord b => [(b, b)] -> S.Set (S.Set b) findTriangles :: (Ord b) => [(b, b)] -> S.Set (S.Set b)
findTriangles edges = S.unions . S.map threeCyclesOf . M.keysSet $ adjacencyMap findTriangles edges = S.unions . S.map threeCyclesOf . M.keysSet $ adjacencyMap
where where
threeCyclesOf node = threeCyclesOf node =
@ -150,26 +142,26 @@ adjacencyMapOf edges = M.fromListWith S.union . map (second S.singleton) $ (edge
where where
edgesReversed = map (\(a, b) -> (b, a)) edges edgesReversed = map (\(a, b) -> (b, a)) edges
triangleAdjacencyMap :: Ord b => S.Set (S.Set b) -> M.Map b (S.Set (S.Set b)) triangleAdjacencyMap :: (Ord b) => S.Set (S.Set b) -> M.Map b (S.Set (S.Set b))
triangleAdjacencyMap s = M.fromListWith S.union . concatMap (\s' -> map (,S.singleton s') . S.toList $ s') $ S.toList s triangleAdjacencyMap s = M.fromListWith S.union . concatMap (\s' -> map (,S.singleton s') . S.toList $ s') $ S.toList s
getPointsInTriangle :: p -> S.Set (P2 Int) -> [(Int, Int)] getPointsInTriangle :: p -> S.Set (P2 Int) -> [(Int, Int)]
getPointsInTriangle image pts = getPointsInTriangle image pts =
S.toList . S.unions . map S.fromList $ S.toList . S.unions . map S.fromList $
[ ptsBtween (makeLine p1 p3) (makeLine p1 p2) [ ptsBtween (makeLine p1 p3) (makeLine p1 p2),
, ptsBtween (makeLine p1 p3) (makeLine p2 p3) ptsBtween (makeLine p1 p3) (makeLine p2 p3),
, ptsBtween (makeLine p1 p2) (makeLine p2 p3) ptsBtween (makeLine p1 p2) (makeLine p2 p3)
] ]
where where
[p1, p2, p3] = sortOn fst . map unp2 . S.toList $ pts [p1, p2, p3] = sortOn fst . map unp2 . S.toList $ pts
blendEqually :: (Ord a, Floating a) => [Colour a] -> Colour a blendEqually :: (Ord a, Floating a) => [Colour a] -> Colour a
blendEqually colors = C.affineCombo (zip (repeat fraction) colors) $ C.white blendEqually colors = C.affineCombo (map (fraction,) colors) C.white
where where
fraction = 1.0 / (fromIntegral . length $ colors) fraction = 1.0 / (fromIntegral . length $ colors)
voroniRegionAverageColor :: (Integral a, Integral b) => Ma.Image Ma.S (Co.SRGB 'Co.Linear) Double -> (a, b) -> [P2 Double] -> Colour Double voroniRegionAverageColor :: (Integral a, Integral b) => Ma.Image Ma.S (Co.SRGB 'Co.Linear) Double -> (a, b) -> [P2 Double] -> Colour Double
voroniRegionAverageColor image (x', y') verticies = voroniRegionAverageColor image (x', y') =
blendEqually blendEqually
. concatMap (getColorsInTriangle image (x', y')) . concatMap (getColorsInTriangle image (x', y'))
. filter ((== 3) . S.size) . filter ((== 3) . S.size)
@ -177,19 +169,16 @@ voroniRegionAverageColor image (x', y') verticies =
. tails . tails
. L.nub . L.nub
. map scaleToImageCoords . map scaleToImageCoords
$ verticies
where where
scaleToImageCoords :: P2 Double -> P2 Int scaleToImageCoords :: P2 Double -> P2 Int
scaleToImageCoords p = fmap round $ p2 ((fromIntegral x' * p ^. _x), fromIntegral y' * p ^. _y) scaleToImageCoords p = round <$> p2 (fromIntegral x' * p ^. _x, fromIntegral y' * p ^. _y)
scaleToUnitCoords :: P2 Int -> P2 Double scaleToUnitCoords :: P2 Int -> P2 Double
scaleToUnitCoords p = p2 ((fromIntegral x' / (fromIntegral $ p ^. _x)), fromIntegral y' / (fromIntegral $ p ^. _y)) scaleToUnitCoords p = p2 ((fromIntegral x' / (fromIntegral $ p ^. _x)), fromIntegral y' / (fromIntegral $ p ^. _y))
getColorsInTriangle :: Ma.Image Ma.S (Co.SRGB 'Co.Linear) Double -> (a, b) -> S.Set (P2 Int) -> [Colour Double] getColorsInTriangle :: Ma.Image Ma.S (Co.SRGB 'Co.Linear) Double -> (a, b) -> S.Set (P2 Int) -> [Colour Double]
getColorsInTriangle image (x', y') triangle = pixels getColorsInTriangle image (x', y') triangle = mapMaybe index' points
where where
pixels = mapMaybe index' points
points :: [(Int, Int)] points :: [(Int, Int)]
points = getPointsInTriangle image triangle points = getPointsInTriangle image triangle
@ -215,15 +204,15 @@ range' :: Int -> Int -> [Int]
range' a b = [(min a b) .. (max a b)] range' a b = [(min a b) .. (max a b)]
yAt :: LineMXB -> Int -> Int yAt :: LineMXB -> Int -> Int
yAt (LineMXB{m = m, b = b}) x = round $ (m * (fromIntegral x)) + b yAt (LineMXB {..}) x = round $ (m * (fromIntegral x)) + b
makeLine :: (Int, Int) -> (Int, Int) -> LineMXB makeLine :: (Int, Int) -> (Int, Int) -> LineMXB
makeLine (x1, y1) (x2, y2) = makeLine (x1, y1) (x2, y2) =
LineMXB LineMXB
{ m = slope { m = slope,
, b = (fromIntegral y1) - (slope * (fromIntegral x1)) b = (fromIntegral y1) - (slope * (fromIntegral x1)),
, startX = min x1 x2 startX = min x1 x2,
, endX = max x1 x2 endX = max x1 x2
} }
where where
slope = slope =
@ -232,9 +221,9 @@ makeLine (x1, y1) (x2, y2) =
else fromIntegral . ceiling $ ((10.0 :: Double) ** 100.0) else fromIntegral . ceiling $ ((10.0 :: Double) ** 100.0)
data LineMXB = LineMXB data LineMXB = LineMXB
{ m :: Rational { m :: Rational,
, b :: Rational b :: Rational,
, startX :: Int startX :: Int,
, endX :: Int endX :: Int
} }
deriving (Show, Ord, Eq) deriving (Show, Ord, Eq)