0 | module CyBy.Draw.Internal.Wedge
 1 |
 2 | import Geom
 3 | import CyBy.Draw.Internal.CoreDims
 4 | import CyBy.Draw.Internal.Label
 5 | import Text.Molfile
 6 | import Text.SVG
 7 |
 8 | %default total
 9 | %hide Geom.Scale.(/)
10 |
11 | --------------------------------------------------------------------------------
12 | -- Util
13 | --------------------------------------------------------------------------------
14 |
15 | lineT : Point Id -> Point Id -> Maybe AffineTransformation
16 | lineT s e = (\phi => AT (rotation phi) (s - origin)) <$> angle (e - s)
17 |
18 | %inline
19 | transform : (t : AffineTransformation) -> Point Id -> Point t
20 | transform t = convert
21 |
22 | --------------------------------------------------------------------------------
23 | -- Wedges
24 | --------------------------------------------------------------------------------
25 |
26 | parameters {auto cd : CoreDims}
27 |
28 |   -- gap : initial gap (half the remaining distance)
29 |   -- bw  : total bar width (stroke plus gap)
30 |   -- tot : total number of bars
31 |   -- x   : index of current bar
32 |   downCmds : (gap,bw,tot : Double) -> AffineTransformation -> Double -> List PathCmd
33 |   downCmds gap bw tot t x =
34 |     let dw      := cd.wedgeWideEnd - cd.wedgeNarrowEnd
35 |         l       := cd.wedgeNarrowEnd + x * dw / tot -- current bar length
36 |         px      := x * bw + gap
37 |         P x1 y1 := transform t $ P px (l/2.0)
38 |         P x2 y2 := transform t $ P px (l/(-2.0))
39 |      in [M x1 y1, L x2 y2]
40 |
41 |   ||| Generates evenly distributed bars for a downward wedge
42 |   ||| beween the two points.
43 |   |||
44 |   ||| This is a sequence of lines in an SVG `<path>`.
45 |   export
46 |   wedgeDown : (start, end : Point Id) -> List PathCmd
47 |   wedgeDown s e =
48 |     let Just t   := lineT s e | Nothing => []
49 |         len      := distance s e -- distance between points
50 |         bw       := cd.downWedgeGap + cd.bondWidth -- total bar width
51 |         True     := len >= cd.bondWidth | False => []
52 |         tot      := floor $ (len - cd.bondWidth) / bw
53 |         gap      := (len - tot * bw) / 2.0
54 |      in [0..cast tot] >>= downCmds gap bw (1.0 + tot) t . cast
55 |
56 |   ||| Generates a wedged bond as a polygon.
57 |   export
58 |   wedgeUp : (s,e : Point Id) -> List (SVGAttribute "polygon") -> SVGNode
59 |   wedgeUp s e as =
60 |     let Just t := lineT s e | Nothing => Empty
61 |         len    := distance s e
62 |         P a b  := transform t $ P 0 (cd.wedgeNarrowEnd / 2.0)
63 |         P c d  := transform t $ P 0 (cd.wedgeNarrowEnd / (-2.0))
64 |         P e f  := transform t $ P len (cd.wedgeWideEnd / (-2.0))
65 |         P g h  := transform t $ P len (cd.wedgeWideEnd / 2.0)
66 |      in polygon (points [a,b,c,d,e,f,g,h] :: as)
67 |
68 | --------------------------------------------------------------------------------
69 | -- Waved (zigzag) Bond
70 | --------------------------------------------------------------------------------
71 |
72 |   waves :
73 |        SnocList PathCmd
74 |     -> (gap : Double)
75 |     -> (pos : Bool)
76 |     -> AffineTransformation
77 |     -> List Nat
78 |     -> List PathCmd
79 |   waves sp gap pos t (a::tl) =
80 |     let P xa ya := transform t $ P (gap + cast a * cd.halfWaveLength) 0
81 |         cmd     := A cd.waveAmplitude cd.waveAmplitude 0 False pos xa ya
82 |      in waves (sp :< cmd) gap (not pos) t tl
83 |   waves sp _ _ _ [] = sp <>> []
84 |
85 |   ||| Computes a "wavy" bond as a sequence of arcs on an SVG `<path>`.
86 |   export
87 |   wave : (start,end : Point Id) -> List PathCmd
88 |   wave s e =
89 |     let Just t := lineT s e | Nothing => []
90 |         len    := distance s e
91 |         True   := len >= cd.halfWaveLength | False => []
92 |         tot    := floor (len / cd.halfWaveLength)
93 |         gap    := len - tot * cd.halfWaveLength
94 |         P x y  := transform t $ P gap 0 
95 |      in waves [<M x y] gap True t [1..cast tot]
96 |