From 002b834449529d5a2aee5d3b7fc9b06c1a65069a Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Tue, 27 Dec 2022 16:12:00 +0100 Subject: [PATCH] Add star generation program --- .envrc | 1 + .gitignore | 1 + genstar/Main.hs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ shell.nix | 11 +++++++++ 4 files changed, 72 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 genstar/Main.hs create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9dd98e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/genstar/doc diff --git a/genstar/Main.hs b/genstar/Main.hs new file mode 100644 index 0000000..6ce945f --- /dev/null +++ b/genstar/Main.hs @@ -0,0 +1,59 @@ +module Main where + +import Control.Monad (join) + +-- | One point of a path, consisting of its \(x\) and \(y\) coordinates. +newtype Vertex = Point (Double, Double) + +instance Show Vertex where + show (Point (x, y)) = show x ++ " " ++ show y + +-- | 'fromAngle' @angle@ +-- creats a point on the unit circle at the specified angle +-- (specified in radians). +fromAngle angle = Point (sin angle, cos angle) + +-- | 'scale' @s@ @p@ scales the vector to @p@ by the factor @s@. +scale :: Integer -> Vertex -> Vertex +scale s (Point (x, y)) = Point (fromInteger s * x, fromInteger s * y) + +-- | 'move' @p1@ @p2@ adds the coordinates of @p1@ and @p2@, +-- effectively moving @p1@ by @p2@ (or vice-versa). +move :: Vertex -> Vertex -> Vertex +move (Point (x1, y1)) (Point (x2, y2)) = Point (x1 + x2, y1 + y2) + +-- | Points \(p_0, p_2, \dots, p_{n-1}\) +-- that should be connected, +-- so that \(p_{i \bmod n}\) is connected to \(p_{i+1 \bmod n}\). +newtype PolygonPath = PolygonPath [Vertex] + +instance Show PolygonPath where + show (PolygonPath (v : vs)) = " " L " ++ show v) vs) ++ " Z\"/>\n" + show (PolygonPath []) = "" + +-- | 'regularPolygonMod' @n@ @rf@ @pos@ +-- creates a regular @n@-gon +-- with the center at @pos@ +-- that is modified in the sense that it takes @rf@, +-- which is used to set the radius for each individual point. +regularPolygonMod :: Integer -> (Integer -> Integer) -> Vertex -> PolygonPath +regularPolygonMod n rf pos = PolygonPath (map (\step -> move pos $ scale (rf step) $ fromAngle (fromInteger step * 2 * pi / fromInteger n)) [0 .. (n - 1)]) + +-- | 'regularPolygon' @n@ @r@ @pos@ +-- creates a regular polygon +-- with the radius @r@ +-- and the center at @pos@. +regularPolygon :: Integer -> Integer -> Vertex -> PolygonPath +regularPolygon n r = regularPolygonMod n (const r) + +-- | 'star' @n@ @r1@ @r2@ @pos@ +-- creates a star +-- with @n@ spikes, +-- the inner radius @r1@, +-- the outer radius @r2@ +-- and the center @pos@. +star :: Integer -> Integer -> Integer -> Vertex -> PolygonPath +star n r1 r2 = regularPolygonMod (n * 2) ((take (fromInteger n * 2) (cycle [r1, r2]) !!) . fromInteger) + +main :: IO () +main = putStr $ join $ map (\n -> show n ++ "-gon: " ++ show (regularPolygon n 100 (Point (100, 100)))) [5, 8, 10, 15, 18, 30] diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..979fcb9 --- /dev/null +++ b/shell.nix @@ -0,0 +1,11 @@ +{ pkgs ? import { } }: + +pkgs.mkShell { + name = "emi5"; + + nativeBuildInputs = with pkgs; [ + (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ + QuickCheck + ])) + ]; +}