Skip to content

Instantly share code, notes, and snippets.

@pbevin
Created April 28, 2017 22:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pbevin/64bf10d4190dcddaa1a92ac8cd38b610 to your computer and use it in GitHub Desktop.
Save pbevin/64bf10d4190dcddaa1a92ac8cd38b610 to your computer and use it in GitHub Desktop.
module Main exposing (..)
import Exts.Float exposing (roundTo)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (on)
import Json.Decode as Decode
import Mouse exposing (Position)
import Keyboard exposing (..)
import Char
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ origin : Mouse.Position
, mousePos : Maybe Mouse.Position
, l1 : Float
, l2 : Float
}
init : ( Model, Cmd Msg )
init =
( Model { x = 400, y = 400 } Nothing 200 200, Cmd.none )
-- UPDATE
type Msg
= TargetPos Mouse.Position
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
( updateHelp msg model, Cmd.none )
updateHelp : Msg -> Model -> Model
updateHelp msg model =
case msg of
TargetPos pos ->
{ model | mousePos = Just pos }
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Mouse.moves TargetPos
-- VIEW
(=>) =
(,)
view : Model -> Html Msg
view model =
case model.mousePos of
Nothing ->
div [] []
Just pos ->
viewWithTargetPos pos model
viewWithTargetPos : Mouse.Position -> Model -> Html Msg
viewWithTargetPos { x, y } model =
let
( x1, y1 ) =
( toFloat model.origin.x, toFloat model.origin.y )
( dx, dy ) =
( toFloat x - x1, toFloat y - y1 )
( angle1, angle2 ) =
calcAngles model.l1 model.l2 ( dx, dy )
( x2, y2 ) =
rotate ( x1, y1 ) angle1 model.l1
( x3, y3 ) =
rotate ( x2, y2 ) (angle1 + angle2) model.l2
isImpossible =
isNaN angle1
in
div
[ style
[ "background-color" => "#555"
, "color" => "#fff"
, "cursor" => "move"
, "width" => "800px"
, "height" => "800px"
, "border-radius" => "4px"
, "position" => "relative"
, "display" => "flex"
, "align-items" => "center"
, "justify-content" => "center"
]
]
[ pre
[ style
[ "position" => "absolute"
, "left" => "0"
, "top" => "0"
]
]
[ text <| "Elbow is at (" ++ showFloat x2 ++ ", " ++ showFloat y2 ++ ")\n"
, text <| "Hand is at (" ++ showFloat x3 ++ ", " ++ showFloat y3 ++ ")\n"
, text <| "Target (" ++ toString x ++ ", " ++ toString y ++ ") => (" ++ showFloat (angle1 * 180 / pi) ++ "°, " ++ showFloat (angle2 * 180 / pi) ++ "°) => (" ++ showFloat x3 ++ ", " ++ showFloat y3 ++ ")\n"
, text <|
if isImpossible then
"IMPOSSIBLE!\n"
else
"\n"
]
, div
[ style
[ "position" => "absolute"
-- , "left" => px x1
-- , "top" => px y1
, "left" => px x1
, "top" => px y1
, "width" => px model.l1
, "height" => "0px"
, "border-top" => "2px solid #3c8d2f"
, "border-bottom" => "2px solid #3c8d2f"
, "transform" => cssTransform [ cssRotate angle1 ]
, "transform-origin" => "0 50%"
]
]
[]
, div
[ style
[ "position" => "absolute"
, "left" => px x2
, "top" => px y2
, "width" => px model.l2
, "height" => "0px"
, "border-top" => "2px solid #2f6a8d"
, "border-bottom" => "2px solid #2f6a8d"
, "transform" => cssTransform [ cssRotate (angle1 + angle2) ]
, "transform-origin" => "0 50%"
]
]
[]
, div
[ style
[ "position" => "absolute"
, "left" => px (x3 - 10)
, "top" => px (y3 - 10)
, "width" => "20px"
, "height" => "20px"
, "border-radius" => "10px"
, "background-color" => "#8d2f2f"
, "transform" => cssTransform [ cssRotate (angle1 + angle2) ]
, "transform-origin" => "50% 50%"
]
]
[]
]
cssTransform : List String -> String
cssTransform =
String.join " " << List.reverse
cssTranslate : Float -> Float -> String
cssTranslate x y =
"translate(" ++ toString x ++ "px, " ++ toString y ++ "px)"
cssRotate : Float -> String
cssRotate angle =
"rotate(" ++ toString angle ++ "rad)"
px : Float -> String
px number =
toString number ++ "px"
type alias Pos =
( Float, Float )
type alias Angle =
Float
type alias Length =
Float
rotate : Pos -> Angle -> Length -> Pos
rotate ( x0, y0 ) angle len =
let
dx =
len * cos angle
dy =
len * sin angle
in
( x0 + dx, y0 + dy )
showFloat : Float -> String
showFloat =
toString << roundTo 2
calcAngles : Length -> Length -> Pos -> ( Angle, Angle )
calcAngles l1 l2 ( x, y ) =
let
aa =
sqrt (2 * l1 * l1 * x * x + 2 * l2 * l2 * x * x + 2 * l1 * l1 * y * y + 2 * l2 * l2 * y * y - l1 * l1 * l1 * l1 - l2 * l2 * l2 * l2 + 2 * l1 * l1 * l2 * l2 - x * x * x * x - 2 * x * x * y * y - y * y * y * y)
d1 =
2 * l1 * x + l1 * l1 - l2 * l2 + x * x + y * y
d2 =
2 * l2 * x - l1 * l1 + l2 * l2 + x * x + y * y
a =
2 * atan ((aa + 2 * l1 * y) / d1)
b =
2 * atan ((2 * l2 * y - aa) / d2)
in
( a, b - a )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment