0 | module Geom.Gen2D.Place
3 | import Geom.Gen2D.State
11 | classMap : {k : _} -> List (Fin k, Nat) -> IArray k Nat
13 | case sortBy (comparing snd) ps of
15 | (x,n)::ps => alloc k Z $
\m => set m x 1 >> go 1 n ps m
17 | go : Nat -> Nat -> List (Fin k, Nat) -> MArray s k Nat -> F1 s (IArray k Nat)
18 | go c p [] m t = unsafeFreeze m t
19 | go c p ((x,n) :: xs) m t =
20 | let c' := if n == p then c else S c
21 | _ # t := set m x c' t
25 | prioritize : {k : _} -> IGraph k e n -> IArray k Nat
26 | prioritize g = go (fill k 1) k
29 | compRank : IArray k Nat -> Fin k -> Nat
30 | compRank prev x = 3 * at prev x + sum (at prev <$> neighbours g x)
32 | go : IArray k Nat -> Nat -> IArray k Nat
35 | let rank := Indexed.generate k (compRank prev)
36 | cmap := classMap $
foldrKV (\x,v,xs => (x,v)::xs) [] rank
37 | in if prev == cmap then prev else go cmap n
40 | parameters {k : Nat}
41 | {auto dg : DebugFlag}
43 | {auto ce : Cast n Elem}
44 | {auto ch : Cast n Hybridization}
47 | isTerminalD4 : Fin k -> Bool
49 | let ns := neighbours g x
50 | in length ns == 4 && count ((> 1) . deg g) ns <= 1
52 | nextBondVector : Fin k -> MolVector -> (p,c : MolPoint) -> Bool -> MolVector
53 | nextBondVector x v p c trans =
54 | case cast @{ch} (lab g x) of
58 | va := rotate a (negate v)
59 | vb := rotate (negate a) (negate v)
60 | in if distance (translate va p) c >= distance (translate vb p) c
67 | if isTerminalD4 x then fromDegree 45
68 | else if isMetal (cast $
lab g x) then fullSteps (deg g x)
69 | else if trans then fromDegree 120 else fromDegree 60
79 | placeChain : PlaceST s k => Fin k -> List (Fin k) -> MolVector -> F1' s
80 | placeChain _ [] _ t = () # t
81 | placeChain p (n::ns) v t =
82 | let pp # t := nodePosition p t
83 | pn := translate v pp
84 | b # t := isPlaced n t
85 | _ # t := when1 (not b) (place n pn) t
86 | c # t := State.center {k} t
87 | in placeChain n ns (nextBondVector n v pn c True) t
91 | {auto st : PlaceST s k}
94 | -> (cur,step : Angle)
95 | -> (dir : MolVector)
97 | polygonCorners [] _ _ _ _ t = () # t
98 | polygonCorners (x :: xs) p cur step dir t =
99 | let theta := cur + step
100 | p2 := translate (rotate theta dir) p
101 | _ # t := debugIf1 "placing \{show x} at \{show p2}" t
102 | _ # t := place x p2 t
103 | in polygonCorners xs p theta step dir t
106 | distributeAtoms : PlaceST s k => Fin k -> (us,ps : List (Fin k)) -> F1' s
107 | distributeAtoms x [] _ t = () # t
108 | distributeAtoms x [u] [p] t =
109 | let px # t := nodePosition x t
110 | pp # t := nodePosition p t
111 | c # t := State.center {k} t
112 | in placeChain x [u] (nextBondVector x (px - pp) px c True) t
113 | distributeAtoms x us@(_::r) ps t =
114 | let px # t := nodePosition x t
115 | ps # t := traverse1 nodePosition ps t
116 | (start,step) := circularFreeSweep (S $
length r) px ps
117 | in polygonCorners us px start step (V BOND_LEN 0) t
120 | placeNeighbours : PlaceST s k => Fin k -> F1 s (List $
Fin k)
121 | placeNeighbours x t =
122 | let (us,ps) # t := partition1 isPlaced (neighbours g x) t
123 | _ # t := debugIf1 "placing neighbours for \{show x}" t
124 | _ # t := distributeAtoms x us ps t
133 | placeAtom : PlaceST s k => Fin k -> F1' s
135 | let False # t := isPlaced x t | _ # t => () # t
136 | in case filter1 isPlaced (neighbours g x) t of
137 | [] # t => place x (P 0 0) t
139 | let ps # t := filter1 isPlaced (neighbours g y) t
140 | in distributeAtoms y [x] ps t
141 | ys # t => let c # t := centerOf ys t in place x c t