mirror of
https://github.com/reanimate/reanimate.git
synced 2026-09-14 09:32:22 +00:00
153 lines
16 KiB
HTML
153 lines
16 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<style type="text/css">
|
|
span.lineno { color: white; background: #aaaaaa; border-right: solid white 12px }
|
|
span.nottickedoff { background: yellow}
|
|
span.istickedoff { background: white }
|
|
span.tickonlyfalse { margin: -1px; border: 1px solid #f20913; background: #f20913 }
|
|
span.tickonlytrue { margin: -1px; border: 1px solid #60de51; background: #60de51 }
|
|
span.funcount { font-size: small; color: orange; z-index: 2; position: absolute; right: 20 }
|
|
span.decl { font-weight: bold }
|
|
span.spaces { background: white }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<pre>
|
|
<span class="decl"><span class="nottickedoff">never executed</span> <span class="tickonlytrue">always true</span> <span class="tickonlyfalse">always false</span></span>
|
|
</pre>
|
|
<pre>
|
|
<span class="lineno"> 1 </span>{-|
|
|
<span class="lineno"> 2 </span> Bounding-boxes can be immensely useful for aligning objects
|
|
<span class="lineno"> 3 </span> but they are not part of the SVG specification and cannot be
|
|
<span class="lineno"> 4 </span> computed for all SVG nodes. In particular, you'll get bad results
|
|
<span class="lineno"> 5 </span> when asking for the bounding boxes of Text nodes (because fonts
|
|
<span class="lineno"> 6 </span> are difficult), clipped nodes, and filtered nodes.
|
|
<span class="lineno"> 7 </span>-}
|
|
<span class="lineno"> 8 </span>module Reanimate.Svg.BoundingBox
|
|
<span class="lineno"> 9 </span> ( boundingBox
|
|
<span class="lineno"> 10 </span> , svgHeight
|
|
<span class="lineno"> 11 </span> , svgWidth
|
|
<span class="lineno"> 12 </span> ) where
|
|
<span class="lineno"> 13 </span>
|
|
<span class="lineno"> 14 </span>import Control.Arrow ((***))
|
|
<span class="lineno"> 15 </span>import Control.Lens ((^.))
|
|
<span class="lineno"> 16 </span>import Data.List
|
|
<span class="lineno"> 17 </span>import Data.Maybe (mapMaybe)
|
|
<span class="lineno"> 18 </span>import qualified Data.Vector.Unboxed as V
|
|
<span class="lineno"> 19 </span>import qualified Geom2D.CubicBezier.Linear as Bezier
|
|
<span class="lineno"> 20 </span>import Graphics.SvgTree hiding (height, line, path, use, width)
|
|
<span class="lineno"> 21 </span>import Linear.V2 hiding (angle)
|
|
<span class="lineno"> 22 </span>import Linear.Vector
|
|
<span class="lineno"> 23 </span>import Reanimate.Constants
|
|
<span class="lineno"> 24 </span>import Reanimate.Svg.LineCommand
|
|
<span class="lineno"> 25 </span>import qualified Reanimate.Transform as Transform
|
|
<span class="lineno"> 26 </span>
|
|
<span class="lineno"> 27 </span>-- | Return bounding box of SVG tree.
|
|
<span class="lineno"> 28 </span>-- The four numbers returned are (minimal X-coordinate, minimal Y-coordinate, width, height)
|
|
<span class="lineno"> 29 </span>--
|
|
<span class="lineno"> 30 </span>-- Note: Bounding boxes are computed on a best-effort basis and will not work
|
|
<span class="lineno"> 31 </span>-- in all cases. The only supported SVG nodes are: path, circle, polyline,
|
|
<span class="lineno"> 32 </span>-- ellipse, line, rectangle, image. All other nodes return (0,0,0,0).
|
|
<span class="lineno"> 33 </span>boundingBox :: Tree -> (Double, Double, Double, Double)
|
|
<span class="lineno"> 34 </span><span class="decl"><span class="istickedoff">boundingBox t =</span>
|
|
<span class="lineno"> 35 </span><span class="spaces"> </span><span class="istickedoff">case svgBoundingPoints t of</span>
|
|
<span class="lineno"> 36 </span><span class="spaces"> </span><span class="istickedoff">[] -> (0,0,0,0)</span>
|
|
<span class="lineno"> 37 </span><span class="spaces"> </span><span class="istickedoff">(V2 x y:rest) -></span>
|
|
<span class="lineno"> 38 </span><span class="spaces"> </span><span class="istickedoff">let (minx, miny, maxx, maxy) = foldl' worker (x, y, x, y) rest</span>
|
|
<span class="lineno"> 39 </span><span class="spaces"> </span><span class="istickedoff">in (minx, miny, maxx-minx, maxy-miny)</span>
|
|
<span class="lineno"> 40 </span><span class="spaces"> </span><span class="istickedoff">where</span>
|
|
<span class="lineno"> 41 </span><span class="spaces"> </span><span class="istickedoff">worker (minx, miny, maxx, maxy) (V2 x y) =</span>
|
|
<span class="lineno"> 42 </span><span class="spaces"> </span><span class="istickedoff">(min minx x, min miny y, max maxx x, max maxy y)</span></span>
|
|
<span class="lineno"> 43 </span>
|
|
<span class="lineno"> 44 </span>-- | Height of SVG node in local units (not pixels). Computed on best-effort basis
|
|
<span class="lineno"> 45 </span>-- and will not give accurate results for all SVG nodes.
|
|
<span class="lineno"> 46 </span>svgHeight :: Tree -> Double
|
|
<span class="lineno"> 47 </span><span class="decl"><span class="nottickedoff">svgHeight t = h</span>
|
|
<span class="lineno"> 48 </span><span class="spaces"> </span><span class="nottickedoff">where</span>
|
|
<span class="lineno"> 49 </span><span class="spaces"> </span><span class="nottickedoff">(_x, _y, _w, h) = boundingBox t</span></span>
|
|
<span class="lineno"> 50 </span>
|
|
<span class="lineno"> 51 </span>-- | Width of SVG node in local units (not pixels). Computed on best-effort basis
|
|
<span class="lineno"> 52 </span>-- and will not give accurate results for all SVG nodes.
|
|
<span class="lineno"> 53 </span>svgWidth :: Tree -> Double
|
|
<span class="lineno"> 54 </span><span class="decl"><span class="nottickedoff">svgWidth t = w</span>
|
|
<span class="lineno"> 55 </span><span class="spaces"> </span><span class="nottickedoff">where</span>
|
|
<span class="lineno"> 56 </span><span class="spaces"> </span><span class="nottickedoff">(_x, _y, w, _h) = boundingBox t</span></span>
|
|
<span class="lineno"> 57 </span>
|
|
<span class="lineno"> 58 </span>-- | Sampling of points in a line path.
|
|
<span class="lineno"> 59 </span>linePoints :: [LineCommand] -> [RPoint]
|
|
<span class="lineno"> 60 </span><span class="decl"><span class="nottickedoff">linePoints = worker zero</span>
|
|
<span class="lineno"> 61 </span><span class="spaces"> </span><span class="nottickedoff">where</span>
|
|
<span class="lineno"> 62 </span><span class="spaces"> </span><span class="nottickedoff">worker _from [] = []</span>
|
|
<span class="lineno"> 63 </span><span class="spaces"> </span><span class="nottickedoff">worker from (x:xs) =</span>
|
|
<span class="lineno"> 64 </span><span class="spaces"> </span><span class="nottickedoff">case x of</span>
|
|
<span class="lineno"> 65 </span><span class="spaces"> </span><span class="nottickedoff">LineMove to -> worker to xs</span>
|
|
<span class="lineno"> 66 </span><span class="spaces"> </span><span class="nottickedoff">-- LineDraw to -> from:to:worker to xs</span>
|
|
<span class="lineno"> 67 </span><span class="spaces"> </span><span class="nottickedoff">LineBezier [p] -></span>
|
|
<span class="lineno"> 68 </span><span class="spaces"> </span><span class="nottickedoff">p : worker p xs</span>
|
|
<span class="lineno"> 69 </span><span class="spaces"> </span><span class="nottickedoff">LineBezier ctrl -> -- approximation</span>
|
|
<span class="lineno"> 70 </span><span class="spaces"> </span><span class="nottickedoff">let bezier = Bezier.AnyBezier (V.fromList (from:ctrl))</span>
|
|
<span class="lineno"> 71 </span><span class="spaces"> </span><span class="nottickedoff">in [ Bezier.evalBezier bezier (recip chunks*i) | i <- [0..chunks]] ++</span>
|
|
<span class="lineno"> 72 </span><span class="spaces"> </span><span class="nottickedoff">worker (last ctrl) xs</span>
|
|
<span class="lineno"> 73 </span><span class="spaces"> </span><span class="nottickedoff">LineEnd p -> p : worker p xs</span>
|
|
<span class="lineno"> 74 </span><span class="spaces"> </span><span class="nottickedoff">chunks = 10</span></span>
|
|
<span class="lineno"> 75 </span>
|
|
<span class="lineno"> 76 </span>svgBoundingPoints :: Tree -> [RPoint]
|
|
<span class="lineno"> 77 </span><span class="decl"><span class="istickedoff">svgBoundingPoints t = map (Transform.transformPoint m) $</span>
|
|
<span class="lineno"> 78 </span><span class="spaces"> </span><span class="istickedoff">case t of</span>
|
|
<span class="lineno"> 79 </span><span class="spaces"> </span><span class="istickedoff">None -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 80 </span><span class="spaces"> </span><span class="istickedoff">UseTree{} -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 81 </span><span class="spaces"> </span><span class="istickedoff">GroupTree g -> concatMap svgBoundingPoints (g^.groupChildren)</span>
|
|
<span class="lineno"> 82 </span><span class="spaces"> </span><span class="istickedoff">SymbolTree (Symbol g) -> <span class="nottickedoff">concatMap svgBoundingPoints (g^.groupChildren)</span></span>
|
|
<span class="lineno"> 83 </span><span class="spaces"> </span><span class="istickedoff">FilterTree{} -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 84 </span><span class="spaces"> </span><span class="istickedoff">DefinitionTree{} -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 85 </span><span class="spaces"> </span><span class="istickedoff">PathTree p -> <span class="nottickedoff">linePoints $ toLineCommands (p^.pathDefinition)</span></span>
|
|
<span class="lineno"> 86 </span><span class="spaces"> </span><span class="istickedoff">CircleTree c -> <span class="nottickedoff">circleBoundingPoints c</span></span>
|
|
<span class="lineno"> 87 </span><span class="spaces"> </span><span class="istickedoff">PolyLineTree pl -> <span class="nottickedoff">pl ^. polyLinePoints</span></span>
|
|
<span class="lineno"> 88 </span><span class="spaces"> </span><span class="istickedoff">EllipseTree e -> <span class="nottickedoff">ellipseBoundingPoints e</span></span>
|
|
<span class="lineno"> 89 </span><span class="spaces"> </span><span class="istickedoff">LineTree line -> <span class="nottickedoff">map pointToRPoint [line^.linePoint1, line^.linePoint2]</span></span>
|
|
<span class="lineno"> 90 </span><span class="spaces"> </span><span class="istickedoff">RectangleTree rect -></span>
|
|
<span class="lineno"> 91 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">case pointToRPoint (rect^.rectUpperLeftCorner) of</span></span>
|
|
<span class="lineno"> 92 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">V2 x y -> V2 x y :</span></span>
|
|
<span class="lineno"> 93 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">case mapTuple (fmap $ toUserUnit defaultDPI) (rect^.rectWidth, rect^.rectHeight) of</span></span>
|
|
<span class="lineno"> 94 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">(Just (Num w), Just (Num h)) -> [V2 (x+w) (y+h)]</span></span>
|
|
<span class="lineno"> 95 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">_ -> []</span></span>
|
|
<span class="lineno"> 96 </span><span class="spaces"> </span><span class="istickedoff">TextTree{} -> []</span>
|
|
<span class="lineno"> 97 </span><span class="spaces"> </span><span class="istickedoff">ImageTree img -></span>
|
|
<span class="lineno"> 98 </span><span class="spaces"> </span><span class="istickedoff">case (img^.imageCornerUpperLeft, img^.imageWidth, img^.imageHeight) of</span>
|
|
<span class="lineno"> 99 </span><span class="spaces"> </span><span class="istickedoff">((Num x, Num y), Num w, Num h) -></span>
|
|
<span class="lineno"> 100 </span><span class="spaces"> </span><span class="istickedoff">[V2 x y, V2 (x+w) (y+h)]</span>
|
|
<span class="lineno"> 101 </span><span class="spaces"> </span><span class="istickedoff">_ -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 102 </span><span class="spaces"> </span><span class="istickedoff">MeshGradientTree{} -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 103 </span><span class="spaces"> </span><span class="istickedoff">_ -> <span class="nottickedoff">[]</span></span>
|
|
<span class="lineno"> 104 </span><span class="spaces"> </span><span class="istickedoff">where</span>
|
|
<span class="lineno"> 105 </span><span class="spaces"> </span><span class="istickedoff">m = Transform.mkMatrix (t^.transform)</span>
|
|
<span class="lineno"> 106 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">mapTuple f = f *** f</span></span>
|
|
<span class="lineno"> 107 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">pointToRPoint p =</span></span>
|
|
<span class="lineno"> 108 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">case mapTuple (toUserUnit defaultDPI) p of</span></span>
|
|
<span class="lineno"> 109 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">(Num x, Num y) -> V2 x y</span></span>
|
|
<span class="lineno"> 110 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">_ -> error "Reanimate.Svg.svgBoundingPoints: Unrecognized number format."</span></span>
|
|
<span class="lineno"> 111 </span><span class="spaces"></span><span class="istickedoff"></span>
|
|
<span class="lineno"> 112 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">circleBoundingPoints circ =</span></span>
|
|
<span class="lineno"> 113 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">let (xnum, ynum) = circ ^. circleCenter</span></span>
|
|
<span class="lineno"> 114 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">rnum = circ ^. circleRadius</span></span>
|
|
<span class="lineno"> 115 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">in case mapMaybe unpackNumber [xnum, ynum, rnum] of</span></span>
|
|
<span class="lineno"> 116 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">[x, y, r] -> [ V2 (x + r * cos angle) (y + r * sin angle) | angle <- [0, pi/10 .. 2 * pi]]</span></span>
|
|
<span class="lineno"> 117 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">_ -> []</span></span>
|
|
<span class="lineno"> 118 </span><span class="spaces"></span><span class="istickedoff"></span>
|
|
<span class="lineno"> 119 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">ellipseBoundingPoints e =</span></span>
|
|
<span class="lineno"> 120 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">let (xnum,ynum) = e ^. ellipseCenter</span></span>
|
|
<span class="lineno"> 121 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">xrnum = e ^. ellipseXRadius</span></span>
|
|
<span class="lineno"> 122 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">yrnum = e ^. ellipseYRadius</span></span>
|
|
<span class="lineno"> 123 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">in case mapMaybe unpackNumber [xnum, ynum, xrnum, yrnum] of</span></span>
|
|
<span class="lineno"> 124 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">[x,y,xr,yr] -> [V2 (x + xr * cos angle) (y + yr * sin angle) | angle <- [0, pi/10 .. 2 * pi]]</span></span>
|
|
<span class="lineno"> 125 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">_ -> []</span></span>
|
|
<span class="lineno"> 126 </span><span class="spaces"></span><span class="istickedoff"></span>
|
|
<span class="lineno"> 127 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">unpackNumber n =</span></span>
|
|
<span class="lineno"> 128 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">case toUserUnit defaultDPI n of</span></span>
|
|
<span class="lineno"> 129 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">Num d -> Just d</span></span>
|
|
<span class="lineno"> 130 </span><span class="spaces"> </span><span class="istickedoff"><span class="nottickedoff">_ -> Nothing</span></span></span>
|
|
|
|
</pre>
|
|
</body>
|
|
</html>
|