We gaan een eigen ijskristal maken:
Zoek op het internet plaatjes van ijskristallen zodat je weet hoe deze er uit zien.
Start het elm programma ijskristal.elm. Je ziet het volgende:
In het vakje kun je invoeren hoeveel maal het ijskristal verdeeld moet worden. Voer 4 in. Je ziet het volgende:
Hoe gaan we een ijskrinstallen maken
In de cell hieronder staat het bestand myijskristallen.elm. Deze code staat in het view model daarvan.
path =
[ koch startP1 startP2 model.passes []
, koch startP2 startP3 model.passes []
, koch startP3 startP1 model.passes []
]
In deze regel worden de punten voor de tekening in een lijst gezet. Dit gebeurt door 3 lijnen te bepalen en deze verder te bewerken zoals je hier ziet:
Daarvoor wordt de functie koch aangeroepen met als parameters:
- Het startpunt van de lijn
- Het eindpunt van de lijn
- Het aantal stappen waarin de lijn bewerkt wordt
- De lijst van punten die tot en met deze stap bepaald zijn
In kock worden de drie nieuwe punten p1, p2 en p3 berekend om de lijn kunnen te tekenen.
Het begin en het eind punt heten binnen koch a en b. Het begin en eindpunt worden als parameters meegegeven.
Als het aantal stappen niet meer dan 1 is geeft de functie koch het volgende terug:
a :: p1 :: p2 :: p3 :: b :: points
Als het aantal stappen meer dan 1 is roept roep de functie koch zichzelf 4 keer aan met als te bewerken lijnen:
- De lijn tussen de punten a en p1
- De lijn tussen de puntern p1 en p2
- De lijn tussen de punten p2 en p3
- De lijn tussen de punten p3 en b
Bij deze aanroepen verlaagt koch het aantal stappen met 1. Alle resulterende lijsten van deze 4 aanroepen zet koch in een gezamenlijke lijst en geeft deze terug.
Opdracht
Maak je eigen ijskristal door de code van ijskristallen.elm in de volgende cell aan te passen.
import Html exposing (text, div, input, Attribute)
import Browser exposing (sandbox)
import Html.Events exposing (on, keyCode, onInput)
import Html.Attributes exposing(..)
import Json.Decode as Json
import String exposing(split)
import List exposing(..)
import Maybe exposing(..)
import Svg exposing (..)
import Svg.Attributes exposing (..)
type alias Point =
{ x : Float
, y : Float
}
koch : Point -> Point -> Int -> List Point -> List Point
koch a b limit points =
let
( dx, dy ) =
( b.x - a.x, b.y - a.y )
dist =
dx * dx + dy * dy |> sqrt
unit =
dist / 3
angle =
atan2 dy dx
p1 =
Point (a.x + dx / 3) (a.y + dy / 3)
p2 =
Point
(p1.x
+ (cos (angle - pi / 3))
* unit
)
(p1.y
+ (sin (angle - pi / 3))
* unit
)
p3 =
Point (b.x - dx / 3) (b.y - dy / 3)
in
if limit > 1 then
let
l =
limit - 1
in
List.concat
[ points
, koch a p1 l points
, koch p1 p2 l points
, koch p2 p3 l points
, koch p3 b l points
]
else
a :: p1 :: p2 :: p3 :: b :: points
startP1 : Point
startP1 =
Point 0 -150
startP2 : Point
startP2 =
Point 150 100
startP3 : Point
startP3 =
Point -150 100
pointsListToString: List Point -> String
pointsListToString l =
if List.isEmpty l then
""
else
let
h = withDefault (Point 0 0) (head (take 1 l))
in
(String.fromFloat h.x) ++ "," ++ (String.fromFloat h.y) ++ " " ++ (pointsListToString (drop 1 l))
main = Browser.sandbox { init = init, update = update, view = view }
type alias Model = { content : String }
init : Model
init = { content = "1" }
view model =
let
path =
pointsListToString (koch startP1 startP2 (Maybe.withDefault 1 (String.toInt model.content)) []) ++ pointsListToString (koch startP2 startP3 (Maybe.withDefault 1 (String.toInt model.content)) []) ++ pointsListToString (koch startP3 startP1 (Maybe.withDefault 1 (String.toInt model.content)) [])
in
div []
[ input [ placeholder "numbers separated by ,", value model.content, onInput Change ] []
, svg [ viewBox "0 0 200 200", Svg.Attributes.width "400px" ]
[ g [ transform "translate(100, 100) scale(0.5,-0.5)" ]
[
polyline [ fill "none", stroke "black", points path] []
]
]
]
type Msg
= Change String
update : Msg -> Model -> Model
update msg model =
case msg of
Change newContent ->
{ model | content = newContent }
-- compile-code