(() => { 'use strict'; // INTERSECTION OF TWO LINES ---------------------------------------------- // intersection :: Line -> Line -> Either String (Float, Float) const intersection = (ab, pq) => { const delta = f => x => f(fst(x)) - f(snd(x)), [abDX, pqDX, abDY, pqDY] = apList( [delta(fst), delta(snd)], [ab, pq] ), determinant = abDX * pqDY - abDY * pqDX; return determinant !== 0 ? Right((() => { const [abD, pqD] = map( ([a, b]) => fst(a) * snd(b) - fst(b) * snd(a), [ab, pq] ); return apList( [([pq, ab]) => (abD * pq - ab * pqD) / determinant ], [ [pqDX, abDX], [pqDY, abDY] ] ); })()) : Left('(Parallel lines – no intersection)'); }; // GENERIC FUNCTIONS ------------------------------------------------------ // Left :: a -> Either a b const Left = x => ({ type: 'Either', Left: x }); // Right :: b -> Either a b const Right = x => ({ type: 'Either', Right: x }); // A list of functions applied to a list of arguments // <*> :: [(a -> b)] -> [a] -> [b] const apList = (fs, xs) => // [].concat.apply([], fs.map(f => // [].concat.apply([], xs.map(x => [f(x)])))); // fst :: (a, b) -> a const fst = tpl => tpl[0]; // map :: (a -> b) -> [a] -> [b] const map = (f, xs) => xs.map(f); // snd :: (a, b) -> b const snd = tpl => tpl[1]; // show :: a -> String const show = x => JSON.stringify(x); //, null, 2); // TEST -------------------------------------------------- // lrIntersection ::Either String Point const lrIntersection = intersection([ [4.0, 0.0], [6.0, 10.0] ], [ [0.0, 3.0], [10.0, 7.0] ]); return show(lrIntersection.Left || lrIntersection.Right); })();