packages feed

diagrams-lib 1.2.0.9 → 1.5.1

raw patch · 156 files changed

Files

+ CHANGELOG.md view
@@ -0,0 +1,1837 @@+## [v1.5.1](https://github.com/diagrams/diagrams-lib/tree/v1.5.1) (2025-12-02)++- New `Semigroup` instance for located lines (i.e. `Located (Trail'+  Line v n)`), which adds an extra segment from the end of the first+  to the start of the second.++## [v1.5.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.5.0.1) (2025-08-25)++- Fix bug in `bezierFindRoot` that caused diagrams to hang when+  computing the trace of certain degenerate Bezier curves.  See+  https://github.com/diagrams/diagrams-contrib/issues/91 .++## [v1.5-r2](https://github.com/diagrams/diagrams-lib/tree/v1.5-r2) (2025-06-12)++- Allow `optparse-applicative-0.19`++## [v1.5-r1](https://github.com/diagrams/diagrams-lib/tree/v1.5-r1) (2025-05-17)++- Allow `monoid-extras-0.7`++## [v1.5](https://github.com/diagrams/diagrams-lib/tree/v1.5) (2025-02-13)++- Allow `base-4.21` and test on GHC 9.12+- Remove looped compilation mode options ([#372](https://github.com/diagrams/diagrams-lib/pull/372))+    - This allows us to remove the `fsnotify` dependency, which in+      turn allows compiling diagrams to Wasm.+    - To recover similar functionality (automatically recompiling+      every time a source file changes), try an external tool like+      `ghcid` or `ghciwatch`, or, more generically, `entr`.++## [v1.4.7](https://github.com/diagrams/diagrams-lib/tree/v1.4.7) (2024-10-26)++- Switch to `data-default-0.8` instead of `data-default-class`++## [v1.4.6.2-r3](https://github.com/diagrams/diagrams-lib/tree/v1.4.6.2-r3) (2024-08-23)++- Allow `hashable-1.5`++## [v1.4.6.2-r2](https://github.com/diagrams/diagrams-lib/tree/v1.4.6.2-r2) (2024-07-01)++- Allow `tasty-quickcheck-0.11`++## [v1.4.6.2-r1](https://github.com/diagrams/diagrams-lib/tree/v1.4.6.2-r1) (2024-05-01)++- Allow `base-4.21` (GHC 9.10), `containers-0.7`, `lens-5.3`, and `filepath-1.5`++## [v1.4.6.2](https://github.com/diagrams/diagrams-lib/tree/v1.4.6.2) (2024-05-01)++- Support for `linear-1.23`.  This version of `linear` introduces a+  breaking change, so add an internal compatibility module that allows+  diagrams to work with any version of `linear` both before and after+  the change.++## [v1.4.6.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.6.1) (2024-02-26)++- Fix compilation on BSD ([#367](https://github.com/diagrams/diagrams-lib/pull/367), thanks to Finn Espen Gundersen)++## [v1.4.6-r4](https://github.com/diagrams/diagrams-lib/tree/v1.4.6-r4) (2024-01-11)++- Allow `base-4.19` and test with GHC 9.8+- Allow `text-2.1`++## [v1.4.6-r3](https://github.com/diagrams/diagrams-lib/tree/v1.4.6-r3) (2023-09-14)++- Allow `tasty-1.5`++## [v1.4.6-r2](https://github.com/diagrams/diagrams-lib/tree/v1.4.6-r2) (2023-08-16)++- Allow `bytestring-0.12` and `deepseq-1.5`++## [v1.4.6-r1](https://github.com/diagrams/diagrams-lib/tree/v1.4.6-r1) (2023-05-25)++- Allow `optparse-applicative-0.18`++## [v1.4.6](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.3) (2023-05-15)++- Allow `base-4.18`; test with GHC 9.6 (thanks to @sergv)+- Fix some warnings (thanks to @sergv)++## [v1.4.5.3](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.3) (2022-09-19)++- Update to `fsnotify-0.4`++- Revisions:+  - r1: require `lens-5.1`+  - r2: allow `mtl-2.3`+  - r3 (3 Dec 2022): allow `linear-1.22`++## [v1.4.5.2](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.2) (2022-09-14)++- Fix build with `transformers-0.6`+- Fix some deprecation warnings++## [v1.4.5.1-r3](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.1-r3) (2022-08-27)++- Allow `base-4.17` and `lens-5.2`; test with GHC 9.4++## [v1.4.5.1-r2](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.1-r2) (2022-02-01)++- Allow `optparse-applicative-0.17`++## [v1.4.5.1-r1](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.1-r1) (2022-01-08)++- Allow `text-2.0`++## [v1.4.5.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.5.1) (2021-12-17)++- Bug fix: make things compile again under versions of `lens` before 5.1.++## [v1.4.5](https://github.com/diagrams/diagrams-lib/tree/v1.4.5) (2021-12-16)++- Allow `base-4.16` (tested with GHC 9.2.1)+- Allow `semigroups-0.20`, `lens-5.1`, `hashable-1.4`,+  `transformers-0.6`+- Add `Eq` instance for `SizeSpec`++## [v1.4.4-r1](https://github.com/diagrams/diagrams-lib/tree/v1.4.4-r1) (2021-06-05)++- Bumps to dependency upper bounds:+    - Allow `tasty-1.4`+    - Allow `bytestring-0.11`++## [v1.4.4](https://github.com/diagrams/diagrams-lib/tree/v1.4.4) (2021-05-24)++- Bumps to upper bounds, to allow building with:+    - `base-4.15` (tested with GHC 9.0.1)+    - `optparse-applicative` (tested with GHC 8.8.4 & 8.10.2)++- Updated use of Kinds thoughout the package++- Drop support for GHC 8.2 or earlier++## [v1.4.3](https://github.com/diagrams/diagrams-lib/tree/v1.4.3) (2019-11-06)++- Bumps to upper bounds, to allow building with:+    - `base-4.13` (tested with GHC 8.8.1)+    - `intervals-0.9`+    - `semigroups-0.19`+    - `hashable-1.3`+- Many bug fixes, including+    - [#313](https://github.com/diagrams/diagrams-lib/issues/313) (`combineBoundaries`)+    - [#322](https://github.com/diagrams/diagrams-lib/issues/322), [#329](https://github.com/diagrams/diagrams-lib/issues/329) (`section`)+    - [#325](https://github.com/diagrams/diagrams-lib/pull/325)+      (Bezier/Bezier intersection)+    - [#339](https://github.com/diagrams/diagrams-lib/pull/339) (`perspectiveZ1`)+- Added derived `Eq` and `Ord` instances for `FixedSegment`++## [v1.4.2.3](https://github.com/diagrams/diagrams-lib/tree/v1.4.2.3) (2018-06-11)++- Bug fix for `extrudeEnvelope` and friends ([#316](https://github.com/diagrams/diagrams-lib/issues/316))++## [v1.4.2.2](https://github.com/diagrams/diagrams-lib/tree/v1.4.2.2) (2018-05-08)++- Fixes for GHC < 8.0++## [v1.4.2.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.2.1) (2018-04-13)++- Allow `base-4.11` (GHC 8.4)+- Allow `tasty-quickcheck-0.10`+- Bug fix for `Diagrams.TwoD.Offset.capArc` ([#310](https://github.com/diagrams/diagrams-lib/pull/310))++## [v1.4.2-r1](https://github.com/diagrams/diagrams-lib/tree/v1.4.2-r1) (2017-12-20)++Hackage revision to allow `tasty-1.0` in the test suite.++## [v1.4.2](https://github.com/diagrams/diagrams-lib/tree/v1.4.2) (2017-12-20)++- New functions:+    - `boxGrid`, for computing a grid of regularly spaced points.+    - `scalingRotationTo` and `scaleRotateTo`, for affine conformal 2D+      transformations.+- Documentation fixes:+    - `dirBetween`+    - `PolyOrientation`+- Upper bound updates: allow `tasty-0.12`, `tasty-quickcheck-0.9`,+  `tasty-hunit-0.10`, `optparse-applicative-0.14`+- Test with GHC 8.2.2++## [v1.4.1.2](https://github.com/diagrams/diagrams-lib/tree/v1.4.1.2) (2017-06-10)++- Fix test suite compilation failure [#299](https://github.com/diagrams/diagrams-lib/issues/299).++## [v1.4.1.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.1.1) (2017-06-06)++- Fix `Diagrams.Points.centroid` to make it total.+- Fix bug in `Diagrams.Transform.Matrix.fromMatWithInv` (and hence+  also related functions which called it, such as `fromMat22` and+  `fromMat33`).++## [v1.4.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.1) (2017-05-28)++- New functions `embeddedImage` and `loadImageEmbBS` for loading+  images.+- Fix [#289](https://github.com/diagrams/diagrams-lib/issues/289)+  which could have caused strange behavior in looped compilation mode+  on 32-bit platforms.+- Allow `intervals-0.8` and `directory-1.3`.+- Minor fixes to compile with GHC 8.2.++## [v1.4.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.4.0.1) (2016-11-07)++- Fix test suite compilation problem ([#286](https://github.com/diagrams/diagrams-lib/issues/286))++## [v1.4](https://github.com/diagrams/diagrams-lib/tree/v1.4) (2016-10-26)++* **New features**++    - New `mkText'` function, which allows making a text primitive+      without recommending a fill colour or font size so users can+      recommend their own (*e.g.* using the `recommendFontSize`+      function).++    - New functions `reflectXY` and `reflectionXY`++    - New `composeAligned` combinator for doing composition under an+      alignment while leaving the local origin unaffected.++    - Add `_LocLoop` and `_LocLine` prisms++    - New `bspline` function for creating uniform cubic B-splines++    - New 3D features:+        - New `Skinned` class+        - Improved handling of 3D primitives+        - CSG++    - New standard attributes for separate fill and stroke opacity+      (see+      [#248](https://github.com/diagrams/diagrams-lib/issues/248)).++    - New `HasQuery` class for things which can be spatially queried+      for values from some monoid.++    - New function `inquire` for testing whether a given point is+      inside a diagram.++    - New font weights: `bolder`, `lighter`, `thinWeight`,+      `ultraLight`, `light`, `mediumWeight`, `heavy`, `semiBold`,+      `ultraBold`.  Note that currently only the SVG backend deals+      with the new weights.++    - Export `GetSegmentCodomain` and update documentation++    - Improved performance of 2D rotations++* **New instances**++    - `Alignable` instance for `Located`++    - `ToPath` instances for lines and loops++    - `Serialize` instances for `Trail`, `Path`, `Located`, `SegTree`,+      `Segment`++    - `Generic` instances for `Path`, `Located`++    - `Action` instance for `Angle`: angles act by rotation.++* **API changes**++    - `snugBL`, `snugBR`, `snugTR` and `snugBR` are deprecated.+      These functions were unintuitive, ad-hoc, and not particularly useful,+      especially since e.g. `snugL` and `snugB` do not commute. You+      can use something like `snugB . snugL` directly, or use `snug`+      with a direction vector.  See+      [#250](https://github.com/diagrams/diagrams-lib/issues/250) for+      more details.++* **Dependency/version changes**++    - upgrade `fsnotify` and drop dependency on deprecated+      `system-filepath`+    - Allow `lens-4.15`+    - Many other bumped upper bounds, see release notes for minor releases+      below++* **Bug fixes**++    - fix `orientPoints` function, which was previously generating NaN+      values with lists of only one or two+      points. ([#210](https://github.com/diagrams/diagrams-lib/issues/210))++    - Broken offset joins with non-vertices in loops ([#263](https://github.com/diagrams/diagrams-lib/issues/263))++    - Properly transform arrow shaft styles ([#274](https://github.com/diagrams/diagrams-lib/issues/274))++    - Fix sign error in `reflectionAbout`++## [v1.3.1.4](https://github.com/diagrams/diagrams-lib/tree/v1.3.1.4) (2016-08-16) (16 August 2016)++- allow `optparse-applicative-0.13`++## [v1.3.1.3](https://github.com/diagrams/diagrams-lib/tree/v1.3.1.3) (2016-06-05)++- allow `base-4.9`+- allow `data-default-class-0.1`+- test with GHC 8.0.1++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.1.2...v1.3.1.3)++## [v1.3.1.2](https://github.com/diagrams/diagrams-lib/tree/v1.3.1.2) (2016-05-01)++- allow `lens-4.14`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.1.1...v1.3.1.2)++## [v1.3.1.2](https://github.com/diagrams/diagrams-lib/tree/v1.3.1.2) (2016-02-19)++  - allow `unordered-containers-0.2.*`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.1.0...v1.3.1.1)++## [v1.3.1.0](https://github.com/diagrams/diagrams-lib/tree/v1.3.1.0) (2016-02-14)++- improve path offset calculations++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.9...v1.3.1.0)++## [v1.3.0.9](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.9) (2016-01-14)++- allow `unordered-containers-0.2.6`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.8...v1.3.0.9)++## [v1.3.0.8](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.8) (2015-11-10)++- allow `semigroups-0.18`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.7...v1.3.0.8)++## [v1.3.0.7](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.7) (2015-10-08) ##++- Add `LambdaCase` extension to `.cabal` file, so `cabal` correctly+  reports that `diagrams-lib` does not build on `GHC-7.4`.++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.6...v1.3.0.7)++## [v1.3.0.6](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.6) (2015-09-29) ##++- Allow `optparse-applicative-0.12`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.5...v1.3.0.6)++## [v1.3.0.5](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.5) (2015-09-18) ##++- Fix compilation problem with `lens-4.13`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.4...v1.3.0.5)++## [v1.3.0.4](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.4) (2015-09-17) ##++**Dependency/version changes**++- Allow `lens-1.13`+- Allow `semigroups-0.17`+- Require `linear-1.20`++## [v1.3.0.3](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.3) (2015-08-10)++**Dependency/version changes**++- Drop dependency on deprecated `system-filepath` package+- Require `fsnotify-0.2.1`++## [v1.3.0.2](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.2) (2015-07-19)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3.0.1...v1.3.0.2)++## [v1.3.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.3.0.1) (2015-05-26)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.3...v1.3.0.1)++## [v1.3](https://github.com/diagrams/diagrams-lib/tree/v1.3) (2015-04-19)++**New features**++- Native image type that backends can specify.++- Affine maps between spaces for path-like objects. A new+  `Diagrams.ThreeD.Projections` has some helper functions for+  orthographic and perspective projections.++- Intersections for path-like objects using Bézier clipping.++- Helper functions in `Diagrams.Matrix` for converting between+  transforms and matrices.++- New `Diagrams` module that only exports functions defined in+  diagrams.++- New `Direction` type. `Direction` is a vector that's forgot it's+  magnitude. Some functions have changed their type from `R2` to+  `Direction V2 n` to make it clear that magnitude has no effect.++- Use the [`fsnotify`](https://hackage.haskell.org/package/fsnotify)+  package for command line looping. Command line looping now works+  on Windows.++- `groupOpacity` function added for lowering the opacity of a+  diagram as a whole.++- New `ToPath` class for converting path-like things to a `Path`.++**New instances**++- `Each` instances for `BoundingBox`, `Offset`, `Segment`,+  `FixedSegment` and `Path`.++- `Reversing` instances for `Offset`, `Segment`, `FixedSegment`,+  `Trail` and `Path`.++- `AsEmpty` instances for `BoundingBox`, `Trail` and `Path`.++- `Cons` and `Snoc` instances for `Path` and `Line`.++- New `Show` instances for `Angle`, `Segment`, `SomeColor`, `Trail'`+  and `at`.++- `Tangent` instance for `(FixedSegment v n)`.++- `Ord` instances for `LineMiterLimit`, `LineJoin` and `LineCap`.++**New helper functions**++- `_Line` and `_Loop` prisms.++- Style lenses: `_fontSize`, `_lineWidth`, `_fillTexture`,+  `_lineTexture`, `_opacity`, `_font`, `_lineCap`, `_lineJoin`+  `_dashing`.++- `_SomeColor` iso and `_AC` prism onto an `AlphaColour`.++- `atPoints` function to zip points with diagrams.++**API changes**++- `Diagram` type synonym now only takes a backend token: `Diagram B`++- Types that previously had a `v` variable now have `v` and `n`.++- `Control.Lens` and `Data.Default.Class` are now exported from from+  `Diagrams.Prelude`++- `Measure` has a new internal representation. `Local`, `Global`,+  `Normalized`, and `Output` have been renamed to `local`, `global`,+  `normalized` and `output` respectivly.++- `SizeSpec2D` has moved to `SizeSpec v n` in `Diagrams.SizeSpec`.+  `Dims, Height, Width and `Absolute` have moved to `dims2D`,+  `mkHeight`, `mkWidth` and `absolute` respectively.++- `Color` instances for `Colour` and `AlphaColour` are limited to+  `Double` for better type inference.++- `under` has been renamed to `underT`. New `transformed`,+  `translated`, `movedTo`, `movedFrom` and `rotated` isomorphisms to+  use with lens's `under` function.++- `stroke` is now polymorphic. Use `strokePath` or `strokeP` to get+  old `stroke` behaviour.++- `angleBetween` now works for any vector space, which means the+  angle is always positive. The old behaviour can be retrieved from+  `signedAngleBetween`++- `arc` now takes a starting `Direction` and a sweep `Angle`.+  `arcCW` and `arcCCW` take a start and finish `Direction`.++**Dependency/version changes**++- use `linear` instead of `vector-space`++**Closed issues:**++- Perspective deformation of square vertices yields extra point [\#244](https://github.com/diagrams/diagrams-lib/issues/244)++- Local fontsize renders inconsistentl on diffrent backends [\#243](https://github.com/diagrams/diagrams-lib/issues/243)++- Factor out Diagrams.Solve into a package? [\#235](https://github.com/diagrams/diagrams-lib/issues/235)++**Merged pull requests:**++- add pathPoints and pathVertices' functions [\#245](https://github.com/diagrams/diagrams-lib/pull/245) ([byorgey](https://github.com/byorgey))++- New loop [\#242](https://github.com/diagrams/diagrams-lib/pull/242) ([cchalmers](https://github.com/cchalmers))++- Pre 1.3 [\#241](https://github.com/diagrams/diagrams-lib/pull/241) ([cchalmers](https://github.com/cchalmers))++- Update CubicSpline.hs [\#240](https://github.com/diagrams/diagrams-lib/pull/240) ([fryguybob](https://github.com/fryguybob))++- updated changes for GHC-7.10 [\#239](https://github.com/diagrams/diagrams-lib/pull/239) ([bergey](https://github.com/bergey))++- split out new package diagrams-solve [\#237](https://github.com/diagrams/diagrams-lib/pull/237) ([byorgey](https://github.com/byorgey))++- Lens style [\#236](https://github.com/diagrams/diagrams-lib/pull/236) ([cchalmers](https://github.com/cchalmers))++- Half-dart arrowheads [\#234](https://github.com/diagrams/diagrams-lib/pull/234) ([byorgey](https://github.com/byorgey))++- TwoD.Points: Needs TypeFamilies [\#233](https://github.com/diagrams/diagrams-lib/pull/233) ([bgamari](https://github.com/bgamari))++- Projections [\#229](https://github.com/diagrams/diagrams-lib/pull/229) ([cchalmers](https://github.com/cchalmers))++## [1.2.0.9]() (2 April 2015)++ - allow `lens-4.9`++ - allow `vector-space-0.10`++## [v1.2.0.8](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.8) (2015-01-13)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.7...v1.2.0.8)++**Merged pull requests:**++- typo in haddocks [\#232](https://github.com/diagrams/diagrams-lib/pull/232) ([ggreif](https://github.com/ggreif))++- Update diagrams-lib.cabal : bumping JuicyPixels dependency [\#230](https://github.com/diagrams/diagrams-lib/pull/230) ([Twinside](https://github.com/Twinside))++## [v1.2.0.7](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.7) (2014-12-07)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.6...v1.2.0.7)++## [v1.2.0.6](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.6) (2014-12-04)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.5...v1.2.0.6)++**Merged pull requests:**++- Minor changes in documentation about Polygons. [\#228](https://github.com/diagrams/diagrams-lib/pull/228) ([alexDarcy](https://github.com/alexDarcy))++## [v1.2.0.5](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.5) (2014-11-17)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.4...v1.2.0.5)++**Implemented enhancements:**++- Path/trail intersection [\#209](https://github.com/diagrams/diagrams-lib/issues/209)++- Turn R2 into D2 \(Generalize R2 to any numeric type\) [\#50](https://github.com/diagrams/diagrams-lib/issues/50)++**Fixed bugs:**++- `Sectionable` instance for `SegTree` is not a linear reparameterization. [\#217](https://github.com/diagrams/diagrams-lib/issues/217)++**Closed issues:**++- bezierFromSweep very slow? [\#227](https://github.com/diagrams/diagrams-lib/issues/227)++- All lines render at same width [\#222](https://github.com/diagrams/diagrams-lib/issues/222)++- numerically stable cubic rootfinder [\#204](https://github.com/diagrams/diagrams-lib/issues/204)++**Merged pull requests:**++- Intersections [\#226](https://github.com/diagrams/diagrams-lib/pull/226) ([cchalmers](https://github.com/cchalmers))++- Linear update [\#225](https://github.com/diagrams/diagrams-lib/pull/225) ([cchalmers](https://github.com/cchalmers))++- Add arcCCW and friends.  Fix offset joins. [\#221](https://github.com/diagrams/diagrams-lib/pull/221) ([fryguybob](https://github.com/fryguybob))++- Reparameterize section [\#220](https://github.com/diagrams/diagrams-lib/pull/220) ([fryguybob](https://github.com/fryguybob))++- Diagram b v n to QDiagram b v n Any [\#219](https://github.com/diagrams/diagrams-lib/pull/219) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- New stuff [\#218](https://github.com/diagrams/diagrams-lib/pull/218) ([cchalmers](https://github.com/cchalmers))++- Linear [\#215](https://github.com/diagrams/diagrams-lib/pull/215) ([cchalmers](https://github.com/cchalmers))++## [v1.2.0.4](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.4) (2014-10-08)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.3...v1.2.0.4)++**Merged pull requests:**++- add semi-portable looping using fsnotify [\#213](https://github.com/diagrams/diagrams-lib/pull/213) ([bergey](https://github.com/bergey))++## [v1.2.0.3](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.3) (2014-09-07)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.2...v1.2.0.3)++**Closed issues:**++- arrowFromLocatedTrail function [\#205](https://github.com/diagrams/diagrams-lib/issues/205)++**Merged pull requests:**++- Added `arrowFromLocatedTrail` [\#206](https://github.com/diagrams/diagrams-lib/pull/206) ([pnutus](https://github.com/pnutus))++## [v1.2.0.2](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.2) (2014-08-22)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2.0.1...v1.2.0.2)++**Implemented enhancements:**++- Generalize Angle class? [\#38](https://github.com/diagrams/diagrams-lib/issues/38)++**Fixed bugs:**++- --selection and --src both use -s abbreviation [\#172](https://github.com/diagrams/diagrams-lib/issues/172)++**Closed issues:**++- Spike arrowhead and tail render with oversized joint [\#203](https://github.com/diagrams/diagrams-lib/issues/203)++**Merged pull requests:**++- Enable compilation with GHC HEAD \(v7.9\) [\#211](https://github.com/diagrams/diagrams-lib/pull/211) ([ggreif](https://github.com/ggreif))++- cli-options [\#200](https://github.com/diagrams/diagrams-lib/pull/200) ([bergey](https://github.com/bergey))++- Add Native images to Diagrams.TwoD.Image [\#199](https://github.com/diagrams/diagrams-lib/pull/199) ([taruti](https://github.com/taruti))++- add atPoints, deprecate decorateFoo [\#198](https://github.com/diagrams/diagrams-lib/pull/198) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Add bg' [\#197](https://github.com/diagrams/diagrams-lib/pull/197) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- add convenience synonyms \[hv\]sep for \[hv\]cat' \(with & sep .~ x\) [\#196](https://github.com/diagrams/diagrams-lib/pull/196) ([byorgey](https://github.com/byorgey))++- Vertices [\#192](https://github.com/diagrams/diagrams-lib/pull/192) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Direction type [\#186](https://github.com/diagrams/diagrams-lib/pull/186) ([bergey](https://github.com/bergey))++## [v1.2.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.2.0.1) (2014-06-04)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.2...v1.2.0.1)++**Closed issues:**++- Local headLength / headGaps act like Output [\#193](https://github.com/diagrams/diagrams-lib/issues/193)++**Merged pull requests:**++- transform Local Measure in arrow styles [\#194](https://github.com/diagrams/diagrams-lib/pull/194) ([bergey](https://github.com/bergey))++## [v1.2](https://github.com/diagrams/diagrams-lib/tree/v1.2) (2014-06-02)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.1.0.4...v1.2)++**New features**++- Several attributes (such as line width, dashing size, arrowhead+  size, and font size) that formerly had a value of type `Double`+  now have the more general type `Measure R2`. This allows the+  attributes to be specified relative to one of four measurement+  frames: `Local`, `Global`, `Normalized`, and `Output`.++- New DSL for specifying measurements.++- New synonyms for specifying measurements, *e.g.* `thin`,+  `thick`, and `medium`, `large`.++- Support for radial and linear gradients for fills and strokes.++- New `DImage` type that supports both embedded and external images in+  Backends that support them.++- New `lengths` Traversal for setting `headLength` and `tailLength`+  simultaneously.++- `Frustrum` and `Box` shapes added to `Diagrams.ThreeD.Shapes`.++- New function `quartForm` to find roots of quartic polynomials.++- New Lenses for polar coordinates.++- New trig functions, `sinA`, `atanA`, etc. which take `Angle` as+  input or output.++**New instances**++- `Transformable` instances for `LineWidth`, `Dashing`,+  `LineTexture`, and  `FillTexture`.++**API changes**++- `FillColor` and `LineColor` attributes have been replaced with+  the more general `FillTexture` and `LineTexture`. Use the `solid`+  function to convert a color to a texture.++- The size of arrow heads and tails is now specified in terms of+  length instead of the radius of their circumcircle.++- Gaps at the ends of arrows are now specified using `Measure R2`.++- The `gap` traversal has been replaced by `gaps` for consistency+  in naming, though `gap` is still provided for backwards compatibility.++- `fontSize` now takes a value of type `Measure R2`.++- Get rid of (bitrotted) `Show` backend.++- Functions in `TwoD.Adjust` now return the adjustment+  transformation itself in addition to the resized `Diagram` and+  `Options` record; this can be used, *e.g.* to convert screen+  coordinates back into diagram coordinates.++- Export `pathLocSegments`.++- The `avgScale` function has been moved to `Diagrams.Core`.++- The `Angle` definition and related functions (*e.g.*+  `angleBetween`) have moved to a separate module, `Diagrams.Angle`.++- A separate `Diagrams.TwoD.Attributes` module now contains most+  of the attributes that require 2D transformation instances.++- The `splitColorFills` function has been replaced by `splitTextureFills`.++**Dependency/version changes**++- Allow `semigroups-0.15`++- Allow `opt-parse-applicative-0.9.0++- Allow `lens-4.2`++**Implemented enhancements:**++- 'image' should be in IO [\#29](https://github.com/diagrams/diagrams-lib/issues/29)++- Add gradient support [\#9](https://github.com/diagrams/diagrams-lib/issues/9)++**Closed issues:**++- fails to build against HP [\#190](https://github.com/diagrams/diagrams-lib/issues/190)++- text does not scale [\#179](https://github.com/diagrams/diagrams-lib/issues/179)++- Please add support for latest version of intervals library [\#170](https://github.com/diagrams/diagrams-lib/issues/170)++- presence of arrowHead can tilt connection sideways [\#162](https://github.com/diagrams/diagrams-lib/issues/162)++**Merged pull requests:**++- Quartic formula, no obvious bugs [\#187](https://github.com/diagrams/diagrams-lib/pull/187) ([Mathnerd314](https://github.com/Mathnerd314))++- Arrow length [\#185](https://github.com/diagrams/diagrams-lib/pull/185) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- fix handling of text scaling [\#182](https://github.com/diagrams/diagrams-lib/pull/182) ([byorgey](https://github.com/byorgey))++- Texture [\#181](https://github.com/diagrams/diagrams-lib/pull/181) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- arrow envelopes [\#180](https://github.com/diagrams/diagrams-lib/pull/180) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- make headSize and tailSize back into ArrowOpts fields [\#177](https://github.com/diagrams/diagrams-lib/pull/177) ([byorgey](https://github.com/byorgey))++- updated the upper bounds of the .cabal constraints for 'semigroups' package [\#176](https://github.com/diagrams/diagrams-lib/pull/176) ([zgredzik](https://github.com/zgredzik))++- Image2 [\#174](https://github.com/diagrams/diagrams-lib/pull/174) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Image [\#173](https://github.com/diagrams/diagrams-lib/pull/173) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Preliminary implementation of Measure [\#159](https://github.com/diagrams/diagrams-lib/pull/159) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Gradient [\#136](https://github.com/diagrams/diagrams-lib/pull/136) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++## [v1.1.0.7]() (2014-05-15)++- Allow `semigroups-0.14`++## [v1.1.0.6]() (2014-04-10)++- Allow `semigroups-0.13`++## [v1.1.0.4](https://github.com/diagrams/diagrams-lib/tree/v1.1.0.4) (2014-04-04)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.1.0.2...v1.1.0.4)++**Merged pull requests:**++- Updates to work with `Backend` redesign [\#171](https://github.com/diagrams/diagrams-lib/pull/171) ([byorgey](https://github.com/byorgey))++- Rework of units [\#169](https://github.com/diagrams/diagrams-lib/pull/169) ([byorgey](https://github.com/byorgey))++- Make Diagrams.Transform.under more polymorphic [\#168](https://github.com/diagrams/diagrams-lib/pull/168) ([FlorentBecker](https://github.com/FlorentBecker))++## [v1.1.0.3]() (2014-03-19)++- Allow `lens-4.1`++## [v1.1.0.2](https://github.com/diagrams/diagrams-lib/tree/v1.1.0.2) (2014-03-19)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.1.0.1...v1.1.0.2)++**Merged pull requests:**++- move avgScale to core [\#167](https://github.com/diagrams/diagrams-lib/pull/167) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- 3d color & lighting, more solids, Angle utilities [\#166](https://github.com/diagrams/diagrams-lib/pull/166) ([bergey](https://github.com/bergey))++- Added bothSize function, lineHead and lineTail [\#165](https://github.com/diagrams/diagrams-lib/pull/165) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++## [v1.1.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.1.0.1) (2014-03-09)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.1...v1.1.0.1)++- Depend on `hashable` package, and add `Hashable` instance for+  `SizeSpec2D`.++  Technically, the PVP specifies that adding a new instance+  requires a major version bump.  However, I highly doubt anyone+  was making their own orphan `Hashable` instances before.  Feel+  free to yell at Brent if this breaks your build.++## [v1.1](https://github.com/diagrams/diagrams-lib/tree/v1.1) (2014-03-09)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.0.1...v1.1)++**New features**++- Support for `Deformation`s, arbitrary (non-affine)+  transformations on objects such as points, paths, and located+  trails (though not on diagrams).++- New functions `clipTo`, which clips a diagram's envelope and+  trace along with its visual representation, and `clipped`, which+  clips the diagram's visual representation but replaces its+  envelope and trace with those of the clipping path.++- New `arrowV` function, for creating an arrow with the direction+  and magnitude of a given vector.++- `gap` traversal, for setting the head and tail gaps of an arrow+  simultaneously.++- Generalized types for `centerXY` and `snugXY`, based on new+  `basis` function from `diagrams-core++- New 3D `Transform`s, alignment, and 3D-specific `Prelude`.++- New `frame` function similar to `pad`, but increases the envelope+  of a diagram by an amount specified in local units in every direction+  irrespective of the local origin.++- New `splitFills` function for pushing fill attributes down to+  subtrees containing only loops (mostly of relevance only to+  backend implementors).++**New instances**++- `Typeable` instances for all data types that are used as diagram+  primitives.++- `Sectionable` instance for `FixedSegment`.++**API changes**++- `Angle` is now a type, rather than a class.  It uses a single+  internal representation for angles, and lenses `turn`, `rad,`+  and `deg` are supplied for constructing (using `@@`) and viewing+  (using `^.`) `Angle`s in various units.  In addition, the `Num`+  instance for `Angle` has been removed, eliminating a class of+  errors where a bare number is interpreted in units other than+  what you expect.++- Removed `Num` instance for angles.++**Dependency/version changes**++- Require `lens >= 4.0`.++- Allow `array-0.5`.++- Allow `hashable-1.1`.++- Remove `NumInstances` dependency.++**Bug fixes**++- Exclude joins in offsets on close segments (#160).++- Exclude extra segment when joining loops in offset (#155).++**Performance improvements**++- `colorToSRGBA` function now avoids expensive matrix operations,+  offering dramatic speedups in rendering diagrams with many color+  attributes.++**Implemented enhancements:**++- Better color model in 3D [\#121](https://github.com/diagrams/diagrams-lib/issues/121)++- Projective/perspective transforms for points and paths [\#108](https://github.com/diagrams/diagrams-lib/issues/108)++- clipTo function [\#35](https://github.com/diagrams/diagrams-lib/issues/35)++**Fixed bugs:**++- Offset Bug [\#155](https://github.com/diagrams/diagrams-lib/issues/155)++**Closed issues:**++- Expand of an expand [\#160](https://github.com/diagrams/diagrams-lib/issues/160)++**Merged pull requests:**++- fix doc for === and ||| [\#164](https://github.com/diagrams/diagrams-lib/pull/164) ([denys-duchier](https://github.com/denys-duchier))++- Split fills [\#161](https://github.com/diagrams/diagrams-lib/pull/161) ([byorgey](https://github.com/byorgey))++- Exclude extra segment when joining loops in offset. Fixes \#155. [\#158](https://github.com/diagrams/diagrams-lib/pull/158) ([fryguybob](https://github.com/fryguybob))++- added basis, generalized `centerXY` and `snugXY` [\#157](https://github.com/diagrams/diagrams-lib/pull/157) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- derive Typeable for all data types used in Prims [\#156](https://github.com/diagrams/diagrams-lib/pull/156) ([byorgey](https://github.com/byorgey))++- Lens4 [\#154](https://github.com/diagrams/diagrams-lib/pull/154) ([bergey](https://github.com/bergey))++- removed NumInstances dependency [\#153](https://github.com/diagrams/diagrams-lib/pull/153) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Remove Num instance for Angle [\#150](https://github.com/diagrams/diagrams-lib/pull/150) ([bergey](https://github.com/bergey))++- Change internal color representation to SRGBA [\#149](https://github.com/diagrams/diagrams-lib/pull/149) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Projections - non-affine transformations [\#148](https://github.com/diagrams/diagrams-lib/pull/148) ([bergey](https://github.com/bergey))++## [v1.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.0.1) (2014-01-26)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.0.0.1...v1.0.1)++**Implemented enhancements:**++- Module for generating nice colors/color schemes [\#77](https://github.com/diagrams/diagrams-lib/issues/77)++**Closed issues:**++- "Maybe.fromJust: Nothing" error when connecting translated small diagram [\#147](https://github.com/diagrams/diagrams-lib/issues/147)++**Merged pull requests:**++- Add Hashable instance for SizeSpec2D [\#146](https://github.com/diagrams/diagrams-lib/pull/146) ([byorgey](https://github.com/byorgey))++- return list of traces [\#145](https://github.com/diagrams/diagrams-lib/pull/145) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- added clipTo [\#144](https://github.com/diagrams/diagrams-lib/pull/144) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- Unified angle type [\#140](https://github.com/diagrams/diagrams-lib/pull/140) ([bergey](https://github.com/bergey))++## [v1.0.0.1](https://github.com/diagrams/diagrams-lib/tree/v1.0.0.1) (2013-11-28)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v1.0...v1.0.0.1)++## [v1.0](https://github.com/diagrams/diagrams-lib/tree/v1.0) (2013-11-25)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.7.1.1...v1.0)++**New features**++- New modules `Diagrams.TwoD.Arrow` and `Diagrams.TwoD.Arrowheads`+  for creating arrows.++- New module `Diagrams.Backend.CmdLine`, providing a flexible+  framework for creating command-line-driven diagram rendering executables.++- New functions in `Diagrams.Offset`: `offsetTrail` and+  `offsetPath` for one-sided offsets of trails and paths;+  `expandTrail` and `expandPath` for "stroking" trails and paths,+  computing a path whose fill corresponds to the stroke of the+  given trail or path.++- New module `Diagrams.Tangent` for computing tangent and normal+  vectors of segments, trails, and paths.++- New functions in `Diagrams.Align` to allow diagrams to be aligned by `Trace`+  called `snug`, `snugBy` and `snugCenter`+  and the ability to define other boundary functions for alignment. Functions+  `snugL`, `snugR`, etc. are included in `TwoD.Align`.++- Lenses from `Control.Lens` are now used consistently for record fields+  throughout the library.++- New function `angleRatio` for calculating the ratio between two angles.++- Restricted identity functions `asTurn`, `asRad`, and `asDeg` for+  resolving type ambiguity++- New miter limit attribute.++- New function `annularWedge` in `TwoD.Arc`++- New `avgScale` utility in `TwoD.Transform`, for backends which+  cannot fully implement freezing of line width++- New function `heptagon`, a vast improvement over the linguistic+  frankenstein `septagon`.++- New function `lookupName` (re-exported from `diagrams-core`) for+  simple lookups of named subdiagrams++- New function `angleBetween` to calculate the angle between two+  vectors.++- New function `arcBetween` to draw an arc between two given+  points.++- A bunch of new modules containing types, primitives and+  utilities for constructing 3D diagrams: `Diagrams.ThreeD.Align`,+  `.Camera`, `.Light`, `.Shapes`, `.Transform`, `.Types`, and+  `.Vector`.  This is still a "feature preview" (in particular,+  appropriate 3D backends are still under construction).++**New instances**++- `AdditiveGroup` and `VectorSpace` instances for `Turn`, `Rad`, `Deg`++- `Alignable` instance for `(->) e`++- `Default` instances for `FillRule`, `FillRuleA`, `LineJoin`,+    `LineCap`, `FillColor`++- `Show` instances for `FillRule`, `FillRuleA`++**API changes**++- `e` no longer exported from `Diagrams.Prelude`.++- `Diagrams.BoundingBox` is no longer exported from `Diagrams.Prelude`.++- Re-export `Diagrams.Core.pointDiagram` from `Diagrams.Prelude`.++- Added `fromAlphaColour` method to `Color` class.++- `&` renamed to `^&`++- Stop re-exporting `tan`, `over`, and `both` from `Data.Colour`.++- New coordinate lenses `_x`, `_y`, and `_z` for `R2`, `P2`, `R3`, `P3`++- Export `fullTurn` from `Diagrams.Prelude`.++- `Codomain (Located a)` is now `Point (Codomain a)` instead of+  `Located (Codomain a)`.++- Export `domainBounds` from `Diagrams.Parametric`.++- Adjusting functionality moved from `Diagrams.Parametric` to its+  own module, `Diagrams.Parametric.Adjust`.++- Rename `strokeT` (and primed variant) to `strokeTrail`; rename+  `strokeLocT` to `strokeLocTrail`.++- `ScaleInv` is now in its own module, `Diagrams.TwoD.Transform.ScaleInv`.++- Re-export `Image` type (but not constructor) from `Diagrams.TwoD`++- Removed `Floating` and `RealFloat` instances for `Turn` and `Deg`++- `offsetSegment` now returns a `Located` instead of a tuple.++- Removed `Num` and `Fractional` instances for `R2`.++**Dependency/version changes**++- Remove `newtype` dependency++- New dependencies on `lens`, `tagged`, `optparse-applicative`,+  `filepath`, `safe`, `vector-space-points`, `MemoTrie`++- Depend on `intervals >= 0.3 && < 0.5`.++**Bug fixes**++- Depend on `intervals 0.3`, which allows diagrams to build on+  Windows, by evading a GHCi linker bug which affects the FFI use in+  previous versions of intervals ([diagrams-contrib#14](https://github.com/diagrams/diagrams-contrib/issues/14))++- Use point envelope at the origin for text objects instead of an+  empty envelope+  ([#115](https://github.com/diagrams/diagrams-lib/issues/115),+  [#116](https://github.com/diagrams/diagrams-lib/issues/116)).++- Adjusting the end of a trail now works correctly ([#95](https://github.com/diagrams/diagrams-lib/issues/95)).++- Only look for miter join on corners in `Diagrams.TwoD.Offset` ([#118](https://github.com/diagrams/diagrams-lib/issues/118)).++- `wedge` from `Diagrams.TwoD.Arc` is now a Loop ([#99](https://github.com/diagrams/diagrams-lib/issues/99))++- Arrows do not behave correctly under scaling [\#112](https://github.com/diagrams/diagrams-lib/issues/112)++**Performance improvements**++- `R2` is now strict and `UNPACK`ed++- Add strictness to `Offset`, `Segment`, `OffsetEnvelope`, and `SizeSpec2D`.++- Make `getEnvelope` calculation for `Segment` more efficient by+  floating divisions out of the inner calculation.++- Use a specialized `HasTrie` instance for `R2`.+++**Closed issues:**++- diagrams-lib-0.7.1.1 fails to build with ghc-7.7 \(-HEAD\) [\#128](https://github.com/diagrams/diagrams-lib/issues/128)++- Arrow misses target [\#126](https://github.com/diagrams/diagrams-lib/issues/126)++**Merged pull requests:**++- Lenses for setting arrow head, tail, and shaft colors [\#138](https://github.com/diagrams/diagrams-lib/pull/138) ([byorgey](https://github.com/byorgey))++- Delayed subtrees [\#137](https://github.com/diagrams/diagrams-lib/pull/137) ([byorgey](https://github.com/byorgey))++- Add helpers for common optparse-applicative backend command line. [\#135](https://github.com/diagrams/diagrams-lib/pull/135) ([fryguybob](https://github.com/fryguybob))++- add located lens for access into Located things [\#134](https://github.com/diagrams/diagrams-lib/pull/134) ([byorgey](https://github.com/byorgey))++- add b-\>a instance for Alignable [\#133](https://github.com/diagrams/diagrams-lib/pull/133) ([cscheid](https://github.com/cscheid))++- Strictness optimizations [\#132](https://github.com/diagrams/diagrams-lib/pull/132) ([JohnLato](https://github.com/JohnLato))++- Lens [\#131](https://github.com/diagrams/diagrams-lib/pull/131) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- 3D scaling, alignment, coordinate lenses [\#129](https://github.com/diagrams/diagrams-lib/pull/129) ([bergey](https://github.com/bergey))++- correctly \(?\) compute shaftScale by solving a quadratic [\#127](https://github.com/diagrams/diagrams-lib/pull/127) ([byorgey](https://github.com/byorgey))++- calculate arrow shaftScale using projection of ends onto shaft offset [\#125](https://github.com/diagrams/diagrams-lib/pull/125) ([bergey](https://github.com/bergey))++- Convert from newtype to lens [\#124](https://github.com/diagrams/diagrams-lib/pull/124) ([byorgey](https://github.com/byorgey))++- Version bump on lens [\#123](https://github.com/diagrams/diagrams-lib/pull/123) ([haasn](https://github.com/haasn))++## [v0.7.1.1](https://github.com/diagrams/diagrams-lib/tree/v0.7.1.1) (2013-09-27)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.7.1...v0.7.1.1)++**Implemented enhancements:**++- Use a point envelope for built-in text objects [\#116](https://github.com/diagrams/diagrams-lib/issues/116)++- implement rotations in 3D [\#86](https://github.com/diagrams/diagrams-lib/issues/86)++- Control over boundary conditions on cubic splines. [\#32](https://github.com/diagrams/diagrams-lib/issues/32)++**Fixed bugs:**++- diagrams with empty envelopes are not properly separated by struts [\#115](https://github.com/diagrams/diagrams-lib/issues/115)++**Closed issues:**++- calculate ratio between two angles [\#109](https://github.com/diagrams/diagrams-lib/issues/109)++- Add primitives for arrows [\#73](https://github.com/diagrams/diagrams-lib/issues/73)++**Merged pull requests:**++- Three d render [\#114](https://github.com/diagrams/diagrams-lib/pull/114) ([bergey](https://github.com/bergey))++- API for computing tangent and normal vectors to segments and trails [\#113](https://github.com/diagrams/diagrams-lib/pull/113) ([byorgey](https://github.com/byorgey))++- change default styles for arrows [\#111](https://github.com/diagrams/diagrams-lib/pull/111) ([byorgey](https://github.com/byorgey))++- 3D utility functions [\#107](https://github.com/diagrams/diagrams-lib/pull/107) ([bergey](https://github.com/bergey))++## [v0.7.1](https://github.com/diagrams/diagrams-lib/tree/v0.7.1) (2013-09-11)++**New features**++- New standard miter limit attribute++- New functions `lineColorA`, `lineWidthA`, `lineMiterLimitA`,+  `fontSizeA` for directly applying attribute values++- `setDefault2DAttributes` now sets default line cap (butt), line+  join (miter), and miter limit (10) attributes++**New instances**++- `Data.Default` instances for++- `LineCap`++- `LineJoin`++- `LineMiterLimit`++- `LineWidth`++- `LineColor`++- `FontSize`++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.7...v0.7.1)++**Implemented enhancements:**++- Path expansion. [\#55](https://github.com/diagrams/diagrams-lib/issues/55)++- way to move diagrams closer together [\#18](https://github.com/diagrams/diagrams-lib/issues/18)++**Fixed bugs:**++- wedge should be closed [\#99](https://github.com/diagrams/diagrams-lib/issues/99)++- Adjusting trail from the end has no effect [\#95](https://github.com/diagrams/diagrams-lib/issues/95)++**Merged pull requests:**++- Add offsetTrail and expandTrail. [\#103](https://github.com/diagrams/diagrams-lib/pull/103) ([fryguybob](https://github.com/fryguybob))++- change Codomain of Located to Point \(Codomain a\) [\#102](https://github.com/diagrams/diagrams-lib/pull/102) ([byorgey](https://github.com/byorgey))++- Default and Show instances for FillRule and FillRuleA [\#100](https://github.com/diagrams/diagrams-lib/pull/100) ([jbracker](https://github.com/jbracker))++- Changes required due to the introduction of Roles in GHC [\#98](https://github.com/diagrams/diagrams-lib/pull/98) ([co-dan](https://github.com/co-dan))++- removed default implementation of reverseDomain [\#97](https://github.com/diagrams/diagrams-lib/pull/97) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++- fixed issue \#95 [\#96](https://github.com/diagrams/diagrams-lib/pull/96) ([jeffreyrosenbluth](https://github.com/jeffreyrosenbluth))++## [v0.7](https://github.com/diagrams/diagrams-lib/tree/v0.7) (2013-08-09)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.6.0.3...v0.7)++**New features**++- New module `Diagrams.TwoD.Curvature`, for computing the+  curvature of 2D segments at any given point.++- New module `Diagrams.Offset`, containing an `offsetSegment`+  function that builds a trail a fixed distance from the original+  segment.  This is a precursor to planned functions `offsetTrail`+  and `offsetPath`.++- New function `Diagrams.TwoD.Transform.onBasis`, for extracting a+  matrix representation of a 2D transformation++- New functions `extrudeEnvelope` and `intrudeEnvelope`, for+  extending or shrinking an envelope only in a certain direction.++- Generalize the `Color` class to absolute colors.+  This addresses concerns raised in issue #66 by letting the backend+  choose which color space to render `Color` instances to. Functions are+  provided for backwards compatibility with the old semantics.++- New function `scaleInvPrim` for creating a diagram from a single+  scale-invariant primitive.++- New module `Diagrams.Parametric`, containing a collection of+  classes abstracting over "parametric" things: `Parametric`,+  `DomainBounds`, `EndValues`, `Sectionable`, and `HasArcLength`,+  with instances for segments, trails, and related things.++- A big refactoring of segments and trails:++  - Segments can now be either "closed" or "open".++  - There are now two types of trails: "lines" (which travel+    from point A to point B) or "loops" (closed curves which end+      where they started). `Trail` is now a wrapper type which can+      contain both loops and lines.++  - There is a new `Located` wrapper type for adding locations to+    translation-invariant things.  `Path`s now consist of a+    collection of `Located Trail`s.++  - The `PathLike` class is now renamed to `TrailLike`; the+    `trailLike` function takes a `Located Trail` as input.++- New convenience functions `boundaryFrom` and `boundaryFromMay`,+  for computing boundaries of subdiagrams.++- Re-export from `diagrams-lib` a lot of things defined in+  `diagrams-core`, to make them easier for users to find.  Several+  new modules have been created as a result: `Diagrams.Query`,+  `Diagrams.Envelope`, `Diagrams.Trace`, and `Diagrams.Names`.++- Export the `centroid` function from `Diagrams.Prelude`.++- `triangle` is now a synonym for `eqTriangle`.++**New instances**++- `IsPrim` instances for `Path`, `Ellipsoid`, `Image`, `Text`, and+  `ScaleInv`++- `Eq`, `Ord`, and `Show` instances for `SizeSpec2D`++**API changes**++- `CircleFrac` has been renamed `Turn` (though `CircleFrac` is+  retained as a deprecated synonym).++- `Diagrams.Coordinates` is no longer exported from+  `Diagrams.Prelude`.  This is for compatibility with `lens`, as `(&)`+  is a rather important lens operator and clashes with+  `Diagrams.Coordinates`.  Users who want the `Coordinates` stuff can import+  `Diagrams.Coordinates` explicitly.++**Dependency/version changes**++- allow `base-4.7`++- upgrade to `monoid-extras-0.3`++- depend on `data-default-class` instead of `data-default`++- Tested with GHC 7.7.++**Bug fixes**++- Added a special case that was a not handled properly by the+  quadratic solver, resulting in bogus envelopes in certain cases+  (#88).++- Import only `Data.NumInstances.Tuple` instead of+  `Data.NumInstances`. Previously, `Diagrams.Prelude` exported+  `Eq`, `Show`, and `Num` instances for functions and tuples; now+  it only exports tuple instances. Users wishing to use+  `Diagrams.CubicSpline` with a vector space built over functions (!?)+  can import `Data.NumInstances.Function` themselves. (#48)++- Do scaling on a `Path` *before* constructing a `TrailLike` in+      `rect` (#43)++**Implemented enhancements:**++- Split PathLike, Trail, and Path into separate modules [\#25](https://github.com/diagrams/diagrams-lib/issues/25)++- Add support for path-oriented diagrams. [\#13](https://github.com/diagrams/diagrams-lib/issues/13)++**Fixed bugs:**++- Wrong envelope for cubic segment [\#88](https://github.com/diagrams/diagrams-lib/issues/88)++- Fix documentation of beside, \(===\), and \(|||\) re: monoidal semantics [\#83](https://github.com/diagrams/diagrams-lib/issues/83)++- reverseTrail should not generate extra segments for closed trails [\#24](https://github.com/diagrams/diagrams-lib/issues/24)++**Closed issues:**++- Test issue [\#91](https://github.com/diagrams/diagrams-lib/issues/91)++**Merged pull requests:**++- Add parametric generalizations for segments, trails, Located, etc. [\#92](https://github.com/diagrams/diagrams-lib/pull/92) ([byorgey](https://github.com/byorgey))++- Adding type signature so it compiles with GHC7.7 [\#90](https://github.com/diagrams/diagrams-lib/pull/90) ([co-dan](https://github.com/co-dan))++- bug fix: add special case for b==0 to quadform solver [\#89](https://github.com/diagrams/diagrams-lib/pull/89) ([byorgey](https://github.com/byorgey))++- Big refactoring of segments and trails. [\#87](https://github.com/diagrams/diagrams-lib/pull/87) ([byorgey](https://github.com/byorgey))++- Stop exporting Diagrams.Coordinates from Diagrams.Prelude [\#82](https://github.com/diagrams/diagrams-lib/pull/82) ([byorgey](https://github.com/byorgey))++- Generalization of R2 to D2 a [\#65](https://github.com/diagrams/diagrams-lib/pull/65) ([jbracker](https://github.com/jbracker))++## [v0.6.0.3](https://github.com/diagrams/diagrams-lib/tree/v0.6.0.3) (2013-05-04)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.6.0.2...v0.6.0.3)++**Closed issues:**++- Offset [\#80](https://github.com/diagrams/diagrams-lib/issues/80)++**Merged pull requests:**++- Added offsetSegment function [\#79](https://github.com/diagrams/diagrams-lib/pull/79) ([fryguybob](https://github.com/fryguybob))++- Working on adding curvature. [\#74](https://github.com/diagrams/diagrams-lib/pull/74) ([fryguybob](https://github.com/fryguybob))++- New `scaleInvPrim` function [\#71](https://github.com/diagrams/diagrams-lib/pull/71) ([byorgey](https://github.com/byorgey))++## [v0.6.0.2](https://github.com/diagrams/diagrams-lib/tree/v0.6.0.2) (2013-03-29)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/types-generalized...v0.6.0.2)++**Implemented enhancements:**++- Don't export Eq and Show instances for functions from Diagrams.Prelude [\#48](https://github.com/diagrams/diagrams-lib/issues/48)++**Closed issues:**++- radius is wrong [\#75](https://github.com/diagrams/diagrams-lib/issues/75)++**Merged pull requests:**++- Matrix basis rep [\#78](https://github.com/diagrams/diagrams-lib/pull/78) ([bergey](https://github.com/bergey))++## [types-generalized](https://github.com/diagrams/diagrams-lib/tree/types-generalized) (2013-02-13)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.6.0.1...types-generalized)++## [v0.6.0.1](https://github.com/diagrams/diagrams-lib/tree/v0.6.0.1) (2013-01-07)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/v0.6...v0.6.0.1)++**Fixed bugs:**++- text on zero width rect leads to nans [\#51](https://github.com/diagrams/diagrams-lib/issues/51)++- wrong result when using `beside` with circle and vector \(1 & \(-1\)\) [\#46](https://github.com/diagrams/diagrams-lib/issues/46)++- Handle `rect` with zero arguments. [\#43](https://github.com/diagrams/diagrams-lib/issues/43)++**Closed issues:**++- Generalization of color space used in rendering [\#66](https://github.com/diagrams/diagrams-lib/issues/66)++**Merged pull requests:**++- do scaling on a Path before constructing PathLike in 'rect' \(fixes \#43\) [\#70](https://github.com/diagrams/diagrams-lib/pull/70) ([byorgey](https://github.com/byorgey))++## [v0.6](https://github.com/diagrams/diagrams-lib/tree/v0.6) (2012-12-12)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/0_5_0_1...v0.6)++**New features**++- `boundingRect` function for constructing a bounding rectangle++- `bg` function for "setting the background color" (*i.e.* placing+  atop a colored bounding rectangle)++- New functions `setDefault2DAttributes` and `adjustDiaSize2D`.+  `adjustDia2D` does both --- so the behavior of `adjustDia2D` has+  not changed, but it is now possible to apply just one of the two+  adjustments using the new functions.++- `Diagrams.TwoD.Transform` now exports a `ScaleInv` type for creating+  scale-invariant objects, which are only affected by rotational+  and translational components of transformations.++- The new `Diagrams.Coordinates` module provides nicer syntax for+  constructing and pattern-matching point and vector literals.++- New `fromFixedSeg` function in `Diagrams.Segment`, which+  decomposes a `FixedSegment` into a starting point and a `Segment`.++- New `withTrace` function for setting the `Trace` of a diagram.++- Three new size-related functions:++    - New `sized` function for scaling an object to a particular size.+      One particularly nice use of this is to obviate the need to keep+      fiddling with the line width to get diagrams to "look right";+      just set the line width relative to some arbitrary scale+      (*e.g.* assuming the final diagram will fit into a 1x1 box) and+      then apply `sized` to the final diagram to make it that given+      arbitrary size.  It can also be used for easily making something+      (a diagram, path, trail, ...) the same size as something else,+      with the help of the new `sizeSpec2D` function.++    - New `sizedAs` function, for setting the size of some object to+      be "the same as" some other object.++    - New `sizeSpec2D` function for conveniently calculating the size+      of an object as a `SizeSpec2D` value (for use with the new `sized`+      funtion).++- New `extrudeEnvelope` and `intrudeEnvelope` functions for+  modifying envelopes in a single direction only, as well as new+  functions `extrude{Left,Right,Bottom,Top}` specializing+  `extrudeEnvelope` to 2D.++- `arcCW` draws clockwise arcs; `arc'` draws arcs counterclockwise+  or clockwise as the radius is positive or negative,+  respectively.++- fill color attribute is generalized to support "recommended" and+  "committed" colors; text objects use a recommended fill color of+  black.++**New instances**++- The `Show` instance for `R2` now produces something like `2 & 6`+  instead of `R2 { unR2 = (2,6) }`.  The `Read` instance has also+  been changed to match, so `read . show = id`.++- `Enveloped` instance for `FixedSegment`++- `Traced` instances for `Segment`, `FixedSegment`, `Trail`, and `Path`++- New derived `Eq` instances for `LineCapA`, `LineJoinA`, `Dashing`,+  `DashingA`, `FillRule`, `Font`, `FontSize`, `FontSlant`, `FontSlantA`,+  `FontWeight`, and `FontWeightA`++- `Renderable Ellipsoid NullBackend` instance++**API changes**++- `Data.Colour` (minus `atop` and `AffineSpace`) is now re-exported+  from Diagrams.Prelude for convenience.++- The `beneath` function is now infixl 6.++- The `BoundingBox` module has had a complete overhaul.  There is+  now a special empty bounding box, and bounding boxes are an+  instance of `Monoid`.++- The type of `withEnvelope` has been slightly generalized.++- `Diagrams.TwoD.Adjust.adjustSize` is now deprecated; it has been+  renamed and moved to `Diagrams.TwoD.Size.requiredScaleT`.++- `expandPath` has been renamed to `scalePath`.++**Dependency/version changes**++- Allow `data-default` 0.4 and 0.5++- Allow `base`-4.6++- Allow `containers`-0.5++**Bug fixes**++- `arc` and `arcT` functions now always produce counterclockwise arcs,+  as claimed.++**Implemented enhancements:**++- Enhancements for `arc`s. [\#54](https://github.com/diagrams/diagrams-lib/issues/54)++- align and friends should be in terms of a new 'Alignable' class instead of 'Boundable' [\#31](https://github.com/diagrams/diagrams-lib/issues/31)++- Tools for more accurate boundary calculations in common cases [\#30](https://github.com/diagrams/diagrams-lib/issues/30)++- Reimplement Diagrams.TwoD.Ellipse in terms of Diagrams.TwoD.Arc [\#27](https://github.com/diagrams/diagrams-lib/issues/27)++- Function to convert angles into 2D unit vectors [\#23](https://github.com/diagrams/diagrams-lib/issues/23)++- 2D specialization of 'beside' which takes an angle instead of a vector [\#22](https://github.com/diagrams/diagrams-lib/issues/22)++- Generalize showOrigin function [\#21](https://github.com/diagrams/diagrams-lib/issues/21)++- Add generic 'extent' and 'breadth' ? functions [\#20](https://github.com/diagrams/diagrams-lib/issues/20)++- Add shearing transformations to standard library [\#19](https://github.com/diagrams/diagrams-lib/issues/19)++- Add support for text [\#15](https://github.com/diagrams/diagrams-lib/issues/15)++- Allow the user to choose the fill rule used for paths when stroking [\#14](https://github.com/diagrams/diagrams-lib/issues/14)++- Image primitives [\#10](https://github.com/diagrams/diagrams-lib/issues/10)++- Merge polygon code from Dmitry Olshansky [\#4](https://github.com/diagrams/diagrams-lib/issues/4)++**Fixed bugs:**++- Enhancements for `arc`s. [\#54](https://github.com/diagrams/diagrams-lib/issues/54)++- boundingBox computes incorrect bounding box for transformed diagrams [\#39](https://github.com/diagrams/diagrams-lib/issues/39)++- hcat is really \*terrible\* performance-wise [\#28](https://github.com/diagrams/diagrams-lib/issues/28)++- stroke sets the fill rule attribute to a default value, so it can't be changed later [\#26](https://github.com/diagrams/diagrams-lib/issues/26)++- Text alignment should be with respect to descent and ascent lines rather than text bounding box [\#17](https://github.com/diagrams/diagrams-lib/issues/17)++- incorrect bounds for Bezier segments [\#11](https://github.com/diagrams/diagrams-lib/issues/11)++- More combinators in D.Combinators [\#5](https://github.com/diagrams/diagrams-lib/issues/5)++**Merged pull requests:**++- clean up and fix bugs with ScaleInv wrapper [\#69](https://github.com/diagrams/diagrams-lib/pull/69) ([byorgey](https://github.com/byorgey))++- Patch proposal for generalized Color [\#67](https://github.com/diagrams/diagrams-lib/pull/67) ([haasn](https://github.com/haasn))++- Renamed `expandPath` to `scalePath` to make room [\#61](https://github.com/diagrams/diagrams-lib/pull/61) ([fryguybob](https://github.com/fryguybob))++- Envelope deformation [\#60](https://github.com/diagrams/diagrams-lib/pull/60) ([mgsloan](https://github.com/mgsloan))++- Added `Eq` instances for some data structures. [\#59](https://github.com/diagrams/diagrams-lib/pull/59) ([fryguybob](https://github.com/fryguybob))++- More involved diameter benchmark + better implementation [\#58](https://github.com/diagrams/diagrams-lib/pull/58) ([mgsloan](https://github.com/mgsloan))++- Add NullBackend for Ellipsoid [\#57](https://github.com/diagrams/diagrams-lib/pull/57) ([mgsloan](https://github.com/mgsloan))++- Fixed `arc` and `arcT` so they are always CCW. [\#56](https://github.com/diagrams/diagrams-lib/pull/56) ([fryguybob](https://github.com/fryguybob))++- new sized, sizedAs, and sizeSpec2D functions [\#52](https://github.com/diagrams/diagrams-lib/pull/52) ([byorgey](https://github.com/byorgey))++- Update to track with diagrams-core renaming, and a better Show instance for R2 [\#47](https://github.com/diagrams/diagrams-lib/pull/47) ([byorgey](https://github.com/byorgey))++- Minor tweaks due to monoid-extra and dual-tree changes [\#45](https://github.com/diagrams/diagrams-lib/pull/45) ([byorgey](https://github.com/byorgey))++- split out default attribute setting and size adjustment into separate functions [\#42](https://github.com/diagrams/diagrams-lib/pull/42) ([byorgey](https://github.com/byorgey))++- make beneath infixl 6 [\#41](https://github.com/diagrams/diagrams-lib/pull/41) ([byorgey](https://github.com/byorgey))++- scale invariant [\#3](https://github.com/diagrams/diagrams-lib/pull/3) ([ludflu](https://github.com/ludflu))++- BoundingBox is now Monoidal [\#2](https://github.com/diagrams/diagrams-lib/pull/2) ([mgsloan](https://github.com/mgsloan))++- New module enabling nice syntax for constructing and pattern-matching literal points and vectors [\#1](https://github.com/diagrams/diagrams-lib/pull/1) ([byorgey](https://github.com/byorgey))++## [v0.5.0.1](https://github.com/diagrams/diagrams-lib/tree/0_5_0_1) (2012-07-24)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/0_5...0_5_0_1)++## [v0.5](https://github.com/diagrams/diagrams-lib/tree/0_5) (2012-03-09)++[Full Changelog](https://github.com/diagrams/diagrams-lib/compare/0_4...0_5)++**New features**+- `mkSizeSpec` function for constructing a `SizeSpec2D` from two `Maybe Double`s++- `beneath` as convenient synonym for `flip atop`++- Improvements and extensions to rounded rectangles by Peter Hall:++    + `roundedRect'` allows rounded rectangles with a different radius+      specified for each corner++    + both `roundedRect'` and `roundedRect` now allow negative radii,+      resulting in "inverted" circular corners++- [\#64](http://code.google.com/p/diagrams/issues/detail?id=64): New `Alignable` class for things that can be aligned.++- `explodeTrail` and `explodePath` have been generalized to return any+  `PathLike` type.++- New path functions `pathCentroid` (compute the centroid of a+  path's vertices) and `expandPath` (scale a path about its centroid).++- Generalized `centroid` function now exported from new module+  `Diagrams.Points`.++- Initial (experimental) support for animation:++    + `Animation` and `QAnimation` defined as synonyms for `Active`+      diagrams (see `active` package)++    + Instances for `Active`: `V`, `HasOrigin`, `Transformable`,+      `HasStyle`, `PathLike`, `Juxtaposable`, `Alignable`++    + `animEnvelope` and `animRect` functions for automatic bounding of+      animations++- `addClosingSegment` function for making the implicit closing+  segment of a closed trail explicit++- Improvements to `BoundingBox` module from Michael Sloan: querying+  of `BoundingBox` bounds, corners, extents, and transformation of+  objects to fit within a given box.++- Text alignment options from Michael Sloan++- `view` function for restricting a diagram's envelope to a+  rectangular region.++- `iterateN` function for iterating a finite number of times++- `atAngle` for placing two diagrams next to each other along a+  specified angle.++- `padX` and `padY` functions for padding in the X- and Y-directions+  independently.+++- generalized `showOrigin` function from Ian Ross++- [\#40](http://code.google.com/p/diagrams/issues/detail?id=40): add shears to `Diagrams.TwoD.Transform`++**Performance improvements**++- Use a balanced folding scheme for `cat'`, reducing time in some+  cases from \\(O(n^2)\\) to \\(O(n \\log n)\\)++- More efficient implementation of `beside`++**New instances**++- `Alignable` instances for `QDiagram`, `Path`, `Envelope`, `Active`, `Set`,+  `Map`, `[]`++- `Renderable` instances for `NullBackend` (`Trail`, `Path`, `Segment`,+  `Image`, `Text`)++- Instances for `Active`: `V`, `HasOrigin`, `Transformable`,+  `HasStyle`, `PathLike`, `Juxtaposable`, `Alignable`++**API changes**++- `R2` used to be a synonym for `(Double, Double)` but is now+  abstract. To convert between pairs of `Doubles` and `R2`, use the+  new functions `r2` and `unr2`.  There are two reasons for this+  change:+      1. to allow for future changes to the implementation of `R2`;+      2. `(Double, Double)` was an awkward special case getting in the+       way of useful tuple instances for classes like `HasOrigin`,+       `Enveloped`, and so on.++- `circlePath` has been removed; its functionality has been+  subsumed by `circle`.++- `adjustSegment` now takes an extra tolerance option.++- Ellipses are now represented using Bezier approximations rather+  than a separate special type.++- `BoundingBox` no longer has a `Transformable` instance; the old+  instance was misleading at best.++- Change semantics of `beside` (hence also `(|||)` and `(===)`) so the+  result's origin is the same as that of the first argument.++- `adjustDia2D` now takes a `SizeSpec2D`.++- `beside` and related functions are now implemented in terms of+  `juxtapose`.++- Instead of taking an `R2`, `roundedRect` now takes a pair of+  `Double`s, to be more consistent with `rect`.++**Dependency/version changes**++- Support for GHC 7.4.1:++    + depend on `colour` >= 2.3.2++    + update `base` and `array` upper bounds++- bump `vector-space` upper bound++**Bug fixes**++- Avoid scale by zero error in `showOrigin`.+- Base `adjustDia2D` translation on output size rather than diagram size.++## [v0.4.0.1] () (30 October 2011)+------------------------++- bump `data-default` dependency to allow version 0.3++## [v0.4]() (23 October 2011)+--------------------++**documentation fixes**++**New functions and primitives**+++ `wedge` shape primitive+++ `fromDirection` function for converting angles to 2D unit vectors;++  inverse function `direction` generalized to return any Angle type++ New functions for computing and adjusting segment lengths+++ `scaleUToX` and `scaleUToY` for doing uniform scales+  resulting in a desired width or height.+++ `circlePath`, `reversePath`, `decoratePath`+++**New features**+++ Completely new and improved polygon generation API+++ Cubic splines+++ User-controllable path fill rules++**Bug fixes**+++ fix incorrect corner case in arc generation+++ fix incorrect `reverseTrail` function++## [v0.3]() (18 June 2011)+-----------------++**New features**+++ new customizable `stroke'` function which lets you assign names to+  path vertices+++ `circle` and `square` functions now take a size argument+++ function for adjusting 2D diagrams to requested size abstracted+  from cairo backend+++ generalize `PathLike` class to include an instance for diagrams,+  and collapse things like `polygon`/`polygonPath` into a single+  polymorphic function+++ basic text support+++ basic support for external images+++ very sketchy initial proof-of-concept library of 3D primitives.+  See also diagrams-povray package.++**Bug fixes**+++ Issue 32 (`mempty` not behaving correctly within concatenations)++## [v0.2]() (3 June 2011)+----------------++**New functions and primitives**+++ `scaleToX` and `scaleToY` for scaling to an absolute width/height+++ `reverseTrail`+++ new `Angle` class and ability to use radians, degrees, or circle fractions+  for specifying angles+++ `rotateAbout` and `reflectAbout` transformations based on new conjugation functions+++ `rect` and `roundedRect` primitives+++ `explodeTrail`/`Path` for breaking trails and paths into individual segments++**New features**+++ opacity attribute+++ support for path clipping++* **New modules**+    + `Diagrams.BoundingBox`++**Fixes and updates**++++ `withBounds` now properly uses the new bounds instead of just combining+      them with the old++## [v0.1.1]() (18 May 2011)+------------------++* minor documentation fixes++* link to new website++## [v0.1]() [17 May 2011]+----------------++* initial preview release++\* *This Change Log was automatically generated by (and then edited by hand) [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
− CHANGES.markdown
@@ -1,754 +0,0 @@-1.2.0.9 (2 April 2015)------------------------- - allow `lens-4.9`- - allow `vector-space-0.10`--1.2.0.8 (13 Jan 2015)------------------------- Allow `vector-space-0.9`-- Allow `lens-4.7`--1.2.0.7 (07 Dec 2014)------------------------- Allow `JuicyPixels-3.2`--1.2.0.6 (04 Dec 2014)------------------------- Allow `semigroups-0.16`--1.2.0.5 (17 November 2014)------------------------------ Allow `lens-4.6`--1.2.0.4 (8 October 2014)---------------------------- Allow and require `optparse-applicative-0.11`--1.2.0.3 (7 September 2014)------------------------------ Allow `optparse-applicative-0.10`--1.2.0.2 (22 August 2014)---------------------------- Allow `lens-4.4`--1.2.0.1 (4 June 2014)------------------------- Bug fix: arrow head and tail length and gaps specified with `Local`-  now work correctly ([#193](https://github.com/diagrams/diagrams-lib/issues/193)).--1.2 (27 May 2014)--------------------* **New features**--    - Several attributes (such as line width, dashing size, arrowhead-      size, and font size) that formerly had a value of type `Double`-      now have the more general type `Measure R2`. This allows the-      attributes to be specified relative to one of four measurement-      frames: `Local`, `Global`, `Normalized`, and `Output`.--    - New DSL for specifying measurements.--    - New synonyms for specifying measurements, *e.g.* `thin`,-      `thick`, and `medium`, `large`.--    - Support for radial and linear gradients for fills and strokes.--    - New `DImage` type that supports both embedded and external images in-      Backends that support them.--    - New `lengths` Traversal for setting `headLength` and `tailLength`-      simultaneously.--    - `Frustrum` and `Box` shapes added to `Diagrams.ThreeD.Shapes`.--    - New function `quartForm` to find roots of quartic polynomials.--    - New Lenses for polar coordinates.--    - New trig functions, `sinA`, `atanA`, etc. which take `Angle` as-      input or output.--* **New instances**--    - `Transformable` instances for `LineWidth`, `Dashing`,-      `LineTexture`, and  `FillTexture`.--* **API changes**--    - `FillColor` and `LineColor` attributes have been replaced with-      the more general `FillTexture` and `LineTexture`. Use the `solid`-      function to convert a color to a texture.--    - The size of arrow heads and tails is now specified in terms of-      length instead of the radius of their circumcircle.--    - Gaps at the ends of arrows are now specified using `Measure R2`.--    - The `gap` traversal has been replaced by `gaps` for consistency-      in naming, though `gap` is still provided for backwards compatibility.--    - `fontSize` now takes a value of type `Measure R2`.--    - Get rid of (bitrotted) `Show` backend.--    - Functions in `TwoD.Adjust` now return the adjustment-      transformation itself in addition to the resized `Diagram` and-      `Options` record; this can be used, *e.g.* to convert screen-      coordinates back into diagram coordinates.--    - Export `pathLocSegments`.--    - The `avgScale` function has been moved to `Diagrams.Core`.--    - The `Angle` definition and related functions (*e.g.*-      `angleBetween`) have moved to a separate module, `Diagrams.Angle`.--    - A separate `Diagrams.TwoD.Attributes` module now contains most-      of the attributes that require 2D transformation instances.--    - The `splitColorFills` function has been replaced by `splitTextureFills`.--* **Dependency/version changes**--  - Allow `semigroups-0.15`--  - Allow `opt-parse-applicative-0.9.0--  - Allow `lens-4.2`--1.1.0.7 (15 May 2014)---------------------------    - Allow `semigroups-0.14`--1.1.0.6 (10 April 2014)---------------------------    - Allow `semigroups-0.13`--1.1.0.4 (4 April 2014)-------------------------  - Require `intervals-0.7`-  - Give `connectOutside` a reasonable behavior even when one or both-    endpoints has no trace--1.1.0.3 (19 March 2014)-------------------------  - Allow `lens-4.1`--1.1.0.2 (18 March 2014)--------------------------  - Allow `optparse-applicative-0.8`--1.1.0.1 (9 March 2014)-------------------------  - Allow `vector-space-points-0.2`--1.1 (8 March 2014)---------------------* **New features**--    - Support for `Deformation`s, arbitrary (non-affine)-      transformations on objects such as points, paths, and located-      trails (though not on diagrams).--    - New functions `clipTo`, which clips a diagram's envelope and-      trace along with its visual representation, and `clipped`, which-      clips the diagram's visual representation but replaces its-      envelope and trace with those of the clipping path.--    - New `arrowV` function, for creating an arrow with the direction-      and magnitude of a given vector.--    - `gap` traversal, for setting the head and tail gaps of an arrow-      simultaneously.--    - Generalized types for `centerXY` and `snugXY`, based on new-      `basis` function from `diagrams-core--    - New 3D `Transform`s, alignment, and 3D-specific `Prelude`.--    - New `frame` function similar to `pad`, but increases the envelope-      of a diagram by an amount specified in local units in every direction-      irrespective of the local origin.--    - New `splitFills` function for pushing fill attributes down to-      subtrees containing only loops (mostly of relevance only to-      backend implementors).--* **New instances**--    - `Typeable` instances for all data types that are used as diagram-      primitives.-    - `Sectionable` instance for `FixedSegment`.--* **API changes**--    - `Angle` is now a type, rather than a class.  It uses a single-      internal representation for angles, and lenses `turn`, `rad,`-      and `deg` are supplied for constructing (using `@@`) and viewing-      (using `^.`) `Angle`s in various units.  In addition, the `Num`-      instance for `Angle` has been removed, eliminating a class of-      errors where a bare number is interpreted in units other than-      what you expect.--    - Removed `Num` instance for angles.--* **Dependency/version changes**--    - Require `lens >= 4.0`.-	- Allow `array-0.5`.-	- Allow `hashable-1.1`.-	- Remove `NumInstances` dependency.--* **Bug fixes**--    - Exclude joins in offsets on close segments (#160).-    - Exclude extra segment when joining loops in offset (#155).--* **Performance improvements**--    - `colorToSRGBA` function now avoids expensive matrix operations,-      offering dramatic speedups in rendering diagrams with many color-      attributes.--1.0.1 (26 January 2014)--------------------------    - Depend on `hashable` package, and add `Hashable` instance for-      `SizeSpec2D`.--      Technically, the PVP specifies that adding a new instance-      requires a major version bump.  However, I highly doubt anyone-      was making their own orphan `Hashable` instances before.  Feel-      free to yell at Brent if this breaks your build.--1.0.0.1 (28 November 2013)-----------------------------    - Allow semigroups-0.12--1.0 (25 November 2013)-------------------------* **New features**--    - New modules `Diagrams.TwoD.Arrow` and `Diagrams.TwoD.Arrowheads`-      for creating arrows.-    - New module `Diagrams.Backend.CmdLine`, providing a flexible-      framework for creating command-line-driven diagram rendering executables.-    - New functions in `Diagrams.Offset`: `offsetTrail` and-      `offsetPath` for one-sided offsets of trails and paths;-      `expandTrail` and `expandPath` for "stroking" trails and paths,-      computing a path whose fill corresponds to the stroke of the-      given trail or path.-    - New module `Diagrams.Tangent` for computing tangent and normal-      vectors of segments, trails, and paths.-    - New functions in `Diagrams.Align` to allow diagrams to be aligned by `Trace`-      called `snug`, `snugBy` and `snugCenter`-      and the ability to define other boundary functions for alignment. Functions-      `snugL`, `snugR`, etc. are included in `TwoD.Align`.-    - Lenses from `Control.Lens` are now used consistently for record fields-      throughout the library.-    - New function `angleRatio` for calculating the ratio between two angles.-    - Restricted identity functions `asTurn`, `asRad`, and `asDeg` for-      resolving type ambiguity-    - New miter limit attribute.-    - New function `annularWedge` in `TwoD.Arc`-    - New `avgScale` utility in `TwoD.Transform`, for backends which-      cannot fully implement freezing of line width-    - New function `heptagon`, a vast improvement over the linguistic-      frankenstein `septagon`.-    - New function `lookupName` (re-exported from `diagrams-core`) for-      simple lookups of named subdiagrams-    - New function `angleBetween` to calculate the angle between two-      vectors.-    - New function `arcBetween` to draw an arc between two given-      points.-    - A bunch of new modules containing types, primitives and-      utilities for constructing 3D diagrams: `Diagrams.ThreeD.Align`,-      `.Camera`, `.Light`, `.Shapes`, `.Transform`, `.Types`, and-      `.Vector`.  This is still a "feature preview" (in particular,-      appropriate 3D backends are still under construction).--* **New instances**--    - `AdditiveGroup` and `VectorSpace` instances for `Turn`, `Rad`, `Deg`-    - `Alignable` instance for `(->) e`-	- `Default` instances for `FillRule`, `FillRuleA`, `LineJoin`,-      `LineCap`, `FillColor`-	- `Show` instances for `FillRule`, `FillRuleA`--* **API changes**--    - `e` no longer exported from `Diagrams.Prelude`.-    - `Diagrams.BoundingBox` is no longer exported from `Diagrams.Prelude`.-    - Re-export `Diagrams.Core.pointDiagram` from `Diagrams.Prelude`.-    - Added `fromAlphaColour` method to `Color` class.-    - `&` renamed to `^&`-    - Stop re-exporting `tan`, `over`, and `both` from `Data.Colour`.-	- New coordinate lenses `_x`, `_y`, and `_z` for `R2`, `P2`, `R3`, `P3`-    - Export `fullTurn` from `Diagrams.Prelude`.-    - `Codomain (Located a)` is now `Point (Codomain a)` instead of-      `Located (Codomain a)`.-	- Export `domainBounds` from `Diagrams.Parametric`.-	- Adjusting functionality moved from `Diagrams.Parametric` to its-      own module, `Diagrams.Parametric.Adjust`.-    - Rename `strokeT` (and primed variant) to `strokeTrail`; rename-      `strokeLocT` to `strokeLocTrail`.-    - `ScaleInv` is now in its own module, `Diagrams.TwoD.Transform.ScaleInv`.-	- Re-export `Image` type (but not constructor) from `Diagrams.TwoD`-    - Removed `Floating` and `RealFloat` instances for `Turn` and `Deg`-    - `offsetSegment` now returns a `Located` instead of a tuple.-    - Removed `Num` and `Fractional` instances for `R2`.--* **Dependency/version changes**--    - Remove `newtype` dependency-    - New dependencies on `lens`, `tagged`, `optparse-applicative`,-      `filepath`, `safe`, `vector-space-points`, `MemoTrie`-    - Depend on `intervals >= 0.3 && < 0.5`.--* **Bug fixes**--    - Depend on `intervals 0.3`, which allows diagrams to build on-      Windows, by evading a GHCi linker bug which affects the FFI use in-      previous versions of intervals ([diagrams-contrib#14](https://github.com/diagrams/diagrams-contrib/issues/14))--    - Use point envelope at the origin for text objects instead of an-      empty envelope-      ([#115](https://github.com/diagrams/diagrams-lib/issues/115),-      [#116](https://github.com/diagrams/diagrams-lib/issues/116)).-    - Adjusting the end of a trail now works correctly ([#95](https://github.com/diagrams/diagrams-lib/issues/95)).-    - Only look for miter join on corners in `Diagrams.TwoD.Offset` ([#118](https://github.com/diagrams/diagrams-lib/issues/118)).-    - `wedge` from `Diagrams.TwoD.Arc` is now a Loop ([#99](https://github.com/diagrams/diagrams-lib/issues/99))--* **Performance improvements**--    - `R2` is now strict and `UNPACK`ed-    - Add strictness to `Offset`, `Segment`, `OffsetEnvelope`, and `SizeSpec2D`.-	- Make `getEnvelope` calculation for `Segment` more efficient by-      floating divisions out of the inner calculation.-    - Use a specialized `HasTrie` instance for `R2`.--0.7.1.1 (27 September 2013)------------------------------* allow semigroups-0.11--0.7.1 (11 September 2013)----------------------------* **New features**--    - New standard miter limit attribute-    - New functions `lineColorA`, `lineWidthA`, `lineMiterLimitA`,-      `fontSizeA` for directly applying attribute values-    - `setDefault2DAttributes` now sets default line cap (butt), line-      join (miter), and miter limit (10) attributes--* **New instances**--    - `Data.Default` instances for-        - `LineCap`-	- `LineJoin`-	- `LineMiterLimit`-	- `LineWidth`-	- `LineColor`-	- `FontSize`--0.7 (9 August 2013)----------------------* **New features**--    - New module `Diagrams.TwoD.Curvature`, for computing the-      curvature of 2D segments at any given point.-    - New module `Diagrams.Offset`, containing an `offsetSegment`-      function that builds a trail a fixed distance from the original-      segment.  This is a precursor to planned functions `offsetTrail`-      and `offsetPath`.-    - New function `Diagrams.TwoD.Transform.onBasis`, for extracting a-      matrix representation of a 2D transformation-    - New functions `extrudeEnvelope` and `intrudeEnvelope`, for-      extending or shrinking an envelope only in a certain direction.-    - Generalize the `Color` class to absolute colors.-      This addresses concerns raised in issue #66 by letting the backend-      choose which color space to render `Color` instances to. Functions are-      provided for backwards compatibility with the old semantics.-    - New function `scaleInvPrim` for creating a diagram from a single-      scale-invariant primitive.-    - New module `Diagrams.Parametric`, containing a collection of-      classes abstracting over "parametric" things: `Parametric`,-      `DomainBounds`, `EndValues`, `Sectionable`, and `HasArcLength`,-      with instances for segments, trails, and related things.-    - A big refactoring of segments and trails:-        - Segments can now be either "closed" or "open".-        - There are now two types of trails: "lines" (which travel-          from point A to point B) or "loops" (closed curves which end-          where they started). `Trail` is now a wrapper type which can-          contain both loops and lines.-        - There is a new `Located` wrapper type for adding locations to-          translation-invariant things.  `Path`s now consist of a-          collection of `Located Trail`s.-        - The `PathLike` class is now renamed to `TrailLike`; the-          `trailLike` function takes a `Located Trail` as input.-    - New convenience functions `boundaryFrom` and `boundaryFromMay`,-      for computing boundaries of subdiagrams.-    - Re-export from `diagrams-lib` a lot of things defined in-      `diagrams-core`, to make them easier for users to find.  Several-      new modules have been created as a result: `Diagrams.Query`,-      `Diagrams.Envelope`, `Diagrams.Trace`, and `Diagrams.Names`.-    - Export the `centroid` function from `Diagrams.Prelude`.-    - `triangle` is now a synonym for `eqTriangle`.--* **New instances**--    - `IsPrim` instances for `Path`, `Ellipsoid`, `Image`, `Text`, and-      `ScaleInv`-    - `Eq`, `Ord`, and `Show` instances for `SizeSpec2D`--* **API changes**--    - `CircleFrac` has been renamed `Turn` (though `CircleFrac` is-      retained as a deprecated synonym).-    - `Diagrams.Coordinates` is no longer exported from-      `Diagrams.Prelude`.  This is for compatibility with `lens`, as `(&)`-      is a rather important lens operator and clashes with-      `Diagrams.Coordinates`.  Users who want the `Coordinates` stuff can import-      `Diagrams.Coordinates` explicitly.--* **Dependency/version changes**--    - allow `base-4.7`-    - upgrade to `monoid-extras-0.3`-    - depend on `data-default-class` instead of `data-default`-    - Tested with GHC 7.7.--* **Bug fixes**--    - Added a special case that was a not handled properly by the-      quadratic solver, resulting in bogus envelopes in certain cases-      (#88).-    - Import only `Data.NumInstances.Tuple` instead of-      `Data.NumInstances`. Previously, `Diagrams.Prelude` exported-      `Eq`, `Show`, and `Num` instances for functions and tuples; now-      it only exports tuple instances. Users wishing to use-      `Diagrams.CubicSpline` with a vector space built over functions (!?)-      can import `Data.NumInstances.Function` themselves. (#48)-    - Do scaling on a `Path` *before* constructing a `TrailLike` in-      `rect` (#43)--0.6.0.3 (4 May 2013)-----------------------* bump upper bound to allow `NumInstances-1.3`--0.6.0.2 (28 March 2013)--------------------------* bump upper bound to allow `NumInstances-1.2`--* Quadratic solver is now more numerically stable, getting rid of some-  incorrect behavior of `juxtapose`-  ([\#46](https://github.com/diagrams/diagrams-lib/issues/46))--0.6.0.1: 7 January 2013--------------------------* allow `semigroups-0.9`--0.6: 11 December 2012------------------------* **New features**--    - `boundingRect` function for constructing a bounding rectangle--    - `bg` function for "setting the background color" (*i.e.* placing-      atop a colored bounding rectangle)--    - New functions `setDefault2DAttributes` and `adjustDiaSize2D`.-      `adjustDia2D` does both --- so the behavior of `adjustDia2D` has-      not changed, but it is now possible to apply just one of the two-      adjustments using the new functions.--    - `Diagrams.TwoD.Transform` now exports a `ScaleInv` type for creating-      scale-invariant objects, which are only affected by rotational-      and translational components of transformations.--    - The new `Diagrams.Coordinates` module provides nicer syntax for-      constructing and pattern-matching point and vector literals.--    - New `fromFixedSeg` function in `Diagrams.Segment`, which-      decomposes a `FixedSegment` into a starting point and a `Segment`.--    - New `withTrace` function for setting the `Trace` of a diagram.--    - Three new size-related functions:--        - New `sized` function for scaling an object to a particular size.-          One particularly nice use of this is to obviate the need to keep-          fiddling with the line width to get diagrams to "look right";-          just set the line width relative to some arbitrary scale-          (*e.g.* assuming the final diagram will fit into a 1x1 box) and-          then apply `sized` to the final diagram to make it that given-          arbitrary size.  It can also be used for easily making something-          (a diagram, path, trail, ...) the same size as something else,-          with the help of the new `sizeSpec2D` function.--        - New `sizedAs` function, for setting the size of some object to-          be "the same as" some other object.--        - New `sizeSpec2D` function for conveniently calculating the size-          of an object as a `SizeSpec2D` value (for use with the new `sized`-          funtion).--    - New `extrudeEnvelope` and `intrudeEnvelope` functions for-      modifying envelopes in a single direction only, as well as new-      functions `extrude{Left,Right,Bottom,Top}` specializing-      `extrudeEnvelope` to 2D.--    - `arcCW` draws clockwise arcs; `arc'` draws arcs counterclockwise-      or clockwise as the radius is positive or negative,-      respectively.--    - fill color attribute is generalized to support "recommended" and-      "committed" colors; text objects use a recommended fill color of-      black.--* **New instances**--    - The `Show` instance for `R2` now produces something like `2 & 6`-      instead of `R2 { unR2 = (2,6) }`.  The `Read` instance has also-      been changed to match, so `read . show = id`.--    - `Enveloped` instance for `FixedSegment`--    - `Traced` instances for `Segment`, `FixedSegment`, `Trail`, and `Path`--    - New derived `Eq` instances for `LineCapA`, `LineJoinA`, `Dashing`,-      `DashingA`, `FillRule`, `Font`, `FontSize`, `FontSlant`, `FontSlantA`,-      `FontWeight`, and `FontWeightA`--    - `Renderable Ellipsoid NullBackend` instance--* **API changes**--    - `Data.Colour` (minus `atop` and `AffineSpace`) is now re-exported-      from Diagrams.Prelude for convenience.--    - The `beneath` function is now infixl 6.--    - The `BoundingBox` module has had a complete overhaul.  There is-      now a special empty bounding box, and bounding boxes are an-      instance of `Monoid`.--    - The type of `withEnvelope` has been slightly generalized.--    - `Diagrams.TwoD.Adjust.adjustSize` is now deprecated; it has been-      renamed and moved to `Diagrams.TwoD.Size.requiredScaleT`.--    - `expandPath` has been renamed to `scalePath`.--* **Dependency/version changes**--    - Allow `data-default` 0.4 and 0.5-    - Allow `base`-4.6-    - Allow `containers`-0.5--* **Bug fixes**--    - `arc` and `arcT` functions now always produce counterclockwise arcs,-      as claimed.--0.5: 9 March 2012--------------------* **New features**-    - `mkSizeSpec` function for constructing a `SizeSpec2D` from two `Maybe Double`s-    - `beneath` as convenient synonym for `flip atop`-    - Improvements and extensions to rounded rectangles by Peter Hall:-        + `roundedRect'` allows rounded rectangles with a different radius-          specified for each corner-        + both `roundedRect'` and `roundedRect` now allow negative radii,-          resulting in "inverted" circular corners-    - [\#64](http://code.google.com/p/diagrams/issues/detail?id=64): New `Alignable` class for things that can be aligned.-    - `explodeTrail` and `explodePath` have been generalized to return any-      `PathLike` type.-    - New path functions `pathCentroid` (compute the centroid of a-      path's vertices) and `expandPath` (scale a path about its centroid).-    - Generalized `centroid` function now exported from new module-      `Diagrams.Points`.-    - Initial (experimental) support for animation:-        + `Animation` and `QAnimation` defined as synonyms for `Active`-          diagrams (see `active` package)-        + Instances for `Active`: `V`, `HasOrigin`, `Transformable`,-          `HasStyle`, `PathLike`, `Juxtaposable`, `Alignable`-        + `animEnvelope` and `animRect` functions for automatic bounding of-          animations-    - `addClosingSegment` function for making the implicit closing-      segment of a closed trail explicit-    - Improvements to `BoundingBox` module from Michael Sloan: querying-      of `BoundingBox` bounds, corners, extents, and transformation of-      objects to fit within a given box.-    - Text alignment options from Michael Sloan-    - `view` function for restricting a diagram's envelope to a-      rectangular region.-    - `iterateN` function for iterating a finite number of times-    - `atAngle` for placing two diagrams next to each other along a-      specified angle.-    - `padX` and `padY` functions for padding in the X- and Y-directions-      independently.-    - generalized `showOrigin` function from Ian Ross-    - [\#40](http://code.google.com/p/diagrams/issues/detail?id=40): add shears to `Diagrams.TwoD.Transform`--* **Performance improvements**-    - Use a balanced folding scheme for `cat'`, reducing time in some-      cases from \\(O(n^2)\\) to \\(O(n \\log n)\\)-    - More efficient implementation of `beside`--* **New instances**-    - `Alignable` instances for `QDiagram`, `Path`, `Envelope`, `Active`, `Set`,-      `Map`, `[]`-    - `Renderable` instances for `NullBackend` (`Trail`, `Path`, `Segment`,-      `Image`, `Text`)-    - Instances for `Active`: `V`, `HasOrigin`, `Transformable`,-      `HasStyle`, `PathLike`, `Juxtaposable`, `Alignable`--* **API changes**-    - `R2` used to be a synonym for `(Double, Double)` but is now-      abstract. To convert between pairs of `Doubles` and `R2`, use the-      new functions `r2` and `unr2`.  There are two reasons for this-      change:-          1. to allow for future changes to the implementation of `R2`;-          2. `(Double, Double)` was an awkward special case getting in the-           way of useful tuple instances for classes like `HasOrigin`,-           `Enveloped`, and so on.-    - `circlePath` has been removed; its functionality has been-      subsumed by `circle`.-    - `adjustSegment` now takes an extra tolerance option.-    - Ellipses are now represented using Bezier approximations rather-      than a separate special type.-    - `BoundingBox` no longer has a `Transformable` instance; the old-      instance was misleading at best.-    - Change semantics of `beside` (hence also `(|||)` and `(===)`) so the-      result's origin is the same as that of the first argument.-    - `adjustDia2D` now takes a `SizeSpec2D`.-    - `beside` and related functions are now implemented in terms of-      `juxtapose`.-    - Instead of taking an `R2`, `roundedRect` now takes a pair of-      `Double`s, to be more consistent with `rect`.--* **Dependency/version changes**-    - Support for GHC 7.4.1:-        + depend on `colour` >= 2.3.2-        + update `base` and `array` upper bounds-    - bump `vector-space` upper bound--* **Bug fixes**-    - Avoid scale by zero error in `showOrigin`.-    - Base `adjustDia2D` translation on output size rather than diagram size.--0.4.0.1: 30 October 2011---------------------------* bump `data-default` dependency to allow version 0.3--0.4: 23 October 2011-----------------------* **documentation fixes**--* **New functions and primitives**--    + `wedge` shape primitive-    + `fromDirection` function for converting angles to 2D unit vectors;-      inverse function `direction` generalized to return any Angle type-    + New functions for computing and adjusting segment lengths-    + `scaleUToX` and `scaleUToY` for doing uniform scales-      resulting in a desired width or height.-    + `circlePath`, `reversePath`, `decoratePath`--* **New features**--    + Completely new and improved polygon generation API-    + Cubic splines-    + User-controllable path fill rules--* **Bug fixes**--    + fix incorrect corner case in arc generation-    + fix incorrect `reverseTrail` function--0.3: 18 June 2011--------------------* **New features**-    + new customizable `stroke'` function which lets you assign names to-      path vertices-    + `circle` and `square` functions now take a size argument-    + function for adjusting 2D diagrams to requested size abstracted-      from cairo backend-    + generalize `PathLike` class to include an instance for diagrams,-      and collapse things like `polygon`/`polygonPath` into a single-      polymorphic function-    + basic text support-    + basic support for external images-    + very sketchy initial proof-of-concept library of 3D primitives.-      See also diagrams-povray package.--* **Bug fixes**-    + Issue 32 (`mempty` not behaving correctly within concatenations)--0.2: 3 June 2011-------------------* **documentation fixes**--* **New functions and primitives**-    + `scaleToX` and `scaleToY` for scaling to an absolute width/height-    + `reverseTrail`-    + new `Angle` class and ability to use radians, degrees, or circle fractions-      for specifying angles-    + `rotateAbout` and `reflectAbout` transformations based on new conjugation functions-    + `rect` and `roundedRect` primitives-    + `explodeTrail`/`Path` for breaking trails and paths into individual segments--* **New features**-    + opacity attribute-    + support for path clipping--* **New modules**-    + `Diagrams.BoundingBox`--* **Fixes and updates**-    + `withBounds` now properly uses the new bounds instead of just combining-      them with the old--0.1.1: 18 May 2011---------------------* minor documentation fixes-* link to new website--0.1: 17 May 2011-------------------* initial preview release
LICENSE view
@@ -1,21 +1,35 @@-Copyright (c) 2011-2014 diagrams-lib team:+Copyright (c) 2011-2016 diagrams-lib team: +  Florent Becker <florent.becker@univ-orleans.fr>   Jan Bracker <jan.bracker@googlemail.com>   Daniel Bergey <bergey@alum.mit.edu>+  Vincent Berthoux <vincent.berthoux@gmail.com>+  Christopher Chalmers <c.chalmers@me.com>+  Michael Chavinda <mchavinda@colgate.edu>   Denys Duchier <denys.duchier@univ-orleans.fr>   Daniil Frumin <difrumin@gmail.com>+  Ben Gamari <ben@smart-cactus.org>+  Allan Gardner <allanegardner@gmail.com>+  Pontus Granström <pnutus@gmail.com>+  Gabor Greif <ggreif@gmail.com>   Niklas Haas <nand@lavabit.com>   Peter Hall <peter.hall@memorphic.com>+  Dashiell Halpern   Claude Heiland-Allen <claudiusmaximus@goto10.org>   Deepak Jois <deepak.jois@gmail.com>+  Sidharth Kapur <sidharthkapur1@gmail.com>+  Taru Karttunen <taruti@taruti.net>   John Lato <jwlato@tsurucapital.com>+  Konrad Madej <kdmadej@gmail.com>   Chris Mears <chris@cmears.id.au>+  Alexis Praga <praga@cerfacs.fr>   Jeffrey Rosenbluth <jeffrey.rosenbluth@gmail.com>   Ian Ross <ian@skybluetrades.net>   Carlos Scheidegger <cscheid@research.att.com>   Michael Sloan <mgsloan@gmail.com>   Jim Snavely <ludflu@gmail.com>   Kanchalai Suveepattananont <ksuvee@seas.upenn.edu>+  Robert Vollmert <rfvollmert@gmail.com>   Scott Walck <walck@lvc.edu>   Ryan Yates <fryguybob@gmail.com>   Brent Yorgey <byorgey@cis.upenn.edu>
README.markdown view
@@ -1,4 +1,4 @@-[![Build Status](https://secure.travis-ci.org/diagrams/diagrams-lib.png)](http://travis-ci.org/diagrams/diagrams-lib)+[![Build Status](https://github.com/diagrams/diagrams-lib/actions/workflows/haskell-ci.yml/badge.svg)](https://github.com/diagrams/diagrams-lib/actions/workflows/haskell-ci.yml)  The standard library for [diagrams](http://projects.haskell.org/diagrams/), a Haskell embedded
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple+import           Distribution.Simple main = defaultMain
diagrams-lib.cabal view
@@ -1,5 +1,5 @@ Name:                diagrams-lib-Version:             1.2.0.9+Version:             1.5.1 Synopsis:            Embedded domain-specific language for declarative graphics Description:         Diagrams is a flexible, extensible EDSL for creating                      graphics of many types.  Graphics can be created@@ -7,8 +7,10 @@                      multiple backends.  diagrams-lib provides a                      standard library of primitives and operations for                      creating diagrams.  To get started using it, see-                     "Diagrams.Prelude".-Homepage:            http://projects.haskell.org/diagrams+                     the "Diagrams" module, and refer to the tutorials and+                     documentation on the diagrams website,+                     <http://diagrams.github.io>.+Homepage:            http://diagrams.github.io License:             BSD3 License-file:        LICENSE Author:              Brent Yorgey@@ -16,103 +18,165 @@ Bug-reports:         http://github.com/diagrams/diagrams-lib/issues Category:            Graphics Build-type:          Simple-Cabal-version:       >=1.10-Extra-source-files:  CHANGES.markdown, README.markdown, diagrams/*.svg-Extra-doc-files:     diagrams/*.svg-Tested-with:         GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.1+Cabal-version:       1.18+Extra-source-files:  diagrams/*.svg+Extra-doc-files:     CHANGELOG.md, README.markdown, diagrams/*.svg+Tested-with:         GHC ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.6 || ==9.8.2 || ==9.10.1 || ==9.12.1 Source-repository head   type:     git   location: http://github.com/diagrams/diagrams-lib.git  Library-  Exposed-modules:     Diagrams.Prelude,-                       Diagrams.Prelude.ThreeD,+  Exposed-modules:     Diagrams,+                       Diagrams.Prelude,                        Diagrams.Align,                        Diagrams.Angle,-                       Diagrams.Combinators,-                       Diagrams.Coordinates,+                       Diagrams.Animation,+                       Diagrams.Animation.Active,                        Diagrams.Attributes,                        Diagrams.Attributes.Compile,-                       Diagrams.Points,+                       Diagrams.Backend.CmdLine,+                       Diagrams.BoundingBox,+                       Diagrams.Combinators,+                       Diagrams.Coordinates,+                       Diagrams.CubicSpline,+                       Diagrams.CubicSpline.Boehm,+                       Diagrams.CubicSpline.Internal,+                       Diagrams.Deform+                       Diagrams.Direction,+                       Diagrams.Envelope,+                       Diagrams.LinearMap,                        Diagrams.Located,+                       Diagrams.Names,                        Diagrams.Parametric,                        Diagrams.Parametric.Adjust,+                       Diagrams.Path,+                       Diagrams.Points,+                       Diagrams.Query,                        Diagrams.Segment,+                       Diagrams.Size,+                       Diagrams.Tangent,+                       Diagrams.ThreeD,+                       Diagrams.ThreeD.Align,+                       Diagrams.ThreeD.Attributes,+                       Diagrams.ThreeD.Camera,+                       Diagrams.ThreeD.Deform,+                       Diagrams.ThreeD.Light,+                       Diagrams.ThreeD.Shapes,+                       Diagrams.ThreeD.Size,+                       Diagrams.ThreeD.Transform,+                       Diagrams.ThreeD.Projection,+                       Diagrams.ThreeD.Types,+                       Diagrams.ThreeD.Vector,+                       Diagrams.Trace,                        Diagrams.Trail,                        Diagrams.TrailLike,-                       Diagrams.Path,-                       Diagrams.CubicSpline,-                       Diagrams.CubicSpline.Internal,-                       Diagrams.Solve,-                       Diagrams.Tangent,                        Diagrams.Transform,-                       Diagrams.Deform-                       Diagrams.BoundingBox,-                       Diagrams.Names,-                       Diagrams.Envelope,-                       Diagrams.Trace,-                       Diagrams.Query,+                       Diagrams.Transform.ScaleInv,+                       Diagrams.Transform.Matrix,                        Diagrams.TwoD,-                       Diagrams.TwoD.Types,+                       Diagrams.TwoD.Adjust,                        Diagrams.TwoD.Align,+                       Diagrams.TwoD.Arc,                        Diagrams.TwoD.Arrow,                        Diagrams.TwoD.Arrowheads,                        Diagrams.TwoD.Attributes,                        Diagrams.TwoD.Combinators,+                       Diagrams.TwoD.Curvature,                        Diagrams.TwoD.Deform,-                       Diagrams.TwoD.Transform,-                       Diagrams.TwoD.Transform.ScaleInv,                        Diagrams.TwoD.Ellipse,-                       Diagrams.TwoD.Arc,-                       Diagrams.TwoD.Segment,-                       Diagrams.TwoD.Curvature,+                       Diagrams.TwoD.Image,+                       Diagrams.TwoD.Model,                        Diagrams.TwoD.Offset,                        Diagrams.TwoD.Path,+                       Diagrams.TwoD.Points,                        Diagrams.TwoD.Polygons,-                       Diagrams.TwoD.Shapes,-                       Diagrams.TwoD.Vector,+                       Diagrams.TwoD.Segment,+                       Diagrams.TwoD.Segment.Bernstein,                        Diagrams.TwoD.Size,-                       Diagrams.TwoD.Model,+                       Diagrams.TwoD.Shapes,                        Diagrams.TwoD.Text,-                       Diagrams.TwoD.Image,-                       Diagrams.TwoD.Adjust,-                       Diagrams.ThreeD.Align,-                       Diagrams.ThreeD.Attributes,-                       Diagrams.ThreeD.Camera,-                       Diagrams.ThreeD.Deform,-                       Diagrams.ThreeD.Light,-                       Diagrams.ThreeD.Shapes,-                       Diagrams.ThreeD.Transform,-                       Diagrams.ThreeD.Types,-                       Diagrams.ThreeD.Vector,-                       Diagrams.ThreeD,-                       Diagrams.Animation,-                       Diagrams.Animation.Active,-                       Diagrams.Util,-                       Diagrams.Backend.CmdLine-  Build-depends:       base >= 4.2 && < 4.8,-                       containers >= 0.3 && < 0.6,+                       Diagrams.TwoD.Transform,+                       Diagrams.TwoD.Types,+                       Diagrams.TwoD.Vector,+                       Diagrams.Util+  other-modules:       Linear.Vector.Compat+  Build-depends:       base >= 4.9 && < 4.22,+                       containers >= 0.3 && < 0.8,                        array >= 0.3 && < 0.6,-                       semigroups >= 0.3.4 && < 0.17,-                       monoid-extras >= 0.3 && < 0.4,+                       semigroups >= 0.3.4 && < 0.21,+                       monoid-extras >= 0.6 && < 0.8,                        dual-tree >= 0.2 && < 0.3,-                       diagrams-core >= 1.2 && < 1.3,-                       active >= 0.1 && < 0.2,-                       vector-space >= 0.7.7 && < 0.11,-                       vector-space-points >= 0.1.2 && < 0.3,-                       MemoTrie >= 0.6 && < 0.7,+                       diagrams-core >= 1.4 && < 1.6,+                       diagrams-solve >= 0.1 && < 0.2,+                       active >= 0.2 && < 0.3,                        colour >= 2.3.2 && < 2.4,-                       data-default-class < 0.1,+                       data-default >= 0.8 && < 0.9,                        fingertree >= 0.1 && < 0.2,-                       intervals >= 0.7 && < 0.8,-                       lens >= 4.0 && < 4.10,-                       tagged >= 0.7,-                       optparse-applicative >= 0.11 && < 0.12,-                       filepath,-                       JuicyPixels >= 3.1.5 && < 3.3,-                       hashable >= 1.1 && < 1.3-  if impl(ghc < 7.6)-    Build-depends: ghc-prim+                       intervals >= 0.7 && < 0.10,+                       lens >= 5.1 && < 5.4,+                       tagged >= 0.7 && < 0.9,+                       optparse-applicative >= 0.11 && < 0.20,+                       filepath >= 1.4 && < 1.6,+                       JuicyPixels >= 3.3.4 && < 3.4,+                       hashable >= 1.1 && < 1.6,+                       linear >= 1.20.1 && < 1.24,+                       adjunctions >= 4.0 && < 5.0,+                       distributive >=0.2.2 && < 1.0,+                       process >= 1.1 && < 1.7,+                       directory >= 1.2 && < 1.4,+                       unordered-containers >= 0.2 && < 0.3,+                       text >= 0.7.1 && < 2.2,+                       mtl >= 2.0 && < 2.3 || >= 2.3.1 && < 2.4,+                       transformers >= 0.3.0 && < 0.7.0,+                       profunctors >= 5.0 && < 6.0,+                       exceptions >= 0.6 && < 1.0,+                       cereal >=0.4.1.1 && <0.6,+                       bytestring >=0.9 && <0.13,+                       fail >= 4.9.0.0 && <4.10   Hs-source-dirs:      src   ghc-options: -Wall   default-language:    Haskell2010+  other-extensions: BangPatterns, CPP, DefaultSignatures, DeriveDataTypeable,+    DeriveFunctor, DeriveGeneric, EmptyDataDecls, ExistentialQuantification,+    GADTs, GeneralizedNewtypeDeriving, NoMonomorphismRestriction, Rank2Types,+    RankNTypes, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell,+    TypeOperators, TypeSynonymInstances, UndecidableInstances, ViewPatterns,+    LambdaCase++test-suite tests+  type: exitcode-stdio-1.0+  main-is: Test.hs+  other-modules: Diagrams.Test.Direction+               , Diagrams.Test.Trail+               , Diagrams.Test.Transform+               , Diagrams.Test.Transform.Matrix+               , Diagrams.Test.TwoD.Offset+               , Diagrams.Test.TwoD.Segment+               , Diagrams.Test.TwoD+               , Diagrams.Test.Angle+               , Instances+  hs-source-dirs: test+  build-depends:       base,+                       tasty >= 0.10 && < 1.6,+                       tasty-hunit >= 0.9.2 && < 0.11,+                       tasty-quickcheck >= 0.8 && < 0.12,+                       QuickCheck >= 2.7,+                       deepseq >= 1.3 && < 1.6,+                       diagrams-lib,+                       lens,+                       distributive,+                       numeric-extras,+                       diagrams-solve+  default-language:    Haskell2010++benchmark benchmarks+  type: exitcode-stdio-1.0+  main-is:Speed.hs+  hs-source-dirs:test+  default-language: Haskell2010+  build-depends:+    base < 5,+    criterion,+    diagrams-core,+    diagrams-lib
+ diagrams/src_Diagrams_Combinators_alignedEx1.svg view
@@ -0,0 +1,1 @@+<svg xmlns="http://www.w3.org/2000/svg" height="151.7241" stroke-opacity="1" viewBox="0 0 400 152" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.9854108192823033" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 393.1034,34.4828 c 0.0000,-15.2354 -12.3508,-27.5862 -27.5862 -27.5862c -15.2354,-0.0000 -27.5862,12.3508 -27.5862 27.5862c -0.0000,15.2354 12.3508,27.5862 27.5862 27.5862c 15.2354,0.0000 27.5862,-12.3508 27.5862 -27.5862Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.9854108192823033" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 310.3448,75.8621 c 0.0000,-38.0886 -30.8769,-68.9655 -68.9655 -68.9655c -38.0886,-0.0000 -68.9655,30.8769 -68.9655 68.9655c -0.0000,38.0886 30.8769,68.9655 68.9655 68.9655c 38.0886,0.0000 68.9655,-30.8769 68.9655 -68.9655Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.9854108192823033" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 144.8276,48.2759 c 0.0000,-22.8532 -18.5261,-41.3793 -41.3793 -41.3793c -22.8532,-0.0000 -41.3793,18.5261 -41.3793 41.3793c -0.0000,22.8532 18.5261,41.3793 41.3793 41.3793c 22.8532,0.0000 41.3793,-18.5261 41.3793 -41.3793Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.9854108192823033" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 34.4828,20.6897 c 0.0000,-7.6177 -6.1754,-13.7931 -13.7931 -13.7931c -7.6177,-0.0000 -13.7931,6.1754 -13.7931 13.7931c -0.0000,7.6177 6.1754,13.7931 13.7931 13.7931c 7.6177,0.0000 13.7931,-6.1754 13.7931 -13.7931Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 28.4138,20.6897 c 0.0000,-4.2659 -3.4582,-7.7241 -7.7241 -7.7241c -4.2659,-0.0000 -7.7241,3.4582 -7.7241 7.7241c -0.0000,4.2659 3.4582,7.7241 7.7241 7.7241c 4.2659,0.0000 7.7241,-3.4582 7.7241 -7.7241Z"/></g></svg>
+ diagrams/src_Diagrams_Combinators_alignedEx2.svg view
@@ -0,0 +1,1 @@+<svg xmlns="http://www.w3.org/2000/svg" height="400.0000" stroke-opacity="1" viewBox="0 0 400 400" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.5999999999999999" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 256.1849,297.9712 l 56.1849,-172.9194 l -147.0940,-106.8700 l -147.0940,106.8700 l 56.1849,172.9194 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.5999999999999999" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 200.0000,175.6410 l -90.9091,-157.4592 l -90.9091,157.4592 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.5999999999999999" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 200.0000,200.0000 l -0.0000,-181.8182 h -181.8182 l -0.0000,181.8182 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.5999999999999999" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 381.8182,200.0000 c 0.0000,-100.4154 -81.4028,-181.8182 -181.8182 -181.8182c -100.4154,-0.0000 -181.8182,81.4028 -181.8182 181.8182c -0.0000,100.4154 81.4028,181.8182 181.8182 181.8182c 100.4154,0.0000 181.8182,-81.4028 181.8182 -181.8182Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 207.2727,200.0000 c 0.0000,-4.0166 -3.2561,-7.2727 -7.2727 -7.2727c -4.0166,-0.0000 -7.2727,3.2561 -7.2727 7.2727c -0.0000,4.0166 3.2561,7.2727 7.2727 7.2727c 4.0166,0.0000 7.2727,-3.2561 7.2727 -7.2727Z"/></g></svg>
diagrams/src_Diagrams_Combinators_appendsEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200.0" height="182.15600114617723" font-size="1" viewBox="0 0 200 182" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7634783583493163" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 160.6111204622467,143.5731526092298 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 99.99494014381385,143.57315260922977 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 69.6969696969697,91.07800057308859 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 99.99494014381389,38.58284853694745 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 160.61112046224676,38.58284853694746 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 190.9090909090909,91.07800057308862 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g><g><path d="M 130.3030303030303,91.07800057308862 c 0.0,-16.735901510024043 -13.567128793006255,-30.3030303030303 -30.303030303030294 -30.3030303030303c -16.735901510024043,-1.024778410754815e-15 -30.3030303030303,13.567128793006253 -30.3030303030303 30.30303030303029c -2.04955682150963e-15,16.735901510024043 13.567128793006251,30.3030303030303 30.303030303030287 30.3030303030303c 16.735901510024043,3.0743352322644448e-15 30.3030303030303,-13.56712879300625 30.303030303030308 -30.30303030303029Z" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="182.1560" stroke-opacity="1" viewBox="0 0 200 182" font-size="1" width="200.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 160.6111,143.5732 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 99.9949,143.5732 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 69.6970,91.0780 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 99.9949,38.5828 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 160.6111,38.5828 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 190.9091,91.0780 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7634783583493163" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 130.3030,91.0780 c 0.0000,-16.7359 -13.5671,-30.3030 -30.3030 -30.3030c -16.7359,-0.0000 -30.3030,13.5671 -30.3030 30.3030c -0.0000,16.7359 13.5671,30.3030 30.3030 30.3030c 16.7359,0.0000 30.3030,-13.5671 30.3030 -30.3030Z"/></g></svg>
diagrams/src_Diagrams_Combinators_besideEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="169.72067997066802" height="200.0" font-size="1" viewBox="0 0 170 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7369573772655632" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g fill="rgb(128,0,128)" fill-opacity="1.0"><g fill="rgb(128,0,128)" fill-opacity="1.0"><g fill="rgb(128,0,128)" fill-opacity="1.0"><path d="M 162.00610360836492,68.63383995200215 c 0.0,-32.884652674811015 -26.658278186282047,-59.54293086109307 -59.542930861093055 -59.54293086109307c -32.884652674811015,-2.0136042319639878e-15 -59.54293086109307,26.658278186282043 -59.54293086109307 59.54293086109305c -4.0272084639279756e-15,32.884652674811015 26.65827818628204,59.54293086109307 59.54293086109304 59.54293086109307c 32.884652674811015,6.0408126958919634e-15 59.54293086109307,-26.658278186282036 59.54293086109308 -59.54293086109305Z" /></g></g></g><g fill="rgb(255,165,0)" fill-opacity="1.0"><g fill="rgb(255,165,0)" fill-opacity="1.0"><g fill="rgb(255,165,0)" fill-opacity="1.0"><path d="M 87.10515084376053,151.2138036683622 c 0.0,-21.923101783207343 -17.772185457521363,-39.69528724072871 -39.6952872407287 -39.69528724072871c -21.923101783207343,-1.342402821309325e-15 -39.69528724072871,17.77218545752136 -39.69528724072871 39.695287240728696c -2.68480564261865e-15,21.923101783207343 17.77218545752136,39.69528724072871 39.695287240728696 39.69528724072871c 21.923101783207343,4.0272084639279756e-15 39.69528724072871,-17.772185457521356 39.69528724072871 -39.695287240728696Z" /></g></g></g><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 51.04622723939545,151.2138036683622 c 0.0,-2.0083081812028856 -1.628055455160751,-3.6363636363636367 -3.6363636363636362 -3.6363636363636367c -2.0083081812028856,-1.2297340929057781e-16 -3.6363636363636367,1.6280554551607507 -3.6363636363636367 3.636363636363636c -2.4594681858115563e-16,2.0083081812028856 1.6280554551607507,3.6363636363636367 3.6363636363636354 3.6363636363636367c 2.0083081812028856,3.689202278717335e-16 3.6363636363636367,-1.6280554551607502 3.636363636363638 -3.636363636363636Z" /></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 170 200" font-size="1" width="169.7207" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.7369573772655632" fill="rgb(128,0,128)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 162.0061,68.6338 c 0.0000,-32.8847 -26.6583,-59.5429 -59.5429 -59.5429c -32.8847,-0.0000 -59.5429,26.6583 -59.5429 59.5429c -0.0000,32.8847 26.6583,59.5429 59.5429 59.5429c 32.8847,0.0000 59.5429,-26.6583 59.5429 -59.5429Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.7369573772655632" fill="rgb(255,165,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 87.1052,151.2138 c 0.0000,-21.9231 -17.7722,-39.6953 -39.6953 -39.6953c -21.9231,-0.0000 -39.6953,17.7722 -39.6953 39.6953c -0.0000,21.9231 17.7722,39.6953 39.6953 39.6953c 21.9231,0.0000 39.6953,-17.7722 39.6953 -39.6953Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 51.0462,151.2138 c 0.0000,-2.0083 -1.6281,-3.6364 -3.6364 -3.6364c -2.0083,-0.0000 -3.6364,1.6281 -3.6364 3.6364c -0.0000,2.0083 1.6281,3.6364 3.6364 3.6364c 2.0083,0.0000 3.6364,-1.6281 3.6364 -3.6364Z"/></g></svg>
diagrams/src_Diagrams_Combinators_positionEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="204.25531914893568" height="300.0" font-size="1" viewBox="0 0 204 300" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.9901643964084406" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 204.25531914893565,6.3829787234042215 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 197.87234042553143,43.40425531914886 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 191.48936170212718,77.87234042553186 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 185.10638297872293,109.78723404255311 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 178.7234042553187,139.14893617021266 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 172.34042553191446,165.95744680851053 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 165.9574468085102,190.2127659574467 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 159.574468085106,211.91489361702116 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 153.19148936170174,231.06382978723394 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 146.8085106382975,247.659574468085 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 140.42553191489327,261.7021276595744 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 134.04255319148902,273.19148936170205 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 127.6595744680848,282.12765957446805 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 121.27659574468056,288.51063829787233 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 114.89361702127631,292.3404255319149 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 108.51063829787208,293.6170212765958 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 102.12765957446784,292.34042553191495 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 95.74468085106359,288.51063829787245 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 89.36170212765936,282.1276595744682 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 82.97872340425512,273.19148936170234 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 76.59574468085087,261.7021276595747 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 70.21276595744663,247.65957446808542 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 63.8297872340424,231.0638297872344 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 57.44680851063816,211.9148936170217 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 51.06382978723392,190.2127659574473 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 44.68085106382968,165.9574468085112 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 38.29787234042544,139.1489361702134 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 31.914893617021193,109.78723404255393 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 25.531914893616957,77.87234042553271 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 19.14893617021272,43.404255319149826 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 12.765957446808471,6.382978723405245 c 0.0,-3.525221807430585 -2.857756915973649,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.525221807430585,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736487 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.525221807430585 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.525221807430585,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z" /></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="300.0000" stroke-opacity="1" viewBox="0 0 204 300" font-size="1" width="204.2553" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 204.2553,6.3830 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 197.8723,43.4043 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 191.4894,77.8723 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 185.1064,109.7872 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 178.7234,139.1489 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 172.3404,165.9574 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 165.9574,190.2128 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 159.5745,211.9149 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 153.1915,231.0638 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 146.8085,247.6596 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 140.4255,261.7021 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 134.0426,273.1915 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 127.6596,282.1277 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 121.2766,288.5106 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 114.8936,292.3404 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 108.5106,293.6170 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 102.1277,292.3404 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.7447,288.5106 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.3617,282.1277 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 82.9787,273.1915 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 76.5957,261.7021 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 70.2128,247.6596 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 63.8298,231.0638 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 57.4468,211.9149 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 51.0638,190.2128 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 44.6809,165.9574 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 38.2979,139.1489 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 31.9149,109.7872 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 25.5319,77.8723 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 19.1489,43.4043 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.9901643964084406" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 12.7660,6.3830 c 0.0000,-3.5252 -2.8578,-6.3830 -6.3830 -6.3830c -3.5252,-0.0000 -6.3830,2.8578 -6.3830 6.3830c -0.0000,3.5252 2.8578,6.3830 6.3830 6.3830c 3.5252,0.0000 6.3830,-2.8578 6.3830 -6.3830Z"/></g></svg>
diagrams/src_Diagrams_Combinators_strutEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="119.99999999999999" font-size="1" viewBox="0 0 300 120" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.758946638440411" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 286.3636363636364,60.0 c 0.0,-30.12462271804328 -24.42083182741126,-54.54545454545455 -54.54545454545453 -54.54545454545455c -30.12462271804328,-1.844601139358667e-15 -54.54545454545455,24.42083182741126 -54.54545454545455 54.545454545454525c -3.689202278717334e-15,30.12462271804328 24.420831827411256,54.54545454545455 54.545454545454525 54.54545454545455c 30.12462271804328,5.533803418076001e-15 54.54545454545455,-24.420831827411252 54.545454545454554 -54.545454545454525Z" /></g><g></g><g><path d="M 122.72727272727272,60.0 c 0.0,-30.12462271804328 -24.42083182741126,-54.54545454545455 -54.54545454545453 -54.54545454545455c -30.12462271804328,-1.844601139358667e-15 -54.54545454545455,24.42083182741126 -54.54545454545455 54.545454545454525c -3.689202278717334e-15,30.12462271804328 24.420831827411256,54.54545454545455 54.545454545454525 54.54545454545455c 30.12462271804328,5.533803418076001e-15 54.54545454545455,-24.420831827411252 54.545454545454554 -54.545454545454525Z" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="120.0000" stroke-opacity="1" viewBox="0 0 300 120" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.758946638440411" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,60.0000 c 0.0000,-30.1246 -24.4208,-54.5455 -54.5455 -54.5455c -30.1246,-0.0000 -54.5455,24.4208 -54.5455 54.5455c -0.0000,30.1246 24.4208,54.5455 54.5455 54.5455c 30.1246,0.0000 54.5455,-24.4208 54.5455 -54.5455Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.758946638440411" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 122.7273,60.0000 c 0.0000,-30.1246 -24.4208,-54.5455 -54.5455 -54.5455c -30.1246,-0.0000 -54.5455,24.4208 -54.5455 54.5455c -0.0000,30.1246 24.4208,54.5455 54.5455 54.5455c 30.1246,0.0000 54.5455,-24.4208 54.5455 -54.5455Z"/></g></svg>
diagrams/src_Diagrams_Combinators_withEnvelopeEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="166.66666666666669" font-size="1" viewBox="0 0 300 167" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.894427190999916" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 261.11111111111114,138.8888888888889 l -1.2335811384723963e-14,-111.11111111111113 h -111.11111111111113 l -1.2335811384723963e-14,111.11111111111113 Z" /></g><g fill="rgb(0,0,255)" fill-opacity="1.0"></g></g></g></g></g></g><g stroke="rgb(255,255,255)" stroke-opacity="1.0" stroke-dasharray="5.555555555555557,5.555555555555557" stroke-dashoffset="0.0"><path d="M 250.0,83.33333333333334 c 0.0,-24.545988881368604 -19.898455563075846,-44.44444444444446 -44.44444444444445 -44.44444444444446c -24.545988881368604,-1.503008335773729e-15 -44.44444444444446,19.898455563075846 -44.44444444444446 44.44444444444444c -3.006016671547458e-15,24.545988881368604 19.898455563075842,44.44444444444446 44.444444444444436 44.44444444444446c 24.545988881368604,4.509025007321188e-15 44.44444444444446,-19.89845556307584 44.44444444444448 -44.44444444444444Z" /></g></g><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><path d="M 161.11111111111111,83.33333333333334 c 0.0,-30.68248610171075 -24.873069453844806,-55.555555555555564 -55.55555555555555 -55.555555555555564c -30.68248610171075,-1.878760419717161e-15 -55.555555555555564,24.873069453844803 -55.555555555555564 55.55555555555554c -3.757520839434322e-15,30.68248610171075 24.8730694538448,55.555555555555564 55.55555555555554 55.555555555555564c 30.68248610171075,5.636281259151484e-15 55.555555555555564,-24.873069453844796 55.55555555555557 -55.55555555555554Z" /></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="166.6667" stroke-opacity="1" viewBox="0 0 300 167" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.8944271909999159" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 261.1111,138.8889 l -0.0000,-111.1111 h -111.1111 l -0.0000,111.1111 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,255)" stroke-width="0.8944271909999159" fill="rgb(0,0,0)" stroke-dashoffset="0.0" stroke-linecap="butt" stroke-miterlimit="10.0" stroke-dasharray="5.555555555555557,5.555555555555557"><path d="M 250.0000,83.3333 c 0.0000,-24.5460 -19.8985,-44.4444 -44.4444 -44.4444c -24.5460,-0.0000 -44.4444,19.8985 -44.4444 44.4444c -0.0000,24.5460 19.8985,44.4444 44.4444 44.4444c 24.5460,0.0000 44.4444,-19.8985 44.4444 -44.4444Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.8944271909999159" fill="rgb(0,128,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 161.1111,83.3333 c 0.0000,-30.6825 -24.8731,-55.5556 -55.5556 -55.5556c -30.6825,-0.0000 -55.5556,24.8731 -55.5556 55.5556c -0.0000,30.6825 24.8731,55.5556 55.5556 55.5556c 30.6825,0.0000 55.5556,-24.8731 55.5556 -55.5556Z"/></g></svg>
+ diagrams/src_Diagrams_CubicSpline_Boehm_bsplineEx.svg view
@@ -0,0 +1,1 @@+<svg xmlns="http://www.w3.org/2000/svg" height="184.6154" stroke-opacity="1" viewBox="0 0 300 185" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.9413574486632834" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 135.5769,106.7308 c 0.0000,-0.0000 0.0000,-0.0000 9.6154 -14.4231c 9.6154,-14.4231 28.8462,-43.2692 52.8846 -33.6538c 24.0385,9.6154 52.8846,57.6923 24.0385 67.3077c -28.8462,9.6154 -115.3846,-19.2308 -139.4231 -43.2692c -24.0385,-24.0385 14.4231,-43.2692 33.6538 -52.8846c 19.2308,-9.6154 19.2308,-9.6154 19.2308 -9.6154"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 141.3462,20.1923 c 0.0000,-3.1863 -2.5830,-5.7692 -5.7692 -5.7692c -3.1863,-0.0000 -5.7692,2.5830 -5.7692 5.7692c -0.0000,3.1863 2.5830,5.7692 5.7692 5.7692c 3.1863,0.0000 5.7692,-2.5830 5.7692 -5.7692Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 25.9615,77.8846 c 0.0000,-3.1863 -2.5830,-5.7692 -5.7692 -5.7692c -3.1863,-0.0000 -5.7692,2.5830 -5.7692 5.7692c -0.0000,3.1863 2.5830,5.7692 5.7692 5.7692c 3.1863,0.0000 5.7692,-2.5830 5.7692 -5.7692Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 285.5769,164.4231 c 0.0000,-3.1863 -2.5830,-5.7692 -5.7692 -5.7692c -3.1863,-0.0000 -5.7692,2.5830 -5.7692 5.7692c -0.0000,3.1863 2.5830,5.7692 5.7692 5.7692c 3.1863,0.0000 5.7692,-2.5830 5.7692 -5.7692Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 199.0385,20.1923 c 0.0000,-3.1863 -2.5830,-5.7692 -5.7692 -5.7692c -3.1863,-0.0000 -5.7692,2.5830 -5.7692 5.7692c -0.0000,3.1863 2.5830,5.7692 5.7692 5.7692c 3.1863,0.0000 5.7692,-2.5830 5.7692 -5.7692Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 141.3462,106.7308 c 0.0000,-3.1863 -2.5830,-5.7692 -5.7692 -5.7692c -3.1863,-0.0000 -5.7692,2.5830 -5.7692 5.7692c -0.0000,3.1863 2.5830,5.7692 5.7692 5.7692c 3.1863,0.0000 5.7692,-2.5830 5.7692 -5.7692Z"/></g></svg>
diagrams/src_Diagrams_CubicSpline_cubicSplineEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600.0" height="150.9864382575878" font-size="1" viewBox="0 0 600 151" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.2039392872038202" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 434.12540826428113,88.50749970338121 c -6.894535367777746,-6.894535367777746 6.894535367777746,-85.03260286925885 50.559926030370136 -75.83988904555518c 43.66539066259239,9.192713823703665 117.20710125222166,105.7162089725921 75.8398890455552 126.39981507592529c -41.36721220666647,20.68360610333324 -197.64334720962873,-34.472676838888724 -227.51966713666556 -75.8398890455552c -29.876319927036917,-41.36721220666648 66.64717522185153,-68.94535367777745 101.1198520607403 -50.55992603037012c 34.47267683888874,18.385427647407315 6.894535367777746,82.73442441333296 -7.105427357601002e-14 75.83988904555521Z" /><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 439.18140086731813,12.667610657826017 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 338.0615488065779,63.227536688196146 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 565.5812159432435,139.06742573375135 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 489.7413268976883,12.667610657826017 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 439.18140086731813,88.50749970338121 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g></g><g></g><path d="M 139.89139549241958,88.50749970338121 c 5.417134931825375,-48.3027864754429 10.83426986365075,-96.6055729508858 50.559926030370136 -75.8398890455552c 39.72565616671939,20.765683905330597 113.75983356833281,110.59983819143467 75.83988904555518 126.39981507592535c -37.9199445227776,15.799976884490668 -187.79401096994619,-42.43422363263207 -227.51966713666562 -75.83988904555518c -39.72565616671941,-33.40566541292313 30.69709794701043,-41.98279572164664 101.11985206074027 -50.559926030370136" /><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 144.9473880954566,12.667610657826017 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 43.82753603471632,63.227536688196146 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 271.3472031713819,139.06742573375135 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 195.50731412582675,12.667610657826017 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 144.9473880954566,88.50749970338121 c 0.0,-2.7923476099146396 -2.263644993122374,-5.055992603037014 -5.055992603037013 -5.055992603037014c -2.7923476099146396,-1.7098197812943627e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.4196395625887253e-16,2.7923476099146396 2.2636449931223734,5.055992603037014 5.055992603037011 5.055992603037014c 2.7923476099146396,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037017 -5.055992603037012Z" /></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="150.9864" stroke-opacity="1" viewBox="0 0 600 151" font-size="1" width="600.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2039392872038202" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 434.1254,88.5075 c -6.8945,-6.8945 6.8945,-85.0326 50.5599 -75.8399c 43.6654,9.1927 117.2071,105.7162 75.8399 126.3998c -41.3672,20.6836 -197.6433,-34.4727 -227.5197 -75.8399c -29.8763,-41.3672 66.6472,-68.9454 101.1199 -50.5599c 34.4727,18.3854 6.8945,82.7344 -0.0000 75.8399Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 439.1814,12.6676 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 338.0615,63.2275 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 565.5812,139.0674 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 489.7413,12.6676 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 439.1814,88.5075 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2039392872038202" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 139.8914,88.5075 c 5.4171,-48.3028 10.8343,-96.6056 50.5599 -75.8399c 39.7257,20.7657 113.7598,110.5998 75.8399 126.3998c -37.9199,15.8000 -187.7940,-42.4342 -227.5197 -75.8399c -39.7257,-33.4057 30.6971,-41.9828 101.1199 -50.5599"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 144.9474,12.6676 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 43.8275,63.2275 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 271.3472,139.0674 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 195.5073,12.6676 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 144.9474,88.5075 c 0.0000,-2.7923 -2.2636,-5.0560 -5.0560 -5.0560c -2.7923,-0.0000 -5.0560,2.2636 -5.0560 5.0560c -0.0000,2.7923 2.2636,5.0560 5.0560 5.0560c 2.7923,0.0000 5.0560,-2.2636 5.0560 -5.0560Z"/></g></svg>
diagrams/src_Diagrams_TrailLike_explodeTrailEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="285.3169548885461" font-size="1" viewBox="0 0 300 285" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.1702655183611206" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 65.72263789774158,272.34800239361215 l 168.5547242045168,-1.871333357211977e-14 " /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 13.636363636363626,112.04293358657401 l 52.086274261377966,160.30506880703814 " /></g><g stroke="rgb(255,255,0)" stroke-opacity="1.0"><path d="M 150.0,12.968952494933887 l -136.36363636363637,99.0739810916401 " /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 286.3636363636364,112.04293358657402 l -136.36363636363635,-99.07398109164014 " /></g><g stroke="rgb(255,165,0)" stroke-opacity="1.0"><path d="M 234.2773621022584,272.34800239361215 l 52.086274261377966,-160.30506880703814 " /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="285.3170" stroke-opacity="1" viewBox="0 0 300 285" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="1.17026551836112" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 65.7226,272.3480 l 168.5547,-0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.17026551836112" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,112.0429 l 52.0863,160.3051 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,0)" stroke-width="1.17026551836112" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 150.0000,12.9690 l -136.3636,99.0740 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="1.17026551836112" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,112.0429 l -136.3636,-99.0740 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,165,0)" stroke-width="1.17026551836112" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 234.2774,272.3480 l 52.0863,-160.3051 "/></g></svg>
diagrams/src_Diagrams_TrailLike_fromOffsetsEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="86.60254037844385" font-size="1" viewBox="0 0 300 87" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.644741959094125" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 13.636363636363626,82.66606127033276 h 90.9090909090909 l 45.45454545454546,-78.72958216222169 l 45.45454545454546,78.72958216222169 h 90.9090909090909 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="86.6025" stroke-opacity="1" viewBox="0 0 300 87" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.644741959094125" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,82.6661 h 90.9091 l 45.4545,-78.7296 l 45.4545,78.7296 h 90.9091 "/></g></svg>
diagrams/src_Diagrams_TrailLike_fromSegmentsEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="247.48737341529161" height="200.00000000000003" font-size="1" viewBox="0 0 247 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.8899211172508118" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 11.249426064331445,190.90909090909093 l 128.564869306645,-128.564869306645 c 128.564869306645,-128.564869306645 128.564869306645,0.0 0.0 128.564869306645h -128.564869306645 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 247 200" font-size="1" width="247.4874" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8899211172508118" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 11.2494,190.9091 l 128.5649,-128.5649 c 128.5649,-128.5649 128.5649,-0.0000 0.0000 128.5649h -128.5649 "/></g></svg>
diagrams/src_Diagrams_TrailLike_fromVerticesEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="305.0220318351292" font-size="1" viewBox="0 0 300 305" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.21000237719131" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 198.02231959365204,226.8357137585907 l 52.57961880085914,-15.539610741748685 l 35.761697969125166,-48.197675766316436 l -52.84137502819749,-45.52029976131276 l 1.4689477105917228,-54.80819289004408 l -34.78774118767253,-48.905296788481024 l -59.62126060155821,36.18858783527575 l -51.671759188017134,-18.33371532625888 l -57.261704414941406,17.972540121134063 l 15.9934095243195,67.88607704837416 l -33.40385114728599,43.47733367835122 l -0.601938394511168,60.012937447513 l 69.50573128358397,5.767315143513668 l 31.02704382385218,45.20418527970044 l 56.88968602799999,19.11749498615032 Z" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="305.0220" stroke-opacity="1" viewBox="0 0 300 305" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2100023771913093" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 198.0223,226.8357 l 52.5796,-15.5396 l 35.7617,-48.1977 l -52.8414,-45.5203 l 1.4689,-54.8082 l -34.7877,-48.9053 l -59.6213,36.1886 l -51.6718,-18.3337 l -57.2617,17.9725 l 15.9934,67.8861 l -33.4039,43.4773 l -0.6019,60.0129 l 69.5057,5.7673 l 31.0270,45.2042 l 56.8897,19.1175 Z"/></g></svg>
diagrams/src_Diagrams_TrailLike_twiddleEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="259.80762113533166" font-size="1" viewBox="0 0 300 260" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.1167258309225196" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 81.81818181818174,247.99818381099834 h 0.0 " /><path d="M 81.81818181818174,247.99818381099834 l -68.18181818181809,-118.09437324333258 " /><path d="M 81.81818181818174,247.99818381099834 l 1.3625464393126918e-13,-236.18874648666508 " /><path d="M 81.81818181818174,247.99818381099834 l 136.36363636363646,-236.188746486665 " /><path d="M 81.81818181818174,247.99818381099834 l 204.5454545454546,-118.09437324333246 " /><path d="M 81.81818181818174,247.99818381099834 l 136.3636363636364,4.5418214643756395e-14 " /><path d="M 13.636363636363654,129.90381056766577 l 68.18181818181809,118.09437324333258 " /><path d="M 13.636363636363654,129.90381056766577 h 0.0 " /><path d="M 13.636363636363654,129.90381056766577 l 68.18181818181822,-118.09437324333248 " /><path d="M 13.636363636363654,129.90381056766577 l 204.54545454545456,-118.09437324333243 " /><path d="M 13.636363636363654,129.90381056766577 l 272.7272727272727,1.2111523905001706e-13 " /><path d="M 13.636363636363654,129.90381056766577 l 204.54545454545445,118.09437324333263 " /><path d="M 81.81818181818187,11.809437324333274 l -1.3625464393126918e-13,236.18874648666508 " /><path d="M 81.81818181818187,11.809437324333274 l -68.18181818181822,118.09437324333248 " /><path d="M 81.81818181818187,11.809437324333274 h 0.0 " /><path d="M 81.81818181818187,11.809437324333274 l 136.36363636363632,6.055761952500853e-14 " /><path d="M 81.81818181818187,11.809437324333274 l 204.54545454545445,118.09437324333261 " /><path d="M 81.81818181818187,11.809437324333274 l 136.36363636363626,236.1887464866651 " /><path d="M 218.1818181818182,11.80943732433333 l -136.36363636363646,236.188746486665 " /><path d="M 218.1818181818182,11.80943732433333 l -204.54545454545456,118.09437324333243 " /><path d="M 218.1818181818182,11.80943732433333 l -136.36363636363632,-6.055761952500853e-14 " /><path d="M 218.1818181818182,11.80943732433333 h 0.0 " /><path d="M 218.1818181818182,11.80943732433333 l 68.18181818181813,118.09437324333256 " /><path d="M 218.1818181818182,11.80943732433333 l -7.569702440626067e-14,236.18874648666505 " /><path d="M 286.3636363636363,129.9038105676659 l -204.5454545454546,118.09437324333246 " /><path d="M 286.3636363636363,129.9038105676659 l -272.7272727272727,-1.2111523905001706e-13 " /><path d="M 286.3636363636363,129.9038105676659 l -204.54545454545445,-118.09437324333261 " /><path d="M 286.3636363636363,129.9038105676659 l -68.18181818181813,-118.09437324333256 " /><path d="M 286.3636363636363,129.9038105676659 h 0.0 " /><path d="M 286.3636363636363,129.9038105676659 l -68.1818181818182,118.0943732433325 " /><path d="M 218.18181818181813,247.9981838109984 l -136.3636363636364,-4.5418214643756395e-14 " /><path d="M 218.18181818181813,247.9981838109984 l -204.54545454545445,-118.09437324333263 " /><path d="M 218.18181818181813,247.9981838109984 l -136.36363636363626,-236.1887464866651 " /><path d="M 218.18181818181813,247.9981838109984 l 7.569702440626067e-14,-236.18874648666505 " /><path d="M 218.18181818181813,247.9981838109984 l 68.1818181818182,-118.0943732433325 " /><path d="M 218.18181818181813,247.9981838109984 h 0.0 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="259.8076" stroke-opacity="1" viewBox="0 0 300 260" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 h 0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 l -68.1818,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 l 0.0000,-236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 l 136.3636,-236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 l 204.5455,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,247.9982 l 136.3636,0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 l 68.1818,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 h 0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 l 68.1818,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 l 204.5455,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 l 272.7273,0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,129.9038 l 204.5455,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 l -0.0000,236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 l -68.1818,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 h 0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 l 136.3636,0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 l 204.5455,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 81.8182,11.8094 l 136.3636,236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 l -136.3636,236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 l -204.5455,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 l -136.3636,-0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 h 0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 l 68.1818,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,11.8094 l -0.0000,236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 l -204.5455,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 l -272.7273,-0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 l -204.5455,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 l -68.1818,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 h 0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,129.9038 l -68.1818,118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 l -136.3636,-0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 l -204.5455,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 l -136.3636,-236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 l 0.0000,-236.1887 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 l 68.1818,-118.0944 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.1167258309225196" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 218.1818,247.9982 h 0.0000 "/></g></svg>
diagrams/src_Diagrams_Trail_closeLineEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500.0" height="68.18181818181819" font-size="1" viewBox="0 0 500 68" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7385489458759964" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 394.6280991735537,3.099173553719009 l 82.64462809917356,41.32231404958678 l -123.96694214876034,20.66115702479339 l -82.64462809917356,-41.32231404958678 l 41.32231404958678,-20.66115702479339 Z" /></g><path d="M 146.69421487603304,3.099173553719009 l 82.64462809917356,41.32231404958678 l -123.96694214876034,20.66115702479339 l -82.64462809917356,-41.32231404958678 l 41.32231404958678,-20.66115702479339 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="68.1818" stroke-opacity="1" viewBox="0 0 500 68" font-size="1" width="500.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7385489458759964" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 394.6281,3.0992 l 82.6446,41.3223 l -123.9669,20.6612 l -82.6446,-41.3223 l 41.3223,-20.6612 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7385489458759964" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 146.6942,3.0992 l 82.6446,41.3223 l -123.9669,20.6612 l -82.6446,-41.3223 l 41.3223,-20.6612 "/></g></svg>
diagrams/src_Diagrams_Trail_glueLineEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500.0" height="68.18181818181819" font-size="1" viewBox="0 0 500 68" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7385489458759964" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 384.297520661157,0.0 l 82.64462809917354,41.32231404958677 l -123.96694214876032,20.661157024793386 l -82.64462809917354,-41.32231404958677 Z" /></g><path d="M 136.36363636363637,0.0 l 82.64462809917354,41.32231404958677 l -123.96694214876032,20.661157024793386 l -82.64462809917354,-41.32231404958677 l 41.32231404958677,-20.661157024793386 " /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="68.1818" stroke-opacity="1" viewBox="0 0 500 68" font-size="1" width="500.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7385489458759964" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 384.2975,0.0000 l 82.6446,41.3223 l -123.9669,20.6612 l -82.6446,-41.3223 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7385489458759964" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 136.3636,0.0000 l 82.6446,41.3223 l -123.9669,20.6612 l -82.6446,-41.3223 l 41.3223,-20.6612 "/></g></svg>
diagrams/src_Diagrams_Trail_lineFromOffsetsEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="50.0" font-size="1" viewBox="0 0 300 50" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 0.0,50.0 l 100.0,-50.0 l 100.0,50.0 l 100.0,-25.0 " /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="50.0000" stroke-opacity="1" viewBox="0 0 300 50" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 0.0000,50.0000 l 100.0000,-50.0000 l 100.0000,50.0000 l 100.0000,-25.0000 "/></g></svg>
diagrams/src_Diagrams_Trail_lineFromVerticesEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="120.00000000000001" font-size="1" viewBox="0 0 300 120" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7589466384404111" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 13.636363636363626,114.54545454545456 v -54.54545454545455 l 54.54545454545455,-54.54545454545455 l 218.1818181818182,54.54545454545455 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="120.0000" stroke-opacity="1" viewBox="0 0 300 120" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.7589466384404111" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,114.5455 v -54.5455 l 54.5455,-54.5455 l 218.1818,54.5455 "/></g></svg>
diagrams/src_Diagrams_Trail_trailOffsetEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="90.00000000000001" font-size="1" viewBox="0 0 300 90" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.6572670690061994" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 177.27272727272728,4.090909090909101 h -109.0909090909091 " /></g><path d="M 177.27272727272728,4.090909090909101 l 109.0909090909091,54.54545454545455 l -163.63636363636363,27.272727272727273 l -109.0909090909091,-54.54545454545455 l 54.54545454545455,-27.272727272727273 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="90.0000" stroke-opacity="1" viewBox="0 0 300 90" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="0.6572670690061994" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 177.2727,4.0909 h -109.0909 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.6572670690061994" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 177.2727,4.0909 l 109.0909,54.5455 l -163.6364,27.2727 l -109.0909,-54.5455 l 54.5455,-27.2727 "/></g></svg>
diagrams/src_Diagrams_TwoD_Arc_annularWedgeEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="178.54130895779457" font-size="1" viewBox="0 0 400 179" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0689548060277785" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 364.6026155171688,49.10118238914234 l 17.215566301012974,-17.21556630101297 c -31.692982425834614,-31.692982425834618 -83.0774595809185,-31.692982425834632 -114.77044200675311 -1.8020020547460663e-14c -31.692982425834618,31.692982425834614 -31.692982425834632,83.0774595809185 -2.7030030821190994e-14 114.77044200675311c 31.69298242583461,31.69298242583462 83.07745958091849,31.692982425834636 114.77044200675309 3.6040041094921325e-14l -17.215566301012966,-17.215566301012974 c -22.185087698084224,22.185087698084217 -58.154221706642936,22.18508769808421 -80.33930940472716 -2.5228028766444926e-14c -22.185087698084224,-22.185087698084224 -22.185087698084214,-58.15422170664295 1.8921021574833692e-14 -80.33930940472717c 22.185087698084224,-22.185087698084228 58.15422170664295,-22.185087698084217 80.3393094047272 1.4210854715202004e-14Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 196.76242196124196,65.05772234978109 l 5.938102119434486,-56.49726773069128 c -22.87402851921224,-2.4041572749570763 -45.693919553281,5.0104747879005584 -62.78626916472949 20.400495504601384l 38.01228629587615,42.21692087747031 c 5.127704883434549,-4.617006215010248 11.973672193655174,-6.841395833867538 18.83588074941885 -6.120148651380411Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 58.75929709319445,89.27083709150592 h 40.57747891137626 c 0.0,-44.820645578667474 -36.33431224408504,-81.15495782275252 -81.15495782275251 -81.15495782275252l -2.4846539833143083e-15,40.57747891137626 c 22.41032278933373,0.0 40.577478911376254,18.167156122042524 40.57747891137625 40.57747891137626Z" /></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="178.5413" stroke-opacity="1" viewBox="0 0 400 179" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 364.6026,49.1012 l 17.2156,-17.2156 c -31.6930,-31.6930 -83.0775,-31.6930 -114.7704 -0.0000c -31.6930,31.6930 -31.6930,83.0775 -0.0000 114.7704c 31.6930,31.6930 83.0775,31.6930 114.7704 0.0000l -17.2156,-17.2156 c -22.1851,22.1851 -58.1542,22.1851 -80.3393 -0.0000c -22.1851,-22.1851 -22.1851,-58.1542 0.0000 -80.3393c 22.1851,-22.1851 58.1542,-22.1851 80.3393 -0.0000Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 196.7624,65.0577 l 5.9381,-56.4973 c -22.8740,-2.4042 -45.6939,5.0105 -62.7863 20.4005l 38.0123,42.2169 c 5.1277,-4.6170 11.9737,-6.8414 18.8359 -6.1201Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 58.7593,89.2708 h 40.5775 c 0.0000,-44.8206 -36.3343,-81.1550 -81.1550 -81.1550l -0.0000,40.5775 c 22.4103,0.0000 40.5775,18.1672 40.5775 40.5775Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arc_arc'Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="299.99999999999994" font-size="1" viewBox="0 0 300 300" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.2" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 286.3636363636364,177.27272727272728 c 0.0,-90.37386815412985 -73.2624954822338,-163.63636363636365 -163.63636363636363 -163.63636363636365" /><path d="M 231.8181818181818,177.27272727272728 c 0.0,60.24924543608655 -48.84166365482254,109.09090909090907 -109.09090909090911 109.09090909090905c -60.24924543608655,0.0 -109.09090909090907,-48.84166365482254 -109.09090909090907 -109.09090909090911c 0.0,-60.24924543608655 48.84166365482254,-109.09090909090907 109.09090909090911 -109.09090909090907" /><path d="M 177.27272727272725,177.27272727272728 c 0.0,-30.124622718043284 -24.420831827411263,-54.545454545454554 -54.54545454545454 -54.545454545454554" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="300.0000" stroke-opacity="1" viewBox="0 0 300 300" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 286.3636,286.3636 c 0.0000,-150.6231 -122.1042,-272.7273 -272.7273 -272.7273"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 195.4545,286.3636 c 0.0000,-100.4154 -81.4028,-181.8182 -181.8182 -181.8182"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.2" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 104.5455,286.3636 c 0.0000,-50.2077 -40.7014,-90.9091 -90.9091 -90.9091"/></g></svg>
diagrams/src_Diagrams_TwoD_Arc_arcBetweenEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="150.0" font-size="1" viewBox="0 0 300 150" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.8485281374238571" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><path d="M 13.636363636364111,143.18181818181793 c 71.7376874363651,-76.52462512726947 168.46496016363756,-124.88826149090566 272.7272727272722 -136.36363636363595" /><path d="M 13.636363636364266,143.1818181818181 c 82.05066190000052,-61.353221654543866 174.4142982636367,-107.53503983636188 272.72727272727207 -136.363636363636" /><path d="M 13.636363636364166,143.18181818181804 l 272.72727272727207,-136.36363636363603 " /><path d="M 13.636363636363624,143.1818181818182 c 98.31297446363554,-28.82859652727414 190.67661082727207,-75.01041470909239 272.72727272727275 -136.36363636363635" /><path d="M 13.636363636364058,143.1818181818181 c 104.26231256363465,-11.475374872730281 200.9895852909071,-59.83901123636646 272.7272727272722 -136.36363636363592" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="150.0000" stroke-opacity="1" viewBox="0 0 300 150" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8485281374238577" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,143.1818 c 71.7377,-76.5246 168.4650,-124.8883 272.7273 -136.3636"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8485281374238577" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,143.1818 c 82.0507,-61.3532 174.4143,-107.5350 272.7273 -136.3636"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8485281374238577" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,143.1818 l 272.7273,-136.3636 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8485281374238577" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,143.1818 c 98.3130,-28.8286 190.6766,-75.0104 272.7273 -136.3636"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.8485281374238577" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,143.1818 c 104.2623,-11.4754 200.9896,-59.8390 272.7273 -136.3636"/></g></svg>
diagrams/src_Diagrams_TwoD_Arc_wedgeEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="178.54130895779457" font-size="1" viewBox="0 0 400 179" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0689548060277785" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 324.43296081480526,89.27083709150592 l 57.385221003376564,-57.38522100337656 c -31.692982425834614,-31.692982425834618 -83.0774595809185,-31.692982425834632 -114.77044200675311 -1.8020020547460663e-14c -31.692982425834618,31.692982425834614 -31.692982425834632,83.0774595809185 -2.7030030821190994e-14 114.77044200675311c 31.69298242583461,31.69298242583462 83.07745958091849,31.692982425834636 114.77044200675309 3.6040041094921325e-14Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g><g fill="rgb(0,0,255)" fill-opacity="1.0"><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 194.21752105291293,89.27083709150592 l 8.483003027763553,-80.71038247241611 c -22.87402851921224,-2.4041572749570763 -45.693919553281,5.0104747879005584 -62.78626916472949 20.400495504601384Z" /></g></g></g><g fill="rgb(0,0,255)" fill-opacity="1.0"><path d="M 18.181818181818187,89.27083709150592 h 81.15495782275252 c 0.0,-44.820645578667474 -36.33431224408504,-81.15495782275252 -81.15495782275251 -81.15495782275252Z" /></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="178.5413" stroke-opacity="1" viewBox="0 0 400 179" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 324.4330,89.2708 l 57.3852,-57.3852 c -31.6930,-31.6930 -83.0775,-31.6930 -114.7704 -0.0000c -31.6930,31.6930 -31.6930,83.0775 -0.0000 114.7704c 31.6930,31.6930 83.0775,31.6930 114.7704 0.0000Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 194.2175,89.2708 l 8.4830,-80.7104 c -22.8740,-2.4042 -45.6939,5.0105 -62.7863 20.4005Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="1.0689548060277785" fill="rgb(0,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 18.1818,89.2708 h 81.1550 c 0.0000,-44.8206 -36.3343,-81.1550 -81.1550 -81.1550Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrow_example1.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="499.99999999999994" height="142.85714285714286" font-size="1" viewBox="0 0 500 143" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0690449676496976" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(169,169,169)" stroke-opacity="1.0" stroke-width="5.345224838248488"><path d="M 461.03896103896096,136.36363636363637 l -1.4418480839287746e-14,-129.87012987012986 h -129.87012987012986 l -1.4418480839287746e-14,129.87012987012986 Z" /><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 398.70129870129864,71.42857142857143 c 0.0,-1.4345058437163465 -1.1628967536862505,-2.5974025974025974 -2.597402597402597 -2.5974025974025974c -1.4345058437163465,-8.783814949326985e-17 -2.5974025974025974,1.1628967536862502 -2.5974025974025974 2.5974025974025965c -1.756762989865397e-16,1.4345058437163465 1.1628967536862502,2.5974025974025974 2.597402597402596 2.5974025974025974c 1.4345058437163465,2.6351444847980957e-16 2.5974025974025974,-1.16289675368625 2.5974025974025987 -2.5974025974025965Z" /></g></g></g></g></g><g></g><g stroke="rgb(169,169,169)" stroke-opacity="1.0" stroke-width="5.345224838248488"><path d="M 136.36363636363632,136.36363636363637 l -1.4418480839287746e-14,-129.87012987012986 h -129.87012987012986 l -1.4418480839287746e-14,129.87012987012986 Z" /><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 74.02597402597398,71.42857142857143 c 0.0,-1.4345058437163465 -1.1628967536862505,-2.5974025974025974 -2.597402597402597 -2.5974025974025974c -1.4345058437163465,-8.783814949326985e-17 -2.5974025974025974,1.1628967536862502 -2.5974025974025974 2.5974025974025965c -1.756762989865397e-16,1.4345058437163465 1.1628967536862502,2.5974025974025974 2.597402597402596 2.5974025974025974c 1.4345058437163465,2.6351444847980957e-16 2.5974025974025974,-1.16289675368625 2.5974025974025987 -2.5974025974025965Z" /></g></g></g></g><g><g><g><path d="M 89.9819766975543,73.83089383093066 c 61.406842947188636,7.951049003214775 122.81368589437727,15.90209800642955 138.71310687684397 10.954204913391047c 15.89942098246672,-4.947893093038505 -13.70857999978851,-22.794728282330297 2.1908409826782096 -27.742621375368802c 15.89942098246672,-4.947893093038505 77.30626392965536,3.0031559101762695 138.71310687684394 10.954204913391044" /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 89.9819766975543,73.83089383093066 l -6.420476687285677e-2,0.49586061338928916 l -0.47159146753799513,-6.106236191164162e-2 l 0.5357962344108519,-0.43479825147764756 l -0.4073867006651384,-0.5569229753009308 l 0.47159146753799513,6.106236191164162e-2 l -6.420476687285677e-2,0.49586061338928916 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 89.9819766975543,73.83089383093066 l -9.81976544020477,7.968732456689302 l -19.326463821857203,-2.5024191691242024 l 10.592823993079056,-7.868635689924334 l -8.239407860814753,-10.307060971598373 l 19.326463821857203,2.5024191691242024 l 7.466349307940467,10.206964204833405 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 396.103896103896,71.42857142857143 l -32.982355078418344,6.185770522810794 l 6.7381797601759725,-9.583905225546857 l -4.075015142080604,-10.984013721974463 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 369.8597207856536,68.03043672583537 l -0.26068935173322666,-3.375444349141672e-2 l -6.420476687285682e-2,0.49586061338928916 l 0.32489411860608347,-0.46210616989787245 l -0.26068935173322666,-3.375444349141672e-2 l 6.420476687285682e-2,-0.49586061338928916 Z" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="142.8571" stroke-opacity="1" viewBox="0 0 500 143" font-size="1" width="500.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(169,169,169)" stroke-width="5.345224838248488" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 461.0390,136.3636 l -0.0000,-129.8701 h -129.8701 l -0.0000,129.8701 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(169,169,169)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 398.7013,71.4286 c 0.0000,-1.4345 -1.1629,-2.5974 -2.5974 -2.5974c -1.4345,-0.0000 -2.5974,1.1629 -2.5974 2.5974c -0.0000,1.4345 1.1629,2.5974 2.5974 2.5974c 1.4345,0.0000 2.5974,-1.1629 2.5974 -2.5974Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(169,169,169)" stroke-width="5.345224838248488" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 136.3636,136.3636 l -0.0000,-129.8701 h -129.8701 l -0.0000,129.8701 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(169,169,169)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 74.0260,71.4286 c 0.0000,-1.4345 -1.1629,-2.5974 -2.5974 -2.5974c -1.4345,-0.0000 -2.5974,1.1629 -2.5974 2.5974c -0.0000,1.4345 1.1629,2.5974 2.5974 2.5974c 1.4345,0.0000 2.5974,-1.1629 2.5974 -2.5974Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.0690449676496976" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.9820,73.8309 c 61.4068,7.9510 122.8137,15.9021 138.7131 10.9542c 15.8994,-4.9479 -13.7086,-22.7947 2.1908 -27.7426c 15.8994,-4.9479 77.3063,3.0032 138.7131 10.9542"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.9820,73.8309 l -7.4663,-10.2070 l -19.3265,-2.5024 l 8.2394,10.3071 l -10.5928,7.8686 l 19.3265,2.5024 l 9.8198,-7.9687 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.9820,73.8309 l 0.0686,-0.5301 l -0.5042,-0.0653 l 0.4355,0.5954 l -0.5728,0.4648 l 0.5042,0.0653 l 0.0686,-0.5301 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 396.1039,71.4286 l -30.2984,-14.3723 l 4.0722,10.9765 l -6.7336,9.5773 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 369.8777,68.0328 l -0.2787,-0.0361 l 0.0686,-0.5301 l 0.2101,0.5662 l -0.2787,-0.0361 l -0.0686,0.5301 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrow_example2.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500.0" height="191.60937134592436" font-size="1" viewBox="0 0 500 192" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.238093280317519" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><g><g><path d="M 92.8160519668354,95.80468567296218 l 2.89201135554859e-15,47.23012965962302 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 92.8160519668354,153.86813153536352 l -4.14210333348447,-12.748083238743886 l 4.142103333484469,2.1776325920251587 l 4.142103333484469,-2.1776325920251596 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 92.8160519668354,143.29768088864478 l -1.6095873091721878e-17,-0.26286555605956674 l -0.5,3.061616997868383e-17 l 0.5,0.2628655560595667 l -1.6095873091721878e-17,-0.26286555605956674 l 0.5,-3.061616997868383e-17 Z" /></g></g></g></g></g></g><g><g stroke="rgb(169,169,169)" stroke-opacity="1.0" stroke-width="6.190466401587595"><path d="M 477.2727272727272,124.83640860416281 l -1.2892674897102844e-14,-58.063445862401316 l -41.05705630836196,-41.05705630836195 l -58.063445862401316,9.337314240960074e-15 l -41.05705630836195,41.05705630836196 l 5.781953584817304e-15,58.063445862401316 l 41.05705630836196,41.05705630836196 l 58.063445862401316,-2.2265929286745346e-15 Z" /></g><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 409.98749920274713,95.80468567296218 c 0.0,-1.5483585563307023 -1.2551926132518025,-2.803551169582505 -2.803551169582504 -2.803551169582505c -1.5483585563307023,-9.480961749714055e-17 -2.803551169582505,1.2551926132518023 -2.803551169582505 2.803551169582504c -1.896192349942811e-16,1.5483585563307023 1.255192613251802,2.803551169582505 2.8035511695825037 2.803551169582505c 1.5483585563307023,2.844288524914217e-16 2.803551169582505,-1.255192613251802 2.8035511695825055 -2.803551169582504Z" /></g></g></g></g><g></g><g stroke="rgb(169,169,169)" stroke-opacity="1.0" stroke-width="6.190466401587595"><path d="M 162.904831206398,124.83640860416281 l -1.2892674897102844e-14,-58.063445862401316 l -41.05705630836196,-41.05705630836195 l -58.063445862401316,9.337314240960074e-15 l -41.05705630836195,41.05705630836196 l 5.781953584817304e-15,58.063445862401316 l 41.05705630836196,41.05705630836196 l 58.063445862401316,-2.2265929286745346e-15 Z" /></g><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 95.61960313641791,95.80468567296218 c 0.0,-1.5483585563307023 -1.2551926132518025,-2.803551169582505 -2.803551169582504 -2.803551169582505c -1.5483585563307023,-9.480961749714055e-17 -2.803551169582505,1.2551926132518023 -2.803551169582505 2.803551169582504c -1.896192349942811e-16,1.5483585563307023 1.255192613251802,2.803551169582505 2.8035511695825037 2.803551169582505c 1.5483585563307023,2.844288524914217e-16 2.803551169582505,-1.255192613251802 2.8035511695825055 -2.803551169582504Z" /></g></g></g><g><g><g><path d="M 92.8160519668354,95.80468567296218 h 292.70126366077255 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 407.18394803316454,95.80468567296218 l -25.81318531625282,8.387212331760587 l 4.4094184667558025,-8.387212331760587 l -4.4094184667558025,-8.387212331760587 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 385.78018118366754,95.80468567296218 h -0.26286555605956674 v 0.5 l 0.26286555605956674,-0.5 h -0.26286555605956674 v -0.5 Z" /></g></g></g></g></g></g><g><g><g><path d="M 162.90483120639794,124.83640860416287 l 152.52370518164744,-2.4886480444135933e-14 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 337.095168793602,124.83640860416284 l -25.81318531625282,8.38721233176059 l 4.409418466755801,-8.387212331760587 l -4.409418466755804,-8.387212331760587 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 315.691401944105,124.83640860416284 l -0.26286555605956674,4.2890372434385847e-17 l 8.15823363800974e-17,0.5 l 0.2628655560595667,-0.5 l -0.26286555605956674,4.2890372434385847e-17 l -8.15823363800974e-17,-0.5 Z" /></g></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="191.6094" stroke-opacity="1" viewBox="0 0 500 192" font-size="1" width="500.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.238093280317519" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8161,95.8047 l 0.0000,47.2301 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8161,153.8681 l 4.1176,-12.6726 l -4.1176,2.1647 l -4.1176,-2.1647 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8161,143.3603 l -0.0000,-0.3255 l 0.6190,-0.0000 l -0.6190,0.3255 l -0.0000,-0.3255 l -0.6190,0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(169,169,169)" stroke-width="6.190466401587595" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 477.2727,124.8364 l -0.0000,-58.0634 l -41.0571,-41.0571 l -58.0634,0.0000 l -41.0571,41.0571 l 0.0000,58.0634 l 41.0571,41.0571 l 58.0634,-0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 409.9875,95.8047 c 0.0000,-1.5484 -1.2552,-2.8036 -2.8036 -2.8036c -1.5484,-0.0000 -2.8036,1.2552 -2.8036 2.8036c -0.0000,1.5484 1.2552,2.8036 2.8036 2.8036c 1.5484,0.0000 2.8036,-1.2552 2.8036 -2.8036Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(169,169,169)" stroke-width="6.190466401587595" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 162.9048,124.8364 l -0.0000,-58.0634 l -41.0571,-41.0571 l -58.0634,0.0000 l -41.0571,41.0571 l 0.0000,58.0634 l 41.0571,41.0571 l 58.0634,-0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.6196,95.8047 c 0.0000,-1.5484 -1.2552,-2.8036 -2.8036 -2.8036c -1.5484,-0.0000 -2.8036,1.2552 -2.8036 2.8036c -0.0000,1.5484 1.2552,2.8036 2.8036 2.8036c 1.5484,0.0000 2.8036,-1.2552 2.8036 -2.8036Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.238093280317519" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8161,95.8047 h 292.7013 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 407.1839,95.8047 l -25.7377,-8.3627 l 4.3965,8.3627 l -4.3965,8.3627 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 385.8428,95.8047 h -0.3255 v -0.6190 l 0.3255,0.6190 h -0.3255 v 0.6190 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.238093280317519" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 162.9048,124.8364 l 152.5237,-0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 337.0952,124.8364 l -25.7377,-8.3627 l 4.3965,8.3627 l -4.3965,8.3627 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 315.7540,124.8364 l -0.3255,0.0000 l -0.0000,-0.6190 l 0.3255,0.6190 l -0.3255,0.0000 l 0.0000,0.6190 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_blockEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.500000000000001,50.0 h -3.3000000000000007 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.500000000000001,48.660607986722184 l -3.8857805861880484e-16,2.6787840265556295 h -3.5000000000000004 l -3.8857805861880484e-16,-2.6787840265556295 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,49.2129 l -0.0000,-34.7894 h -45.4545 l -0.0000,34.7894 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_dart'Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.5000000000000013,50.0 h -3.3000000000000087 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.5000000000000013,50.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 4.440892098500626e-16,50.0 l 4.221039653541545,1.371498922015771 l -0.7210396535415439,-1.371498922015771 l 0.7210396535415439,-1.371498922015771 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 l 54.8187,-17.8117 l -9.3642,17.8117 l 9.3642,17.8117 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 0.0000 h -0.0000 h 0.0000 h 0.0000 h 0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_dartEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 0.0,50.0 h -3.3000000000000087 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.19999999999999218,50.0 l -4.221039653541545,1.371498922015771 l 0.7210396535415439,-1.371498922015771 l -0.7210396535415439,-1.371498922015771 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M -3.3000000000000087,50.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,31.8182 l -54.8187,-17.8117 l 9.3642,17.8117 l -9.3642,17.8117 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h -0.0000 h 0.0000 h 0.0000 h 0.0000 h 0.0000 Z"/></g></svg>
+ diagrams/src_Diagrams_TwoD_Arrowheads_halfDart'Ex.svg view
@@ -0,0 +1,1 @@+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 l 54.8187,-17.8117 l -9.3642,17.8117 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 0.0000 h -0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
+ diagrams/src_Diagrams_TwoD_Arrowheads_halfDartEx.svg view
@@ -0,0 +1,1 @@+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,31.8182 l -54.8187,-17.8117 l 9.3642,17.8117 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h -0.0000 h 0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_quillEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.5000000000000004,50.0 h -3.3000000000000007 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.5000000000000004,50.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.5000000000000004,50.0 l -1.6304662335935967,1.7143736525197137 h -3.645833333333334 l 1.7762995669269297,-1.7143736525197137 l -1.7762995669269297,-1.7143736525197137 h 3.645833333333334 l 1.6304662335935967,1.7143736525197137 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 l -21.1749,-22.2646 h -47.3485 l 23.0688,22.2646 l -23.0688,22.2646 h 47.3485 l 21.1749,-22.2646 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 0.0000 h 0.0000 h 0.0000 h 0.0000 h 0.0000 h 0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_spike'Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.500000000000001,50.0 h -3.3000000000000007 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.500000000000001,50.0 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 4.440892098500626e-16,50.0 l 4.224873734152917,1.7500000000000004 c -0.9664983122038887,-0.9664983122038886 -0.9664983122038892,-2.533501687796112 -5.495323605393214e-16 -3.5000000000000004l -4.224873734152917,1.7500000000000004 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 l 54.8685,-22.7273 c -12.5519,12.5519 -12.5519,32.9026 0.0000 45.4545l -54.8685,-22.7273 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_spikeEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 0.0,50.0 h -3.3000000000000007 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.19999999999999973,50.0 l -4.224873734152917,1.7500000000000004 c 0.9664983122038887,-0.9664983122038886 0.9664983122038892,-2.533501687796112 5.495323605393214e-16 -3.5000000000000004l 4.224873734152917,1.7500000000000004 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M -3.3000000000000007,50.0 Z" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,31.8182 l -54.8685,-22.7273 c 12.5519,12.5519 12.5519,32.9026 0.0000 45.4545l 54.8685,-22.7273 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_thorn'Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.500000000000001,50.0 h -3.3000000000000007 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 3.500000000000001,50.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 8.881784197001252e-16,50.0 c 2.3333333333333335,0.0 3.9832491561019445,1.649915822768611 3.9832491561019445 1.649915822768611l -0.48324915610194413,-1.649915822768611 h -3.5 c 2.3333333333333335,0.0 3.9832491561019445,-1.649915822768611 3.9832491561019445 -1.649915822768611l -0.48324915610194413,1.649915822768611 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 c 30.3030,0.0000 51.7305,-21.4275 51.7305 -21.4275l -6.2760,21.4275 h -45.4545 c 30.3030,0.0000 51.7305,21.4275 51.7305 21.4275l -6.2760,-21.4275 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 0.0000 h -0.0000 h 0.0000 h 0.0000 h 0.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_thornEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 0.0,50.0 h -3.2999999478459427 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.20000005215405725,50.0 c -2.3333333333333335,0.0 -3.9832491561019445,1.649915822768611 -3.9832491561019445 1.649915822768611l 0.48324915610194413,-1.649915822768611 h 3.5 c -2.3333333333333335,0.0 -3.9832491561019445,-1.649915822768611 -3.9832491561019445 -1.649915822768611l 0.48324915610194413,1.649915822768611 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M -3.2999999478459427,50.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,31.8182 c -30.3030,0.0000 -51.7305,-21.4275 -51.7305 -21.4275l 6.2760,21.4275 h 45.4545 c -30.3030,0.0000 -51.7305,21.4275 -51.7305 21.4275l 6.2760,-21.4275 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h -0.0000 h 0.0000 h 0.0000 h 0.0000 h 0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_tri'Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 3.5,50.0 h -3.300000000000003 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.0,50.0 l 3.5,2.0207259421636903 v -4.041451884327381 Z" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 l 45.4545,-26.2432 v 52.4864 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_tri25Ex.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="120.0" height="119.99999999999996" font-size="1" viewBox="0 0 120 120" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 120.0,119.99999999999996 l -1.3322676295501874e-14,-119.99999999999996 h -119.99999999999996 l -1.3322676295501874e-14,119.99999999999996 Z" /></g><g><g><g stroke-width="0.0"><path d="M 0.0,59.99999999999998 h -3.999999999999999 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.20000000000000018,59.99999999999998 l -4.199999999999999,1.3646627241782066 v -2.729325448356413 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="120.0000" stroke-opacity="1" viewBox="0 0 120 120" font-size="1" width="120.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 105.0000,105.0000 l -0.0000,-90.0000 h -90.0000 l -0.0000,90.0000 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 15.0000,60.0000 h -0.0000 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 90.0000,60.0000 l -75.0000,-24.3690 v 48.7380 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Arrowheads_triEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="0.0"><path d="M 100.0,100.0 l -1.1102230246251565e-14,-100.0 h -100.0 l -1.1102230246251565e-14,100.0 Z" /></g><g><g><g stroke-width="0.0"><path d="M 0.0,50.0 h -3.300000000000003 " /></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g><g stroke-width="0.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="M 0.19999999999999707,50.0 l -3.5,2.0207259421636903 v -4.041451884327381 Z" /></g></g></g><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><g fill="rgb(0,0,0)" fill-opacity="1.0"><path d="" /></g></g></g></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="63.6364" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.5455,54.5455 l -0.0000,-45.4545 h -45.4545 l -0.0000,45.4545 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,31.8182 h 45.4545 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,31.8182 l -45.4545,-26.2432 v 52.4864 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g></svg>
diagrams/src_Diagrams_TwoD_Curvature_diagramA.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="200.0" font-size="1" viewBox="0 0 400 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0285189544531599" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="1.9284730395996748"><path d="M 18.18181818181816,175.13148009015777 c 218.1818181818182,0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.9284730395996748" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 18.1818,175.1315 c 218.1818,-0.0000 145.4545,-181.8182 363.6364 -145.4545"/></g></svg>
diagrams/src_Diagrams_TwoD_Curvature_diagramNeg.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="200.0" font-size="1" viewBox="0 0 400 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0285189544531599" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><g><path d="M 281.16363636363644,30.840570999248655 l 37.77763883175646,135.36987248046086 " /><g><path d="M 459.483626004958,166.2104434797095 c 0.0,-77.61939705749228 -62.922953752072814,-140.5423508095651 -140.54235080956508 -140.5423508095651c -77.61939705749228,-4.75281730791027e-15 -140.5423508095651,62.92295375207281 -140.5423508095651 140.54235080956505c -9.50563461582054e-15,77.61939705749228 62.9229537520728,140.5423508095651 140.54235080956505 140.5423508095651c 77.61939705749228,1.425845192373081e-14 140.5423508095651,-62.92295375207279 140.54235080956516 -140.54235080956505Z" /></g></g></g><g stroke-width="1.9284730395996748"><path d="M 18.18181818181816,175.13148009015777 c 218.1818181818182,0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 281.1636,30.8406 l 37.7776,135.3699 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 459.4836,166.2104 c 0.0000,-77.6194 -62.9230,-140.5424 -140.5424 -140.5424c -77.6194,-0.0000 -140.5424,62.9230 -140.5424 140.5424c -0.0000,77.6194 62.9230,140.5424 140.5424 140.5424c 77.6194,0.0000 140.5424,-62.9230 140.5424 -140.5424Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.9284730395996748" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 18.1818,175.1315 c 218.1818,-0.0000 145.4545,-181.8182 363.6364 -145.4545"/></g></svg>
diagrams/src_Diagrams_TwoD_Curvature_diagramPos.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="200.0" font-size="1" viewBox="0 0 400 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0285189544531599" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><g><path d="M 118.83636363636364,156.51329827197594 l -70.91174171622768,-156.36948173322 " /><g><path d="M 219.62170963785124,0.14381653875594225 c 0.0,-94.82568313685418 -76.87140458086108,-171.69708771771528 -171.69708771771525 -171.69708771771528c -94.82568313685418,-5.806398466525481e-15 -171.69708771771528,76.87140458086107 -171.69708771771528 171.69708771771522c -1.1612796933050962e-14,94.82568313685418 76.87140458086105,171.69708771771528 171.6970877177152 171.69708771771528c 94.82568313685418,1.741919539957644e-14 171.69708771771528,-76.87140458086105 171.6970877177153 -171.69708771771522Z" /></g></g></g><g stroke-width="1.9284730395996748"><path d="M 18.18181818181816,175.13148009015777 c 218.1818181818182,0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 118.8364,156.5133 l -70.9117,-156.3695 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 219.6217,0.1438 c 0.0000,-94.8257 -76.8714,-171.6971 -171.6971 -171.6971c -94.8257,-0.0000 -171.6971,76.8714 -171.6971 171.6971c -0.0000,94.8257 76.8714,171.6971 171.6971 171.6971c 94.8257,0.0000 171.6971,-76.8714 171.6971 -171.6971Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.9284730395996748" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 18.1818,175.1315 c 218.1818,-0.0000 145.4545,-181.8182 363.6364 -145.4545"/></g></svg>
diagrams/src_Diagrams_TwoD_Curvature_diagramZero.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="200.0" font-size="1" viewBox="0 0 400 200" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.0285189544531599" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><g><path d="M 189.01818181818183,101.12693463561232 l -602.0741002308241,-540.4757599431822 " /><g><path d="M 396.0221181542372,-439.3488253075699 c 0.0,-446.8414610189286 -362.2365755479508,-809.0780365668795 -809.0780365668793 -809.0780365668795c -446.8414610189286,-2.7361148248157886e-14 -809.0780365668795,362.2365755479508 -809.0780365668795 809.0780365668793c -5.472229649631577e-14,446.8414610189286 362.23657554795074,809.0780365668795 809.0780365668792 809.0780365668795c 446.8414610189286,8.208344474447366e-14 809.0780365668795,-362.2365755479507 809.0780365668796 -809.0780365668793Z" /></g></g></g><g stroke-width="1.9284730395996748"><path d="M 18.18181818181816,175.13148009015777 c 218.1818181818182,0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="200.0000" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 189.0182,101.1269 l -602.0741,-540.4758 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="1.0285189544531599" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 396.0221,-439.3488 c 0.0000,-446.8415 -362.2366,-809.0780 -809.0780 -809.0780c -446.8415,-0.0000 -809.0780,362.2366 -809.0780 809.0780c -0.0000,446.8415 362.2366,809.0780 809.0780 809.0780c 446.8415,0.0000 809.0780,-362.2366 809.0780 -809.0780Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="1.9284730395996748" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 18.1818,175.1315 c 218.1818,-0.0000 145.4545,-181.8182 363.6364 -145.4545"/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_cubicOffsetExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600.0" height="302.85875688987323" font-size="1" viewBox="0 0 600 303" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.7051228888683605" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><g><g stroke-width="3.1971054166281756"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 511.9817800443453,129.7570514462028 c 10.606235857710121,25.069284754587564 34.20547084215346,55.8254698109027 80.48722731216127 86.67997412424124" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 504.6599970504862,99.66254214599796 c 0.33466387043136825,8.255042137307122 2.4133795608657396,18.492828458584018 7.321782993859167 30.094509300204834" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 506.49373385140154,85.26625987587948 c -1.4640943353929654,2.9281886707859424 -2.1082544888015438,7.624845968926011 -1.8337368009153654 14.396282270118487" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 506.20843689577913,85.59271401011557 c 6.779273038019215e-2,-7.684807703746527e-2 0.22264374631797684,-0.20114771562720807 0.2852969556224121 -0.3264541342360786" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 502.6579126738121,87.93569090398208 c 1.0996662998461504,-0.4143670115362421 2.4468736239330267,-1.09190726288214 3.550524221967022 -2.3429768938665214" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 494.06231178115127,87.58378657314935 c 2.9457623866121128,1.3739128917795689 5.382041925447614,1.56281060833337 8.595600892660828 0.35190433083272776" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 489.69619466917715,83.76303109322222 c 1.2338357087118965,2.0880296608970546 2.8653457932043813,3.120790991330947 4.3661171119741375 3.820755479927119" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 489.27962586563393,82.94401200781272 c 7.734890935360485e-2,0.32804714747133107 0.30246544790101604,0.6259210989381142 0.4165688035432176 0.8190190854095305" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 489.54489237921933,85.09467757558335 c -5.201273523887837e-2,-0.8562096416246061 -0.12423198149539025,-1.552519112523536 -0.2652665135854216 -2.1506655677706314" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 488.88654448360757,96.10544324136518 c 0.6285951592007363,-4.609697834138748 0.828592417895299,-8.2082789143452 0.6583478956117675 -11.010765665781841" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 441.84915448663645,221.4997735858574 c 31.929731500854007,-63.859463001708015 44.04397766876603,-103.4426399376551 47.0373899969711 -125.39433034449225" /></g></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0" stroke-width="3.1971054166281756"><path d="M 453.61585838946286,227.38312553727062 c 131.55574898915938,-263.11149797831877 -65.77787449457969,-131.55574898915938 131.55574898915938 0.0" /></g></g></g><g><g stroke-width="3.1971054166281756"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 364.7622235703774,85.96753101537462 c 0.0,15.32911917179821 0.6082191299019319,77.38134470418049 61.92469581709475 138.6978213913733" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 364.7418968655278,83.13929813428342 c 1.788756316072539e-2,0.7020868540585622 2.0326704849611067e-2,1.6834288388046041 2.0326704849611067e-2 2.8282328810911928" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 364.66018914900314,81.56310499408985 c 3.509055922831261e-2,0.4103645954199807 6.611191242317345e-2,0.9640578292107734 8.170771652464312e-2 1.5761931401935576" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 364.0519985963925,78.3408445789562 c 0.1986120881746295,0.6454892865675517 0.49647125301243666,1.9157652726099432 0.6081905526106672 3.222260415133674" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 361.61586606058245,73.77595634835652 c 0.7782819994477024,0.9536356598170914 1.821193672048922,2.5663369233759687 2.4361325358100574 4.56488823059968" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 357.18966169675525,70.25802410049732 c 1.5342253961814387,0.7533004195932371 3.0492264459247083,1.8307093052441525 4.4262043638271615 3.5179322478592" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 349.91728913050906,68.98396616497621 c 2.6563706456126566,-0.29220077101738523 4.874998058580779,9.695369318400074e-2 7.272372566246194 1.2740579355211068" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 344.50737812673475,70.81874430723295 c 1.8904834233446657,-1.1435066965469183 3.695186810264414,-1.646158480970656 5.409911003774321 -1.8347781422567455" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 341.90372938933297,72.87554041429576 c 0.8842995586107709,-0.8970890150369701 1.797912982551884,-1.5694264639648254 2.603648737401782 -2.0567961070628042" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 339.9429387947987,75.39357199790629 c 0.6567471005360201,-1.07633552587847 1.4089406003338527,-1.9582002878411218 1.9607905945342574 -2.518031583610547" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 338.2153466102729,79.15920115255244 c 0.597623909908983,-1.6434657522496974 1.3914287352020123,-3.2146946126988167 1.7275921845258109 -3.7656291546461453" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 331.02089158742825,99.97173175435304 c 4.036215742086064,-11.099593290736674 6.185401087323137,-18.037632279116448 7.194455022844654 -20.812530601800606" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 274.0620702740554,228.08439667676572 c 32.5250961454588,-65.0501922909176 48.82754727700816,-105.75166132240976 56.95882131337286 -128.11266492241268" /></g></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0" stroke-width="3.1971054166281756"><path d="M 285.8287741768818,233.96774862817892 c 131.55574898915938,-263.11149797831877 0.0,-131.55574898915938 131.55574898915938 0.0" /></g></g></g><g><g><g stroke-width="3.1971054166281756"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 243.50666848816087,119.71820244879379 c -3.7564422059063327,1.274913718368207 -8.501013484230306,2.111132473581956 -14.329190482484984 2.111132473581956" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 255.13710847034906,112.19787026866632 c -2.6841784256200127,3.067632486422875 -6.357946646148891,5.7308798963808005 -11.630439982188191 7.520332180127452" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 258.96767454384855,87.61006066523365 c 3.4874720283559038,9.299925408949084 2.272509976123352,17.612865546720847 -3.830566073499483 24.58780960343268" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 220.95524369385342,62.629247877254016 c 17.797228450008376,0.0 33.56312373749303,13.115993821307395 38.01243084999512 24.980812787979637" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 193.4370789740102,72.62776873252105 c 9.382487531803335,-7.358813750433995 18.687588219322443,-9.998520855267019 27.518164719843227 -9.998520855267019" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 170.96813963611902,103.1924277725802 c 6.767680004875894,-14.76584728336559 14.6245829686032,-24.412222671990158 22.468939337891168 -30.564659040059155" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 150.24402861218024,240.2295090126192 c 0.0,-68.44669429030839 8.959835442792022,-111.36957088117335 20.724111023938775 -137.037081240039" /></g></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0" stroke-width="3.1971054166281756"><path d="M 163.3996035110962,240.2295090126192 c 0.0,-263.11149797831877 131.55574898915938,-131.55574898915938 65.77787449457969 -131.55574898915938" /></g></g></g><g><g stroke-width="3.1971054166281756"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 107.3603699766031,38.693005210400855 c 6.432503982934959,-12.169602129876955 14.760815226591284,-20.476100728687896 25.887308602478793 -24.92669807904294" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 95.42391061094953,75.63181695246936 c 2.8371303744504006,-14.299137087230031 6.687768172920306,-27.008855431492076 11.936459365653556 -36.938811742068495" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 83.97921363564316,165.6871778325085 c 4.142251616420563,-31.481112284796282 6.26688245478068,-63.95917569658957 11.444696975306384 -90.05536088003915" /></g><g stroke="rgb(255,0,0)" stroke-opacity="1.0"><path d="M 62.05745780862836,244.98865707076718 c 12.61861350979178,-21.354576708878394 18.039105516309633,-49.793336876899446 21.921755827014795 -79.30147923825866" /></g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 6.577787449457958,275.93687485959947 c 26.333097622202164,0.0 44.78184945015078,-12.844213173568285 55.4796703591704 -30.94821778883227" /></g></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0" stroke-width="3.1971054166281756"><path d="M 6.577787449457958,289.0924497585154 c 131.55574898915938,0.0 65.77787449457969,-236.8003481804869 131.55574898915938 -263.11149797831877" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="302.8588" stroke-opacity="1" viewBox="0 0 600 303" font-size="1" width="600.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 511.9818,129.7571 c 10.6062,25.0693 34.2055,55.8255 80.4872 86.6800"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 504.6600,99.6625 c 0.3347,8.2550 2.4134,18.4928 7.3218 30.0945"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 506.4937,85.2663 c -1.4641,2.9282 -2.1083,7.6248 -1.8337 14.3963"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 506.2084,85.5927 c 0.0678,-0.0768 0.2226,-0.2011 0.2853 -0.3265"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 502.6579,87.9357 c 1.0997,-0.4144 2.4469,-1.0919 3.5505 -2.3430"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 494.0623,87.5838 c 2.9458,1.3739 5.3820,1.5628 8.5956 0.3519"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 489.6962,83.7630 c 1.2338,2.0880 2.8653,3.1208 4.3661 3.8208"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 489.2796,82.9440 c 0.0773,0.3280 0.3025,0.6259 0.4166 0.8190"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 489.5449,85.0947 c -0.0520,-0.8562 -0.1242,-1.5525 -0.2653 -2.1507"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 488.8865,96.1054 c 0.6286,-4.6097 0.8286,-8.2083 0.6583 -11.0108"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 441.8492,221.4998 c 31.9297,-63.8595 44.0440,-103.4426 47.0374 -125.3943"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 453.6159,227.3831 c 131.5557,-263.1115 -65.7779,-131.5557 131.5557 -0.0000"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 364.7622,85.9675 c 0.0000,15.3291 0.6082,77.3813 61.9247 138.6978"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 364.7419,83.1393 c 0.0179,0.7021 0.0203,1.6834 0.0203 2.8282"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 364.6602,81.5631 c 0.0351,0.4104 0.0661,0.9641 0.0817 1.5762"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 364.0520,78.3408 c 0.1986,0.6455 0.4965,1.9158 0.6082 3.2223"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 361.6159,73.7760 c 0.7783,0.9536 1.8212,2.5663 2.4361 4.5649"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 357.1897,70.2580 c 1.5342,0.7533 3.0492,1.8307 4.4262 3.5179"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 349.9173,68.9840 c 2.6564,-0.2922 4.8750,0.0970 7.2724 1.2741"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 344.5074,70.8187 c 1.8905,-1.1435 3.6952,-1.6462 5.4099 -1.8348"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 341.9037,72.8755 c 0.8843,-0.8971 1.7979,-1.5694 2.6036 -2.0568"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 339.9429,75.3936 c 0.6567,-1.0763 1.4089,-1.9582 1.9608 -2.5180"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 338.2153,79.1592 c 0.5976,-1.6435 1.3914,-3.2147 1.7276 -3.7656"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 331.0209,99.9717 c 4.0362,-11.0996 6.1854,-18.0376 7.1945 -20.8125"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 274.0621,228.0844 c 32.5251,-65.0502 48.8275,-105.7517 56.9588 -128.1127"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 285.8288,233.9677 c 131.5557,-263.1115 0.0000,-131.5557 131.5557 -0.0000"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 243.5067,119.7182 c -3.7564,1.2749 -8.5010,2.1111 -14.3292 2.1111"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 255.1371,112.1979 c -2.6842,3.0676 -6.3579,5.7309 -11.6304 7.5203"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 258.9677,87.6101 c 3.4875,9.2999 2.2725,17.6129 -3.8306 24.5878"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 220.9552,62.6292 c 17.7972,-0.0000 33.5631,13.1160 38.0124 24.9808"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 193.4371,72.6278 c 9.3825,-7.3588 18.6876,-9.9985 27.5182 -9.9985"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 170.9681,103.1924 c 6.7677,-14.7658 14.6246,-24.4122 22.4689 -30.5647"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 150.2440,240.2295 c 0.0000,-68.4467 8.9598,-111.3696 20.7241 -137.0371"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 163.3996,240.2295 c 0.0000,-263.1115 131.5557,-131.5557 65.7779 -131.5557"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 107.3604,38.6930 c 6.4325,-12.1696 14.7608,-20.4761 25.8873 -24.9267"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4239,75.6318 c 2.8371,-14.2991 6.6878,-27.0089 11.9365 -36.9388"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 83.9792,165.6872 c 4.1423,-31.4811 6.2669,-63.9592 11.4447 -90.0554"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,0,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 62.0575,244.9887 c 12.6186,-21.3546 18.0391,-49.7933 21.9218 -79.3015"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 6.5778,275.9369 c 26.3331,-0.0000 44.7818,-12.8442 55.4797 -30.9482"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.197105416628175" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 6.5778,289.0924 c 131.5557,-0.0000 65.7779,-236.8003 131.5557 -263.1115"/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_expandLoopExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="300.00000000000006" font-size="1" viewBox="0 0 300 300" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.2" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g fill="rgb(0,128,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><path d="M 36.363636363636374,286.3636363636364 h 113.63636363636363 c 6.027647496353275,-2.892321107515236e-15 11.80841824405711,-2.3944736446685924 16.070608663330628 -6.656664063942104l 113.63636363636363,-113.63636363636363 c 4.262190419273511,-4.262190419273516 6.656664063942097,-10.042961166977355 6.656664063942101 -16.070608663330628v -113.63636363636363 c 0.0,-12.551926132518032 -10.175346594754691,-22.727272727272727 -22.727272727272723 -22.727272727272727c -6.027647496353271,2.1541471862354763e-15 -11.80841824405711,2.394473644668591 -16.070608663330628 6.6566640639421015l -227.27272727272725,227.27272727272725 c -8.875552085256137,8.875552085256135 -8.87555208525614,23.265665241405113 -5.0464682937507114e-15 32.14121732666125c 4.262190419273514,4.262190419273512 10.042961166977355,6.656664063942098 16.07060866333063 6.656664063942117ZM 36.363636363636374,240.9090909090909 c -12.551926132518032,3.7848512203130333e-14 -22.727272727272727,10.17534659475473 -22.727272727272727 22.72727272727276c -2.5232341468753557e-15,12.551926132518032 10.17534659475469,22.727272727272727 22.727272727272716 22.727272727272727c 6.027647496353271,-1.2616170734376779e-15 11.80841824405711,-2.3944736446685897 16.070608663330628 -6.656664063942099l 227.27272727272725,-227.27272727272725 c 8.875552085256135,-8.875552085256134 8.875552085256137,-23.265665241405113 0.0 -32.14121732666125c -8.875552085256134,-8.875552085256135 -23.265665241405113,-8.875552085256137 -32.14121732666125 -2.5232341468753557e-15c -4.262190419273512,4.262190419273517 -6.656664063942098,10.042961166977355 -6.6566640639421015 16.070608663330628v 113.63636363636363 c -2.5232341468753557e-15,12.551926132518032 10.17534659475469,22.727272727272727 22.72727272727272 22.72727272727273c 12.551926132518032,2.5232341468753557e-15 22.727272727272727,-10.17534659475469 22.72727272727273 -22.727272727272716c 2.5232341468753557e-15,-12.551926132518032 -10.175346594754686,-22.727272727272727 -22.727272727272712 -22.72727272727273c -6.027647496353266,1.2616170734376779e-15 -11.808418244057094,2.3944736446685777 -16.07060866333061 6.656664063942079l -113.63636363636363,113.63636363636363 c -8.875552085256132,8.875552085256139 -8.875552085256128,23.265665241405113 1.0092936587501423e-14 32.14121732666125c 8.875552085256139,8.875552085256132 23.265665241405113,8.87555208525613 32.14121732666125 -7.569702440626068e-15c 8.875552085256134,-8.875552085256139 8.87555208525613,-23.265665241405113 -5.0464682937507114e-15 -32.14121732666124c -4.262190419273514,-4.262190419273507 -10.042961166977339,-6.656664063942092 -16.070608663330603 -6.656664063942101Z" /></g></g></g><g stroke="rgb(255,255,255)" stroke-opacity="1.0" stroke-width="3.0"><path d="M 36.363636363636374,263.6363636363636 h 113.63636363636363 l 113.63636363636363,-113.63636363636363 v -113.63636363636363 Z" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="300.0000" stroke-opacity="1" viewBox="0 0 300 300" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,128,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 36.3636,286.3636 h 113.6364 c 6.0276,-0.0000 11.8084,-2.3945 16.0706 -6.6567l 113.6364,-113.6364 c 4.2622,-4.2622 6.6567,-10.0430 6.6567 -16.0706v -113.6364 c 0.0000,-12.5519 -10.1753,-22.7273 -22.7273 -22.7273c -6.0276,0.0000 -11.8084,2.3945 -16.0706 6.6567l -227.2727,227.2727 c -8.8756,8.8756 -8.8756,23.2657 -0.0000 32.1412c 4.2622,4.2622 10.0430,6.6567 16.0706 6.6567ZM 36.3636,240.9091 c -12.5519,0.0000 -22.7273,10.1753 -22.7273 22.7273c -0.0000,12.5519 10.1753,22.7273 22.7273 22.7273c 6.0276,-0.0000 11.8084,-2.3945 16.0706 -6.6567l 227.2727,-227.2727 c 8.8756,-8.8756 8.8756,-23.2657 0.0000 -32.1412c -8.8756,-8.8756 -23.2657,-8.8756 -32.1412 -0.0000c -4.2622,4.2622 -6.6567,10.0430 -6.6567 16.0706v 113.6364 c -0.0000,12.5519 10.1753,22.7273 22.7273 22.7273c 12.5519,0.0000 22.7273,-10.1753 22.7273 -22.7273c 0.0000,-12.5519 -10.1753,-22.7273 -22.7273 -22.7273c -6.0276,0.0000 -11.8084,2.3945 -16.0706 6.6567l -113.6364,113.6364 c -8.8756,8.8756 -8.8756,23.2657 0.0000 32.1412c 8.8756,8.8756 23.2657,8.8756 32.1412 -0.0000c 8.8756,-8.8756 8.8756,-23.2657 -0.0000 -32.1412c -4.2622,-4.2622 -10.0430,-6.6567 -16.0706 -6.6567Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 36.3636,263.6364 h 113.6364 l 113.6364,-113.6364 v -113.6364 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_expandTrailExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600.0" height="197.3830287816636" font-size="1" viewBox="0 0 600 197" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.376545341172593" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(12.98696646675048,0.0,0.0,12.98696646675048,481.81818181818187,168.9306232278259)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineCapSquare</text></g></g></g><g><g fill="rgb(0,128,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><path d="M 416.8830238425919,97.50165637702322 h -25.97393293350096 v 51.94786586700192 h 25.97393293350096 h 129.86966466750482 c 14.345007052300385,-8.783783485172937e-16 25.97393293350096,-11.628925881200574 25.973932933500958 -25.973932933500958c 0.0,-6.076251092058475 -2.130283781570332,-11.960201272862653 -6.020204939150425 -16.62810666195877l -64.93483233375241,-77.92179880050288 l -16.628106661958775,-19.953727994350533 l -39.907455988701045,33.25621332391753 l 16.628106661958775,19.953727994350533 l 64.93483233375241,77.92179880050288 c 9.183449727959651,11.020139673551585 25.561694982757718,12.509071060351415 36.5818346563093 3.325621332391765c 11.020139673551585,-9.183449727959651 12.509071060351415,-25.561694982757714 3.3256213323917683 -36.5818346563093c -4.934886876493225,-5.921864251791868 -12.245188268797092,-9.34582627154219 -19.95372799435053 -9.34582627154219Z" /></g></g></g><g stroke="rgb(255,255,255)" stroke-opacity="1.0" stroke-width="3.4413633529314827"><path d="M 416.8830238425919,123.47558931052419 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 " /></g></g></g><g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(12.98696646675048,0.0,0.0,12.98696646675048,287.0130335332496,163.62699800825925)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineCapRound</text></g></g></g><g><g fill="rgb(0,128,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><path d="M 222.07787555765964,92.19803115745658 c -14.345007052300385,-8.783783485172937e-16 -25.97393293350096,11.628925881200571 -25.97393293350096 25.973932933500954c -1.7567566970345874e-15,14.345007052300385 11.628925881200571,25.97393293350096 25.97393293350095 25.97393293350096h 129.86966466750482 c 14.345007052300385,-8.783783485172937e-16 25.97393293350096,-11.628925881200574 25.973932933500958 -25.973932933500958c 0.0,-6.076251092058475 -2.130283781570332,-11.960201272862653 -6.020204939150425 -16.62810666195877l -64.93483233375241,-77.92179880050288 c -9.183449727959651,-11.020139673551583 -25.56169498275772,-12.50907106035141 -36.5818346563093 -3.3256213323917594c -11.020139673551583,9.183449727959651 -12.509071060351411,25.56169498275772 -3.3256213323917625 36.5818346563093l 64.93483233375241,77.92179880050288 c 9.183449727959651,11.020139673551585 25.561694982757718,12.509071060351415 36.5818346563093 3.325621332391765c 11.020139673551585,-9.183449727959651 12.509071060351415,-25.561694982757714 3.3256213323917683 -36.5818346563093c -4.934886876493225,-5.921864251791868 -12.245188268797092,-9.34582627154219 -19.95372799435053 -9.34582627154219Z" /></g></g></g><g stroke="rgb(255,255,255)" stroke-opacity="1.0" stroke-width="3.4413633529314827"><path d="M 222.07787555765964,118.17196409095754 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 " /></g></g></g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(12.98696646675048,0.0,0.0,12.98696646675048,105.19485171506778,158.95375923065063)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineCapButt</text></g></g></g><g><g fill="rgb(0,128,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><g fill="rgb(0,128,0)" fill-opacity="1.0"><path d="M 27.272727272727366,87.52479237984795 v 51.94786586700192 h 129.86966466750482 c 14.345007052300385,-8.783783485172937e-16 25.97393293350096,-11.628925881200574 25.973932933500958 -25.973932933500958c 0.0,-6.076251092058475 -2.130283781570332,-11.960201272862653 -6.020204939150425 -16.62810666195877l -64.93483233375241,-77.92179880050288 l -39.907455988701045,33.25621332391753 l 64.93483233375241,77.92179880050288 c 9.183449727959651,11.020139673551585 25.561694982757718,12.509071060351415 36.5818346563093 3.325621332391765c 11.020139673551585,-9.183449727959651 12.509071060351415,-25.561694982757714 3.3256213323917683 -36.5818346563093c -4.934886876493225,-5.921864251791868 -12.245188268797092,-9.34582627154219 -19.95372799435053 -9.34582627154219Z" /></g></g></g><g stroke="rgb(255,255,255)" stroke-opacity="1.0" stroke-width="3.4413633529314827"><path d="M 27.272727272727366,113.49872531334891 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 " /></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="197.3830" stroke-opacity="1" viewBox="0 0 600 197" font-size="1" width="600.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="12.98696646675048px" stroke="rgb(0,0,0)" stroke-width="1.376545341172593" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,481.8182,168.9306)" stroke="none" text-anchor="middle">LineCapSquare</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,128,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 416.8830,97.5017 h -25.9739 v 51.9479 h 25.9739 h 129.8697 c 14.3450,-0.0000 25.9739,-11.6289 25.9739 -25.9739c 0.0000,-6.0763 -2.1303,-11.9602 -6.0202 -16.6281l -64.9348,-77.9218 l -16.6281,-19.9537 l -39.9075,33.2562 l 16.6281,19.9537 l 64.9348,77.9218 c 9.1834,11.0201 25.5617,12.5091 36.5818 3.3256c 11.0201,-9.1834 12.5091,-25.5617 3.3256 -36.5818c -4.9349,-5.9219 -12.2452,-9.3458 -19.9537 -9.3458Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,255)" stroke-width="3.4413633529314827" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 416.8830,123.4756 h 129.8697 l -64.9348,-77.9218 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="12.98696646675048px" stroke="rgb(0,0,0)" stroke-width="1.376545341172593" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,287.0130,163.6270)" stroke="none" text-anchor="middle">LineCapRound</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,128,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 222.0779,92.1980 c -14.3450,-0.0000 -25.9739,11.6289 -25.9739 25.9739c -0.0000,14.3450 11.6289,25.9739 25.9739 25.9739h 129.8697 c 14.3450,-0.0000 25.9739,-11.6289 25.9739 -25.9739c 0.0000,-6.0763 -2.1303,-11.9602 -6.0202 -16.6281l -64.9348,-77.9218 c -9.1834,-11.0201 -25.5617,-12.5091 -36.5818 -3.3256c -11.0201,9.1834 -12.5091,25.5617 -3.3256 36.5818l 64.9348,77.9218 c 9.1834,11.0201 25.5617,12.5091 36.5818 3.3256c 11.0201,-9.1834 12.5091,-25.5617 3.3256 -36.5818c -4.9349,-5.9219 -12.2452,-9.3458 -19.9537 -9.3458Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,255)" stroke-width="3.4413633529314827" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 222.0779,118.1720 h 129.8697 l -64.9348,-77.9218 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="12.98696646675048px" stroke="rgb(0,0,0)" stroke-width="1.376545341172593" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,105.1949,158.9538)" stroke="none" text-anchor="middle">LineCapButt</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(0,128,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 27.2727,87.5248 v 51.9479 h 129.8697 c 14.3450,-0.0000 25.9739,-11.6289 25.9739 -25.9739c 0.0000,-6.0763 -2.1303,-11.9602 -6.0202 -16.6281l -64.9348,-77.9218 l -39.9075,33.2562 l 64.9348,77.9218 c 9.1834,11.0201 25.5617,12.5091 36.5818 3.3256c 11.0201,-9.1834 12.5091,-25.5617 3.3256 -36.5818c -4.9349,-5.9219 -12.2452,-9.3458 -19.9537 -9.3458Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(255,255,255)" stroke-width="3.4413633529314827" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 27.2727,113.4987 h 129.8697 l -64.9348,-77.9218 "/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_offsetTrailExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600.0" height="185.1008379753402" font-size="1" viewBox="0 0 600 185" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.333029648793779" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="3.0"><g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(13.702641330909062,0.0,0.0,13.702641330909062,493.6874054156325,156.13320152555207)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineJoinBevel</text></g></g></g><g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 414.64753810399236,135.57923952918844 h 137.02641330909063 l 21.0533213141897,-44.949717090309534 l -68.51320665454531,-82.21584798545437 " /></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 414.64753810399236,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 " /></g></g></g><g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(13.702641330909062,0.0,0.0,13.702641330909062,318.7290487876289,156.13320152555207)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineJoinRound</text></g></g></g><g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 236.51320080217454,135.57923952918844 h 137.02641330909063 c 15.135519678924403,-9.267832864113272e-16 27.405282661818124,-12.269762982893718 27.40528266181812 -27.40528266181812c 0.0,-6.411096044960741 -2.247677674893909,-12.619294021209988 -6.3519613476284205 -17.54443442849141l -68.51320665454531,-82.21584798545437 " /></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 236.51320080217454,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 " /></g></g></g><g><g fill="rgb(0,0,0)" fill-opacity="1.0" font-weight="bold" font-family="Helvetica"><g fill="rgb(0,0,0)" fill-opacity="1.0"><text transform="matrix(13.702641330909062,0.0,0.0,13.702641330909062,125.0416433719964,156.13320152555207)" dominant-baseline="middle" text-anchor="middle" stroke="none">LineJoinMiter</text></g></g></g><g><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 27.27272727272728,135.57923952918844 h 137.02641330909063 h 58.51141888944763 l -37.45809757525794,-44.949717090309534 l -68.51320665454531,-82.21584798545437 " /></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 27.27272727272728,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 " /></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="185.1008" stroke-opacity="1" viewBox="0 0 600 185" font-size="1" width="600.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="13.702641330909062px" stroke="rgb(0,0,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,493.6874,156.1332)" stroke="none" text-anchor="middle">LineJoinBevel</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 414.6475,135.5792 h 137.0264 l 21.0533,-44.9497 l -68.5132,-82.2158 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 414.6475,108.1740 h 137.0264 l -68.5132,-82.2158 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="13.702641330909062px" stroke="rgb(0,0,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,318.7290,156.1332)" stroke="none" text-anchor="middle">LineJoinRound</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 236.5132,135.5792 h 137.0264 c 15.1355,-0.0000 27.4053,-12.2698 27.4053 -27.4053c 0.0000,-6.4111 -2.2477,-12.6193 -6.3520 -17.5444l -68.5132,-82.2158 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 236.5132,108.1740 h 137.0264 l -68.5132,-82.2158 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" font-size="13.702641330909062px" stroke="rgb(0,0,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" font-family="Helvetica" stroke-miterlimit="10.0" font-weight="bold"><text dominant-baseline="middle" transform="matrix(1.0000,0.0000,0.0000,1.0000,125.0416,156.1332)" stroke="none" text-anchor="middle">LineJoinMiter</text></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 27.2727,135.5792 h 137.0264 h 58.5114 l -37.4581,-44.9497 l -68.5132,-82.2158 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 27.2727,108.1740 h 137.0264 l -68.5132,-82.2158 "/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_offsetTrailLeftExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200.0" height="154.67216693398285" font-size="1" viewBox="0 0 200 155" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.7035274935556856" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="3.0"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 9.090909090909093,7.030553042453764 h 151.51451832306768 c 7.088955375224059,5.0464472042177966e-15 13.953559821257857,2.4853295947320184 19.399446190621173 7.023568235868117c 12.856821943491788,10.714018286243158 14.59390752436739,29.82195967587481 3.8798892381242314 42.678781619366596l -75.75725916153384,90.9087109938406 " /></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 9.090909090909093,37.3334567070673 h 151.51451832306768 l -75.75725916153384,90.9087109938406 " /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="154.6722" stroke-opacity="1" viewBox="0 0 200 155" font-size="1" width="200.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,7.0306 h 151.5145 c 7.0890,0.0000 13.9536,2.4853 19.3994 7.0236c 12.8568,10.7140 14.5939,29.8220 3.8799 42.6788l -75.7573,90.9087 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909,37.3335 h 151.5145 l -75.7573,90.9087 "/></g></svg>
diagrams/src_Diagrams_TwoD_Offset_offsetTrailOuterExample.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="271.2911579538083" font-size="1" viewBox="0 0 300 271" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="1.141138711190835" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g stroke-width="3.0"><g stroke="rgb(0,128,0)" stroke-opacity="1.0"><path d="M 232.44254819939368,239.47922220266122 l 48.701298701298725,-84.35312374523753 c 6.959719283925273,-12.05458740617544 6.959719283925287,-26.906451554863526 1.9464949133038462e-14 -38.961038961038966l -48.701298701298676,-84.35312374523755 c -6.959719283925259,-12.054587406175445 -19.82181093024447,-19.480519480519487 -33.741249498095 -19.4805194805195l -97.40259740259742,-4.325544251786325e-14 c -13.919438567850523,-7.0337922695555446e-15 -26.781530214169745,7.42593207434402 -33.741249498095016 19.480519480519458l -48.70129870129873,84.35312374523753 c -6.959719283925277,12.05458740617544 -6.959719283925293,26.906451554863523 -2.811603763661111e-14 38.961038961038966l 48.70129870129864,84.35312374523757 c 6.9597192839252635,12.054587406175456 19.82181093024449,19.480519480519504 33.74124949809503 19.4805194805195h 97.40259740259745 c 13.919438567850523,2.238416443174295e-15 26.78153021416974,-7.42593207434403 33.74124949809499 -19.480519480519447Z" /></g><g stroke="rgb(0,0,255)" stroke-opacity="1.0"><path d="M 198.70129870129864,219.99870272214173 l 48.701298701298725,-84.35312374523753 l -48.701298701298676,-84.35312374523755 l -97.40259740259742,-4.325544251786325e-14 l -48.70129870129873,84.35312374523753 l 48.70129870129864,84.35312374523757 Z" /></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="271.2912" stroke-opacity="1" viewBox="0 0 300 271" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,128,0)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 232.4425,239.4792 l 48.7013,-84.3531 c 6.9597,-12.0546 6.9597,-26.9065 -0.0000 -38.9610l -48.7013,-84.3531 c -6.9597,-12.0546 -19.8218,-19.4805 -33.7412 -19.4805h -97.4026 c -13.9194,-0.0000 -26.7815,7.4259 -33.7412 19.4805l -48.7013,84.3531 c -6.9597,12.0546 -6.9597,26.9065 -0.0000 38.9610l 48.7013,84.3531 c 6.9597,12.0546 19.8218,19.4805 33.7412 19.4805l 97.4026,-0.0000 c 13.9194,-0.0000 26.7815,-7.4259 33.7412 -19.4805Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,255)" stroke-width="3.0" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 198.7013,219.9987 l 48.7013,-84.3531 l -48.7013,-84.3531 h -97.4026 l -48.7013,84.3531 l 48.7013,84.3531 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_decagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="95.10565162951534" font-size="1" viewBox="0 0 100 95" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 86.7734997443158,74.27033728259734 l 8.681045710229654,-26.717511467839685 l -8.681045710229668,-26.717511467839678 l -22.727272727272723,-16.512330181940012 l -28.092454034086124,4.678333393029941e-15 l -22.72727272727272,16.51233018194002 l -8.681045710229657,26.717511467839685 l 8.681045710229663,26.71751146783968 l 22.727272727272723,16.512330181940015 l 28.092454034086124,-1.5594444643433139e-15 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="95.1057" stroke-opacity="1" viewBox="0 0 100 95" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 86.7735,74.2703 l 8.6810,-26.7175 l -8.6810,-26.7175 l -22.7273,-16.5123 l -28.0925,0.0000 l -22.7273,16.5123 l -8.6810,26.7175 l 8.6810,26.7175 l 22.7273,16.5123 l 28.0925,-0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_dodecagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="99.99999999999999" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454545,62.179508746869196 l -5.408788415759074e-15,-24.35901749373842 l -12.179508746869214,-21.09552796080702 l -21.095527960807022,-12.179508746869208 l -24.35901749373842,3.917228775555017e-15 l -21.09552796080702,12.179508746869208 l -12.179508746869214,21.09552796080702 l -8.391907696167188e-15,24.35901749373842 l 12.1795087468692,21.095527960807026 l 21.095527960807015,12.179508746869216 l 24.35901749373842,-9.341094951469035e-16 l 21.095527960807015,-12.17950874686922 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="100.0000" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,62.1795 l -0.0000,-24.3590 l -12.1795,-21.0955 l -21.0955,-12.1795 l -24.3590,0.0000 l -21.0955,12.1795 l -12.1795,21.0955 l -0.0000,24.3590 l 12.1795,21.0955 l 21.0955,12.1795 l 24.3590,-0.0000 l 21.0955,-12.1795 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_hendecagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="98.98214418809326" font-size="1" viewBox="0 0 100 99" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454545,57.04953832667333 l -3.6824569441366046,-25.612050621948153 l -16.94479989871783,-19.55534153624188 l -24.827288611691024,-7.289949684219485 l -24.827288611691028,7.289949684219488 l -16.944799898717825,19.55534153624188 l -3.6824569441365966,25.612050621948153 l 10.74904007121057,23.537114601287985 l 21.767792813036245,13.989311000023635 l 25.875425140597297,-1.4363746381527874e-15 l 21.767792813036245,-13.989311000023637 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="98.9821" stroke-opacity="1" viewBox="0 0 100 99" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,57.0495 l -3.6825,-25.6121 l -16.9448,-19.5553 l -24.8273,-7.2899 l -24.8273,7.2899 l -16.9448,19.5553 l -3.6825,25.6121 l 10.7490,23.5371 l 21.7678,13.9893 l 25.8754,-0.0000 l 21.7678,-13.9893 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_heptagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="97.49279121818235" font-size="1" viewBox="0 0 100 97" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454544,61.66054654499813 l -9.002830190689187,-39.443976283414365 l -36.45171526385628,-17.554220883072148 l -36.45171526385627,17.554220883072173 l -9.002830190689156,39.443976283414365 l 25.22536964033506,31.631613031861047 l 40.45835162842079,-1.0106503541157029e-14 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="97.4928" stroke-opacity="1" viewBox="0 0 100 97" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,61.6605 l -9.0028,-39.4440 l -36.4517,-17.5542 l -36.4517,17.5542 l -9.0028,39.4440 l 25.2254,31.6316 l 40.4584,-0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_hexagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="86.6025403784439" font-size="1" viewBox="0 0 100 87" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 72.72727272727272,82.66606127033282 l 22.72727272727274,-39.364791081110845 l -22.727272727272712,-39.36479108111086 l -45.45454545454545,-2.018587317500285e-14 l -22.727272727272744,39.36479108111084 l 22.727272727272698,39.36479108111087 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="86.6025" stroke-opacity="1" viewBox="0 0 100 87" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 72.7273,82.6661 l 22.7273,-39.3648 l -22.7273,-39.3648 l -45.4545,-0.0000 l -22.7273,39.3648 l 22.7273,39.3648 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_hruleEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300.0" height="48.00000000000001" font-size="1" viewBox="0 0 300 48" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 13.636363636363626,45.81818181818183 h 272.72727272727275 " /></g><g><g><path d="M 40.90909090909091,34.909090909090914 h 218.1818181818182 " /></g><path d="M 68.18181818181819,24.000000000000004 h 163.63636363636363 " /></g><g><path d="M 95.45454545454545,13.090909090909093 h 109.0909090909091 " /></g><path d="M 122.72727272727272,2.1818181818181834 h 54.54545454545455 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="48.0000" stroke-opacity="1" viewBox="0 0 300 48" font-size="1" width="300.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 13.6364,45.8182 h 272.7273 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 40.9091,34.9091 h 218.1818 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 68.1818,24.0000 h 163.6364 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,13.0909 h 109.0909 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 122.7273,2.1818 h 54.5455 "/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_nonagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="98.48077530122083" font-size="1" viewBox="0 0 100 98" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 89.97205643508258,73.84920813714508 l 5.482489019462867,-31.09274030233352 l -15.786197969720943,-27.342496941897323 l -29.668347484824512,-10.798395384342669 l -29.668347484824512,10.798395384342673 l -15.786197969720938,27.342496941897327 l 5.4824890194628795,31.09274030233352 l 24.185858465361633,20.294344917990855 l 31.57239593944188,5.257860137182526e-15 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="98.4808" stroke-opacity="1" viewBox="0 0 100 98" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.9721,73.8492 l 5.4825,-31.0927 l -15.7862,-27.3425 l -29.6683,-10.7984 l -29.6683,10.7984 l -15.7862,27.3425 l 5.4825,31.0927 l 24.1859,20.2943 l 31.5724,0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_octagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="99.99999999999999" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454544,68.82788919877703 l -8.361262437429426e-15,-37.65577839755409 l -26.626656255768403,-26.6266562557684 l -37.65577839755409,6.0555110132310925e-15 l -26.6266562557684,26.626656255768403 l 3.74975958903276e-15,37.65577839755409 l 26.626656255768403,26.626656255768403 l 37.65577839755409,-1.4440081648344269e-15 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="100.0000" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,68.8279 l -0.0000,-37.6558 l -26.6267,-26.6267 l -37.6558,0.0000 l -26.6267,26.6267 l 0.0000,37.6558 l 26.6267,26.6267 l 37.6558,-0.0000 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_pentagonEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="95.10565162951536" font-size="1" viewBox="0 0 100 95" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 78.09245403408613,91.239057046097 l 17.362091420459326,-53.43502293567938 l -45.45454545454545,-33.024660363880045 l -45.45454545454546,33.02466036388004 l 17.362091420459322,53.435022935679385 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="95.1057" stroke-opacity="1" viewBox="0 0 100 95" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 78.0925,91.2391 l 17.3621,-53.4350 l -45.4545,-33.0247 l -45.4545,33.0247 l 17.3621,53.4350 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_rectEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150.0" height="104.99999999999999" font-size="1" viewBox="0 0 150 105" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5019960159204453" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 143.1818181818182,100.22727272727272 l -1.5139404881252133e-14,-95.45454545454544 h -136.36363636363635 l -1.5139404881252133e-14,95.45454545454544 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="105.0000" stroke-opacity="1" viewBox="0 0 150 105" font-size="1" width="150.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5019960159204453" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 143.1818,100.2273 l -0.0000,-95.4545 h -136.3636 l -0.0000,95.4545 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_roundedRectEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400.0" height="76.19047619047622" font-size="1" viewBox="0 0 400 76" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.6982972487551757" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 381.81818181818187,55.41125541125544 v -17.31601731601732 c -19.126744582884623,-7.689856447620133e-15 -34.63203463203463,-15.505290049150023 -34.63203463203463 -34.63203463203465h -51.94805194805195 c -19.126744582884626,-1.1711753265769319e-15 -34.63203463203464,15.505290049150009 -34.63203463203464 34.63203463203463v 34.63203463203464 h 103.89610389610392 c 9.563372291442313,1.7567629898653979e-15 17.31601731601732,-7.752645024575003 17.31601731601728 -17.316017316017295Z" /></g><g><path d="M 225.97402597402595,55.41125541125544 v -34.632034632034646 c -9.563372291442311,-3.844928223810067e-15 -17.316017316017316,-7.752645024575012 -17.316017316017316 -17.316017316017327h -51.94805194805196 c -3.844928223810067e-15,9.56337229144231 -7.752645024575012,17.316017316017316 -17.316017316017327 17.316017316017312v 34.63203463203464 c 9.563372291442311,3.844928223810067e-15 17.316017316017316,7.752645024575012 17.316017316017312 17.316017316017327h 51.94805194805197 c 0.0,-9.563372291442311 7.752645024575012,-17.316017316017316 17.316017316017323 -17.31601731601731Z" /></g><path d="M 104.76190476190474,55.41125541125544 v -34.632034632034646 c 0.0,-9.563372291442313 -7.752645024575005,-17.31601731601732 -17.316017316017316 -17.31601731601732h -51.94805194805196 c -9.563372291442313,-5.855876632884659e-16 -17.31601731601732,7.7526450245750045 -17.31601731601732 17.316017316017316v 34.63203463203464 c -1.1711753265769319e-15,9.563372291442313 7.7526450245750045,17.31601731601732 17.316017316017316 17.316017316017327h 51.94805194805197 c 9.563372291442313,1.7567629898653979e-15 17.31601731601732,-7.752645024575003 17.31601731601731 -17.316017316017316Z" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="76.1905" stroke-opacity="1" viewBox="0 0 400 76" font-size="1" width="400.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.6982972487551757" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 381.8182,55.4113 v -17.3160 c -19.1267,-0.0000 -34.6320,-15.5053 -34.6320 -34.6320h -51.9481 c -19.1267,-0.0000 -34.6320,15.5053 -34.6320 34.6320v 34.6320 h 103.8961 c 9.5634,0.0000 17.3160,-7.7526 17.3160 -17.3160Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.6982972487551757" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 225.9740,55.4113 v -34.6320 c -9.5634,-0.0000 -17.3160,-7.7526 -17.3160 -17.3160h -51.9481 c -0.0000,9.5634 -7.7526,17.3160 -17.3160 17.3160v 34.6320 c 9.5634,0.0000 17.3160,7.7526 17.3160 17.3160h 51.9481 c 0.0000,-9.5634 7.7526,-17.3160 17.3160 -17.3160Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.6982972487551757" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 104.7619,55.4113 v -34.6320 c 0.0000,-9.5634 -7.7526,-17.3160 -17.3160 -17.3160h -51.9481 c -9.5634,-0.0000 -17.3160,7.7526 -17.3160 17.3160v 34.6320 c -0.0000,9.5634 7.7526,17.3160 17.3160 17.3160h 51.9481 c 9.5634,0.0000 17.3160,-7.7526 17.3160 -17.3160Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_squareEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200.0" height="85.71428571428572" font-size="1" viewBox="0 0 200 86" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5237229365663817" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><path d="M 190.90909090909093,81.81818181818181 l -8.651088503572648e-15,-77.92207792207792 h -77.92207792207792 l -8.651088503572648e-15,77.92207792207792 Z" /></g><g><path d="M 100.0,68.83116883116884 l -5.767392335715099e-15,-51.94805194805195 h -51.94805194805195 l -5.767392335715099e-15,51.94805194805195 Z" /></g><path d="M 35.06493506493507,55.84415584415585 l -2.8836961678575494e-15,-25.974025974025974 h -25.974025974025974 l -2.8836961678575494e-15,25.974025974025974 Z" /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="85.7143" stroke-opacity="1" viewBox="0 0 200 86" font-size="1" width="200.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5237229365663817" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 190.9091,81.8182 l -0.0000,-77.9221 h -77.9221 l -0.0000,77.9221 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5237229365663817" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0000,68.8312 l -0.0000,-51.9481 h -51.9481 l -0.0000,51.9481 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5237229365663817" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 35.0649,55.8442 l -0.0000,-25.9740 h -25.9740 l -0.0000,25.9740 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_triangleEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="86.60254037844385" font-size="1" viewBox="0 0 100 87" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454545,83.97822097303646 l -45.454545454545475,-78.72958216222167 l -45.454545454545446,78.72958216222169 Z" /></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="86.6025" stroke-opacity="1" viewBox="0 0 100 87" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,83.9782 l -45.4545,-78.7296 l -45.4545,78.7296 Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_unitSquareEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100.0" height="100.0" font-size="1" viewBox="0 0 100 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><path d="M 95.45454545454545,95.45454545454545 l -1.0092936587501423e-14,-90.9090909090909 h -90.9090909090909 l -1.0092936587501423e-14,90.9090909090909 Z" /><g fill="rgb(255,0,0)" fill-opacity="1.0" stroke-width="0.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><g fill="rgb(255,0,0)" fill-opacity="1.0"><path d="M 51.99999999999999,50.0 c 0.0,-1.104569499661587 -0.895430500338413,-2.0 -1.9999999999999998 -2.0c -1.104569499661587,-6.76353751098178e-17 -2.0,0.8954305003384128 -2.0 1.9999999999999996c -1.352707502196356e-16,1.104569499661587 0.8954305003384126,2.0 1.9999999999999991 2.0c 1.104569499661587,2.029061253294534e-16 2.0,-0.8954305003384126 2.000000000000001 -1.9999999999999996Z" /></g></g></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="100.0000" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 95.4545,95.4545 l -0.0000,-90.9091 h -90.9091 l -0.0000,90.9091 Z"/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="1.0" stroke="rgb(0,0,0)" stroke-width="0.0" fill="rgb(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 52.0000,50.0000 c 0.0000,-1.1046 -0.8954,-2.0000 -2.0000 -2.0000c -1.1046,-0.0000 -2.0000,0.8954 -2.0000 2.0000c -0.0000,1.1046 0.8954,2.0000 2.0000 2.0000c 1.1046,0.0000 2.0000,-0.8954 2.0000 -2.0000Z"/></g></svg>
diagrams/src_Diagrams_TwoD_Shapes_vruleEx.svg view
@@ -1,4 +1,1 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"-    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="50.00000000000001" height="100.0" font-size="1" viewBox="0 0 50 100" stroke="rgb(0,0,0)" stroke-opacity="1"><g><g fill="rgb(0,0,0)" fill-opacity="0.0"><g stroke="rgb(0,0,0)" stroke-opacity="1.0" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" font-size="1.0em" stroke-miterlimit="10.0"><g><g><g><path d="M 47.727272727272734,4.545454545454547 v 90.9090909090909 " /></g><path d="M 38.63636363636364,9.090909090909086 v 81.81818181818183 " /></g><g><g><path d="M 29.545454545454547,13.636363636363633 v 72.72727272727273 " /></g><path d="M 20.454545454545457,18.18181818181818 v 63.63636363636364 " /></g><g><path d="M 11.363636363636365,22.727272727272723 v 54.545454545454554 " /></g><path d="M 2.2727272727272734,27.27272727272727 v 45.45454545454546 " /></g></g></g></g></svg>+<svg xmlns="http://www.w3.org/2000/svg" height="100.0000" stroke-opacity="1" viewBox="0 0 50 100" font-size="1" width="50.0000" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><defs></defs><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 47.7273,4.5455 v 90.9091 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 38.6364,9.0909 v 81.8182 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 29.5455,13.6364 v 72.7273 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 20.4545,18.1818 v 63.6364 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 11.3636,22.7273 v 54.5455 "/></g><g stroke-linejoin="miter" stroke-opacity="1.0" fill-opacity="0.0" stroke="rgb(0,0,0)" stroke-width="0.5" fill="rgb(0,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 2.2727,27.2727 v 45.4545 "/></g></svg>
+ src/Diagrams.hs view
@@ -0,0 +1,153 @@+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams+-- Copyright   :  (c) 2015 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- This module only contains exports defined in @diagrams-lib@ or+-- @diagrams-core@. This module can be used if you want to avoid some+-- potential conflicts with other modules, but importing+-- "Diagrams.Prelude" (which includes re-exports from other packages)+-- is often more convenient.+--+-----------------------------------------------------------------------------++module Diagrams+  (+    -- * Core library+    -- | The core definitions of transformations, diagrams,+    --   backends, and so on.+    module Diagrams.Core++    -- * Standard library++    -- | Attributes (color, line style, etc.) and styles.+  , module Diagrams.Attributes++    -- | Alignment of diagrams relative to their envelopes.+  , module Diagrams.Align++    -- | Creating and using bounding boxes.+  , module Diagrams.BoundingBox++    -- | Combining multiple diagrams into one.+  , module Diagrams.Combinators++    -- | Giving concrete locations to translation-invariant things.+  , module Diagrams.Located++    -- | Linear and cubic bezier segments.+  , module Diagrams.Segment++    -- | Trails.+  , module Diagrams.Trail++    -- | Parametrization of segments and trails.+  , module Diagrams.Parametric++    -- | Adjusting the length of parameterized objects.+  , module Diagrams.Parametric.Adjust++    -- | Computing tangent and normal vectors of segments and+    --   trails.+  , module Diagrams.Tangent++    -- | Trail-like things.+  , module Diagrams.TrailLike++    -- | Paths.+  , module Diagrams.Path++    -- | Cubic splines.+  , module Diagrams.CubicSpline++    -- | Some additional transformation-related functions, like+    --   conjugation of transformations.+  , module Diagrams.Transform++    -- | Projective transformations and other deformations+    -- lacking an inverse.+  , module Diagrams.Deform++    -- | Giving names to subdiagrams and later retrieving+    --   subdiagrams by name.+  , module Diagrams.Names++    -- | Envelopes, aka functional bounding regions.+  , module Diagrams.Envelope++    -- | Traces, aka embedded raytracers, for finding points on+    --   the boundary of a diagram.+  , module Diagrams.Trace++    -- | A query is a function that maps points in a vector space+    --   to values in some monoid; they can be used to annotate+    --   the points of a diagram with some values.+  , module Diagrams.Query++    -- | Utilities for working with points.+  , module Diagrams.Points++    -- | Utilities for working with size.+  , module Diagrams.Size++    -- | Angles+  , module Diagrams.Angle++    -- | Convenience infix operators for working with coordinates.+  , module Diagrams.Coordinates++    -- | Directions, distinguished from angles or vectors+  , module Diagrams.Direction++    -- | A wide range of things (shapes, transformations,+    --   combinators) specific to creating two-dimensional+    --   diagrams.+  , module Diagrams.TwoD++    -- | Extra things for three-dimensional diagrams.+  , module Diagrams.ThreeD++    -- | Tools for making animations.+  , module Diagrams.Animation++    -- | Various utility definitions.+  , module Diagrams.Util++  ) where++import           Diagrams.Core++import           Diagrams.Align+import           Diagrams.Angle+import           Diagrams.Animation+import           Diagrams.Attributes+import           Diagrams.BoundingBox       hiding (contains, inside,+                                             intersection, outside, union)+import           Diagrams.Combinators+import           Diagrams.Coordinates+import           Diagrams.CubicSpline+import           Diagrams.Deform+import           Diagrams.Direction         hiding (dir)+import           Diagrams.Envelope+import           Diagrams.Located+import           Diagrams.Names+import           Diagrams.Parametric+import           Diagrams.Parametric.Adjust+import           Diagrams.Path              hiding (pathPoints)+import           Diagrams.Points+import           Diagrams.Query+import           Diagrams.Segment+import           Diagrams.Size+import           Diagrams.Tangent+import           Diagrams.ThreeD+import           Diagrams.Trace+import           Diagrams.Trail             hiding (linePoints, loopPoints,+                                             trailPoints)+import           Diagrams.TrailLike+import           Diagrams.Transform+import           Diagrams.TwoD+import           Diagrams.Util+
src/Diagrams/Align.hs view
@@ -1,6 +1,9 @@-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstrainedClassMethods #-}+{-# LANGUAGE ConstraintKinds         #-}+{-# LANGUAGE FlexibleContexts        #-}+{-# LANGUAGE TypeFamilies            #-}+{-# LANGUAGE TypeOperators           #-}+{-# LANGUAGE UndecidableInstances    #-}  ----------------------------------------------------------------------------- -- |@@ -38,15 +41,20 @@ import           Diagrams.Core import           Diagrams.Util    (applyAll) -import           Data.AffineSpace (alerp, (.-.))-import           Data.VectorSpace import           Data.Maybe       (fromMaybe) import           Data.Ord         (comparing)+import           Data.Traversable+import           Prelude +import qualified Data.Foldable    as F import qualified Data.Map         as M import qualified Data.Set         as S-import qualified Data.Foldable    as F +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector        (negated)+import           Linear.Vector.Compat (lerp)+ -- | Class of things which can be aligned. class Alignable a where @@ -56,61 +64,60 @@   --   edge of the boundary in the direction of the negation of @v@.   --   Other values of @d@ interpolate linearly (so for example, @d =   --   0@ centers the origin along the direction of @v@).-  alignBy' :: ( HasOrigin a, AdditiveGroup (V a), Num (Scalar (V a))-              , Fractional (Scalar (V a)))-            => (V a -> a -> Point (V a)) -> V a -> Scalar (V a) -> a -> a+  alignBy' :: (InSpace v n a, Fractional n, HasOrigin a)+           => (v n -> a -> Point v n) -> v n -> n -> a -> a   alignBy' = alignBy'Default -  defaultBoundary :: V a -> a -> Point (V a)+  defaultBoundary :: (V a ~ v, N a ~ n) => v n -> a -> Point v n -  alignBy :: (HasOrigin a, Num (Scalar (V a)), Fractional (Scalar (V a)))-           => V a -> Scalar (V a) -> a -> a+  alignBy :: (InSpace v n a, Fractional n, HasOrigin a)+          => v n -> n -> a -> a   alignBy = alignBy' defaultBoundary  -- | Default implementation of 'alignBy' for types with 'HasOrigin' --   and 'AdditiveGroup' instances.-alignBy'Default :: ( HasOrigin a, AdditiveGroup (V a), Num (Scalar (V a))-                   , Fractional (Scalar (V a)))-                 => (V a -> a -> Point (V a)) -> V a -> Scalar (V a) -> a -> a-alignBy'Default boundary v d a = moveOriginTo (alerp (boundary (negateV v) a)-                                    (boundary v a)-                                    ((d + 1) / 2)) a+alignBy'Default :: (InSpace v n a, Fractional n, HasOrigin a)+                => (v n -> a -> Point v n) -> v n -> n -> a -> a+alignBy'Default boundary v d a = moveOriginTo (lerp ((d + 1) / 2)+                                                    (boundary (negated v) a)+                                                    (boundary v a)+                                              ) a+{-# ANN alignBy'Default ("HLint: ignore Use camelCase" :: String) #-} + -- | Some standard functions which can be used as the `boundary` argument to --  `alignBy'`.-envelopeBoundary :: Enveloped a => V a -> a -> Point (V a)+envelopeBoundary :: (V a ~ v, N a ~ n, Enveloped a) => v n -> a -> Point v n envelopeBoundary = envelopeP -traceBoundary :: Traced a => V a -> a -> Point (V a)+traceBoundary :: (V a ~ v, N a ~ n, Num n, Traced a) => v n -> a -> Point v n traceBoundary v a = fromMaybe origin (maxTraceP origin v a)  combineBoundaries-  :: (F.Foldable f, InnerSpace (V a), Ord (Scalar (V a)))-  => (V a -> a -> Point (V a)) -> (V a -> f a -> Point (V a))+  :: (InSpace v n a, Metric v, Ord n, F.Foldable f)+  => (v n -> a -> Point v n) -> v n -> f a -> Point v n combineBoundaries b v fa-    = b v $ F.maximumBy (comparing (magnitudeSq . (.-. origin) . b v)) fa+  = b v $ F.maximumBy (comparing (dot v . (.-.origin) . b v)) fa -instance (InnerSpace v, OrderedField (Scalar v)) => Alignable (Envelope v) where+instance (Metric v, OrderedField n) => Alignable (Envelope v n) where   defaultBoundary = envelopeBoundary -instance (InnerSpace v, OrderedField (Scalar v)) => Alignable (Trace v) where+instance (Metric v, OrderedField n) => Alignable (Trace v n) where   defaultBoundary = traceBoundary -instance (InnerSpace (V b), Ord (Scalar (V b)), Alignable b)-       => Alignable [b] where+instance (V b ~ v, N b ~ n, Metric v, OrderedField n, Alignable b) => Alignable [b] where   defaultBoundary = combineBoundaries defaultBoundary -instance (InnerSpace (V b), Ord (Scalar (V b)), Alignable b)-       => Alignable (S.Set b) where+instance (V b ~ v, N b ~ n, Metric v, OrderedField n, Alignable b)+    => Alignable (S.Set b) where   defaultBoundary = combineBoundaries defaultBoundary -instance (InnerSpace (V b), Ord (Scalar (V b)), Alignable b)-       => Alignable (M.Map k b) where+instance (V b ~ v, N b ~ n, Metric v, OrderedField n, Alignable b)+    => Alignable (M.Map k b) where   defaultBoundary = combineBoundaries defaultBoundary -instance ( HasLinearMap v, InnerSpace v, OrderedField (Scalar v)-         , Monoid' m-         ) => Alignable (QDiagram b v m) where+instance (Metric v, OrderedField n, Monoid' m)+    => Alignable (QDiagram b v n m) where   defaultBoundary = envelopeBoundary  -- | Although the 'alignBy' method for the @(b -> a)@ instance is@@ -118,8 +125,8 @@ --   'defaultBoundary'. Instead, we provide a total method, but one that --   is not sensible. This should not present a serious problem as long --   as your use of 'Alignable' happens through 'alignBy'.-instance (HasOrigin a, Alignable a) => Alignable (b -> a) where-  alignBy v d f b = alignBy v d (f b)+instance (InSpace v n a, HasOrigin a, Alignable a) => Alignable (b -> a) where+  alignBy v d f b     = alignBy v d (f b)   defaultBoundary _ _ = origin  -- | @align v@ aligns an enveloped object along the edge in the@@ -127,42 +134,41 @@ --   direction of @v@ until it is on the edge of the envelope.  (Note --   that if the local origin is outside the envelope to begin with, --   it may have to move \"backwards\".)-align :: ( Alignable a, HasOrigin a, Num (Scalar (V a))-         , Fractional (Scalar (V a))) => V a -> a -> a+align :: (InSpace v n a, Fractional n, Alignable a, HasOrigin a) => v n -> a -> a align v = alignBy v 1  -- | Version of @alignBy@ specialized to use @traceBoundary@-snugBy :: (Alignable a, Traced a, HasOrigin a, Num (Scalar (V a)), Fractional (Scalar (V a)))-       => V a -> Scalar (V a) -> a -> a+snugBy :: (InSpace v n a, Fractional n, Alignable a, Traced a, HasOrigin a)+       => v n -> n -> a -> a snugBy = alignBy' traceBoundary  -- | Like align but uses trace.-snug :: (Fractional (Scalar (V a)), Alignable a, Traced a, HasOrigin a)-      => V a -> a -> a-snug v = snugBy  v 1+snug :: (InSpace v n a, Fractional n, Alignable a, Traced a, HasOrigin a)+      => v n -> a -> a+snug v = snugBy v 1  -- | @centerV v@ centers an enveloped object along the direction of --   @v@.-centerV :: ( Alignable a, HasOrigin a, Num (Scalar (V a))-          , Fractional (Scalar (V a))) => V a -> a -> a+centerV :: (InSpace v n a, Fractional n, Alignable a, HasOrigin a) => v n -> a -> a centerV v = alignBy v 0  -- | @center@ centers an enveloped object along all of its basis vectors.-center :: ( HasLinearMap (V a), Alignable a, HasOrigin a, Num (Scalar (V a)),-             Fractional (Scalar (V a))) => a -> a-center d = applyAll fs d+center :: (InSpace v n a, Fractional n, Traversable v, Alignable a, HasOrigin a) => a -> a+center = applyAll fs   where     fs = map centerV basis  -- | Like @centerV@ using trace. snugCenterV-  :: (Fractional (Scalar (V a)), Alignable a, Traced a, HasOrigin a)-   => V a -> a -> a-snugCenterV v = (alignBy' traceBoundary) v 0+  :: (InSpace v n a, Fractional n, Alignable a, Traced a, HasOrigin a)+   => v n -> a -> a+snugCenterV v = alignBy' traceBoundary v 0  -- | Like @center@ using trace.-snugCenter :: ( HasLinearMap (V a), Alignable a, HasOrigin a, Num (Scalar (V a)),-                      Fractional (Scalar (V a)), Traced a) => a -> a-snugCenter d = applyAll fs d+snugCenter :: (InSpace v n a, Traversable v, Fractional n, Alignable a, HasOrigin a, Traced a)+           => a -> a+snugCenter = applyAll fs   where     fs = map snugCenterV basis++{-# ANN module ("HLint: ignore Use camelCase" :: String) #-}
src/Diagrams/Angle.hs view
@@ -1,6 +1,12 @@+{-# LANGUAGE ConstraintKinds            #-}+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE RankNTypes                 #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Angle@@ -8,106 +14,271 @@ -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com ----- Type for representing angles, independent of vector-space+-- Type for representing angles. -- -----------------------------------------------------------------------------  module Diagrams.Angle-       (+       ( -- * Angle type          Angle-       , rad, turn, deg-       , fullTurn, fullCircle, angleRatio-       , sinA, cosA, tanA, asinA, acosA, atanA-       , (@@)-       , angleBetween++         -- ** Using angles+       , (@@), rad, turn, deg++         -- ** Common angles+       , fullTurn, halfTurn, quarterTurn++         -- ** Trigonometric functions+       , sinA, cosA, tanA+       , asinA, acosA, atanA, atan2A, atan2A'++         -- ** Angle utilities+       , angleBetween, angleRatio, normalizeAngle++         -- ** Classes        , HasTheta(..)+       , HasPhi(..)++         -- * Rotation+       , rotation, rotate        ) where -import           Control.Lens            (Iso', Lens', iso, review, (^.))-                                         -- , review , (^.), _1, _2, Lens', lens)+import           Control.Applicative+import           Control.Lens            (AReview, Iso', Lens', iso, over,+                                          review, (^.))+import           Data.Fixed+import           Data.Monoid             hiding ((<>))+import           Data.Monoid.Action+import           Data.Semigroup+import           Prelude+import           Text.Read -import           Data.VectorSpace+import           Diagrams.Core           (OrderedField)+import           Diagrams.Core.Transform+import           Diagrams.Core.V+import           Diagrams.Points+import           Linear.V2               (V2 (..)) +import           Linear.Metric+import           Linear.Vector+ -- | Angles can be expressed in a variety of units.  Internally,--- they are represented in radians.-newtype Angle = Radians Double-              deriving (Read, Show, Eq, Ord, Enum, AdditiveGroup)+--   they are represented in radians.+newtype Angle n = Radians n+  deriving (Eq, Ord, Enum, Functor) -instance VectorSpace Angle where-  type Scalar Angle = Double-  s *^ Radians t = Radians (s*t)+instance Show n => Show (Angle n) where+  showsPrec d (Radians a) = showParen (d > 5) $+    showsPrec 6 a . showString " @@ rad" --- | The radian measure of an @Angle@ @a@ can be accessed as @a--- ^. rad@.  A new @Angle@ can be defined in radians as @pi \@\@ rad@.-rad :: Iso' Angle Double+instance Read n => Read (Angle n) where+  readPrec = parens . prec 5 $ do+    x <- readPrec+    Symbol "@@" <- lexP+    Ident "rad" <- lexP+    pure (Radians x)++type instance N (Angle n) = n++instance Applicative Angle where+  pure = Radians+  {-# INLINE pure #-}+  Radians f <*> Radians x = Radians (f x)+  {-# INLINE (<*>) #-}++instance Additive Angle where+  zero = pure 0+  {-# INLINE zero #-}++instance Num n => Semigroup (Angle n) where+  (<>) = (^+^)+  {-# INLINE (<>) #-}++instance Num n => Monoid (Angle n) where+  mappend = (<>)+  mempty  = Radians 0++-- | The radian measure of an 'Angle' @a@ can be accessed as @a '^.'+--   rad@. A new 'Angle' can be defined in radians as @pi \@\@+--   rad@.+rad :: Iso' (Angle n) n rad = iso (\(Radians r) -> r) Radians+{-# INLINE rad #-} --- | The measure of an @Angle@ @a@ in full circles can be accessed as--- @a ^. turn@.  A new @Angle@ of one-half circle can be defined in as--- @1/2 \@\@ turn@.-turn :: Iso' Angle Double-turn = iso (\(Radians r) -> r/2/pi) (Radians . (*(2*pi)))+-- | The measure of an 'Angle' @a@ in full circles can be accessed as+--   @a '^.' turn@.  A new 'Angle' of one-half circle can be defined in as+--   @1/2 \@\@ turn@.+turn :: Floating n => Iso' (Angle n) n+turn = iso (\(Radians r) -> r / (2*pi)) (Radians . (*(2*pi)))+{-# INLINE turn #-} --- | The degree measure of an @Angle@ @a@ can be accessed as @a--- ^. deg@.  A new @Angle@ can be defined in degrees as @180 \@\@--- deg@.-deg :: Iso' Angle Double-deg = iso (\(Radians r) -> r/2/pi*360) (Radians . (*(2*pi/360)))+-- | The degree measure of an 'Angle' @a@ can be accessed as @a+--   '^.' deg@. A new 'Angle' can be defined in degrees as @180 \@\@+--   deg@.+deg :: Floating n => Iso' (Angle n) n+deg = iso (\(Radians r) -> r / (2*pi/360)) (Radians . ( * (2*pi/360)))+{-# INLINE deg #-}  -- | An angle representing one full turn.-fullTurn :: Angle+fullTurn :: Floating v => Angle v fullTurn = 1 @@ turn --- | Deprecated synonym for 'fullTurn', retained for backwards compatibility.-fullCircle :: Angle-fullCircle = fullTurn+-- | An angle representing a half turn.+halfTurn :: Floating v => Angle v+halfTurn = 0.5 @@ turn +-- | An angle representing a quarter turn.+quarterTurn :: Floating v => Angle v+quarterTurn = 0.25 @@ turn+ -- | Calculate ratio between two angles.-angleRatio :: Angle -> Angle -> Double-angleRatio a b = (a^.rad) / (b^.rad)+angleRatio :: Floating n => Angle n -> Angle n -> n+angleRatio a b = (a ^. rad) / (b ^. rad)  -- | The sine of the given @Angle@.-sinA :: Angle -> Double+sinA :: Floating n => Angle n -> n sinA (Radians r) = sin r  -- | The cosine of the given @Angle@.-cosA :: Angle -> Double+cosA :: Floating n => Angle n -> n cosA (Radians r) = cos r  -- | The tangent function of the given @Angle@.-tanA :: Angle -> Double+tanA :: Floating n => Angle n -> n tanA (Radians r) = tan r  -- | The @Angle@ with the given sine.-asinA :: Double -> Angle+asinA :: Floating n => n -> Angle n asinA = Radians . asin  -- | The @Angle@ with the given cosine.-acosA :: Double -> Angle+acosA :: Floating n => n -> Angle n acosA = Radians . acos  -- | The @Angle@ with the given tangent.-atanA :: Double -> Angle+atanA :: Floating n => n -> Angle n atanA = Radians . atan --- | @30 \@\@ deg@ is an @Angle@ of the given measure and units.+-- | @atan2A y x@ is the angle between the positive x-axis and the vector given+--   by the coordinates (x, y). The 'Angle' returned is in the [-pi,pi] range.+atan2A :: RealFloat n => n -> n -> Angle n+atan2A y x = Radians $ atan2 y x++-- | Similar to 'atan2A' but without the 'RealFloat' constraint. This means it+--   doesn't handle negative zero cases. However, for most geometric purposes,+--   the outcome will be the same.+atan2A' :: OrderedField n => n -> n -> Angle n+atan2A' y x = atan2' y x @@ rad++-- atan2 without negative zero tests+atan2' :: OrderedField n => n -> n -> n+atan2' y x+  | x > 0            =  atan (y/x)+  | x == 0 && y > 0  =  pi/2+  | x <  0 && y > 0  =  pi + atan (y/x)+  | x <= 0 && y < 0  = -atan2' (-y) x+  | y == 0 && x < 0  =  pi    -- must be after the previous test on zero y+  | x==0 && y==0     =  y     -- must be after the other double zero tests+  | otherwise        =  x + y -- x or y is a NaN, return a NaN (via +)++-- | @30 \@\@ deg@ is an 'Angle' of the given measure and units. ----- More generally, @\@\@@ reverses the @Iso\'@ on its right, and--- applies the @Iso\'@ to the value on the left.  @Angle@s are the--- motivating example where this order improves readability.-(@@) :: b -> Iso' a b -> a--- The signature above is slightly specialized, in favor of readability+-- >>> pi @@ rad+-- 3.141592653589793 @@ rad+--+-- >>> 1 @@ turn+-- 6.283185307179586 @@ rad+--+-- >>> 30 @@ deg+-- 0.5235987755982988 @@ rad+--+--   For 'Iso''s, ('@@') reverses the 'Iso'' on its right, and applies+--   the 'Iso'' to the value on the left. 'Angle's are the motivating+--   example where this order improves readability.+--+--   This is the same as a flipped 'review'.+--+-- @+-- ('@@') :: a -> 'Iso''      s a -> s+-- ('@@') :: a -> 'Prism''    s a -> s+-- ('@@') :: a -> 'Review'    s a -> s+-- ('@@') :: a -> 'Equality'' s a -> s+-- @+(@@) :: b -> AReview a b -> a a @@ i = review i a  infixl 5 @@ --- | compute the positive angle between the two vectors in their common plane-angleBetween  :: (InnerSpace v, Scalar v ~ Double) => v -> v -> Angle-angleBetween v1 v2 = acos (normalized v1 <.> normalized v2) @@ rad+-- | Compute the positive angle between the two vectors in their common+--   plane in the [0,pi] range. For a signed angle see+--   'Diagrams.TwoD.Vector.signedAngleBetween'.+--+--   Returns NaN if either of the vectors are zero.+angleBetween  :: (Metric v, Floating n, Ord n) => v n -> v n -> Angle n+angleBetween v1 v2 = acosA (min 1 . max (-1) $ signorm v1 `dot` signorm v2)+-- N.B.: Currently discards the common plane information. +-- | Normalize an angle so that it lies in the [0,tau) range.+normalizeAngle :: (Floating n, Real n) => Angle n -> Angle n+normalizeAngle = over rad (`mod'` (2 * pi))+ ------------------------------------------------------------+-- Rotation++-- These functions are defined here (instead of in+-- Diagrams.TwoD.Transform) because the Action instance needs to go+-- here.++-- | Create a transformation which performs a rotation about the local+--   origin by the given angle.  See also 'rotate'.+rotation :: Floating n => Angle n -> Transformation V2 n+rotation theta = fromLinear r (linv r)+    where+    c = cosA theta+    s = sinA theta+    r               = rot c s <-> rot c (-s)+    rot co si (V2 x y) = V2 (co * x - si * y)+                            (si * x + co * y)++-- | Rotate about the local origin by the given angle. Positive angles+--   correspond to counterclockwise rotation, negative to+--   clockwise. The angle can be expressed using any of the 'Iso's on+--   'Angle'.  For example, @rotate (1\/4 \@\@ 'turn')@, @rotate+--   (tau\/4 \@\@ rad)@, and @rotate (90 \@\@ deg)@ all+--   represent the same transformation, namely, a counterclockwise+--   rotation by a right angle.  To rotate about some point other than+--   the local origin, see 'rotateAbout'.+--+--   Note that writing @rotate (1\/4)@, with no 'Angle' constructor,+--   will yield an error since GHC cannot figure out which sort of+--   angle you want to use.  In this common situation you can use+--   'rotateBy', which interprets its argument as a number of turns.++rotate :: (InSpace V2 n t, Transformable t, Floating n) => Angle n -> t -> t+rotate = transform . rotation++-- | Angles act on other things by rotation.+instance (V t ~ V2, N t ~ n, Transformable t, Floating n)+  => Action (Angle n) t where+  act = rotate++------------------------------------------------------------ -- Polar Coordinates --- | The class of types with at least one angle coordinate, called _theta.+-- | The class of types with at least one angle coordinate, called '_theta'. class HasTheta t where-    _theta :: Lens' t Angle+  _theta :: RealFloat n => Lens' (t n) (Angle n)++-- | The class of types with at least two angle coordinates, the second called+--   '_phi'. '_phi' is the positive angle measured from the z axis.+class HasTheta t => HasPhi t where+  _phi :: RealFloat n => Lens' (t n) (Angle n)++-- Point instances+instance HasTheta v => HasTheta (Point v) where+  _theta = lensP . _theta+  {-# INLINE _theta #-}++instance HasPhi v => HasPhi (Point v) where+  _phi = lensP . _phi+  {-# INLINE _phi #-}
src/Diagrams/Animation.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies          #-}@@ -29,6 +30,9 @@         ) where +import           Data.Active+import           Data.Semigroup+ import           Diagrams.Core  import           Diagrams.Animation.Active ()@@ -38,18 +42,13 @@ import           Diagrams.TwoD.Shapes import           Diagrams.TwoD.Types -import           Data.Active-import           Data.Semigroup--import           Control.Applicative       ((<$>))-import           Data.Foldable             (foldMap)-import           Data.VectorSpace+import           Linear.Metric  -- | A value of type @QAnimation b v m@ is an animation (a --   time-varying diagram with start and end times) that can be---   rendered by backspace @b@, with vector space @v@ and monoidal+--   rendered by backend @b@, with vector space @v@ and monoidal --   annotations of type @m@.-type QAnimation b v m = Active (QDiagram b v m)+type QAnimation b v n m = Active (QDiagram b v n m)  -- | A value of type @Animation b v@ is an animation (a time-varying --   diagram with start and end times) in vector space @v@ that can be@@ -58,7 +57,7 @@ --   Note that @Animation@ is actually a synonym for @QAnimation@ --   where the type of the monoidal annotations has been fixed to --   'Any' (the default).-type Animation b v = QAnimation b v Any+type Animation b v n = QAnimation b v n Any  -- $animComb -- Most combinators for working with animations are to be found in the@@ -90,16 +89,16 @@ -- --   See also 'animRect' for help constructing a background to go --   behind an animation.-animEnvelope :: (Backend b v, OrderedField (Scalar v), InnerSpace v, Monoid' m)-           => QAnimation b v m -> QAnimation b v m+animEnvelope :: (OrderedField n, Metric v, Monoid' m)+           => QAnimation b v n m -> QAnimation b v n m animEnvelope = animEnvelope' 30  -- | Like 'animEnvelope', but with an adjustible sample rate.  The first --   parameter is the number of samples per time unit to use.  Lower --   rates will be faster but less accurate; higher rates are more --   accurate but slower.-animEnvelope' :: (Backend b v, OrderedField (Scalar v), InnerSpace v, Monoid' m)-            => Rational -> QAnimation b v m -> QAnimation b v m+animEnvelope' :: (OrderedField n, Metric v, Monoid' m)+            => Rational -> QAnimation b v n m -> QAnimation b v n m animEnvelope' r a = withEnvelope (simulate r a) <$> a  -- | @animRect@ works similarly to 'animEnvelope' for 2D diagrams, but@@ -109,18 +108,16 @@ -- --   Uses 30 samples per time unit by default; to adjust this number --   see 'animRect''.-animRect :: (TrailLike t, Enveloped t, Transformable t, Monoid t, V t ~ R2-            , Monoid' m)-         => QAnimation b R2 m -> t+animRect :: (InSpace V2 n t, Monoid' m, TrailLike t, Enveloped t, Transformable t, Monoid t)+         => QAnimation b V2 n m -> t animRect = animRect' 30  -- | Like 'animRect', but with an adjustible sample rate.  The first --   parameter is the number of samples per time unit to use.  Lower --   rates will be faster but less accurate; higher rates are more --   accurate but slower.-animRect' :: (TrailLike t, Enveloped t, Transformable t, Monoid t, V t ~ R2-             , Monoid' m)-          => Rational -> QAnimation b R2 m -> t+animRect' :: (InSpace V2 n t, Monoid' m, TrailLike t, Enveloped t, Transformable t, Monoid t)+          => Rational -> QAnimation b V2 n m -> t animRect' r anim     | null results = rect 1 1     | otherwise    = boxFit (foldMap boundingBox results) (rect 1 1)
src/Diagrams/Animation/Active.hs view
@@ -37,14 +37,13 @@  module Diagrams.Animation.Active where -import           Control.Applicative (pure, (<$>))- import           Diagrams.Core import           Diagrams.TrailLike  import           Data.Active  type instance V (Active a) = V a+type instance N (Active a) = N a  -- Yes, these are all orphan instances. Get over it.  We don't want to -- put them in the 'active' package because 'active' is supposed to be@@ -95,5 +94,5 @@       )       a1 ---instance Alignable a => Alignable (Active a) where---  alignBy v d a = alignBy v d <$> a+-- instance Alignable a => Alignable (Active a) where+--   alignBy v d a = alignBy v d <$> a
src/Diagrams/Attributes.hs view
@@ -1,12 +1,19 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DeriveFunctor              #-} {-# LANGUAGE ExistentialQuantification  #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE ViewPatterns               #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Attributes--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -24,43 +31,220 @@ -----------------------------------------------------------------------------  module Diagrams.Attributes (+    -- ** Standard measures+    ultraThin, veryThin, thin, medium, thick, veryThick, ultraThick, none+  , tiny, verySmall, small, normal, large, veryLarge, huge++    -- ** Line width+  , LineWidth, getLineWidth+  , _LineWidth, _LineWidthM+  , lineWidth, lineWidthM+  , _lineWidth, _lw, _lineWidthU+  , lw, lwN, lwO, lwL, lwG++    -- ** Dashing+  , Dashing(..), getDashing+  , dashing, dashingN, dashingO, dashingL, dashingG+  , _dashing, _dashingU+   -- * Color   -- $color -    Color(..), SomeColor(..), someToAlpha+  , Color(..), SomeColor(..), _SomeColor, someToAlpha    -- ** Opacity-  , Opacity, getOpacity, opacity+  , Opacity, _Opacity+  , getOpacity, opacity, _opacity +  , FillOpacity, _FillOpacity+  , getFillOpacity, fillOpacity, _fillOpacity++  , StrokeOpacity, _StrokeOpacity+  , getStrokeOpacity, strokeOpacity, _strokeOpacity+   -- ** Converting colors   , colorToSRGBA, colorToRGBA    -- * Line stuff   -- ** Cap style-  , LineCap(..), LineCapA, getLineCap, lineCap+  , LineCap(..)+  , getLineCap, lineCap, _lineCap    -- ** Join style-  , LineJoin(..), LineJoinA, getLineJoin, lineJoin+  , LineJoin(..)+  , getLineJoin, lineJoin, _lineJoin    -- ** Miter limit-  , LineMiterLimit(..), getLineMiterLimit, lineMiterLimit, lineMiterLimitA+  , LineMiterLimit(..), _LineMiterLimit+  , getLineMiterLimit, lineMiterLimit, lineMiterLimitA, _lineMiterLimit +  -- * Recommend optics++  , _Recommend+  , _Commit+  , _recommend+  , isCommitted+  , committed+   ) where +import           Control.Lens          hiding (none, over) import           Data.Colour-import           Data.Colour.RGBSpace        (RGB (..))-import           Data.Colour.SRGB            (toSRGB)-import           Data.Default.Class-+import           Data.Colour.RGBSpace  (RGB (..))+import           Data.Colour.SRGB      (toSRGB)+import           Data.Default+import           Data.Distributive+import           Data.Monoid.Recommend import           Data.Semigroup import           Data.Typeable  import           Diagrams.Core ----------------------------------------------------------------  Color  --------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+-- Standard measures+------------------------------------------------------------------------ +none, ultraThin, veryThin, thin, medium, thick, veryThick, ultraThick,+  tiny, verySmall, small, normal, large, veryLarge, huge+  :: OrderedField n => Measure n+none       = output 0+ultraThin  = normalized 0.0005 `atLeast` output 0.5+veryThin   = normalized 0.001  `atLeast` output 0.5+thin       = normalized 0.002  `atLeast` output 0.5+medium     = normalized 0.004  `atLeast` output 0.5+thick      = normalized 0.0075 `atLeast` output 0.5+veryThick  = normalized 0.01   `atLeast` output 0.5+ultraThick = normalized 0.02   `atLeast` output 0.5++tiny      = normalized 0.01+verySmall = normalized 0.015+small     = normalized 0.023+normal    = normalized 0.035+large     = normalized 0.05+veryLarge = normalized 0.07+huge      = normalized 0.10++------------------------------------------------------------------------+-- Line width+------------------------------------------------------------------------++-- | Line widths specified on child nodes always override line widths+--   specified at parent nodes.+newtype LineWidth n = LineWidth (Last n)+  deriving (Typeable, Semigroup)++_LineWidth :: Iso' (LineWidth n) n+_LineWidth = iso getLineWidth (LineWidth . Last)++_LineWidthM :: Iso' (LineWidthM n) (Measure n)+_LineWidthM = mapping _LineWidth++instance Typeable n => AttributeClass (LineWidth n)++type LineWidthM n = Measured n (LineWidth n)++instance OrderedField n => Default (LineWidthM n) where+  def = fmap (LineWidth . Last) medium++getLineWidth :: LineWidth n -> n+getLineWidth (LineWidth (Last w)) = w++-- | Set the line (stroke) width.+lineWidth :: (N a ~ n, HasStyle a, Typeable n) => Measure n -> a -> a+lineWidth = applyMAttr . fmap (LineWidth . Last)++-- | Apply a 'LineWidth' attribute.+lineWidthM :: (N a ~ n, HasStyle a, Typeable n) => LineWidthM n -> a -> a+lineWidthM = applyMAttr++-- | Default for 'lineWidth'.+lw :: (N a ~ n, HasStyle a, Typeable n) => Measure n -> a -> a+lw = lineWidth++-- | A convenient synonym for 'lineWidth (global w)'.+lwG :: (N a ~ n, HasStyle a, Typeable n, Num n) => n -> a -> a+lwG = lw . global++-- | A convenient synonym for 'lineWidth (normalized w)'.+lwN :: (N a ~ n, HasStyle a, Typeable n, Num n) => n -> a -> a+lwN = lw . normalized++-- | A convenient synonym for 'lineWidth (output w)'.+lwO :: (N a ~ n, HasStyle a, Typeable n) => n -> a -> a+lwO = lw . output++-- | A convenient sysnonym for 'lineWidth (local w)'.+lwL :: (N a ~ n, HasStyle a, Typeable n, Num n) => n -> a -> a+lwL = lw . local++-- | Lens onto a measured line width in a style.+_lineWidth, _lw :: (Typeable n, OrderedField n) => Lens' (Style v n) (Measure n)+_lineWidth = atMAttr . anon def (const False) . _LineWidthM+_lw = _lineWidth++-- | Lens onto the unmeasured linewith attribute. This is useful for+--   backends to use on styles once they have been unmeasured. Using on+--   a diagram style could lead to unexpected results.+_lineWidthU :: Typeable n => Lens' (Style v n) (Maybe n)+_lineWidthU = atAttr . mapping _LineWidth++------------------------------------------------------------------------+-- Dashing+------------------------------------------------------------------------++-- | Create lines that are dashing... er, dashed.+data Dashing n = Dashing [n] n+  deriving (Functor, Typeable, Eq)++instance Semigroup (Dashing n) where+  _ <> b = b++instance Typeable n => AttributeClass (Dashing n)++getDashing :: Dashing n -> Dashing n+getDashing = id++-- | Set the line dashing style.+dashing :: (N a ~ n, HasStyle a, Typeable n)+        => [Measure n]  -- ^ A list specifying alternate lengths of on+                        --   and off portions of the stroke.  The empty+                        --   list indicates no dashing.+        -> Measure n    -- ^ An offset into the dash pattern at which the+                        --   stroke should start.+        -> a -> a+dashing ds offs = applyMAttr . distribute $ Dashing ds offs++-- | A convenient synonym for 'dashing (global w)'.+dashingG :: (N a ~ n, HasStyle a, Typeable n, Num n) => [n] -> n -> a -> a+dashingG w v = dashing (map global w) (global v)++-- | A convenient synonym for 'dashing (normalized w)'.+dashingN :: (N a ~ n, HasStyle a, Typeable n, Num n) => [n] -> n -> a -> a+dashingN w v = dashing (map normalized w) (normalized v)++-- | A convenient synonym for 'dashing (output w)'.+dashingO :: (N a ~ n, HasStyle a, Typeable n) => [n] -> n -> a -> a+dashingO w v = dashing (map output w) (output v)++-- | A convenient sysnonym for 'dashing (local w)'.+dashingL :: (N a ~ n, HasStyle a, Typeable n, Num n) => [n] -> n -> a -> a+dashingL w v = dashing (map local w) (local v)++-- | Lens onto a measured dashing attribute in a style.+_dashing :: Typeable n+         => Lens' (Style v n) (Maybe (Measured n (Dashing n)))+_dashing = atMAttr++-- | Lens onto the unmeasured 'Dashing' attribute. This is useful for+--   backends to use on styles once they have been unmeasured. Using on+--   a diagram style could lead to unexpected results.+_dashingU :: Typeable n => Lens' (Style v n) (Maybe (Dashing n))+_dashingU = atAttr++------------------------------------------------------------------------+-- Color+------------------------------------------------------------------------+ -- $color -- Diagrams outsources all things color-related to Russell O\'Connor\'s -- very nice colour package@@ -86,20 +270,36 @@ data SomeColor = forall c. Color c => SomeColor c   deriving Typeable +instance Show SomeColor where+  showsPrec d (colorToSRGBA -> (r,g,b,a)) =+    showParen (d > 10) $ showString "SomeColor " .+      if a == 0+        then showString "transparent"+        else showString "(sRGB " . showsPrec 11 r . showChar ' '+                                 . showsPrec 11 g . showChar ' '+                                 . showsPrec 11 b .+                        (if a /= 1+                           then showString " `withOpacity` " . showsPrec 11 a+                           else id) . showChar ')'++-- | Isomorphism between 'SomeColor' and 'AlphaColour' 'Double'.+_SomeColor :: Iso' SomeColor (AlphaColour Double)+_SomeColor = iso toAlphaColour fromAlphaColour+ someToAlpha :: SomeColor -> AlphaColour Double someToAlpha (SomeColor c) = toAlphaColour c -instance (Floating a, Real a) => Color (Colour a) where-  toAlphaColour   = opaque . colourConvert-  fromAlphaColour = colourConvert . (`over` black)+instance a ~ Double => Color (Colour a) where+  toAlphaColour   = opaque+  fromAlphaColour = (`over` black) -instance (Floating a, Real a) => Color (AlphaColour a) where-  toAlphaColour   = alphaColourConvert-  fromAlphaColour = alphaColourConvert+instance a ~ Double => Color (AlphaColour a) where+  toAlphaColour   = id+  fromAlphaColour = id  instance Color SomeColor where   toAlphaColour (SomeColor c) = toAlphaColour c-  fromAlphaColour c = SomeColor c+  fromAlphaColour             = SomeColor  -- | Convert to sRGBA. colorToSRGBA, colorToRGBA :: Color c => c -> (Double, Double, Double, Double)@@ -113,12 +313,13 @@ colorToRGBA = colorToSRGBA {-# DEPRECATED colorToRGBA "Renamed to colorToSRGBA." #-} -alphaToColour :: (Floating a, Ord a, Fractional a) => AlphaColour a -> Colour a+alphaToColour :: (Floating a, Ord a) => AlphaColour a -> Colour a alphaToColour ac | alphaChannel ac == 0 = ac `over` black                  | otherwise = darken (recip (alphaChannel ac)) (ac `over` black) -------------------------------------------------------------+------------------------------------------------------------------------ -- Opacity+------------------------------------------------------------------------  -- | Although the individual colors in a diagram can have --   transparency, the opacity/transparency of a diagram as a whole@@ -132,6 +333,9 @@   deriving (Typeable, Semigroup) instance AttributeClass Opacity +_Opacity :: Iso' Opacity Double+_Opacity = iso getOpacity (Opacity . Product)+ getOpacity :: Opacity -> Double getOpacity (Opacity (Product d)) = d @@ -141,64 +345,139 @@ opacity :: HasStyle a => Double -> a -> a opacity = applyAttr . Opacity . Product ----------------------------------------------------------------  Line stuff    --------------------------------------------------------------------------------------------------+-- | Lens onto the opacity in a style.+_opacity :: Lens' (Style v n) Double+_opacity = atAttr . mapping _Opacity . non 1 +-- fill opacity --------------------------------------------------------++-- | Like 'Opacity', but set the opacity only for fills (as opposed to strokes).+--   As with 'Opacity', the fill opacity is a value between 1+--   (completely opaque, the default) and 0 (completely transparent),+--   and is multiplicative.+newtype FillOpacity = FillOpacity (Product Double)+  deriving (Typeable, Semigroup)+instance AttributeClass FillOpacity++_FillOpacity :: Iso' FillOpacity Double+_FillOpacity = iso getFillOpacity (FillOpacity . Product)++getFillOpacity :: FillOpacity -> Double+getFillOpacity (FillOpacity (Product d)) = d++-- | Multiply the fill opacity (see 'FillOpacity') by the given value.  For+--   example, @fillOpacity 0.8@ means \"decrease this diagram's fill opacity to+--   80% of its previous value\".+fillOpacity :: HasStyle a => Double -> a -> a+fillOpacity = applyAttr . FillOpacity . Product++-- | Lens onto the fill opacity in a style.+_fillOpacity :: Lens' (Style v n) Double+_fillOpacity = atAttr . mapping _FillOpacity . non 1++-- stroke opacity --------------------------------------------------------++-- | Like 'Opacity', but set the opacity only for strokes (as opposed to fills).+--   As with 'Opacity', the fill opacity is a value between 1+--   (completely opaque, the default) and 0 (completely transparent),+--   and is multiplicative.+newtype StrokeOpacity = StrokeOpacity (Product Double)+  deriving (Typeable, Semigroup)+instance AttributeClass StrokeOpacity++_StrokeOpacity :: Iso' StrokeOpacity Double+_StrokeOpacity = iso getStrokeOpacity (StrokeOpacity . Product)++getStrokeOpacity :: StrokeOpacity -> Double+getStrokeOpacity (StrokeOpacity (Product d)) = d++-- | Multiply the stroke opacity (see 'StrokeOpacity') by the given value.  For+--   example, @strokeOpacity 0.8@ means \"decrease this diagram's+--   stroke opacity to 80% of its previous value\".+strokeOpacity :: HasStyle a => Double -> a -> a+strokeOpacity = applyAttr . StrokeOpacity . Product++-- | Lens onto the stroke opacity in a style.+_strokeOpacity :: Lens' (Style v n) Double+_strokeOpacity = atAttr . mapping _StrokeOpacity . non 1++------------------------------------------------------------------------+-- Line stuff+------------------------------------------------------------------------++-- line cap ------------------------------------------------------------+ -- | What sort of shape should be placed at the endpoints of lines? data LineCap = LineCapButt   -- ^ Lines end precisely at their endpoints.              | LineCapRound  -- ^ Lines are capped with semicircles                              --   centered on endpoints.              | LineCapSquare -- ^ Lines are capped with a squares                              --   centered on endpoints.-  deriving (Eq,Show,Typeable)--newtype LineCapA = LineCapA (Last LineCap)-  deriving (Typeable, Semigroup, Eq)-instance AttributeClass LineCapA+  deriving (Eq, Ord, Show, Typeable)  instance Default LineCap where-    def = LineCapButt+  def = LineCapButt -getLineCap :: LineCapA -> LineCap-getLineCap (LineCapA (Last c)) = c+instance AttributeClass LineCap +-- | Last semigroup structure.+instance Semigroup LineCap where+  _ <> b = b++getLineCap :: LineCap -> LineCap+getLineCap = id+ -- | Set the line end cap attribute. lineCap :: HasStyle a => LineCap -> a -> a-lineCap = applyAttr . LineCapA . Last+lineCap = applyAttr +-- | Lens onto the line cap in a style.+_lineCap :: Lens' (Style v n) LineCap+_lineCap = atAttr . non def +-- line join -----------------------------------------------------------+ -- | How should the join points between line segments be drawn? data LineJoin = LineJoinMiter    -- ^ Use a \"miter\" shape (whatever that is).               | LineJoinRound    -- ^ Use rounded join points.               | LineJoinBevel    -- ^ Use a \"bevel\" shape (whatever                                  --   that is).  Are these...                                  --   carpentry terms?-  deriving (Eq,Show,Typeable)+  deriving (Eq, Ord, Show, Typeable) -newtype LineJoinA = LineJoinA (Last LineJoin)-  deriving (Typeable, Semigroup, Eq)-instance AttributeClass LineJoinA+instance AttributeClass LineJoin +-- | Last semigroup structure.+instance Semigroup LineJoin where+  _ <> b = b+ instance Default LineJoin where-    def = LineJoinMiter+  def = LineJoinMiter -getLineJoin :: LineJoinA -> LineJoin-getLineJoin (LineJoinA (Last j)) = j+getLineJoin :: LineJoin -> LineJoin+getLineJoin = id  -- | Set the segment join style. lineJoin :: HasStyle a => LineJoin -> a -> a-lineJoin = applyAttr . LineJoinA . Last+lineJoin = applyAttr +-- | Lens onto the line join type in a style.+_lineJoin :: Lens' (Style v n) LineJoin+_lineJoin = atAttr . non def +-- miter limit ---------------------------------------------------------+ -- | Miter limit attribute affecting the 'LineJoinMiter' joins. --   For some backends this value may have additional effects. newtype LineMiterLimit = LineMiterLimit (Last Double)-  deriving (Typeable, Semigroup)+  deriving (Typeable, Semigroup, Eq, Ord) instance AttributeClass LineMiterLimit +_LineMiterLimit :: Iso' LineMiterLimit Double+_LineMiterLimit = iso getLineMiterLimit (LineMiterLimit . Last)+ instance Default LineMiterLimit where-    def = LineMiterLimit (Last 10)+  def = LineMiterLimit (Last 10)  getLineMiterLimit :: LineMiterLimit -> Double getLineMiterLimit (LineMiterLimit (Last l)) = l@@ -210,3 +489,40 @@ -- | Apply a 'LineMiterLimit' attribute. lineMiterLimitA :: HasStyle a => LineMiterLimit -> a -> a lineMiterLimitA = applyAttr++-- | Lens onto the line miter limit in a style.+_lineMiterLimit :: Lens' (Style v n) Double+_lineMiterLimit = atAttr . non def . _LineMiterLimit++------------------------------------------------------------------------+-- Recommend optics+------------------------------------------------------------------------++-- | Prism onto a 'Recommend'.+_Recommend :: Prism' (Recommend a) a+_Recommend = prism' Recommend $ \case (Recommend a) -> Just a; _ -> Nothing++-- | Prism onto a 'Commit'.+_Commit :: Prism' (Recommend a) a+_Commit = prism' Commit $ \case (Commit a) -> Just a; _ -> Nothing++-- | Lens onto the value inside either a 'Recommend' or 'Commit'. Unlike+--   'committed', this is a valid lens.+_recommend :: Lens (Recommend a) (Recommend b) a b+_recommend f (Recommend a) = Recommend <$> f a+_recommend f (Commit a)    = Commit <$> f a++-- | Lens onto whether something is committed or not.+isCommitted :: Lens' (Recommend a) Bool+isCommitted f r@(Recommend a) = f False <&> \b -> if b then Commit a else r+isCommitted f r@(Commit a)    = f True  <&> \b -> if b then r else Recommend a++-- | 'Commit' a value for any 'Recommend'. This is *not* a valid 'Iso'+--   because the resulting @Recommend b@ is always a 'Commit'. This is+--   useful because it means any 'Recommend' styles set with a lens will+--   not be accidentally overridden. If you want a valid lens onto a+--   recommend value use '_recommend'.+--+--   Other lenses that use this are labeled with a warning.+committed :: Iso (Recommend a) (Recommend b) a b+committed = iso getRecommend Commit
src/Diagrams/Attributes/Compile.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE GADTs               #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies        #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Attributes.Compile@@ -21,12 +25,13 @@  import           Control.Arrow       (second) import           Control.Lens        ((%~), (&), _Wrapping')-import qualified Data.Map            as M-import           Data.Semigroup      ((<>))+import           Data.Kind           (Type)+import qualified Data.HashMap.Strict as HM+import           Data.Semigroup import           Data.Tree           (Tree (..))  import           Diagrams.Core-import           Diagrams.Core.Style (Style (..), attrToStyle)+import           Diagrams.Core.Style (Style (..), attributeToStyle) import           Diagrams.Core.Types (RNode (..), RTree)  ------------------------------------------------------------@@ -35,8 +40,8 @@ -- splitFills; it's done this way to facilitate testing.  class (AttributeClass (AttrType code), Typeable (PrimType code)) => SplitAttribute code where-  type AttrType code :: *-  type PrimType code :: *+  type AttrType code :: Type+  type PrimType code :: Type    primOK :: code -> PrimType code -> Bool @@ -44,7 +49,7 @@ --   containing only "safe" nodes.  In particular this is used to push --   fill attributes down until they are over only loops; see --   'splitFills'.-splitAttr :: forall code b v a. SplitAttribute code => code -> RTree b v a -> RTree b v a+splitAttr :: forall code b v n a. SplitAttribute code => code -> RTree b v n a -> RTree b v n a splitAttr code = fst . splitAttr' Nothing   where @@ -57,7 +62,7 @@   -- Output: tree with attributes pushed down appropriately, and   -- a Bool indicating whether the tree contains only "safe" prims (True) or   -- contains some unsafe ones (False).-  splitAttr' :: Maybe (AttrType code) -> RTree b v a -> (RTree b v a, Bool)+  splitAttr' :: Maybe (AttrType code) -> RTree b v n a -> (RTree b v n a, Bool)    -- RStyle node: Check for the special attribute, and split it out of   -- the style, combining it with the incoming attribute.  Recurse and@@ -73,8 +78,8 @@   splitAttr' mattr (Node (RStyle sty) cs) = (t', ok)     where       mattr' = mattr <> getAttr sty-      sty' = sty & _Wrapping' Style %~ M.delete ty-      ty   = show . typeOf $ (undefined :: AttrType code)+      sty' = sty & _Wrapping' Style %~ HM.delete ty+      ty   = typeOf (undefined :: AttrType code)       (cs', ok) = splitAttr'Forest mattr' cs       t' | ok        = rebuildNode Nothing ok (RStyle sty) cs'          | otherwise = rebuildNode mattr ok (RStyle sty') cs'@@ -87,9 +92,9 @@       case cast prm :: Maybe (PrimType code) of         Nothing  -> (Node rp [], True)         Just p ->-          case primOK code p of-            True  -> (rebuildNode mattr True rp [], True)-            False -> (Node rp [], False)+          if primOK code p+            then (rebuildNode mattr True rp [], True)+            else (Node rp [], False)    -- RFrozenTr, RAnnot, REmpty cases: just recurse and rebuild.  Note   -- we assume that transformations do not affect the attributes.@@ -101,7 +106,7 @@   -- Recursively call splitAttr' on all subtrees, returning the   -- logical AND of the Bool results returned (the whole forest is   -- safe iff all subtrees are).-  splitAttr'Forest :: Maybe (AttrType code) -> [RTree b v a] -> ([RTree b v a], Bool)+  splitAttr'Forest :: Maybe (AttrType code) -> [RTree b v n a] -> ([RTree b v n a], Bool)   splitAttr'Forest mattr cs = (cs', ok)     where       (cs', ok) = second and . unzip . map (splitAttr' mattr) $ cs@@ -110,13 +115,13 @@   -- subforest contains only loops, a node, and a subforest, rebuild a   -- tree, applying the fill attribute as appropriate (only if the   -- Bool is true and the attribute is not Nothing).-  rebuildNode :: Maybe (AttrType code) -> Bool -> RNode b v a -> [RTree b v a] -> RTree b v a+  rebuildNode :: Maybe (AttrType code) -> Bool -> RNode b v n a -> [RTree b v n a] -> RTree b v n a   rebuildNode mattr ok nd cs     | ok        = applyMattr mattr (Node nd cs)     | otherwise = Node nd cs    -- Prepend a new fill color node if Just; the identity function if   -- Nothing.-  applyMattr :: Maybe (AttrType code) -> RTree b v a -> RTree b v a+  applyMattr :: Maybe (AttrType code) -> RTree b v n a -> RTree b v n a   applyMattr Nothing  t = t-  applyMattr (Just a) t = Node (RStyle $ attrToStyle a) [t]+  applyMattr (Just a) t = Node (RStyle $ attributeToStyle (Attribute a)) [t]
src/Diagrams/Backend/CmdLine.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP                       #-}+{-# LANGUAGE ConstrainedClassMethods   #-} {-# LANGUAGE DeriveDataTypeable        #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE FlexibleInstances         #-}@@ -13,98 +15,94 @@ -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com ----- Convenient creation of command-line-driven executables for--- rendering diagrams.  This module provides a general framework--- and default behaviors for parsing command-line arguments,--- records for diagram creation options in various forms, and--- classes and instances for a unified entry point to command-line-driven--- diagram creation executables.+-- Convenient creation of command-line-driven executables for rendering+-- diagrams.  This module provides a general framework and default+-- behaviors for parsing command-line arguments, records for diagram+-- creation options in various forms, and classes and instances for a+-- unified entry point to command-line-driven diagram creation+-- executables. -- -- For a tutorial on command-line diagram creation see--- <http://projects.haskell.org/diagrams/doc/cmdline.html>.+-- <https://diagrams.github.io/doc/cmdline.html>. -- -----------------------------------------------------------------------------  module Diagrams.Backend.CmdLine-       (--         -- * Options+  ( -         -- ** Standard options-         DiagramOpts(..)-       , diagramOpts-       , width-       , height-       , output+    -- * Options -         -- ** Multi-diagram options-       , DiagramMultiOpts(..)-       , diagramMultiOpts-       , selection-       , list+    -- ** Standard options+    DiagramOpts(..)+  , diagramOpts+  , width+  , height+  , output -         -- ** Animation options-       , DiagramAnimOpts(..)-       , diagramAnimOpts-       , fpu+    -- ** Multi-diagram options+  , DiagramMultiOpts(..)+  , diagramMultiOpts+  , selection+  , list -         -- ** Loop options-       , DiagramLoopOpts(..)-       , diagramLoopOpts-       , loop-       , src-       , interval+    -- ** Animation options+  , DiagramAnimOpts(..)+  , diagramAnimOpts+  , fpu -         -- * Parsing-       , Parseable(..)-       , readHexColor+    -- * Parsing+  , Parseable(..)+  , readHexColor -         -- * Command-line programs (@Mainable@)-         -- ** Arguments, rendering, and entry point-       , Mainable(..)+    -- * Command-line programs (@Mainable@)+    -- ** Arguments, rendering, and entry point+  , Mainable(..) -         -- ** General currying-       , ToResult(..)+    -- ** General currying+  , ToResult(..) -         -- ** Default @mainRender@ implementations-       , defaultAnimMainRender-       , defaultMultiMainRender-       ) where+    -- ** helper functions for implementing @mainRender@+  , defaultAnimMainRender+  , defaultMultiMainRender+  ) where -import           Control.Lens        hiding (argument)+import           Control.Lens              (Lens', makeLenses, (&), (.~), (^.)) import           Diagrams.Animation import           Diagrams.Attributes-import           Diagrams.Core       hiding (value)+import           Diagrams.Core             hiding (output)  import           Options.Applicative import           Options.Applicative.Types (readerAsk) -import           Prelude+import           Control.Monad             (forM_) -import           Control.Monad       (forM_)+-- MonadFail comes from Prelude in base-4.13 and up+#if !MIN_VERSION_base(4,13,0)+import           Control.Monad.Fail        (MonadFail)+#endif -import           Data.Active         hiding (interval)-import           Data.Char           (isDigit)+import           Data.Active               hiding (interval)+import           Data.Char                 (isDigit) import           Data.Colour import           Data.Colour.Names import           Data.Colour.SRGB import           Data.Data-import           Data.List           (intercalate)+import           Data.Functor.Identity+import           Data.Kind                 (Type) import           Data.Monoid- import           Numeric -import           System.Environment  (getProgName)-import           System.FilePath     (addExtension, splitExtension)+import           System.Environment        (getProgName)+import           System.FilePath           (addExtension, splitExtension)  import           Text.Printf  -- | Standard options most diagrams are likely to have. data DiagramOpts = DiagramOpts-    { _width  :: Maybe Int -- ^ Final output width of diagram.-    , _height :: Maybe Int -- ^ Final output height of diagram.-    , _output :: FilePath  -- ^ Output file path, format is typically chosen by extension.-    }+  { _width  :: Maybe Int -- ^ Final output width of diagram.+  , _height :: Maybe Int -- ^ Final output height of diagram.+  , _output :: FilePath  -- ^ Output file path, format is typically chosen by extension.+  }   deriving (Show, Data, Typeable)  makeLenses ''DiagramOpts@@ -112,110 +110,91 @@ -- | Extra options for a program that can offer a choice --   between multiple diagrams. data DiagramMultiOpts = DiagramMultiOpts-    { _selection :: Maybe String -- ^ Selected diagram to render.-    , _list      :: Bool         -- ^ Flag to indicate that a list of available diagrams should-                                 --   be printed to standard out.-    }+  { _selection :: Maybe String -- ^ Selected diagram to render.+  , _list      :: Bool         -- ^ Flag to indicate that a list of available diagrams should+                               --   be printed to standard out.+  }   deriving (Show, Data, Typeable)  makeLenses ''DiagramMultiOpts  -- | Extra options for animations. data DiagramAnimOpts = DiagramAnimOpts-    { _fpu :: Double -- ^ Number of frames per unit time to generate for the animation.-    }+  { _fpu :: Double -- ^ Number of frames per unit time to generate for the animation.+  }   deriving (Show, Data, Typeable)  makeLenses ''DiagramAnimOpts --- | Extra options for command-line looping.-data DiagramLoopOpts = DiagramLoopOpts-    { _loop     :: Bool            -- ^ Flag to indicate that the program should loop creation.-    , _src      :: Maybe FilePath  -- ^ File path for the source file to recompile.-    , _interval :: Int             -- ^ Interval in seconds at which to check for recompilation.-    }--makeLenses ''DiagramLoopOpts- -- | Command line parser for 'DiagramOpts'. --   Width is option @--width@ or @-w@. --   Height is option @--height@ or @-h@ (note we change help to be @-?@ due to this). --   Output is option @--output@ or @-o@. diagramOpts :: Parser DiagramOpts diagramOpts = DiagramOpts-    <$> (optional . option auto)-        ( long "width" <> short 'w'-       <> metavar "WIDTH"-       <> help "Desired WIDTH of the output image")-    <*> (optional . option auto)-        ( long "height" <> short 'h'-       <> metavar "HEIGHT"-       <> help "Desired HEIGHT of the output image")-    <*> strOption-        ( long "output" <> short 'o'-       <> value ""-       <> metavar "OUTPUT"-       <> help "OUTPUT file")+  <$> (optional . option auto)+      ( long "width" <> short 'w'+     <> metavar "WIDTH"+     <> help "Desired WIDTH of the output image")+  <*> (optional . option auto)+      ( long "height" <> short 'h'+     <> metavar "HEIGHT"+     <> help "Desired HEIGHT of the output image")+  <*> strOption+      ( long "output" <> short 'o'+     <> value ""+     <> metavar "OUTPUT"+     <> help "OUTPUT file")  -- | Command line parser for 'DiagramMultiOpts'.---   Selection is option @--selection@ or @-s@.---   List is @--list@ or @-l@.+--   Selection is option @--selection@ or @-S@.+--   List is @--list@ or @-L@. diagramMultiOpts :: Parser DiagramMultiOpts diagramMultiOpts = DiagramMultiOpts-    <$> (optional . strOption)-        ( long "selection" <> short 's'-       <> metavar "NAME"-       <> help "NAME of the diagram to render")-    <*> switch-        ( long "list" <> short 'l'-       <> help "List all available diagrams")+  <$> (optional . strOption)+      ( long "selection" <> short 'S'+     <> metavar "NAME"+     <> help "NAME of the diagram to render")+  <*> switch+      ( long "list" <> short 'L'+     <> help "List all available diagrams")  -- | Command line parser for 'DiagramAnimOpts' --   Frames per unit is @--fpu@ or @-f@. diagramAnimOpts :: Parser DiagramAnimOpts diagramAnimOpts = DiagramAnimOpts-    <$> option auto-        ( long "fpu" <> short 'f'-       <> value 30.0-       <> help "Frames per unit time (for animations)")---- | CommandLine parser for 'DiagramLoopOpts'---   Loop is @--loop@ or @-l@.---   Source is @--src@ or @-s@.---   Interval is @-i@ defaulting to one second.-diagramLoopOpts :: Parser DiagramLoopOpts-diagramLoopOpts = DiagramLoopOpts-    <$> switch (long "loop" <> short 'l' <> help "Run in a self-recompiling loop")-    <*> (optional . strOption)-        ( long "src" <> short 's'-       <> help "Source file to watch")-    <*> option auto-        ( long "interval" <> short 'i'-       <> value 1-       <> metavar "INTERVAL"-       <> help "When running in a loop, check for changes every INTERVAL seconds.")+  <$> option auto+      ( long "fpu" <> short 'f'+     <> value 30.0+     <> help "Frames per unit time (for animations)")  -- | A hidden \"helper\" option which always fails. --   Taken from Options.Applicative.Extra but without the --   short option 'h'.  We want the 'h' for Height. helper' :: Parser (a -> a)-helper' = abortOption ShowHelpText $ mconcat+helper' = abortOption param $ mconcat   [ long "help"   , short '?'   , help "Show this help text"   ]+  where+#if MIN_VERSION_optparse_applicative(0,16,0)+    param = ShowHelpText Nothing+#else+    param = ShowHelpText +#endif  -- | Apply a parser to the command line that includes the standard --   program description and help behavior.  Results in parsed commands --   or fails with a help message. defaultOpts :: Parser a -> IO a defaultOpts optsParser = do-    prog <- getProgName-    let p = info (helper' <*> optsParser)-                ( fullDesc-               <> progDesc "Command-line diagram generation."-               <> header prog)-    execParser p+  prog <- getProgName+  let p = info (helper' <*> optsParser)+              ( fullDesc+             <> progDesc "Command-line diagram generation."+             <> header prog)+  execParser p  -- | Parseable instances give a command line parser for a type.  If a custom --   parser for a common type is wanted a newtype wrapper could be used to make@@ -223,7 +202,7 @@ --   instances as 'Read' because we want to limit ourselves to things that make --   sense to parse from the command line. class Parseable a where-    parser :: Parser a+  parser :: Parser a  -- The following instance would overlap with the product instance for -- Parseable.  We can't tell if one wants to parse (a,b) as one argument or a@@ -235,51 +214,46 @@  -- | Parse 'Int' according to its 'Read' instance. instance Parseable Int where-    parser = argument auto mempty+  parser = argument auto mempty  -- | Parse 'Double' according to its 'Read' instance. instance Parseable Double where-    parser = argument auto mempty+  parser = argument auto mempty  -- | Parse a string by just accepting the given string. instance Parseable String where-    parser = argument str mempty+  parser = argument str mempty  -- | Parse 'DiagramOpts' using the 'diagramOpts' parser. instance Parseable DiagramOpts where-    parser = diagramOpts+  parser = diagramOpts  -- | Parse 'DiagramMultiOpts' using the 'diagramMultiOpts' parser. instance Parseable DiagramMultiOpts where-    parser = diagramMultiOpts+  parser = diagramMultiOpts  -- | Parse 'DiagramAnimOpts' using the 'diagramAnimOpts' parser. instance Parseable DiagramAnimOpts where-    parser = diagramAnimOpts---- | Parse 'DiagramLoopOpts' using the 'diagramLoopOpts' parser.-instance Parseable DiagramLoopOpts where-    parser = diagramLoopOpts-+  parser = diagramAnimOpts  -- | Parse @'Colour' Double@ as either a named color from "Data.Colour.Names" --   or a hexadecimal color. instance Parseable (Colour Double) where-    parser = argument (rc <|> rh) mempty-      where-        rh, rc :: ReadM (Colour Double)-        rh = f . colorToSRGBA <$> (readerAsk >>= readHexColor)-        rc = readerAsk >>= readColourName-        f (r,g,b,_) = sRGB r g b -- TODO: this seems unfortunate.  Should the alpha-                                 -- value be applied to the r g b values?+  parser = argument (rc <|> rh) mempty+    where+      rh, rc :: ReadM (Colour Double)+      rh = f . colorToSRGBA <$> (readerAsk >>= readHexColor)+      rc = readerAsk >>= readColourName+      f (r,g,b,_) = sRGB r g b -- TODO: this seems unfortunate.  Should the alpha+                               -- value be applied to the r g b values?  -- | Parse @'AlphaColour' Double@ as either a named color from "Data.Colour.Names" --   or a hexadecimal color. instance Parseable (AlphaColour Double) where-    parser = argument (rc <|> rh) mempty-      where-        rh = readerAsk >>= readHexColor-        rc = opaque <$> (readerAsk >>= readColourName)+  parser = argument (rc <|> rh) mempty+    where+      rh = readerAsk >>= readHexColor+      rc = opaque <$> (readerAsk >>= readColourName)  -- Addapted from the Clay.Color module of the clay package @@ -289,11 +263,11 @@ --   example, @\"0xfc4\"@ is the same as @\"0xffcc44\"@.  When eight or six --   digits are given each pair of digits is a color or alpha channel with the --   order being red, green, blue, alpha.-readHexColor :: (Applicative m, Monad m) => String -> m (AlphaColour Double)+readHexColor :: (Applicative m, MonadFail m) => String -> m (AlphaColour Double) readHexColor cs = case cs of-     ('0':'x':hs) -> handle hs-     ('#':hs)     -> handle hs-     hs           -> handle hs+  ('0':'x':hs) -> handle hs+  ('#':hs)     -> handle hs+  hs           -> handle hs   where     handle hs | length hs <= 8 && all isHexDigit hs       = case hs of@@ -304,70 +278,76 @@         _                 -> fail $ "could not parse as a colour" ++ cs     handle _ = fail $ "could not parse as a colour: " ++ cs -    isHexDigit c = isDigit c|| c `elem` "abcdef"+    isHexDigit c = isDigit c || c `elem` "abcdef"      hex a b = (/ 255) <$> case readHex [a,b] of                 [(h,"")] -> return h-                _        -> fail $ "could not parse as a hex value" ++ (a:b:[])+                _        -> fail $ "could not parse as a hex value" ++ [a,b]   -- | This instance is needed to signal the end of a chain of --   nested tuples, it always just results in the unit value --   without consuming anything. instance Parseable () where-    parser = pure ()+  parser = pure ()  -- | Allow 'Parseable' things to be combined. instance (Parseable a, Parseable b) => Parseable (a,b) where-    parser = (,) <$> parser <*> parser+  parser = (,) <$> parser <*> parser +-- | Triples of Parsebales should also be Parseable.+instance (Parseable a, Parseable b, Parseable c) => Parseable (a, b, c) where+  parser = (,,) <$> parser <*> parser <*> parser +instance (Parseable a, Parseable b, Parseable c, Parseable d) => Parseable (a, b, c, d) where+  parser = (,,,) <$> parser <*> parser <*> parser <*> parser+ -- | This class allows us to abstract over functions that take some arguments --   and produce a final value.  When some @d@ is an instance of --   'ToResult' we get a type @'Args' d@ that is a type of /all/ the arguments --   at once, and a type @'ResultOf' d@ that is the type of the final result from --   some base case instance. class ToResult d where-    type Args d :: *-    type ResultOf d :: *+  type Args d :: Type+  type ResultOf d :: Type -    toResult :: d -> Args d -> ResultOf d+  toResult :: d -> Args d -> ResultOf d  -- | A diagram can always produce a diagram when given @()@ as an argument. --   This is our base case.-instance ToResult (Diagram b v) where-    type Args (Diagram b v) = ()-    type ResultOf (Diagram b v) = Diagram b v+instance ToResult (QDiagram b v n Any) where+  type Args (QDiagram b v n Any) = ()+  type ResultOf (QDiagram b v n Any) = QDiagram b v n Any -    toResult d _ = d+  toResult d _ = d  -- | A list of diagrams can produce pages.-instance ToResult [Diagram b v] where-   type Args [Diagram b v] = ()-   type ResultOf [Diagram b v] = [Diagram b v]+instance ToResult [QDiagram b v n Any] where+  type Args [QDiagram b v n Any] = ()+  type ResultOf [QDiagram b v n Any] = [QDiagram b v n Any] -   toResult ds _ = ds+  toResult ds _ = ds  -- | A list of named diagrams can give the multi-diagram interface.-instance ToResult [(String,Diagram b v)] where-   type Args [(String,Diagram b v)]  = ()-   type ResultOf [(String,Diagram b v)] = [(String,Diagram b v)]+instance ToResult [(String, QDiagram b v n Any)] where+  type Args [(String,QDiagram b v n Any)] = ()+  type ResultOf [(String,QDiagram b v n Any)] = [(String,QDiagram b v n Any)] -   toResult ds _ = ds+  toResult ds _ = ds  -- | An animation is another suitable base case.-instance ToResult (Animation b v) where-   type Args (Animation b v) = ()-   type ResultOf (Animation b v) = Animation b v+instance ToResult (Animation b v n) where+  type Args (Animation b v n) = ()+  type ResultOf (Animation b v n) = Animation b v n -   toResult a _ = a+  toResult a _ = a  -- | Diagrams that require IO to build are a base case. instance ToResult d => ToResult (IO d) where-   type Args (IO d) = Args d-   type ResultOf (IO d) = IO (ResultOf d)+  type Args (IO d) = Args d+  type ResultOf (IO d) = IO (ResultOf d) -   toResult d args = flip toResult args <$> d+  toResult d args = flip toResult args <$> d  -- | An instance for a function that, given some 'a', can produce a 'd' that is --   also an instance of 'ToResult'.  For this to work we need both the@@ -379,10 +359,10 @@ --   is clearer and easier to understand then paragraphs in English written by --   me. instance ToResult d => ToResult (a -> d) where-    type Args (a -> d) = (a, Args d)-    type ResultOf (a -> d) = ResultOf d+  type Args (a -> d) = (a, Args d)+  type ResultOf (a -> d) = ResultOf d -    toResult f (a,args) = toResult (f a) args+  toResult f (a,args) = toResult (f a) args   -- | This class represents the various ways we want to support diagram creation@@ -401,62 +381,59 @@ --   The associated type 'MainOpts' describes the options which need to be parsed --   from the command-line and passed to @mainRender@. class Mainable d where-    -- | Associated type that describes the options which need to be parsed-    -- from the command-line and passed to @mainRender@.-    type MainOpts d :: *+  -- | Associated type that describes the options which need to be parsed+  -- from the command-line and passed to @mainRender@.+  type MainOpts d :: Type -    -- | This method invokes the command-line parser resulting in an options-    -- value or ending the program with an error or help message.-    -- Typically the default instance will work.  If a different help message-    -- or parsing behavior is desired a new implementation is appropriate.-    ---    -- Note the @d@ argument should only be needed to fix the type @d@.  Its-    -- value should not be relied on as a parameter.-    mainArgs :: Parseable (MainOpts d) => d -> IO (MainOpts d)-    mainArgs _ = defaultOpts parser+  -- | This method invokes the command-line parser resulting in an options+  -- value or ending the program with an error or help message.+  -- Typically the default instance will work.  If a different help message+  -- or parsing behavior is desired a new implementation is appropriate.+  mainArgs :: Parseable (MainOpts d) => proxy d -> IO (MainOpts d)+  mainArgs _ = defaultOpts parser -    -- | Backend specific work of rendering with the given options and mainable-    -- value is done here.  All backend instances should implement this method.-    mainRender :: MainOpts d -> d -> IO ()+  -- | Backend specific work of rendering with the given options and mainable+  -- value is done here.  All backend instances should implement this method.+  mainRender :: MainOpts d -> d -> IO () -    -- | Main entry point for command-line diagram creation.  This is the method-    -- that users will call from their program @main@.  For instance an expected-    -- user program would take the following form.-    ---    -- @-    -- import Diagrams.Prelude-    -- import Diagrams.Backend.TheBestBackend.CmdLine-    ---    -- d :: Diagram B R2-    -- d = ...-    ---    -- main = mainWith d-    -- @-    ---    -- Most backends should be able to use the default implementation.  A different-    -- implementation should be used to handle more complex interactions with the user.-    mainWith :: Parseable (MainOpts d) => d -> IO ()-    mainWith d = do-        opts <- mainArgs d-        mainRender opts d+  -- | Main entry point for command-line diagram creation.  This is the method+  -- that users will call from their program @main@.  For instance an expected+  -- user program would take the following form.+  --+  -- @+  -- import Diagrams.Prelude+  -- import Diagrams.Backend.TheBestBackend.CmdLine+  --+  -- d :: Diagram B R2+  -- d = ...+  --+  -- main = mainWith d+  -- @+  --+  -- Most backends should be able to use the default implementation.  A different+  -- implementation should be used to handle more complex interactions with the user.+  mainWith :: Parseable (MainOpts d) => d -> IO ()+  mainWith d = do+    opts <- mainArgs (Identity d)+    mainRender opts d  -- | This instance allows functions resulting in something that is 'Mainable' to --   be 'Mainable'.  It takes a parse of collected arguments and applies them to --   the given function producing the 'Mainable' result.-instance (Parseable (Args (a -> d)), ToResult d, Mainable (ResultOf d))+instance (ToResult d, Mainable (ResultOf d))         => Mainable (a -> d) where-    type MainOpts (a -> d) = (MainOpts (ResultOf (a -> d)), Args (a -> d))+  type MainOpts (a -> d) = (MainOpts (ResultOf (a -> d)), Args (a -> d)) -    mainRender (opts, a) f  = mainRender opts (toResult f a)+  mainRender (opts, a) f  = mainRender opts (toResult f a) -- TODO: why can't we get away with: instance (Parseable (Args (a -> d)), Mainable (ResultOf d)) => ... --       Doesn't `Args (a -> d)` imply `ToResult (a -> d)` which implies `ToResult d` ?  -- | With this instance we can perform IO to produce something --   'Mainable' before rendering. instance Mainable d => Mainable (IO d) where-    type MainOpts (IO d) = MainOpts d+  type MainOpts (IO d) = MainOpts d -    mainRender opts dio = dio >>= mainRender opts+  mainRender opts dio = dio >>= mainRender opts  -- | @defaultMultiMainRender@ is an implementation of 'mainRender' where --   instead of a single diagram it takes a list of diagrams paired with names@@ -464,11 +441,11 @@ --   specifying the name of the diagram that should be rendered.  The list of --   available diagrams may also be printed by passing the option @--list@. -----   Typically a backend can write its @[(String,Diagram B V)]@ instance as+--   Typically a backend can write its @[(String,QDiagram b v n Any)]@ instance as -- --   @---   instance Mainable [(String,Diagram B V)] where---       type MainOpts [(String,Diagram B V)] = (DiagramOpts, DiagramMultiOpts)+--   instance Mainable [(String,QDiagram b v n Any)] where+--       type MainOpts [(String,QDiagram b v n Any)] = (DiagramOpts, DiagramMultiOpts) --       mainRender = defaultMultiMainRender --   @ --@@ -476,19 +453,19 @@ --   opt-in to this form or provide a different instance that makes more sense. defaultMultiMainRender :: Mainable d => (MainOpts d, DiagramMultiOpts) -> [(String, d)] -> IO () defaultMultiMainRender (opts,multi) ds =-    if multi^.list-      then showDiaList (map fst ds)-      else case multi^.selection of-             Nothing  -> putStrLn "No diagram selected." >> showDiaList (map fst ds)-             Just sel -> case lookup sel ds of-                           Nothing -> putStrLn $ "Unknown diagram: " ++ sel-                           Just d  -> mainRender opts d+  if multi^.list+    then showDiaList (map fst ds)+    else case multi^.selection of+           Nothing  -> putStrLn "No diagram selected." >> showDiaList (map fst ds)+           Just sel -> case lookup sel ds of+                         Nothing -> putStrLn $ "Unknown diagram: " ++ sel+                         Just d  -> mainRender opts d  -- | Display the list of diagrams available for rendering. showDiaList :: [String] -> IO () showDiaList ds = do   putStrLn "Available diagrams:"-  putStrLn $ "  " ++ intercalate " " ds+  putStrLn $ "  " ++ unwords ds  -- | @defaultAnimMainRender@ is an implementation of 'mainRender' which renders --   an animation as numbered frames, named by extending the given output file@@ -506,9 +483,8 @@ --   be output for each second (unit time) of animation. -- --   This function requires a lens into the structure that the particular backend---   uses for it's diagram base case.  If @MainOpts (Diagram b v) ~ DiagramOpts@---   then this lens will simply be 'output'.  For a backend supporting looping---   it will most likely be @_1 . output@.  This lens is required because the+--   uses for its diagram base case.  If @MainOpts (QDiagram b v n Any) ~ DiagramOpts@+--   then this lens will simply be 'output'.  This lens is required because the --   implementation works by modifying the output field and running the base @mainRender@. --   Typically a backend can write its @Animation B V@ instance as --@@ -520,21 +496,23 @@ -- --   We do not provide this instance in general so that backends can choose to --   opt-in to this form or provide a different instance that makes more sense.-defaultAnimMainRender :: (Mainable (Diagram b v))-                      => (Lens' (MainOpts (Diagram b v)) FilePath) -- ^ A lens into the output path.-                      -> (MainOpts (Diagram b v),DiagramAnimOpts)-                      -> Animation b v-                      -> IO ()-defaultAnimMainRender out (opts,animOpts) anim = do-    let frames  = simulate (toRational $ animOpts^.fpu) anim-        nDigits = length . show . length $ frames-    forM_ (zip [1..] frames) $ \(i,d) -> mainRender (indexize out nDigits i opts) d +defaultAnimMainRender ::+    (opts -> QDiagram b v n Any -> IO ())+    -> Lens' opts FilePath -- ^ A lens into the output path.+    -> (opts, DiagramAnimOpts)+    -> Animation b v n+    -> IO ()+defaultAnimMainRender renderF out (opts,animOpts) anim = do+  let frames  = simulate (toRational $ animOpts^.fpu) anim+      nDigits = length . show . length $ frames+  forM_ (zip [1..] frames) $ \(i,d) -> renderF (indexize out nDigits i opts) d+ -- | @indexize d n@ adds the integer index @n@ to the end of the --   output file name, padding with zeros if necessary so that it uses --   at least @d@ digits.-indexize :: Lens' s FilePath ->  Int -> Integer -> s -> s+indexize :: Lens' s FilePath -> Int -> Integer -> s -> s indexize out nDigits i opts = opts & out .~ output'   where fmt         = "%0" ++ show nDigits ++ "d"-        output'     = addExtension (base ++ printf fmt (i::Integer)) ext+        output'     = addExtension (base ++ printf fmt i) ext         (base, ext) = splitExtension (opts^.out)
src/Diagrams/BoundingBox.hs view
@@ -1,16 +1,19 @@-{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveFunctor              #-} {-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE NoMonomorphismRestriction  #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE StandaloneDeriving         #-} {-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE UndecidableInstances       #-}+{-# LANGUAGE ViewPatterns               #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.BoundingBox--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -23,310 +26,309 @@ -----------------------------------------------------------------------------  module Diagrams.BoundingBox-       ( -- * Bounding boxes-         BoundingBox()+  ( -- * Bounding boxes+    BoundingBox -         -- * Constructing bounding boxes-       , emptyBox, fromCorners, fromPoint, fromPoints-       , boundingBox+    -- * Constructing bounding boxes+  , emptyBox, fromCorners, fromPoint, fromPoints+  , boundingBox -         -- * Queries on bounding boxes-       , isEmptyBox-       , getCorners, getAllCorners-       , boxExtents, boxTransform, boxFit-       , contains, contains'-       , inside, inside', outside, outside'+    -- * Queries on bounding boxes+  , isEmptyBox+  , getCorners, getAllCorners+  , boxExtents, boxCenter+  , mCenterPoint, centerPoint+  , boxTransform, boxFit+  , contains, contains'+  , inside, inside', outside, outside' -         -- * Operations on bounding boxes-       , union, intersection-       ) where+  , boxGrid -import           Control.Applicative     ((<$>))-import qualified Data.Foldable           as F-import           Data.Map                (Map, fromDistinctAscList, fromList,-                                          toAscList, toList)+    -- * Operations on bounding boxes+  , union, intersection+  ) where +import           Control.Lens            (AsEmpty (..), Each (..), nearly)+import           Data.Foldable           as F import           Data.Maybe              (fromMaybe)--import           Data.VectorSpace--- (VectorSpace, Scalar, AdditiveGroup, zeroV, negateV, (^+^), (^-^))-import           Data.Basis              (Basis, HasBasis, basisValue,-                                          decompose, recompose)-import           Data.Monoid             (Monoid (..))-import           Data.Semigroup          (Option (..), Semigroup (..))+import           Data.Semigroup+import           Text.Read -import           Data.Data               (Data)-import           Data.Typeable           (Typeable)+import           Diagrams.Align+import           Diagrams.Core+import           Diagrams.Core.Transform+import           Diagrams.Path+import           Diagrams.Query+import           Diagrams.ThreeD.Shapes  (cube)+import           Diagrams.ThreeD.Types+import           Diagrams.TwoD.Path      ()+import           Diagrams.TwoD.Shapes+import           Diagrams.TwoD.Types -import           Diagrams.Core.Envelope  (Enveloped (..), appEnvelope)-import           Diagrams.Core.HasOrigin (HasOrigin (..))-import           Diagrams.Core.Points    (Point (..))-import           Diagrams.Core.Transform (HasLinearMap, Transformable (..),-                                          Transformation (..), (<->))-import           Diagrams.Core.V         (V)+import           Control.Applicative+import           Data.Traversable        as T+import           Linear.Affine+import           Linear.Metric+import           Linear.Vector           hiding (lerp)+import           Linear.Vector.Compat    (lerp)  -- Unexported utility newtype -newtype NonEmptyBoundingBox v = NonEmptyBoundingBox (Point v, Point v)-  deriving (Eq, Data, Typeable)+newtype NonEmptyBoundingBox v n = NonEmptyBoundingBox (Point v n, Point v n)+  deriving (Eq, Functor) -fromNonEmpty :: NonEmptyBoundingBox v -> BoundingBox v-fromNonEmpty = BoundingBox . Option . Just+type instance V (NonEmptyBoundingBox v n) = v+type instance N (NonEmptyBoundingBox v n) = n -fromMaybeEmpty :: Maybe (NonEmptyBoundingBox v) -> BoundingBox v+fromNonEmpty :: NonEmptyBoundingBox v n -> BoundingBox v n+fromNonEmpty = BoundingBox . Just++fromMaybeEmpty :: Maybe (NonEmptyBoundingBox v n) -> BoundingBox v n fromMaybeEmpty = maybe emptyBox fromNonEmpty -nonEmptyCorners :: NonEmptyBoundingBox v -> (Point v, Point v)+nonEmptyCorners :: NonEmptyBoundingBox v n -> (Point v n, Point v n) nonEmptyCorners (NonEmptyBoundingBox x) = x -instance (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-    => Semigroup (NonEmptyBoundingBox v) where+instance (Additive v, Ord n) => Semigroup (NonEmptyBoundingBox v n) where   (NonEmptyBoundingBox (ul, uh)) <> (NonEmptyBoundingBox (vl, vh))-    = NonEmptyBoundingBox-    $ mapT toPoint (combineP min ul vl, combineP max uh vh)-+    = NonEmptyBoundingBox (liftU2 min ul vl, liftU2 max uh vh)  -- | A bounding box is an axis-aligned region determined by two points --   indicating its \"lower\" and \"upper\" corners.  It can also represent --   an empty bounding box - the points are wrapped in @Maybe@.-newtype BoundingBox v = BoundingBox (Option (NonEmptyBoundingBox v))-  deriving (Eq, Data, Typeable)+newtype BoundingBox v n = BoundingBox (Maybe (NonEmptyBoundingBox v n))+  deriving (Eq, Functor) -deriving instance-  ( HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v)-  ) => Semigroup (BoundingBox v)-deriving instance-  ( HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v)-  ) => Monoid (BoundingBox v)+deriving instance (Additive v, Ord n) => Semigroup (BoundingBox v n)+deriving instance (Additive v, Ord n) => Monoid (BoundingBox v n) -type instance V (BoundingBox v) = v+instance AsEmpty (BoundingBox v n) where+  _Empty = nearly emptyBox isEmptyBox --- Map a function on a homogenous 2-tuple. (unexported utility)+-- | Only valid if the second point is not smaller than the first.+instance (Additive v', Foldable v', Ord n') =>+    Each (BoundingBox v n) (BoundingBox v' n') (Point v n) (Point v' n') where+  each f (getCorners -> Just (l, u)) = fromCorners <$> f l <*> f u+  each _ _                           = pure emptyBox++type instance V (BoundingBox v n) = v+type instance N (BoundingBox v n) = n++-- Map a function on a homogeneous 2-tuple. (unexported utility) mapT :: (a -> b) -> (a, a) -> (b, b) mapT f (x, y) = (f x, f y) -instance ( VectorSpace v, HasBasis v, Ord (Basis v)-         , AdditiveGroup (Scalar v), Ord (Scalar v)-         )  => HasOrigin (BoundingBox v) where+instance (Additive v, Num n) => HasOrigin (BoundingBox v n) where   moveOriginTo p b     = fromMaybeEmpty-    ( NonEmptyBoundingBox . mapT (moveOriginTo p) <$> getCorners b )+    (NonEmptyBoundingBox . mapT (moveOriginTo p) <$> getCorners b) -instance ( InnerSpace v, HasBasis v, Ord (Basis v)-         , AdditiveGroup (Scalar v), Ord (Scalar v), Floating (Scalar v)-         ) => Enveloped (BoundingBox v) where+instance (Additive v, Foldable v, Ord n)+     => HasQuery (BoundingBox v n) Any where+  getQuery bb = Query $ Any . contains bb++instance (Metric v, Traversable v, OrderedField n)+     => Enveloped (BoundingBox v n) where   getEnvelope = getEnvelope . getAllCorners -instance Show v => Show (BoundingBox v) where-  show-    = maybe "emptyBox" (\(l, u) -> "fromCorners " ++ show l ++ " " ++ show u)-    . getCorners+-- Feels like cheating.+-- Should be possible to generalise this.+instance RealFloat n => Traced (BoundingBox V2 n) where+  getTrace = getTrace+           . ((`boxFit` rect 1 1) . boundingBox :: Envelope V2 n -> Path V2 n)+           . getEnvelope -{- TODO-instance Read v => Read (BoundingBox v) where-  read "emptyBox" = emptyBox--}+instance TypeableFloat n => Traced (BoundingBox V3 n) where+  getTrace bb = foldMap (\tr -> getTrace $ transform tr cube) $+                boxTransform (boundingBox cube) bb +instance (Metric v, Traversable v, OrderedField n) => Alignable (BoundingBox v n) where+  defaultBoundary = envelopeP++instance Show (v n) => Show (BoundingBox v n) where+  showsPrec d b = case getCorners b of+    Just (l, u) -> showParen (d > 10) $+      showString "fromCorners " . showsPrec 11 l . showChar ' ' . showsPrec 11 u+    Nothing     -> showString "emptyBox"++instance Read (v n) => Read (BoundingBox v n) where+  readPrec = parens $+    (do+      Ident "emptyBox" <- lexP+      pure emptyBox+    ) <|>+    (prec 10 $ do+      Ident "fromCorners" <- lexP+      l <- step readPrec+      h <- step readPrec+      pure . fromNonEmpty $ NonEmptyBoundingBox (l, h)+    )+ -- | An empty bounding box.  This is the same thing as @mempty@, but it doesn't---   require the same type constraints that the @Monoid@-emptyBox :: BoundingBox v-emptyBox = BoundingBox $ Option Nothing+--   require the same type constraints that the @Monoid@ instance does.+emptyBox :: BoundingBox v n+emptyBox = BoundingBox Nothing  -- | Create a bounding box from a point that is component-wise @(<=)@ than the --   other.  If this is not the case, then @mempty@ is returned. fromCorners-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => Point v -> Point v -> BoundingBox v+  :: (Additive v, Foldable v, Ord n)+  => Point v n -> Point v n -> BoundingBox v n fromCorners l h-  | F.and (combineP (<=) l h) = fromNonEmpty $ NonEmptyBoundingBox (l, h)-  | otherwise = mempty+  | F.and (liftI2 (<=) l h) = fromNonEmpty $ NonEmptyBoundingBox (l, h)+  | otherwise               = mempty  -- | Create a degenerate bounding \"box\" containing only a single point.-fromPoint-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => Point v -> BoundingBox v+fromPoint :: Point v n -> BoundingBox v n fromPoint p = fromNonEmpty $ NonEmptyBoundingBox (p, p)  -- | Create the smallest bounding box containing all the given points.-fromPoints-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => [Point v] -> BoundingBox v+fromPoints :: (Additive v, Ord n) => [Point v n] -> BoundingBox v n fromPoints = mconcat . map fromPoint  -- | Create a bounding box for any enveloped object (such as a diagram or path).-boundingBox :: forall a. ( Enveloped a, HasBasis (V a), AdditiveGroup (V a)-                         , Ord (Basis (V a))-                         ) => a -> BoundingBox (V a)+boundingBox :: (InSpace v n a, HasBasis v, Enveloped a)+            => a -> BoundingBox v n boundingBox a = fromMaybeEmpty $ do-    env <- appEnvelope $ getEnvelope a-    let h = recompose $ map (\v -> (v,          env           $ basisValue v)) us-        l = recompose $ map (\v -> (v, negate . env . negateV $ basisValue v)) us-    return $ NonEmptyBoundingBox (P l, P h)-  where-    -- The units. Might not work if 0-components aren't reported.-    --TODO: Depend on Enum Basis?-    us = map fst $ decompose (zeroV :: V a)+  env <- (appEnvelope . getEnvelope) a+  let h = fmap env eye+      l = negated $ fmap (env . negated) eye+  return $ NonEmptyBoundingBox (P l, P h)  -- | Queries whether the BoundingBox is empty.-isEmptyBox :: BoundingBox v -> Bool-isEmptyBox (BoundingBox (Option Nothing)) = True-isEmptyBox _ = False+isEmptyBox :: BoundingBox v n -> Bool+isEmptyBox (BoundingBox Nothing) = True+isEmptyBox _                              = False  -- | Gets the lower and upper corners that define the bounding box.-getCorners :: BoundingBox v -> Maybe (Point v, Point v)-getCorners (BoundingBox p) = nonEmptyCorners <$> getOption p+getCorners :: BoundingBox v n -> Maybe (Point v n, Point v n)+getCorners (BoundingBox p) = nonEmptyCorners <$> p  -- | Computes all of the corners of the bounding box.-getAllCorners :: (HasBasis v, AdditiveGroup (Scalar v), Ord (Basis v))-              => BoundingBox v -> [Point v]-getAllCorners (BoundingBox (Option Nothing)) = []-getAllCorners (BoundingBox (Option (Just (NonEmptyBoundingBox (l, u)))))-  = map (P . recompose)-  -- Enumerate all combinations of selections of lower / higher values.-  . mapM (\(b, (l', u')) -> [(b, l'), (b, u')])-  -- List of [(basis, (lower, upper))]-  . toList-  $ combineP (,) l u+getAllCorners :: (Additive v, Traversable v) => BoundingBox v n -> [Point v n]+getAllCorners (BoundingBox Nothing) = []+getAllCorners (BoundingBox (Just (NonEmptyBoundingBox (l, u))))+  = T.sequence (liftI2 (\a b -> [a,b]) l u)  -- | Get the size of the bounding box - the vector from the (component-wise) --   lesser point to the greater point.-boxExtents :: (AdditiveGroup v) => BoundingBox v -> v-boxExtents = maybe zeroV (\(P l, P h) -> h ^-^ l) . getCorners+boxExtents :: (Additive v, Num n) => BoundingBox v n -> v n+boxExtents = maybe zero (\(l,u) -> u .-. l) . getCorners --- | Create a transformation mapping points from one bounding box to the other.-boxTransform :: (AdditiveGroup v, HasLinearMap v,-                 Fractional (Scalar v), AdditiveGroup (Scalar v), Ord (Basis v))-             => BoundingBox v -> BoundingBox v -> Maybe (Transformation v)+-- | Get the center point in a bounding box.+boxCenter :: (Additive v, Fractional n) => BoundingBox v n -> Maybe (Point v n)+boxCenter = fmap (uncurry (lerp 0.5)) . getCorners++-- | Get the center of a the bounding box of an enveloped object, return+--   'Nothing' for object with empty envelope.+mCenterPoint :: (InSpace v n a, HasBasis v, Enveloped a)+            => a -> Maybe (Point v n)+mCenterPoint = boxCenter . boundingBox++-- | Get the center of a the bounding box of an enveloped object, return+--   the origin for object with empty envelope.+centerPoint :: (InSpace v n a, HasBasis v, Enveloped a)+            => a -> Point v n+centerPoint = fromMaybe origin . mCenterPoint++-- | Create a transformation mapping points from one bounding box to the+--   other. Returns 'Nothing' if either of the boxes are empty.+boxTransform+  :: (Additive v, Fractional n)+  => BoundingBox v n -> BoundingBox v n -> Maybe (Transformation v n) boxTransform u v = do-    ((P ul), _) <- getCorners u-    ((P vl), _) <- getCorners v-    let lin_map = box_scale (v, u) <-> box_scale (u, v)-        box_scale = combineV' (*) . uncurry (combineV' (/)) . mapT boxExtents-        combineV' f x = toVector . combineV f x-    return $ Transformation lin_map lin_map (vl ^-^ box_scale (v, u) ul)+  (P ul, _) <- getCorners u+  (P vl, _) <- getCorners v+  let i  = s (v, u) <-> s (u, v)+      s = liftU2 (*) . uncurry (liftU2 (/)) . mapT boxExtents+  return $ Transformation i i (vl ^-^ s (v, u) ul) --- | Transforms an enveloped thing to fit within a @BoundingBox@.  If it's---   empty, then the result is also @mempty@.-boxFit :: (Enveloped a, Transformable a, Monoid a, Ord (Basis (V a)))-       => BoundingBox (V a) -> a -> a+-- | Transforms an enveloped thing to fit within a @BoundingBox@.  If the+--   bounding box is empty, then the result is also @mempty@.+boxFit+  :: (InSpace v n a, HasBasis v, Enveloped a, Transformable a, Monoid a)+  => BoundingBox v n -> a -> a boxFit b x = maybe mempty (`transform` x) $ boxTransform (boundingBox x) b  -- | Check whether a point is contained in a bounding box (including its edges).-contains-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> Point v -> Bool+contains :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> Point v n -> Bool contains b p = maybe False check $ getCorners b   where-    check (l, h) = F.and (combineP (<=) l p)-                && F.and (combineP (<=) p h)+    check (l, h) = F.and (liftI2 (<=) l p)+                && F.and (liftI2 (<=) p h)  -- | Check whether a point is /strictly/ contained in a bounding box.-contains'-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> Point v -> Bool+contains' :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> Point v n -> Bool contains' b p = maybe False check $ getCorners b   where-    check (l, h) = F.and (combineP (<) l p)-                && F.and (combineP (<) p h)+    check (l, h) = F.and (liftI2 (<) l p)+                && F.and (liftI2 (<) p h)  -- | Test whether the first bounding box is contained inside --   the second.-inside-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> BoundingBox v -> Bool+inside :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> BoundingBox v n -> Bool inside u v = fromMaybe False $ do   (ul, uh) <- getCorners u   (vl, vh) <- getCorners v-  return $ F.and (combineP (>=) ul vl)-        && F.and (combineP (<=) uh vh)+  return $ F.and (liftI2 (>=) ul vl)+        && F.and (liftI2 (<=) uh vh)  -- | Test whether the first bounding box is /strictly/ contained --   inside the second.-inside'-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> BoundingBox v -> Bool+inside' :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> BoundingBox v n -> Bool inside' u v = fromMaybe False $ do   (ul, uh) <- getCorners u   (vl, vh) <- getCorners v-  return $ F.and (combineP (>) ul vl)-        && F.and (combineP (<) uh vh)+  return $ F.and (liftI2 (>) ul vl)+        && F.and (liftI2 (<) uh vh)  -- | Test whether the first bounding box lies outside the second --   (although they may intersect in their boundaries).-outside-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> BoundingBox v -> Bool+outside :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> BoundingBox v n -> Bool outside u v = fromMaybe True $ do   (ul, uh) <- getCorners u   (vl, vh) <- getCorners v-  return $ F.or (combineP (<=) uh vl)-        || F.or (combineP (>=) ul vh)+  return $ F.or (liftI2 (<=) uh vl)+        || F.or (liftI2 (>=) ul vh)  -- | Test whether the first bounding box lies /strictly/ outside the second --   (they do not intersect at all).-outside'-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> BoundingBox v -> Bool+outside' :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> BoundingBox v n -> Bool outside' u v = fromMaybe True $ do   (ul, uh) <- getCorners u   (vl, vh) <- getCorners v-  return $ F.or (combineP (<) uh vl)-        || F.or (combineP (>) ul vh)+  return $ F.or (liftI2 (<) uh vl)+        || F.or (liftI2 (>) ul vh)  -- | Form the largest bounding box contained within this given two --   bounding boxes, or @Nothing@ if the two bounding boxes do not --   overlap at all. intersection-  :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-  => BoundingBox v -> BoundingBox v -> BoundingBox v+  :: (Additive v, Foldable v, Ord n)+  => BoundingBox v n -> BoundingBox v n -> BoundingBox v n intersection u v = maybe mempty (uncurry fromCorners) $ do   (ul, uh) <- getCorners u   (vl, vh) <- getCorners v-  return $ mapT toPoint (combineP max ul vl, combineP min uh vh)+  return (liftI2 max ul vl, liftI2 min uh vh)  -- | Form the smallest bounding box containing the given two bound union.  This --   function is just an alias for @mappend@.-union :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v), Ord (Scalar v))-      => BoundingBox v -> BoundingBox v -> BoundingBox v+union :: (Additive v, Ord n) => BoundingBox v n -> BoundingBox v n -> BoundingBox v n union = mappend --- internals using Map (Basis v) (Scalar v)--- probably paranoia, but decompose might not always---   1. contain basis elements whose component is zero---   2. have basis elements in the same order--fromVector :: (HasBasis v, Ord (Basis v)) => v -> Map (Basis v) (Scalar v)-fromVector = fromList . decompose--toVector :: HasBasis v => Map (Basis v) (Scalar v) -> v-toVector = recompose . toList--toPoint :: HasBasis v => Map (Basis v) (Scalar v) -> Point v-toPoint = P . toVector--combineV :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v))-         => (Scalar v -> Scalar v -> a) -> v -> v -> Map (Basis v) a-combineV f u v = combineDefault zeroV zeroV f (fromVector u) (fromVector v)--combineP :: (HasBasis v, Ord (Basis v), AdditiveGroup (Scalar v))-         => (Scalar v -> Scalar v -> a) -> Point v -> Point v -> Map (Basis v) a-combineP f (P u) (P v) = combineV f u v--combineDefault :: Ord k => a -> b -> (a -> b -> c) -> Map k a -> Map k b -> Map k c-combineDefault a b f = combine g+-- | @boxGrid f box@ returns a grid of regularly spaced points inside+--   the box, such that there are @(1/f)@ points along each dimension.+--   For example, for a 3D box with corners at (0,0,0) and (2,2,2),+--   @boxGrid 0.1@ would yield a grid of approximately 1000 points (it+--   might actually be @11^3@ instead of @10^3@) spaced @0.2@ units+--   apart.+boxGrid+  :: (Traversable v, Additive v, Num n, Enum n)+  => n -> BoundingBox v n -> [Point v n]+boxGrid f = maybe [] (sequenceA . uncurry (liftI2 mkRange)) . getCorners   where-    g Nothing  Nothing  = f a b-    g Nothing  (Just y) = f a y-    g (Just x) Nothing  = f x b-    g (Just x) (Just y) = f x y+    mkRange lo hi = [lo, (1-f)*lo + f*hi .. hi] -combine :: Ord k => (Maybe a -> Maybe b -> c) -> Map k a -> Map k b -> Map k c-combine f am bm = fromDistinctAscList $ merge (toAscList am) (toAscList bm)-  where-    merge [] [] = []-    merge ((x,a):xs) [] = (x, f (Just a) Nothing) : merge xs []-    merge [] ((y,b):ys) = (y, f Nothing (Just b)) : merge [] ys-    merge xs0@((x,a):xs) ys0@((y,b):ys) = case compare x y of-      LT -> (x, f (Just a) Nothing ) : merge xs ys0-      EQ -> (x, f (Just a) (Just b)) : merge xs ys-      GT -> (y, f Nothing  (Just b)) : merge xs0 ys+    -- liftA2 mkRange on the two corner points creates a (Point V2+    -- [n]), where each component is the range of values for that+    -- dimension.  sequenceA then yields a grid of type [Point V2 n].
src/Diagrams/Combinators.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP                   #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE Rank2Types            #-}@@ -28,41 +28,38 @@        , atop        , beneath        , beside+       , atDirection           -- * n-ary operations        , appends-       , position, decorateTrail, decorateLocatedTrail, decoratePath+       , position, atPoints        , cat, cat'        , CatOpts(_catMethod, _sep), catMethod, sep        , CatMethod(..)+       , composeAligned         ) where -import           Data.Typeable--import           Control.Lens          (Lens', generateSignatures,-                                        lensRules, makeLensesWith, (%~), (&),-                                        (.~), (^.), _Wrapping)-import           Data.AdditiveGroup-import           Data.AffineSpace      ((.+^))-import           Data.Default.Class+import           Control.Lens          hiding (beside, ( # ))+import           Data.Default+import           Data.Maybe            (fromJust) import           Data.Monoid.Deletable (toDeletable) import           Data.Monoid.MList     (inj)-#if __GLASGOW_HASKELL__ < 707 import           Data.Proxy-#endif import           Data.Semigroup import qualified Data.Tree.DUAL        as D-import           Data.VectorSpace  import           Diagrams.Core import           Diagrams.Core.Types   (QDiagram (QD))-import           Diagrams.Located-import           Diagrams.Path+import           Diagrams.Direction+import           Diagrams.Names        (named) import           Diagrams.Segment      (straight)-import           Diagrams.Trail        (Trail, trailVertices) import           Diagrams.Util +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ ------------------------------------------------------------ -- Working with envelopes ------------------------------------------------------------@@ -76,23 +73,23 @@ --   >     circle 1 # fc green --   >     ||| --   >     (    c # dashingG [0.1,0.1] 0 # lc white---   >       <> square 2 # withEnvelope (c :: D R2) # fc blue+--   >       <> square 2 # withEnvelope (c :: D V2 Double) # fc blue --   >     ) --   > c = circle 0.8 --   > withEnvelopeEx = sqNewEnv # centerXY # pad 1.5-withEnvelope :: (HasLinearMap (V a), Enveloped a, Monoid' m)-           => a -> QDiagram b (V a) m -> QDiagram b (V a) m+withEnvelope :: (InSpace v n a, Monoid' m, Enveloped a)+           => a -> QDiagram b v n m -> QDiagram b v n m withEnvelope = setEnvelope . getEnvelope  -- | Use the trace from some object as the trace for a diagram, in --   place of the diagram's default trace.-withTrace :: (HasLinearMap (V a), Traced a, OrderedField (Scalar (V a)), InnerSpace (V a), Monoid' m)-          => a -> QDiagram b (V a) m -> QDiagram b (V a) m+withTrace :: (InSpace v n a, Metric v, OrderedField n, Monoid' m, Traced a)+          => a -> QDiagram b v n m -> QDiagram b v n m withTrace = setTrace . getTrace  -- | @phantom x@ produces a \"phantom\" diagram, which has the same --   envelope and trace as @x@ but produces no output.-phantom :: (Backend b (V a), Typeable (V a), Enveloped a, Traced a, Monoid' m) => a -> QDiagram b (V a) m+phantom :: (InSpace v n a, Monoid' m, Enveloped a, Traced a) => a -> QDiagram b v n m phantom a = QD $ D.leafU ((inj . toDeletable . getEnvelope $ a) <> (inj . toDeletable . getTrace $ a))  -- | @pad s@ \"pads\" a diagram, expanding its envelope by a factor of@@ -101,39 +98,31 @@ --   origin, so if the origin is not centered the padding may appear --   \"uneven\".  If this is not desired, the origin can be centered --   (using, e.g., 'centerXY' for 2D diagrams) before applying @pad@.-pad :: ( Backend b v-       , InnerSpace v, OrderedField (Scalar v)-       , Monoid' m )-    => Scalar v -> QDiagram b v m -> QDiagram b v m+pad :: (Metric v, OrderedField n, Monoid' m)+    => n -> QDiagram b v n m -> QDiagram b v n m pad s d = withEnvelope (d # scale s) d  -- | @frame s@ increases the envelope of a diagram by and absolute amount @s@, --   s is in the local units of the diagram. This function is similar to @pad@, --   only it takes an absolute quantity and pre-centering should not be --   necessary.-frame :: ( Backend b v, InnerSpace v, OrderedField (Scalar v), Monoid' m)-        => Scalar v -> QDiagram b v m -> QDiagram b v m-frame s d = setEnvelope (onEnvelope t (d^.envelope)) d-  where-    t f = \x -> f x + s+frame :: (Metric v, OrderedField n, Monoid' m)+        => n -> QDiagram b v n m -> QDiagram b v n m+frame s = over envelope (onEnvelope $ \f x -> f x + s)  -- | @strut v@ is a diagram which produces no output, but with respect --   to alignment and envelope acts like a 1-dimensional segment --   oriented along the vector @v@, with local origin at its --   center. (Note, however, that it has an empty trace; for 2D struts---   with a nonempty trace see 'strutR2', 'strutX', and 'strutY' from+--   with a nonempty trace see 'strutR2' from --   "Diagrams.TwoD.Combinators".) Useful for manually creating --   separation between two diagrams. -- --   <<diagrams/src_Diagrams_Combinators_strutEx.svg#diagram=strutEx&width=300>> -- --   > strutEx = (circle 1 ||| strut unitX ||| circle 1) # centerXY # pad 1.1-strut :: ( Backend b v, Typeable v-         , InnerSpace v-         , OrderedField (Scalar v)-         , Monoid' m-         )-      => v -> QDiagram b v m+strut :: (Metric v, OrderedField n)+      => v n -> QDiagram b v n m strut v = QD $ D.leafU (inj . toDeletable $ env)   where env = translate ((-0.5) *^ v) . getEnvelope $ straight v   -- note we can't use 'phantom' here because it tries to construct a@@ -154,10 +143,9 @@ --   the cosine of the difference in angle, and leaving it unchanged --   when this factor is negative. extrudeEnvelope-  :: ( Ord (Scalar v), Num (Scalar v), AdditiveGroup (Scalar v)-     , Floating (Scalar v), HasLinearMap v, InnerSpace v, Monoid' m )-  => v -> QDiagram b v m -> QDiagram b v m-extrudeEnvelope = deformEnvelope 0.5+  :: (Metric v, OrderedField n, Monoid' m)+  => v n -> QDiagram b v n m -> QDiagram b v n m+extrudeEnvelope = deformEnvelope 1  -- | @intrudeEnvelope v d@ asymmetrically \"intrudes\" the envelope of --   a diagram away from the given direction.  All parts of the envelope@@ -167,24 +155,22 @@ --   Note that this could create strange inverted envelopes, where --   @ diameter v d < 0 @. intrudeEnvelope-  :: ( Ord (Scalar v), Num (Scalar v), AdditiveGroup (Scalar v)-     , Floating (Scalar v), HasLinearMap v, InnerSpace v, Monoid' m )-  => v -> QDiagram b v m -> QDiagram b v m-intrudeEnvelope = deformEnvelope (-0.5)+  :: (Metric v, OrderedField n, Monoid' m)+  => v n -> QDiagram b v n m -> QDiagram b v n m+intrudeEnvelope = deformEnvelope (-1)  -- Utility for extrudeEnvelope / intrudeEnvelope deformEnvelope-  :: ( Ord (Scalar v), Num (Scalar v), AdditiveGroup (Scalar v)-     , Floating (Scalar v), HasLinearMap v, InnerSpace v, Monoid' m )-  => (Scalar v) -> v -> QDiagram b v m -> QDiagram b v m-deformEnvelope s v d = setEnvelope (getEnvelope d & _Wrapping Envelope %~ deformE) d+  :: (Metric v, OrderedField n, Monoid' m)+  => n -> v n -> QDiagram b v n m -> QDiagram b v n m+deformEnvelope s v = over (envelope . _Wrapping Envelope) deformE   where-    deformE = Option . fmap deformE' . getOption+    deformE = fmap deformE'     deformE' env v'-        | dot > 0 = Max $ getMax (env v') + (dot * s) / magnitude v'+        | dp > 0    = Max $ getMax (env v') + (dp * s) / quadrance v'         | otherwise = env v'       where-        dot = v' <.> v+        dp = v' `dot` v  ------------------------------------------------------------ -- Combining two objects@@ -193,8 +179,8 @@ -- | @beneath@ is just a convenient synonym for @'flip' 'atop'@; that is, --   @d1 \`beneath\` d2@ is the diagram with @d2@ superimposed on top of --   @d1@.-beneath :: (HasLinearMap v, OrderedField (Scalar v), InnerSpace v, Monoid' m)-     => QDiagram b v m -> QDiagram b v m -> QDiagram b v m+beneath :: (Metric v, OrderedField n, Monoid' m)+     => QDiagram b v n m -> QDiagram b v n m -> QDiagram b v n m beneath = flip atop  infixl 6 `beneath`@@ -234,9 +220,18 @@ --   To get something like @beside v x1 x2@ whose local origin is --   identified with that of @x2@ instead of @x1@, use @beside --   (negateV v) x2 x1@.-beside :: (Juxtaposable a, Semigroup a) => V a -> a -> a -> a+beside :: (Juxtaposable a, Semigroup a) => Vn a -> a -> a -> a beside v d1 d2 = d1 <> juxtapose v d1 d2 +-- | Place two diagrams (or other juxtaposable objects) adjacent to+--   one another, with the second diagram placed in the direction 'd'+--   from the first.  The local origin of the resulting combined+--   diagram is the same as the local origin of the first.  See the+--   documentation of 'beside' for more information.+atDirection :: (InSpace v n a, Metric v, Floating n, Juxtaposable a, Semigroup a)+            => Direction v n -> a -> a -> a+atDirection = beside . fromDirection+ ------------------------------------------------------------ -- Combining multiple objects ------------------------------------------------------------@@ -251,7 +246,7 @@ --   > appendsEx = appends c (zip (iterateN 6 (rotateBy (1/6)) unitX) (repeat c)) --   >             # centerXY # pad 1.1 --   >   where c = circle 1-appends :: (Juxtaposable a, Monoid' a) => a -> [(V a,a)] -> a+appends :: (Juxtaposable a, Monoid' a) => a -> [(Vn a,a)] -> a appends d1 apps = d1 <> mconcat (map (\(v,d) -> juxtapose v d1 d) apps)  -- | Position things absolutely: combine a list of objects@@ -260,39 +255,17 @@ -- --   <<diagrams/src_Diagrams_Combinators_positionEx.svg#diagram=positionEx&height=300>> -----   > positionEx = position (zip (map mkPoint [-3, -2.8 .. 3]) (repeat dot))---   >   where dot       = circle 0.2 # fc black---   >         mkPoint x = p2 (x,x^2)-position :: (HasOrigin a, Monoid' a) => [(Point (V a), a)] -> a+--   > positionEx = position (zip (map mkPoint [-3, -2.8 .. 3]) (repeat spot))+--   >   where spot      = circle 0.2 # fc black+--   >         mkPoint :: Double -> P2 Double+--   >         mkPoint x = p2 (x,x*x)+position :: (InSpace v n a, HasOrigin a, Monoid' a) => [(Point v n, a)] -> a position = mconcat . map (uncurry moveTo) --- | Combine a list of diagrams (or paths) by using them to---   \"decorate\" a trail, placing the local origin of one object at---   each successive vertex of the trail.  The first vertex of the---   trail is placed at the origin.  If the trail and list of objects---   have different lengths, the extra tail of the longer one is---   ignored.-decorateTrail :: (InnerSpace (V a), OrderedField (Scalar (V a)), HasOrigin a, Monoid' a)-              => Trail (V a) -> [a] -> a-decorateTrail = decorateLocatedTrail . (`at` origin)---- | Combine a list of diagrams (or paths) by using them to---   \"decorate\" a concretely located trail, placing the local origin---   of one object at each successive vertex of the trail. If the---   trail and list of objects have different lengths, the extra tail---   of the longer one is ignored.-decorateLocatedTrail :: (InnerSpace (V a), OrderedField (Scalar (V a)), HasOrigin a, Monoid' a)-              => Located (Trail (V a)) -> [a] -> a-decorateLocatedTrail t = position . zip (trailVertices t)---- | Combine a list of diagrams (or paths) by using them to---   \"decorate\" a path, placing the local origin of one object at---   each successive vertex of the path.  If the path and list of objects---   have different lengths, the extra tail of the longer one is---   ignored.-decoratePath :: (InnerSpace (V a), OrderedField (Scalar (V a)), HasOrigin a, Monoid' a)-             => Path (V a) -> [a] -> a-decoratePath p = position . zip (concat $ pathVertices p)+-- | Curried version of @position@, takes a list of points and a list of+--   objects.+atPoints :: (InSpace v n a, HasOrigin a, Monoid' a) => [Point v n] -> [a] -> a+atPoints ps as = position $ zip ps as  -- | Methods for concatenating diagrams. data CatMethod = Cat     -- ^ Normal catenation: simply put diagrams@@ -311,9 +284,9 @@                          --   of separation, diagrams may overlap.  -- | Options for 'cat''.-data CatOpts v = CatOpts { _catMethod       :: CatMethod-                         , _sep             :: Scalar v-                         , catOptsvProxy__ :: Proxy v+data CatOpts n = CatOpts { _catMethod    :: CatMethod+                         , _sep          :: n+                         , catOptsvProxy :: Proxy n                          }  -- The reason the proxy field is necessary is that without it,@@ -327,24 +300,22 @@ -- this is not a problem when using the 'sep' lens, as its type is -- more restricted. -makeLensesWith-  ( lensRules & generateSignatures .~ False)-  ''CatOpts+makeLensesWith (lensRules & generateSignatures .~ False) ''CatOpts  -- | Which 'CatMethod' should be used: --   normal catenation (default), or distribution?-catMethod :: forall v. Lens' (CatOpts v) CatMethod+catMethod :: Lens' (CatOpts n) CatMethod  -- | How much separation should be used between successive diagrams --   (default: 0)?  When @catMethod = Cat@, this is the distance between --   /envelopes/; when @catMethod = Distrib@, this is the distance --   between /origins/.-sep :: forall v. Lens' (CatOpts v) (Scalar v)+sep :: Lens' (CatOpts n) n -instance Num (Scalar v) => Default (CatOpts v) where-  def = CatOpts { _catMethod       = Cat-                , _sep             = 0-                , catOptsvProxy__ = Proxy+instance Num n => Default (CatOpts n) where+  def = CatOpts { _catMethod    = Cat+                , _sep          = 0+                , catOptsvProxy = Proxy                 }  -- | @cat v@ positions a list of objects so that their local origins@@ -355,10 +326,8 @@ -- --   See also 'cat'', which takes an extra options record allowing --   certain aspects of the operation to be tweaked.-cat :: ( Juxtaposable a, Monoid' a, HasOrigin a-       , InnerSpace (V a), OrderedField (Scalar (V a))-       )-       => V a -> [a] -> a+cat :: (InSpace v n a, Metric v, Floating n, Juxtaposable a, Monoid' a, HasOrigin a)+       => v n -> [a] -> a cat v = cat' v def  -- | Like 'cat', but taking an extra 'CatOpts' arguments allowing the@@ -378,13 +347,53 @@ --   Note that @cat' v (with & catMethod .~ Distrib) === mconcat@ --   (distributing with a separation of 0 is the same as --   superimposing).-cat' :: ( Juxtaposable a, Monoid' a, HasOrigin a-        , InnerSpace (V a), OrderedField (Scalar (V a))-        )-     => V a -> CatOpts (V a) -> [a] -> a+cat' :: (InSpace v n a, Metric v, Floating n, Juxtaposable a, Monoid' a, HasOrigin a)+     => v n -> CatOpts n -> [a] -> a cat' v (CatOpts { _catMethod = Cat, _sep = s }) = foldB comb mempty   where comb d1 d2 = d1 <> (juxtapose v d1 d2 # moveOriginBy vs)-        vs = s *^ normalized (negateV v)+        vs = s *^ signorm (negated v)  cat' v (CatOpts { _catMethod = Distrib, _sep = s }) =-  position . zip (iterate (.+^ (s *^ normalized v)) origin)+  position . zip (iterate (.+^ (s *^ signorm v)) origin)++-- | Compose a list of diagrams using the given composition function,+--   first aligning them all according to the given alignment, /but/+--   retain the local origin of the first diagram, as it would be if+--   the composition function were applied directly.  That is,+--   @composeAligned algn comp@ is equivalent to @translate v . comp+--   . map algn@ for some appropriate translation vector @v@.+--+--   Unfortunately, this only works for diagrams (and not, say, paths)+--   because there is no most general type for alignment functions,+--   and no generic way to find out what an alignment function does to+--   the origin of things.  (However, it should be possible to make a+--   version of this function that works /specifically/ on paths, if+--   such a thing were deemed useful.)+--+--   <<diagrams/src_Diagrams_Combinators_alignedEx1.svg#diagram=alignedEx1&width=400>>+--+--   > alignedEx1 = (hsep 2 # composeAligned alignT) (map circle [1,3,5,2])+--   >            # showOrigin+--   >            # frame 0.5+--+--   <<diagrams/src_Diagrams_Combinators_alignedEx2.svg#diagram=alignedEx2&width=400>>+--+--   > alignedEx2 = (mconcat # composeAligned alignTL) [circle 1, square 1, triangle 1, pentagon 1]+--   >            # showOrigin+--   >            # frame 0.1+composeAligned+  :: (Monoid' m, Floating n, Ord n, Metric v)+  => (QDiagram b v n m -> QDiagram b v n m)    -- ^ Alignment function+  -> ([QDiagram b v n m] -> QDiagram b v n m)  -- ^ Composition function+  -> ([QDiagram b v n m] -> QDiagram b v n m)+composeAligned _ combine [] = combine []+composeAligned algn comb (d:ds) = (comb $ map algn (d:ds)) # moveOriginTo l+  where+    mss = ( (() .>> d)   -- qualify first to avoid stomping on an existing () name+          # named ()     -- Mark the origin+          # algn         -- Apply the alignment function+          )+          -- then find out what happened to the origin+        ^. subMap . _Wrapped . Control.Lens.at (toName ())+    l   = location . head . fromJust $ mss+          -- the fromJust is Justified since we put the () name in
src/Diagrams/Coordinates.hs view
@@ -1,5 +1,7 @@-{-# LANGUAGE TypeFamilies  #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Coordinates@@ -14,23 +16,12 @@  module Diagrams.Coordinates     ( (:&)(..), Coordinates(..)--    -- * Lenses for particular axes-    , HasX(..), HasY(..), HasZ(..), HasR(..)     )     where -import           Control.Lens          (Lens')--import           Diagrams.Core.Points---- | A pair of values, with a convenient infix (left-associative)---   data constructor.-data a :& b = a :& b-  deriving (Eq, Ord, Show)--infixl 7 :&-+import           Data.Kind       (Type)+import           Diagrams.Points+import           Linear          (V2 (..), V3 (..), V4 (..))  -- | Types which are instances of the @Coordinates@ class can be --   constructed using '^&' (for example, a three-dimensional vector@@ -45,13 +36,13 @@ class Coordinates c where    -- | The type of the final coordinate.-  type FinalCoord c    :: *+  type FinalCoord c    :: Type    -- | The type of everything other than the final coordinate.-  type PrevDim c       :: *+  type PrevDim c       :: Type    -- | Decomposition of @c@ into applications of ':&'.-  type Decomposition c :: *+  type Decomposition c :: Type     -- Decomposition c = Decomposition (PrevDim c) :& FinalCoord c  (essentially)    -- | Construct a value of type @c@ by providing something of one@@ -60,7 +51,7 @@   --   -- @   -- 2 ^& 3 :: P2-  -- 3 ^& 5 ^& 6 :: R3+  -- 3 ^& 5 ^& 6 :: V3   -- @   --   --   Note that @^&@ is left-associative.@@ -76,6 +67,22 @@  infixl 7 ^& +-- | A pair of values, with a convenient infix (left-associative)+--   data constructor.+data a :& b = a :& b+  deriving (Eq, Ord, Show)++infixl 7 :&++-- Instance for :& (the buck stops here)+instance Coordinates (a :& b) where+  type FinalCoord (a :& b) = b+  type PrevDim (a :& b) = a+  type Decomposition (a :& b) = a :& b+  x ^& y                    = x :& y+  coords (x :& y)           = x :& y++ -- Some standard instances for plain old tuples  instance Coordinates (a,b) where@@ -83,7 +90,7 @@   type PrevDim (a,b)       = a   type Decomposition (a,b) = a :& b -  x ^& y                    = (x,y)+  x ^& y                   = (x,y)   coords (x,y)             = x :& y  instance Coordinates (a,b,c) where@@ -99,30 +106,40 @@   type PrevDim (a,b,c,d)       = (a,b,c)   type Decomposition (a,b,c,d) = Decomposition (a,b,c) :& d -  (w,x,y)  ^& z                  = (w,x,y,z)+  (w,x,y)  ^& z                = (w,x,y,z)   coords (w,x,y,z)             = coords (w,x,y) :& z -instance Coordinates v => Coordinates (Point v) where-  type FinalCoord (Point v)    = FinalCoord v-  type PrevDim (Point v)       = PrevDim v-  type Decomposition (Point v) = Decomposition v+instance Coordinates (v n) => Coordinates (Point v n) where+  type FinalCoord (Point v n)    = FinalCoord (v n)+  type PrevDim (Point v n)       = PrevDim (v n)+  type Decomposition (Point v n) = Decomposition (v n) -  x ^& y        = P (x ^& y)+  x ^& y       = P (x ^& y)   coords (P v) = coords v --- | The class of types with at least one coordinate, called _x.-class HasX t where-    _x :: Lens' t Double+-- instances for linear --- | The class of types with at least two coordinates, the second called _y.-class HasY t where-    _y :: Lens' t Double+instance Coordinates (V2 n) where+  type FinalCoord (V2 n)    = n+  type PrevDim (V2 n)       = n+  type Decomposition (V2 n) = n :& n --- | The class of types with at least three coordinates, the third called _z.-class HasZ t where-    _z :: Lens' t Double+  x ^& y          = V2 x y+  coords (V2 x y) = x :& y --- | The class of types with a single length coordinate _r.  _r is--- magnitude of a vector, or the distance from the origin of a point.-class HasR t where-    _r :: Lens' t Double+instance Coordinates (V3 n) where+  type FinalCoord (V3 n)    = n+  type PrevDim (V3 n)       = V2 n+  type Decomposition (V3 n) = n :& n :& n++  V2 x y ^& z       = V3 x y z+  coords (V3 x y z) = x :& y :& z++instance Coordinates (V4 n) where+  type FinalCoord (V4 n)    = n+  type PrevDim (V4 n)       = V3 n+  type Decomposition (V4 n) = n :& n :& n :& n++  V3 x y z ^& w       = V4 x y z w+  coords (V4 x y z w) = x :& y :& z :& w+
src/Diagrams/CubicSpline.hs view
@@ -1,6 +1,10 @@+{-# LANGUAGE ConstraintKinds  #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies     #-}+{-# LANGUAGE TypeOperators    #-}+ {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.CubicSpline@@ -8,31 +12,43 @@ -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com ----- A /cubic spline/ is a smooth, connected sequence of cubic curves--- passing through a given sequence of points.  This module provides--- the 'cubicSpline' method, which can be used to create closed or--- open cubic splines from a list of points.  For access to the--- internals of the spline generation algorithm (including in--- particular a solver for cyclic tridiagonal systems of linear--- equations), see "Diagrams.CubicSpline.Internal".+-- A /cubic spline/ is a smooth, connected sequence of cubic curves.+-- This module provides two methods for constructing splines. --+-- The 'cubicSpline' method can be used to create closed or open cubic+-- splines from a list of points. The resulting splines /pass through/+-- all the control points, but depend on the control points in a+-- "global" way (that is, changing one control point may alter the+-- entire curve).  For access to the internals of the spline+-- generation algorithm, see "Diagrams.CubicSpline.Internal".+--+-- 'bspline' creates a cubic B-spline, which starts and ends at the+-- first and last control points, but does not necessarily pass+-- through any of the other control points.  It depends on the control+-- points in a "local" way, that is, changing one control point will+-- only affect a local portion of the curve near that control point.+-- ----------------------------------------------------------------------------- module Diagrams.CubicSpline        (          -- * Constructing paths from cubic splines          cubicSpline+       , BSpline+       , bspline        ) where +import           Control.Lens                  (view)+ import           Diagrams.Core-import           Diagrams.Core.Points+import           Diagrams.CubicSpline.Boehm import           Diagrams.CubicSpline.Internal import           Diagrams.Located              (Located, at, mapLoc) import           Diagrams.Segment import           Diagrams.Trail import           Diagrams.TrailLike            (TrailLike (..)) -import           Data.AffineSpace.Point-import           Data.VectorSpace+import           Linear.Affine+import           Linear.Metric  -- | Construct a spline path-like thing of cubic segments from a list of --   vertices, with the first vertex as the starting point.  The first@@ -41,22 +57,23 @@ --   <<diagrams/src_Diagrams_CubicSpline_cubicSplineEx.svg#diagram=cubicSplineEx&width=600>> -- --   > pts = map p2 [(0,0), (2,3), (5,-2), (-4,1), (0,3)]---   > dot = circle 0.2 # fc blue # lw none---   > mkPath closed = position (zip pts (repeat dot))+--   > spot = circle 0.2 # fc blue # lw none+--   > mkPath closed = position (zip pts (repeat spot)) --   >              <> cubicSpline closed pts --   > cubicSplineEx = (mkPath False ||| strutX 2 ||| mkPath True) --   >               # centerXY # pad 1.1 -- --   For more information, see <http://mathworld.wolfram.com/CubicSpline.html>.-cubicSpline :: (TrailLike t, Fractional (V t)) => Bool -> [Point (V t)] -> t-cubicSpline closed [] = trailLike . closeIf closed $ emptyLine `at` origin-cubicSpline closed ps = flattenBeziers . map f . solveCubicSplineCoefficients closed . map unPoint $ ps+cubicSpline :: (V t ~ v, N t ~ n, TrailLike t, Fractional (v n)) => Bool -> [Point v n] -> t+cubicSpline closed []  = trailLike . closeIf closed $ emptyLine `at` origin+cubicSpline closed [p] = trailLike . closeIf closed $ emptyLine `at` p+cubicSpline closed ps  = flattenBeziers . map f . solveCubicSplineCoefficients closed . map (view lensP) $ ps   where     f [a,b,c,d] = [a, (3*a+b)/3, (3*a+2*b+c)/3, a+b+c+d]     flattenBeziers bs@((b:_):_)       = trailLike . closeIf closed $ lineFromSegments (map bez bs) `at` P b     bez [a,b,c,d] = bezier3 (b - a) (c - a) (d - a) -closeIf :: (InnerSpace v, OrderedField (Scalar v))-        => Bool -> Located (Trail' Line v) -> Located (Trail v)+closeIf :: (Metric v, OrderedField n)+        => Bool -> Located (Trail' Line v n) -> Located (Trail v n) closeIf c = mapLoc (if c then wrapLoop . glueLine else wrapLine)
+ src/Diagrams/CubicSpline/Boehm.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies     #-}+{-# LANGUAGE TypeOperators    #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.CubicSpline.Boehm+-- Copyright   :  (c) 2015 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Boehm's algorithm for converting a cubic B-spline into a sequence+-- of cubic Bezier curves.+--+-- See+--+--   * Thomas W. Sederberg, /An Introduction to B-Spline Curves/,+--     <http://web.archive.org/web/20120227050519/http://tom.cs.byu.edu/~455/bs.pdf>+--+--   * Lyle Ramshaw, /Blossoming: A Connect-the-Dots Approach to Splines/,+--     <http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-19.pdf>+--+-----------------------------------------------------------------------------+module Diagrams.CubicSpline.Boehm+       ( BSpline+       , bsplineToBeziers+       , bspline+       ) where++import           Data.List          (sort, tails)+import           Diagrams.Core      (N, Point, V, origin)+import           Diagrams.Located   (at, loc, unLoc)+import           Diagrams.Segment   (FixedSegment (..), fromFixedSeg)+import           Diagrams.TrailLike (TrailLike, fromLocSegments)+import           Diagrams.Util      (iterateN)+import           Linear.Vector      (Additive)+import           Linear.Vector.Compat (lerp)++type BSpline v n = [Point v n]++-- | @affineCombo a b t x y@ computes an affine combination of x and y+--   which lies at parameter t, if x has parameter a and y has parameter b.+--   The usual @lerp@ arises by giving x parameter 0 and y parameter 1.+affineCombo :: (Additive f, Fractional a) => a -> a -> a -> f a -> f a -> f a+affineCombo a b t = lerp ((t-a)/(b-a))++-- | @windows k xs@ yields all the length-@k@ windows from @xs@, e.g.+--   @windows 3 [a,b,c,d,e] == [[a,b,c], [b,c,d], [c,d,e]]@.+windows :: Int -> [a] -> [[a]]+windows k = takeWhile ((==k) . length) . map (take k) . tails++-- | @extend k xs@ extends @xs@ on both ends by prepending @k@ copies+-- of its head and appending @k@ copies of its last element.  For example,+-- @extend 2 [1..5] == [1,1,1,2,3,4,5,5,5]@.+extend :: Int -> [a] -> [a]+extend k xs = replicate k (head xs) ++ xs ++ replicate k (last xs)++-- | A "polar point" is a point along with three knot values.+--   We consider the "blossom" of a cubic spline, a 3-ary symmetric+--   polynomial; a polar point consists of 3 values paired with the+--   output of the blossom at those input values.  Blossoms have nice+--   affine properties so this makes it easy to keep track of how+--   points may be combined to yield other points of interest.+--+--   Invariant: knot values are in nondecreasing order.+data PolarPt v n = PP { unPP :: Point v n, _knots :: [n] }++mkPolarPt :: Ord n => Point v n -> [n] -> PolarPt v n+mkPolarPt pt kts = PP pt (sort kts)++-- | Precondition: the knots of the two polar points overlap, like abc+--   and bcd.  The @Int@ should be 0 or 1, indicating which knot to+--   replicate (0 means to replicate b, yielding bbc, 1 means to+--   replicate c, yielding bcc).+combine+  :: (Additive v, Fractional n, Ord n)+  => Int -> PolarPt v n -> PolarPt v n -> PolarPt v n+combine k (PP pt1 kts1) (PP pt2 kts2)+  = mkPolarPt+      (affineCombo (head kts1) (last kts2) newKt pt1 pt2)+      (newKt : drop 1 kts1)+  where+    newKt = kts2 !! k++-- | Convert a uniform cubic B-spline to a sequence of cubic beziers.+--   (/Uniform/ refers to the fact that the knots are assumed to be+--   evenly spaced, with no duplicates.)  The knots at the end are+--   replicated so the cubic spline begins and ends at the first and+--   last control points, tangent to the line from the end control+--   point to the next.+bsplineToBeziers+  :: (Additive v, Fractional n, Num n, Ord n)+  => BSpline v n+  -> [FixedSegment v n]+bsplineToBeziers controls = beziers+  where+    n                            = length controls+    numKnots                     = n + 2+    knots                        = iterateN numKnots (+1/(fromIntegral numKnots - 1)) 0++    -- The control points are P(a,b,c), P(b,c,d), P(c,d,e), and so on.+    controls' = zipWith mkPolarPt (extend 2 controls) (windows 3 $ extend 2 knots)++    -- The bezier internal control points are affine combinations of+    -- the spline control points.+    bezierControls        = map combineC (windows 2 controls')+    combineC [pabc, pbcd] = (combine 0 pabc pbcd, combine 1 pabc pbcd)+    combineC _ = error "combineC must be called on a list of length 2"++    -- The bezier end points are affine combinations of the bezier+    -- control points.+    bezierEnds                   = map combineE (windows 2 bezierControls)+    combineE [(_,pabb),(pbbc,_)] = combine 0 pabb pbbc+    combineE _ = error "combineE must be called on a list of length 2"++    -- Finally, we actually put together the generated bezier segments.+    beziers                      = zipWith mkBezier (drop 1 bezierControls) (windows 2 bezierEnds)+      where+        mkBezier (paab,pabb) [paaa,pbbb]+          = FCubic (unPP paaa) (unPP paab) (unPP pabb) (unPP pbbb)+        mkBezier _ _ = error "mkBezier must be called on a list of length 2"++    -- Note that the above algorithm works in any dimension but is+    -- very specific to *cubic* splines.  This can of course be+    -- generalized to higher degree splines but keeping track of+    -- everything gets a bit more complicated; to be honest I am not+    -- quite sure how to do it.++-- | Generate a uniform cubic B-spline from the given control points.+--   The spline starts and ends at the first and last control points,+--   and is tangent to the line to the second(-to-last) control point.+--   It does not necessarily pass through any of the other control+--   points.+--+--   <<diagrams/src_Diagrams_CubicSpline_Boehm_bsplineEx.svg#diagram=bsplineEx&width=300>>+--+--   > pts = map p2 [(0,0), (2,3), (5,-2), (-4,1), (0,3)]+--   > spot = circle 0.2 # fc blue # lw none+--   > bsplineEx = mconcat+--   >   [ position (zip pts (repeat spot))+--   >   , bspline pts+--   >   ]+--   >   # frame 0.5++bspline :: (TrailLike t, V t ~ v, N t ~ n) => BSpline v n -> t+bspline = fromLocSegments . fixup . map fromFixedSeg . bsplineToBeziers+  where+    fixup []        = [] `at` origin+    fixup (b1:rest) = (unLoc b1 : map unLoc rest) `at` loc b1
src/Diagrams/CubicSpline/Internal.hs view
@@ -1,7 +1,3 @@-{-# LANGUAGE TypeFamilies-           , FlexibleContexts-  #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.CubicSpline@@ -18,76 +14,19 @@ module Diagrams.CubicSpline.Internal        (          -- * Solving for spline coefficents-         solveTriDiagonal-       , solveCyclicTriDiagonal-       , solveCubicSplineDerivatives+         solveCubicSplineDerivatives        , solveCubicSplineDerivativesClosed        , solveCubicSplineCoefficients        ) where -import Data.List---- | Solves a system of the form 'A*X=D' for 'x' where 'A' is an ---   'n' by 'n' matrix with 'bs' as the main diagonal and ---   'as' the diagonal below and 'cs' the diagonal above.---   See: <http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm>-solveTriDiagonal :: Fractional a => [a] -> [a] -> [a] -> [a] -> [a]-solveTriDiagonal as (b0:bs) (c0:cs) (d0:ds) = h cs' ds'-  where-    cs' = c0 / b0 : f cs' as bs cs-    f _ [_] _ _ = []-    f (c':cs') (a:as) (b:bs) (c:cs) = c / (b - c' * a) : f cs' as bs cs-    f _ _ _ _ = error "solveTriDiagonal.f: impossible!"--    ds' = d0 / b0 : g ds' as bs cs' ds -    g _ [] _ _ _ = []-    g (d':ds') (a:as) (b:bs) (c':cs') (d:ds) = (d - d' * a)/(b - c' * a) : g ds' as bs cs' ds-    g _ _ _ _ _ = error "solveTriDiagonal.g: impossible!"-    -    h _ [d] = [d]-    h (c:cs) (d:ds) = let xs@(x:_) = h cs ds in d - c * x : xs-    h _ _ = error "solveTriDiagonal.h: impossible!"--solveTriDiagonal _ _ _ _ = error "arguments 2,3,4 to solveTriDiagonal must be nonempty"---- Helper that applies the passed function only to the last element of a list-modifyLast :: (a -> a) -> [a] -> [a]-modifyLast _ []     = []-modifyLast f [a]    = [f a]-modifyLast f (a:as) = a : modifyLast f as---- Helper that builds a list of length n of the form: '[s,m,m,...,m,m,e]'-sparseVector :: Int -> a -> a -> a -> [a]-sparseVector n s m e -    | n < 1     = []-    | otherwise = s : h (n - 1)-  where -    h 1 = [e]-    h n = m : h (n - 1)-    --- | Solves a system similar to the tri-diagonal system using a special case---   of the Sherman-Morrison formula <http://en.wikipedia.org/wiki/Sherman-Morrison_formula>.---   This code is based on /Numerical Recpies in C/'s @cyclic@ function in section 2.7.-solveCyclicTriDiagonal :: Fractional a => [a] -> [a] -> [a] -> [a] -> a -> a -> [a]-solveCyclicTriDiagonal as (b0:bs) cs ds alpha beta = zipWith ((+) . (fact *)) zs xs-  where-    l = length ds-    gamma = -b0-    us = sparseVector l gamma 0 alpha-    -    bs' = (b0 - gamma) : modifyLast (subtract (alpha*beta/gamma)) bs-    -    xs@(x:_) = solveTriDiagonal as bs' cs ds-    zs@(z:_) = solveTriDiagonal as bs' cs us-    -    fact = -(x + beta * last xs / gamma) / (1.0 + z + beta * last zs / gamma)+import           Diagrams.Solve.Tridiagonal -solveCyclicTriDiagonal _ _ _ _ _ _ = error "second argument to solveCyclicTriDiagonal must be nonempty"+import           Data.List  -- | Use the tri-diagonal solver with the appropriate parameters for an open cubic spline. solveCubicSplineDerivatives :: Fractional a => [a] -> [a] solveCubicSplineDerivatives (x:xs) = solveTriDiagonal as bs as ds-  where +  where     as = replicate (l - 1) 1     bs = 2 : replicate (l - 2) 4 ++ [2]     l  = length ds@@ -99,7 +38,7 @@ -- | Use the cyclic-tri-diagonal solver with the appropriate parameters for a closed cubic spline. solveCubicSplineDerivativesClosed :: Fractional a => [a] -> [a] solveCubicSplineDerivativesClosed xs = solveCyclicTriDiagonal as bs as ds 1 1-  where +  where     as = replicate (l - 1) 1     bs = replicate l 4     l  = length xs@@ -109,11 +48,11 @@  -- | Use the cyclic-tri-diagonal solver with the appropriate parameters for a closed cubic spline. solveCubicSplineCoefficients :: Fractional a => Bool -> [a] -> [[a]]-solveCubicSplineCoefficients closed xs = +solveCubicSplineCoefficients closed xs =     [ [x,d,3*(x1-x)-2*d-d1,2*(x-x1)+d+d1]     | (x,x1,d,d1) <- zip4 xs' (tail xs') ds' (tail ds')     ]-  where +  where     ds | closed    = solveCubicSplineDerivativesClosed xs        | otherwise = solveCubicSplineDerivatives xs     close as | closed    = as ++ [head as]
src/Diagrams/Deform.hs view
@@ -1,19 +1,22 @@-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE GADTs                #-}-{-# LANGUAGE ScopedTypeVariables  #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} -module Diagrams.Deform (Deformation(..), Deformable(..), asDeformation) where+module Diagrams.Deform+       ( Deformation(..)+       , Deformable(..)+       , asDeformation+       ) where -import           Control.Lens        (under, _Unwrapped)-import           Data.AffineSpace-import           Data.Basis-import           Data.MemoTrie+import           Control.Lens        (mapped, over, _Wrapped) import           Data.Monoid         hiding ((<>)) import           Data.Semigroup-import           Data.VectorSpace+import           Prelude  import           Diagrams.Core import           Diagrams.Located@@ -22,97 +25,105 @@ import           Diagrams.Segment import           Diagrams.Trail +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ ------------------------------------------------------------ -- Deformations  -- | @Deformations@ are a superset of the affine transformations--- represented by the 'Transformation' type.  In general they are not--- invertable.  @Deformation@s include projective transformations.--- @Deformation@ can represent other functions from points to points--- which are "well-behaved", in that they do not introduce small wiggles.-data Deformation v = Deformation (Point v -> Point v)+--   represented by the 'Transformation' type.  In general they are not+--   invertible.  @Deformation@s include projective transformations.+--   @Deformation@ can represent other functions from points to points+--   which are "well-behaved", in that they do not introduce small wiggles.+newtype Deformation v u n = Deformation (Point v n -> Point u n) -instance Semigroup (Deformation v) where-    (Deformation p1) <> (Deformation p2) = Deformation (p1 . p2)+instance Semigroup (Deformation v v n) where+  (Deformation p1) <> (Deformation p2) = Deformation (p1 . p2) -instance Monoid (Deformation v) where-    mappend = (<>)-    mempty = Deformation id+instance Monoid (Deformation v v n) where+  mappend = (<>)+  mempty = Deformation id -class Deformable a where-    -- | @deform' epsilon d a@ transforms @a@ by the deformation @d@.-    -- If the type of @a@ is not closed under projection, approximate-    -- to accuracy @epsilon@.-    deform' :: Scalar (V a) -> Deformation (V a) -> a -> a+class Deformable a b where+  -- | @deform' epsilon d a@ transforms @a@ by the deformation @d@.+  -- If the type of @a@ is not closed under projection, approximate+  -- to accuracy @epsilon@.+  deform' :: N a -> Deformation (V a) (V b) (N a) -> a -> b -    -- | @deform d a@ transforms @a@ by the deformation @d@.-    -- If the type of @a@ is not closed under projection, @deform@-    -- should call @deform'@ with some reasonable default value of-    -- @epsilon@.-    deform  :: Deformation (V a) -> a -> a+  -- | @deform d a@ transforms @a@ by the deformation @d@.+  -- If the type of @a@ is not closed under projection, @deform@+  -- should call @deform'@ with some reasonable default value of+  -- @epsilon@.+  deform :: Deformation (V a) (V b) (N a) -> a -> b  -- | @asDeformation@ converts a 'Transformation' to a 'Deformation' by -- discarding the inverse transform.  This allows reusing -- @Transformation@s in the construction of @Deformation@s.-asDeformation-  ::  ( HasTrie (Basis v), HasBasis v) => Transformation v -> Deformation v-asDeformation t = Deformation f' where-      f' = papply t+asDeformation :: (Additive v, Num n) => Transformation v n -> Deformation v v n+asDeformation t = Deformation (papply t)  ------------------------------------------------------------ -- Instances -instance Deformable (Point v) where-    deform' = const deform-    deform (Deformation l) = l+instance r ~ Point u n => Deformable (Point v n) r where+  deform' = const deform +  deform (Deformation l) = l+ -- | Cubic curves are not closed under perspective projections. -- Therefore @Segment@s are not an instance of Deformable.  However, -- the deformation of a @Segment@ can be approximated to arbitrary -- precision by a series of @Segment@s.  @deformSegment@ does this, -- which allows types built from lists of @Segment@s to themselves be -- @Deformable@.-deformSegment :: (VectorSpace v, InnerSpace v, s ~ Scalar v, Ord s, Fractional s, Floating s) =>-                  s -> Deformation v -> FixedSegment v -> [FixedSegment v]-deformSegment epsilon t s-    | goodEnough epsilon t s = [approx t s]-    | otherwise  = concatMap (deformSegment epsilon t) [s1, s2]+deformSegment :: (Metric v, Metric u, OrderedField n)+   => n -> Deformation v u n -> FixedSegment v n -> [FixedSegment u n]+deformSegment epsilon t = go (0::Int)   where-    (s1, s2) = splitAtParam s 0.5+    go n s+      | n == 100               = [approx t s]+      | goodEnough epsilon t s = [approx t s]+      | otherwise              = concatMap (go (n+1)) [s1, s2]+      where+        (s1, s2) = splitAtParam s 0.5+-- deformSegment epsilon t s+--     | goodEnough epsilon t s = [approx t s]+--     | otherwise              = concatMap (deformSegment epsilon t) [s1, s2]+--   where+--     (s1, s2) = splitAtParam s 0.5 -approx :: (VectorSpace v, InnerSpace v, s ~ Scalar v, Ord s, Fractional s, Floating s) =>-          Deformation v -> FixedSegment v -> FixedSegment v-approx t (FLinear p0 p1) = FLinear (deform t p0) (deform t p1)-approx t (FCubic p0 c1 c2 p1) = FCubic (f p0) (f c1) (f c2) (f p1) where-      f = deform t+approx :: Deformation v u n -> FixedSegment v n -> FixedSegment u n+approx t (FLinear p0 p1)      = FLinear (deform t p0) (deform t p1)+approx t (FCubic p0 c1 c2 p1) = FCubic (f p0) (f c1) (f c2) (f p1)+  where f = deform t -goodEnough :: (VectorSpace v, InnerSpace v, s ~ Scalar v, Ord s, Fractional s, Floating s) =>-              s -> Deformation v -> FixedSegment v -> Bool+goodEnough :: (Metric v, Metric u, OrderedField n) => n -> Deformation v u n -> FixedSegment v n -> Bool goodEnough e t s =-    all (< e) [magnitude $ deform t (s `atParam` u) .-. approx t s `atParam` u+    all (< e) [norm $ deform t (s `atParam` u) .-. approx t s `atParam` u               | u <- [0.25, 0.5, 0.75]] -instance (VectorSpace v, InnerSpace v,-          s ~ Scalar v, Ord s, Fractional s, Floating s, Show s, Show v) =>-         Deformable (Located (Trail v)) where-             deform' eps p t-                 | isLine $ unLoc t  = line `at` p0-                 | otherwise = glueTrail line `at` p0-               where-                 segs = concatMap (deformSegment eps p) $ fixTrail t-                 p0 = case segs of-                     (FLinear start _:_) -> start-                     (FCubic start _ _ _:_) -> start-                     _      -> loc t  -- default in case of empty trail-                 line = trailFromSegments $ map (unLoc . fromFixedSeg) segs-             deform p t = deform' (0.01 * extent) p t where-                           -- estimate the "size" of the Trail' as-                           -- the maximum distance to any vertex-                extent = maximum . map dist . trailVertices $ t-                dist pt = magnitude $ pt .-. loc t+instance (Metric v, Metric u, OrderedField n, r ~ Located (Trail u n))+    => Deformable (Located (Trail v n)) r where+  deform' eps p t+    | isLine $ unLoc t  = line `at` p0+    | otherwise = glueTrail line `at` p0+    where+      segs = concatMap (deformSegment eps p) $ fixTrail t+      p0 = case segs of+             (FLinear start _:_)    -> start+             (FCubic start _ _ _:_) -> start+             _                      -> deform p (loc t)+      line = trailFromSegments $ map (unLoc . fromFixedSeg) segs -instance (VectorSpace v, InnerSpace v,-          s ~ Scalar v, Ord s, Fractional s, Floating s, Show s, Show v) =>-         Deformable (Path v) where-             deform' eps p = under _Unwrapped $ map (deform' eps p)-             deform p = under _Unwrapped $ map (deform p)+  deform p t = deform' (0.01 * extent) p t+    where+      -- estimate the "size" of the Trail' as+      -- the maximum distance to any vertex+      extent = maximum . map dist . trailVertices $ t+      dist pt = norm $ pt .-. loc t++instance (Metric v, Metric u, OrderedField n, r ~ Path u n) => Deformable (Path v n) r where+  deform' eps p = over (_Wrapped . mapped) (deform' eps p)+  deform p      = over (_Wrapped . mapped) (deform p)
+ src/Diagrams/Direction.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE DeriveFunctor        #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE UndecidableInstances #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.Direction+-- Copyright   :  (c) 2014 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Type for representing directions, polymorphic in vector space+--+-----------------------------------------------------------------------------++module Diagrams.Direction+       ( Direction+       , _Dir+       , direction, dir, fromDirection, fromDir+       , angleBetweenDirs+       , dirBetween+       ) where++import           Control.Lens   (Iso', iso)++import           Diagrams.Angle+import           Diagrams.Core++import           Linear.Affine+import           Linear.Metric+import           Linear.Vector++--------------------------------------------------------------------------------+-- Direction++-- | A vector is described by a @Direction@ and a magnitude.  So we+-- can think of a @Direction@ as a vector that has forgotten its+-- magnitude.  @Direction@s can be used with 'fromDirection' and the+-- lenses provided by its instances.+newtype Direction v n = Dir (v n)+  deriving (Read, Show, Eq, Ord, Functor) -- todo: special instances++type instance V (Direction v n) = v+type instance N (Direction v n) = n++instance (V (v n) ~ v, N (v n) ~ n, Transformable (v n)) => Transformable (Direction v n) where+  transform t (Dir v) = Dir (transform t v)++instance HasTheta v => HasTheta (Direction v) where+  _theta = _Dir . _theta++instance HasPhi v => HasPhi (Direction v) where+  _phi = _Dir . _phi++-- | _Dir is provided to allow efficient implementations of functions+--   in particular vector-spaces, but should be used with care as it+--   exposes too much information.+_Dir :: Iso' (Direction v n) (v n)+_Dir = iso (\(Dir v) -> v) Dir++-- | @direction v@ is the direction in which @v@ points.  Returns an+--   unspecified value when given the zero vector as input.+direction :: v n -> Direction v n+direction = Dir++-- | Synonym for 'direction'.+dir :: v n -> Direction v n+dir = Dir++-- | @fromDirection d@ is the unit vector in the direction @d@.+fromDirection :: (Metric v, Floating n) => Direction v n -> v n+fromDirection (Dir v) = signorm v++-- | Synonym for 'fromDirection'.+fromDir :: (Metric v, Floating n) => Direction v n -> v n+fromDir (Dir v) = signorm v++-- | compute the positive angle between the two directions in their common plane+angleBetweenDirs :: (Metric v, Floating n, Ord n)+  => Direction v n -> Direction v n -> Angle n+angleBetweenDirs d1 d2 = angleBetween (fromDirection d1) (fromDirection d2)++-- | @dirBetween p q@ returns the direction from @p@ to @q@.+dirBetween :: (Additive v, Num n) => Point v n -> Point v n -> Direction v n+dirBetween p q = dir $ q .-. p
+ src/Diagrams/LinearMap.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE ImpredicativeTypes    #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.LinearMap+-- Copyright   :  (c) 2014-2015 diagrams team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Linear maps. Unlike 'Transformation's these are not restricted to the+-- same space. In practice these are used for projections in+-- "Diagrams.ThreeD.Projection". Unless you want to work with+-- projections you're probably better off using 'Diagrams.Transform'.+--+-- Currently only path-like things can be projected. In the future we+-- hope to support projecting diagrams.+--+-----------------------------------------------------------------------------++module Diagrams.LinearMap+  ( -- * Linear maps+    LinearMap (..)+  , LinearMappable (..)+    -- ** Applying linear maps+  , linmap++    -- * Affine maps+  , AffineMap (..)+  , AffineMappable (..)++    -- ** Constructing affine maps+  , mkAffineMap+  , toAffineMap+  ) where++import           Control.Lens+import           Data.FingerTree         as FT+import qualified Data.Foldable           as F++import           Diagrams.Core+import           Diagrams.Core.Transform+import           Diagrams.Located+import           Diagrams.Path+import           Diagrams.Segment+import           Diagrams.Trail          hiding (offset)++import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+++-- | Type for holding linear maps. Note that these are not affine transforms so+--   attemping apply a translation with 'LinearMap' will likely produce incorrect+--   results.+newtype LinearMap v u n = LinearMap { lapply :: v n -> u n }++toLinearMap :: Transformation v n -> LinearMap v v n+toLinearMap (Transformation (m :-: _) _ _) = LinearMap m++-- | Class of things that have vectors that can be mapped over.+class LinearMappable a b where+  -- | Apply a linear map to an object. If the map is not linear,+  --   behaviour will likely be wrong.+  vmap :: (Vn a -> Vn b) -> a -> b+  -- this uses a function instead of LinearMap so we can also use this+  -- class to change number types++-- Note: instances need to be of the form+--+-- r ~ A u m => LinearMappable (A v n) r+--+-- so ghc knows there's only one possible result from calling vmap.++-- | Apply a linear map.+linmap :: (InSpace v n a, LinearMappable a b, N b ~ n)+     => LinearMap v (V b) n -> a -> b+linmap = vmap . lapply++instance r ~ Offset c u m => LinearMappable (Offset c v n) r where+  vmap f (OffsetClosed v) = OffsetClosed (f v)+  vmap _ OffsetOpen       = OffsetOpen+  {-# INLINE vmap #-}++instance r ~ Segment c u m => LinearMappable (Segment c v n) r where+  vmap f (Linear offset)      = Linear (vmap f offset)+  vmap f (Cubic v1 v2 offset) = Cubic (f v1) (f v2) (vmap f offset)+  {-# INLINE vmap #-}++instance (Metric v, Metric u, OrderedField n, OrderedField m, r ~ SegTree u m)+    => LinearMappable (SegTree v n) r where+  vmap f = over _Wrapped (fmap' (vmap f))+  {-# INLINE vmap #-}++instance (Metric v, Metric u, OrderedField n, OrderedField m, r ~ Trail' l u m)+    => LinearMappable (Trail' l v n) r where+  vmap f (Line st)        = Line (vmap f st)+  vmap f (Loop st offset) = Loop (vmap f st) (vmap f offset)+  {-# INLINE vmap #-}++instance (Metric v, Metric u, OrderedField n, OrderedField m, r ~ Trail u m)+    => LinearMappable (Trail v n) r where+  vmap f (Trail (Line st))        = Trail $ Line (vmap f st)+  vmap f (Trail (Loop st offset)) = Trail $ Loop (vmap f st) (vmap f offset)+  {-# INLINE vmap #-}++instance LinearMappable (Point v n) (Point u m) where+  vmap f (P v) = P (f v)+  {-# INLINE vmap #-}++instance r ~ FixedSegment u m => LinearMappable (FixedSegment v n) r where+  vmap f (FLinear p0 p1)      = FLinear (vmap f p0) (vmap f p1)+  vmap f (FCubic p0 p1 p2 p3) = FCubic (vmap f p0) (vmap f p1)+                                       (vmap f p2) (vmap f p3)+  {-# INLINE vmap #-}++instance (LinearMappable a b, r ~ Located b) => LinearMappable (Located a) r where+  vmap f (Loc p a) = Loc (vmap f p) (vmap f a)+  {-# INLINE vmap #-}++instance (Metric v, Metric u, OrderedField n, OrderedField m, r ~ Path u m)+    => LinearMappable (Path v n) r where+  vmap f = _Wrapped . mapped %~ vmap f+  {-# INLINE vmap #-}++-- | Affine linear maps. Unlike 'Transformation' these do not have to be+--   invertible so we can map between spaces.+data AffineMap v u n = AffineMap (LinearMap v u n) (u n)++-- | Make an affine map from a linear function and a translation.+mkAffineMap :: (v n -> u n) -> u n -> AffineMap v u n+mkAffineMap f = AffineMap (LinearMap f)++toAffineMap :: Transformation v n -> AffineMap v v n+toAffineMap t = AffineMap (toLinearMap t) (transl t)++class (LinearMappable a b, N a ~ N b) => AffineMappable a b where+  -- | Affine map over an object. Has a default implimentation of only+  --   applying the linear map+  amap :: (Additive (V a), F.Foldable (V a), Additive (V b), Num (N b))+       => AffineMap (V a) (V b) (N b) -> a -> b+  amap (AffineMap f _) = linmap f+  {-# INLINE amap #-}++instance r ~ Offset c u n => AffineMappable (Offset c v n) r+instance r ~ Segment c u n => AffineMappable (Segment c v n) r+instance (Metric v, Metric u, OrderedField n, r ~ SegTree u n) => AffineMappable (SegTree v n) r+instance (Metric v, Metric u, OrderedField n, r ~ Trail' l u n) => AffineMappable (Trail' l v n) r+instance (Metric v, Metric u, OrderedField n, r ~ Trail u n) => AffineMappable (Trail v n) r++instance (Additive v, Num n, r ~ Point u n) => AffineMappable (Point v n) r where+  amap (AffineMap f v) p = linmap f p .+^ v+  {-# INLINE amap #-}++instance r ~ FixedSegment u n => AffineMappable (FixedSegment v n) r where+  amap m (FLinear p0 p1)      = FLinear (amap m p0) (amap m p1)+  amap m (FCubic p0 p1 p2 p3) = FCubic (amap m p0) (amap m p1) (amap m p2) (amap m p3)+  {-# INLINE amap #-}++instance (LinearMappable a b, N a ~ N b, r ~ Located b) => AffineMappable (Located a) r where+  amap m@(AffineMap l _) (Loc p x) = Loc (amap m p) (linmap l x)+  {-# INLINE amap #-}++instance (Metric v, Metric u, OrderedField n, r ~ Path u n)+    => AffineMappable (Path v n) r where+  amap m = _Wrapped . mapped %~ amap m+  {-# INLINE amap #-}
src/Diagrams/Located.hs view
@@ -1,11 +1,15 @@-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE StandaloneDeriving   #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Located--- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2013-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -18,22 +22,25 @@ -----------------------------------------------------------------------------  module Diagrams.Located-    ( Located-    , at, viewLoc, unLoc, loc, mapLoc, located+    ( Located (..)+    , at, viewLoc, mapLoc, located, _loc     )     where -import           Control.Lens            (Lens)-import           Data.AffineSpace-import           Data.Functor            ((<$>))-import           Data.VectorSpace+import           Control.Lens            (Lens, Lens')+import           Text.Read +import           Linear.Affine+import           Linear.Vector++import           Diagrams.Align import           Diagrams.Core-import           Diagrams.Core.Points    () import           Diagrams.Core.Transform import           Diagrams.Parametric-  -- for GHC 7.4 type family bug +import           Data.Serialize          (Serialize)+import           GHC.Generics            (Generic)+ -- | \"Located\" things, /i.e./ things with a concrete location: --   intuitively, @Located a ~ (Point, a)@.  Wrapping a translationally --   invariant thing (/e.g./ a 'Segment' or 'Trail') in 'Located' pins@@ -49,27 +56,30 @@ --   'HasOrigin', 'Transformable', 'Enveloped', 'Traced', and --   'TrailLike' instances are particularly useful; see the documented --   instances below for more information.-data Located a = Loc { loc   :: Point (V a)   -- ^ Project out the-                                              --   location of a @Located@-                                              --   value.-                     , unLoc :: a             -- ^ Project the value-                                              --   of type @a@ out of-                                              --   a @Located a@,-                                              --   discarding the-                                              --   location.-                     }+data Located a =+  Loc { loc   :: Point (V a) (N a)  -- ^ Project out the+                                --   location of a @Located@+                                --   value.+      , unLoc :: a              -- ^ Project the value+                                --   of type @a@ out of+                                --   a @Located a@,+                                --   discarding the+                                --   location.+      } deriving (Generic) +instance (Serialize a, Serialize (V a (N a))) => Serialize (Located a)+ infix 5 `at`  -- | Construct a @Located a@ from a value of type @a@ and a location. --   @at@ is intended to be used infix, like @x \`at\` origin@.-at :: a -> Point (V a) -> Located a+at :: a -> Point (V a) (N a) -> Located a at a p = Loc p a  -- | Deconstruct a @Located a@ into a location and a value of type --   @a@.  @viewLoc@ can be especially useful in conjunction with the --   @ViewPatterns@ extension.-viewLoc :: Located a -> (Point (V a), a)+viewLoc :: Located a -> (Point (V a) (N a), a) viewLoc (Loc p a) = (p,a)  -- | 'Located' is not a @Functor@, since changing the type could@@ -82,32 +92,49 @@ --   @Located@ is a little-f (endo)functor on the category of types --   with associated vector space @v@; but that is not covered by the --   standard @Functor@ class.)-mapLoc :: (V a ~ V b) => (a -> b) -> Located a -> Located b+mapLoc :: SameSpace a b => (a -> b) -> Located a -> Located b mapLoc f (Loc p a) = Loc p (f a)  -- | A lens giving access to the object within a 'Located' wrapper.-located :: (V a ~ V a') => Lens (Located a) (Located a') a a'+located :: SameSpace a b => Lens (Located a) (Located b) a b located f (Loc p a) = Loc p <$> f a -deriving instance (Eq   (V a), Eq a  ) => Eq   (Located a)-deriving instance (Ord  (V a), Ord a ) => Ord  (Located a)-deriving instance (Show (V a), Show a) => Show (Located a)+-- | Lens onto the location of something 'Located'.+_loc :: Lens' (Located a) (Point (V a) (N a))+_loc f (Loc p a) = flip Loc a <$> f p +deriving instance (Eq   (V a (N a)), Eq a  ) => Eq   (Located a)+deriving instance (Ord  (V a (N a)), Ord a ) => Ord  (Located a)++instance (Show (V a (N a)), Show a) => Show (Located a) where+  showsPrec d (Loc p a) = showParen (d > 5) $+    showsPrec 6 a . showString " `at` " . showsPrec 6 p++instance (Read (V a (N a)), Read a) => Read (Located a) where+  readPrec = parens . prec 5 $ do+    a <- readPrec+    Punc "`"   <- lexP+    Ident "at" <- lexP+    Punc "`"   <- lexP+    p <- readPrec+    return (Loc p a)+ type instance V (Located a) = V a+type instance N (Located a) = N a  -- | @Located a@ is an instance of @HasOrigin@ whether @a@ is or not. --   In particular, translating a @Located a@ simply translates the --   associated point (and does /not/ affect the value of type @a@).-instance VectorSpace (V a) => HasOrigin (Located a) where+instance (Num (N a), Additive (V a)) => HasOrigin (Located a) where   moveOriginTo o (Loc p a) = Loc (moveOriginTo o p) a  -- | Applying a transformation @t@ to a @Located a@ results in the --   transformation being applied to the location, and the /linear/ --   /portion/ of @t@ being applied to the value of type @a@ (/i.e./ --   it is not translated).-instance Transformable a => Transformable (Located a) where+instance (Additive (V a), Num (N a), Transformable a) => Transformable (Located a) where   transform t@(Transformation t1 t2 _) (Loc p a)-    = Loc (transform t p) (transform (Transformation t1 t2 zeroV) a)+    = Loc (transform t p) (transform (Transformation t1 t2 zero) a)  -- | The envelope of a @Located a@ is the envelope of the @a@, --   translated to the location.@@ -119,38 +146,38 @@  -- | The trace of a @Located a@ is the trace of the @a@, --   translated to the location.-instance Traced a => Traced (Located a) where+instance (Traced a, Num (N a)) => Traced (Located a) where   getTrace (Loc p a) = moveTo p (getTrace a) +instance Alignable a => Alignable (Located a) where+  defaultBoundary v = defaultBoundary v . unLoc+ instance Qualifiable a => Qualifiable (Located a) where-  n |> (Loc p a) = Loc p (n |> a)+  n .>> Loc p a = Loc p (n .>> a)  type instance Codomain (Located a) = Point (Codomain a) -instance (Codomain a ~ V a, AdditiveGroup (V a), Parametric a)+instance (InSpace v n a, Parametric a, Codomain a ~ v)     => Parametric (Located a) where-  (Loc x a) `atParam` p = x .+^ (a `atParam` p)+  Loc x a `atParam` p = x .+^ (a `atParam` p)  instance DomainBounds a => DomainBounds (Located a) where   domainLower (Loc _ a) = domainLower a   domainUpper (Loc _ a) = domainUpper a -instance (Codomain a ~ V a, AdditiveGroup (V a), EndValues a)-    => EndValues (Located a)+instance (InSpace v n a, EndValues a, Codomain a ~ v) => EndValues (Located a) -instance ( Codomain a ~ V a, Fractional (Scalar (V a)), AdditiveGroup (V a)-         , Sectionable a, Parametric a-         )+instance (InSpace v n a, Fractional n, Parametric a, Sectionable a, Codomain a ~ v)     => Sectionable (Located a) where   splitAtParam (Loc x a) p = (Loc x a1, Loc (x .+^ (a `atParam` p)) a2)     where (a1,a2) = splitAtParam a p +  section (Loc x a) p1 p2 = Loc (x .+^ (a `atParam` p1)) (section a p1 p2)+   reverseDomain (Loc x a) = Loc (x .+^ y) (reverseDomain a)-    where y = a `atParam` (domainUpper a)+    where y = a `atParam` domainUpper a -instance ( Codomain a ~ V a, AdditiveGroup (V a), Fractional (Scalar (V a))-         , HasArcLength a-         )+instance (InSpace v n a, Fractional n, HasArcLength a, Codomain a ~ v)     => HasArcLength (Located a) where-  arcLengthBounded eps (Loc _ a)   = arcLengthBounded eps a-  arcLengthToParam eps (Loc _ a) l = arcLengthToParam eps a l+  arcLengthBounded eps (Loc _ a) = arcLengthBounded eps a+  arcLengthToParam eps (Loc _ a) = arcLengthToParam eps a
src/Diagrams/Names.hs view
@@ -1,4 +1,10 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MonoLocalBinds   #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Names@@ -39,23 +45,22 @@     ) where  import           Data.Semigroup-import           Data.VectorSpace -import           Diagrams.Core       (HasLinearMap, OrderedField, Point)+import           Diagrams.Core       (OrderedField, Point) import           Diagrams.Core.Names import           Diagrams.Core.Types +import           Linear.Metric+ -- | Attach an atomic name to a diagram.-named :: ( IsName n-         , HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m)-      => n -> QDiagram b v m -> QDiagram b v m+named :: (IsName nm, Metric v, OrderedField n, Semigroup m)+      => nm -> QDiagram b v n m -> QDiagram b v n m named = nameSub mkSubdiagram  -- | Attach an atomic name to a certain point (which may be computed --   from the given diagram), treated as a subdiagram with no content --   and a point envelope.-namePoint :: ( IsName n-             , HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m)-          => (QDiagram b v m -> Point v) -> n -> QDiagram b v m -> QDiagram b v m+namePoint :: (IsName nm , Metric v, OrderedField n, Semigroup m)+          => (QDiagram b v n m -> Point v n) -> nm -> QDiagram b v n m -> QDiagram b v n m namePoint p = nameSub (subPoint . p) 
src/Diagrams/Parametric.hs view
@@ -22,14 +22,13 @@    ) where -import           Diagrams.Core--import           Data.VectorSpace-import qualified Numeric.Interval.Kaucher   as I+import           Data.Kind (Type)+import           Diagrams.Core.V+import qualified Numeric.Interval.Kaucher as I  -- | Codomain of parametric classes.  This is usually either @(V p)@, for relative --   vector results, or @(Point (V p))@, for functions with absolute coordinates.-type family Codomain p :: *+type family Codomain p :: Type -> Type  -- | Type class for parametric functions. class Parametric p where@@ -37,7 +36,7 @@   -- | 'atParam' yields a parameterized view of an object as a   --   continuous function. It is designed to be used infix, like @path   --   ``atParam`` 0.5@.-  atParam :: p -> Scalar (V p) -> Codomain p+  atParam :: p -> N p -> Codomain p (N p)  -- | Type class for parametric functions with a bounded domain.  The --   default bounds are @[0,1]@.@@ -48,16 +47,16 @@ class DomainBounds p where   -- | 'domainLower' defaults to being constantly 0 (for vector spaces with   --   numeric scalars).-  domainLower :: p -> Scalar (V p)+  domainLower :: p -> N p -  default domainLower :: Num (Scalar (V p)) => p -> Scalar (V p)+  default domainLower :: Num (N p) => p -> N p   domainLower = const 0    -- | 'domainUpper' defaults to being constantly 1 (for vector spaces   --   with numeric scalars).-  domainUpper :: p -> Scalar (V p)+  domainUpper :: p -> N p -  default domainUpper :: Num (Scalar (V p)) => p -> Scalar (V p)+  default domainUpper :: Num (N p) => p -> N p   domainUpper = const 1  -- | Type class for querying the values of a parametric object at the@@ -69,7 +68,7 @@   --   --   This is the default implementation, but some representations will   --   have a more efficient and/or precise implementation.-  atStart :: p -> Codomain p+  atStart :: p -> Codomain p (N p)   atStart x = x `atParam` domainLower x    -- | 'atEnd' is the value at the end of the domain. That is,@@ -78,12 +77,12 @@   --   --   This is the default implementation, but some representations will   --   have a more efficient and/or precise implementation.-  atEnd :: p -> Codomain p+  atEnd :: p -> Codomain p (N p)   atEnd x = x `atParam` domainUpper x  -- | Return the lower and upper bounds of a parametric domain together --   as a pair.-domainBounds :: DomainBounds p => p -> (Scalar (V p), Scalar (V p))+domainBounds :: DomainBounds p => p -> (N p, N p) domainBounds x = (domainLower x, domainUpper x)  -- | Type class for parametric objects which can be split into@@ -97,10 +96,12 @@   --   portion of @p@ for parameter values from @0@ to @t@ and @r@ for   --   to that from @t@ to @1@.  The following property should hold:   ---  -- > prop_splitAtParam f t u =-  -- >   | u < t     = atParam f u == atParam l (u / t)-  -- >   | otherwise = atParam f u == atParam f t ??? atParam l ((u - t) / (domainUpper f - t))-  -- >   where (l,r) = splitAtParam f t+  -- @+  --   prop_splitAtParam f t u =+  --     | u < t     = atParam f u == atParam l (u / t)+  --     | otherwise = atParam f u == atParam f t ??? atParam l ((u - t) / (domainUpper f - t))+  --     where (l,r) = splitAtParam f t+  -- @   --   --   where @(???) = (^+^)@ if the codomain is a vector type, or   --   @const flip@ if the codomain is a point type.  Stated more@@ -113,7 +114,7 @@   --   result paths where the first is the original path extended to   --   the parameter 2, and the second result path travels /backwards/   --   from the end of the first to the end of the original path.-  splitAtParam :: p -> Scalar (V p) -> (p, p)+  splitAtParam :: p -> N p -> (p, p)   splitAtParam x t     = ( section x (domainLower x) t       , section x t (domainUpper x))@@ -129,8 +130,8 @@   --   --   That is, the section should have the same domain as the   --   original, and the reparameterization should be linear.-  section :: p -> Scalar (V p) -> Scalar (V p) -> p-  default section :: Fractional (Scalar (V p)) => p -> Scalar (V p) -> Scalar (V p) -> p+  section :: p -> N p -> N p -> p+  default section :: Fractional (N p) => p -> N p -> N p -> p   section x t1 t2 = snd (splitAtParam (fst (splitAtParam x t2)) (t1/t2))    -- | Flip the parameterization on the domain.@@ -148,18 +149,18 @@   -- | @arcLengthBounded eps x@ approximates the arc length of @x@.   --   The true arc length is guaranteed to lie within the interval   --   returned, which will have a size of at most @eps@.-  arcLengthBounded :: Scalar (V p) -> p -> I.Interval (Scalar (V p))+  arcLengthBounded :: N p -> p -> I.Interval (N p)    -- | @arcLength eps s@ approximates the arc length of @x@ up to the   --   accuracy @eps@ (plus or minus).-  arcLength :: Scalar (V p) -> p -> Scalar (V p)-  default arcLength :: Fractional (Scalar (V p)) => Scalar (V p ) -> p -> Scalar (V p)+  arcLength :: N p -> p -> N p+  default arcLength :: Fractional (N p) => N p -> p -> N p   arcLength eps = I.midpoint . arcLengthBounded eps    -- | Approximate the arc length up to a standard accuracy of   --   'stdTolerance' (@1e-6@).-  stdArcLength :: p -> Scalar (V p)-  default stdArcLength :: Fractional (Scalar (V p)) => p -> Scalar (V p)+  stdArcLength :: p -> N p+  default stdArcLength :: Fractional (N p) => p -> N p   stdArcLength = arcLength stdTolerance    -- | @'arcLengthToParam' eps s l@ converts the absolute arc length@@ -169,11 +170,11 @@   --   --   This should work for /any/ arc length, and may return any   --   parameter value (not just parameters in the domain).-  arcLengthToParam :: Scalar (V p) -> p -> Scalar (V p) -> Scalar (V p)+  arcLengthToParam :: N p -> p -> N p -> N p    -- | A simple interface to convert arc length to a parameter,   --   guaranteed to be accurate within 'stdTolerance', or @1e-6@.-  stdArcLengthToParam :: p -> Scalar (V p) -> Scalar (V p)-  default stdArcLengthToParam :: Fractional (Scalar (V p))-                              => p -> Scalar (V p) -> Scalar (V p)+  stdArcLengthToParam :: p -> N p -> N p+  default stdArcLengthToParam :: Fractional (N p) => p -> N p -> N p   stdArcLengthToParam = arcLengthToParam stdTolerance+
src/Diagrams/Parametric/Adjust.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE TemplateHaskell      #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -20,23 +22,23 @@      ) where -import           Control.Lens (makeLensesWith, lensRules, generateSignatures, (^.), (&), (.~), Lens')+import           Control.Lens        (Lens', generateSignatures, lensRules, makeLensesWith, (&),+                                      (.~), (^.)) import           Data.Proxy -import           Data.Default.Class-import           Data.VectorSpace+import           Data.Default  import           Diagrams.Core.V import           Diagrams.Parametric  -- | What method should be used for adjusting a segment, trail, or --   path?-data AdjustMethod v = ByParam (Scalar v)     -- ^ Extend by the given parameter value-                                             --   (use a negative parameter to shrink)-                    | ByAbsolute (Scalar v)  -- ^ Extend by the given arc length-                                             --   (use a negative length to shrink)-                    | ToAbsolute (Scalar v)  -- ^ Extend or shrink to the given-                                             --   arc length+data AdjustMethod n = ByParam n     -- ^ Extend by the given parameter value+                                    --   (use a negative parameter to shrink)+                    | ByAbsolute n  -- ^ Extend by the given arc length+                                    --   (use a negative length to shrink)+                    | ToAbsolute n  -- ^ Extend or shrink to the given+                                    --   arc length  -- | Which side of a segment, trail, or path should be adjusted? data AdjustSide = Start  -- ^ Adjust only the beginning@@ -45,43 +47,43 @@   deriving (Show, Read, Eq, Ord, Bounded, Enum)  -- | How should a segment, trail, or path be adjusted?-data AdjustOpts v = AO { _adjMethod       :: AdjustMethod v-                       , _adjSide         :: AdjustSide-                       , _adjEps          :: Scalar v-                       , adjOptsvProxy__ :: Proxy v+data AdjustOpts n = AO { _adjMethod    :: AdjustMethod n+                       , _adjSide      :: AdjustSide+                       , _adjEps       :: n+                       , adjOptsvProxy :: Proxy n                        } -makeLensesWith-  ( lensRules & generateSignatures .~ False)-  ''AdjustOpts+-- See Diagrams.Combinators for reasoning behind 'Proxy'. +makeLensesWith (lensRules & generateSignatures .~ False) ''AdjustOpts+ -- | Which method should be used for adjusting?-adjMethod :: Lens' (AdjustOpts v) (AdjustMethod v)+adjMethod :: Lens' (AdjustOpts n) (AdjustMethod n)  -- | Which end(s) of the object should be adjusted?-adjSide :: Lens' (AdjustOpts v) AdjustSide+adjSide :: Lens' (AdjustOpts n) AdjustSide  -- | Tolerance to use when doing adjustment.-adjEps :: Lens' (AdjustOpts v) (Scalar v)+adjEps :: Lens' (AdjustOpts n) n -instance Fractional (Scalar v) => Default (AdjustMethod v) where+instance Fractional n => Default (AdjustMethod n) where   def = ByParam 0.2  instance Default AdjustSide where   def = Both -instance Fractional (Scalar v) => Default (AdjustOpts v) where-  def = AO { _adjMethod = def-           , _adjSide = def-           , _adjEps = stdTolerance-           , adjOptsvProxy__ = Proxy+instance Fractional n => Default (AdjustOpts n) where+  def = AO { _adjMethod    = def+           , _adjSide      = def+           , _adjEps       = stdTolerance+           , adjOptsvProxy = Proxy            }  -- | Adjust the length of a parametric object such as a segment or --   trail.  The second parameter is an option record which controls how --   the adjustment should be performed; see 'AdjustOpts'.-adjust :: (DomainBounds a, Sectionable a, HasArcLength a, Fractional (Scalar (V a)))-       => a -> AdjustOpts (V a) -> a+adjust :: (N t ~ n, Sectionable t, HasArcLength t, Fractional n)+       => t -> AdjustOpts n -> t adjust s opts = section s   (if opts^.adjSide == End   then domainLower s else getParam s)   (if opts^.adjSide == Start then domainUpper s else domainUpper s - getParam (reverseDomain s))
src/Diagrams/Path.hs view
@@ -1,15 +1,20 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Path@@ -35,12 +40,15 @@          -- * Constructing paths          -- $construct +       , ToPath (..)        , pathFromTrail        , pathFromTrailAt        , pathFromLocTrail           -- * Eliminating paths +       , pathPoints+       , pathVertices'        , pathVertices        , pathOffsets        , pathCentroid@@ -58,11 +66,15 @@         ) where +import           Control.Arrow      ((***))+import           Control.Lens       hiding (at, transform, ( # ))+import qualified Data.Foldable      as F+import           Data.List          (partition)+import           Data.Semigroup import           Data.Typeable  import           Diagrams.Align import           Diagrams.Core-import           Diagrams.Core.Points () import           Diagrams.Located import           Diagrams.Points import           Diagrams.Segment@@ -70,15 +82,12 @@ import           Diagrams.TrailLike import           Diagrams.Transform -import           Control.Arrow        ((***))-import           Control.Lens         (Rewrapped, Wrapped (..), iso, mapped, op,-                                       over, view, (%~), _Unwrapped', _Wrapped)-import           Data.AffineSpace-import qualified Data.Foldable        as F-import           Data.List            (partition)-import           Data.Semigroup-import           Data.VectorSpace+import           Linear.Metric+import           Linear.Vector +import           Data.Serialize     (Serialize)+import           GHC.Generics       (Generic)+ ------------------------------------------------------------ --  Paths  ------------------------------------------------- ------------------------------------------------------------@@ -87,86 +96,136 @@ --   Hence, unlike trails, paths are not translationally invariant, --   and they form a monoid under /superposition/ (placing one path on --   top of another) rather than concatenation.-newtype Path v = Path [Located (Trail v)]-  deriving (Semigroup, Monoid, Typeable)+newtype Path v n = Path [Located (Trail v n)]+  deriving (Semigroup, Monoid, Generic+  , Typeable+  ) -instance Wrapped (Path v) where-    type Unwrapped (Path v) = [Located (Trail v)]-    _Wrapped' = iso (\(Path x) -> x) Path+-- instance (OrderedField n, Metric v, Serialize (v n), Serialize (V n (N n))) =>+instance (OrderedField n, Metric v, Serialize (v n), Serialize (V (v n) (N (v n)))) =>+  Serialize (Path v n) -instance Rewrapped (Path v) (Path v')+instance Wrapped (Path v n) where+  type Unwrapped (Path v n) = [Located (Trail v n)]+  _Wrapped' = iso (\(Path x) -> x) Path +instance Rewrapped (Path v n) (Path v' n')++instance Each (Path v n) (Path v' n') (Located (Trail v n)) (Located (Trail v' n')) where+  each = _Wrapped . traverse++instance AsEmpty (Path v n) where+  _Empty = _Wrapped' . _Empty++instance Cons (Path v n) (Path v' n') (Located (Trail v n)) (Located (Trail v' n')) where+  _Cons = _Wrapped . _Cons . bimapping id _Unwrapped+  {-# INLINE _Cons #-}++instance Snoc (Path v n) (Path v' n') (Located (Trail v n)) (Located (Trail v' n')) where+  _Snoc = _Wrapped . _Snoc . bimapping _Unwrapped id+  {-# INLINE _Snoc #-}+ -- | Extract the located trails making up a 'Path'.-pathTrails :: Path v -> [Located (Trail v)]+pathTrails :: Path v n -> [Located (Trail v n)] pathTrails = op Path -deriving instance Show v => Show (Path v)-deriving instance Eq   v => Eq   (Path v)-deriving instance Ord  v => Ord  (Path v)+deriving instance Show (v n) => Show (Path v n)+deriving instance Eq   (v n) => Eq   (Path v n)+deriving instance Ord  (v n) => Ord  (Path v n) -type instance V (Path v) = v+type instance V (Path v n) = v+type instance N (Path v n) = n -instance VectorSpace v => HasOrigin (Path v) where+instance (Additive v, Num n) => HasOrigin (Path v n) where   moveOriginTo = over _Wrapped' . map . moveOriginTo-  --moveOriginTo = over pathTrails . map . moveOriginTo  -- | Paths are trail-like; a trail can be used to construct a --   singleton path.-instance (InnerSpace v, OrderedField (Scalar v)) => TrailLike (Path v) where+instance (Metric v, OrderedField n) => TrailLike (Path v n) where   trailLike = Path . (:[])  -- See Note [Transforming paths]-instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-    => Transformable (Path v) where+instance (HasLinearMap v, Metric v, OrderedField n)+    => Transformable (Path v n) where   transform = over _Wrapped . map . transform -{- ~~~~ Note [Transforming paths]--Careful!  It's tempting to just define--> transform = fmap . transform--but that doesn't take into account the fact that some-of the v's are inside Points and hence ought to be translated.--}--instance (InnerSpace v, OrderedField (Scalar v)) => Enveloped (Path v) where-  getEnvelope = F.foldMap trailEnvelope . op Path --view pathTrails+instance (Metric v, OrderedField n) => Enveloped (Path v n) where+  getEnvelope = F.foldMap trailEnvelope . op Path           -- this type signature is necessary to work around an apparent bug in ghc 6.12.1-    where trailEnvelope :: Located (Trail v) -> Envelope v+    where trailEnvelope :: Located (Trail v n) -> Envelope v n           trailEnvelope (viewLoc -> (p, t)) = moveOriginTo ((-1) *. p) (getEnvelope t) -instance (InnerSpace v, OrderedField (Scalar v)) => Juxtaposable (Path v) where+instance (Metric v, OrderedField n) => Juxtaposable (Path v n) where   juxtapose = juxtaposeDefault -instance (InnerSpace v, OrderedField (Scalar v)) => Alignable (Path v) where+instance (Metric v, OrderedField n) => Alignable (Path v n) where   defaultBoundary = envelopeBoundary -instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-    => Renderable (Path v) NullBackend where+instance (HasLinearMap v, Metric v, OrderedField n)+    => Renderable (Path v n) NullBackend where   render _ _ = mempty  ------------------------------------------------------------ --  Constructing paths  ------------------------------------ ------------------------------------------------------------ +-- | Type class for things that can be converted to a 'Path'.+--+--   Note that this class is very different from 'TrailLike'. 'TrailLike' is+--   usually the result of a library function to give you a convenient,+--   polymorphic result ('Path', 'Diagram' etc.).+--+class ToPath t where+  -- | 'toPath' takes something that can be converted to 'Path' and returns+  --    the 'Path'.+  toPath :: (Metric (V t), OrderedField (N t)) => t -> Path (V t) (N t)++instance ToPath (Path v n) where+  toPath = id++instance ToPath (Trail v n) where+  toPath = pathFromTrail++instance ToPath (Trail' l v n) where+  toPath t = Path [Trail t `at` origin]++instance ToPath (Located (Trail v n)) where+  toPath = pathFromLocTrail++instance ToPath (Located (Trail' l v n)) where+  toPath = pathFromLocTrail . mapLoc Trail++instance ToPath (Located (Segment Closed v n)) where+  toPath (viewLoc -> (p,seg))+    = Path [trailFromSegments [seg] `at` p]++instance ToPath (Located [Segment Closed v n]) where+  toPath (viewLoc -> (p,segs))+    = Path [trailFromSegments segs `at` p]++instance ToPath (FixedSegment v n) where+  toPath = toPath . fromFixedSeg++instance ToPath a => ToPath [a] where+  toPath = F.foldMap toPath+ -- $construct -- Since paths are 'TrailLike', any function producing a 'TrailLike' -- can be used to construct a (singleton) path.  The functions in this -- section are provided for convenience.  -- | Convert a trail to a path beginning at the origin.-pathFromTrail :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> Path v+pathFromTrail :: (Metric v, OrderedField n) => Trail v n -> Path v n pathFromTrail = trailLike . (`at` origin)  -- | Convert a trail to a path with a particular starting point.-pathFromTrailAt :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> Point v -> Path v+pathFromTrailAt :: (Metric v, OrderedField n) => Trail v n -> Point v n -> Path v n pathFromTrailAt t p = trailLike (t `at` p)  -- | Convert a located trail to a singleton path.  This is equivalent --   to 'trailLike', but provided with a more specific name and type --   for convenience.-pathFromLocTrail :: (InnerSpace v, OrderedField (Scalar v)) => Located (Trail v) -> Path v+pathFromLocTrail :: (Metric v, OrderedField n) => Located (Trail v n) -> Path v n pathFromLocTrail = trailLike  ------------------------------------------------------------@@ -174,37 +233,64 @@ ------------------------------------------------------------  -- | Extract the vertices of a path, resulting in a separate list of---   vertices for each component trail (see 'trailVertices').-pathVertices :: (InnerSpace v, OrderedField (Scalar v)) => Path v -> [[Point v]]+--   vertices for each component trail.  Here a /vertex/ is defined as+--   a non-differentiable point on the trail, /i.e./ a sharp corner.+--   (Vertices are thus a subset of the places where segments join; if+--   you want all joins between segments, see 'pathPoints'.)  The+--   tolerance determines how close the tangents of two segments must be+--   at their endpoints to consider the transition point to be+--   differentiable.  See 'trailVertices' for more information.+pathVertices' :: (Metric v, OrderedField n) => n -> Path v n -> [[Point v n]]+pathVertices' toler = map (trailVertices' toler) . op Path++-- | Like 'pathVertices'', with a default tolerance.+pathVertices :: (Metric v, OrderedField n) => Path v n -> [[Point v n]] pathVertices = map trailVertices . op Path +-- | Extract the points of a path, resulting in a separate list of+--   points for each component trail.  Here a /point/ is any place+--   where two segments join; see also 'pathVertices' and 'trailPoints'.+--+--   This function allows you "observe" the fact that trails are+--   implemented as lists of segments, which may be problematic if we+--   want to think of trails as parametric vector functions. This also+--   means that the behavior of this function may not be stable under+--   future changes to the implementation of trails and paths.  For an+--   unproblematic version which only yields vertices at which there+--   is a sharp corner, excluding points differentiable points, see+--   'pathVertices'.+--+--   This function is not re-exported from "Diagrams.Prelude"; to use+--   it, import "Diagrams.Path".+pathPoints :: (Metric v, OrderedField n) => Path v n -> [[Point v n]]+pathPoints = map trailPoints . op Path+ -- | Compute the total offset of each trail comprising a path (see 'trailOffset').-pathOffsets :: (InnerSpace v, OrderedField (Scalar v)) => Path v -> [v]+pathOffsets :: (Metric v, OrderedField n) => Path v n -> [v n] pathOffsets = map (trailOffset . unLoc) . op Path  -- | Compute the /centroid/ of a path (/i.e./ the average location of---   its vertices).-pathCentroid :: (InnerSpace v, OrderedField (Scalar v)) => Path v -> Point v+--   its /vertices/; see 'pathVertices').+pathCentroid :: (Metric v, OrderedField n) => Path v n -> Point v n pathCentroid = centroid . concat . pathVertices  -- | Convert a path into a list of lists of located segments.-pathLocSegments :: (InnerSpace v, OrderedField (Scalar v))-                 => Path v -> [[Located (Segment Closed v)]]+pathLocSegments :: (Metric v, OrderedField n) => Path v n -> [[Located (Segment Closed v n)]] pathLocSegments = map trailLocSegments . op Path  -- | Convert a path into a list of lists of 'FixedSegment's.-fixPath :: (InnerSpace v, OrderedField (Scalar v)) => Path v -> [[FixedSegment v]]+fixPath :: (Metric v, OrderedField n) => Path v n -> [[FixedSegment v n]] fixPath = map fixTrail . op Path  -- | \"Explode\" a path by exploding every component trail (see --   'explodeTrail').-explodePath :: (VectorSpace (V t), TrailLike t) => Path (V t) -> [[t]]+explodePath :: (V t ~ v, N t ~ n, TrailLike t) => Path v n -> [[t]] explodePath = map explodeTrail . op Path  -- | Partition a path into two paths based on a predicate on trails: --   the first containing all the trails for which the predicate returns --   @True@, and the second containing the remaining trails.-partitionPath :: (Located (Trail v) -> Bool) -> Path v -> (Path v, Path v)+partitionPath :: (Located (Trail v n) -> Bool) -> Path v n -> (Path v n, Path v n) partitionPath p = (view _Unwrapped' *** view _Unwrapped') . partition p . op Path  ------------------------------------------------------------@@ -213,10 +299,13 @@  -- | Scale a path using its centroid (see 'pathCentroid') as the base --   point for the scale.-scalePath :: (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-          => Scalar v -> Path v -> Path v-scalePath d p = (scale d `under` translation (origin .-. pathCentroid p)) p+scalePath :: (HasLinearMap v, Metric v, OrderedField n) => n -> Path v n -> Path v n+scalePath d p = under (movedFrom (pathCentroid p)) (scale d) p  -- | Reverse all the component trails of a path.-reversePath :: (InnerSpace v, OrderedField (Scalar v)) => Path v -> Path v+reversePath :: (Metric v, OrderedField n) => Path v n -> Path v n reversePath = _Wrapped . mapped %~ reverseLocTrail++-- | Same as 'reversePath'.+instance (Metric v, OrderedField n) => Reversing (Path v n) where+  reversing = _Wrapped' . mapped %~ reversing
src/Diagrams/Points.hs view
@@ -1,6 +1,3 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies     #-}- ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Points@@ -9,28 +6,36 @@ -- Maintainer  :  diagrams-discuss@googlegroups.com -- -- Points in space.  For more tools for working with points and--- vectors, see "Data.AffineSpace" and "Diagrams.Coordinates".+-- vectors, see "Linear.Affine". -- -----------------------------------------------------------------------------  module Diagrams.Points        ( -- * Points-         Point, origin, (*.)+         Point (..), origin, (*.)           -- * Point-related utilities        , centroid        , pointDiagram-+       , _Point, lensP        ) where -import           Diagrams.Core          (pointDiagram)+import           Diagrams.Core        (pointDiagram) import           Diagrams.Core.Points -import           Control.Arrow          ((&&&))+import           Data.Foldable        as F -import           Data.AffineSpace.Point-import           Data.VectorSpace+import           Linear.Affine+import           Linear.Vector  -- | The centroid of a set of /n/ points is their sum divided by /n/.-centroid :: (VectorSpace v, Fractional (Scalar v)) => [Point v] -> Point v-centroid = P . uncurry (^/) . (sumV &&& (fromIntegral . length)) . map unPoint+--   Returns the origin for an empty list of points.+centroid :: (Additive v, Fractional n) => [Point v n] -> Point v n+centroid [] = origin+centroid ps = meanV ps+{-# INLINE centroid #-}++meanV :: (Foldable f, Additive v, Fractional a) => f (v a) -> v a+meanV = uncurry (^/) . F.foldl' (\(s,c) e -> (e ^+^ s,c+1)) (zero,0)+{-# INLINE meanV #-}+
src/Diagrams/Prelude.hs view
@@ -1,8 +1,9 @@ {-# OPTIONS_GHC -fno-warn-duplicate-exports #-}+{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Prelude--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -12,148 +13,93 @@ -----------------------------------------------------------------------------  module Diagrams.Prelude-       (-         -- * Core library-         -- | The core definitions of transformations, diagrams,-         --   backends, and so on.-         module Diagrams.Core--         -- * Standard library--         -- | Attributes (color, line style, etc.) and styles.-       , module Diagrams.Attributes--         -- | Alignment of diagrams relative to their envelopes.-       , module Diagrams.Align--         -- | Combining multiple diagrams into one.-       , module Diagrams.Combinators--         -- | Giving concrete locations to translation-invariant things.-       , module Diagrams.Located--         -- | Linear and cubic bezier segments.-       , module Diagrams.Segment--         -- | Trails.-       , module Diagrams.Trail--         -- | Parametrization of segments and trails.-       , module Diagrams.Parametric--         -- | Adjusting the length of parameterized objects.-       , module Diagrams.Parametric.Adjust--         -- | Computing tangent and normal vectors of segments and-         --   trails.-       , module Diagrams.Tangent--         -- | Trail-like things.-       , module Diagrams.TrailLike--         -- | Paths.-       , module Diagrams.Path--         -- | Cubic splines.-       , module Diagrams.CubicSpline--         -- | Some additional transformation-related functions, like-         --   conjugation of transformations.-       , module Diagrams.Transform--         -- | Projective transformations and other deformations-         -- lacking an inverse.-       , module Diagrams.Deform+  (+    -- * Diagrams library+    -- | Exports from this library for working with diagrams.+    module Diagrams -         -- | Giving names to subdiagrams and later retrieving-         --   subdiagrams by name.-       , module Diagrams.Names+    -- * Convenience re-exports from other packages -         -- | Envelopes, aka functional bounding regions.-       , module Diagrams.Envelope+    -- | For working with default values. Diagrams also exports 'with',+    --   an alias for 'def'.+  , module Data.Default -         -- | Traces, aka embedded raytracers, for finding points on-         --   the boundary of a diagram.-       , module Diagrams.Trace+    -- | For representing and operating on colors.+  , module Data.Colour -         -- | A query is a function that maps points in a vector space-         --   to values in some monoid; they can be used to annotate-         --   the points of a diagram with some values.-       , module Diagrams.Query+    -- | A large list of color names.+  , module Data.Colour.Names -         -- | Utilities for working with points.-       , module Diagrams.Points+    -- | Specify your own colours.+  , module Data.Colour.SRGB -         -- | Angles-       , module Diagrams.Angle-         -- | Convenience infix operators for working with coordinates.-       , module Diagrams.Coordinates+    -- | Semigroups and monoids show up all over the place, so things from+    --   Data.Semigroup and Data.Monoid often come in handy.+  , module Data.Semigroup -         -- | A wide range of things (shapes, transformations,-         --   combinators) specific to creating two-dimensional-         --   diagrams.-       , module Diagrams.TwoD+    -- | For computing with vectors.+  , module Linear.Vector -         -- | Tools for making animations.-       , module Diagrams.Animation+    -- | For computing with points and vectors.+  , module Linear.Affine -         -- | Various utility definitions.-       , module Diagrams.Util+    -- | For computing with dot products and norm.+  , module Linear.Metric -         -- * Convenience re-exports-         -- | For representing and operating on colors.-       , module Data.Colour-         -- | A large list of color names.-       , module Data.Colour.Names-         -- | Semigroups and monoids show up all over the place, so things from-         --   Data.Semigroup and Data.Monoid often come in handy.-       , module Data.Semigroup-         -- | For computing with vectors.-       , module Data.VectorSpace-         -- | For computing with points and vectors.-       , module Data.AffineSpace+    -- | For working with 'Active' (i.e. animated) things.+  , module Data.Active -         -- | For working with 'Active' (i.e. animated) things.-       , module Data.Active+    -- | Most of the lens package. The following functions are not+    --   exported from lens because they either conflict with+    --   diagrams or may conflict with other libraries:+    --+    --   * 'Control.Lens.At.at'+    --   * 'Control.Lens.At.contains'+    --   * 'Control.Lens.Indexed..>'+    --   * 'Control.Lens.Indexed.<.>'+    --   * 'Control.Lens.Indexed.index'+    --   * 'Control.Lens.Indexed.indices'+    --   * 'Control.Lens.Indexed.none'+    --   * 'Control.Lens.Internal.Getter.coerce'+    --   * 'Control.Lens.Internal.Indexed.indexed'+    --   * 'Control.Lens.Lens.inside'+    --   * 'Control.Lens.Level.levels'+    --   * 'Control.Lens.Plated....'+    --   * 'Control.Lens.Plated.children'+    --   * 'Control.Lens.Plated.transform'+    --   * 'Control.Lens.Prism.outside'+    --   * 'Control.Lens.Setter.argument'+    --   * 'Control.Lens.Traversal.beside'+    --   * 'Control.Lens.Traversal.singular'+  , module Control.Lens -         -- | Essential Lens Combinators-       , (&), (.~), (%~)+  , Applicative(..), (*>), (<*), (<$>), (<$), liftA, liftA2, liftA3+  ) where -       , Applicative(..), (*>), (<*), (<$>), (<$), liftA, liftA2, liftA3-       ) where+import           Diagrams -import           Diagrams.Core+import           Control.Applicative -import           Diagrams.Align-import           Diagrams.Angle-import           Diagrams.Animation-import           Diagrams.Attributes-import           Diagrams.Combinators-import           Diagrams.Coordinates-import           Diagrams.CubicSpline-import           Diagrams.Deform-import           Diagrams.Envelope-import           Diagrams.Located-import           Diagrams.Names-import           Diagrams.Parametric-import           Diagrams.Parametric.Adjust-import           Diagrams.Path-import           Diagrams.Points-import           Diagrams.Query-import           Diagrams.Segment-import           Diagrams.Tangent-import           Diagrams.Trace-import           Diagrams.Trail-import           Diagrams.TrailLike-import           Diagrams.Transform-import           Diagrams.TwoD-import           Diagrams.Util+#if MIN_VERSION_lens(4,13,0)+import           Control.Lens        hiding (argument, at, backwards, beside,+                                      children, contains, indexed, indices,+                                      inside, levels, none, outside, singular,+                                      transform, ( # ), (...), (.>), (<.>))+#else+import           Control.Lens        hiding (argument, at, backwards, beside,+                                      children, coerce, contains, indexed,+                                      indices, inside, levels, none, outside,+                                      singular, transform, ( # ), (...), (.>),+                                      (<.>))+#endif -import           Control.Applicative import           Data.Active-import           Data.AffineSpace-import           Data.Colour                hiding (AffineSpace (..), atop, over)-import           Data.Colour.Names          hiding (tan)+import           Data.Colour         hiding (AffineSpace (..), atop, over)+import           Data.Colour.Names   hiding (tan)+import           Data.Colour.SRGB+import           Data.Default import           Data.Semigroup-import           Data.VectorSpace           hiding (Sum (..))-import           Control.Lens               ((&), (.~), (%~))++import           Linear.Affine+import           Linear.Metric+import           Linear.Vector
− src/Diagrams/Prelude/ThreeD.hs
@@ -1,154 +0,0 @@-{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}--------------------------------------------------------------------------------- |--- Module      :  Diagrams.Prelude.ThreeD--- Copyright   :  (c) 2014 diagrams-lib team (see LICENSE)--- License     :  BSD-style (see LICENSE)--- Maintainer  :  diagrams-discuss@googlegroups.com------ A module to re-export most of the functionality of the diagrams--- core and standard library, including 3D types and functions.-----------------------------------------------------------------------------------module Diagrams.Prelude.ThreeD-       (-         -- * Core library-         -- | The core definitions of transformations, diagrams,-         --   backends, and so on.-         module Diagrams.Core--         -- * Standard library--         -- | Attributes (color, line style, etc.) and styles.-       , module Diagrams.Attributes--         -- | Alignment of diagrams relative to their envelopes.-       , module Diagrams.Align--         -- | Combining multiple diagrams into one.-       , module Diagrams.Combinators--         -- | Giving concrete locations to translation-invariant things.-       , module Diagrams.Located--         -- | Linear and cubic bezier segments.-       , module Diagrams.Segment--         -- | Trails.-       , module Diagrams.Trail--         -- | Parametrization of segments and trails.-       , module Diagrams.Parametric--         -- | Adjusting the length of parameterized objects.-       , module Diagrams.Parametric.Adjust--         -- | Computing tangent and normal vectors of segments and-         --   trails.-       , module Diagrams.Tangent--         -- | Trail-like things.-       , module Diagrams.TrailLike--         -- | Paths.-       , module Diagrams.Path--         -- | Cubic splines.-       , module Diagrams.CubicSpline--         -- | Some additional transformation-related functions, like-         --   conjugation of transformations.-       , module Diagrams.Transform--         -- | Giving names to subdiagrams and later retrieving-         --   subdiagrams by name.-       , module Diagrams.Names--         -- | Envelopes, aka functional bounding regions.-       , module Diagrams.Envelope--         -- | Traces, aka embedded raytracers, for finding points on-         --   the boundary of a diagram.-       , module Diagrams.Trace--         -- | A query is a function that maps points in a vector space-         --   to values in some monoid; they can be used to annotate-         --   the points of a diagram with some values.-       , module Diagrams.Query--         -- | Utilities for working with points.-       , module Diagrams.Points--         -- | Angles-       , module Diagrams.Angle--         -- | Convenience infix operators for working with coordinates.-       , module Diagrams.Coordinates--         -- | things (shapes, transformations, combinators) specific-         -- to creating three-dimensional diagrams.-       , module Diagrams.ThreeD--         -- | Tools for making animations.-       , module Diagrams.Animation--         -- | Various utility definitions.-       , module Diagrams.Util--         -- * Convenience re-exports-         -- | For representing and operating on colors.-       , module Data.Colour-         -- | A large list of color names.-       , module Data.Colour.Names-         -- | Semigroups and monoids show up all over the place, so things from-         --   Data.Semigroup and Data.Monoid often come in handy.-       , module Data.Semigroup-         -- | For computing with vectors.-       , module Data.VectorSpace-         -- | For computing with points and vectors.-       , module Data.AffineSpace--         -- | For working with 'Active' (i.e. animated) things.-       , module Data.Active--         -- | Essential Lens Combinators-       , (&), (.~), (%~)--       , Applicative(..), (*>), (<*), (<$>), (<$), liftA, liftA2, liftA3-       ) where--import           Diagrams.Core--import           Diagrams.Align-import           Diagrams.Angle-import           Diagrams.Animation-import           Diagrams.Attributes-import           Diagrams.Combinators-import           Diagrams.Coordinates-import           Diagrams.CubicSpline-import           Diagrams.Envelope-import           Diagrams.Located-import           Diagrams.Names-import           Diagrams.Parametric-import           Diagrams.Parametric.Adjust-import           Diagrams.Path-import           Diagrams.Points-import           Diagrams.Query-import           Diagrams.Segment-import           Diagrams.Tangent-import           Diagrams.Trace-import           Diagrams.Trail-import           Diagrams.TrailLike-import           Diagrams.Transform-import           Diagrams.ThreeD-import           Diagrams.Util--import           Control.Applicative-import           Data.Active-import           Data.AffineSpace-import           Data.Colour                hiding (AffineSpace (..), atop, over)-import           Data.Colour.Names          hiding (tan)-import           Data.Semigroup-import           Data.VectorSpace           hiding (Sum (..))-import           Control.Lens               ((&), (.~), (%~))
src/Diagrams/Query.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE FlexibleContexts       #-}+{-# LANGUAGE FlexibleInstances      #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses  #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Query@@ -12,8 +16,78 @@ -----------------------------------------------------------------------------  module Diagrams.Query-    ( Query(..), query, sample, value, resetValue, clearValue+  ( -- * Queries+    Query(..)+  , HasQuery (..)+  , sample+  , inquire -    ) where+    -- ** Queries on diagrams+  , query+  , value+  , resetValue+  , clearValue+  ) where +import           Data.Monoid+ import           Diagrams.Core++-- | Types which can answer a 'Query' about points inside the geometric+--   object.+--+--   If @t@ and @m@ are both a 'Semigroup's, 'getQuery' should satisfy+--+-- @+-- 'getQuery' (t1 <> t2) = 'getQuery' t1 <> 'getQuery' t2+-- @+class HasQuery t m | t -> m where+  -- | Extract the query of an object.+  getQuery :: t -> Query (V t) (N t) m++instance HasQuery (Query v n m) m where+  getQuery = id++instance Monoid m => HasQuery (QDiagram b v n m) m where+  getQuery = query++-- | Test if a point is not equal to 'mempty'.+--+-- @+-- 'inquire' :: 'QDiagram' b v n 'Any' -> 'Point' v n -> 'Bool'+-- 'inquire' :: 'Query' v n 'Any'      -> 'Point' v n -> 'Bool'+-- 'inquire' :: 'Diagrams.BoundingBox.BoundingBox' v n  -> 'Point' v n -> 'Bool'+-- @+inquire :: HasQuery t Any => t -> Point (V t) (N t) -> Bool+inquire t = getAny . sample t++-- | Sample a diagram's query function at a given point.+--+-- @+-- 'sample' :: 'QDiagram' b v n m -> 'Point' v n -> m+-- 'sample' :: 'Query' v n m      -> 'Point' v n -> m+-- 'sample' :: 'Diagrams.BoundingBox.BoundingBox' v n  -> 'Point' v n -> 'Any'+-- 'sample' :: 'Diagrams.Path.Path' 'V2' 'Double'   -> 'Point' v n -> 'Diagrams.TwoD.Path.Crossings'+-- @+sample :: HasQuery t m => t -> Point (V t) (N t) -> m+sample = runQuery . getQuery++-- | Set the query value for 'True' points in a diagram (/i.e./ points+--   \"inquire\" the diagram); 'False' points will be set to 'mempty'.+value :: Monoid m => m -> QDiagram b v n Any -> QDiagram b v n m+value m = fmap fromAny+  where fromAny (Any True)  = m+        fromAny (Any False) = mempty++-- | Reset the query values of a diagram to @True@/@False@: any values+--   equal to 'mempty' are set to 'False'; any other values are set to+--   'True'.+resetValue :: (Eq m, Monoid m) => QDiagram b v n m -> QDiagram b v n Any+resetValue = fmap toAny+  where toAny m | m == mempty = Any False+                | otherwise   = Any True++-- | Set all the query values of a diagram to 'False'.+clearValue :: QDiagram b v n m -> QDiagram b v n Any+clearValue = fmap (const (Any False))+
src/Diagrams/Segment.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE BangPatterns               #-} {-# LANGUAGE DeriveFunctor              #-} {-# LANGUAGE EmptyDataDecls             #-}@@ -11,7 +12,6 @@ {-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE TypeOperators              #-} {-# LANGUAGE UndecidableInstances       #-}-{-# LANGUAGE ViewPatterns               #-}  ----------------------------------------------------------------------------- -- |@@ -42,15 +42,17 @@           -- * Segment offsets -       , Offset(..), segOffset+       , Offset(..) , segOffset           -- * Constructing and modifying segments -       , Segment(..), straight, bezier3, bézier3, reverseSegment+       , Segment(..), straight, bezier3, bézier3, reverseSegment, mapSegmentVectors+       , openLinear, openCubic           -- * Fixed (absolutely located) segments        , FixedSegment(..)        , mkFixedSeg, fromFixedSeg+       , fixedSegIso           -- * Segment measures          -- $segmeas@@ -64,21 +66,26 @@         ) where -import           Control.Lens (makeLenses, Wrapped(..), Rewrapped, iso, op)-import           Control.Applicative (liftA2)-import           Data.AffineSpace+import           Control.Lens              hiding (at, transform) import           Data.FingerTree import           Data.Monoid.MList import           Data.Semigroup-import           Data.VectorSpace    hiding (Sum (..))-import           Numeric.Interval.Kaucher    (Interval (..))-import qualified Numeric.Interval.Kaucher    as I+import           Numeric.Interval.Kaucher  (Interval (..))+import qualified Numeric.Interval.Kaucher  as I -import           Diagrams.Core+import           Linear.Affine+import           Linear.Metric+import           Linear.Vector             hiding (lerp)+import           Linear.Vector.Compat      (lerp)++import           Control.Applicative+import           Diagrams.Core             hiding (Measured) import           Diagrams.Located import           Diagrams.Parametric-import           Diagrams.Solve+import           Diagrams.Solve.Polynomial +import           Data.Serialize            (Serialize)+import qualified Data.Serialize            as Serialize  ------------------------------------------------------------ --  Open/closed type tags  ---------------------------------@@ -102,23 +109,35 @@ --   the context, /i.e./ its endpoint is not fixed.  The offset for a --   /closed/ segment is stored explicitly, /i.e./ its endpoint is at --   a fixed offset from its start.-data Offset c v where-  OffsetOpen   :: Offset Open v-  OffsetClosed :: !v -> Offset Closed v+data Offset c v n where+  OffsetOpen   :: Offset Open v n+  OffsetClosed :: v n -> Offset Closed v n -deriving instance Show v => Show (Offset c v)-deriving instance Eq   v => Eq   (Offset c v)-deriving instance Ord  v => Ord  (Offset c v)+deriving instance Show (v n) => Show (Offset c v n)+deriving instance Eq   (v n) => Eq   (Offset c v n)+deriving instance Ord  (v n) => Ord  (Offset c v n) -instance Functor (Offset c) where+instance Functor v => Functor (Offset c v) where   fmap _ OffsetOpen       = OffsetOpen-  fmap f (OffsetClosed v) = OffsetClosed (f v)+  fmap f (OffsetClosed v) = OffsetClosed (fmap f v) -type instance V (Offset c v) = v+instance Each (Offset c v n) (Offset c v' n') (v n) (v' n') where+  each f (OffsetClosed v) = OffsetClosed <$> f v+  each _ OffsetOpen       = pure OffsetOpen+  {-# INLINE each #-} -instance HasLinearMap v => Transformable (Offset c v) where-  transform = fmap . apply+-- | Reverses the direction of closed offsets.+instance (Additive v, Num n) => Reversing (Offset c v n) where+  reversing (OffsetClosed off) = OffsetClosed $ negated off+  reversing a@OffsetOpen       = a +type instance V (Offset c v n) = v+type instance N (Offset c v n) = n++instance Transformable (Offset c v n) where+  transform _ OffsetOpen       = OffsetOpen+  transform t (OffsetClosed v) = OffsetClosed (apply t v)+ ------------------------------------------------------------ --  Constructing segments  --------------------------------- ------------------------------------------------------------@@ -130,34 +149,62 @@ --   \"location\" and are unaffected by translations.  They are, --   however, affected by other transformations such as rotations and --   scales.-data Segment c v-    = Linear !(Offset c v)+data Segment c v n+    = Linear !(Offset c v n)       -- ^ A linear segment with given offset. -    | Cubic !v !v !(Offset c v)+    | Cubic !(v n) !(v n) !(Offset c v n)       -- ^ A cubic Bézier segment specified by       --   three offsets from the starting       --   point to the first control point,       --   second control point, and ending       --   point, respectively. -  deriving (Show, Functor, Eq, Ord)+  deriving (Functor, Eq, Ord) +instance Show (v n) => Show (Segment c v n) where+  showsPrec d seg = case seg of+    Linear (OffsetClosed v)       -> showParen (d > 10) $+      showString "straight " . showsPrec 11 v+    Cubic v1 v2 (OffsetClosed v3) -> showParen (d > 10) $+      showString "bézier3  " . showsPrec 11 v1 . showChar ' '+                             . showsPrec 11 v2 . showChar ' '+                             . showsPrec 11 v3+    Linear OffsetOpen             -> showString "openLinear"+    Cubic v1 v2 OffsetOpen        -> showParen (d > 10) $+      showString "openCubic " . showsPrec 11 v1 . showChar ' '+                              . showsPrec 11 v2+++instance Each (Segment c v n) (Segment c v' n') (v n) (v' n') where+  each f (Linear offset)      = Linear <$> each f offset+  each f (Cubic v1 v2 offset) = Cubic  <$> f v1 <*> f v2 <*> each f offset+  {-# INLINE each #-}++-- | Reverse the direction of a segment.+instance (Additive v, Num n) => Reversing (Segment Closed v n) where+  reversing = reverseSegment++-- | Map over the vectors of each segment.+mapSegmentVectors :: (v n -> v' n') -> Segment c v n -> Segment c v' n'+mapSegmentVectors = over each+ -- Note, can't yet have Haddock comments on GADT constructors; see -- http://trac.haskell.org/haddock/ticket/43. For now we don't need -- Segment to be a GADT but we might in the future. (?) -type instance V (Segment c v) = v+type instance V (Segment c v n) = v+type instance N (Segment c v n) = n -instance HasLinearMap v => Transformable (Segment c v) where-  transform = fmap . apply+instance Transformable (Segment c v n) where+  transform = mapSegmentVectors . apply -instance HasLinearMap v => Renderable (Segment c v) NullBackend where+instance Renderable (Segment c v n) NullBackend where   render _ _ = mempty  -- | @'straight' v@ constructs a translationally invariant linear --   segment with direction and length given by the vector @v@.-straight :: v -> Segment Closed v+straight :: v n -> Segment Closed v n straight = Linear . OffsetClosed  -- Note, if we didn't have a Linear constructor we could also create@@ -169,40 +216,50 @@ --   Bézier curve where the offsets from the first endpoint to the --   first and second control point and endpoint are respectively --   given by @c1@, @c2@, and @x@.-bezier3 :: v -> v -> v -> Segment Closed v+bezier3 :: v n -> v n -> v n -> Segment Closed v n bezier3 c1 c2 x = Cubic c1 c2 (OffsetClosed x)  -- | @bézier3@ is the same as @bezier3@, but with more snobbery.-bézier3 :: v -> v -> v -> Segment Closed v+bézier3 :: v n -> v n -> v n -> Segment Closed v n bézier3 = bezier3 -type instance Codomain (Segment Closed v) = v+type instance Codomain (Segment Closed v n) = v  -- | 'atParam' yields a parametrized view of segments as continuous --   functions @[0,1] -> v@, which give the offset from the start of --   the segment for each value of the parameter between @0@ and @1@. --   It is designed to be used infix, like @seg ``atParam`` 0.5@.-instance (VectorSpace v, Num (Scalar v)) => Parametric (Segment Closed v) where+instance (Additive v, Num n) => Parametric (Segment Closed v n) where   atParam (Linear (OffsetClosed x)) t       = t *^ x   atParam (Cubic c1 c2 (OffsetClosed x2)) t =     (3 * t'*t'*t ) *^ c1                                               ^+^ (3 * t'*t *t ) *^ c2                                               ^+^ (    t *t *t ) *^ x2     where t' = 1-t -instance Num (Scalar v) => DomainBounds (Segment Closed v)+instance Num n => DomainBounds (Segment Closed v n) -instance (VectorSpace v, Num (Scalar v)) => EndValues (Segment Closed v) where-  atStart                            = const zeroV+instance (Additive v, Num n) => EndValues (Segment Closed v n) where+  atStart                            = const zero   atEnd (Linear (OffsetClosed v))    = v   atEnd (Cubic _ _ (OffsetClosed v)) = v  -- | Compute the offset from the start of a segment to the --   end.  Note that in the case of a Bézier segment this is /not/ the --   same as the length of the curve itself; for that, see 'arcLength'.-segOffset :: Segment Closed v -> v+segOffset :: Segment Closed v n -> v n segOffset (Linear (OffsetClosed v))    = v segOffset (Cubic _ _ (OffsetClosed v)) = v +-- | An open linear segment. This means the trail makes a straight line+-- from the last segment the beginning to form a loop.+openLinear :: Segment Open v n+openLinear = Linear OffsetOpen++-- | An open cubic segment. This means the trail makes a cubic bézier+-- with control vectors @v1@ and @v2@ to form a loop.+openCubic :: v n -> v n -> Segment Open v n+openCubic v1 v2 = Cubic v1 v2 OffsetOpen+ ------------------------------------------------------------ --  Computing segment envelope  ------------------------------ ------------------------------------------------------------@@ -230,63 +287,68 @@ -}  -- | The envelope for a segment is based at the segment's start.-instance (InnerSpace v, OrderedField (Scalar v)) => Enveloped (Segment Closed v) where+instance (Metric v, OrderedField n) => Enveloped (Segment Closed v n) where    getEnvelope (s@(Linear {})) = mkEnvelope $ \v ->-    maximum (map (\t -> ((s `atParam` t) <.> v)) [0,1]) / magnitudeSq v+    maximum (map (\t -> (s `atParam` t) `dot` v) [0,1]) / quadrance v    getEnvelope (s@(Cubic c1 c2 (OffsetClosed x2))) = mkEnvelope $ \v ->     maximum .-    map (\t -> ((s `atParam` t) <.> v) / magnitudeSq v) $+    map (\t -> ((s `atParam` t) `dot` v) / quadrance v) $     [0,1] ++     filter (liftA2 (&&) (>0) (<1))-      (quadForm (3 * ((3 *^ c1 ^-^ 3 *^ c2 ^+^ x2) <.> v))-                (6 * (((-2) *^ c1 ^+^ c2) <.> v))-                ((3 *^ c1) <.> v))+      (quadForm (3 * ((3 *^ c1 ^-^ 3 *^ c2 ^+^ x2) `dot` v))+                (6 * (((-2) *^ c1 ^+^ c2) `dot` v))+                ((3 *^ c1) `dot` v))  ------------------------------------------------------------ --  Manipulating segments ------------------------------------------------------------ -instance (VectorSpace v, Fractional (Scalar v)) => Sectionable (Segment Closed v) where+instance (Additive v, Fractional n) => Sectionable (Segment Closed v n) where   splitAtParam (Linear (OffsetClosed x1)) t = (left, right)     where left  = straight p           right = straight (x1 ^-^ p)-          p = lerp zeroV x1 t+          p = lerp t zero x1   splitAtParam (Cubic c1 c2 (OffsetClosed x2)) t = (left, right)     where left  = bezier3 a b e           right = bezier3 (c ^-^ e) (d ^-^ e) (x2 ^-^ e)-          p = lerp c1    c2 t-          a = lerp zeroV c1 t-          b = lerp a     p  t-          d = lerp c2    x2 t-          c = lerp p     d  t-          e = lerp b     c  t+          p = lerp t c1 c2+          a = lerp t zero c1+          b = lerp t a p+          d = lerp t c2 x2+          c = lerp t p d+          e = lerp t b c    reverseDomain = reverseSegment  -- | Reverse the direction of a segment.-reverseSegment :: AdditiveGroup v => Segment Closed v -> Segment Closed v-reverseSegment (Linear (OffsetClosed v))       = straight (negateV v)-reverseSegment (Cubic c1 c2 (OffsetClosed x2)) = bezier3 (c2 ^-^ x2) (c1 ^-^ x2) (negateV x2)+reverseSegment :: (Num n, Additive v) => Segment Closed v n -> Segment Closed v n+reverseSegment (Linear (OffsetClosed v))       = straight (negated v)+reverseSegment (Cubic c1 c2 (OffsetClosed x2)) = bezier3 (c2 ^-^ x2) (c1 ^-^ x2) (negated x2) -instance (InnerSpace v, Floating (Scalar v), Ord (Scalar v), AdditiveGroup v)-      => HasArcLength (Segment Closed v) where+-- Imitates I.elem for intervals<0.8 and I.member for intervals>=0.8+member :: Ord a => a -> I.Interval a -> Bool+member x (I.I a b) = x >= a && x <= b+{-# INLINE member #-} -  arcLengthBounded _ (Linear (OffsetClosed x1)) = I.singleton $ magnitude x1+instance (Metric v, OrderedField n)+      => HasArcLength (Segment Closed v n) where++  arcLengthBounded _ (Linear (OffsetClosed x1)) = I.singleton $ norm x1   arcLengthBounded m s@(Cubic c1 c2 (OffsetClosed x2))     | ub - lb < m = I lb ub     | otherwise   = arcLengthBounded (m/2) l + arcLengthBounded (m/2) r    where (l,r) = s `splitAtParam` 0.5-         ub    = sum (map magnitude [c1, c2 ^-^ c1, x2 ^-^ c2])-         lb    = magnitude x2+         ub    = sum (map norm [c1, c2 ^-^ c1, x2 ^-^ c2])+         lb    = norm x2    arcLengthToParam m s _ | arcLength m s == 0 = 0.5   arcLengthToParam m s@(Linear {}) len = len / arcLength m s   arcLengthToParam m s@(Cubic {})  len-    | len `I.elem` (I (-m/2) (m/2)) = 0+    | len `member` I (-m/2) (m/2) = 0     | len < 0              = - arcLengthToParam m (fst (splitAtParam s (-1))) (-len)-    | len `I.elem` slen    = 1+    | len `member` slen    = 1     | len > I.sup slen     = 2 * arcLengthToParam m (fst (splitAtParam s 2)) len     | len < I.sup llen     = (*0.5) $ arcLengthToParam m l len     | otherwise            = (+0.5) . (*0.5)@@ -308,39 +370,30 @@ --   (Segment Closed v)@, as witnessed by 'mkFixedSeg' and --   'fromFixedSeg', but @FixedSegment@ is convenient when one needs --   the absolute locations of the vertices and control points.-data FixedSegment v = FLinear (Point v) (Point v)-                    | FCubic (Point v) (Point v) (Point v) (Point v)-  deriving Show+data FixedSegment v n = FLinear (Point v n) (Point v n)+                      | FCubic (Point v n) (Point v n) (Point v n) (Point v n)+  deriving (Eq, Ord, Show) -type instance V (FixedSegment v) = v+type instance V (FixedSegment v n) = v+type instance N (FixedSegment v n) = n -instance HasLinearMap v => Transformable (FixedSegment v) where-  transform t (FLinear p1 p2)-    = FLinear-      (transform t p1)-      (transform t p2)+instance Each (FixedSegment v n) (FixedSegment v' n') (Point v n) (Point v' n') where+  each f (FLinear p0 p1)      = FLinear <$> f p0 <*> f p1+  each f (FCubic p0 p1 p2 p3) = FCubic  <$> f p0 <*> f p1 <*> f p2 <*> f p3+  {-# INLINE each #-} -  transform t (FCubic p1 c1 c2 p2)-    = FCubic-      (transform t p1)-      (transform t c1)-      (transform t c2)-      (transform t p2)+-- | Reverses the control points.+instance Reversing (FixedSegment v n) where+  reversing (FLinear p0 p1)      = FLinear p1 p0+  reversing (FCubic p0 p1 p2 p3) = FCubic p3 p2 p1 p0 -instance VectorSpace v => HasOrigin (FixedSegment v) where-  moveOriginTo o (FLinear p1 p2)-    = FLinear-      (moveOriginTo o p1)-      (moveOriginTo o p2)+instance (Additive v, Num n) => Transformable (FixedSegment v n) where+  transform t = over each (papply t) -  moveOriginTo o (FCubic p1 c1 c2 p2)-    = FCubic-      (moveOriginTo o p1)-      (moveOriginTo o c1)-      (moveOriginTo o c2)-      (moveOriginTo o p2)+instance (Additive v, Num n) => HasOrigin (FixedSegment v n) where+  moveOriginTo o = over each (moveOriginTo o) -instance (InnerSpace v, OrderedField (Scalar v)) => Enveloped (FixedSegment v) where+instance (Metric v, OrderedField n) => Enveloped (FixedSegment v n) where   getEnvelope f = moveTo p (getEnvelope s)     where (p, s) = viewLoc $ fromFixedSeg f @@ -349,57 +402,67 @@     -- Envelope, and implement the Segment instance in terms of it,     -- instead of the other way around +instance (Metric v, OrderedField n)+      => HasArcLength (FixedSegment v n) where+  arcLengthBounded m s = arcLengthBounded m (fromFixedSeg s)+  arcLengthToParam m s = arcLengthToParam m (fromFixedSeg s)+ -- | Create a 'FixedSegment' from a located 'Segment'.-mkFixedSeg :: AdditiveGroup v => Located (Segment Closed v) -> FixedSegment v+mkFixedSeg :: (Num n, Additive v) => Located (Segment Closed v n) -> FixedSegment v n mkFixedSeg ls =   case viewLoc ls of     (p, Linear (OffsetClosed v))       -> FLinear p (p .+^ v)     (p, Cubic c1 c2 (OffsetClosed x2)) -> FCubic  p (p .+^ c1) (p .+^ c2) (p .+^ x2)  -- | Convert a 'FixedSegment' back into a located 'Segment'.-fromFixedSeg :: AdditiveGroup v => FixedSegment v -> Located (Segment Closed v)+fromFixedSeg :: (Num n, Additive v) => FixedSegment v n -> Located (Segment Closed v n) fromFixedSeg (FLinear p1 p2)      = straight (p2 .-. p1) `at` p1 fromFixedSeg (FCubic x1 c1 c2 x2) = bezier3 (c1 .-. x1) (c2 .-. x1) (x2 .-. x1) `at` x1 -type instance Codomain (FixedSegment v) = Point v+-- | Use a 'FixedSegment' to make an 'Iso' between an+-- a fixed segment and a located segment.+fixedSegIso :: (Num n, Additive v) => Iso' (FixedSegment v n) (Located (Segment Closed v n))+fixedSegIso = iso fromFixedSeg mkFixedSeg -instance VectorSpace v => Parametric (FixedSegment v) where-  atParam (FLinear p1 p2) t = alerp p1 p2 t+type instance Codomain (FixedSegment v n) = Point v++instance (Additive v, Num n) => Parametric (FixedSegment v n) where+  atParam (FLinear p1 p2) t = lerp t p1 p2   atParam (FCubic x1 c1 c2 x2) t = p3-    where p11 = alerp x1 c1 t-          p12 = alerp c1 c2 t-          p13 = alerp c2 x2 t+    where p11 = lerp t x1 c1+          p12 = lerp t c1 c2+          p13 = lerp t c2 x2 -          p21 = alerp p11 p12 t-          p22 = alerp p12 p13 t+          p21 = lerp t p11 p12+          p22 = lerp t p12 p13 -          p3  = alerp p21 p22 t+          p3  = lerp t p21 p22 -instance Num (Scalar v) => DomainBounds (FixedSegment v)+instance Num n => DomainBounds (FixedSegment v n) -instance (VectorSpace v, Num (Scalar v)) => EndValues (FixedSegment v) where+instance (Additive v, Num n) => EndValues (FixedSegment v n) where   atStart (FLinear p0 _)     = p0   atStart (FCubic  p0 _ _ _) = p0   atEnd   (FLinear _ p1)     = p1   atEnd   (FCubic _ _ _ p1 ) = p1 -instance (VectorSpace v, Fractional (Scalar v)) => Sectionable (FixedSegment v) where+instance (Additive v, Fractional n) => Sectionable (FixedSegment v n) where   splitAtParam (FLinear p0 p1) t = (left, right)     where left  = FLinear p0 p           right = FLinear p  p1-          p = alerp p0 p1 t+          p = lerp t p0 p1   splitAtParam (FCubic p0 c1 c2 p1) t = (left, right)     where left  = FCubic p0 a b cut           right = FCubic cut c d p1           -- first round-          a   = alerp p0 c1 t-          p   = alerp c1 c2 t-          d   = alerp c2 p1 t+          a   = lerp t p0 c1+          p   = lerp t c1 c2+          d   = lerp t c2 p1           -- second round-          b   = alerp a  p  t-          c   = alerp p  d  t+          b   = lerp t a p+          c   = lerp t p d           -- final round-          cut = alerp b  c  t+          cut = lerp t b c    reverseDomain (FLinear p0 p1) = FLinear p1 p0   reverseDomain (FCubic p0 c1 c2 p1) = FCubic p1 c2 c1 p0@@ -417,8 +480,8 @@   deriving (Semigroup, Monoid)  instance Wrapped SegCount where-    type Unwrapped SegCount = Sum Int-    _Wrapped' = iso (\(SegCount x) -> x) SegCount+  type Unwrapped SegCount = Sum Int+  _Wrapped' = iso (\(SegCount x) -> x) SegCount  instance Rewrapped SegCount SegCount @@ -428,70 +491,69 @@ --   a generic arc length function taking the tolerance as an --   argument. -newtype ArcLength v-  = ArcLength (Sum (Interval (Scalar v)), Scalar v -> Sum (Interval (Scalar v)))+newtype ArcLength n+  = ArcLength (Sum (Interval n), n -> Sum (Interval n)) -instance Wrapped (ArcLength v) where-    type Unwrapped (ArcLength v) =-        (Sum (Interval (Scalar v)), Scalar v -> Sum (Interval (Scalar v)))-    _Wrapped' = iso (\(ArcLength x) -> x) ArcLength+instance Wrapped (ArcLength n) where+  type Unwrapped (ArcLength n) = (Sum (Interval n), n -> Sum (Interval n))+  _Wrapped' = iso (\(ArcLength x) -> x) ArcLength -instance Rewrapped (ArcLength v) (ArcLength v')+instance Rewrapped (ArcLength n) (ArcLength n')  -- | Project out the cached arc length, stored together with error --   bounds.-getArcLengthCached :: ArcLength v -> Interval (Scalar v)+getArcLengthCached :: ArcLength n -> Interval n getArcLengthCached = getSum . fst . op ArcLength  -- | Project out the generic arc length function taking the tolerance as --   an argument.-getArcLengthFun :: ArcLength v -> Scalar v -> Interval (Scalar v)+getArcLengthFun :: ArcLength n -> n -> Interval n getArcLengthFun = fmap getSum . snd . op ArcLength  -- | Given a specified tolerance, project out the cached arc length if --   it is accurate enough; otherwise call the generic arc length --   function with the given tolerance.-getArcLengthBounded :: (Num (Scalar v), Ord (Scalar v))-                    => Scalar v -> ArcLength v -> Interval (Scalar v)+getArcLengthBounded :: (Num n, Ord n)+                    => n -> ArcLength n -> Interval n getArcLengthBounded eps al   | I.width cached <= eps = cached   | otherwise             = getArcLengthFun al eps   where     cached = getArcLengthCached al-deriving instance (Num (Scalar v), Ord (Scalar v)) => Semigroup (ArcLength v)-deriving instance (Num (Scalar v), Ord (Scalar v)) => Monoid    (ArcLength v)+deriving instance (Num n, Ord n) => Semigroup (ArcLength n)+deriving instance (Num n, Ord n) => Monoid    (ArcLength n)  -- | A type to represent the total cumulative offset of a chain of --   segments.-newtype TotalOffset v = TotalOffset v+newtype TotalOffset v n = TotalOffset (v n) -instance Wrapped (TotalOffset v) where-    type Unwrapped (TotalOffset v) = v-    _Wrapped' = iso (\(TotalOffset x) -> x) TotalOffset+instance Wrapped (TotalOffset v n) where+  type Unwrapped (TotalOffset v n) = v n+  _Wrapped' = iso (\(TotalOffset x) -> x) TotalOffset -instance Rewrapped (TotalOffset v) (TotalOffset v')+instance Rewrapped (TotalOffset v n) (TotalOffset v' n') -instance AdditiveGroup v => Semigroup (TotalOffset v) where+instance (Num n, Additive v) => Semigroup (TotalOffset v n) where   TotalOffset v1 <> TotalOffset v2 = TotalOffset (v1 ^+^ v2) -instance AdditiveGroup v => Monoid (TotalOffset v) where-  mempty  = TotalOffset zeroV+instance (Num n, Additive v) => Monoid (TotalOffset v n) where+  mempty  = TotalOffset zero   mappend = (<>)  -- | A type to represent the offset and envelope of a chain of --   segments.  They have to be paired into one data structure, since --   combining the envelopes of two consecutive chains needs to take---   the offset of the the offset of the first into account.-data OffsetEnvelope v = OffsetEnvelope-  { _oeOffset   :: !(TotalOffset v)-  , _oeEnvelope :: Envelope v+--   the offset of the first into account.+data OffsetEnvelope v n = OffsetEnvelope+  { _oeOffset   :: !(TotalOffset v n)+  , _oeEnvelope :: Envelope v n   }  makeLenses ''OffsetEnvelope -instance (InnerSpace v, OrderedField (Scalar v)) => Semigroup (OffsetEnvelope v) where+instance (Metric v, OrderedField n) => Semigroup (OffsetEnvelope v n) where   (OffsetEnvelope o1 e1) <> (OffsetEnvelope o2 e2)-    = let !negOff = negateV . op TotalOffset $ o1+    = let !negOff = negated . op TotalOffset $ o1           e2Off = moveOriginBy negOff e2           !_unused = maybe () (\f -> f `seq` ()) $ appEnvelope e2Off       in OffsetEnvelope@@ -500,32 +562,75 @@  -- | @SegMeasure@ collects up all the measurements over a chain of --   segments.-type SegMeasure v = SegCount-                ::: ArcLength v-                ::: OffsetEnvelope v-                ::: ()+type SegMeasure v n = SegCount+                  ::: ArcLength n+                  ::: OffsetEnvelope v n+                  ::: ()   -- unfortunately we can't cache Trace, since there is not a generic   -- instance Traced (Segment Closed v), only Traced (Segment Closed R2). -instance (InnerSpace v, OrderedField (Scalar v))-    => Measured (SegMeasure v) (SegMeasure v) where+instance (Metric v, OrderedField n)+    => Measured (SegMeasure v n) (SegMeasure v n) where   measure = id -instance (OrderedField (Scalar v), InnerSpace v)-    => Measured (SegMeasure v) (Segment Closed v) where-  measure s = (SegCount . Sum $ 1)+instance (OrderedField n, Metric v)+    => Measured (SegMeasure v n) (Segment Closed v n) where+  measure s = (SegCount . Sum) 1              -- cache arc length with two orders of magnitude more             -- accuracy than standard, so we have a hope of coming out             -- with an accurate enough total arc length for             -- reasonable-length trails-           *: (ArcLength $ ( Sum $ arcLengthBounded (stdTolerance/100) s-                           , Sum . flip arcLengthBounded s-                           )-              )+            *: ArcLength ( Sum $ arcLengthBounded (stdTolerance/100) s+                         , Sum . flip arcLengthBounded s               ) -           *: (OffsetEnvelope-                (TotalOffset . segOffset $ s)-                (getEnvelope s)-              )-           *: ()+            *: OffsetEnvelope (TotalOffset . segOffset $ s)+                              (getEnvelope s)++            *: ()++------------------------------------------------------------+--  Serialize instances+------------------------------------------------------------++instance (Serialize (v n)) => Serialize (Segment Open v n) where+  {-# INLINE put #-}+  put segment = case segment of+    Linear OffsetOpen    -> Serialize.put True+    Cubic v w OffsetOpen -> do+      Serialize.put False+      Serialize.put v+      Serialize.put w++  {-# INLINE get #-}+  get = do+    isLinear <- Serialize.get+    case isLinear of+      True  -> return (Linear OffsetOpen)+      False -> do+        v <- Serialize.get+        w <- Serialize.get+        return (Cubic v w OffsetOpen)++instance (Serialize (v n)) => Serialize (Segment Closed v n) where+  {-# INLINE put #-}+  put segment = case segment of+    Linear (OffsetClosed z)    -> do+      Serialize.put z+      Serialize.put True+    Cubic v w (OffsetClosed z) -> do+      Serialize.put z+      Serialize.put False+      Serialize.put v+      Serialize.put w++  {-# INLINE get #-}+  get = do+    z <- Serialize.get+    isLinear <- Serialize.get+    case isLinear of+      True  -> return (Linear (OffsetClosed z))+      False -> do+        v <- Serialize.get+        w <- Serialize.get+        return (Cubic v w (OffsetClosed z))
+ src/Diagrams/Size.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE ConstraintKinds            #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE UndecidableInstances       #-}+{-# LANGUAGE ViewPatterns               #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.Size+-- Copyright   :  (c) 2014 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Utilities for working with sizes of objects.+--+-----------------------------------------------------------------------------+module Diagrams.Size+  ( -- * Size spec+    SizeSpec++    -- ** Making size spec+  , mkSizeSpec+  , dims+  , absolute++    -- ** Extracting size specs+  , getSpec+  , specToSize++    -- ** Functions on size specs+  , requiredScale+  , requiredScaling+  , sized+  , sizedAs+  , sizeAdjustment+  ) where++import           Control.Applicative+import           Control.Lens         hiding (transform)+import           Control.Monad+import           Data.Foldable        as F+import           Data.Hashable+import           Data.Maybe+import           Data.Semigroup+import           Data.Typeable+import           GHC.Generics         (Generic)+import           Prelude++import           Diagrams.BoundingBox+import           Diagrams.Core++import           Linear.Affine+import           Linear.Vector++------------------------------------------------------------+-- Computing diagram sizes+------------------------------------------------------------++-- | A 'SizeSpec' is a way of specifying a size without needed lengths for all+--   the dimensions.+newtype SizeSpec v n = SizeSpec (v n)+  deriving (+  Eq,+  Typeable,+  Functor,+  Generic,+  Hashable,+  Show)++type instance V (SizeSpec v n) = v+type instance N (SizeSpec v n) = n++-- | Retrieve a size spec as a vector of maybe values. Only positive sizes are+--   returned.+getSpec :: (Functor v, Num n, Ord n) => SizeSpec v n -> v (Maybe n)+getSpec (SizeSpec sp) = mfilter (>0) . Just <$> sp++-- | Make a 'SizeSpec' from a vector of maybe values. Any negative values will+--   be ignored. For 2D 'SizeSpec's see 'mkWidth' and 'mkHeight' from+--   "Diagrams.TwoD.Size".+mkSizeSpec :: (Functor v, Num n) => v (Maybe n) -> SizeSpec v n+mkSizeSpec = dims . fmap (fromMaybe 0)++-- | Make a 'SizeSpec' from a vector. Any negative values will be ignored.+dims :: v n -> SizeSpec v n+dims = SizeSpec++-- | A size spec with no hints to the size.+absolute :: (Additive v, Num n) => SizeSpec v n+absolute = SizeSpec zero++-- | @specToSize n spec@ extracts a size from a 'SizeSpec' @sz@. Any values not+--   specified in the spec are replaced by the smallest of the values that are+--   specified. If there are no specified values (i.e. 'absolute') then @n@ is+--   used.+specToSize :: (Foldable v, Functor v, Num n, Ord n) => n -> SizeSpec v n -> v n+specToSize n (getSpec -> spec) = fmap (fromMaybe smallest) spec+  where+    smallest = fromMaybe n $ minimumOf (folded . _Just) spec++-- | @requiredScale spec sz@ returns the largest scaling factor to make+--   something of size @sz@ fit the requested size @spec@ without changing the+--   aspect ratio. @sz@ should be non-zero (otherwise a scale of 1 is+--   returned). For non-uniform scaling see 'boxFit'.+requiredScale :: (Additive v, Foldable v, Fractional n, Ord n)+              => SizeSpec v n -> v n -> n+requiredScale (getSpec -> spec) sz+  | allOf (folded . _Just) (<= 0) usedSz = 1+  | otherwise                            = fromMaybe 1 mScale+  where+    usedSz = liftI2 (<$) sz spec+    scales = liftI2 (^/) spec sz+    mScale = minimumOf (folded . _Just) scales++-- | Return the 'Transformation' calcuated from 'requiredScale'.+requiredScaling :: (Additive v, Foldable v, Fractional n, Ord n)+  => SizeSpec v n -> v n -> Transformation v n+requiredScaling spec = scaling . requiredScale spec++-- | Uniformly scale any enveloped object so that it fits within the+--   given size. For non-uniform scaling see 'boxFit'.+sized :: (InSpace v n a, HasLinearMap v, Transformable a, Enveloped a)+      => SizeSpec v n -> a -> a+sized spec a = transform (requiredScaling spec (size a)) a++-- | Uniformly scale an enveloped object so that it \"has the same+--   size as\" (fits within the width and height of) some other+--   object.+sizedAs :: (InSpace v n a, SameSpace a b, HasLinearMap v, Transformable a,+            Enveloped a, Enveloped b)+        => b -> a -> a+sizedAs other = sized (dims $ size other)++-- | Get the adjustment to fit a 'BoundingBox' in the given 'SizeSpec'. The+--   vector is the new size and the transformation to position the lower+--   corner at the origin and scale to the size spec.+sizeAdjustment :: (Additive v, Foldable v, OrderedField n)+  => SizeSpec v n -> BoundingBox v n -> (v n, Transformation v n)+sizeAdjustment spec bb = (sz', t)+  where+    v = (0.5 *^ P sz') .-. (s *^ fromMaybe origin (boxCenter bb))++    sz  = boxExtents bb+    sz' = if allOf folded isJust (getSpec spec)+            then specToSize 0 spec+            else s *^ sz++    s = requiredScale spec sz++    t = translation v <> scaling s
− src/Diagrams/Solve.hs
@@ -1,187 +0,0 @@--------------------------------------------------------------------------------- |--- Module      :  Diagrams.Solve--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)--- License     :  BSD-style (see LICENSE)--- Maintainer  :  diagrams-discuss@googlegroups.com------ Exact solving of low-degree (n <= 4) polynomials.----------------------------------------------------------------------------------module Diagrams.Solve-       ( quadForm-       , cubForm-       , quartForm-       , cubForm'-       , quartForm'-       ) where--import           Data.List     (maximumBy)-import           Data.Ord      (comparing)--import           Diagrams.Util (tau)--import           Prelude hiding ((^))-import qualified Prelude as P ((^))---- | A specialization of (^) to Integer---   c.f. http://comments.gmane.org/gmane.comp.lang.haskell.libraries/21164---   for discussion. "The choice in (^) and (^^) to overload on the---   power's Integral type... was a genuinely bad idea." - Edward Kmett-(^) :: (Num a) => a -> Integer -> a-(^) = (P.^)---- | Utility function used to avoid singularities-aboutZero' :: (Ord a, Num a) => a -> a -> Bool-aboutZero' toler x = abs x < toler----------------------------------------------------------------- Quadratic formula----------------------------------------------------------------- | The quadratic formula.-quadForm :: (Floating d, Ord d) => d -> d -> d -> [d]-quadForm a b c--    -- There are infinitely many solutions in this case,-    -- so arbitrarily return 0-  | a == 0 && b == 0 && c == 0 = [0]--    -- c /= 0-  | a == 0 && b == 0 = []--    -- linear-  | a == 0    = [-c/b]--    -- no real solutions-  | d < 0     = []--    -- ax^2 + c = 0-  | b == 0    = [sqrt (-c/a), -sqrt (-c/a)]--    -- multiplicity 2 solution-  | d == 0    = [-b/(2*a)]--    -- see http://www.mpi-hd.mpg.de/astrophysik/HEA/internal/Numerical_Recipes/f5-6.pdf-  | otherwise = [q/a, c/q]- where d = b^2 - 4*a*c-       q = -1/2*(b + signum b * sqrt d)--_quadForm_prop :: Double -> Double -> Double -> Bool-_quadForm_prop a b c = all (aboutZero' 1e-10 . eval) (quadForm a b c)-  where eval x = a*x^2 + b*x + c----------------------------------------------------------------- Cubic formula----------------------------------------------------------------- See http://en.wikipedia.org/wiki/Cubic_formula#General_formula_of_roots---- | Solve the cubic equation ax^3 + bx^2 + cx + d = 0, returning a---   list of all real roots. First argument is tolerance.-cubForm' :: (Floating d, Ord d) => d -> d -> d -> d -> d -> [d]-cubForm' toler a b c d-  | aboutZero' toler a      = quadForm b c d--    -- three real roots, use trig method to avoid complex numbers-  | delta >  0              = map trig [0,1,2]--    -- one real root of multiplicity 3-  | delta == 0 && disc == 0 = [ -b/(3*a) ]--    -- two real roots, one of multiplicity 2-  | delta == 0 && disc /= 0 = [ (b*c - 9*a*d)/(2*disc)-                              , (9*a^2*d - 4*a*b*c + b^3)/(a * disc)-                              ]--    -- one real root (and two complex)-  | otherwise               = [-b/(3*a) - cc/(3*a) + disc/(3*a*cc)]-- where delta  = 18*a*b*c*d - 4*b^3*d + b^2*c^2 - 4*a*c^3 - 27*a^2*d^2-       disc   = 3*a*c - b^2-       qq     = sqrt(-27*(a^2)*delta)-       qq'    | aboutZero' toler disc = maximumBy (comparing (abs . (+xx))) [qq, -qq]-              | otherwise = qq-       cc     = cubert (1/2*(qq' + xx))-       xx     = 2*b^3 - 9*a*b*c + 27*a^2*d-       p      = disc/(3*a^2)-       q      = xx/(27*a^3)-       phi = 1/3*acos(3*q/(2*p)*sqrt(-3/p))-       trig k = 2 * sqrt(-p/3) * cos(phi - k*tau/3) - b/(3*a)-       cubert x | x < 0     = -((-x)**(1/3))-                | otherwise = x**(1/3)---- | Solve the cubic equation ax^3 + bx^2 + cx + d = 0, returning a---   list of all real roots within 1e-10 tolerance---   (although currently it's closer to 1e-5)-cubForm :: (Floating d, Ord d) => d -> d -> d -> d -> [d]-cubForm = cubForm' 1e-10--_cubForm_prop :: Double -> Double -> Double -> Double -> Bool-_cubForm_prop a b c d = all (aboutZero' 1e-5 . eval) (cubForm a b c d)-  where eval x = a*x^3 + b*x^2 + c*x + d-           -- Basically, however large you set the tolerance it seems-           -- that quickcheck can always come up with examples where-           -- the returned solutions evaluate to something near zero-           -- but larger than the tolerance (but it takes it more-           -- tries the larger you set the tolerance). Wonder if this-           -- is an inherent limitation or (more likely) a problem-           -- with numerical stability.  If this turns out to be an-           -- issue in practice we could, say, use the solutions-           -- generated here as very good guesses to a numerical-           -- solver which can give us a more precise answer?-           ---------------------------------------------------------------- Quartic formula----------------------------------------------------------------- Based on http://tog.acm.org/resources/GraphicsGems/gems/Roots3b/and4.c--- as of 5/12/14, with help from http://en.wikipedia.org/wiki/Quartic_function---- | Solve the quartic equation c4 x^4 + c3 x^3 + c2 x^2 + c1 x + c0 = 0, returning a---   list of all real roots. First argument is tolerance.-quartForm' :: (Floating d, Ord d) => d -> d -> d -> d -> d -> d -> [d]-quartForm' toler c4 c3 c2 c1 c0-  -- obvious cubic-  | aboutZero' toler c4 = cubForm c3 c2 c1 c0-  -- x(ax^3+bx^2+cx+d)-  | aboutZero' toler c0 = 0 : cubForm c4 c3 c2 c1-  -- substitute solutions of y back to x-  | otherwise = map (\x->x-(a/4)) roots-    where-      -- eliminate c4: x^4+ax^3+bx^2+cx+d-      [a,b,c,d] = map (/c4) [c3,c2,c1,c0]-      -- eliminate cubic term via x = y - a/4-      -- reduced quartic: y^4 + py^2 + qy + r = 0-      p = b - 3/8*a^2-      q = 1/8*a^3-a*b/2+c-      r = (-3/256)*a^4+a^2*b/16-a*c/4+d--      -- | roots of the reduced quartic-      roots | aboutZero' toler r =-                0 : cubForm 1 0 p q   -- no constant term: y(y^3 + py + q) = 0-            | u < 0 || v < 0 = []     -- no real solutions due to square root-            | otherwise      = s1++s2 -- solutions of the quadratics--      -- solve the resolvent cubic - only one solution is needed-      z:_ = cubForm 1 (-p/2) (-r) (p*r/2 - q^2/8)-      -      -- solve the two quadratic equations-      -- y^2 ± v*y-(±u-z)-      u = z^2 - r-      v = 2*z - p-      u' = if aboutZero' toler u then 0 else sqrt u-      v' = if aboutZero' toler v then 0 else sqrt v-      s1 = quadForm 1 (if q<0 then -v' else v') (z-u')-      s2 = quadForm 1 (if q<0 then v' else -v') (z+u')---- | Solve the quartic equation c4 x^4 + c3 x^3 + c2 x^2 + c1 x + c0 = 0, returning a---   list of all real roots within 1e-10 tolerance---   (although currently it's closer to 1e-5)-quartForm :: (Floating d, Ord d) => d -> d -> d -> d -> d -> [d]-quartForm = quartForm' 1e-10--_quartForm_prop :: Double -> Double -> Double -> Double -> Double -> Bool-_quartForm_prop a b c d e = all (aboutZero' 1e-5 . eval) (quartForm a b c d e)-  where eval x = a*x^4 + b*x^3 + c*x^2 + d*x + e-           -- Same note about tolerance as for cubic
src/Diagrams/Tangent.hs view
@@ -1,6 +1,7 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE GADTs                #-} -- for ghc < 7.8, TypeFamilies covers GADT patten mathcing in > 7.8 {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE GADTs                #-} {-# LANGUAGE TypeFamilies         #-} {-# LANGUAGE UndecidableInstances #-} @@ -15,27 +16,30 @@ -- ----------------------------------------------------------------------------- module Diagrams.Tangent-    ( tangentAtParam+    ( -- ** Tangents+      tangentAtParam     , tangentAtStart     , tangentAtEnd++      -- ** Normals     , normalAtParam     , normalAtStart     , normalAtEnd++      -- ** Tangent newtype     , Tangent(..)     )     where -import           Control.Lens         (cloneIso, (^.))--import           Data.VectorSpace import           Diagrams.Core import           Diagrams.Located import           Diagrams.Parametric import           Diagrams.Segment-import           Diagrams.Trail-import           Diagrams.TwoD.Types  (R2)-import           Diagrams.TwoD.Vector (perp) +import           Linear.Vector+import           Linear.Metric+import           Linear.V2+ ------------------------------------------------------------ -- Tangent ------------------------------------------------------------@@ -45,13 +49,13 @@ newtype Tangent t = Tangent t  type instance V (Tangent t) = V t+type instance N (Tangent t) = N t+type instance Codomain (Tangent t) = V t  instance DomainBounds t => DomainBounds (Tangent t) where   domainLower (Tangent t) = domainLower t   domainUpper (Tangent t) = domainUpper t -type instance Codomain (Tangent (Located t)) = Codomain (Tangent t)- instance Parametric (Tangent t) => Parametric (Tangent (Located t)) where   Tangent l `atParam` p = Tangent (unLoc l) `atParam` p @@ -65,92 +69,48 @@ -- --   Examples of more specific types this function can have include -----   * @Segment Closed R2 -> Double -> R2@+--   * @Segment Closed V2 -> Double -> V2 Double@ -----   * @Trail' Line R2 -> Double -> R2@+--   * @Trail' Line V2 -> Double -> V2 Double@ -----   * @Located (Trail R2) -> Double -> R2@+--   * @Located (Trail V2) -> Double -> V2 Double@ -- --   See the instances listed for the 'Tangent' newtype for more.-tangentAtParam :: Parametric (Tangent t) => t -> Scalar (V t) -> Codomain (Tangent t)+tangentAtParam :: Parametric (Tangent t) => t -> N t -> Vn t tangentAtParam t p = Tangent t `atParam` p  -- | Compute the tangent vector at the start of a segment or trail.-tangentAtStart :: EndValues (Tangent t) => t -> Codomain (Tangent t)+tangentAtStart :: EndValues (Tangent t) => t -> Vn t tangentAtStart = atStart . Tangent  -- | Compute the tangent vector at the end of a segment or trail.-tangentAtEnd :: EndValues (Tangent t) => t -> Codomain (Tangent t)+tangentAtEnd :: EndValues (Tangent t) => t -> Vn t tangentAtEnd = atEnd . Tangent  -------------------------------------------------- -- Segment -type instance Codomain (Tangent (Segment Closed v)) = Codomain (Segment Closed v)--instance (VectorSpace v, Num (Scalar v))-    => Parametric (Tangent (Segment Closed v)) where+instance (Additive v, Num n)+    => Parametric (Tangent (Segment Closed v n)) where   Tangent (Linear (OffsetClosed v)) `atParam` _ = v   Tangent (Cubic c1 c2 (OffsetClosed x2)) `atParam` p     = (3*(3*p*p-4*p+1))*^c1 ^+^ (3*(2-3*p)*p)*^c2 ^+^ (3*p*p)*^x2 -instance (VectorSpace v, Num (Scalar v))-    => EndValues (Tangent (Segment Closed v)) where+instance (Additive v, Num n)+    => EndValues (Tangent (Segment Closed v n)) where   atStart (Tangent (Linear (OffsetClosed v)))      = v   atStart (Tangent (Cubic c1 _ _))                 = c1   atEnd   (Tangent (Linear (OffsetClosed v)))      = v   atEnd   (Tangent (Cubic _ c2 (OffsetClosed x2))) = x2 ^-^ c2 ------------------------------------------------------ Trail' and Trail--type instance Codomain (Tangent (Trail' c v)) = Codomain (Trail' c v)--instance ( Parametric (GetSegment (Trail' c v))-         , VectorSpace v-         , Num (Scalar v)-         )-    => Parametric (Tangent (Trail' c v)) where-  Tangent tr `atParam` p =-    case GetSegment tr `atParam` p of-      Nothing                -> zeroV-      Just (_, seg, reparam) -> Tangent seg `atParam` (p ^. cloneIso reparam)--instance ( Parametric (GetSegment (Trail' c v))-         , EndValues (GetSegment (Trail' c v))-         , VectorSpace v-         , Num (Scalar v)-         )-    => EndValues (Tangent (Trail' c v)) where-  atStart (Tangent tr) =-    case atStart (GetSegment tr) of-      Nothing          -> zeroV-      Just (_, seg, _) -> atStart (Tangent seg)-  atEnd (Tangent tr) =-    case atEnd (GetSegment tr) of-      Nothing          -> zeroV-      Just (_, seg, _) -> atEnd (Tangent seg)--type instance Codomain (Tangent (Trail v)) = Codomain (Trail v)--instance ( InnerSpace v-         , OrderedField (Scalar v)-         , RealFrac (Scalar v)-         )-    => Parametric (Tangent (Trail v)) where-  Tangent tr `atParam` p-    = withTrail-        ((`atParam` p) . Tangent)-        ((`atParam` p) . Tangent)-        tr+instance (Additive v, Num n)+    => Parametric (Tangent (FixedSegment v n)) where+  atParam (Tangent fSeg) = atParam $ Tangent (fromFixedSeg fSeg) -instance ( InnerSpace v-         , OrderedField (Scalar v)-         , RealFrac (Scalar v)-         )-    => EndValues (Tangent (Trail v)) where-  atStart (Tangent tr) = withTrail (atStart . Tangent) (atStart . Tangent) tr-  atEnd   (Tangent tr) = withTrail (atEnd   . Tangent) (atEnd   . Tangent) tr+instance (Additive v, Num n)+    => EndValues (Tangent (FixedSegment v n)) where+  atStart (Tangent fSeg) = atStart $ Tangent (fromFixedSeg fSeg)+  atEnd (Tangent fSeg)   = atEnd $ Tangent (fromFixedSeg fSeg)  ------------------------------------------------------------ -- Normal@@ -161,30 +121,30 @@ -- --   Examples of more specific types this function can have include -----   * @Segment Closed R2 -> Double -> R2@+--   * @Segment Closed V2 Double -> Double -> V2 Double@ -----   * @Trail' Line R2 -> Double -> R2@+--   * @Trail' Line V2 Double -> Double -> V2 Double@ -----   * @Located (Trail R2) -> Double -> P2@+--   * @Located (Trail V2 Double) -> Double -> V2 Double@ -- --   See the instances listed for the 'Tangent' newtype for more. normalAtParam-  :: (Codomain (Tangent t) ~ R2, Parametric (Tangent t))-  => t -> Scalar (V t) -> R2+  :: (InSpace V2 n t, Parametric (Tangent t), Floating n)+  => t -> n -> V2 n normalAtParam t p = normize (t `tangentAtParam` p)  -- | Compute the normal vector at the start of a segment or trail. normalAtStart-  :: (Codomain (Tangent t) ~ R2, EndValues (Tangent t))-  => t -> R2+  :: (InSpace V2 n t, EndValues (Tangent t), Floating n)+  => t -> V2 n normalAtStart = normize . tangentAtStart  -- | Compute the normal vector at the end of a segment or trail. normalAtEnd-  :: (Codomain (Tangent t) ~ R2, EndValues (Tangent t))-  => t -> R2+  :: (InSpace V2 n t, EndValues (Tangent t), Floating n)+  => t -> V2 n normalAtEnd = normize . tangentAtEnd  -- | Construct a normal vector from a tangent.-normize :: R2 -> R2-normize = negateV . perp . normalized+normize :: Floating n => V2 n -> V2 n+normize = negated . perp . signorm
src/Diagrams/ThreeD.hs view
@@ -4,7 +4,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD--- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2013-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -17,9 +17,11 @@ --     diagrams, including types representing the 3D Euclidean vector --     space and various systems of representing directions. -----   * "Diagrams.ThreeD.Transform" defines R^3-specific transformations---     such as rotation by an angle, and scaling, translation, and---     reflection in the X, Y, and Z directions.+--   * "Diagrams.ThreeD.Transform" defines R^3-specific+--     transformations such as rotation by an angle, and scaling,+--     translation, and reflection in the X, Y, and Z directions.+--     "Diagrams.ThreeD.Deform" defines several R^3-specific+--     non-affine transformations, such as projections. -- --   * "Diagrams.ThreeD.Shapes" defines three-dimensional solids, --     e.g. spheres and cubes.@@ -29,24 +31,32 @@ -- --   * "Diagrams.ThreeD.Light" and "Diagrams.ThreeD.Camera" define types needed --     for rendering 3D geometry to (2D) images.+--+--   * "Diagrams.ThreeD.Align" defines many alignment combinators+--     specialized to three dimensions.+--+--   * "Diagrams.ThreeD.Attributes" defines 3D-specific attributes+--     such as surface color, diffuse reflectance, and specular+--     highlights. ----------------------------------------------------------------------------- module Diagrams.ThreeD-       (-         module Diagrams.ThreeD.Align-       , module Diagrams.ThreeD.Attributes-       , module Diagrams.ThreeD.Camera-       , module Diagrams.ThreeD.Light-       , module Diagrams.ThreeD.Shapes-       , module Diagrams.ThreeD.Transform-       , module Diagrams.ThreeD.Types-       , module Diagrams.ThreeD.Vector-       ) where+  ( module Diagrams.ThreeD.Align+  , module Diagrams.ThreeD.Attributes+  , module Diagrams.ThreeD.Camera+  , module Diagrams.ThreeD.Deform+  , module Diagrams.ThreeD.Light+  , module Diagrams.ThreeD.Shapes+  , module Diagrams.ThreeD.Transform+  , module Diagrams.ThreeD.Types+  , module Diagrams.ThreeD.Vector+  ) where -import Diagrams.ThreeD.Align-import Diagrams.ThreeD.Attributes-import Diagrams.ThreeD.Camera-import Diagrams.ThreeD.Light-import Diagrams.ThreeD.Shapes-import Diagrams.ThreeD.Transform-import Diagrams.ThreeD.Types-import Diagrams.ThreeD.Vector+import           Diagrams.ThreeD.Align+import           Diagrams.ThreeD.Attributes+import           Diagrams.ThreeD.Camera+import           Diagrams.ThreeD.Deform+import           Diagrams.ThreeD.Light+import           Diagrams.ThreeD.Shapes+import           Diagrams.ThreeD.Transform+import           Diagrams.ThreeD.Types+import           Diagrams.ThreeD.Vector
src/Diagrams/ThreeD/Align.hs view
@@ -1,5 +1,7 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies     #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeFamilies    #-}+{-# LANGUAGE TypeOperators   #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD.Align@@ -44,166 +46,95 @@ import           Diagrams.Align import           Diagrams.ThreeD.Types import           Diagrams.ThreeD.Vector--import           Data.VectorSpace+import           Diagrams.TwoD.Align  -- | Translate the diagram along unitX so that all points have--- positive x-values.-alignXMin :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-alignXMin = align (negateV unitX)+--   positive x-values.+alignXMin :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a+alignXMin = align unit_X -snugXMin :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugXMin = snug (negateV unitX)+snugXMin :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a+snugXMin = snug unit_X  -- | Translate the diagram along unitX so that all points have -- negative x-values.-alignXMax :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a+alignXMax :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a alignXMax = align unitX -snugXMax :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugXMax :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugXMax = snug unitX   -- | Translate the diagram along unitY so that all points have+--   positive y-values.+alignYMin :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a+alignYMin = align unit_Y++snugYMin :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a+snugYMin = snug unit_Y++-- | Translate the diagram along unitY so that all points have -- negative y-values.-alignYMax :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a+alignYMax :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a alignYMax = align unitY --- | Move the origin along unitY until it touches the edge of the--- diagram.-snugYMax:: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugYMax :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugYMax = snug unitY --- | Translate the diagram along unitY so that all points have--- positive y-values.-alignYMin :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-alignYMin = align (negateV unitY) -snugYMin :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugYMin = snug (negateV unitY)+-- | Translate the diagram along unitZ so that all points have+--   positive z-values.+alignZMin :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a+alignZMin = align unit_Z +snugZMin :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a+snugZMin = snug unit_Z+ -- | Translate the diagram along unitZ so that all points have -- negative z-values.-alignZMax :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a+alignZMax :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a alignZMax = align unitZ --- | Move the origin along unitZ until it touches the edge of the--- diagram.-snugZMax:: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugZMax :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugZMax = snug unitZ --- | Translate the diagram along unitZ so that all points have--- positive z-values.-alignZMin :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-alignZMin = align (negateV unitZ)---- | Move the origin along unit_Z until it touches the edge of the--- diagram.-snugZMin :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugZMin = snug (negateV unitZ)---- | @alignX@ and @snugX@ move the local origin along unitX as follows:------   * @alignX (-1)@ moves the local origin to the low-x of the boundary;------   * @align 1@ moves the local origin to the high-x edge;------   * any other argument interpolates linearly between these.  For---     example, @alignX 0@ centers, @alignX 2@ moves the origin one---     \"radius\" to the right of the right edge, and so on.------   * @snugX@ works the same way.--alignX :: (Alignable a, HasOrigin a, V a ~ R3) => Double -> a -> a-alignX = alignBy unitX---- | See the documentation for 'alignX'.-snugX :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => Double -> a -> a-snugX = snugBy unitX---- | Like 'alignX', but moving the local origin vertically, with an---   argument of @1@ corresponding to the top edge and @(-1)@ corresponding---   to the bottom edge.-alignY :: (Alignable a, HasOrigin a, V a ~ R3) => Double -> a -> a-alignY = alignBy unitY--snugY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => Double -> a -> a-snugY = snugBy unitY-- -- | Like 'alignX', but moving the local origin in the Z direction, with an --   argument of @1@ corresponding to the top edge and @(-1)@ corresponding --   to the bottom edge.-alignZ :: (Alignable a, HasOrigin a, V a ~ R3) => Double -> a -> a+alignZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a alignZ = alignBy unitZ -snugZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => Double -> a -> a+-- | See the documentation for 'alignZ'.+snugZ :: (V a ~ v, N a ~ n, Alignable a, Traced a, HasOrigin a,+          R3 v, Fractional n) => n -> a -> a snugZ = snugBy unitZ --- | Center the local origin along the X-axis.-centerX  :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-centerX  = alignBy unitX 0 -snugCenterX :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugCenterX = snugBy unitX 0---- | Center the local origin along the Y-axis.-centerY  :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-centerY  = alignBy unitY 0--snugCenterY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugCenterY = snugBy unitY 0- -- | Center the local origin along the Z-axis.-centerZ  :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-centerZ  = alignBy unitZ 0+centerZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a+centerZ = alignBy unitZ 0 -snugCenterZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugCenterZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugCenterZ = snugBy unitZ 0 --- | Center along both the X- and Y-axes.-centerXY :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a-centerXY = centerX . centerY--snugCenterXY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a-snugCenterXY = snugCenterX . snugCenterY-- -- | Center along both the X- and Z-axes.-centerXZ :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a+centerXZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a centerXZ = centerX . centerZ -snugCenterXZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugCenterXZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugCenterXZ = snugCenterX . snugCenterZ   -- | Center along both the Y- and Z-axes.-centerYZ :: (Alignable a, HasOrigin a, V a ~ R3) => a -> a+centerYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a centerYZ = centerZ . centerY -snugCenterYZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugCenterYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugCenterYZ = snugCenterZ . snugCenterY  -- | Center an object in three dimensions.-centerXYZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+centerXYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a centerXYZ = centerX . centerY . centerZ -snugCenterXYZ :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R3) => a -> a+snugCenterXYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a snugCenterXYZ = snugCenterX . snugCenterY . snugCenterZ
src/Diagrams/ThreeD/Attributes.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE ExistentialQuantification  #-}+{-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE TypeFamilies               #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD.Attributes@@ -25,36 +27,43 @@  module Diagrams.ThreeD.Attributes where -import Control.Lens-import Data.Semigroup-import Data.Typeable+import           Control.Lens+import           Data.Semigroup+import           Data.Typeable -import Data.Colour+import           Data.Colour -import Diagrams.Core+import           Diagrams.Core  -- | @SurfaceColor@ is the inherent pigment of an object, assumed to -- be opaque. newtype SurfaceColor = SurfaceColor (Last (Colour Double))-                     deriving (Typeable, Semigroup)+  deriving (Typeable, Semigroup, Show)+ instance AttributeClass SurfaceColor -surfaceColor :: Iso' SurfaceColor (Colour Double)-surfaceColor = iso (\(SurfaceColor (Last c)) -> c) (SurfaceColor . Last)+_SurfaceColor :: Iso' SurfaceColor (Colour Double)+_SurfaceColor = iso (\(SurfaceColor (Last c)) -> c) (SurfaceColor . Last)  -- | Set the surface color. sc :: HasStyle d => Colour Double -> d -> d-sc = applyAttr . review surfaceColor+sc = applyAttr . review _SurfaceColor +-- | Lens onto the surface colour of a style.+_sc :: Lens' (Style v n) (Maybe (Colour Double))+_sc = atAttr . mapping _SurfaceColor+ -- | @Diffuse@ is the fraction of incident light reflected diffusely, -- that is, in all directions.  The actual light reflected is the -- product of this value, the incident light, and the @SurfaceColor@ -- Attribute.  For physical reasonableness, @Diffuse@ should have a -- value between 0 and 1; this is not checked. newtype Diffuse = Diffuse (Last Double)-                deriving (Typeable, Semigroup)+  deriving (Typeable, Semigroup, Show)+ instance AttributeClass Diffuse +-- | Isomorphism between 'Diffuse' and 'Double' _Diffuse :: Iso' Diffuse Double _Diffuse = iso (\(Diffuse (Last d)) -> d) (Diffuse . Last) @@ -62,6 +71,10 @@ diffuse :: HasStyle d => Double -> d -> d diffuse = applyAttr . review _Diffuse +-- | Lens onto the possible diffuse reflectance in a style.+_diffuse :: Lens' (Style v n) (Maybe Double)+_diffuse = atAttr . mapping _Diffuse+ -- | @Ambient@ is an ad-hoc representation of indirect lighting.  The -- product of @Ambient@ and @SurfaceColor@ is added to the light -- leaving an object due to diffuse and specular terms.  @Ambient@ can@@ -69,7 +82,8 @@ -- indirect lighting incident on that object and the diffuse -- reflectance. newtype Ambient = Ambient (Last Double)-                deriving (Typeable, Semigroup)+  deriving (Typeable, Semigroup, Show)+ instance AttributeClass Ambient  _Ambient :: Iso' Ambient Double@@ -79,6 +93,10 @@ ambient :: HasStyle d => Double -> d -> d ambient = applyAttr . review _Ambient +-- | Lens onto the possible ambience in a style.+_ambient :: Lens' (Style v n) (Maybe Double)+_ambient = atAttr . mapping _Ambient+ -- | A specular highlight has two terms, the intensity, between 0 and -- 1, and the size.  The highlight size is assumed to be the exponent -- in a Phong shading model (though Backends are free to use a@@ -86,14 +104,16 @@ -- between 1 and 50 or so, with higher values for shinier objects. -- Physically, the intensity and the value of @Diffuse@ must add up to -- less than 1; this is not enforced.-data Specular = Specular { _specularIntensity :: Double-                         , _specularSize :: Double-                         }+data Specular = Specular+  { _specularIntensity :: Double+  , _specularSize      :: Double+  } deriving Show  makeLenses ''Specular  newtype Highlight = Highlight (Last Specular)-                    deriving (Typeable, Semigroup)+  deriving (Typeable, Semigroup, Show)+ instance AttributeClass Highlight  _Highlight :: Iso' Highlight Specular@@ -102,3 +122,17 @@ -- | Set the specular highlight. highlight :: HasStyle d => Specular -> d -> d highlight = applyAttr . review _Highlight++-- | Lens onto the possible specular highlight in a style+_highlight :: Lens' (Style v n) (Maybe Specular)+_highlight = atAttr . mapping _Highlight++-- | Traversal over the highlight intensity of a style. If the style has+--   no 'Specular', setting this will do nothing.+highlightIntensity :: Traversal' (Style v n) Double+highlightIntensity = _highlight . _Just . specularSize++-- | Traversal over the highlight size in a style. If the style has no+--   'Specular', setting this will do nothing.+highlightSize :: Traversal' (Style v n) Double+highlightSize = _highlight . _Just . specularSize
src/Diagrams/ThreeD/Camera.hs view
@@ -1,9 +1,10 @@ {-# LANGUAGE DeriveDataTypeable    #-} {-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE GADTs                 #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-} {-# LANGUAGE TemplateHaskell       #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE UndecidableInstances  #-}  ----------------------------------------------------------------------------- -- |@@ -30,81 +31,91 @@        where  import           Control.Lens           (makeLenses)-import           Data.Cross import           Data.Monoid import           Data.Typeable  import           Diagrams.Angle import           Diagrams.Core-import           Diagrams.ThreeD.Types+import           Diagrams.Direction import           Diagrams.ThreeD.Vector +import           Linear.V3+ -- Parameterize Camera on the lens type, so that Backends can express which -- lenses they handle.-data Camera l = Camera-    { camLoc  :: P3-    , forward :: R3-    , up      :: R3-    , lens    :: l+data Camera l n = Camera+    { camLoc  :: Point V3 n+    , forward :: V3 n+    , up      :: V3 n+    , lens    :: l n     }   deriving Typeable +type instance V (Camera l n) = V3+type instance N (Camera l n) = n+ class Typeable l => CameraLens l where-    -- | The natural aspect ratio of the projection.-    aspect :: l -> Double+  -- | The natural aspect ratio of the projection.+  aspect :: Floating n => l n -> n  -- | A perspective projection-data PerspectiveLens = PerspectiveLens-                     { _horizontalFieldOfView :: Angle -- ^ Horizontal field of view.-                     , _verticalFieldOfView   :: Angle -- ^ Vertical field of view.-                     }+data PerspectiveLens n = PerspectiveLens+  { _horizontalFieldOfView :: Angle n -- ^ Horizontal field of view.+  , _verticalFieldOfView   :: Angle n -- ^ Vertical field of view.+  }   deriving Typeable  makeLenses ''PerspectiveLens +type instance V (PerspectiveLens n) = V3+type instance N (PerspectiveLens n) = n+ instance CameraLens PerspectiveLens where-    aspect (PerspectiveLens h v) = angleRatio h v+  aspect (PerspectiveLens h v) = angleRatio h v  -- | An orthographic projection-data OrthoLens = OrthoLens-               { _orthoWidth  :: Double -- ^ Width-               , _orthoHeight :: Double -- ^ Height+data OrthoLens n = OrthoLens+               { _orthoWidth  :: n -- ^ Width+               , _orthoHeight :: n -- ^ Height                }   deriving Typeable  makeLenses ''OrthoLens -instance CameraLens OrthoLens where-    aspect (OrthoLens h v) = h / v+type instance V (OrthoLens n) = V3+type instance N (OrthoLens n) = n -type instance V (Camera l) = R3+instance CameraLens OrthoLens where+  aspect (OrthoLens h v) = h / v -instance Transformable (Camera l) where+instance Num n => Transformable (Camera l n) where   transform t (Camera p f u l) =       Camera (transform t p)              (transform t f)              (transform t u)              l -instance Renderable (Camera l) NullBackend where-    render _ _ = mempty+instance Num n => Renderable (Camera l n) NullBackend where+  render _ _ = mempty  -- | A camera at the origin facing along the negative Z axis, with its -- up-axis coincident with the positive Y axis.  The field of view is -- chosen to match a 50mm camera on 35mm film. Note that Cameras take -- up no space in the Diagram.-mm50Camera :: (Backend b R3, Renderable (Camera PerspectiveLens) b) => Diagram b R3+mm50Camera :: (Typeable n, Floating n, Ord n, Renderable (Camera PerspectiveLens n) b)+           => QDiagram b V3 n Any mm50Camera = facing_ZCamera mm50  -- | 'facing_ZCamera l' is a camera at the origin facing along the -- negative Z axis, with its up-axis coincident with the positive Y -- axis, with the projection defined by l.-facing_ZCamera :: (CameraLens l, Backend b R3, Renderable (Camera l) b) =>-                  l -> Diagram b R3+facing_ZCamera :: (Floating n, Ord n, Typeable n, CameraLens l, Renderable (Camera l n) b) =>+                  l n -> QDiagram b V3 n Any facing_ZCamera l = mkQD (Prim $ Camera origin unit_Z unitY l)         mempty mempty mempty (Query . const . Any $ False)+{-# ANN facing_ZCamera ("HLint: ignore Use camelCase" :: String) #-} -mm50, mm50Wide, mm50Narrow :: PerspectiveLens+mm50, mm50Wide, mm50Narrow :: Floating n => PerspectiveLens n  -- | mm50 has the field of view of a 50mm lens on standard 35mm film, -- hence an aspect ratio of 3:2.@@ -115,21 +126,21 @@ mm50Wide = PerspectiveLens (43.2 @@ deg)  (27 @@ deg)  -- | mm50Narrow has the same vertical field of view as mm50, but an--- aspect ratio of 4:3, for VGA and similar computer resulotions.+-- aspect ratio of 4:3, for VGA and similar computer resolutions. mm50Narrow = PerspectiveLens (36 @@ deg) (27 @@ deg) -camForward :: Camera l -> Direction+camForward :: Camera l n -> Direction V3 n camForward = direction . forward -camUp :: Camera l -> Direction+camUp :: Camera l n -> Direction V3 n camUp = direction . up -camRight :: Camera l -> Direction+camRight :: Fractional n => Camera l n -> Direction V3 n camRight c = direction right where-  right = cross3 (forward c) (up c)+  right = cross (forward c) (up c) -camLens :: Camera l -> l+camLens :: Camera l n -> l n camLens = lens -camAspect :: CameraLens l => Camera l -> Double+camAspect :: (Floating n, CameraLens l) => Camera l n -> n camAspect = aspect . camLens
src/Diagrams/ThreeD/Deform.hs view
@@ -1,51 +1,28 @@-module Diagrams.ThreeD.Deform where--import Control.Lens--import Diagrams.Deform--import Diagrams.Coordinates-import Diagrams.ThreeD.Types---- | The parallel projection onto the plane x=0-parallelX0 :: Deformation R3-parallelX0 = Deformation (& _x .~ 0)+module Diagrams.ThreeD.Deform+  ( parallelX0, perspectiveX1, facingX+  , parallelY0, perspectiveY1, facingY+  , parallelZ0, perspectiveZ1, facingZ+  ) where --- | The perspective division onto the plane x=1 along lines going--- through the origin.-perspectiveX1 :: Deformation R3-perspectiveX1 = Deformation (\p -> let x = p^._x in-                             p & _x .~ 1 & _y //~ x & _z //~ x )+import           Control.Lens --- | The parallel projection onto the plane y=0-parallelY0 :: Deformation R3-parallelY0 = Deformation (& _y .~ 0)+import           Diagrams.Deform+import           Diagrams.TwoD.Deform --- | The perspective division onto the plane y=1 along lines going--- through the origin.-perspectiveY1 :: Deformation R3-perspectiveY1 = Deformation (\p -> let y = p^._y in-                             p & _x //~ y & _y .~ 1 & _z //~ y )+import           Linear.V3+import           Linear.Vector  -- | The parallel projection onto the plane z=0-parallelZ0 :: Deformation R3-parallelZ0 = Deformation (& _z .~ 0)+parallelZ0 :: (R3 v, Num n) => Deformation v v n+parallelZ0 = Deformation (_z .~ 0)  -- | The perspective division onto the plane z=1 along lines going--- through the origin.-perspectiveZ1 :: Deformation R3-perspectiveZ1 = Deformation (\p -> let z = p^._z in-                             p & _x //~ z & _y //~ z & _z .~ 1 )---- | The viewing transform for a viewer facing along the positive X--- axis.  X coördinates stay fixed, while Y coördinates are compressed--- with increasing distance.  @asDeformation (translation unitX) <>--- parallelX0 <> frustrumX = perspectiveX1@-facingX :: Deformation R3-facingX = Deformation (\v -> v & _y //~ (v^._x) & _z //~ (v^._x))+--   through the origin.+perspectiveZ1 :: (R3 v, Functor v, Fractional n) => Deformation v v n+perspectiveZ1 = Deformation $ \p -> p ^/ (p ^. _z) -facingY :: Deformation R3-facingY = Deformation (\v -> v & _x //~ (v^._y) & _z //~ (v^._y))+facingZ :: (R3 v, Functor v, Fractional n) => Deformation v v n+facingZ = Deformation $+  \p -> let z = p ^. _z+        in  p ^/ z & _z .~ z -facingZ :: Deformation R3-facingZ = Deformation (\v -> v & _x //~ (v^._z) & _y //~ (v^._z))
src/Diagrams/ThreeD/Light.hs view
@@ -1,7 +1,9 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable    #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE UndecidableInstances  #-}  ----------------------------------------------------------------------------- -- |@@ -21,35 +23,43 @@ import           Data.Typeable  import           Diagrams.Core+import           Diagrams.Direction import           Diagrams.ThreeD.Types -data PointLight = PointLight P3 (Colour Double)+-- | A @PointLight@ radiates uniformly in all directions from a given+-- point.+data PointLight n = PointLight (Point V3 n) (Colour Double)   deriving Typeable -data ParallelLight = ParallelLight R3 (Colour Double)+type instance V (PointLight n) = V3+type instance N (PointLight n) = n++-- | A @ParallelLight@ casts parallel rays in the specified direction,+-- from some distant location outside the scene.+data ParallelLight n = ParallelLight (V3 n) (Colour Double)   deriving Typeable -type instance V PointLight = R3-type instance V ParallelLight = R3+type instance V (ParallelLight n) = V3+type instance N (ParallelLight n) = n -instance Transformable PointLight where-    transform t (PointLight p c) = PointLight (transform t p) c+instance Fractional n => Transformable (PointLight n) where+  transform t (PointLight p c) = PointLight (transform t p) c -instance Transformable ParallelLight where-    transform t (ParallelLight v c) = ParallelLight (transform t v) c+instance Transformable (ParallelLight n) where+  transform t (ParallelLight v c) = ParallelLight (transform t v) c  -- | Construct a Diagram with a single PointLight at the origin, which -- takes up no space.-pointLight :: (Backend b R3, Renderable PointLight b)+pointLight :: (Typeable n, Num n, Ord n, Renderable (PointLight n) b)               => Colour Double -- ^ The color of the light-              -> Diagram b R3+              -> QDiagram b V3 n Any pointLight c = mkQD (Prim $ PointLight origin c) mempty mempty mempty                (Query . const . Any $ False)  -- | Construct a Diagram with a single ParallelLight, which takes up no space.-parallelLight :: (Backend b R3, Renderable ParallelLight b)-                 => Direction -- ^ The direction in which the light travels.-                 -> Colour Double -- ^ The color of the light.-                 -> Diagram b R3+parallelLight :: (Typeable n, OrderedField n, Renderable (ParallelLight n) b)+                 => Direction V3 n -- ^ The direction in which the light travels.+                 -> Colour Double  -- ^ The color of the light.+                 -> QDiagram b V3 n Any parallelLight d c = mkQD (Prim $ ParallelLight (fromDirection d) c)                     mempty mempty mempty (Query . const . Any $ False)
+ src/Diagrams/ThreeD/Projection.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE TypeFamilies          #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.ThreeD.Projection+-- Copyright   :  (c) 2014 diagrams team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- 3D projections are a way of viewing a three-dimensional objects on a+-- two-dimensional plane.+--+-- This module can be used with the functions in "Linear.Projection".+--+-- Disclaimer: This module should be considered experimental and is+-- likely to change.+--+-----------------------------------------------------------------------------++module Diagrams.ThreeD.Projection+  ( -- * Orthographic projections++    -- $orthographic+    -- ** Parallel projections+    facingXY+  , facingXZ+  , facingYZ++    -- ** axonometric+    -- $axonometric++    -- *** Isometric projections+    -- $isometric+  , isometricApply+  , isometric++  , lookingAt++    -- ** Affine maps+  , m44AffineApply+  , m44AffineMap+  , m33AffineApply+  , m33AffineMap++    -- * Perspective projections+    -- $perspective+    -- ** Perspective deformations+  , m44Deformation+  , module Linear.Projection+  ) where++import           Control.Lens           hiding (transform)+import           Data.Functor.Rep++import           Diagrams.Core+import           Diagrams.Deform+import           Diagrams.Direction+import           Diagrams.LinearMap+import           Diagrams.ThreeD.Types  (P3)+import           Diagrams.ThreeD.Vector++import           Linear                 as L+import           Linear.Affine+import           Linear.Projection++------------------------------------------------------------------------+-- Orthographic projections+------------------------------------------------------------------------++-- $orthographic+-- Orthographic projections are a form of parallel projections where are+-- projection lines are orthogonal to the projection plane.++-- Parallel projections++-- | Look at the xy-plane with y as the up direction.+facingXY :: (Epsilon n, Floating n) => AffineMap V3 V2 n+facingXY = lookingAt unitZ origin yDir++-- | Look at the xz-plane with z as the up direction.+facingXZ :: (Epsilon n, Floating n) => AffineMap V3 V2 n+facingXZ = lookingAt unitY origin zDir++-- | Look at the yz-plane with z as the up direction.+facingYZ :: (Epsilon n, Floating n) => AffineMap V3 V2 n+facingYZ = lookingAt unitX origin zDir++-- $axonometric+-- Axonometric projections are a type of orthographic projection where+-- the object is rotated along one or more of its axes relative to the+-- plane of projection.++-- $isometric+-- Isometric projections are when the scale along each axis of the+-- projection is the same and the angle between any axis is 120+-- degrees.++-- | Apply an isometric projection given the up direction+isometricApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b, Floating n, Epsilon n)+               => Direction V3 n -> a -> b+isometricApply up = amap (isometric up)++-- | Make an isometric affine map with the given up direction.+isometric :: (Floating n, Epsilon n) => Direction V3 n -> AffineMap V3 V2 n+isometric up = m44AffineMap m+  where+    m = lookAt (V3 1 1 1) zero (fromDirection up)++lookingAt :: (Epsilon n, Floating n)+          => P3 n -- ^ Eye+          -> P3 n -- ^ Center+          -> Direction V3 n -- ^ Up+          -> AffineMap V3 V2 n+lookingAt (P cam) (P center) d = m44AffineMap m+  where+    m = lookAt cam center (d^._Dir)++-- | Apply the affine part of a homogeneous matrix.+m44AffineApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b)+               => M44 n -> a -> b+m44AffineApply = amap . m44AffineMap++-- | Create an 'AffineMap' from a 4x4 homogeneous matrix, ignoring any+--   perspective transforms.+m44AffineMap :: Num n => M44 n -> AffineMap V3 V2 n+m44AffineMap m = AffineMap (LinearMap f) (f v)+  where+    f  = view _xy . (m' !*)+    m' = m ^. linearTransform+    v  = m ^. L.translation++-- | Apply a transformation matrix and translation.+m33AffineApply :: (InSpace V3 n a, InSpace V2 n b, AffineMappable a b)+               => M33 n -> V2 n -> a -> b+m33AffineApply m = amap . m33AffineMap m++-- | Create an 'AffineMap' from a 3x3 transformation matrix and a+--   translation vector.+m33AffineMap :: Num n => M33 n -> V2 n -> AffineMap V3 V2 n+m33AffineMap m = AffineMap (LinearMap f)+  where+    f = view _xy . (m !*)++-- | Extract the linear transform part of a homogeneous matrix.+linearTransform :: (Representable u, R3 v, R3 u) => Lens' (u (v n)) (M33 n)+linearTransform = column _xyz . _xyz++------------------------------------------------------------------------+-- Perspective transforms+------------------------------------------------------------------------++-- For the time being projective transforms use the deformable class.+-- Eventually we would like to replace this with a more specialised+-- method.++-- $perspective+-- Perspective projections are when closer objects appear bigger.++-- | Make a deformation from a 4x4 homogeneous matrix.+m44Deformation :: Fractional n => M44 n -> Deformation V3 V2 n+m44Deformation m =+  Deformation (P . view _xy . normalizePoint . (m !*) . point . view _Point)+
src/Diagrams/ThreeD/Shapes.hs view
@@ -1,7 +1,11 @@+{-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE DeriveDataTypeable    #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD.Shapes@@ -14,149 +18,307 @@ -----------------------------------------------------------------------------  module Diagrams.ThreeD.Shapes-       (-         Ellipsoid(..), sphere-       , Box(..), cube-       , Frustum(..) , frustum, cone, cylinder-       ) where+  (+    -- * Skinned class+    Skinned(..) -import           Control.Applicative-import           Control.Lens           (review, (^.), _1)+    -- * Basic 3D shapes+  , Ellipsoid(..)+  , sphere++  , Box(..)+  , cube++  , Frustum(..)+  , frustum+  , cone+  , cylinder++    -- * Constructive solid geometry+  , CSG(..)+  , union+  , intersection+  , difference+  ) where++import           Control.Lens              (review, (^.), _1) import           Data.Typeable -import           Data.AffineSpace import           Data.Semigroup-import           Data.VectorSpace import           Diagrams.Angle-import           Diagrams.Coordinates import           Diagrams.Core-import           Diagrams.Solve+import           Diagrams.Core.Trace+import           Diagrams.Points+import           Diagrams.Query+import           Diagrams.Solve.Polynomial import           Diagrams.ThreeD.Types import           Diagrams.ThreeD.Vector -data Ellipsoid = Ellipsoid T3+import           Linear.Affine+import           Linear.Metric+import           Linear.Vector++data Ellipsoid n = Ellipsoid (Transformation V3 n)   deriving Typeable -type instance V Ellipsoid = R3+type instance V (Ellipsoid n) = V3+type instance N (Ellipsoid n) = n -instance Transformable Ellipsoid where+instance Fractional n => Transformable (Ellipsoid n) where   transform t1 (Ellipsoid t2) = Ellipsoid (t1 <> t2) -instance Renderable Ellipsoid NullBackend where+instance Fractional n => Renderable (Ellipsoid n) NullBackend where   render _ _ = mempty +instance OrderedField n => Enveloped (Ellipsoid n) where+  getEnvelope (Ellipsoid tr) = transform tr . mkEnvelope $ \v -> 1 / norm v++instance OrderedField n => Traced (Ellipsoid n) where+  getTrace (Ellipsoid tr) = transform tr . mkTrace $ \(P p) v -> let+    a  =    v `dot` v+    b  = 2 * (p `dot` v)+    c  =    (p `dot` p) - 1+    in+     mkSortedList $ quadForm a b c+ -- | A sphere of radius 1 with its center at the origin.-sphere :: (Backend b R3, Renderable Ellipsoid b) => Diagram b R3-sphere = mkQD (Prim $ Ellipsoid mempty)-              (mkEnvelope sphereEnv)-              (mkTrace sphereTrace)-              mempty-              (Query sphereQuery)-  where sphereEnv v = 1 / magnitude v-        sphereTrace p v = mkSortedList $ quadForm a b c-          where a = v <.> v-                b = 2 *^ p' <.> v-                c = p' <.> p' - 1-                p' = p .-. origin-        sphereQuery v = Any $ magnitudeSq (v .-. origin) <= 1+sphere :: Num n => Ellipsoid n+sphere = Ellipsoid mempty -data Box = Box T3-         deriving (Typeable)+data Box n = Box (Transformation V3 n)+  deriving Typeable -type instance V Box = R3+type instance V (Box n) = V3+type instance N (Box n) = n -instance Transformable Box where-    transform t1 (Box t2) = Box (t1 <> t2)+instance Fractional n => Transformable (Box n) where+  transform t1 (Box t2) = Box (t1 <> t2) -instance Renderable Box NullBackend where-    render _ _ = mempty+instance Fractional n => Renderable (Box n) NullBackend where+  render _ _ = mempty --- | A cube with side length 1, in the positive octant, with one--- vertex at the origin.-cube :: (Backend b R3, Renderable Box b) => Diagram b R3-cube = mkQD (Prim $ Box mempty)-            (mkEnvelope boxEnv)-            (mkTrace boxTrace)-            mempty-            (Query boxQuery)-  where-    corners = mkR3 <$> [0,1] <*> [0,1] <*> [0,1]-    boxEnv v = maximum (map (v <.>) corners) / magnitudeSq v-    -- ts gives all intersections with the planes forming the box-    -- filter keeps only those actually on the box surface-    boxTrace p v = mkSortedList . filter (range . atT) $ ts where-      (x0, y0, z0) = unp3 p-      (vx, vy, vz) = unr3 v-      intersections f d = case d of-          0 -> []-          _ -> [-f/d, (1-f)/d]-      ts = concat $ zipWith intersections [x0,y0,z0] [vx,vy,vz]-      atT t = p .+^ (t*^v)+instance OrderedField n => Enveloped (Box n) where+  getEnvelope (Box tr) = transform tr . mkEnvelope $ \v ->+    maximum (map (v `dot`) corners) / quadrance v where+      corners = mkR3 <$> [0,1] <*> [0,1] <*> [0,1]++instance (Fractional n, Ord n) => Traced (Box n) where+  getTrace (Box tr) = transform tr . mkTrace $ \p v -> let+    (x0, y0, z0) = unp3 p+    (vx, vy, vz) = unr3 v+    intersections f d = case d of+      0 -> []+      _ -> [-f/d, (1-f)/d]+    ts = concat $ zipWith intersections [x0,y0,z0] [vx,vy,vz]+    atT t = p .+^ (t*^v)     range u = and [x >= 0, x <= 1, y >= 0, y <= 1, z >= 0, z <= 1] where       (x, y, z) = unp3 u-    boxQuery = Any . range+    in+     -- ts gives all intersections with the planes forming the box+     -- filter keeps only those actually on the box surface+     mkSortedList . filter (range . atT) $ ts where -data Frustum = Frustum Double Double T3-         deriving (Typeable)+-- | A cube with side length 1, in the positive octant, with one+-- vertex at the origin.+cube :: Num n => Box n+cube = Box mempty -type instance V Frustum = R3+data Frustum n = Frustum n n (Transformation V3 n)+  deriving Typeable -instance Transformable Frustum where-    transform t1 (Frustum r0 r1 t2) = Frustum r0 r1 (t1 <> t2)+type instance V (Frustum n) = V3+type instance N (Frustum n) = n -instance Renderable Frustum NullBackend where-    render _ _ = mempty+instance Fractional n => Transformable (Frustum n) where+  transform t1 (Frustum r0 r1 t2) = Frustum r0 r1 (t1 <> t2) +instance Fractional n => Renderable (Frustum n) NullBackend where+  render _ _ = mempty++instance (OrderedField n, RealFloat n) => Enveloped (Frustum n) where+  -- The plane containing v and the z axis intersects the frustum in a trapezoid+  -- Test the four corners of this trapezoid; one must determine the Envelope+  getEnvelope (Frustum r0 r1 tr) = transform tr . mkEnvelope $ \v ->let+    θ = v ^. _theta+    corners = [(r1,θ,1), (-r1,θ,1), (r0,θ,0), (-r0,θ,0)]+    in+     maximum . map (norm . project v . review r3CylindricalIso) $ corners++instance (RealFloat n, Ord n) => Traced (Frustum n) where+  -- The trace can intersect the sides of the cone or one of the end+  -- caps The sides are described by a quadric equation; substitute+  -- in the parametric form of the ray but disregard any+  -- intersections outside z = [0,1] Similarly, find intersections+  -- with the planes z=0, z=1, but disregard any r>r0, r>r1+  getTrace (Frustum r0 r1 tr) = transform tr . mkTrace $ \p v -> let+    (px, py, pz) = unp3 p+    (vx, vy, vz) = unr3 v+    ray t = p .+^ t *^ v+    dr = r1 - r0+    a = vx**2 + vy**2 - vz**2 * dr**2+    b = 2 * (px * vx + py * vy - (r0+pz*dr) * dr  * vz)+    c = px**2 + py**2 - (r0 + dr*pz)**2+    zbounds t = ray t ^. _z >= 0+         && ray t ^. _z <= 1+    ends = concatMap cap [0,1]+    cap z = [ t | ray t ^. lensP . r3CylindricalIso . _1 < r0 + z * dr ]+      where+      t = (z - pz) / vz+    in+     mkSortedList $ filter zbounds (quadForm a b c) ++ ends+ -- | A frustum of a right circular cone.  It has height 1 oriented -- along the positive z axis, and radii r0 and r1 at Z=0 and Z=1. -- 'cone' and 'cylinder' are special cases.-frustum :: (Backend b R3, Renderable Frustum b) => Double -> Double -> Diagram b R3-frustum r0 r1 = mkQD (Prim $ Frustum r0 r1 mempty)-                 (mkEnvelope frEnv)-                 (mkTrace frTrace)-                 mempty-                 (Query frQuery)-  where-    projectXY u = u ^-^ project unitZ u-    frQuery p = Any $ x >= 0 && x <= 1 && a <= r where-      (x, _, z) = unp3 p-      r = r0 + (r1-r0)*z-      v = p .-. origin-      a = magnitude $ projectXY v-    -- The plane containing v and the z axis intersects the frustum in a trapezoid-    -- Test the four corners of this trapezoid; one must determine the Envelope-    frEnv v = maximum . map (magnitude . project v . review cylindrical) $ corners-      where-        θ = v^._theta-        corners = [(r1,θ,1), (-r1,θ,1), (r0,θ,0), (-r0,θ,0)]-    -- The trace can intersect the sides of the cone or one of the end-    -- caps The sides are described by a quadric equation; substitute-    -- in the parametric form of the ray but disregard any-    -- intersections outside z = [0,1] Similarly, find intersections-    -- with the planes z=0, z=1, but disregard any r>r0, r>r1-    frTrace p v = mkSortedList $ filter zbounds (quadForm a b c) ++ ends-      where-        (px, py, pz) = unp3 p-        (vx, vy, vz) = unr3 v-        ray t = p .+^ t*^v-        dr = r1-r0-        a = vx**2 + vy**2 - vz**2 * dr**2-        b = 2 * (px * vx + py * vy - (r0+pz*dr) * dr  * vz)-        c = px**2 + py**2 - (r0 + dr*pz)**2-        zbounds t = (ray t)^._z >= 0 && (ray t)^._z <= 1-        ends = concatMap cap [0,1]-        cap z = if (ray t)^.cylindrical._1 < r0 + z*dr-                then [t]-                else []-          where-            t = (z - pz) / vz+frustum :: Num n => n -> n -> Frustum n+frustum r0 r1 = Frustum r0 r1 mempty  -- | A cone with its base centered on the origin, with radius 1 at the -- base, height 1, and it's apex on the positive Z axis.-cone :: (Backend b R3, Renderable Frustum b) => Diagram b R3+cone :: Num n => Frustum n cone = frustum 1 0  -- | A circular cylinder of radius 1 with one end cap centered on the -- origin, and extending to Z=1.-cylinder :: (Backend b R3, Renderable Frustum b) => Diagram b R3+cylinder :: Num n => Frustum n cylinder = frustum 1 1++-- | Types which can be rendered as 3D Diagrams.+class Skinned t where+  skin :: (Renderable t b, N t ~ n, TypeableFloat n) => t -> QDiagram b V3 n Any++instance (Num n, Ord n) => HasQuery (Ellipsoid n) Any where+  getQuery (Ellipsoid tr) = transform tr $+    Query $ \v -> Any $ quadrance (v .-. origin) <= 1++instance OrderedField n => Skinned (Ellipsoid n) where+  skin s = mkQD (Prim s) (getEnvelope s) (getTrace s) mempty (getQuery s)++instance (Num n, Ord n) => HasQuery (Box n) Any where+  getQuery (Box tr) = transform tr . Query $ Any . range where+    range u = and [x >= 0, x <= 1, y >= 0, y <= 1, z >= 0, z <= 1] where+      (x, y, z) = unp3 u++instance OrderedField n => Skinned (Box n) where+  skin s = mkQD (Prim s) (getEnvelope s) (getTrace s) mempty (getQuery s)++instance (OrderedField n) => HasQuery (Frustum n) Any where+  getQuery (Frustum r0 r1 tr)= transform tr $+    Query $ \p -> let+      z = p^._z+      r = r0 + (r1 - r0)*z+      v = p .-. origin+      a = norm $ projectXY v+      projectXY u = u ^-^ project unitZ u+      in+       Any $ z >= 0 && z <= 1 && a <= r++instance Skinned (Frustum n) where+  skin s = mkQD (Prim s) (getEnvelope s) (getTrace s) mempty (getQuery s)++-- The CSG type needs to form a tree to be useful.  This+-- implementation requires Backends to support all the included+-- primitives.  If that turns out to be a problem, we have several+-- options:+-- a) accept runtime errors for unsupported primitives+-- b) carry the set of primitives in a row type in the CSG type+-- c) implement CSG in Haskell, so Backends supporting triangle meshes+--    can fall back to those.+-- (c) is worth doing anyway; I'm ambivalent about the others.  -DMB++-- | A tree of Constructive Solid Geometry operations and the primitives that+-- can be used in them.+data CSG n+  = CsgEllipsoid (Ellipsoid n)+  | CsgBox (Box n)+  | CsgFrustum (Frustum n)+  | CsgUnion [CSG n]+  | CsgIntersection [CSG n]+  | CsgDifference (CSG n) (CSG n)+  deriving Typeable++type instance V (CSG n) = V3+type instance N (CSG n) = n++instance Fractional n => Transformable (CSG n) where+  transform t (CsgEllipsoid p) = CsgEllipsoid $ transform t p+  transform t (CsgBox p) = CsgBox $ transform t p+  transform t (CsgFrustum p) = CsgFrustum $ transform t p+  transform t (CsgUnion ps) = CsgUnion $ map (transform t) ps+  transform t (CsgIntersection ps) = CsgIntersection $ map (transform t) ps+  transform t (CsgDifference p1 p2) = CsgDifference (transform t p1) (transform t p2)++-- | The Envelope for an Intersection or Difference is simply the+-- Envelope of the Union.  This is wrong but easy to implement.+instance RealFloat n => Enveloped (CSG n) where+  getEnvelope (CsgEllipsoid p)      = getEnvelope p+  getEnvelope (CsgBox p)            = getEnvelope p+  getEnvelope (CsgFrustum p)        = getEnvelope p+  getEnvelope (CsgUnion ps)         = foldMap getEnvelope ps+  getEnvelope (CsgIntersection ps)  = foldMap getEnvelope ps+  getEnvelope (CsgDifference p1 p2) = getEnvelope p1 <> getEnvelope p2+-- TODO after implementing some approximation scheme, calculate+-- correct (approximate) envelopes for intersections and difference.++instance (Floating n, Ord n) => HasQuery (CSG n) Any where+  getQuery (CsgEllipsoid prim) = getQuery prim+  getQuery (CsgBox prim) = getQuery prim+  getQuery (CsgFrustum prim) = getQuery prim+  getQuery (CsgUnion ps) = foldMap getQuery ps+  getQuery (CsgIntersection ps) =+    Any . getAll <$> foldMap (fmap (All . getAny) . getQuery) ps+  getQuery (CsgDifference p1 p2) = inOut <$> getQuery p1 <*> getQuery p2 where+    inOut (Any a) (Any b) = Any $ a && not b++instance (RealFloat n, Ord n) => Traced (CSG n) where+  getTrace (CsgEllipsoid p) = getTrace p+  getTrace (CsgBox p) = getTrace p+  getTrace (CsgFrustum p) = getTrace p+  -- on surface of some p, and not inside any of the others+  getTrace (CsgUnion []) = mempty+  getTrace (CsgUnion (s:ss)) = mkTrace t where+    t pt v = onSortedList (filter $ without s) (appTrace (getTrace (CsgUnion ss)) pt v)+         <> onSortedList (filter $ without (CsgUnion ss)) (appTrace (getTrace s) pt v) where+      newPt dist = pt .+^ v ^* dist+      without prim = not . inquire prim . newPt+  -- on surface of some p, and inside all the others+  getTrace (CsgIntersection []) = mempty+  getTrace (CsgIntersection (s:ss)) = mkTrace t where+    t pt v = onSortedList (filter $ within s) (appTrace (getTrace (CsgIntersection ss)) pt v)+         <> onSortedList (filter $ within (CsgIntersection ss)) (appTrace (getTrace s) pt v) where+      newPt dist = pt .+^ v ^* dist+      within prim = inquire prim . newPt+  -- on surface of p1, outside p2, or on surface of p2, inside p1+  getTrace (CsgDifference s1 s2) = mkTrace t where+    t pt v = onSortedList (filter $ not . within s2) (appTrace (getTrace s1) pt v)+         <> onSortedList (filter $ within s1) (appTrace (getTrace s2) pt v) where+      newPt dist = pt .+^ v ^* dist+      within prim = inquire prim . newPt++instance (RealFloat n, Ord n) => Skinned (CSG n) where+  skin s = mkQD (Prim s) (getEnvelope s) (getTrace s) mempty (getQuery s)++-- | Types which can be included in CSG trees.+class CsgPrim a where+  toCsg :: a n -> CSG n++instance CsgPrim Ellipsoid where+  toCsg = CsgEllipsoid++instance CsgPrim Box where+  toCsg = CsgBox++instance CsgPrim Frustum where+  toCsg = CsgFrustum++instance CsgPrim CSG where+  toCsg = id++union :: (CsgPrim a, CsgPrim b) => a n -> b n -> CSG n+union a b = CsgUnion [toCsg a, toCsg b]++intersection :: (CsgPrim a, CsgPrim b) => a n -> b n -> CSG n+intersection a b = CsgIntersection [toCsg a, toCsg b]++difference :: (CsgPrim a, CsgPrim b) => a n -> b n -> CSG n+difference a b = CsgDifference (toCsg a) (toCsg b)
+ src/Diagrams/ThreeD/Size.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies     #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.ThreeD.Size+-- Copyright   :  (c) 2014 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Utilities for working with sizes of three-dimensional objects.+--+-----------------------------------------------------------------------------+module Diagrams.ThreeD.Size+       (+         -- ** Computing sizes+         extentX, extentY, extentZ++         -- ** Specifying sizes+       , mkSizeSpec3D+       , dims3D++       ) where++import           Diagrams.Core+import           Diagrams.Core.Envelope+import           Diagrams.Size+import           Diagrams.TwoD.Size+import           Diagrams.ThreeD.Types+import           Diagrams.ThreeD.Vector++------------------------------------------------------------+-- Computing diagram sizes+------------------------------------------------------------++-- | Compute the absolute z-coordinate range of an enveloped object in+--   the form @(lo,hi)@. Return @Nothing@ for objects with an empty+--   envelope.+extentZ :: (InSpace v n a, R3 v, Enveloped a) => a -> Maybe (n, n)+extentZ = extent unitZ++-- | Make a 'SizeSpec' from possibly-specified width and height.+mkSizeSpec3D :: Num n => Maybe n -> Maybe n -> Maybe n -> SizeSpec V3 n+mkSizeSpec3D x y z = mkSizeSpec (V3 x y z)++-- | Make a 'SizeSpec' from a width and height.+dims3D :: n -> n -> n -> SizeSpec V3 n+dims3D x y z = dims (V3 x y z)+
src/Diagrams/ThreeD/Transform.hs view
@@ -1,8 +1,15 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-} {-# LANGUAGE ViewPatterns          #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD.Transform@@ -17,10 +24,12 @@ -----------------------------------------------------------------------------  module Diagrams.ThreeD.Transform-       (+       ( T3+          -- * Rotation-         aboutX, aboutY, aboutZ-       , rotationAbout, pointAt, pointAt'+       , aboutX, aboutY, aboutZ+       , rotationAbout, rotateAbout+       , pointAt, pointAt'         -- * Scaling        , scalingX, scalingY, scalingZ@@ -37,26 +46,27 @@        , reflectionX, reflectX        , reflectionY, reflectY        , reflectionZ, reflectZ-       , reflectionAbout, reflectAbout+       , reflectionAcross, reflectAcross -       -- * Utilities for Backends-       , onBasis        ) where  import           Diagrams.Core-import qualified Diagrams.Core.Transform as T+import           Diagrams.Core.Transform  import           Diagrams.Angle-import           Diagrams.Transform+import           Diagrams.Direction+import           Diagrams.Points import           Diagrams.ThreeD.Types-import           Diagrams.Coordinates+import           Diagrams.Transform -import           Control.Lens                   (view, (*~), (//~))+import           Control.Lens            (view, (&), (*~), (.~), (//~)) import           Data.Semigroup+import           Diagrams.TwoD.Transform -import           Data.AffineSpace-import           Data.Cross-import           Data.VectorSpace+import           Linear.Affine+import           Linear.Metric+import           Linear.V3               (cross)+import           Linear.Vector  -- | Create a transformation which rotates by the given angle about --   a line parallel the Z axis passing through the local origin.@@ -72,192 +82,142 @@ --   Note that writing @aboutZ (1\/4)@, with no type annotation, will --   yield an error since GHC cannot figure out which sort of angle --   you want to use.-aboutZ :: Angle -> T3-aboutZ ang = fromLinear r (linv r) where-  r = rot theta <-> rot (-theta)-  theta = view rad ang-  rot th (coords -> x :& y :& z) = (cos th * x - sin th * y) ^&-                                   (sin th * x + cos th * y) ^&-                                   z+aboutZ :: Floating n => Angle n -> Transformation V3 n+aboutZ (view rad -> a) = fromOrthogonal r where+  r = rot a <-> rot (-a)+  rot θ (V3 x y z) = V3 (cos θ * x - sin θ * y)+                        (sin θ * x + cos θ * y)+                        z  -- | Like 'aboutZ', but rotates about the X axis, bringing positive y-values -- towards the positive z-axis.-aboutX :: Angle -> T3-aboutX ang = fromLinear r (linv r) where-  r = rot theta <-> rot (-theta)-  theta = view rad ang-  rot th (coords -> x :& y :& z) = (x) ^&-                                   (cos th * y - sin th * z) ^&-                                   (sin th * y + cos th * z)+aboutX :: Floating n => Angle n -> Transformation V3 n+aboutX (view rad -> a) = fromOrthogonal r where+  r = rot a <-> rot (-a)+  rot θ (V3 x y z) = V3 x+                        (cos θ * y - sin θ * z)+                        (sin θ * y + cos θ * z)  -- | Like 'aboutZ', but rotates about the Y axis, bringing postive -- x-values towards the negative z-axis.-aboutY :: Angle -> T3-aboutY ang = fromLinear r (linv r) where-  r = rot theta <-> rot (-theta)-  theta = view rad ang-  rot th (coords -> x :& y :& z) = (cos th * x + sin th * z) ^&-                                    y ^&-                                    (-sin th * x + cos th * z)+aboutY :: Floating n => Angle n -> Transformation V3 n+aboutY (view rad -> a) = fromOrthogonal r where+  r = rot a <-> rot (-a)+  rot θ (V3 x y z) = V3 (cos θ * x + sin θ * z)+                        y+                        (-sin θ * x + cos θ * z)  -- | @rotationAbout p d a@ is a rotation about a line parallel to @d@ --   passing through @p@.-rotationAbout ::-     P3        -- ^ origin of rotation-  -> Direction -- ^ direction of rotation axis-  -> Angle     -- ^ angle of rotation-  -> T3-rotationAbout p d a-  = mconcat [translation (negateV t),-             fromLinear r (linv r),+rotationAbout+  :: Floating n+  => Point V3 n         -- ^ origin of rotation+  -> Direction V3 n     -- ^ direction of rotation axis+  -> Angle n            -- ^ angle of rotation+  -> Transformation V3 n+rotationAbout (P t) d (view rad -> a)+  = mconcat [translation (negated t),+             fromOrthogonal r,              translation t] where-    r = rot theta <-> rot (-theta)-    theta = view rad a+    r = rot a <-> rot (-a)     w = fromDirection d-    rot :: Double -> R3 -> R3-    rot th v = v ^* cos th ^+^-               cross3 w v ^* sin th ^+^-               w ^* ((w <.> v) * (1 - cos th))-    t = p .-. origin +    rot θ v =          v ^* cos θ+           ^+^ cross w v ^* sin θ+           ^+^         w ^* ((w `dot` v) * (1 - cos θ))++-- | @rotationAbout p d a@ is a rotation about a line parallel to @d@+--   passing through @p@.+rotateAbout+  :: (InSpace V3 n t, Floating n, Transformable t)+  => Point V3 n         -- ^ origin of rotation+  -> Direction V3 n     -- ^ direction of rotation axis+  -> Angle n            -- ^ angle of rotation+  -> t -> t+rotateAbout p d theta = transform (rotationAbout p d theta)+ -- | @pointAt about initial final@ produces a rotation which brings -- the direction @initial@ to point in the direction @final@ by first -- panning around @about@, then tilting about the axis perpendicular--- to initial and final.  In particular, if this can be accomplished+-- to @about@ and @final@.  In particular, if this can be accomplished -- without tilting, it will be, otherwise if only tilting is -- necessary, no panning will occur.  The tilt will always be between -- ± 1/4 turn.-pointAt :: Direction -> Direction -> Direction -> T3+pointAt :: (Floating n, Ord n)+        => Direction V3 n -> Direction V3 n -> Direction V3 n+        -> Transformation V3 n pointAt a i f = pointAt' (fromDirection a) (fromDirection i) (fromDirection f)  -- | pointAt' has the same behavior as 'pointAt', but takes vectors -- instead of directions.-pointAt' :: R3 -> R3 -> R3 -> T3-pointAt' about initial final = tilt <> pan where-  inPanPlane    = final ^-^ project final initial-  panAngle      = angleBetween initial inPanPlane-  pan           = rotationAbout origin (direction about) panAngle-  tiltAngle     = angleBetween initial inPanPlane-  tiltDir       = direction $ cross3 inPanPlane about-  tilt          = rotationAbout origin tiltDir tiltAngle---- Scaling ----------------------------------------------------- | Construct a transformation which scales by the given factor in---   the x direction.-scalingX :: Double -> T3-scalingX c = fromLinear s s-  where s = (_x *~ c) <-> (_x //~ c)---- | Scale a diagram by the given factor in the x (horizontal)---   direction.  To scale uniformly, use 'scale'.-scaleX :: (Transformable t, V t ~ R3) => Double -> t -> t-scaleX = transform . scalingX+pointAt' :: (Floating n, Ord n) => V3 n -> V3 n -> V3 n -> Transformation V3 n+pointAt' about initial final = pointAtUnit (signorm about) (signorm initial) (signorm final) --- | Construct a transformation which scales by the given factor in---   the y direction.-scalingY :: Double -> T3-scalingY c = fromLinear s s-  where s = (_y *~ c) <-> (_y //~ c)+-- | pointAtUnit has the same behavior as @pointAt@, but takes unit vectors.+pointAtUnit :: (Floating n, Ord n) => V3 n -> V3 n -> V3 n -> Transformation V3 n+pointAtUnit about initial final = tilt <> pan where+  -- rotating u by (signedAngle rel u v) about rel gives a vector in the direction of v+  signedAngle rel u v = signum (cross u v `dot` rel) *^ angleBetween u v+  inPanPlaneF = final ^-^ project about final+  inPanPlaneI = initial ^-^ project about initial+  panAngle    = signedAngle about inPanPlaneI inPanPlaneF+  pan         = rotationAbout origin (direction about) panAngle+  tiltAngle   = signedAngle tiltAxis (transform pan initial) final+  tiltAxis    = cross final about+  tilt        = rotationAbout origin (direction tiltAxis) tiltAngle --- | Scale a diagram by the given factor in the y (vertical)---   direction.  To scale uniformly, use 'scale'.-scaleY :: (Transformable t, V t ~ R3) => Double -> t -> t-scaleY = transform . scalingY+-- Scaling -------------------------------------------------  -- | Construct a transformation which scales by the given factor in --   the z direction.-scalingZ :: Double -> T3-scalingZ c = fromLinear s s-  where s = (_z *~ c) <-> (_z //~ c)+scalingZ :: (Additive v, R3 v, Fractional n) => n -> Transformation v n+scalingZ c = fromSymmetric $ (_z *~ c) <-> (_z //~ c)  -- | Scale a diagram by the given factor in the z direction.  To scale -- uniformly, use 'scale'.-scaleZ :: (Transformable t, V t ~ R3) => Double -> t -> t+scaleZ :: (InSpace v n t, R3 v, Fractional n, Transformable t) => n -> t -> t scaleZ = transform . scalingZ  -- Translation ----------------------------------------  -- | Construct a transformation which translates by the given distance---   in the x direction.-translationX :: Double -> T3-translationX x = translation (x ^& 0 ^& 0)---- | Translate a diagram by the given distance in the x---   direction.-translateX :: (Transformable t, V t ~ R3) => Double -> t -> t-translateX = transform . translationX---- | Construct a transformation which translates by the given distance---   in the y direction.-translationY :: Double -> T3-translationY y = translation (0 ^& y ^& 0)---- | Translate a diagram by the given distance in the y---   direction.-translateY :: (Transformable t, V t ~ R3) => Double -> t -> t-translateY = transform . translationY---- | Construct a transformation which translates by the given distance --   in the z direction.-translationZ :: Double -> T3-translationZ z = translation (0 ^& 0 ^& z)+translationZ :: (Additive v, R3 v, Num n) => n -> Transformation v n+translationZ z = translation (zero & _z .~ z)  -- | Translate a diagram by the given distance in the y --   direction.-translateZ :: (Transformable t, V t ~ R3) => Double -> t -> t+translateZ :: (InSpace v n t, R3 v, Transformable t) => n -> t -> t translateZ = transform . translationZ  -- Reflection ---------------------------------------------- --- | Construct a transformation which flips a diagram across x=0,--- i.e. sends the point (x,y,z) to (-x,y,z).-reflectionX :: T3-reflectionX = scalingX (-1)---- | Flip a diagram across x=0, i.e. send the point (x,y,z) to (-x,y,z).-reflectX :: (Transformable t, V t ~ R3) => t -> t-reflectX = transform reflectionX---- | Construct a transformation which flips a diagram across y=0,--- i.e. sends the point (x,y,z) to (x,-y,z).-reflectionY :: T3-reflectionY = scalingY (-1)---- | Flip a diagram across y=0, i.e. send the point (x,y,z) to--- (x,-y,z).-reflectY :: (Transformable t, V t ~ R3) => t -> t-reflectY = transform reflectionY- -- | Construct a transformation which flips a diagram across z=0, -- i.e. sends the point (x,y,z) to (x,y,-z).-reflectionZ :: T3-reflectionZ = scalingZ (-1)+reflectionZ :: (Additive v, R3 v, Num n) => Transformation v n+reflectionZ = fromSymmetric $ (_z *~ (-1)) <-> (_z *~ (-1))  -- | Flip a diagram across z=0, i.e. send the point (x,y,z) to -- (x,y,-z).-reflectZ :: (Transformable t, V t ~ R3) => t -> t+reflectZ :: (InSpace v n t, R3 v, Transformable t) => t -> t reflectZ = transform reflectionZ --- | @reflectionAbout p v@ is a reflection across the plane through---   the point @p@ and normal to vector @v@.-reflectionAbout :: P3 -> R3 -> T3-reflectionAbout p v =-  conjugate (translation (origin .-. p)) reflect where-    reflect = fromLinear t (linv t)-    t = f v <-> f (negateV v)-    f u w = w ^-^ 2 *^ project u w---- | @reflectAbout p v@ reflects a diagram in the line determined by---   the point @p@ and the vector @v@.-reflectAbout :: (Transformable t, V t ~ R3) => P3 -> R3 -> t -> t-reflectAbout p v = transform (reflectionAbout p v)---- Utilities ----------------------------------------+-- | @reflectionAcross p v@ is a reflection across the plane through+--   the point @p@ and normal to vector @v@. This also works as a 2D+--   transform where @v@ is the normal to the line passing through point+--   @p@.+reflectionAcross :: (Metric v, Fractional n)+  => Point v n -> v n -> Transformation v n+reflectionAcross p v =+  conjugate (translation (origin .-. p)) reflect+    where+      reflect = fromLinear t (linv t)+      t       = f v <-> f (negated v)+      f u w   = w ^-^ 2 *^ project u w --- | Get the matrix equivalent of an affine transform, as a triple of---   columns paired with the translation vector.  This is mostly---   useful for implementing backends.-onBasis :: T3 -> ((R3, R3, R3), R3)-onBasis t = ((x, y, z), v)-  where (x:y:z:[], v) = T.onBasis t+-- | @reflectAcross p v@ reflects a diagram across the plane though+--   the point @p@ and the vector @v@. This also works as a 2D transform+--   where @v@ is the normal to the line passing through point @p@.+reflectAcross :: (InSpace v n t, Metric v, Fractional n, Transformable t)+  => Point v n -> v n -> t -> t+reflectAcross p v = transform (reflectionAcross p v)
src/Diagrams/ThreeD/Types.hs view
@@ -1,12 +1,5 @@-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE RankNTypes                 #-}-{-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE TypeOperators              #-}-{-# LANGUAGE TypeSynonymInstances       #-}-{-# LANGUAGE UndecidableInstances       #-}-{-# LANGUAGE ViewPatterns               #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  ----------------------------------------------------------------------------- -- |@@ -21,203 +14,85 @@  module Diagrams.ThreeD.Types        ( -- * 3D Euclidean space-         R3(..), r3, unr3, mkR3-       , P3, p3, unp3, mkP3-       , T3-       , r3Iso, p3Iso+         r3, unr3, mkR3+       , p3, unp3, mkP3+       , r3Iso, p3Iso, project+       , r3SphericalIso, r3CylindricalIso+       , V3 (..), P3,      T3+       , R1 (..), R2 (..), R3 (..) -         -- * Directions in 3D-       , Direction, direction, fromDirection, angleBetweenDirs-       -- * other coördinate systems-       , Spherical(..), Cylindrical(..), HasPhi(..)        ) where -import           Control.Lens           (Iso', Lens', iso, over-                                        , _1, _2, _3, (^.))+import           Control.Lens        (Iso', iso, _1, _2, _3) -import           Diagrams.Core import           Diagrams.Angle-import           Diagrams.TwoD.Types    (R2)-import           Diagrams.Coordinates+import           Diagrams.Core+import           Diagrams.Points+import           Diagrams.TwoD.Types -import           Data.AffineSpace.Point-import           Data.Basis-import           Data.Cross-import           Data.VectorSpace+import           Linear.Metric+import           Linear.V3           as V  ------------------------------------------------------------ -- 3D Euclidean space --- | The three-dimensional Euclidean vector space R^3.-data R3 = R3 !Double !Double !Double-  deriving (Eq, Ord, Show, Read)+-- Basic R3 types -r3Iso :: Iso' R3 (Double, Double, Double)+type P3 = Point V3+type T3 = Transformation V3++r3Iso :: Iso' (V3 n) (n, n, n) r3Iso = iso unr3 r3  -- | Construct a 3D vector from a triple of components.-r3 :: (Double, Double, Double) -> R3-r3 (x,y,z) = R3 x y z+r3 :: (n, n, n) -> V3 n+r3 (x,y,z) = V3 x y z  -- | Curried version of `r3`.-mkR3 :: Double -> Double -> Double -> R3-mkR3 = R3+mkR3 :: n -> n -> n -> V3 n+mkR3 = V3  -- | Convert a 3D vector back into a triple of components.-unr3 :: R3 -> (Double, Double, Double)-unr3 (R3 x y z) = (x,y,z)--instance AdditiveGroup R3 where-    zeroV = R3 0 0 0-    R3 x1 y1 z1 ^+^ R3 x2 y2 z2 = R3 (x1 + x2) (y1 + y2) (z1 + z2)-    negateV (R3 x y z) = R3 (-x) (-y) (-z)--type instance V R3 = R3--instance VectorSpace R3 where-  type Scalar R3 = Double-  (*^) = over r3Iso . (*^)--instance HasBasis R3 where-  type Basis R3 = Either () (Either () ()) -- = Basis (Double, Double, Double)-  basisValue = r3 . basisValue-  decompose  = decompose  . unr3-  decompose' = decompose' . unr3--instance InnerSpace R3 where-    (R3 x1 y1 z1) <.> (R3 x2 y2 z2) = x1*x2 + y1*y2 + z1*z2--instance Coordinates R3 where-  type FinalCoord R3       = Double-  type PrevDim R3          = R2-  type Decomposition R3    = Double :& Double :& Double--  (coords -> x :& y) ^& z   = R3 x y z-  coords (R3 x y z) = x :& y :& z---- | Points in R^3.-type P3 = Point R3+unr3 :: V3 n -> (n, n, n)+unr3 (V3 x y z) = (x,y,z)  -- | Construct a 3D point from a triple of coordinates.-p3 :: (Double, Double, Double) -> P3+p3 :: (n, n, n) -> P3 n p3 = P . r3  -- | Convert a 3D point back into a triple of coordinates.-unp3 :: P3 -> (Double, Double, Double)-unp3 = unr3 . unPoint+unp3 :: P3 n -> (n, n, n)+unp3 (P (V3 x y z)) = (x,y,z) -p3Iso :: Iso' P3 (Double, Double, Double)+p3Iso :: Iso' (P3 n) (n, n, n) p3Iso = iso unp3 p3  -- | Curried version of `r3`.-mkP3 :: Double -> Double -> Double -> P3+mkP3 :: n -> n -> n -> P3 n mkP3 x y z = p3 (x, y, z) --- | Transformations in R^3.-type T3 = Transformation R3+type instance V (V3 n) = V3+type instance N (V3 n) = n -instance Transformable R3 where+instance Transformable (V3 n) where   transform = apply -instance HasCross3 R3 where-  cross3 u v = r3 $ cross3 (unr3 u) (unr3 v)------------------------------------------------------------------------------------- Direction---- | A @Direction@ represents directions in R3.  The constructor is--- not exported; @Direction@s can be used with 'fromDirection' and the--- lenses provided by its instances.-data Direction = Direction R3---- | Not exported-_Dir :: Iso' Direction R3-_Dir = iso (\(Direction v) -> v) Direction--instance HasX R3 where-    _x = r3Iso . _1--instance HasX P3 where-    _x = p3Iso . _1--instance HasY R3 where-    _y = r3Iso . _2--instance HasY P3 where-    _y = p3Iso . _2--instance HasZ R3 where-    _z = r3Iso . _3--instance HasZ P3 where-    _z = p3Iso . _3---- | Types which can be expressed in spherical 3D coordinates, as a--- triple (r,θ,φ), where θ is rotation about the Z axis, and φ is the--- angle from the Z axis.-class Spherical t where-    spherical :: Iso' t (Double, Angle, Angle)---- | Types which can be expressed in cylindrical 3D coordinates.-class Cylindrical t where-    cylindrical :: Iso' t (Double, Angle, Double) -- r, θ, z--instance Cylindrical R3 where-    cylindrical = iso (\(R3 x y z) -> (sqrt (x^(2::Int)+y^(2::Int)), atanA (y/x), z))-                      (\(r,θ,z) -> R3 (r*cosA θ) (r*sinA θ) z)--instance Spherical R3 where-    spherical = iso-      (\v@(R3 x y z) -> (magnitude v, atanA (y/x), atanA (v^._r/z)))-      (\(r,θ,φ) -> R3 (r*cosA θ*sinA φ) (r*sinA θ*sinA φ) (r*cosA φ))---- We'd like to write: instance Spherical t => HasR t--- But GHC can't work out that the instance won't overlap.  Just write them explicitly:--instance HasR R3 where-    _r = spherical . _1--instance HasR P3 where-    _r = spherical . _1--instance HasTheta R3 where-    _theta = cylindrical . _2--instance HasTheta P3 where-    _theta = cylindrical . _2---- | The class of types with at least two angle coordinates, the--- second called _phi.-class HasPhi t where-    _phi :: Lens' t Angle--instance HasPhi R3 where-    _phi = spherical . _3--instance HasPhi P3 where-    _phi = spherical . _3--instance Cylindrical P3 where-    cylindrical = _relative origin . cylindrical--instance Spherical P3 where-    spherical = _relative origin . spherical+r3SphericalIso :: RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)+r3SphericalIso = iso+  (\v@(V3 x y z) -> (norm v, atan2A y x, acosA (z / norm v)))+  (\(r,θ,φ)   -> V3 (r * cosA θ * sinA φ) (r * sinA θ * sinA φ) (r * cosA φ)) -instance HasTheta Direction where-    _theta = _Dir . _theta+r3CylindricalIso :: RealFloat n => Iso' (V3 n) (n, Angle n, n)+r3CylindricalIso = iso+  (\(V3 x y z) -> (sqrt $ x*x + y*y, atan2A y x, z))+  (\(r,θ,z)    -> V3 (r*cosA θ) (r*sinA θ) z) -instance HasPhi Direction where-    _phi = _Dir . _phi+instance HasR V3 where+  _r = r3SphericalIso . _1 --- | @direction v@ is the direction in which @v@ points.  Returns an---   unspecified value when given the zero vector as input.-direction :: R3 -> Direction-direction = Direction+instance HasTheta V3 where+  _theta = r3CylindricalIso . _2 --- | @fromDirection d@ is the unit vector in the direction @d@.-fromDirection :: Direction -> R3-fromDirection (Direction v) = normalized v+instance HasPhi V3 where+  _phi = r3SphericalIso . _3 --- | compute the positive angle between the two directions in their common plane-angleBetweenDirs  :: Direction -> Direction -> Angle-angleBetweenDirs d1 d2 = angleBetween (fromDirection d1) (fromDirection d2)
src/Diagrams/ThreeD/Vector.hs view
@@ -1,7 +1,3 @@-{-# LANGUAGE FlexibleContexts-           , TypeFamilies-           , ViewPatterns-  #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.ThreeD.Vector@@ -13,34 +9,27 @@ -- ----------------------------------------------------------------------------- module Diagrams.ThreeD.Vector-       ( -- * Special 2D vectors-         unitX, unitY, unitZ, unit_X, unit_Y, unit_Z,+       ( -- * Special 3D vectors+         unitX, unitY, unitZ, unit_X, unit_Y, unit_Z+       , xDir, yDir, zDir        ) where -import Diagrams.Coordinates-import Diagrams.ThreeD.Types+import           Control.Lens          ((&), (.~)) +import           Diagrams.ThreeD.Types+import           Diagrams.TwoD.Vector+import           Diagrams.Direction --- | The unit vector in the positive X direction.-unitX :: R3-unitX = 1 ^& 0 ^& 0+import           Linear.Vector  -- | The unit vector in the positive Y direction.-unitY :: R3-unitY = 0 ^& 1 ^& 0---- | The unit vector in the positive Z direction.-unitZ :: R3-unitZ = 0 ^& 0 ^& 1+unitZ :: (R3 v, Additive v, Num n) => v n+unitZ = zero & _z .~ 1  -- | The unit vector in the negative X direction.-unit_X :: R3-unit_X = (-1) ^& 0 ^& 0---- | The unit vector in the negative Y direction.-unit_Y :: R3-unit_Y = 0 ^& (-1) ^& 0+unit_Z :: (R3 v, Additive v, Num n) => v n+unit_Z = zero & _z .~ (-1) --- | The unit vector in the negative Z direction.-unit_Z :: R3-unit_Z = 0 ^& 0 ^& (-1)+-- | A 'Direction' pointing in the Z direction.+zDir :: (R3 v, Additive v, Num n) => Direction v n+zDir = dir unitZ
src/Diagrams/Trace.hs view
@@ -1,4 +1,10 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MonoLocalBinds   #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Trace@@ -27,28 +33,30 @@      ) where -import           Diagrams.Core        (HasLinearMap, Point, Subdiagram-                                      , location, origin, setTrace, trace-                                      , OrderedField)+import           Diagrams.Core        (OrderedField, Point, Subdiagram, location,+                                       origin, setTrace, trace) import           Diagrams.Core.Trace  import           Data.Maybe import           Data.Semigroup-import           Data.VectorSpace     (Scalar, negateV, InnerSpace) import           Diagrams.Combinators (withTrace) +import           Linear.Metric+import           Linear.Vector+ -- | Compute the furthest point on the boundary of a subdiagram, --   beginning from the location (local origin) of the subdiagram and --   moving in the direction of the given vector.  If there is no such --   point, the origin is returned; see also 'boundaryFromMay'.-boundaryFrom :: (HasLinearMap v, OrderedField (Scalar v), InnerSpace v, Semigroup m)-                => Subdiagram b v m -> v -> Point v+boundaryFrom :: (OrderedField n, Metric v, Semigroup m)+              => Subdiagram b v n m -> v n -> Point v n boundaryFrom s v = fromMaybe origin $ boundaryFromMay s v  -- | Compute the furthest point on the boundary of a subdiagram, --   beginning from the location (local origin) of the subdiagram and --   moving in the direction of the given vector, or @Nothing@ if --   there is no such point.-boundaryFromMay :: (HasLinearMap v, OrderedField (Scalar v), Semigroup m, InnerSpace v)-                   => Subdiagram b v m -> v -> Maybe (Point v)-boundaryFromMay s v = traceP (location s) (negateV v) s+boundaryFromMay :: (Metric v, OrderedField n, Semigroup m)+                => Subdiagram b v n m -> v n -> Maybe (Point v n)+boundaryFromMay s v = traceP (location s) (negated v) s+
src/Diagrams/Trail.hs view
@@ -1,25 +1,27 @@-{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE CPP                        #-} {-# LANGUAGE EmptyDataDecls             #-} {-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GADTs                      #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase                 #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE TypeOperators              #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}  {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-} -- We have an orphan Transformable FingerTree instance here.  ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Trail--- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2013-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -55,6 +57,8 @@          -- ** Generic trails         , Trail(..)+       , _Line, _Loop+       , _LocLine, _LocLoop        , wrapTrail, wrapLine, wrapLoop        , onTrail, onLine @@ -66,6 +70,7 @@        , lineFromVertices, trailFromVertices        , lineFromOffsets,  trailFromOffsets        , lineFromSegments, trailFromSegments+       , loopFromSegments           -- * Eliminating trails @@ -76,8 +81,10 @@        , onLineSegments        , trailOffsets, trailOffset        , lineOffsets, lineOffset, loopOffsets+       , trailPoints, linePoints, loopPoints+       , trailVertices', lineVertices', loopVertices'        , trailVertices, lineVertices, loopVertices-       , trailLocSegments, fixTrail+       , trailLocSegments, fixTrail, unfixTrail           -- * Modifying trails @@ -98,27 +105,34 @@           -- ** Extracting segments -       , GetSegment(..), getSegment+       , GetSegment(..), getSegment, GetSegmentCodomain(..)         ) where -import           Control.Arrow       ((***))-import           Control.Lens        (AnIso', iso, view, op, Wrapped(..), Rewrapped)-import           Data.AffineSpace-import           Data.FingerTree     (FingerTree, ViewL (..), ViewR (..), (<|),-                                      (|>))-import qualified Data.FingerTree     as FT-import qualified Data.Foldable       as F+import           Control.Arrow            ((***))+import           Control.Lens             hiding (at, transform, (<|), (|>))+import           Data.FingerTree          (FingerTree, ViewL (..), ViewR (..),+                                           viewl, (<|), (|>))+import qualified Data.FingerTree          as FT+import           Data.Fixed+import qualified Data.Foldable            as F import           Data.Monoid.MList import           Data.Semigroup-import           Data.VectorSpace    hiding (Sum (..))-import qualified Numeric.Interval.Kaucher    as I+import qualified Numeric.Interval.Kaucher as I -import           Diagrams.Core       hiding ((|>))+import           Diagrams.Core import           Diagrams.Located import           Diagrams.Parametric import           Diagrams.Segment+import           Diagrams.Tangent +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector++import           Data.Serialize            (Serialize)+import qualified Data.Serialize            as Serialize+ -- $internals -- -- Most users of diagrams should not need to use anything in this@@ -130,13 +144,26 @@ ------------------------------------------------------------  type instance V (FingerTree m a) = V a+type instance N (FingerTree m a) = N a -instance ( HasLinearMap (V a), InnerSpace (V a), OrderedField (Scalar (V a))-         , FT.Measured m a, Transformable a-         )+instance (FT.Measured m a, Transformable a)     => Transformable (FingerTree m a) where   transform = FT.fmap' . transform +instance (FT.Measured m a, FT.Measured n b)+  => Cons (FingerTree m a) (FingerTree n b) a b where+  _Cons = prism (uncurry (FT.<|)) $ \aas -> case FT.viewl aas of+    a FT.:< as -> Right (a, as)+    EmptyL     -> Left mempty+  {-# INLINE _Cons #-}++instance (FT.Measured m a, FT.Measured n b)+  => Snoc (FingerTree m a) (FingerTree n b) a b where+  _Snoc = prism (uncurry (FT.|>)) $ \aas -> case FT.viewr aas of+    as FT.:> a -> Right (as, a)+    EmptyR  -> Left mempty+  {-# INLINE _Snoc #-}+ ------------------------------------------------------------ --  Segment trees  ----------------------------------------- ------------------------------------------------------------@@ -148,72 +175,95 @@ --   (/e.g./, split off the smallest number of segments from the --   beginning which have a combined arc length of at least 5). -newtype SegTree v = SegTree (FingerTree (SegMeasure v) (Segment Closed v))-  deriving (Eq, Ord, Show)+newtype SegTree v n = SegTree (FingerTree (SegMeasure v n) (Segment Closed v n))+  deriving (Eq, Ord, Show, Monoid, Transformable, FT.Measured (SegMeasure v n)) -instance Wrapped (SegTree v) where-    type Unwrapped (SegTree v) = FingerTree (SegMeasure v) (Segment Closed v)-    _Wrapped' = iso (\(SegTree x) -> x) SegTree+-- Only derive the Semigroup instance for versions of base that+-- include Semigroup.  This is because the fingertree package has+-- similar CPP to only export a Semigroup instance for those versions+-- of base, so for GHC 7.10 and earlier we get a 'no instance found'+-- error when trying to derive the Semigroup instance for SegTree.  It+-- would also be possible to depend on the 'semigroups' package in+-- order to get the Semigroup class regardless of base version, but+-- presumably fingertree didn't want to add a dependency.+#if MIN_VERSION_base(4,9,0)+deriving instance (Ord n, Floating n, Metric v) => Semigroup (SegTree v n)+#endif -instance Rewrapped (SegTree v) (SegTree v')+instance Wrapped (SegTree v n) where+  type Unwrapped (SegTree v n) = FingerTree (SegMeasure v n) (Segment Closed v n)+  _Wrapped' = iso (\(SegTree x) -> x) SegTree+  {-# INLINE _Wrapped' #-} -type instance V (SegTree v) = v+instance (Metric v, OrderedField n, Metric u, OrderedField n')+  => Cons (SegTree v n) (SegTree u n') (Segment Closed v n) (Segment Closed u n') where+  _Cons = _Wrapped . _Cons . bimapping id _Unwrapped+  {-# INLINE _Cons #-} -deriving instance (OrderedField (Scalar v), InnerSpace v)-  => Monoid (SegTree v)-deriving instance (OrderedField (Scalar v), InnerSpace v)-  => FT.Measured (SegMeasure v) (SegTree v)-deriving instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-  => Transformable (SegTree v)+instance (Metric v, OrderedField n, Metric u, OrderedField n')+  => Snoc (SegTree v n) (SegTree u n') (Segment Closed v n) (Segment Closed u n') where+  _Snoc = _Wrapped . _Snoc . bimapping _Unwrapped id+  {-# INLINE _Snoc #-} -type instance Codomain (SegTree v) = v+instance Rewrapped (SegTree v n) (SegTree v' n') -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => Parametric (SegTree v) where+type instance V (SegTree v n) = v+type instance N (SegTree v n) = n++type instance Codomain (SegTree v n) = v++instance (Metric v, OrderedField n, Real n)+    => Parametric (SegTree v n) where   atParam t p = offset . fst $ splitAtParam t p -instance Num (Scalar v) => DomainBounds (SegTree v)+instance Num n => DomainBounds (SegTree v n) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v), Num (Scalar v))-    => EndValues (SegTree v)+instance (Metric v, OrderedField n, Real n)+    => EndValues (SegTree v n) -instance (InnerSpace v, RealFrac (Scalar v), Floating (Scalar v))-    => Sectionable (SegTree v) where-  splitAtParam (SegTree t) p-    | p < 0     = case FT.viewl t of-                    EmptyL    -> emptySplit-                    seg :< t' ->-                      case seg `splitAtParam` (p * tSegs) of-                        (seg1, seg2) -> ( SegTree $ FT.singleton seg1-                                        , SegTree $ seg2 <| t'-                                        )-    | p >= 1    = case FT.viewr t of-                    EmptyR    -> emptySplit-                    t' :> seg ->-                      case seg `splitAtParam` (1 - (1 - p)*tSegs) of-                        (seg1, seg2) -> ( SegTree $ t' |> seg1-                                        , SegTree $ FT.singleton seg2-                                        )-    | otherwise = case FT.viewl after of-                    EmptyL    -> emptySplit-                    seg :< after' ->-                      case seg `splitAtParam` (snd . propFrac $ p * tSegs) of-                        (seg1, seg2) -> ( SegTree $ before |> seg1-                                        , SegTree $ seg2   <| after'-                                        )-    where-      (before, after) = FT.split ((p * tSegs <) . numSegs) t-      tSegs           = numSegs t-      emptySplit      = (SegTree t, SegTree t)+splitAtParam' :: (Metric v, OrderedField n, Real n)+              => SegTree v n -> n -> ((SegTree v n, SegTree v n), n -> n)+splitAtParam' (SegTree t) p+  | tSegs == 0 = ((mempty       , mempty       ), id)+  | otherwise  = ((SegTree treeL, SegTree treeR), rescale)+  where+    tSegs  = numSegs t+    splitParam q | q <  0    = (0        , q           * tSegs)+                 | q >= 1    = (tSegs - 1, 1 + (q - 1) * tSegs)+                 | otherwise = propFrac $  q           * tSegs+      where propFrac x = let m = mod1 x in (x - m, m)+    (pSegs, pParam) = splitParam p+    (before, viewl -> seg FT.:< after) = FT.split ((pSegs <) . numSegs) t+    (segL, segR) = seg `splitAtParam` pParam+    (treeL, treeR) | pParam == 0 = (before        , seg  <| after)+                   | pParam == 1 = (before |> seg ,         after)+                   | otherwise   = (before |> segL, segR <| after)+    -- section uses rescale to find the new value of p1 after the split at p2+    rescale u | pSegs' == uSegs = (uSegs + uParam / pParam' {-'1-}) / (pSegs' + 1) {-'2-}+              | otherwise       = u * tSegs / (pSegs' + 1) {-'3-}+      where+        -- param 0 on a segment is param 1 on the previous segment+        (pSegs', pParam') | pParam == 0 = (pSegs-1, 1)+                          | otherwise   = (pSegs  , pParam)+        (uSegs , uParam ) = splitParam u+        -- '1 (pParam ≠ 0 → pParam' = pParam) ∧ (pParam = 0 → pParam' = 1) → pParam' ≠ 0+        -- '2 uSegs ≥ 0 ∧ pSegs' = uSegs → pSegs' ≥ 0 → pSegs' + 1 > 0+        -- '3 pSegs' + 1 = 0 → pSegs' = -1 → pSegs = 0 ∧ pParam = 0 → p = 0+        --    → rescale is not called +instance (Metric v, OrderedField n, Real n) => Sectionable (SegTree v n) where+  splitAtParam tree p = fst $ splitAtParam' tree p+   reverseDomain (SegTree t) = SegTree $ FT.reverse t'     where t' = FT.fmap' reverseSegment t -  -- XXX seems like it should be possible to collapse some of the-  -- above cases into one?+  section x p1 p2 | p2 == 0   = reverseDomain . fst $ splitAtParam x p1+                  | p1 <= p2  = let ((a, _), rescale) = splitAtParam' x p2+                                in  snd $ splitAtParam a (rescale p1)+                  | otherwise = reverseDomain $ section x p2 p1 -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => HasArcLength (SegTree v) where+instance (Metric v, OrderedField n, Real n)+    => HasArcLength (SegTree v n) where   arcLengthBounded eps t     -- Use the cached value if it is accurate enough; otherwise fall     -- back to recomputing a more accurate value@@ -221,60 +271,61 @@     | otherwise        = fun (eps / numSegs t)     where       i   = trailMeasure (I.singleton 0)-              (getArcLengthCached :: ArcLength v -> I.Interval (Scalar v))+              getArcLengthCached               t       fun = trailMeasure (const 0)-              (getArcLengthFun :: ArcLength v -> Scalar v -> I.Interval (Scalar v))+              getArcLengthFun               t    arcLengthToParam eps st@(SegTree t) l     | l < 0        = case FT.viewl t of                        EmptyL   -> 0-                       seg :< _ -> arcLengthToParam eps seg l / tSegs+                       seg FT.:< _ -> arcLengthToParam eps seg l / tSegs     | l >= totalAL = case FT.viewr t of                        EmptyR    -> 0-                       t' :> seg ->+                       t' FT.:> seg ->                          let p = arcLengthToParam (eps/2) seg                                    (l - arcLength (eps/2) (SegTree t'))                          in  (p - 1)/tSegs + 1     | otherwise    = case FT.viewl after of                        EmptyL    -> 0-                       seg :< _  ->+                       seg FT.:< _  ->                          let p = arcLengthToParam (eps/2) seg                                    (l - arcLength (eps/2) (SegTree before))                          in  (numSegs before + p) / tSegs     where       totalAL         = arcLength eps st       tSegs           = numSegs t-      before, after :: FingerTree (SegMeasure v) (Segment Closed v)-      (before, after) = FT.split ((>= l) . trailMeasure 0 (I.midpoint . (getArcLengthBounded eps :: ArcLength v -> I.Interval (Scalar v)))) t+      before, after :: FingerTree (SegMeasure v n) (Segment Closed v n)+      (before, after) =+        FT.split ((>= l)+                 . trailMeasure+                 0+                 (I.midpoint . getArcLengthBounded eps))+                 t  -- | Given a default result (to be used in the case of an empty --   trail), and a function to map a single measure to a result, --   extract the given measure for a trail and use it to compute a --   result.  Put another way, lift a function on a single measure --   (along with a default value) to a function on an entire trail.-trailMeasure :: ( InnerSpace v, OrderedField (Scalar v)-                , SegMeasure v :>: m, FT.Measured (SegMeasure v) t-                )+trailMeasure :: ( SegMeasure v n :>: m, FT.Measured (SegMeasure v n) t )              => a -> (m -> a) -> t -> a-trailMeasure d f = option d f . get . FT.measure+trailMeasure d f = maybe d f . get . FT.measure  -- | Compute the number of segments of anything measured by --   'SegMeasure' (/e.g./ @SegMeasure@ itself, @Segment@, @SegTree@, --   @Trail@s...)-numSegs :: ( Floating (Scalar v), Num c, Ord (Scalar v), InnerSpace v,-             FT.Measured (SegMeasure v) a-           )+numSegs :: (Num c, FT.Measured (SegMeasure v n) a)         => a -> c numSegs = fromIntegral . trailMeasure 0 (getSum . op SegCount)  -- | Compute the total offset of anything measured by 'SegMeasure'.-offset :: ( Floating (Scalar v), Ord (Scalar v), InnerSpace v,-            FT.Measured (SegMeasure v) t+offset :: ( OrderedField n, Metric v,+            FT.Measured (SegMeasure v n) t           )-       => t -> v-offset = trailMeasure zeroV (op TotalOffset . view oeOffset)+       => t -> v n+offset = trailMeasure zero (op TotalOffset . view oeOffset)  ------------------------------------------------------------ --  Trails  ------------------------------------------------@@ -342,85 +393,125 @@ --   To extract information from trails, see 'withLine', 'isLoop', --   'trailSegments', 'trailOffsets', 'trailVertices', and friends. -data Trail' l v where-  Line :: SegTree v                   -> Trail' Line v-  Loop :: SegTree v -> Segment Open v -> Trail' Loop v+data Trail' l v n where+  Line :: SegTree v n                     -> Trail' Line v n+  Loop :: SegTree v n -> Segment Open v n -> Trail' Loop v n  -- | A generic eliminator for 'Trail'', taking functions specifying --   what to do in the case of a line or a loop.-withTrail' :: (Trail' Line v -> r) -> (Trail' Loop v -> r) -> Trail' l v -> r+withTrail' :: (Trail' Line v n -> r) -> (Trail' Loop v n -> r) -> Trail' l v n -> r withTrail' line _    t@(Line{}) = line t withTrail' _    loop t@(Loop{}) = loop t -deriving instance Show v => Show (Trail' l v)-deriving instance Eq   v => Eq   (Trail' l v)-deriving instance Ord  v => Ord  (Trail' l v)+deriving instance Eq  (v n) => Eq   (Trail' l v n)+deriving instance Ord (v n) => Ord  (Trail' l v n) -type instance V (Trail' l v) = v+instance Show (v n) => Show (Trail' l v n) where+  showsPrec d (Line (SegTree ft)) = showParen (d > 10) $+    showString "lineFromSegments " . showList (F.toList ft) -type instance Codomain (Trail' l v) = v+  showsPrec d (Loop (SegTree ft) o) = showParen (d > 10) $+    showString "loopFromSegments " . showList (F.toList ft) .+    showChar ' ' . showsPrec 11 o -instance (OrderedField (Scalar v), InnerSpace v) => Semigroup (Trail' Line v) where+type instance V (Trail' l v n) = v+type instance N (Trail' l v n) = n++type instance Codomain (Trail' l v n) = v++instance (OrderedField n, Metric v) => Semigroup (Trail' Line v n) where   (Line t1) <> (Line t2) = Line (t1 `mappend` t2)  -- | The empty trail is constantly the zero vector.  Trails are --   composed via concatenation.  Note that only lines have a monoid --   instance (and not loops).-instance (OrderedField (Scalar v), InnerSpace v) => Monoid (Trail' Line v) where+instance (Metric v, OrderedField n) => Monoid (Trail' Line v n) where   mempty  = emptyLine   mappend = (<>) -instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-    => Transformable (Trail' l v) where+instance (Metric v, OrderedField n) => AsEmpty (Trail' Line v n) where+  _Empty = nearly emptyLine isLineEmpty++instance (HasLinearMap v, Metric v, OrderedField n)+    => Transformable (Trail' l v n) where   transform tr (Line t  ) = Line (transform tr t)   transform tr (Loop t s) = Loop (transform tr t) (transform tr s)  -- | The envelope for a trail is based at the trail's start.-instance (InnerSpace v, OrderedField (Scalar v)) => Enveloped (Trail' l v) where+instance (Metric v, OrderedField n) => Enveloped (Trail' l v n) where   getEnvelope = withTrail' ftEnv (ftEnv . cutLoop)     where-      ftEnv :: Trail' Line v -> Envelope v-      ftEnv (Line t) = trailMeasure mempty (view oeEnvelope) $ t+      ftEnv :: Trail' Line v n -> Envelope v n+      ftEnv (Line t) = trailMeasure mempty (view oeEnvelope) t -instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-    => Renderable (Trail' o v) NullBackend where+instance (HasLinearMap v, Metric v, OrderedField n)+    => Renderable (Trail' o v n) NullBackend where   render _ _ = mempty -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => Parametric (Trail' l v) where+instance (Metric v, OrderedField n, Real n)+    => Parametric (Trail' l v n) where   atParam t p = withTrail'                   (\(Line segT) -> segT `atParam` p)                   (\l -> cutLoop l `atParam` mod1 p)                   t +instance (Parametric (GetSegment (Trail' c v n)), Additive v, Num n)+    => Parametric (Tangent (Trail' c v n)) where+  Tangent tr `atParam` p =+    case GetSegment tr `atParam` p of+      GetSegmentCodomain Nothing                  -> zero+      GetSegmentCodomain (Just (_, seg, reparam)) -> Tangent seg `atParam` (p ^. cloneIso reparam)++instance ( Parametric (GetSegment (Trail' c v n))+         , EndValues (GetSegment (Trail' c v n))+         , Additive v+         , Num n+         )+    => EndValues (Tangent (Trail' c v n)) where+  atStart (Tangent tr) =+    case atStart (GetSegment tr) of+      GetSegmentCodomain Nothing            -> zero+      GetSegmentCodomain (Just (_, seg, _)) -> atStart (Tangent seg)+  atEnd (Tangent tr) =+    case atEnd (GetSegment tr) of+      GetSegmentCodomain Nothing            -> zero+      GetSegmentCodomain (Just (_, seg, _)) -> atEnd (Tangent seg)++instance (Metric v , OrderedField n, Real n)+    => Parametric (Tangent (Trail v n)) where+  Tangent tr `atParam` p+    = withTrail+        ((`atParam` p) . Tangent)+        ((`atParam` p) . Tangent)+        tr++instance (Metric v, OrderedField n, Real n)+    => EndValues (Tangent (Trail v n)) where+  atStart (Tangent tr) = withTrail (atStart . Tangent) (atStart . Tangent) tr+  atEnd   (Tangent tr) = withTrail (atEnd   . Tangent) (atEnd   . Tangent) tr+ -- | Compute the remainder mod 1.  Convenient for constructing loop --   parameterizations that wrap around.-mod1 :: RealFrac a => a -> a-mod1 p = p'- where-   pf = snd . propFrac $ p-   p' | p >= 0    = pf-      | otherwise = 1 + pf---- Get rid of defaulting warnings-propFrac :: RealFrac a => a -> (Int, a)-propFrac = properFraction+mod1 :: Real a => a -> a+mod1 = (`mod'` 1) -instance Num (Scalar v) => DomainBounds (Trail' l v)+instance Num n => DomainBounds (Trail' l v n) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-  => EndValues (Trail' l v)+instance (Metric v, OrderedField n, Real n)+  => EndValues (Trail' l v n) -instance (InnerSpace v, RealFrac (Scalar v), Floating (Scalar v))-    => Sectionable (Trail' Line v) where+instance (Metric v, OrderedField n, Real n)+    => Sectionable (Trail' Line v n) where   splitAtParam (Line t) p = (Line t1, Line t2)     where       (t1, t2) = splitAtParam t p +  section (Line t) p1 p2 = Line (section t p1 p2)+   reverseDomain = reverseLine -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => HasArcLength (Trail' l v) where+instance (Metric v, OrderedField n, Real n)+    => HasArcLength (Trail' l v n) where   arcLengthBounded eps =     withTrail'       (\(Line t) -> arcLengthBounded eps t)@@ -432,6 +523,33 @@       (\lp -> arcLengthToParam eps (cutLoop lp) l)       tr +instance Rewrapped (Trail' Line v n) (Trail' Line v' n')+instance Wrapped (Trail' Line v n) where+  type Unwrapped (Trail' Line v n) = SegTree v n+  _Wrapped' = iso (\(Line x) -> x) Line+  {-# INLINE _Wrapped' #-}++instance (Metric v, OrderedField n, Metric u, OrderedField n')+  => Cons (Trail' Line v n) (Trail' Line u n') (Segment Closed v n) (Segment Closed u n') where+  _Cons = _Wrapped . _Cons . bimapping id _Unwrapped+  {-# INLINE _Cons #-}++instance (Metric v, OrderedField n, Metric u, OrderedField n')+  => Snoc (Trail' Line v n) (Trail' Line u n') (Segment Closed v n) (Segment Closed u n') where+  _Snoc = _Wrapped . _Snoc . bimapping _Unwrapped id+  {-# INLINE _Snoc #-}++-- | Compose two Located trails by adding a segment joining the endpoint+--   of the first to the starting point of the second.  Note, if you have+--   two located trails such that the end of the first coincides with the+--   start of the second, this will still add a trivial zero-length segment+--   between them; in that case you are probably better off with something+--   like @mapLoc (<> unLoc t2) t1@.+instance (Real n, Floating n, Metric v)+  => Semigroup (Located (Trail' Line v n)) where+    a@(Loc aLoc aLine) <> b@(Loc _ bLine) =+      Loc aLoc (aLine <> lineFromOffsets [atStart b .-. atEnd a] <> bLine)+ -------------------------------------------------- -- Extracting segments @@ -453,9 +571,10 @@ --   trail, respectively. -- --   The codomain for 'GetSegment', /i.e./ the result you get from---   calling 'atParam', 'atStart', or 'atEnd', is @Maybe (v, Segment---   Closed v, AnIso' (Scalar v) (Scalar v))@.  @Nothing@ results if---   the trail is empty; otherwise, you get:+--   calling 'atParam', 'atStart', or 'atEnd', is+--   'GetSegmentCodomain', which is a newtype wrapper around @Maybe+--   (v, Segment Closed v, AnIso' n n)@.  @Nothing@ results if the+--   trail is empty; otherwise, you get: -- --   * the offset from the start of the trail to the beginning of the --     segment,@@ -469,41 +588,42 @@ --     you can use. newtype GetSegment t = GetSegment t +newtype GetSegmentCodomain v n =+  GetSegmentCodomain+    (Maybe ( v n                -- offset from trail start to segment start+           , Segment Closed v n -- the segment+           , AnIso' n n         -- reparameterization, trail <-> segment+           ))+ -- | Create a 'GetSegment' wrapper around a trail, after which you can --   call 'atParam', 'atStart', or 'atEnd' to extract a segment. getSegment :: t -> GetSegment t getSegment = GetSegment  type instance V (GetSegment t) = V t-type instance Codomain (GetSegment t)-  = Maybe-    ( V t                                   -- offset from trail start to segment start-    , Segment Closed (V t)                  -- the segment-    , AnIso' (Scalar (V t)) (Scalar (V t))  -- reparameterization, trail <-> segment-    )+type instance N (GetSegment t) = N t +type instance Codomain (GetSegment t) = GetSegmentCodomain (V t)+ -- | Parameters less than 0 yield the first segment; parameters --   greater than 1 yield the last.  A parameter exactly at the --   junction of two segments yields the second segment (/i.e./ the --   one with higher parameter values).-instance (InnerSpace v, OrderedField (Scalar v))-    => Parametric (GetSegment (Trail' Line v)) where+instance (Metric v, OrderedField n) => Parametric (GetSegment (Trail' Line v n)) where   atParam (GetSegment (Line (SegTree ft))) p-    | p <= 0-    = case FT.viewl ft of-        EmptyL    -> Nothing-        seg :< _  -> Just (zeroV, seg, reparam 0)+    | p <= 0 = case FT.viewl ft of+        EmptyL   -> GetSegmentCodomain Nothing+        seg FT.:< _ -> GetSegmentCodomain $ Just (zero, seg, reparam 0) -    | p >= 1-    = case FT.viewr ft of-        EmptyR     -> Nothing-        ft' :> seg -> Just (offset ft', seg, reparam (n-1))+    | p >= 1 = case FT.viewr ft of+        EmptyR     -> GetSegmentCodomain Nothing+        ft' FT.:> seg -> GetSegmentCodomain $ Just (offset ft', seg, reparam (n-1))      | otherwise-    = let (before, after) = FT.split ((p*n <) . numSegs) $ ft+    = let (before, after) = FT.split ((p*n <) . numSegs) ft       in  case FT.viewl after of-            EmptyL   -> Nothing-            seg :< _ -> Just (offset before, seg, reparam (numSegs before))+            EmptyL   -> GetSegmentCodomain Nothing+            seg FT.:< _ -> GetSegmentCodomain $ Just (offset before, seg, reparam (numSegs before))     where       n = numSegs ft       reparam k = iso (subtract k . (*n))@@ -511,12 +631,11 @@  -- | The parameterization for loops wraps around, /i.e./ parameters --   are first reduced \"mod 1\".-instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => Parametric (GetSegment (Trail' Loop v)) where+instance (Metric v, OrderedField n, Real n) => Parametric (GetSegment (Trail' Loop v n)) where   atParam (GetSegment l) p = atParam (GetSegment (cutLoop l)) (mod1 p) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => Parametric (GetSegment (Trail v)) where+instance (Metric v, OrderedField n, Real n)+    => Parametric (GetSegment (Trail v n)) where   atParam (GetSegment t) p     = withTrail       ((`atParam` p) . GetSegment)@@ -527,40 +646,41 @@   domainLower (GetSegment t) = domainLower t   domainUpper (GetSegment t) = domainUpper t -instance (InnerSpace v, OrderedField (Scalar v))-    => EndValues (GetSegment (Trail' Line v)) where+instance (Metric v, OrderedField n)+    => EndValues (GetSegment (Trail' Line v n)) where   atStart (GetSegment (Line (SegTree ft)))     = case FT.viewl ft of-        EmptyL   -> Nothing-        seg :< _ ->+        EmptyL   -> GetSegmentCodomain Nothing+        seg FT.:< _ ->           let n = numSegs ft-          in  Just (zeroV, seg, iso (*n) (/n))+          in  GetSegmentCodomain $ Just (zero, seg, iso (*n) (/n))    atEnd (GetSegment (Line (SegTree ft)))     = case FT.viewr ft of-        EmptyR     -> Nothing-        ft' :> seg ->+        EmptyR     -> GetSegmentCodomain Nothing+        ft' FT.:> seg ->           let n = numSegs ft-          in  Just (offset ft', seg, iso (subtract (n-1) . (*n))+          in  GetSegmentCodomain $+                Just (offset ft', seg, iso (subtract (n-1) . (*n))                                          ((/n) . (+ (n-1)))-                   )+                     ) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => EndValues (GetSegment (Trail' Loop v)) where+instance (Metric v, OrderedField n, Real n)+    => EndValues (GetSegment (Trail' Loop v n)) where   atStart (GetSegment l) = atStart (GetSegment (cutLoop l))   atEnd   (GetSegment l) = atEnd   (GetSegment (cutLoop l)) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => EndValues (GetSegment (Trail v)) where+instance (Metric v, OrderedField n, Real n)+    => EndValues (GetSegment (Trail v n)) where   atStart (GetSegment t)     = withTrail-      (\l -> atStart (GetSegment l))-      (\l -> atStart (GetSegment l))+      (atStart . GetSegment)+      (atStart . GetSegment)       t   atEnd (GetSegment t)     = withTrail-      (\l -> atEnd (GetSegment l))-      (\l -> atEnd (GetSegment l))+      (atEnd . GetSegment)+      (atEnd . GetSegment)       t  --------------------------------------------------@@ -569,23 +689,23 @@ -- | @Trail@ is a wrapper around @Trail'@, hiding whether the --   underlying @Trail'@ is a line or loop (though which it is can be --   recovered; see /e.g./ 'withTrail').-data Trail v where-  Trail :: Trail' l v -> Trail v+data Trail v n where+  Trail :: Trail' l v n -> Trail v n -deriving instance Show v => Show (Trail v)+deriving instance Show (v n) => Show (Trail v n) -instance Eq v => Eq (Trail v) where+instance Eq (v n) => Eq (Trail v n) where   t1 == t2 =     withTrail       (\ln1 -> withTrail (\ln2 -> ln1 == ln2) (const False) t2)       (\lp1 -> withTrail (const False) (\lp2 -> lp1 == lp2) t2)       t1 -instance Ord v => Ord (Trail v) where+instance Ord (v n) => Ord (Trail v n) where   compare t1 t2 =     withTrail-      (\ln1 -> withTrail (\ln2 -> compare ln1 ln2) (const LT) t2)-      (\lp1 -> withTrail (const GT) (\lp2 -> compare lp1 lp2) t2)+      (\ln1 -> withTrail (compare ln1) (const LT) t2)+      (\lp1 -> withTrail (const GT) (compare lp1) t2)       t1  -- | Two @Trail@s are combined by first ensuring they are both lines@@ -593,7 +713,7 @@ --   result, in general, is a line.  However, there is a special case --   for the empty line, which acts as the identity (so combining the --   empty line with a loop results in a loop).-instance (OrderedField (Scalar v), InnerSpace v) => Semigroup (Trail v) where+instance (OrderedField n, Metric v) => Semigroup (Trail v n) where   (Trail (Line (SegTree ft))) <> t2 | FT.null ft = t2   t1 <> (Trail (Line (SegTree ft))) | FT.null ft = t1   t1 <> t2 = flip withLine t1 $ \l1 ->@@ -608,29 +728,32 @@ --   strange.  Mostly it is provided for convenience, so one can work --   directly with @Trail@s instead of working with @Trail' Line@s and --   then wrapping.-instance (OrderedField (Scalar v), InnerSpace v) => Monoid (Trail v) where+instance (Metric v, OrderedField n) => Monoid (Trail v n) where   mempty  = wrapLine emptyLine   mappend = (<>) -type instance V (Trail v) = v+instance (Metric v, OrderedField n) => AsEmpty (Trail v n) where+  _Empty = nearly emptyTrail isTrailEmpty -type instance Codomain (Trail v) = v+type instance V (Trail v n) = v+type instance N (Trail v n) = n -instance (HasLinearMap v, InnerSpace v, OrderedField (Scalar v))-    => Transformable (Trail v) where+type instance Codomain (Trail v n) = v++instance (HasLinearMap v, Metric v, OrderedField n)+    => Transformable (Trail v n) where   transform t = onTrail (transform t) (transform t) -instance (InnerSpace v, OrderedField (Scalar v)) => Enveloped (Trail v) where+instance (Metric v, OrderedField n) => Enveloped (Trail v n) where   getEnvelope = withTrail getEnvelope getEnvelope -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => Parametric (Trail v) where+instance (Metric v, OrderedField n, Real n)+    => Parametric (Trail v n) where   atParam t p = withTrail (`atParam` p) (`atParam` p) t -instance Num (Scalar v) => DomainBounds (Trail v)+instance Num n => DomainBounds (Trail v n) -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-  => EndValues (Trail v)+instance (Metric v, OrderedField n, Real n) => EndValues (Trail v n)  -- | Note that there is no @Sectionable@ instance for @Trail' Loop@, --   because it does not make sense (splitting a loop at a parameter@@ -641,29 +764,57 @@ --   semantically a bit silly, so please don't rely on it. (*E.g.* if --   this is really the behavior you want, consider first calling --   'cutLoop' yourself.)-instance (InnerSpace v, RealFrac (Scalar v), Floating (Scalar v))-    => Sectionable (Trail v) where+instance (Metric v, OrderedField n, Real n) => Sectionable (Trail v n) where   splitAtParam t p = withLine ((wrapLine *** wrapLine) . (`splitAtParam` p)) t +  section t p1 p2 = withLine (wrapLine . (\l -> section l p1 p2)) t+   reverseDomain = reverseTrail -instance (InnerSpace v, OrderedField (Scalar v), RealFrac (Scalar v))-    => HasArcLength (Trail v) where+instance (Metric v, OrderedField n, Real n)+    => HasArcLength (Trail v n) where   arcLengthBounded = withLine . arcLengthBounded   arcLengthToParam eps tr al = withLine (\ln -> arcLengthToParam eps ln al) tr +-- lens instrances -----------------------------------------------------++-- | Prism onto a 'Line'.+_Line :: Prism' (Trail v n) (Trail' Line v n)+_Line = _Wrapped' . _Left++-- | Prism onto a 'Loop'.+_Loop :: Prism' (Trail v n) (Trail' Loop v n)+_Loop = _Wrapped' . _Right++-- | Prism onto a 'Located' 'Line'.+_LocLine :: Prism' (Located (Trail v n)) (Located (Trail' Line v n))+_LocLine = prism' (mapLoc Trail) $ located (preview _Line)++-- | Prism onto a 'Located' 'Loop'.+_LocLoop :: Prism' (Located (Trail v n)) (Located (Trail' Loop v n))+_LocLoop = prism' (mapLoc Trail) $ located (preview _Loop)++instance Rewrapped (Trail v n) (Trail v' n')+instance Wrapped (Trail v n) where+  type Unwrapped (Trail v n) = Either (Trail' Line v n) (Trail' Loop v n)+  _Wrapped' = iso getTrail (either Trail Trail)+    where+      getTrail :: Trail v n -> Either (Trail' Line v n) (Trail' Loop v n)+      getTrail (Trail t@(Line {})) = Left t+      getTrail (Trail t@(Loop {})) = Right t+ -------------------------------------------------- -- Constructors and eliminators for Trail  -- | A generic eliminator for 'Trail', taking functions specifying --   what to do in the case of a line or a loop.-withTrail :: (Trail' Line v -> r) -> (Trail' Loop v -> r) -> Trail v -> r+withTrail :: (Trail' Line v n -> r) -> (Trail' Loop v n -> r) -> Trail v n -> r withTrail line loop (Trail t) = withTrail' line loop t  -- | Modify a @Trail@, specifying two separate transformations for the --   cases of a line or a loop.-onTrail :: (Trail' Line v -> Trail' l1 v) -> (Trail' Loop v -> Trail' l2 v)-        -> (Trail v -> Trail v)+onTrail :: (Trail' Line v n -> Trail' l1 v n) -> (Trail' Loop v n -> Trail' l2 v n)+        -> Trail v n -> Trail v n onTrail o c = withTrail (wrapTrail . o) (wrapTrail . c)  -- | An eliminator for @Trail@ based on eliminating lines: if the@@ -673,8 +824,8 @@ -- @ -- withLine f === 'withTrail' f (f . 'cutLoop') -- @-withLine :: (InnerSpace v, OrderedField (Scalar v))-              => (Trail' Line v -> r) -> Trail v -> r+withLine :: (Metric v, OrderedField n)+              => (Trail' Line v n -> r) -> Trail v n -> r withLine f = withTrail f (f . cutLoop)  -- | Modify a @Trail@ by specifying a transformation on lines.  If the@@ -690,25 +841,25 @@ --   Note that there is no corresponding @onLoop@ function, because --   there is no nice way in general to convert a line into a loop, --   operate on it, and then convert back.-onLine :: (InnerSpace v, OrderedField (Scalar v))-            => (Trail' Line v -> Trail' Line v) -> Trail v -> Trail v+onLine :: (Metric v, OrderedField n)+       => (Trail' Line v n -> Trail' Line v n) -> Trail v n -> Trail v n onLine f = onTrail f (glueLine . f . cutLoop)  -- | Convert a 'Trail'' into a 'Trail', hiding the type-level --   distinction between lines and loops.-wrapTrail :: Trail' l v -> Trail v+wrapTrail :: Trail' l v n -> Trail v n wrapTrail = Trail  -- | Convert a line into a 'Trail'.  This is the same as 'wrapTrail', --   but with a more specific type, which can occasionally be --   convenient for fixing the type of a polymorphic expression.-wrapLine :: Trail' Line v -> Trail v+wrapLine :: Trail' Line v n -> Trail v n wrapLine = wrapTrail  -- | Convert a loop into a 'Trail'.  This is the same as 'wrapTrail', --   but with a more specific type, which can occasionally be --   convenient for fixing the type of a polymorphic expression.-wrapLoop :: Trail' Loop v -> Trail v+wrapLoop :: Trail' Loop v n -> Trail v n wrapLoop = wrapTrail  ------------------------------------------------------------@@ -716,22 +867,28 @@ ------------------------------------------------------------  -- | The empty line, which is the identity for concatenation of lines.-emptyLine :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Line v+emptyLine :: (Metric v, OrderedField n) => Trail' Line v n emptyLine = Line mempty  -- | A wrapped variant of 'emptyLine'.-emptyTrail :: (InnerSpace v, OrderedField (Scalar v)) => Trail v+emptyTrail :: (Metric v, OrderedField n) => Trail v n emptyTrail = wrapLine emptyLine  -- | Construct a line from a list of closed segments.-lineFromSegments :: (InnerSpace v, OrderedField (Scalar v))-                   => [Segment Closed v] -> Trail' Line v+lineFromSegments :: (Metric v, OrderedField n)+                   => [Segment Closed v n] -> Trail' Line v n lineFromSegments = Line . SegTree . FT.fromList +-- | Construct a loop from a list of closed segments and an open segment+--   that completes the loop.+loopFromSegments :: (Metric v, OrderedField n)+                  => [Segment Closed v n] -> Segment Open v n -> Trail' Loop v n+loopFromSegments segs = Loop (SegTree (FT.fromList segs))+ -- | @trailFromSegments === 'wrapTrail' . 'lineFromSegments'@, for --   conveniently constructing a @Trail@ instead of a @Trail'@.-trailFromSegments :: (InnerSpace v, OrderedField (Scalar v))-                  => [Segment Closed v] -> Trail v+trailFromSegments :: (Metric v, OrderedField n)+                  => [Segment Closed v n] -> Trail v n trailFromSegments = wrapTrail . lineFromSegments  -- | Construct a line containing only linear segments from a list of@@ -742,14 +899,12 @@ -- --   > import Diagrams.Coordinates --   > lineFromOffsetsEx = strokeLine $ lineFromOffsets [ 2 ^& 1, 2 ^& (-1), 2 ^& 0.5 ]-lineFromOffsets :: (InnerSpace v, OrderedField (Scalar v))-                  => [v] -> Trail' Line v+lineFromOffsets :: (Metric v, OrderedField n) => [v n] -> Trail' Line v n lineFromOffsets = lineFromSegments . map straight  -- | @trailFromOffsets === 'wrapTrail' . 'lineFromOffsets'@, for --   conveniently constructing a @Trail@ instead of a @Trail' Line@.-trailFromOffsets :: (InnerSpace v, OrderedField (Scalar v))-                 => [v] -> Trail v+trailFromOffsets :: (Metric v, OrderedField n) => [v n] -> Trail v n trailFromOffsets = wrapTrail . lineFromOffsets  -- | Construct a line containing only linear segments from a list of@@ -771,8 +926,8 @@ --   > import Diagrams.Coordinates --   > lineFromVerticesEx = pad 1.1 . centerXY . strokeLine --   >   $ lineFromVertices [origin, 0 ^& 1, 1 ^& 2, 5 ^& 1]-lineFromVertices :: (InnerSpace v, OrderedField (Scalar v))-                   => [Point v] -> Trail' Line v+lineFromVertices :: (Metric v, OrderedField n)+                   => [Point v n] -> Trail' Line v n lineFromVertices []  = emptyLine lineFromVertices [_] = emptyLine lineFromVertices ps  = lineFromSegments . map straight $ zipWith (.-.) (tail ps) ps@@ -780,8 +935,8 @@  -- | @trailFromVertices === 'wrapTrail' . 'lineFromVertices'@, for --   conveniently constructing a @Trail@ instead of a @Trail' Line@.-trailFromVertices :: (InnerSpace v, OrderedField (Scalar v))-                  => [Point v] -> Trail v+trailFromVertices :: (Metric v, OrderedField n)+                  => [Point v n] -> Trail v n trailFromVertices = wrapTrail . lineFromVertices  ------------------------------------------------------------@@ -797,10 +952,10 @@ -- --   <<diagrams/src_Diagrams_Trail_glueLineEx.svg#diagram=glueLineEx&width=500>> -----   > glueLineEx = pad 1.1 . hcat' (with & sep .~ 1)+--   > glueLineEx = pad 1.1 . hsep 1 --   >   $ [almostClosed # strokeLine, almostClosed # glueLine # strokeLoop] --   >---   > almostClosed :: Trail' Line R2+--   > almostClosed :: Trail' Line V2 Double --   > almostClosed = fromOffsets $ map r2 [(2, -1), (-3, -0.5), (-2, 1), (1, 0.5)] -- --   @glueLine@ is left inverse to 'cutLoop', that is,@@ -808,16 +963,16 @@ --   @ --   glueLine . cutLoop === id --   @-glueLine :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Line v -> Trail' Loop v+glueLine :: (Metric v, OrderedField n) => Trail' Line v n -> Trail' Loop v n glueLine (Line (SegTree t)) =   case FT.viewr t of-    FT.EmptyR             -> Loop mempty (Linear OffsetOpen)-    t' :> (Linear _)      -> Loop (SegTree t') (Linear OffsetOpen)-    t' :> (Cubic c1 c2 _) -> Loop (SegTree t') (Cubic c1 c2 OffsetOpen)+    FT.EmptyR           -> Loop mempty (Linear OffsetOpen)+    t' FT.:> Linear _      -> Loop (SegTree t') (Linear OffsetOpen)+    t' FT.:> Cubic c1 c2 _ -> Loop (SegTree t') (Cubic c1 c2 OffsetOpen)  -- | @glueTrail@ is a variant of 'glueLine' which works on 'Trail's. --   It performs 'glueLine' on lines and is the identity on loops.-glueTrail :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> Trail v+glueTrail :: (Metric v, OrderedField n) => Trail v n -> Trail v n glueTrail = onTrail glueLine id  -- | Make a line into a loop by adding a new linear segment from the@@ -843,12 +998,12 @@ -- --   > closeLineEx = pad 1.1 . centerXY . hcat' (with & sep .~ 1) --   >   $ [almostClosed # strokeLine, almostClosed # closeLine # strokeLoop]-closeLine :: Trail' Line v -> Trail' Loop v+closeLine :: Trail' Line v n -> Trail' Loop v n closeLine (Line t) = Loop t (Linear OffsetOpen)  -- | @closeTrail@ is a variant of 'closeLine' for 'Trail', which --   performs 'closeLine' on lines and is the identity on loops.-closeTrail :: Trail v -> Trail v+closeTrail :: Trail v n -> Trail v n closeTrail = onTrail closeLine id  -- | Turn a loop into a line by \"cutting\" it at the common start/end@@ -860,22 +1015,22 @@ --   @ --   glueLine . cutLoop === id --   @-cutLoop :: forall v. (InnerSpace v, OrderedField (Scalar v))-         => Trail' Loop v -> Trail' Line v+cutLoop :: forall v n. (Metric v, OrderedField n)+         => Trail' Loop v n -> Trail' Line v n cutLoop (Loop (SegTree t) c) =   case (FT.null t, c) of     (True, Linear OffsetOpen)      -> emptyLine     (_   , Linear OffsetOpen)      -> Line (SegTree (t |> Linear off))     (_   , Cubic c1 c2 OffsetOpen) -> Line (SegTree (t |> Cubic c1 c2 off))   where-    offV :: v-    offV = negateV . trailMeasure zeroV (op TotalOffset .view oeOffset) $ t+    offV :: v n+    offV = negated . trailMeasure zero (op TotalOffset .view oeOffset) $ t     off = OffsetClosed offV  -- | @cutTrail@ is a variant of 'cutLoop' for 'Trail'; it is the is --   the identity on lines and performs 'cutLoop' on loops.-cutTrail :: (InnerSpace v, OrderedField (Scalar v))-         => Trail v -> Trail v+cutTrail :: (Metric v, OrderedField n)+         => Trail v n -> Trail v n cutTrail = onTrail id cutLoop  ------------------------------------------------------------@@ -883,45 +1038,45 @@ ------------------------------------------------------------  -- | Test whether a line is empty.-isLineEmpty :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Line v -> Bool+isLineEmpty :: (Metric v, OrderedField n) => Trail' Line v n -> Bool isLineEmpty (Line (SegTree t)) = FT.null t  -- | Test whether a trail is empty.  Note that loops are never empty.-isTrailEmpty :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> Bool+isTrailEmpty :: (Metric v, OrderedField n) => Trail v n -> Bool isTrailEmpty = withTrail isLineEmpty (const False)  -- | Determine whether a trail is a line.-isLine :: Trail v -> Bool+isLine :: Trail v n -> Bool isLine = not . isLoop  -- | Determine whether a trail is a loop.-isLoop :: Trail v -> Bool+isLoop :: Trail v n -> Bool isLoop = withTrail (const False) (const True)  -- | Extract the segments comprising a line.-lineSegments :: Trail' Line v -> [Segment Closed v]+lineSegments :: Trail' Line v n -> [Segment Closed v n] lineSegments (Line (SegTree t)) = F.toList t  -- | Modify a line by applying a function to its list of segments. onLineSegments-  :: (InnerSpace v, OrderedField (Scalar v))-  => ([Segment Closed v] -> [Segment Closed v])-  -> Trail' Line v -> Trail' Line v+  :: (Metric v, OrderedField n)+  => ([Segment Closed v n] -> [Segment Closed v n])+  -> Trail' Line v n -> Trail' Line v n onLineSegments f = lineFromSegments . f . lineSegments  -- | Extract the segments comprising a loop: a list of closed --   segments, and one final open segment.-loopSegments :: Trail' Loop v -> ([Segment Closed v], Segment Open v)+loopSegments :: Trail' Loop v n -> ([Segment Closed v n], Segment Open v n) loopSegments (Loop (SegTree t) c) = (F.toList t, c)  -- | Extract the segments of a trail.  If the trail is a loop it will --   first have 'cutLoop' applied.-trailSegments :: (InnerSpace v, OrderedField (Scalar v))-              => Trail v -> [Segment Closed v]+trailSegments :: (Metric v, OrderedField n)+              => Trail v n -> [Segment Closed v n] trailSegments = withLine lineSegments  -- | Extract the offsets of the segments of a trail.-trailOffsets :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> [v]+trailOffsets :: (Metric v, OrderedField n) => Trail v n -> [v n] trailOffsets = withLine lineOffsets  -- | Compute the offset from the start of a trail to the end.  Satisfies@@ -936,67 +1091,208 @@ -- --   > trailOffsetEx = (strokeLine almostClosed <> showOffset) # centerXY # pad 1.1 --   >   where showOffset = fromOffsets [trailOffset (wrapLine almostClosed)]---   >                    # stroke # lc red-trailOffset :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> v+--   >                    # strokeP # lc red+trailOffset :: (Metric v, OrderedField n) => Trail v n -> v n trailOffset = withLine lineOffset  -- | Extract the offsets of the segments of a line.-lineOffsets :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Line v -> [v]+lineOffsets :: Trail' Line v n -> [v n] lineOffsets = map segOffset . lineSegments  -- | Extract the offsets of the segments of a loop.-loopOffsets :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Loop v -> [v]+loopOffsets :: (Metric v, OrderedField n) => Trail' Loop v n -> [v n] loopOffsets = lineOffsets . cutLoop  -- | Compute the offset from the start of a line to the end.  (Note, --   there is no corresponding @loopOffset@ function because by --   definition it would be constantly zero.)-lineOffset :: (InnerSpace v, OrderedField (Scalar v)) => Trail' Line v -> v-lineOffset (Line t) = trailMeasure zeroV (op TotalOffset . view oeOffset) t+lineOffset :: (Metric v, OrderedField n) => Trail' Line v n -> v n+lineOffset (Line t) = trailMeasure zero (op TotalOffset . view oeOffset) t --- | Extract the vertices of a concretely located trail.  Note that---   for loops, the starting vertex will /not/ be repeated at the end.---   If you want this behavior, you can use 'cutTrail' to make the---   loop into a line first, which happens to repeat the same vertex---   at the start and end, /e.g./ with @trailVertices . mapLoc+-- | Extract the points of a concretely located trail, /i.e./ the points+--   where one segment ends and the next begins. Note that for loops,+--   the starting point will /not/ be repeated at the end.  If you+--   want this behavior, you can use 'cutTrail' to make the loop into+--   a line first, which happens to repeat the same point at the start+--   and end, /e.g./ with @trailPoints . mapLoc cutTrail@.+--+--   Note that it does not make sense to ask for the points of a+--   'Trail' by itself; if you want the points of a trail+--   with the first point at, say, the origin, you can use+--   @trailPoints . (\`at\` origin)@.+--+--   This function allows you "observe" the fact that trails are+--   implemented as lists of segments, which may be problematic if we+--   want to think of trails as parametric vector functions. This also+--   means that the behavior of this function may not be stable under+--   future changes to the implementation of trails.  For an+--   unproblematic version which only yields vertices at which there+--   is a sharp corner, excluding points where the trail is+--   differentiable, see 'trailVertices'.+--+--   This function is not re-exported from "Diagrams.Prelude"; to use+--   it, import "Diagrams.Trail".+trailPoints :: (Metric v, OrderedField n)+              => Located (Trail v n) -> [Point v n]+trailPoints (viewLoc -> (p,t))+  = withTrail (linePoints . (`at` p)) (loopPoints . (`at` p)) t++-- | Extract the segment join points of a concretely located line.  See+--   'trailPoints' for more information.+--+--   This function allows you "observe" the fact that lines are+--   implemented as lists of segments, which may be problematic if we+--   want to think of lines as parametric vector functions. This also+--   means that the behavior of this function may not be stable under+--   future changes to the implementation of trails.  For an+--   unproblematic version which only yields vertices at which there+--   is a sharp corner, excluding points where the trail is+--   differentiable, see 'lineVertices'.+--+--   This function is not re-exported from "Diagrams.Prelude"; to use+--   it, import "Diagrams.Trail".+linePoints :: (Metric v, OrderedField n)+             => Located (Trail' Line v n) -> [Point v n]+linePoints (viewLoc -> (p,t))+  = segmentPoints p . lineSegments $ t++-- | Extract the segment join points of a concretely located loop.  Note that the+--   initial vertex is not repeated at the end.  See 'trailPoints' for+--   more information.+--+--   This function allows you "observe" the fact that lines are+--   implemented as lists of segments, which may be problematic if we+--   want to think of lines as parametric vector functions. This also+--   means that the behavior of this function may not be stable under+--   future changes to the implementation of trails.  For an+--   unproblematic version which only yields vertices at which there+--   is a sharp corner, excluding points where the trail is+--   differentiable, see 'lineVertices'.+--+--   This function is not re-exported from "Diagrams.Prelude"; to use+--   it, import "Diagrams.Trail".+loopPoints :: (Metric v, OrderedField n)+             => Located (Trail' Loop v n) -> [Point v n]+loopPoints (viewLoc -> (p,t))+  = segmentPoints p . fst . loopSegments $ t++segmentPoints :: (Additive v, Num n) => Point v n -> [Segment Closed v n] -> [Point v n]+segmentPoints p = scanl (.+^) p . map segOffset++tolerance :: OrderedField a => a+tolerance = 10e-16++-- | Extract the vertices of a concretely located trail.  Here a /vertex/+--   is defined as a non-differentiable point on the trail, /i.e./ a+--   sharp corner.  (Vertices are thus a subset of the places where+--   segments join; if you want all joins between segments, see+--   'trailPoints'.)  The tolerance determines how close the tangents+--   of two segments must be at their endpoints to consider the+--   transition point to be differentiable.+--+--   Note that for loops, the starting vertex will /not/ be repeated+--   at the end.  If you want this behavior, you can use 'cutTrail' to+--   make the loop into a line first, which happens to repeat the same+--   vertex at the start and end, /e.g./ with @trailVertices . mapLoc --   cutTrail@. -----   Note that it does not make sense to ask for the vertices of a---   'Trail' by itself; if you want the vertices of a trail---   with the first vertex at, say, the origin, you can use---   @trailVertices . (\`at\` origin)@.-trailVertices :: (InnerSpace v, OrderedField (Scalar v))-              => Located (Trail v) -> [Point v]-trailVertices (viewLoc -> (p,t))-  = withTrail (lineVertices . (`at` p)) (loopVertices . (`at` p)) t+--   It does not make sense to ask for the vertices of a 'Trail' by+--   itself; if you want the vertices of a trail with the first vertex+--   at, say, the origin, you can use @trailVertices . (\`at\`+--   origin)@.+trailVertices' :: (Metric v, OrderedField n)+              => n ->  Located (Trail v n) -> [Point v n]+trailVertices' toler (viewLoc -> (p,t))+  = withTrail (lineVertices' toler . (`at` p)) (loopVertices' toler . (`at` p)) t +-- | Like 'trailVertices'', with a default tolerance.+trailVertices :: (Metric v, OrderedField n)+              => Located (Trail v n) -> [Point v n]+trailVertices = trailVertices' tolerance+ -- | Extract the vertices of a concretely located line.  See --   'trailVertices' for more information.-lineVertices :: (InnerSpace v, OrderedField (Scalar v))-             => Located (Trail' Line v) -> [Point v]-lineVertices (viewLoc -> (p,t))-  = segmentVertices p . lineSegments $ t+lineVertices' :: (Metric v, OrderedField n)+             => n -> Located (Trail' Line v n) -> [Point v n]+lineVertices' toler (viewLoc -> (p,t))+  = segmentVertices' toler p . lineSegments $ t +-- | Like 'lineVertices'', with a default tolerance.+lineVertices :: (Metric v, OrderedField n)+             => Located (Trail' Line v n) -> [Point v n]+lineVertices = lineVertices' tolerance+ -- | Extract the vertices of a concretely located loop.  Note that the --   initial vertex is not repeated at the end.  See 'trailVertices' for --   more information.-loopVertices :: (InnerSpace v, OrderedField (Scalar v))-             => Located (Trail' Loop v) -> [Point v]-loopVertices (viewLoc -> (p,t))-  = segmentVertices p . fst . loopSegments $ t+loopVertices' :: (Metric v, OrderedField n)+             => n -> Located (Trail' Loop v n) -> [Point v n]+loopVertices' toler (viewLoc -> (p,t))+  | length segs > 1 = if far > toler  then init ps else init . drop 1 $ ps+  | otherwise       = ps+  where+    far = quadrance ((signorm . tangentAtStart . head $ segs) ^-^+                       (signorm . tangentAtEnd   . last $ segs))+    segs = lineSegments . cutLoop $ t+    ps = segmentVertices' toler p segs -segmentVertices :: AdditiveGroup v => Point v -> [Segment Closed v] -> [Point v]-segmentVertices p = scanl (.+^) p . map segOffset+-- | Same as 'loopVertices'', with a default tolerance.+loopVertices :: (Metric v, OrderedField n)+             => Located (Trail' Loop v n) -> [Point v n]+loopVertices = loopVertices' tolerance +-- | The vertices of a list of segments laid end to end.+--   The start and end points are always included in the list of+--   vertices.  The other points connecting segments are included if+--   the slope at the end of a segment is not equal to the slope at+--   the beginning of the next.  The 'toler' parameter is used to+--   control how close the slopes need to be in order to declare them+--   equal.+segmentVertices' :: (Metric v, OrderedField n)+             => n -> Point v n -> [Segment Closed v n] -> [Point v n]+segmentVertices' toler p ts  =+  case ps of+    (x:_:_) -> x : select (drop 1 ps) ds ++ [last ps]+    _       -> ps+    where+      ds = zipWith far tans (drop 1 tans)+      tans = [(signorm . tangentAtStart $ s+              ,signorm . tangentAtEnd   $ s) | s <- ts]+      ps = scanl (.+^) p . map segOffset $ ts+      far p2 q2 = quadrance (snd p2 ^-^ fst q2) > toler++select :: [a] -> [Bool] -> [a]+select xs bs = map fst $ filter snd (zip xs bs)+ -- | Convert a concretely located trail into a list of fixed segments.-fixTrail :: (InnerSpace v, OrderedField (Scalar v))-         => Located (Trail v) -> [FixedSegment v]+--   'unfixTrail' is almost its left inverse.+fixTrail :: (Metric v, OrderedField n)+         => Located (Trail v n) -> [FixedSegment v n] fixTrail t = map mkFixedSeg (trailLocSegments t) +-- | Convert a list of fixed segments into a located trail.  Note that+--   this may lose information: it throws away the locations of all+--   but the first @FixedSegment@.  This does not matter precisely+--   when each @FixedSegment@ begins where the previous one ends.+--+--   This is almost left inverse to 'fixTrail', that is, @unfixTrail+--   . fixTrail == id@, except for the fact that @unfixTrail@ will+--   never yield a @Loop@.  In the case of a loop, we instead have+--   @glueTrail . unfixTrail . fixTrail == id@.  On the other hand, it+--   is not the case that @fixTrail . unfixTrail == id@ since+--   @unfixTrail@ may lose information.+unfixTrail+  :: (Metric v, Ord n, Floating n)+  => [FixedSegment v n] -> Located (Trail v n)+unfixTrail = mapLoc trailFromSegments . takeLoc . map fromFixedSeg+  where+    takeLoc []       = [] `at` origin+    takeLoc xs@(x:_) = map unLoc xs `at` loc x+ -- | Convert a concretely located trail into a list of located segments.-trailLocSegments :: (InnerSpace v, OrderedField (Scalar v))-                  => Located (Trail v) -> [Located (Segment Closed v)]-trailLocSegments t = zipWith at (trailSegments (unLoc t)) (trailVertices t)+trailLocSegments :: (Metric v, OrderedField n)+                  => Located (Trail v n) -> [Located (Segment Closed v n)]+trailLocSegments t = zipWith at (trailSegments (unLoc t)) (trailPoints t)  ------------------------------------------------------------ --  Modifying trails  --------------------------------------@@ -1009,7 +1305,7 @@ --   @ --   reverseTrail . reverseTrail === id --   @-reverseTrail :: (InnerSpace v, OrderedField (Scalar v)) => Trail v -> Trail v+reverseTrail :: (Metric v, OrderedField n) => Trail v n -> Trail v n reverseTrail = onTrail reverseLine reverseLoop  -- | Reverse a concretely located trail.  The endpoint of the original@@ -1020,27 +1316,81 @@ --   @ --   reverseLocTrail . reverseLocTrail === id --   @-reverseLocTrail :: (InnerSpace v, OrderedField (Scalar v))-                => Located (Trail v) -> Located (Trail v)+reverseLocTrail :: (Metric v, OrderedField n)+                => Located (Trail v n) -> Located (Trail v n) reverseLocTrail (viewLoc -> (p, t)) = reverseTrail t `at` (p .+^ trailOffset t)  -- | Reverse a line.  See 'reverseTrail'.-reverseLine :: (InnerSpace v, OrderedField (Scalar v))-            => Trail' Line v -> Trail' Line v+reverseLine :: (Metric v, OrderedField n)+            => Trail' Line v n -> Trail' Line v n reverseLine = onLineSegments (reverse . map reverseSegment)  -- | Reverse a concretely located line.  See 'reverseLocTrail'.-reverseLocLine :: (InnerSpace v, OrderedField (Scalar v))-               => Located (Trail' Line v) -> Located (Trail' Line v)+reverseLocLine :: (Metric v, OrderedField n)+               => Located (Trail' Line v n) -> Located (Trail' Line v n) reverseLocLine (viewLoc -> (p,l)) = reverseLine l `at` (p .+^ lineOffset l)  -- | Reverse a loop.  See 'reverseTrail'.-reverseLoop :: (InnerSpace v, OrderedField (Scalar v))-            => Trail' Loop v -> Trail' Loop v+reverseLoop :: (Metric v, OrderedField n)+            => Trail' Loop v n -> Trail' Loop v n reverseLoop = glueLine . reverseLine . cutLoop  -- | Reverse a concretely located loop.  See 'reverseLocTrail'.  Note --   that this is guaranteed to preserve the location.-reverseLocLoop :: (InnerSpace v, OrderedField (Scalar v))-               => Located (Trail' Loop v) -> Located (Trail' Loop v)+reverseLocLoop :: (Metric v, OrderedField n)+               => Located (Trail' Loop v n) -> Located (Trail' Loop v n) reverseLocLoop = mapLoc reverseLoop++-- | Same as 'reverseLine' or 'reverseLoop'.+instance (Metric v, OrderedField n) => Reversing (Trail' l v n) where+  reversing t@(Line _)   = onLineSegments (reverse . map reversing) t+  reversing t@(Loop _ _) = glueLine . reversing . cutLoop $ t++-- | Same as 'reverseTrail'.+instance (Metric v, OrderedField n) => Reversing (Trail v n) where+  reversing (Trail t) = Trail (reversing t)++-- | Same as 'reverseLocLine' or 'reverseLocLoop'.+instance (Metric v, OrderedField n) => Reversing (Located (Trail' l v n)) where+  reversing l@(Loc _ Line {}) = reverseLocLine l+  reversing l@(Loc _ Loop {}) = reverseLocLoop l++-- | Same as 'reverseLocTrail'.+instance (Metric v, OrderedField n) => Reversing (Located (Trail v n)) where+  reversing = reverseLocTrail++------------------------------------------------------------+--  Serialize instances+------------------------------------------------------------++instance (Serialize (v n), OrderedField n, Metric v) => Serialize (Trail v n) where+  {-# INLINE get #-}+  get = do+    isLine <- Serialize.get+    case isLine of+      True  -> do+        segTree <- Serialize.get+        return (Trail (Line segTree))+      False -> do+        segTree <- Serialize.get+        segment <- Serialize.get+        return (Trail (Loop segTree segment))++  {-# INLINE put #-}+  put (Trail (Line segTree)) = do+    Serialize.put True+    Serialize.put segTree++  put (Trail (Loop segTree segment)) = do+    Serialize.put False+    Serialize.put segTree+    Serialize.put segment++instance (OrderedField n, Metric v, Serialize (v n)) => Serialize (SegTree v n) where+  {-# INLINE put #-}+  put (SegTree fingerTree) = Serialize.put (F.toList fingerTree)++  {-# INLINE get #-}+  get = do+    fingerTree <- Serialize.get+    return (SegTree (FT.fromList fingerTree))
src/Diagrams/TrailLike.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE ConstraintKinds      #-} {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE FlexibleInstances    #-} {-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -28,15 +30,17 @@         ) where -import           Data.AffineSpace ((.-.))-import           Data.VectorSpace-import           Control.Lens (view, _Unwrapped')+import           Control.Lens     (view, _Unwrapped')  import           Diagrams.Core import           Diagrams.Located import           Diagrams.Segment import           Diagrams.Trail +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ ------------------------------------------------------------ --  TrailLike class ------------------------------------------------------------@@ -61,36 +65,36 @@ --   course call 'trailLike' directly; more typically, one would use --   one of the provided functions like 'fromOffsets', 'fromVertices', --   'fromSegments', or '~~'.-class (InnerSpace (V t), OrderedField (Scalar (V t))) => TrailLike t where+class (Metric (V t), OrderedField (N t)) => TrailLike t where    trailLike-    :: Located (Trail (V t))  -- ^ The concretely located trail.  Note-                              --   that some trail-like things-                              --   (e.g. 'Trail's) may ignore the-                              --   location.+    :: Located (Trail (V t) (N t)) -- ^ The concretely located trail.  Note+                                   --   that some trail-like things+                                   --   (e.g. 'Trail's) may ignore the+                                   --   location.     -> t  ------------------------------------------------------------ --  Instances  ---------------------------------------------  -- | A list of points is trail-like; this instance simply---   computes the vertices of the trail, using 'trailVertices'.-instance (InnerSpace v, OrderedField (Scalar v)) => TrailLike [Point v] where-  trailLike = trailVertices+--   computes the vertices of the trail, using 'trailPoints'.+instance (Metric v, OrderedField n) => TrailLike [Point v n] where+  trailLike = trailPoints  -- | Lines are trail-like.  If given a 'Trail' which contains a loop, --   the loop will be cut with 'cutLoop'.  The location is ignored.-instance (InnerSpace v, OrderedField (Scalar v)) => TrailLike (Trail' Line v) where+instance (Metric v, OrderedField n) => TrailLike (Trail' Line v n) where   trailLike = withTrail id cutLoop . unLoc  -- | Loops are trail-like.  If given a 'Trail' containing a line, the --   line will be turned into a loop using 'glueLine'.  The location --   is ignored.-instance (InnerSpace v, OrderedField (Scalar v)) => TrailLike (Trail' Loop v) where+instance (Metric v, OrderedField n) => TrailLike (Trail' Loop v n) where   trailLike = withTrail glueLine id . unLoc  -- | 'Trail's are trail-like; the location is simply ignored.-instance (InnerSpace v, OrderedField (Scalar v)) => TrailLike (Trail v) where+instance (Metric v, OrderedField n) => TrailLike (Trail v n) where   trailLike = unLoc  -- | Translationally invariant things are trail-like as long as the@@ -119,11 +123,11 @@ --   >   , straight unit_X --   >   ] --   >   # centerXY # pad 1.1-fromSegments :: TrailLike t => [Segment Closed (V t)] -> t+fromSegments :: TrailLike t => [Segment Closed (V t) (N t)] -> t fromSegments = fromLocSegments . (`at` origin)  -- | Construct a trail-like thing from a located list of segments.-fromLocSegments :: TrailLike t => Located [Segment Closed (V t)] -> t+fromLocSegments :: TrailLike t => Located [Segment Closed (V t) (N t)] -> t fromLocSegments = trailLike . mapLoc trailFromSegments  -- | Construct a trail-like thing of linear segments from a list@@ -138,12 +142,12 @@ --   >   , unitX --   >   ] --   >   # centerXY # pad 1.1-fromOffsets :: TrailLike t => [V t] -> t+fromOffsets :: TrailLike t => [Vn t] -> t fromOffsets = trailLike . (`at` origin) . trailFromOffsets  -- | Construct a trail-like thing of linear segments from a located --   list of offsets.-fromLocOffsets :: (V (V t) ~ V t, TrailLike t) => Located [V t] -> t+fromLocOffsets :: (V t ~ v, N t ~ n, V (v n) ~ v, N (v n) ~ n, TrailLike t) => Located [v n] -> t fromLocOffsets = trailLike . mapLoc trailFromOffsets  -- | Construct a trail-like thing connecting the given vertices with@@ -166,11 +170,11 @@ --   >   # fromVertices --   >   # closeTrail # strokeTrail --   >   # centerXY # pad 1.1-fromVertices :: TrailLike t => [Point (V t)] -> t+fromVertices :: TrailLike t => [Point (V t) (N t)] -> t fromVertices []       = trailLike (emptyTrail `at` origin) fromVertices ps@(p:_) = trailLike (trailFromSegments (segmentsFromVertices ps) `at` p) -segmentsFromVertices :: AdditiveGroup v => [Point v] -> [Segment Closed v]+segmentsFromVertices :: (Additive v, Num n) => [Point v n] -> [Segment Closed v n] segmentsFromVertices []         = [] segmentsFromVertices vvs@(_:vs) = map straight (zipWith (flip (.-.)) vvs vs) @@ -181,7 +185,7 @@ --   > twiddleEx --   >   = mconcat ((~~) <$> hexagon 1 <*> hexagon 1) --   >   # centerXY # pad 1.1-(~~) :: TrailLike t => Point (V t) -> Point (V t) -> t+(~~) :: (V t ~ v, N t ~ n, TrailLike t) => Point v n -> Point v n -> t p1 ~~ p2 = fromVertices [p1, p2]  -- | Given a concretely located trail, \"explode\" it by turning each@@ -195,7 +199,7 @@ --   >   # explodeTrail  -- generate a list of diagrams --   >   # zipWith lc [orange, green, yellow, red, blue] --   >   # mconcat # centerXY # pad 1.1-explodeTrail :: (VectorSpace (V t), TrailLike t) => Located (Trail (V t)) -> [t]+explodeTrail :: (V t ~ v, N t ~ n, TrailLike t) => Located (Trail v n) -> [t] explodeTrail = map (mkTrail . fromFixedSeg) . fixTrail   where     mkTrail = trailLike . mapLoc (trailFromSegments . (:[]))
src/Diagrams/Transform.hs view
@@ -1,7 +1,15 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE TypeFamilies          #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Transform--- Copyright   :  (c) 2011-13 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-15 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -11,7 +19,6 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE TypeFamilies #-}  module Diagrams.Transform     ( -- * Transformations@@ -24,7 +31,7 @@     , translation, translate, moveTo, place, scaling, scale        -- * Miscellaneous transformation-related utilities-    , conjugate, under+    , conjugate, underT, transformed, translated, movedTo, movedFrom        -- * The HasOrigin class @@ -32,27 +39,90 @@      ) where +import           Control.Lens   hiding (transform) import           Data.Semigroup import           Diagrams.Core +import           Linear.Vector+ -- | Conjugate one transformation by another. @conjugate t1 t2@ is the --   transformation which performs first @t1@, then @t2@, then the --   inverse of @t1@.-conjugate :: HasLinearMap v => Transformation v -> Transformation v -> Transformation v-conjugate t1 t2  = inv t1 <> t2 <> t1+conjugate :: (Additive v, Num n)+          => Transformation v n -> Transformation v n -> Transformation v n+conjugate t1 t2 = inv t1 <> t2 <> t1 --- | Carry out some transformation \"under\" another one: @f ``under``+-- | Carry out some transformation \"under\" another one: @f ``underT`` --   t@ first applies @t@, then @f@, then the inverse of @t@.  For---   example, @'scaleX' 2 ``under`` 'rotation' (-1/8 \@\@ Turn)@+--   example, @'scaleX' 2 ``underT`` 'rotation' (-1/8 \@\@ Turn)@ --   is the transformation which scales by a factor of 2 along the --   diagonal line y = x. -- --   Note that -----   @---   (transform t2) `under` t1 == transform (conjugate t1 t2)---   @+-- @+-- (transform t2) `underT` t1 == transform (conjugate t1 t2)+-- @ -- --   for all transformations @t1@ and @t2@.-under :: (Transformable a, Transformable b, V a ~ V b) => (a -> b) -> Transformation (V a) -> a -> b-f `under` t = transform (inv t) . f . transform t+--+--   See also the isomorphisms like 'transformed', 'movedTo',+--   'movedFrom', and 'translated'.+underT :: (InSpace v n a, SameSpace a b, Transformable a, Transformable b)+      => (a -> b) -> Transformation v n -> a -> b+f `underT` t = transform (inv t) . f . transform t++-- | Use a 'Transformation' to make an 'Iso' between an object+--   transformed and untransformed. This is useful for carrying out+--   functions 'under' another transform:+--+-- @+-- under (transformed t) f               == transform (inv t) . f . transform t+-- under (transformed t1) (transform t2) == transform (conjugate t1 t2)+-- transformed t ## a                    == transform t a+-- a ^. transformed t                    == transform (inv t) a+-- @+transformed :: (InSpace v n a, SameSpace a b, Transformable a, Transformable b)+            => Transformation v n -> Iso a b a b+transformed t = iso (transform $ inv t) (transform t)++-- | Use a 'Point' to make an 'Iso' between an object+--   moved to and from that point:+--+-- @+-- under (movedTo p) f == moveTo (-p) . f . moveTo p+-- over (movedTo p) f  == moveTo p . f . moveTo (-p)+-- movedTo p           == from (movedFrom p)+-- movedTo p ## a      == moveTo p a+-- a ^. movedTo p      == moveOriginTo p a+-- @+movedTo :: (InSpace v n a, SameSpace a b, HasOrigin a, HasOrigin b)+        => Point v n -> Iso a b a b+movedTo p = iso (moveTo (negated p)) (moveTo p)++-- | Use a 'Transformation' to make an 'Iso' between an object+--   transformed and untransformed. We have+--+-- @+-- under (movedFrom p) f == moveTo p . f . moveTo (-p)+-- movedFrom p           == from (movedTo p)+-- movedFrom p ## a      == moveOriginTo p a+-- a ^. movedFrom p      == moveTo p a+-- over (movedFrom p) f  == moveTo (-p) . f . moveTo p+-- @+movedFrom :: (InSpace v n a, SameSpace a b, HasOrigin a, HasOrigin b)+          => Point v n -> Iso a b a b+movedFrom p = iso (moveOriginTo (negated p)) (moveOriginTo p)++-- | Use a vector to make an 'Iso' between an object translated and+--   untranslated.+--+-- @+-- under (translated v) f == translate (-v) . f . translate v+-- translated v ## a      == translate v a+-- a ^. translated v      == translate (-v) a+-- over (translated v) f  == translate v . f . translate (-v)+-- @+translated :: (InSpace v n a, SameSpace a b, Transformable a, Transformable b)+           => v n -> Iso a b a b+translated v = transformed $ translation v
+ src/Diagrams/Transform/Matrix.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE MonoLocalBinds  #-}+{-# LANGUAGE TypeFamilies    #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.Transform.Matrix+-- Copyright   :  (c) 2014 diagrams team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Functions for converting between 'Transformation's and matricies.+--+-----------------------------------------------------------------------------++module Diagrams.Transform.Matrix where++import           Control.Arrow           ((&&&))+import           Control.Lens+import           Data.Distributive+import qualified Data.Foldable           as F+import           Data.Functor.Rep++import           Diagrams.Core.Transform as D+import           Diagrams.ThreeD.Types+import           Diagrams.TwoD.Types++import           Linear.Matrix+import           Linear.Vector++-- | Build a matrix from a 'Transformation', ignoring the translation.+mkMat :: (HasBasis v, Num n) => Transformation v n -> v (v n)+mkMat t = distribute . tabulate $ apply t . unit . (\x -> el x)++-- | Build a 3D transformation matrix in homogeneous coordinates from+--   a 'Transformation V3'.+mkMatHomo :: Num n => Transformation V3 n -> M44 n+mkMatHomo t = mkTransformationMat (mkMat t) (transl t)++-- | Make a 2D transformation from a 2x2 transform matrix and a+--   translation vector. Does not check if the matrix is not invertible+--   (in which case the 'T2' will be invalid).+fromMat22 :: Floating n => M22 n -> V2 n -> T2 n+fromMat22 m v = fromMatWithInv m (inv22 m) v++-- | Make a 3D transformation from a 3x3 transform matrix and a+--   translation vector. Does not check if the matrix is not invertible+--   (in which case the 'T3' will be invalid).+fromMat33 :: Floating n => M33 n -> V3 n -> T3 n+fromMat33 m v = fromMatWithInv m (inv33 m) v++-- | Build a transform with a maxtrix along with its inverse.+fromMatWithInv :: (Additive v, Distributive v, F.Foldable v, Num n)+  => v (v n) -- ^ matrix+  -> v (v n) -- ^ inverse+  -> v n     -- ^ translation+  -> Transformation v n+fromMatWithInv m m_ v =+  Transformation ((m !*)            <-> (m_ !*))+                 ((distribute m !*) <-> (distribute m_ !*))+                 v++-- | Prism onto a 2D transformation from a 2x2 transform matrix and+--   translation vector. Does not check if the matrix is invertible (in+--   which case the 'T2' will be invalid).+mat22 :: Floating n => Iso' (M22 n, V2 n) (T2 n)+mat22 = iso (uncurry fromMat22) (mkMat &&& transl)++-- | Prism onto a 3D transformation from a 3x3 transform matrix and+--   translation vector. Does not check if the matrix is invertible+--   (in which case the 'T3' will be invalid).+mat33 :: Floating n => Iso' (M33 n, V3 n) (T3 n)+mat33 = iso (uncurry fromMat33) (mkMat &&& transl)
+ src/Diagrams/Transform/ScaleInv.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DeriveDataTypeable    #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.TwoD.Transform.ScaleInv+-- Copyright   :  (c) 2012-2013 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Wrapper for creating scale-invariant objects in two dimensions.+--+-----------------------------------------------------------------------------++module Diagrams.Transform.ScaleInv+    ( ScaleInv(..)+    , scaleInvObj, scaleInvDir, scaleInvLoc+    , scaleInv, scaleInvPrim)+    where++import           Control.Lens            (makeLenses, view, (^.))+import           Data.Typeable++import           Diagrams.Angle+import           Diagrams.Core+import           Diagrams.TwoD.Transform+import           Diagrams.TwoD.Types++import           Linear.Affine+import           Linear.Vector++-- | The @ScaleInv@ wrapper creates two-dimensional /scale-invariant/+--   objects.  Intuitively, a scale-invariant object is affected by+--   transformations like translations and rotations, but not by scales.+--+--   However, this is problematic when it comes to /non-uniform/+--   scales (/e.g./ @scaleX 2 . scaleY 3@) since they can introduce a+--   perceived rotational component.  The prototypical example is an+--   arrowhead on the end of a path, which should be scale-invariant.+--   However, applying a non-uniform scale to the path but not the+--   arrowhead would leave the arrowhead pointing in the wrong+--   direction.+--+--   Moreover, for objects whose local origin is not at the local+--   origin of the parent diagram, any scale can result in a+--   translational component as well.+--+--   The solution is to also store a point (indicating the location,+--   /i.e./ the local origin) and a unit vector (indicating the+--   /direction/) along with a scale-invariant object.  A+--   transformation to be applied is decomposed into rotational and+--   translational components as follows:+--+--   * The transformation is applied to the direction vector, and the+--   difference in angle between the original direction vector and its+--   image under the transformation determines the rotational+--   component.  The rotation is applied with respect to the stored+--   location, rather than the global origin.+--+--   * The vector from the location to the image of the location under+--   the transformation determines the translational component.++data ScaleInv t =+  ScaleInv+  { _scaleInvObj :: t+  , _scaleInvDir :: Vn t+  , _scaleInvLoc :: Point (V t) (N t)+  }+  deriving Typeable++deriving instance (Show t, Show (Vn t)) => Show (ScaleInv t)++makeLenses ''ScaleInv++-- | Create a scale-invariant object pointing in the given direction,+--   located at the origin.+scaleInv :: (V t ~ v, N t ~ n, Additive v, Num n) => t -> v n -> ScaleInv t+scaleInv t d = ScaleInv t d origin++type instance V (ScaleInv t) = V t+type instance N (ScaleInv t) = N t++instance (V t ~ v, N t ~ n, Additive v, Num n, HasOrigin t) => HasOrigin (ScaleInv t) where+  moveOriginTo p (ScaleInv t v l) = ScaleInv (moveOriginTo p t) v (moveOriginTo p l)++instance (V t ~ V2, N t ~ n, RealFloat n, Transformable t) => Transformable (ScaleInv t) where+  transform tr (ScaleInv t v l) = ScaleInv (trans . rot $ t) (rot v) l'+    where+      angle = transform tr v ^. _theta++      rot :: (V k ~ V t, N k ~ N t, Transformable k) => k -> k+      rot = rotateAround l angle++      l'  = transform tr l++      trans = translate (l' .-. l)++{- Proof that the above satisfies the monoid action laws.++   1. transform mempty (ScaleInv t v l)+      = ScaleInv (trans . rot $ t) (rot v) l'+        { l'    = transform mempty l = l }+        { trans = translate (l' .-. l)+                = translate (l .-. l)+                = translate zeroV+                = id+        }+        { rot   = rotateAround l angle+                = rotateAround l (direction (transform mempty v) - direction v)+                = rotateAround l (direction v - direction v)+                = rotateAround l 0+                = id+        }+      = ScaleInv t v l++  2. transform t1 (transform t2 (ScaleInv t v l))+     = let angle = direction (transform t2 v) - direction v+           rot   = rotateAround l angle+           l'    = transform t2 l+           trans = translate (l' .-. l)+       in+           transform t1 (ScaleInv (trans . rot $ t) (rot v) l')++     = let angle  = direction (transform t2 v) - direction v+           rot    = rotateAround l angle+           l'     = transform t2 l+           trans  = translate (l' .-. l)+           angle2 = direction (transform t1 (rot v)) - direction (rot v)+           rot2   = rotateAround l' angle2+           l'2    = transform t1 l'+           trans2 = translate (l'2 .-. l')+       in+           ScaleInv (trans2 . rot2 . trans . rot $ t) (rot2 . rot $ v) l'2++       { l'2 = transform t1 l'+             = transform t1 (transform t2 l)+             = transform (t1 <> t2) l+       }+       { trans2 = translate (l'2 .-. l')+                = translate (transform (t1 <> t2) l .-. transform t2 l)+                = translate (transform t1 l .-. l)+       }+       { rot v  = rotateAround l angle v+                = rotate angle `under` translation (origin .-. l) $ v+                = rotate angle v+       }+       { angle2 = direction (transform t1 (rot v)) - direction (rot v)+                = direction (transform t1 (rotate angle v)) - direction (rotate angle v)+                = direction (transform t1 (rotate angle v)) - direction v - angle+       }+       { rot2   = rotateAround l' angle2+                = ???+       }++-}++instance (V t ~ V2, N t ~ n, RealFloat n, Renderable t b) => Renderable (ScaleInv t) b where+  render b = render b . view scaleInvObj++-- | Create a diagram from a single scale-invariant primitive.  The+--   vector argument specifies the direction in which the primitive is+--   \"pointing\" (for the purpose of keeping it rotated correctly+--   under non-uniform scaling).  The primitive is assumed to be+--   \"located\" at the origin (for the purpose of translating it+--   correctly under scaling).+--+--   Note that the resulting diagram will have an /empty/ envelope,+--   trace, and query.  The reason is that the envelope, trace, and+--   query cannot be cached---applying a transformation would cause+--   the cached envelope, etc. to get \"out of sync\" with the+--   scale-invariant object.  The intention, at any rate, is that+--   scale-invariant things will be used only as \"decorations\" (/e.g./+--   arrowheads) which should not affect the envelope, trace, and+--   query.+scaleInvPrim :: (V t ~ V2, N t ~ n, RealFloat n, Typeable t, Renderable t b, Monoid m)+             => t -> V2 n -> QDiagram b (V t) (N t) m+scaleInvPrim t d = mkQD (Prim $ scaleInv t d) mempty mempty mempty mempty
src/Diagrams/TwoD.hs view
@@ -4,7 +4,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -25,10 +25,17 @@ --     specialized to two dimensions (see also "Diagrams.Combinators" --     for more general combining). --+--   * "Diagrams.TwoD.Attributes" defines attributes specific to two+--     dimensions, *e.g.* fill color, line color, and gradients.+-- --   * "Diagrams.TwoD.Transform" defines R^2-specific transformations --     such as rotation by an angle, and scaling, translation, and --     reflection in the X and Y directions. --+--   * "Diagrams.TwoD.Deform" defines some non-affine transformations+--     specific to two dimensions, *e.g.* parallel and perspective+--     projections.+-- --   * "Diagrams.TwoD.Ellipse" defines circles and ellipses. -- --   * "Diagrams.TwoD.Arc" defines circular arcs.@@ -43,7 +50,8 @@ --     e.g. various polygons. -- --   * "Diagrams.TwoD.Arrow" contains tools for drawing arrows between---     things.+--     things, and "Diagrams.TwoD.Arrowheads" defines a collection of+--     arrowheads. -- --   * "Diagrams.TwoD.Text" defines primitive text diagrams. --@@ -61,25 +69,38 @@ ----------------------------------------------------------------------------- module Diagrams.TwoD        ( -- * R^2-         R2, r2, unr2, mkR2-       , P2, p2, unp2, mkP2-       , T2+         V2 (..), R1 (..), R2 (..)+       , P2, T2+       , r2, unr2, mkR2+       , p2, unp2, mkP2        , unitX, unitY, unit_X, unit_Y-       , direction, fromDirection+       , perp, leftTurn+       , xDir, yDir           -- * Angles        , tau+       , angleV+       , angleDir+       , signedAngleBetween , signedAngleBetweenDirs +       -- * Polar Coördinates+       , HasR(..), r2PolarIso+          -- * Paths          -- ** Stroking-       , stroke, stroke', strokeTrail, strokeT, strokeTrail', strokeT'+       , stroke, stroke'+       , strokePath, strokeP, strokePath', strokeP'+       , strokeTrail, strokeT, strokeTrail', strokeT'        , strokeLine, strokeLoop        , strokeLocTrail, strokeLocT, strokeLocLine, strokeLocLoop-       , FillRule(..), fillRule+       , FillRule(..), fillRule, _fillRule        , StrokeOpts(..), vertexNames, queryFillRule+       , intersectPoints, intersectPoints'+       , intersectPointsP, intersectPointsP'+       , intersectPointsT, intersectPointsT'           -- ** Clipping-       , clipBy, clipTo, clipped+       , clipBy, clipTo, clipped, _Clip, _clip           -- * Shapes          -- ** Rules@@ -93,6 +114,7 @@        , arc        , arc'        , arcCW+       , arcCCW        , wedge        , arcBetween        , annularWedge@@ -159,12 +181,15 @@           -- * Text        , text, topLeftText, alignedText, baselineText-       , font, italic, oblique, bold, fontSize+       , font, italic, oblique, fontSize+       , bold, bolder, lighter, thinWeight+       , ultraLight, light, mediumWeight, heavy, semiBold, ultraBold+       , _font, _fontSizeR, _fontSize        , fontSizeO, fontSizeL, fontSizeN, fontSizeG           -- * Images        , DImage(..), ImageData(..)-       , Embedded, External+       , Embedded, External, Native        , image        , loadImageEmb        , loadImageExt@@ -174,8 +199,9 @@           -- * Transformations          -- ** Rotation-       , rotation, rotate, rotateBy-       , rotationAbout, rotateAbout+       , rotation, rotate, rotateBy, rotated+       , rotationAround, rotateAround+       , rotationTo, rotateTo          -- ** Scaling        , scalingX, scaleX        , scalingY, scaleY@@ -186,9 +212,12 @@        , translationX, translateX        , translationY, translateY        , translation, translate+         -- ** Conformal affine maps+       , scalingRotationTo, scaleRotateTo          -- ** Reflection        , reflectionX, reflectX        , reflectionY, reflectY+       , reflectionXY, reflectXY        , reflectionAbout, reflectAbout          -- ** Shears        , shearingX, shearX@@ -200,21 +229,22 @@           -- * Combinators          -- ** Combining multiple diagrams-       , (===), (|||), atAngle-       , hcat, hcat'-       , vcat, vcat' +       , (===), (|||)+       , hcat, hcat', hsep+       , vcat, vcat', vsep+          -- ** Spacing and envelopes        , strutX, strutY        , padX, padY         , extrudeLeft, extrudeRight, extrudeBottom, extrudeTop -       , view+       , rectEnvelope, crop           -- ** Background -       , boundingRect, bg+       , boundingRect, bg, bgFrame           -- * Alignment        , alignL, alignR, alignT, alignB, alignTL, alignTR, alignBL, alignBR@@ -222,53 +252,49 @@        , centerX, centerY, centerXY           -- * Snugging-       , snugL, snugR, snugT, snugB, snugTL, snugTR, snugBL, snugBR+       , snugL, snugR, snugT, snugB        , snugX, snugY        , snugCenterX, snugCenterY, snugCenterXY           -- * Size          -- ** Computing size-       , width, height, size2D, sizeSpec2D-       , extentX, extentY, center2D+       , width, height+       , extentX, extentY           -- ** Specifying size-       , SizeSpec2D(..)-       , mkSizeSpec--         -- ** Adjusting size-       , sized, sizedAs--        -- * Textures-      , Texture(..), solid -      , SpreadMethod(..), GradientStop(..), mkStops, getFillTexture-      , fillTexture, getLineTexture, lineTexture, lineTextureA-      , stopFraction, stopColor--      , LGradient(..), lGradStops, lGradTrans, lGradStart, lGradEnd-      , lGradSpreadMethod, defaultLG, _LG, mkLinearGradient+       , mkSizeSpec2D+       , mkWidth+       , mkHeight+       , dims2D -      , RGradient(..)-      , rGradStops, rGradCenter0, rGradRadius0, rGradCenter1, rGradRadius1-      , rGradTrans, rGradSpreadMethod, defaultRG, _RG, mkRadialGradient+         -- * Textures+       , Texture(..), solid+       , SpreadMethod(..), GradientStop(..)+       , _FillTexture, fillTexture, _fillTexture, getFillTexture+       , _LineTexture, lineTexture, _lineTexture, lineTextureA, getLineTexture+       , stopFraction, stopColor, mkStops -        -- ** Colors-      , fillColor, fc, fcA, recommendFillColor-      , lineColor, lc, lcA, _SC+       , LGradient(..), _LG, lGradStops, lGradTrans, lGradStart, lGradEnd+       , lGradSpreadMethod, defaultLG, mkLinearGradient -       -- ** Width-       , LineWidth, getLineWidth, lineWidth, lineWidthA-       , lw, lwN, lwO, lwL, lwG-       , ultraThin, veryThin, thin, medium, thick, veryThick, ultraThick, none-       , tiny, verySmall, small, normal, large, veryLarge, huge+       , RGradient(..)+       , rGradStops, rGradCenter0, rGradRadius0, rGradCenter1, rGradRadius1+       , rGradTrans, rGradSpreadMethod, defaultRG, _RG, mkRadialGradient -       -- ** Dashing-       , Dashing(..), DashingA, getDashing-       , dashing, dashingO, dashingL, dashingN, dashingG+         -- ** Colors+       , fillColor, _SC, _AC, fc, fcA, recommendFillColor+       , lineColor, lc, lcA           -- * Visual aids for understanding the internal model        , showOrigin        , showOrigin'        , OriginOpts(..), oColor, oScale, oMinSize+       , showEnvelope+       , showEnvelope'+       , EnvelopeOpts(..), eColor, eLineWidth, ePoints+       , showTrace+       , showTrace'+       , TraceOpts(..), tColor, tScale, tMinSize, tPoints        , showLabels         ) where
src/Diagrams/TwoD/Adjust.hs view
@@ -1,5 +1,11 @@-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE Rank2Types       #-}+{-# LANGUAGE TypeFamilies     #-} +{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Adjust@@ -13,45 +19,44 @@ -----------------------------------------------------------------------------  module Diagrams.TwoD.Adjust-    (-      setDefault2DAttributes-    , adjustDiaSize2D+    ( setDefault2DAttributes+    , adjustSize2D     , adjustDia2D     ) where -import           Diagrams.Attributes      (lineCap, lineJoin,-                                           lineMiterLimitA)+import           Diagrams.Attributes+import           Diagrams.BoundingBox import           Diagrams.Core-import           Diagrams.TwoD.Attributes (lineWidthA, lineTextureA)-import           Diagrams.TwoD.Size       (SizeSpec2D (..), center2D,-                                           requiredScale, size2D)-import           Diagrams.TwoD.Text       (fontSizeA)-import           Diagrams.TwoD.Types      (R2, T2, p2)+import           Diagrams.Size+import           Diagrams.TwoD.Attributes (lineTextureA)+import           Diagrams.TwoD.Types import           Diagrams.Util            (( # )) -import           Control.Lens             (Lens', (&), (.~), (^.))-import           Data.AffineSpace         ((.-.))-import           Data.Default.Class+import           Control.Lens             (Lens', set, (^.))+import           Data.Default import           Data.Semigroup + -- | Set default attributes of a 2D diagram (in case they have not --   been set): -----       * Line width 0.01------       * Line color black+--       * 'LineWidth':  0.01 -----       * Font size 1+--       * 'LineTexture': solid black -----       * Line cap LineCapButt+--       * 'LineCap': LineCapButt -----       * line join miter+--       * 'LineJoin': miter -----       * Miter limit 10-setDefault2DAttributes :: Semigroup m => QDiagram b R2 m -> QDiagram b R2 m-setDefault2DAttributes d = d # lineWidthA def # lineTextureA def # fontSizeA def-                             # lineCap def # lineJoin def # lineMiterLimitA def-+--       * 'MiterLimit': 10+setDefault2DAttributes :: (TypeableFloat n, Semigroup m)+  => QDiagram b V2 n m -> QDiagram b V2 n m+setDefault2DAttributes d+  = d # lineWidthM def+      # lineTextureA def+      # lineCap def+      # lineJoin def+      # lineMiterLimitA def  -- | Adjust the size and position of a 2D diagram to fit within the --   requested size. The first argument is a lens into the output@@ -60,25 +65,17 @@ --   inverse of which can be used, say, to translate output/device --   coordinates back into local diagram coordinates), and the --   modified diagram itself.-adjustDiaSize2D :: Monoid' m-                => Lens' (Options b R2) SizeSpec2D-                -> b -> Options b R2 -> QDiagram b R2 m-                -> (Options b R2, T2, QDiagram b R2 m)-adjustDiaSize2D szL _ opts d =-  ( case spec of-     Dims _ _ -> opts-     _        -> opts & szL .~ (uncurry Dims . scale s $ size)-  , adjustT-  , d # transform adjustT-  )-  where spec = opts ^. szL-        size = size2D d-        s    = requiredScale spec size-        finalSz = case spec of-                    Dims w h -> (w,h)-                    _        -> scale s size-        tr = (0.5 *. p2 finalSz) .-. (s *. center2D d)-        adjustT = translation tr <> scaling s+adjustSize2D+  :: (TypeableFloat n, Monoid' m)+  => Lens' (Options b V2 n) (SizeSpec V2 n)+  -> b+  -> Options b V2 n+  -> QDiagram b V2 n m+  -> (Options b V2 n, Transformation V2 n, QDiagram b V2 n m)+adjustSize2D szL _ opts d = (set szL spec opts, t, d # transform t)+  where+    spec    = dims sz+    (sz, t) = sizeAdjustment (opts ^. szL) (boundingBox d)  -- | @adjustDia2D@ provides a useful default implementation of --   the 'adjustDia' method from the 'Backend' type class.@@ -97,10 +94,10 @@ --   to the diagram (the inverse of which can be used, say, to --   translate output/device coordinates back into local diagram --   coordinates), and the modified diagram itself.-adjustDia2D :: Monoid' m-            => Lens' (Options b R2) SizeSpec2D-            -> b -> Options b R2 -> QDiagram b R2 m-            -> (Options b R2, T2, QDiagram b R2 m)+adjustDia2D :: (TypeableFloat n, Monoid' m)+            => Lens' (Options b V2 n) (SizeSpec V2 n)+            -> b -> Options b V2 n -> QDiagram b V2 n m+            -> (Options b V2 n, Transformation V2 n, QDiagram b V2 n m) adjustDia2D szL b opts d-  = adjustDiaSize2D szL b opts (d # setDefault2DAttributes)+  = adjustSize2D szL b opts (d # setDefault2DAttributes) 
src/Diagrams/TwoD/Align.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies     #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Align@@ -28,7 +30,6 @@        -- ** Align by trace     , snugL, snugR, snugT, snugB-    , snugTL, snugTR, snugBL, snugBR        -- * Relative alignment     , alignX, snugX, alignY, snugY@@ -45,57 +46,43 @@ import           Diagrams.TwoD.Types import           Diagrams.TwoD.Vector -import           Data.VectorSpace- -- | Align along the left edge, i.e. translate the diagram in a --   horizontal direction so that the local origin is on the left edge --   of the envelope.-alignL :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a-alignL = align (negateV unitX)+alignL :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a+alignL = align unit_X -snugL :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a-snugL = snug (negateV unitX)+snugL :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a+snugL = snug unit_X  -- | Align along the right edge.-alignR :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a+alignR :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a alignR = align unitX -snugR :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a+snugR :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a snugR = snug unitX   -- | Align along the top edge.-alignT :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a+alignT :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a alignT = align unitY -snugT:: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a+snugT:: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a snugT = snug unitY  -- | Align along the bottom edge.-alignB :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a-alignB = align (negateV unitY)+alignB :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a+alignB = align unit_Y -snugB :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a-snugB = snug (negateV unitY)+snugB :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a+snugB = snug unit_Y -alignTL, alignTR, alignBL, alignBR :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a+alignTL, alignTR, alignBL, alignBR :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a alignTL = alignT . alignL alignTR = alignT . alignR alignBL = alignB . alignL alignBR = alignB . alignR -snugTL, snugTR, snugBL, snugBR-  :: (Fractional (Scalar (V a)), Alignable a, Traced a, HasOrigin a, V a ~ R2)-   => a -> a-snugTL = snugT . snugL-snugTR = snugT . snugR-snugBL = snugB . snugL-snugBR = snugB . snugR- -- | @alignX@ and @snugX@ move the local origin horizontally as follows: -- --   * @alignX (-1)@ moves the local origin to the left edge of the boundary;@@ -108,44 +95,40 @@ -- --   * @snugX@ works the same way. -alignX :: (Alignable a, HasOrigin a, V a ~ R2) => Double -> a -> a+alignX :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a alignX = alignBy unitX  -- | See the documentation for 'alignX'.-snugX :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => Double -> a -> a+snugX :: (InSpace v n a, R1 v, Fractional n, Alignable a, Traced a, HasOrigin a) => n -> a -> a snugX = snugBy unitX  -- | Like 'alignX', but moving the local origin vertically, with an --   argument of @1@ corresponding to the top edge and @(-1)@ corresponding --   to the bottom edge.-alignY :: (Alignable a, HasOrigin a, V a ~ R2) => Double -> a -> a+alignY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a alignY = alignBy unitY -snugY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => Double -> a -> a+-- | See the documentation for 'alignY'.+snugY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => n -> a -> a snugY = snugBy unitY  -- | Center the local origin along the X-axis.-centerX  :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a-centerX  = alignBy unitX 0+centerX :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a+centerX = alignBy unitX 0 -snugCenterX :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a+snugCenterX :: (InSpace v n a, R1 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a snugCenterX = snugBy unitX 0  -- | Center the local origin along the Y-axis.-centerY  :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a-centerY  = alignBy unitY 0+centerY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a+centerY = alignBy unitY 0 -snugCenterY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a+snugCenterY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a snugCenterY = snugBy unitY 0  -- | Center along both the X- and Y-axes.-centerXY :: (Alignable a, HasOrigin a, V a ~ R2) => a -> a-centerXY = center+centerXY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a+centerXY = centerX . centerY -snugCenterXY :: (Fractional (Scalar (V a)), Alignable a, Traced a,-      HasOrigin a, V a ~ R2) => a -> a-snugCenterXY = snugCenter+snugCenterXY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a+snugCenterXY = snugCenterX . snugCenterY
src/Diagrams/TwoD/Arc.hs view
@@ -1,5 +1,12 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ConstraintKinds  #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies     #-}+{-# LANGUAGE TypeOperators    #-}+{-# LANGUAGE ViewPatterns     #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Arc@@ -14,8 +21,11 @@ module Diagrams.TwoD.Arc     ( arc     , arc'-    , arcCW     , arcT++    , arcCCW+    , arcCW+     , bezierFromSweep      , wedge@@ -25,49 +35,49 @@  import           Diagrams.Angle import           Diagrams.Core+import           Diagrams.Direction import           Diagrams.Located        (at) import           Diagrams.Segment import           Diagrams.Trail import           Diagrams.TrailLike import           Diagrams.TwoD.Transform import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector    (direction, e, unitX)+import           Diagrams.TwoD.Vector    (e, unitX, unitY, unit_Y) import           Diagrams.Util           (( # )) -import           Control.Lens            ((^.))-import           Data.AffineSpace        ((.-.))-import           Data.Semigroup          ((<>))-import           Data.VectorSpace-import           Diagrams.Coordinates+import           Control.Lens            ((&), (<>~), (^.))+import           Data.Semigroup +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ -- For details of this approximation see: --   http://www.tinaja.com/glib/bezcirc2.pdf  -- | @bezierFromSweepQ1 s@ constructs a 'Cubic' segment that starts in---   the positive y direction and sweeps counterclockwise through @s@---   radians.  The approximation is only valid for angles in the first---   quadrant.-bezierFromSweepQ1 :: Angle -> Segment Closed R2-bezierFromSweepQ1 s = fmap (^-^ v) . rotate (s ^/ 2) $ bezier3 c2 c1 p0-  where p0@(coords -> x :& y) = rotate (s ^/ 2) v-        c1                    = ((4-x)/3)  ^&  ((1-x)*(3-x)/(3*y))-        c2                    = reflectY c1-        v                     = unitX+--  the positive y direction and sweeps counterclockwise through an+--  angle @s@.  The approximation is only valid for angles in the+--  first quadrant.+bezierFromSweepQ1 :: Floating n => Angle n -> Segment Closed V2 n+bezierFromSweepQ1 s = mapSegmentVectors (^-^ unitX) . rotate (s ^/ 2) $ bezier3 c2 c1 p0+  where p0@(V2 x y) = e (s ^/ 2)+        c1          = V2 ((4-x)/3) ((1-x)*(3-x)/(3*y))+        c2          = reflectY c1  -- | @bezierFromSweep s@ constructs a series of 'Cubic' segments that --   start in the positive y direction and sweep counter clockwise --   through the angle @s@.  If @s@ is negative, it will start in the --   negative y direction and sweep clockwise.  When @s@ is less than---   0.0001 the empty list results.  If the sweep is greater than tau---   radians then it is truncated to one full revolution.-bezierFromSweep :: Angle -> [Segment Closed R2]+--   0.0001 the empty list results.  If the sweep is greater than @fullTurn@+--   later segments will overlap earlier segments.+bezierFromSweep :: OrderedField n => Angle n -> [Segment Closed V2 n] bezierFromSweep s-  | s > fullTurn = bezierFromSweep fullTurn-  | s < zeroV      = fmap reflectY . bezierFromSweep $ (negateV s)-  | s < 0.0001 @@ rad     = []-  | s < fullTurn^/4      = [bezierFromSweepQ1 s]-  | otherwise      = bezierFromSweepQ1 (fullTurn^/4)-          : map (rotateBy (1/4)) (bezierFromSweep (max (s ^-^ fullTurn^/4) zeroV))+  | s < zero          = fmap reflectY . bezierFromSweep $ negated s+  | s < 0.0001 @@ rad = []+  | s < fullTurn^/4   = [bezierFromSweepQ1 s]+  | otherwise         = bezierFromSweepQ1 (fullTurn^/4)+          : map (rotateBy (1/4)) (bezierFromSweep (max (s ^-^ fullTurn^/4) zero))  {- ~~~~ Note [segment spacing]@@ -89,72 +99,71 @@ the approximation error. -} --- | Given a start angle @s@ and an end angle @e@, @'arcT' s e@ is the---   'Trail' of a radius one arc counterclockwise between the two angles.-arcT :: Angle -> Angle -> Trail R2-arcT start end-    | end' < start' = arcT start (end ^+^ (fromIntegral d @@ turn))-    | otherwise     = (if sweep >= fullTurn then glueTrail else id)-                    $ trailFromSegments bs-  where sweep = end ^-^ start-        bs    = map (rotate start) . bezierFromSweep $ sweep--        -- We want to compare the start and the end and in case-        -- there isn't some law about 'Angle' ordering, we use a-        -- known 'Angle' for that.-        start' = start^.turn-        end'   = end^.turn-        d      = ceiling (start' - end') :: Integer---- | Given a start angle @s@ and an end angle @e@, @'arc' s e@ is the---   path of a radius one arc counterclockwise between the two angles.---   The origin of the arc is its center.-arc :: (TrailLike t, V t ~ R2) => Angle -> Angle -> t-arc start end = trailLike $ arcT start end `at` (rotate start $ p2 (1,0))+-- | Given a start direction @d@ and a sweep angle @s@, @'arcT' d s@+--   is the 'Trail' of a radius one arc starting at @d@ and sweeping out+--   the angle @s@ counterclockwise (for positive s).  The resulting+--   @Trail@ is allowed to wrap around and overlap itself.+arcT :: OrderedField n => Direction V2 n -> Angle n -> Trail V2 n+arcT start sweep = trailFromSegments bs+  where+    bs = map (rotateTo start) . bezierFromSweep $ sweep --- | Like 'arc' but clockwise.-arcCW :: (TrailLike t, V t ~ R2) => Angle -> Angle -> t-arcCW start end = trailLike $-                            -- flipped arguments to get the path we want-                            -- then reverse the trail to get the cw direction.-                            (reverseTrail $ arcT end start)-                            `at`-                            (rotate start $ p2 (1,0))-                   -- We could just have `arcCW = reversePath . flip arc`-                   -- but that wouldn't be `TrailLike`.+-- | Given a start direction @d@ and a sweep angle @s@, @'arc' d s@ is the+--   path of a radius one arc starting at @d@ and sweeping out the angle+--   @s@ counterclockwise (for positive s).  The resulting+--   @Trail@ is allowed to wrap around and overlap itself.+arc :: (InSpace V2 n t, OrderedField n, TrailLike t) => Direction V2 n -> Angle n -> t+arc start sweep = trailLike $ arcT start sweep `at` P (fromDirection start) --- | Given a radus @r@, a start angle @s@ and an end angle @e@,---   @'arc'' r s e@ is the path of a radius @(abs r)@ arc between---   the two angles.  If a negative radius is given, the arc will---   be clockwise, otherwise it will be counterclockwise. The origin---   of the arc is its center.+-- | Given a radus @r@, a start direction @d@ and an angle @s@,+--   @'arc'' r d s@ is the path of a radius @(abs r)@ arc starting at+--   @d@ and sweeping out the angle @s@ counterclockwise (for positive+--   s).  The origin of the arc is its center. -- --   <<diagrams/src_Diagrams_TwoD_Arc_arc'Ex.svg#diagram=arc'Ex&width=300>> -----   > arc'Ex = mconcat [ arc' r (0 @@ turn) (1/4 @@ turn) | r <- [0.5,-1,1.5] ]+--   > arc'Ex = mconcat [ arc' r xDir (1/4 @@ turn) | r <- [0.5,-1,1.5] ] --   >        # centerXY # pad 1.1-arc' :: (TrailLike p, V p ~ R2) => Double -> Angle -> Angle -> p-arc' r start end = trailLike $ scale (abs r) ts `at` (rotate start $ p2 (abs r,0))-  where ts | r < 0     = reverseTrail $ arcT end start-           | otherwise = arcT start end+arc' :: (InSpace V2 n t, OrderedField n, TrailLike t) => n -> Direction V2 n -> Angle n -> t+arc' (abs -> r) start sweep = trailLike $ scale r ts `at` P (r *^ fromDirection start)+  where ts = arcT start sweep +arcCCWT :: RealFloat n => Direction V2 n -> Direction V2 n -> Trail V2 n+arcCCWT start end = trailFromSegments bs+  where+    bs    = map (rotateTo start) . bezierFromSweep $ sweep+    sweep = normalizeAngle $ end ^. _theta ^-^ start ^. _theta++-- | Given a start direction @s@ and end direction @e@, @arcCCW s e@ is the+--   path of a radius one arc counterclockwise between the two directions.+--   The origin of the arc is its center.+arcCCW :: (InSpace V2 n t, RealFloat n, TrailLike t) => Direction V2 n -> Direction V2 n -> t+arcCCW start end = trailLike $ arcCCWT start end `at` P (fromDirection start)++-- | Like 'arcAngleCCW' but clockwise.+arcCW :: (InSpace V2 n t, RealFloat n, TrailLike t) => Direction V2 n -> Direction V2 n -> t+arcCW start end = trailLike $+  -- flipped arguments to get the path we want+  -- then reverse the trail to get the cw direction.+  reverseTrail (arcCCWT end start) `at` P (fromDirection start)+ -- | Create a circular wedge of the given radius, beginning at the---   first angle and extending counterclockwise to the second.+--   given direction and extending through the given angle. -- --   <<diagrams/src_Diagrams_TwoD_Arc_wedgeEx.svg#diagram=wedgeEx&width=400>> -- --   > wedgeEx = hcat' (with & sep .~ 0.5)---   >   [ wedge 1 (0 @@ turn) (1/4 @@ turn)---   >   , wedge 1 (7/30 @@ turn) (11/30 @@ turn)---   >   , wedge 1 (1/8 @@ turn) (7/8 @@ turn)+--   >   [ wedge 1 xDir (1/4 @@ turn)+--   >   , wedge 1 (rotate (7/30 @@ turn) xDir) (4/30 @@ turn)+--   >   , wedge 1 (rotate (1/8 @@ turn) xDir) (3/4 @@ turn) --   >   ] --   >   # fc blue --   >   # centerXY # pad 1.1-wedge :: (TrailLike p, V p ~ R2) => Double -> Angle -> Angle -> p-wedge r a1 a2 = trailLike . (`at` origin) . glueTrail . wrapLine-              $ fromOffsets [r *^ e a1]-                <> arc a1 a2 # scale r-                <> fromOffsets [r *^ negateV (e a2)]+wedge :: (InSpace V2 n t, OrderedField n, TrailLike t) => n -> Direction V2 n -> Angle n -> t+wedge r d s = trailLike . (`at` origin) . glueTrail . wrapLine+              $ fromOffsets [r *^ fromDirection d]+                <> arc d s # scale r+                <> fromOffsets [r *^ negated (rotate s $ fromDirection d)]  -- | @arcBetween p q height@ creates an arc beginning at @p@ and --   ending at @q@, with its midpoint at a distance of @abs height@@@ -167,45 +176,47 @@ --   > arcBetweenEx = mconcat --   >   [ arcBetween origin (p2 (2,1)) ht | ht <- [-0.2, -0.1 .. 0.2] ] --   >   # centerXY # pad 1.1-arcBetween :: (TrailLike t, V t ~ R2) => P2 -> P2 -> Double -> t-arcBetween p q ht = trailLike (a # rotate (direction v) # moveTo p)+arcBetween :: (TrailLike t, V t ~ V2, N t ~ n, RealFloat n) => Point V2 n -> Point V2 n -> n -> t+arcBetween p q ht = trailLike (a # rotate (v^._theta) # moveTo p)   where     h = abs ht     isStraight = h < 0.00001     v = q .-. p-    d = magnitude (q .-. p)-    th  = acos ((d*d - 4*h*h)/(d*d + 4*h*h))-    r = d/(2*sin th)-    mid | ht >= 0    = fullTurn ^/ 4-        | otherwise = 3 *^ fullTurn ^/ 4-    st  = mid ^-^ (th @@ rad)-    end = mid ^+^ (th @@ rad)+    d = norm (q .-. p)+    th  = acosA ((d*d - 4*h*h)/(d*d + 4*h*h))+    r = d/(2*sinA th)+    mid | ht >= 0    = direction unitY+        | otherwise  = direction unit_Y+    st  = mid & _theta <>~ negated th     a | isStraight       = fromOffsets [d *^ unitX]       | otherwise-      = arc st end+      = arc st (2 *^ th)         # scale r-        # translateY ((if ht > 0 then negate else id) (r-h))+        # translateY ((if ht > 0 then negate else id) (r - h))         # translateX (d/2)         # (if ht > 0 then reverseLocTrail else id)  -- | Create an annular wedge of the given radii, beginning at the---   first angle and extending counterclockwise to the second.+--   first direction and extending through the given sweep angle. --   The radius of the outer circle is given first. -- --   <<diagrams/src_Diagrams_TwoD_Arc_annularWedgeEx.svg#diagram=annularWedgeEx&width=400>> -----   > annularWedgeEx = hcat' (with & sep .~ 0.50)---   >   [ annularWedge 1 0.5 (0 @@ turn) (1/4 @@ turn)---   >   , annularWedge 1 0.3 (7/30 @@ turn) (11/30 @@ turn)---   >   , annularWedge 1 0.7 (1/8 @@ turn) (7/8 @@ turn)+--   > annularWedgeEx = hsep 0.50+--   >   [ annularWedge 1 0.5 xDir (1/4 @@ turn)+--   >   , annularWedge 1 0.3 (rotate (7/30 @@ turn) xDir) (4/30 @@ turn)+--   >   , annularWedge 1 0.7 (rotate (1/8 @@ turn) xDir) (3/4 @@ turn) --   >   ] --   >   # fc blue --   >   # centerXY # pad 1.1-annularWedge :: (TrailLike p, V p ~ R2) => Double -> Double -> Angle -> Angle -> p-annularWedge r1' r2' a1 a2 = trailLike . (`at` o) . glueTrail . wrapLine-              $ fromOffsets [(r1'-r2') *^ e a1]-                <> arc a1 a2 # scale r1'-                <> fromOffsets [(r1'-r2') *^ negateV (e a2)]-                <> arcCW a2 a1 # scale r2'-  where o = origin # translate (r2' *^ e a1)+annularWedge :: (TrailLike t, V t ~ V2, N t ~ n, RealFloat n) =>+                n -> n -> Direction V2 n -> Angle n -> t+annularWedge r1' r2' d1 s = trailLike . (`at` o) . glueTrail . wrapLine+              $ fromOffsets [(r1' - r2') *^ fromDirection d1]+                <> arc d1 s # scale r1'+                <> fromOffsets [(r1' - r2') *^ negated (fromDirection d2)]+                <> arc d2 (negated s) # scale r2'+  where o = origin # translate (r2' *^ fromDirection d1)+        d2 = d1 & _theta <>~ s+
src/Diagrams/TwoD/Arrow.hs view
@@ -1,21 +1,25 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-} {-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE GADTs                      #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE UndecidableInstances       #-}  ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Arrow--- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2013-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com -- -- Drawing arrows in two dimensions.  For a tutorial on drawing arrows -- using this module, see the diagrams website:--- <http://projects.haskell.org/diagrams/doc/arrow.html>.+-- <https://diagrams.github.io/doc/arrow.html>. -- ----------------------------------------------------------------------------- @@ -73,6 +77,9 @@        , arrow        , arrow' +       , arrowFromLocatedTrail+       , arrowFromLocatedTrail'+          -- * Options        , ArrowOpts(..) @@ -98,57 +105,62 @@        , module Diagrams.TwoD.Arrowheads        ) where -import           Control.Applicative      ((<*>))-import           Control.Lens             (Lens', Setter', Traversal',-                                           generateSignatures, lensRules,-                                           makeLensesWith, (%~), (&), (.~),-                                           (^.))-import           Data.AffineSpace-import           Data.Default.Class-import           Data.Functor             ((<$>))-import           Data.Maybe               (fromMaybe)-import           Data.Monoid.Coproduct    (untangle)+import           Control.Lens              (Lens', Traversal',+                                            generateSignatures, lensRules,+                                            makeLensesWith, view, (%~), (&),+                                            (.~), (^.))+import           Data.Default+import           Data.Maybe                (fromMaybe)+import           Data.Monoid.Coproduct     (untangle) import           Data.Semigroup-import           Data.VectorSpace+import           Data.Typeable -import           Data.Colour              hiding (atop)+import           Data.Colour               hiding (atop) import           Diagrams.Core-import           Diagrams.Core.Types      (QDiaLeaf (..), mkQD')+import           Diagrams.Core.Style       (unmeasureAttrs)+import           Diagrams.Core.Types       (QDiaLeaf (..), mkQD')  import           Diagrams.Angle import           Diagrams.Attributes+import           Diagrams.Direction        hiding (dir)+import           Diagrams.Located          (Located (..), unLoc) import           Diagrams.Parametric import           Diagrams.Path-import           Diagrams.Solve           (quadForm)-import           Diagrams.Tangent         (tangentAtEnd, tangentAtStart)+import           Diagrams.Solve.Polynomial (quadForm)+import           Diagrams.Tangent          (tangentAtEnd, tangentAtStart) import           Diagrams.Trail import           Diagrams.TwoD.Arrowheads import           Diagrams.TwoD.Attributes-import           Diagrams.TwoD.Path       (stroke, strokeT)-import           Diagrams.TwoD.Transform  (rotate, translateX)+import           Diagrams.TwoD.Path        (stroke, strokeT)+import           Diagrams.TwoD.Transform   (reflectY, translateX) import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector     (direction, unitX, unit_X)-import           Diagrams.Util            (( # ))+import           Diagrams.TwoD.Vector      (unitX, unit_X)+import           Diagrams.Util             (( # )) -data ArrowOpts+import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+++data ArrowOpts n   = ArrowOpts-    { _arrowHead  :: ArrowHT-    , _arrowTail  :: ArrowHT-    , _arrowShaft :: Trail R2-    , _headGap    :: Measure R2-    , _tailGap    :: Measure R2-    , _headStyle  :: Style R2-    , _headLength :: Measure R2-    , _tailStyle  :: Style R2-    , _tailLength :: Measure R2-    , _shaftStyle :: Style R2+    { _arrowHead  :: ArrowHT n+    , _arrowTail  :: ArrowHT n+    , _arrowShaft :: Trail V2 n+    , _headGap    :: Measure n+    , _tailGap    :: Measure n+    , _headStyle  :: Style V2 n+    , _headLength :: Measure n+    , _tailStyle  :: Style V2 n+    , _tailLength :: Measure n+    , _shaftStyle :: Style V2 n     }  -- | Straight line arrow shaft.-straightShaft :: Trail R2+straightShaft :: OrderedField n => Trail V2 n straightShaft = trailFromOffsets [unitX] -instance Default ArrowOpts where+instance TypeableFloat n => Default (ArrowOpts n) where   def = ArrowOpts         { _arrowHead    = dart         , _arrowTail    = noTail@@ -158,61 +170,63 @@          -- See note [Default arrow style attributes]         , _headStyle    = mempty-        , _headLength     = normal+        , _headLength   = normal         , _tailStyle    = mempty-        , _tailLength     = normal+        , _tailLength   = normal         , _shaftStyle   = mempty         }  makeLensesWith (lensRules & generateSignatures .~ False) ''ArrowOpts  -- | A shape to place at the head of the arrow.-arrowHead :: Lens' ArrowOpts ArrowHT+arrowHead :: Lens' (ArrowOpts n) (ArrowHT n)  -- | A shape to place at the tail of the arrow.-arrowTail :: Lens' ArrowOpts ArrowHT+arrowTail :: Lens' (ArrowOpts n) (ArrowHT n)  -- | The trail to use for the arrow shaft.-arrowShaft :: Lens' ArrowOpts (Trail R2)+arrowShaft :: Lens' (ArrowOpts n) (Trail V2 n)  -- | Distance to leave between the head and the target point.-headGap :: Lens' ArrowOpts (Measure R2)+headGap :: Lens' (ArrowOpts n) (Measure n)  -- | Distance to leave between the starting point and the tail.-tailGap :: Lens' ArrowOpts (Measure R2)+tailGap :: Lens' (ArrowOpts n) (Measure n)  -- | Set both the @headGap@ and @tailGap@ simultaneously.-gaps :: Traversal' ArrowOpts (Measure R2) +gaps :: Traversal' (ArrowOpts n) (Measure n) gaps f opts = (\h t -> opts & headGap .~ h & tailGap .~ t)         <$> f (opts ^. headGap)         <*> f (opts ^. tailGap)  -- | Same as gaps, provided for backward compatiiblity.-gap :: Traversal' ArrowOpts (Measure R2)+gap :: Traversal' (ArrowOpts n) (Measure n) gap = gaps  -- | Style to apply to the head. @headStyle@ is modified by using the lens --   combinator @%~@ to change the current style. For example, to change --   an opaque black arrowhead to translucent orange: --   @(with & headStyle %~ fc orange .  opacity 0.75)@.-headStyle :: Lens' ArrowOpts (Style R2)+headStyle :: Lens' (ArrowOpts n) (Style V2 n)  -- | Style to apply to the tail. See `headStyle`.-tailStyle :: Lens' ArrowOpts (Style R2)+tailStyle :: Lens' (ArrowOpts n) (Style V2 n)  -- | Style to apply to the shaft. See `headStyle`.-shaftStyle :: Lens' ArrowOpts (Style R2)+shaftStyle :: Lens' (ArrowOpts n) (Style V2 n)  -- | The length from the start of the joint to the tip of the head.-headLength :: Lens' ArrowOpts (Measure R2)+headLength :: Lens' (ArrowOpts n) (Measure n) --- | The length of the tail plus its joint. -tailLength :: Lens' ArrowOpts (Measure R2)+-- | The length of the tail plus its joint.+tailLength :: Lens' (ArrowOpts n) (Measure n)  -- | Set both the @headLength@ and @tailLength@ simultaneously.-lengths :: Traversal' ArrowOpts (Measure R2)-lengths f opts = (\h t -> opts & headLength .~ h & tailLength .~ t) <$> f (opts ^. headLength)-             <*> f (opts ^. tailLength)+lengths :: Traversal' (ArrowOpts n) (Measure n)+lengths f opts =+  (\h t -> opts & headLength .~ h & tailLength .~ t)+    <$> f (opts ^. headLength)+    <*> f (opts ^. tailLength)  -- | A lens for setting or modifying the texture of an arrowhead. For --   example, one may write @... (with & headTexture .~ grad)@ to get an@@ -220,108 +234,107 @@ --   defined. Or @... (with & headTexture .~ solid blue@ to set the head --   color to blue. For more general control over the style of arrowheads, --   see 'headStyle'.-headTexture :: Setter' ArrowOpts Texture-headTexture = headStyle . styleFillTexture+headTexture :: TypeableFloat n => Lens' (ArrowOpts n) (Texture n)+headTexture = headStyle . _fillTexture  -- | A lens for setting or modifying the texture of an arrow---   tail.-tailTexture :: Setter' ArrowOpts Texture-tailTexture = tailStyle . styleFillTexture+--   tail. This is *not* a valid lens (see 'committed').+tailTexture :: TypeableFloat n => Lens' (ArrowOpts n) (Texture n)+tailTexture = tailStyle . _fillTexture  -- | A lens for setting or modifying the texture of an arrow --   shaft.-shaftTexture :: Setter' ArrowOpts Texture-shaftTexture = shaftStyle . styleLineTexture+shaftTexture :: TypeableFloat n => Lens' (ArrowOpts n) (Texture n)+shaftTexture = shaftStyle . _lineTexture  -- Set the default shaft style of an `ArrowOpts` record by applying the -- default style after all other styles have been applied. -- The semigroup stucture of the lw attribute will insure that the default -- is only used if it has not been set in @opts@.-shaftSty :: ArrowOpts -> Style R2+shaftSty :: ArrowOpts n -> Style V2 n shaftSty opts = opts^.shaftStyle  -- Set the default head style. See `shaftSty`.-headSty :: ArrowOpts -> Style R2+headSty :: TypeableFloat n => ArrowOpts n -> Style V2 n headSty opts = fc black (opts^.headStyle)  -- Set the default tail style. See `shaftSty`.-tailSty :: ArrowOpts -> Style R2+tailSty :: TypeableFloat n => ArrowOpts n -> Style V2 n tailSty opts = fc black (opts^.tailStyle) -fromMeasure :: Double -> Double -> Measure R2 -> Double-fromMeasure g n m = u-  where Output u = toOutput g n m- -- | Calculate the length of the portion of the horizontal line that passes --   through the origin and is inside of p.-xWidth :: (Traced t, V t ~ R2) => t -> Double+xWidth :: Floating n => (Traced t, V t ~ V2, N t ~ n) => t -> n xWidth p = a + b   where-    a = fromMaybe 0 (magnitude <$> traceV origin unitX p)-    b = fromMaybe 0 (magnitude <$> traceV origin unit_X p)+    a = fromMaybe 0 (norm <$> traceV origin unitX p)+    b = fromMaybe 0 (norm <$> traceV origin unit_X p)  -- | Get the line color from the shaft to use as the fill color for the joint. --   And set the opacity of the shaft to the current opacity.-colorJoint :: Style R2 -> Style R2+colorJoint :: TypeableFloat n => Style V2 n -> Style V2 n colorJoint sStyle =-    let c = fmap getLineTexture . getAttr $ sStyle-        o = fmap getOpacity . getAttr $ sStyle-    in-    case (c, o) of-        (Nothing, Nothing) -> fillColor (black :: Colour Double) $ mempty-        (Just t, Nothing) -> fillTexture t $ mempty-        (Nothing, Just o') -> opacity o' . fillColor (black :: Colour Double)  $ mempty-        (Just t, Just o') -> opacity o' . fillTexture t $ mempty+  let c = fmap getLineTexture . getAttr $ sStyle+      o = fmap getOpacity . getAttr $ sStyle+  in+  case (c, o) of+      (Nothing, Nothing) -> fillColor black mempty+      (Just t, Nothing)  -> fillTexture t mempty+      (Nothing, Just o') -> opacity o' . fillColor black $ mempty+      (Just t, Just o')  -> opacity o' . fillTexture t $ mempty  -- | Get line width from a style.-widthOfJoint :: Style v -> Double -> Double  -> Double+widthOfJoint :: forall n. TypeableFloat n => Style V2 n -> n -> n -> n widthOfJoint sStyle gToO nToO =-  maybe (fromMeasure gToO nToO (Output 1)) -- Should be same as default line width-        (fromMeasure gToO nToO)-        (fmap getLineWidth . getAttr $ sStyle)+  fromMaybe+    (fromMeasured gToO nToO medium) -- should be same as default line width+    (fmap getLineWidth . getAttr . unmeasureAttrs gToO nToO $ sStyle)  -- | Combine the head and its joint into a single scale invariant diagram --   and move the origin to the attachment point. Return the diagram --   and its width.-mkHead :: Renderable (Path R2) b =>-          Double -> ArrowOpts -> Double -> Double -> (Diagram b R2, Double)-mkHead size opts gToO nToO = ((j <> h) # moveOriginBy (jWidth *^ unit_X) # lwO 0-              , hWidth + jWidth)-  where-    (h', j') = (opts^.arrowHead) size-               (widthOfJoint (shaftSty opts) gToO nToO)-    hWidth = xWidth h'-    jWidth = xWidth j'-    h = stroke h' # applyStyle (headSty opts)-    j = stroke j' # applyStyle (colorJoint (opts^.shaftStyle))+mkHead :: (TypeableFloat n, Renderable (Path V2 n) b) =>+          n -> ArrowOpts n -> n -> n -> Bool -> (QDiagram b V2 n Any, n)+mkHead = mkHT unit_X arrowHead headSty --- | Just like mkHead only the attachment point is on the right.-mkTail :: Renderable (Path R2) b =>-          Double -> ArrowOpts -> Double -> Double -> (Diagram b R2, Double)-mkTail size opts gToO nToO = ((t <> j) # moveOriginBy (jWidth *^ unitX) # lwO 0-              , tWidth + jWidth)+mkTail :: (TypeableFloat n, Renderable (Path V2 n) b) =>+          n -> ArrowOpts n -> n -> n -> Bool -> (QDiagram b V2 n Any, n)+mkTail = mkHT unitX arrowTail tailSty++mkHT+  :: (TypeableFloat n, Renderable (Path V2 n) b)+  => V2 n -> Lens' (ArrowOpts n) (ArrowHT n) -> (ArrowOpts n -> Style V2 n)+  -> n -> ArrowOpts n -> n -> n -> Bool -> (QDiagram b V2 n Any, n)+mkHT xDir htProj styProj sz opts gToO nToO reflect+    = ( (j <> ht)+        # (if reflect then reflectY else id)+        # moveOriginBy (jWidth *^ xDir) # lwO 0+      , htWidth + jWidth+      )   where-    (t', j') = (opts^.arrowTail) size-               (widthOfJoint (shaftSty opts) gToO nToO)-    tWidth = xWidth t'-    jWidth = xWidth j'-    t = stroke t' # applyStyle (tailSty opts)-    j = stroke j' # applyStyle (colorJoint (opts^.shaftStyle))+    (ht', j') = (opts^.htProj) sz+                (widthOfJoint (shaftSty opts) gToO nToO)+    htWidth = xWidth ht'+    jWidth  = xWidth j'+    ht = stroke ht' # applyStyle (styProj opts)+    j  = stroke j'  # applyStyle (colorJoint (opts^.shaftStyle)) --- | Make a trail with the same angles and offset as an arrow with tail width---   tw, head width hw and shaft of tr, such that the magnituted of the shaft---   offset is size. Used for calculating the offset of an arrow.-spine :: Trail R2 -> Double -> Double -> Double -> Trail R2-spine tr tw hw size = tS <> tr # scale size <> hS+-- | @spine tr tw hw sz@ makes a trail with the same angles and offset+--   as an arrow with tail width @t@w, head width @hw@ and shaft @tr@,+--   such that the magnitude of the shaft offset is @sz@. Used for+--   calculating the offset of an arrow.+spine :: TypeableFloat n => Trail V2 n -> n -> n -> n -> Trail V2 n+spine tr tw hw sz = tS <> tr # scale sz <> hS   where-    tSpine = trailFromOffsets [(normalized . tangentAtStart) $ tr] # scale tw-    hSpine = trailFromOffsets [(normalized . tangentAtEnd) $ tr] # scale hw+    tSpine = trailFromOffsets [signorm . tangentAtStart $ tr] # scale tw+    hSpine = trailFromOffsets [signorm . tangentAtEnd $ tr] # scale hw     hS = if hw > 0 then hSpine else mempty     tS = if tw > 0 then tSpine else mempty ---  | Calculate the amount required to scale a shaft trail so that an arrow with---    head width hw and tail width tw has offset t.-scaleFactor :: Trail R2 -> Double -> Double -> Double -> Double+-- | @scaleFactor tr tw hw t@ calculates the amount required to scale+--   a shaft trail @tr@ so that an arrow with head width @hw@ and tail+--   width @tw@ has offset @t@.+scaleFactor :: TypeableFloat n => Trail V2 n -> n -> n -> n -> n scaleFactor tr tw hw t    -- Let tv be a vector representing the tail width, i.e. a vector@@ -336,9 +349,9 @@   -- dot product, resulting in a quadratic in k.    = case quadForm-             (magnitudeSq v)-             (2* (v <.> (tv ^+^ hv)))-             (magnitudeSq (tv ^+^ hv) - t*t)+             (quadrance v)+             (2* (v `dot` (tv ^+^ hv)))+             (quadrance (tv ^+^ hv) - t*t)     of       []  -> 1   -- no scale works, just return 1       [s] -> s   -- single solution@@ -346,34 +359,35 @@         -- we will usually get both a positive and a negative solution;         -- return the maximum (i.e. positive) solution   where-    tv = tw *^ (tangentAtStart tr # normalized)-    hv = hw *^ (tangentAtEnd   tr # normalized)+    tv = tw *^ (tangentAtStart tr # signorm)+    hv = hw *^ (tangentAtEnd   tr # signorm)     v  = trailOffset tr  -- Calculate the approximate envelope of a horizontal arrow -- as if the arrow were made only of a shaft.-arrowEnv :: ArrowOpts -> Double -> Envelope R2+arrowEnv :: TypeableFloat n => ArrowOpts n -> n -> Envelope V2 n arrowEnv opts len = getEnvelope horizShaft   where-    horizShaft = shaft # rotate (negateV direction v) # scale (len / m)-    m = magnitude v+    horizShaft = shaft # rotate (negated (v ^. _theta)) # scale (len / m)+    m = norm v     v = trailOffset shaft     shaft = opts ^. arrowShaft  -- | @arrow len@ creates an arrow of length @len@ with default --   parameters, starting at the origin and ending at the point --   @(len,0)@.-arrow :: Renderable (Path R2) b => Double -> Diagram b R2-arrow len = arrow' def len+arrow :: (TypeableFloat n, Renderable (Path V2 n) b) => n -> QDiagram b V2 n Any+arrow = arrow' def  -- | @arrow' opts len@ creates an arrow of length @len@ using the --   given options, starting at the origin and ending at the point --   @(len,0)@.  In particular, it scales the given 'arrowShaft' so --   that the entire arrow has length @len@.-arrow' :: Renderable (Path R2) b => ArrowOpts -> Double -> Diagram b R2+arrow' :: (TypeableFloat n, Renderable (Path V2 n) b) => ArrowOpts n -> n -> QDiagram b V2 n Any arrow' opts len = mkQD' (DelayedLeaf delayedArrow) -      -- Currently arrows have an empty envelope and trace.+      -- Currently we approximate the envelope of an arrow by using the+      -- envelope of its shaft (see 'arrowEnv'). The trace of an arrow is empty.       (arrowEnv opts len) mempty mempty mempty    where@@ -388,13 +402,13 @@     -- uniformly as the transformation applied to the entire arrow.     -- See https://github.com/diagrams/diagrams-lib/issues/112.     delayedArrow da g n =-      let (trans, globalSty) = option mempty untangle . fst $ da+      let (trans, globalSty) = maybe mempty untangle . fst $ da       in  dArrow globalSty trans len g n      -- Build an arrow and set its endpoints to the image under tr of origin and (len,0).     dArrow sty tr ln gToO nToO = (h' <> t' <> shaft)                # moveOriginBy (tWidth *^ (unit_X # rotate tAngle))-               # rotate (direction (q .-. p) ^-^ dir)+               # rotate (((q .-. p)^._theta) ^-^ (dir^._theta))                # moveTo p       where @@ -403,29 +417,31 @@          -- Use the existing line color for head, tail, and shaft by         -- default (can be overridden by explicitly setting headStyle,-        -- tailStyle, or shaftStyle).+        -- tailStyle, or shaftStyle).  Also use existing global line width+        -- for shaft if not explicitly set in shaftStyle.         globalLC = getLineTexture <$> getAttr sty         opts' = opts           & headStyle  %~ maybe id fillTexture globalLC           & tailStyle  %~ maybe id fillTexture globalLC-          & shaftStyle %~ maybe id lineTexture globalLC+          & shaftStyle %~ applyStyle sty . transform tr          -- The head size, tail size, head gap, and tail gap are obtained         -- from the style and converted to output units.-        hSize = fromMeasure gToO nToO . transform tr $ opts ^. headLength-        tSize = fromMeasure gToO nToO . transform tr $ opts ^. tailLength-        hGap = fromMeasure gToO nToO . transform tr $ opts ^. headGap-        tGap = fromMeasure gToO nToO . transform tr $ opts ^. tailGap+        scaleFromMeasure = fromMeasured gToO nToO . scaleLocal (avgScale tr)+        hSize = scaleFromMeasure $ opts ^. headLength+        tSize = scaleFromMeasure $ opts ^. tailLength+        hGap  = scaleFromMeasure $ opts ^. headGap+        tGap  = scaleFromMeasure $ opts ^. tailGap          -- Make the head and tail and save their widths.-        (h, hWidth') = mkHead hSize opts' gToO nToO-        (t, tWidth') = mkTail tSize opts' gToO nToO+        (h, hWidth') = mkHead hSize opts' gToO nToO (isReflection tr)+        (t, tWidth') = mkTail tSize opts' gToO nToO (isReflection tr)          rawShaftTrail = opts^.arrowShaft         shaftTrail           = rawShaftTrail             -- rotate it so it is pointing in the positive X direction-          # rotate (negateV direction (trailOffset rawShaftTrail))+          # rotate (negated . view _theta . trailOffset $ rawShaftTrail)             -- apply the context transformation -- in case it includes             -- things like flips and shears (the possibility of shears             -- is why we must rotate it to a neutral position first)@@ -436,15 +452,15 @@         hWidth = hWidth' + hGap          -- Calculate the angles that the head and tail should point.-        tAngle = direction . tangentAtStart $ shaftTrail-        hAngle = direction . tangentAtEnd $ shaftTrail+        tAngle = tangentAtStart shaftTrail ^. _theta+        hAngle = tangentAtEnd shaftTrail ^. _theta          -- Calculte the scaling factor to apply to the shaft shaftTrail so that the entire         -- arrow will be of length len. Then apply it to the shaft and make the         -- shaft into a Diagram with using its style.-        sf = scaleFactor shaftTrail tWidth hWidth (magnitude (q .-. p))+        sf = scaleFactor shaftTrail tWidth hWidth (norm (q .-. p))         shaftTrail' = shaftTrail # scale sf-        shaft = strokeT shaftTrail' # applyStyle (shaftSty opts)+        shaft = strokeT shaftTrail' # applyStyle (shaftSty opts')          -- Adjust the head and tail to point in the directions of the shaft ends.         h' = h # rotate hAngle@@ -457,7 +473,7 @@  -- | @arrowBetween s e@ creates an arrow pointing from @s@ to @e@ --   with default parameters.-arrowBetween :: Renderable (Path R2) b => P2 -> P2 -> Diagram b R2+arrowBetween :: (TypeableFloat n, Renderable (Path V2 n) b) => Point V2 n -> Point V2 n -> QDiagram b V2 n Any arrowBetween = arrowBetween' def  -- | @arrowBetween' opts s e@ creates an arrow pointing from @s@ to@@ -465,47 +481,64 @@ --   rotates @arrowShaft@ to go between @s@ and @e@, taking head, --   tail, and gaps into account. arrowBetween'-  :: Renderable (Path R2) b =>-     ArrowOpts -> P2 -> P2 -> Diagram b R2+  :: (TypeableFloat n, Renderable (Path V2 n) b) =>+     ArrowOpts n -> Point V2 n -> Point V2 n -> QDiagram b V2 n Any arrowBetween' opts s e = arrowAt' opts s (e .-. s)  -- | Create an arrow starting at s with length and direction determined by --   the vector v.-arrowAt :: Renderable (Path R2) b => P2 -> R2 -> Diagram b R2-arrowAt s v = arrowAt' def s v+arrowAt :: (TypeableFloat n, Renderable (Path V2 n) b) => Point V2 n -> V2 n -> QDiagram b V2 n Any+arrowAt = arrowAt' def  arrowAt'-  :: Renderable (Path R2) b =>-     ArrowOpts -> P2 -> R2 -> Diagram b R2+  :: (TypeableFloat n, Renderable (Path V2 n) b) =>+     ArrowOpts n -> Point V2 n -> V2 n -> QDiagram b V2 n Any arrowAt' opts s v = arrow' opts len                   # rotate dir # moveTo s   where-    len = magnitude v-    dir = direction v+    len = norm v+    dir = v ^. _theta --- | @arrowV v@ creates an arrow with the direction and magnitude of+-- | @arrowV v@ creates an arrow with the direction and norm of --   the vector @v@ (with its tail at the origin), using default --   parameters.-arrowV :: Renderable (Path R2) b => R2 -> Diagram b R2+arrowV :: (TypeableFloat n, Renderable (Path V2 n) b) => V2 n -> QDiagram b V2 n Any arrowV = arrowV' def --- | @arrowV' v@ creates an arrow with the direction and magnitude of+-- | @arrowV' v@ creates an arrow with the direction and norm of --   the vector @v@ (with its tail at the origin). arrowV'-  :: Renderable (Path R2) b-  => ArrowOpts -> R2 -> Diagram b R2+  :: (TypeableFloat n, Renderable (Path V2 n) b)+  => ArrowOpts n -> V2 n -> QDiagram b V2 n Any arrowV' opts = arrowAt' opts origin +-- | Turn a located trail into a default arrow by putting an+--   arrowhead at the end of the trail.+arrowFromLocatedTrail+  :: (Renderable (Path V2 n) b, RealFloat n, Typeable n)+  => Located (Trail V2 n) -> QDiagram b V2 n Any+arrowFromLocatedTrail = arrowFromLocatedTrail' def++-- | Turn a located trail into an arrow using the given options.+arrowFromLocatedTrail'+  :: (Renderable (Path V2 n) b, RealFloat n, Typeable n)+  => ArrowOpts n -> Located (Trail V2 n) -> QDiagram b V2 n Any+arrowFromLocatedTrail' opts trail = arrowBetween' opts' start end+  where+    opts' = opts & arrowShaft .~ unLoc trail+    start = atStart trail+    end   = atEnd trail+ -- | Connect two diagrams with a straight arrow. connect-  :: (Renderable (Path R2) b, IsName n1, IsName n2)-  => n1 -> n2 -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+  => n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any connect = connect' def  -- | Connect two diagrams with an arbitrary arrow. connect'-  :: (Renderable (Path R2) b, IsName n1, IsName n2)-  => ArrowOpts -> n1 -> n2 -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+  => ArrowOpts n -> n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any connect' opts n1 n2 =   withName n1 $ \sub1 ->   withName n2 $ \sub2 ->@@ -515,15 +548,15 @@ -- | Connect two diagrams at point on the perimeter of the diagrams, choosen --   by angle. connectPerim-  :: (Renderable (Path R2) b, IsName n1, IsName n2)- => n1 -> n2 -> Angle -> Angle-  -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+ => n1 -> n2 -> Angle n -> Angle n+  -> QDiagram b V2 n Any -> QDiagram b V2 n Any connectPerim = connectPerim' def  connectPerim'-  :: (Renderable (Path R2) b, IsName n1, IsName n2)-  => ArrowOpts -> n1 -> n2 -> Angle -> Angle-  -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+  => ArrowOpts n -> n1 -> n2 -> Angle n -> Angle n+  -> QDiagram b V2 n Any -> QDiagram b V2 n Any connectPerim' opts n1 n2 a1 a2 =   withName n1 $ \sub1 ->   withName n2 $ \sub2 ->@@ -537,19 +570,19 @@ --   drawn so that it stops at the boundaries of the diagrams, using traces --   to find the intersection points. connectOutside-  :: (Renderable (Path R2) b, IsName n1, IsName n2)-  => n1 -> n2 -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+  => n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any connectOutside = connectOutside' def  connectOutside'-  :: (Renderable (Path R2) b, IsName n1, IsName n2)-  => ArrowOpts -> n1 -> n2 -> (Diagram b R2 -> Diagram b R2)+  :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)+  => ArrowOpts n -> n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any connectOutside' opts n1 n2 =   withName n1 $ \b1 ->   withName n2 $ \b2 ->     let v = location b2 .-. location b1-        midpoint = location b1 .+^ (v/2)-        s' = fromMaybe (location b1) $ traceP midpoint (-v) b1+        midpoint = location b1 .+^ (v ^/ 2)+        s' = fromMaybe (location b1) $ traceP midpoint (negated v) b1         e' = fromMaybe (location b2) $ traceP midpoint v b2     in       atop (arrowBetween' opts s' e')
src/Diagrams/TwoD/Arrowheads.hs view
@@ -1,6 +1,9 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables       #-} {-# LANGUAGE TypeFamilies              #-}+{-# OPTIONS_GHC -fno-warn-unused-imports       #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Arrowheads@@ -20,6 +23,7 @@        -- ** Standard arrowheads          tri        , dart+       , halfDart        , spike        , thorn        , lineHead@@ -31,6 +35,7 @@        --   left point of the arrowhead.        , arrowheadTriangle        , arrowheadDart+       , arrowheadHalfDart        , arrowheadSpike        , arrowheadThorn @@ -38,6 +43,7 @@        -- ** Standard arrow tails        , tri'        , dart'+       , halfDart'        , spike'        , thorn'        , lineTail@@ -54,16 +60,13 @@        , ArrowHT        ) where -import           Control.Lens            ((&), (.~), (^.))-import           Data.AffineSpace-import           Data.Default.Class+import           Control.Lens            ((&), (.~), (<>~), (^.))+import           Data.Default import           Data.Monoid             (mempty, (<>))-import           Data.VectorSpace  import           Diagrams.Angle import           Diagrams.Core -import           Diagrams.Coordinates    ((^&)) import           Diagrams.Path import           Diagrams.Segment import           Diagrams.Trail@@ -75,66 +78,91 @@ import           Diagrams.TwoD.Shapes import           Diagrams.TwoD.Transform import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector    (fromDirection, direction, unit_X)+import           Diagrams.TwoD.Vector    (unitX, unit_X, xDir) import           Diagrams.Util           (( # )) +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ ----------------------------------------------------------------------------- -type ArrowHT = Double -> Double -> (Path R2, Path R2)+type ArrowHT n = n -> n -> (Path V2 n, Path V2 n) -closedPath :: (Floating (Scalar v), Ord (Scalar v), InnerSpace v) => Trail v -> Path v+closedPath :: OrderedField n => Trail V2 n -> Path V2 n closedPath = pathFromTrail . closeTrail  -- Heads ---------------------------------------------------------------------   > drawHead h = arrowAt' (with & arrowHead .~ h & shaftStyle %~ lw none)---   >         origin (r2 (0.001, 0))---   >      <> square 0.5 # alignL # lw none+--   > drawHead h = arrowAt' (with & arrowHead .~ h & shaftStyle %~ lw none+--   >                             & headLength .~ local 0.5)+--   >         origin (r2 (1, 0))+--   >      <> square 0.5 # alignL # lw none # frame 0.1  -- | Isoceles triangle style. The above example specifies an angle of `2/5 Turn`.  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_tri25Ex.svg#diagram=tri25Ex&width=120>> ---   > tri25Ex = arrowAt' (with & arrowHead .~ arrowheadTriangle (2/5 @@ turn) & shaftStyle %~ lw none)---   >           origin (r2 (0.001, 0))---   >        <> square 0.6 # alignL # lw none-arrowheadTriangle :: Angle -> ArrowHT+--   > tri25Ex = arrowAt' (with & arrowHead .~ arrowheadTriangle (2/5 @@ turn)+--   >                          & shaftStyle %~ lw none & headLength .~ local 0.5)+--   >           origin (r2 (0.5, 0))+--   >        <> square 0.6 # alignL # lw none # frame 0.1+arrowheadTriangle :: RealFloat n => Angle n -> ArrowHT n arrowheadTriangle theta = aHead   where     aHead len _ = (p, mempty)       where         psi = pi - (theta ^. rad)         r = len / (1 + cos psi)-        p = polygon (def & polyType .~ PolyPolar [theta, (negateV 2 *^ theta)]+        p = polygon (def & polyType .~ PolyPolar [theta, (-2) *^ theta]             (repeat r) & polyOrient .~ NoOrient)  # alignL   -- | Isoceles triangle with linear concave base. Inkscape type 1 - dart like.-arrowheadDart :: Angle -> ArrowHT-arrowheadDart theta len shaftWidth = (hd # scale size, jt)+arrowheadDart :: RealFloat n => Angle n -> ArrowHT n+arrowheadDart theta len shaftWidth = (hd # scale sz, jt)   where     hd = snugL . pathFromTrail . glueTrail $ fromOffsets [t1, t2, b2, b1]     jt = pathFromTrail . glueTrail $ j <> reflectY j-    j = closeTrail $ fromOffsets [(-jLength ^& 0), (0 ^& shaftWidth / 2)]-    v = fromDirection theta-    (t1, t2) = (unit_X ^+^ v, (-0.5 ^& 0) ^-^ v)-    [b1, b2] = map (reflectY . negateV) [t1, t2]-    psi = pi - (direction . negateV $ t2) ^. rad+    j = closeTrail $ fromOffsets [V2 (-jLength) 0, V2 0 (shaftWidth / 2)]+    v = rotate theta unitX+    (t1, t2) = (unit_X ^+^ v, V2 (-0.5) 0 ^-^ v)+    [b1, b2] = map (reflectY . negated) [t1, t2]+    psi = pi - negated t2 ^. _theta . rad     jLength = shaftWidth / (2 * tan psi) -    -- If the shaft if too wide, set the size to a default value of 1.-    size = max 1 ((len - jLength) / (1.5))+    -- If the shaft is too wide, set the size to a default value of 1.+    sz = max 1 ((len - jLength) / 1.5) +-- | Top half of an 'arrowheadDart'.+arrowheadHalfDart :: RealFloat n => Angle n -> ArrowHT n+arrowheadHalfDart theta len shaftWidth = (hd, jt)+  where+    hd = fromOffsets [t1, t2]+       # closeTrail # pathFromTrail+       # translateX 1.5 # scale sz+       # translateY (-shaftWidth/2)+       # snugL+    jt = snugR . translateY (-shaftWidth/2) . pathFromTrail . closeTrail $ fromOffsets [V2 (-jLength) 0, V2 0 shaftWidth]+    v = rotate theta unitX+    (t1, t2) = (unit_X ^+^ v, (0.5 *^ unit_X) ^-^ v)+    psi = pi - negated t2 ^. _theta . rad+    jLength = shaftWidth / tan psi++    -- If the shaft is too wide, set the size to a default value of 1.+    sz = max 1 ((len - jLength) / 1.5)+ -- | Isoceles triangle with curved concave base. Inkscape type 2.-arrowheadSpike :: Angle -> ArrowHT+arrowheadSpike :: RealFloat n => Angle n -> ArrowHT n arrowheadSpike theta len shaftWidth  = (hd # scale r, jt # scale r)   where     hd = snugL . closedPath $ l1 <> c <> l2     jt = alignR . centerY . pathFromTrail-                . closeTrail $ arc' 1 (negateV phi) phi+                . closeTrail $ arc' 1 (xDir & _theta <>~ negated phi) (2 *^ phi)     l1 = trailFromSegments [straight $ unit_X ^+^ v]-    l2 = trailFromSegments [reverseSegment . straight $ (unit_X ^+^ (reflectY v))]-    c = reflectX $ arc' 1 theta (negateV theta)-    v = fromDirection theta+    l2 = trailFromSegments [reverseSegment . straight $ (unit_X ^+^ reflectY v)]+    c = arc' 1 (rotate α xDir) ((-2) *^ α)+    α = (1/2 @@ turn) ^-^ theta+    v = rotate theta unitX      -- The length of the head without its joint is, -2r cos theta and     -- the length of the joint is r - sqrt (r^2 - y^2). So the total@@ -149,157 +177,170 @@     -- 2/3 * len by setting d=1 and phi=pi/2.     d = max 1 (len**2 + (1 - a**2) * y**2)     r = (a * len + sqrt d) / (a**2 -1)-    phi = asin (min 1 (y/r)) @@ rad+    phi = asinA (min 1 (y/r))  -- | Curved sides, linear concave base. Illustrator CS5 #3-arrowheadThorn :: Angle -> ArrowHT-arrowheadThorn theta len shaftWidth = (hd # scale size, jt)+arrowheadThorn :: RealFloat n => Angle n -> ArrowHT n+arrowheadThorn theta len shaftWidth = (hd # scale sz, jt)   where     hd = snugL . pathFromTrail . glueTrail $ hTop <> reflectY hTop     hTop = closeTrail . trailFromSegments $ [c, l]     jt = pathFromTrail . glueTrail $ j <> reflectY j-    j = closeTrail $ fromOffsets [(-jLength ^& 0), (0 ^& shaftWidth / 2)]+    j = closeTrail $ fromOffsets [V2 (-jLength) 0, V2 0 (shaftWidth / 2)]     c = curvedSide theta-    v = fromDirection theta+    v = rotate theta unitX     l = reverseSegment . straight $ t-    t = v ^-^ (-0.5 ^& 0)-    psi = pi - (direction . negateV $ t) ^. rad-    jLength = shaftWidth / (2 * tan psi)+    t = v ^-^ V2 (-0.5) 0+    psi = fullTurn ^/ 2 ^-^ (negated t ^. _theta)+    jLength = shaftWidth / (2 * tanA psi) -    -- If the shaft if too wide, set the size to a default value of 1.    -    size = max 1 ((len - jLength) / (1.5))+    -- If the shaft if too wide, set the size to a default value of 1.+    sz = max 1 ((len - jLength) / 1.5)  -- | Make a side for the thorn head.-curvedSide :: Angle -> Segment Closed R2+curvedSide :: Floating n => Angle n -> Segment Closed V2 n curvedSide theta = bezier3 ctrl1 ctrl2 end   where     v0    = unit_X-    v1    = fromDirection theta+    v1    = rotate theta unitX     ctrl1 = v0     ctrl2 = v0 ^+^ v1     end   = v0 ^+^ v1  -- Standard heads --------------------------------------------------------- -- | A line the same width as the shaft.-lineHead :: ArrowHT+lineHead :: RealFloat n => ArrowHT n lineHead s w = (square 1 # scaleX s # scaleY w # alignL, mempty) -noHead :: ArrowHT+noHead :: ArrowHT n noHead _ _ = (mempty, mempty)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_triEx.svg#diagram=triEx&width=100>>  --   > triEx = drawHead tri-tri :: ArrowHT+tri :: RealFloat n => ArrowHT n tri = arrowheadTriangle (1/3 @@ turn)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_spikeEx.svg#diagram=spikeEx&width=100>>  --   > spikeEx = drawHead spike-spike :: ArrowHT+spike :: RealFloat n => ArrowHT n spike = arrowheadSpike (3/8 @@ turn)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_thornEx.svg#diagram=thornEx&width=100>>  --   > thornEx = drawHead thorn-thorn :: ArrowHT-thorn = arrowheadThorn (3/8 @@ turn) +thorn :: RealFloat n => ArrowHT n+thorn = arrowheadThorn (3/8 @@ turn)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_dartEx.svg#diagram=dartEx&width=100>>  --   > dartEx = drawHead dart-dart :: ArrowHT+dart :: RealFloat n => ArrowHT n dart = arrowheadDart (2/5 @@ turn) +-- | <<diagrams/src_Diagrams_TwoD_Arrowheads_halfDartEx.svg#diagram=halfDartEx&width=100>>++--   > halfDartEx = drawHead halfDart+halfDart :: RealFloat n => ArrowHT n+halfDart = arrowheadHalfDart (2/5 @@ turn)+ -- Tails ---------------------------------------------------------------------   > drawTail t = arrowAt' (with  & arrowTail .~ t & shaftStyle %~ lw none & arrowHead .~ noHead)---   >         origin (r2 (0.001, 0))---   >      <> square 0.5 # alignL # lw none+--   > drawTail t = arrowAt' (with  & arrowTail .~ t & shaftStyle %~ lw none+--   >                              & arrowHead .~ noHead & tailLength .~ local 0.5)+--   >         origin (r2 (1, 0))+--   >      <> square 0.5 # alignL # lw none # frame 0.1  -- | Utility function to convert any arrowhead to an arrowtail, i.e. --   attached at the start of the trail.-headToTail :: ArrowHT -> ArrowHT+headToTail :: OrderedField n => ArrowHT n -> ArrowHT n headToTail hd = tl   where-    tl size shaftWidth = (t, j)+    tl sz shaftWidth = (t, j)       where-        (t', j') = hd size shaftWidth+        (t', j') = hd sz shaftWidth         t = reflectX t'         j = reflectX j' -arrowtailBlock :: Angle -> ArrowHT+arrowtailBlock :: forall n. (RealFloat n) => Angle n -> ArrowHT n arrowtailBlock theta = aTail   where    aTail len _ = (t, mempty)       where-        t = rect len (len * x) # alignR-        a'  = fromDirection theta-        a = a' ^-^ (reflectY a')-        x = magnitude a+        t  = rect len (len * x) # alignR+        a' :: V2 n+        a' = rotate theta unitX+        a  = a' ^-^ reflectY a'+        x  = norm a  -- | The angle is where the top left corner intersects the circle.-arrowtailQuill :: Angle -> ArrowHT+arrowtailQuill :: OrderedField n => Angle n -> ArrowHT n arrowtailQuill theta = aTail   where    aTail len shaftWidth = (t, j)       where-        t = ( closedPath $ trailFromVertices [v0, v1, v2, v3, v4, v5, v0] )-            # scale size # alignR-        size = len / 0.6+        t = closedPath (trailFromVertices [v0, v1, v2, v3, v4, v5, v0])+              # scale sz # alignR+        sz = len / 0.6         v0 = p2 (0.5, 0)-        v2 = p2 (unr2 $ fromDirection theta # scale 0.5)+        v2 = origin .+^ (rotate theta unitX # scale 0.5)         v1 = v2 # translateX (5/8)         v3 = p2 (-0.1, 0)         v4 = v2 # reflectY         v5 = v4 # translateX (5/8)-        s = 1 - shaftWidth / magnitude (v1 .-. v5)+        s = 1 - shaftWidth / norm (v1 .-. v5)         n1 = v0 # translateY (0.5 * shaftWidth)         n2 = v1 .-^ ((v1 .-. v0) # scale s)         n3 = v5 .-^ ((v5 .-. v0) # scale s)         n4 = n1 # reflectY-        j = ( closedPath $ trailFromVertices-                [ v0, n1, n2, v0, n3, n4, v0 ])+        j  = closedPath $ trailFromVertices [v0, n1, n2, v0, n3, n4, v0]  -- Standard tails --------------------------------------------------------- -- | A line the same width as the shaft.-lineTail :: ArrowHT+lineTail :: RealFloat n => ArrowHT n lineTail s w = (square 1 # scaleY w # scaleX s # alignR, mempty) -noTail :: ArrowHT+noTail :: ArrowHT n noTail _ _ = (mempty, mempty)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_tri'Ex.svg#diagram=tri'Ex&width=100>>  --   > tri'Ex = drawTail tri'-tri' :: ArrowHT+tri' :: RealFloat n => ArrowHT n tri' = headToTail tri  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_spike'Ex.svg#diagram=spike'Ex&width=100>>  --   > spike'Ex = drawTail spike'-spike' :: ArrowHT+spike' :: RealFloat n => ArrowHT n spike' = headToTail spike  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_thorn'Ex.svg#diagram=thorn'Ex&width=100>>  --   > thorn'Ex = drawTail thorn'-thorn' :: ArrowHT+thorn' :: RealFloat n => ArrowHT n thorn' = headToTail thorn  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_dart'Ex.svg#diagram=dart'Ex&width=100>>  --   > dart'Ex = drawTail dart'-dart' :: ArrowHT+dart' :: RealFloat n => ArrowHT n dart' = headToTail dart +-- | <<diagrams/src_Diagrams_TwoD_Arrowheads_halfDart'Ex.svg#diagram=halfDart'Ex&width=100>>++--   > halfDart'Ex = drawTail halfDart'+halfDart' :: RealFloat n => ArrowHT n+halfDart' = headToTail halfDart+ -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_quillEx.svg#diagram=quillEx&width=100>>  --   > quillEx = drawTail quill-quill :: ArrowHT+quill :: (Floating n, Ord n) => ArrowHT n quill = arrowtailQuill (2/5 @@ turn)  -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_blockEx.svg#diagram=blockEx&width=100>>  --   > blockEx = drawTail block-block :: ArrowHT+block :: RealFloat n => ArrowHT n block = arrowtailBlock (7/16 @@ turn)
src/Diagrams/TwoD/Attributes.hs view
@@ -1,21 +1,26 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE ExistentialQuantification  #-}+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE StandaloneDeriving         #-} {-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE UndecidableInstances       #-}  ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Attributes--- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2013-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com -- -- Diagrams may have /attributes/ which affect the way they are -- rendered. This module defines /Textures/ (Gradients and Colors) in two--- dimensions. Like the attriubtes defined in the Diagrams.Attributes module,+-- dimensions. Like the attributes defined in the Diagrams.Attributes module, -- all attributes defined here use the 'Last' or 'Recommend' /semigroup/ structure. -- 'FillColor' and 'LineColor' attributes are provided so that backends that -- don't support gradients need not be concerned with using textures. Backends@@ -24,18 +29,8 @@ -----------------------------------------------------------------------------  module Diagrams.TwoD.Attributes (-    -- ** Width-    LineWidth, getLineWidth, lineWidth, lineWidthA-  , lw, lwN, lwO, lwL, lwG-  , ultraThin, veryThin, thin, medium, thick, veryThick, ultraThick, none-  , tiny, verySmall, small, normal, large, veryLarge, huge--    -- ** Dashing-  , Dashing(..), DashingA, getDashing-  , dashing, dashingN, dashingO, dashingL, dashingG-   -- * Textures-  , Texture(..), solid, _SC, _LG, _RG, defaultLG, defaultRG+    Texture(..), solid, _SC, _AC, _LG, _RG, defaultLG, defaultRG   , GradientStop(..), stopColor, stopFraction, mkStops   , SpreadMethod(..), lineLGradient, lineRGradient @@ -49,15 +44,15 @@   , rGradSpreadMethod, mkRadialGradient    -- ** Line texture-  ,  LineTexture(..), getLineTexture, lineTexture, lineTextureA-  ,  mkLineTexture, styleLineTexture+  , LineTexture(..), _LineTexture, getLineTexture, lineTexture, lineTextureA+  , mkLineTexture, _lineTexture    -- ** Line color   , lineColor, lc, lcA    -- ** Fill texture-  , FillTexture(..), getFillTexture, fillTexture-  , mkFillTexture, styleFillTexture+  , FillTexture(..), _FillTexture, getFillTexture, fillTexture+  , mkFillTexture, _fillTexture, _fillTextureR    -- ** Fill color   , fillColor, fc, fcA, recommendFillColor@@ -67,160 +62,41 @@    ) where -import           Diagrams.Core-import           Diagrams.Core.Style         (setAttr)+import           Control.Lens                hiding (transform)+import           Data.Colour                 hiding (AffineSpace, over)+import           Data.Data+import           Data.Default+import           Data.Monoid.Recommend+import           Data.Semigroup+ import           Diagrams.Attributes import           Diagrams.Attributes.Compile-import           Diagrams.TwoD.Types-+import           Diagrams.Core import           Diagrams.Core.Types         (RTree) import           Diagrams.Located            (unLoc) import           Diagrams.Path               (Path, pathTrails) import           Diagrams.Trail              (isLoop)+import           Diagrams.TwoD.Types+import           Diagrams.Util -import           Control.Lens ( makeLensesWith, generateSignatures, lensRules-                              , makePrisms, Lens', (&), (%~), (.~), Setter', sets) -import           Data.Colour hiding (AffineSpace)-import           Data.Data-import           Data.Default.Class-import           Data.Maybe                  (fromMaybe)--import           Data.Monoid.Recommend-import           Data.Semigroup---- | Standard 'Measures'.-none, ultraThin, veryThin, thin, medium, thick, veryThick, ultraThick,-  tiny, verySmall, small, normal, large, veryLarge, huge :: Measure R2-none       = Output 0-ultraThin  = Normalized 0.0005 `atLeast` Output 0.5-veryThin   = Normalized 0.001  `atLeast` Output 0.5-thin       = Normalized 0.002  `atLeast` Output 0.5-medium     = Normalized 0.004  `atLeast` Output 0.5-thick      = Normalized 0.0075 `atLeast` Output 0.5-veryThick  = Normalized 0.01   `atLeast` Output 0.5-ultraThick = Normalized 0.02   `atLeast` Output 0.5--tiny      = Normalized 0.01-verySmall = Normalized 0.015-small     = Normalized 0.023-normal    = Normalized 0.035-large     = Normalized 0.05-veryLarge = Normalized 0.07-huge      = Normalized 0.10- --------------------------------------------------------------------  Line Width  ----------------------------------------------------------------------------------------------------------------------- | Line widths specified on child nodes always override line widths---   specified at parent nodes.-newtype LineWidth = LineWidth (Last (Measure R2))-  deriving (Typeable, Data, Semigroup)-instance AttributeClass LineWidth--type instance V LineWidth = R2--instance Transformable LineWidth where-  transform t (LineWidth (Last w)) =-    LineWidth (Last (transform t w))--instance Default LineWidth where-    def = LineWidth (Last medium)--getLineWidth :: LineWidth -> Measure R2-getLineWidth (LineWidth (Last w)) = w---- | Set the line (stroke) width.-lineWidth :: (HasStyle a, V a ~ R2) => Measure R2 -> a -> a-lineWidth = applyGTAttr . LineWidth . Last---- | Apply a 'LineWidth' attribute.-lineWidthA ::  (HasStyle a, V a ~ R2) => LineWidth -> a -> a-lineWidthA = applyGTAttr---- | Default for 'lineWidth'.-lw :: (HasStyle a, V a ~ R2) => Measure R2 -> a -> a-lw = lineWidth---- | A convenient synonym for 'lineWidth (Global w)'.-lwG :: (HasStyle a, V a ~ R2) => Double -> a -> a-lwG w = lineWidth (Global w)---- | A convenient synonym for 'lineWidth (Normalized w)'.-lwN :: (HasStyle a, V a ~ R2) => Double -> a -> a-lwN w = lineWidth (Normalized w)---- | A convenient synonym for 'lineWidth (Output w)'.-lwO :: (HasStyle a, V a ~ R2) => Double -> a -> a-lwO w = lineWidth (Output w)---- | A convenient sysnonym for 'lineWidth (Local w)'.-lwL :: (HasStyle a, V a ~ R2) => Double -> a -> a-lwL w = lineWidth (Local w)----------------------------------------------------------------------  Dashing  ----------------------------------------------------+--  Gradients  -------------------------------------------------- ----------------------------------------------------------------- --- | Create lines that are dashing... er, dashed.-data Dashing = Dashing [Measure R2] (Measure R2)-  deriving (Typeable, Data, Eq)--newtype DashingA = DashingA (Last Dashing)-  deriving (Typeable, Data, Semigroup, Eq)-instance AttributeClass DashingA--type instance V DashingA = R2--instance Transformable DashingA where-  transform t (DashingA (Last (Dashing w v))) =-    DashingA (Last (Dashing r s))-    where-      r = map (transform t) w-      s = transform t v--getDashing :: DashingA -> Dashing-getDashing (DashingA (Last d)) = d---- | Set the line dashing style.-dashing :: (HasStyle a, V a ~ R2) =>-           [Measure R2]  -- ^ A list specifying alternate lengths of on-                         --   and off portions of the stroke.  The empty-                         --   list indicates no dashing.-        -> Measure R2    -- ^ An offset into the dash pattern at which the-                         --   stroke should start.-        -> a -> a-dashing ds offs = applyGTAttr (DashingA (Last (Dashing ds offs)))---- | A convenient synonym for 'dashing (Global w)'.-dashingG :: (HasStyle a, V a ~ R2) => [Double] -> Double -> a -> a-dashingG w v = dashing (map Global w) (Global v)---- | A convenient synonym for 'dashing (Normalized w)'.-dashingN :: (HasStyle a, V a ~ R2) => [Double] -> Double -> a -> a-dashingN w v = dashing (map Normalized w) (Normalized v)---- | A convenient synonym for 'dashing (Output w)'.-dashingO :: (HasStyle a, V a ~ R2) => [Double] -> Double -> a -> a-dashingO w v = dashing (map Output w) (Output v)---- | A convenient sysnonym for 'dashing (Local w)'.-dashingL :: (HasStyle a, V a ~ R2) => [Double] -> Double -> a -> a-dashingL w v = dashing (map Local w) (Local v)- -- | A gradient stop contains a color and fraction (usually between 0 and 1)-data GradientStop = GradientStop-     { _stopColor    :: SomeColor-     , _stopFraction :: Double}+data GradientStop d = GradientStop+  { _stopColor    :: SomeColor+  , _stopFraction :: d+  }  makeLensesWith (lensRules & generateSignatures .~ False) ''GradientStop  -- | A color for the stop.-stopColor :: Lens' GradientStop SomeColor+stopColor :: Lens' (GradientStop n) SomeColor  -- | The fraction for stop.-stopFraction :: Lens' GradientStop Double+stopFraction :: Lens' (GradientStop n) n  -- | The 'SpreadMethod' determines what happens before 'lGradStart' and after --   'lGradEnd'. 'GradPad' fills the space before the start of the gradient@@ -230,278 +106,309 @@ data SpreadMethod = GradPad | GradReflect | GradRepeat  -- | Linear Gradient-data LGradient = LGradient-    { _lGradStops        :: [GradientStop]-    , _lGradStart        :: P2-    , _lGradEnd          :: P2-    , _lGradTrans        :: T2-    , _lGradSpreadMethod :: SpreadMethod }+data LGradient n = LGradient+  { _lGradStops        :: [GradientStop n]+  , _lGradStart        :: Point V2 n+  , _lGradEnd          :: Point V2 n+  , _lGradTrans        :: Transformation V2 n+  , _lGradSpreadMethod :: SpreadMethod } +type instance V (LGradient n) = V2+type instance N (LGradient n) = n+ makeLensesWith (lensRules & generateSignatures .~ False) ''LGradient +instance Fractional n => Transformable (LGradient n) where+  transform = over lGradTrans . transform+ -- | A list of stops (colors and fractions).-lGradStops :: Lens' LGradient [GradientStop]+lGradStops :: Lens' (LGradient n) [GradientStop n]  -- | A transformation to be applied to the gradient. Usually this field will --   start as the identity transform and capture the transforms that are applied --   to the gradient.-lGradTrans :: Lens' LGradient T2+lGradTrans :: Lens' (LGradient n) (Transformation V2 n)  -- | The starting point for the first gradient stop. The coordinates are in---   'Local' units and the default is (-0.5, 0).-lGradStart :: Lens' LGradient P2+--   'local' units and the default is (-0.5, 0).+lGradStart :: Lens' (LGradient n) (Point V2 n)  -- | The ending point for the last gradient stop.The coordinates are in---   'Local' units and the default is (0.5, 0).-lGradEnd :: Lens' LGradient P2+--   'local' units and the default is (0.5, 0).+lGradEnd :: Lens' (LGradient n) (Point V2 n)  -- | For setting the spread method.-lGradSpreadMethod :: Lens' LGradient SpreadMethod+lGradSpreadMethod :: Lens' (LGradient n) SpreadMethod  -- | Radial Gradient-data RGradient = RGradient-    { _rGradStops        :: [GradientStop]-    , _rGradCenter0      :: P2-    , _rGradRadius0      :: Double-    , _rGradCenter1      :: P2-    , _rGradRadius1      :: Double-    , _rGradTrans        :: T2-    , _rGradSpreadMethod :: SpreadMethod }+data RGradient n = RGradient+  { _rGradStops        :: [GradientStop n]+  , _rGradCenter0      :: Point V2 n+  , _rGradRadius0      :: n+  , _rGradCenter1      :: Point V2 n+  , _rGradRadius1      :: n+  , _rGradTrans        :: Transformation V2 n+  , _rGradSpreadMethod :: SpreadMethod }  makeLensesWith (lensRules & generateSignatures .~ False) ''RGradient +type instance V (RGradient n) = V2+type instance N (RGradient n) = n++instance Fractional n => Transformable (RGradient n) where+  transform = over rGradTrans . transform+ -- | A list of stops (colors and fractions).-rGradStops :: Lens' RGradient [GradientStop]+rGradStops :: Lens' (RGradient n) [GradientStop n]  -- | The center point of the inner circle.-rGradCenter0 :: Lens' RGradient P2+rGradCenter0 :: Lens' (RGradient n) (Point V2 n) --- | The radius of the inner cirlce in 'Local' coordinates.-rGradRadius0 :: Lens' RGradient Double+-- | The radius of the inner cirlce in 'local' coordinates.+rGradRadius0 :: Lens' (RGradient n) n  -- | The center of the outer circle.-rGradCenter1  :: Lens' RGradient P2+rGradCenter1  :: Lens' (RGradient n) (Point V2 n) --- | The radius of the outer circle in 'Local' coordinates.-rGradRadius1 :: Lens' RGradient Double+-- | The radius of the outer circle in 'local' coordinates.+rGradRadius1 :: Lens' (RGradient n) n  -- | A transformation to be applied to the gradient. Usually this field will --   start as the identity transform and capture the transforms that are applied --   to the gradient.-rGradTrans :: Lens' RGradient T2+rGradTrans :: Lens' (RGradient n) (Transformation V2 n)  -- | For setting the spread method.-rGradSpreadMethod :: Lens' RGradient SpreadMethod+rGradSpreadMethod :: Lens' (RGradient n) SpreadMethod +-----------------------------------------------------------------+--  Textures  ---------------------------------------------------+-----------------------------------------------------------------+ -- | A Texture is either a color 'SC', linear gradient 'LG', or radial gradient 'RG'. --   An object can have only one texture which is determined by the 'Last' --   semigroup structure.-data Texture = SC SomeColor | LG LGradient | RG RGradient-  deriving (Typeable)+data Texture n = SC SomeColor | LG (LGradient n) | RG (RGradient n)+  deriving Typeable +type instance V (Texture n) = V2+type instance N (Texture n) = n+ makePrisms ''Texture +-- | Prism onto an 'AlphaColour' 'Double' of a 'SC' texture.+_AC :: Prism' (Texture n) (AlphaColour Double)+_AC = _SC . _SomeColor++instance Floating n => Transformable (Texture n) where+  transform t (LG lg) = LG $ transform t lg+  transform t (RG rg) = RG $ transform t rg+  transform _ sc      = sc+ -- | Convert a solid colour into a texture.-solid :: Color a => a -> Texture+solid :: Color a => a -> Texture n solid = SC . SomeColor  -- | A default is provided so that linear gradients can easily be created using --   lenses. For example, @lg = defaultLG & lGradStart .~ (0.25 ^& 0.33)@. Note that --   no default value is provided for @lGradStops@, this must be set before --   the gradient value is used, otherwise the object will appear transparent.-defaultLG :: Texture-defaultLG = LG (LGradient-    { _lGradStops        = []-    , _lGradStart        = mkP2 (-0.5) 0-    , _lGradEnd          = mkP2 (0.5)  0-    , _lGradTrans        = mempty-    , _lGradSpreadMethod = GradPad-    })+defaultLG :: Fractional n => Texture n+defaultLG = LG LGradient+  { _lGradStops        = []+  , _lGradStart        = mkP2 (-0.5) 0+  , _lGradEnd          = mkP2 0.5 0+  , _lGradTrans        = mempty+  , _lGradSpreadMethod = GradPad+  }  -- | A default is provided so that radial gradients can easily be created using --   lenses. For example, @rg = defaultRG & rGradRadius1 .~ 0.25@. Note that --   no default value is provided for @rGradStops@, this must be set before --   the gradient value is used, otherwise the object will appear transparent.-defaultRG :: Texture-defaultRG = RG (RGradient-    { _rGradStops        = []-    , _rGradCenter0      = mkP2 0 0-    , _rGradRadius0      = 0.0-    , _rGradCenter1      = mkP2 0 0-    , _rGradRadius1      = 0.5-    , _rGradTrans        = mempty-    , _rGradSpreadMethod = GradPad-    })+defaultRG :: Fractional n => Texture n+defaultRG = RG RGradient+  { _rGradStops        = []+  , _rGradCenter0      = mkP2 0 0+  , _rGradRadius0      = 0.0+  , _rGradCenter1      = mkP2 0 0+  , _rGradRadius1      = 0.5+  , _rGradTrans        = mempty+  , _rGradSpreadMethod = GradPad+  }  -- | A convenient function for making gradient stops from a list of triples. --   (An opaque color, a stop fraction, an opacity).-mkStops :: [(Colour Double, Double, Double)] -> [GradientStop]+mkStops :: [(Colour Double, d, Double)] -> [GradientStop d] mkStops = map (\(x, y, z) -> GradientStop (SomeColor (withOpacity x z)) y)  -- | Make a linear gradient texture from a stop list, start point, end point, --   and 'SpreadMethod'. The 'lGradTrans' field is set to the identity --   transfrom, to change it use the 'lGradTrans' lens.-mkLinearGradient :: [GradientStop]  -> P2 -> P2 -> SpreadMethod -> Texture+mkLinearGradient :: Num n => [GradientStop n] -> Point V2 n -> Point V2 n -> SpreadMethod -> Texture n mkLinearGradient stops  start end spreadMethod   = LG (LGradient stops start end mempty spreadMethod)  -- | Make a radial gradient texture from a stop list, radius, start point, --   end point, and 'SpreadMethod'. The 'rGradTrans' field is set to the identity --   transfrom, to change it use the 'rGradTrans' lens.-mkRadialGradient :: [GradientStop] -> P2 -> Double-                  -> P2 -> Double -> SpreadMethod -> Texture+mkRadialGradient :: Num n => [GradientStop n] -> Point V2 n -> n+                  -> Point V2 n -> n -> SpreadMethod -> Texture n mkRadialGradient stops c0 r0 c1 r1 spreadMethod   = RG (RGradient stops c0 r0 c1 r1 mempty spreadMethod) +-- Line Texture --------------------------------------------------------+ -- | The texture with which lines are drawn.  Note that child --   textures always override parent textures. --   More precisely, the semigroup structure on line texture attributes --   is that of 'Last'.-newtype LineTexture = LineTexture (Last Texture)+newtype LineTexture n = LineTexture (Last (Texture n))   deriving (Typeable, Semigroup)-instance AttributeClass LineTexture+instance (Typeable n) => AttributeClass (LineTexture n) -type instance V LineTexture = R2+type instance V (LineTexture n) = V2+type instance N (LineTexture n) = n +_LineTexture :: Iso (LineTexture n) (LineTexture n')+                    (Texture n)     (Texture n')+_LineTexture = iso getLineTexture (LineTexture . Last)+ -- Only gradients get transformed. The transform is applied to the gradients -- transform field. Colors are left unchanged.-instance Transformable LineTexture where-  transform t (LineTexture (Last texture)) = LineTexture (Last tx)-    where-      tx = texture & lgt . rgt-      lgt = _LG . lGradTrans %~ f-      rgt = _RG . rGradTrans %~ f-      f = transform t+instance Floating n => Transformable (LineTexture n) where+  transform t (LineTexture (Last tx)) = LineTexture (Last $ transform t tx) -instance Default LineTexture where-    def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))+instance Default (LineTexture n) where+  def = _LineTexture . _SC ## SomeColor black -getLineTexture :: LineTexture -> Texture+mkLineTexture :: Texture n -> LineTexture n+mkLineTexture = LineTexture . Last++getLineTexture :: LineTexture n -> Texture n getLineTexture (LineTexture (Last t)) = t -lineTexture :: (HasStyle a, V a ~ R2) => Texture-> a -> a+lineTexture :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Texture n -> a -> a lineTexture = applyTAttr . LineTexture . Last -lineTextureA :: (HasStyle a, V a ~ R2) => LineTexture -> a -> a+lineTextureA :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => LineTexture n -> a -> a lineTextureA = applyTAttr -mkLineTexture :: Texture  -> LineTexture-mkLineTexture = LineTexture . Last--styleLineTexture :: Setter' (Style v) Texture-styleLineTexture = sets modifyLineTexture+_lineTexture :: (Floating n, Typeable n) => Lens' (Style V2 n) (Texture n)+_lineTexture = atTAttr . anon def isDef . _LineTexture   where-    modifyLineTexture f s-      = flip setAttr s-      . mkLineTexture-      . f-      . getLineTexture-      . fromMaybe def . getAttr-      $ s+    isDef = anyOf (_LineTexture . _AC) (== opaque black)  -- | Set the line (stroke) color.  This function is polymorphic in the --   color type (so it can be used with either 'Colour' or --   'AlphaColour'), but this can sometimes create problems for type --   inference, so the 'lc' and 'lcA' variants are provided with more --   concrete types.-lineColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a+lineColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a lineColor = lineTexture . SC . SomeColor  -- | A synonym for 'lineColor', specialized to @'Colour' Double@ --   (i.e. opaque colors).  See comment in 'lineColor' about backends.-lc :: (HasStyle a, V a ~ R2) => Colour Double -> a -> a+lc :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Colour Double -> a -> a lc = lineColor  -- | A synonym for 'lineColor', specialized to @'AlphaColour' Double@ --   (i.e. colors with transparency).  See comment in 'lineColor' --   about backends.-lcA :: (HasStyle a, V a ~ R2) => AlphaColour Double -> a -> a+lcA :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => AlphaColour Double -> a -> a lcA = lineColor  -- | Apply a linear gradient.-lineLGradient :: (HasStyle a, V a ~ R2) => LGradient -> a -> a+lineLGradient :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => LGradient n -> a -> a lineLGradient g = lineTexture (LG g)  -- | Apply a radial gradient.-lineRGradient :: (HasStyle a, V a ~ R2) => RGradient -> a -> a+lineRGradient :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => RGradient n -> a -> a lineRGradient g = lineTexture (RG g) +-- Fill Texture --------------------------------------------------------+ -- | The texture with which objects are filled. --   The semigroup structure on fill texture attributes --   is that of 'Recommed . Last'.-newtype FillTexture = FillTexture (Recommend (Last Texture))+newtype FillTexture n = FillTexture (Recommend (Last (Texture n)))   deriving (Typeable, Semigroup) -instance AttributeClass FillTexture+instance Typeable n => AttributeClass (FillTexture n) -type instance V FillTexture = R2+_FillTexture :: Iso' (FillTexture n) (Recommend (Texture n))+_FillTexture = iso getter setter+  where+    getter (FillTexture (Recommend (Last t))) = Recommend t+    getter (FillTexture (Commit    (Last t))) = Commit t+    setter (Recommend t) = FillTexture (Recommend (Last t))+    setter (Commit t)    = FillTexture (Commit (Last t))+  -- = iso (\(FillTexture a) -> a) FillTexture . mapping _Wrapped+  -- -- once we depend on monoid-extras-0.4 +type instance V (FillTexture n) = V2+type instance N (FillTexture n) = n+ -- Only gradients get transformed. The transform is applied to the gradients -- transform field. Colors are left unchanged.-instance Transformable FillTexture where-  transform _ tx@(FillTexture (Recommend _)) = tx-  transform t (FillTexture (Commit (Last texture))) = FillTexture (Commit (Last tx))-    where-      tx = texture & lgt . rgt-      lgt = _LG . lGradTrans %~ f-      rgt = _RG . rGradTrans %~ f-      f = transform t+instance Floating n => Transformable (FillTexture n) where+  transform = over (_FillTexture . _recommend) . transform -instance Default FillTexture where-    def = FillTexture (Recommend (Last (SC-                      (SomeColor (transparent :: AlphaColour Double)))))+instance Default (FillTexture n) where+  def = mkFillTexture $ _AC ## transparent -getFillTexture :: FillTexture -> Texture+getFillTexture :: FillTexture n -> Texture n getFillTexture (FillTexture tx) = getLast . getRecommend $ tx -fillTexture :: (HasStyle a, V a ~ R2) => Texture -> a -> a-fillTexture = applyTAttr . FillTexture . Commit . Last+fillTexture :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Texture n -> a -> a+fillTexture = applyTAttr . mkFillTexture -mkFillTexture :: Texture  -> FillTexture+mkFillTexture :: Texture n -> FillTexture n mkFillTexture = FillTexture . Commit . Last -styleFillTexture :: Setter' (Style v) Texture-styleFillTexture = sets modifyFillTexture+-- | Lens onto the 'Recommend' of a fill texture in a style.+_fillTextureR :: (Typeable n, Floating n) => Lens' (Style V2 n) (Recommend (Texture n))+_fillTextureR = atTAttr . anon def isDef . _FillTexture   where-    modifyFillTexture f s-      = flip setAttr s-      . mkFillTexture-      . f-      . getFillTexture-      . fromMaybe def . getAttr-      $ s+    isDef = anyOf (_FillTexture . _Recommend . _AC) (== transparent) +-- | Commit a fill texture in a style. This is /not/ a valid setter+--   because it doesn't abide the functor law (see 'committed').+_fillTexture :: (Typeable n, Floating n) => Lens' (Style V2 n) (Texture n)+_fillTexture = _fillTextureR . committed+ -- | Set the fill color.  This function is polymorphic in the color --   type (so it can be used with either 'Colour' or 'AlphaColour'), --   but this can sometimes create problems for type inference, so the --   'fc' and 'fcA' variants are provided with more concrete types.-fillColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a+fillColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a fillColor = fillTexture . SC . SomeColor  -- | Set a \"recommended\" fill color, to be used only if no explicit --   calls to 'fillColor' (or 'fc', or 'fcA') are used. --   See comment after 'fillColor' about backends.-recommendFillColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a+recommendFillColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a recommendFillColor =   applyTAttr . FillTexture . Recommend . Last . SC . SomeColor  -- | A synonym for 'fillColor', specialized to @'Colour' Double@ --   (i.e. opaque colors). See comment after 'fillColor' about backends.-fc :: (HasStyle a, V a ~ R2) => Colour Double -> a -> a+fc :: (InSpace V2 n a, Floating n, Typeable n, HasStyle a) => Colour Double -> a -> a fc = fillColor  -- | A synonym for 'fillColor', specialized to @'AlphaColour' Double@ --   (i.e. colors with transparency). See comment after 'fillColor' about backends.-fcA :: (HasStyle a, V a ~ R2) => AlphaColour Double -> a -> a+fcA :: (InSpace V2 n a, Floating n, Typeable n, HasStyle a) => AlphaColour Double -> a -> a fcA = fillColor------------------------------------------------------------- -data FillTextureLoops v = FillTextureLoops+-- Split fills --------------------------------------------------------- -instance Typeable v => SplitAttribute (FillTextureLoops v) where-  type AttrType (FillTextureLoops v) = FillTexture-  type PrimType (FillTextureLoops v) = Path v+data FillTextureLoops n = FillTextureLoops +instance Typeable n => SplitAttribute (FillTextureLoops n) where+  type AttrType (FillTextureLoops n) = FillTexture n+  type PrimType (FillTextureLoops n) = Path V2 n+   primOK _ = all (isLoop . unLoc) . pathTrails  -- | Push fill attributes down until they are at the root of subtrees@@ -510,5 +417,7 @@ --   applied to lines/non-closed paths as well as loops/closed paths, --   whereas in the semantics of diagrams, fill attributes only apply --   to loops.-splitTextureFills :: forall b v a. Typeable v => RTree b v a -> RTree b v a-splitTextureFills = splitAttr (FillTextureLoops :: FillTextureLoops v)+splitTextureFills+  :: forall b v n a. (+                     Typeable n) => RTree b v n a -> RTree b v n a+splitTextureFills = splitAttr (FillTextureLoops :: FillTextureLoops n)
src/Diagrams/TwoD/Combinators.hs view
@@ -1,7 +1,12 @@+{-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-} {-# LANGUAGE TypeFamilies          #-}-{-# LANGUAGE ViewPatterns          #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Combinators@@ -18,11 +23,11 @@     (       -- * Binary combinators -      (===), (|||), atAngle+      (===), (|||)        -- * n-ary combinators-    , hcat, hcat'-    , vcat, vcat'+    , hcat, hcat', hsep+    , vcat, vcat', vsep        -- * Spacing/envelopes     , strutR2@@ -31,36 +36,38 @@      , extrudeLeft, extrudeRight, extrudeBottom, extrudeTop -    , view+    , rectEnvelope, crop -    , boundingRect, bg+    , boundingRect, bg, bgFrame      ) where -import           Data.AffineSpace+import           Control.Lens             ((&), (.~)) import           Data.Colour-import           Data.Default.Class+import           Data.Default import           Data.Semigroup-import           Data.VectorSpace  import           Diagrams.Core -import           Diagrams.Angle+import           Diagrams.Attributes      (lwO) import           Diagrams.BoundingBox import           Diagrams.Combinators-import           Diagrams.Coordinates import           Diagrams.Path+import           Diagrams.Query           (value) import           Diagrams.Segment import           Diagrams.TrailLike import           Diagrams.TwoD.Align-import           Diagrams.TwoD.Attributes (lineWidth, fc)+import           Diagrams.TwoD.Attributes (fc) import           Diagrams.TwoD.Path       () import           Diagrams.TwoD.Shapes import           Diagrams.TwoD.Transform  (scaleX, scaleY) import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector     (fromDirection, unitX, unitY)+import           Diagrams.TwoD.Vector import           Diagrams.Util            (( # )) +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector  infixl 6 === infixl 6 |||@@ -79,8 +86,8 @@ --   combined diagram is the same as the local origin of the first. --   @(===)@ is associative and has 'mempty' as an identity.  See the --   documentation of 'beside' for more information.-(===) :: (Juxtaposable a, V a ~ R2, Semigroup a) => a -> a -> a-(===) = beside (negateV unitY)+(===) :: (InSpace V2 n a, Juxtaposable a, Semigroup a) => a -> a -> a+(===) = beside unit_Y  -- | Place two diagrams (or other juxtaposable objects) horizontally --   adjacent to one another, with the first diagram to the left of@@ -88,17 +95,9 @@ --   is the same as the local origin of the first.  @(|||)@ is --   associative and has 'mempty' as an identity.  See the --   documentation of 'beside' for more information.-(|||) :: (Juxtaposable a, V a ~ R2, Semigroup a) => a -> a -> a+(|||) :: (InSpace V2 n a, Juxtaposable a, Semigroup a) => a -> a -> a (|||) = beside unitX --- | Place two diagrams (or other juxtaposable objects) adjacent to one---   another, with the second diagram placed along a line at angle---   'th' from the first.  The local origin of the resulting combined---   diagram is the same as the local origin of the first.---   See the documentation of 'beside' for more information.-atAngle :: (Juxtaposable a, V a ~ R2, Semigroup a) => Angle -> a -> a -> a-atAngle th = beside (fromDirection th)- -- | Lay out a list of juxtaposable objects in a row from left to right, --   so that their local origins lie along a single horizontal line, --   with successive envelopes tangent to one another.@@ -110,17 +109,24 @@ --     "Diagrams.TwoD.Align" before applying 'hcat'. -- --   * For non-axis-aligned layout, see 'cat'.-hcat :: (Juxtaposable a, HasOrigin a, Monoid' a, V a ~ R2)+hcat :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)      => [a] -> a hcat = hcat' def  -- | A variant of 'hcat' taking an extra 'CatOpts' record to control --   the spacing.  See the 'cat'' documentation for a description of---   the possibilities.-hcat' :: (Juxtaposable a, HasOrigin a, Monoid' a, V a ~ R2)-      => CatOpts R2 -> [a] -> a+--   the possibilities. For the common case of setting just a+--   separation amount, see 'hsep'.+hcat' :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)+      => CatOpts n -> [a] -> a hcat' = cat' unitX +-- | A convenient synonym for horizontal concatenation with+--   separation: @hsep s === hcat' (with & sep .~ s)@.+hsep :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)+     => n -> [a] -> a+hsep s = hcat' (def & sep .~ s)+ -- | Lay out a list of juxtaposable objects in a column from top to --   bottom, so that their local origins lie along a single vertical --   line, with successive envelopes tangent to one another.@@ -132,24 +138,31 @@ --     "Diagrams.TwoD.Align" before applying 'vcat'. -- --   * For non-axis-aligned layout, see 'cat'.-vcat :: (Juxtaposable a, HasOrigin a, Monoid' a, V a ~ R2)+vcat :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)      => [a] -> a vcat = vcat' def  -- | A variant of 'vcat' taking an extra 'CatOpts' record to control---   the spacing.  See the 'cat'' documentation for a description of the---   possibilities.-vcat' :: (Juxtaposable a, HasOrigin a, Monoid' a, V a ~ R2)-      => CatOpts R2 -> [a] -> a-vcat' = cat' (negateV unitY)+--   the spacing.  See the 'cat'' documentation for a description of+--   the possibilities.  For the common case of setting just a+--   separation amount, see 'vsep'.+vcat' :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)+      => CatOpts n -> [a] -> a+vcat' = cat' unit_Y +-- | A convenient synonym for vertical concatenation with+--   separation: @vsep s === vcat' (with & sep .~ s)@.+vsep :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)+     => n -> [a] -> a+vsep s = vcat' (def & sep .~ s)+ -- | @strutR2 v@ is a two-dimensional diagram which produces no --   output, but with respect to alignment, envelope, /and trace/ acts --   like a 1-dimensional segment oriented along the vector @v@, with --   local origin at its center.  If you don't care about the trace --   then there's no difference between @strutR2@ and the more general --   'strut'.-strutR2 :: (Backend b R2, Monoid' m) => R2 -> QDiagram b R2 m+strutR2 :: (RealFloat n, Monoid' m) => V2 n -> QDiagram b V2 n m strutR2 v = phantom seg   where     seg = FLinear (origin .+^ 0.5 *^ v) (origin .+^ (-0.5) *^ v)@@ -157,14 +170,14 @@ -- | @strutX w@ is an empty diagram with width @w@, height 0, and a --   centered local origin.  Note that @strutX (-w)@ behaves the same as --   @strutX w@.-strutX :: (Backend b R2, Monoid' m) => Double -> QDiagram b R2 m-strutX d = strut (d ^& 0)+strutX :: (Metric v, R1 v, OrderedField n) => n -> QDiagram b v n m+strutX d = strut (zero & _x .~ d)  -- | @strutY h@ is an empty diagram with height @h@, width 0, and a --   centered local origin. Note that @strutY (-h)@ behaves the same as --   @strutY h@.-strutY :: (Backend b R2, Monoid' m) => Double -> QDiagram b R2 m-strutY d = strut (0 ^& d)+strutY :: (Metric v, R2 v, OrderedField n) => n -> QDiagram b v n m+strutY d = strut (zero & _y .~ d)  -- | @padX s@ \"pads\" a diagram in the x-direction, expanding its --   envelope horizontally by a factor of @s@ (factors between 0 and 1@@ -173,8 +186,8 @@ --   centered horizontally the padding may appear \"uneven\".  If this --   is not desired, the origin can be centered (using 'centerX') --   before applying @padX@.-padX :: ( Backend b R2, Monoid' m )-     => Double -> QDiagram b R2 m -> QDiagram b R2 m+padX :: (Metric v, R2 v, OrderedField n, Monoid' m)+     => n -> QDiagram b v n m -> QDiagram b v n m padX s d = withEnvelope (d # scaleX s) d  -- | @padY s@ \"pads\" a diagram in the y-direction, expanding its@@ -184,8 +197,8 @@ --   so if the origin is not centered vertically the padding may appear --   \"uneven\".  If this is not desired, the origin can be centered --   (using 'centerY') before applying @padY@.-padY :: ( Backend b R2, Monoid' m )-     => Double -> QDiagram b R2 m -> QDiagram b R2 m+padY :: (Metric v, R2 v, Monoid' m, OrderedField n)+     => n -> QDiagram b v n m -> QDiagram b v n m padY s d = withEnvelope (d # scaleY s) d  -- | @extrudeLeft s@ \"extrudes\" a diagram in the negative x-direction,@@ -193,7 +206,7 @@ --   the envelope is inset instead. -- --   See the documentation for 'extrudeEnvelope' for more information.-extrudeLeft :: Monoid' m => Double -> QDiagram b R2 m -> QDiagram b R2 m+extrudeLeft :: (OrderedField n, Monoid' m) => n -> QDiagram b V2 n m -> QDiagram b V2 n m extrudeLeft s   | s >= 0    = extrudeEnvelope $ unitX ^* negate s   | otherwise = intrudeEnvelope $ unitX ^* negate s@@ -203,7 +216,7 @@ --   the envelope is inset instead. -- --   See the documentation for 'extrudeEnvelope' for more information.-extrudeRight :: Monoid' m => Double -> QDiagram b R2 m -> QDiagram b R2 m+extrudeRight :: (OrderedField n, Monoid' m) => n -> QDiagram b V2 n m -> QDiagram b V2 n m extrudeRight s   | s >= 0    = extrudeEnvelope $ unitX ^* s   | otherwise = intrudeEnvelope $ unitX ^* s@@ -213,7 +226,7 @@ --   the envelope is inset instead. -- --   See the documentation for 'extrudeEnvelope' for more information.-extrudeBottom :: Monoid' m => Double -> QDiagram b R2 m -> QDiagram b R2 m+extrudeBottom :: (OrderedField n, Monoid' m) => n -> QDiagram b V2 n m -> QDiagram b V2 n m extrudeBottom s   | s >= 0    = extrudeEnvelope $ unitY ^* negate s   | otherwise = intrudeEnvelope $ unitY ^* negate s@@ -223,29 +236,44 @@ --   the envelope is inset instead. -- --   See the documentation for 'extrudeEnvelope' for more information.-extrudeTop :: Monoid' m => Double -> QDiagram b R2 m -> QDiagram b R2 m+extrudeTop :: (OrderedField n, Monoid' m) => n -> QDiagram b V2 n m -> QDiagram b V2 n m extrudeTop s   | s >= 0    = extrudeEnvelope $ unitY ^* s   | otherwise = intrudeEnvelope $ unitY ^* s --- | @view p v@ sets the envelope of a diagram to a rectangle whose+-- | @rectEnvelope p v@ sets the envelope of a diagram to a rectangle whose --   lower-left corner is at @p@ and whose upper-right corner is at @p --   .+^ v@.  Useful for selecting the rectangular portion of a --   diagram which should actually be \"viewed\" in the final render, --   if you don't want to see the entire diagram.-view :: ( Backend b R2, Monoid' m )-     => P2 -> R2 -> QDiagram b R2 m -> QDiagram b R2 m-view p (coords -> w :& h) = withEnvelope (rect w h # alignBL # moveTo p :: D R2)+rectEnvelope :: forall b n m. (OrderedField n, Monoid' m)+     => Point V2 n -> V2 n -> QDiagram b V2 n m -> QDiagram b V2 n m+rectEnvelope p (V2 w h) = withEnvelope (rect w h # alignBL # moveTo p :: Path V2 n) +-- | A synonym for 'rectEnvelope'.+crop :: forall b n m. (OrderedField n, Monoid' m)+     => Point V2 n -> V2 n -> QDiagram b V2 n m -> QDiagram b V2 n m+crop = rectEnvelope+ -- | Construct a bounding rectangle for an enveloped object, that is, --   the smallest axis-aligned rectangle which encloses the object.-boundingRect :: ( Enveloped t, Transformable t, TrailLike t, Monoid t, V t ~ R2-                , Enveloped a, V a ~ R2-                )+boundingRect :: ( InSpace V2 n a, SameSpace a t+                , Enveloped t, Transformable t, TrailLike t, Monoid t+                , Enveloped a)              => a -> t boundingRect = (`boxFit` rect 1 1) . boundingBox  -- | \"Set the background color\" of a diagram.  That is, place a --   diagram atop a bounding rectangle of the given color.-bg :: (Renderable (Path R2) b) => Colour Double -> Diagram b R2 -> Diagram b R2-bg c d = d <> boundingRect d # lineWidth (Output 0) # fc c+--   The background does not change the result of queries.+bg :: (TypeableFloat n, Renderable (Path V2 n) b, Monoid' q)+    => Colour Double -> QDiagram b V2 n q -> QDiagram b V2 n q+bg c d = d <> boundingRect d # lwO 0 # fc c # value mempty++-- | Similar to 'bg' but makes the colored background rectangle larger than+--   the diagram. The first parameter is used to set how far the background+--   extends beyond the diagram.+--   The background does not change the result of queries.+bgFrame :: (TypeableFloat n, Renderable (Path V2 n) b, Monoid' q)+    => n -> Colour Double -> QDiagram b V2 n q -> QDiagram b V2 n q+bgFrame f c d = d <> boundingRect (frame f d) # lwO 0 # fc c # value mempty
src/Diagrams/TwoD/Curvature.hs view
@@ -19,16 +19,16 @@     , squaredRadiusOfCurvature     ) where +import           Control.Lens        (over)+import           Control.Monad import           Data.Monoid.Inf-import           Data.VectorSpace -import           Control.Arrow        (first, second)-import           Control.Monad        (join)- import           Diagrams.Segment import           Diagrams.Tangent import           Diagrams.TwoD.Types +import           Linear.Vector+ -- | Curvature measures how curved the segment is at a point.  One intuition -- for the concept is how much you would turn the wheel when driving a car -- along the curve.  When the wheel is held straight there is zero curvature.@@ -68,9 +68,10 @@ -- > import Data.Monoid.Inf -- > import Diagrams.Coordinates -- >+-- > segmentA :: Segment Closed V2 Double -- > segmentA = Cubic (12 ^& 0) (8 ^& 10) (OffsetClosed (20 ^& 8)) -- >--- > curveA = lw thick . stroke . fromSegments $ [segmentA]+-- > curveA = lw thick . strokeP . fromSegments $ [segmentA] -- > -- > diagramA = pad 1.1 . centerXY $ curveA -- >@@ -83,9 +84,10 @@ -- > diagramWithRadius t = pad 1.1 . centerXY -- >          $ curveA -- >         <> showCurvature segmentA t--- >          # withEnvelope (curveA :: D R2)+-- >          # withEnvelope (curveA :: D V2 Double) -- >          # lc red -- >+-- > showCurvature :: Segment Closed V2 Double -> Double -> Diagram SVG -- > showCurvature bez@(Cubic b c (OffsetClosed d)) t -- >   | v == (0,0) = mempty -- >   | otherwise  = go (radiusOfCurvature bez t)@@ -97,41 +99,41 @@ -- > -- >     go Infinity   = mempty -- >     go (Finite r) = (circle (abs r) # translate vpr--- >                  <> stroke (origin ~~ (origin .+^ vpr)))+-- >                  <> strokeP (origin ~~ (origin .+^ vpr))) -- >                   # moveTo (origin .+^ atParam bez t) -- >       where--- >         vpr = r2 (normalized vp ^* r)+-- >         vpr = signorm vp ^* r -- > ---curvature :: Segment Closed R2  -- ^ Segment to measure on.-          -> Double           -- ^ Parameter to measure at.-          -> PosInf Double    -- ^ Result is a @PosInf@ value where @PosInfty@ represents-                              -- infinite curvature or zero radius of curvature.-curvature s = toPosInf . second sqrt . curvaturePair (fmap unr2 s) -- TODO: Use the generalized unr2+curvature :: RealFloat n+          => Segment Closed V2 n  -- ^ Segment to measure on.+          -> n                    -- ^ Parameter to measure at.+          -> PosInf n             -- ^ Result is a @PosInf@ value where @PosInfty@ represents+                                  --   infinite curvature or zero radius of curvature.+curvature s = toPosInf . over _y sqrt . curvaturePair s  -- | With @squaredCurvature@ we can compute values in spaces that do not support -- 'sqrt' and it is just as useful for relative ordering of curvatures or looking -- for zeros.-squaredCurvature :: Segment Closed R2 -> Double -> PosInf Double-squaredCurvature s = toPosInf . first (join (*)) . curvaturePair (fmap unr2 s) -- TODO: Use the generalized unr2-+squaredCurvature :: RealFloat n => Segment Closed V2 n -> n -> PosInf n+squaredCurvature s = toPosInf . over _x (join (*)) . curvaturePair s  -- | Reciprocal of @curvature@.-radiusOfCurvature :: Segment Closed R2  -- ^ Segment to measure on.-                  -> Double           -- ^ Parameter to measure at.-                  -> PosInf Double    -- ^ Result is a @PosInf@ value where @PosInfty@ represents-                                      -- infinite radius of curvature or zero curvature.-radiusOfCurvature s = toPosInf . (\(p,q) -> (q,p)) . second sqrt . curvaturePair (fmap unr2 s)+radiusOfCurvature :: RealFloat n+                  => Segment Closed V2 n -- ^ Segment to measure on.+                  -> n                   -- ^ Parameter to measure at.+                  -> PosInf n            -- ^ Result is a @PosInf@ value where @PosInfty@ represents+                                         --   infinite radius of curvature or zero curvature.+radiusOfCurvature s = toPosInf . (\(V2 p q) -> V2 (sqrt q) p) . curvaturePair s  -- | Reciprocal of @squaredCurvature@-squaredRadiusOfCurvature :: Segment Closed R2 -> Double -> PosInf Double-squaredRadiusOfCurvature s = toPosInf . (\(p,q) -> (q,p)) . first (join (*)) . curvaturePair (fmap unr2 s)-+squaredRadiusOfCurvature :: RealFloat n => Segment Closed V2 n -> n -> PosInf n+squaredRadiusOfCurvature s = toPosInf . (\(V2 p q) -> (V2 q (p * p))) . curvaturePair s  -- Package up problematic values with the appropriate infinity.-toPosInf :: RealFloat a => (a,a) -> PosInf a-toPosInf (_,0) = Infinity-toPosInf (p,q)+toPosInf :: RealFloat a => V2 a -> PosInf a+toPosInf (V2 _ 0) = Infinity+toPosInf (V2 p q)   | isInfinite r || isNaN r = Infinity   | otherwise               = Finite r   where r = p / q@@ -139,13 +141,14 @@ -- Internal function that is not quite curvature or squaredCurvature but lets -- us get there by either taking the square root of the numerator or squaring -- the denominator respectively.-curvaturePair :: (Num t, Num (Scalar t), VectorSpace t)-    => Segment Closed (t, t) -> Scalar t -> (t, t)-curvaturePair (Linear _) _ = (0,1) -- Linear segments always have zero curvature (infinite radius).-curvaturePair seg@(Cubic b c (OffsetClosed d)) t = ((x'*y'' - y'*x''), (x'*x' + y'*y')^(3 :: Integer))+curvaturePair :: Num n+    => Segment Closed V2 n -> n -> V2 n+curvaturePair (Linear _) _ = V2 0 1 -- Linear segments always have zero curvature (infinite radius).+curvaturePair seg@(Cubic b c (OffsetClosed d)) t+  = V2 (x'*y'' - y'*x'') ((x'*x' + y'*y')^(3 :: Int))   where-    (x' ,y' ) = seg `tangentAtParam` t-    (x'',y'') = secondDerivative+    (V2 x'  y' )     = seg `tangentAtParam` t+    (V2 x'' y'')     = secondDerivative     secondDerivative = (6*(3*t-2))*^b ^+^ (6-18*t)*^c ^+^ (6*t)*^d  -- TODO: We should be able to generalize this to higher dimensions.  See@@ -153,3 +156,11 @@ -- -- TODO: I'm not sure what the best way to generalize squaredCurvature to other spaces is. +-- curvaturePair :: (Num t, Num (Scalar t), VectorSpace t)+--     => Segment Closed (t, t) -> Scalar t -> (t, t)+-- curvaturePair (Linear _) _ = (0,1) -- Linear segments always have zero curvature (infinite radius).+-- curvaturePair seg@(Cubic b c (OffsetClosed d)) t = ((x'*y'' - y'*x''), (x'*x' + y'*y')^(3 :: Integer))+--   where+--     (x' ,y' ) = seg `tangentAtParam` t+--     (x'',y'') = secondDerivative+--     secondDerivative = (6*(3*t-2))*^b ^+^ (6-18*t)*^c ^+^ (6*t)*^d
src/Diagrams/TwoD/Deform.hs view
@@ -1,36 +1,41 @@ module Diagrams.TwoD.Deform where -import Control.Lens+import           Control.Lens -import Diagrams.Deform+import           Diagrams.Deform -import Diagrams.Coordinates-import Diagrams.TwoD.Types+import           Linear.V2+import           Linear.Vector --- | The parallel projection onto the line x=0-parallelX0 :: Deformation R2-parallelX0 = Deformation (& _x .~ 0)+-- | The parallel projection onto the plane x=0+parallelX0 :: (R1 v, Num n) => Deformation v v n+parallelX0 = Deformation (_x .~ 0) --- | The perspective division onto the line x=1 along lines going+-- | The perspective division onto the plane x=1 along lines going -- through the origin.-perspectiveX1 :: Deformation R2-perspectiveX1 = Deformation (\p -> p & _y //~ (p^._x) & _x .~ 1)+perspectiveX1 :: (R1 v, Functor v, Fractional n) => Deformation v v n+perspectiveX1 = Deformation $ \p -> p ^/ (p ^. _x) --- | The parallel projection onto the line y=0-parallelY0 :: Deformation R2-parallelY0 = Deformation (& _y .~ 0)+-- | The parallel projection onto the plane y=0+parallelY0 :: (R2 v, Num n) => Deformation v v n+parallelY0 = Deformation (_y .~ 0) --- | The perspective division onto the line y=1 along lines going+-- | The perspective division onto the plane y=1 along lines going -- through the origin.-perspectiveY1 :: Deformation R2-perspectiveY1 = Deformation (\p -> p & _x //~ (p^._y) & _y .~ 1)+perspectiveY1 :: (R2 v, Functor v, Floating n) => Deformation v v n+perspectiveY1 = Deformation $ \p -> p ^/ (p ^. _y)  -- | The viewing transform for a viewer facing along the positive X -- axis.  X coördinates stay fixed, while Y coördinates are compressed -- with increasing distance.  @asDeformation (translation unitX) <> -- parallelX0 <> frustrumX = perspectiveX1@-facingX :: Deformation R2-facingX = Deformation (\v -> v & _y //~ (v^._x))+facingX :: (R1 v, Functor v, Fractional n) => Deformation v v n+facingX = Deformation $+  \p -> let x = p ^. _x+        in  p ^/ x & _x .~ x -facingY :: Deformation R2-facingY = Deformation (\v -> v & _x //~ (v^._y))+facingY :: (R2 v, Functor v, Fractional n) => Deformation v v n+facingY = Deformation $+  \p -> let y = p ^. _y+        in  p ^/ y & _y .~ y+
src/Diagrams/TwoD/Ellipse.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-} {-# LANGUAGE TypeSynonymInstances  #-} ----------------------------------------------------------------------------- -- |@@ -22,31 +23,31 @@     , ellipseXY     ) where -import           Data.AdditiveGroup- import           Diagrams.Core  import           Diagrams.Angle import           Diagrams.Located        (at)+import           Diagrams.Trail          (glueTrail) import           Diagrams.TrailLike import           Diagrams.TwoD.Arc import           Diagrams.TwoD.Transform import           Diagrams.TwoD.Types+import           Diagrams.TwoD.Vector    (xDir) import           Diagrams.Util  -- | A circle of radius 1, with center at the origin.-unitCircle :: (TrailLike t, V t ~ R2) => t-unitCircle = trailLike $ arcT zeroV fullTurn `at` (p2 (1,0))+unitCircle :: (TrailLike t, V t ~ V2, N t ~ n) => t+unitCircle = trailLike $ glueTrail (arcT xDir fullTurn) `at` p2 (1,0)  -- | A circle of the given radius, centered at the origin.  As a path, --   it begins at (r,0).-circle :: (TrailLike t, V t ~ R2, Transformable t) => Double -> t+circle :: (TrailLike t, V t ~ V2, N t ~ n, Transformable t) => n -> t circle d = unitCircle # scale d  -- | @ellipse e@ constructs an ellipse with eccentricity @e@ by --   scaling the unit circle in the X direction.  The eccentricity must --   be within the interval [0,1).-ellipse :: (TrailLike t, V t ~ R2, Transformable t) => Double -> t+ellipse :: (TrailLike t, V t ~ V2, N t ~ n, Transformable t) => n -> t ellipse e     | e >= 0 && e < 1  = scaleX (sqrt (1 - e*e)) unitCircle     | otherwise        = error "Eccentricity of ellipse must be >= 0 and < 1."@@ -54,5 +55,5 @@ -- | @ellipseXY x y@ creates an axis-aligned ellipse, centered at the --   origin, with radius @x@ along the x-axis and radius @y@ along the --   y-axis.-ellipseXY :: (TrailLike t, V t ~ R2, Transformable t) => Double -> Double -> t+ellipseXY :: (TrailLike t, V t ~ V2, N t ~ n, Transformable t) => n -> n -> t ellipseXY x y = unitCircle # scaleX x # scaleY y
src/Diagrams/TwoD/Image.hs view
@@ -1,9 +1,12 @@+{-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE DeriveDataTypeable    #-} {-# LANGUAGE EmptyDataDecls        #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE GADTs                 #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE UndecidableInstances  #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Image@@ -11,93 +14,121 @@ -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com ----- Importing external images into diagrams.--- Usage: To create a diagram from an embedded image with width 1 and height---   set according to the aspect ratio: 'image img # scaleUToX 1`---   where 'img' is a 'DImage Embedded'+-- Importing external images into diagrams.  Usage example: To create+-- a diagram from an embedded image with width 1 and height set+-- according to the aspect ratio, use @image img # scaleUToX 1@, where+-- @img@ is a value of type @DImage n e@, created with a function like+-- 'loadImageEmb', 'loadImageExt', or 'raster'. -----------------------------------------------------------------------------  module Diagrams.TwoD.Image     (       DImage(..), ImageData(..)-    , Embedded, External+    , Embedded, External, Native     , image+    , embeddedImage     , loadImageEmb+    , loadImageEmbBS     , loadImageExt     , uncheckedImageRef     , raster     , rasterDia     ) where - import           Codec.Picture-import           Codec.Picture.Types  (dynamicMap) -import           Data.Typeable        (Typeable) import           Data.Colour          (AlphaColour)+import           Data.Kind            (Type)+import           Data.Semigroup+import           Data.Typeable        (Typeable)  import           Diagrams.Core  import           Diagrams.Attributes  (colorToSRGBA) import           Diagrams.Path        (Path)+import           Diagrams.Query import           Diagrams.TwoD.Path   (isInsideEvenOdd) import           Diagrams.TwoD.Shapes (rect)-import           Diagrams.TwoD.Types  (R2, T2)+import           Diagrams.TwoD.Types -import           Data.AffineSpace     ((.-.))-import           Data.Semigroup+import           Data.ByteString +import           Linear.Affine+ data Embedded deriving Typeable data External deriving Typeable+data Native (t :: Type) deriving Typeable  -- | 'ImageData' is either a JuicyPixels @DynamicImage@ tagged as 'Embedded' or---   a reference tagged as 'External'.-data ImageData :: * -> * where+--   a reference tagged as 'External'. Additionally 'Native' is provided for+--   external libraries to hook into.+data ImageData :: Type -> Type where   ImageRaster :: DynamicImage -> ImageData Embedded-  ImageRef :: FilePath -> ImageData External+  ImageRef    :: FilePath -> ImageData External+  ImageNative :: t -> ImageData (Native t)  ------------------------------------------------------------------------------- -- | An image primitive, the two ints are width followed by height. --   Will typically be created by @loadImageEmb@ or @loadImageExt@ which,---   will handle setting the width and heigh to the actual width and height+--   will handle setting the width and height to the actual width and height --   of the image.-data DImage :: * -> * where-  DImage :: ImageData t -> Int -> Int -> T2 -> DImage t+data DImage :: Type -> Type -> Type where+  DImage :: ImageData t -> Int -> Int -> Transformation V2 n -> DImage n t   deriving Typeable -type instance V (DImage a) = R2+type instance V (DImage n a) = V2+type instance N (DImage n a) = n -instance Transformable (DImage a) where+instance RealFloat n => HasQuery (DImage n a) Any where+  getQuery (DImage _ w h _) = -- transform t $+    Query $ \p -> Any (isInsideEvenOdd r p)+    where+    r = rectPath (fromIntegral w) (fromIntegral h)++instance Fractional n => Transformable (DImage n a) where   transform t1 (DImage iD w h t2) = DImage iD w h (t1 <> t2) -instance HasOrigin (DImage a) where+instance Fractional n => HasOrigin (DImage n a) where   moveOriginTo p = translate (origin .-. p)  -- | Make a 'DImage' into a 'Diagram'.-image :: (Typeable a, Renderable (DImage a) b) => DImage a -> Diagram b R2-image img = mkQD (Prim (img)) (getEnvelope r) (getTrace r) mempty-                  (Query $ \p -> Any (isInsideEvenOdd p r))+image :: (TypeableFloat n, Typeable a, Renderable (DImage n a) b)+      => DImage n a -> QDiagram b V2 n Any+image img+  = mkQD (Prim img)+         (getEnvelope r)+         (getTrace r)+         mempty+         (Query $ \p -> Any (isInsideEvenOdd r p))   where-    r :: Path R2-    r = rect (fromIntegral w) (fromIntegral h)+    r = rectPath (fromIntegral w) (fromIntegral h)+    -- should we use the transform here?     DImage _ w h _ = img --- | Use JuicyPixels to read an image in any format and wrap it in a 'DImage'.+rectPath :: RealFloat n => n -> n -> Path V2 n+rectPath = rect++-- | Read a JuicyPixels @DynamicImage@ and wrap it in a 'DImage'. --   The width and height of the image are set to their actual values.-loadImageEmb :: FilePath -> IO (Either String (DImage Embedded))-loadImageEmb path = do-    dImg <- readImage path-    return $ case dImg of-      Left msg  -> Left msg-      Right img -> Right (DImage (ImageRaster img) w h mempty)-        where-          w = dynamicMap imageWidth img-          h = dynamicMap imageHeight img+embeddedImage :: Num n => DynamicImage -> DImage n Embedded+embeddedImage img = DImage (ImageRaster img) w h mempty+  where+    w = dynamicMap imageWidth img+    h = dynamicMap imageHeight img +-- | Use JuicyPixels to read a file in any format and wrap it in a 'DImage'.+--   The width and height of the image are set to their actual values.+loadImageEmb :: Num n => FilePath -> IO (Either String (DImage n Embedded))+loadImageEmb path = fmap embeddedImage `fmap` readImage path++-- | A pure variant of 'loadImageEmb'+loadImageEmbBS :: Num n => ByteString -> Either String (DImage n Embedded)+loadImageEmbBS bs = embeddedImage `fmap` decodeImage bs+ -- | Check that a file exists, and use JuicyPixels to figure out --   the right size, but save a reference to the image instead --   of the raster data-loadImageExt :: FilePath -> IO (Either String (DImage External))+loadImageExt :: Num n => FilePath -> IO (Either String (DImage n External)) loadImageExt path = do   dImg <- readImage path   return $ case dImg of@@ -110,16 +141,16 @@ -- | Make an "unchecked" image reference; have to specify a --   width and height. Unless the aspect ratio of the external --   image is the w :: h, then the image will be distorted.-uncheckedImageRef :: FilePath -> Int -> Int -> DImage External+uncheckedImageRef :: Num n => FilePath -> Int -> Int -> DImage n External uncheckedImageRef path w h = DImage (ImageRef path) w h mempty  -- | Crate a diagram from raw raster data.-rasterDia :: Renderable (DImage Embedded) b-          => (Int -> Int -> AlphaColour Double) -> Int -> Int -> Diagram b R2+rasterDia :: (TypeableFloat n, Renderable (DImage n Embedded) b)+          => (Int -> Int -> AlphaColour Double) -> Int -> Int -> QDiagram b V2 n Any rasterDia f w h = image $ raster f w h  -- | Create an image "from scratch" by specifying the pixel data-raster :: (Int -> Int -> AlphaColour Double) -> Int -> Int -> DImage Embedded+raster :: Num n => (Int -> Int -> AlphaColour Double) -> Int -> Int -> DImage n Embedded raster f w h = DImage (ImageRaster (ImageRGBA8 img)) w h mempty   where     img = generateImage g w h@@ -132,5 +163,6 @@     (r', g', b', a') = colorToSRGBA c     int x = round (255 * x) -instance Renderable (DImage a) NullBackend where+instance Fractional n => (Renderable (DImage n a) NullBackend) where   render _ _ = mempty+
src/Diagrams/TwoD/Model.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE TypeFamilies          #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Model@@ -9,7 +11,7 @@ -- Maintainer  :  diagrams-discuss@googlegroups.com -- -- Tools for visualizing diagrams' internal model: local origins,--- envelopes, /etc./+-- envelopes, traces, /etc./ -- ----------------------------------------------------------------------------- module Diagrams.TwoD.Model@@ -17,72 +19,155 @@          showOrigin        , showOrigin'        , OriginOpts(..), oColor, oScale, oMinSize++         -- * Showing an approximation of the envelope+       , showEnvelope+       , showEnvelope'+       , EnvelopeOpts(..), eColor, eLineWidth, ePoints++         -- * Showing an approximation of the trace+       , showTrace+       , showTrace'+       , TraceOpts(..), tColor, tScale, tMinSize, tPoints++         -- * Showing labels of all named subdiagrams        , showLabels        ) where -import           Control.Lens          (makeLenses, (^.))+import           Control.Arrow            (second)+import           Control.Lens             (makeLenses, (^.))+import           Data.Colour              (Colour)+import           Data.Colour.Names+import           Data.Default+import           Data.List                (intercalate)+import qualified Data.Map                 as M+import           Data.Maybe               (catMaybes)+import           Data.Semigroup +import           Diagrams.Attributes+import           Diagrams.Combinators     (atPoints) import           Diagrams.Core-import           Diagrams.TwoD.Attributes+import           Diagrams.Core.Names+import           Diagrams.CubicSpline import           Diagrams.Path+import           Diagrams.TwoD.Attributes import           Diagrams.TwoD.Ellipse import           Diagrams.TwoD.Path-import           Diagrams.TwoD.Size    (size2D) import           Diagrams.TwoD.Text+import           Diagrams.TwoD.Transform  (rotateBy) import           Diagrams.TwoD.Types+import           Diagrams.TwoD.Vector     (unitX) import           Diagrams.Util -import           Control.Arrow         (second)-import           Data.AffineSpace      ((.-.))-import           Data.Default.Class-import           Data.Semigroup-import           Data.VectorSpace      ((^*))--import qualified Data.Map              as M--import           Data.Colour           (Colour)-import           Data.Colour.Names+import           Linear.Affine+import           Linear.Vector  ------------------------------------------------------------ -- Marking the origin ------------------------------------------------------------ -data OriginOpts = OriginOpts { _oColor   :: Colour Double-                             , _oScale   :: Double-                             , _oMinSize :: Double-                             }+data OriginOpts n = OriginOpts+  { _oColor   :: Colour Double+  , _oScale   :: n+  , _oMinSize :: n+  }  makeLenses ''OriginOpts -instance Default OriginOpts where+instance Fractional n => Default (OriginOpts n) where   def = OriginOpts red (1/50) 0.001 +data EnvelopeOpts n = EnvelopeOpts+  { _eColor     :: Colour Double+  , _eLineWidth :: Measure n+  , _ePoints    :: Int+  }++makeLenses ''EnvelopeOpts++instance OrderedField n => Default (EnvelopeOpts n) where+  def = EnvelopeOpts red medium 32++data TraceOpts n = TraceOpts+  { _tColor   :: Colour Double+  , _tScale   :: n+  , _tMinSize :: n+  , _tPoints  :: Int+  }++makeLenses ''TraceOpts++instance Floating n => Default (TraceOpts n) where+  def = TraceOpts red (1/100) 0.001 64+ -- | Mark the origin of a diagram by placing a red dot 1/50th its size.-showOrigin :: (Renderable (Path R2) b, Backend b R2, Monoid' m)-           => QDiagram b R2 m -> QDiagram b R2 m+showOrigin :: (TypeableFloat n, Renderable (Path V2 n) b, Monoid' m)+           => QDiagram b V2 n m -> QDiagram b V2 n m showOrigin = showOrigin' def  -- | Mark the origin of a diagram, with control over colour and scale -- of marker dot.-showOrigin' :: (Renderable (Path R2) b, Backend b R2, Monoid' m)-           => OriginOpts -> QDiagram b R2 m -> QDiagram b R2 m+showOrigin' :: (TypeableFloat n, Renderable (Path V2 n) b, Monoid' m)+           => OriginOpts n -> QDiagram b V2 n m -> QDiagram b V2 n m showOrigin' oo d = o <> d-  where o     = stroke (circle sz)-                # fc (oo^.oColor)-                # lineWidth (Output 0)-                # fmap (const mempty)-        (w,h) = size2D d ^* oo^.oScale-        sz = maximum [w, h, oo^.oMinSize]+  where o      = strokeP (circle sz)+                   # fc (oo^.oColor)+                   # lw none+                   # fmap (const mempty)+        V2 w h = oo^.oScale *^ size d+        sz     = maximum [w, h, oo^.oMinSize] +-- | Mark the envelope with an approximating cubic spline with control +--   over the color, line width and number of points.+showEnvelope' :: (Enum n, TypeableFloat n, Renderable (Path V2 n) b) +              => EnvelopeOpts n -> QDiagram b V2 n Any -> QDiagram b V2 n Any+showEnvelope' opts d = cubicSpline True pts # lc (opts^.eColor)+                                            # lw w <> d+  where+    pts = catMaybes [envelopePMay v d | v <- map (`rotateBy` unitX) [0,inc..top]]+    w   = opts ^. eLineWidth+    inc = 1 / fromIntegral (opts^.ePoints)+    top = 1 - inc+++-- | Mark the envelope with an approximating cubic spline+--   using 32 points, medium line width and red line color.+showEnvelope :: (Enum n, TypeableFloat n, Renderable (Path V2 n) b)+             => QDiagram b V2 n Any -> QDiagram b V2 n Any+showEnvelope = showEnvelope' def++-- | Mark the trace of a diagram, with control over colour and scale+-- of marker dot and the number of points on the trace.+showTrace' :: (Enum n, TypeableFloat n, Renderable (Path V2 n) b) +          => TraceOpts n -> QDiagram b V2 n Any -> QDiagram b V2 n Any+showTrace' opts d =  atPoints ps (repeat pt) <> d+  where+    ps = concatMap p ts+    ts = zip rs vs+    p (r, v) = [origin .+^ (s *^ v) | s <- r]+    vs = map (`rotateBy` unitX) [0, inc..top]+    rs = [getSortedList $ (appTrace . getTrace) d origin v | v <- vs]+    pt = circle sz # fc (opts^.tColor) # lw none+    V2 w h = opts^.tScale *^ size d+    sz     = maximum [w, h, opts^.tMinSize]+    inc = 1 / fromIntegral (opts^.tPoints)+    top = 1 - inc++-- | Mark the trace of a diagram by placing 64 red dots 1/100th its size+--   along the trace.+showTrace :: (Enum n, TypeableFloat n, Renderable (Path V2 n) b) +          => QDiagram b V2 n Any -> QDiagram b V2 n Any+showTrace = showTrace' def+ ------------------------------------------------------------ -- Labeling named points ------------------------------------------------------------ -showLabels :: (Renderable Text b, Backend b R2, Semigroup m)-           => QDiagram b R2 m -> QDiagram b R2 Any+showLabels :: (TypeableFloat n, Renderable (Text n) b, Semigroup m)+           => QDiagram b V2 n m -> QDiagram b V2 n Any showLabels d =              ( mconcat-             . map (\(n,p) -> text (show n) # translate (p .-. origin))+             . map (\(n,p) -> text (simpleName n) # translate (p .-. origin))              . concatMap (\(n,ps) -> zip (repeat n) ps)              . (map . second . map) location              . M.assocs@@ -91,3 +176,5 @@              fmap (const (Any False)) d   where     SubMap m = d^.subMap+    simpleName (Name ns) = intercalate " .> " $ map simpleAName ns+    simpleAName (AName n) = show n
src/Diagrams/TwoD/Offset.hs view
@@ -1,8 +1,16 @@-{-# LANGUAGE GADTs            #-}-{-# LANGUAGE TemplateHaskell  #-}-{-# LANGUAGE TypeFamilies     #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ViewPatterns     #-}+{-# LANGUAGE ConstraintKinds      #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE GADTs                #-}+{-# LANGUAGE StandaloneDeriving   #-}+{-# LANGUAGE TemplateHaskell      #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns         #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Offset@@ -10,15 +18,15 @@ -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com ----- Compute offsets to segments in two dimensions.  More details can be --- found in the manual at --- <http://projects.haskell.org/diagrams/doc/manual.html#offsets-of-segments-trails-and-paths>.+-- Compute offsets to segments in two dimensions.  More details can be+-- found in the manual at+-- <https://diagrams.github.io/doc/manual.html#offsets-of-segments-trails-and-paths>. -- ----------------------------------------------------------------------------- module Diagrams.TwoD.Offset-    ( +    (       -- * Offsets-      +       offsetSegment      , OffsetOpts(..), offsetJoin, offsetMiterLimit, offsetEpsilon@@ -37,40 +45,44 @@      ) where -import Control.Applicative-import Control.Lens            hiding (at)+import           Control.Applicative+import           Control.Lens            hiding (at)+import           Prelude -import Data.AffineSpace-import Data.Maybe              (catMaybes)-import Data.Monoid-import Data.Monoid.Inf-import Data.VectorSpace+import           Data.Maybe              (catMaybes)+import           Data.Monoid+import           Data.Monoid.Inf -import Data.Default.Class+import           Data.Default -import Diagrams.Core+import           Diagrams.Core -import Diagrams.Attributes-import Diagrams.Located-import Diagrams.Parametric-import Diagrams.Path-import Diagrams.Segment-import Diagrams.Trail           hiding (offset, isLoop)-import Diagrams.TrailLike-import Diagrams.TwoD.Arc-import Diagrams.TwoD.Curvature-import Diagrams.TwoD.Path       ()-import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector     (perp, direction)+import           Diagrams.Attributes+import           Diagrams.Direction+import           Diagrams.Located+import           Diagrams.Parametric+import           Diagrams.Path+import           Diagrams.Segment+import           Diagrams.Trail          hiding (isLoop, offset)+import           Diagrams.TrailLike+import           Diagrams.TwoD.Arc+import           Diagrams.TwoD.Curvature+import           Diagrams.TwoD.Path      ()+import           Diagrams.TwoD.Types+import           Diagrams.TwoD.Vector    hiding (e) -unitPerp :: R2 -> R2-unitPerp = normalized . perp+import           Linear.Affine+import           Linear.Metric+import           Linear.Vector -perpAtParam :: Segment Closed R2 -> Double -> R2-perpAtParam   (Linear (OffsetClosed a))  _ = -unitPerp a-perpAtParam s@(Cubic _ _ _)              t = -unitPerp a+unitPerp :: OrderedField n => V2 n -> V2 n+unitPerp = signorm . perp++perpAtParam :: OrderedField n => Segment Closed V2 n -> n -> V2 n+perpAtParam (Linear (OffsetClosed a)) _ = negated $ unitPerp a+perpAtParam cubic t                     = negated $ unitPerp a   where-    (Cubic a _ _) = snd $ splitAtParam s t+    (Cubic a _ _) = snd $ splitAtParam cubic t  -- | Compute the offset of a segment.  Given a segment compute the offset --   curve that is a fixed distance from the original curve.  For linear@@ -101,59 +113,63 @@  -- | Options for specifying line join and segment epsilon for an offset --   involving multiple segments.-data OffsetOpts = OffsetOpts-    { _offsetJoin :: LineJoin-    , _offsetMiterLimit :: Double-    , _offsetEpsilon :: Double-    } deriving (Eq, Show)+data OffsetOpts d = OffsetOpts+    { _offsetJoin       :: LineJoin+    , _offsetMiterLimit :: d+    , _offsetEpsilon    :: d+    } +deriving instance Eq d => Eq (OffsetOpts d)+deriving instance Show d => Show (OffsetOpts d)+ makeLensesWith (lensRules & generateSignatures .~ False) ''OffsetOpts  -- | Specifies the style of join for between adjacent offset segments.-offsetJoin :: Lens' OffsetOpts LineJoin+offsetJoin :: Lens' (OffsetOpts d) LineJoin  -- | Specifies the miter limit for the join.-offsetMiterLimit :: Lens' OffsetOpts Double+offsetMiterLimit :: Lens' (OffsetOpts d) d  -- | Epsilon perimeter for 'offsetSegment'.-offsetEpsilon :: Lens' OffsetOpts Double+offsetEpsilon :: Lens' (OffsetOpts d) d  -- | The default offset options use the default 'LineJoin' ('LineJoinMiter'), a --   miter limit of 10, and epsilon factor of 0.01.-instance Default OffsetOpts where+instance Fractional d => Default (OffsetOpts d) where     def = OffsetOpts def 10 0.01  -- | Options for specifying how a 'Trail' should be expanded.-data ExpandOpts = ExpandOpts-    { _expandJoin :: LineJoin-    , _expandMiterLimit :: Double-    , _expandCap  :: LineCap-    , _expandEpsilon :: Double+data ExpandOpts d = ExpandOpts+    { _expandJoin       :: LineJoin+    , _expandMiterLimit :: d+    , _expandCap        :: LineCap+    , _expandEpsilon    :: d     } deriving (Eq, Show)  makeLensesWith (lensRules & generateSignatures .~ False) ''ExpandOpts  -- | Specifies the style of join for between adjacent offset segments.-expandJoin :: Lens' ExpandOpts LineJoin+expandJoin :: Lens' (ExpandOpts d) LineJoin  -- | Specifies the miter limit for the join.-expandMiterLimit :: Lens' ExpandOpts Double+expandMiterLimit :: Lens' (ExpandOpts d) d  -- | Specifies how the ends are handled.-expandCap :: Lens' ExpandOpts LineCap+expandCap :: Lens' (ExpandOpts d) LineCap  -- | Epsilon perimeter for 'offsetSegment'.-expandEpsilon :: Lens' ExpandOpts Double+expandEpsilon :: Lens' (ExpandOpts d) d    -- | The default 'ExpandOpts' is the default 'LineJoin' ('LineJoinMiter'), --   miter limit of 10, default 'LineCap' ('LineCapButt'), and epsilon factor --   of 0.01.-instance Default ExpandOpts where+instance (Fractional d) => Default (ExpandOpts d) where     def = ExpandOpts def 10 def 0.01 -offsetSegment :: Double     -- ^ Epsilon factor that when multiplied to the+offsetSegment :: RealFloat n+              => n   -- ^ Epsilon factor that when multiplied to the                             --   absolute value of the radius gives a                             --   value that represents the maximum                             --   allowed deviation from the true offset.  In@@ -161,20 +177,20 @@                             --   should be bounded by arcs that are plus or                             --   minus epsilon factor from the radius of curvature of                             --   the offset.-              -> Double     -- ^ Offset from the original segment, positive is+              -> n   -- ^ Offset from the original segment, positive is                             --   on the right of the curve, negative is on the                             --   left.-              -> Segment Closed R2  -- ^ Original segment-              -> Located (Trail R2) -- ^ Resulting located (at the offset) trail.+              -> Segment Closed V2 n  -- ^ Original segment+              -> Located (Trail V2 n) -- ^ Resulting located (at the offset) trail. offsetSegment _       r s@(Linear (OffsetClosed a))    = trailFromSegments [s] `at` origin .+^ va-  where va = -r *^ unitPerp a+  where va = (-r) *^ unitPerp a  offsetSegment epsilon r s@(Cubic a b (OffsetClosed c)) = t `at` origin .+^ va   where     t = trailFromSegments (go (radiusOfCurvature s 0.5))     -- Perpendiculars to handles.-    va = -r *^ unitPerp a-    vc = -r *^ unitPerp (c ^-^ b)+    va = (-r) *^ unitPerp a+    vc = (-r) *^ unitPerp (c ^-^ b)     -- Split segments.     ss = (\(x,y) -> [x,y]) $ splitAtParam s 0.5     subdivided = concatMap (trailSegments . unLoc . offsetSegment epsilon r) ss@@ -198,7 +214,7 @@               Infinity  -> 1          -- Do the right thing.               Finite sr -> 1 + r / sr -        close = and [epsilon * abs r > (magnitude (p o ^+^ va ^-^ p s ^-^ pp s))+        close = and [epsilon * abs r > norm (p o ^+^ va ^-^ p s ^-^ pp s)                     | t' <- [0.25, 0.5, 0.75]                     , let p = (`atParam` t')                     , let pp = (r *^) . (`perpAtParam` t')@@ -207,16 +223,16 @@  -- > import Diagrams.TwoD.Offset -- >--- > showExample :: Segment Closed R2 -> Diagram SVG R2+-- > showExample :: Segment Closed V2 Double -> Diagram SVG -- > showExample s = pad 1.1 . centerXY $ d # lc blue # lw thick <> d' # lw thick -- >   where--- >       d  = stroke . fromSegments $ [s]--- >       d' = mconcat . zipWith lc colors . map stroke . explodeTrail+-- >       d  = strokeP . fromSegments $ [s]+-- >       d' = mconcat . zipWith lc colors . map strokeP . explodeTrail -- >          $ offsetSegment 0.1 (-1) s -- > -- >       colors = cycle [green, red] -- >--- > cubicOffsetExample :: Diagram SVG R2+-- > cubicOffsetExample :: Diagram SVG -- > cubicOffsetExample = hcat . map showExample $ -- >         [ bezier3 (10 ^&  0) (  5  ^& 18) (10 ^& 20) -- >         , bezier3 ( 0 ^& 20) ( 10  ^& 10) ( 5 ^& 10)@@ -229,16 +245,16 @@ -- collapse the Located into the result.  This assumes that Located has the -- meaning of merely taking something that cannot be translated and lifting -- it into a space with translation.-bindLoc :: (Transformable b, V a ~ V b) => (a -> b) -> Located a -> b+bindLoc :: (Transformable b, V a ~ V b, N a ~ N b, V a ~ V2, N a ~ n, Num n) => (a -> b) -> Located a -> b bindLoc f = join' . mapLoc f   where     join' (viewLoc -> (p,a)) = translate (p .-. origin) a --- While we build offsets and expansions we will use the [Located (Segment Closed R2)]--- and [Located (Trail R2)] intermediate representations.-locatedTrailSegments :: (InnerSpace v, OrderedField (Scalar v))-                     => Located (Trail v) -> [Located (Segment Closed v)]-locatedTrailSegments t = zipWith at (trailSegments (unLoc t)) (trailVertices t)+-- While we build offsets and expansions we will use the [Located (Segment Closed v)]+-- and [Located (Trail V2 n)] intermediate representations.+locatedTrailSegments :: OrderedField n+                     => Located (Trail V2 n) -> [Located (Segment Closed V2 n)]+locatedTrailSegments t = zipWith at (trailSegments (unLoc t)) (trailPoints t)  -- | Offset a 'Trail' with options and by a given radius.  This generates a new --   trail that is always radius 'r' away from the given 'Trail' (depending on@@ -258,46 +274,47 @@ -- --   <<diagrams/src_Diagrams_TwoD_Offset_offsetTrailOuterExample.svg#diagram=offsetTrailOuterExample&width=300>> ---offsetTrail' :: OffsetOpts-             -> Double  -- ^ Radius of offset.  A negative value gives an offset on-                        --   the left for a line and on the inside for a counter-clockwise-                        --   loop.-             -> Located (Trail R2)-             -> Located (Trail R2)+offsetTrail' :: RealFloat n+             => OffsetOpts n+             -> n -- ^ Radius of offset.  A negative value gives an offset on+                         --   the left for a line and on the inside for a counter-clockwise+                         --   loop.+             -> Located (Trail V2 n)+             -> Located (Trail V2 n) offsetTrail' opts r t = joinSegments eps j isLoop (opts^.offsetMiterLimit) r ends . offset $ t     where       eps = opts^.offsetEpsilon       offset = map (bindLoc (offsetSegment eps r)) . locatedTrailSegments-      ends | isLoop    = (\(a:as) -> as ++ [a]) . trailVertices $ t-           | otherwise = tail . trailVertices $ t+      ends | isLoop    = (\(a:as) -> as ++ [a]) . trailPoints $ t+           | otherwise = tail . trailPoints $ t       j = fromLineJoin (opts^.offsetJoin)        isLoop = withTrail (const False) (const True) (unLoc t)  -- | Offset a 'Trail' with the default options and a given radius.  See 'offsetTrail''.-offsetTrail :: Double -> Located (Trail R2) -> Located (Trail R2)+offsetTrail :: RealFloat n => n -> Located (Trail V2 n) -> Located (Trail V2 n) offsetTrail = offsetTrail' def  -- | Offset a 'Path' by applying 'offsetTrail'' to each trail in the path.-offsetPath' :: OffsetOpts -> Double -> Path R2 -> Path R2+offsetPath' :: RealFloat n => OffsetOpts n -> n -> Path V2 n -> Path V2 n offsetPath' opts r = mconcat                    . map (bindLoc (trailLike . offsetTrail' opts r) . (`at` origin))                    . op Path  -- | Offset a 'Path' with the default options and given radius.  See 'offsetPath''.-offsetPath :: Double -> Path R2 -> Path R2+offsetPath :: RealFloat n => n -> Path V2 n -> Path V2 n offsetPath = offsetPath' def  -- TODO: Include arrowheads on examples to indicate direction so the "left" and -- "right" make sense. -- -- > import Diagrams.TwoD.Offset--- > import Data.Default.Class+-- > import Data.Default -- >--- > corner :: Located (Trail R2)+-- > corner :: (OrderedField n) => Located (Trail V2 n) -- > corner = fromVertices (map p2 [(0, 0), (10, 0), (5, 6)]) `at` origin -- >--- > offsetTrailExample :: Diagram SVG R2+-- > offsetTrailExample :: Diagram SVG -- > offsetTrailExample = pad 1.1 . centerXY . lwO 3 . hcat' (def & sep .~ 1 ) -- >                    . map (uncurry showStyle) -- >                    $ [ (LineJoinMiter, "LineJoinMiter")@@ -309,7 +326,7 @@ -- >               <> trailLike (offsetTrail' (def & offsetJoin .~ j) 2 corner) # lc green) -- >            === (strutY 3 <> text s # font "Helvetica" # bold) -- >--- > offsetTrailLeftExample :: Diagram SVG R2+-- > offsetTrailLeftExample :: Diagram SVG -- > offsetTrailLeftExample = pad 1.1 . centerXY . lwO 3 -- >                        $ (trailLike c # lc blue) -- >                        <> (lc green . trailLike@@ -317,7 +334,7 @@ -- >   where -- >     c = reflectY corner -- >--- > offsetTrailOuterExample :: Diagram SVG R2+-- > offsetTrailOuterExample :: Diagram SVG -- > offsetTrailOuterExample = pad 1.1 . centerXY . lwO 3 -- >                         $ (trailLike c # lc blue) -- >                         <> (lc green . trailLike@@ -325,7 +342,7 @@ -- >   where -- >     c = hexagon 5 -withTrailL :: (Located (Trail' Line v) -> r) -> (Located (Trail' Loop v) -> r) -> Located (Trail v) -> r+withTrailL :: (Located (Trail' Line V2 n) -> r) -> (Located (Trail' Loop V2 n) -> r) -> Located (Trail V2 n) -> r withTrailL f g l = withTrail (f . (`at` p)) (g . (`at` p)) (unLoc l)   where     p = loc l@@ -343,57 +360,58 @@ -- --   <<diagrams/src_Diagrams_TwoD_Offset_expandLoopExample.svg#diagram=expandLoopExample&width=300>> ---expandTrail' :: ExpandOpts-             -> Double  -- ^ Radius of offset.  Only non-negative values allowed.+expandTrail' :: (OrderedField n, RealFloat n, RealFrac n)+             => ExpandOpts n+             -> n  -- ^ Radius of offset.  Only non-negative values allowed.                         --   For a line this gives a loop of the offset.  For a                         --   loop this gives two loops, the outer counter-clockwise                         --   and the inner clockwise.-             -> Located (Trail R2)-             -> Path R2+             -> Located (Trail V2 n)+             -> Path V2 n expandTrail' o r t   | r < 0     = error "expandTrail' with negative radius"                 -- TODO: consider just reversing the path instead of this error.   | otherwise = withTrailL (pathFromLocTrail . expandLine o r) (expandLoop o r) t -expandLine :: ExpandOpts -> Double -> Located (Trail' Line R2) -> Located (Trail R2)+expandLine :: RealFloat n => ExpandOpts n -> n -> Located (Trail' Line V2 n) -> Located (Trail V2 n) expandLine opts r (mapLoc wrapLine -> t) = caps cap r s e (f r) (f $ -r)     where       eps = opts^.expandEpsilon       offset r' = map (bindLoc (offsetSegment eps r')) . locatedTrailSegments-      f r' = joinSegments eps (fromLineJoin (opts^.expandJoin)) False (opts^.expandMiterLimit) r' ends +      f r' = joinSegments eps (fromLineJoin (opts^.expandJoin)) False (opts^.expandMiterLimit) r' ends            . offset r' $ t-      ends = tail . trailVertices $ t+      ends = tail . trailPoints $ t       s = atStart t       e = atEnd t       cap = fromLineCap (opts^.expandCap) -expandLoop :: ExpandOpts -> Double -> Located (Trail' Loop R2) -> Path R2-expandLoop opts r (mapLoc wrapLoop -> t) = (trailLike $ f r) <> (trailLike . reverseDomain . f $ -r)+expandLoop :: RealFloat n => ExpandOpts n -> n -> Located (Trail' Loop V2 n) -> Path V2 n+expandLoop opts r (mapLoc wrapLoop -> t) = trailLike (f r) <> (trailLike . reverseDomain . f $ -r)     where       eps = opts^.expandEpsilon       offset r' = map (bindLoc (offsetSegment eps r')) . locatedTrailSegments-      f r' = joinSegments eps (fromLineJoin (opts^.expandJoin)) True (opts^.expandMiterLimit) r' ends +      f r' = joinSegments eps (fromLineJoin (opts^.expandJoin)) True (opts^.expandMiterLimit) r' ends            . offset r' $ t-      ends = (\(a:as) -> as ++ [a]) . trailVertices $ t+      ends = (\(a:as) -> as ++ [a]) . trailPoints $ t  -- | Expand a 'Trail' with the given radius and default options.  See 'expandTrail''.-expandTrail :: Double -> Located (Trail R2) -> Path R2+expandTrail :: RealFloat n => n -> Located (Trail V2 n) -> Path V2 n expandTrail = expandTrail' def  -- | Expand a 'Path' using 'expandTrail'' on each trail in the path.-expandPath' :: ExpandOpts -> Double -> Path R2 -> Path R2+expandPath' :: RealFloat n => ExpandOpts n -> n -> Path V2 n -> Path V2 n expandPath' opts r = mconcat                    . map (bindLoc (expandTrail' opts r) . (`at` origin))                    . op Path  -- | Expand a 'Path' with the given radius and default options.  See 'expandPath''.-expandPath :: Double -> Path R2 -> Path R2+expandPath :: RealFloat n => n -> Path V2 n -> Path V2 n expandPath = expandPath' def  -- > import Diagrams.TwoD.Offset--- > import Data.Default.Class+-- > import Data.Default -- >--- > expandTrailExample :: Diagram SVG R2+-- > expandTrailExample :: Diagram SVG -- > expandTrailExample = pad 1.1 . centerXY . hcat' (def & sep .~ 1) -- >                    . map (uncurry showStyle) -- >                    $ [ (LineCapButt,   "LineCapButt")@@ -409,7 +427,7 @@ -- >                                      # lw none # fc green) -- >               === (strutY 3 <> text s # font "Helvetica" # bold) -- >--- > expandLoopExample :: Diagram SVG R2+-- > expandLoopExample :: Diagram SVG -- > expandLoopExample = pad 1.1 . centerXY $ ((strokeLocT t # lw veryThick # lc white) -- >                                        <> (stroke t' # lw none # fc green)) -- >   where@@ -426,8 +444,8 @@ --   caps  takes the radius and the start and end points of the original line and --   the offset trails going out and coming back.  The result is a new list of --   trails with the caps included.-caps :: (Double -> P2 -> P2 -> P2 -> Trail R2)-     -> Double -> P2 -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Located (Trail R2)+caps :: RealFloat n => (n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n)+     -> n -> Point V2 n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Located (Trail V2 n) caps cap r s e fs bs = mapLoc glueTrail $ mconcat     [ cap r s (atStart bs) (atStart fs)     , unLoc fs@@ -436,37 +454,29 @@     ] `at` atStart bs  -- | Take a LineCap style and give a function for building the cap from-fromLineCap :: LineCap -> Double -> P2 -> P2 -> P2 -> Trail R2+fromLineCap :: RealFloat n => LineCap -> n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n fromLineCap c = case c of     LineCapButt   -> capCut     LineCapRound  -> capArc     LineCapSquare -> capSquare  -- | Builds a cap that directly connects the ends.-capCut :: Double -> P2 -> P2 -> P2 -> Trail R2+capCut :: RealFloat n => n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n capCut _r _c a b = fromSegments [straight (b .-. a)]  -- | Builds a cap with a square centered on the end.-capSquare :: Double -> P2 -> P2 -> P2 -> Trail R2+capSquare :: RealFloat n => n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n capSquare _r c a b = unLoc $ fromVertices [ a, a .+^ v, b .+^ v, b ]   where     v = perp (a .-. c)  -- | Builds an arc to fit with a given radius, center, start, and end points. --   A Negative r means a counter-clockwise arc-capArc :: Double -> P2 -> P2 -> P2 -> Trail R2+capArc :: RealFloat n => n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n capArc r c a b = trailLike . moveTo c $ fs   where-    fs | r < 0     = scale (-r) $ arcVCW (a .-. c) (b .-. c)-       | otherwise = scale r    $ arcV   (a .-. c) (b .-. c)---- Arc helpers-arcV :: (TrailLike t, V t ~ R2) => R2 -> R2 -> t-arcV u v = arc (direction u) (direction v)--arcVCW :: (TrailLike t, V t ~ R2) => R2 -> R2 -> t-arcVCW u v = arcCW (direction u) (direction v)-+    fs | r < 0     = scale (-r) $ arcCW  (dirBetween c a) (dirBetween c b)+       | otherwise = scale r    $ arcCCW (dirBetween c a) (dirBetween c b)  -- | Join together a list of located trails with the given join style.  The --   style is given as a function to compute the join given the local information@@ -476,14 +486,15 @@ --   Note: this is not a general purpose join and assumes that we are joining an --   offset trail.  For instance, a fixed radius arc will not fit between arbitrary --   trails without trimming or extending.-joinSegments :: Double-             -> (Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2)+joinSegments :: RealFloat n+             => n+             -> (n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n)              -> Bool-             -> Double-             -> Double-             -> [Point R2]-             -> [Located (Trail R2)]-             -> Located (Trail R2)+             -> n+             -> n+             -> [Point V2 n]+             -> [Located (Trail V2 n)]+             -> Located (Trail V2 n) joinSegments _ _ _ _ _ _ [] = mempty `at` origin joinSegments _ _ _ _ _ [] _ = mempty `at` origin joinSegments epsilon j isLoop ml r es ts@(t:_) = t'@@ -498,7 +509,7 @@  -- | Take a join style and give the join function to be used by joinSegments. fromLineJoin-  :: LineJoin -> Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2+  :: RealFloat n => LineJoin -> n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n fromLineJoin j = case j of     LineJoinMiter -> joinSegmentIntersect     LineJoinRound -> joinSegmentArc@@ -508,7 +519,7 @@ -- how useful it is graphically, I mostly had it as it was useful for debugging {- -- | Join with segments going back to the original corner.-joinSegmentCut :: Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2+joinSegmentCut :: (OrderedField n) => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n joinSegmentCut _ _ e a b = fromSegments     [ straight (e .-. atEnd a)     , straight (atStart b .-. e)@@ -518,19 +529,21 @@ -- | Join by directly connecting the end points.  On an inside corner this --   creates negative space for even-odd fill.  Here is where we would want to --   use an arc or something else in the future.-joinSegmentClip :: Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2+joinSegmentClip :: RealFloat n+  => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n joinSegmentClip _ _ _ a b = fromSegments [straight $ atStart b .-. atEnd a]  -- | Join with a radius arc.  On an inside corner this will loop around the interior --   of the offset trail.  With a winding fill this will not be visible.-joinSegmentArc :: Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2+joinSegmentArc :: RealFloat n+  => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n joinSegmentArc _ r e a b = capArc r e (atEnd a) (atStart b)  -- | Join to the intersection of the incoming trails projected tangent to their ends. --   If the intersection is beyond the miter limit times the radius, stop at the limit. joinSegmentIntersect-    :: Double -> Double -> P2 -> Located (Trail R2) -> Located (Trail R2) -> Trail R2-joinSegmentIntersect miterLimit r e a b = +    :: RealFloat n => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n+joinSegmentIntersect miterLimit r e a b =     if cross < 0.000001       then clip       else case traceP pa va t of@@ -545,10 +558,9 @@   where     t = straight (miter vb) `at` pb     va = unitPerp (pa .-. e)-    vb = -unitPerp (pb .-. e)+    vb = negated $ unitPerp (pb .-. e)     pa = atEnd a     pb = atStart b-    miter v = (abs (miterLimit * r)) *^ v+    miter v = abs (miterLimit * r) *^ v     clip = joinSegmentClip miterLimit r e a b     cross = let (xa,ya) = unr2 va; (xb,yb) = unr2 vb in abs (xa * yb - xb * ya)-
src/Diagrams/TwoD/Path.hs view
@@ -1,17 +1,23 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-} {-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE Rank2Types                 #-}+{-# LANGUAGE StandaloneDeriving         #-} {-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}+ {-# OPTIONS_GHC -fno-warn-orphans #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Path--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -23,54 +29,66 @@ -----------------------------------------------------------------------------  module Diagrams.TwoD.Path-       ( -- * Constructing path-based diagrams+  ( -- * Constructing path-based diagrams -         stroke, stroke', strokeTrail, strokeT, strokeTrail', strokeT'-       , strokeLine, strokeLoop-       , strokeLocTrail, strokeLocT, strokeLocLine, strokeLocLoop+    stroke, stroke'+  , strokePath, strokeP, strokePath', strokeP'+  , strokeTrail, strokeT, strokeTrail', strokeT'+  , strokeLine, strokeLoop+  , strokeLocTrail, strokeLocT, strokeLocLine, strokeLocLoop -         -- ** Stroke options+    -- ** Stroke options -       , FillRule(..)-       , FillRuleA(..), getFillRule, fillRule-       , StrokeOpts(..), vertexNames, queryFillRule+  , FillRule(..)+  , getFillRule, fillRule, _fillRule+  , StrokeOpts(..), vertexNames, queryFillRule -         -- ** Inside/outside testing+    -- ** Inside/outside testing -       , isInsideWinding, isInsideEvenOdd+  , Crossings (..)+  , isInsideWinding+  , isInsideEvenOdd -         -- * Clipping+    -- * Clipping -       , Clip(..), clipBy, clipTo, clipped-       ) where+  , Clip(..), _Clip, _clip+  , clipBy, clipTo, clipped -import           Control.Applicative   (liftA2)-import           Control.Lens          (Lens, Lens', generateSignatures,-                                        lensRules, makeLensesWith, makeWrapped,-                                        op, (.~), (^.), _Wrapped')-import qualified Data.Foldable         as F+    -- * Intersections++  , intersectPoints, intersectPoints'+  , intersectPointsP, intersectPointsP'+  , intersectPointsT, intersectPointsT'+  ) where++import           Control.Applicative       (liftA2)+import           Control.Lens              hiding (at, transform)+import qualified Data.Foldable             as F import           Data.Semigroup import           Data.Typeable -import           Data.AffineSpace-import           Data.Default.Class-import           Data.VectorSpace+import           Data.Default -import           Diagrams.Combinators  (withEnvelope, withTrace)-import           Diagrams.Coordinates+import           Diagrams.Angle+import           Diagrams.Combinators      (withEnvelope, withTrace) import           Diagrams.Core import           Diagrams.Core.Trace-import           Diagrams.Located      (Located, mapLoc, unLoc)+import           Diagrams.Located          (Located, mapLoc, unLoc) import           Diagrams.Parametric import           Diagrams.Path+import           Diagrams.Query import           Diagrams.Segment-import           Diagrams.Solve+import           Diagrams.Solve.Polynomial import           Diagrams.Trail import           Diagrams.TrailLike-import           Diagrams.TwoD.Segment ()+import           Diagrams.TwoD.Segment import           Diagrams.TwoD.Types-import           Diagrams.Util         (tau)+import           Diagrams.TwoD.Vector+import           Diagrams.Util             (tau) +import           Linear.Affine+import           Linear.Vector+ ------------------------------------------------------------ --  Trail and path traces  --------------------------------- ------------------------------------------------------------@@ -79,14 +97,14 @@  -- XXX can the efficiency of this be improved?  See the comment in -- Diagrams.Path on the Enveloped instance for Trail.-instance Traced (Trail R2) where+instance RealFloat n => Traced (Trail V2 n) where   getTrace = withLine $       foldr-        (\seg bds -> moveOriginBy (negateV . atEnd $ seg) bds <> getTrace seg)+        (\seg bds -> moveOriginBy (negated . atEnd $ seg) bds <> getTrace seg)         mempty     . lineSegments -instance Traced (Path R2) where+instance RealFloat n => Traced (Path V2 n) where   getTrace = F.foldMap getTrace . op Path  ------------------------------------------------------------@@ -95,17 +113,21 @@  -- | Enumeration of algorithms or \"rules\" for determining which --   points lie in the interior of a (possibly self-intersecting)---   closed path.-data FillRule = Winding  -- ^ Interior points are those with a nonzero-                         --   /winding/ /number/.  See-                         --   <http://en.wikipedia.org/wiki/Nonzero-rule>.-              | EvenOdd  -- ^ Interior points are those where a ray-                         --   extended infinitely in a particular-                         --   direction crosses the path an odd number-                         --   of times. See-                         --   <http://en.wikipedia.org/wiki/Even-odd_rule>.-    deriving (Eq, Show)+--   path.+data FillRule+  = Winding  -- ^ Interior points are those with a nonzero+             --   /winding/ /number/.  See+             --   <http://en.wikipedia.org/wiki/Nonzero-rule>.+  | EvenOdd  -- ^ Interior points are those where a ray+             --   extended infinitely in a particular direction crosses+             --   the path an odd number of times. See+             --   <http://en.wikipedia.org/wiki/Even-odd_rule>.+    deriving (Show, Typeable, Eq, Ord) +instance AttributeClass FillRule+instance Semigroup FillRule where+  _ <> b = b+ instance Default FillRule where   def = Winding @@ -132,14 +154,13 @@ -- --   The default value is the empty list. -vertexNames :: forall a a'. Lens (StrokeOpts a) (StrokeOpts a') [[a]] [[a']]+vertexNames :: Lens (StrokeOpts a) (StrokeOpts a') [[a]] [[a']]  -- | The fill rule used for determining which points are inside the path. --   The default is 'Winding'.  NOTE: for now, this only affects the resulting --   diagram's 'Query', /not/ how it will be drawn!  To set the fill rule --   determining how it is to be drawn, use the 'fillRule' function.-queryFillRule :: forall a. Lens' (StrokeOpts a) FillRule-+queryFillRule :: Lens' (StrokeOpts a) FillRule  instance Default (StrokeOpts a) where   def = StrokeOpts@@ -147,35 +168,54 @@         , _queryFillRule = def         } --- | Convert a path into a diagram.  The resulting diagram has the+-- | Convert a 'ToPath' object into a diagram.  The resulting diagram has the --   names 0, 1, ... assigned to each of the path's vertices. -- --   See also 'stroke'', which takes an extra options record allowing---   its behavior to be customized.+--   its behaviour to be customized. -----   Note that a bug in GHC 7.0.1 causes a context stack overflow when---   inferring the type of @stroke@.  The solution is to give a type---   signature to expressions involving @stroke@, or (recommended)---   upgrade GHC (the bug is fixed in 7.0.2 onwards).-stroke :: Renderable (Path R2) b-       => Path R2 -> Diagram b R2-stroke = stroke' (def :: StrokeOpts ())--instance Renderable (Path R2) b => TrailLike (QDiagram b R2 Any) where-  trailLike = stroke . trailLike+-- @+-- 'stroke' :: 'Path' 'V2' 'Double'                  -> 'Diagram' b+-- 'stroke' :: 'Located' ('Trail' 'V2' 'Double')       -> 'Diagram' b+-- 'stroke' :: 'Located' ('Trail'' 'Loop' 'V2' 'Double') -> 'Diagram' b+-- 'stroke' :: 'Located' ('Trail'' 'Line' 'V2' 'Double') -> 'Diagram' b+-- @+stroke :: (InSpace V2 n t, ToPath t, TypeableFloat n, Renderable (Path V2 n) b)+       => t -> QDiagram b V2 n Any+stroke = strokeP . toPath  -- | A variant of 'stroke' that takes an extra record of options to---   customize its behavior.  In particular:+--   customize its behaviour.  In particular: -- --     * Names can be assigned to the path's vertices -- --   'StrokeOpts' is an instance of 'Default', so @stroke' ('with' & --   ... )@ syntax may be used.-stroke' :: (Renderable (Path R2) b, IsName a) => StrokeOpts a -> Path R2 -> Diagram b R2-stroke' opts path-  | null (pLines ^. _Wrapped') =           mkP pLoops+stroke' :: (InSpace V2 n t, ToPath t, TypeableFloat n, Renderable (Path V2 n) b, IsName a)+       => StrokeOpts a -> t -> QDiagram b V2 n Any+stroke' opts = strokeP' opts . toPath++-- | 'stroke' specialised to 'Path'.+strokeP :: (TypeableFloat n, Renderable (Path V2 n) b)+        => Path V2 n -> QDiagram b V2 n Any+strokeP = strokeP' (def :: StrokeOpts ())++-- | 'stroke' specialised to 'Path'.+strokePath :: (TypeableFloat n, Renderable (Path V2 n) b)+        => Path V2 n -> QDiagram b V2 n Any+strokePath = strokeP++instance (TypeableFloat n, Renderable (Path V2 n) b)+    => TrailLike (QDiagram b V2 n Any) where+  trailLike = strokeP . trailLike++-- | 'stroke'' specialised to 'Path'.+strokeP' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)+    => StrokeOpts a -> Path V2 n -> QDiagram b V2 n Any+strokeP' opts path+  | null (pLines ^. _Wrapped') = mkP pLoops   | null (pLoops ^. _Wrapped') = mkP pLines-  | otherwise                   = mkP pLines <> mkP pLoops+  | otherwise                  = mkP pLines <> mkP pLoops   where     (pLines,pLoops) = partitionPath (isLine . unLoc) path     mkP p@@ -185,134 +225,176 @@          (fromNames . concat $            zipWith zip (opts^.vertexNames) ((map . map) subPoint (pathVertices p))          )-         (Query $ Any . flip (runFillRule (opts^.queryFillRule)) p)+         (Query $ Any . (runFillRule (opts^.queryFillRule)) p) +-- | 'stroke'' specialised to 'Path'.+strokePath' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)+    => StrokeOpts a -> Path V2 n -> QDiagram b V2 n Any+strokePath' = strokeP' --- | A composition of 'stroke' and 'pathFromTrail' for conveniently---   converting a trail directly into a diagram.------   Note that a bug in GHC 7.0.1 causes a context stack overflow when---   inferring the type of 'stroke' and hence of @strokeTrail@ as well.---   The solution is to give a type signature to expressions involving---   @strokeTrail@, or (recommended) upgrade GHC (the bug is fixed in 7.0.2---   onwards).-strokeTrail :: (Renderable (Path R2) b) => Trail R2 -> Diagram b R2+-- | 'stroke' specialised to 'Trail'.+strokeTrail :: (TypeableFloat n, Renderable (Path V2 n) b)+            => Trail V2 n -> QDiagram b V2 n Any strokeTrail = stroke . pathFromTrail --- | Deprecated synonym for 'strokeTrail'.-strokeT :: (Renderable (Path R2) b) => Trail R2 -> Diagram b R2+-- | 'stroke' specialised to 'Trail'.+strokeT :: (TypeableFloat n, Renderable (Path V2 n) b)+        => Trail V2 n -> QDiagram b V2 n Any strokeT = strokeTrail  -- | A composition of 'stroke'' and 'pathFromTrail' for conveniently --   converting a trail directly into a diagram.-strokeTrail' :: (Renderable (Path R2) b, IsName a)-             => StrokeOpts a -> Trail R2 -> Diagram b R2+strokeTrail' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)+             => StrokeOpts a -> Trail V2 n -> QDiagram b V2 n Any strokeTrail' opts = stroke' opts . pathFromTrail  -- | Deprecated synonym for 'strokeTrail''.-strokeT' :: (Renderable (Path R2) b, IsName a)-         => StrokeOpts a -> Trail R2 -> Diagram b R2+strokeT' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)+         => StrokeOpts a -> Trail V2 n -> QDiagram b V2 n Any strokeT' = strokeTrail'  -- | A composition of 'strokeT' and 'wrapLine' for conveniently --   converting a line directly into a diagram.-strokeLine :: (Renderable (Path R2) b) => Trail' Line R2 -> Diagram b R2+strokeLine :: (TypeableFloat n, Renderable (Path V2 n) b)+           => Trail' Line V2 n -> QDiagram b V2 n Any strokeLine = strokeT . wrapLine  -- | A composition of 'strokeT' and 'wrapLoop' for conveniently --   converting a loop directly into a diagram.-strokeLoop :: (Renderable (Path R2) b) => Trail' Loop R2 -> Diagram b R2+strokeLoop :: (TypeableFloat n, Renderable (Path V2 n) b)+           => Trail' Loop V2 n -> QDiagram b V2 n Any strokeLoop = strokeT . wrapLoop  -- | A convenience function for converting a @Located Trail@ directly --   into a diagram; @strokeLocTrail = stroke . trailLike@.-strokeLocTrail :: (Renderable (Path R2) b) => Located (Trail R2) -> Diagram b R2-strokeLocTrail = stroke . trailLike+strokeLocTrail :: (TypeableFloat n, Renderable (Path V2 n) b)+               => Located (Trail V2 n) -> QDiagram b V2 n Any+strokeLocTrail = strokeP . trailLike  -- | Deprecated synonym for 'strokeLocTrail'.-strokeLocT :: (Renderable (Path R2) b) => Located (Trail R2) -> Diagram b R2+strokeLocT :: (TypeableFloat n, Renderable (Path V2 n) b)+           => Located (Trail V2 n) -> QDiagram b V2 n Any strokeLocT = strokeLocTrail  -- | A convenience function for converting a @Located@ line directly --   into a diagram; @strokeLocLine = stroke . trailLike . mapLoc wrapLine@.-strokeLocLine :: (Renderable (Path R2) b) => Located (Trail' Line R2) -> Diagram b R2-strokeLocLine = stroke . trailLike . mapLoc wrapLine+strokeLocLine :: (TypeableFloat n, Renderable (Path V2 n) b)+              => Located (Trail' Line V2 n) -> QDiagram b V2 n Any+strokeLocLine = strokeP . trailLike . mapLoc wrapLine  -- | A convenience function for converting a @Located@ loop directly --   into a diagram; @strokeLocLoop = stroke . trailLike . mapLoc wrapLoop@.-strokeLocLoop :: (Renderable (Path R2) b) => Located (Trail' Loop R2) -> Diagram b R2-strokeLocLoop = stroke . trailLike . mapLoc wrapLoop+strokeLocLoop :: (TypeableFloat n, Renderable (Path V2 n) b)+              => Located (Trail' Loop V2 n) -> QDiagram b V2 n Any+strokeLocLoop = strokeP . trailLike . mapLoc wrapLoop  ------------------------------------------------------------ --  Inside/outside testing ------------------------------------------------------------ ---runFillRule :: FillRule -> P2 -> Path R2 -> Bool+runFillRule :: RealFloat n => FillRule -> Path V2 n -> Point V2 n -> Bool runFillRule Winding = isInsideWinding runFillRule EvenOdd = isInsideEvenOdd -newtype FillRuleA = FillRuleA (Last FillRule)-  deriving (Typeable, Semigroup, Show)-instance AttributeClass FillRuleA--instance Default FillRuleA where-  def = FillRuleA $ Last $ def- -- | Extract the fill rule from a 'FillRuleA' attribute.-getFillRule :: FillRuleA -> FillRule-getFillRule (FillRuleA (Last r)) = r+getFillRule :: FillRule -> FillRule+getFillRule = id  -- | Specify the fill rule that should be used for determining which --   points are inside a path. fillRule :: HasStyle a => FillRule -> a -> a-fillRule = applyAttr . FillRuleA . Last+fillRule = applyAttr -cross :: R2 -> R2 -> Double-cross (coords -> x :& y) (coords -> x' :& y') = x * y' - y * x'+-- | Lens onto the fill rule of a style.+_fillRule :: Lens' (Style V2 n) FillRule+_fillRule = atAttr . non def --- XXX link to more info on this+-- | The sum of /signed/ crossings of a path as we travel in the+--   positive x direction from a given point.+--+--     - A point is filled according to the 'Winding' fill rule, if the+--       number of 'Crossings' is non-zero (see 'isInsideWinding').+--+--     - A point is filled according to the 'EvenOdd' fill rule, if the+--       number of 'Crossings' is odd (see 'isInsideEvenOdd').+--+--   This is the 'HasQuery' result for 'Path's, 'Located' 'Trail's and+--   'Located' 'Loops'.+--+-- @+-- 'sample' :: 'Path' 'V2' 'Double'                  -> 'Point' 'V2' 'Double' -> 'Crossings'+-- 'sample' :: 'Located' ('Trail' 'V2' 'Double')       -> 'Point' 'V2' 'Double' -> 'Crossings'+-- 'sample' :: 'Located' ('Trail'' 'Loop' 'V2' 'Double') -> 'Point' 'V2' 'Double' -> 'Crossings'+-- @+--+--   Note that 'Line's have no inside or outside, so don't contribute+--   crossings+newtype Crossings = Crossings Int+  deriving (Show, Eq, Ord, Num, Enum, Real, Integral) --- | Test whether the given point is inside the given (closed) path,+instance Semigroup Crossings where+  Crossings a <> Crossings b = Crossings (a + b)++instance Monoid Crossings where+  mempty  = Crossings 0+  mappend = (<>)++instance RealFloat n => HasQuery (Located (Trail V2 n)) Crossings where+  getQuery trail = Query $ \p -> trailCrossings p trail++instance RealFloat n => HasQuery (Located (Trail' l V2 n)) Crossings where+  getQuery trail' = getQuery (mapLoc Trail trail')++instance RealFloat n => HasQuery (Path V2 n) Crossings where+  getQuery = foldMapOf each getQuery++-- | Test whether the given point is inside the given path, --   by testing whether the point's /winding number/ is nonzero. Note---   that @False@ is /always/ returned for /open/ paths, regardless of---   the winding number.-isInsideWinding :: P2 -> Path R2 -> Bool-isInsideWinding p = (/= 0) . crossings p+--   that @False@ is /always/ returned for paths consisting of lines+--   (as opposed to loops), regardless of the winding number.+--+-- @+-- 'isInsideWinding' :: 'Path' 'V2' 'Double'                  -> 'Point' 'V2' 'Double' -> 'Bool'+-- 'isInsideWinding' :: 'Located' ('Trail' 'V2' 'Double')       -> 'Point' 'V2' 'Double' -> 'Bool'+-- 'isInsideWinding' :: 'Located' ('Trail'' 'Loop' 'V2' 'Double') -> 'Point' 'V2' 'Double' -> 'Bool'+-- @+isInsideWinding :: HasQuery t Crossings => t -> Point (V t) (N t) -> Bool+isInsideWinding t = (/= 0) . sample t --- | Test whether the given point is inside the given (closed) path,+-- | Test whether the given point is inside the given path, --   by testing whether a ray extending from the point in the positive --   x direction crosses the path an even (outside) or odd (inside) --   number of times.  Note that @False@ is /always/ returned for---   /open/ paths, regardless of the number of crossings.-isInsideEvenOdd :: P2 -> Path R2 -> Bool-isInsideEvenOdd p = odd . crossings p---- | Compute the sum of /signed/ crossings of a path as we travel in the---   positive x direction from a given point.-crossings :: P2 -> Path R2 -> Int-crossings p = F.sum . map (trailCrossings p) . op Path+--   paths consisting of lines (as opposed to loops), regardless of+--   the number of crossings.+--+-- @+-- 'isInsideEvenOdd' :: 'Path' 'V2' 'Double'                  -> 'Point' 'V2' 'Double' -> 'Bool'+-- 'isInsideEvenOdd' :: 'Located' ('Trail' 'V2' 'Double')       -> 'Point' 'V2' 'Double' -> 'Bool'+-- 'isInsideEvenOdd' :: 'Located' ('Trail'' 'Loop' 'V2' 'Double') -> 'Point' 'V2' 'Double' -> 'Bool'+-- @+isInsideEvenOdd :: HasQuery t Crossings => t -> Point (V t) (N t) -> Bool+isInsideEvenOdd t = odd . sample t  -- | Compute the sum of signed crossings of a trail starting from the --   given point in the positive x direction.-trailCrossings :: P2 -> Located (Trail R2) -> Int+trailCrossings :: RealFloat n => Point V2 n -> Located (Trail V2 n) -> Crossings    -- non-loop trails have no inside or outside, so don't contribute crossings trailCrossings _ t | not (isLoop (unLoc t)) = 0  trailCrossings p@(unp2 -> (x,y)) tr-  = sum . map test $ fixTrail tr+  = F.foldMap test $ fixTrail tr   where     test (FLinear a@(unp2 -> (_,ay)) b@(unp2 -> (_,by)))       | ay <= y && by > y && isLeft a b > 0 =  1       | by <= y && ay > y && isLeft a b < 0 = -1       | otherwise                           =  0 -    test c@(FCubic (unp2 -> x1@(_,x1y))-                   (unp2 -> c1@(_,c1y))-                   (unp2 -> c2@(_,c2y))-                   (unp2 -> x2@(_,x2y))+    test c@(FCubic (P x1@(V2 _ x1y))+                   (P c1@(V2 _ c1y))+                   (P c2@(V2 _ c2y))+                   (P x2@(V2 _ x2y))            ) =         sum . map testT $ ts       where ts = filter (liftA2 (&&) (>=0) (<=1))@@ -323,15 +405,15 @@             testT t = let (unp2 -> (px,_)) = c `atParam` t                       in  if px > x then signFromDerivAt t else 0             signFromDerivAt t =-              let (dx,dy) = (3*t*t) *^ ((-1)*^x1 ^+^ 3*^c1 ^-^ 3*^c2 ^+^ x2)-                        ^+^ (2*t)   *^ (3*^x1 ^-^ 6*^c1 ^+^ 3*^c2)-                        ^+^            ((-3)*^x1 ^+^ 3*^c1)-                  ang = atan2 dy dx+              let v =  (3*t*t) *^ ((-1)*^x1 ^+^ 3*^c1 ^-^ 3*^c2 ^+^ x2)+                   ^+^ (2*t)   *^ (3*^x1 ^-^ 6*^c1 ^+^ 3*^c2)+                   ^+^            ((-3)*^x1 ^+^ 3*^c1)+                  ang = v ^. _theta . rad               in  case () of _ | 0      < ang && ang < tau/2 && t < 1 ->  1                                | -tau/2 < ang && ang < 0     && t > 0 -> -1                                | otherwise                            ->  0 -    isLeft a b = cross (b .-. a) (p .-. a)+    isLeft a b = cross2 (b .-. a) (p .-. a)  ------------------------------------------------------------ --  Clipping  ----------------------------------------------@@ -342,25 +424,42 @@ --   concatenation, so applying multiple clipping paths is sensible. --   The clipping region is the intersection of all the applied --   clipping paths.-newtype Clip = Clip [Path R2]+newtype Clip n = Clip [Path V2 n]   deriving (Typeable, Semigroup)  makeWrapped ''Clip -instance AttributeClass Clip+instance Typeable n => AttributeClass (Clip n) -type instance V Clip = R2+instance AsEmpty (Clip n) where+  _Empty = _Clip . _Empty -instance Transformable Clip where+type instance V (Clip n) = V2+type instance N (Clip n) = n++instance (OrderedField n) => Transformable (Clip n) where   transform t (Clip ps) = Clip (transform t ps) +-- | A point inside a clip if the point is in 'All' invididual clipping+--   paths.+instance RealFloat n => HasQuery (Clip n) All where+  getQuery (Clip paths) = Query $ \p ->+    F.foldMap (All . flip isInsideWinding p) paths++_Clip :: Iso (Clip n) (Clip n') [Path V2 n] [Path V2 n']+_Clip = _Wrapped++-- | Lens onto the Clip in a style. An empty list means no clipping.+_clip :: (Typeable n, OrderedField n) => Lens' (Style V2 n) [Path V2 n]+_clip = atTAttr . non' _Empty . _Clip+ -- | Clip a diagram by the given path: -- --   * Only the parts of the diagram which lie in the interior of the --     path will be drawn. -- --   * The envelope of the diagram is unaffected.-clipBy :: (HasStyle a, V a ~ R2) => Path R2 -> a -> a+clipBy :: (HasStyle a, V a ~ V2, N a ~ n, TypeableFloat n) => Path V2 n -> a -> a clipBy = applyTAttr . Clip . (:[])  -- | Clip a diagram to the given path setting its envelope to the@@ -368,7 +467,8 @@ --   trace consists of those parts of the original diagram's trace --   which fall within the clipping path, or parts of the path's trace --   within the original diagram.-clipTo :: (Renderable (Path R2) b) => Path R2 ->  Diagram b R2 ->  Diagram b R2+clipTo :: TypeableFloat n+  => Path V2 n -> QDiagram b V2 n Any -> QDiagram b V2 n Any clipTo p d = setTrace intersectionTrace . toEnvelope $ clipBy p d   where     envP = appEnvelope . getEnvelope $ p@@ -376,17 +476,56 @@     toEnvelope = case (envP, envD) of       (Just eP, Just eD) -> setEnvelope . mkEnvelope $ \v -> min (eP v) (eD v)       (_, _)             -> id-    intersectionTrace = Trace intersections-    intersections pt v =+    intersectionTrace = Trace traceIntersections+    traceIntersections pt v =         -- on boundary of d, inside p         onSortedList (filter pInside) (appTrace (getTrace d) pt v) <>         -- or on boundary of p, inside d         onSortedList (filter dInside) (appTrace (getTrace p) pt v) where           newPt dist = pt .+^ v ^* dist-          pInside dDist = runFillRule Winding (newPt dDist) p+          pInside dDist = runFillRule Winding p (newPt dDist)           dInside pDist = getAny . sample d $ newPt pDist  -- | Clip a diagram to the clip path taking the envelope and trace of the clip --   path.-clipped :: (Renderable (Path R2) b) => Path R2 ->  Diagram b R2 ->  Diagram b R2-clipped p = (withTrace p) . (withEnvelope p) . (clipBy p)+clipped :: TypeableFloat n+  => Path V2 n -> QDiagram b V2 n Any -> QDiagram b V2 n Any+clipped p = withTrace p . withEnvelope p . clipBy p++------------------------------------------------------------+--  Intersections  -----------------------------------------+------------------------------------------------------------++-- | Find the intersect points of two objects that can be converted to a path.+intersectPoints :: (InSpace V2 n t, SameSpace t s, ToPath t, ToPath s, OrderedField n)+  => t -> s -> [P2 n]+intersectPoints = intersectPoints' 1e-8++-- | Find the intersect points of two objects that can be converted to a path+--   within the given tolerance.+intersectPoints' :: (InSpace V2 n t, SameSpace t s, ToPath t, ToPath s, OrderedField n)+  => n -> t -> s -> [P2 n]+intersectPoints' eps t s = intersectPointsP' eps (toPath t) (toPath s)++-- | Compute the intersect points between two paths.+intersectPointsP :: OrderedField n => Path V2 n -> Path V2 n -> [P2 n]+intersectPointsP = intersectPointsP' 1e-8++-- | Compute the intersect points between two paths within given tolerance.+intersectPointsP' :: OrderedField n => n -> Path V2 n -> Path V2 n -> [P2 n]+intersectPointsP' eps as bs = do+  a <- pathTrails as+  b <- pathTrails bs+  intersectPointsT' eps a b++-- | Compute the intersect points between two located trails.+intersectPointsT :: OrderedField n => Located (Trail V2 n) -> Located (Trail V2 n) -> [P2 n]+intersectPointsT = intersectPointsT' 1e-8++-- | Compute the intersect points between two located trails within the given+--   tolerance.+intersectPointsT' :: OrderedField n => n -> Located (Trail V2 n) -> Located (Trail V2 n) -> [P2 n]+intersectPointsT' eps as bs = do+  a <- fixTrail as+  b <- fixTrail bs+  intersectPointsS' eps a b
+ src/Diagrams/TwoD/Points.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE ConstraintKinds #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.TwoD.Points+-- Copyright   :  (c) 2014 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Special functions for points in R2.+--+-----------------------------------------------------------------------------++{-# LANGUAGE TypeFamilies #-}++module Diagrams.TwoD.Points where++import Data.List++import Diagrams.Core+import Diagrams.TwoD.Vector+import Diagrams.TwoD.Types (P2)++import Linear.Affine++-- | Find the convex hull of a list of points using Andrew's monotone chain+--   algorithm O(n log n).+--   +--   Returns clockwise list of points starting from the left-most point.+convexHull2D :: OrderedField n => [P2 n] -> [P2 n]+convexHull2D ps = init upper ++ reverse (tail lower)+  where+    (upper, lower) = sortedConvexHull (sort ps)++-- | Find the convex hull of a set of points already sorted in the x direction. +--   The first list of the tuple is the upper hull going clockwise from +--   left-most to right-most point. The second is the lower hull from +--   right-most to left-most in the anti-clockwise direction.+sortedConvexHull :: OrderedField n => [P2 n] -> ([P2 n], [P2 n])+sortedConvexHull ps = (chain True ps, chain False ps)+ where+   chain upper (p1_:p2_:rest_) =+     case go (p2_ .-. p1_) p2_ rest_ of+       Right l -> p1_:l+       Left l  -> chain upper (p1_:l)+     where+       test = if upper then (>0) else (<0)+       -- find the convex hull by comparing the angles of the vectors with+       -- the cross product and backtracking if necessary+       go dir p1 l@(p2:rest)+         -- backtrack if the direction is outward+         | test $ dir `cross2` dir' = Left l+         | otherwise                =+             case go dir' p2 rest of+               Left m  -> go dir p1 m+               Right m -> Right (p1:m)+         where+           dir' = p2 .-. p1+       go _ p1 p = Right (p1:p)++   chain _ l = l
src/Diagrams/TwoD/Polygons.hs view
@@ -1,9 +1,10 @@-{-# LANGUAGE DeriveFunctor             #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ScopedTypeVariables       #-}-{-# LANGUAGE TemplateHaskell           #-}-{-# LANGUAGE TypeFamilies              #-}-{-# LANGUAGE ViewPatterns              #-}+{-# LANGUAGE ConstraintKinds     #-}+{-# LANGUAGE DeriveFunctor       #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeFamilies        #-}+{-# LANGUAGE ViewPatterns        #-}  ----------------------------------------------------------------------------- -- |@@ -45,35 +46,34 @@      ) where -import           Control.Lens            (Lens', generateSignatures, lensRules,-                                          makeLensesWith, (.~), (^.), view)-import           Control.Monad           (forM, liftM)-import           Control.Monad.ST        (ST, runST)-import           Data.Array.ST           (STUArray, newArray, readArray,-                                          writeArray)-import           Data.List               (maximumBy, minimumBy)-import           Data.Maybe              (catMaybes)-import           Data.Monoid             (mconcat, mempty)-import           Data.Ord                (comparing)--import           Data.AffineSpace        ((.+^), (.-.))-import           Data.Default.Class-import           Data.VectorSpace+import           Control.Lens         (Lens', generateSignatures, lensRules,+                                       makeLensesWith, view, (.~), (^.))+import           Control.Monad        (forM, liftM)+import           Control.Monad.ST     (ST, runST)+import           Data.Array.ST        (STUArray, newArray, readArray,+                                       writeArray)+import           Data.Default+import           Data.List            (maximumBy, minimumBy)+import           Data.Maybe           (catMaybes)+import           Data.Ord             (comparing)  import           Diagrams.Angle import           Diagrams.Core import           Diagrams.Located import           Diagrams.Path-import           Diagrams.Points         (centroid)+import           Diagrams.Points      (centroid) import           Diagrams.Trail import           Diagrams.TrailLike-import           Diagrams.TwoD.Transform import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector    (leftTurn, unitX, unitY, unit_Y)-import           Diagrams.Util           (tau, ( # ))+import           Diagrams.TwoD.Vector (leftTurn, unitX, unitY, unit_Y)+import           Diagrams.Util        (tau, ( # )) +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ -- | Method used to determine the vertices of a polygon.-data PolyType = PolyPolar [Angle] [Double]+data PolyType n = PolyPolar [Angle n] [n]                 -- ^ A \"polar\" polygon.                 --                 --   * The first argument is a list of /central/@@ -90,21 +90,21 @@                 --   circle) can be constructed using a second                 --   argument of @(repeat r)@. -              | PolySides [Angle] [Double]+              | PolySides [Angle n] [n]                 -- ^ A polygon determined by the distance between-                --   successive vertices and the angles formed by-                --   each three successive vertices.  In other+                --   successive vertices and the external angles formed+                --   by each three successive vertices. In other                 --   words, a polygon specified by \"turtle                 --   graphics\": go straight ahead x1 units; turn by-                --   angle a1; go straght ahead x2 units; turn by-                --   angle a2; etc. The polygon will be centered at-                --   the /centroid/ of its vertices.+                --   external angle a1; go straight ahead x2 units; turn by+                --   external angle a2; etc. The polygon will be centered+                --   at the /centroid/ of its vertices.                 --                 --   * The first argument is a list of /vertex/-                --     /angles/, giving the angle at each vertex+                --     /angles/, giving the external angle at each vertex                 --     from the previous vertex to the next.  The-                --     first angle in the list is the angle at the-                --     /second/ vertex; the first edge always starts+                --     first angle in the list is the external angle at+                --     the /second/ vertex; the first edge always starts                 --     out heading in the positive y direction from                 --     the first vertex.                 --@@ -115,54 +115,54 @@                 --   angles and /n-1/ edge lengths.  Extra angles or                 --   lengths are ignored. -              | PolyRegular Int Double+              | PolyRegular Int n                 -- ^ A regular polygon with the given number of                 --   sides (first argument) and the given radius                 --   (second argument).  -- | Determine how a polygon should be oriented.-data PolyOrientation = NoOrient     -- ^ No special orientation; the first-                                    --   vertex will be at (1,0).-                                    --   This is the default.-                     | OrientH      -- ^ Orient /horizontally/, so the-                                    --   bottommost edge is parallel to-                                    --   the x-axis.-                     | OrientV      -- ^ Orient /vertically/, so the-                                    --   leftmost edge is parallel to the-                                    --   y-axis.-                     | OrientTo R2  -- ^ Orient so some edge is-                                    --   /facing/ /in/ /the/ /direction/-                                    --   /of/, that is, perpendicular-                                    --   to, the given vector.-  deriving (Eq, Ord, Show, Read)+data PolyOrientation n = NoOrient        -- ^ No special orientation; the first+                                         --   vertex will be at (1,0).+                       | OrientH         -- ^ Orient /horizontally/, so the+                                         --   bottommost edge is parallel to+                                         --   the x-axis.+                                         --   This is the default.+                       | OrientV         -- ^ Orient /vertically/, so the+                                         --   leftmost edge is parallel to the+                                         --   y-axis.+                       | OrientTo (V2 n) -- ^ Orient so some edge is+                                         --   /facing/ /in/ /the/ /direction/+                                         --   /of/, that is, perpendicular+                                         --   to, the given vector.+                       deriving (Eq, Ord, Show, Read)  -- | Options for specifying a polygon.-data PolygonOpts = PolygonOpts-                   { _polyType   :: PolyType-                   , _polyOrient :: PolyOrientation-                   , _polyCenter :: P2+data PolygonOpts n = PolygonOpts+                   { _polyType   :: PolyType n+                   , _polyOrient :: PolyOrientation n+                   , _polyCenter :: Point V2 n                    }  makeLensesWith (generateSignatures .~ False $ lensRules) ''PolygonOpts  -- | Specification for the polygon's vertices.-polyType :: Lens' PolygonOpts PolyType+polyType :: Lens' (PolygonOpts n) (PolyType n)  -- | Should a rotation be applied to the polygon in order to orient it in a --   particular way?-polyOrient :: Lens' PolygonOpts PolyOrientation+polyOrient :: Lens' (PolygonOpts n) (PolyOrientation n)  -- | Should a translation be applied to the polygon in order to place the center --   at a particular location?-polyCenter :: Lens' PolygonOpts P2+polyCenter :: Lens' (PolygonOpts n) (Point V2 n)  -- | The default polygon is a regular pentagon of radius 1, centered --   at the origin, aligned to the x-axis.-instance Default PolygonOpts where+instance Num n => Default (PolygonOpts n) where     def = PolygonOpts (PolyRegular 5 1) OrientH origin  -- | Generate a polygon.  See 'PolygonOpts' for more information.-polyTrail :: PolygonOpts -> Located (Trail R2)+polyTrail :: OrderedField n => PolygonOpts n -> Located (Trail V2 n) polyTrail po = transform ori tr     where         tr = case po^.polyType of@@ -170,18 +170,18 @@             PolySides ans szs -> polySidesTrail ans szs             PolyRegular n r   -> polyRegularTrail n r         ori = case po^.polyOrient of-            OrientH      -> orient unit_Y tr-            OrientV      -> orient unitX  tr-            OrientTo v   -> orient v      tr-            NoOrient     -> mempty+            OrientH    -> orient unit_Y tr+            OrientV    -> orient unitX  tr+            OrientTo v -> orient v      tr+            NoOrient   -> mempty  -- | Generate the polygon described by the given options.-polygon :: (TrailLike t, V t ~ R2) => PolygonOpts -> t+polygon :: (InSpace V2 n t, TrailLike t) => PolygonOpts n -> t polygon = trailLike . polyTrail  -- | Generate the located trail of a polygon specified by polar data --   (central angles and radii). See 'PolyPolar'.-polyPolarTrail :: [Angle] -> [Double] -> Located (Trail R2)+polyPolarTrail :: OrderedField n =>  [Angle n] -> [n] -> Located (Trail V2 n) polyPolarTrail [] _ = emptyTrail `at` origin polyPolarTrail _ [] = emptyTrail `at` origin polyPolarTrail ans (r:rs) = tr `at` p1@@ -190,52 +190,54 @@     tr = closeTrail . trailFromVertices $            zipWith              (\a l -> rotate a . scale l $ p2 (1,0))-             (scanl (^+^) zeroV ans)+             (scanl (^+^) zero ans)              (r:rs)  -- | Generate the vertices of a polygon specified by side length and --   angles, and a starting point for the trail such that the origin --   is at the centroid of the vertices.  See 'PolySides'.-polySidesTrail :: [Angle] -> [Double] -> Located (Trail R2)+polySidesTrail :: OrderedField n =>  [Angle n] -> [n] -> Located (Trail V2 n) polySidesTrail ans ls = tr `at` (centroid ps # scale (-1))   where-    ans'    = scanl (^+^) zeroV ans+    ans'    = scanl (^+^) zero ans     offsets = zipWith rotate ans' (map (unitY ^*) ls)     ps      = scanl (.+^) origin offsets     tr      = closeTrail . trailFromOffsets $ offsets  -- | Generate the vertices of a regular polygon.  See 'PolyRegular'.-polyRegularTrail :: Int -> Double -> Located (Trail R2)+polyRegularTrail :: OrderedField n =>  Int -> n -> Located (Trail V2 n) polyRegularTrail n r = polyPolarTrail-                         (take (n-1) . repeat $ fullTurn ^/ fromIntegral n)+                         (replicate (n - 1) $ fullTurn ^/ fromIntegral n)                          (repeat r)  -- | Generate a transformation to orient a trail.  @orient v t@ --   generates the smallest rotation such that one of the segments --   adjacent to the vertex furthest in the direction of @v@ is --   perpendicular to @v@.-orient :: R2 -> Located (Trail R2) -> T2+orient :: OrderedField n => V2 n -> Located (Trail V2 n) -> Transformation V2 n orient v = orientPoints v . trailVertices -orientPoints :: R2 -> [P2] -> T2+orientPoints :: OrderedField n => V2 n -> [Point V2 n] -> Transformation V2 n+orientPoints _ [] = mempty+orientPoints _ [_] = mempty orientPoints v xs = rotation a   where     (n1,x,n2) = maximumBy (comparing (distAlong v . sndOf3))                   (zip3 (tail (cycle xs)) xs (last xs : init xs))-    distAlong w ((.-. origin) -> p) = signum (w <.> p) * magnitude (project w p)+    distAlong w ((.-. origin) -> p) = signum (w `dot` p) * norm (project w p)     sndOf3 (_,b,_) = b-    a :: Angle+    -- a :: Angle (Scalar v)     a = minimumBy (comparing $ abs . view rad)         . map (angleFromNormal . (.-. x)) $ [n1,n2]-    v' = normalized v-    angleFromNormal :: R2 -> Angle+    v' = signorm v+    -- angleFromNormal :: v -> Angle (Scalar v)     angleFromNormal o       | leftTurn o' v' = phi-      | otherwise      = negateV phi+      | otherwise      = negated phi       where-        o' = normalized o-        theta = acos (v' <.> o')-        phi :: Angle+        o' = signorm o+        theta = acos (v' `dot` o')+        -- phi :: Angle (Scalar v)         phi           | theta <= tau/4 = tau/4 - theta @@ rad           | otherwise      = theta - tau/4 @@ rad@@ -275,10 +277,10 @@     markRho :: Int -> STUArray s Int Bool -> ST s [Int]     markRho i marks = do       isMarked <- readArray marks i-      case isMarked of-        True  -> return []-        False -> writeArray marks i True >>-                 liftM (i:) (markRho (f_n i) marks)+      if isMarked+        then return []+        else writeArray marks i True >>+               liftM (i:) (markRho (f_n i) marks)      splitParts :: [Int] -> [GraphPart Int]     splitParts tr = hair ++ cyc@@ -317,13 +319,13 @@ -- | Create a generalized /star/ /polygon/.  The 'StarOpts' are used --   to determine in which order the given vertices should be --   connected.  The intention is that the second argument of type---   @[P2]@ could be generated by a call to 'polygon', 'regPoly', or+--   @[Point v]@ could be generated by a call to 'polygon', 'regPoly', or --   the like, since a list of vertices is 'TrailLike'.  But of course---   the list can be generated any way you like.  A @'Path' 'R2'@ is+--   the list can be generated any way you like.  A @'Path' 'v'@ is --   returned (instead of any 'TrailLike') because the resulting path --   may have more than one component, for example if the vertices are --   to be connected in several disjoint cycles.-star :: StarOpts -> [P2] -> Path R2+star :: OrderedField n => StarOpts -> [Point V2 n] -> Path V2 n star sOpts vs = graphToPath $ mkGraph f vs   where f = case sOpts of               StarFun g  -> g
src/Diagrams/TwoD/Segment.hs view
@@ -1,9 +1,12 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE ViewPatterns         #-} {-# LANGUAGE UndecidableInstances #-}  {-# OPTIONS_GHC -fno-warn-orphans #-}--- Orphan Traced instances for Segment Closed R2 and FixedSegment R2.+-- Orphan Traced instances for Segment Closed V2 and FixedSegment V2. -- They can't go in Traced; but they shouldn't really go in -- Diagrams.Segment either because we only have Traced instances for -- the special case of R2.@@ -19,89 +22,358 @@ -- ----------------------------------------------------------------------------- -module Diagrams.TwoD.Segment where+module Diagrams.TwoD.Segment+  ( -- * Segment intersections -import           Control.Applicative     (liftA2)+    intersectPointsS+  , intersectPointsS' -import           Data.AffineSpace-import           Data.VectorSpace+    -- * Closest point on a segment +  , closestPoint+  , closestPoint'+  , closestDistance+  , closestDistance'+  , closestParam+  , closestParam'++    -- ** Low level functions+  , segmentSegment+  , lineSegment+  )+  where++import           Control.Lens                    hiding (at, contains, transform, ( # ))+import           Data.Maybe+ import           Diagrams.Core +import           Diagrams.Direction import           Diagrams.Located import           Diagrams.Parametric import           Diagrams.Segment-import           Diagrams.Solve+import           Diagrams.TwoD.Points+import           Diagrams.TwoD.Segment.Bernstein import           Diagrams.TwoD.Transform-import           Diagrams.TwoD.Types+import           Diagrams.TwoD.Types             hiding (p2) import           Diagrams.TwoD.Vector-import           Diagrams.Util +import           Linear.Affine+import           Linear.Metric+ {- All instances of Traced should maintain the invariant that the list of    traces is sorted in increasing order. -} -instance Traced (Segment Closed R2) where+instance OrderedField n => Traced (Segment Closed V2 n) where   getTrace = getTrace . mkFixedSeg . (`at` origin) -instance Traced (FixedSegment R2) where+instance OrderedField n => Traced (FixedSegment V2 n) where+  getTrace seg = mkTrace $ \p v ->+    mkSortedList . map (view _1) $ lineSegment defEps (v `at` p) seg -{- Given lines defined by p0 + t0 * v0 and p1 + t1 * v1, their point of-   intersection in 2D is given by+defEps :: Fractional n => n+defEps = 1e-8 -     t_i = (v_(1-i)^ . (p1 - p0)) / (v1^ . v0)+-- | Compute the intersections between two fixed segments.+intersectPointsS :: OrderedField n => FixedSegment V2 n -> FixedSegment V2 n -> [P2 n]+intersectPointsS = intersectPointsS' defEps -   where v^ denotes the perpendicular to v, i.e. v rotated by-   -tau/4.+-- | Compute the intersections between two segments using the given tolerance.+intersectPointsS' :: OrderedField n => n -> FixedSegment V2 n -> FixedSegment V2 n -> [P2 n]+intersectPointsS' eps s1 s2 = map (view _3) $ segmentSegment eps s1 s2 -   This can be derived by starting with the parametric equation+-- | Get the closest distance(s) from a point to a 'FixedSegment'.+closestDistance :: OrderedField n => FixedSegment V2 n -> P2 n -> [n]+closestDistance = closestDistance' defEps -     p0 + v0 t0 = p1 + v1 t1+-- | Get the closest distance(s) from a point to a 'FixedSegment' within given+--   tolerance.+closestDistance' :: OrderedField n => n -> FixedSegment V2 n -> P2 n -> [n]+closestDistance' eps seg p = map (distanceA p) $ closestPoint' eps seg p -   and rearranging to get the matrix equation+-- | Get the closest point(s) on a 'FixedSegment' from a point.+closestPoint :: OrderedField n => FixedSegment V2 n -> P2 n -> [P2 n]+closestPoint = closestPoint' defEps -     [v0 -v1] [ t0 ]  =  (p1 - p0)-              [ t1 ]+-- | Get the closest point(s) on a 'FixedSegment' from a point within given+--   tolerance.+closestPoint' :: OrderedField n => n -> FixedSegment V2 n -> P2 n -> [P2 n]+closestPoint' eps seg = map (seg `atParam`) . closestParam' eps seg -   Working out the product of the inverse of [v0 -v1] with (p1 - p0)-   results in the above formulas for t_i.--}+-- | Find the closest value(s) on the Bêzier to the given point.+closestParam :: OrderedField n => FixedSegment V2 n -> P2 n -> [n]+closestParam = closestParam' defEps -  getTrace (FLinear p0 p0') = mkTrace $ \p1 v1 ->-    let-      v0     = p0' .-. p0-      det    = perp v1 <.> v0-      p      = p1 .-. p0-      t0     = (perp v1 <.> p) / det-      t1     = (perp v0 <.> p) / det-    in-      if det == 0 || t0 < 0 || t0 > 1-        then mkSortedList []-        else mkSortedList [t1]+-- | Find the closest value(s) on the Bêzier to the given point within given+--   tolerance.+closestParam' :: OrderedField n => n -> FixedSegment V2 n -> P2 n -> [n]+closestParam' _ (FLinear p0 p1) p+  | t < 0     = [0]+  | t > 1     = [1]+  | otherwise = [t]+  where+    vp = p  .-. p0+    v  = p1 .-. p0+    dp = vp `dot` v+    t  = dp / quadrance v+closestParam' eps cb (P (V2 px py)) = bezierFindRoot eps poly 0 1+  where+    (bx, by) = bezierToBernstein cb+    bx'  = bernsteinDeriv bx+    by'  = bernsteinDeriv by+    poly = (bx - listToBernstein [px, px, px, px]) * bx'+         + (by - listToBernstein [py, py, py, py]) * by' -{- To do intersection of a line with a cubic Bezier, we first rotate-   and scale everything so that the line has parameters (origin, unitX);-   then we find the intersection(s) of the Bezier with the x-axis.+------------------------------------------------------------------------+-- Low level+------------------------------------------------------------------------ -   XXX could we speed this up by first checking whether all the-   control point y-coordinates lie on the same side of the x-axis (if so,-   there can't possibly be any intersections)?  Need to set up some-   benchmarks.--}+-- | Return the intersection points with the parameters at which each segment+--   intersects.+segmentSegment :: OrderedField n => n -> FixedSegment V2 n -> FixedSegment V2 n -> [(n, n, P2 n)]+segmentSegment eps s1 s2 =+  case (s1,s2) of+    (FCubic{}, FCubic{})  -> map (\(t1,t2) -> (t1,t2, s1 `atParam` t1))+                           $ bezierClip eps s1 s2+    (FCubic{}, FLinear{}) -> map flip12 $ linearSeg (segLine s2) s1+    _                     -> linearSeg (segLine s1) s2 -- s1 is linear+  where+    linearSeg l s  = filter (inRange . view _1) $ lineSegment eps l s+    flip12 (a,b,c) = (b,a,c) -  getTrace bez@(FCubic {}) = mkTrace $ \p1 v1 ->-    let-      bez'@(FCubic x1 c1 c2 x2) =-        bez # moveOriginTo p1-            # rotate (negateV (direction v1))-            # scale (1/magnitude v1)-      [y0,y1,y2,y3] = map (snd . unp2) [x1,c1,c2,x2]-      a  = -y0 + 3*y1 - 3*y2 + y3-      b  = 3*y0 - 6*y1 + 3*y2-      c  = -3*y0 + 3*y1-      d  = y0-      ts = filter (liftA2 (&&) (>= 0) (<= 1)) (cubForm a b c d)-      xs = map (fst . unp2 . atParam bez') ts-    in-      mkSortedList xs+-- | Return the intersection points with the parameters at which the line and segment+--   intersect.+lineSegment :: OrderedField n => n -> Located (V2 n) -> FixedSegment V2 n -> [(n, n, P2 n)]+lineSegment _ l1 p@(FLinear p0 p1)+  = map (\(tl,tp) -> (tl, tp, p `atParam` tp))+  . filter (inRange . snd) . maybeToList $ lineLine l1 (mkLine p0 p1)+lineSegment eps (viewLoc -> (p,r)) cb = map addPoint params+  where+    params = bezierFindRoot eps (listToBernstein $ cb' ^.. each . _y) 0 1+    cb'    = transform (inv (rotationTo $ dir r)) . moveOriginTo p $ cb+    --+    addPoint bt = (lt, bt, intersect)+      where+        intersect = cb `atParam` bt+        lt        = (cb' `atParam` bt) ^. _x / norm r++-- Adapted from from kuribas's cubicbezier package https://github.com/kuribas/cubicbezier++-- | Use the Bêzier clipping algorithm to return the parameters at which the+--   Bêzier curves intersect.+bezierClip :: OrderedField n => n -> FixedSegment V2 n -> FixedSegment V2 n -> [(n, n)]+bezierClip eps p_ q_ = filter (allOf both inRange) -- sometimes this returns NaN+                     $ go p_ q_ 0 1 0 1 0 False+  where+  go p q tmin tmax umin umax clip revCurves+    | isNothing chopInterval = []++    -- This check happens before the subdivision+    -- test to avoid non-termination as values+    -- transition to within epsilon.+    | max (umax - umin) (tmax' - tmin') < eps =+      if revCurves -- return parameters in correct order+      then [ (avg umin  umax,  avg tmin' tmax') ]+      else [ (avg tmin' tmax', avg umin  umax ) ]++    -- split the curve if there isn't enough reduction+    | clip > 0.8 && clip' > 0.8 =+      if tmax' - tmin' > umax - umin -- split the longest segment+      then let (pl, pr) = p' `splitAtParam` 0.5+               tmid = avg tmin' tmax'+           in  go q pl umin umax tmin' tmid  clip' (not revCurves) +++               go q pr umin umax tmid  tmax' clip' (not revCurves)+      else let (ql, qr) = q `splitAtParam` 0.5+               umid = avg umin umax+           in  go ql p' umin umid tmin' tmax' clip' (not revCurves) +++               go qr p' umid umax tmin' tmax' clip' (not revCurves)++    -- iterate with the curves reversed.+    | otherwise = go q p' umin umax tmin' tmax' clip' (not revCurves)+    where+      chopInterval              = chopCubics p q+      Just (tminChop, tmaxChop) = chopInterval+      p'    = section p tminChop tmaxChop+      clip' = tmaxChop - tminChop+      tmin' = tmax * tminChop + tmin * (1 - tminChop)+      tmax' = tmax * tmaxChop + tmin * (1 - tmaxChop)++-- | Find the zero of a 1D Bêzier curve of any degree.  Note that this+--   can be used as a Bernstein polynomial root solver by converting from+--   the power basis to the Bernstein basis.+bezierFindRoot :: OrderedField n+               => n   -- ^ The accuracy+               -> BernsteinPoly n -- ^ the Bernstein coefficients of the polynomial+               -> n   -- ^ The lower bound of the interval+               -> n   -- ^ The upper bound of the interval+               -> [n] -- ^ The roots found+bezierFindRoot eps p tmin tmax+  -- If we generated the max number of roots and tmax is also a root+  -- (which is not among the generated ones), there must in fact be an+  -- infinite number of roots, so just include tmax.+  | length roots == bernsteinDegree p && last roots /= tmax && abs (evaluateBernstein p tmax) <= eps+  = roots ++ [tmax]+  | otherwise = roots+ where+  -- Lazily take a number of roots at most the degree of the bernstein+  -- polynomial, to avoid generating a ton of roots in the case of a+  -- straight Bezier segment along the x-axis. See https://github.com/diagrams/diagrams-contrib/issues/91 .+  roots = take (bernsteinDegree p) $ go p tmin tmax+  go p tmin tmax+    | isNothing chopInterval = []+    | tmax' - tmin' < eps = [avg tmin' tmax']+    | clip > 0.8 = let (p1, p2) = splitAtParam newP 0.5+                       tmid     = tmin' + (tmax' - tmin') / 2+                   in  go p1 tmin' tmid  +++                       go p2 tmid  tmax'+    | otherwise = bezierFindRoot eps newP tmin' tmax'+    where+      chopInterval              = chopYs (bernsteinCoeffs p)+      Just (tminChop, tmaxChop) = chopInterval+      newP  = section p tminChop tmaxChop+      clip  = tmaxChop - tminChop+      tmin' = tmax * tminChop + tmin * (1 - tminChop)+      tmax' = tmax * tmaxChop + tmin * (1 - tmaxChop)++------------------------------------------------------------------------+-- Internal+------------------------------------------------------------------------++-- | An approximation of the fat line for a cubic Bêzier segment. Returns+--   @(0,0)@ for a linear segment.+fatLine :: OrderedField n => FixedSegment V2 n -> (n,n)+fatLine (FCubic p0 p1 p2 p3)+  = case (d1 > 0, d2 > 0) of+      (True,  True)  -> (0,                0.75 * max d1 d2)+      (False, False) -> (0.75 * min d1 d2, 0               )+      (True,  False) -> (4/9 * d2,         4/9 * d1        )+      (False, True)  -> (4/9 * d1,         4/9 * d2        )+  where+    d = lineDistance p0 p3+    d1 = d p1; d2 = d p2+fatLine _ = (0,0)++chopYs :: OrderedField n => [n] -> Maybe (n, n)+chopYs ds = chopHull 0 0 points+  where+    points = zipWith mkP2 [fromIntegral i / fromIntegral n | i <- [0..n]] ds+    n      = length ds - 1++chopCubics :: OrderedField n => FixedSegment V2 n -> FixedSegment V2 n -> Maybe (n,n)+chopCubics p q@(FCubic q0 _ _ q3)+  = chopHull dmin dmax dps+  where+    dps = zipWith mkP2 [0, 1/3, 2/3, 1] ds+    ds  = p ^.. each . to d+    d   = lineDistance q0 q3+    --+    (dmin,dmax) = fatLine q+chopCubics _ _ = Nothing++-- Reduce the interval which the intersection is known to lie in using the fat+-- line of one curve and convex hull of the points formed from the distance to+-- the thin line of the other+chopHull :: OrderedField n => n -> n -> [P2 n] -> Maybe (n, n)+chopHull dmin dmax dps = do+  tL <- testBelow upper           $ testBetween (head upper) $ testAbove lower+  tR <- testBelow (reverse upper) $ testBetween (last upper) $ testAbove (reverse lower)+  Just (tL, tR)+    where+      (upper, lower) = sortedConvexHull dps++      testBelow (p1@(P (V2 _ y1)) : p2@(P (V2 _ y2)) : ps) continue+        | y1 >= dmin = continue+        | y1 >  y2   = Nothing+        | y2 <  dmin = testBelow (p2:ps) continue+        | otherwise  = Just $ intersectPt dmin p1 p2+      testBelow _ _  = Nothing++      testBetween (P (V2 x y)) continue+        | y <= dmax = Just x+        | otherwise = continue++      testAbove (p1@(P (V2 _ y1)) : p2@(P (V2 _ y2)) : ps)+        | y1 < y2      = Nothing+        | y2 > dmax    = testAbove (p2:ps)+        | y2 - y1 == 0 = Nothing  -- Check this condition to prevent+                                  -- division by zero in `intersectPt`.+        | otherwise    = Just $ intersectPt dmax p1 p2+      testAbove _      = Nothing++      -- find the x value where the line through the two points+      -- intersect the line y=d.  Note that `y2 - y1 != 0` due+      -- to checks above.+      intersectPt d (P (V2 x1 y1)) (P (V2 x2 y2)) =+          x1 + (d - y1) * (x2 - x1) / (y2 - y1)++++bezierToBernstein :: Fractional n => FixedSegment V2 n -> (BernsteinPoly n, BernsteinPoly n)+bezierToBernstein seg =+    (listToBernstein $ map (view _x) coeffs, listToBernstein $ map (view _y) coeffs)+  where coeffs = toListOf each seg++------------------------------------------------------------------------+-- Lines+------------------------------------------------------------------------++-- Could split this into a separate module.++-- | Returns @(a, b, c, d)@ such that @ax + by + c = 0@ is the line going through+--   @p1@ and @p2@ with @(a^2)/d + (b^2)/d = 1@.  We delay the division by+--   @d@ as it may not be needed in all cases and @d@ may be zero.+lineEquation :: Floating n => P2 n -> P2 n -> (n, n, n, n)+lineEquation (P (V2 x1 y1)) (P (V2 x2 y2)) = (a, b, c, d)+  where+    c  = -(x1*a + y1*b)+    a = y1 - y2+    b = x2 - x1+    d  = a*a + b*b++-- | Return the distance from a point to the line.+lineDistance :: (Ord n, Floating n) => P2 n -> P2 n -> P2 n -> n+lineDistance p1 p2 p3@(P (V2 x y))+    -- I have included the check that d' <= 0 in case+    -- there exists some d > 0 where sqrt d == 0.  I don't+    -- think this can happen as sqrt is at least recommended+    -- to be within one value of correct for sqrt and near+    -- zero values get bigger.+    | d <= 0 || d' <= 0 = norm (p1 .-. p3)+    | otherwise = (a*x + b*y + c) / d'+  where+    (a, b, c, d) = lineEquation p1 p2+    d' = sqrt d++-- clockwise :: (Num n, Ord n) => V2 n -> V2 n -> Bool+-- clockwise a b = a `cross2` b <= 0++avg :: Fractional n => n -> n -> n+avg a b = (a + b)/2++lineLine :: (Fractional n, Eq n) => Located (V2 n) -> Located (V2 n) -> Maybe (n,n)+lineLine (viewLoc -> (p,r)) (viewLoc -> (q,s))+  | x1 == 0 && x2 /= 0 = Nothing                 -- parallel+  | otherwise          = Just (x3 / x1, x2 / x1) -- intersecting or collinear+  where+    x1 = r × s+    x2 = v × r+    x3 = v × s+    v  = q .-. p++(×) :: Num n => V2 n -> V2 n -> n+(×) = cross2++mkLine :: InSpace v n (v n) => Point v n -> Point v n -> Located (v n)+mkLine p0 p1 = (p1 .-. p0) `at` p0++segLine :: InSpace v n (v n) => FixedSegment v n -> Located (v n)+segLine (FLinear p0 p1)    = mkLine p0 p1+segLine (FCubic p0 _ _ p3) = mkLine p0 p3++-- This function uses `defEps`, but is used in functions+-- above that take an epsilon parameter.  It would be nice+-- to clearify the meaning of each of these epsilons.+inRange :: (Fractional n, Ord n) => n -> Bool+inRange x = x < (1+defEps) && x > (-defEps) 
+ src/Diagrams/TwoD/Segment/Bernstein.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE TypeFamilies  #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.TwoD.Segment.Bernstein+-- Copyright   :  (c) 2014-2015 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Bernstein polynomials, used internally by code to find+-- intersections of paths.  This module is probably not of any+-- relevance to most users of diagrams.+-----------------------------------------------------------------------------+module Diagrams.TwoD.Segment.Bernstein+  ( BernsteinPoly (..)+  , listToBernstein+  , evaluateBernstein++  , degreeElevate+  , bernsteinDeriv+  , evaluateBernsteinDerivs+  ) where++import           Data.List           (tails)+import           Diagrams.Core.V+import           Diagrams.Parametric+import           Linear.V1++-- | Compute the binomial coefficients of degree n.+binomials :: Num n => Int -> [n]+binomials n = map fromIntegral $ scanl (\x m -> x * (n - m+1) `quot` m) 1 [1..n]++data BernsteinPoly n = BernsteinPoly+  { bernsteinDegree :: Int+  , bernsteinCoeffs :: [n]+  } deriving (Show, Functor)++type instance V        (BernsteinPoly n) = V1+type instance N        (BernsteinPoly n) = n+type instance Codomain (BernsteinPoly n) = V1++-- | Create a bernstein polynomial from a list of coëfficients.+listToBernstein :: Fractional n => [n] -> BernsteinPoly n+listToBernstein [] = 0+listToBernstein l  = BernsteinPoly (length l - 1) l++-- | Degree elevate a bernstein polynomial a number of times.+degreeElevate :: Fractional n => BernsteinPoly n -> Int -> BernsteinPoly n+degreeElevate b                    0     = b+degreeElevate (BernsteinPoly lp p) times =+  degreeElevate (BernsteinPoly (lp+1) (head p:inner p 1)) (times-1)+  where+    n = fromIntegral lp++    inner []         _ = [0]+    inner [a]        _ = [a]+    inner (a:b:rest) i = (i*a/(n+1) + b*(1 - i/(n+1))) : inner (b:rest) (i+1)++-- | Evaluate the bernstein polynomial.+evaluateBernstein :: Fractional n => BernsteinPoly n -> n -> n+evaluateBernstein (BernsteinPoly _ [])       _ = 0+evaluateBernstein (BernsteinPoly _ [b])      _ = b+evaluateBernstein (BernsteinPoly lp (b':bs)) t = go t n (b'*u) 2 bs+  where+    u = 1-t+    n = fromIntegral lp++    go tn bc tmp _ [b]      = tmp + tn*bc*b+    go tn bc tmp i (b:rest) =+      go (tn*t)              -- tn+         (bc*(n - i+1)/i)    -- bc+         ((tmp + tn*bc*b)*u) -- tmp+         (i+1)               -- i+         rest+    go _ _ _ _ []           = error "evaluateBernstein: impossible"++-- | Evaluate the bernstein polynomial and its derivatives.+evaluateBernsteinDerivs :: Fractional n => BernsteinPoly n -> n -> [n]+evaluateBernsteinDerivs b t+  | bernsteinDegree b == 0 = [evaluateBernstein b t]+  | otherwise              = evaluateBernstein b t : evaluateBernsteinDerivs (bernsteinDeriv b) t++-- | Find the derivative of a bernstein polynomial.+bernsteinDeriv :: Fractional n => BernsteinPoly n -> BernsteinPoly n+bernsteinDeriv (BernsteinPoly 0 _)  = 0+bernsteinDeriv (BernsteinPoly lp p) =+  -- BernsteinPoly (lp-1) $ map (* fromIntegral lp) $ zipWith (-) (tail p) p+  BernsteinPoly (lp-1) $ zipWith (\a b -> (a - b) * fromIntegral lp) (tail p) p++instance Fractional n => Parametric (BernsteinPoly n) where+  atParam b = V1 . evaluateBernstein b+instance Num n        => DomainBounds (BernsteinPoly n)+instance Fractional n => EndValues    (BernsteinPoly n)+instance Fractional n => Sectionable  (BernsteinPoly n) where+  splitAtParam  = bernsteinSplit+  reverseDomain (BernsteinPoly i xs) = BernsteinPoly i (reverse xs)++-- | Split a bernstein polynomial.+bernsteinSplit :: Num n => BernsteinPoly n -> n -> (BernsteinPoly n, BernsteinPoly n)+bernsteinSplit (BernsteinPoly lp p) t =+  (BernsteinPoly lp $ map head controls,+   BernsteinPoly lp $ reverse $ map last controls)+  where+    interp a b = (1-t)*a + t*b++    terp [_] = []+    terp l   = let ctrs = zipWith interp l (tail l)+               in  ctrs : terp ctrs+    controls = p : terp p++instance Fractional n => Num (BernsteinPoly n) where+  ba@(BernsteinPoly la a) + bb@(BernsteinPoly lb b)+    | la < lb   = BernsteinPoly lb $ zipWith (+) (bernsteinCoeffs $ degreeElevate ba $ lb - la) b+    | la > lb   = BernsteinPoly la $ zipWith (+) a (bernsteinCoeffs $ degreeElevate bb $ la - lb)+    | otherwise = BernsteinPoly la $ zipWith (+) a b++  ba@(BernsteinPoly la a) - bb@(BernsteinPoly lb b)+    | la < lb   = BernsteinPoly lb $ zipWith (-) (bernsteinCoeffs $ degreeElevate ba (lb - la)) b+    | la > lb   = BernsteinPoly la $ zipWith (-) a (bernsteinCoeffs $ degreeElevate bb (la - lb))+    | otherwise = BernsteinPoly la $ zipWith (-) a b++  (BernsteinPoly la a) * (BernsteinPoly lb b) =+    BernsteinPoly (la+lb) $+    zipWith (flip (/)) (binomials (la + lb)) $+                   init $ map sum $+                   map (zipWith (*) a') (down b') +++                   map (zipWith (*) (reverse b')) (tail $ tails a')+                   -- zipWith (zipWith (*)) (tail $ tails a') (repeat $ reverse b')+    where down l = tail $ scanl (flip (:)) [] l -- [[1], [2, 1], [3, 2, 1], ...+          a' = zipWith (*) a (binomials la)+          b' = zipWith (*) b (binomials lb)++  fromInteger a = BernsteinPoly 0 [fromInteger a]++  signum (BernsteinPoly _ [])    = 0+  signum (BernsteinPoly _ (a:_)) = BernsteinPoly 0 [signum a]++  abs = fmap abs
src/Diagrams/TwoD/Shapes.hs view
@@ -1,7 +1,11 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TemplateHaskell  #-} {-# LANGUAGE TypeFamilies     #-} +{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Shapes@@ -45,6 +49,10 @@        , roundedRect'        ) where +import           Control.Lens            (makeLenses, op, (&), (.~), (<>~), (^.))+import           Data.Default+import           Data.Semigroup+ import           Diagrams.Core  import           Diagrams.Angle@@ -57,12 +65,9 @@ import           Diagrams.TwoD.Polygons import           Diagrams.TwoD.Transform import           Diagrams.TwoD.Types-+import           Diagrams.TwoD.Vector import           Diagrams.Util -import           Control.Lens            (makeLenses, op, (&), (.~), (^.))-import           Data.Default.Class-import           Data.Semigroup  -- | Create a centered horizontal (L-R) line of the given length. --@@ -70,8 +75,8 @@ -- --   > hruleEx = vcat' (with & sep .~ 0.2) (map hrule [1..5]) --   >         # centerXY # pad 1.1-hrule :: (TrailLike t, V t ~ R2) => Double -> t-hrule d = trailLike $ trailFromSegments [straight $ r2 (d, 0)] `at` (p2 (-d/2,0))+hrule :: (InSpace V2 n t, TrailLike t) => n -> t+hrule d = trailLike $ trailFromSegments [straight $ r2 (d, 0)] `at` p2 (-d/2,0)  -- | Create a centered vertical (T-B) line of the given length. --@@ -79,14 +84,14 @@ -- --   > vruleEx = hcat' (with & sep .~ 0.2) (map vrule [1, 1.2 .. 2]) --   >         # centerXY # pad 1.1-vrule :: (TrailLike t, V t ~ R2) => Double -> t-vrule d = trailLike $ trailFromSegments [straight $ r2 (0, (-d))] `at` (p2 (0,d/2))+vrule :: (InSpace V2 n t, TrailLike t) => n -> t+vrule d = trailLike $ trailFromSegments [straight $ r2 (0, -d)] `at` p2 (0,d/2)  -- | A square with its center at the origin and sides of length 1, --   oriented parallel to the axes. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_unitSquareEx.svg#diagram=unitSquareEx&width=100>>-unitSquare :: (TrailLike t, V t ~ R2) => t+unitSquare :: (InSpace V2 n t, TrailLike t) => t unitSquare = polygon (def & polyType   .~ PolyRegular 4 (sqrt 2 / 2)                           & polyOrient .~ OrientH) @@ -96,7 +101,7 @@ --   length, oriented parallel to the axes. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_squareEx.svg#diagram=squareEx&width=200>>-square :: (TrailLike t, Transformable t, V t ~ R2) => Double -> t+square :: (InSpace V2 n t, TrailLike t) => n -> t square d = rect d d  -- > squareEx = hcat' (with & sep .~ 0.5) [square 1, square 2, square 3]@@ -106,7 +111,7 @@ --   @h@, centered at the origin. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_rectEx.svg#diagram=rectEx&width=150>>-rect :: (TrailLike t, Transformable t, V t ~ R2) => Double -> Double -> t+rect :: (InSpace V2 n t, TrailLike t) => n -> n -> t rect w h = trailLike . head . op Path $ unitSquare # scaleX w # scaleY h  -- > rectEx = rect 1 0.7 # pad 1.1@@ -138,7 +143,7 @@ --   polygons of a given /radius/). -- --   The polygon will be oriented with one edge parallel to the x-axis.-regPoly :: (TrailLike t, V t ~ R2) => Int -> Double -> t+regPoly :: (InSpace V2 n t, TrailLike t) => Int -> n -> t regPoly n l = polygon (def & polyType .~                                PolySides                                  (repeat (1/fromIntegral n @@ turn))@@ -158,90 +163,90 @@ -- > dodecagonEx  = shapeEx dodecagon  -- | A synonym for 'triangle', provided for backwards compatibility.-eqTriangle :: (TrailLike t, V t ~ R2) => Double -> t+eqTriangle :: (InSpace V2 n t, TrailLike t) => n -> t eqTriangle = triangle  -- | An equilateral triangle, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_triangleEx.svg#diagram=triangleEx&width=100>>-triangle :: (TrailLike t, V t ~ R2) => Double -> t+triangle :: (InSpace V2 n t, TrailLike t) => n -> t triangle = regPoly 3  -- | A regular pentagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_pentagonEx.svg#diagram=pentagonEx&width=100>>-pentagon :: (TrailLike t, V t ~ R2) => Double -> t+pentagon :: (InSpace V2 n t, TrailLike t) => n -> t pentagon = regPoly 5  -- | A regular hexagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_hexagonEx.svg#diagram=hexagonEx&width=100>>-hexagon :: (TrailLike t, V t ~ R2) => Double -> t+hexagon :: (InSpace V2 n t, TrailLike t) => n -> t hexagon = regPoly 6  -- | A regular heptagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_heptagonEx.svg#diagram=heptagonEx&width=100>>-heptagon :: (TrailLike t, V t ~ R2) => Double -> t+heptagon :: (InSpace V2 n t, TrailLike t) => n -> t heptagon = regPoly 7  -- | A synonym for 'heptagon'.  It is, however, completely inferior, --   being a base admixture of the Latin /septum/ (seven) and the --   Greek γωνία (angle).-septagon :: (TrailLike t, V t ~ R2) => Double -> t+septagon :: (InSpace V2 n t, TrailLike t) => n -> t septagon = heptagon  -- | A regular octagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_octagonEx.svg#diagram=octagonEx&width=100>>-octagon :: (TrailLike t, V t ~ R2) => Double -> t+octagon :: (InSpace V2 n t, TrailLike t) => n -> t octagon = regPoly 8  -- | A regular nonagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_nonagonEx.svg#diagram=nonagonEx&width=100>>-nonagon :: (TrailLike t, V t ~ R2) => Double -> t+nonagon :: (InSpace V2 n t, TrailLike t) => n -> t nonagon = regPoly 9  -- | A regular decagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_decagonEx.svg#diagram=decagonEx&width=100>>-decagon :: (TrailLike t, V t ~ R2) => Double -> t+decagon :: (InSpace V2 n t, TrailLike t) => n -> t decagon = regPoly 10  -- | A regular hendecagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_hendecagonEx.svg#diagram=hendecagonEx&width=100>>-hendecagon :: (TrailLike t, V t ~ R2) => Double -> t+hendecagon :: (InSpace V2 n t, TrailLike t) => n -> t hendecagon = regPoly 11  -- | A regular dodecagon, with sides of the given length and base --   parallel to the x-axis. -- --   <<diagrams/src_Diagrams_TwoD_Shapes_dodecagonEx.svg#diagram=dodecagonEx&width=100>>-dodecagon :: (TrailLike t, V t ~ R2) => Double -> t+dodecagon :: (InSpace V2 n t, TrailLike t) => n -> t dodecagon = regPoly 12  ------------------------------------------------------------ --  Other shapes  ------------------------------------------ -------------------------------------------------------------data RoundedRectOpts = RoundedRectOpts { _radiusTL :: Double-                                       , _radiusTR :: Double-                                       , _radiusBL :: Double-                                       , _radiusBR :: Double-                                       }+data RoundedRectOpts d = RoundedRectOpts { _radiusTL :: d+                                         , _radiusTR :: d+                                         , _radiusBL :: d+                                         , _radiusBR :: d+                                         }  makeLenses ''RoundedRectOpts -instance Default RoundedRectOpts where+instance (Num d) => Default (RoundedRectOpts d) where   def = RoundedRectOpts 0 0 0 0  -- | @roundedRect w h r@ generates a closed trail, or closed path@@ -265,7 +270,7 @@ --   >                                & radiusBR .~ 0.1) --   >   ] -roundedRect :: (TrailLike t, V t ~ R2) => Double -> Double -> Double -> t+roundedRect :: (InSpace V2 n t, TrailLike t, RealFloat n) => n -> n -> n -> t roundedRect w h r = roundedRect' w h (def & radiusTL .~ r                                           & radiusBR .~ r                                           & radiusTR .~ r@@ -275,10 +280,10 @@ --   each corner indivually, using @RoundedRectOpts@. The default corner radius is 0. --   Each radius can also be negative, which results in the curves being reversed --   to be inward instead of outward.-roundedRect' :: (TrailLike t, V t ~ R2) => Double -> Double -> RoundedRectOpts -> t+roundedRect' :: (InSpace V2 n t, TrailLike t, RealFloat n) => n -> n -> RoundedRectOpts n -> t roundedRect' w h opts    = trailLike-   . (`at` (p2 (w/2, abs rBR - h/2)))+   . (`at` p2 (w/2, abs rBR - h/2))    . wrapTrail    . glueLine    $ seg (0, h - abs rTR - abs rBR)@@ -310,6 +315,8 @@                                 else r         sign n = if n < 0 then -1 else 1         mkCorner k r | r == 0    = mempty-                     | r < 0     = doArc 3 2+                     | r < 0     = doArc 3 (-1)                      | otherwise = doArc 0 1-                     where doArc d d' = arc' r ((k+d)/4 @@ turn) ((k+d')/4 @@ turn)+                     where+                       doArc d s =+                           arc' r (xDir & _theta <>~ ((k+d)/4 @@ turn)) (s/4 @@ turn)
src/Diagrams/TwoD/Size.hs view
@@ -1,8 +1,7 @@-{-# LANGUAGE DeriveGeneric    #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies     #-} -{-# OPTIONS_GHC -funbox-strict-fields #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Size@@ -15,143 +14,65 @@ ----------------------------------------------------------------------------- module Diagrams.TwoD.Size        (-         -- * Size and extent of diagrams in R2          -- ** Computing sizes-         width, height, size2D, sizeSpec2D-       , extentX, extentY, center2D+         width, height+       , extentX, extentY           -- ** Specifying sizes-       , SizeSpec2D(..)-       , mkSizeSpec--       , requiredScaleT, requiredScale+       , mkSizeSpec2D+       , mkWidth+       , mkHeight+       , dims2D -         -- ** Changing the size of things-       , sized, sizedAs, sizePair        ) where  import           Diagrams.Core+import           Diagrams.Core.Envelope+import           Diagrams.Size import           Diagrams.TwoD.Types import           Diagrams.TwoD.Vector -import           Control.Applicative  (liftA2, (<$>))-import           Control.Arrow        ((&&&), (***))-import           Data.Hashable        (Hashable)-import           GHC.Generics         (Generic)- ------------------------------------------------------------ -- Computing diagram sizes ------------------------------------------------------------  -- | Compute the width of an enveloped object.-width :: (Enveloped a, V a ~ R2) => a -> Double-width = maybe 0 (negate . uncurry (-)) . extentX+--+--   Note this is just @diameter unitX@.+width :: (InSpace V2 n a, Enveloped a) => a -> n+width = diameter unitX  -- | Compute the height of an enveloped object.-height :: (Enveloped a, V a ~ R2) => a -> Double-height = maybe 0 (negate . uncurry (-)) . extentY---- | Compute the width and height of an enveloped object.-size2D :: (Enveloped a, V a ~ R2) => a -> (Double, Double)-size2D = width &&& height---- | Compute the size of an enveloped object as a 'SizeSpec2D' value.-sizeSpec2D :: (Enveloped a, V a ~ R2) => a -> SizeSpec2D-sizeSpec2D = uncurry Dims . size2D+height :: (InSpace V2 n a, Enveloped a) => a -> n+height = diameter unitY --- | Compute the absolute  x-coordinate range of an enveloped object in---   R2, in  the form (lo,hi).   Return @Nothing@ for objects  with an---   empty envelope.-extentX :: (Enveloped a, V a ~ R2) => a -> Maybe (Double, Double)-extentX d = (\f -> (-f unit_X, f unitX)) <$> (appEnvelope . getEnvelope $ d)+-- | Compute the absolute x-coordinate range of an enveloped object in+--   the form @(lo,hi)@. Return @Nothing@ for objects with an empty+--   envelope.+--+--   Note this is just @extent unitX@.+extentX :: (InSpace v n a, R1 v, Enveloped a) => a -> Maybe (n, n)+extentX = extent unitX  -- | Compute the absolute y-coordinate range of an enveloped object in---   R2, in the form (lo,hi).-extentY :: (Enveloped a, V a ~ R2) => a -> Maybe (Double, Double)-extentY d = (\f -> (-f unit_Y, f unitY)) <$> (appEnvelope . getEnvelope $ d)---- | Compute the point at the center (in the x- and y-directions) of a---   enveloped object.  Return the origin for objects with an empty+--   the form @(lo,hi)@. Return @Nothing@ for objects with an empty --   envelope.-center2D :: (Enveloped a, V a ~ R2) => a -> P2-center2D = maybe origin (p2 . (mid *** mid)) . mm . (extentX &&& extentY)-  where mm = uncurry (liftA2 (,))-        mid = (/2) . uncurry (+)----------------------------------------------------------------- Size specifications----------------------------------------------------------------- | A specification of a (requested) rectangular size.-data SizeSpec2D = Width  !Double       -- ^ Specify an explicit-                                      -- width. The height should be-                                      -- determined automatically (so-                                      -- as to preserve aspect ratio).-                | Height !Double       -- ^ Specify an explicit-                                      -- height. The width should be-                                      -- determined automatically (so-                                      -- as to preserve aspect ratio).-                | Dims !Double !Double  -- ^ An explicit specification-                                      -- of a width and height.-                | Absolute            -- ^ Absolute size: use whatever-                                      -- size an object already has;-                                      -- do not rescale.-  deriving (Eq, Ord, Show, Generic)--instance Hashable SizeSpec2D---- | Create a size specification from a possibly-specified width and---   height.-mkSizeSpec :: Maybe Double -> Maybe Double -> SizeSpec2D-mkSizeSpec Nothing  Nothing  = Absolute-mkSizeSpec (Just w) Nothing  = Width w-mkSizeSpec Nothing  (Just h) = Height h-mkSizeSpec (Just w) (Just h) = Dims w h+extentY :: (InSpace v n a, R2 v, Enveloped a) => a -> Maybe (n, n)+extentY = extent unitY --- | @requiredScaleT spec sz@ returns a transformation (a uniform scale)---   which can be applied to something of size @sz@ to make it fit the---   requested size @spec@, without changing the aspect ratio.-requiredScaleT :: SizeSpec2D -> (Double, Double) -> Transformation R2-requiredScaleT spec size = scaling (requiredScale spec size)+-- | Make a 'SizeSpec' from possibly-specified width and height.+mkSizeSpec2D :: Num n => Maybe n -> Maybe n -> SizeSpec V2 n+mkSizeSpec2D x y = mkSizeSpec (V2 x y) --- | @requiredScale spec sz@ returns a scaling factor necessary to---   make something of size @sz@ fit the requested size @spec@,---   without changing the aspect ratio.  Hence an explicit---   specification of both dimensions may not be honored if the aspect---   ratios do not match; in that case the scaling will be as large as---   possible so that the object still fits within the requested size.-requiredScale :: SizeSpec2D -> (Double, Double) -> Double-requiredScale Absolute _    = 1-requiredScale (Width wSpec) (w,_)-  | wSpec == 0 || w == 0 = 1-  | otherwise            = wSpec / w-requiredScale (Height hSpec) (_,h)-  | hSpec == 0 || h == 0 = 1-  | otherwise            = hSpec / h-requiredScale (Dims wSpec hSpec) (w,h) = s-  where xscale  = wSpec / w-        yscale  = hSpec / h-        s'      = min xscale yscale-        s | isInfinite s' = 1-          | otherwise     = s'+-- | Make a 'SizeSpec' from a width and height.+dims2D :: n -> n -> SizeSpec V2 n+dims2D x y = dims (V2 x y) --- | Uniformly scale any enveloped object so that it fits within the---   given size.-sized :: (Transformable a, Enveloped a, V a ~ R2)-      => SizeSpec2D -> a -> a-sized spec a = transform (requiredScaleT spec (size2D a)) a+-- | Make a 'SizeSpec' with only width defined.+mkWidth :: Num n => n -> SizeSpec V2 n+mkWidth w = dims (V2 w 0) --- | Uniformly scale an enveloped object so that it \"has the same---   size as\" (fits within the width and height of) some other---   object.-sizedAs :: ( Transformable a, Enveloped a, V a ~ R2-           , Enveloped b, V b ~ R2)-        => b -> a -> a-sizedAs other = sized (sizeSpec2D other)+-- | Make a 'SizeSpec' with only height defined.+mkHeight :: Num n => n -> SizeSpec V2 n+mkHeight h = dims (V2 0 h) --- | Make width and height of `SizeSpec2D` into a tuple.-sizePair :: SizeSpec2D -> (Double, Double)-sizePair (Width w')   = (w',w')-sizePair (Height h')  = (h',h')-sizePair (Dims w' h') = (w',h')-sizePair Absolute     = (100,100)
src/Diagrams/TwoD/Text.hs view
@@ -1,12 +1,17 @@+{-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DeriveDataTypeable         #-} {-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE UndecidableInstances       #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Text--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -18,72 +23,99 @@   -- * Creating text diagrams     Text(..), TextAlignment(..)   , text, topLeftText, alignedText, baselineText+  , mkText, mkText'    -- * Text attributes+   -- ** Font family-  , Font(..), getFont, font+  , Font(..), _Font+  , getFont, font, _font+   -- ** Font size-  , FontSize(..), getFontSize, getFontSizeIsLocal, fontSizeA, fontSize+  , FontSize(..), _FontSize+  , fontSize, recommendFontSize   , fontSizeN, fontSizeO, fontSizeL, fontSizeG+  , getFontSize, fontSizeM+  , _fontSizeR, _fontSize, _fontSizeU+   -- ** Font slant-  , FontSlant(..), FontSlantA, getFontSlant, fontSlant, italic, oblique+  , FontSlant(..)+  , getFontSlant, fontSlant, italic, oblique, _fontSlant+   -- ** Font weight-  , FontWeight(..), FontWeightA, getFontWeight, fontWeight, bold+  , FontWeight(..)+  , getFontWeight, fontWeight, bold, bolder, lighter, _fontWeight+  , thinWeight, ultraLight, light, mediumWeight, heavy, semiBold, ultraBold+   ) where +import           Control.Lens             hiding (transform)+import           Diagrams.Attributes      (committed) import           Diagrams.Core import           Diagrams.Core.Envelope   (pointEnvelope) import           Diagrams.TwoD.Attributes (recommendFillColor) import           Diagrams.TwoD.Types -import           Data.AffineSpace         ((.-.))-import           Data.Colour-import           Data.Data-import           Data.Default.Class+import           Data.Colour              hiding (over)+import           Data.Default+import           Data.Monoid.Recommend import           Data.Semigroup+import           Data.Typeable +import           Linear.Affine+ ------------------------------------------------------------ -- Text diagrams ------------------------------------------------------------ --- | A text primitive consists of the string contents and alignment---   specification, along with two transformations: the first---   accumulates all transformations which have been applied to the---   text; the second accumulates normalized, "anti-scaled" versions---   of the transformations which have had their average scaling---   component removed.-data Text = Text T2 T2 TextAlignment String+-- | A 'Text' primitive consists of the string contents, text alignment+--   and the transformation to be applied. The transformation is scale+--   invarient, the average scale of the transform should always be 1.+--   All text scaling is obtained from the 'FontSize' attribute.+--+--   This constructor should not be used directly. Use 'text',+--   'alignedText' or 'baselineText'.+data Text n = Text (T2 n) (TextAlignment n) String   deriving Typeable -type instance V Text = R2+type instance V (Text n) = V2+type instance N (Text n) = n -instance Transformable Text where-  transform t (Text tt tn a s) = Text (t <> tt) (t <> tn <> t') a s-    where-      t' = scaling (1 / avgScale t)-      -- It's important that the anti-scaling is applied *first*,-      -- followed by the old transformation tn and then the new-      -- transformation t.  That way translation is handled properly.+instance Floating n => Transformable (Text n) where+  transform t (Text tt a s) = Text (t <> tt <> t') a s+    where t' = scaling (1 / avgScale t) -instance HasOrigin Text where+instance Floating n => HasOrigin (Text n) where   moveOriginTo p = translate (origin .-. p) -instance Renderable Text NullBackend where+instance Floating n => Renderable (Text n) NullBackend where   render _ _ = mempty  -- | @TextAlignment@ specifies the alignment of the text's origin.-data TextAlignment = BaselineText | BoxAlignedText Double Double+data TextAlignment n = BaselineText | BoxAlignedText n n -mkText :: Renderable Text b => TextAlignment -> String -> Diagram b R2-mkText a t = recommendFillColor (black :: Colour Double)-             -- See Note [recommendFillColor]+-- | Make a text from a 'TextAlignment', recommending a fill colour of+--   'black' and 'fontSize' of @'local' 1@.+mkText :: (TypeableFloat n, Renderable (Text n) b)+  => TextAlignment n -> String -> QDiagram b V2 n Any+mkText a = recommendFillColor black+           -- See Note [recommendFillColor]+         . recommendFontSize (local 1)+           -- See Note [recommendFontSize]+         . mkText' a -           $ mkQD (Prim (Text mempty mempty a t))-                       (pointEnvelope origin)-                       mempty-                       mempty-                       mempty+-- | Make a text from a 'TextAlignment' without any default size or fill+--   colour. This is useful is you want to recommend your own using+--   'recommendFillColor' or 'recommendFontSize'.+mkText' :: (TypeableFloat n, Renderable (Text n) b)+  => TextAlignment n -> String -> QDiagram b V2 n Any+mkText' a t = mkQD (Prim $ Text mempty a t)+                   (pointEnvelope origin)+                   mempty+                   mempty+                   mempty + -- ~~~~ Note [recommendFillColor]  -- The reason we "recommend" a fill color of black instead of setting@@ -106,12 +138,16 @@ -- recommendation; normally, the innermost occurrence of an attribute -- would override all outer occurrences. +-- ~~~~ Note [recommendFontSize]+-- The reason we "recommend" a font size is so any local scales get+-- recorded.+ -- | Create a primitive text diagram from the given string, with center --   alignment, equivalent to @'alignedText' 0.5 0.5@. -- --   Note that it /takes up no space/, as text size information is not --   available.-text :: Renderable Text b => String -> Diagram b R2+text :: (TypeableFloat n, Renderable (Text n) b) => String -> QDiagram b V2 n Any text = alignedText 0.5 0.5  -- | Create a primitive text diagram from the given string, origin at@@ -119,19 +155,21 @@ --   @'alignedText' 0 1@. -- --   Note that it /takes up no space/.-topLeftText :: Renderable Text b => String -> Diagram b R2+topLeftText :: (TypeableFloat n, Renderable (Text n) b) => String -> QDiagram b V2 n Any topLeftText = alignedText 0 1  -- | Create a primitive text diagram from the given string, with the --   origin set to a point interpolated within the bounding box.  The --   first parameter varies from 0 (left) to 1 (right), and the second---   parameter from 0 (bottom) to 1 (top).+--   parameter from 0 (bottom) to 1 (top). Some backends do not+--   implement this and instead snap to closest corner or the center. -- --   The height of this box is determined by the font's potential ascent --   and descent, rather than the height of the particular string. -- --   Note that it /takes up no space/.-alignedText :: Renderable Text b => Double -> Double -> String -> Diagram b R2+alignedText :: (TypeableFloat n, Renderable (Text n) b)+  => n -> n -> String -> QDiagram b V2 n Any alignedText w h = mkText (BoxAlignedText w h)  -- | Create a primitive text diagram from the given string, with the@@ -140,7 +178,8 @@ --   graphics library. -- --   Note that it /takes up no space/.-baselineText :: Renderable Text b => String -> Diagram b R2+baselineText :: (TypeableFloat n, Renderable (Text n) b)+  => String -> QDiagram b V2 n Any baselineText = mkText BaselineText  ------------------------------------------------------------@@ -154,6 +193,10 @@ --   @Font@ attributes override outer ones. newtype Font = Font (Last String)   deriving (Typeable, Semigroup, Eq)++_Font :: Iso' Font String+_Font = iso getFont (Font . Last)+ instance AttributeClass Font  -- | Extract the font family name from a @Font@ attribute.@@ -164,94 +207,123 @@ font :: HasStyle a => String -> a -> a font = applyAttr . Font . Last +-- | Lens onto the font name of a style.+_font :: Lens' (Style v n) (Maybe String)+_font = atAttr . mapping _Font+ -------------------------------------------------- -- Font size  -- | The @FontSize@ attribute specifies the size of a font's --   em-square.  Inner @FontSize@ attributes override outer ones.-newtype FontSize = FontSize (Last (Measure R2, Bool))-  deriving (Typeable, Data, Semigroup)-instance AttributeClass FontSize+newtype FontSize n = FontSize (Recommend (Last n))+  deriving (Typeable, Semigroup) --- Note, the Bool stored in the FontSize indicates whether it started--- life as Local.  Typically, if the Bool is True, backends should use--- the first T2 value stored in a Text object; otherwise, the second--- (anti-scaled) T2 value should be used.+-- not sure why this can't be derived+instance Functor FontSize where+  fmap f (FontSize (Recommend (Last a))) = FontSize (Recommend (Last (f a)))+  fmap f (FontSize (Commit (Last a)))    = FontSize (Commit (Last (f a))) -type instance V FontSize = R2+_FontSize :: Iso' (FontSize n) (Recommend n)+_FontSize = iso getter setter+  where getter (FontSize (Recommend (Last a))) = Recommend a+        getter (FontSize (Commit    (Last a))) = Commit a+        setter (Recommend a) = FontSize $ Recommend (Last a)+        setter (Commit    a) = FontSize $ Commit (Last a)+      -- = iso (\(FontSize a) -> a) FontSize . mapping _Wrapped+      -- once we depend on monoid-extras-0.4 -instance Default FontSize where-    def = FontSize (Last (Local 1, True))+_FontSizeM :: Iso' (FontSizeM n) (Measured n (Recommend n))+_FontSizeM = mapping _FontSize --- FontSize has to be Transformable + also have an instance of Data,--- so the Measure inside it will be automatically converted to Output.--- However, we don't actually want the Transformable instance to do--- anything.  All the scaling of text happens not by manipulating the--- font size but by accumulating T2 values in Text objects.-instance Transformable FontSize where-  transform _ f = f+type FontSizeM n = Measured n (FontSize n) --- | Extract the size from a @FontSize@ attribute.-getFontSize :: FontSize -> Measure R2-getFontSize (FontSize (Last (s,_))) = s+instance Typeable n => AttributeClass (FontSize n) --- | Determine whether a @FontSize@ attribute began its life measured---   in 'Local' units.-getFontSizeIsLocal :: FontSize -> Bool-getFontSizeIsLocal (FontSize (Last (_,b))) = b+instance Num n => Default (FontSizeM n) where+  def = FontSize . Recommend . Last <$> local 1 +-- | Extract the size from a @FontSize@ attribute.+getFontSize :: FontSize n -> n+getFontSize (FontSize (Recommend (Last s))) = s+getFontSize (FontSize (Commit (Last s)))    = s+ -- | Set the font size, that is, the size of the font's em-square as---   measured within the current local vector space.  The default size---   is @1@.-fontSize :: (HasStyle a, V a ~ R2) => Measure R2 -> a -> a-fontSize m@(Local {}) = applyGTAttr . FontSize . Last $ (m,True)-fontSize m            = applyGTAttr . FontSize . Last $ (m,False)+--   measured within the current local vector space. The default size+--   is @local 1@ (which is applied by 'recommendFontSize').+fontSize :: (N a ~ n, Typeable n, HasStyle a) => Measure n -> a -> a+fontSize = applyMAttr . fmap (FontSize . Commit . Last) +-- | 'Recommend' a font size. Any use of 'fontSize' above this will+--   overwrite any recommended size. This should only be used with+--   'mkText'', other text functions already has a recommended font+--   size so this will be ignored.+recommendFontSize :: (N a ~ n, Typeable n, HasStyle a) => Measure n -> a -> a+recommendFontSize = applyMAttr . fmap (FontSize . Recommend . Last)+ -- | A convenient synonym for 'fontSize (Global w)'.-fontSizeG :: (HasStyle a, V a ~ R2) => Double -> a -> a-fontSizeG w = fontSize (Global w)+fontSizeG :: (N a ~ n, Typeable n, Num n, HasStyle a) => n -> a -> a+fontSizeG = fontSize . global  -- | A convenient synonym for 'fontSize (Normalized w)'.-fontSizeN :: (HasStyle a, V a ~ R2) => Double -> a -> a-fontSizeN w = fontSize (Normalized w)+fontSizeN :: (N a ~ n, Typeable n, Num n, HasStyle a) => n -> a -> a+fontSizeN = fontSize . normalized  -- | A convenient synonym for 'fontSize (Output w)'.-fontSizeO :: (HasStyle a, V a ~ R2) => Double -> a -> a-fontSizeO w = fontSize (Output w)+fontSizeO :: (N a ~ n, Typeable n, HasStyle a) => n -> a -> a+fontSizeO = fontSize . output  -- | A convenient sysnonym for 'fontSize (Local w)'.-fontSizeL :: (HasStyle a, V a ~ R2) => Double -> a -> a-fontSizeL w = fontSize (Local w)+fontSizeL :: (N a ~ n, Typeable n, Num n, HasStyle a) => n -> a -> a+fontSizeL = fontSize . local  -- | Apply a 'FontSize' attribute.-fontSizeA :: (HasStyle a, V a ~ R2) => FontSize -> a -> a-fontSizeA = applyGTAttr+fontSizeM :: (N a ~ n, Typeable n, HasStyle a) => FontSizeM n -> a -> a+fontSizeM = applyMAttr +_fontSizeR :: (Typeable n, OrderedField n) => Lens' (Style v n) (Measured n (Recommend n))+_fontSizeR = atMAttr . anon def (const False) . _FontSizeM++-- | Lens to commit a font size. This is *not* a valid lens (see+--   'commited'.+_fontSize :: (Typeable n, OrderedField n) => Lens' (Style v n) (Measure n)+_fontSize = _fontSizeR . mapping committed++_fontSizeU :: (Typeable n) => Lens' (Style v n) (Maybe n)+_fontSizeU = atAttr . mapping (_FontSize . committed)+ -------------------------------------------------- -- Font slant +-- | The @FontSlantA@ attribute specifies the slant (normal, italic,+--   or oblique) that should be used for all text within a diagram.+--   Inner @FontSlantA@ attributes override outer ones. data FontSlant = FontSlantNormal                | FontSlantItalic                | FontSlantOblique-    deriving (Eq)+  deriving (Eq, Show, Typeable, Ord) --- | The @FontSlantA@ attribute specifies the slant (normal, italic,---   or oblique) that should be used for all text within a diagram.---   Inner @FontSlantA@ attributes override outer ones.-newtype FontSlantA = FontSlantA (Last FontSlant)-  deriving (Typeable, Semigroup, Eq)-instance AttributeClass FontSlantA+instance AttributeClass FontSlant where+instance Semigroup FontSlant where+  _ <> b = b +instance Default FontSlant where+  def = FontSlantNormal+ -- | Extract the font slant from a 'FontSlantA' attribute.-getFontSlant :: FontSlantA -> FontSlant-getFontSlant (FontSlantA (Last s)) = s+getFontSlant :: FontSlant -> FontSlant+getFontSlant = id  -- | Specify the slant (normal, italic, or oblique) that should be --   used for all text within a diagram.  See also 'italic' and --   'oblique' for useful special cases. fontSlant :: HasStyle a => FontSlant -> a -> a-fontSlant = applyAttr . FontSlantA . Last+fontSlant = applyAttr +-- | Lens onto the font slant in a style.+_fontSlant :: Lens' (Style v n) FontSlant+_fontSlant = atAttr . non def+ -- | Set all text in italics. italic :: HasStyle a => a -> a italic = fontSlant FontSlantItalic@@ -263,27 +335,82 @@ -------------------------------------------------- -- Font weight -data FontWeight = FontWeightNormal-                | FontWeightBold-    deriving (Eq)- -- | The @FontWeightA@ attribute specifies the weight (normal or bold) --   that should be used for all text within a diagram.  Inner --   @FontWeightA@ attributes override outer ones.-newtype FontWeightA = FontWeightA (Last FontWeight)-  deriving (Typeable, Semigroup, Eq)-instance AttributeClass FontWeightA+data FontWeight = FontWeightNormal+                | FontWeightBold+                | FontWeightBolder+                | FontWeightLighter+                | FontWeightThin+                | FontWeightUltraLight+                | FontWeightLight+                | FontWeightMedium+                | FontWeightSemiBold+                | FontWeightUltraBold+                | FontWeightHeavy+    deriving (Eq,+              Ord, Show, Typeable) --- | Extract the font weight from a 'FontWeightA' attribute.-getFontWeight :: FontWeightA -> FontWeight-getFontWeight (FontWeightA (Last w)) = w+instance AttributeClass FontWeight --- | Specify the weight (normal or bold) that should be+-- | Last semigroup structure+instance Semigroup FontWeight where+  _ <> b = b++instance Default FontWeight where+  def = FontWeightNormal++-- | Extract the font weight.+getFontWeight :: FontWeight -> FontWeight+getFontWeight = id++-- | Specify the weight (normal, bolder, lighter or bold) that should be --   used for all text within a diagram.  See also 'bold' --   for a useful special case. fontWeight :: HasStyle a => FontWeight -> a -> a-fontWeight = applyAttr . FontWeightA . Last+fontWeight = applyAttr  -- | Set all text using a bold font weight. bold :: HasStyle a => a -> a bold = fontWeight FontWeightBold++-- | Set all text using a thin font weight.+thinWeight :: HasStyle a => a -> a+thinWeight = fontWeight FontWeightThin++-- | Set all text using a extra light font weight.+ultraLight :: HasStyle a => a -> a+ultraLight = fontWeight FontWeightUltraLight++-- | Set all text using a light font weight.+light :: HasStyle a => a -> a+light = fontWeight FontWeightLight++-- | Set all text using a medium font weight.+mediumWeight :: HasStyle a => a -> a+mediumWeight = fontWeight FontWeightMedium++-- | Set all text using a semi-bold font weight.+semiBold :: HasStyle a => a -> a+semiBold = fontWeight FontWeightSemiBold++-- | Set all text using an ultra-bold font weight.+ultraBold :: HasStyle a => a -> a+ultraBold = fontWeight FontWeightUltraBold++-- | Set all text using a heavy/black font weight.+heavy :: HasStyle a => a -> a+heavy = fontWeight FontWeightHeavy++-- | Set all text to be bolder than the inherited font weight.+bolder :: HasStyle a => a -> a+bolder = fontWeight FontWeightBolder++-- | Set all text to be lighter than the inherited font weight.+lighter :: HasStyle a => a -> a+lighter = fontWeight FontWeightLighter++-- | Lens onto the font weight in a style.+_fontWeight :: Lens' (Style v n) FontWeight+_fontWeight = atAttr . non def
src/Diagrams/TwoD/Transform.hs view
@@ -1,12 +1,19 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-} {-# LANGUAGE ViewPatterns          #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+  -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Transform--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -18,10 +25,11 @@  module Diagrams.TwoD.Transform        (+         T2          -- * Rotation-         rotation, rotate, rotateBy--       , rotationAbout, rotateAbout+       , rotation, rotate, rotateBy, rotated+       , rotationAround, rotateAround+       , rotationTo, rotateTo           -- * Scaling        , scalingX, scaleX@@ -36,216 +44,262 @@        , translationY, translateY        , translation, translate +         -- * Conformal affine maps+       , scalingRotationTo, scaleRotateTo+          -- * Reflection        , reflectionX, reflectX        , reflectionY, reflectY+       , reflectionXY, reflectXY        , reflectionAbout, reflectAbout           -- * Shears        , shearingX, shearX        , shearingY, shearY -         -- * Utilities-       , onBasis        ) where -import           Diagrams.Core-import qualified Diagrams.Core.Transform as T- import           Diagrams.Angle+import           Diagrams.Core+import           Diagrams.Core.Transform+import           Diagrams.Direction import           Diagrams.Transform-import           Diagrams.TwoD.Size      (height, width)+import           Diagrams.Transform.Matrix import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector    (direction)-import           Diagrams.Coordinates+import           Diagrams.TwoD.Vector -import           Data.AdditiveGroup-import           Data.AffineSpace+import           Control.Lens              hiding (at, transform) import           Data.Semigroup-import           Control.Lens            (review, (^.)) --- Rotation ------------------------------------------------+import           Linear.Affine+import           Linear.Metric+import           Linear.V2+import           Linear.Vector --- | Create a transformation which performs a rotation about the local---   origin by the given angle.  See also 'rotate'.-rotation :: Angle -> T2-rotation ang = fromLinear r (linv r)-  where-    r            = rot theta <-> rot (-theta)-    theta    = ang^.rad-    rot th (coords -> x :& y) = (cos th * x - sin th * y) ^& (sin th * x + cos th * y)+-- Rotation ------------------------------------------------ --- | Rotate about the local origin by the given angle. Positive angles---   correspond to counterclockwise rotation, negative to---   clockwise. The angle can be expressed using any of the 'Iso's on---   'Angle'.  For example, @rotate (1\/4 \@\@ 'turn')@, @rotate---   (tau\/4 \@\@ rad)@, and @rotate (90 \@\@ deg)@ all---   represent the same transformation, namely, a counterclockwise---   rotation by a right angle.  To rotate about some point other than---   the local origin, see 'rotateAbout'.------   Note that writing @rotate (1\/4)@, with no 'Angle' constructor,---   will yield an error since GHC cannot figure out which sort of---   angle you want to use.  In this common situation you can use---   'rotateBy', which interprets its argument as a number of turns.-rotate :: (Transformable t, V t ~ R2) => Angle -> t -> t-rotate = transform . rotation+-- For the definitions of 'rotation' and 'rotate', see Diagrams.Angle.  -- | A synonym for 'rotate', interpreting its argument in units of -- turns; it can be more convenient to write @rotateBy (1\/4)@ than -- @'rotate' (1\/4 \@\@ 'turn')@.-rotateBy :: (Transformable t, V t ~ R2) => Double -> t -> t+rotateBy :: (InSpace V2 n t, Transformable t, Floating n) => n -> t -> t rotateBy = transform . rotation . review turn +-- | Use an 'Angle' to make an 'Iso' between an object+--   rotated and unrotated. This us useful for performing actions+--   'under' a rotation:+--+-- @+-- under (rotated t) f = rotate (negated t) . f . rotate t+-- rotated t ## a      = rotate t a+-- a ^. rotated t      = rotate (-t) a+-- over (rotated t) f  = rotate t . f . rotate (negated t)+-- @+rotated :: (InSpace V2 n a, Floating n, SameSpace a b, Transformable a, Transformable b)+        => Angle n -> Iso a b a b+rotated a = transformed $ rotation a+ -- | @rotationAbout p@ is a rotation about the point @p@ (instead of --   around the local origin).-rotationAbout :: P2 -> Angle -> T2-rotationAbout p angle = conjugate (translation (origin .-. p)) (rotation angle)+rotationAround :: Floating n => P2 n -> Angle n -> T2 n+rotationAround p theta =+  conjugate (translation (origin .-. p)) (rotation theta)  -- | @rotateAbout p@ is like 'rotate', except it rotates around the --   point @p@ instead of around the local origin.-rotateAbout :: (Transformable t, V t ~ R2) => P2 -> Angle -> t -> t-rotateAbout p angle = rotate angle `under` translation (origin .-. p)+rotateAround :: (InSpace V2 n t, Transformable t, Floating n)+             => P2 n -> Angle n -> t -> t+rotateAround p theta = transform (rotationAround p theta) +-- | The rotation that aligns the x-axis with the given direction.+rotationTo :: OrderedField n => Direction V2 n -> T2 n+rotationTo (view _Dir -> V2 x y) = rotation (atan2A' y x)++-- | Rotate around the local origin such that the x axis aligns with the+--   given direction.+rotateTo :: (InSpace V2 n t, OrderedField n, Transformable t) => Direction V2 n -> t -> t+rotateTo = transform . rotationTo+ -- Scaling -------------------------------------------------  -- | Construct a transformation which scales by the given factor in --   the x (horizontal) direction.-scalingX :: Double -> T2-scalingX c = fromLinear s s-  where s = (\(R2 x y) -> R2 (x*c) y) <-> (\(R2 x y) -> R2 (x/c) y)+scalingX :: (Additive v, R1 v, Fractional n) => n -> Transformation v n+scalingX c = fromSymmetric $ (_x *~ c) <-> (_x //~ c)  -- | Scale a diagram by the given factor in the x (horizontal) --   direction.  To scale uniformly, use 'scale'.-scaleX :: (Transformable t, V t ~ R2) => Double -> t -> t+scaleX :: (InSpace v n t, R2 v, Fractional n, Transformable t) => n -> t -> t scaleX = transform . scalingX  -- | Construct a transformation which scales by the given factor in --   the y (vertical) direction.-scalingY :: Double -> T2-scalingY c = fromLinear s s-  where s = (\(R2 x y) -> R2 x (y*c)) <-> (\(R2 x y) -> R2 x (y/c))+scalingY :: (Additive v, R2 v, Fractional n) => n -> Transformation v n+scalingY c = fromSymmetric $ (_y *~ c) <-> (_y //~ c)  -- | Scale a diagram by the given factor in the y (vertical) --   direction.  To scale uniformly, use 'scale'.-scaleY :: (Transformable t, V t ~ R2) => Double -> t -> t+scaleY :: (InSpace v n t, R2 v, Fractional n, Transformable t)+  => n -> t -> t scaleY = transform . scalingY  -- | @scaleToX w@ scales a diagram in the x (horizontal) direction by --   whatever factor required to make its width @w@.  @scaleToX@ --   should not be applied to diagrams with a width of 0, such as --   'vrule'.-scaleToX :: (Enveloped t, Transformable t, V t ~ R2) => Double -> t -> t-scaleToX w d = scaleX (w / width d) d+scaleToX :: (InSpace v n t, R2 v, Enveloped t, Transformable t) => n -> t -> t+scaleToX w d = scaleX (w / diameter unitX d) d  -- | @scaleToY h@ scales a diagram in the y (vertical) direction by --   whatever factor required to make its height @h@.  @scaleToY@ --   should not be applied to diagrams with a height of 0, such as --   'hrule'.-scaleToY :: (Enveloped t, Transformable t, V t ~ R2) => Double -> t -> t-scaleToY h d = scaleY (h / height d) d+scaleToY :: (InSpace v n t, R2 v, Enveloped t, Transformable t) => n -> t -> t+scaleToY h d = scaleY (h / diameter unitY d) d  -- | @scaleUToX w@ scales a diagram /uniformly/ by whatever factor --   required to make its width @w@.  @scaleUToX@ should not be --   applied to diagrams with a width of 0, such as 'vrule'.-scaleUToX :: (Enveloped t, Transformable t, V t ~ R2) => Double -> t -> t-scaleUToX w d = scale (w / width d) d+scaleUToX :: (InSpace v n t, R1 v, Enveloped t, Transformable t) => n -> t -> t+scaleUToX w d = scale (w / diameter unitX d) d  -- | @scaleUToY h@ scales a diagram /uniformly/ by whatever factor --   required to make its height @h@.  @scaleUToY@ should not be applied --   to diagrams with a height of 0, such as 'hrule'.-scaleUToY :: (Enveloped t, Transformable t, V t ~ R2) => Double -> t -> t-scaleUToY h d = scale (h / height d) d+scaleUToY :: (InSpace v n t, R2 v, Enveloped t, Transformable t) => n -> t -> t+scaleUToY h d = scale (h / diameter unitY d) d  -- Translation ---------------------------------------------  -- | Construct a transformation which translates by the given distance --   in the x (horizontal) direction.-translationX :: Double -> T2-translationX x = translation (x ^& 0)+translationX :: (Additive v, R1 v, Num n) => n -> Transformation v n+translationX x = translation (zero & _x .~ x)  -- | Translate a diagram by the given distance in the x (horizontal) --   direction.-translateX :: (Transformable t, V t ~ R2) => Double -> t -> t+translateX :: (InSpace v n t, R1 v, Transformable t) => n -> t -> t translateX = transform . translationX  -- | Construct a transformation which translates by the given distance --   in the y (vertical) direction.-translationY :: Double -> T2-translationY y = translation (0 ^& y)+translationY :: (Additive v, R2 v, Num n) => n -> Transformation v n+translationY y = translation (zero & _y .~ y)  -- | Translate a diagram by the given distance in the y (vertical) --   direction.-translateY :: (Transformable t, V t ~ R2) => Double -> t -> t+translateY :: (InSpace v n t, R2 v, Transformable t)+  => n -> t -> t translateY = transform . translationY +-- Conformal affine maps -----------------------------------++-- | The angle-preserving linear map that aligns the x-axis unit vector+--   with the given vector.  See also 'scaleRotateTo'.+scalingRotationTo :: (Floating n) => V2 n -> T2 n+scalingRotationTo v = fromMatWithInv (conf v) (conf w) zero+  where+    w = reflectY (v ^/ quadrance v)+    conf (V2 a b) = (V2 (V2 a (-b)) (V2 b a))++-- | Rotate and uniformly scale around the local origin such that the+--   x-axis aligns with the given vector.  This satisfies the equation+--+-- @+-- scaleRotateTo v = rotateTo (dir v) . scale (norm v)+-- @+--+-- up to floating point rounding errors, but is more accurate and+-- performant since it avoids cancellable uses of trigonometric functions.+scaleRotateTo :: (InSpace V2 n t, Transformable t, Floating n)+              => V2 n -> t -> t+scaleRotateTo = transform . scalingRotationTo+ -- Reflection ----------------------------------------------  -- | Construct a transformation which flips a diagram from left to --   right, i.e. sends the point (x,y) to (-x,y).-reflectionX :: T2-reflectionX = scalingX (-1)+reflectionX :: (Additive v, R1 v, Num n) => Transformation v n+reflectionX = fromSymmetric $ (_x *~ (-1)) <-> (_x *~ (-1))  -- | Flip a diagram from left to right, i.e. send the point (x,y) to --   (-x,y).-reflectX :: (Transformable t, V t ~ R2) => t -> t+reflectX :: (InSpace v n t, R1 v, Transformable t) => t -> t reflectX = transform reflectionX  -- | Construct a transformation which flips a diagram from top to --   bottom, i.e. sends the point (x,y) to (x,-y).-reflectionY :: T2-reflectionY = scalingY (-1)+reflectionY :: (Additive v, R2 v, Num n) => Transformation v n+reflectionY = fromSymmetric $ (_y *~ (-1)) <-> (_y *~ (-1))  -- | Flip a diagram from top to bottom, i.e. send the point (x,y) to --   (x,-y).-reflectY :: (Transformable t, V t ~ R2) => t -> t+reflectY :: (InSpace v n t, R2 v, Transformable t) => t -> t reflectY = transform reflectionY --- | @reflectionAbout p v@ is a reflection in the line determined by---   the point @p@ and vector @v@.-reflectionAbout :: P2 -> R2 -> T2-reflectionAbout p v =-  conjugate (rotation (negateV $ direction v) <> translation (origin .-. p))+-- | Construct a transformation which flips the diagram about x=y, i.e.+--   sends the point (x,y) to (y,x).+reflectionXY :: (Additive v, R2 v, Num n) => Transformation v n+reflectionXY = fromSymmetric $ (_xy %~ view _yx) <-> (_xy %~ view _yx)++-- | Flips the diagram about x=y, i.e. send the point (x,y) to (y,x).+reflectXY :: (InSpace v n t, R2 v, Transformable t) => t -> t+reflectXY = transform reflectionXY++-- | @reflectionAbout p d@ is a reflection in the line determined by+--   the point @p@ and direction @d@.+reflectionAbout :: OrderedField n => P2 n -> Direction V2 n -> T2 n+reflectionAbout p d =+  conjugate (rotationTo (reflectY d) <> translation (origin .-. p))             reflectionY --- | @reflectAbout p v@ reflects a diagram in the line determined by---   the point @p@ and the vector @v@.-reflectAbout :: (Transformable t, V t ~ R2) => P2 -> R2 -> t -> t++++-- | @reflectAbout p d@ reflects a diagram in the line determined by+--   the point @p@ and direction @d@.+reflectAbout :: (InSpace V2 n t, OrderedField n, Transformable t)+             => P2 n -> Direction V2 n -> t -> t reflectAbout p v = transform (reflectionAbout p v)  -- Shears -------------------------------------------------- +-- auxiliary functions for shearingX/shearingY+sh :: (n -> n -> n -> n) -> (n -> n -> n -> n) -> n -> V2 n -> V2 n+sh f g k (V2 x y) = V2 (f k x y) (g k x y)++sh' :: (n -> n -> n -> n) -> (n -> n -> n -> n) -> n -> V2 n -> V2 n+sh' f g k = swap . sh f g k . swap++swap :: V2 n -> V2 n+swap (V2 x y) = V2 y x+{-# INLINE swap #-}+ -- | @shearingX d@ is the linear transformation which is the identity on --   y coordinates and sends @(0,1)@ to @(d,1)@.-shearingX :: Double -> T2-shearingX d = fromLinear (sh d  <-> sh (-d))-                         (sh' d <-> sh' (-d))-  where sh  k (R2 x y) = R2 (x+k*y) y-        sh' k          = swap . sh k . swap-        swap (R2 x y)  = R2 y x+shearingX :: Num n => n -> T2 n+shearingX d = fromLinear (sh f g d  <-> sh f g (-d))+                         (sh' f g d <-> sh' f g (-d))+  where+    f k x y = x + k*y+    g _ _ y = y  -- | @shearX d@ performs a shear in the x-direction which sends --   @(0,1)@ to @(d,1)@.-shearX :: (Transformable t, V t ~ R2) => Double -> t -> t+shearX :: (InSpace V2 n t, Transformable t) => n -> t -> t shearX = transform . shearingX  -- | @shearingY d@ is the linear transformation which is the identity on --   x coordinates and sends @(1,0)@ to @(1,d)@.-shearingY :: Double -> T2-shearingY d = fromLinear (sh d  <-> sh (-d))-                         (sh' d <-> sh' (-d))-  where sh  k (R2 x y) = R2 x (y+k*x)-        sh' k          = swap . sh k . swap-        swap (R2 x y)  = R2 y x+shearingY :: Num n => n -> T2 n+shearingY d = fromLinear (sh f g d  <-> sh f g (-d))+                         (sh' f g d <-> sh' f g (-d))+        where+          f _ x _ = x+          g k x y = y + k*x  -- | @shearY d@ performs a shear in the y-direction which sends --   @(1,0)@ to @(1,d)@.-shearY :: (Transformable t, V t ~ R2) => Double -> t -> t+shearY :: (InSpace V2 n t, Transformable t) => n -> t -> t shearY = transform . shearingY---- | Get the matrix equivalent of the linear transform,---   (as a pair of columns) and the translation vector.  This---   is mostly useful for implementing backends.-onBasis :: Transformation R2 -> ((R2, R2), R2)-onBasis t = ((x, y), v)-  where ((x:y:[]), v) = T.onBasis t
− src/Diagrams/TwoD/Transform/ScaleInv.hs
@@ -1,173 +0,0 @@-{-# LANGUAGE DeriveDataTypeable    #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell       #-}-{-# LANGUAGE TypeFamilies          #-}--------------------------------------------------------------------------------- |--- Module      :  Diagrams.TwoD.Transform.ScaleInv--- Copyright   :  (c) 2012-2013 diagrams-lib team (see LICENSE)--- License     :  BSD-style (see LICENSE)--- Maintainer  :  diagrams-discuss@googlegroups.com------ Wrapper for creating scale-invariant objects in two dimensions.-----------------------------------------------------------------------------------module Diagrams.TwoD.Transform.ScaleInv-    ( ScaleInv(..)-    , scaleInvObj, scaleInvDir, scaleInvLoc-    , scaleInv, scaleInvPrim )-    where--import           Control.Lens            (makeLenses, view)-import           Data.AdditiveGroup-import           Data.AffineSpace        ((.-.))-import           Data.Semigroup-import           Data.Typeable--import           Diagrams.Core-import           Diagrams.TwoD.Transform-import           Diagrams.TwoD.Types-import           Diagrams.TwoD.Vector---- | The @ScaleInv@ wrapper creates two-dimensional /scale-invariant/---   objects.  Intuitively, a scale-invariant object is affected by---   transformations like translations and rotations, but not by scales.------   However, this is problematic when it comes to /non-uniform/---   scales (/e.g./ @scaleX 2 . scaleY 3@) since they can introduce a---   perceived rotational component.  The prototypical example is an---   arrowhead on the end of a path, which should be scale-invariant.---   However, applying a non-uniform scale to the path but not the---   arrowhead would leave the arrowhead pointing in the wrong---   direction.------   Moreover, for objects whose local origin is not at the local---   origin of the parent diagram, any scale can result in a---   translational component as well.------   The solution is to also store a point (indicating the location,---   /i.e./ the local origin) and a unit vector (indicating the---   /direction/) along with a scale-invariant object.  A---   transformation to be applied is decomposed into rotational and---   translational components as follows:------   * The transformation is applied to the direction vector, and the---   difference in angle between the original direction vector and its---   image under the transformation determines the rotational---   component.  The rotation is applied with respect to the stored---   location, rather than the global origin.------   * The vector from the location to the image of the location under---   the transformation determines the translational component.--data ScaleInv t =-  ScaleInv-  { _scaleInvObj :: t-  , _scaleInvDir :: R2-  , _scaleInvLoc :: P2-  }-  deriving (Show, Typeable)--makeLenses ''ScaleInv---- | Create a scale-invariant object pointing in the given direction,---   located at the origin.-scaleInv :: t -> R2 -> ScaleInv t-scaleInv t d = ScaleInv t d origin--type instance V (ScaleInv t) = R2--instance (V t ~ R2, HasOrigin t) => HasOrigin (ScaleInv t) where-  moveOriginTo p (ScaleInv t v l) = ScaleInv (moveOriginTo p t) v (moveOriginTo p l)--instance (V t ~ R2, Transformable t) => Transformable (ScaleInv t) where-  transform tr (ScaleInv t v l) = ScaleInv (trans . rot $ t) (rot v) l'-    where-      angle = direction (transform tr v) ^-^ direction v-      rot :: (Transformable t, V t ~ R2) => t -> t-      rot = rotateAbout l angle-      l'  = transform tr l-      trans = translate (l' .-. l)--{- Proof that the above satisfies the monoid action laws.--   1. transform mempty (ScaleInv t v l)-      = ScaleInv (trans . rot $ t) (rot v) l'-        { l'    = transform mempty l = l }-        { trans = translate (l' .-. l)-                = translate (l .-. l)-                = translate zeroV-                = id-        }-        { rot   = rotateAbout l angle-                = rotateAbout l (direction (transform mempty v) - direction v)-                = rotateAbout l (direction v - direction v)-                = rotateAbout l 0-                = id-        }-      = ScaleInv t v l--  2. transform t1 (transform t2 (ScaleInv t v l))-     = let angle = direction (transform t2 v) - direction v-           rot   = rotateAbout l angle-           l'    = transform t2 l-           trans = translate (l' .-. l)-       in-           transform t1 (ScaleInv (trans . rot $ t) (rot v) l')--     = let angle  = direction (transform t2 v) - direction v-           rot    = rotateAbout l angle-           l'     = transform t2 l-           trans  = translate (l' .-. l)-           angle2 = direction (transform t1 (rot v)) - direction (rot v)-           rot2   = rotateAbout l' angle2-           l'2    = transform t1 l'-           trans2 = translate (l'2 .-. l')-       in-           ScaleInv (trans2 . rot2 . trans . rot $ t) (rot2 . rot $ v) l'2--       { l'2 = transform t1 l'-             = transform t1 (transform t2 l)-             = transform (t1 <> t2) l-       }-       { trans2 = translate (l'2 .-. l')-                = translate (transform (t1 <> t2) l .-. transform t2 l)-                = translate (transform t1 l .-. l)-       }-       { rot v  = rotateAbout l angle v-                = rotate angle `under` translation (origin .-. l) $ v-                = rotate angle v-       }-       { angle2 = direction (transform t1 (rot v)) - direction (rot v)-                = direction (transform t1 (rotate angle v)) - direction (rotate angle v)-                = direction (transform t1 (rotate angle v)) - direction v - angle-       }-       { rot2   = rotateAbout l' angle2-                = ???-       }---}--instance (Renderable t b, V t ~ R2) => Renderable (ScaleInv t) b where-  render b = render b . view scaleInvObj---- | Create a diagram from a single scale-invariant primitive.  The---   vector argument specifies the direction in which the primitive is---   \"pointing\" (for the purpose of keeping it rotated correctly---   under non-uniform scaling).  The primitive is assumed to be---   \"located\" at the origin (for the purpose of translating it---   correctly under scaling).------   Note that the resulting diagram will have an /empty/ envelope,---   trace, and query.  The reason is that the envelope, trace, and---   query cannot be cached---applying a transformation would cause---   the cached envelope, etc. to get \"out of sync\" with the---   scale-invariant object.  The intention, at any rate, is that---   scale-invariant things will be used only as \"decorations\" (/e.g./---   arrowheads) which should not affect the envelope, trace, and---   query.-scaleInvPrim :: (Transformable t, Typeable t, Renderable t b, V t ~ R2, Monoid m)-             => t -> R2 -> QDiagram b R2 m-scaleInvPrim t d = mkQD (Prim $ scaleInv t d) mempty mempty mempty mempty
src/Diagrams/TwoD/Types.hs view
@@ -1,13 +1,7 @@-{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE RankNTypes                 #-}-{-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE TypeOperators              #-}-{-# LANGUAGE TypeSynonymInstances       #-}+{-# LANGUAGE TypeFamilies #-}  {-# OPTIONS_GHC -fno-warn-orphans #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Types@@ -21,226 +15,80 @@  module Diagrams.TwoD.Types        ( -- * 2D Euclidean space-         R2(..), r2, unr2, mkR2, r2Iso-       , P2, p2, mkP2, unp2, p2Iso-       , T2-+         V2 (..), R1 (..), R2 (..)+       , P2, T2+       , r2, unr2, mkR2, r2Iso+       , p2, mkP2, unp2, p2Iso+       , r2PolarIso+       , HasR (..)        ) where -import           Control.Lens           (Iso', Rewrapped, Wrapped (..), iso,-                                         lens, (^.), _1, _2)+import           Control.Lens            (Iso', Lens', iso, _1, _2)  import           Diagrams.Angle-import           Diagrams.Coordinates-import           Diagrams.Core--import           Data.AffineSpace.Point-import           Data.Basis-import           Data.MemoTrie          (HasTrie (..))-import           Data.VectorSpace--import           Data.Data---------------------------------------------------------------- 2D Euclidean space---- | The two-dimensional Euclidean vector space R^2.  This type is---   intentionally abstract.------   * To construct a vector, use 'r2', or '^&' (from "Diagrams.Coordinates"):------ @--- r2 (3,4) :: R2--- 3 ^& 4    :: R2--- @------     Note that "Diagrams.Coordinates" is not re-exported by---     "Diagrams.Prelude" and must be explicitly imported.------   * To construct the vector from the origin to a point @p@, use---     @p 'Data.AffineSpace..-.' 'origin'@.------   * To convert a vector @v@ into the point obtained by following---     @v@ from the origin, use @'origin' 'Data.AffineSpace..+^' v@.------   * To convert a vector back into a pair of components, use 'unv2'---     or 'coords' (from "Diagrams.Coordinates").  These are typically---     used in conjunction with the @ViewPatterns@ extension:------ @--- foo (unr2 -> (x,y)) = ...--- foo (coords -> x :& y) = ...--- @--data R2 = R2 {-# UNPACK #-} !Double-             {-# UNPACK #-} !Double-  deriving (Eq, Ord, Typeable, Data)--instance AdditiveGroup R2 where-  zeroV = R2 0 0-  R2 x1 y1 ^+^ R2 x2 y2 = R2 (x1 + x2) (y1 + y2)-  negateV (R2 x y) = R2 (-x) (-y)--instance Num R2 where-  (+)                 = (^+^)-  R2 x1 y1 * R2 x2 y2 = R2 (x1 * x2) (y1 * y2)  -- this is sort of bogus-  (-)                 = (^-^)-  negate              = negateV-  abs (R2 x y)        = R2 (abs x) (abs y)-  signum (R2 x y)     = R2 (signum x) (signum y)-  fromInteger i       = R2 i' i'-    where i' = fromInteger i+import           Diagrams.Points -instance Fractional R2 where-  R2 x1 y1 / R2 x2 y2 = R2 (x1/x2) (y1/y2)-  recip (R2 x y) = R2 (recip x) (recip y)-  fromRational r = R2 r' r'-    where r' = fromRational r+import           Diagrams.Core.Transform+import           Diagrams.Core.V+import           Linear.Metric+import           Linear.V2 -instance Show R2 where-  showsPrec p (R2 x y) = showParen (p >= 7) $-    showCoord x . showString " ^& " . showCoord y-   where-    showCoord c | c < 0     = showParen True (shows c)-                | otherwise = shows c+type P2 = Point V2+type T2 = Transformation V2 -instance Read R2 where-  readsPrec d r = readParen (d > app_prec)-                  (\rr -> [ (R2 x y, r''')-                          | (x,r')    <- readsPrec (amp_prec + 1) rr-                          , ("^&",r'') <- lex r'-                          , (y,r''')  <- readsPrec (amp_prec + 1) r''-                          ])-                  r-    where-      app_prec = 10-      amp_prec = 7+type instance V (V2 n) = V2+type instance N (V2 n) = n  -- | Construct a 2D vector from a pair of components.  See also '&'.-r2 :: (Double, Double) -> R2-r2 (x,y) = R2 x y+r2 :: (n, n) -> V2 n+r2 = uncurry V2  -- | Convert a 2D vector back into a pair of components.  See also 'coords'.-unr2 :: R2 -> (Double, Double)-unr2 (R2 x y) = (x,y)+unr2 :: V2 n -> (n, n)+unr2 (V2 x y) = (x, y)  -- | Curried form of `r2`.-mkR2 :: Double -> Double -> R2-mkR2 = curry r2---- | Lens wrapped isomorphisms for R2.-instance Wrapped R2 where-    type Unwrapped R2 = (Double, Double)-    _Wrapped' = iso unr2 r2-    {-# INLINE _Wrapped' #-}--instance Rewrapped R2 R2--type instance V R2 = R2--instance VectorSpace R2 where-  type Scalar R2 = Double-  s *^ R2 x y = R2 (s*x) (s*y)--data R2Basis = XB | YB deriving (Eq, Ord, Enum)--instance HasTrie R2Basis where-    data R2Basis :->: x = R2Trie x x-    trie f = R2Trie (f XB) (f YB)-    untrie (R2Trie x _y) XB = x-    untrie (R2Trie _x y) YB = y-    enumerate (R2Trie x y)  = [(XB,x),(YB,y)]--instance HasBasis R2 where-  type Basis R2 = R2Basis-  basisValue XB          = R2 1 0-  basisValue YB          = R2 0 1--  decompose (R2 x y)             = [(XB, x), (YB, y)]--  decompose' (R2 x _) (XB)  = x-  decompose' (R2 _ y) (YB) = y--instance InnerSpace R2 where-  (R2 x1 y1) <.> (R2 x2 y2) = x1*x2 + y1*y2--instance Coordinates R2 where-  type FinalCoord R2     = Double-  type PrevDim R2        = Double-  type Decomposition R2  = Double :& Double--  x ^& y           = R2 x y-  coords (R2 x y) = x :& y+mkR2 :: n -> n -> V2 n+mkR2 = V2 -r2Iso :: Iso' R2 (Double, Double)+r2Iso :: Iso' (V2 n) (n, n) r2Iso = iso unr2 r2 -instance HasX R2 where-    _x = r2Iso . _1--instance HasY R2 where-    _y = r2Iso . _2--instance HasTheta R2 where-    _theta = lens (\v -> atanA (v^._y / v^._x))-      (\v θ -> let r = magnitude v in R2 (r * cosA θ) (r * sinA θ))--instance HasR R2 where-    _r = lens magnitude (\v r -> let s = r/magnitude v in s *^ v)---- | Points in R^2.  This type is intentionally abstract.------   * To construct a point, use 'p2', or '^&' (see---     "Diagrams.Coordinates"):------ @--- p2 (3,4)  :: P2--- 3 ^& 4    :: P2--- @------   * To construct a point from a vector @v@, use @'origin' 'Data.AffineSpace..+^' v@.------   * To convert a point @p@ into the vector from the origin to @p@,---   use @p 'Data.AffineSpace..-.' 'origin'@.------   * To convert a point back into a pair of coordinates, use 'unp2',---     or 'coords' (from "Diagrams.Coordinates").  It's common to use---     these in conjunction with the @ViewPatterns@ extension:------ @--- foo (unp2 -> (x,y)) = ...--- foo (coords -> x :& y) = ...--- @-type P2 = Point R2- -- | Construct a 2D point from a pair of coordinates.  See also '^&'.-p2 :: (Double, Double) -> P2-p2 = P . r2+p2 :: (n, n) -> P2 n+p2 = P . uncurry V2  -- | Convert a 2D point back into a pair of coordinates.  See also 'coords'.-unp2 :: P2 -> (Double, Double)-unp2 (P v) = unr2 v+unp2 :: P2 n -> (n,n)+unp2 (P (V2 x y)) = (x,y)  -- | Curried form of `p2`.-mkP2 :: Double -> Double -> P2-mkP2 = curry p2+mkP2 :: n -> n -> P2 n+mkP2 x y = P (V2 x y) --- | Transformations in R^2.-type T2 = Transformation R2+p2Iso :: Iso' (Point V2 n) (n, n)+p2Iso = iso unp2 p2 -instance Transformable R2 where+instance Transformable (V2 n) where   transform = apply -p2Iso :: Iso' P2 (Double, Double)-p2Iso = iso unp2 p2+r2PolarIso :: RealFloat n => Iso' (V2 n) (n, Angle n)+r2PolarIso = iso (\v@(V2 x y) -> (norm v, atan2A y x))+              (\(r,θ)      -> V2 (r * cosA θ) (r * sinA θ))+{-# INLINE r2PolarIso #-} -instance HasX P2 where-    _x = p2Iso . _1+-- | A space which has magnitude '_r' that can be calculated numerically.+class HasR t where+  _r :: RealFloat n => Lens' (t n) n -instance HasY P2 where-    _y = p2Iso . _2+instance HasR v => HasR (Point v) where+  _r = lensP . _r+  {-# INLINE _r #-} -instance HasR P2 where-    _r = _relative origin . _r+instance HasR V2 where+  _r = r2PolarIso . _1+  {-# INLINE _r #-} -instance HasTheta P2 where-    _theta = _relative origin . _theta+instance HasTheta V2 where+  _theta = r2PolarIso . _2+  {-# INLINE _theta #-}
src/Diagrams/TwoD/Vector.hs view
@@ -1,6 +1,3 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies     #-}-{-# LANGUAGE ViewPatterns     #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Vector@@ -14,59 +11,82 @@ module Diagrams.TwoD.Vector        ( -- * Special 2D vectors          unitX, unitY, unit_X, unit_Y+       , xDir, yDir           -- * Converting between vectors and angles-       , direction, angleBetween, fromDirection, e+       , angleV, angleDir, e, signedAngleBetween, signedAngleBetweenDirs           -- * 2D vector utilities-       , perp, leftTurn+       , perp, leftTurn, cross2+        ) where -import           Control.Lens         ((^.))-import           Data.VectorSpace     ((<.>))+import           Control.Lens        (view, (&), (.~), (^.))  import           Diagrams.Angle+import           Diagrams.Direction import           Diagrams.TwoD.Types-import           Diagrams.Coordinates --- | The unit vector in the positive X direction.-unitX :: R2-unitX = 1 ^& 0+import           Linear.Metric+import           Linear.V2+import           Linear.Vector --- | The unit vector in the positive Y direction.-unitY :: R2-unitY = 0 ^& 1+-- | The unit vector in the positive X direction.+unitX :: (R1 v, Additive v, Num n) => v n+unitX = zero & _x .~ 1  -- | The unit vector in the negative X direction.-unit_X :: R2-unit_X = (-1) ^& 0+unit_X :: (R1 v, Additive v, Num n) => v n+unit_X = zero & _x .~ (-1) +-- | The unit vector in the positive Y direction.+unitY :: (R2 v, Additive v, Num n) => v n+unitY = zero & _y .~ 1+ -- | The unit vector in the negative Y direction.-unit_Y :: R2-unit_Y = 0 ^& (-1)+unit_Y :: (R2 v, Additive v, Num n) => v n+unit_Y = zero & _y .~ (-1) --- | Compute the direction of a vector, measured counterclockwise from---   the positive x-axis as a fraction of a full turn.  The zero---   vector is arbitrarily assigned the direction 0.-direction :: R2 -> Angle-direction (coords -> x :& y) = atan2 y x @@ rad+-- | A 'Direction' pointing in the X direction.+xDir :: (R1 v, Additive v, Num n) => Direction v n+xDir = dir unitX --- | Convert an angle into a unit vector pointing in that direction.-fromDirection :: Angle -> R2-fromDirection a = cos a' ^& sin a'-  where a' = a^.rad+-- | A 'Direction' pointing in the Y direction.+yDir :: (R2 v, Additive v, Num n) => Direction v n+yDir = dir unitY --- | A convenient synonym for 'fromDirection'.-e :: Angle -> R2-e = fromDirection+-- | A direction at a specified angle counter-clockwise from the 'xDir'.+angleDir :: Floating n => Angle n -> Direction V2 n+angleDir = dir . angleV --- | @perp v@ is perpendicular to and has the same magnitude as @v@.---   In particular @perp v == rotateBy (1/4) v@.-perp :: R2 -> R2-perp (coords -> x :& y) = (-y) ^& x+-- | A unit vector at a specified angle counter-clockwise from the+--   positive x-axis+angleV :: Floating n => Angle n -> V2 n+angleV = angle . view rad +-- | A unit vector at a specified angle counter-clockwise from the+--   positive X axis.+e :: Floating n => Angle n -> V2 n+e = angleV+ -- | @leftTurn v1 v2@ tests whether the direction of @v2@ is a left --   turn from @v1@ (that is, if the direction of @v2@ can be obtained --   from that of @v1@ by adding an angle 0 <= theta <= tau/2).-leftTurn :: R2 -> R2 -> Bool-leftTurn v1 v2 = (v1 <.> perp v2) < 0+leftTurn :: (Num n, Ord n) => V2 n -> V2 n -> Bool+leftTurn v1 v2 = (v1 `dot` perp v2) < 0++-- | Cross product on vectors in R2.+cross2 :: Num n => V2 n -> V2 n -> n+cross2 (V2 x1 y1) (V2 x2 y2) = x1 * y2 - y1 * x2++-- | Signed angle between two vectors. Currently defined as+--+-- @+-- signedAngleBetween u v = (u ^. _theta) ^-^ (v ^. _theta)+-- @+signedAngleBetween :: RealFloat n => V2 n -> V2 n -> Angle n+signedAngleBetween u v = (u ^. _theta) ^-^ (v ^. _theta)++-- | Same as 'signedAngleBetween' but for 'Directions's.+signedAngleBetweenDirs :: RealFloat n => Direction V2 n -> Direction V2 n -> Angle n+signedAngleBetweenDirs u v = (u ^. _theta) ^-^ (v ^. _theta)
src/Diagrams/Util.hs view
@@ -1,7 +1,9 @@+{-# LANGUAGE CPP #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Util--- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)+-- Copyright   :  (c) 2011-2015 diagrams-lib team (see LICENSE) -- License     :  BSD-style (see LICENSE) -- Maintainer  :  diagrams-discuss@googlegroups.com --@@ -10,23 +12,44 @@ -----------------------------------------------------------------------------  module Diagrams.Util-       ( -- * Utilities for users+  ( -- * Utilities for users -         with-       , applyAll-       , (#)+    with+  , applyAll+  , (#)+  , (##) -       , iterateN+  , iterateN -       , tau+  , tau -         -- * Internal utilities-       , foldB+    -- * Finding files+  , findHsFile -       ) where+    -- * Finding sandboxes+  , findSandbox+  , globalPackage -import           Data.Default.Class+    -- * Internal utilities+  , foldB++  ) where++import           Control.Applicative+import           Control.Lens              hiding (( # ))+import           Control.Monad+import           Control.Monad.Catch+import           Control.Monad.Trans+import           Control.Monad.Trans.Maybe+import           Data.Default+import           Data.List+import           Data.Maybe import           Data.Monoid+import           System.Directory+import           System.Environment+import           System.FilePath+import           System.FilePath.Lens+import           System.Process  -- | Several functions exported by the diagrams library take a number --   of arguments giving the user control to \"tweak\" various aspects@@ -67,6 +90,13 @@ (#) :: a -> (a -> b) -> b (#) = flip ($) +-- | A replacement for lenses' 'Control.Lens.Review.#' operator.+(##) :: AReview t b -> b -> t+(##) = review+{-# INLINE (##) #-}+infixr 8 ##++ -- | @iterateN n f x@ returns the list of the first @n@ iterates of --   @f@ starting at @x@, that is, the list @[x, f x, f (f x), ...]@ --   of length @n@. (Note that the last element of the list will be@@ -102,3 +132,127 @@         go []         = []         go [x]        = [x]         go (x1:x2:xs) = f x1 x2 : go xs++------------------------------------------------------------------------+-- Files+------------------------------------------------------------------------++-- | Given some file (no extension or otherwise) try to find a haskell+--   source file.+findHsFile :: FilePath -> IO (Maybe FilePath)+findHsFile file = runMaybeT $ hs <|> lhs+  where+    hs      = check (addExtension file "hs")+    lhs     = check (addExtension file "lhs")+    check f = do+      lift (doesFileExist f) >>= guard+      pure f++------------------------------------------------------------------------+-- Sandbox+------------------------------------------------------------------------++-- | Parse cabal config file to find the location of the package+--   database.+parseConfig :: FilePath -> MaybeT IO FilePath+parseConfig file = do+  config <- maybeIO $ readFile file+  hoistMaybe $ config ^? lined . prefixed "package-db: "++-- | Seach the given directory and all parent directories until a cabal+--   config file is found. First search for \"cabal.config\", then+--   \"cabal.sandbox.config\". Return the location of the package+--   database in the config file.+configSearch :: FilePath -> MaybeT IO FilePath+configSearch p0 = do+  p0' <- maybeIO $ canonicalizePath p0++  let mkPaths p+        | all isPathSeparator p || p == "."+                    = []+        | otherwise = (p </> "cabal.sandbox.config")+                    : mkPaths (p ^. directory)++  foldMaybeT parseConfig (mkPaths p0')++-- | Check if the folder is a database, or if it contains a database.+--   Returns the database location if it's found.+isDB :: FilePath -> MaybeT IO FilePath+isDB path =+  if isConf path+    then return path+    else maybeIO (getDirectoryContents path) >>= hoistMaybe . find isConf+    where+      isConf = isSuffixOf ".conf.d"++-- | Search for a sandbox in the following order:+--+--   * Test given FilePaths if they point directly to a database or+--     contain a cabal config file (or any parent directory containing a+--     config file).+--+--   * Same test for @DIAGRAMS_SANDBOX@ environment value+--+--   * Environment values of @GHC_PACKAGE_PATH@, @HSENV@ and+--     @PACKAGE_DB_FOR_GHC@ that point to a database.+--+--   * Test for config file (cabal.sandbox.config) in the current+--     directory and its parents.+--+findSandbox :: [FilePath] -> IO (Maybe FilePath)+findSandbox paths = runMaybeT $ pathsTest <|> diaSB <|> envDB <|> wdConfig+  where+    -- first path in environment+    lookEnv = MaybeT . (fmap . fmap) (head . splitSearchPath) . lookupEnv+    envDB   = foldMaybeT lookEnv ["GHC_PACKAGE_PATH", "HSENV", "PACKAGE_DB_FOR_GHC"]++    -- test if path points directly to db or contains a config file+    test x    = isDB x <|> configSearch x+    pathsTest = foldMaybeT test paths+    diaSB     = lookEnv "DIAGRAMS_SANDBOX" >>= test+    wdConfig  = maybeIO getCurrentDirectory >>= configSearch++-- -- | Use the given path for the sandbox in the @GHC_PACKAGE_PATH@+-- --   environment (appending the ghc global package database from @ghc+-- --   --info@. @GHC_PACKAGE_PATH@ if the variable ghc and other tools use+-- --   to find the package database. (This is what @cabal exec@ sets)+-- ghcPackagePath :: FilePath -> IO ()+-- ghcPackagePath db = do+--   gdb <- globalPackage+--   let dbs = intercalate [searchPathSeparator] [db,gdb]+--   setEnv "GHC_PACKAGE_PATH" dbs+-- -- setEnv is only in base > 4.7, either need to use setenv package or+-- -- -package-db flag++-- | Find ghc's global package database. Throws an error if it isn't+--   found.+globalPackage :: IO FilePath+globalPackage = do+  info <- read <$> readProcess "ghc" ["--info"] ""+  return $ fromMaybe (error "Unable to parse ghc --info.")+                     (lookup "Global Package DB" info)++-- MaybeT utilities++-- | Lift an 'IO' action. If any exceptions are raised, return Nothing.+maybeIO :: (MonadCatch m, MonadIO m) => IO a -> MaybeT m a+maybeIO io = liftIO io `catchAll` const mzero++-- hoistMaybe is exported from transformers as of version 0.6+#if MIN_VERSION_transformers(0,6,0)+#else+-- | Lift a maybe value to a MaybeT of any monad.+hoistMaybe :: Monad m => Maybe a -> MaybeT m a+hoistMaybe = MaybeT . return+#endif++-- | Fold a list of 'MaybeT's that short-circuits as soon as a Just value+--   is found (instead going through the whole list).+foldMaybeT :: Monad m => (a -> MaybeT m b) -> [a] -> MaybeT m b+foldMaybeT _ []     = mzero+foldMaybeT f (a:as) = MaybeT $ do+  x <- runMaybeT (f a)+  if isJust x+    then return x+    else runMaybeT (foldMaybeT f as)+
+ src/Linear/Vector/Compat.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE CPP #-}++-- |+-- Module      :  Linear.Vector.Compat+-- Copyright   :  (c) 2024 diagrams-lib team (see LICENSE)+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  diagrams-discuss@googlegroups.com+--+-- Compatibility layer for working with versions of linear both before+-- (< 1.23) and after (>= 1.23) the interpolation direction of `lerp`+-- was reversed.+module Linear.Vector.Compat (lerp) where++import qualified Linear.Vector as V++-- | Linearly interpolate between two vectors, such that @lerp 0 x y =+--   x@ and @lerp 1 x y = 1@.+lerp :: (V.Additive f, Num a) => a -> f a -> f a -> f a+lerp =+#if MIN_VERSION_linear(1,23,0)+  V.lerp+#else+  V.lerp . (1-)+#endif
+ test/Diagrams/Test/Angle.hs view
@@ -0,0 +1,29 @@+-- |++module Diagrams.Test.Angle where+++import           Test.Tasty+import           Test.Tasty.QuickCheck+import           Diagrams.Prelude+import Instances++tests :: TestTree+tests = testGroup "Angle" [+         testProperty "2π radians per turn" $+           \θ -> θ^.rad =~ θ^.turn*2*(pi :: Double)+         , testProperty "360 degrees per turn" $+           \θ -> θ^.deg =~ θ^.turn*(360 :: Double)+         , testProperty "Angle vector addition is commutative" $+           \θ φ -> (θ :: Angle Double) ^+^ φ =~ φ ^+^ θ+         , testProperty "Angle subtraction is the inverse of addition" $+           \θ φ -> (θ :: Angle Double) ^+^ φ ^-^ φ =~ θ+         , testProperty "Angle vector negation squared is identity" $+           \θ -> negated (negated (θ :: Angle Double)) =~ θ+         , testProperty "A negated angle is the additive inverse of the original" $+           \θ -> (θ :: Angle Double) ^+^ (negated θ) =~ 0@@turn+         , testProperty "A negated angle is the additive inverse of the original" $+           \θ -> (θ :: Angle Double) ^+^ (negated θ) =~ 0@@turn+++      ]
+ test/Diagrams/Test/Direction.hs view
@@ -0,0 +1,34 @@+-- |++module Diagrams.Test.Direction where+++import           Diagrams.Direction+import           Diagrams.Prelude+import           Instances+import           Test.Tasty+import           Test.Tasty.QuickCheck++tests :: TestTree+tests = testGroup "Direction" [+         testProperty "Length does not effect from direction" $+           \(Positive f) (NonZero v) -> fromDirection(dir ((v  :: V2 Double) ^* (f+0.001))) =~ fromDirection(dir v)+         , testProperty "HasTheta subtraction yeilds same result as anglebetween" $+            (anglebetsub)+         , testProperty "anglebetweenDirs is commutative" $+           \a b -> angleBetweenDirs (a :: Direction V2 Double) b =~ angleBetweenDirs b a+         , testProperty "fromdirection does not effect angleBetweenDirs" $+           \a b -> angleBetween (fromDirection (a  :: Direction V2 Double)) (fromDirection b) =~ angleBetweenDirs a b++++      ]++if' :: Bool -> a -> a -> a+if' True  x _ = x+if' False _ y = y++anglebetsub :: Direction V2 Double -> Direction V2 Double -> Bool+anglebetsub a b = (if' (abs (a ^.  _theta^.rad  - b ^. _theta^.rad) < pi)+                       (abs ((a ^.  _theta  ^-^ b ^. _theta)^.rad))+                       (2*pi - abs (a ^.  _theta^.rad  - b ^. _theta^.rad) ) =~ angleBetweenDirs a b ^.rad)
+ test/Diagrams/Test/Trail.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies     #-}++module Diagrams.Test.Trail where++import           Diagrams.Prelude+import           Instances+import           Test.Tasty+import           Test.Tasty.QuickCheck++import           Data.Fixed+import           Data.List++tests :: TestTree+tests = testGroup "Trail"+  [ let wrap :: Trail' Line V2 Double -> Located (Trail V2 Double)+        wrap = (`at` origin) . wrapLine+    in+    testProperty "unfixTrail . fixTrail == id for lines" $+    \l -> (unfixTrail . fixTrail $ wrap l) =~ (wrap l)++  , testProperty "glueLine . cutLoop == id" $+    \loop -> (glueLine . cutLoop $ loop) =~ (loop :: Trail' Loop V2 Double)++  , testProperty "trailOffset == sumV . trailOffsets" $+    \t -> trailOffset t =~ (sumV . trailOffsets $ (t :: Trail V2 Double))++  , testProperty "reverseTrail . reverseTrail == id" $+    \t -> (reverseTrail . reverseTrail $ t) =~ (t :: Trail V2 Double)++  , testProperty "reverseLocTrail . reverseLocTrail == id" $+    \t -> (reverseLocTrail . reverseLocTrail $ t) =~+          (t :: Located (Trail V2 Double))++  , testProperty "reverseLine . reverseLine == id" $+    \t -> (reverseLine . reverseLine $ t) =~+          (t :: Trail' Line V2 Double)++  , testProperty "reverseLocLine . reverseLocLine == id" $+    \t -> (reverseLocLine . reverseLocLine $ t) =~+          (t :: Located (Trail' Line V2 Double))++  , testProperty "reverseLoop . reverseLoop == id" $+    \t -> (reverseLoop . reverseLoop $ t) =~+          (t :: Trail' Loop V2 Double)++  , testProperty "reverseLocLoop . reverseLocLoop == id" $+    \t -> (reverseLocLoop . reverseLocLoop $ t) =~+          (t :: Located (Trail' Loop V2 Double))++  , testProperty "section on Trail' Line endpoints match paramaters" $+    \t (Param a) (Param b) ->+      let s = section (t :: Located (Trail' Line V2 Double)) a b+      in  t `atParam` a =~ s `atParam` 0 &&+          t `atParam` b =~ s `atParam` 1++  , testProperty "section on Trail' Line where a paramater is 0 or 1" $+    \t (Param a) ->+      let l = section (t :: Located (Trail' Line V2 Double)) 0 a+          r = section (t :: Located (Trail' Line V2 Double)) a 1+      in  t `atParam` 0 =~ l `atParam` 0 &&+          t `atParam` a =~ l `atParam` 1 &&+          t `atParam` a =~ r `atParam` 0 &&+          t `atParam` 1 =~ r `atParam` 1++  , testProperty "section on Trail' Line where a segment paramater is 0 or 1" $+    \t (Param a) i ->+      let st = unLoc t # \(Line st') -> st' :: SegTree V2 Double+          b | (numSegs st :: Word) > 0 = (fromIntegral (i `mod` (numSegs st + 1) :: Word)) / numSegs st+            | otherwise                = 0+          s = section (t :: Located (Trail' Line V2 Double)) a b+      in  t `atParam` a =~ s `atParam` 0 &&+          t `atParam` b =~ s `atParam` 1++  , testProperty "section on Trail' Line matches section on FixedSegment" $+    \t (Param a) (Param b) -> sectionTrailSectionFixedSegment t a b++  ]++data Param = Param Double deriving Show++instance Arbitrary Param where+  arbitrary = Param <$> choose (-0.5, 1.5)++sectionTrailSectionFixedSegment :: Located (Trail' Line V2 Double) -> Double -> Double -> Bool+sectionTrailSectionFixedSegment t k1 k2+  | null segs = t == t'+  | otherwise = aSecT =~ aSecFS && bSecT =~ bSecFS+  where+    a = min k1 k2+    b = max k1 k2+    t' = section t a b++    segs  = fixTrail $ mapLoc wrapLine t+    segs' = fixTrail $ mapLoc wrapLine t'++    aSecT = head segs'+    bSecT = last segs'++    (aSegIx, a') = splitParam a+    (bSegIx, b') = splitParam b++    aSecFS = section (segs !! floor aSegIx) a' x+      where x = if aSegIx == bSegIx then b' else 1+    bSecFS = section (segs !! floor bSegIx) x  b'+      where x = if aSegIx == bSegIx then a' else 0++    splitParam p | p <  0    = (0    , p           * n)+                 | p >= 1    = (n - 1, 1 + (p - 1) * n)+                 | otherwise = propFrac $  p       * n+      where+        propFrac x = let m = x `mod'` 1 in (x - m, m)+        n = genericLength segs
+ test/Diagrams/Test/Transform.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE TypeFamilies          #-}+++module Diagrams.Test.Transform where++import           Test.Tasty+import           Test.Tasty.QuickCheck+import           Diagrams.Prelude+import           Diagrams.Direction+import Instances++tests :: TestTree+tests = testGroup "Transform" [++        testProperty "rotating a vector by a number then its additive inverse will yield the original vector" $+          \θ a -> rotate ((θ * (-1)) @@ deg) (rotate ((θ :: Double) @@ deg) (a ::  V2 Double)) =~ a+        , testProperty "under rotated allows scaling along an angle" $+          \θ f a -> under (rotated ((θ :: Double) @@ deg)) (scaleX (f :: Double)) (a ::  V2 Double) =~ (rotate (negated (θ @@ deg)) . (scaleX f) . rotate (θ @@ deg)) a+        , testProperty "a rotation of 0 does nothing" $+          \a -> rotate (0 @@ deg) (a ::  V2 Double) =~ a+        , testProperty "adding 360 degrees to a turn does nothing" $+          \c a -> rotate (((c :: Double) + 360) @@ deg) (a ::  V2 Double) =~ rotate (c @@ deg) a+        , testProperty "over rotated allows scaling along x of a rotated shape" $+          \θ f a -> over (rotated ((θ :: Double) @@ deg)) (scaleX (f :: Double)) (a ::  V2 Double) =~ (rotate (θ @@ deg) . (scaleX f) . rotate (negated (θ @@ deg))) a+        , testProperty "scaleX" $+          \f a b -> (scaleX (f :: Double)) (V2 (a ::  Double) b) =~ V2 (a * f) b+        , testProperty "scaleY" $+          \f a b -> (scaleY (f :: Double)) (V2 (a ::  Double) b) =~ V2 a  (f * b)+        , testProperty "reflectX" $+          \a b -> reflectX (V2 (a ::  Double) b) =~ V2 (a * (-1))  b+        , testProperty "reflectY" $+          \a b -> reflectY (V2 (a ::  Double) b) =~ V2 a  ((-1) * b)+        , testProperty "reflectXY" $+          \a b -> reflectXY (V2 (a ::  Double) b) =~ V2 b a+        , testProperty "translate" $+          \a b c d -> translateX (a :: Double) (translateY b (P (V2 c d ))) =~ P (V2 (a + c) (b + d))+        , testProperty "shear" $+          \a b c d -> shearX (a :: Double) (shearY b (V2 c d)) =~ V2 ((c*b + d) * a + c) (c*b + d)+        , testProperty "(1,0) rotateTo some dir will return normalised dir" $+          \(NonZero a) b -> rotateTo  (dir (V2 (a :: Double) b)) (V2 1 0) =~ signorm (V2 a b)+        , testProperty "rotates" $+          \a c -> rotate ((a :: Double)@@ deg) (c :: V2 Double)   =~ rotate'' ((a :: Double)@@ deg) (c :: V2 Double) && rotate ((a :: Double)@@ deg) (c :: V2 Double)   =~ rotate' ((a :: Double)@@ deg) (c :: V2 Double)+        , testProperty "reflectAbout works for a vector" $+          \a b c d e f -> reflectAbout (P (V2 (a :: Double) b)) (dir (V2 c d)) (V2 e f) =~  over (rotated (atan2A' d c)) reflectY (V2 e f)+        , testProperty "reflectAbout works for a point" $+          \a b c d e f -> reflectAbout (P (V2 (a :: Double) b)) (dir (V2 c d)) (P (V2 e f)) =~ translate (V2 a b)  ((over (rotated (atan2A' d c)) reflectY) ((translate (V2 (-a) (-b)) )  (P (V2 e f))))+++        ]++--the original " '' " and a secondary " ' " rotate function for testing++rotation'' :: Floating n => Angle n -> T2 n+rotation'' theta = fromLinear r (linv r)+          where+            r               = rot theta <-> rot (negated theta)+            rot th (V2 x y) = V2 (cosA th * x - sinA th * y)+                                 (sinA th * x + cosA th * y)++rotate'' :: (InSpace V2 n t, Transformable t, Floating n) => Angle n -> t -> t+rotate'' = transform . rotation''++rotation' :: Floating n => Angle n -> T2 n+rotation' theta = fromLinear r (linv r)+            where+            r               = rot theta <-> rot (negated theta)+            rot th (V2 x y) = V2 (c * x - s * y)+                                 (s * x + c * y)+                                  where+                                    c = cosA th+                                    s = sinA th++rotate' :: (InSpace V2 n t, Transformable t, Floating n) => Angle n -> t -> t+rotate'  = transform . rotation'
+ test/Diagrams/Test/Transform/Matrix.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- |++module Diagrams.Test.Transform.Matrix where+++import           Test.Tasty+import           Test.Tasty.QuickCheck+import           Diagrams.Transform.Matrix+import           Diagrams.Prelude+import           Data.Distributive (distribute)++import Instances++tests :: TestTree+tests = testGroup "Transform.Matrix"+  [+    testProperty "mkMat column vectors (2D)" $+      \(Blind (t :: T2 Double)) -> distribute (mkMat t) =~ V2 (transform t unitX) (transform t unitY)+  , testProperty "mkMat / fromMat22" $+      \(m :: V2 (V2 Double)) -> mkMat (fromMat22 m zero) =~ m++  , testProperty "mkMat / fromMat33" $+      \(m :: V3 (V3 Double)) -> mkMat (fromMat33 m zero) =~ m+  ]
+ test/Diagrams/Test/TwoD.hs view
@@ -0,0 +1,65 @@+-- |++module Diagrams.Test.TwoD where++import           Diagrams.Prelude+import qualified Diagrams.Query as Query (sample)+import           Diagrams.Trail        (linePoints)+import           Instances+import           Test.Tasty+import           Test.Tasty.QuickCheck as QC++newtype SmallAngle = SmallAngle (Angle Double)+  deriving (Eq, Ord, Show)++-- Generate random angles within a reasonably small range (+/- 5+-- turns).+instance Arbitrary SmallAngle where+  arbitrary = SmallAngle . (@@turn) <$> choose (-5, 5)++tests :: TestTree+tests = testGroup "TwoD"+    [ testGroup "TwoD.Arc" [+           testProperty "arc start point is at radius 1 in the starting direction" $ \d (SmallAngle a) ->+               pathVertices (arc d a :: Path V2 Double) ^? _head . _head =~ Just (origin .+^ fromDirection d )+           , testProperty "arc end point is at radius 1 in the ending direction" $ \d (SmallAngle a) ->+               pathVertices (arc d a :: Path V2 Double) ^? _head . _last =~ Just (origin .+^ fromDirection (rotate a d))+         ]+    , testGroup "TwoD.Types" [+         testProperty "R2 vector addition is commutative" $+           \u v -> (u :: V2 Double) ^+^ v =~ v ^+^ u+         , testProperty "R2 subtraction is the inverse of addition" $+           \u v -> u ^+^ v ^-^ v =~ (u :: V2 Double)+         , testProperty "R2 vector negation squared is identity" $+           \u -> negated (negated (u :: V2 Double)) =~ u+         ]+      , testGroup "cubicSpline" [+         testProperty "Open cubic spline interpolates all points" $+         \pts -> length pts > 1 ==> and (zipWith (=~) pts (cubicSpline False pts :: [P2 Double]))+         , testProperty "Closed cubic spline interpolates all points" $+           \pts -> length pts > 1 ==> and (zipWith (=~) pts (cubicSpline True pts :: [P2 Double]))+    ]+      , testGroup "Trail" [+         testProperty "glueLine . cutLoop === id" $+         \l -> glueLine (cutLoop l :: Trail' Line V2 Double) =~ l+         , testProperty "cutLoop ends at starting point" $+           \l -> let ps = linePoints (cutLoop (l :: Trail' Loop V2 Double) `at` origin) in (ps ^? _head) =~ (ps ^? _last)+         , testProperty "cutTrail makes a Line" $+           \t -> isLine (cutTrail (t :: Trail V2 Double))+          , testProperty "fromSegments . lineSegments === id" $+            \l -> fromSegments (lineSegments l) =~ (l :: Trail' Line V2 Double)+          , testProperty "lineSegments . fromSegments === id" $+            \segs -> lineSegments (fromSegments segs) =~ (segs :: [Segment Closed V2 Double])+          ]+    , testGroup "Queries and Backgrounds"+        (let dia :: QDiagram NullBackend V2 Double [Int]+             dia = circle 5 # scaleX 2 # rotateBy (1/14) # value [1]+                   <>+                   circle 2 # scaleX 5 # rotateBy (-4/14) # value [2]+         in [+           testProperty "sample dia pt === sample (dia # bg color) pt" $+           \pt -> Query.sample dia pt QC.=== Query.sample (dia # bg orange) pt+         , testProperty "sample dia pt === sample (dia # bgFrame 0.1 color) pt" $+           \pt -> Query.sample dia pt QC.=== Query.sample (dia # bgFrame 0.1 green) pt+         ])+    ]
+ test/Diagrams/Test/TwoD/Offset.hs view
@@ -0,0 +1,48 @@+module Diagrams.Test.TwoD.Offset+    (+      tests+    ) where++import Test.Tasty (TestTree)+import Test.Tasty.HUnit++import Diagrams.Prelude+import Diagrams.TwoD.Offset++tests :: [TestTree]+tests =+    [ testCase "line"+          (offsetTrailVertices+              [p2 (0, 0), p2 (1, 0)]+              [p2 (0, -1), p2 (1, -1)])+    , testCase "square"+          (offsetTrailVertices+              [p2 (0, 0), p2 (1, 0), p2 (1, 1), p2 (0, 1), p2 (0, 0)]+              [p2 (0, -1), p2 (2, -1), p2 (2, 2), p2 (-1, 2), p2 (-1, 0)])+    , testCase "square loop"+          (offsetTrailLoopVertices+              [p2 (0, 0), p2 (1, 0), p2 (1, 1), p2 (0, 1), p2 (0, 0)]+              [p2 (2, -1), p2 (2, 2), p2 (-1, 2), p2 (-1, -1)])+    , testCase "redundant line"+          (offsetTrailVertices+              [p2 (0, 0), p2 (0.5, 0), p2 (1, 0)]+              [p2 (0, -1), p2 (1, -1)])+    , testCase "redundant square"+          (offsetTrailVertices+              [p2 (0, 0), p2 (1, 0), p2 (1, 0.5), p2 (1, 1), p2 (0, 1), p2 (0, 0)]+              [p2 (0, -1), p2 (2, -1), p2 (2, 2), p2 (-1, 2), p2 (-1, 0)])+    , testCase "redundant square loop"+          (offsetTrailLoopVertices+              [p2 (0, 0), p2 (1, 0), p2 (1, 0.5), p2 (1, 1), p2 (0, 1), p2 (0, 0)]+              [p2 (2, -1), p2 (2, 2), p2 (-1, 2), p2 (-1, -1)])+    ]++offsetTrailVertices :: [Point V2 Double] -> [Point V2 Double] -> Assertion+offsetTrailVertices orig off =+    (trailVertices . offsetTrail 1 . fromVertices $ orig) @?= off++offsetTrailLoopVertices :: [Point V2 Double] -> [Point V2 Double] -> Assertion+offsetTrailLoopVertices orig off =+    (trailVertices . offsetTrail 1 . loopTrailFromVertices $ orig) @?= off+  where+    loopTrailFromVertices = (`at` origin) . wrapTrail . glueLine . lineFromVertices
+ test/Diagrams/Test/TwoD/Segment.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE FlexibleInstances #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Diagrams.Test.TwoD.Segment+    (+      tests+    ) where++import qualified Test.QuickCheck.Property as Q+import           Test.Tasty               (TestTree)+import           Test.Tasty.QuickCheck++import           Diagrams.Prelude+import           Diagrams.TwoD.Segment++newtype InBox = InBox { unInBox :: Double }++instance Arbitrary InBox where+  arbitrary = InBox <$> choose (-1, 1)++instance Arbitrary (Point V2 Double) where+  arbitrary = curry p2 <$> (unInBox <$> arbitrary)+                       <*> (unInBox <$> arbitrary)++instance Arbitrary (FixedSegment V2 Double) where+   arbitrary = oneof [FLinear <$> arbitrary <*> arbitrary, FCubic <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary]++epsT, epsE :: Double+epsT = 1.0e-9 -- parameter space epsilon+epsE = 1.0e-8 -- Euclidean space epsilon++(.=~.) :: P2 Double -> P2 Double -> Bool+x .=~. y = norm (x .-. y) < epsE++tests :: [TestTree]+tests =+    [ testProperty "segmentSegment" $+        \a b -> validateIntersections a b (segmentSegment epsT a b)+    ]++validateIntersections :: FixedSegment V2 Double -> FixedSegment V2 Double -> [(Double, Double, P2 Double)] -> Q.Result+validateIntersections _ _ [] = Q.rejected -- TODO: check for false negatives (rasterize both and look for overlap?)+validateIntersections a b isects = go isects+  where+    go [] = Q.succeeded+    go ((ta,tb,p):is)+      | and [ 0 <= ta && ta <= 1+            , 0 <= tb && tb <= 1+            , a `atParam` ta .=~. p+            , b `atParam` tb .=~. p+            ] = go is+      | otherwise = Q.failed
+ test/Instances.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE GADTs                #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns         #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++-- | instances for QuickCheck Arbitrary and approximate equality++module Instances where++import           Diagrams.Prelude+import           Numeric.Extras+import           Test.Tasty.QuickCheck (Arbitrary (..), Gen)+import qualified Test.Tasty.QuickCheck as QC++------------------------------------------------------------+    -- Approximate Comparison for Doubles, Points++epsilon :: Double+epsilon = 0.001++class Approx a where+  (=~) :: a -> a -> Bool++infix 4 =~++--instance (Fractional a, Ord a) => Approx a where+instance Approx Double where+  (=~) a b = abs (a - b) < epsilon++instance Approx Float where+    (=~) a b = abs (a - b) < 0.001++instance Approx n => Approx (V2 n) where+    z1 =~ z2 = (z1^._x) =~ (z2^._x) && (z1^._y) =~ (z2^._y)++instance Approx n => Approx (V3 n) where+    z1 =~ z2 = (z1^._x) =~ (z2^._x) && (z1^._y) =~ (z2^._y) && (z1^._z) =~ (z2^._z)++instance Approx (v n) => Approx (Point v n) where+    p =~ q = view _Point p =~ view _Point q++instance (Approx n, RealExtras n) => Approx (Angle n) where+    a =~ b = normA (a^.rad) =~ normA (b^.rad) where+      normA ang = let ang' = ang `fmod` pi in if ang' >= 0 then ang' else ang'+pi++instance Approx n => Approx (Offset Closed V2 n) where+    OffsetClosed v0 =~ OffsetClosed v1 = v0 =~ v1++instance Approx n => Approx (Segment Closed V2 n) where+    Linear o0 =~ Linear o1 = o0 =~ o1+    Cubic c0 d0 o0 =~ Cubic c1 d1 o1 = c0 =~ c1 && d0 =~ d1 && o0 =~ o1+    _ =~ _ = False+    -- The above is conservative:+    -- Cubic never equals Linear even if they describe the same points++instance Approx n => Approx (FixedSegment V2 n) where+    FLinear a0 b0 =~ FLinear a1 b1 = a0 =~ a1 && b0 =~ b1+    FCubic a0 b0 c0 d0 =~ FCubic a1 b1 c1 d1 = a0 =~ a1 && b0 =~ b1 && c0 =~ c1 && d0 =~ d1+    _ =~ _ = False++instance Approx n => Approx (Trail' Line V2 n) where+    l0 =~ l1 = and $ zipWith (=~) (lineSegments l0) (lineSegments l1)++instance Approx n => Approx (Trail' Loop V2 n) where+    l0 =~ l1 = fst (loopSegments l0) =~ fst (loopSegments l1)++instance (Approx n, Floating n, Ord n) => Approx (Trail V2 n) where+    t0 =~ t1 = and $ zipWith (=~) (trailSegments t0) (trailSegments t1)++instance (Approx a, Approx (Vn a), Num (N a), Additive (V a)) =>+         Approx (Located a) where+           a0 =~ a1 = (loc a0 .-. origin) =~ (loc a1 .-. origin) && unLoc a0 =~ unLoc a1++instance Approx a => Approx (Maybe a) where+    Nothing =~ Nothing = True+    Nothing =~ Just _ = False+    Just _ =~ Nothing = False+    Just l =~ Just r = l =~ r++-- These may be too general+instance Approx a => Approx [a] where+    a =~ b = and $ zipWith (=~) a b++instance (Approx a, Approx b) => Approx (a, b) where+    (a0, b0) =~ (a1,b1) = (a0 =~ a1) && (b0 =~ b1)++------------------------------------------------------------+-- Arbitrary instances for Points, Paths++instance Arbitrary n => Arbitrary (V2 n) where+    arbitrary = (^&) <$> arbitrary <*> arbitrary+    shrink (coords -> x :& y) = (^&) <$> shrink x <*> shrink y++instance Arbitrary n => Arbitrary (V3 n) where+    arbitrary = V3 <$> arbitrary <*> arbitrary <*> arbitrary+    shrink (coords -> x :& y :& z) = V3 <$> shrink x <*> shrink y <*> shrink z++instance Arbitrary (v n) => Arbitrary (Point v n) where+    arbitrary = P <$> arbitrary+    shrink (P v) = P <$> shrink v++instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Transformation V2 n) where+    arbitrary = QC.sized arbT+      where+        arbT 0 = return mempty+        arbT n = QC.oneof+          [ rotation    <$> arbitrary+          , scaling     <$> arbitrary+          , translation <$> arbitrary+          , reflectionAbout <$> arbitrary <*> arbitrary+          , (<>) <$> arbT (n `div` 2) <*> arbT (n `div` 2)+          ]++instance Arbitrary n => Arbitrary (Angle n) where+    arbitrary = review rad <$> arbitrary++instance (Arbitrary n, Floating n) => Arbitrary (Direction V2 n) where+    arbitrary = rotate <$> arbitrary <*> pure xDir++-- -- | Not a valid Show instance because not valid Haskell input+-- instance (Show n, RealFloat n) => Show (Direction V2 n) where+--     show d = "Dir" <> ( show $ d ^. _theta . turn )++-- NOTE on shrinks: Adding definitions of 'shrink' below seems to work+--   in simple tests, but test case failures hang for a very long time+--   (presumably trying lots and lots of expensive shrinks).  Not sure+--   how to make shrinking more tractable.++instance (Arbitrary a, Arbitrary (Vn a)) => Arbitrary (Located a) where+    arbitrary = at <$> arbitrary <*> arbitrary+--    shrink (viewLoc -> (p,a)) = uncurry at <$> shrink (a,p)++instance Arbitrary n => Arbitrary (Offset Closed V2 n) where+    arbitrary = OffsetClosed <$> arbitrary+--    shrink (OffsetClosed x) = OffsetClosed <$> shrink x++instance Arbitrary n =>  Arbitrary (Segment Closed V2 n) where+    arbitrary = QC.oneof [Linear <$> arbitrary, Cubic <$> arbitrary <*> arbitrary <*> arbitrary]+    -- shrink (Linear x) = Linear <$> shrink x+    -- shrink (Cubic x y z) = Linear z+    --                      : [Cubic x' y' z' | (x',y',z') <- shrink (x,y,z)]++instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail' Line V2 n) where+    arbitrary = lineFromSegments <$> arbitrary+--    shrink (lineSegments -> segs) = lineFromSegments <$> shrink segs++instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail' Loop V2 n) where+    arbitrary = closeLine <$> arbitrary+--    shrink (cutLoop -> l) = closeLine <$> shrink l++instance (Arbitrary n, Floating n, Ord n) => Arbitrary (Trail V2 n) where+    arbitrary = QC.oneof [Trail <$> (arbitrary :: Gen (Trail' Loop V2 n)), Trail <$> (arbitrary :: Gen (Trail' Line V2 n))]+
+ test/Speed.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE TypeFamilies          #-}++module Main where++import Criterion+import Criterion.Main (defaultMain)++import Diagrams.Prelude+++main :: IO ()+main = defaultMain+    [ bgroup "rotates"+        [ bench "rotate"  $ whnf (rotate (90 @@ deg :: Angle Double)) (V2 3 3)+         ,bench "rotate1" $ whnf (rotate' (90 @@ deg :: Angle Double)) (V2 3 3)+         ,bench "rotate2" $ whnf (rotate'' (90 @@ deg :: Angle Double)) (V2 3 3)+        ]+    ]++--the original " '' " and a secondary " ' " rotate function for comparing speed testing+--note: function time changes dramatically when function is in this file rather than imported+++rotation' :: Floating n => Angle n -> T2 n+rotation' theta = fromLinear r (linv r)+                where+                r               = rot theta <-> rot (negated theta)+                rot th (V2 x y) = V2 (c * x - s * y)+                                     (s * x + c * y)+                                      where+                                        c = cosA th+                                        s = sinA th++rotate' :: (InSpace V2 n t, Transformable t, Floating n) => Angle n -> t -> t+rotate'  = transform . rotation'++rotation'' :: Floating n => Angle n -> T2 n+rotation'' theta = fromLinear r (linv r)+              where+                r               = rot theta <-> rot (negated theta)+                rot th (V2 x y) = V2 (cosA th * x - sinA th * y)+                                     (sinA th * x + cosA th * y)++rotate'' :: (InSpace V2 n t, Transformable t, Floating n) => Angle n -> t -> t+rotate'' = transform . rotation''
+ test/Test.hs view
@@ -0,0 +1,26 @@+import           Test.Tasty                (TestTree, defaultMain, testGroup)++import qualified Diagrams.Test.Angle            as Angle+import qualified Diagrams.Test.Direction        as Direction+import qualified Diagrams.Test.Transform        as Transform+import qualified Diagrams.Test.Transform.Matrix as TransformMatrix+import qualified Diagrams.Test.TwoD             as TwoD+import qualified Diagrams.Test.TwoD.Offset      as TwoD.Offset+import qualified Diagrams.Test.TwoD.Segment     as TwoD.Segment++import qualified Diagrams.Test.Trail            as Trail++tests :: TestTree+tests = testGroup "unit tests"+    [ testGroup "TwoD.Offset" TwoD.Offset.tests+    , testGroup "TwoD.Segment" TwoD.Segment.tests+    , TwoD.tests+    , Angle.tests+    , Direction.tests+    , Transform.tests+    , TransformMatrix.tests+    , Trail.tests+    ]++main :: IO ()+main = defaultMain tests