swapping to voroni diagram
This commit is contained in:
parent
f1e5ff2b86
commit
dd9bb2c88a
17 changed files with 416 additions and 19 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake;
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,4 +1 @@
|
||||||
.stack-work/*
|
|
||||||
dist/*
|
|
||||||
/dist-newstyle/
|
/dist-newstyle/
|
||||||
/cabal.project.local
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
# image-triangles
|
# image-triangles
|
||||||
### examples
|
### examples
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
### to run:
|
### to run:
|
||||||
|
|
||||||
|
|
@ -11,5 +11,5 @@ Install [cabal & ghc](https://www.haskell.org/ghcup/) if you don't have them.
|
||||||
|
|
||||||
```
|
```
|
||||||
cabal update
|
cabal update
|
||||||
cabal run image-triangles -- --cornerCount 1000 --input examples/sierra.jpg --output output.png
|
cabal run image-triangles -- --cornerCount 800 --input examples/sierra.jpg --output output.svg
|
||||||
```
|
```
|
||||||
|
|
|
||||||
5
cabal.project
Normal file
5
cabal.project
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
packages:
|
||||||
|
./
|
||||||
|
|
||||||
|
-- package repa
|
||||||
|
-- ghc-options: -fincomplete-uni-patterns
|
||||||
3
examples/luna-result.svg
Normal file
3
examples/luna-result.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 2.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 747 KiB |
3
examples/sierra-result.svg
Normal file
3
examples/sierra-result.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 2.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 227 KiB |
134
flake.lock
generated
Normal file
134
flake.lock
generated
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704982712,
|
||||||
|
"narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "07f6395285469419cf9d078f59b5b49993198c00",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haskell-flake": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705079807,
|
||||||
|
"narHash": "sha256-8snpmo0PGMqirgVnw9OnHF2FtsVkcdWLup+TzV3PCIE=",
|
||||||
|
"owner": "srid",
|
||||||
|
"repo": "haskell-flake",
|
||||||
|
"rev": "55efd0cbf1b5b4a402dc88c3c962c24e13f0fd8b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "srid",
|
||||||
|
"repo": "haskell-flake",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hip": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1680449103,
|
||||||
|
"narHash": "sha256-7mO0EifBLn16iTCxiOF74Ek89TDj4na6O7/WgAxKcp0=",
|
||||||
|
"owner": "lehins",
|
||||||
|
"repo": "hip",
|
||||||
|
"rev": "05adf58fa2581f4940e8d1b28280f64aea02f3ee",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lehins",
|
||||||
|
"repo": "hip",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704290814,
|
||||||
|
"narHash": "sha256-LWvKHp7kGxk/GEtlrGYV68qIvPHkU9iToomNFGagixU=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "70bdadeb94ffc8806c0570eb5c2695ad29f0e421",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-23.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "lib",
|
||||||
|
"lastModified": 1703961334,
|
||||||
|
"narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "lib",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"haskell-flake": "haskell-flake",
|
||||||
|
"hip": "hip",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"systems": "systems",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"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": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704649711,
|
||||||
|
"narHash": "sha256-+qxqJrZwvZGilGiLQj3QbYssPdYCwl7ejwMImgH7VBQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "04f25d7bec9fb29d2c3bacaa48a3304840000d36",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
104
flake.nix
Normal file
104
flake.nix
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
description = "srid/haskell-template: Nix template for Haskell projects";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
|
||||||
|
systems.url = "github:nix-systems/default";
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
haskell-flake.url = "github:srid/haskell-flake";
|
||||||
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
|
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
hip.url = "github:lehins/hip";
|
||||||
|
hip.flake = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs:
|
||||||
|
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||||
|
systems = import inputs.systems;
|
||||||
|
imports = [
|
||||||
|
inputs.haskell-flake.flakeModule
|
||||||
|
inputs.treefmt-nix.flakeModule
|
||||||
|
];
|
||||||
|
perSystem = { self', system, lib, config, pkgs, ... }: {
|
||||||
|
# Our only Haskell project. You can have multiple projects, but this template
|
||||||
|
# has only one.
|
||||||
|
# See https://github.com/srid/haskell-flake/blob/master/example/flake.nix
|
||||||
|
haskellProjects.default = {
|
||||||
|
# The base package set (this value is the default)
|
||||||
|
# basePackages = pkgs.haskellPackages;
|
||||||
|
|
||||||
|
# Packages to add on top of `basePackages`
|
||||||
|
packages = {
|
||||||
|
# Add source or Hackage overrides here
|
||||||
|
# (Local packages are added automatically)
|
||||||
|
# https://github.com/lehins/hip.git
|
||||||
|
# hip.source = inputs.hip + "/hip";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Add your package overrides here
|
||||||
|
settings = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
haskell-template = {
|
||||||
|
haddock = false;
|
||||||
|
};
|
||||||
|
aeson = {
|
||||||
|
check = false;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
hip = {
|
||||||
|
jailbreak = true;
|
||||||
|
broken = false;
|
||||||
|
failOnAllWarnings = false;
|
||||||
|
check = false;
|
||||||
|
# extraBuildFlags = ["--ghc-option=-Wno-incomplete-uni-patterns"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Development shell configuration
|
||||||
|
devShell = {
|
||||||
|
hlsCheck.enable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# What should haskell-flake add to flake outputs?
|
||||||
|
autoWire = [ "packages" "apps" "checks" ]; # Wire all but the devShell
|
||||||
|
};
|
||||||
|
|
||||||
|
# Auto formatters. This also adds a flake check to ensure that the
|
||||||
|
# source tree was auto formatted.
|
||||||
|
treefmt.config = {
|
||||||
|
projectRootFile = "flake.nix";
|
||||||
|
|
||||||
|
programs.ormolu.enable = true;
|
||||||
|
programs.nixpkgs-fmt.enable = true;
|
||||||
|
programs.cabal-fmt.enable = true;
|
||||||
|
programs.hlint.enable = true;
|
||||||
|
|
||||||
|
# We use fourmolu
|
||||||
|
# programs.ormolu.package = pkgs.haskellPackages.fourmolu;
|
||||||
|
# settings.formatter.ormolu = {
|
||||||
|
# options = [
|
||||||
|
# "--ghc-opt"
|
||||||
|
# "-XImportQualifiedPost"
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
# Default package & app.
|
||||||
|
packages.default = self'.packages.image-triangles;
|
||||||
|
apps.default = self'.apps.image-triangles;
|
||||||
|
|
||||||
|
# Default shell.
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
name = "haskell-template";
|
||||||
|
meta.description = "Haskell development environment";
|
||||||
|
# See https://zero-to-flakes.com/haskell-flake/devshell#composing-devshells
|
||||||
|
inputsFrom = [
|
||||||
|
config.haskellProjects.default.outputs.devShell
|
||||||
|
config.treefmt.build.devShell
|
||||||
|
];
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
cabal-version: 3.4
|
||||||
-- Initial image-triangles.cabal generated by cabal init. For further
|
-- Initial image-triangles.cabal generated by cabal init. For further
|
||||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ version: 0.1.0.0
|
||||||
-- description:
|
-- description:
|
||||||
|
|
||||||
-- The license under which the package is released.
|
-- The license under which the package is released.
|
||||||
license: BSD3
|
license: BSD-3-Clause
|
||||||
|
|
||||||
-- The file containing the license text.
|
-- The file containing the license text.
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
|
|
@ -40,10 +41,8 @@ build-type: Simple
|
||||||
|
|
||||||
-- Extra files to be distributed with the package, such as examples or a
|
-- Extra files to be distributed with the package, such as examples or a
|
||||||
-- README.
|
-- README.
|
||||||
extra-source-files: CHANGELOG.md, README.md
|
extra-source-files: README.md
|
||||||
|
|
||||||
-- Constraint on the version of Cabal needed to build this package.
|
|
||||||
cabal-version: >=1.10
|
|
||||||
|
|
||||||
|
|
||||||
executable image-triangles
|
executable image-triangles
|
||||||
|
|
@ -51,7 +50,7 @@ executable image-triangles
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
|
||||||
-- Modules included in this executable, other than Main.
|
-- Modules included in this executable, other than Main.
|
||||||
other-modules: Render, Triangles
|
other-modules: Render, Triangles, CircumCircle
|
||||||
|
|
||||||
-- LANGUAGE extensions used by modules in this package.
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
default-extensions: ScopedTypeVariables,
|
default-extensions: ScopedTypeVariables,
|
||||||
|
|
@ -84,7 +83,6 @@ executable image-triangles
|
||||||
, diagrams-cairo
|
, diagrams-cairo
|
||||||
, diagrams-svg
|
, diagrams-svg
|
||||||
, parallel
|
, parallel
|
||||||
, repa
|
|
||||||
, linear
|
, linear
|
||||||
, vector
|
, vector
|
||||||
, containers
|
, containers
|
||||||
|
|
|
||||||
65
src/CircumCircle.hs
Normal file
65
src/CircumCircle.hs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
module CircumCircle where
|
||||||
|
import Diagrams.Prelude
|
||||||
|
import Triangles
|
||||||
|
import qualified Data.Set as S
|
||||||
|
import qualified Data.List as L
|
||||||
|
import Diagrams.TwoD
|
||||||
|
import Diagrams.Direction
|
||||||
|
import qualified Data.Colour.Names as CN
|
||||||
|
import Diagrams.Backend.SVG
|
||||||
|
import GHC.Generics
|
||||||
|
import Data.Maybe
|
||||||
|
|
||||||
|
data Circle n = Circle {
|
||||||
|
loc :: P2 n,
|
||||||
|
radius :: n
|
||||||
|
}
|
||||||
|
|
||||||
|
placeCircle :: Colour Double -> Circle Double -> Diagram B
|
||||||
|
placeCircle col (Circle{..}) = circle radius # translate (loc .-. origin) # lw 0 # fc col
|
||||||
|
|
||||||
|
-- placeCircle (Circle{loc = loc, radius = rad}) = circle rad $ fc blue -- # opacity .25
|
||||||
|
|
||||||
|
circumCircle :: (Ord a, Floating a) => S.Set (P2 a) -> Maybe (Circle a)
|
||||||
|
circumCircle pts = circumCircleFromLoc <$> loc
|
||||||
|
where
|
||||||
|
circumCircleFromLoc loc' = Circle loc' (magnitude $ p1 .-. loc')
|
||||||
|
|
||||||
|
loc = listToMaybe $ intersectPointsT (mapLoc (fromOffsets. L.singleton . (^* circumfrence) . fromDir) bisectP1P2)
|
||||||
|
(mapLoc (fromOffsets. L.singleton . (^* circumfrence) . fromDir) bisectP2P3)
|
||||||
|
|
||||||
|
bisectP1P2 = bisect p1 p2
|
||||||
|
|
||||||
|
bisectP2P3 = bisect p2 p3
|
||||||
|
|
||||||
|
[p1, p2, p3] = L.sortOn (snd . unp2) . S.toList $ pts
|
||||||
|
|
||||||
|
circumfrence = sum . map magnitude $ [(p2 .-. p1), (p2 .-. p3), (p1 .-. p3)]
|
||||||
|
|
||||||
|
|
||||||
|
-- circumDebug :: (Ord a, Floating a) => S.Set (P2 a) -> Maybe (Circle a)
|
||||||
|
circumDebug pts = (bisectP1P2, bisectP2P3)
|
||||||
|
where
|
||||||
|
circumCircleFromLoc loc' = Circle loc' (magnitude $ p1 .-. loc')
|
||||||
|
|
||||||
|
loc = listToMaybe $ intersectPointsT (mapLoc (fromOffsets. L.singleton . fromDir) bisectP1P2) (mapLoc (fromOffsets. L.singleton . fromDir) bisectP1P2)
|
||||||
|
|
||||||
|
bisectP1P2 = bisect p1 p2
|
||||||
|
|
||||||
|
bisectP2P3 = bisect p2 p3
|
||||||
|
|
||||||
|
[p1, p2, p3] = L.sortOn (snd . unp2) . S.toList $ pts
|
||||||
|
|
||||||
|
circumfrence = 400
|
||||||
|
|
||||||
|
|
||||||
|
magnitude :: Floating a => V2 a -> a
|
||||||
|
magnitude v = sqrt (x * x + y * y)
|
||||||
|
where
|
||||||
|
(x, y) = unr2 v
|
||||||
|
|
||||||
|
-- assumes x of p1 is smaller than x of p2
|
||||||
|
bisect :: Floating n => Point V2 n -> Point V2 n -> Located (Direction V2 n)
|
||||||
|
bisect p1 p2 = at (rotateBy (1 / 4) $ dir bisectVec) (p1 .+^ bisectVec)
|
||||||
|
where
|
||||||
|
bisectVec = (p2 .-. p1) ^/ 2
|
||||||
33
src/Main.hs
33
src/Main.hs
|
|
@ -22,7 +22,7 @@ import qualified System.Environment as Env
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Diagrams.Backend.SVG
|
import Diagrams.Backend.SVG
|
||||||
import Diagrams.Backend.Cairo
|
import qualified Data.Colour.Names as CN
|
||||||
import Triangles (getTriangleAverageRGB)
|
import Triangles (getTriangleAverageRGB)
|
||||||
import Options.Generic
|
import Options.Generic
|
||||||
import qualified Data.Colour.SRGB as CL
|
import qualified Data.Colour.SRGB as CL
|
||||||
|
|
@ -31,6 +31,7 @@ import qualified Data.Maybe as My
|
||||||
import Control.Arrow
|
import Control.Arrow
|
||||||
import Data.Colour.RGBSpace (uncurryRGB)
|
import Data.Colour.RGBSpace (uncurryRGB)
|
||||||
import qualified Control.Monad.Parallel as MP
|
import qualified Control.Monad.Parallel as MP
|
||||||
|
import qualified CircumCircle as CC
|
||||||
|
|
||||||
data Options = Options {
|
data Options = Options {
|
||||||
numPoints :: Int,
|
numPoints :: Int,
|
||||||
|
|
@ -55,7 +56,7 @@ corners = (,) <$> [0, 1] <*> [0, 1]
|
||||||
scalePointToImage :: (Int, Int) -> Point V2 Double -> Point V2 Int
|
scalePointToImage :: (Int, Int) -> Point V2 Double -> Point V2 Int
|
||||||
scalePointToImage (ymax, xmax) p = round <$> (p2 (fromIntegral xmax, fromIntegral ymax) * p)
|
scalePointToImage (ymax, xmax) p = round <$> (p2 (fromIntegral xmax, fromIntegral ymax) * p)
|
||||||
|
|
||||||
genImage :: Image VU G.RGB Double -> StdGen -> Int -> QDiagram Cairo V2 Double Any
|
genImage :: Image VU G.RGB Double -> StdGen -> Int -> QDiagram B V2 Double Any
|
||||||
genImage image gen cornerCount =
|
genImage image gen cornerCount =
|
||||||
scaleY widthHeightRatio
|
scaleY widthHeightRatio
|
||||||
. reflectY
|
. reflectY
|
||||||
|
|
@ -75,6 +76,30 @@ genImage image gen cornerCount =
|
||||||
where
|
where
|
||||||
scaled = S.map (scalePointToImage dimensions) tri
|
scaled = S.map (scalePointToImage dimensions) tri
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- genImage' :: Image VU G.RGB Double -> StdGen -> Int -> QDiagram Cairo V2 Double Any
|
||||||
|
genImage' image gen cornerCount = -- image gen cornerCount =
|
||||||
|
scaleY widthHeightRatio
|
||||||
|
. reflectY
|
||||||
|
. rectEnvelope (mkP2 0 0) (1 ^& 1)
|
||||||
|
. position
|
||||||
|
. map (\shape -> (head shape, ) . showOrigin
|
||||||
|
. fillColor (Tri.getShapeAverageRGB img' dimensions . map (scalePointToImage dimensions) $ shape)
|
||||||
|
. strokeLoop . closeLine . fromVertices $ shape)
|
||||||
|
-- . withStrategy (parListChunk 1000 rdeepseq)
|
||||||
|
$ voroni
|
||||||
|
where
|
||||||
|
widthHeightRatio = (fromIntegral $ fst dimensions) / ((fromIntegral $ snd dimensions) :: Double)
|
||||||
|
|
||||||
|
triColor tri = getTriangleAverageRGB img' dimensions <$> (if S.size scaled == 3 then Just scaled else Nothing)
|
||||||
|
where
|
||||||
|
scaled = S.map (scalePointToImage dimensions) tri
|
||||||
|
|
||||||
|
img' = convImage image
|
||||||
|
dimensions = Img.dims image
|
||||||
|
voroni = take 40 . Tri.findVoroniDiagram . withStrategy (parListChunk 1000 rdeepseq) . Tri.toPlanarGraph . take cornerCount . map p2 $ corners ++ Tri.randomPoints 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)
|
||||||
|
|
||||||
|
|
@ -93,12 +118,12 @@ main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
CLIOptions{..} <- getRecord "image options"
|
CLIOptions{..} <- getRecord "image options"
|
||||||
let (Options {gen = gen}) = defaultOpts
|
let (Options {gen = gen}) = defaultOpts
|
||||||
gen' <- getStdGen
|
gen' <- pure . mkStdGen $ 2345 -- getStdGen
|
||||||
let gens :: [StdGen] = map fst . iterate (split . snd) . split $ gen'
|
let gens :: [StdGen] = map fst . iterate (split . snd) . split $ gen'
|
||||||
print gen'
|
print gen'
|
||||||
image <- Img.readImageRGB VU input
|
image <- Img.readImageRGB VU input
|
||||||
let diagram = genImage image gen' cornerCount
|
let diagram = genImage image gen' cornerCount
|
||||||
let nums = zip gens $ map show [0..60]
|
let nums = zip gens $ map show [0..60]
|
||||||
let dimVector = toDimensionVector image
|
let dimVector = toDimensionVector image
|
||||||
renderCairo output dimVector (genImage image gen' cornerCount)
|
renderSVG output dimVector (genImage' image gen' cornerCount)
|
||||||
-- MP.forM_ nums (\(gen'', x) -> renderCairo ("output/" ++ x ++ "-" ++ output) dimVector (genImage image gen'' cornerCount))
|
-- MP.forM_ nums (\(gen'', x) -> renderCairo ("output/" ++ x ++ "-" ++ output) dimVector (genImage image gen'' cornerCount))
|
||||||
|
|
|
||||||
36
src/Main.log
Normal file
36
src/Main.log
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/VoidLinux) (preloaded format=pdflatex 2023.1.13) 8 FEB 2023 18:35
|
||||||
|
entering extended mode
|
||||||
|
restricted \write18 enabled.
|
||||||
|
%&-line parsing enabled.
|
||||||
|
**/home/jackoe/Documents/projects/image-triangles/src/Main.hs
|
||||||
|
(/home/jackoe/Documents/projects/image-triangles/src/Main.hs
|
||||||
|
LaTeX2e <2020-10-01> patch level 4
|
||||||
|
L3 programming layer <2021-02-18>
|
||||||
|
|
||||||
|
! LaTeX Error: Missing \begin{document}.
|
||||||
|
|
||||||
|
See the LaTeX manual or LaTeX Companion for explanation.
|
||||||
|
Type H <return> for immediate help.
|
||||||
|
...
|
||||||
|
|
||||||
|
l.1 m
|
||||||
|
odule Main where
|
||||||
|
?
|
||||||
|
! Emergency stop.
|
||||||
|
...
|
||||||
|
|
||||||
|
l.1 m
|
||||||
|
odule Main where
|
||||||
|
You're in trouble here. Try typing <return> to proceed.
|
||||||
|
If that doesn't work, type X <return> to quit.
|
||||||
|
|
||||||
|
|
||||||
|
Here is how much of TeX's memory you used:
|
||||||
|
19 strings out of 478994
|
||||||
|
669 string characters out of 5864719
|
||||||
|
283044 words of memory out of 5000000
|
||||||
|
17602 multiletter control sequences out of 15000+600000
|
||||||
|
403430 words of font info for 27 fonts, out of 8000000 for 9000
|
||||||
|
1141 hyphenation exceptions out of 8191
|
||||||
|
13i,0n,15p,108b,14s stack positions out of 5000i,500n,10000p,200000b,80000s
|
||||||
|
! ==> Fatal error occurred, no output PDF file produced!
|
||||||
|
|
@ -11,6 +11,9 @@ import qualified Data.Colour.Names as CN
|
||||||
|
|
||||||
|
|
||||||
-- makeTriangle :: [Point V2 Double] -> Colour Double -> Diagram SVG
|
-- makeTriangle :: [Point V2 Double] -> Colour Double -> Diagram SVG
|
||||||
|
-- makeTriangle :: (base-4.16.4.0:Data.Typeable.Internal.Typeable n, RealFloat n,
|
||||||
|
-- Renderable (Path V2 n) b) =>
|
||||||
|
-- [Point V2 n] -> Colour Double -> QDiagram b V2 n Any
|
||||||
makeTriangle verts col = fromVertices verts
|
makeTriangle verts col = fromVertices verts
|
||||||
# mapLoc closeLine
|
# mapLoc closeLine
|
||||||
# strokeLocLoop
|
# strokeLocLoop
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import Diagrams.Prelude
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Control.Arrow
|
import Control.Arrow
|
||||||
|
import qualified Data.List as L
|
||||||
-- import qualified Linear.Affine as L
|
-- import qualified Linear.Affine as L
|
||||||
type Image_ = Vec.Vector Pixel_
|
type Image_ = Vec.Vector Pixel_
|
||||||
type Pixel_ = Colour Double
|
type Pixel_ = Colour Double
|
||||||
|
|
@ -66,6 +67,7 @@ combinations xs =
|
||||||
edgeLengthThreshold = 45
|
edgeLengthThreshold = 45
|
||||||
|
|
||||||
-- toPlanarGraph :: (NFData n, Floating n, Ord n) => [Point V2 n] -> [(Point V2 n, Point V2 n)]
|
-- toPlanarGraph :: (NFData n, Floating n, Ord n) => [Point V2 n] -> [(Point V2 n, Point V2 n)]
|
||||||
|
toPlanarGraph :: (NFData n, Floating n, Ord n) => [P2 n] -> [(Point V2 n, Point V2 n)]
|
||||||
toPlanarGraph points =
|
toPlanarGraph points =
|
||||||
removeIntersections . combinations $ points
|
removeIntersections . combinations $ points
|
||||||
where
|
where
|
||||||
|
|
@ -82,6 +84,14 @@ toPlanarGraph points =
|
||||||
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
|
||||||
|
|
||||||
|
-- findVoroniDiagram :: (Ord (v n), Additive v, Fractional n) => [(Point v n, Point v n)] -> [[Point v n]]
|
||||||
|
findVoroniDiagram :: (Ord n, Ord (v n), Metric v, Floating n, R1 v, Real n) => [(Point v n, Point v n)] -> [[Point v n]]
|
||||||
|
findVoroniDiagram edges = M.elems . M.mapWithKey (\key -> L.sortOn (normalizeAngle . angleBetweenDirs xDir . dirBetween key) .
|
||||||
|
map (pointBetween key) . S.toList) $ adjacencyMap
|
||||||
|
where
|
||||||
|
adjacencyMap = adjacencyMapOf edges
|
||||||
|
|
||||||
|
pointBetween p0 p1 = p0 .+^ ((p0 .-. p1) ^/ 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
|
||||||
|
|
@ -92,9 +102,14 @@ findTriangles edges = S.unions . S.map threeCyclesOf . M.keysSet $ adjacencyMap
|
||||||
where
|
where
|
||||||
originalNodeNeighbors = fromMaybe S.empty (adjacencyMap M.!? node)
|
originalNodeNeighbors = fromMaybe S.empty (adjacencyMap M.!? node)
|
||||||
|
|
||||||
adjacencyMap = M.fromListWith S.union . map (second S.singleton) $ (edges ++ edgesReversed)
|
adjacencyMap = adjacencyMapOf edges
|
||||||
|
|
||||||
|
adjacencyMapOf edges = M.fromListWith S.union . map (second S.singleton) $ (edges ++ edgesReversed)
|
||||||
|
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 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 = S.toList . S.unions . map S.fromList $ [
|
getPointsInTriangle image pts = S.toList . S.unions . map S.fromList $ [
|
||||||
|
|
@ -108,8 +123,11 @@ blendEqually colors = C.affineCombo (zip (repeat fraction) colors) $ C.black
|
||||||
where
|
where
|
||||||
fraction = 1.0 / (fromIntegral . length $ colors)
|
fraction = 1.0 / (fromIntegral . length $ colors)
|
||||||
|
|
||||||
getTriangleAverageRGB :: Image_ -> (Int, Int) -> S.Set (P2 Int) -> C.Colour Double
|
getShapeAverageRGB :: Image_ -> (Int, Int) -> [P2 Int] -> C.Colour Double
|
||||||
getTriangleAverageRGB image (y', x') triangle = blendEqually pixels
|
getShapeAverageRGB image sizes = blendEqually . concatMap (getColorsInTriangle image sizes) . filter ((== 3) . S.size) . map (S.fromList . take 3) . tails . L.sortOn (fst . unp2)
|
||||||
|
|
||||||
|
getColorsInTriangle :: Image_ -> (Int, Int) -> S.Set (P2 Int) -> [C.Colour Double]
|
||||||
|
getColorsInTriangle image (y', x') triangle = pixels
|
||||||
where
|
where
|
||||||
|
|
||||||
pixels :: [Pixel_]
|
pixels :: [Pixel_]
|
||||||
|
|
@ -126,6 +144,11 @@ getTriangleAverageRGB image (y', x') triangle = blendEqually pixels
|
||||||
| x < 0 = Nothing
|
| x < 0 = Nothing
|
||||||
| otherwise = image Vec.!? ((y * x') + x)
|
| otherwise = image Vec.!? ((y * x') + x)
|
||||||
|
|
||||||
|
|
||||||
|
getTriangleAverageRGB :: Image_ -> (Int, Int) -> S.Set (P2 Int) -> C.Colour Double
|
||||||
|
getTriangleAverageRGB image (y', x') triangle = blendEqually $ getColorsInTriangle image (y', x') triangle
|
||||||
|
|
||||||
|
|
||||||
ptsBtween :: LineMXB -> LineMXB -> [(Int, Int)]
|
ptsBtween :: LineMXB -> LineMXB -> [(Int, Int)]
|
||||||
ptsBtween l1 l2 = concatMap rasterLine . noSingletons $ [startingX .. endingX]
|
ptsBtween l1 l2 = concatMap rasterLine . noSingletons $ [startingX .. endingX]
|
||||||
where
|
where
|
||||||
|
|
|
||||||
BIN
src/dist-newstyle/cache/compiler
vendored
Normal file
BIN
src/dist-newstyle/cache/compiler
vendored
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue