Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error handling #6

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
elm-stuff
31 changes: 21 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ It is quite efficient, usually converging within one or two iterations.
```elm
import Collision exposing (..)

-- this is what polySupport looked like in 0.14 code
-- Example polySupport function
dot : Pt -> Pt -> Float
dot (x1,y1) (x2,y2) = (x1*x2) + (y1*y2)

polySupport : List Pt -> Pt -> Pt
polySupport : List Pt -> Pt -> Maybe Pt
polySupport list d =
let
dotList = List.map (dot d) list
decorated = (List.map2 (,)) dotList list
(m, p) = List.maximum decorated -- maximum now returns a Maybe b
max = List.maximum decorated
in
p
case max of
Just (m, p) -> Just p
_ -> Nothing

poly1 = [(-15,-10),(0,15),(12,-5)]
poly2 = [(-9,13),(6,13),(-2,22)]
collision 10 (poly1, polySupport) (poly2, polySupport) == True
collision 10 (poly1, polySupport) (poly2, polySupport) == Just True
````
**Note:** the first parameter to collision is max recursion depth. It can easily be elided by defining an auxiliary helper
like `myCollision = collision 100`. Control over recursion depth can be useful when defining your own support
Expand All @@ -32,18 +34,18 @@ functions.

```elm
type alias Pt = (Float, Float)
type alias Mink a = (a, a -> Pt -> Pt)
type alias Mink a = (a, (a -> Pt -> Maybe Pt))

collision : Int -> Mink a -> Mink b -> Bool
collision : Int -> Mink a -> Mink b -> Maybe Bool
```
**Note:** a `Mink b` is a pair of: a boundary object of type `b`, and a suppport function of type
`f: b -> Pt -> Pt` which given a boundary object, and a direction vector (given by a Pt), produces
`f: b -> Pt -> Maybe Pt` which given a boundary object, and a direction vector (given by a Pt), produces
a point on the boundary furthest in the direction of the vector.

**example**
```elm
polySupport [(-15,-10),(0,15),(12,5)] (1,0) == (12,5)
polySupport [(-15,-10),(0,15),(12,5)] (0,-1) == (-15,10)
polySupport [(-15,-10),(0,15),(12,5)] (1,0) == Just (12,5)
polySupport [(-15,-10),(0,15),(12,5)] (0,-1) == Just (-15,10)
```

You can define your own boundary objects and corresponding support functions, perhaps to handle
Expand All @@ -54,3 +56,12 @@ library to prescribe a boundary representation (for circles, or any OTHER object

Determining if a point is inside an object is just a special case of this: (pt, (\a b -> a)) : Mink Pt is a
perfectly valid Minkowski object.

## Credits

* [Michael Bakkemo](https://github.com/bakkemo)
* [Firas Zaidan](https://github.com/zaidan)

## License

See `LICENSE` file.
64 changes: 44 additions & 20 deletions src/Collision.elm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type alias Pt = (Float, Float)

{-| Simple alias for boundary objects bundled with a support function
-}
type alias Mink a = (a, (a -> Pt -> Pt))
type alias Mink a = (a, (a -> Pt -> Maybe Pt))


{-
Expand Down Expand Up @@ -75,16 +75,17 @@ isSameDirection a b = (dot a b) > 0

{-
- calculate the support of the Minkowski difference
- of two Mink's
- of two Mink's
-}
calcMinkSupport : Mink a -> Mink b -> (Float, Float) -> (Float,Float)
calcMinkSupport : Mink a -> Mink b -> (Float, Float) -> Maybe (Float, Float)
calcMinkSupport (objA, suppA) (objB, suppB) d =
let
p1 = suppA objA (neg d)
p2 = suppB objB d
maybep1 = suppA objA (neg d)
maybep2 = suppB objB d
in
sub p1 p2

case (maybep1, maybep2) of
(Just p1, Just p2) -> Just (sub p1 p2)
_ -> Nothing

-- pass bc as first parameter
getDirectionVector : Pt -> Pt -> Pt
Expand Down Expand Up @@ -121,24 +122,35 @@ the case where you are writing your own support functions.
poly1 = [(-15,-10),(0,15),(12,-5)]
poly2 = [(-9,13),(6,13),(-2,22)]

collision 10 (poly1, polySupport) (poly2, polySupport) == True
collision 10 (poly1, polySupport) (poly2, polySupport) == Just True
-}
collision : Int -> Mink a -> Mink b -> Bool
collision : Int -> Mink a -> Mink b -> Maybe Bool
collision limit minkA minkB =
let
d1 = (1.0, 0.0)
d2 = neg d1
c = calcMinkSupport minkA minkB d1
b = calcMinkSupport minkA minkB d2
maybec = calcMinkSupport minkA minkB d1
maybeb = calcMinkSupport minkA minkB d2
in
case (maybec, maybeb) of
(Just c, Just b) -> collision2 limit minkA minkB c b
_ -> Nothing

{-
- Prepares the input for doSimplex and starts the calculation.
-}
collision2 : Int -> Mink a -> Mink b -> (Float, Float) -> (Float, Float) -> Maybe Bool
collision2 limit minkA minkB c b =
let
-- simplex is cb and direction is (cb x c0 x cb)
cb = from c b
c0 = neg c
d = getDirectionVector cb c0
(intersects, (sim, newD)) = doSimplex limit 0 minkA minkB ([b,c], d)
simplexResult = doSimplex limit 0 minkA minkB ([b,c], d)
in
intersects


case simplexResult of
Just (intersects, _) -> Just intersects
_ -> Nothing

{-
- The algorithm proceeds by continually trying to surround the origin with a 2-simplex
Expand All @@ -154,20 +166,32 @@ collision limit minkA minkB =
- to speak) a is obtained by finding the direction of the origin from the currently
- building simplex, and finding the extremal point on the boundry in that direction.
-}
doSimplex : Int -> Int -> Mink a -> Mink b -> (List Pt, Pt) -> (Bool, (List Pt, Pt))
doSimplex : Int -> Int -> Mink a -> Mink b -> (List Pt, Pt) -> Maybe (Bool, (List Pt, Pt))
doSimplex limit depth minkA minkB (sim, d) =
let
a = (calcMinkSupport minkA minkB d)
maybea = (calcMinkSupport minkA minkB d)
in
case maybea of
Just a -> doSimplex2 limit depth minkA minkB (sim, d) a
_ -> Nothing

{-
- Actual doSimplex calculation. doSimplex handles the error case of calcMinkSupport and
- feeds a real a to doSimplex2.
-}
doSimplex2 : Int -> Int -> Mink a -> Mink b -> (List Pt, Pt) -> (Float, Float) -> Maybe (Bool, (List Pt, Pt))
doSimplex2 limit depth minkA minkB (sim, d) a =
let
notPastOrig = ((dot a d) < 0) -- if not past origin, there is no intersection
--b = unsafeHead sim
(intersects, (newSim, newDir)) = enclosesOrigin a sim
in
if notPastOrig then
(False, ([], (toFloat depth,toFloat depth)))
Just (False, ([], (toFloat depth,toFloat depth)))
else if intersects then
(True, (sim, a))
Just (True, (sim, a))
else if (depth > limit) then
(False, (newSim, newDir))
Just (False, (newSim, newDir))
else
doSimplex limit (depth+1) minkA minkB (newSim, newDir)

Expand Down