diagrams-lib 1.3.1.4 → 1.6
raw patch · 146 files changed
Files
- CHANGELOG.md +306/−0
- LICENSE +12/−1
- README.markdown +1/−1
- diagrams-lib.cabal +58/−36
- diagrams/src_Diagrams_Combinators_alignedEx1.svg +1/−0
- diagrams/src_Diagrams_Combinators_alignedEx2.svg +1/−0
- diagrams/src_Diagrams_Combinators_appendsEx.svg +1/−3
- diagrams/src_Diagrams_Combinators_besideEx.svg +1/−3
- diagrams/src_Diagrams_Combinators_positionEx.svg +1/−3
- diagrams/src_Diagrams_Combinators_strutEx.svg +1/−3
- diagrams/src_Diagrams_Combinators_withEnvelopeEx.svg +1/−3
- diagrams/src_Diagrams_CubicSpline_Boehm_bsplineEx.svg +1/−0
- diagrams/src_Diagrams_CubicSpline_cubicSplineEx.svg +1/−3
- diagrams/src_Diagrams_TrailLike_explodeTrailEx.svg +1/−3
- diagrams/src_Diagrams_TrailLike_fromOffsetsEx.svg +1/−3
- diagrams/src_Diagrams_TrailLike_fromSegmentsEx.svg +1/−3
- diagrams/src_Diagrams_TrailLike_fromVerticesEx.svg +1/−3
- diagrams/src_Diagrams_TrailLike_twiddleEx.svg +1/−3
- diagrams/src_Diagrams_Trail_closeLineEx.svg +1/−3
- diagrams/src_Diagrams_Trail_glueLineEx.svg +1/−3
- diagrams/src_Diagrams_Trail_lineFromOffsetsEx.svg +1/−3
- diagrams/src_Diagrams_Trail_lineFromVerticesEx.svg +1/−3
- diagrams/src_Diagrams_Trail_trailOffsetEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arc_annularWedgeEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arc_arc'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arc_arcBetweenEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arc_wedgeEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrow_example1.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrow_example2.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_blockEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_dart'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_dartEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_halfDart'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_halfDartEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_quillEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_spike'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_spikeEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_thorn'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_thornEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_tri'Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_tri25Ex.svg +1/−3
- diagrams/src_Diagrams_TwoD_Arrowheads_triEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Curvature_diagramA.svg +1/−3
- diagrams/src_Diagrams_TwoD_Curvature_diagramNeg.svg +1/−3
- diagrams/src_Diagrams_TwoD_Curvature_diagramPos.svg +1/−3
- diagrams/src_Diagrams_TwoD_Curvature_diagramZero.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_cubicOffsetExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_expandLoopExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_expandTrailExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_offsetTrailExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_offsetTrailLeftExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Offset_offsetTrailOuterExample.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_decagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_dodecagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_hendecagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_heptagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_hexagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_hruleEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_nonagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_octagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_pentagonEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_rectEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_roundedRectEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_squareEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_triangleEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_unitSquareEx.svg +1/−3
- diagrams/src_Diagrams_TwoD_Shapes_vruleEx.svg +1/−3
- src/Diagrams/Align.hs +10/−7
- src/Diagrams/Angle.hs +62/−7
- src/Diagrams/Animation.hs +2/−6
- src/Diagrams/Animation/Active.hs +0/−5
- src/Diagrams/Attributes.hs +67/−12
- src/Diagrams/Attributes/Compile.hs +8/−3
- src/Diagrams/Backend/CmdLine.hs +205/−315
- src/Diagrams/BoundingBox.hs +38/−17
- src/Diagrams/Combinators.hs +192/−118
- src/Diagrams/Coordinates.hs +4/−4
- src/Diagrams/CubicSpline.hs +46/−33
- src/Diagrams/CubicSpline/Boehm.hs +156/−0
- src/Diagrams/CubicSpline/Internal.hs +51/−43
- src/Diagrams/CubicSpline/NonSingleton.hs +47/−0
- src/Diagrams/Deform.hs +2/−0
- src/Diagrams/Direction.hs +5/−5
- src/Diagrams/LinearMap.hs +2/−0
- src/Diagrams/Located.hs +15/−5
- src/Diagrams/Names.hs +6/−0
- src/Diagrams/Parametric.hs +3/−2
- src/Diagrams/Parametric/Adjust.hs +2/−1
- src/Diagrams/Path.hs +84/−93
- src/Diagrams/Points.hs +4/−1
- src/Diagrams/Prelude.hs +72/−75
- src/Diagrams/Query.hs +75/−2
- src/Diagrams/Segment.hs +304/−214
- src/Diagrams/Size.hs +88/−87
- src/Diagrams/Tangent.hs +1/−0
- src/Diagrams/ThreeD.hs +11/−13
- src/Diagrams/ThreeD/Align.hs +2/−0
- src/Diagrams/ThreeD/Attributes.hs +6/−8
- src/Diagrams/ThreeD/Camera.hs +1/−16
- src/Diagrams/ThreeD/Deform.hs +1/−1
- src/Diagrams/ThreeD/Light.hs +1/−2
- src/Diagrams/ThreeD/Shapes.hs +238/−91
- src/Diagrams/ThreeD/Size.hs +1/−0
- src/Diagrams/ThreeD/Transform.hs +9/−4
- src/Diagrams/Trace.hs +6/−0
- src/Diagrams/Trail.hs +1539/−1313
- src/Diagrams/TrailLike.hs +2/−0
- src/Diagrams/Transform.hs +6/−1
- src/Diagrams/Transform/Matrix.hs +11/−8
- src/Diagrams/Transform/ScaleInv.hs +1/−5
- src/Diagrams/TwoD.hs +8/−3
- src/Diagrams/TwoD/Adjust.hs +8/−4
- src/Diagrams/TwoD/Align.hs +1/−11
- src/Diagrams/TwoD/Arc.hs +9/−3
- src/Diagrams/TwoD/Arrow.hs +381/−352
- src/Diagrams/TwoD/Arrowheads.hs +198/−177
- src/Diagrams/TwoD/Attributes.hs +159/−106
- src/Diagrams/TwoD/Combinators.hs +21/−7
- src/Diagrams/TwoD/Ellipse.hs +1/−0
- src/Diagrams/TwoD/Image.hs +98/−70
- src/Diagrams/TwoD/Model.hs +2/−1
- src/Diagrams/TwoD/Offset.hs +281/−243
- src/Diagrams/TwoD/Path.hs +318/−211
- src/Diagrams/TwoD/Points.hs +33/−36
- src/Diagrams/TwoD/Polygons.hs +253/−230
- src/Diagrams/TwoD/Segment.hs +241/−204
- src/Diagrams/TwoD/Segment/Bernstein.hs +85/−81
- src/Diagrams/TwoD/Shapes.hs +153/−127
- src/Diagrams/TwoD/Size.hs +1/−0
- src/Diagrams/TwoD/Text.hs +190/−85
- src/Diagrams/TwoD/Transform.hs +51/−29
- src/Diagrams/TwoD/Vector.hs +6/−0
- src/Diagrams/Util.hs +8/−3
- src/Linear/Vector/Compat.hs +24/−0
- test/Diagrams/Test/Angle.hs +29/−0
- test/Diagrams/Test/Direction.hs +34/−0
- test/Diagrams/Test/Trail.hs +113/−0
- test/Diagrams/Test/Transform.hs +76/−0
- test/Diagrams/Test/Transform/Matrix.hs +26/−0
- test/Diagrams/Test/TwoD.hs +65/−0
- test/Diagrams/Test/TwoD/Offset.hs +48/−0
- test/Diagrams/Test/TwoD/Segment.hs +54/−0
- test/Diagrams/TwoD/OffsetTest.hs +0/−48
- test/Instances.hs +157/−0
- test/Speed.hs +47/−0
- test/Test.hs +19/−3
CHANGELOG.md view
@@ -1,3 +1,309 @@+## [v1.6](https://github.com/diagrams/diagrams-lib/tree/v1.6) (2026-08-06)++- Fix a ton of warnings+ - Remove redundant `Typable` derivations+ - Use safer function variants, `NonEmpty`, etc.+ - Redefine `Diagrams.CubicSpline.Boehm.BSpline` as `NonEmpty (Point v n)`+ - New module `Diagrams.CubicSpline.Nonsingleton` for lists with at+ least two elements, needed for safe operation of `CubicSpline`+ methods+- Dependency updates+ - Allow `base-4.22` and test on GHC 9.14+ - Remove support for GHC 8.4+ - Depend on `diagrams-solve-0.3`+ - Allow `containers-0.8`+ - Remove unused dependencies `semigroups`, `tagged`, `text`,+ `profunctors`, `fail`, `deepseq`+- Fix documentation for `splitTextureFills` (thanks to @kostmo)++## [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`
LICENSE view
@@ -1,24 +1,35 @@-Copyright (c) 2011-2015 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 @@-[](https://travis-ci.org/diagrams/diagrams-lib)+[](https://github.com/diagrams/diagrams-lib/actions/workflows/haskell-ci.yml) The standard library for [diagrams](http://projects.haskell.org/diagrams/), a Haskell embedded
diagrams-lib.cabal view
@@ -1,5 +1,5 @@ Name: diagrams-lib-Version: 1.3.1.4+Version: 1.6 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@@ -9,8 +9,8 @@ creating diagrams. To get started using it, see the "Diagrams" module, and refer to the tutorials and documentation on the diagrams website,- <http://projects.haskell.org/diagrams>.-Homepage: http://projects.haskell.org/diagrams+ <http://diagrams.github.io>.+Homepage: http://diagrams.github.io License: BSD3 License-file: LICENSE Author: Brent Yorgey@@ -18,10 +18,10 @@ Bug-reports: http://github.com/diagrams/diagrams-lib/issues Category: Graphics Build-type: Simple-Cabal-version: >=1.10-Extra-source-files: CHANGELOG.md, README.markdown, diagrams/*.svg-Extra-doc-files: diagrams/*.svg-Tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.1+Cabal-version: 1.18+Extra-source-files: diagrams/*.svg+Extra-doc-files: CHANGELOG.md, README.markdown, diagrams/*.svg+Tested-with: GHC ==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 || ==9.14.1 Source-repository head type: git location: http://github.com/diagrams/diagrams-lib.git@@ -40,7 +40,9 @@ Diagrams.Combinators, Diagrams.Coordinates, Diagrams.CubicSpline,+ Diagrams.CubicSpline.Boehm, Diagrams.CubicSpline.Internal,+ Diagrams.CubicSpline.NonSingleton, Diagrams.Deform Diagrams.Direction, Diagrams.Envelope,@@ -99,38 +101,36 @@ Diagrams.TwoD.Types, Diagrams.TwoD.Vector, Diagrams.Util- Build-depends: base >= 4.2 && < 4.10,- containers >= 0.3 && < 0.6,+ other-modules: Linear.Vector.Compat+ Build-depends: base >= 4.9 && < 4.23,+ base-compat >= 0.9,+ containers >= 0.3 && < 0.9, array >= 0.3 && < 0.6,- semigroups >= 0.3.4 && < 0.19,- monoid-extras >= 0.3 && < 0.5,+ monoid-extras >= 0.6 && < 0.8, dual-tree >= 0.2 && < 0.3,- diagrams-core >= 1.3 && < 1.4,- diagrams-solve >= 0.1 && < 0.2,+ diagrams-core >= 1.4 && < 1.6,+ diagrams-solve >= 0.3 && < 0.4, active >= 0.2 && < 0.3, colour >= 2.3.2 && < 2.4,- data-default-class < 0.2,+ data-default >= 0.8 && < 0.9, fingertree >= 0.1 && < 0.2,- intervals >= 0.7 && < 0.8,- lens >= 4.6 && < 4.15,- tagged >= 0.7,- optparse-applicative >= 0.11 && < 0.14,- filepath,- JuicyPixels >= 3.1.5 && < 3.3,- hashable >= 1.1 && < 1.3,- linear >= 1.20.1 && < 1.21,+ intervals >= 0.7 && < 0.10,+ lens >= 5.1 && < 5.4,+ 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.5,- fsnotify >= 0.2.1 && < 0.3,- directory >= 1.2 && < 1.3,+ process >= 1.1 && < 1.7,+ directory >= 1.2 && < 1.4, unordered-containers >= 0.2 && < 0.3,- text >= 0.7.1 && < 1.3,- mtl >= 2.0 && < 2.3,- transformers >= 0.3.0 && < 0.6.0,- exceptions >= 0.6 && < 1.0- if impl(ghc < 7.6)- Build-depends: ghc-prim+ mtl >= 2.0 && < 2.3 || >= 2.3.1 && < 2.4,+ transformers >= 0.3.0 && < 0.7.0,+ exceptions >= 0.6 && < 1.0,+ cereal >=0.4.1.1 && <0.6,+ bytestring >=0.9 && <0.13 Hs-source-dirs: src ghc-options: -Wall default-language: Haskell2010@@ -144,10 +144,32 @@ test-suite tests type: exitcode-stdio-1.0 main-is: Test.hs- other-modules: Diagrams.TwoD.OffsetTest+ 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 >= 4.2 && < 4.10,- tasty >= 0.10,- tasty-hunit >= 0.9.2,- diagrams-lib+ build-depends: base,+ tasty >= 0.10 && < 1.6,+ tasty-hunit >= 0.9.2 && < 0.11,+ tasty-quickcheck >= 0.8 && < 0.12,+ QuickCheck >= 2.7,+ diagrams-lib,+ distributive,+ numeric-extras 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-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,3 +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" height="182.15600114617723" stroke-opacity="1" viewBox="0 0 200 182" font-size="1" width="200.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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><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 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><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 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><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 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><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.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><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 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><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 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></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,3 +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" height="200.0" stroke-opacity="1" viewBox="0 0 170 200" font-size="1" width="169.72067997066802" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.00610360836492,68.63383995200215 c 0.0,-32.884652674811015 -26.658278186282047,-59.54293086109307 -59.54293086109305 -59.54293086109307c -32.884652674811015,-2.0136042319639878e-15 -59.54293086109307,26.658278186282043 -59.54293086109307 59.54293086109305c -4.0272084639279756e-15,32.884652674811015 26.658278186282036,59.54293086109307 59.54293086109304 59.54293086109307c 32.884652674811015,6.0408126958919634e-15 59.54293086109307,-26.658278186282033 59.54293086109307 -59.54293086109305Z"/></g><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(255,165,0)" stroke-linecap="butt" stroke-miterlimit="10.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><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(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.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></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,3 +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" height="300.0" stroke-opacity="1" viewBox="0 0 204 300" font-size="1" width="204.25531914893568" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.25531914893565,6.3829787234042215 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 197.87234042553143,43.40425531914886 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 191.48936170212718,77.87234042553186 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 185.10638297872293,109.78723404255311 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 178.7234042553187,139.14893617021266 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 172.34042553191446,165.95744680851053 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 165.9574468085102,190.2127659574467 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 159.574468085106,211.91489361702116 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 153.19148936170174,231.06382978723394 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 146.8085106382975,247.659574468085 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 140.42553191489327,261.7021276595744 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 134.04255319148902,273.19148936170205 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 127.6595744680848,282.12765957446805 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 121.27659574468056,288.51063829787233 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 114.89361702127631,292.3404255319149 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 108.51063829787208,293.6170212765958 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 102.12765957446784,292.34042553191495 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 95.74468085106359,288.51063829787245 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 89.36170212765936,282.1276595744682 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 82.97872340425512,273.19148936170234 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 76.59574468085087,261.7021276595747 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 70.21276595744663,247.65957446808542 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 63.8297872340424,231.0638297872344 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 57.44680851063816,211.9148936170217 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 51.06382978723392,190.2127659574473 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 44.68085106382968,165.9574468085112 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 38.29787234042544,139.1489361702134 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 31.914893617021193,109.78723404255393 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 25.531914893616957,77.87234042553271 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 19.14893617021272,43.404255319149826 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></g><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 12.765957446808471,6.382978723405245 c 0.0,-3.5252218074305848 -2.8577569159736487,-6.382978723404235 -6.382978723404233 -6.382978723404235c -3.5252218074305848,-2.1585758013771565e-16 -6.382978723404235,2.8577569159736482 -6.382978723404235 6.382978723404233c -4.317151602754313e-16,3.5252218074305848 2.8577569159736482,6.382978723404235 6.382978723404232 6.382978723404235c 3.5252218074305848,6.47572740413147e-16 6.382978723404235,-2.857756915973648 6.382978723404236 -6.382978723404233Z"/></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,3 +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" height="119.99999999999999" stroke-opacity="1" viewBox="0 0 300 120" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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><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 122.72727272727273,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></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,3 +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" height="166.66666666666666" stroke-opacity="1" viewBox="0 0 300 167" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.11111111111114,138.8888888888889 l -1.2335811384723963e-14,-111.11111111111113 h -111.11111111111113 l -1.2335811384723963e-14,111.11111111111113 Z"/></g><defs></defs><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.0,83.33333333333334 c 0.0,-24.5459888813686 -19.898455563075846,-44.44444444444446 -44.44444444444444 -44.44444444444446c -24.5459888813686,-1.503008335773729e-15 -44.44444444444446,19.898455563075842 -44.44444444444446 44.44444444444444c -3.006016671547458e-15,24.5459888813686 19.898455563075842,44.44444444444446 44.444444444444436 44.44444444444446c 24.5459888813686,4.509025007321188e-15 44.44444444444446,-19.89845556307584 44.444444444444464 -44.44444444444444Z"/></g><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,128,0)" stroke-linecap="butt" stroke-miterlimit="10.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></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,3 +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" height="150.98643825758782" stroke-opacity="1" viewBox="0 0 600 151" font-size="1" width="600.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.1254082642812,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><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 439.1814008673182,12.667610657826017 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 338.0615488065779,63.227536688196146 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 565.5812159432436,139.06742573375135 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 489.74132689768834,12.667610657826017 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 439.1814008673182,88.50749970338121 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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 139.8913954924196,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><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 144.94738809545663,12.667610657826017 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 43.827536034716346,63.227536688196146 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 271.3472031713819,139.06742573375135 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 195.50731412582675,12.667610657826017 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></g><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,0,255)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 144.94738809545663,88.50749970338121 c 0.0,-2.792347609914639 -2.263644993122374,-5.055992603037014 -5.055992603037012 -5.055992603037014c -2.792347609914639,-1.7098197812943624e-16 -5.055992603037014,2.2636449931223734 -5.055992603037014 5.055992603037012c -3.419639562588725e-16,2.792347609914639 2.2636449931223734,5.055992603037014 5.055992603037012 5.055992603037014c 2.792347609914639,5.129459343883088e-16 5.055992603037014,-2.263644993122373 5.055992603037014 -5.055992603037012Z"/></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,3 +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" height="285.31695488854604" stroke-opacity="1" viewBox="0 0 300 285" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.72263789774162,272.3480023936121 h 168.55472420451676 "/></g><defs></defs><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.636363636363654,112.042933586574 l 52.08627426137796,160.3050688070381 "/></g><defs></defs><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.00000000000003,12.968952494933887 l -136.36363636363635,99.07398109164009 "/></g><defs></defs><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.3636363636364,112.04293358657401 l -136.36363636363635,-99.0739810916401 "/></g><defs></defs><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.2773621022584,272.3480023936121 l 52.08627426137797,-160.3050688070381 "/></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,3 +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" height="86.60254037844385" stroke-opacity="1" viewBox="0 0 300 87" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.636363636363626,82.66606127033276 h 90.9090909090909 l 45.45454545454546,-78.72958216222169 l 45.45454545454546,78.72958216222169 h 90.9090909090909 "/></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,3 +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" height="200.00000000000003" stroke-opacity="1" viewBox="0 0 247 200" font-size="1" width="247.48737341529161" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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></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,3 +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" height="305.0220318351291" stroke-opacity="1" viewBox="0 0 300 305" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.02231959365207,226.83571375859063 l 52.57961880085914,-15.539610741748671 l 35.76169796912516,-48.19767576631638 l -52.84137502819748,-45.52029976131281 l 1.4689477105917226,-54.80819289004406 l -34.787741187672516,-48.90529678848097 l -59.62126060155822,36.188587835275676 l -51.67175918801713,-18.333715326258865 l -57.26170441494141,17.972540121134085 l 15.99340952431951,67.88607704837412 l -33.40385114728599,43.47733367835123 l -0.601938394511219,60.012937447513046 l 69.50573128358401,5.76731514351359 l 31.027043823852175,45.20418527970046 l 56.88968602799995,19.117494986150366 Z"/></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,3 +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" height="259.80762113533166" stroke-opacity="1" viewBox="0 0 300 260" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.81818181818176,247.99818381099834 h 0.0 "/></g><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.81818181818176,247.99818381099834 l -68.18181818181809,-118.09437324333258 "/></g><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.81818181818176,247.99818381099834 l 1.3625464393126918e-13,-236.18874648666508 "/></g><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.81818181818176,247.99818381099834 l 136.36363636363646,-236.18874648666497 "/></g><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.81818181818176,247.99818381099834 l 204.5454545454546,-118.09437324333244 "/></g><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.81818181818176,247.99818381099834 l 136.3636363636364,6.055761952500853e-14 "/></g><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 13.636363636363683,129.90381056766577 l 68.18181818181809,118.09437324333258 "/></g><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 13.636363636363683,129.90381056766577 h 0.0 "/></g><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 13.636363636363683,129.90381056766577 l 68.18181818181822,-118.09437324333248 "/></g><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 13.636363636363683,129.90381056766577 l 204.5454545454546,-118.09437324333241 "/></g><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 13.636363636363683,129.90381056766577 l 272.7272727272727,1.3625464393126918e-13 "/></g><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 13.636363636363683,129.90381056766577 l 204.54545454545448,118.09437324333264 "/></g><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.81818181818188,11.809437324333274 l -1.3625464393126918e-13,236.18874648666508 "/></g><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.81818181818188,11.809437324333274 l -68.18181818181822,118.09437324333248 "/></g><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.81818181818188,11.809437324333274 h 0.0 "/></g><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.81818181818188,11.809437324333274 l 136.36363636363635,7.569702440626067e-14 "/></g><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.81818181818188,11.809437324333274 l 204.54545454545445,118.09437324333263 "/></g><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.81818181818188,11.809437324333274 l 136.36363636363626,236.18874648666514 "/></g><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 218.18181818181824,11.80943732433336 l -136.36363636363646,236.18874648666497 "/></g><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 218.18181818181824,11.80943732433336 l -204.5454545454546,118.09437324333241 "/></g><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 218.18181818181824,11.80943732433336 l -136.36363636363635,-7.569702440626067e-14 "/></g><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 218.18181818181824,11.80943732433336 h 0.0 "/></g><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 218.18181818181824,11.80943732433336 l 68.18181818181812,118.09437324333256 "/></g><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 218.18181818181824,11.80943732433336 l -7.569702440626067e-14,236.18874648666505 "/></g><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 286.3636363636364,129.90381056766591 l -204.5454545454546,118.09437324333244 "/></g><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 286.3636363636364,129.90381056766591 l -272.7272727272727,-1.3625464393126918e-13 "/></g><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 286.3636363636364,129.90381056766591 l -204.54545454545445,-118.09437324333263 "/></g><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 286.3636363636364,129.90381056766591 l -68.18181818181812,-118.09437324333256 "/></g><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 286.3636363636364,129.90381056766591 h 0.0 "/></g><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 286.3636363636364,129.90381056766591 l -68.18181818181819,118.0943732433325 "/></g><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 218.18181818181816,247.9981838109984 l -136.3636363636364,-6.055761952500853e-14 "/></g><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 218.18181818181816,247.9981838109984 l -204.54545454545448,-118.09437324333264 "/></g><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 218.18181818181816,247.9981838109984 l -136.36363636363626,-236.18874648666514 "/></g><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 218.18181818181816,247.9981838109984 l 7.569702440626067e-14,-236.18874648666505 "/></g><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 218.18181818181816,247.9981838109984 l 68.18181818181819,-118.0943732433325 "/></g><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 218.18181818181816,247.9981838109984 h 0.0 "/></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,3 +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" height="68.18181818181819" stroke-opacity="1" viewBox="0 0 500 68" font-size="1" width="500.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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><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 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></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,3 +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" height="68.18181818181819" stroke-opacity="1" viewBox="0 0 500 68" font-size="1" width="500.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.297520661157,0.0 l 82.64462809917354,41.32231404958677 l -123.96694214876032,20.661157024793386 l -82.64462809917354,-41.32231404958677 Z"/></g><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 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></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,3 +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" height="50.0" stroke-opacity="1" viewBox="0 0 300 50" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.0,50.0 l 100.0,-50.0 l 100.0,50.0 l 100.0,-25.0 "/></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,3 +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" height="120.00000000000001" stroke-opacity="1" viewBox="0 0 300 120" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.636363636363626,114.54545454545456 v -54.54545454545455 l 54.54545454545455,-54.54545454545455 l 218.1818181818182,54.54545454545455 "/></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,3 +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" height="90.00000000000001" stroke-opacity="1" viewBox="0 0 300 90" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.27272727272728,4.090909090909101 h -109.0909090909091 "/></g><defs></defs><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.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></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,3 +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" height="178.54130895779463" stroke-opacity="1" viewBox="0 0 400 179" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.6026155171689,49.10118238914238 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.21556630101297,-17.215566301012974 c -22.18508769808423,22.185087698084228 -58.15422170664295,22.18508769808423 -80.33930940472717 -0.0c -22.185087698084228,-22.18508769808423 -22.18508769808423,-58.15422170664295 -6.3070071916112315e-15 -80.33930940472717c 22.185087698084228,-22.18508769808423 58.15422170664295,-22.185087698084235 80.33930940472723 -1.4210854715202004e-14Z"/></g><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 196.76242196124198,65.05772234978113 l 5.938102119434486,-56.49726773069128 c -22.874028519212235,-2.4041572749570754 -45.69391955328102,5.010474787900576 -62.786269164729504 20.400495504601412l 38.01228629587617,42.2169208774703 c 5.127704883434546,-4.617006215010249 11.97367219365518,-6.841395833867544 18.83588074941884 -6.120148651380433Z"/></g><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 58.75929709319445,89.27083709150597 h 40.57747891137626 c 0.0,-44.820645578667474 -36.33431224408504,-81.15495782275252 -81.15495782275251 -81.15495782275252l -2.4846539833143083e-15,40.57747891137626 c 22.410322789333737,1.372236503590827e-15 40.57747891137626,18.167156122042524 40.57747891137625 40.57747891137626Z"/></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,3 +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" height="300.00000000000006" stroke-opacity="1" viewBox="0 0 300 300" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.3636363636364,286.3636363636364 c 0.0,-150.6231135902164 -122.10415913705633,-272.72727272727275 -272.7272727272727 -272.72727272727275"/></g><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 195.45454545454547,286.3636363636364 c 0.0,-100.41540906014427 -81.40277275803754,-181.81818181818184 -181.8181818181818 -181.81818181818184"/></g><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 104.54545454545455,286.3636363636364 c 0.0,-50.207704530072135 -40.70138637901877,-90.90909090909092 -90.9090909090909 -90.90909090909092"/></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,3 +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" height="150.0000000000002" stroke-opacity="1" viewBox="0 0 300 150" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.636363636363699,143.1818181818182 c 71.73768743636519,-76.52462512726964 168.46496016363787,-124.88826149090595 272.72727272727263 -136.36363636363623"/></g><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.636363636363782,143.18181818181836 c 82.05066190000068,-61.35322165454398 174.41429826363702,-107.53503983636207 272.7272727272726 -136.3636363636363"/></g><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.636363636363683,143.1818181818183 l 272.7272727272726,-136.36363636363632 "/></g><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.636363636363656,143.1818181818182 c 98.31297446363557,-28.82859652727422 190.67661082727184,-75.01041470909232 272.7272727272726 -136.36363636363635"/></g><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.636363636363656,143.1818181818183 c 104.26231256363477,-11.475374872730326 200.98958529090743,-59.839011236366616 272.72727272727263 -136.36363636363632"/></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,3 +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" height="178.54130895779463" stroke-opacity="1" viewBox="0 0 400 179" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.4329608148053,89.27083709150597 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><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 194.21752105291293,89.27083709150597 l 8.483003027763553,-80.71038247241613 c -22.874028519212235,-2.4041572749570754 -45.69391955328102,5.010474787900576 -62.786269164729504 20.400495504601412Z"/></g><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 18.181818181818187,89.27083709150597 h 81.15495782275252 c 0.0,-44.820645578667474 -36.33431224408504,-81.15495782275252 -81.15495782275251 -81.15495782275252Z"/></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,3 +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" height="142.85714285714286" stroke-opacity="1" viewBox="0 0 500 143" font-size="1" width="499.99999999999994" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.03896103896096,136.36363636363637 l -1.4418480839287746e-14,-129.87012987012986 h -129.87012987012986 l -1.4418480839287746e-14,129.87012987012986 Z"/></g><defs></defs><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.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><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 136.36363636363632,136.36363636363637 l -1.4418480839287746e-14,-129.87012987012986 h -129.87012987012986 l -1.4418480839287746e-14,129.87012987012986 Z"/></g><defs></defs><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.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><defs></defs><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.98197669755432,73.83089383093066 c 61.406842947188636,7.951049003214775 122.81368589437727,15.90209800642955 138.71310687684397 10.954204913391045c 15.89942098246672,-4.947893093038505 -13.70857999978851,-22.794728282330297 2.1908409826782096 -27.742621375368802c 15.89942098246672,-4.947893093038505 77.30626392965536,3.003155910176269 138.71310687684394 10.954204913391042"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.98197669755432,73.83089383093066 l -7.466349307940467,-10.206964204833406 l -19.326463821857203,-2.5024191691242015 l 8.239407860814753,10.307060971598373 l -10.592823993079055,7.868635689924335 l 19.326463821857203,2.5024191691242015 l 9.819765440204769,-7.9687324566893025 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.98197669755432,73.83089383093066 l 6.863778292454953e-2,-0.5300972933995118 l -0.5041524851580295,-6.527841071444503e-2 l 0.43551470223348,0.5953757041139568 l -0.572790268082579,0.4648188826850668 l 0.5041524851580295,6.527841071444503e-2 l 6.863778292454953e-2,-0.5300972933995118 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 396.10389610389603,71.42857142857143 l -30.29839636677383,-14.372284581539233 l 4.072220336388497,10.976480453262068 l -6.733558451422118,9.577332206320406 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 369.8777200735107,68.03276730029427 l -0.27868863959026763,-3.608501795031509e-2 l 6.863778292454958e-2,-0.5300972933995118 l 0.2100508566657181,0.566182311349827 l -0.27868863959026763,-3.608501795031509e-2 l -6.863778292454958e-2,0.5300972933995118 Z"/></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,3 +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" height="191.60937134592436" stroke-opacity="1" viewBox="0 0 500 192" font-size="1" width="500.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.8160519668354,95.80468567296218 l 2.8920113555485896e-15,47.23012965962301 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8160519668354,153.8681315353635 l 4.117578376862937,-12.672603183499865 l -4.117578376862938,2.164739059305849 l -4.117578376862938,-2.164739059305848 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 92.8160519668354,143.36026741116947 l -1.9928192315704405e-17,-0.3254520785842773 l 0.6190466401587595,-3.790567431966741e-17 l -0.6190466401587595,0.3254520785842774 l -1.9928192315704405e-17,-0.3254520785842773 l -0.6190466401587595,3.790567431966741e-17 Z"/></g><defs></defs><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.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><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(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.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><defs></defs><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.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><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(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.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><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.8160519668354,95.80468567296218 h 292.70126366077255 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 407.1839480331646,95.80468567296218 l -25.737705261008802,-8.362687375139057 l 4.396524934036492,8.362687375139057 l -4.396524934036492,8.362687375139057 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 385.84276770619226,95.80468567296218 h -0.3254520785842773 v -0.6190466401587595 l 0.3254520785842773,0.6190466401587595 h -0.3254520785842773 v 0.6190466401587595 Z"/></g><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 162.90483120639803,124.8364086041629 l 152.52370518164733,-4.977296088827186e-14 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 337.09516879360194,124.83640860416284 l -25.737705261008806,-8.36268737513905 l 4.396524934036495,8.362687375139055 l -4.396524934036489,8.362687375139059 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 315.7539884666296,124.83640860416284 l -0.3254520785842773,1.062045638026577e-16 l -2.0201308492960426e-16,-0.6190466401587595 l 0.3254520785842775,0.6190466401587594 l -0.3254520785842773,1.062045638026577e-16 l 2.0201308492960426e-16,0.6190466401587595 Z"/></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.545454545454554,31.818181818181817 h 45.454545454545446 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.545454545454554,49.212883289322264 l -5.0464682937507114e-15,-34.789402942280894 h -45.45454545454545 l -5.0464682937507114e-15,34.789402942280894 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545454545456,31.818181818181817 h 45.45454545454544 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909090909091,31.818181818181817 l 54.818696799240826,-17.811674311893128 l -9.364151344695374,17.811674311893128 l 9.364151344695374,17.811674311893128 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545456,31.818181818181817 h 0.0 h -0.0 h 0.0 h 0.0 h 0.0 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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 9.090909090909093,31.818181818181817 h 45.45454545454544 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0,31.818181818181817 l -54.818696799240826,-17.811674311893128 l 9.364151344695374,17.811674311893128 l -9.364151344695374,17.811674311893128 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545453,31.818181818181817 h -0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z"/></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
@@ -1,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545454545455,31.818181818181817 h 45.45454545454545 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.090909090909093,31.818181818181817 l 54.818696799240826,-17.811674311893128 l -9.364151344695374,17.811674311893128 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 h 0.0 h -0.0 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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 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
@@ -1,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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 9.090909090909093,31.818181818181817 h 45.45454545454545 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0,31.818181818181817 l -54.818696799240826,-17.811674311893128 l 9.364151344695374,17.811674311893128 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 h -0.0 h 0.0 Z"/></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 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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545454545455,31.818181818181817 h 45.45454545454545 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 l -21.174886150566188,-22.264592889866414 h -47.34848484848485 l 23.068825544505582,22.264592889866414 l -23.068825544505582,22.264592889866414 h 47.34848484848485 l 21.174886150566188,-22.264592889866414 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545454545455,31.818181818181817 h 45.45454545454545 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.0909090909091,31.818181818181817 l 54.868490053933975,-22.727272727272727 c -12.55192613251803,12.551926132518032 -12.551926132518032,32.90261932202742 0.0 45.454545454545446l -54.868490053933975,-22.727272727272727 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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 9.090909090909093,31.818181818181817 h 45.45454545454545 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0,31.818181818181817 l -54.868490053933975,-22.727272727272727 c 12.55192613251803,12.551926132518032 12.551926132518032,32.90261932202742 0.0 45.454545454545446l 54.868490053933975,-22.727272727272727 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545454545455,31.818181818181817 Z"/></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545419347618,31.818181818181817 h 45.45454580652382 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.090908738930736,31.818181818181817 c 30.3030303030303,0.0 51.73050852080446,-21.42747821777417 51.73050852080446 -21.42747821777417l -6.275963066259013,21.42747821777417 h -45.45454545454545 c 30.3030303030303,0.0 51.73050852080446,21.42747821777417 51.73050852080446 21.42747821777417l -6.275963066259013,-21.42747821777417 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.54545419347618,31.818181818181817 h 0.0 h -0.0 h 0.0 h 0.0 h 0.0 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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 9.090909090909093,31.818181818181817 h 45.45454620476741 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.00000075022194,31.818181818181817 c -30.3030303030303,0.0 -51.73050852080446,-21.42747821777417 -51.73050852080446 -21.42747821777417l 6.275963066259013,21.42747821777417 h 45.45454545454545 c -30.3030303030303,0.0 -51.73050852080446,21.42747821777417 -51.73050852080446 21.42747821777417l 6.275963066259013,-21.42747821777417 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 54.545455295676504,31.818181818181817 h -0.0 h 0.0 h 0.0 h 0.0 h 0.0 Z"/></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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.54545454545453,31.818181818181817 h 45.45454545454546 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 9.090909090909086,31.818181818181817 l 45.454545454545446,-26.243194054073903 v 52.48638810814781 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="119.99999999999999" stroke-opacity="1" viewBox="0 0 120 120" font-size="1" width="120.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.0,104.99999999999999 l -9.992007221626407e-15,-89.99999999999999 h -89.99999999999999 l -9.992007221626407e-15,89.99999999999999 Z"/></g><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 14.999999999999993,59.99999999999999 h -1.8189894035458565e-14 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 89.99999999999996,59.99999999999999 l -74.99999999999999,-24.368977217467975 v 48.73795443493595 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="63.63636363636363" stroke-opacity="1" viewBox="0 0 100 64" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.54545454545455,54.54545454545455 l -5.0464682937507114e-15,-45.45454545454545 h -45.45454545454545 l -5.0464682937507114e-15,45.45454545454545 Z"/></g><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 9.090909090909093,31.818181818181817 h 45.45454545454546 "/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"><path d="M 100.0,31.818181818181817 l -45.454545454545446,-26.243194054073903 v 52.48638810814781 Z"/></g><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,0,0)" stroke-linecap="butt" stroke-miterlimit="10.0"></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,3 +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" height="200.0" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.18181818181816,175.13148009015777 c 218.1818181818182,-0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547"/></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,3 +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" height="200.0" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.16363636363644,30.840570999248655 l 37.77763883175646,135.36987248046086 "/></g><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 459.483626004958,166.2104434797095 c 0.0,-77.61939705749228 -62.92295375207282,-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><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.18181818181816,175.13148009015777 c 218.1818181818182,-0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547"/></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,3 +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" height="200.0" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.83636363636364,156.51329827197594 l -70.9117417162277,-156.36948173322 "/></g><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 219.6217096378512,0.14381653875594225 c 0.0,-94.82568313685418 -76.87140458086108,-171.69708771771528 -171.69708771771525 -171.69708771771528c -94.82568313685418,-5.8063984665254804e-15 -171.69708771771528,76.87140458086107 -171.69708771771528 171.69708771771522c -1.1612796933050961e-14,94.82568313685418 76.87140458086105,171.69708771771528 171.69708771771522 171.69708771771528c 94.82568313685418,1.741919539957644e-14 171.69708771771528,-76.87140458086105 171.69708771771528 -171.69708771771522Z"/></g><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.18181818181816,175.13148009015777 c 218.1818181818182,-0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547"/></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,3 +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" height="200.0" stroke-opacity="1" viewBox="0 0 400 200" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.01818181818183,101.12693463561232 l -602.0741002308241,-540.4757599431822 "/></g><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 396.0221181542372,-439.3488253075699 c 0.0,-446.8414610189286 -362.23657554795085,-809.0780365668795 -809.0780365668794 -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.0780365668791 809.0780365668795c 446.8414610189286,8.208344474447366e-14 809.0780365668795,-362.2365755479506 809.07803656688 -809.0780365668793Z"/></g><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.18181818181816,175.13148009015777 c 218.1818181818182,-0.0 145.45454545454547,-181.81818181818184 363.6363636363637 -145.45454545454547"/></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,3 +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" height="302.8587568898731" stroke-opacity="1" viewBox="0 0 600 303" font-size="1" width="600.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.98178004434516,129.75705144620275 c 10.606235857710116,25.069284754587557 34.205470842153446,55.82546981090268 80.48722731216125 86.6799741242412"/></g><defs></defs><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.65999705048597,99.66254214599793 c 0.3346638704313681,8.255042137307118 2.4133795608657382,18.49282845858401 7.3217829938591645 30.09450930020482"/></g><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 506.4937338514014,85.26625987587946 c -1.4640943353929647,2.928188670785941 -2.1082544888015486,7.624845968926008 -1.8337368009153647 14.396282270118482"/></g><defs></defs><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.20843689577896,85.59271401011554 c 6.779273038019212e-2,-7.684807703746524e-2 0.22264374631797676,-0.20114771562720798 0.285296955622412 -0.3264541342360785"/></g><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 502.65791267381195,87.93569090398205 c 1.09966629984615,-0.41436701153624195 2.44687362393302,-1.0919072628821396 3.5505242219670206 -2.3429768938665205"/></g><defs></defs><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.0623117811511,87.58378657314933 c 2.9457623866121114,1.3739128917795682 5.382041925447612,1.5628106083333693 8.595600892660824 0.35190433083272765"/></g><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 489.696194669177,83.7630310932222 c 1.233835708711896,2.088029660897054 2.86534579320438,3.1207909913309457 4.366117111974136 3.8207554799271173"/></g><defs></defs><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.27962586563376,82.94401200781269 c 7.73489093536048e-2,0.32804714747133096 0.30246544790102176,0.625921098938114 0.4165688035432233 0.8190190854095302"/></g><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 489.54489237921916,85.09467757558332 c -5.201273523887835e-2,-0.8562096416246057 -0.12423198149539019,-1.5525191125235354 -0.26526651358542147 -2.1506655677706306"/></g><defs></defs><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.8865444836074,96.10544324136515 c 0.6285951592007359,-4.609697834138746 0.8285924178952987,-8.208278914345197 0.6583478956117672 -11.010765665781838"/></g><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 441.8491544866363,221.49977358585733 c 31.929731500853993,-63.85946300170799 44.043977668766026,-103.44263993765506 47.037389996971086 -125.39433034449219"/></g><defs></defs><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.6158583894627,227.38312553727053 c 131.55574898915933,-263.11149797831865 -65.77787449457966,-131.55574898915933 131.55574898915933 -0.0"/></g><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 364.7622235703773,85.96753101537462 c 0.0,15.329119171798204 0.6082191299019316,77.38134470418046 61.92469581709472 138.69782139137325"/></g><defs></defs><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.7418968655277,83.13929813428342 c 1.7887563160725383e-2,0.7020868540585619 2.0326704849611056e-2,1.6834288388046035 2.0326704849611056e-2 2.8282328810911914"/></g><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 364.66018914900303,81.56310499408985 c 3.50905592283126e-2,0.41036459541998055 6.611191242317342e-2,0.964057829210773 8.170771652464309e-2 1.576193140193557"/></g><defs></defs><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.05199859639237,78.3408445789562 c 0.19861208817462941,0.6454892865675514 0.49647125301243644,1.9157652726099426 0.6081905526106669 3.2222604151336727"/></g><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 361.6158660605823,73.77595634835652 c 0.778281999447702,0.9536356598170911 1.8211936720489095,2.566336923375968 2.4361325358100565 4.564888230599678"/></g><defs></defs><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.18966169675514,70.25802410049732 c 1.534225396181438,0.7533004195932368 3.0492264459247074,1.8307093052441519 4.42620436382716 3.517932247859198"/></g><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 349.91728913050895,68.98396616497621 c 2.6563706456126557,-0.2922007710173851 4.874998058580777,9.695369318400071e-2 7.272372566246191 1.2740579355211061"/></g><defs></defs><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.50737812673464,70.81874430723295 c 1.890483423344665,-1.1435066965469178 3.6951868102644125,-1.6461584809706553 5.40991100377432 -1.8347781422567448"/></g><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 341.90372938933285,72.87554041429576 c 0.8842995586107706,-0.8970890150369698 1.7979129825518834,-1.5694264639648248 2.6036487374017807 -2.0567961070628034"/></g><defs></defs><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.9429387947986,75.39357199790632 c 0.6567471005360198,-1.0763355258784695 1.408940600333852,-1.9582002878411209 1.9607905945342565 -2.5180315836105462"/></g><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 338.2153466102728,79.15920115255244 c 0.5976239099089827,-1.6434657522496967 1.3914287352020118,-3.2146946126988154 1.7275921845258102 -3.765629154646144"/></g><defs></defs><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.02089158742814,99.97173175435304 c 4.036215742086062,-11.09959329073667 6.185401087323134,-18.03763227911644 7.194455022844651 -20.8125306018006"/></g><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 274.06207027405526,228.08439667676566 c 32.52509614545878,-65.05019229091756 48.82754727700814,-105.75166132240972 56.95882131337283 -128.11266492241262"/></g><defs></defs><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.82877417688167,233.96774862817887 c 131.55574898915933,-263.11149797831865 0.0,-131.55574898915933 131.55574898915933 -0.0"/></g><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 243.5066684881608,119.71820244879375 c -3.7564422059063314,1.2749137183682067 -8.501013484230302,2.111132473581955 -14.329190482484977 2.111132473581955"/></g><defs></defs><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.137108470349,112.19787026866629 c -2.684178425620012,3.0676324864228737 -6.357946646148888,5.730879896380798 -11.630439982188188 7.520332180127449"/></g><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 258.9676745438485,87.61006066523362 c 3.4874720283559024,9.29992540894908 2.272509976123351,17.61286554672084 -3.8305660734994813 24.58780960343267"/></g><defs></defs><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.9552436938534,62.629247877254016 c 17.79722845000837,-0.0 33.563123737493015,13.11599382130739 38.012430849995106 24.980812787979627"/></g><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 193.43707897401018,72.62776873252102 c 9.382487531803331,-7.358813750433993 18.687588219322436,-9.998520855267016 27.518164719843217 -9.998520855267016"/></g><defs></defs><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.96813963611902,103.19242777258017 c 6.767680004875888,-14.765847283365584 14.62458296860319,-24.412222671990147 22.468939337891157 -30.56465904005914"/></g><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 150.24402861218024,240.2295090126191 c 0.0,-68.44669429030836 8.95983544279202,-111.3695708811733 20.724111023938768 -137.03708124003893"/></g><defs></defs><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.3996035110962,240.2295090126191 c 0.0,-263.11149797831865 131.55574898915933,-131.55574898915933 65.77787449457966 -131.55574898915933"/></g><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 107.36036997660308,38.693005210400855 c 6.432503982934956,-12.16960212987695 14.760815226591278,-20.476100728687936 25.887308602478782 -24.92669807904293"/></g><defs></defs><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.42391061094953,75.63181695246934 c 2.8371303744503993,-14.299137087230024 6.687768172920303,-27.008855431492066 11.936459365653551 -36.93881174206848"/></g><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 83.97921363564315,165.68717783250844 c 4.142251616420562,-31.48111228479627 6.266882454780677,-63.95917569658954 11.44469697530638 -90.0553608800391"/></g><defs></defs><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.057457808628364,244.9886570707671 c 12.618613509791775,-21.354576708878387 18.039105516309625,-49.79333687689943 21.92175582701479 -79.30147923825864"/></g><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 6.577787449457986,275.93687485959936 c 26.333097622202153,-0.0 44.78184945015076,-12.84421317356828 55.47967035917038 -30.948217788832256"/></g><defs></defs><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.577787449457986,289.0924497585153 c 131.55574898915933,-0.0 65.77787449457966,-236.8003481804868 131.55574898915933 -263.11149797831865"/></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,3 +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" height="300.00000000000006" stroke-opacity="1" viewBox="0 0 300 300" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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.551926132518012,1.766263902812749e-14 -22.727272727272705,10.175346594754709 -22.727272727272705 22.727272727272737c -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.027647496353271,1.2616170734376779e-15 -11.80841824405711,2.394473644668588 -16.070608663330628 6.656664063942097l -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><defs></defs><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.363636363636374,263.6363636363636 h 113.63636363636363 l 113.63636363636363,-113.63636363636363 v -113.63636363636363 Z"/></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,3 +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" height="197.38302878166363" stroke-opacity="1" viewBox="0 0 600 197" font-size="1" width="600.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.0,0.0,0.0,1.0,481.81818181818187,168.93062322782592)" stroke="none" text-anchor="middle">LineCapSquare</text></g><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 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.25621332391755 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.921864251791873 -12.245188268797088,-9.345826271542187 -19.95372799435053 -9.345826271542196Z"/></g><defs></defs><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.8830238425919,123.47558931052419 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 "/></g><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.0,0.0,0.0,1.0,287.01303353324954,163.62699800825928)" stroke="none" text-anchor="middle">LineCapRound</text></g><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 222.07787555765958,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.921864251791873 -12.245188268797088,-9.345826271542187 -19.95372799435053 -9.345826271542196Z"/></g><defs></defs><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.07787555765958,118.17196409095754 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 "/></g><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.0,0.0,0.0,1.0,105.19485171506776,158.95375923065066)" stroke="none" text-anchor="middle">LineCapButt</text></g><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 27.272727272727337,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.25621332391755 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.921864251791873 -12.245188268797088,-9.345826271542187 -19.95372799435053 -9.345826271542196Z"/></g><defs></defs><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.272727272727337,113.49872531334891 h 129.86966466750482 l -64.93483233375241,-77.92179880050288 "/></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,3 +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" height="185.1008379753402" stroke-opacity="1" viewBox="0 0 600 185" font-size="1" width="600.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.0,0.0,0.0,1.0,493.6874054156325,156.13320152555207)" stroke="none" text-anchor="middle">LineJoinBevel</text></g><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 414.64753810399236,135.57923952918844 h 137.02641330909063 l 21.0533213141897,-44.949717090309534 l -68.51320665454531,-82.21584798545437 "/></g><defs></defs><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.64753810399236,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 "/></g><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.0,0.0,0.0,1.0,318.7290487876289,156.13320152555207)" stroke="none" text-anchor="middle">LineJoinRound</text></g><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 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><defs></defs><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.51320080217454,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 "/></g><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.0,0.0,0.0,1.0,125.0416433719964,156.13320152555207)" stroke="none" text-anchor="middle">LineJoinMiter</text></g><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 27.27272727272728,135.57923952918844 h 137.02641330909063 h 58.51141888944763 l -37.45809757525794,-44.949717090309534 l -68.51320665454531,-82.21584798545437 "/></g><defs></defs><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.27272727272728,108.17395686737032 h 137.02641330909063 l -68.51320665454531,-82.21584798545437 "/></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,3 +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" height="154.67216693398285" stroke-opacity="1" viewBox="0 0 200 155" font-size="1" width="200.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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><defs></defs><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.090909090909093,37.3334567070673 h 151.51451832306768 l -75.75725916153384,90.9087109938406 "/></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,3 +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" height="271.2911579538083" stroke-opacity="1" viewBox="0 0 300 271" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.44254819939374,239.47922220266116 l 48.70129870129868,-84.35312374523754 c 6.959719283925263,-12.054587406175445 6.959719283925263,-26.90645155486352 -1.2976632755358973e-14 -38.96103896103896l -48.7012987012987,-84.35312374523751 c -6.959719283925261,-12.054587406175434 -19.821810930244474,-19.480519480519472 -33.741249498095 -19.48051948051947l -97.4025974025974,-8.651088503572648e-15 c -13.919438567850529,-8.523197944023185e-16 -26.781530214169752,7.425932074344035 -33.74124949809501 19.480519480519483l -48.70129870129869,84.35312374523754 c -6.959719283925264,12.054587406175434 -6.959719283925272,26.906451554863505 -1.5139404881252133e-14 38.96103896103895l 48.70129870129866,84.35312374523754 c 6.959719283925264,12.054587406175457 19.821810930244496,19.48051948051951 33.741249498095044 19.480519480519497l 97.40259740259744,-3.460435401429059e-14 c 13.919438567850529,-8.523197944023185e-16 26.781530214169752,-7.425932074344039 33.74124949809496 -19.480519480519476Z"/></g><defs></defs><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.70129870129873,219.99870272214167 l 48.70129870129868,-84.35312374523754 l -48.7012987012987,-84.35312374523751 l -97.4025974025974,-8.651088503572648e-15 l -48.70129870129869,84.35312374523754 l 48.70129870129866,84.35312374523754 Z"/></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,3 +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" height="95.10565162951534" stroke-opacity="1" viewBox="0 0 100 95" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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.681045710229665,26.717511467839678 l 22.727272727272723,16.512330181940015 l 28.092454034086124,-1.5594444643433139e-15 Z"/></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,3 +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" height="99.99999999999999" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.45454545454545,62.17950874686919 l -5.408788415759074e-15,-24.35901749373842 l -12.179508746869214,-21.09552796080702 l -21.095527960807022,-12.179508746869208 l -24.35901749373842,3.917228775555017e-15 l -21.095527960807022,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.179508746869216 Z"/></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,3 +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" height="98.98214418809326" stroke-opacity="1" viewBox="0 0 100 99" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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.94479989871783,19.55534153624188 l -3.6824569441365953,25.612050621948153 l 10.74904007121057,23.537114601287985 l 21.767792813036245,13.989311000023635 l 25.875425140597297,-7.181873190763937e-16 l 21.767792813036245,-13.989311000023637 Z"/></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,3 +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" height="97.49279121818239" stroke-opacity="1" viewBox="0 0 100 97" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.45454545454545,61.660546544998155 l -9.00283019068918,-39.44397628341438 l -36.451715263856286,-17.554220883072162 l -36.451715263856286,17.55422088307217 l -9.002830190689167,39.44397628341438 l 25.22536964033506,31.631613031861065 l 40.4583516284208,-1.122944837906337e-15 Z"/></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,3 +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" height="86.6025403784439" stroke-opacity="1" viewBox="0 0 100 87" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.72727272727272,82.66606127033282 l 22.72727272727274,-39.364791081110845 l -22.727272727272712,-39.36479108111086 l -45.45454545454546,-2.2709107321878204e-14 l -22.727272727272744,39.36479108111084 l 22.727272727272698,39.36479108111087 Z"/></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,3 +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" height="48.00000000000001" stroke-opacity="1" viewBox="0 0 300 48" font-size="1" width="300.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.636363636363626,45.81818181818183 h 272.72727272727275 "/></g><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 40.90909090909091,34.909090909090914 h 218.1818181818182 "/></g><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 68.18181818181819,24.000000000000004 h 163.63636363636363 "/></g><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.45454545454545,13.090909090909093 h 109.0909090909091 "/></g><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 122.72727272727272,2.1818181818181834 h 54.54545454545455 "/></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,3 +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" height="98.48077530122083" stroke-opacity="1" viewBox="0 0 100 98" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.97205643508258,73.8492081371451 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></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,3 +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" height="99.99999999999999" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.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></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,3 +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" height="95.10565162951535" stroke-opacity="1" viewBox="0 0 100 95" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.09245403408613,91.23905704609697 l 17.362091420459322,-53.43502293567937 l -45.454545454545446,-33.02466036388004 l -45.45454545454545,33.02466036388003 l 17.36209142045932,53.43502293567937 Z"/></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,3 +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" height="104.99999999999999" stroke-opacity="1" viewBox="0 0 150 105" font-size="1" width="150.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.1818181818182,100.22727272727272 l -1.5139404881252133e-14,-95.45454545454544 h -136.36363636363635 l -1.5139404881252133e-14,95.45454545454544 Z"/></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,3 +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" height="76.19047619047622" stroke-opacity="1" viewBox="0 0 400 76" font-size="1" width="400.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.81818181818187,55.41125541125544 v -17.31601731601732 c -19.126744582884626,-3.0758151178316683e-15 -34.63203463203464,-15.505290049150018 -34.63203463203464 -34.63203463203464h -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.5379075589158342e-15 17.31601731601732,-7.752645024575003 17.316017316017295 -17.31601731601731Z"/></g><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 225.97402597402595,55.41125541125544 v -34.632034632034646 c -9.563372291442313,-1.5379075589158342e-15 -17.31601731601732,-7.752645024575009 -17.31601731601732 -17.31601731601732h -51.94805194805196 c -2.3423506531538637e-15,9.563372291442313 -7.752645024575009,17.31601731601732 -17.31601731601732 17.316017316017316v 34.63203463203464 c 9.563372291442313,2.709082885492766e-15 17.31601731601732,7.75264502457501 17.316017316017316 17.31601731601732h 51.94805194805197 c 5.418165770985532e-15,-9.563372291442313 7.752645024575015,-17.316017316017316 17.31601731601731 -17.3160173160173Z"/></g><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 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.5379075589158342e-15 17.31601731601732,-7.752645024575003 17.31601731601731 -17.316017316017316Z"/></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,3 +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" height="85.71428571428572" stroke-opacity="1" viewBox="0 0 200 86" font-size="1" width="200.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.90909090909093,81.81818181818181 l -8.651088503572648e-15,-77.92207792207792 h -77.92207792207792 l -8.651088503572648e-15,77.92207792207792 Z"/></g><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 100.0,68.83116883116884 l -5.767392335715099e-15,-51.94805194805195 h -51.94805194805195 l -5.767392335715099e-15,51.94805194805195 Z"/></g><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 35.06493506493507,55.84415584415585 l -2.8836961678575494e-15,-25.974025974025974 h -25.974025974025974 l -2.8836961678575494e-15,25.974025974025974 Z"/></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,3 +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" height="86.60254037844383" stroke-opacity="1" viewBox="0 0 100 87" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.45454545454545,83.97822097303643 l -45.45454545454546,-78.72958216222166 l -45.45454545454544,78.72958216222166 Z"/></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,3 +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" height="100.0" stroke-opacity="1" viewBox="0 0 100 100" font-size="1" width="100.0" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.45454545454545,95.45454545454545 l -1.0092936587501423e-14,-90.9090909090909 h -90.9090909090909 l -1.0092936587501423e-14,90.9090909090909 Z"/></g><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(255,0,0)" stroke-linecap="butt" stroke-miterlimit="10.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></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,3 +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" height="100.0" stroke-opacity="1" viewBox="0 0 50 100" font-size="1" width="50.00000000000001" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="rgb(0,0,0)" version="1.1"><g><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.727272727272734,4.545454545454547 v 90.9090909090909 "/></g><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 38.63636363636364,9.090909090909086 v 81.81818181818183 "/></g><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 29.545454545454547,13.636363636363633 v 72.72727272727273 "/></g><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 20.454545454545457,18.18181818181818 v 63.63636363636364 "/></g><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 11.363636363636365,22.727272727272723 v 54.545454545454554 "/></g><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 2.2727272727272734,27.27272727272727 v 45.45454545454546 "/></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/Align.hs view
@@ -1,7 +1,9 @@-{-# LANGUAGE ConstrainedClassMethods #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstrainedClassMethods #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -50,7 +52,8 @@ import Linear.Affine import Linear.Metric-import Linear.Vector+import Linear.Vector (negated)+import Linear.Vector.Compat (lerp) -- | Class of things which can be aligned. class Alignable a where@@ -76,8 +79,8 @@ 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 v a) (boundary (negated v) a)+ (boundary v a) ) a {-# ANN alignBy'Default ("HLint: ignore Use camelCase" :: String) #-} @@ -94,7 +97,7 @@ :: (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 (quadrance . (.-. origin) . b v)) fa+ = b v $ F.maximumBy (comparing (dot v . (.-.origin) . b v)) fa instance (Metric v, OrderedField n) => Alignable (Envelope v n) where defaultBoundary = envelopeBoundary
src/Diagrams/Angle.hs view
@@ -1,7 +1,12 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Angle@@ -33,19 +38,26 @@ -- ** Classes , HasTheta(..) , HasPhi(..)++ -- * Rotation+ , rotation, rotate ) where import Control.Applicative-import Control.Lens (AReview, Iso', Lens', iso, over, review, (^.))+import Control.Lens (AReview, Iso', Lens', iso, over,+ review, (^.)) import Data.Fixed-import Data.Monoid hiding ((<>))+import Data.Monoid hiding ((<>))+import Data.Monoid.Action import Data.Semigroup-import Text.Read import Prelude+import Text.Read -import Diagrams.Core (OrderedField)+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@@ -197,15 +209,58 @@ infixl 5 @@ --- | Compute the positive angle between the two vectors in their common plane.+-- | 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) => v n -> v n -> Angle n-angleBetween v1 v2 = acosA (signorm v1 `dot` signorm v2)+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
src/Diagrams/Animation.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-}@@ -31,10 +31,6 @@ ) where import Data.Active-#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>))-import Data.Foldable (foldMap)-#endif import Data.Semigroup import Diagrams.Core@@ -50,7 +46,7 @@ -- | 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 n m = Active (QDiagram b v n m)
src/Diagrams/Animation/Active.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -37,10 +36,6 @@ ----------------------------------------------------------------------------- module Diagrams.Animation.Active where--#if __GLASGOW_HASKELL__ < 710-import Control.Applicative (pure, (<$>))-#endif import Diagrams.Core import Diagrams.TrailLike
src/Diagrams/Attributes.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE ExistentialQuantification #-}@@ -8,6 +8,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- -- |@@ -55,6 +56,12 @@ , Opacity, _Opacity , getOpacity, opacity, _opacity + , FillOpacity, _FillOpacity+ , getFillOpacity, fillOpacity, _fillOpacity++ , StrokeOpacity, _StrokeOpacity+ , getStrokeOpacity, strokeOpacity, _strokeOpacity+ -- ** Converting colors , colorToSRGBA, colorToRGBA @@ -81,14 +88,11 @@ ) where -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative-#endif 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.Default import Data.Distributive import Data.Monoid.Recommend import Data.Semigroup@@ -127,7 +131,7 @@ -- | Line widths specified on child nodes always override line widths -- specified at parent nodes. newtype LineWidth n = LineWidth (Last n)- deriving (Typeable, Semigroup)+ deriving (Semigroup) _LineWidth :: Iso' (LineWidth n) n _LineWidth = iso getLineWidth (LineWidth . Last)@@ -190,7 +194,7 @@ -- | Create lines that are dashing... er, dashed. data Dashing n = Dashing [n] n- deriving (Functor, Typeable, Eq)+ deriving (Functor, Eq) instance Semigroup (Dashing n) where _ <> b = b@@ -264,7 +268,6 @@ -- | An existential wrapper for instances of the 'Color' class. data SomeColor = forall c. Color c => SomeColor c- deriving Typeable instance Show SomeColor where showsPrec d (colorToSRGBA -> (r,g,b,a)) =@@ -326,7 +329,7 @@ -- words, for example, @opacity 0.8@ means \"decrease this diagram's -- opacity to 80% of its previous opacity\". newtype Opacity = Opacity (Product Double)- deriving (Typeable, Semigroup)+ deriving (Semigroup) instance AttributeClass Opacity _Opacity :: Iso' Opacity Double@@ -345,6 +348,58 @@ _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 (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 (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 ------------------------------------------------------------------------@@ -357,7 +412,7 @@ -- centered on endpoints. | LineCapSquare -- ^ Lines are capped with a squares -- centered on endpoints.- deriving (Eq, Ord, Show, Typeable)+ deriving (Eq, Ord, Show) instance Default LineCap where def = LineCapButt@@ -387,7 +442,7 @@ | LineJoinBevel -- ^ Use a \"bevel\" shape (whatever -- that is). Are these... -- carpentry terms?- deriving (Eq, Ord, Show, Typeable)+ deriving (Eq, Ord, Show) instance AttributeClass LineJoin @@ -414,7 +469,7 @@ -- | Miter limit attribute affecting the 'LineJoinMiter' joins. -- For some backends this value may have additional effects. newtype LineMiterLimit = LineMiterLimit (Last Double)- deriving (Typeable, Semigroup, Eq, Ord)+ deriving (Semigroup, Eq, Ord) instance AttributeClass LineMiterLimit _LineMiterLimit :: Iso' LineMiterLimit Double
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,8 +25,9 @@ import Control.Arrow (second) import Control.Lens ((%~), (&), _Wrapping')+import Data.Kind (Type) import qualified Data.HashMap.Strict as HM-import Data.Semigroup ((<>))+import Data.Semigroup import Data.Tree (Tree (..)) import Diagrams.Core@@ -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
src/Diagrams/Backend/CmdLine.hs view
@@ -1,13 +1,14 @@-{-# LANGUAGE ConstrainedClassMethods #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstrainedClassMethods #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}------------------------------------------------------------------------------+ -- | -- Module : Diagrams.Backend.CmdLine -- Copyright : (c) 2013 Diagrams team (see LICENSE)@@ -22,202 +23,178 @@ -- executables. -- -- For a tutorial on command-line diagram creation see--- <http://projects.haskell.org/diagrams/doc/cmdline.html>.-----------------------------------------------------------------------------------module Diagrams.Backend.CmdLine- (-- -- * Options-- -- ** Standard options- DiagramOpts(..)- , diagramOpts- , width- , height- , output-- -- ** Multi-diagram options- , DiagramMultiOpts(..)- , diagramMultiOpts- , selection- , list-- -- ** Animation options- , DiagramAnimOpts(..)- , diagramAnimOpts- , fpu-- -- ** Loop options- , DiagramLoopOpts(..)- , diagramLoopOpts- , loop- , src- , interval-- -- * Parsing- , Parseable(..)- , readHexColor+-- <https://diagrams.github.io/doc/cmdline.html>.+module Diagrams.Backend.CmdLine (+ -- * Options - -- * Command-line programs (@Mainable@)- -- ** Arguments, rendering, and entry point- , Mainable(..)+ -- ** Standard options+ DiagramOpts (..),+ diagramOpts,+ width,+ height,+ output, - -- ** General currying- , ToResult(..)+ -- ** Multi-diagram options+ DiagramMultiOpts (..),+ diagramMultiOpts,+ selection,+ list, - -- ** helper functions for implementing @mainRender@- , defaultAnimMainRender- , defaultMultiMainRender- , defaultLoopRender- ) where+ -- ** Animation options+ DiagramAnimOpts (..),+ diagramAnimOpts,+ fpu, -import Control.Lens (Lens', makeLenses, (&), (.~), (^.))-import Diagrams.Animation-import Diagrams.Attributes-import Diagrams.Core hiding (output, value)-import Diagrams.Util+ -- * Parsing+ Parseable (..),+ readHexColor, -import Options.Applicative-import Options.Applicative.Types (readerAsk)+ -- * Command-line programs (@Mainable@) -import Control.Monad (forM_, forever, unless, when)+ -- ** Arguments, rendering, and entry point+ Mainable (..), -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.IORef-import Data.List (delete)-import Data.Maybe (fromMaybe)-import Data.Monoid-import Numeric+ -- ** General currying+ ToResult (..), -import Control.Concurrent (threadDelay)-import System.Directory (canonicalizePath)-import System.Environment (getArgs, getProgName)-import System.Exit (ExitCode (..))-import System.FilePath (addExtension, dropExtension,- replaceExtension, splitExtension,- takeDirectory, takeFileName, (</>))-import System.FSNotify (WatchConfig (..), defaultConfig,- eventTime, watchDir,- withManagerConf)-import System.FSNotify.Devel (existsEvents)-import System.Info (os)-import System.IO (hFlush, stdout)-import System.Process (readProcessWithExitCode)+ -- ** helper functions for implementing @mainRender@+ defaultAnimMainRender,+ defaultMultiMainRender,+) where -import Text.Printf+import Control.Lens (Lens', makeLenses, (&), (.~), (^.))+import Control.Monad (forM_)+import Control.Monad.Fail.Compat (MonadFail)+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.Functor.Identity+import Data.Kind (Type)+import Data.Monoid+import Diagrams.Animation+import Diagrams.Attributes+import Diagrams.Core hiding (output)+import Numeric+import Options.Applicative+import Options.Applicative.Types (readerAsk)+import System.Environment (getProgName)+import System.FilePath (addExtension, splitExtension)+import Text.Printf+import Prelude hiding (MonadFail) -- | 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)+ deriving (Show, Data) makeLenses ''DiagramOpts -- | 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)+ deriving (Show, Data) 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)+ deriving (Show, Data) 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")+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"+ ) -- | Command line parser for 'DiagramMultiOpts'. -- 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")+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"+ ) -- | 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.")+diagramAnimOpts =+ DiagramAnimOpts+ <$> 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- [ long "help"- , short '?'- , help "Show this help text"- ]+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@@ -225,10 +202,13 @@ defaultOpts :: Parser a -> IO a defaultOpts optsParser = do prog <- getProgName- let p = info (helper' <*> optsParser)- ( fullDesc- <> progDesc "Command-line diagram generation."- <> header prog)+ 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@@ -271,29 +251,24 @@ instance Parseable DiagramAnimOpts where parser = diagramAnimOpts --- | Parse 'DiagramLoopOpts' using the 'diagramLoopOpts' parser.-instance Parseable DiagramLoopOpts where- parser = diagramLoopOpts-- -- | 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?+ 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)+ where+ rh = readerAsk >>= readHexColor+ rc = opaque <$> (readerAsk >>= readColourName) -- Addapted from the Clay.Color module of the clay package @@ -303,27 +278,27 @@ -- 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- where- handle hs | length hs <= 8 && all isHexDigit hs- = case hs of- [a,b,c,d,e,f,g,h] -> withOpacity <$> (sRGB <$> hex a b <*> hex c d <*> hex e f) <*> hex g h- [a,b,c,d,e,f ] -> opaque <$> (sRGB <$> hex a b <*> hex c d <*> hex e f)- [a,b,c,d ] -> withOpacity <$> (sRGB <$> hex a a <*> hex b b <*> hex c c) <*> hex d d- [a,b,c ] -> opaque <$> (sRGB <$> hex a a <*> hex b b <*> hex c c)- _ -> fail $ "could not parse as a colour" ++ cs- handle _ = fail $ "could not parse as a colour: " ++ cs-- isHexDigit c = isDigit c || c `elem` "abcdef"+ ('0' : 'x' : hs) -> handle hs+ ('#' : hs) -> handle hs+ hs -> handle hs+ where+ handle hs | length hs <= 8 && all isHexDigit hs =+ case hs of+ [a, b, c, d, e, f, g, h] -> withOpacity <$> (sRGB <$> hex a b <*> hex c d <*> hex e f) <*> hex g h+ [a, b, c, d, e, f] -> opaque <$> (sRGB <$> hex a b <*> hex c d <*> hex e f)+ [a, b, c, d] -> withOpacity <$> (sRGB <$> hex a a <*> hex b b <*> hex c c) <*> hex d d+ [a, b, c] -> opaque <$> (sRGB <$> hex a a <*> hex b b <*> hex c c)+ _ -> fail $ "could not parse as a colour" ++ cs+ handle _ = fail $ "could not parse as a colour: " ++ cs - hex a b = (/ 255) <$> case readHex [a,b] of- [(h,"")] -> return h- _ -> fail $ "could not parse as a hex value" ++ [a,b]+ 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] -- | This instance is needed to signal the end of a chain of -- nested tuples, it always just results in the unit value@@ -332,7 +307,7 @@ parser = pure () -- | Allow 'Parseable' things to be combined.-instance (Parseable a, Parseable b) => Parseable (a,b) where+instance (Parseable a, Parseable b) => Parseable (a, b) where parser = (,) <$> parser <*> parser -- | Triples of Parsebales should also be Parseable.@@ -348,8 +323,8 @@ -- 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 @@ -370,8 +345,8 @@ -- | A list of named diagrams can give the multi-diagram interface. 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)]+ 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 @@ -402,8 +377,7 @@ 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 -- from the command line. It has the right instances to select between creating@@ -423,16 +397,13 @@ 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 :: *+ 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 :: Parseable (MainOpts d) => proxy d -> IO (MainOpts d) mainArgs _ = defaultOpts parser -- | Backend specific work of rendering with the given options and mainable@@ -457,17 +428,20 @@ -- implementation should be used to handle more complex interactions with the user. mainWith :: Parseable (MainOpts d) => d -> IO () mainWith d = do- opts <- mainArgs d+ 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 (ToResult d, Mainable (ResultOf d))- => Mainable (a -> d) where+instance+ (ToResult d, Mainable (ResultOf d)) =>+ Mainable (a -> d)+ where 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` ? @@ -495,14 +469,14 @@ -- 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. defaultMultiMainRender :: Mainable d => (MainOpts d, DiagramMultiOpts) -> [(String, d)] -> IO ()-defaultMultiMainRender (opts,multi) ds =- if multi^.list+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+ 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 ()@@ -526,9 +500,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 (QDiagram b v n Any) ~ 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 --@@ -540,107 +513,24 @@ -- -- 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 ::- (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+ (opts -> QDiagram b v n Any -> IO ()) ->+ -- | A lens into the output path.+ Lens' opts FilePath ->+ (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+ 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 out nDigits i opts = opts & out .~ output'- where fmt = "%0" ++ show nDigits ++ "d"- output' = addExtension (base ++ printf fmt i) ext- (base, ext) = splitExtension (opts^.out)--putStrF :: String -> IO ()-putStrF s = putStr s >> hFlush stdout--defaultLoopRender :: DiagramLoopOpts -> IO ()-defaultLoopRender opts = when (opts ^. loop) $ do- putStrLn "Looping turned on"- prog <- getProgName- args <- getArgs-- srcPath <- case opts ^. src of- Just path -> return path- Nothing -> fromMaybe (error nosrc) <$> findHsFile prog- where- nosrc = "Unable to find Haskell source file.\n"- ++ "Specify source file with '-s' or '--src'"- srcPath' <- canonicalizePath srcPath-- sandbox <- findSandbox []- sandboxArgs <- case sandbox of- Nothing -> return []- Just sb -> do- putStrLn ("Using sandbox " ++ takeDirectory sb)- return ["-package-db", sb]-- let args' = delete "-l" . delete "--loop" $ args- newProg = newProgName (takeFileName srcPath) prog- timeOfDay = take 8 . drop 11 . show . eventTime-- -- Polling is only used on Windows- withManagerConf defaultConfig { confPollInterval = opts ^. interval } $- \mgr -> do- lock <- newIORef False-- _ <- watchDir mgr (takeDirectory srcPath') (existsEvents (== srcPath'))- $ \ev -> do- running <- atomicModifyIORef lock ((,) True)- unless running $ do- putStrF ("Modified " ++ timeOfDay ev ++ " ... ")- exitCode <- recompile srcPath' newProg sandboxArgs- -- Call the new program without the looping option- run newProg args' exitCode- atomicWriteIORef lock False-- putStrLn $ "Watching source file " ++ srcPath- putStrLn $ "Compiling target: " ++ newProg- putStrLn $ "Program args: " ++ unwords args'- forever . threadDelay $ case os of- -- https://ghc.haskell.org/trac/ghc/ticket/7325- "darwin" -> 5000000000000- _ -> maxBound--recompile :: FilePath -> FilePath -> [String] -> IO ExitCode-recompile srcFile outFile args = do- let ghcArgs = ["--make", srcFile, "-o", outFile] ++ args- putStrF "compiling ... "- (exit, _, stderr) <- readProcessWithExitCode "ghc" ghcArgs ""- when (exit /= ExitSuccess) $ putStrLn ('\n':stderr)- return exit---- | On Windows, the next compilation must have a different output--- than the currently running program.-newProgName :: FilePath -> String -> String-newProgName srcFile oldName = case os of- "mingw32" ->- if oldName == replaceExtension srcFile "exe"- then replaceExtension srcFile ".1.exe"- else replaceExtension srcFile "exe"- _ -> dropExtension srcFile---- | Run the given program with specified arguments, if and only if--- the previous command returned ExitSuccess.-run :: String -> [String] -> ExitCode -> IO ()-run prog args ExitSuccess = do- let path = "." </> prog- putStrF "running ... "- (exit, stdOut, stdErr) <- readProcessWithExitCode path args ""- case exit of- ExitSuccess -> putStrLn "done."- ExitFailure r -> do- putStrLn $ prog ++ " failed with exit code " ++ show r- unless (null stdOut) $ putStrLn "stdout:" >> putStrLn stdOut- unless (null stdErr) $ putStrLn "stderr:" >> putStrLn stdErr-run _ _ _ = return ()+ where+ fmt = "%0" ++ show nDigits ++ "d"+ output' = addExtension (base ++ printf fmt i) ext+ (base, ext) = splitExtension (opts ^. out)
src/Diagrams/BoundingBox.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}@@ -38,9 +39,11 @@ , boxExtents, boxCenter , mCenterPoint, centerPoint , boxTransform, boxFit- , contains, contains', boundingBoxQuery+ , contains, contains' , inside, inside', outside, outside' + , boxGrid+ -- * Operations on bounding boxes , union, intersection ) where@@ -55,7 +58,8 @@ import Diagrams.Core import Diagrams.Core.Transform import Diagrams.Path-import Diagrams.ThreeD.Shapes+import Diagrams.Query+import Diagrams.ThreeD.Shapes (cube) import Diagrams.ThreeD.Types import Diagrams.TwoD.Path () import Diagrams.TwoD.Shapes@@ -65,7 +69,8 @@ import Data.Traversable as T import Linear.Affine import Linear.Metric-import Linear.Vector+import Linear.Vector hiding (lerp)+import Linear.Vector.Compat (lerp) -- Unexported utility newtype @@ -76,7 +81,7 @@ type instance N (NonEmptyBoundingBox v n) = n fromNonEmpty :: NonEmptyBoundingBox v n -> BoundingBox v n-fromNonEmpty = BoundingBox . Option . Just+fromNonEmpty = BoundingBox . Just fromMaybeEmpty :: Maybe (NonEmptyBoundingBox v n) -> BoundingBox v n fromMaybeEmpty = maybe emptyBox fromNonEmpty@@ -91,7 +96,7 @@ -- | 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 n = BoundingBox (Option (NonEmptyBoundingBox v n))+newtype BoundingBox v n = BoundingBox (Maybe (NonEmptyBoundingBox v n)) deriving (Eq, Functor) deriving instance (Additive v, Ord n) => Semigroup (BoundingBox v n)@@ -118,8 +123,12 @@ = fromMaybeEmpty (NonEmptyBoundingBox . mapT (moveOriginTo p) <$> getCorners b) +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+ => Enveloped (BoundingBox v n) where getEnvelope = getEnvelope . getAllCorners -- Feels like cheating.@@ -130,9 +139,8 @@ . getEnvelope instance TypeableFloat n => Traced (BoundingBox V3 n) where- getTrace = getTrace- . ((`boxFit` cube) . boundingBox :: Envelope V3 n -> D V3 n)- . getEnvelope+ 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@@ -159,7 +167,7 @@ -- | An empty bounding box. This is the same thing as @mempty@, but it doesn't -- require the same type constraints that the @Monoid@ instance does. emptyBox :: BoundingBox v n-emptyBox = BoundingBox $ Option Nothing+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.@@ -189,17 +197,17 @@ -- | Queries whether the BoundingBox is empty. isEmptyBox :: BoundingBox v n -> Bool-isEmptyBox (BoundingBox (Option Nothing)) = True+isEmptyBox (BoundingBox Nothing) = True isEmptyBox _ = False -- | Gets the lower and upper corners that define the bounding box. getCorners :: BoundingBox v n -> Maybe (Point v n, Point v n)-getCorners (BoundingBox p) = nonEmptyCorners <$> getOption p+getCorners (BoundingBox p) = nonEmptyCorners <$> p -- | Computes all of the corners of the bounding box. getAllCorners :: (Additive v, Traversable v) => BoundingBox v n -> [Point v n]-getAllCorners (BoundingBox (Option Nothing)) = []-getAllCorners (BoundingBox (Option (Just (NonEmptyBoundingBox (l, u)))))+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)@@ -256,9 +264,6 @@ check (l, h) = F.and (liftI2 (<) l p) && F.and (liftI2 (<) p h) -boundingBoxQuery :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> Query v n Any-boundingBoxQuery bb = Query $ Any . contains bb- -- | Test whether the first bounding box is contained inside -- the second. inside :: (Additive v, Foldable v, Ord n) => BoundingBox v n -> BoundingBox v n -> Bool@@ -311,3 +316,19 @@ union :: (Additive v, Ord n) => BoundingBox v n -> BoundingBox v n -> BoundingBox v n union = mappend +-- | @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+ mkRange lo hi = [lo, (1-f)*lo + f*hi .. hi]++ -- 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,10 +1,15 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+ -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.Combinators -- Copyright : (c) 2011 diagrams-lib team (see LICENSE)@@ -12,49 +17,55 @@ -- Maintainer : diagrams-discuss@googlegroups.com -- -- Higher-level tools for combining diagrams.-----------------------------------------------------------------------------------module Diagrams.Combinators- ( -- * Unary operations-- withEnvelope, withTrace- , phantom, strut- , pad, frame- , extrudeEnvelope, intrudeEnvelope-- -- * Binary operations- , atop- , beneath- , beside- , atDirection+module Diagrams.Combinators (+ -- * Unary operations+ withEnvelope,+ withTrace,+ phantom,+ strut,+ pad,+ frame,+ extrudeEnvelope,+ intrudeEnvelope, - -- * n-ary operations- , appends- , position, atPoints- , cat, cat'- , CatOpts(_catMethod, _sep), catMethod, sep- , CatMethod(..)+ -- * Binary operations+ atop,+ beneath,+ beside,+ atDirection, - ) where+ -- * n-ary operations+ appends,+ position,+ atPoints,+ cat,+ cat',+ CatOpts (_catMethod, _sep),+ catMethod,+ sep,+ CatMethod (..),+ composeAligned,+) where -import Control.Lens hiding (beside, ( # ))-import Data.Default.Class-import Data.Monoid.Deletable (toDeletable)-import Data.Monoid.MList (inj)-import Data.Proxy-import Data.Semigroup-import qualified Data.Tree.DUAL as D+import Control.Lens hiding (beside, (#))+import Data.Default+import Data.Maybe (fromJust, listToMaybe)+import Data.Monoid.Deletable (toDeletable)+import Data.Monoid.MList (inj)+import Data.Proxy+import Data.Semigroup+import qualified Data.Tree.DUAL as D -import Diagrams.Core-import Diagrams.Core.Types (QDiagram (QD))-import Diagrams.Direction-import Diagrams.Segment (straight)-import Diagrams.Util+import Diagrams.Core+import Diagrams.Core.Types (QDiagram (QD))+import Diagrams.Direction+import Diagrams.Names (named)+import Diagrams.Segment (straight)+import Diagrams.Util -import Linear.Affine-import Linear.Metric-import Linear.Vector+import Linear.Affine+import Linear.Metric+import Linear.Vector ------------------------------------------------------------ -- Working with envelopes@@ -73,14 +84,16 @@ -- > ) -- > c = circle 0.8 -- > withEnvelopeEx = sqNewEnv # centerXY # pad 1.5-withEnvelope :: (InSpace v n a, Monoid' m, Enveloped a)- => a -> QDiagram b v n m -> QDiagram b v n 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 :: (InSpace v n a, Metric v, OrderedField n, Monoid' m, Traced a)- => a -> QDiagram b v n m -> QDiagram b v n 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@@ -94,42 +107,47 @@ -- 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 :: (Metric v, OrderedField n, Monoid' m)- => n -> QDiagram b v n m -> QDiagram b v n 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 :: (Metric v, OrderedField n, Monoid' m)- => n -> QDiagram b v n m -> QDiagram b v n m+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 :: (Metric v, OrderedField n)- => v n -> QDiagram b v n 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- -- trace as well, and segments do not have a trace in general (only- -- in 2D; see Diagrams.TwoD.Segment). This is a good reason to have- -- a special 'strut' combinator (before the introduction of traces- -- it was mostly just for convenience).- --- -- also note that we can't remove the call to getEnvelope, since- -- translating a segment has no effect.+ where+ env = translate ((-0.5) *^ v) . getEnvelope $ straight v +-- note we can't use 'phantom' here because it tries to construct a+-- trace as well, and segments do not have a trace in general (only+-- in 2D; see Diagrams.TwoD.Segment). This is a good reason to have+-- a special 'strut' combinator (before the introduction of traces+-- it was mostly just for convenience).+--+-- also note that we can't remove the call to getEnvelope, since+-- translating a segment has no effect.+ -- | @extrudeEnvelope v d@ asymmetrically \"extrudes\" the envelope of -- a diagram in the given direction. All parts of the envelope -- within 90 degrees of this direction are modified, offset outwards@@ -138,10 +156,10 @@ -- This works by offsetting the envelope distance proportionally to -- the cosine of the difference in angle, and leaving it unchanged -- when this factor is negative.-extrudeEnvelope- :: (Metric v, OrderedField n, Monoid' m)- => v n -> QDiagram b v n m -> QDiagram b v n m-extrudeEnvelope = deformEnvelope 0.5+extrudeEnvelope ::+ (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@@ -150,23 +168,23 @@ -- -- Note that this could create strange inverted envelopes, where -- @ diameter v d < 0 @.-intrudeEnvelope- :: (Metric v, OrderedField n, Monoid' m)- => v n -> QDiagram b v n m -> QDiagram b v n m-intrudeEnvelope = deformEnvelope (-0.5)+intrudeEnvelope ::+ (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- :: (Metric v, OrderedField n, Monoid' m)- => n -> v n -> QDiagram b v n m -> QDiagram b v n m+deformEnvelope ::+ (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' env v'- | dp > 0 = Max $ getMax (env v') + (dp * s) / norm v'- | otherwise = env v'- where- dp = v' `dot` v+ where+ deformE = fmap deformE'+ deformE' env v'+ | dp > 0 = Max $ getMax (env v') + (dp * s) / quadrance v'+ | otherwise = env v'+ where+ dp = v' `dot` v ------------------------------------------------------------ -- Combining two objects@@ -175,8 +193,9 @@ -- | @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 :: (Metric v, OrderedField n, Monoid' m)- => QDiagram b v n m -> QDiagram b v n m -> QDiagram b v n 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`@@ -224,8 +243,9 @@ -- 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 ::+ (InSpace v n a, Metric v, Floating n, Juxtaposable a, Semigroup a) =>+ Direction v n -> a -> a -> a atDirection = beside . fromDirection ------------------------------------------------------------@@ -242,8 +262,8 @@ -- > 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 -> [(Vn a,a)] -> a-appends d1 apps = d1 <> mconcat (map (\(v,d) -> juxtapose v d1 d) apps)+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 -- (e.g. diagrams or paths) by assigning them absolute positions in@@ -264,26 +284,30 @@ atPoints ps as = position $ zip ps as -- | Methods for concatenating diagrams.-data CatMethod = Cat -- ^ Normal catenation: simply put diagrams- -- next to one another (possibly with a- -- certain distance in between each). The- -- distance between successive diagram- -- /envelopes/ will be consistent; the- -- distance between /origins/ may vary if- -- the diagrams are of different sizes.- | Distrib -- ^ Distribution: place the local origins of- -- diagrams at regular intervals. With- -- this method, the distance between- -- successive /origins/ will be consistent- -- but the distance between envelopes may- -- not be. Indeed, depending on the amount- -- of separation, diagrams may overlap.+data CatMethod+ = -- | Normal catenation: simply put diagrams+ -- next to one another (possibly with a+ -- certain distance in between each). The+ -- distance between successive diagram+ -- /envelopes/ will be consistent; the+ -- distance between /origins/ may vary if+ -- the diagrams are of different sizes.+ Cat+ | -- | Distribution: place the local origins of+ -- diagrams at regular intervals. With+ -- this method, the distance between+ -- successive /origins/ will be consistent+ -- but the distance between envelopes may+ -- not be. Indeed, depending on the amount+ -- of separation, diagrams may overlap.+ Distrib -- | Options for 'cat''.-data CatOpts n = CatOpts { _catMethod :: CatMethod- , _sep :: n- , catOptsvProxy :: Proxy n- }+data CatOpts n = CatOpts+ { _catMethod :: CatMethod+ , _sep :: n+ , catOptsvProxy :: Proxy n+ } -- The reason the proxy field is necessary is that without it, -- altering the sep field could theoretically change the type of a@@ -309,10 +333,12 @@ sep :: Lens' (CatOpts n) n instance Num n => Default (CatOpts n) where- def = CatOpts { _catMethod = Cat- , _sep = 0- , catOptsvProxy = Proxy- }+ def =+ CatOpts+ { _catMethod = Cat+ , _sep = 0+ , catOptsvProxy = Proxy+ } -- | @cat v@ positions a list of objects so that their local origins -- lie along a line in the direction of @v@. Successive objects@@ -322,8 +348,9 @@ -- -- See also 'cat'', which takes an extra options record allowing -- certain aspects of the operation to be tweaked.-cat :: (InSpace v n a, Metric v, Floating n, Juxtaposable a, Monoid' a, HasOrigin a)- => v n -> [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@@ -343,11 +370,58 @@ -- Note that @cat' v (with & catMethod .~ Distrib) === mconcat@ -- (distributing with a separation of 0 is the same as -- superimposing).-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 *^ signorm (negated v)--cat' v (CatOpts { _catMethod = Distrib, _sep = s }) =+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 *^ signorm (negated v)+cat' v (CatOpts {_catMethod = Distrib, _sep = s}) = 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) =>+ -- | Alignment function+ (QDiagram b v n m -> QDiagram b v n m) ->+ -- | Composition function+ ([QDiagram b v n m] -> QDiagram b v n m) ->+ ([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 = maybe origin location . listToMaybe . fromJust $ mss++-- the fromJust is Justified since we put the () name in
src/Diagrams/Coordinates.hs view
@@ -19,8 +19,8 @@ ) where +import Data.Kind (Type) import Diagrams.Points- import Linear (V2 (..), V3 (..), V4 (..)) -- | Types which are instances of the @Coordinates@ class can be@@ -36,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
src/Diagrams/CubicSpline.hs view
@@ -1,39 +1,51 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}------------------------------------------------------------------------------+ -- | -- Module : Diagrams.CubicSpline -- Copyright : (c) 2011 diagrams-lib team (see LICENSE) -- 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. ---------------------------------------------------------------------------------module Diagrams.CubicSpline- (- -- * Constructing paths from cubic splines- cubicSpline- ) where+-- 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 Control.Lens (view)+import Data.List.NonEmpty (NonEmpty (..))+import Diagrams.CubicSpline.NonSingleton (NonSingleton (..)) -import Diagrams.Core-import Diagrams.CubicSpline.Internal-import Diagrams.Located (Located, at, mapLoc)-import Diagrams.Segment-import Diagrams.Trail-import Diagrams.TrailLike (TrailLike (..))+import Diagrams.Core+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 Linear.Affine-import Linear.Metric+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@@ -50,15 +62,16 @@ -- -- For more information, see <http://mathworld.wolfram.com/CubicSpline.html>. 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 [] = 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)+cubicSpline closed (p1 : p2 : ps) = flattenBeziers . map f . solveCubicSplineCoefficients closed . fmap (view lensP) $ (p1 :|| (p2 :| 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 :: (Metric v, OrderedField n)- => Bool -> Located (Trail' Line v n) -> Located (Trail v n)+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,156 @@+{-# 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.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE+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 = NonEmpty (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))++takeMaybe :: Int -> [a] -> Maybe [a]+takeMaybe 0 _ = Just []+takeMaybe _ [] = Nothing+takeMaybe k (a : as) = (a :) <$> takeMaybe (k - 1) as++-- | @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] -> [NonEmpty a]+windows 0 _ = []+windows _ [] = []+windows k (a : as) = case takeMaybe (k - 1) as of+ Just as' -> (a :| as') : windows k as+ Nothing -> []++-- | @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 _ [] = []+extend k (x : xs) = replicate k x ++ (x : xs) ++ replicate k (NE.last (x :| 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 :: NonEmpty n}++mkPolarPt :: Ord n => Point v n -> NonEmpty n -> PolarPt v n+mkPolarPt pt kts = PP pt (NE.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 (NE.head kts1) (NE.last kts2) newKt pt1 pt2)+ (newKt :| NE.drop 1 kts1)+ where+ newKt = NE.toList 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 = NE.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 (NE.toList 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,6 +1,7 @@------------------------------------------------------------------------------+{-# LANGUAGE GADTs #-}+ -- |--- Module : Diagrams.CubicSpline+-- Module : Diagrams.CubicSpline.Internal -- Copyright : (c) 2011 diagrams-lib team (see LICENSE) -- License : BSD-style (see LICENSE) -- Maintainer : diagrams-discuss@googlegroups.com@@ -9,53 +10,60 @@ -- passing through a given sequence of points. This module implements -- a straightforward spline generation algorithm based on solving -- tridiagonal systems of linear equations.----------------------------------------------------------------------------------module Diagrams.CubicSpline.Internal- (- -- * Solving for spline coefficents- solveCubicSplineDerivatives- , solveCubicSplineDerivativesClosed- , solveCubicSplineCoefficients- ) where--import Diagrams.Solve.Tridiagonal+module Diagrams.CubicSpline.Internal (+ -- * Solving for spline coefficents+ solveCubicSplineDerivatives,+ solveCubicSplineDerivativesClosed,+ solveCubicSplineCoefficients,+) where -import Data.List+import Data.List+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty.Compat as NE+import Diagrams.CubicSpline.NonSingleton (NonSingleton (..))+import qualified Diagrams.CubicSpline.NonSingleton as NS+import Diagrams.Solve.Tridiagonal -- | 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- as = replicate (l - 1) 1- bs = 2 : replicate (l - 2) 4 ++ [2]- l = length ds- ds = zipWith f (xs ++ [last xs]) (x:x:xs)- f a b = 3*(a - b)--solveCubicSplineDerivatives _ = error "argument to solveCubicSplineDerivatives must be nonempty"+--+-- See e.g. https://observablehq.com/@jrus/cubic-spline+solveCubicSplineDerivatives :: Fractional a => NonSingleton a -> NonEmpty a+solveCubicSplineDerivatives xs = solveTriDiagonal as bs as (NS.toNonEmpty ds)+ where+ as = NE.map (const 1) (NS.tail ds)+ bs = 2 :| map (const 4) (NE.tail (NS.tail ds)) ++ [2]+ -- zipWith f [x1, x2, x3, ..., xn, xn] [x0, x0, x1, ... x{n-2}, x{n-1}]+ ds = NS.zipWith f (NS.dupLast (NS.tail xs)) (NS.dupFirst xs)+ f a b = 3 * (a - b) -- | Use the cyclic-tri-diagonal solver with the appropriate parameters for a closed cubic spline.-solveCubicSplineDerivativesClosed :: Fractional a => [a] -> [a]+solveCubicSplineDerivativesClosed :: Fractional a => NonSingleton a -> NonEmpty a solveCubicSplineDerivativesClosed xs = solveCyclicTriDiagonal as bs as ds 1 1- where- as = replicate (l - 1) 1- bs = replicate l 4- l = length xs- xs' = cycle xs- ds = take l $ zipWith f (drop 1 xs') (drop (l - 1) xs')- f a b = 3*(a - b)+ where+ as = fmap (const 1) (NS.tail xs)+ bs = fmap (const 4) (NS.toNonEmpty xs) + -- zipWith f [x1, x2, x3, ..., xn, x0] [xn, x0, x1, ..., x{n-1}]+ -- ds = take l $ zipWith f (drop 1 xs') (drop (l - 1) xs') where l = length xs+ xsNE = NS.toNonEmpty xs+ ds = NE.zipWith f (NE.tail xsNE |: NE.head xsNE) (NE.cons (NE.last xsNE) xsNE)+ f a b = 3 * (a - b)++ (|:) :: [a] -> a -> NonEmpty a+ (|:) ys y = foldr NE.cons (NE.singleton y) ys+ -- | Use the cyclic-tri-diagonal solver with the appropriate parameters for a closed cubic spline.-solveCubicSplineCoefficients :: Fractional a => Bool -> [a] -> [[a]]+solveCubicSplineCoefficients :: Fractional a => Bool -> NonSingleton a -> [[a]] 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- ds | closed = solveCubicSplineDerivativesClosed xs- | otherwise = solveCubicSplineDerivatives xs- close as | closed = as ++ [head as]- | otherwise = as- xs' = close xs- ds' = close ds+ [ [x, d, 3 * (x1 - x) - 2 * d - d1, 2 * (x - x1) + d + d1]+ | (x, x1, d, d1) <- zip4 (NE.toList xs') (NE.tail xs') (NE.toList ds') (NE.tail ds')+ ]+ where+ ds+ | closed = solveCubicSplineDerivativesClosed xs+ | otherwise = solveCubicSplineDerivatives xs+ close as+ | closed = as <> NE.singleton (NE.head as)+ | otherwise = as+ xs' = close (NS.toNonEmpty xs)+ ds' = close ds
+ src/Diagrams/CubicSpline/NonSingleton.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE GADTSyntax #-}++-- |+-- Module : Diagrams.CubicSpline.NonSingleton+-- Copyright : (c) 2026 diagrams-lib team (see LICENSE)+-- License : BSD-style (see LICENSE)+-- Maintainer : diagrams-discuss@googlegroups.com+--+-- A simple type representing lists with at least 2 elements, needed+-- as input for the cubic spline solver.+module Diagrams.CubicSpline.NonSingleton (+ -- * Non-singleton lists+ NonSingleton (..),+ toNonEmpty,+ tail,+ zipWith,+ dupFirst,+ dupLast,+) where++import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE+import Prelude hiding (tail, zipWith)++-- | Lists with at least 2 elements.+data NonSingleton a where+ (:||) :: a -> NonEmpty a -> NonSingleton a+ deriving (Functor)++infixr 5 :||++toNonEmpty :: NonSingleton a -> NonEmpty a+toNonEmpty (x :|| xs) = NE.cons x xs++dupFirst :: NonSingleton a -> NonSingleton a+dupFirst (x :|| xs) = x :|| NE.cons x xs++dupLast :: NonEmpty a -> NonSingleton a+dupLast (x :| []) = x :|| (x :| [])+dupLast (x :| (y : ys)) = x :|| (y :| (ys ++ [NE.last (y :| ys)]))++zipWith :: (a -> b -> c) -> NonSingleton a -> NonSingleton b -> NonSingleton c+zipWith f (x :|| xs) (y :|| ys) = f x y :|| NE.zipWith f xs ys++tail :: NonSingleton a -> NonEmpty a+tail (_ :|| xs) = xs
src/Diagrams/Deform.hs view
@@ -1,8 +1,10 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Diagrams.Deform
src/Diagrams/Direction.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -27,8 +28,8 @@ import Diagrams.Core import Linear.Affine-import Linear.Vector import Linear.Metric+import Linear.Vector -------------------------------------------------------------------------------- -- Direction@@ -76,11 +77,10 @@ fromDir (Dir v) = signorm v -- | compute the positive angle between the two directions in their common plane-angleBetweenDirs :: (Metric v, Floating n)+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 directions from @p@ to @q@+-- | @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 $ p .-. q-+dirBetween p q = dir $ q .-. p
src/Diagrams/LinearMap.hs view
@@ -6,7 +6,9 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.LinearMap
src/Diagrams/Located.hs view
@@ -1,8 +1,10 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -26,18 +28,19 @@ where import Control.Lens (Lens, Lens')-#if __GLASGOW_HASKELL__ < 710-import Data.Functor ((<$>))-#endif import Text.Read import Linear.Affine import Linear.Vector +import Diagrams.Align import Diagrams.Core import Diagrams.Core.Transform import Diagrams.Parametric +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@@ -62,8 +65,10 @@ -- 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.@@ -144,6 +149,9 @@ 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) @@ -163,6 +171,8 @@ => 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
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
src/Diagrams/Parametric.hs view
@@ -22,12 +22,13 @@ ) where +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@@ -55,7 +56,7 @@ -- with numeric scalars). domainUpper :: p -> N p - default domainUpper :: Num n => p -> n+ default domainUpper :: Num (N p) => p -> N p domainUpper = const 1 -- | Type class for querying the values of a parametric object at the
src/Diagrams/Parametric/Adjust.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -25,7 +26,7 @@ (.~), (^.)) import Data.Proxy -import Data.Default.Class+import Data.Default import Diagrams.Core.V import Diagrams.Parametric
src/Diagrams/Path.hs view
@@ -1,17 +1,19 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 707-{-# LANGUAGE DeriveDataTypeable #-}-#endif-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}------------------------------------------------------------------------------+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}++-- for Data.Semigroup+ -- | -- Module : Diagrams.Path -- Copyright : (c) 2011 diagrams-lib team (see LICENSE)@@ -23,63 +25,56 @@ -- similar notion of \"path\". Note that paths with multiple trails -- are necessary for being able to draw /e.g./ filled objects with -- holes in them.-----------------------------------------------------------------------------------module Diagrams.Path- (-- -- * Paths-- Path(..), pathTrails-- -- * Constructing paths- -- $construct-- , ToPath (..)- , pathFromTrail- , pathFromTrailAt- , pathFromLocTrail-- -- * Eliminating paths-- , pathPoints- , pathVertices'- , pathVertices- , pathOffsets- , pathCentroid- , pathLocSegments, fixPath+module Diagrams.Path (+ -- * Paths+ Path (..),+ pathTrails, - -- * Modifying paths+ -- * Constructing paths+ -- $construct+ ToPath (..),+ pathFromTrail,+ pathFromTrailAt,+ pathFromLocTrail, - , scalePath- , reversePath+ -- * Eliminating paths+ pathPoints,+ pathVertices',+ pathVertices,+ pathOffsets,+ pathCentroid,+ pathLocSegments,+ fixPath, - -- * Miscellaneous+ -- * Modifying paths+ scalePath,+ reversePath, - , explodePath- , partitionPath+ -- * Miscellaneous+ explodePath,+ partitionPath,+) where - ) where+import Control.Arrow ((***))+import Control.Lens hiding (at, transform, (#))+import qualified Data.Foldable as F+import Data.List (partition)+import Data.Semigroup -import Control.Arrow ((***))-import Control.Lens hiding ((#), transform, at)-import qualified Data.Foldable as F-import Data.List (partition)-import Data.Semigroup-import Data.Typeable+import Diagrams.Align+import Diagrams.Core+import Diagrams.Located+import Diagrams.Points+import Diagrams.Segment+import Diagrams.Trail+import Diagrams.TrailLike+import Diagrams.Transform -import Diagrams.Align-import Diagrams.Core-import Diagrams.Located-import Diagrams.Points-import Diagrams.Segment-import Diagrams.Trail-import Diagrams.TrailLike-import Diagrams.Transform+import Linear.Metric+import Linear.Vector -import Linear.Metric-import Linear.Vector+import Data.Serialize (Serialize)+import GHC.Generics (Generic) ------------------------------------------------------------ -- Paths -------------------------------------------------@@ -90,23 +85,12 @@ -- and they form a monoid under /superposition/ (placing one path on -- top of another) rather than concatenation. newtype Path v n = Path [Located (Trail v n)]- deriving (Semigroup, Monoid-#if __GLASGOW_HASKELL__ >= 707- , Typeable-#endif- )+ deriving (Semigroup, Monoid, Generic) -#if __GLASGOW_HASKELL__ < 707--- This should really be Typeable2 Path but since Path has kind--- (* -> *) -> * -> *--- not--- * -> * -> *--- we can only do Typeable1 (Path v). This is why the instance cannot be--- derived.-instance forall v. Typeable1 v => Typeable1 (Path v) where- typeOf1 _ = mkTyConApp (mkTyCon3 "diagrams-lib" "Diagrams.Path" "Path") [] `mkAppTy`- typeOf1 (undefined :: v n)-#endif+-- 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 Wrapped (Path v n) where type Unwrapped (Path v n) = [Located (Trail v n)]@@ -133,8 +117,8 @@ pathTrails = op Path 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)+deriving instance Eq (v n) => Eq (Path v n)+deriving instance Ord (v n) => Ord (Path v n) type instance V (Path v n) = v type instance N (Path v n) = n@@ -145,18 +129,21 @@ -- | Paths are trail-like; a trail can be used to construct a -- singleton path. instance (Metric v, OrderedField n) => TrailLike (Path v n) where- trailLike = Path . (:[])+ trailLike = Path . (: []) -- See Note [Transforming paths]-instance (HasLinearMap v, Metric v, OrderedField n)- => Transformable (Path v n) where+instance+ (HasLinearMap v, Metric v, OrderedField n) =>+ Transformable (Path v n)+ where transform = over _Wrapped . map . transform 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 n) -> Envelope v n- trailEnvelope (viewLoc -> (p, t)) = moveOriginTo ((-1) *. p) (getEnvelope t)+ where+ -- this type signature is necessary to work around an apparent bug in ghc 6.12.1+ trailEnvelope :: Located (Trail v n) -> Envelope v n+ trailEnvelope (viewLoc -> (p, t)) = moveOriginTo ((-1) *. p) (getEnvelope t) instance (Metric v, OrderedField n) => Juxtaposable (Path v n) where juxtapose = juxtaposeDefault@@ -164,8 +151,10 @@ instance (Metric v, OrderedField n) => Alignable (Path v n) where defaultBoundary = envelopeBoundary -instance (HasLinearMap v, Metric v, OrderedField n)- => Renderable (Path v n) NullBackend where+instance+ (HasLinearMap v, Metric v, OrderedField n) =>+ Renderable (Path v n) NullBackend+ where render _ _ = mempty ------------------------------------------------------------@@ -177,7 +166,6 @@ -- 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'.@@ -189,6 +177,9 @@ 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 @@ -196,12 +187,12 @@ toPath = pathFromLocTrail . mapLoc Trail instance ToPath (Located (Segment Closed v n)) where- toPath (viewLoc -> (p,seg))- = Path [trailFromSegments [seg] `at` p]+ 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]+ toPath (viewLoc -> (p, segs)) =+ Path [trailFromSegments segs `at` p] instance ToPath (FixedSegment v n) where toPath = toPath . fromFixedSeg
src/Diagrams/Points.hs view
@@ -29,8 +29,11 @@ import Linear.Vector -- | The centroid of a set of /n/ points is their sum divided by /n/.+-- Returns the origin for an empty list of points. centroid :: (Additive v, Fractional n) => [Point v n] -> Point v n-centroid = meanV+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)
src/Diagrams/Prelude.hs view
@@ -1,6 +1,6 @@-{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} {-# LANGUAGE CPP #-}------------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}+ -- | -- Module : Diagrams.Prelude -- Copyright : (c) 2011-2015 diagrams-lib team (see LICENSE)@@ -9,76 +9,73 @@ -- -- A module to re-export most of the functionality of the diagrams -- core and standard library.-----------------------------------------------------------------------------------module Diagrams.Prelude- (- -- * Diagrams library- -- | Exports from this library for working with diagrams.- module Diagrams-- -- * Convenience re-exports from other packages-- -- | For working with default values. Diagrams also exports 'with',- -- an alias for 'def'.- , module Data.Default.Class-- -- | For representing and operating on colors.- , module Data.Colour-- -- | A large list of color names.- , module Data.Colour.Names-- -- | Specify your own colours.- , module Data.Colour.SRGB-- -- | 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 Linear.Vector-- -- | For computing with points and vectors.- , module Linear.Affine+module Diagrams.Prelude (+ -- * Diagrams library - -- | For computing with dot products and norm.- , module Linear.Metric+ -- | Exports from this library for working with diagrams.+ module Diagrams, - -- | For working with 'Active' (i.e. animated) things.- , module Data.Active+ -- * Convenience re-exports from other packages - -- | 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+ -- | For working with default values. Diagrams also exports 'with',+ -- an alias for 'def'.+ module Data.Default,+ -- | For representing and operating on colors.+ module Data.Colour,+ -- | A large list of color names.+ module Data.Colour.Names,+ -- | Specify your own colours.+ module Data.Colour.SRGB,+ -- | 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 Linear.Vector,+ -- | For computing with points and vectors.+ module Linear.Affine,+ -- | For computing with dot products and norm.+ module Linear.Metric,+ -- | 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,+ Applicative (..),+ (*>),+ (<*),+ (<$>),+ (<$),+ liftA,+ liftA2,+ liftA3,+) where - , Applicative(..), (*>), (<*), (<$>), (<$), liftA, liftA2, liftA3- ) where+import Diagrams -import Diagrams+import Prelude.Compat+import Prelude () -import Control.Applicative+import Control.Applicative #if MIN_VERSION_lens(4,13,0) import Control.Lens hiding (argument, at, backwards, beside,@@ -93,13 +90,13 @@ (<.>)) #endif -import Data.Active-import Data.Colour hiding (AffineSpace (..), atop, over)-import Data.Colour.Names hiding (tan)-import Data.Colour.SRGB-import Data.Default.Class-import Data.Semigroup+import Data.Active+import Data.Colour hiding (AffineSpace (..), atop, over)+import Data.Colour.Names hiding (tan)+import Data.Colour.SRGB+import Data.Default+import Data.Semigroup -import Linear.Affine-import Linear.Metric-import Linear.Vector+import Linear.Affine+import Linear.Metric+import Linear.Vector
src/Diagrams/Query.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Query@@ -12,9 +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,18 +1,18 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} ------------------------------------------------------------------------------ -- | -- Module : Diagrams.Segment -- Copyright : (c) 2011-2013 diagrams-lib team (see LICENSE)@@ -31,57 +31,63 @@ -- "Diagrams.Trail", "Diagrams.TrailLike", and "Diagrams.Path" should -- usually suffice. However, directly manipulating segments can -- occasionally be useful.-----------------------------------------------------------------------------------module Diagrams.Segment- ( -- * Open/closed tags-- Open, Closed-- -- * Segment offsets-- , Offset(..) , segOffset-- -- * Constructing and modifying segments-- , Segment(..), straight, bezier3, bézier3, reverseSegment, mapSegmentVectors- , openLinear, openCubic-- -- * Fixed (absolutely located) segments- , FixedSegment(..)- , mkFixedSeg, fromFixedSeg- , fixedSegIso-- -- * Segment measures- -- $segmeas-- , SegCount(..)- , ArcLength(..)- , getArcLengthCached, getArcLengthFun, getArcLengthBounded- , TotalOffset(..)- , OffsetEnvelope(..), oeOffset, oeEnvelope- , SegMeasure+module Diagrams.Segment (+ -- * Open/closed tags+ Open,+ Closed, - ) where+ -- * Segment offsets+ Offset (..),+ segOffset, -import Control.Lens hiding (at, transform)-import Data.FingerTree-import Data.Monoid.MList-import Data.Semigroup-import Numeric.Interval.Kaucher (Interval (..))-import qualified Numeric.Interval.Kaucher as I+ -- * Constructing and modifying segments+ Segment (..),+ straight,+ bezier3,+ bézier3,+ reverseSegment,+ mapSegmentVectors,+ openLinear,+ openCubic, -import Linear.Affine-import Linear.Metric-import Linear.Vector+ -- * Fixed (absolutely located) segments+ FixedSegment (..),+ mkFixedSeg,+ fromFixedSeg,+ fixedSegIso, -import Control.Applicative-import Diagrams.Core hiding (Measured)-import Diagrams.Located-import Diagrams.Parametric-import Diagrams.Solve.Polynomial+ -- * Segment measures+ -- $segmeas+ SegCount (..),+ ArcLength (..),+ getArcLengthCached,+ getArcLengthFun,+ getArcLengthBounded,+ TotalOffset (..),+ OffsetEnvelope (..),+ oeOffset,+ oeEnvelope,+ SegMeasure,+) where +import Control.Lens hiding (at, transform)+import Data.FingerTree+import Data.Monoid.MList+import Data.Semigroup+import Data.Serialize (Serialize)+import qualified Data.Serialize as Serialize+import Diagrams.Core hiding (Measured)+import Diagrams.Located+import Diagrams.Parametric+import Diagrams.Solve.Polynomial+import Linear.Affine+import Linear.Metric+import Linear.Vector hiding (lerp)+import Linear.Vector.Compat (lerp)+import Numeric.Interval.Kaucher (Interval (..))+import qualified Numeric.Interval.Kaucher as I+import Prelude.Compat+import Prelude () ------------------------------------------------------------ -- Open/closed type tags ---------------------------------@@ -106,32 +112,32 @@ -- /closed/ segment is stored explicitly, /i.e./ its endpoint is at -- a fixed offset from its start. data Offset c v n where- OffsetOpen :: Offset Open v n+ OffsetOpen :: Offset Open v n OffsetClosed :: v n -> Offset Closed v n 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)+deriving instance Eq (v n) => Eq (Offset c v n)+deriving instance Ord (v n) => Ord (Offset c v n) instance Functor v => Functor (Offset c v) where- fmap _ OffsetOpen = OffsetOpen+ fmap _ OffsetOpen = OffsetOpen fmap f (OffsetClosed v) = OffsetClosed (fmap f 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+ each _ OffsetOpen = pure OffsetOpen {-# INLINE each #-} -- | 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+ 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 _ OffsetOpen = OffsetOpen transform t (OffsetClosed v) = OffsetClosed (apply t v) ------------------------------------------------------------@@ -146,35 +152,41 @@ -- however, affected by other transformations such as rotations and -- scales. data Segment c v n- = Linear !(Offset c v n)- -- ^ A linear segment with given offset.-- | 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.-+ = -- | A linear segment with given offset.+ Linear !(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.+ Cubic !(v n) !(v n) !(Offset c v n) 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-+ 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+ 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.@@ -226,24 +238,29 @@ -- 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 (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+ 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 n => DomainBounds (Segment Closed v n) instance (Additive v, Num n) => EndValues (Segment Closed v n) where- atStart = const zero- atEnd (Linear (OffsetClosed v)) = v+ 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 n -> v n-segOffset (Linear (OffsetClosed v)) = v+segOffset (Linear (OffsetClosed v)) = v segOffset (Cubic _ _ (OffsetClosed v)) = v -- | An open linear segment. This means the trail makes a straight line@@ -284,18 +301,19 @@ -- | The envelope for a segment is based at the segment's start. instance (Metric v, OrderedField n) => Enveloped (Segment Closed v n) where- getEnvelope (s@(Linear {})) = mkEnvelope $ \v ->- maximum (map (\t -> (s `atParam` t) `dot` v) [0,1]) / quadrance 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) `dot` v) / quadrance v) $- [0,1] ++- filter (liftA2 (&&) (>0) (<1))- (quadForm (3 * ((3 *^ c1 ^-^ 3 *^ c2 ^+^ x2) `dot` v))- (6 * (((-2) *^ c1 ^+^ c2) `dot` v))- ((3 *^ c1) `dot` v))+ maximum+ . map (\t -> ((s `atParam` t) `dot` v) / quadrance v)+ $ [0, 1]+ ++ filter+ (liftA2 (&&) (> 0) (< 1))+ ( quadForm+ (3 * ((3 *^ c1 ^-^ 3 *^ c2 ^+^ x2) `dot` v))+ (6 * (((-2) *^ c1 ^+^ c2) `dot` v))+ ((3 *^ c1) `dot` v)+ ) ------------------------------------------------------------ -- Manipulating segments@@ -303,54 +321,66 @@ 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 t x1 zero+ where+ left = straight p+ right = straight (x1 ^-^ p)+ 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 t c2 c1- a = lerp t c1 zero- b = lerp t p a- d = lerp t x2 c2- c = lerp t d p- e = lerp t c b+ where+ left = bezier3 a b e+ right = bezier3 (c ^-^ e) (d ^-^ e) (x2 ^-^ e)+ 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 :: (Num n, Additive v) => Segment Closed v n -> Segment Closed v n-reverseSegment (Linear (OffsetClosed v)) = straight (negated v)+reverseSegment (Linear (OffsetClosed v)) = straight (negated v) reverseSegment (Cubic c1 c2 (OffsetClosed x2)) = bezier3 (c2 ^-^ x2) (c1 ^-^ x2) (negated x2) -instance (Metric v, OrderedField n)- => HasArcLength (Segment Closed v n) 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 #-} +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 norm [c1, c2 ^-^ c1, x2 ^-^ c2])- lb = norm x2+ | otherwise = arcLengthBounded (m / 2) l + arcLengthBounded (m / 2) r+ where+ (l, r) = s `splitAtParam` 0.5+ 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 < 0 = - arcLengthToParam m (fst (splitAtParam s (-1))) (-len)- | len `I.elem` 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)- $ arcLengthToParam (9*m/10) r (len - I.midpoint llen)- where (l,r) = s `splitAtParam` 0.5- llen = arcLengthBounded (m/10) l- slen = arcLengthBounded m s+ arcLengthToParam m s@(Cubic {}) len+ | len `member` I (-m / 2) (m / 2) = 0+ | len < 0 = -arcLengthToParam m (fst (splitAtParam s (-1))) (-len)+ | 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)+ $ arcLengthToParam (9 * m / 10) r (len - I.midpoint llen)+ where+ (l, r) = s `splitAtParam` 0.5+ llen = arcLengthBounded (m / 10) l+ slen = arcLengthBounded m s - -- Note, the above seems to be quite slow since it duplicates a lot of- -- work. We could trade off some time for space by building a tree of- -- parameter values (up to a certain depth...)+-- Note, the above seems to be quite slow since it duplicates a lot of+-- work. We could trade off some time for space by building a tree of+-- parameter values (up to a certain depth...) ------------------------------------------------------------ -- Fixed segments@@ -361,21 +391,22 @@ -- (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 n = FLinear (Point v n) (Point v n)- | FCubic (Point v n) (Point v n) (Point v n) (Point v n)- 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 n) = v type instance N (FixedSegment v n) = n 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+ 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 #-} -- | Reverses the control points. instance Reversing (FixedSegment v n) where- reversing (FLinear p0 p1) = FLinear p1 p0+ reversing (FLinear p0 p1) = FLinear p1 p0 reversing (FCubic p0 p1 p2 p3) = FCubic p3 p2 p1 p0 instance (Additive v, Num n) => Transformable (FixedSegment v n) where@@ -386,15 +417,18 @@ instance (Metric v, OrderedField n) => Enveloped (FixedSegment v n) where getEnvelope f = moveTo p (getEnvelope s)- where (p, s) = viewLoc $ fromFixedSeg f+ where+ (p, s) = viewLoc $ fromFixedSeg f - -- Eventually we might decide it's cleaner/more efficient (?) to- -- have all the computation in the FixedSegment instance of- -- Envelope, and implement the Segment instance in terms of it,- -- instead of the other way around+-- Eventually we might decide it's cleaner/more efficient (?) to+-- have all the computation in the FixedSegment instance of+-- 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+instance+ (Metric v, OrderedField n) =>+ HasArcLength (FixedSegment v n)+ where arcLengthBounded m s = arcLengthBounded m (fromFixedSeg s) arcLengthToParam m s = arcLengthToParam m (fromFixedSeg s) @@ -402,12 +436,12 @@ 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)+ (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 :: (Num n, Additive v) => FixedSegment v n -> Located (Segment Closed v n)-fromFixedSeg (FLinear p1 p2) = straight (p2 .-. p1) `at` p1+fromFixedSeg (FLinear p1 p2) = straight (p2 .-. p1) `at` p1 fromFixedSeg (FCubic x1 c1 c2 x2) = bezier3 (c1 .-. x1) (c2 .-. x1) (x2 .-. x1) `at` x1 -- | Use a 'FixedSegment' to make an 'Iso' between an@@ -418,42 +452,45 @@ 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 p2 p1+ atParam (FLinear p1 p2) t = lerp t p1 p2 atParam (FCubic x1 c1 c2 x2) t = p3- where p11 = lerp t c1 x1- p12 = lerp t c2 c1- p13 = lerp t x2 c2+ where+ p11 = lerp t x1 c1+ p12 = lerp t c1 c2+ p13 = lerp t c2 x2 - p21 = lerp t p12 p11- p22 = lerp t p13 p12+ p21 = lerp t p11 p12+ p22 = lerp t p12 p13 - p3 = lerp t p22 p21+ p3 = lerp t p21 p22 instance Num n => DomainBounds (FixedSegment v n) 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+ atStart (FLinear p0 _) = p0+ atStart (FCubic p0 _ _ _) = p0+ atEnd (FLinear _ p1) = p1+ atEnd (FCubic _ _ _ p1) = p1 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 = lerp t p1 p0+ where+ left = FLinear p0 p+ right = FLinear p p1+ 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 = lerp t c1 p0- p = lerp t c2 c1- d = lerp t p1 c2- -- second round- b = lerp t p a- c = lerp t d p- -- final round- cut = lerp t c b+ where+ left = FCubic p0 a b cut+ right = FCubic cut c d p1+ -- first round+ a = lerp t p0 c1+ p = lerp t c1 c2+ d = lerp t c2 p1+ -- second round+ b = lerp t a p+ c = lerp t p d+ -- final round+ cut = lerp t b c reverseDomain (FLinear p0 p1) = FLinear p1 p0 reverseDomain (FCubic p0 c1 c2 p1) = FCubic p1 c2 c1 p0@@ -481,7 +518,6 @@ -- computed to within a tolerance of @10e-6@. The second component is -- a generic arc length function taking the tolerance as an -- argument.- newtype ArcLength n = ArcLength (Sum (Interval n), n -> Sum (Interval n)) @@ -504,15 +540,17 @@ -- | 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 n, Ord n)- => n -> ArcLength n -> Interval n+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+ | otherwise = getArcLengthFun al eps+ where+ cached = getArcLengthCached al+ deriving instance (Num n, Ord n) => Semigroup (ArcLength n)-deriving instance (Num n, Ord n) => Monoid (ArcLength n)+deriving instance (Num n, Ord n) => Monoid (ArcLength n) -- | A type to represent the total cumulative offset of a chain of -- segments.@@ -528,7 +566,7 @@ TotalOffset v1 <> TotalOffset v2 = TotalOffset (v1 ^+^ v2) instance (Num n, Additive v) => Monoid (TotalOffset v n) where- mempty = TotalOffset zero+ mempty = TotalOffset zero mappend = (<>) -- | A type to represent the offset and envelope of a chain of@@ -536,47 +574,99 @@ -- combining the envelopes of two consecutive chains needs to take -- the offset of the first into account. data OffsetEnvelope v n = OffsetEnvelope- { _oeOffset :: !(TotalOffset v n)+ { _oeOffset :: !(TotalOffset v n) , _oeEnvelope :: Envelope v n } makeLenses ''OffsetEnvelope instance (Metric v, OrderedField n) => Semigroup (OffsetEnvelope v n) where- (OffsetEnvelope o1 e1) <> (OffsetEnvelope o2 e2)- = let !negOff = negated . op TotalOffset $ o1- e2Off = moveOriginBy negOff e2- !_unused = maybe () (\f -> f `seq` ()) $ appEnvelope e2Off- in OffsetEnvelope+ (OffsetEnvelope o1 e1) <> (OffsetEnvelope o2 e2) =+ let !negOff = negated . op TotalOffset $ o1+ e2Off = moveOriginBy negOff e2+ !_unused = maybe () (\f -> f `seq` ()) $ appEnvelope e2Off+ in OffsetEnvelope (o1 <> o2) (e1 <> e2Off) -- | @SegMeasure@ collects up all the measurements over a chain of -- segments.-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).+type SegMeasure v n =+ SegCount+ ::: ArcLength n+ ::: OffsetEnvelope v n+ ::: () -instance (Metric v, OrderedField n)- => Measured (SegMeasure v n) (SegMeasure v n) where+-- unfortunately we can't cache Trace, since there is not a generic+-- instance Traced (Segment Closed v), only Traced (Segment Closed R2).++instance+ (Metric v, OrderedField n) =>+ Measured (SegMeasure v n) (SegMeasure v n)+ where measure = id -instance (OrderedField n, Metric v)- => Measured (SegMeasure v n) (Segment Closed v n) 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+ )+ *: OffsetEnvelope+ (TotalOffset . segOffset $ s)+ (getEnvelope s)+ *: () - -- 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 )+------------------------------------------------------------+-- Serialize instances+------------------------------------------------------------ - *: OffsetEnvelope (TotalOffset . segOffset $ s)- (getEnvelope s)+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
@@ -1,19 +1,19 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 707-{-# LANGUAGE DeriveDataTypeable #-}-#endif-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-} -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.Size -- Copyright : (c) 2014 diagrams-lib team (see LICENSE)@@ -21,45 +21,42 @@ -- Maintainer : diagrams-discuss@googlegroups.com -- -- Utilities for working with sizes of objects.----------------------------------------------------------------------------------module Diagrams.Size- ( -- * Size spec- SizeSpec+module Diagrams.Size (+ -- * Size spec+ SizeSpec, - -- ** Making size spec- , mkSizeSpec- , dims- , absolute+ -- ** Making size spec+ mkSizeSpec,+ dims,+ absolute, - -- ** Extracting size specs- , getSpec- , specToSize+ -- ** Extracting size specs+ getSpec,+ specToSize, - -- ** Functions on size specs- , requiredScale- , requiredScaling- , sized- , sizedAs- , sizeAdjustment- ) where+ -- ** 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.Semigroup-import Data.Maybe-import Data.Typeable-import GHC.Generics (Generic)-import Prelude+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 GHC.Generics (Generic)+import Prelude -import Diagrams.Core-import Diagrams.BoundingBox+import Diagrams.BoundingBox+import Diagrams.Core -import Linear.Affine-import Linear.Vector+import Linear.Affine+import Linear.Vector ------------------------------------------------------------ -- Computing diagram sizes@@ -68,20 +65,13 @@ -- | A 'SizeSpec' is a way of specifying a size without needed lengths for all -- the dimensions. newtype SizeSpec v n = SizeSpec (v n)- deriving (-#if __GLASGOW_HASKELL__ >= 707- Typeable,-#endif- Functor,- Generic,- Hashable,- Show)--#if __GLASGOW_HASKELL__ < 707-instance forall v. Typeable1 v => Typeable1 (SizeSpec v) where- typeOf1 _ = mkTyConApp (mkTyCon3 "diagrams-lib" "Diagrams.Size" "Size") [] `mkAppTy`- typeOf1 (undefined :: v n)-#endif+ deriving+ ( Eq+ , Functor+ , Generic+ , Hashable+ , Show+ ) type instance V (SizeSpec v n) = v type instance N (SizeSpec v n) = n@@ -89,7 +79,7 @@ -- | 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+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@@ -111,56 +101,67 @@ -- 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+ 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 ::+ (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+ | 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 ::+ (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 ::+ (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 ::+ ( 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 ::+ (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))+ 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+ sz = boxExtents bb+ sz' =+ if allOf folded isJust (getSpec spec)+ then specToSize 0 spec+ else s *^ sz - s = requiredScale spec sz+ s = requiredScale spec sz - t = translation v <> scaling s+ t = translation v <> scaling s
src/Diagrams/Tangent.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE GADTs #-} -- for ghc < 7.8, TypeFamilies covers GADT patten mathcing in > 7.8 {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}
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 --@@ -40,17 +40,16 @@ -- highlights. ----------------------------------------------------------------------------- module Diagrams.ThreeD- (- 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+ ( 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@@ -61,4 +60,3 @@ import Diagrams.ThreeD.Transform import Diagrams.ThreeD.Types import Diagrams.ThreeD.Vector-
src/Diagrams/ThreeD/Align.hs view
@@ -1,4 +1,6 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} ----------------------------------------------------------------------------- -- |
src/Diagrams/ThreeD/Attributes.hs view
@@ -1,9 +1,9 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.ThreeD.Attributes@@ -29,7 +29,6 @@ import Control.Lens import Data.Semigroup-import Data.Typeable import Data.Colour @@ -38,7 +37,7 @@ -- | @SurfaceColor@ is the inherent pigment of an object, assumed to -- be opaque. newtype SurfaceColor = SurfaceColor (Last (Colour Double))- deriving (Typeable, Semigroup)+ deriving (Semigroup, Show) instance AttributeClass SurfaceColor @@ -59,7 +58,7 @@ -- 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 (Semigroup, Show) instance AttributeClass Diffuse @@ -82,7 +81,7 @@ -- indirect lighting incident on that object and the diffuse -- reflectance. newtype Ambient = Ambient (Last Double)- deriving (Typeable, Semigroup)+ deriving (Semigroup, Show) instance AttributeClass Ambient @@ -107,12 +106,12 @@ data Specular = Specular { _specularIntensity :: Double , _specularSize :: Double- }+ } deriving Show makeLenses ''Specular newtype Highlight = Highlight (Last Specular)- deriving (Typeable, Semigroup)+ deriving (Semigroup, Show) instance AttributeClass Highlight @@ -136,4 +135,3 @@ -- 'Specular', setting this will do nothing. highlightSize :: Traversal' (Style v n) Double highlightSize = _highlight . _Just . specularSize-
src/Diagrams/ThreeD/Camera.hs view
@@ -1,10 +1,9 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} -----------------------------------------------------------------------------@@ -50,23 +49,11 @@ , up :: V3 n , lens :: l n }-#if __GLASGOW_HASKELL__ >= 707- deriving Typeable-#else -instance forall l. Typeable1 l => Typeable1 (Camera l) where- typeOf1 _ = mkTyConApp (mkTyCon3 "diagrams-lib" "Diagrams.ThreeD.Camera" "Camera") [] `mkAppTy`- typeOf1 (undefined :: l n)-#endif- type instance V (Camera l n) = V3 type instance N (Camera l n) = n -#if __GLASGOW_HASKELL__ > 707 class Typeable l => CameraLens l where-#else-class Typeable1 l => CameraLens l where-#endif -- | The natural aspect ratio of the projection. aspect :: Floating n => l n -> n @@ -75,7 +62,6 @@ { _horizontalFieldOfView :: Angle n -- ^ Horizontal field of view. , _verticalFieldOfView :: Angle n -- ^ Vertical field of view. }- deriving Typeable makeLenses ''PerspectiveLens @@ -90,7 +76,6 @@ { _orthoWidth :: n -- ^ Width , _orthoHeight :: n -- ^ Height }- deriving Typeable makeLenses ''OrthoLens
src/Diagrams/ThreeD/Deform.hs view
@@ -19,7 +19,7 @@ -- | The perspective division onto the plane z=1 along lines going -- through the origin. perspectiveZ1 :: (R3 v, Functor v, Fractional n) => Deformation v v n-perspectiveZ1 = Deformation $ \p -> p ^/ (p ^. _x)+perspectiveZ1 = Deformation $ \p -> p ^/ (p ^. _z) facingZ :: (R3 v, Functor v, Fractional n) => Deformation v v n facingZ = Deformation $
src/Diagrams/ThreeD/Light.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -28,7 +29,6 @@ -- | A @PointLight@ radiates uniformly in all directions from a given -- point. data PointLight n = PointLight (Point V3 n) (Colour Double)- deriving Typeable type instance V (PointLight n) = V3 type instance N (PointLight n) = n@@ -36,7 +36,6 @@ -- | 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 (ParallelLight n) = V3 type instance N (ParallelLight n) = n
src/Diagrams/ThreeD/Shapes.hs view
@@ -1,9 +1,10 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -17,22 +18,37 @@ ----------------------------------------------------------------------------- module Diagrams.ThreeD.Shapes- (- Ellipsoid(..), sphere- , Box(..), cube- , Frustum(..) , frustum, cone, cylinder- ) where+ (+ -- * Skinned class+ Skinned(..) -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative-#endif+ -- * 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.Semigroup import Diagrams.Angle import Diagrams.Core+import Diagrams.Core.Trace import Diagrams.Points+import Diagrams.Query import Diagrams.Solve.Polynomial import Diagrams.ThreeD.Types import Diagrams.ThreeD.Vector@@ -42,7 +58,6 @@ import Linear.Vector data Ellipsoid n = Ellipsoid (Transformation V3 n)- deriving Typeable type instance V (Ellipsoid n) = V3 type instance N (Ellipsoid n) = n@@ -53,61 +68,59 @@ 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 :: (Typeable n, OrderedField n, Renderable (Ellipsoid n) b) => QDiagram b V3 n Any-sphere = mkQD (Prim $ Ellipsoid mempty)- (mkEnvelope sphereEnv)- (mkTrace sphereTrace)- mempty- (Query sphereQuery)- where- sphereEnv v = 1 / norm v- sphereTrace (P p) v = mkSortedList $ quadForm a b c- where- a = v `dot` v- b = 2 * (p `dot` v)- c = p `dot` (p - 1)- sphereQuery v = Any $ quadrance (v .-. origin) <= 1+sphere :: Num n => Ellipsoid n+sphere = Ellipsoid mempty data Box n = Box (Transformation V3 n)- deriving Typeable type instance V (Box n) = V3 type instance N (Box n) = n instance Fractional n => Transformable (Box n) where- transform t1 (Box t2) = Box (t1 <> t2)+ transform t1 (Box t2) = Box (t1 <> t2) 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 :: (Typeable n, OrderedField n, Renderable (Box n) b) => QDiagram b V3 n Any-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 `dot`) corners) / quadrance 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 +-- | A cube with side length 1, in the positive octant, with one+-- vertex at the origin.+cube :: Num n => Box n+cube = Box mempty+ data Frustum n = Frustum n n (Transformation V3 n)- deriving Typeable type instance V (Frustum n) = V3 type instance N (Frustum n) = n@@ -118,55 +131,189 @@ 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 :: (TypeableFloat n, Renderable (Frustum n) b) => n -> n -> QDiagram b V3 n Any-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 = norm $ 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 (norm . project v . review r3CylindricalIso) $ 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 = [ t | ray t ^. lensP . r3CylindricalIso . _1 < r0 + z * dr ]- 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 :: (TypeableFloat n, Renderable (Frustum n) b) => QDiagram b V3 n Any+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 :: (TypeableFloat n, Renderable (Frustum n) b) => QDiagram b V3 n Any+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)++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
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}
src/Diagrams/ThreeD/Transform.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -5,6 +6,10 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.ThreeD.Transform@@ -50,9 +55,9 @@ import Diagrams.Angle import Diagrams.Direction+import Diagrams.Points import Diagrams.ThreeD.Types import Diagrams.Transform-import Diagrams.Points import Control.Lens (view, (&), (*~), (.~), (//~)) import Data.Semigroup@@ -138,18 +143,18 @@ -- 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 :: Floating n+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' :: Floating n => V3 n -> V3 n -> V3 n -> Transformation V3 n+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) -- | pointAtUnit has the same behavior as @pointAt@, but takes unit vectors.-pointAtUnit :: Floating n => V3 n -> V3 n -> V3 n -> Transformation V3 n+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
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
src/Diagrams/Trail.hs view
@@ -1,1313 +1,1539 @@-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# 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-2015 diagrams-lib team (see LICENSE)--- License : BSD-style (see LICENSE)--- Maintainer : diagrams-discuss@googlegroups.com------ This module defines /trails/, translationally invariant paths--- through space. Trails form a central part of the diagrams-lib API,--- so the documentation for this module merits careful study.------ Related modules include:------ * The 'TrailLike' class ("Diagrams.TrailLike") exposes a generic--- API for building a wide range of things out of trails.------ * 'Path's ("Diagrams.Path") are collections of 'Located'--- ("Diagrams.Located") trails.------ * Trails are composed of 'Segment's (see "Diagrams.Segment"),--- though most users should not need to work with segments directly.-----------------------------------------------------------------------------------module Diagrams.Trail- (- -- * Type definitions-- -- ** Lines and loops-- Trail'(..)-- , glueLine- , closeLine- , cutLoop-- -- ** Generic trails-- , Trail(..)- , _Line, _Loop- , wrapTrail, wrapLine, wrapLoop- , onTrail, onLine-- , glueTrail, closeTrail, cutTrail-- -- * Constructing trails-- , emptyLine, emptyTrail- , lineFromVertices, trailFromVertices- , lineFromOffsets, trailFromOffsets- , lineFromSegments, trailFromSegments- , loopFromSegments-- -- * Eliminating trails-- , withTrail', withTrail, withLine- , isLineEmpty, isTrailEmpty- , isLine, isLoop- , trailSegments, lineSegments, loopSegments- , onLineSegments- , trailOffsets, trailOffset- , lineOffsets, lineOffset, loopOffsets- , trailPoints, linePoints, loopPoints- , trailVertices', lineVertices', loopVertices'- , trailVertices, lineVertices, loopVertices- , trailLocSegments, fixTrail-- -- * Modifying trails-- , reverseTrail, reverseLocTrail- , reverseLine, reverseLocLine- , reverseLoop, reverseLocLoop-- -- * Internals- -- $internals-- -- ** Type tags-- , Line, Loop-- -- ** Segment trees-- , SegTree(..), trailMeasure, numSegs, offset-- -- ** Extracting segments-- , GetSegment(..), getSegment-- ) where--import Control.Arrow ((***))-import Control.Lens hiding (at, transform, (<|), (|>))-import Data.FingerTree (FingerTree, ViewL (..), ViewR (..),- (<|), (|>))-import qualified Data.FingerTree as FT-import Data.Fixed-import qualified Data.Foldable as F-import Data.Monoid.MList-import Data.Semigroup-import qualified Numeric.Interval.Kaucher as I--import Diagrams.Core-import Diagrams.Located-import Diagrams.Parametric-import Diagrams.Segment-import Diagrams.Tangent--import Linear.Affine-import Linear.Metric-import Linear.Vector---- $internals------ Most users of diagrams should not need to use anything in this--- section directly, but they are exported on the principle that we--- can't forsee what uses people might have for them.----------------------------------------------------------------- FingerTree instances---------------------------------------------------------------type instance V (FingerTree m a) = V a-type instance N (FingerTree m a) = N 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 ---------------------------------------------------------------------------------------------------------- | A @SegTree@ represents a sequence of closed segments, stored in a--- fingertree so we can easily recover various monoidal measures of--- the segments (number of segments, arc length, envelope...) and--- also easily slice and dice them according to the measures--- (/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 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 n) where- type Unwrapped (SegTree v n) = FingerTree (SegMeasure v n) (Segment Closed v n)- _Wrapped' = iso (\(SegTree x) -> x) SegTree- {-# INLINE _Wrapped' #-}--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 #-}--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 #-}--instance Rewrapped (SegTree v n) (SegTree v' n')--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 n => DomainBounds (SegTree v n)--instance (Metric v, OrderedField n, Real n)- => EndValues (SegTree v n)--type SplitResult v n = ((SegTree v n, n -> n), (SegTree v n, n -> n))--splitAtParam' :: (Metric v, OrderedField n, Real n) => SegTree v n -> n -> SplitResult v n-splitAtParam' tree@(SegTree t) p- | p < 0 =- case FT.viewl t of- EmptyL -> emptySplit- seg FT.:< t' ->- case seg `splitAtParam` (p * tSegs) of- (seg1, seg2) ->- ( (SegTree $ FT.singleton seg1, (*p))- , (SegTree $ seg2 <| t', \u -> 1 - (1 - u) * tSegs / (tSegs + 1))- )- | p >= 1 =- case FT.viewr t of- EmptyR -> emptySplit- t' FT.:> seg ->- case seg `splitAtParam` (1 - (1 - p)*tSegs) of- (seg1, seg2) ->- ( (SegTree $ t' |> seg1, \u -> u * tSegs / (tSegs + 1))- , (SegTree $ FT.singleton seg2, \u -> (u - p) / (1 - p))- )- | otherwise =- case FT.viewl after of- EmptyL -> emptySplit- seg FT.:< after' ->- let (n, p') = propFrac $ p * tSegs- f p n u | u * tSegs < n = u * tSegs / (n + 1)- | otherwise = (n + (u * tSegs - n) / (p * tSegs - n)) / (n+1)- in case seg `splitAtParam` p' of- (seg1, seg2) ->- ( ( SegTree $ before |> seg1 , f p n )- , ( SegTree $ seg2 <| after'- , \v -> 1 - f (1 - p) (tSegs - n - 1) (1 - v)- )- )- where- (before, after) = FT.split ((p * tSegs <) . numSegs) t- tSegs = numSegs t- emptySplit = let t' = (tree, id) in (t',t')-- propFrac x = let m = signum x * mod1 x in (x - m, m)--instance (Metric v, OrderedField n, Real n) => Sectionable (SegTree v n) where- splitAtParam tree p = let ((a,_),(b,_)) = splitAtParam' tree p in (a,b)-- reverseDomain (SegTree t) = SegTree $ FT.reverse t'- where t' = FT.fmap' reverseSegment t-- section x t1 t2 = let ((a,fa),_) = splitAtParam' x t2- in snd $ splitAtParam a (fa t1)-- -- XXX seems like it should be possible to collapse some of the- -- above cases into one?--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- | I.width i <= eps = i- | otherwise = fun (eps / numSegs t)- where- i = trailMeasure (I.singleton 0)- getArcLengthCached- t- fun = trailMeasure (const 0)- getArcLengthFun- t-- arcLengthToParam eps st@(SegTree t) l- | l < 0 = case FT.viewl t of- EmptyL -> 0- seg FT.:< _ -> arcLengthToParam eps seg l / tSegs- | l >= totalAL = case FT.viewr t of- EmptyR -> 0- 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 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 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 :: ( SegMeasure v n :>: m, FT.Measured (SegMeasure v n) t )- => a -> (m -> a) -> t -> a-trailMeasure d f = option d f . get . FT.measure---- | Compute the number of segments of anything measured by--- 'SegMeasure' (/e.g./ @SegMeasure@ itself, @Segment@, @SegTree@,--- @Trail@s...)-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 :: ( OrderedField n, Metric v,- FT.Measured (SegMeasure v n) t- )- => t -> v n-offset = trailMeasure zero (op TotalOffset . view oeOffset)----------------------------------------------------------------- Trails ----------------------------------------------------------------------------------------------------------------- Eventually we should use DataKinds for this, but not until we drop--- support for GHC 7.4.---- | Type tag for trails with distinct endpoints.-data Line---- | Type tag for \"loopy\" trails which return to their starting--- point.-data Loop------------------------------------------------------- The Trail' type---- | Intuitively, a trail is a single, continuous path through space.--- However, a trail has no fixed starting point; it merely specifies--- /how/ to move through space, not /where/. For example, \"take--- three steps forward, then turn right twenty degrees and take two--- more steps\" is an intuitive analog of a trail; these--- instructions specify a path through space from any given starting--- location. To be precise, trails are /translation-invariant/;--- applying a translation to a trail has no effect.------ A @'Located' Trail@, on the other hand, is a trail paired with--- some concrete starting location (\"start at the big tree on the--- corner, then take three steps forward, ...\"). See the--- "Diagrams.Located" module for help working with 'Located' values.------ Formally, the semantics of a trail is a continuous (though not--- necessarily differentiable) function from the real interval [0,1]--- to vectors in some vector space. (In contrast, a 'Located' trail--- is a continuous function from [0,1] to /points/ in some /affine/--- space.)------ There are two types of trails:------ * A \"line\" (think of the \"train\", \"subway\", or \"bus\"--- variety, rather than the \"straight\" variety...) is a trail--- with two distinct endpoints. Actually, a line can have the--- same start and end points, but it is still /drawn/ as if it had--- distinct endpoints: the two endpoints will have the appropriate--- end caps, and the trail will not be filled. Lines have a--- @Monoid@ instance where @mappend@ corresponds to concatenation,--- /i.e./ chaining one line after the other.------ * A \"loop\" is required to end in the same place it starts (that--- is, t(0) = t(1)). Loops are filled and are drawn as one--- continuous loop, with the appropriate join at the--- start/endpoint rather than end caps. Loops do not have a--- @Monoid@ instance.------ To convert between lines and loops, see 'glueLine',--- 'closeLine', and 'cutLoop'.------ To construct trails, see 'emptyTrail', 'trailFromSegments',--- 'trailFromVertices', 'trailFromOffsets', and friends. You can--- also get any type of trail from any function which returns a--- 'TrailLike' (/e.g./ functions in "Diagrams.TwoD.Shapes", and many--- others; see "Diagrams.TrailLike").------ To extract information from trails, see 'withLine', 'isLoop',--- 'trailSegments', 'trailOffsets', 'trailVertices', and friends.--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 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 Eq (v n) => Eq (Trail' l v n)-deriving instance Ord (v n) => Ord (Trail' l v n)--instance Show (v n) => Show (Trail' l v n) where- showsPrec d (Line (SegTree ft)) = showParen (d > 10) $- showString "lineFromSegments " . showList (F.toList ft)-- showsPrec d (Loop (SegTree ft) o) = showParen (d > 10) $- showString "loopFromSegments " . showList (F.toList ft) .- showChar ' ' . showsPrec 11 o--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 (Metric v, OrderedField n) => Monoid (Trail' Line v n) where- mempty = emptyLine- mappend = (<>)--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 (Metric v, OrderedField n) => Enveloped (Trail' l v n) where- getEnvelope = withTrail' ftEnv (ftEnv . cutLoop)- where- ftEnv :: Trail' Line v n -> Envelope v n- ftEnv (Line t) = trailMeasure mempty (view oeEnvelope) t--instance (HasLinearMap v, Metric v, OrderedField n)- => Renderable (Trail' o v n) NullBackend where- render _ _ = mempty--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 :: Real a => a -> a-mod1 = (`mod'` 1)--instance Num n => DomainBounds (Trail' l v n)--instance (Metric v, OrderedField n, Real n)- => EndValues (Trail' l v n)--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-- reverseDomain = reverseLine--instance (Metric v, OrderedField n, Real n)- => HasArcLength (Trail' l v n) where- arcLengthBounded eps =- withTrail'- (\(Line t) -> arcLengthBounded eps t)- (arcLengthBounded eps . cutLoop)-- arcLengthToParam eps tr l =- withTrail'- (\(Line t) -> arcLengthToParam eps t l)- (\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 #-}------------------------------------------------------- Extracting segments---- | A newtype wrapper around trails which exists solely for its--- 'Parametric', 'DomainBounds' and 'EndValues' instances. The idea--- is that if @tr@ is a trail, you can write, /e.g./------ @--- getSegment tr `atParam` 0.6--- @------ or------ @--- atStart (getSegment tr)--- @------ to get the segment at parameter 0.6 or the first segment in the--- 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' 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,------ * the segment itself, and------ * a reparameterization isomorphism: in the forward direction, it--- translates from parameters on the whole trail to a parameters--- on the segment. Note that for technical reasons you have to--- call 'cloneIso' on the @AnIso'@ value to get a real isomorphism--- 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 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 (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 -> GetSegmentCodomain Nothing- seg FT.:< _ -> GetSegmentCodomain $ Just (zero, seg, reparam 0)-- | 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- in case FT.viewl after of- EmptyL -> GetSegmentCodomain Nothing- seg FT.:< _ -> GetSegmentCodomain $ Just (offset before, seg, reparam (numSegs before))- where- n = numSegs ft- reparam k = iso (subtract k . (*n))- ((/n) . (+ k))---- | The parameterization for loops wraps around, /i.e./ parameters--- are first reduced \"mod 1\".-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 (Metric v, OrderedField n, Real n)- => Parametric (GetSegment (Trail v n)) where- atParam (GetSegment t) p- = withTrail- ((`atParam` p) . GetSegment)- ((`atParam` p) . GetSegment)- t--instance DomainBounds t => DomainBounds (GetSegment t) where- domainLower (GetSegment t) = domainLower t- domainUpper (GetSegment t) = domainUpper t--instance (Metric v, OrderedField n)- => EndValues (GetSegment (Trail' Line v n)) where- atStart (GetSegment (Line (SegTree ft)))- = case FT.viewl ft of- EmptyL -> GetSegmentCodomain Nothing- seg FT.:< _ ->- let n = numSegs ft- in GetSegmentCodomain $ Just (zero, seg, iso (*n) (/n))-- atEnd (GetSegment (Line (SegTree ft)))- = case FT.viewr ft of- EmptyR -> GetSegmentCodomain Nothing- ft' FT.:> seg ->- let n = numSegs ft- in GetSegmentCodomain $- Just (offset ft', seg, iso (subtract (n-1) . (*n))- ((/n) . (+ (n-1)))- )--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 (Metric v, OrderedField n, Real n)- => EndValues (GetSegment (Trail v n)) where- atStart (GetSegment t)- = withTrail- (atStart . GetSegment)- (atStart . GetSegment)- t- atEnd (GetSegment t)- = withTrail- (atEnd . GetSegment)- (atEnd . GetSegment)- t------------------------------------------------------- The Trail type---- | @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 n where- Trail :: Trail' l v n -> Trail v n--deriving instance Show (v n) => Show (Trail v n)--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 n) => Ord (Trail v n) where- compare t1 t2 =- withTrail- (\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--- (using 'cutTrail' on loops) and then concatenating them. The--- 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 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 ->- flip withLine t2 $ \l2 ->- wrapLine (l1 <> l2)---- | @Trail@s are combined as described in the 'Semigroup' instance;--- the empty line is the identity element, with special cases so--- that combining the empty line with a loop results in the--- unchanged loop (in all other cases loops will be cut). Note that--- this does, in fact, satisfy the monoid laws, though it is a bit--- 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 (Metric v, OrderedField n) => Monoid (Trail v n) where- mempty = wrapLine emptyLine- mappend = (<>)--instance (Metric v, OrderedField n) => AsEmpty (Trail v n) where- _Empty = nearly emptyTrail isTrailEmpty--type instance V (Trail v n) = v-type instance N (Trail v n) = n--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 (Metric v, OrderedField n) => Enveloped (Trail v n) where- getEnvelope = withTrail getEnvelope getEnvelope--instance (Metric v, OrderedField n, Real n)- => Parametric (Trail v n) where- atParam t p = withTrail (`atParam` p) (`atParam` p) t--instance Num n => DomainBounds (Trail v n)--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--- results in a single line, not two loops). However, it's--- convenient to have a @Sectionable@ instance for @Trail@; if the--- @Trail@ contains a loop the loop will first be cut and then--- @splitAtParam@ called on the resulting line. This is--- 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 (Metric v, OrderedField n, Real n) => Sectionable (Trail v n) where- splitAtParam t p = withLine ((wrapLine *** wrapLine) . (`splitAtParam` p)) t-- reverseDomain = reverseTrail--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--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 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 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--- trail is a line, the given function is applied; if it is a loop, it--- is first converted to a line with 'cutLoop'. That is,------ @--- withLine f === 'withTrail' f (f . 'cutLoop')--- @-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--- trail is a line, the transformation will be applied directly. If--- it is a loop, it will first be cut using 'cutLoop', the--- transformation applied, and then glued back into a loop with--- 'glueLine'. That is,------ @--- onLine f === onTrail f (glueLine . f . cutLoop)--- @------ 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 :: (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 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 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 n -> Trail v n-wrapLoop = wrapTrail----------------------------------------------------------------- Constructing trails ---------------------------------------------------------------------------------------------------- | The empty line, which is the identity for concatenation of lines.-emptyLine :: (Metric v, OrderedField n) => Trail' Line v n-emptyLine = Line mempty---- | A wrapped variant of 'emptyLine'.-emptyTrail :: (Metric v, OrderedField n) => Trail v n-emptyTrail = wrapLine emptyLine---- | Construct a line from a list of closed segments.-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 :: (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--- vectors, where each vector represents the offset from one vertex--- to the next. See also 'fromOffsets'.------ <<diagrams/src_Diagrams_Trail_lineFromOffsetsEx.svg#diagram=lineFromOffsetsEx&width=300>>------ > import Diagrams.Coordinates--- > lineFromOffsetsEx = strokeLine $ lineFromOffsets [ 2 ^& 1, 2 ^& (-1), 2 ^& 0.5 ]-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 :: (Metric v, OrderedField n) => [v n] -> Trail v n-trailFromOffsets = wrapTrail . lineFromOffsets---- | Construct a line containing only linear segments from a list of--- vertices. Note that only the relative offsets between the--- vertices matters; the information about their absolute position--- will be discarded. That is, for all vectors @v@,------ @--- lineFromVertices === lineFromVertices . 'translate' v--- @------ If you want to retain the position information, you should--- instead use the more general 'fromVertices' function to--- construct, say, a @'Located' ('Trail'' 'Line' v)@ or a @'Located'--- ('Trail' v)@.------ <<diagrams/src_Diagrams_Trail_lineFromVerticesEx.svg#diagram=lineFromVerticesEx&width=300>>------ > import Diagrams.Coordinates--- > lineFromVerticesEx = pad 1.1 . centerXY . strokeLine--- > $ lineFromVertices [origin, 0 ^& 1, 1 ^& 2, 5 ^& 1]-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----- | @trailFromVertices === 'wrapTrail' . 'lineFromVertices'@, for--- conveniently constructing a @Trail@ instead of a @Trail' Line@.-trailFromVertices :: (Metric v, OrderedField n)- => [Point v n] -> Trail v n-trailFromVertices = wrapTrail . lineFromVertices----------------------------------------------------------------- Converting between lines and loops ------------------------------------------------------------------------------------- | Make a line into a loop by \"gluing\" the endpoint to the--- starting point. In particular, the offset of the final segment--- is modified so that it ends at the starting point of the entire--- trail. Typically, you would first construct a line which you--- know happens to end where it starts, and then call 'glueLine' to--- turn it into a loop.------ <<diagrams/src_Diagrams_Trail_glueLineEx.svg#diagram=glueLineEx&width=500>>------ > glueLineEx = pad 1.1 . hsep 1--- > $ [almostClosed # strokeLine, almostClosed # glueLine # strokeLoop]--- >--- > 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,------ @--- glueLine . cutLoop === id--- @-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' 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 :: (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--- line's end to its start.------ @closeLine@ does not have any particularly nice theoretical--- properties, but can be useful /e.g./ when you want to make a--- closed polygon out of a list of points where the initial point is--- not repeated at the end. To use 'glueLine', one would first have--- to duplicate the initial vertex, like------ @--- 'glueLine' . 'lineFromVertices' $ ps ++ [head ps]--- @------ Using @closeLine@, however, one can simply------ @--- closeLine . lineFromVertices $ ps--- @------ <<diagrams/src_Diagrams_Trail_closeLineEx.svg#diagram=closeLineEx&width=500>>------ > closeLineEx = pad 1.1 . centerXY . hcat' (with & sep .~ 1)--- > $ [almostClosed # strokeLine, almostClosed # closeLine # strokeLoop]-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 n -> Trail v n-closeTrail = onTrail closeLine id---- | Turn a loop into a line by \"cutting\" it at the common start/end--- point, resulting in a line which just happens to start and end at--- the same place.------ @cutLoop@ is right inverse to 'glueLine', that is,------ @--- glueLine . cutLoop === id--- @-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 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 :: (Metric v, OrderedField n)- => Trail v n -> Trail v n-cutTrail = onTrail id cutLoop----------------------------------------------------------------- Eliminating trails ----------------------------------------------------------------------------------------------------- | Test whether a line is empty.-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 :: (Metric v, OrderedField n) => Trail v n -> Bool-isTrailEmpty = withTrail isLineEmpty (const False)---- | Determine whether a trail is a line.-isLine :: Trail v n -> Bool-isLine = not . isLoop---- | Determine whether a trail is a loop.-isLoop :: Trail v n -> Bool-isLoop = withTrail (const False) (const True)---- | Extract the segments comprising a line.-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- :: (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 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 :: (Metric v, OrderedField n)- => Trail v n -> [Segment Closed v n]-trailSegments = withLine lineSegments---- | Extract the offsets of the segments of a trail.-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------ @--- trailOffset === sumV . trailOffsets--- @------ but is more efficient.------ <<diagrams/src_Diagrams_Trail_trailOffsetEx.svg#diagram=trailOffsetEx&width=300>>------ > trailOffsetEx = (strokeLine almostClosed <> showOffset) # centerXY # pad 1.1--- > where showOffset = fromOffsets [trailOffset (wrapLine almostClosed)]--- > # 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 :: Trail' Line v n -> [v n]-lineOffsets = map segOffset . lineSegments---- | Extract the offsets of the segments of a loop.-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 :: (Metric v, OrderedField n) => Trail' Line v n -> v n-lineOffset (Line t) = trailMeasure zero (op TotalOffset . view oeOffset) t---- | 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@.------ 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' :: (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' :: (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---- | 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 :: (Metric v, OrderedField n)- => Located (Trail v n) -> [FixedSegment v n]-fixTrail t = map mkFixedSeg (trailLocSegments t)---- | Convert a concretely located trail into a list of located segments.-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 ------------------------------------------------------------------------------------------------------- | Reverse a trail. Semantically, if a trail given by a function t--- from [0,1] to vectors, then the reverse of t is given by t'(s) =--- t(1-s). @reverseTrail@ is an involution, that is,------ @--- reverseTrail . reverseTrail === id--- @-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--- trail becomes the starting point of the reversed trail, so the--- original and reversed trails comprise exactly the same set of--- points. @reverseLocTrail@ is an involution, /i.e./------ @--- reverseLocTrail . reverseLocTrail === id--- @-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 :: (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 :: (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 :: (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 :: (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-+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- We have an orphan Transformable FingerTree instance here.++-- |+-- Module : Diagrams.Trail+-- Copyright : (c) 2013-2015 diagrams-lib team (see LICENSE)+-- License : BSD-style (see LICENSE)+-- Maintainer : diagrams-discuss@googlegroups.com+--+-- This module defines /trails/, translationally invariant paths+-- through space. Trails form a central part of the diagrams-lib API,+-- so the documentation for this module merits careful study.+--+-- Related modules include:+--+-- * The 'TrailLike' class ("Diagrams.TrailLike") exposes a generic+-- API for building a wide range of things out of trails.+--+-- * 'Path's ("Diagrams.Path") are collections of 'Located'+-- ("Diagrams.Located") trails.+--+-- * Trails are composed of 'Segment's (see "Diagrams.Segment"),+-- though most users should not need to work with segments directly.+module Diagrams.Trail (+ -- * Type definitions++ -- ** Lines and loops+ Trail' (..),+ glueLine,+ closeLine,+ cutLoop,++ -- ** Generic trails+ Trail (..),+ _Line,+ _Loop,+ _LocLine,+ _LocLoop,+ wrapTrail,+ wrapLine,+ wrapLoop,+ onTrail,+ onLine,+ glueTrail,+ closeTrail,+ cutTrail,++ -- * Constructing trails+ emptyLine,+ emptyTrail,+ lineFromVertices,+ trailFromVertices,+ lineFromOffsets,+ trailFromOffsets,+ lineFromSegments,+ trailFromSegments,+ loopFromSegments,++ -- * Eliminating trails+ withTrail',+ withTrail,+ withLine,+ isLineEmpty,+ isTrailEmpty,+ isLine,+ isLoop,+ trailSegments,+ lineSegments,+ loopSegments,+ onLineSegments,+ trailOffsets,+ trailOffset,+ lineOffsets,+ lineOffset,+ loopOffsets,+ trailPoints,+ linePoints,+ loopPoints,+ trailVertices',+ lineVertices',+ loopVertices',+ trailVertices,+ lineVertices,+ loopVertices,+ trailLocSegments,+ fixTrail,+ unfixTrail,++ -- * Modifying trails+ reverseTrail,+ reverseLocTrail,+ reverseLine,+ reverseLocLine,+ reverseLoop,+ reverseLocLoop,++ -- * Internals+ -- $internals++ -- ** Type tags+ Line,+ Loop,++ -- ** Segment trees+ SegTree (..),+ trailMeasure,+ numSegs,+ offset,++ -- ** Extracting segments+ GetSegment (..),+ getSegment,+ GetSegmentCodomain (..),+) where++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 qualified Data.List.NonEmpty as NE+import Data.Monoid.MList+import Data.Semigroup+import qualified Numeric.Interval.Kaucher as I++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+-- section directly, but they are exported on the principle that we+-- can't forsee what uses people might have for them.++------------------------------------------------------------+-- FingerTree instances+------------------------------------------------------------++type instance V (FingerTree m a) = V a+type instance N (FingerTree m a) = N 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 -----------------------------------------+------------------------------------------------------------++-- | A @SegTree@ represents a sequence of closed segments, stored in a+-- fingertree so we can easily recover various monoidal measures of+-- the segments (number of segments, arc length, envelope...) and+-- also easily slice and dice them according to the measures+-- (/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 n = SegTree (FingerTree (SegMeasure v n) (Segment Closed v n))+ deriving (Eq, Ord, Show, Monoid, Transformable, FT.Measured (SegMeasure v n), Semigroup)++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' #-}++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 #-}++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 #-}++instance Rewrapped (SegTree v n) (SegTree v' n')++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 n => DomainBounds (SegTree v n)++instance+ (Metric v, OrderedField n, Real n) =>+ EndValues (SegTree v n)++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, seg, after) = case FT.split ((pSegs <) . numSegs) t of+ (before, rest) -> case viewl rest of+ EmptyL -> (before, Linear (OffsetClosed zero), rest)+ seg FT.:< after -> (before, seg, after)+ (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++ 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+ (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+ | I.width i <= eps = i+ | otherwise = fun (eps / numSegs t)+ where+ i =+ trailMeasure+ (I.singleton 0)+ getArcLengthCached+ t+ fun =+ trailMeasure+ (const 0)+ getArcLengthFun+ t++ arcLengthToParam eps st@(SegTree t) l+ | l < 0 = case FT.viewl t of+ EmptyL -> 0+ seg FT.:< _ -> arcLengthToParam eps seg l / tSegs+ | l >= totalAL = case FT.viewr t of+ EmptyR -> 0+ 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 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 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 ::+ (SegMeasure v n :>: m, FT.Measured (SegMeasure v n) t) =>+ a -> (m -> a) -> t -> a+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 ::+ (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 ::+ ( OrderedField n+ , Metric v+ , FT.Measured (SegMeasure v n) t+ ) =>+ t -> v n+offset = trailMeasure zero (op TotalOffset . view oeOffset)++------------------------------------------------------------+-- Trails ------------------------------------------------+------------------------------------------------------------++-- Eventually we should use DataKinds for this, but not until we drop+-- support for GHC 7.4.++-- | Type tag for trails with distinct endpoints.+data Line++-- | Type tag for \"loopy\" trails which return to their starting+-- point.+data Loop++--------------------------------------------------+-- The Trail' type++-- | Intuitively, a trail is a single, continuous path through space.+-- However, a trail has no fixed starting point; it merely specifies+-- /how/ to move through space, not /where/. For example, \"take+-- three steps forward, then turn right twenty degrees and take two+-- more steps\" is an intuitive analog of a trail; these+-- instructions specify a path through space from any given starting+-- location. To be precise, trails are /translation-invariant/;+-- applying a translation to a trail has no effect.+--+-- A @'Located' Trail@, on the other hand, is a trail paired with+-- some concrete starting location (\"start at the big tree on the+-- corner, then take three steps forward, ...\"). See the+-- "Diagrams.Located" module for help working with 'Located' values.+--+-- Formally, the semantics of a trail is a continuous (though not+-- necessarily differentiable) function from the real interval [0,1]+-- to vectors in some vector space. (In contrast, a 'Located' trail+-- is a continuous function from [0,1] to /points/ in some /affine/+-- space.)+--+-- There are two types of trails:+--+-- * A \"line\" (think of the \"train\", \"subway\", or \"bus\"+-- variety, rather than the \"straight\" variety...) is a trail+-- with two distinct endpoints. Actually, a line can have the+-- same start and end points, but it is still /drawn/ as if it had+-- distinct endpoints: the two endpoints will have the appropriate+-- end caps, and the trail will not be filled. Lines have a+-- @Monoid@ instance where @mappend@ corresponds to concatenation,+-- /i.e./ chaining one line after the other.+--+-- * A \"loop\" is required to end in the same place it starts (that+-- is, t(0) = t(1)). Loops are filled and are drawn as one+-- continuous loop, with the appropriate join at the+-- start/endpoint rather than end caps. Loops do not have a+-- @Monoid@ instance.+--+-- To convert between lines and loops, see 'glueLine',+-- 'closeLine', and 'cutLoop'.+--+-- To construct trails, see 'emptyTrail', 'trailFromSegments',+-- 'trailFromVertices', 'trailFromOffsets', and friends. You can+-- also get any type of trail from any function which returns a+-- 'TrailLike' (/e.g./ functions in "Diagrams.TwoD.Shapes", and many+-- others; see "Diagrams.TrailLike").+--+-- To extract information from trails, see 'withLine', 'isLoop',+-- 'trailSegments', 'trailOffsets', 'trailVertices', and friends.+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 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 Eq (v n) => Eq (Trail' l v n)+deriving instance Ord (v n) => Ord (Trail' l v n)++instance Show (v n) => Show (Trail' l v n) where+ showsPrec d (Line (SegTree ft)) =+ showParen (d > 10) $+ showString "lineFromSegments " . showList (F.toList ft)+ showsPrec d (Loop (SegTree ft) o) =+ showParen (d > 10) $+ showString "loopFromSegments "+ . showList (F.toList ft)+ . showChar ' '+ . showsPrec 11 o++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 (Metric v, OrderedField n) => Monoid (Trail' Line v n) where+ mempty = emptyLine+ mappend = (<>)++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 (Metric v, OrderedField n) => Enveloped (Trail' l v n) where+ getEnvelope = withTrail' ftEnv (ftEnv . cutLoop)+ where+ ftEnv :: Trail' Line v n -> Envelope v n+ ftEnv (Line t) = trailMeasure mempty (view oeEnvelope) t++instance+ (HasLinearMap v, Metric v, OrderedField n) =>+ Renderable (Trail' o v n) NullBackend+ where+ render _ _ = mempty++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 :: Real a => a -> a+mod1 = (`mod'` 1)++instance Num n => DomainBounds (Trail' l v n)++instance+ (Metric v, OrderedField n, Real n) =>+ EndValues (Trail' l v n)++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+ (Metric v, OrderedField n, Real n) =>+ HasArcLength (Trail' l v n)+ where+ arcLengthBounded eps =+ withTrail'+ (\(Line t) -> arcLengthBounded eps t)+ (arcLengthBounded eps . cutLoop)++ arcLengthToParam eps tr l =+ withTrail'+ (\(Line t) -> arcLengthToParam eps t l)+ (\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++-- | A newtype wrapper around trails which exists solely for its+-- 'Parametric', 'DomainBounds' and 'EndValues' instances. The idea+-- is that if @tr@ is a trail, you can write, /e.g./+--+-- @+-- getSegment tr `atParam` 0.6+-- @+--+-- or+--+-- @+-- atStart (getSegment tr)+-- @+--+-- to get the segment at parameter 0.6 or the first segment in the+-- trail, respectively.+--+-- The codomain for 'GetSegment', /i.e./ the result you get from+-- 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,+--+-- * the segment itself, and+--+-- * a reparameterization isomorphism: in the forward direction, it+-- translates from parameters on the whole trail to a parameters+-- on the segment. Note that for technical reasons you have to+-- call 'cloneIso' on the @AnIso'@ value to get a real isomorphism+-- 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 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 (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 -> GetSegmentCodomain Nothing+ seg FT.:< _ -> GetSegmentCodomain $ Just (zero, seg, reparam 0)+ | 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+ in case FT.viewl after of+ EmptyL -> GetSegmentCodomain Nothing+ seg FT.:< _ -> GetSegmentCodomain $ Just (offset before, seg, reparam (numSegs before))+ where+ n = numSegs ft+ reparam k =+ iso+ (subtract k . (* n))+ ((/ n) . (+ k))++-- | The parameterization for loops wraps around, /i.e./ parameters+-- are first reduced \"mod 1\".+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+ (Metric v, OrderedField n, Real n) =>+ Parametric (GetSegment (Trail v n))+ where+ atParam (GetSegment t) p =+ withTrail+ ((`atParam` p) . GetSegment)+ ((`atParam` p) . GetSegment)+ t++instance DomainBounds t => DomainBounds (GetSegment t) where+ domainLower (GetSegment t) = domainLower t+ domainUpper (GetSegment t) = domainUpper t++instance+ (Metric v, OrderedField n) =>+ EndValues (GetSegment (Trail' Line v n))+ where+ atStart (GetSegment (Line (SegTree ft))) =+ case FT.viewl ft of+ EmptyL -> GetSegmentCodomain Nothing+ seg FT.:< _ ->+ let n = numSegs ft+ in GetSegmentCodomain $ Just (zero, seg, iso (* n) (/ n))++ atEnd (GetSegment (Line (SegTree ft))) =+ case FT.viewr ft of+ EmptyR -> GetSegmentCodomain Nothing+ ft' FT.:> seg ->+ let n = numSegs ft+ in GetSegmentCodomain $+ Just+ ( offset ft'+ , seg+ , iso+ (subtract (n - 1) . (* n))+ ((/ n) . (+ (n - 1)))+ )++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+ (Metric v, OrderedField n, Real n) =>+ EndValues (GetSegment (Trail v n))+ where+ atStart (GetSegment t) =+ withTrail+ (atStart . GetSegment)+ (atStart . GetSegment)+ t+ atEnd (GetSegment t) =+ withTrail+ (atEnd . GetSegment)+ (atEnd . GetSegment)+ t++--------------------------------------------------+-- The Trail type++-- | @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 n where+ Trail :: Trail' l v n -> Trail v n++deriving instance Show (v n) => Show (Trail v n)++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 n) => Ord (Trail v n) where+ compare t1 t2 =+ withTrail+ (\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+-- (using 'cutTrail' on loops) and then concatenating them. The+-- 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 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 ->+ flip withLine t2 $ \l2 ->+ wrapLine (l1 <> l2)++-- | @Trail@s are combined as described in the 'Semigroup' instance;+-- the empty line is the identity element, with special cases so+-- that combining the empty line with a loop results in the+-- unchanged loop (in all other cases loops will be cut). Note that+-- this does, in fact, satisfy the monoid laws, though it is a bit+-- 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 (Metric v, OrderedField n) => Monoid (Trail v n) where+ mempty = wrapLine emptyLine+ mappend = (<>)++instance (Metric v, OrderedField n) => AsEmpty (Trail v n) where+ _Empty = nearly emptyTrail isTrailEmpty++type instance V (Trail v n) = v+type instance N (Trail v n) = n++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 (Metric v, OrderedField n) => Enveloped (Trail v n) where+ getEnvelope = withTrail getEnvelope getEnvelope++instance+ (Metric v, OrderedField n, Real n) =>+ Parametric (Trail v n)+ where+ atParam t p = withTrail (`atParam` p) (`atParam` p) t++instance Num n => DomainBounds (Trail v n)++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+-- results in a single line, not two loops). However, it's+-- convenient to have a @Sectionable@ instance for @Trail@; if the+-- @Trail@ contains a loop the loop will first be cut and then+-- @splitAtParam@ called on the resulting line. This is+-- 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 (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+ (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 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 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+-- trail is a line, the given function is applied; if it is a loop, it+-- is first converted to a line with 'cutLoop'. That is,+--+-- @+-- withLine f === 'withTrail' f (f . 'cutLoop')+-- @+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+-- trail is a line, the transformation will be applied directly. If+-- it is a loop, it will first be cut using 'cutLoop', the+-- transformation applied, and then glued back into a loop with+-- 'glueLine'. That is,+--+-- @+-- onLine f === onTrail f (glueLine . f . cutLoop)+-- @+--+-- 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 ::+ (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 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 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 n -> Trail v n+wrapLoop = wrapTrail++------------------------------------------------------------+-- Constructing trails -----------------------------------+------------------------------------------------------------++-- | The empty line, which is the identity for concatenation of lines.+emptyLine :: (Metric v, OrderedField n) => Trail' Line v n+emptyLine = Line mempty++-- | A wrapped variant of 'emptyLine'.+emptyTrail :: (Metric v, OrderedField n) => Trail v n+emptyTrail = wrapLine emptyLine++-- | Construct a line from a list of closed segments.+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 ::+ (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+-- vectors, where each vector represents the offset from one vertex+-- to the next. See also 'fromOffsets'.+--+-- <<diagrams/src_Diagrams_Trail_lineFromOffsetsEx.svg#diagram=lineFromOffsetsEx&width=300>>+--+-- > import Diagrams.Coordinates+-- > lineFromOffsetsEx = strokeLine $ lineFromOffsets [ 2 ^& 1, 2 ^& (-1), 2 ^& 0.5 ]+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 :: (Metric v, OrderedField n) => [v n] -> Trail v n+trailFromOffsets = wrapTrail . lineFromOffsets++-- | Construct a line containing only linear segments from a list of+-- vertices. Note that only the relative offsets between the+-- vertices matters; the information about their absolute position+-- will be discarded. That is, for all vectors @v@,+--+-- @+-- lineFromVertices === lineFromVertices . 'translate' v+-- @+--+-- If you want to retain the position information, you should+-- instead use the more general 'fromVertices' function to+-- construct, say, a @'Located' ('Trail'' 'Line' v)@ or a @'Located'+-- ('Trail' v)@.+--+-- <<diagrams/src_Diagrams_Trail_lineFromVerticesEx.svg#diagram=lineFromVerticesEx&width=300>>+--+-- > import Diagrams.Coordinates+-- > lineFromVerticesEx = pad 1.1 . centerXY . strokeLine+-- > $ lineFromVertices [origin, 0 ^& 1, 1 ^& 2, 5 ^& 1]+lineFromVertices ::+ (Metric v, OrderedField n) =>+ [Point v n] -> Trail' Line v n+lineFromVertices [] = emptyLine+lineFromVertices [_] = emptyLine+lineFromVertices ps = lineFromSegments . map straight $ zipWith (.-.) (drop 1 ps) ps++-- | @trailFromVertices === 'wrapTrail' . 'lineFromVertices'@, for+-- conveniently constructing a @Trail@ instead of a @Trail' Line@.+trailFromVertices ::+ (Metric v, OrderedField n) =>+ [Point v n] -> Trail v n+trailFromVertices = wrapTrail . lineFromVertices++------------------------------------------------------------+-- Converting between lines and loops --------------------+------------------------------------------------------------++-- | Make a line into a loop by \"gluing\" the endpoint to the+-- starting point. In particular, the offset of the final segment+-- is modified so that it ends at the starting point of the entire+-- trail. Typically, you would first construct a line which you+-- know happens to end where it starts, and then call 'glueLine' to+-- turn it into a loop.+--+-- <<diagrams/src_Diagrams_Trail_glueLineEx.svg#diagram=glueLineEx&width=500>>+--+-- > glueLineEx = pad 1.1 . hsep 1+-- > $ [almostClosed # strokeLine, almostClosed # glueLine # strokeLoop]+-- >+-- > 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,+--+-- @+-- glueLine . cutLoop === id+-- @+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' 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 :: (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+-- line's end to its start.+--+-- @closeLine@ does not have any particularly nice theoretical+-- properties, but can be useful /e.g./ when you want to make a+-- closed polygon out of a list of points where the initial point is+-- not repeated at the end. To use 'glueLine', one would first have+-- to duplicate the initial vertex, like+--+-- @+-- 'glueLine' . 'lineFromVertices' $ ps ++ [head ps]+-- @+--+-- Using @closeLine@, however, one can simply+--+-- @+-- closeLine . lineFromVertices $ ps+-- @+--+-- <<diagrams/src_Diagrams_Trail_closeLineEx.svg#diagram=closeLineEx&width=500>>+--+-- > closeLineEx = pad 1.1 . centerXY . hcat' (with & sep .~ 1)+-- > $ [almostClosed # strokeLine, almostClosed # closeLine # strokeLoop]+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 n -> Trail v n+closeTrail = onTrail closeLine id++-- | Turn a loop into a line by \"cutting\" it at the common start/end+-- point, resulting in a line which just happens to start and end at+-- the same place.+--+-- @cutLoop@ is right inverse to 'glueLine', that is,+--+-- @+-- glueLine . cutLoop === id+-- @+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 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 ::+ (Metric v, OrderedField n) =>+ Trail v n -> Trail v n+cutTrail = onTrail id cutLoop++------------------------------------------------------------+-- Eliminating trails ------------------------------------+------------------------------------------------------------++-- | Test whether a line is empty.+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 :: (Metric v, OrderedField n) => Trail v n -> Bool+isTrailEmpty = withTrail isLineEmpty (const False)++-- | Determine whether a trail is a line.+isLine :: Trail v n -> Bool+isLine = not . isLoop++-- | Determine whether a trail is a loop.+isLoop :: Trail v n -> Bool+isLoop = withTrail (const False) (const True)++-- | Extract the segments comprising a line.+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 ::+ (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 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 ::+ (Metric v, OrderedField n) =>+ Trail v n -> [Segment Closed v n]+trailSegments = withLine lineSegments++-- | Extract the offsets of the segments of a trail.+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+--+-- @+-- trailOffset === sumV . trailOffsets+-- @+--+-- but is more efficient.+--+-- <<diagrams/src_Diagrams_Trail_trailOffsetEx.svg#diagram=trailOffsetEx&width=300>>+--+-- > trailOffsetEx = (strokeLine almostClosed <> showOffset) # centerXY # pad 1.1+-- > where showOffset = fromOffsets [trailOffset (wrapLine almostClosed)]+-- > # 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 :: Trail' Line v n -> [v n]+lineOffsets = map segOffset . lineSegments++-- | Extract the offsets of the segments of a loop.+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 :: (Metric v, OrderedField n) => Trail' Line v n -> v n+lineOffset (Line t) = trailMeasure zero (op TotalOffset . view oeOffset) t++-- | 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@.+--+-- 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' ::+ (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' ::+ (Metric v, OrderedField n) =>+ n -> Located (Trail' Loop v n) -> [Point v n]+loopVertices' toler (viewLoc -> (p, t)) = case NE.nonEmpty . lineSegments . cutLoop $ t of+ Nothing -> []+ Just segs+ | NE.length segs > 1 -> if far > toler then init ps else init . drop 1 $ ps+ | otherwise -> ps+ where+ far =+ quadrance+ ( (signorm . tangentAtStart . NE.head $ segs)+ ^-^ (signorm . tangentAtEnd . NE.last $ segs)+ )+ ps = segmentVertices' toler p (NE.toList segs)++-- | 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.+-- '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 ::+ (Metric v, OrderedField n) =>+ Located (Trail v n) -> [Located (Segment Closed v n)]+trailLocSegments t = zipWith at (trailSegments (unLoc t)) (trailPoints t)++------------------------------------------------------------+-- Modifying trails --------------------------------------+------------------------------------------------------------++-- | Reverse a trail. Semantically, if a trail given by a function t+-- from [0,1] to vectors, then the reverse of t is given by t'(s) =+-- t(1-s). @reverseTrail@ is an involution, that is,+--+-- @+-- reverseTrail . reverseTrail === id+-- @+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+-- trail becomes the starting point of the reversed trail, so the+-- original and reversed trails comprise exactly the same set of+-- points. @reverseLocTrail@ is an involution, /i.e./+--+-- @+-- reverseLocTrail . reverseLocTrail === id+-- @+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 ::+ (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 ::+ (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 ::+ (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 ::+ (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 #-} ----------------------------------------------------------------------------- -- |
src/Diagrams/Transform.hs view
@@ -1,6 +1,11 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Transform@@ -120,4 +125,4 @@ -- @ translated :: (InSpace v n a, SameSpace a b, Transformable a, Transformable b) => v n -> Iso a b a b-translated = transformed . translation+translated v = transformed $ translation v
src/Diagrams/Transform/Matrix.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- |@@ -28,7 +30,7 @@ -- | 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 . el+mkMat t = distribute . tabulate $ apply t . unit . (\x -> el x) -- | Build a 3D transformation matrix in homogeneous coordinates from -- a 'Transformation V3'.@@ -39,13 +41,13 @@ -- 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 = flip (fromMatWithInv m) v $ inv22 m+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 = flip (fromMatWithInv m) v $ inv33 m+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)@@ -54,8 +56,8 @@ -> v n -- ^ translation -> Transformation v n fromMatWithInv m m_ v =- Transformation ((*! m) <-> (*! m_))- ((*! distribute m) <-> (*! distribute m_))+ Transformation ((m !*) <-> (m_ !*))+ ((distribute m !*) <-> (distribute m_ !*)) v -- | Prism onto a 2D transformation from a 2x2 transform matrix and@@ -64,7 +66,8 @@ mat22 :: Floating n => Iso' (M22 n, V2 n) (T2 n) mat22 = iso (uncurry fromMat22) (mkMat &&& transl) --- | Prism onto a 2D transformation from a 2x2 transform matrix and--- translation vector (in which case the 'T3' will be invalid).+-- | 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
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-}@@ -8,6 +7,7 @@ {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- |@@ -27,9 +27,6 @@ where import Control.Lens (makeLenses, view, (^.))-#if __GLASGOW_HASKELL__ < 710-import Data.Semigroup-#endif import Data.Typeable import Diagrams.Angle@@ -77,7 +74,6 @@ , _scaleInvDir :: Vn t , _scaleInvLoc :: Point (V t) (N t) }- deriving Typeable deriving instance (Show t, Show (Vn t)) => Show (ScaleInv t)
src/Diagrams/TwoD.hs view
@@ -181,7 +181,9 @@ -- * 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 @@ -210,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@@ -235,7 +240,7 @@ , extrudeLeft, extrudeRight, extrudeBottom, extrudeTop - , rectEnvelope+ , rectEnvelope, crop -- ** Background @@ -247,7 +252,7 @@ , centerX, centerY, centerXY -- * Snugging- , snugL, snugR, snugT, snugB, snugTL, snugTR, snugBL, snugBR+ , snugL, snugR, snugT, snugB , snugX, snugY , snugCenterX, snugCenterY, snugCenterXY
src/Diagrams/TwoD/Adjust.hs view
@@ -1,7 +1,11 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.TwoD.Adjust@@ -21,15 +25,15 @@ ) where import Diagrams.Attributes+import Diagrams.BoundingBox import Diagrams.Core+import Diagrams.Size import Diagrams.TwoD.Attributes (lineTextureA) import Diagrams.TwoD.Types import Diagrams.Util (( # ))-import Diagrams.Size-import Diagrams.BoundingBox -import Control.Lens (Lens', (^.), set)-import Data.Default.Class+import Control.Lens (Lens', set, (^.))+import Data.Default import Data.Semigroup
src/Diagrams/TwoD/Align.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} @@ -29,7 +30,6 @@ -- ** Align by trace , snugL, snugR, snugT, snugB- , snugTL, snugTR, snugBL, snugBR -- * Relative alignment , alignX, snugX, alignY, snugY@@ -83,14 +83,6 @@ alignBL = alignB . alignL alignBR = alignB . alignR -snugTL, snugTR, snugBL, snugBR- :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a)- => 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;@@ -140,5 +132,3 @@ 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,6 +1,12 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.TwoD.Arc@@ -36,11 +42,11 @@ import Diagrams.TrailLike import Diagrams.TwoD.Transform import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector (unitX, unitY, unit_Y, e)+import Diagrams.TwoD.Vector (e, unitX, unitY, unit_Y) import Diagrams.Util (( # )) import Control.Lens ((&), (<>~), (^.))-import Data.Semigroup ((<>))+import Data.Semigroup import Linear.Affine import Linear.Metric
src/Diagrams/TwoD/Arrow.hs view
@@ -1,15 +1,15 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} ------------------------------------------------------------------------------ -- | -- Module : Diagrams.TwoD.Arrow -- Copyright : (c) 2013-2015 diagrams-lib team (see LICENSE)@@ -18,165 +18,166 @@ -- -- 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>.------------------------------------------------------------------------------------module Diagrams.TwoD.Arrow- ( -- * Examples- -- ** Example 1--- | <<diagrams/src_Diagrams_TwoD_Arrow_example1.svg#diagram=example1&width=500>>------ > -- Connecting two diagrams at their origins.--- >--- > sq = square 2 # showOrigin # lc darkgray # lw ultraThick--- > ds = (sq # named "left") ||| strutX 3 ||| (sq # named "right")--- >--- > shaft = cubicSpline False ( map p2 [(0, 0), (1, 0), (1, 0.2), (2, 0.2)])--- >--- > example1 = ds # connect' (with & arrowHead .~ dart & arrowTail .~ quill--- > & arrowShaft .~ shaft--- > & headLength .~ huge & tailLength .~ veryLarge)--- > "left" "right" # pad 1.1-- -- ** Example 2---- | <<diagrams/src_Diagrams_TwoD_Arrow_example2.svg#diagram=example2&width=500>>------ > -- Comparing connect, connectPerim, and arrowAt.--- >--- > oct = octagon 1 # lc darkgray # lw ultraThick # showOrigin--- > dias = oct # named "first" ||| strut 3 ||| oct # named "second"--- >--- > -- Connect two diagrams and two points on their trails.--- > ex12 = dias # connect' (with & lengths .~ veryLarge) "first" "second"--- > # connectPerim' (with & lengths .~ veryLarge)--- > "first" "second" (15/16 @@ turn) (9/16 @@ turn)--- >--- > -- Place an arrow at (0,0) the size and direction of (0,1).--- > ex3 = arrowAt origin unit_Y--- >--- > example2 = (ex12 <> ex3) # centerXY # pad 1.1-- -- * Creating arrows- arrowV- , arrowV'- , arrowAt- , arrowAt'- , arrowBetween- , arrowBetween'- , connect- , connect'- , connectPerim- , connectPerim'- , connectOutside- , connectOutside'+-- <https://diagrams.github.io/doc/arrow.html>.+module Diagrams.TwoD.Arrow (+ -- * Examples - , arrow- , arrow'+ -- ** Example 1 - , arrowFromLocatedTrail- , arrowFromLocatedTrail'+ -- | <<diagrams/src_Diagrams_TwoD_Arrow_example1.svg#diagram=example1&width=500>>+ --+ -- > -- Connecting two diagrams at their origins.+ -- >+ -- > sq = square 2 # showOrigin # lc darkgray # lw ultraThick+ -- > ds = (sq # named "left") ||| strutX 3 ||| (sq # named "right")+ -- >+ -- > shaft = cubicSpline False ( map p2 [(0, 0), (1, 0), (1, 0.2), (2, 0.2)])+ -- >+ -- > example1 = ds # connect' (with & arrowHead .~ dart & arrowTail .~ quill+ -- > & arrowShaft .~ shaft+ -- > & headLength .~ huge & tailLength .~ veryLarge)+ -- > "left" "right" # pad 1.1 - -- * Options- , ArrowOpts(..)+ -- ** Example 2 - , arrowHead- , arrowTail- , arrowShaft- , headGap- , tailGap- , gaps, gap- , headTexture- , headStyle- , headLength- , tailTexture- , tailStyle- , tailLength- , lengths- , shaftTexture- , shaftStyle- , straightShaft+ -- | <<diagrams/src_Diagrams_TwoD_Arrow_example2.svg#diagram=example2&width=500>>+ --+ -- > -- Comparing connect, connectPerim, and arrowAt.+ -- >+ -- > oct = octagon 1 # lc darkgray # lw ultraThick # showOrigin+ -- > dias = oct # named "first" ||| strut 3 ||| oct # named "second"+ -- >+ -- > -- Connect two diagrams and two points on their trails.+ -- > ex12 = dias # connect' (with & lengths .~ veryLarge) "first" "second"+ -- > # connectPerim' (with & lengths .~ veryLarge)+ -- > "first" "second" (15/16 @@ turn) (9/16 @@ turn)+ -- >+ -- > -- Place an arrow at (0,0) the size and direction of (0,1).+ -- > ex3 = arrowAt origin unit_Y+ -- >+ -- > example2 = (ex12 <> ex3) # centerXY # pad 1.1 - -- | See "Diagrams.TwoD.Arrowheads" for a list of standard- -- arrowheads and help creating your own.- , module Diagrams.TwoD.Arrowheads- ) where+ -- * Creating arrows+ arrowV,+ arrowV',+ arrowAt,+ arrowAt',+ arrowBetween,+ arrowBetween',+ connect,+ connect',+ connectPerim,+ connectPerim',+ connectOutside,+ connectOutside',+ arrow,+ arrow',+ arrowFromLocatedTrail,+ arrowFromLocatedTrail', -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>), (<*>))-#endif-import Control.Lens (Lens', Traversal',- generateSignatures, lensRules,- makeLensesWith, view, (%~), (&),- (.~), (^.))-import Data.Default.Class-import Data.Maybe (fromMaybe)-import Data.Monoid.Coproduct (untangle)-import Data.Semigroup-import Data.Typeable+ -- * Options+ ArrowOpts (..),+ arrowHead,+ arrowTail,+ arrowShaft,+ headGap,+ tailGap,+ gaps,+ gap,+ headTexture,+ headStyle,+ headLength,+ tailTexture,+ tailStyle,+ tailLength,+ lengths,+ shaftTexture,+ shaftStyle,+ straightShaft,+ -- | See "Diagrams.TwoD.Arrowheads" for a list of standard+ -- arrowheads and help creating your own.+ module Diagrams.TwoD.Arrowheads,+) where -import Data.Colour hiding (atop)-import Diagrams.Core-import Diagrams.Core.Style (unmeasureAttrs)-import Diagrams.Core.Types (QDiaLeaf (..), mkQD')+import Control.Lens (+ Lens',+ Traversal',+ both,+ generateSignatures,+ lensRules,+ makeLensesWith,+ over,+ view,+ (%~),+ (&),+ (.~),+ (^.),+ )+import Data.Default+import Data.Maybe (fromMaybe)+import Data.Monoid.Coproduct (untangle)+import Data.Semigroup+import Data.Typeable -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.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 (reflectY, rotate, translateX)-import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector (unitX, unit_X)-import Diagrams.Util (( # ))+import Data.Colour hiding (atop, over)+import Diagrams.Core+import Diagrams.Core.Style (unmeasureAttrs)+import Diagrams.Core.Types (QDiaLeaf (..), mkQD') -import Linear.Affine-import Linear.Metric-import Linear.Vector+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.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 (reflectY, translateX)+import Diagrams.TwoD.Types+import Diagrams.TwoD.Vector (unitX, unit_X)+import Diagrams.Util ((#)) +import Linear.Affine+import Linear.Metric+import Linear.Vector data ArrowOpts n = ArrowOpts- { _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- }+ { _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 :: OrderedField n => Trail V2 n straightShaft = trailFromOffsets [unitX] instance TypeableFloat n => Default (ArrowOpts n) where- def = ArrowOpts- { _arrowHead = dart- , _arrowTail = noTail- , _arrowShaft = straightShaft- , _headGap = none- , _tailGap = none-- -- See note [Default arrow style attributes]- , _headStyle = mempty- , _headLength = normal- , _tailStyle = mempty- , _tailLength = normal- , _shaftStyle = mempty- }+ def =+ ArrowOpts+ { _arrowHead = dart+ , _arrowTail = noTail+ , _arrowShaft = straightShaft+ , _headGap = none+ , _tailGap = none+ , -- See note [Default arrow style attributes]+ _headStyle = mempty+ , _headLength = normal+ , _tailStyle = mempty+ , _tailLength = normal+ , _shaftStyle = mempty+ } makeLensesWith (lensRules & generateSignatures .~ False) ''ArrowOpts @@ -197,9 +198,10 @@ -- | Set both the @headGap@ and @tailGap@ simultaneously. gaps :: Traversal' (ArrowOpts n) (Measure n)-gaps f opts = (\h t -> opts & headGap .~ h & tailGap .~ t)- <$> f (opts ^. headGap)- <*> f (opts ^. tailGap)+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 n) (Measure n)@@ -254,23 +256,23 @@ -- 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 n -> Style V2 n-shaftSty opts = opts^.shaftStyle+shaftSty opts = opts ^. shaftStyle -- Set the default head style. See `shaftSty`. headSty :: TypeableFloat n => ArrowOpts n -> Style V2 n-headSty opts = fc black (opts^.headStyle)+headSty opts = fc black (opts ^. headStyle) -- Set the default tail style. See `shaftSty`. tailSty :: TypeableFloat n => ArrowOpts n -> Style V2 n-tailSty opts = fc black (opts^.tailStyle)+tailSty opts = fc black (opts ^. tailStyle) -- | Calculate the length of the portion of the horizontal line that passes -- through the origin and is inside of p. xWidth :: Floating n => (Traced t, V t ~ V2, N t ~ n) => t -> n xWidth p = a + b- where- a = fromMaybe 0 (norm <$> traceV origin unitX p)- b = fromMaybe 0 (norm <$> traceV origin unit_X p)+ where+ 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.@@ -278,12 +280,11 @@ colorJoint sStyle = 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+ 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 :: forall n. TypeableFloat n => Style V2 n -> n -> n -> n@@ -295,48 +296,61 @@ -- | 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 :: (TypeableFloat n, Renderable (Path V2 n) b) =>- n -> ArrowOpts n -> n -> n -> Bool -> (QDiagram b V2 n Any, n)+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 -mkTail :: (TypeableFloat n, Renderable (Path V2 n) b) =>- n -> ArrowOpts n -> n -> n -> Bool -> (QDiagram b V2 n Any, n)+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- (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))+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+ (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 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 [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+ where+ 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 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-+scaleFactor tr tw hw t = -- Let tv be a vector representing the tail width, i.e. a vector -- of length tw tangent to the trail's start; similarly for hv. -- Let v be the vector offset of the trail.@@ -348,30 +362,30 @@ -- We can solve by squaring both sides and expanding the LHS as a -- dot product, resulting in a quadratic in k. - = case quadForm- (quadrance v)- (2* (v `dot` (tv ^+^ hv)))- (quadrance (tv ^+^ hv) - t*t)- of- [] -> 1 -- no scale works, just return 1- [s] -> s -- single solution- ss -> maximum ss- -- we will usually get both a positive and a negative solution;- -- return the maximum (i.e. positive) solution- where- tv = tw *^ (tangentAtStart tr # signorm)- hv = hw *^ (tangentAtEnd tr # signorm)- v = trailOffset tr+ case quadForm+ (quadrance v)+ (2 * (v `dot` (tv ^+^ hv)))+ (quadrance (tv ^+^ hv) - t * t) of+ [] -> 1 -- no scale works, just return 1+ [s] -> s -- single solution+ ss -> maximum ss+ where+ -- we will usually get both a positive and a negative solution;+ -- return the maximum (i.e. positive) solution + 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 :: TypeableFloat n => ArrowOpts n -> n -> Envelope V2 n arrowEnv opts len = getEnvelope horizShaft- where- horizShaft = shaft # rotate (negated (v ^. _theta)) # scale (len / m)- m = norm v- v = trailOffset shaft- shaft = opts ^. arrowShaft+ where+ 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@@ -384,92 +398,97 @@ -- @(len,0)@. In particular, it scales the given 'arrowShaft' so -- that the entire arrow has length @len@. arrow' :: (TypeableFloat n, Renderable (Path V2 n) b) => ArrowOpts n -> n -> QDiagram b V2 n Any-arrow' opts len = mkQD' (DelayedLeaf delayedArrow)-- -- 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-- -- Once we learn the global transformation context (da) and the two scale- -- factors, normal to output (n) and global to output (g), this arrow is- -- drawn in, we can apply it to the origin and (len,0) to find out- -- the actual final points between which this arrow should be- -- drawn. We need to know this to draw it correctly, since the- -- head and tail are scale invariant, and hence the precise points- -- between which we need to draw the shaft do not transform- -- 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- 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 (((q .-. p)^._theta) ^-^ (dir^._theta))- # moveTo p- where+arrow' opts len =+ mkQD'+ (DelayedLeaf delayedArrow)+ -- 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+ -- Once we learn the global transformation context (da) and the two scale+ -- factors, normal to output (n) and global to output (g), this arrow is+ -- drawn in, we can apply it to the origin and (len,0) to find out+ -- the actual final points between which this arrow should be+ -- drawn. We need to know this to draw it correctly, since the+ -- head and tail are scale invariant, and hence the precise points+ -- between which we need to draw the shaft do not transform+ -- 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) = maybe mempty untangle . fst $ da+ in dArrow globalSty trans len g n - p = origin # transform tr- q = origin # translateX ln # transform tr+ -- 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 (((q .-. p) ^. _theta) ^-^ (dir ^. _theta))+ # moveTo p+ where+ p = origin # transform tr+ q = origin # translateX ln # transform tr - -- Use the existing line color for head, tail, and shaft by- -- default (can be overridden by explicitly setting headStyle,- -- 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 %~ applyStyle sty+ -- Use the existing line color for head, tail, and shaft by+ -- default (can be overridden by explicitly setting headStyle,+ -- 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 %~ applyStyle sty . transform tr - -- The head size, tail size, head gap, and tail gap are obtained- -- from the style and converted to output units.- scaleFromMeasure = fromMeasured gToO nToO . scaleLocal (avgScale tr)- hSize = scaleFromMeasure $ opts ^. headLength- tSize = scaleFromMeasure $ opts ^. tailLength- hGap = scaleFromMeasure $ opts ^. headGap- tGap = scaleFromMeasure $ opts ^. tailGap+ -- The head size, tail size, head gap, and tail gap are obtained+ -- from the style and converted to output units.+ 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 (isReflection tr)- (t, tWidth') = mkTail tSize opts' gToO nToO (isReflection tr)+ -- Make the head and tail and save their widths.+ (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 (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)- # transform tr+ rawShaftTrail = opts ^. arrowShaft+ shaftTrail =+ rawShaftTrail+ -- rotate it so it is pointing in the positive X direction+ # 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)+ # transform tr - -- Adjust the head width and tail width to take gaps into account- tWidth = tWidth' + tGap- hWidth = hWidth' + hGap+ -- Adjust the head width and tail width to take gaps into account+ tWidth = tWidth' + tGap+ hWidth = hWidth' + hGap - -- Calculate the angles that the head and tail should point.- tAngle = tangentAtStart shaftTrail ^. _theta- hAngle = tangentAtEnd shaftTrail ^. _theta+ -- Calculate the angles that the head and tail should point.+ 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 (norm (q .-. p))- shaftTrail' = shaftTrail # scale sf- shaft = strokeT shaftTrail' # applyStyle (shaftSty opts')+ -- 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 (norm (q .-. p))+ shaftTrail' = shaftTrail # scale sf+ shaft = strokeT shaftTrail' # applyStyle (shaftSty opts') - -- Adjust the head and tail to point in the directions of the shaft ends.- h' = h # rotate hAngle- # moveTo (origin .+^ shaftTrail' `atParam` domainUpper shaftTrail')- t' = t # rotate tAngle+ -- Adjust the head and tail to point in the directions of the shaft ends.+ h' =+ h+ # rotate hAngle+ # moveTo (origin .+^ shaftTrail' `atParam` domainUpper shaftTrail')+ t' = t # rotate tAngle - -- Find out what direction the arrow is pointing so we can set it back- -- to point in the direction unitX when we are done.- dir = direction (trailOffset $ spine shaftTrail tWidth hWidth sf)+ -- Find out what direction the arrow is pointing so we can set it back+ -- to point in the direction unitX when we are done.+ dir = direction (trailOffset $ spine shaftTrail tWidth hWidth sf) -- | @arrowBetween s e@ creates an arrow pointing from @s@ to @e@ -- with default parameters.@@ -480,9 +499,9 @@ -- @e@ using the given options. In particular, it scales and -- rotates @arrowShaft@ to go between @s@ and @e@, taking head, -- tail, and gaps into account.-arrowBetween'- :: (TypeableFloat n, Renderable (Path V2 n) b) =>- ArrowOpts n -> Point V2 n -> Point V2 n -> QDiagram b V2 n Any+arrowBetween' ::+ (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@@ -490,14 +509,16 @@ arrowAt :: (TypeableFloat n, Renderable (Path V2 n) b) => Point V2 n -> V2 n -> QDiagram b V2 n Any arrowAt = arrowAt' def -arrowAt'- :: (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 = norm v- dir = v ^. _theta+arrowAt' ::+ (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 = norm v+ dir = v ^. _theta -- | @arrowV v@ creates an arrow with the direction and norm of -- the vector @v@ (with its tail at the origin), using default@@ -507,82 +528,90 @@ -- | @arrowV' v@ creates an arrow with the direction and norm of -- the vector @v@ (with its tail at the origin).-arrowV'- :: (TypeableFloat n, Renderable (Path V2 n) b)- => ArrowOpts n -> V2 n -> QDiagram b V2 n Any+arrowV' ::+ (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 ::+ (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' ::+ (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+ where+ opts' = opts & arrowShaft .~ unLoc trail+ start = atStart trail+ end = atEnd trail -- | Connect two diagrams with a straight arrow.-connect- :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)- => n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any+connect ::+ (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'- :: (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' ::+ (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 ->- let [s,e] = map location [sub1, sub2]- in atop (arrowBetween' opts s e)+ withName n2 $ \sub2 ->+ let (s, e) = over both location (sub1, sub2)+ in atop (arrowBetween' opts s e) -- | Connect two diagrams at point on the perimeter of the diagrams, choosen -- by angle.-connectPerim- :: (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 ::+ (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'- :: (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' ::+ (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 ->- let [os, oe] = map location [sub1, sub2]- s = fromMaybe os (maxTraceP os (unitX # rotate a1) sub1)- e = fromMaybe oe (maxTraceP oe (unitX # rotate a2) sub2)- in atop (arrowBetween' opts s e)+ withName n2 $ \sub2 ->+ let (os, oe) = over both location (sub1, sub2)+ s = fromMaybe os (maxTraceP os (unitX # rotate a1) sub1)+ e = fromMaybe oe (maxTraceP oe (unitX # rotate a2) sub2)+ in atop (arrowBetween' opts s e) -- | Draw an arrow from diagram named "n1" to diagram named "n2". The -- arrow lies on the line between the centres of the diagrams, but is -- drawn so that it stops at the boundaries of the diagrams, using traces -- to find the intersection points.-connectOutside- :: (TypeableFloat n, Renderable (Path V2 n) b, IsName n1, IsName n2)- => n1 -> n2 -> QDiagram b V2 n Any -> QDiagram b V2 n Any+connectOutside ::+ (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'- :: (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' ::+ (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 (negated v) b1- e' = fromMaybe (location b2) $ traceP midpoint v b2- in- atop (arrowBetween' opts s' e')+ withName n2 $ \b2 ->+ let v = location b2 .-. location 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,9 +1,14 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Arrowheads -- Copyright : (c) 2013 diagrams-lib team (see LICENSE)@@ -13,77 +18,75 @@ -- Standard arrowheads and tails. Each arrowhead or tail is designed -- to be drawn filled, with a line width of 0, and is normalized to -- fit inside a circle of diameter 1.---------------------------------------------------------------------------------+module Diagrams.TwoD.Arrowheads (+ -- * Arrowheads -module Diagrams.TwoD.Arrowheads- (- -- * Arrowheads- -- ** Standard arrowheads- tri- , dart- , halfDart- , spike- , thorn- , lineHead- , noHead+ -- ** Standard arrowheads+ tri,+ dart,+ halfDart,+ spike,+ thorn,+ lineHead,+ noHead, - -- ** Configurable arrowheads- -- | Creates arrowheads of the same shape as the standard heads but- -- where the angle parameter is used to specify the angle to the top- -- left point of the arrowhead.- , arrowheadTriangle- , arrowheadDart- , arrowheadHalfDart- , arrowheadSpike- , arrowheadThorn+ -- ** Configurable arrowheads - -- * Arrow tails- -- ** Standard arrow tails- , tri'- , dart'- , halfDart'- , spike'- , thorn'- , lineTail- , noTail- , quill- , block+ -- | Creates arrowheads of the same shape as the standard heads but+ -- where the angle parameter is used to specify the angle to the top+ -- left point of the arrowhead.+ arrowheadTriangle,+ arrowheadDart,+ arrowheadHalfDart,+ arrowheadSpike,+ arrowheadThorn, - -- ** Configurable arrow tails+ -- * Arrow tails - , arrowtailQuill- , arrowtailBlock+ -- ** Standard arrow tails+ tri',+ dart',+ halfDart',+ spike',+ thorn',+ lineTail,+ noTail,+ quill,+ block, - -- * Internals- , ArrowHT- ) where+ -- ** Configurable arrow tails+ arrowtailQuill,+ arrowtailBlock, -import Control.Lens ((&), (.~), (<>~), (^.))-import Data.Default.Class-import Data.Monoid (mempty, (<>))+ -- * Internals+ ArrowHT,+) where -import Diagrams.Angle-import Diagrams.Core+import Control.Lens (both, over, (&), (.~), (<>~), (^.))+import Data.Default+import Data.Monoid (mempty, (<>)) -import Diagrams.Path-import Diagrams.Segment-import Diagrams.Trail-import Diagrams.TrailLike (fromOffsets)-import Diagrams.TwoD.Align-import Diagrams.TwoD.Arc (arc')-import Diagrams.TwoD.Path ()-import Diagrams.TwoD.Polygons-import Diagrams.TwoD.Shapes-import Diagrams.TwoD.Transform-import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector (unitX, unit_X, xDir)-import Diagrams.Util (( # ))+import Diagrams.Angle+import Diagrams.Core -import Linear.Affine-import Linear.Metric-import Linear.Vector+import Diagrams.Path+import Diagrams.Segment+import Diagrams.Trail+import Diagrams.TrailLike (fromOffsets)+import Diagrams.TwoD.Align+import Diagrams.TwoD.Arc (arc')+import Diagrams.TwoD.Path ()+import Diagrams.TwoD.Polygons+import Diagrams.TwoD.Shapes+import Diagrams.TwoD.Transform+import Diagrams.TwoD.Types+import Diagrams.TwoD.Vector (unitX, unit_X, xDir)+import Diagrams.Util ((#)) +import Linear.Affine+import Linear.Metric+import Linear.Vector+ ----------------------------------------------------------------------------- type ArrowHT n = n -> n -> (Path V2 n, Path V2 n)@@ -107,106 +110,121 @@ -- > <> 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, (-2) *^ theta]- (repeat r) & polyOrient .~ NoOrient) # alignL-+ where+ aHead len _ = (p, mempty)+ where+ psi = pi - (theta ^. rad)+ r = len / (1 + cos psi)+ 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 :: 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 [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)+ where+ hd = snugL . pathFromTrail . glueTrail $ fromOffsets [t1, t2, b2, b1]+ jt = pathFromTrail . glueTrail $ j <> reflectY j+ 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) = over both (reflectY . negated) (t1, t2)+ psi = pi - negated t2 ^. _theta . rad+ jLength = shaftWidth / (2 * tan psi) - -- If the shaft is too wide, set the size to a default value of 1.- sz = 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+ 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)+ -- 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 :: 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 (xDir & _theta <>~ negated phi) (2 *^ phi)- l1 = trailFromSegments [straight $ unit_X ^+^ v]- l2 = trailFromSegments [reverseSegment . straight $ (unit_X ^+^ reflectY v)]- c = arc' 1 (rotate α xDir) ((-2) *^ α)- α = (1/2 @@ turn) ^-^ theta- v = rotate theta unitX+arrowheadSpike theta len shaftWidth = (hd # scale r, jt # scale r)+ where+ hd = snugL . closedPath $ l1 <> c <> l2+ jt =+ alignR+ . centerY+ . pathFromTrail+ . closeTrail+ $ arc' 1 (xDir & _theta <>~ negated phi) (2 *^ phi)+ l1 = trailFromSegments [straight $ unit_X ^+^ v]+ 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- -- length of the arrow head is given by r(1 - 2 cos theta)-sqrt (r^2-y^2).- -- Solving the quadratic gives two roots, we want the larger one.+ -- 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+ -- length of the arrow head is given by r(1 - 2 cos theta)-sqrt (r^2-y^2).+ -- Solving the quadratic gives two roots, we want the larger one. - -- 1/4 turn < theta < 2/3 turn.- a = 1 - 2 * cos (theta ^. rad)- y = shaftWidth / 2+ -- 1/4 turn < theta < 2/3 turn.+ a = 1 - 2 * cos (theta ^. rad)+ y = shaftWidth / 2 - -- If the shaft is too wide for the head, we default the radius r to- -- 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 = asinA (min 1 (y/r))+ -- If the shaft is too wide for the head, we default the radius r to+ -- 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 = asinA (min 1 (y / r)) -- | Curved sides, linear concave base. Illustrator CS5 #3 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 [V2 (-jLength) 0, V2 0 (shaftWidth / 2)]- c = curvedSide theta- v = rotate theta unitX- l = reverseSegment . straight $ t- t = v ^-^ V2 (-0.5) 0- psi = fullTurn ^/ 2 ^-^ (negated t ^. _theta)- jLength = shaftWidth / (2 * tanA psi)+ where+ hd = snugL . pathFromTrail . glueTrail $ hTop <> reflectY hTop+ hTop = closeTrail . trailFromSegments $ [c, l]+ jt = pathFromTrail . glueTrail $ j <> reflectY j+ j = closeTrail $ fromOffsets [V2 (-jLength) 0, V2 0 (shaftWidth / 2)]+ c = curvedSide theta+ v = rotate theta unitX+ l = reverseSegment . straight $ t+ 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.- sz = 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 :: Floating n => Angle n -> Segment Closed V2 n curvedSide theta = bezier3 ctrl1 ctrl2 end- where- v0 = unit_X- v1 = rotate theta unitX- ctrl1 = v0- ctrl2 = v0 ^+^ v1- end = v0 ^+^ v1+ where+ v0 = unit_X+ v1 = rotate theta unitX+ ctrl1 = v0+ ctrl2 = v0 ^+^ v1+ end = v0 ^+^ v1 -- Standard heads ---------------------------------------------------------+ -- | A line the same width as the shaft. lineHead :: RealFloat n => ArrowHT n lineHead s w = (square 1 # scaleX s # scaleY w # alignL, mempty)@@ -218,31 +236,31 @@ -- > triEx = drawHead tri tri :: RealFloat n => ArrowHT n-tri = arrowheadTriangle (1/3 @@ turn)+tri = arrowheadTriangle (1 / 3 @@ turn) -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_spikeEx.svg#diagram=spikeEx&width=100>> -- > spikeEx = drawHead spike spike :: RealFloat n => ArrowHT n-spike = arrowheadSpike (3/8 @@ turn)+spike = arrowheadSpike (3 / 8 @@ turn) -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_thornEx.svg#diagram=thornEx&width=100>> -- > thornEx = drawHead thorn thorn :: RealFloat n => ArrowHT n-thorn = arrowheadThorn (3/8 @@ turn)+thorn = arrowheadThorn (3 / 8 @@ turn) -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_dartEx.svg#diagram=dartEx&width=100>> -- > dartEx = drawHead dart dart :: RealFloat n => ArrowHT n-dart = arrowheadDart (2/5 @@ turn)+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)+halfDart = arrowheadHalfDart (2 / 5 @@ turn) -- Tails ------------------------------------------------------------------ -- > drawTail t = arrowAt' (with & arrowTail .~ t & shaftStyle %~ lw none@@ -254,47 +272,50 @@ -- attached at the start of the trail. headToTail :: OrderedField n => ArrowHT n -> ArrowHT n headToTail hd = tl- where- tl sz shaftWidth = (t, j)- where- (t', j') = hd sz shaftWidth- t = reflectX t'- j = reflectX j'+ where+ tl sz shaftWidth = (t, j)+ where+ (t', j') = hd sz shaftWidth+ t = reflectX t'+ j = reflectX j' -arrowtailBlock :: forall n. (RealFloat n) => Angle n -> ArrowHT n+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' :: V2 n- a' = rotate theta unitX- a = a' ^-^ reflectY a'- x = norm a+ where+ aTail len _ = (t, mempty)+ where+ 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 :: 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 sz # alignR- sz = len / 0.6- v0 = p2 (0.5, 0)- 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 / 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]+ where+ aTail len shaftWidth = (t, j)+ where+ t =+ closedPath (trailFromVertices [v0, v1, v2, v3, v4, v5, v0])+ # scale sz+ # alignR+ sz = len / 0.6+ v0 = p2 (0.5, 0)+ 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 / 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] -- Standard tails ---------------------------------------------------------+ -- | A line the same width as the shaft. lineTail :: RealFloat n => ArrowHT n lineTail s w = (square 1 # scaleY w # scaleX s # alignR, mempty)@@ -336,10 +357,10 @@ -- > quillEx = drawTail quill quill :: (Floating n, Ord n) => ArrowHT n-quill = arrowtailQuill (2/5 @@ turn)+quill = arrowtailQuill (2 / 5 @@ turn) -- | <<diagrams/src_Diagrams_TwoD_Arrowheads_blockEx.svg#diagram=blockEx&width=100>> -- > blockEx = drawTail block block :: RealFloat n => ArrowHT n-block = arrowtailBlock (7/16 @@ turn)+block = arrowtailBlock (7 / 16 @@ turn)
src/Diagrams/TwoD/Attributes.hs view
@@ -1,18 +1,19 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Attributes -- Copyright : (c) 2013-2015 diagrams-lib team (see LICENSE)@@ -26,60 +27,93 @@ -- 'FillColor' and 'LineColor' attributes are provided so that backends that -- don't support gradients need not be concerned with using textures. Backends -- should only implement color attributes or textures attributes, not both.---------------------------------------------------------------------------------- module Diagrams.TwoD.Attributes ( -- * Textures- Texture(..), solid, _SC, _AC, _LG, _RG, defaultLG, defaultRG- , GradientStop(..), stopColor, stopFraction, mkStops- , SpreadMethod(..), lineLGradient, lineRGradient+ Texture (..),+ solid,+ _SC,+ _AC,+ _LG,+ _RG,+ defaultLG,+ defaultRG,+ GradientStop (..),+ stopColor,+ stopFraction,+ mkStops,+ SpreadMethod (..),+ lineLGradient,+ lineRGradient, -- ** Linear Gradients- , LGradient(..), lGradStops, lGradTrans, lGradStart, lGradEnd- , lGradSpreadMethod, mkLinearGradient+ LGradient (..),+ lGradStops,+ lGradTrans,+ lGradStart,+ lGradEnd,+ lGradSpreadMethod,+ mkLinearGradient, -- ** Radial Gradients- , RGradient(..), rGradStops, rGradTrans- , rGradCenter0, rGradRadius0, rGradCenter1, rGradRadius1- , rGradSpreadMethod, mkRadialGradient+ RGradient (..),+ rGradStops,+ rGradTrans,+ rGradCenter0,+ rGradRadius0,+ rGradCenter1,+ rGradRadius1,+ rGradSpreadMethod,+ mkRadialGradient, -- ** Line texture- , LineTexture(..), _LineTexture, getLineTexture, lineTexture, lineTextureA- , mkLineTexture, _lineTexture+ LineTexture (..),+ _LineTexture,+ getLineTexture,+ lineTexture,+ lineTextureA,+ mkLineTexture,+ _lineTexture, -- ** Line color- , lineColor, lc, lcA+ lineColor,+ lc,+ lcA, -- ** Fill texture- , FillTexture(..), _FillTexture, getFillTexture, fillTexture- , mkFillTexture, _fillTexture, _fillTextureR+ FillTexture (..),+ _FillTexture,+ getFillTexture,+ fillTexture,+ mkFillTexture,+ _fillTexture,+ _fillTextureR, -- ** Fill color- , fillColor, fc, fcA, recommendFillColor+ fillColor,+ fc,+ fcA,+ recommendFillColor, -- * Compilation utilities- , splitTextureFills-- ) where--import Control.Lens hiding (transform)-import Data.Colour hiding (AffineSpace, over)-import Data.Data-import Data.Default.Class-import Data.Monoid.Recommend-import Data.Semigroup+ splitTextureFills,+) where -import Diagrams.Attributes-import Diagrams.Attributes.Compile-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 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.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 ----------------------------------------------------------------- -- Gradients --------------------------------------------------@@ -87,7 +121,7 @@ -- | A gradient stop contains a color and fraction (usually between 0 and 1) data GradientStop d = GradientStop- { _stopColor :: SomeColor+ { _stopColor :: SomeColor , _stopFraction :: d } @@ -108,11 +142,12 @@ -- | Linear Gradient data LGradient n = LGradient- { _lGradStops :: [GradientStop n]- , _lGradStart :: Point V2 n- , _lGradEnd :: Point V2 n- , _lGradTrans :: Transformation V2 n- , _lGradSpreadMethod :: SpreadMethod }+ { _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@@ -143,13 +178,14 @@ -- | Radial Gradient 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 }+ { _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 @@ -169,7 +205,7 @@ rGradRadius0 :: Lens' (RGradient n) n -- | The center of the outer circle.-rGradCenter1 :: Lens' (RGradient n) (Point V2 n)+rGradCenter1 :: Lens' (RGradient n) (Point V2 n) -- | The radius of the outer circle in 'local' coordinates. rGradRadius1 :: Lens' (RGradient n) n@@ -190,7 +226,6 @@ -- An object can have only one texture which is determined by the 'Last' -- semigroup structure. 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@@ -204,7 +239,7 @@ 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+ transform _ sc = sc -- | Convert a solid colour into a texture. solid :: Color a => a -> Texture n@@ -215,28 +250,32 @@ -- no default value is provided for @lGradStops@, this must be set before -- the gradient value is used, otherwise the object will appear transparent. defaultLG :: Fractional n => Texture n-defaultLG = LG LGradient- { _lGradStops = []- , _lGradStart = mkP2 (-0.5) 0- , _lGradEnd = mkP2 0.5 0- , _lGradTrans = mempty- , _lGradSpreadMethod = GradPad- }+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 :: 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- }+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).@@ -247,16 +286,23 @@ -- and 'SpreadMethod'. The 'lGradTrans' field is set to the identity -- transfrom, to change it use the 'lGradTrans' lens. 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)+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 :: 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)+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 -------------------------------------------------------- @@ -265,14 +311,19 @@ -- More precisely, the semigroup structure on line texture attributes -- is that of 'Last'. newtype LineTexture n = LineTexture (Last (Texture n))- deriving (Typeable, Semigroup)-instance (Typeable n) => AttributeClass (LineTexture n)+ deriving (Semigroup) +instance Typeable n => AttributeClass (LineTexture n)+ type instance V (LineTexture n) = V2 type instance N (LineTexture n) = n -_LineTexture :: Iso (LineTexture n) (LineTexture n')- (Texture n) (Texture 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@@ -297,8 +348,8 @@ _lineTexture :: (Floating n, Typeable n) => Lens' (Style V2 n) (Texture n) _lineTexture = atTAttr . anon def isDef . _LineTexture- where- isDef = anyOf (_LineTexture . _AC) (== opaque black)+ where+ 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@@ -333,20 +384,21 @@ -- The semigroup structure on fill texture attributes -- is that of 'Recommed . Last'. newtype FillTexture n = FillTexture (Recommend (Last (Texture n)))- deriving (Typeable, Semigroup)+ deriving (Semigroup) instance Typeable n => AttributeClass (FillTexture n) _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+ 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 @@ -370,8 +422,8 @@ -- | 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- isDef = anyOf (_FillTexture . _Recommend . _AC) (== transparent)+ where+ 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').@@ -415,10 +467,11 @@ -- | Push fill attributes down until they are at the root of subtrees -- containing only loops. This makes life much easier for backends, -- which typically have a semantics where fill attributes are--- applied to lines/non-closed paths as well as loops/closed paths,+-- 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 n a. (- Typeable n) => RTree b v n a -> RTree b v n a+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 #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.TwoD.Combinators@@ -31,7 +36,7 @@ , extrudeLeft, extrudeRight, extrudeBottom, extrudeTop - , rectEnvelope+ , rectEnvelope, crop , boundingRect, bg, bgFrame @@ -39,7 +44,7 @@ import Control.Lens ((&), (.~)) import Data.Colour-import Data.Default.Class+import Data.Default import Data.Semigroup import Diagrams.Core@@ -48,6 +53,7 @@ import Diagrams.BoundingBox import Diagrams.Combinators import Diagrams.Path+import Diagrams.Query (value) import Diagrams.Segment import Diagrams.TrailLike import Diagrams.TwoD.Align@@ -244,6 +250,11 @@ => 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 :: ( InSpace V2 n a, SameSpace a t@@ -254,12 +265,15 @@ -- | \"Set the background color\" of a diagram. That is, place a -- diagram atop a bounding rectangle of the given color.-bg :: (TypeableFloat n, Renderable (Path V2 n) b) => Colour Double -> QDiagram b V2 n Any -> QDiagram b V2 n Any-bg c d = d <> boundingRect d # lwO 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.-bgFrame :: (TypeableFloat n, Renderable (Path V2 n) b)- => n -> Colour Double -> QDiagram b V2 n Any -> QDiagram b V2 n Any-bgFrame f c d = d <> boundingRect (frame f d) # lwO 0 # fc c+-- 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/Ellipse.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- |
src/Diagrams/TwoD/Image.hs view
@@ -1,12 +1,16 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Image -- Copyright : (c) 2011 diagrams-lib team (see LICENSE)@@ -18,60 +22,73 @@ -- 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,+ Native,+ image,+ embeddedImage,+ loadImageEmb,+ loadImageEmbBS,+ loadImageExt,+ uncheckedImageRef,+ raster,+ rasterDia,+) where -module Diagrams.TwoD.Image- (- DImage(..), ImageData(..)- , Embedded, External, Native- , image- , loadImageEmb- , loadImageExt- , uncheckedImageRef- , raster- , rasterDia- ) where+import Codec.Picture -import Codec.Picture-import Codec.Picture.Types (dynamicMap)+import Data.Colour (AlphaColour)+import Data.Kind (Type)+import Data.Semigroup+import Data.Typeable (Typeable) -import Data.Colour (AlphaColour)-import Data.Semigroup-import Data.Typeable (Typeable)+import Diagrams.Core -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 -import Diagrams.Attributes (colorToSRGBA)-import Diagrams.TwoD.Path (isInsideEvenOdd)-import Diagrams.TwoD.Shapes (rect)-import Diagrams.TwoD.Types+import Data.ByteString -import Linear.Affine+import Linear.Affine -data Embedded deriving Typeable-data External deriving Typeable-data Native (t :: *) deriving Typeable+data Embedded+data External+data Native (t :: Type) -- | 'ImageData' is either a JuicyPixels @DynamicImage@ tagged as 'Embedded' or -- a reference tagged as 'External'. Additionally 'Native' is provided for -- external libraries to hook into.-data ImageData :: * -> * where+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 height to the actual width and height -- of the image.-data DImage :: * -> * -> * where+data DImage :: Type -> Type -> Type where DImage :: ImageData t -> Int -> Int -> Transformation V2 n -> DImage n t- deriving Typeable type instance V (DImage n a) = V2 type instance N (DImage n a) = n +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) @@ -79,30 +96,41 @@ moveOriginTo p = translate (origin .-. p) -- | Make a 'DImage' into a 'Diagram'.-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 p r))- where- r = rect (fromIntegral w) (fromIntegral h)- DImage _ w h _ = img+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 = 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.+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 = 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+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@@ -110,11 +138,11 @@ loadImageExt path = do dImg <- readImage path return $ case dImg of- Left msg -> Left msg+ Left msg -> Left msg Right img -> Right $ DImage (ImageRef path) w h mempty- where- w = dynamicMap imageWidth img- h = dynamicMap imageHeight img+ where+ w = dynamicMap imageWidth img+ h = dynamicMap imageHeight img -- | Make an "unchecked" image reference; have to specify a -- width and height. Unless the aspect ratio of the external@@ -123,24 +151,24 @@ uncheckedImageRef path w h = DImage (ImageRef path) w h mempty -- | Crate a diagram from raw raster data.-rasterDia :: (TypeableFloat n, Renderable (DImage n Embedded) b)- => (Int -> Int -> AlphaColour Double) -> Int -> Int -> QDiagram b V2 n Any+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 :: 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- g x y = fromAlphaColour $ f x y+ where+ img = generateImage g w h+ g x y = fromAlphaColour $ f x y fromAlphaColour :: AlphaColour Double -> PixelRGBA8 fromAlphaColour c = PixelRGBA8 r g b a- where- (r, g, b, a) = (int r', int g', int b', int a')- (r', g', b', a') = colorToSRGBA c- int x = round (255 * x)+ where+ (r, g, b, a) = (int r', int g', int b', int a')+ (r', g', b', a') = colorToSRGBA c+ int x = round (255 * x) instance Fractional n => (Renderable (DImage n a) NullBackend) where render _ _ = mempty-
src/Diagrams/TwoD/Model.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell #-}@@ -37,7 +38,7 @@ import Control.Lens (makeLenses, (^.)) import Data.Colour (Colour) import Data.Colour.Names-import Data.Default.Class+import Data.Default import Data.List (intercalate) import qualified Data.Map as M import Data.Maybe (catMaybes)
src/Diagrams/TwoD/Offset.hs view
@@ -1,12 +1,16 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-} ------------------------------------------------------------------------------+-- for Data.Semigroup+ -- | -- Module : Diagrams.TwoD.Offset -- Copyright : (c) 2013 diagrams-lib team (see LICENSE)@@ -15,69 +19,71 @@ -- -- 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>.----------------------------------------------------------------------------------module Diagrams.TwoD.Offset- (- -- * Offsets-- offsetSegment-- , OffsetOpts(..), offsetJoin, offsetMiterLimit, offsetEpsilon- , offsetTrail- , offsetTrail'- , offsetPath- , offsetPath'-- -- * Expansions-- , ExpandOpts(..), expandJoin, expandMiterLimit, expandCap, expandEpsilon- , expandTrail- , expandTrail'- , expandPath- , expandPath'+-- <https://diagrams.github.io/doc/manual.html#offsets-of-segments-trails-and-paths>.+module Diagrams.TwoD.Offset (+ -- * Offsets+ offsetSegment,+ OffsetOpts (..),+ offsetJoin,+ offsetMiterLimit,+ offsetEpsilon,+ offsetTrail,+ offsetTrail',+ offsetPath,+ offsetPath', - ) where+ -- * Expansions+ ExpandOpts (..),+ expandJoin,+ expandMiterLimit,+ expandCap,+ expandEpsilon,+ expandTrail,+ expandTrail',+ expandPath,+ expandPath',+) where -import Control.Applicative-import Control.Lens hiding (at)-import Prelude+import Control.Applicative+import Control.Lens hiding (at)+import Prelude -import Data.Maybe (catMaybes)-import Data.Monoid-import Data.Monoid.Inf+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.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)+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) -import Linear.Affine-import Linear.Metric-import Linear.Vector+import Linear.Affine+import Linear.Metric+import Linear.Vector 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 cubic t+perpAtParam cubic t = negated $ unitPerp a+ where+ a = case snd $ splitAtParam cubic t of+ Cubic x _ _ -> x+ _ -> error "Impossible: splitAtParam on a cubic segment returned a non-cubic segment" -- | Compute the offset of a segment. Given a segment compute the offset -- curve that is a fixed distance from the original curve. For linear@@ -104,15 +110,14 @@ -- Note that when the original curve has a cusp, the offset curve forms a -- radius around the cusp, and when there is a loop in the original curve, -- there can be two cusps in the offset curve.--- -- | Options for specifying line join and segment epsilon for an offset -- involving multiple segments. data OffsetOpts d = OffsetOpts- { _offsetJoin :: LineJoin- , _offsetMiterLimit :: d- , _offsetEpsilon :: d- }+ { _offsetJoin :: LineJoin+ , _offsetMiterLimit :: d+ , _offsetEpsilon :: d+ } deriving instance Eq d => Eq (OffsetOpts d) deriving instance Show d => Show (OffsetOpts d)@@ -131,15 +136,16 @@ -- | The default offset options use the default 'LineJoin' ('LineJoinMiter'), a -- miter limit of 10, and epsilon factor of 0.01. instance Fractional d => Default (OffsetOpts d) where- def = OffsetOpts def 10 0.01+ def = OffsetOpts def 10 0.01 -- | Options for specifying how a 'Trail' should be expanded. data ExpandOpts d = ExpandOpts- { _expandJoin :: LineJoin- , _expandMiterLimit :: d- , _expandCap :: LineCap- , _expandEpsilon :: d- } deriving (Eq, Show)+ { _expandJoin :: LineJoin+ , _expandMiterLimit :: d+ , _expandCap :: LineCap+ , _expandEpsilon :: d+ }+ deriving (Eq, Show) makeLensesWith (lensRules & generateSignatures .~ False) ''ExpandOpts @@ -155,66 +161,70 @@ -- | Epsilon perimeter for 'offsetSegment'. 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 (Fractional d) => Default (ExpandOpts d) where- def = ExpandOpts def 10 def 0.01--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- -- the current implementation each result segment- -- should be bounded by arcs that are plus or- -- minus epsilon factor from the radius of curvature of- -- the offset.- -> n -- ^ Offset from the original segment, positive is- -- on the right of the curve, negative is on the- -- left.- -> 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+instance Fractional d => Default (ExpandOpts d) where+ def = ExpandOpts def 10 def 0.01 +offsetSegment ::+ RealFloat 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+ -- the current implementation each result segment+ -- should be bounded by arcs that are plus or+ -- minus epsilon factor from the radius of curvature of+ -- the offset.+ n ->+ -- | Offset from the original segment, positive is+ -- on the right of the curve, negative is on the+ -- left.+ n ->+ -- | Original segment+ Segment Closed V2 n ->+ -- | Resulting located (at the offset) trail.+ Located (Trail V2 n)+offsetSegment _ r s@(Linear (OffsetClosed a)) = trailFromSegments [s] `at` origin .+^ va+ 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)- -- Split segments.- ss = (\(x,y) -> [x,y]) $ splitAtParam s 0.5- subdivided = concatMap (trailSegments . unLoc . offsetSegment epsilon r) ss-- -- Offset with handles scaled based on curvature.- offset factor = bezier3 (a^*factor) ((b ^-^ c)^*factor ^+^ c ^+^ vc ^-^ va) (c ^+^ vc ^-^ va)+ where+ t = trailFromSegments (go (radiusOfCurvature s 0.5))+ -- Perpendiculars to handles.+ 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 - -- We observe a corner. Subdivide right away.- go (Finite 0) = subdivided- -- We have some curvature- go roc- | close = [o]- | otherwise = subdivided- where- -- We want the multiplicative factor that takes us from the original- -- segment's radius of curvature roc, to roc + r.- --- -- r + sr = x * sr- --- o = offset $ case roc of- Infinity -> 1 -- Do the right thing.- Finite sr -> 1 + r / sr+ -- Offset with handles scaled based on curvature.+ offset factor = bezier3 (a ^* factor) ((b ^-^ c) ^* factor ^+^ c ^+^ vc ^-^ va) (c ^+^ vc ^-^ va) - 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')- ]+ -- We observe a corner. Subdivide right away.+ go (Finite 0) = subdivided+ -- We have some curvature+ go roc+ | close = [o]+ | otherwise = subdivided+ where+ -- We want the multiplicative factor that takes us from the original+ -- segment's radius of curvature roc, to roc + r.+ --+ -- r + sr = x * sr+ --+ o = offset $ case roc of+ Infinity -> 1 -- Do the right thing.+ Finite sr -> 1 + r / sr + 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')+ ] -- > import Diagrams.TwoD.Offset -- >@@ -242,13 +252,14 @@ -- it into a space with translation. 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+ where+ join' (viewLoc -> (p, a)) = translate (p .-. origin) a -- 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 ::+ 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@@ -268,23 +279,25 @@ -- while a negative radius gives an inner loop (both counter-clockwise). -- -- <<diagrams/src_Diagrams_TwoD_Offset_offsetTrailOuterExample.svg#diagram=offsetTrailOuterExample&width=300>>----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]) . trailPoints $ t- | otherwise = tail . trailPoints $ t- j = fromLineJoin (opts^.offsetJoin)+offsetTrail' ::+ RealFloat n =>+ OffsetOpts 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.+ n ->+ 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 = rotateL . trailPoints $ t+ | otherwise = drop 1 . trailPoints $ t+ j = fromLineJoin (opts ^. offsetJoin) - isLoop = withTrail (const False) (const True) (unLoc t)+ isLoop = withTrail (const False) (const True) (unLoc t) -- | Offset a 'Trail' with the default options and a given radius. See 'offsetTrail''. offsetTrail :: RealFloat n => n -> Located (Trail V2 n) -> Located (Trail V2 n)@@ -292,9 +305,10 @@ -- | Offset a 'Path' by applying 'offsetTrail'' to each trail in the path. 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+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 :: RealFloat n => n -> Path V2 n -> Path V2 n@@ -304,7 +318,7 @@ -- "right" make sense. -- -- > import Diagrams.TwoD.Offset--- > import Data.Default.Class+-- > import Data.Default -- > -- > corner :: (OrderedField n) => Located (Trail V2 n) -- > corner = fromVertices (map p2 [(0, 0), (10, 0), (5, 6)]) `at` origin@@ -339,8 +353,8 @@ 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+ where+ p = loc l -- | Expand a 'Trail' with the given options and radius 'r' around a given 'Trail'. -- Expanding can be thought of as generating the loop that, when filled, represents@@ -354,40 +368,45 @@ -- Loops result in a path with an inner and outer loop: -- -- <<diagrams/src_Diagrams_TwoD_Offset_expandLoopExample.svg#diagram=expandLoopExample&width=300>>----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 V2 n)- -> Path V2 n+expandTrail' ::+ (OrderedField n, RealFloat n, RealFrac n) =>+ ExpandOpts 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.+ n ->+ 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.+ | 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 :: 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- . offset r' $ t- ends = tail . trailPoints $ t- s = atStart t- e = atEnd t- cap = fromLineCap (opts^.expandCap)+ where+ eps = opts ^. expandEpsilon+ offset r' = map (bindLoc (offsetSegment eps r')) . locatedTrailSegments+ f r' =+ joinSegments eps (fromLineJoin (opts ^. expandJoin)) False (opts ^. expandMiterLimit) r' ends+ . offset r'+ $ t+ ends = drop 1 . trailPoints $ t+ s = atStart t+ e = atEnd t+ cap = fromLineCap (opts ^. expandCap) 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- . offset r' $ t- ends = (\(a:as) -> as ++ [a]) . trailPoints $ t+ where+ eps = opts ^. expandEpsilon+ offset r' = map (bindLoc (offsetSegment eps r')) . locatedTrailSegments+ f r' =+ joinSegments eps (fromLineJoin (opts ^. expandJoin)) True (opts ^. expandMiterLimit) r' ends+ . offset r'+ $ t+ ends = rotateL . trailPoints $ t -- | Expand a 'Trail' with the given radius and default options. See 'expandTrail''. expandTrail :: RealFloat n => n -> Located (Trail V2 n) -> Path V2 n@@ -395,16 +414,17 @@ -- | Expand a 'Path' using 'expandTrail'' on each trail in the path. 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+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 :: 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 -- > expandTrailExample = pad 1.1 . centerXY . hcat' (def & sep .~ 1)@@ -429,7 +449,6 @@ -- > t = mapLoc glueTrail $ fromVertices (map p2 [(0, 0), (5, 0), (10, 5), (10, 10), (0, 0)]) -- > t' = expandTrail' (def & expandJoin .~ LineJoinRound) 1 t - -- | When we expand a line (the original line runs through the center of offset -- lines at r and -r) there is some choice in what the ends will look like. -- If we are using a circle brush we should see a half circle at each end.@@ -439,21 +458,31 @@ -- 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 :: 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- , cap r e (atEnd fs) (atEnd bs)- , reverseDomain (unLoc bs)- ] `at` atStart bs+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+ , cap r e (atEnd fs) (atEnd bs)+ , reverseDomain (unLoc bs)+ ]+ `at` atStart bs -- | Take a LineCap style and give a function for building the cap from 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+ LineCapButt -> capCut+ LineCapRound -> capArc+ LineCapSquare -> capSquare -- | Builds a cap that directly connects the ends. capCut :: RealFloat n => n -> Point V2 n -> Point V2 n -> Point V2 n -> Trail V2 n@@ -461,17 +490,18 @@ -- | Builds a cap with a square centered on the end. 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)+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 :: 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) $ arcCW (dirBetween a c) (dirBetween b c)- | otherwise = scale r $ arcCCW (dirBetween a c) (dirBetween b c)+ where+ 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@@ -481,34 +511,36 @@ -- 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 :: RealFloat n- => n- -> (n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n)- -> Bool- -> n- -> n- -> [Point V2 n]- -> [Located (Trail V2 n)]- -> Located (Trail V2 n)+joinSegments ::+ RealFloat n =>+ n ->+ (n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n) ->+ Bool ->+ 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'- where- t' | isLoop = mapLoc (glueTrail . (<> f (take (length ts * 2 - 1) $ ss es (ts ++ [t])))) t- | otherwise = mapLoc (<> f (ss es ts)) t- ss es' ts' = concat [[test a b $ j ml r e a b, Just $ unLoc b] | (e,(a,b)) <- zip es' . (zip <*> tail) $ ts']- test a b tj- | atStart b `distance` atEnd a > epsilon = Just tj- | otherwise = Nothing- f = mconcat . catMaybes+joinSegments epsilon j isLoop ml r es ts@(t : _) = t'+ where+ t'+ | isLoop = mapLoc (glueTrail . (<> f (take (length ts * 2 - 1) $ ss es (ts ++ [t])))) t+ | otherwise = mapLoc (<> f (ss es ts)) t+ ss es' ts' = concat [[test a b $ j ml r e a b, Just $ unLoc b] | (e, (a, b)) <- zip es' . (zip <*> drop 1) $ ts']+ test a b tj+ | atStart b `distance` atEnd a > epsilon = Just tj+ | otherwise = Nothing+ f = mconcat . catMaybes -- | Take a join style and give the join function to be used by joinSegments.-fromLineJoin- :: RealFloat n => LineJoin -> n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n+fromLineJoin ::+ 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- LineJoinBevel -> joinSegmentClip+ LineJoinMiter -> joinSegmentIntersect+ LineJoinRound -> joinSegmentArc+ LineJoinBevel -> joinSegmentClip -- TODO: The joinSegmentCut option is not in our standard line joins. I don't know -- how useful it is graphically, I mostly had it as it was useful for debugging@@ -524,38 +556,44 @@ -- | 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 :: RealFloat n- => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n+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 :: RealFloat n- => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n+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- :: RealFloat n => n -> n -> Point V2 n -> Located (Trail V2 n) -> Located (Trail V2 n) -> Trail V2 n+joinSegmentIntersect ::+ 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- -- clip join when we excede the miter limit. We could instead- -- Join at exactly the miter limit, but standard behavior seems- -- to be clipping.- Nothing -> clip- Just p- -- If trace gave us garbage...- | p `distance` pb > abs (miterLimit * r) -> clip- | otherwise -> unLoc $ fromVertices [ pa, p, pb ]- where- t = straight (miter vb) `at` pb- va = unitPerp (pa .-. e)- vb = negated $ unitPerp (pb .-. e)- pa = atEnd a- pb = atStart b- 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)+ if cross < 0.000001+ then clip+ else case traceP pa va t of+ -- clip join when we excede the miter limit. We could instead+ -- Join at exactly the miter limit, but standard behavior seems+ -- to be clipping.+ Nothing -> clip+ Just p+ -- If trace gave us garbage...+ | p `distance` pb > abs (miterLimit * r) -> clip+ | otherwise -> unLoc $ fromVertices [pa, p, pb]+ where+ t = straight (miter vb) `at` pb+ va = unitPerp (pa .-. e)+ vb = negated $ unitPerp (pb .-. e)+ pa = atEnd a+ pb = atStart b+ 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)++rotateL :: [a] -> [a]+rotateL [] = []+rotateL (a : as) = as ++ [a]
src/Diagrams/TwoD/Path.hs view
@@ -1,19 +1,20 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# 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 --@@ -21,66 +22,81 @@ -- create a 2D diagram, and (eventually) perform operations such as -- intersection and union. They also have a trace, whereas paths in -- higher dimensions do not.-----------------------------------------------------------------------------------module Diagrams.TwoD.Path- ( -- * Constructing path-based diagrams-- stroke, stroke'- , strokePath, strokeP, strokePath', strokeP'- , strokeTrail, strokeT, strokeTrail', strokeT'- , strokeLine, strokeLoop- , strokeLocTrail, strokeLocT, strokeLocLine, strokeLocLoop-- -- ** Stroke options-- , FillRule(..)- , getFillRule, fillRule, _fillRule- , StrokeOpts(..), vertexNames, queryFillRule-- -- ** Inside/outside testing-- , isInsideWinding, isInsideEvenOdd-- -- * Clipping-- , Clip(..), _Clip, _clip- , clipBy, clipTo, clipped-- -- * Intersections+module Diagrams.TwoD.Path (+ -- * Constructing path-based diagrams+ stroke,+ stroke',+ strokePath,+ strokeP,+ strokePath',+ strokeP',+ strokeTrail,+ strokeT,+ strokeTrail',+ strokeT',+ strokeLine,+ strokeLoop,+ strokeLocTrail,+ strokeLocT,+ strokeLocLine,+ strokeLocLoop, - , intersectPoints, intersectPoints'- , intersectPointsP, intersectPointsP'- , intersectPointsT, intersectPointsT'- ) where+ -- ** Stroke options+ FillRule (..),+ getFillRule,+ fillRule,+ _fillRule,+ StrokeOpts (..),+ vertexNames,+ queryFillRule, -import Control.Applicative (liftA2)-import Control.Lens hiding (at, transform)-import qualified Data.Foldable as F-import Data.Semigroup-import Data.Typeable+ -- ** Inside/outside testing+ Crossings (..),+ isInsideWinding,+ isInsideEvenOdd, -import Data.Default.Class+ -- * Clipping+ Clip (..),+ _Clip,+ _clip,+ clipBy,+ clipTo,+ clipped, -import Diagrams.Angle-import Diagrams.Combinators (withEnvelope, withTrace)-import Diagrams.Core-import Diagrams.Core.Trace-import Diagrams.Located (Located, mapLoc, unLoc)-import Diagrams.Parametric-import Diagrams.Path-import Diagrams.Segment-import Diagrams.Solve.Polynomial-import Diagrams.Trail-import Diagrams.TrailLike-import Diagrams.TwoD.Segment-import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector-import Diagrams.Util (tau)+ -- * Intersections+ intersectPoints,+ intersectPoints',+ intersectPointsP,+ intersectPointsP',+ intersectPointsT,+ intersectPointsT',+) where -import Linear.Affine-import Linear.Vector+import Control.Lens hiding (at, transform)+import Data.Default+import qualified Data.Foldable as F+import Data.Semigroup+import Data.Typeable+import Diagrams.Angle+import Diagrams.Combinators (withEnvelope, withTrace)+import Diagrams.Core+import Diagrams.Core.Trace+import Diagrams.Located (Located, mapLoc, unLoc)+import Diagrams.Parametric+import Diagrams.Path+import Diagrams.Query+import Diagrams.Segment+import Diagrams.Solve.Polynomial+import Diagrams.Trail+import Diagrams.TrailLike+import Diagrams.TwoD.Segment+import Diagrams.TwoD.Types+import Diagrams.TwoD.Vector+import Diagrams.Util (tau)+import Linear.Affine+import Linear.Vector+import Prelude.Compat+import Prelude () ------------------------------------------------------------ -- Trail and path traces ---------------------------------@@ -91,11 +107,12 @@ -- XXX can the efficiency of this be improved? See the comment in -- Diagrams.Path on the Enveloped instance for Trail. instance RealFloat n => Traced (Trail V2 n) where- getTrace = withLine $- foldr+ getTrace =+ withLine+ $ foldr (\seg bds -> moveOriginBy (negated . atEnd $ seg) bds <> getTrace seg) mempty- . lineSegments+ . lineSegments instance RealFloat n => Traced (Path V2 n) where getTrace = F.foldMap getTrace . op Path@@ -107,15 +124,17 @@ -- | Enumeration of algorithms or \"rules\" for determining which -- points lie in the interior of a (possibly self-intersecting) -- 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)+data FillRule+ = -- | Interior points are those with a nonzero+ -- /winding/ /number/. See+ -- <http://en.wikipedia.org/wiki/Nonzero-rule>.+ Winding+ | -- | 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>.+ EvenOdd+ deriving (Show, Eq, Ord) instance AttributeClass FillRule instance Semigroup FillRule where@@ -129,11 +148,9 @@ -- records can be created using @'with' { ... }@ notation. data StrokeOpts a = StrokeOpts- { _vertexNames :: [[a]]-- , _queryFillRule :: FillRule-- }+ { _vertexNames :: [[a]]+ , _queryFillRule :: FillRule+ } makeLensesWith (generateSignatures .~ False $ lensRules) ''StrokeOpts @@ -146,29 +163,36 @@ -- so on. -- -- 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- { _vertexNames = []- , _queryFillRule = def- }+ def =+ StrokeOpts+ { _vertexNames = []+ , _queryFillRule = def+ } -- | 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 behaviour to be customized.-stroke :: (InSpace V2 n t, ToPath t, TypeableFloat n, Renderable (Path V2 n) b)- => t -> QDiagram b V2 n Any+--+-- @+-- '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@@ -178,108 +202,127 @@ -- -- 'StrokeOpts' is an instance of 'Default', so @stroke' ('with' & -- ... )@ syntax may be used.-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' ::+ (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 ::+ (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 ::+ (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+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' ::+ (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- where- (pLines,pLoops) = partitionPath (isLine . unLoc) path- mkP p- = mkQD (Prim p)- (getEnvelope p)- (getTrace p)- (fromNames . concat $- zipWith zip (opts^.vertexNames) ((map . map) subPoint (pathVertices p))- )- (Query $ Any . flip (runFillRule (opts^.queryFillRule)) p)+ | otherwise = mkP pLines <> mkP pLoops+ where+ (pLines, pLoops) = partitionPath (isLine . unLoc) path+ mkP p =+ mkQD+ (Prim p)+ (getEnvelope p)+ (getTrace p)+ ( fromNames+ . concat+ $ zipWith zip (opts ^. vertexNames) ((map . map) subPoint (pathVertices 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' ::+ (TypeableFloat n, Renderable (Path V2 n) b, IsName a) =>+ StrokeOpts a -> Path V2 n -> QDiagram b V2 n Any strokePath' = strokeP' -- | 'stroke' specialised to 'Trail'.-strokeTrail :: (TypeableFloat n, Renderable (Path V2 n) b)- => Trail V2 n -> QDiagram b V2 n Any+strokeTrail ::+ (TypeableFloat n, Renderable (Path V2 n) b) =>+ Trail V2 n -> QDiagram b V2 n Any strokeTrail = stroke . pathFromTrail -- | 'stroke' specialised to 'Trail'.-strokeT :: (TypeableFloat n, Renderable (Path V2 n) b)- => Trail V2 n -> QDiagram b V2 n Any+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' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)- => StrokeOpts a -> Trail V2 n -> QDiagram b V2 n Any+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' :: (TypeableFloat n, Renderable (Path V2 n) b, IsName a)- => StrokeOpts a -> Trail V2 n -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Trail' Line V2 n -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Trail' Loop V2 n -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Located (Trail V2 n) -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Located (Trail V2 n) -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Located (Trail' Line V2 n) -> QDiagram b V2 n Any+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 :: (TypeableFloat n, Renderable (Path V2 n) b)- => Located (Trail' Loop V2 n) -> QDiagram b V2 n Any+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 :: RealFloat n => FillRule -> Point V2 n -> Path V2 n -> Bool+runFillRule :: RealFloat n => FillRule -> Path V2 n -> Point V2 n -> Bool runFillRule Winding = isInsideWinding runFillRule EvenOdd = isInsideEvenOdd @@ -296,14 +339,57 @@ _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) +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 paths consisting of lines -- (as opposed to loops), regardless of the winding number.-isInsideWinding :: RealFloat n => Point V2 n -> Path V2 n -> Bool-isInsideWinding p = (/= 0) . crossings p+--+-- @+-- '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 path, -- by testing whether a ray extending from the point in the positive@@ -311,52 +397,61 @@ -- number of times. Note that @False@ is /always/ returned for -- paths consisting of lines (as opposed to loops), regardless of -- the number of crossings.-isInsideEvenOdd :: RealFloat n => Point V2 n -> Path V2 n -> 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 :: RealFloat n => Point V2 n -> Path V2 n -> Int-crossings p = F.sum . map (trailCrossings p) . op Path+--+-- @+-- '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 :: RealFloat n => Point V2 n -> Located (Trail V2 n) -> Int-- -- non-loop trails have no inside or outside, so don't contribute crossings+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- 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 (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))- $ cubForm (- x1y + 3*c1y - 3*c2y + x2y)- ( 3*x1y - 6*c1y + 3*c2y)- (-3*x1y + 3*c1y)- (x1y - y)- testT t = let (unp2 -> (px,_)) = c `atParam` t- in if px > x then signFromDerivAt t else 0- signFromDerivAt t =- 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+trailCrossings p@(unp2 -> (x, y)) 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+ (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))+ $ cubForm+ (-x1y + 3 * c1y - 3 * c2y + x2y)+ (3 * x1y - 6 * c1y + 3 * c2y)+ (-3 * x1y + 3 * c1y)+ (x1y - y)+ testT t =+ let (unp2 -> (px, _)) = c `atParam` t+ in if px > x then signFromDerivAt t else 0+ signFromDerivAt t =+ 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 = cross2 (b .-. a) (p .-. a)+ isLeft a b = cross2 (b .-. a) (p .-. a) ------------------------------------------------------------ -- Clipping ----------------------------------------------@@ -368,7 +463,7 @@ -- The clipping region is the intersection of all the applied -- clipping paths. newtype Clip n = Clip [Path V2 n]- deriving (Typeable, Semigroup)+ deriving (Semigroup) makeWrapped ''Clip @@ -380,9 +475,15 @@ type instance V (Clip n) = V2 type instance N (Clip n) = n -instance (OrderedField n) => Transformable (Clip n) where+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 @@ -397,36 +498,40 @@ -- -- * The envelope of the diagram is unaffected. clipBy :: (HasStyle a, V a ~ V2, N a ~ n, TypeableFloat n) => Path V2 n -> a -> a-clipBy = applyTAttr . Clip . (:[])+clipBy = applyTAttr . Clip . (: []) -- | Clip a diagram to the given path setting its envelope to the -- pointwise minimum of the envelopes of the diagram and path. The -- 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 :: TypeableFloat n- => Path V2 n -> QDiagram b V2 n Any -> QDiagram b V2 n Any+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- envD = appEnvelope . getEnvelope $ d- toEnvelope = case (envP, envD) of- (Just eP, Just eD) -> setEnvelope . mkEnvelope $ \v -> min (eP v) (eD v)- (_, _) -> id- 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- dInside pDist = getAny . sample d $ newPt pDist+ where+ envP = appEnvelope . getEnvelope $ p+ envD = appEnvelope . getEnvelope $ d+ toEnvelope = case (envP, envD) of+ (Just eP, Just eD) -> setEnvelope . mkEnvelope $ \v -> min (eP v) (eD v)+ (_, _) -> id+ 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 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 :: TypeableFloat n- => Path V2 n -> QDiagram b V2 n Any -> QDiagram b V2 n Any+clipped ::+ TypeableFloat n =>+ Path V2 n -> QDiagram b V2 n Any -> QDiagram b V2 n Any clipped p = withTrace p . withEnvelope p . clipBy p ------------------------------------------------------------@@ -434,19 +539,21 @@ ------------------------------------------------------------ -- | 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-10+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' ::+ (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-10+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]@@ -457,7 +564,7 @@ -- | Compute the intersect points between two located trails. intersectPointsT :: OrderedField n => Located (Trail V2 n) -> Located (Trail V2 n) -> [P2 n]-intersectPointsT = intersectPointsT' 1e-10+intersectPointsT = intersectPointsT' 1e-8 -- | Compute the intersect points between two located trails within the given -- tolerance.
src/Diagrams/TwoD/Points.hs view
@@ -1,4 +1,6 @@------------------------------------------------------------------------------+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeFamilies #-}+ -- | -- Module : Diagrams.TwoD.Points -- Copyright : (c) 2014 diagrams-lib team (see LICENSE)@@ -6,54 +8,49 @@ -- Maintainer : diagrams-discuss@googlegroups.com -- -- Special functions for points in R2.-----------------------------------------------------------------------------------{-# LANGUAGE TypeFamilies #-}- module Diagrams.TwoD.Points where -import Data.List-+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE import Diagrams.Core-import Diagrams.TwoD.Vector import Diagrams.TwoD.Types (P2)+import Diagrams.TwoD.Vector 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)+convexHull2D [] = []+convexHull2D (p : ps) = NE.init upper ++ reverse (NE.tail lower)+ where+ (upper, lower) = sortedConvexHull (NE.sort (p :| 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 +-- | 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 :: OrderedField n => NonEmpty (P2 n) -> (NonEmpty (P2 n), NonEmpty (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)+ 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- 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+ dir' = p2 .-. p1+ go _ p1 p = Right (p1 : p)+ chain _ l = l
src/Diagrams/TwoD/Polygons.hs view
@@ -1,12 +1,11 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-} ------------------------------------------------------------------------------ -- | -- Module : Diagrams.TwoD.Polygons -- Copyright : (c) 2011 diagrams-lib team (see LICENSE)@@ -15,137 +14,147 @@ -- -- This module defines a general API for creating various types of -- polygons.-----------------------------------------------------------------------------------module Diagrams.TwoD.Polygons(- -- * Polygons- PolyType(..)- , PolyOrientation(..)- , PolygonOpts(..), polyType, polyOrient, polyCenter-- , polygon- , polyTrail-- -- ** Generating polygon vertices-- , polyPolarTrail- , polySidesTrail- , polyRegularTrail-- , orient+module Diagrams.TwoD.Polygons (+ -- * Polygons+ PolyType (..),+ PolyOrientation (..),+ PolygonOpts (..),+ polyType,+ polyOrient,+ polyCenter,+ polygon,+ polyTrail, - -- * Star polygons- , StarOpts(..)- , star+ -- ** Generating polygon vertices+ polyPolarTrail,+ polySidesTrail,+ polyRegularTrail,+ orient, - -- ** Function graphs- -- $graphs- , GraphPart(..)- , orbits, mkGraph+ -- * Star polygons+ StarOpts (..),+ star, - ) where+ -- ** Function graphs+ -- $graphs+ GraphPart (..),+ orbits,+ mkGraph,+) 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.Default.Class-import Data.List (maximumBy, minimumBy)-import Data.Maybe (catMaybes)-#if __GLASGOW_HASKELL__ < 710-import Data.Monoid (mconcat, mempty)-#endif-import Data.Ord (comparing)+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.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE+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.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.Angle+import Diagrams.Core+import Diagrams.Located+import Diagrams.Path+import Diagrams.Points (centroid)+import Diagrams.Trail+import Diagrams.TrailLike+import Diagrams.TwoD.Types+import Diagrams.TwoD.Vector (leftTurn, unitX, unitY, unit_Y)+import Diagrams.Util (tau, (#)) -import Linear.Affine-import Linear.Metric-import Linear.Vector+import Linear.Affine+import Linear.Metric+import Linear.Vector -- | Method used to determine the vertices of a polygon.-data PolyType n = PolyPolar [Angle n] [n]- -- ^ A \"polar\" polygon.- --- -- * The first argument is a list of /central/- -- /angles/ from each vertex to the next.- --- -- * The second argument is a list of /radii/ from- -- the origin to each successive vertex.- --- -- To construct an /n/-gon, use a list of /n-1/- -- angles and /n/ radii. Extra angles or radii- -- are ignored.- --- -- Cyclic polygons (with all vertices lying on a- -- circle) can be constructed using a second- -- argument of @(repeat r)@.-- | PolySides [Angle n] [n]- -- ^ A polygon determined by the distance between- -- 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- -- 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 external angle at each vertex- -- from the previous vertex to the next. The- -- 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.- --- -- * The second argument is a list of distances- -- between successive vertices.- --- -- To construct an /n/-gon, use a list of /n-2/- -- angles and /n-1/ edge lengths. Extra angles or- -- lengths are ignored.-- | PolyRegular Int n- -- ^ A regular polygon with the given number of- -- sides (first argument) and the given radius- -- (second argument).+data PolyType n+ = -- | A \"polar\" polygon.+ --+ -- * The first argument is a list of /central/+ -- /angles/ from each vertex to the next.+ --+ -- * The second argument is a list of /radii/ from+ -- the origin to each successive vertex.+ --+ -- To construct an /n/-gon, use a list of /n-1/+ -- angles and /n/ radii. Extra angles or radii+ -- are ignored.+ --+ -- Cyclic polygons (with all vertices lying on a+ -- circle) can be constructed using a second+ -- argument of @(repeat r)@.+ PolyPolar [Angle n] [n]+ | -- | A polygon determined by the distance between+ -- 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+ -- 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 external angle at each vertex+ -- from the previous vertex to the next. The+ -- 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.+ --+ -- * The second argument is a list of distances+ -- between successive vertices.+ --+ -- To construct an /n/-gon, use a list of /n-2/+ -- angles and /n-1/ edge lengths. Extra angles or+ -- lengths are ignored.+ PolySides [Angle n] [n]+ | -- | A regular polygon with the given number of+ -- sides (first argument) and the given radius+ -- (second argument).+ PolyRegular Int n -- | Determine how a polygon should be oriented.-data PolyOrientation n = 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 (V2 n) -- ^ 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+ = -- | No special orientation; the first+ -- vertex will be at (1,0).+ NoOrient+ | -- | Orient /horizontally/, so the+ -- bottommost edge is parallel to+ -- the x-axis.+ -- This is the default.+ OrientH+ | -- | Orient /vertically/, so the+ -- leftmost edge is parallel to the+ -- y-axis.+ OrientV+ | -- | Orient so some edge is+ -- /facing/ /in/ /the/ /direction/+ -- /of/, that is, perpendicular+ -- to, the given vector.+ OrientTo (V2 n)+ deriving (Eq, Ord, Show, Read) -- | Options for specifying a polygon. data PolygonOpts n = PolygonOpts- { _polyType :: PolyType n- , _polyOrient :: PolyOrientation n- , _polyCenter :: Point V2 n- }+ { _polyType :: PolyType n+ , _polyOrient :: PolyOrientation n+ , _polyCenter :: Point V2 n+ } makeLensesWith (generateSignatures .~ False $ lensRules) ''PolygonOpts @@ -163,21 +172,21 @@ -- | The default polygon is a regular pentagon of radius 1, centered -- at the origin, aligned to the x-axis. instance Num n => Default (PolygonOpts n) where- def = PolygonOpts (PolyRegular 5 1) OrientH origin+ def = PolygonOpts (PolyRegular 5 1) OrientH origin -- | Generate a polygon. See 'PolygonOpts' for more information. polyTrail :: OrderedField n => PolygonOpts n -> Located (Trail V2 n) polyTrail po = transform ori tr- where- tr = case po^.polyType of- PolyPolar ans szs -> polyPolarTrail ans szs- 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+ where+ tr = case po ^. polyType of+ PolyPolar ans szs -> polyPolarTrail ans szs+ 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 -- | Generate the polygon described by the given options. polygon :: (InSpace V2 n t, TrailLike t) => PolygonOpts n -> t@@ -185,34 +194,36 @@ -- | Generate the located trail of a polygon specified by polar data -- (central angles and radii). See 'PolyPolar'.-polyPolarTrail :: OrderedField n => [Angle n] -> [n] -> Located (Trail V2 n)+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- where- p1 = p2 (1,0) # scale r- tr = closeTrail . trailFromVertices $- zipWith- (\a l -> rotate a . scale l $ p2 (1,0))- (scanl (^+^) zero ans)- (r:rs)+polyPolarTrail ans (r : rs) = tr `at` p1+ where+ p1 = p2 (1, 0) # scale r+ tr =+ closeTrail . trailFromVertices $+ zipWith+ (\a l -> rotate a . scale l $ p2 (1, 0))+ (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 :: OrderedField n => [Angle n] -> [n] -> Located (Trail V2 n)+polySidesTrail :: OrderedField n => [Angle n] -> [n] -> Located (Trail V2 n) polySidesTrail ans ls = tr `at` (centroid ps # scale (-1))- where- ans' = scanl (^+^) zero ans- offsets = zipWith rotate ans' (map (unitY ^*) ls)- ps = scanl (.+^) origin offsets- tr = closeTrail . trailFromOffsets $ offsets+ where+ 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 :: OrderedField n => Int -> n -> Located (Trail V2 n)-polyRegularTrail n r = polyPolarTrail- (replicate (n - 1) $ fullTurn ^/ fromIntegral n)- (repeat r)+polyRegularTrail :: OrderedField n => Int -> n -> Located (Trail V2 n)+polyRegularTrail n r =+ polyPolarTrail+ (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@@ -222,27 +233,33 @@ orient v = orientPoints v . trailVertices orientPoints :: OrderedField n => V2 n -> [Point V2 n] -> Transformation V2 n-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 `dot` p) * norm (project w p)- sndOf3 (_,b,_) = b- -- a :: Angle (Scalar v)- a = minimumBy (comparing $ abs . view rad)- . map (angleFromNormal . (.-. x)) $ [n1,n2]- v' = signorm v- -- angleFromNormal :: v -> Angle (Scalar v)- angleFromNormal o- | leftTurn o' v' = phi- | otherwise = negated phi- where- 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+orientPoints _ [] = mempty+orientPoints _ [_] = mempty+orientPoints v xs@(y : ys) = rotation a+ where+ (n1, x, n2) =+ maximumBy+ (comparing (distAlong v . sndOf3))+ (zip3 (ys ++ [y]) xs (NE.last (y :| ys) : NE.init (y :| ys)))+ distAlong w ((.-. origin) -> p) = signum (w `dot` p) * norm (project w p)+ sndOf3 (_, b, _) = b+ -- a :: Angle (Scalar v)+ a =+ minimumBy (comparing $ abs . view rad)+ . map (angleFromNormal . (.-. x))+ $ [n1, n2]+ v' = signorm v+ -- angleFromNormal :: v -> Angle (Scalar v)+ angleFromNormal o+ | leftTurn o' v' = phi+ | otherwise = negated phi+ where+ 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 ------------------------------------------------------------ -- Function graphs@@ -253,49 +270,54 @@ -- the offchance that someone else finds them useful. -- | Pieces of a function graph can either be cycles or \"hairs\".-data GraphPart a = Cycle [a]- | Hair [a]+data GraphPart a+ = Cycle [a]+ | Hair [a] deriving (Show, Functor) -- | @orbits f n@ computes the graph of @f@ on the integers mod @n@. orbits :: (Int -> Int) -> Int -> [GraphPart Int] orbits f n = runST genOrbits- where- f_n i = f i `mod` n+ where+ f_n i = f i `mod` n - genOrbits :: ST s [GraphPart Int]- genOrbits = newArray (0,n-1) False >>= genOrbits'+ genOrbits :: ST s [GraphPart Int]+ genOrbits = newArray (0, n - 1) False >>= genOrbits' - genOrbits' :: STUArray s Int Bool -> ST s [GraphPart Int]- genOrbits' marks = liftM (concat . catMaybes) (forM [0 .. n-1] (genPart marks))+ genOrbits' :: STUArray s Int Bool -> ST s [GraphPart Int]+ genOrbits' marks = liftM (concat . catMaybes) (forM [0 .. n - 1] (genPart marks)) - genPart :: STUArray s Int Bool -> Int -> ST s (Maybe [GraphPart Int])- genPart marks i = do- tr <- markRho i marks- case tr of- [] -> return Nothing- _ -> return . Just . splitParts $ tr+ genPart :: STUArray s Int Bool -> Int -> ST s (Maybe [GraphPart Int])+ genPart marks i = do+ tr <- markRho i marks+ case tr of+ [] -> return Nothing+ _ -> return . Just . splitParts $ tr - markRho :: Int -> STUArray s Int Bool -> ST s [Int]- markRho i marks = do- isMarked <- readArray marks i- if isMarked- then return []- else writeArray marks i True >>- liftM (i:) (markRho (f_n i) marks)+ markRho :: Int -> STUArray s Int Bool -> ST s [Int]+ markRho i marks = do+ isMarked <- readArray marks i+ if isMarked+ then return []+ else+ writeArray marks i True+ >> liftM (i :) (markRho (f_n i) marks) - splitParts :: [Int] -> [GraphPart Int]- splitParts tr = hair ++ cyc- where hair | not (null tl) = [Hair $ tl ++ [f_n (last tl)]]- | otherwise = []- cyc | not (null body) = [Cycle body]- | otherwise = []- l = last tr- (tl, body) = span (/= f_n l) tr+ splitParts :: [Int] -> [GraphPart Int]+ splitParts tr = hair ++ cyc+ where+ hair+ | not (null tl) = [Hair $ tl ++ [f_n (last tl)]]+ | otherwise = []+ cyc+ | not (null body) = [Cycle body]+ | otherwise = []+ l = last tr+ (tl, body) = span (/= f_n l) tr -- | Generate a function graph from the given function and labels. mkGraph :: (Int -> Int) -> [a] -> [GraphPart a]-mkGraph f xs = (map . fmap) (xs!!) $ orbits f (length xs)+mkGraph f xs = (map . fmap) (xs !!) $ orbits f (length xs) ------------------------------------------------------------ -- Star polygons@@ -303,20 +325,20 @@ -- | Options for creating \"star\" polygons, where the edges connect -- possibly non-adjacent vertices.-data StarOpts = StarFun (Int -> Int)- -- ^ Specify the order in which the vertices should be- -- connected by a function that maps each vertex- -- index to the index of the vertex that should come- -- next. Indexing of vertices begins at 0.-- | StarSkip Int- -- ^ Specify a star polygon by a \"skip\". A skip of- -- 1 indicates a normal polygon, where edges go- -- between successive vertices. A skip of 2 means- -- that edges will connect every second vertex,- -- skipping one in between. Generally, a skip of- -- /n/ means that edges will connect every /n/th- -- vertex.+data StarOpts+ = -- | Specify the order in which the vertices should be+ -- connected by a function that maps each vertex+ -- index to the index of the vertex that should come+ -- next. Indexing of vertices begins at 0.+ StarFun (Int -> Int)+ | -- | Specify a star polygon by a \"skip\". A skip of+ -- 1 indicates a normal polygon, where edges go+ -- between successive vertices. A skip of 2 means+ -- that edges will connect every second vertex,+ -- skipping one in between. Generally, a skip of+ -- /n/ means that edges will connect every /n/th+ -- vertex.+ StarSkip Int -- | Create a generalized /star/ /polygon/. The 'StarOpts' are used -- to determine in which order the given vertices should be@@ -329,14 +351,15 @@ -- to be connected in several disjoint cycles. 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- StarSkip k -> (+k)- graphToPath = mconcat . map partToPath-- partToPath (Cycle ps) = pathFromLocTrail- . mapLoc closeTrail- . fromVertices- $ ps+ where+ f = case sOpts of+ StarFun g -> g+ StarSkip k -> (+ k)+ graphToPath = mconcat . map partToPath - partToPath (Hair ps) = fromVertices ps+ partToPath (Cycle ps) =+ pathFromLocTrail+ . mapLoc closeTrail+ . fromVertices+ $ ps+ partToPath (Hair ps) = fromVertices ps
src/Diagrams/TwoD/Segment.hs view
@@ -1,15 +1,17 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-+{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+ -- 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.------------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Segment -- Copyright : (c) 2012 diagrams-lib team (see LICENSE)@@ -18,47 +20,44 @@ -- -- Segments in two dimensions are special since we may meaningfully -- compute their point of intersection with a ray.-----------------------------------------------------------------------------------module Diagrams.TwoD.Segment- ( -- * Segment intersections-- intersectPointsS- , intersectPointsS'-- -- * Closest point on a segment+module Diagrams.TwoD.Segment (+ -- * Segment intersections+ intersectPointsS,+ intersectPointsS', - , closestPoint- , closestPoint'- , closestDistance- , closestDistance'- , closestParam- , closestParam'+ -- * Closest point on a segment+ closestPoint,+ closestPoint',+ closestDistance,+ closestDistance',+ closestParam,+ closestParam', - -- ** Low level functions- , segmentSegment- , lineSegment- )- where+ -- ** Low level functions+ segmentSegment,+ lineSegment,+)+where -import Control.Lens hiding (at, contains, transform, ( # ))-import Data.Maybe+import Control.Lens hiding (at, contains, transform, (#))+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE+import Data.Maybe -import Diagrams.Core+import Diagrams.Core -import Diagrams.Direction-import Diagrams.Located-import Diagrams.Parametric-import Diagrams.Segment-import Diagrams.TwoD.Points-import Diagrams.TwoD.Segment.Bernstein-import Diagrams.TwoD.Transform-import Diagrams.TwoD.Types hiding (p2)-import Diagrams.TwoD.Vector+import Diagrams.Direction+import Diagrams.Located+import Diagrams.Parametric+import Diagrams.Segment+import Diagrams.TwoD.Points+import Diagrams.TwoD.Segment.Bernstein+import Diagrams.TwoD.Transform+import Diagrams.TwoD.Types hiding (p2)+import Diagrams.TwoD.Vector -import Linear.Affine-import Linear.Metric+import Linear.Affine+import Linear.Metric {- All instances of Traced should maintain the invariant that the list of traces is sorted in increasing order.@@ -108,21 +107,22 @@ -- tolerance. closestParam' :: OrderedField n => n -> FixedSegment V2 n -> P2 n -> [n] closestParam' _ (FLinear p0 p1) p- | t < 0 = [0]- | t > 1 = [1]+ | t < 0 = [0]+ | t > 1 = [1] | otherwise = [t]- where- vp = p .-. p0- v = p1 .-. p0- dp = vp `dot` v- t = dp / quadrance v+ 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'+ 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' ------------------------------------------------------------------------ -- Low level@@ -132,65 +132,70 @@ -- 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)+ 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) -- | 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+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 = []-- -- 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)-- | 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 ) ]-- -- 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+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 = case chopCubics p q of+ Nothing -> []+ -- This check happens before the subdivision+ -- test to avoid non-termination as values+ -- transition to within epsilon.+ Just (tminChop, tmaxChop)+ | 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+ p' = section p tminChop tmaxChop clip' = tmaxChop - tminChop tmin' = tmax * tminChop + tmin * (1 - tminChop) tmax' = tmax * tmaxChop + tmin * (1 - tmaxChop)@@ -198,29 +203,45 @@ -- | 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- | isNothing chopInterval = []- | clip > 0.8 = let (p1, p2) = splitAtParam newP 0.5- tmid = tmin' + (tmax' - tmin') / 2- in bezierFindRoot eps p1 tmin' tmid ++- bezierFindRoot eps p2 tmid tmax'- | tmax' - tmin' < eps = [avg tmin' 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)--+bezierFindRoot ::+ OrderedField n =>+ -- | The accuracy+ n ->+ -- | the Bernstein coefficients of the polynomial+ BernsteinPoly n ->+ -- | The lower bound of the interval+ n ->+ -- | The upper bound of the interval+ n ->+ -- | The roots found+ [n]+bezierFindRoot eps p initMin initMax+ -- 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 /= initMax && abs (evaluateBernstein p initMax) <= eps =+ roots ++ [initMax]+ | 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 initMin initMax+ go pInit tmin tmax = case chopYs (bernsteinCoeffs pInit) of+ Nothing -> []+ Just (tminChop, tmaxChop)+ | 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+ newP = section pInit tminChop tmaxChop+ clip = tmaxChop - tminChop+ tmin' = tmax * tminChop + tmin * (1 - tminChop)+ tmax' = tmax * tmaxChop + tmin * (1 - tmaxChop) ------------------------------------------------------------------------ -- Internal@@ -228,67 +249,79 @@ -- | 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)+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 :: OrderedField n => NonEmpty 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+ where+ points = NE.zipWith mkP2 (NE.zipWith (\i _ -> fromIntegral @Integer i / fromIntegral n) (0 :| [1 ..]) ds) ds+ n = NE.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 :: OrderedField n => FixedSegment V2 n -> FixedSegment V2 n -> Maybe (n, n)+chopCubics p q@(FCubic q0 _ _ q3) =+ chopHull dmin dmax dps+ where+ dps = NE.zipWith mkP2 (0 :| [1 / 3, 2 / 3, 1]) ds+ ds = NE.map d $ case p of+ FLinear p0 p1 -> p0 :| [p1]+ FCubic p0 p1 p2 p3 -> p0 :| [p1, p2, p3]+ 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 :: OrderedField n => n -> n -> NonEmpty (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)+ tL <- testBelow upper $ testBetween (NE.head upper) $ testAbove lower+ tR <- testBelow (NE.reverse upper) $ testBetween (NE.last upper) $ testAbove (NE.reverse lower) Just (tL, tR)- where- (upper, lower) = sortedConvexHull dps+ 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+ 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+ 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)- | otherwise = Just $ intersectPt dmax p1 p2- testAbove _ = Nothing+ 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+ (listToBernstein $ map (view _x) coeffs, listToBernstein $ map (view _y) coeffs)+ where+ coeffs = toListOf each seg ------------------------------------------------------------------------ -- Lines@@ -296,44 +329,46 @@ -- Could split this into a separate module. --- | Returns @(a, b, c)@ such that @ax + by + c = 0@ is the line going through--- @p1@ and @p2@ with @a^2 + b^2 = 1@.-lineEquation :: Floating n => P2 n -> P2 n -> (n, n, n)-lineEquation (P (V2 x1 y1)) (P (V2 x2 y2)) = (a, b, c)- where- a = a' / d- b = b' / d- c = -(x1*a' + y1*b') / d- a' = y1 - y2- b' = x2 - x1- d = sqrt $ a'*a' + b'*b'+-- | 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 :: Floating n => P2 n -> P2 n -> P2 n -> n-lineDistance p1 p2 (P (V2 x y)) = a*x + b*y + c- where (a, b, c) = lineEquation p1 p2---- find the x value where the line through the two points--- intersect the line y=d-intersectPt :: OrderedField n => n -> P2 n -> P2 n -> n-intersectPt d (P (V2 x1 y1)) (P (V2 x2 y2)) =- x1 + (d - y1) * (x2 - x1) / (y2 - y1)+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+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+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@@ -342,9 +377,11 @@ 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 (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)-+inRange x = x < (1 + defEps) && x > (-defEps)
src/Diagrams/TwoD/Segment/Bernstein.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE TypeFamilies #-}------------------------------------------------------------------------------+{-# LANGUAGE TypeFamilies #-}+ -- | -- Module : Diagrams.TwoD.Segment.Bernstein -- Copyright : (c) 2014-2015 diagrams-lib team (see LICENSE)@@ -10,129 +10,133 @@ -- 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+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+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty.Compat as NE+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]+binomials :: Num n => Int -> NonEmpty n+binomials n = NE.map fromIntegral $ NE.scanl (\x m -> x * (n - m + 1) `quot` m) 1 [1 .. n] data BernsteinPoly n = BernsteinPoly { bernsteinDegree :: Int- , bernsteinCoeffs :: [n]- } deriving (Show, Functor)+ , bernsteinCoeffs :: NonEmpty n+ }+ deriving (Show, Functor) -type instance V (BernsteinPoly n) = V1-type instance N (BernsteinPoly n) = n+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+listToBernstein l = case NE.nonEmpty l of+ Nothing -> 0+ Just ne -> BernsteinPoly (length l - 1) ne -- | Degree elevate a bernstein polynomial a number of times. degreeElevate :: Fractional n => BernsteinPoly n -> Int -> BernsteinPoly n-degreeElevate b 0 = b+degreeElevate b 0 = b degreeElevate (BernsteinPoly lp p) times =- degreeElevate (BernsteinPoly (lp+1) (head p:inner p 1)) (times-1)- where- n = fromIntegral lp+ degreeElevate (BernsteinPoly (lp + 1) (NE.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)+ 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+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"+ 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+ | 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+bernsteinDeriv (BernsteinPoly _ (_ :| [])) = 0+bernsteinDeriv (BernsteinPoly lp p@(_ :| (a1 : as))) =+ -- BernsteinPoly (lp-1) $ map (* fromIntegral lp) $ zipWith (-) (drop 1 p) p+ BernsteinPoly (lp - 1) $ NE.zipWith (\a b -> (a - b) * fromIntegral lp) (a1 :| as) 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)+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 (NE.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+ ( BernsteinPoly lp $ NE.map NE.head controls+ , BernsteinPoly lp $ NE.reverse $ NE.map NE.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+ -- terp :: NonEmpty n -> [NonEmpty n]+ terp l@(_ :| as) = case NE.nonEmpty as of+ Nothing -> []+ Just as' ->+ let ctrs = NE.zipWith interp l as'+ 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+ | la < lb = BernsteinPoly lb $ NE.zipWith (+) (bernsteinCoeffs $ degreeElevate ba $ lb - la) b+ | la > lb = BernsteinPoly la $ NE.zipWith (+) a (bernsteinCoeffs $ degreeElevate bb $ la - lb)+ | otherwise = BernsteinPoly la $ NE.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+ | la < lb = BernsteinPoly lb $ NE.zipWith (-) (bernsteinCoeffs $ degreeElevate ba (lb - la)) b+ | la > lb = BernsteinPoly la $ NE.zipWith (-) a (bernsteinCoeffs $ degreeElevate bb (la - lb))+ | otherwise = BernsteinPoly la $ NE.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)+ BernsteinPoly (la + lb) $+ NE.zipWith (flip (/)) (binomials (la + lb)) $+ NE.map sum $+ NE.appendList+ (NE.map (NE.zipWith (*) a') (down b'))+ (map (NE.zipWith (*) (NE.reverse b')) (NE.tail $ NE.tails1 a'))+ where+ down (x :| xs) = NE.scanl (flip NE.cons) (x :| []) xs -- [[1], [2, 1], [3, 2, 1], ...+ a' = NE.zipWith (*) a (binomials la)+ b' = NE.zipWith (*) b (binomials lb) - fromInteger a = BernsteinPoly 0 [fromInteger a]+ fromInteger a = BernsteinPoly 0 (fromInteger a :| []) - signum (BernsteinPoly _ []) = 0- signum (BernsteinPoly _ (a:_)) = BernsteinPoly 0 [signum a]+ signum (BernsteinPoly _ (a :| _)) = BernsteinPoly 0 (signum a :| []) abs = fmap abs
src/Diagrams/TwoD/Shapes.hs view
@@ -1,8 +1,15 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-} +-- for Data.Semigroup+ -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Shapes -- Copyright : (c) 2011 diagrams-lib team (see LICENSE)@@ -10,60 +17,58 @@ -- Maintainer : diagrams-discuss@googlegroups.com -- -- Various two-dimensional shapes.-----------------------------------------------------------------------------------module Diagrams.TwoD.Shapes- (- -- * Miscellaneous- hrule, vrule-- -- * Regular polygons-- , regPoly- , triangle- , eqTriangle- , square- , pentagon- , hexagon- , heptagon- , septagon- , octagon- , nonagon- , decagon- , hendecagon- , dodecagon-- -- * Other special polygons- , unitSquare- , rect+module Diagrams.TwoD.Shapes (+ -- * Miscellaneous+ hrule,+ vrule, - -- * Other shapes+ -- * Regular polygons+ regPoly,+ triangle,+ eqTriangle,+ square,+ pentagon,+ hexagon,+ heptagon,+ septagon,+ octagon,+ nonagon,+ decagon,+ hendecagon,+ dodecagon, - , roundedRect- , RoundedRectOpts(..), radiusTL, radiusTR, radiusBL, radiusBR- , roundedRect'- ) where+ -- * Other special polygons+ unitSquare,+ rect, -import Control.Lens (makeLenses, op, (&), (.~), (<>~), (^.))-import Data.Default.Class-import Data.Semigroup+ -- * Other shapes+ roundedRect,+ RoundedRectOpts (..),+ radiusTL,+ radiusTR,+ radiusBL,+ radiusBR,+ roundedRect',+) where -import Diagrams.Core+import Control.Lens (makeLenses, op, (&), (.~), (<>~), (^.))+import Data.Default+import Data.Semigroup -import Diagrams.Angle-import Diagrams.Located (at)-import Diagrams.Path-import Diagrams.Segment-import Diagrams.Trail-import Diagrams.TrailLike-import Diagrams.TwoD.Arc-import Diagrams.TwoD.Polygons-import Diagrams.TwoD.Transform-import Diagrams.TwoD.Types-import Diagrams.TwoD.Vector-import Diagrams.Util+import Diagrams.Core +import Diagrams.Angle+import Diagrams.Located (at)+import Diagrams.Path+import Diagrams.Segment+import Diagrams.Trail+import Diagrams.TrailLike+import Diagrams.TwoD.Arc+import Diagrams.TwoD.Polygons+import Diagrams.TwoD.Transform+import Diagrams.TwoD.Types+import Diagrams.TwoD.Vector+import Diagrams.Util -- | Create a centered horizontal (L-R) line of the given length. --@@ -72,7 +77,7 @@ -- > hruleEx = vcat' (with & sep .~ 0.2) (map hrule [1..5]) -- > # centerXY # pad 1.1 hrule :: (InSpace V2 n t, TrailLike t) => n -> t-hrule d = trailLike $ trailFromSegments [straight $ r2 (d, 0)] `at` p2 (-d/2,0)+hrule d = trailLike $ trailFromSegments [straight $ r2 (d, 0)] `at` p2 (-d / 2, 0) -- | Create a centered vertical (T-B) line of the given length. --@@ -81,15 +86,19 @@ -- > vruleEx = hcat' (with & sep .~ 0.2) (map vrule [1, 1.2 .. 2]) -- > # centerXY # pad 1.1 vrule :: (InSpace V2 n t, TrailLike t) => n -> t-vrule d = trailLike $ trailFromSegments [straight $ r2 (0, -d)] `at` p2 (0,d/2)+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 :: (InSpace V2 n t, TrailLike t) => t-unitSquare = polygon (def & polyType .~ PolyRegular 4 (sqrt 2 / 2)- & polyOrient .~ OrientH)+unitSquare =+ polygon+ ( def+ & polyType .~ PolyRegular 4 (sqrt 2 / 2)+ & polyOrient .~ OrientH+ ) -- > unitSquareEx = unitSquare # pad 1.1 # showOrigin @@ -108,26 +117,29 @@ -- -- <<diagrams/src_Diagrams_TwoD_Shapes_rectEx.svg#diagram=rectEx&width=150>> rect :: (InSpace V2 n t, TrailLike t) => n -> n -> t-rect w h = trailLike . head . op Path $ unitSquare # scaleX w # scaleY h+rect w h = case op Path $ unitSquare # scaleX w # scaleY h of+ (t : _) -> trailLike t+ -- This case can't happen---the unitSquare path is definitely non-empty.+ [] -> error "Impossible - unitSquare returned an empty path!" -- > rectEx = rect 1 0.7 # pad 1.1 - -- The above may seem a bit roundabout. In fact, we used to have- --- -- rect w h = unitSquare # scaleX w # scaleY h- --- -- since unitSquare can produce any TrailLike. The current code- -- instead uses (unitSquare # scaleX w # scaleY h) to specifically- -- produce a Path, which is then deconstructed and passed back into- -- 'trailLike' to create any TrailLike.- --- -- The difference is that while scaling by zero works fine for- -- Path it does not work very well for, say, Diagrams (leading to- -- NaNs or worse). This way, we force the scaling to happen on a- -- Path, where we know it will behave properly, and then use the- -- resulting geometry to construct an arbitrary TrailLike.- --- -- See https://github.com/diagrams/diagrams-lib/issues/43 .+-- The above may seem a bit roundabout. In fact, we used to have+--+-- rect w h = unitSquare # scaleX w # scaleY h+--+-- since unitSquare can produce any TrailLike. The current code+-- instead uses (unitSquare # scaleX w # scaleY h) to specifically+-- produce a Path, which is then deconstructed and passed back into+-- 'trailLike' to create any TrailLike.+--+-- The difference is that while scaling by zero works fine for+-- Path it does not work very well for, say, Diagrams (leading to+-- NaNs or worse). This way, we force the scaling to happen on a+-- Path, where we know it will behave properly, and then use the+-- resulting geometry to construct an arbitrary TrailLike.+--+-- See https://github.com/diagrams/diagrams-lib/issues/43 . ------------------------------------------------------------ -- Regular polygons@@ -140,12 +152,15 @@ -- -- The polygon will be oriented with one edge parallel to the x-axis. regPoly :: (InSpace V2 n t, TrailLike t) => Int -> n -> t-regPoly n l = polygon (def & polyType .~- PolySides- (repeat (1/fromIntegral n @@ turn))- (replicate (n-1) l)- & polyOrient .~ OrientH- )+regPoly n l =+ polygon+ ( def+ & polyType+ .~ PolySides+ (repeat (1 / fromIntegral n @@ turn))+ (replicate (n - 1) l)+ & polyOrient .~ OrientH+ ) -- > shapeEx sh = sh 1 # pad 1.1 -- > triangleEx = shapeEx triangle@@ -234,15 +249,16 @@ ------------------------------------------------------------ -- Other shapes ------------------------------------------ -------------------------------------------------------------data RoundedRectOpts d = RoundedRectOpts { _radiusTL :: d- , _radiusTR :: d- , _radiusBL :: d- , _radiusBR :: d- }+data RoundedRectOpts d = RoundedRectOpts+ { _radiusTL :: d+ , _radiusTR :: d+ , _radiusBL :: d+ , _radiusBR :: d+ } makeLenses ''RoundedRectOpts -instance (Num d) => Default (RoundedRectOpts d) 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,54 +281,64 @@ -- > & radiusTR .~ -0.2 -- > & radiusBR .~ 0.1) -- > ]- 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- & radiusBL .~ r)+roundedRect w h r =+ roundedRect'+ w+ h+ ( def+ & radiusTL .~ r+ & radiusBR .~ r+ & radiusTR .~ r+ & radiusBL .~ r+ ) -- | @roundedRect'@ works like @roundedRect@ but allows you to set the radius of -- 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' :: (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))- . wrapTrail- . glueLine- $ seg (0, h - abs rTR - abs rBR)- <> mkCorner 0 rTR- <> seg (abs rTR + abs rTL - w, 0)- <> mkCorner 1 rTL- <> seg (0, abs rTL + abs rBL - h)- <> mkCorner 2 rBL- <> seg (w - abs rBL - abs rBR, 0)- <> mkCorner 3 rBR- where seg = lineFromOffsets . (:[]) . r2- diag = sqrt (w * w + h * h)- -- to clamp corner radius, need to compare with other corners that share an- -- edge. If the corners overlap then reduce the largest corner first, as far- -- as 50% of the edge in question.- rTL = clampCnr radiusTR radiusBL radiusBR radiusTL- rBL = clampCnr radiusBR radiusTL radiusTR radiusBL- rTR = clampCnr radiusTL radiusBR radiusBL radiusTR- rBR = clampCnr radiusBL radiusTR radiusTL radiusBR- clampCnr rx ry ro r = let (rx',ry',ro',r') = (opts^.rx, opts^.ry, opts^.ro, opts^.r)- in clampDiag ro' . clampAdj h ry' . clampAdj w rx' $ r'- -- prevent curves of adjacent corners from overlapping- clampAdj len adj r = if abs r > len/2- then sign r * max (len/2) (min (len - abs adj) (abs r))- else r- -- prevent inward curves of diagonally opposite corners from intersecting- clampDiag opp r = if r < 0 && opp < 0 && abs r > diag / 2- then sign r * max (diag / 2) (min (abs r) (diag + opp))- else r- sign n = if n < 0 then -1 else 1- mkCorner k r | r == 0 = mempty- | r < 0 = doArc 3 (-1)- | otherwise = doArc 0 1- where- doArc d s =- arc' r (xDir & _theta <>~ ((k+d)/4 @@ turn)) (s/4 @@ turn)+roundedRect' w h opts =+ trailLike+ . (`at` p2 (w / 2, abs rBR - h / 2))+ . wrapTrail+ . glueLine+ $ seg (0, h - abs rTR - abs rBR)+ <> mkCorner 0 rTR+ <> seg (abs rTR + abs rTL - w, 0)+ <> mkCorner 1 rTL+ <> seg (0, abs rTL + abs rBL - h)+ <> mkCorner 2 rBL+ <> seg (w - abs rBL - abs rBR, 0)+ <> mkCorner 3 rBR+ where+ seg = lineFromOffsets . (: []) . r2+ diag = sqrt (w * w + h * h)+ -- to clamp corner radius, need to compare with other corners that share an+ -- edge. If the corners overlap then reduce the largest corner first, as far+ -- as 50% of the edge in question.+ rTL = clampCnr radiusTR radiusBL radiusBR radiusTL+ rBL = clampCnr radiusBR radiusTL radiusTR radiusBL+ rTR = clampCnr radiusTL radiusBR radiusBL radiusTR+ rBR = clampCnr radiusBL radiusTR radiusTL radiusBR+ clampCnr rx ry ro r =+ let (rx', ry', ro', r') = (opts ^. rx, opts ^. ry, opts ^. ro, opts ^. r)+ in clampDiag ro' . clampAdj h ry' . clampAdj w rx' $ r'+ -- prevent curves of adjacent corners from overlapping+ clampAdj len adj r =+ if abs r > len / 2+ then sign r * max (len / 2) (min (len - abs adj) (abs r))+ else r+ -- prevent inward curves of diagonally opposite corners from intersecting+ clampDiag opp r =+ if r < 0 && opp < 0 && abs r > diag / 2+ then sign r * max (diag / 2) (min (abs r) (diag + opp))+ else r+ sign n = if n < 0 then -1 else 1+ mkCorner k r+ | r == 0 = mempty+ | r < 0 = doArc 3 (-1)+ | otherwise = doArc 0 1+ where+ doArc d s =+ arc' r (xDir & _theta <>~ ((k + d) / 4 @@ turn)) (s / 4 @@ turn)
src/Diagrams/TwoD/Size.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}
src/Diagrams/TwoD/Text.hs view
@@ -1,13 +1,16 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module : Diagrams.TwoD.Text -- Copyright : (c) 2011-2015 diagrams-lib team (see LICENSE)@@ -15,48 +18,80 @@ -- Maintainer : diagrams-discuss@googlegroups.com -- -- Very basic text primitives along with associated attributes.---------------------------------------------------------------------------------- module Diagrams.TwoD.Text ( -- * Creating text diagrams- Text(..), TextAlignment(..)- , text, topLeftText, alignedText, baselineText, mkText+ Text (..),+ TextAlignment (..),+ text,+ topLeftText,+ alignedText,+ baselineText,+ mkText,+ mkText', -- * Text attributes+ -- ** Font family- , Font(..), _Font- , getFont, font, _font+ Font (..),+ _Font,+ getFont,+ font,+ _font,+ -- ** Font size- , FontSize(..), _FontSize- , getFontSize, fontSizeM, fontSize- , fontSizeN, fontSizeO, fontSizeL, fontSizeG- , _fontSizeR, _fontSize, _fontSizeU+ FontSize (..),+ _FontSize,+ fontSize,+ recommendFontSize,+ fontSizeN,+ fontSizeO,+ fontSizeL,+ fontSizeG,+ getFontSize,+ fontSizeM,+ _fontSizeR,+ _fontSize,+ _fontSizeU,+ -- ** Font slant- , FontSlant(..)- , getFontSlant, fontSlant, italic, oblique, _fontSlant+ FontSlant (..),+ getFontSlant,+ fontSlant,+ italic,+ oblique,+ _fontSlant,+ -- ** Font weight- , FontWeight(..)- , getFontWeight, fontWeight, bold, _fontWeight- ) where+ 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 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.Colour hiding (over)-import Data.Default.Class-#if __GLASGOW_HASKELL__ < 710-import Data.Functor-#endif-import Data.Monoid.Recommend-import Data.Semigroup-import Data.Typeable+import Data.Colour hiding (over)+import Data.Default+import Data.Monoid.Recommend+import Data.Semigroup+import Data.Typeable -import Linear.Affine+import Linear.Affine ------------------------------------------------------------ -- Text diagrams@@ -70,14 +105,14 @@ -- 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 n) = V2 type instance N (Text n) = n 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)+ where+ t' = scaling (1 / avgScale t) instance Floating n => HasOrigin (Text n) where moveOriginTo p = translate (origin .-. p)@@ -88,19 +123,31 @@ -- | @TextAlignment@ specifies the alignment of the text's origin. data TextAlignment n = BaselineText | BoxAlignedText n n --- | Make a text from a 'TextAlignment'.-mkText :: (TypeableFloat n, Renderable (Text n) b)- => TextAlignment n -> String -> QDiagram b V2 n Any-mkText a t = recommendFillColor black- -- See Note [recommendFillColor]- . recommendFontSize (local 1)- -- See Note [recommendFontSize]+-- | 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 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] @@ -116,17 +163,20 @@ -- must therefore explicitly set the fill to transparent -- but this -- meant that it was also drawing text with a transparent fill. The -- solution is that we now explicitly inform all backends that the--- *default* ("recommended") fill color for text should be black; an++-- * default* ("recommended") fill color for text should be black; an+ -- absence of fill specification now consistently means to use a -- "transparent" fill no matter what the primitive. The reason we -- need the special recommend/commit distinction is because if the -- user explicitly sets a fill color later it should override this -- recommendation; normally, the innermost occurrence of an attribute -- would override all outer occurrences.------ The reason we "recommend" a fill color of black instead of setting--- it directly (or instead of simply not specifying a fill color at +-- ~~~~ 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@. --@@ -153,8 +203,9 @@ -- and descent, rather than the height of the particular string. -- -- Note that it /takes up no space/.-alignedText :: (TypeableFloat n, Renderable (Text n) b)- => n -> n -> String -> QDiagram b V2 n Any+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@@ -163,8 +214,9 @@ -- graphics library. -- -- Note that it /takes up no space/.-baselineText :: (TypeableFloat n, Renderable (Text n) b)- => String -> QDiagram b V2 n Any+baselineText ::+ (TypeableFloat n, Renderable (Text n) b) =>+ String -> QDiagram b V2 n Any baselineText = mkText BaselineText ------------------------------------------------------------@@ -177,7 +229,7 @@ -- | The @Font@ attribute specifies the name of a font family. Inner -- @Font@ attributes override outer ones. newtype Font = Font (Last String)- deriving (Typeable, Semigroup, Eq)+ deriving (Semigroup, Eq) _Font :: Iso' Font String _Font = iso getFont (Font . Last)@@ -202,22 +254,24 @@ -- | The @FontSize@ attribute specifies the size of a font's -- em-square. Inner @FontSize@ attributes override outer ones. newtype FontSize n = FontSize (Recommend (Last n))- deriving (Typeable, Semigroup)+ deriving (Semigroup) -- 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)))+ fmap f (FontSize (Commit (Last a))) = FontSize (Commit (Last (f a))) _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+ 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+ _FontSizeM :: Iso' (FontSizeM n) (Measured n (Recommend n)) _FontSizeM = mapping _FontSize @@ -231,14 +285,21 @@ -- | Extract the size from a @FontSize@ attribute. getFontSize :: FontSize n -> n getFontSize (FontSize (Recommend (Last s))) = s-getFontSize (FontSize (Commit (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@.+-- 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 :: (N a ~ n, Typeable n, Num n, HasStyle a) => n -> a -> a fontSizeG = fontSize . global@@ -259,9 +320,6 @@ fontSizeM :: (N a ~ n, Typeable n, HasStyle a) => FontSizeM n -> a -> a fontSizeM = applyMAttr -recommendFontSize :: (N a ~ n, Typeable n, HasStyle a) => Measure n -> a -> a-recommendFontSize = applyMAttr . fmap (FontSize . Recommend . Last)- _fontSizeR :: (Typeable n, OrderedField n) => Lens' (Style v n) (Measured n (Recommend n)) _fontSizeR = atMAttr . anon def (const False) . _FontSizeM @@ -270,7 +328,7 @@ _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 :: Typeable n => Lens' (Style v n) (Maybe n) _fontSizeU = atAttr . mapping (_FontSize . committed) --------------------------------------------------@@ -279,12 +337,13 @@ -- | 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, Show, Typeable, Ord)+data FontSlant+ = FontSlantNormal+ | FontSlantItalic+ | FontSlantOblique+ deriving (Eq, Show, Ord) -instance AttributeClass FontSlant where+instance AttributeClass FontSlant instance Semigroup FontSlant where _ <> b = b @@ -319,9 +378,19 @@ -- | 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.-data FontWeight = FontWeightNormal- | FontWeightBold- deriving (Eq, Ord, Show, Typeable)+data FontWeight+ = FontWeightNormal+ | FontWeightBold+ | FontWeightBolder+ | FontWeightLighter+ | FontWeightThin+ | FontWeightUltraLight+ | FontWeightLight+ | FontWeightMedium+ | FontWeightSemiBold+ | FontWeightUltraBold+ | FontWeightHeavy+ deriving (Eq, Ord, Show) instance AttributeClass FontWeight @@ -336,7 +405,7 @@ getFontWeight :: FontWeight -> FontWeight getFontWeight = id --- | Specify the weight (normal or bold) that should be+-- | 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@@ -345,6 +414,42 @@ -- | 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
src/Diagrams/TwoD/Transform.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -5,6 +6,10 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ -- for Data.Semigroup+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.TwoD.Transform@@ -23,7 +28,6 @@ T2 -- * Rotation , rotation, rotate, rotateBy, rotated- , rotationAround, rotateAround , rotationTo, rotateTo @@ -40,9 +44,13 @@ , translationY, translateY , translation, translate + -- * Conformal affine maps+ , scalingRotationTo, scaleRotateTo+ -- * Reflection , reflectionX, reflectX , reflectionY, reflectY+ , reflectionXY, reflectXY , reflectionAbout, reflectAbout -- * Shears@@ -56,41 +64,21 @@ import Diagrams.Core.Transform import Diagrams.Direction import Diagrams.Transform+import Diagrams.Transform.Matrix import Diagrams.TwoD.Types import Diagrams.TwoD.Vector -import Control.Lens hiding (at, transform)+import Control.Lens hiding (at, transform) import Data.Semigroup import Linear.Affine+import Linear.Metric+import Linear.V2 import Linear.Vector -- Rotation ------------------------------------------------ --- | Create a transformation which performs a rotation about the local--- origin by the given angle. See also 'rotate'.-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 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+-- 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@@ -110,7 +98,7 @@ -- @ rotated :: (InSpace V2 n a, Floating n, SameSpace a b, Transformable a, Transformable b) => Angle n -> Iso a b a b-rotated = transformed . rotation+rotated a = transformed $ rotation a -- | @rotationAbout p@ is a rotation about the point @p@ (instead of -- around the local origin).@@ -205,6 +193,29 @@ => 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@@ -227,13 +238,25 @@ reflectY :: (InSpace v n t, R2 v, Transformable t) => t -> t reflectY = transform reflectionY +-- | 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 d <> translation (origin .-. p))+ conjugate (rotationTo (reflectY d) <> translation (origin .-. p)) reflectionY +++ -- | @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)@@ -280,4 +303,3 @@ -- @(1,0)@ to @(1,d)@. shearY :: (InSpace V2 n t, Transformable t) => n -> t -> t shearY = transform . shearingY-
src/Diagrams/TwoD/Vector.hs view
@@ -79,8 +79,14 @@ 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,3 +1,5 @@+{-# LANGUAGE CPP #-}+ ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Util@@ -39,9 +41,8 @@ import Control.Monad.Catch import Control.Monad.Trans import Control.Monad.Trans.Maybe-import Data.Default.Class+import Data.Default import Data.List-import Data.List.Lens import Data.Maybe import Data.Monoid import System.Directory@@ -202,7 +203,7 @@ findSandbox paths = runMaybeT $ pathsTest <|> diaSB <|> envDB <|> wdConfig where -- first path in environment- lookEnv = MaybeT . (fmap . fmap) (head . splitSearchPath) . lookupEnv+ lookEnv = MaybeT . fmap ((listToMaybe . 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@@ -237,9 +238,13 @@ 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).
+ 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/Diagrams/TwoD/OffsetTest.hs
@@ -1,48 +0,0 @@-module Diagrams.TwoD.OffsetTest- (- 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/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
@@ -1,10 +1,26 @@-import Test.Tasty (defaultMain, testGroup, TestTree)+import Test.Tasty (TestTree, defaultMain, testGroup) -import qualified Diagrams.TwoD.OffsetTest as TwoD.OffsetTest+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.OffsetTest.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