-- LML original: Sandra Foubister, 1990
-- Haskell translation: Colin Runciman, May 1991
module Auxprogfuns(
nearx,neary, deline, orient, display, cs,
wwscale, wscale, wline, showoris) where
import List ( (\\) ) -- 1.3
import Mgrfuns
import Diff
import Drawfuns
import Geomfuns
import Layout
import Rational
concmap3 :: (a -> b -> c -> [d]) -> [a] -> [b] -> [c] -> [d]
concmap3 f (x:xs) (y:ys) (z:zs) = f x y z ++ concmap3 f xs ys zs
concmap3 f _ _ _ = []
-- see the pic related definitions for where the numbers come from
--CR numeric literals here not acceptable - needs abstraction
display :: [(a, [[Int]])] -> [Char]
display slist = concmap3 place [624,624,624,624,724,724,724,724]
[676,776,876,976,676,776,876,976]
(map snd slist)
-- These codings are used for the eight pictures,
-- for the program state,
-- and for the postscript file
-- CR replaced multiclause defn by case
orient :: Int -> Int -> [[Int]] -> [[Int]]
orient m n = case n of
0 -> (\_ -> [[0,0,0,0]])
1 -> (\x -> x)
2 -> rotatecw m
3 -> rotatecw m . rotatecw m
4 -> antirotate m
5 -> tbinvert m
6 -> tbinvert m . rotatecw m
7 -> lrinvert m
8 -> lrinvert m . rotatecw m
pixdist :: Int
pixdist = 10
--CR removed old 'rmin2' definition - now use rmin from Rational module
between :: Int -> Int -> Int -> Bool
between n1 n2 n = (n1 <= n && n2 >= n) || (n1 >= n && n2 <= n)
--CR now uses Rational's rmin instead of old rmin2
--CR k1 redefined to avoid explicit use of norm
online :: [Int] -> Int -> Int -> Bool
online [x0,y0,x1,y1] xp yp =
if y0 == y1 then between x0 x1 xp && abs (y0 - yp) < pixdist
else if x0 == x1 then between y0 y1 yp && abs (x0 - xp) < pixdist
else b2 <= a2 + c2 && c2 <= a2 + b2 && intval (rmin dx dy) < pixdist
where
k1 = rdiv (torat (x0 - x1)) (torat (y0 - y1))
k0 = rsub (torat x0) (rmul k1 (torat y0))
xp' = radd k0 (rmul k1 (torat yp))
yp' = rdiv (rsub (torat xp) k0) k1
a2 = square (diff x0 x1) + square (diff y0 y1)
b2 = square (diff x1 xp) + square (diff y1 yp)
c2 = square (diff x0 xp) + square (diff y0 yp)
dx = rabs (rsub (torat xp) xp')
dy = rabs (rsub (torat yp) yp')
--CR renamed firstline as thisline, firstcircs as thesecircs
--CR note allowance for argument order bug using \\ instead of difference
deline :: [([Int],[Int])] -> [Int] -> ([Char], [([Int],[Int])])
deline ls [px,py] =
deline' ls
where
deline' [] = ("",ls)
deline' (pl:pls) =
if online thisline px py then
(undraw thisline ++ (undo . wline) thisline ++ decircs, remove1 ls pl)
else deline' pls
where
(thisline, thesecircs) = pl
restcircs = listremove1 (concat (map snd ls)) thesecircs
decircs = (concat . map decirc) (restcircs \\ thesecircs)
--CR remove1 xs y is xs with 1st occurrence (if any) of y removed
remove1 :: (Eq a) => [a] -> a -> [a]
remove1 (l:ls) i = if i==l then ls else l : remove1 ls i
remove1 [] i = []
--CR replaced explicit recursion with foldl application
listremove1 :: (Eq a) => [a] -> [a] -> [a]
listremove1 = foldl remove1
-- functions to do with the drawing of lines and marking of circles
-- in the design phase
-- as the x and y lists for the design area are the same, the function
-- onedge can be defined without specifying onedgex and onedgey
onedge :: Int -> Bool
onedge n = n == dpxyorig || n == dpxyorig + (dpxynum -1) * dpxygap
-- similarly the method of finding the nearest x or y points
-- on the grid are equivalent
nearest :: Int -> Int
nearest n = if n - n1 < n2 - n then n1 else n2
where
n1 = dpxyorig + ((n - dpxyorig) `div` dpxygap) * dpxygap
n2 = n1 + dpxygap
-- but the cursor is not symmetrical in its deficiencies, so we have:
nearx, neary :: Int -> Int
nearx x = nearest (x - 4)
neary y = nearest (y - 5)
-- numassoc is to give points on the edge an associated number
numassoc :: Int -> Int
numassoc n = if n1 <= 9 then n1 else 18 - n1
where
n1 = (n - dpxyorig) `div` dpxygap
-- circ6 for drawing the little circles
circ6 :: Int -> Int -> [Char]
circ6 x y = circle [x,y,6]
-- circsym for identifying symmetrically placed dots and
-- drawing circles round them. It assumes that the x and y
-- have been adjusted to allow for the dicky cursor.
circsym :: Int -> Int -> ([Char], [Int])
circsym xn yn = if onedge xn then (symcircs yn,[numassoc yn])
else if onedge yn then (symcircs xn,[numassoc xn])
else ("",[])
--CR explanation of numeric literals?
sympat :: Int -> [Int]
sympat n = [n, 400-n, 380, 380, 400-n, n, 20, 20]
symcircs :: Int -> [Char]
symcircs n = concat (zipWith circ6 (sympat n) (reverse (sympat n)))
-- assumes the coordinates have already been corrected to allow
-- for the deficiencies of the cursor, and to fit into the grid
cs :: [Int] -> ([Char], [Int])
cs [x0,y0,x1,y1] =
(line [x0,y0,x1,y1] ++ circles0 ++ circles1, ids0++ids1)
where
(circles0,ids0) = circsym x0 y0
(circles1,ids1) = circsym x1 y1
decirc :: Int -> [Char]
decirc n = (undo . symcircs) (n * dpxygap + dpxyorig)
-- wscale for the lines in the wee square
wscale :: Int -> Int
wscale n = (n - dpxyorig) `div` 5
-- wwscale for the lines in postscript
wwscale :: Int -> Int
wwscale n = (n - dpxyorig) `div` 10
wline :: [Int] -> [Char]
wline = line .
mapx (\x -> x + picxorig) .
mapy (\y -> y + picyorig) .
map wscale
showoris :: [[Int]] -> Int -> [Char]
showoris coords n = place x y (((orient xymax) n . map (map wscale)) coords)
where
[x,y,w,h] = picbox n
|