From 6f9e1680085e7bb4d258f6f8116369d122e196e1 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 16 Jan 2023 03:03:27 +0000 Subject: CTAN sync 202301160303 --- .../base/tex/generic/basiclayer/pgfcore.code.tex | 41 + .../tex/generic/basiclayer/pgfcorearrows.code.tex | 1253 +++++ .../generic/basiclayer/pgfcoreexternal.code.tex | 542 ++ .../basiclayer/pgfcoregraphicstate.code.tex | 280 + .../tex/generic/basiclayer/pgfcoreimage.code.tex | 242 + .../tex/generic/basiclayer/pgfcorelayers.code.tex | 210 + .../tex/generic/basiclayer/pgfcoreobjects.code.tex | 101 + .../basiclayer/pgfcorepathconstruct.code.tex | 1477 ++++++ .../basiclayer/pgfcorepathprocessing.code.tex | 563 ++ .../generic/basiclayer/pgfcorepathusage.code.tex | 661 +++ .../generic/basiclayer/pgfcorepatterns.code.tex | 301 ++ .../tex/generic/basiclayer/pgfcorepoints.code.tex | 1212 +++++ .../tex/generic/basiclayer/pgfcorequick.code.tex | 134 + .../tex/generic/basiclayer/pgfcorerdf.code.tex | 228 + .../tex/generic/basiclayer/pgfcorescopes.code.tex | 771 +++ .../tex/generic/basiclayer/pgfcoreshade.code.tex | 974 ++++ .../basiclayer/pgfcoretransformations.code.tex | 819 +++ .../basiclayer/pgfcoretransparency.code.tex | 312 ++ .../circuits/tikzlibrarycircuits.code.tex | 264 + .../circuits/tikzlibrarycircuits.ee.IEC.code.tex | 442 ++ .../circuits/tikzlibrarycircuits.ee.code.tex | 148 + .../tikzlibrarycircuits.logic.CDH.code.tex | 28 + .../tikzlibrarycircuits.logic.IEC.code.tex | 75 + .../circuits/tikzlibrarycircuits.logic.US.code.tex | 64 + .../circuits/tikzlibrarycircuits.logic.code.tex | 45 + .../tikzlibrarydatavisualization.3d.code.tex | 79 + ...tikzlibrarydatavisualization.barcharts.code.tex | 43 + .../tikzlibrarydatavisualization.code.tex | 2733 ++++++++++ ...arydatavisualization.formats.functions.code.tex | 16 + .../tikzlibrarydatavisualization.polar.code.tex | 565 ++ ...ikzlibrarydatavisualization.sparklines.code.tex | 37 + .../libraries/graphs/tikzlibrarygraphs.code.tex | 2674 ++++++++++ .../graphs/tikzlibrarygraphs.standard.code.tex | 109 + .../tikz/libraries/tikzexternalshared.code.tex | 1714 ++++++ .../tikz/libraries/tikzlibrary3d.code.tex | 108 + .../tikz/libraries/tikzlibraryangles.code.tex | 100 + .../tikz/libraries/tikzlibraryanimations.code.tex | 904 ++++ .../tikz/libraries/tikzlibraryarrows.code.tex | 14 + .../tikz/libraries/tikzlibraryautomata.code.tex | 105 + .../tikz/libraries/tikzlibrarybabel.code.tex | 17 + .../tikz/libraries/tikzlibrarybackgrounds.code.tex | 148 + .../tikz/libraries/tikzlibrarybending.code.tex | 15 + .../tikz/libraries/tikzlibrarycalc.code.tex | 618 +++ .../tikz/libraries/tikzlibrarycalendar.code.tex | 444 ++ .../tikz/libraries/tikzlibrarychains.code.tex | 214 + .../tikz/libraries/tikzlibrarydecorations.code.tex | 194 + .../tikzlibrarydecorations.footprints.code.tex | 13 + .../tikzlibrarydecorations.fractals.code.tex | 13 + .../tikzlibrarydecorations.markings.code.tex | 31 + .../tikzlibrarydecorations.pathmorphing.code.tex | 13 + .../tikzlibrarydecorations.pathreplacing.code.tex | 36 + .../tikzlibrarydecorations.shapes.code.tex | 13 + .../libraries/tikzlibrarydecorations.text.code.tex | 704 +++ .../tikz/libraries/tikzlibraryer.code.tex | 40 + .../tikz/libraries/tikzlibraryfadings.code.tex | 48 + .../tikz/libraries/tikzlibraryfit.code.tex | 132 + .../tikzlibraryfixedpointarithmetic.code.tex | 10 + .../tikz/libraries/tikzlibraryfolding.code.tex | 2444 +++++++++ .../tikz/libraries/tikzlibraryfpu.code.tex | 10 + .../libraries/tikzlibraryintersections.code.tex | 148 + .../tikzlibrarylindenmayersystems.code.tex | 81 + .../tikz/libraries/tikzlibrarymath.code.tex | 731 +++ .../tikz/libraries/tikzlibrarymatrix.code.tex | 144 + .../tikz/libraries/tikzlibrarymindmap.code.tex | 417 ++ .../tikz/libraries/tikzlibrarypatterns.code.tex | 31 + .../libraries/tikzlibrarypatterns.meta.code.tex | 98 + .../tikz/libraries/tikzlibraryperspective.code.tex | 111 + .../tikz/libraries/tikzlibrarypetri.code.tex | 146 + .../libraries/tikzlibraryplothandlers.code.tex | 14 + .../tikz/libraries/tikzlibraryplotmarks.code.tex | 14 + .../tikz/libraries/tikzlibrarypositioning.code.tex | 118 + .../tikz/libraries/tikzlibraryquotes.code.tex | 90 + .../tikz/libraries/tikzlibraryrdf.code.tex | 291 + .../tikz/libraries/tikzlibraryscopes.code.tex | 42 + .../tikz/libraries/tikzlibraryshadings.code.tex | 21 + .../tikz/libraries/tikzlibraryshadows.code.tex | 146 + .../libraries/tikzlibraryshapes.arrows.code.tex | 16 + .../libraries/tikzlibraryshapes.callouts.code.tex | 35 + .../tikz/libraries/tikzlibraryshapes.code.tex | 19 + .../tikzlibraryshapes.gates.logic.IEC.code.tex | 38 + .../tikzlibraryshapes.gates.logic.US.code.tex | 40 + .../libraries/tikzlibraryshapes.geometric.code.tex | 14 + .../tikz/libraries/tikzlibraryshapes.misc.code.tex | 14 + .../libraries/tikzlibraryshapes.multipart.code.tex | 36 + .../libraries/tikzlibraryshapes.symbols.code.tex | 17 + .../tikz/libraries/tikzlibrarysnakes.code.tex | 77 + .../tikz/libraries/tikzlibraryspy.code.tex | 134 + .../tikz/libraries/tikzlibrarysvg.path.code.tex | 33 + .../tikz/libraries/tikzlibrarythrough.code.tex | 36 + .../tikz/libraries/tikzlibrarytopaths.code.tex | 381 ++ .../tikz/libraries/tikzlibrarytrees.code.tex | 109 + .../tikz/libraries/tikzlibraryturtle.code.tex | 84 + .../tikz/libraries/tikzlibraryviews.code.tex | 45 + .../tex/generic/frontendlayer/tikz/tikz.code.tex | 5599 ++++++++++++++++++++ .../tex/generic/graphdrawing/lua/LUA_CODING_STYLE | 27 + .../pgf/base/tex/generic/graphdrawing/lua/pgf.lua | 72 + .../base/tex/generic/graphdrawing/lua/pgf/gd.lua | 72 + .../generic/graphdrawing/lua/pgf/gd/bindings.lua | 26 + .../graphdrawing/lua/pgf/gd/bindings/Binding.lua | 265 + .../lua/pgf/gd/bindings/BindingToPGF.lua | 374 ++ .../generic/graphdrawing/lua/pgf/gd/circular.lua | 22 + .../lua/pgf/gd/circular/Tantau2012.lua | 153 + .../graphdrawing/lua/pgf/gd/circular/doc.lua | 145 + .../graphdrawing/lua/pgf/gd/circular/library.lua | 30 + .../generic/graphdrawing/lua/pgf/gd/control.lua | 26 + .../graphdrawing/lua/pgf/gd/control/Anchoring.lua | 104 + .../lua/pgf/gd/control/ComponentAlign.lua | 540 ++ .../lua/pgf/gd/control/ComponentDirection.lua | 58 + .../lua/pgf/gd/control/ComponentDistance.lua | 108 + .../lua/pgf/gd/control/ComponentOrder.lua | 105 + .../graphdrawing/lua/pgf/gd/control/Components.lua | 127 + .../graphdrawing/lua/pgf/gd/control/Distances.lua | 454 ++ .../graphdrawing/lua/pgf/gd/control/FineTune.lua | 164 + .../lua/pgf/gd/control/LayoutPipeline.lua | 1347 +++++ .../lua/pgf/gd/control/NodeAnchors.lua | 175 + .../lua/pgf/gd/control/Orientation.lua | 303 ++ .../graphdrawing/lua/pgf/gd/control/Sublayouts.lua | 536 ++ .../graphdrawing/lua/pgf/gd/control/doc.lua | 245 + .../graphdrawing/lua/pgf/gd/control/library.lua | 196 + .../graphdrawing/lua/pgf/gd/deprecated/Cluster.lua | 65 + .../graphdrawing/lua/pgf/gd/deprecated/Edge.lua | 358 ++ .../graphdrawing/lua/pgf/gd/deprecated/Graph.lua | 396 ++ .../lua/pgf/gd/deprecated/Iterators.lua | 91 + .../graphdrawing/lua/pgf/gd/deprecated/Node.lua | 280 + .../graphdrawing/lua/pgf/gd/deprecated/Vector.lua | 256 + .../tex/generic/graphdrawing/lua/pgf/gd/doc.lua | 124 + .../lua/pgf/gd/doc/ogdf/energybased.lua | 19 + .../lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua | 129 + .../doc/ogdf/energybased/FastMultipoleEmbedder.lua | 51 + .../lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua | 103 + .../gd/doc/ogdf/energybased/MultilevelLayout.lua | 33 + .../gd/doc/ogdf/energybased/SpringEmbedderFR.lua | 53 + .../doc/ogdf/energybased/SpringEmbedderFRExact.lua | 57 + .../gd/doc/ogdf/energybased/SpringEmbedderKK.lua | 62 + .../multilevelmixer/BarycenterPlacer.lua | 33 + .../energybased/multilevelmixer/CirclePlacer.lua | 45 + .../multilevelmixer/EdgeCoverMerger.lua | 33 + .../multilevelmixer/IndependentSetMerger.lua | 33 + .../multilevelmixer/LocalBiconnectedMerger.lua | 33 + .../energybased/multilevelmixer/MatchingMerger.lua | 33 + .../energybased/multilevelmixer/MedianPlacer.lua | 27 + .../energybased/multilevelmixer/RandomMerger.lua | 33 + .../energybased/multilevelmixer/RandomPlacer.lua | 33 + .../energybased/multilevelmixer/SolarMerger.lua | 39 + .../energybased/multilevelmixer/SolarPlacer.lua | 27 + .../energybased/multilevelmixer/ZeroPlacer.lua | 33 + .../graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua | 19 + .../gd/doc/ogdf/layered/BarycenterHeuristic.lua | 23 + .../gd/doc/ogdf/layered/CoffmanGrahamRanking.lua | 35 + .../pgf/gd/doc/ogdf/layered/DfsAcyclicSubgraph.lua | 27 + .../gd/doc/ogdf/layered/FastHierarchyLayout.lua | 99 + .../doc/ogdf/layered/FastSimpleHierarchyLayout.lua | 99 + .../pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua | 27 + .../gd/doc/ogdf/layered/GreedyInsertHeuristic.lua | 23 + .../pgf/gd/doc/ogdf/layered/LongestPathRanking.lua | 57 + .../pgf/gd/doc/ogdf/layered/MedianHeuristic.lua | 24 + .../lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua | 35 + .../pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua | 34 + .../lua/pgf/gd/doc/ogdf/layered/SplitHeuristic.lua | 24 + .../lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua | 113 + .../lua/pgf/gd/doc/ogdf/misclayout.lua | 19 + .../pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua | 48 + .../pgf/gd/doc/ogdf/misclayout/CircularLayout.lua | 95 + .../gd/doc/ogdf/module/AcyclicSubgraphModule.lua | 18 + .../gd/doc/ogdf/module/HierarchyLayoutModule.lua | 17 + .../lua/pgf/gd/doc/ogdf/module/InitialPlacer.lua | 17 + .../pgf/gd/doc/ogdf/module/MultilevelBuilder.lua | 17 + .../lua/pgf/gd/doc/ogdf/module/RankingModule.lua | 17 + .../pgf/gd/doc/ogdf/module/TwoLayerCrossMin.lua | 17 + .../graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua | 19 + .../gd/doc/ogdf/planarity/PlanarizationLayout.lua | 66 + .../generic/graphdrawing/lua/pgf/gd/examples.lua | 26 + .../lua/pgf/gd/examples/ASCIIDisplayer.lua | 32 + .../lua/pgf/gd/examples/BindingToASCII.lua | 87 + .../lua/pgf/gd/examples/SimpleDemo.lua | 82 + .../lua/pgf/gd/examples/SimpleEdgeDemo.lua | 144 + .../lua/pgf/gd/examples/SimpleHuffman.lua | 287 + .../examples/example_graph_for_ascii_displayer.txt | 20 + .../graphdrawing/lua/pgf/gd/examples/library.lua | 30 + .../evolving/GraphAnimationCoordination.lua | 638 +++ .../evolving/GreedyTemporalCycleRemoval.lua | 177 + .../pgf/gd/experimental/evolving/Skambath2016.lua | 875 +++ .../pgf/gd/experimental/evolving/Supergraph.lua | 571 ++ .../evolving/SupergraphVertexSplitOptimization.lua | 196 + .../lua/pgf/gd/experimental/evolving/TimeSpec.lua | 62 + .../lua/pgf/gd/experimental/evolving/doc.lua | 120 + .../lua/pgf/gd/experimental/evolving/layered.lua | 107 + .../lua/pgf/gd/experimental/evolving/library.lua | 33 + .../tex/generic/graphdrawing/lua/pgf/gd/force.lua | 26 + .../graphdrawing/lua/pgf/gd/force/CoarseGraph.lua | 435 ++ .../lua/pgf/gd/force/ControlCoarsening.lua | 148 + .../lua/pgf/gd/force/ControlDeclare.lua | 41 + .../lua/pgf/gd/force/ControlElectric.lua | 105 + .../lua/pgf/gd/force/ControlIteration.lua | 136 + .../lua/pgf/gd/force/ControlSprings.lua | 59 + .../graphdrawing/lua/pgf/gd/force/ControlStart.lua | 41 + .../graphdrawing/lua/pgf/gd/force/QuadTree.lua | 280 + .../lua/pgf/gd/force/SpringElectricalHu2006.lua | 633 +++ .../lua/pgf/gd/force/SpringElectricalLayouts.lua | 54 + .../pgf/gd/force/SpringElectricalWalshaw2000.lua | 520 ++ .../graphdrawing/lua/pgf/gd/force/SpringHu2006.lua | 386 ++ .../lua/pgf/gd/force/SpringLayouts.lua | 36 + .../force/jedi/algorithms/FruchtermanReingold.lua | 124 + .../force/jedi/algorithms/HuSpringElectricalFW.lua | 95 + .../pgf/gd/force/jedi/algorithms/SimpleSpring.lua | 74 + .../jedi/algorithms/SocialGravityCloseness.lua | 129 + .../force/jedi/algorithms/SocialGravityDegree.lua | 183 + .../lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua | 264 + .../lua/pgf/gd/force/jedi/base/ForceController.lua | 489 ++ .../lua/pgf/gd/force/jedi/base/ForceTemplate.lua | 44 + .../lua/pgf/gd/force/jedi/base/InitialTemplate.lua | 64 + .../lua/pgf/gd/force/jedi/base/PathLengthsFW.lua | 174 + .../lua/pgf/gd/force/jedi/base/Preprocessing.lua | 122 + .../graphdrawing/lua/pgf/gd/force/jedi/doc.lua | 377 ++ .../force/jedi/forcetypes/ForceAbsoluteValue.lua | 94 + .../force/jedi/forcetypes/ForceCanvasDistance.lua | 201 + .../force/jedi/forcetypes/ForceCanvasPosition.lua | 117 + .../force/jedi/forcetypes/ForceGraphDistance.lua | 205 + .../gd/force/jedi/forcetypes/ForcePullToGrid.lua | 123 + .../gd/force/jedi/forcetypes/ForcePullToPoint.lua | 119 + .../CircularInitialPositioning.lua | 60 + .../initialpositioning/GridInitialPositioning.lua | 60 + .../RandomInitialPositioning.lua | 49 + .../graphdrawing/lua/pgf/gd/force/jedi/library.lua | 115 + .../graphdrawing/lua/pgf/gd/force/library.lua | 126 + .../generic/graphdrawing/lua/pgf/gd/interface.lua | 26 + .../lua/pgf/gd/interface/InterfaceCore.lua | 191 + .../lua/pgf/gd/interface/InterfaceToAlgorithms.lua | 968 ++++ .../lua/pgf/gd/interface/InterfaceToC.lua | 78 + .../lua/pgf/gd/interface/InterfaceToDisplay.lua | 1002 ++++ .../graphdrawing/lua/pgf/gd/interface/Scope.lua | 92 + .../generic/graphdrawing/lua/pgf/gd/layered.lua | 159 + .../layered/CrossingMinimizationGansnerKNV1993.lua | 342 ++ .../pgf/gd/layered/CycleRemovalBergerS1990a.lua | 74 + .../pgf/gd/layered/CycleRemovalBergerS1990b.lua | 76 + .../lua/pgf/gd/layered/CycleRemovalEadesLS1993.lua | 124 + .../pgf/gd/layered/CycleRemovalGansnerKNV1993.lua | 52 + .../pgf/gd/layered/EdgeRoutingGansnerKNV1993.lua | 22 + .../lua/pgf/gd/layered/NetworkSimplex.lua | 898 ++++ .../gd/layered/NodePositioningGansnerKNV1993.lua | 154 + .../pgf/gd/layered/NodeRankingGansnerKNV1993.lua | 159 + .../pgf/gd/layered/NodeRankingMinimumHeight.lua | 47 + .../graphdrawing/lua/pgf/gd/layered/Ranking.lua | 291 + .../graphdrawing/lua/pgf/gd/layered/Sugiyama.lua | 476 ++ .../lua/pgf/gd/layered/crossing_minimization.lua | 81 + .../lua/pgf/gd/layered/cycle_removal.lua | 136 + .../lua/pgf/gd/layered/edge_routing.lua | 49 + .../graphdrawing/lua/pgf/gd/layered/library.lua | 94 + .../lua/pgf/gd/layered/node_positioning.lua | 55 + .../lua/pgf/gd/layered/node_ranking.lua | 72 + .../tex/generic/graphdrawing/lua/pgf/gd/lib.lua | 435 ++ .../generic/graphdrawing/lua/pgf/gd/lib/Bezier.lua | 160 + .../lua/pgf/gd/lib/DepthFirstSearch.lua | 125 + .../generic/graphdrawing/lua/pgf/gd/lib/Direct.lua | 95 + .../generic/graphdrawing/lua/pgf/gd/lib/Event.lua | 98 + .../graphdrawing/lua/pgf/gd/lib/LookupTable.lua | 111 + .../graphdrawing/lua/pgf/gd/lib/PathLengths.lua | 209 + .../graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua | 342 ++ .../graphdrawing/lua/pgf/gd/lib/Simplifiers.lua | 279 + .../generic/graphdrawing/lua/pgf/gd/lib/Stack.lua | 61 + .../graphdrawing/lua/pgf/gd/lib/Storage.lua | 110 + .../graphdrawing/lua/pgf/gd/lib/Transform.lua | 120 + .../tex/generic/graphdrawing/lua/pgf/gd/model.lua | 26 + .../generic/graphdrawing/lua/pgf/gd/model/Arc.lua | 653 +++ .../graphdrawing/lua/pgf/gd/model/Collection.lua | 208 + .../graphdrawing/lua/pgf/gd/model/Coordinate.lua | 306 ++ .../graphdrawing/lua/pgf/gd/model/Digraph.lua | 849 +++ .../generic/graphdrawing/lua/pgf/gd/model/Edge.lua | 209 + .../graphdrawing/lua/pgf/gd/model/Hyperedge.lua | 56 + .../generic/graphdrawing/lua/pgf/gd/model/Path.lua | 1278 +++++ .../graphdrawing/lua/pgf/gd/model/Path_arced.lua | 316 ++ .../graphdrawing/lua/pgf/gd/model/Vertex.lua | 296 ++ .../graphdrawing/lua/pgf/gd/model/library.lua | 15 + .../tex/generic/graphdrawing/lua/pgf/gd/ogdf.lua | 26 + .../graphdrawing/lua/pgf/gd/ogdf/library.lua | 33 + .../generic/graphdrawing/lua/pgf/gd/pedigrees.lua | 21 + .../lua/pgf/gd/pedigrees/Koerner2015.lua | 163 + .../graphdrawing/lua/pgf/gd/pedigrees/library.lua | 21 + .../graphdrawing/lua/pgf/gd/phylogenetics.lua | 21 + .../gd/phylogenetics/AuthorDefinedPhylogeny.lua | 77 + .../gd/phylogenetics/BalancedMinimumEvolution.lua | 593 +++ .../BalancedNearestNeighbourInterchange.lua | 372 ++ .../lua/pgf/gd/phylogenetics/DistanceMatrix.lua | 451 ++ .../lua/pgf/gd/phylogenetics/Maeusle2012.lua | 778 +++ .../lua/pgf/gd/phylogenetics/PhylogeneticTree.lua | 91 + .../lua/pgf/gd/phylogenetics/SokalMichener1958.lua | 261 + .../lua/pgf/gd/phylogenetics/library.lua | 35 + .../tex/generic/graphdrawing/lua/pgf/gd/planar.lua | 6 + .../lua/pgf/gd/planar/BoyerMyrvold2004.lua | 678 +++ .../graphdrawing/lua/pgf/gd/planar/Embedding.lua | 788 +++ .../graphdrawing/lua/pgf/gd/planar/LinkedList.lua | 88 + .../graphdrawing/lua/pgf/gd/planar/List.lua | 49 + .../generic/graphdrawing/lua/pgf/gd/planar/PDP.lua | 576 ++ .../lua/pgf/gd/planar/PlanarLayout.lua | 159 + .../graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua | 128 + .../graphdrawing/lua/pgf/gd/planar/library.lua | 2 + .../graphdrawing/lua/pgf/gd/planar/parameters.lua | 144 + .../generic/graphdrawing/lua/pgf/gd/routing.lua | 22 + .../graphdrawing/lua/pgf/gd/routing/Hints.lua | 100 + .../lua/pgf/gd/routing/NecklaceRouting.lua | 90 + .../graphdrawing/lua/pgf/gd/routing/library.lua | 29 + .../graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua | 183 + .../tex/generic/graphdrawing/lua/pgf/gd/trees.lua | 21 + .../graphdrawing/lua/pgf/gd/trees/ChildSpec.lua | 226 + .../lua/pgf/gd/trees/ReingoldTilford1981.lua | 211 + .../lua/pgf/gd/trees/SpanningTreeComputation.lua | 646 +++ .../generic/graphdrawing/lua/pgf/gd/trees/doc.lua | 340 ++ .../graphdrawing/lua/pgf/gd/trees/library.lua | 35 + .../tikzlibrarygraphdrawing.evolving.code.tex | 21 + .../tex/pgflibrarygraphdrawing.circular.code.tex | 16 + .../tex/pgflibrarygraphdrawing.code.tex | 1165 ++++ .../tex/pgflibrarygraphdrawing.examples.code.tex | 17 + .../tex/pgflibrarygraphdrawing.force.code.tex | 136 + .../tex/pgflibrarygraphdrawing.layered.code.tex | 17 + .../tex/pgflibrarygraphdrawing.trees.code.tex | 19 + .../tex/tikzlibrarygraphdrawing.code.tex | 262 + .../pgflibrarydatavisualization.barcharts.code.tex | 135 + ...arydatavisualization.formats.functions.code.tex | 209 + .../pgflibrarydatavisualization.polar.code.tex | 198 + .../pgflibrarydecorations.footprints.code.tex | 230 + .../pgflibrarydecorations.fractals.code.tex | 65 + .../pgflibrarydecorations.markings.code.tex | 179 + .../pgflibrarydecorations.pathmorphing.code.tex | 294 + .../pgflibrarydecorations.pathreplacing.code.tex | 240 + .../pgflibrarydecorations.shapes.code.tex | 468 ++ .../pgflibrarydecorations.text.code.tex | 357 ++ .../libraries/luamath/pgf/luamath/functions.lua | 626 +++ .../libraries/luamath/pgf/luamath/parser.lua | 481 ++ .../libraries/luamath/pgflibraryluamath.code.tex | 558 ++ .../generic/libraries/pgflibraryarrows.code.tex | 936 ++++ .../libraries/pgflibraryarrows.meta.code.tex | 1607 ++++++ .../libraries/pgflibraryarrows.spaced.code.tex | 92 + .../libraries/pgflibrarycurvilinear.code.tex | 379 ++ .../generic/libraries/pgflibraryfadings.code.tex | 57 + .../pgflibraryfixedpointarithmetic.code.tex | 656 +++ .../tex/generic/libraries/pgflibraryfpu.code.tex | 2392 +++++++++ .../libraries/pgflibraryintersections.code.tex | 1172 ++++ .../pgflibrarylindenmayersystems.code.tex | 229 + .../generic/libraries/pgflibrarypatterns.code.tex | 264 + .../libraries/pgflibrarypatterns.meta.code.tex | 458 ++ .../libraries/pgflibraryplothandlers.code.tex | 1114 ++++ .../generic/libraries/pgflibraryplotmarks.code.tex | 453 ++ .../generic/libraries/pgflibraryprofiler.code.tex | 530 ++ .../generic/libraries/pgflibraryshadings.code.tex | 444 ++ .../generic/libraries/pgflibrarysnakes.code.tex | 16 + .../generic/libraries/pgflibrarysvg.path.code.tex | 829 +++ .../generic/libraries/pgflibrarytimelines.code.tex | 197 + .../pgflibraryshapes.gates.ee.IEC.code.tex | 679 +++ .../circuits/pgflibraryshapes.gates.ee.code.tex | 170 + .../pgflibraryshapes.gates.logic.IEC.code.tex | 739 +++ .../pgflibraryshapes.gates.logic.US.code.tex | 2525 +++++++++ .../circuits/pgflibraryshapes.gates.logic.code.tex | 103 + .../shapes/pgflibraryshapes.arrows.code.tex | 2361 +++++++++ .../shapes/pgflibraryshapes.callouts.code.tex | 951 ++++ .../libraries/shapes/pgflibraryshapes.code.tex | 21 + .../shapes/pgflibraryshapes.geometric.code.tex | 4417 +++++++++++++++ .../shapes/pgflibraryshapes.misc.code.tex | 1127 ++++ .../shapes/pgflibraryshapes.multipart.code.tex | 1356 +++++ .../shapes/pgflibraryshapes.symbols.code.tex | 2775 ++++++++++ graphics/pgf/base/tex/generic/lua/pgf/manual.lua | 18 + .../tex/generic/lua/pgf/manual/DocumentParser.lua | 613 +++ graphics/pgf/base/tex/generic/math/pgfint.code.tex | 126 + .../pgf/base/tex/generic/math/pgfmath.code.tex | 37 + .../pgf/base/tex/generic/math/pgfmathcalc.code.tex | 537 ++ .../base/tex/generic/math/pgfmathfloat.code.tex | 2669 ++++++++++ .../generic/math/pgfmathfunctions.base.code.tex | 330 ++ .../generic/math/pgfmathfunctions.basic.code.tex | 803 +++ .../tex/generic/math/pgfmathfunctions.code.tex | 267 + .../math/pgfmathfunctions.comparison.code.tex | 179 + .../pgfmathfunctions.integerarithmetics.code.tex | 124 + .../generic/math/pgfmathfunctions.misc.code.tex | 353 ++ .../generic/math/pgfmathfunctions.random.code.tex | 246 + .../generic/math/pgfmathfunctions.round.code.tex | 123 + .../math/pgfmathfunctions.trigonometric.code.tex | 1571 ++++++ .../pgf/base/tex/generic/math/pgfmathode.code.tex | 178 + .../base/tex/generic/math/pgfmathparser.code.tex | 1017 ++++ .../pgf/base/tex/generic/math/pgfmathutil.code.tex | 298 ++ .../generic/modules/pgfmoduleanimations.code.tex | 1314 +++++ .../tex/generic/modules/pgfmodulebending.code.tex | 356 ++ .../modules/pgfmoduledatavisualization.code.tex | 3216 +++++++++++ .../generic/modules/pgfmoduledecorations.code.tex | 2191 ++++++++ .../tex/generic/modules/pgfmodulematrix.code.tex | 660 +++ .../pgfmodulenonlineartransformations.code.tex | 342 ++ .../base/tex/generic/modules/pgfmoduleoo.code.tex | 844 +++ .../tex/generic/modules/pgfmoduleparser.code.tex | 697 +++ .../tex/generic/modules/pgfmoduleplot.code.tex | 561 ++ .../tex/generic/modules/pgfmoduleshapes.code.tex | 1334 +++++ .../tex/generic/modules/pgfmodulesnakes.code.tex | 369 ++ .../tex/generic/modules/pgfmodulesorting.code.tex | 69 + graphics/pgf/base/tex/generic/pgf.revision.tex | 4 + graphics/pgf/base/tex/generic/systemlayer/pgf.cfg | 33 + .../systemlayer/pgfsys-common-pdf-via-dvi.def | 172 + .../tex/generic/systemlayer/pgfsys-common-pdf.def | 119 + .../systemlayer/pgfsys-common-postscript.def | 600 +++ .../tex/generic/systemlayer/pgfsys-common-svg.def | 1613 ++++++ .../base/tex/generic/systemlayer/pgfsys-dvi.def | 394 ++ .../tex/generic/systemlayer/pgfsys-dvipdfm.def | 110 + .../tex/generic/systemlayer/pgfsys-dvipdfmx.def | 504 ++ .../base/tex/generic/systemlayer/pgfsys-dvips.def | 644 +++ .../tex/generic/systemlayer/pgfsys-dvisvgm.def | 217 + .../tex/generic/systemlayer/pgfsys-dvisvgm4ht.def | 86 + .../base/tex/generic/systemlayer/pgfsys-luatex.def | 401 ++ .../base/tex/generic/systemlayer/pgfsys-pdftex.def | 398 ++ .../base/tex/generic/systemlayer/pgfsys-tex4ht.def | 487 ++ .../tex/generic/systemlayer/pgfsys-textures.def | 95 + .../base/tex/generic/systemlayer/pgfsys-vtex.def | 110 + .../base/tex/generic/systemlayer/pgfsys-xetex.def | 79 + .../base/tex/generic/systemlayer/pgfsys.code.tex | 1775 +++++++ .../generic/systemlayer/pgfsysanimations.code.tex | 2010 +++++++ .../generic/systemlayer/pgfsysprotocol.code.tex | 70 + .../generic/systemlayer/pgfsyssoftpath.code.tex | 204 + .../tex/generic/utilities/pgfcalendar.code.tex | 801 +++ .../pgf/base/tex/generic/utilities/pgfexternal.tex | 32 + .../tex/generic/utilities/pgfexternalwithdepth.tex | 43 + .../pgf/base/tex/generic/utilities/pgffor.code.tex | 767 +++ .../base/tex/generic/utilities/pgfkeys.code.tex | 1232 +++++ .../utilities/pgfkeyslibraryfiltered.code.tex | 1015 ++++ .../pgf/base/tex/generic/utilities/pgfrcs.code.tex | 153 + .../tex/generic/utilities/pgfutil-common-lists.tex | 163 + .../base/tex/generic/utilities/pgfutil-common.tex | 913 ++++ .../base/tex/generic/utilities/pgfutil-context.def | 373 ++ .../base/tex/generic/utilities/pgfutil-latex.def | 217 + .../base/tex/generic/utilities/pgfutil-plain.def | 343 ++ 423 files changed, 145752 insertions(+) create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcore.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorearrows.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoreexternal.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoregraphicstate.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoreimage.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorelayers.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoreobjects.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorepathconstruct.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorepathusage.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorepatterns.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorepoints.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorequick.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorerdf.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcorescopes.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoreshade.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoretransformations.code.tex create mode 100644 graphics/pgf/base/tex/generic/basiclayer/pgfcoretransparency.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.IEC.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.CDH.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.IEC.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.US.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.3d.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.barcharts.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.formats.functions.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.polar.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.sparklines.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.standard.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzexternalshared.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrary3d.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryangles.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryanimations.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryarrows.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryautomata.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybabel.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybending.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalendar.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarychains.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.footprints.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.fractals.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.markings.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathmorphing.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathreplacing.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.shapes.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.text.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryer.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfadings.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfixedpointarithmetic.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfolding.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfpu.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarylindenmayersystems.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymath.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymatrix.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymindmap.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.meta.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryperspective.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypetri.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplothandlers.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplotmarks.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypositioning.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryquotes.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryrdf.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryscopes.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadings.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadows.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.arrows.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.callouts.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.IEC.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.US.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.geometric.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.misc.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.multipart.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.symbols.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysnakes.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryspy.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysvg.path.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarythrough.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytrees.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryturtle.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryviews.code.tex create mode 100644 graphics/pgf/base/tex/generic/frontendlayer/tikz/tikz.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/LUA_CODING_STYLE create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/Binding.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Anchoring.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Components.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Distances.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/FineTune.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Orientation.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Sublayouts.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Edge.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Graph.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Node.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Vector.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/BarycenterHeuristic.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/DfsAcyclicSubgraph.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyInsertHeuristic.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/MedianHeuristic.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SplitHeuristic.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/AcyclicSubgraphModule.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/HierarchyLayoutModule.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/InitialPlacer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/MultilevelBuilder.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/RankingModule.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/TwoLayerCrossMin.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleDemo.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleEdgeDemo.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/example_graph_for_ascii_displayer.txt create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlElectric.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlIteration.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlSprings.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlStart.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/QuadTree.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/Scope.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalEadesLS1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/EdgeRoutingGansnerKNV1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Ranking.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/edge_routing.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_positioning.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_ranking.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Bezier.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/DepthFirstSearch.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Direct.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Event.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/LookupTable.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PathLengths.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Stack.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Storage.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Transform.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Arc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Collection.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Coordinate.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Digraph.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Edge.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Hyperedge.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path_arced.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Vertex.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/Embedding.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/LinkedList.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/List.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PDP.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/parameters.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/Hints.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/doc.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/library.lua create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/experimental/tikzlibrarygraphdrawing.evolving.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex create mode 100644 graphics/pgf/base/tex/generic/graphdrawing/tex/tikzlibrarygraphdrawing.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.barcharts.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.formats.functions.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.polar.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.footprints.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.fractals.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.markings.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathmorphing.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.shapes.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.text.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/functions.lua create mode 100644 graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/parser.lua create mode 100644 graphics/pgf/base/tex/generic/libraries/luamath/pgflibraryluamath.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.meta.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.spaced.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarycurvilinear.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryfadings.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryfixedpointarithmetic.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryfpu.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryintersections.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarylindenmayersystems.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.meta.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryplothandlers.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryplotmarks.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryprofiler.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibraryshadings.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarysnakes.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarysvg.path.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/pgflibrarytimelines.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.IEC.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.IEC.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.US.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.arrows.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.callouts.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.geometric.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.misc.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.multipart.code.tex create mode 100644 graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.symbols.code.tex create mode 100644 graphics/pgf/base/tex/generic/lua/pgf/manual.lua create mode 100644 graphics/pgf/base/tex/generic/lua/pgf/manual/DocumentParser.lua create mode 100644 graphics/pgf/base/tex/generic/math/pgfint.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmath.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathcalc.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfloat.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.base.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.basic.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.comparison.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.integerarithmetics.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.misc.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.random.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.round.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathfunctions.trigonometric.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathode.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathparser.code.tex create mode 100644 graphics/pgf/base/tex/generic/math/pgfmathutil.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduleanimations.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmodulebending.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduledatavisualization.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduledecorations.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmodulematrix.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmodulenonlineartransformations.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduleoo.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduleparser.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduleplot.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmoduleshapes.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmodulesnakes.code.tex create mode 100644 graphics/pgf/base/tex/generic/modules/pgfmodulesorting.code.tex create mode 100644 graphics/pgf/base/tex/generic/pgf.revision.tex create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgf.cfg create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-common-pdf-via-dvi.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-common-pdf.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-common-postscript.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-common-svg.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvi.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvipdfm.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvipdfmx.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvips.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvisvgm.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-dvisvgm4ht.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-luatex.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-pdftex.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-tex4ht.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-textures.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-vtex.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys-xetex.def create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsys.code.tex create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsysanimations.code.tex create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsysprotocol.code.tex create mode 100644 graphics/pgf/base/tex/generic/systemlayer/pgfsyssoftpath.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfcalendar.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfexternal.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfexternalwithdepth.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgffor.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfkeys.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfkeyslibraryfiltered.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfrcs.code.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfutil-common-lists.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfutil-common.tex create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfutil-context.def create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfutil-latex.def create mode 100644 graphics/pgf/base/tex/generic/utilities/pgfutil-plain.def (limited to 'graphics/pgf/base/tex/generic') diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcore.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcore.code.tex new file mode 100644 index 0000000000..b7e47f4ee3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcore.code.tex @@ -0,0 +1,41 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesPackageRCS{pgfcore.code.tex} + +\newif\ifpgf@draftmode +\def\pgf@typeout{\immediate\write0} + +\ifdefined\pgfmathloaded\else + \input pgfmath.code.tex +\fi + +\ifdefined\pgfintloaded\else + \input pgfint.code.tex +\fi + +\input pgfcorepoints.code.tex +\input pgfcorepathconstruct.code.tex +\input pgfcorepathusage.code.tex +\input pgfcorescopes.code.tex +\input pgfcoregraphicstate.code.tex +\input pgfcoretransformations.code.tex +\input pgfcorequick.code.tex +\input pgfcoreobjects.code.tex +\input pgfcorepathprocessing.code.tex +\input pgfcorearrows.code.tex +\input pgfcoreshade.code.tex +\input pgfcoreimage.code.tex +\input pgfcoreexternal.code.tex +\input pgfcorelayers.code.tex +\input pgfcoretransparency.code.tex +\input pgfcorepatterns.code.tex +\input pgfcorerdf.code.tex + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorearrows.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorearrows.code.tex new file mode 100644 index 0000000000..7f079fa841 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorearrows.code.tex @@ -0,0 +1,1253 @@ +% Copyright 2006, 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorearrows.code.tex} + + + +% Define a new (meta) arrow or a shorthand +% +% #1 = key--value pairs +% +% Description: +% +% This command is used to define a new arrow tip kind. For more +% details on the description of the keys, please see the pgfmanual. +% +% name = Name of the arrow. If the name contains a dash +% (hyphen), the text before the hyphen is the start name +% and the text behind it the end name. +% +% means = If set, none of the below options may be +% given. The effect is that whenever the arrow is +% used, it gets replaced by this "text", which is +% parsed by the parser. +% +% setup code = Code that does "precomputations". These will be +% executed only once for each combination of the +% dependencies. At the end of this code, you can use +% \savethe and \save to "save" computed values, which +% will then be available inside the "code". Values needed +% only for the "... end" keys and the convex hull do not +% need to be saved since these are also executed only +% once. +% drawing code = Code for drawing the arrow. When the cache key is set to +% true, which is the default, the code will be protocolled +% and the resulting code is inserted using \pgflowlevelobj. +% cache = Boolean that decides whether the arrow can be cached. The +% default is true, so you have to say cache=false to switch +% caching off. In this case, each time the arrow is drawn, +% its code is simply executed. This allows you to put things +% like text or shadings in arrow tips. +% bending mode = Can be set to "orthogonal", "polar", or +% "none". Defaults to "orthogonal". +% defaults = A list of "default" options for the arrow tip. These +% are executed as if they were given to the arrow tip in +% brackets. This is useful for setting up default values. +% parameters = A list of comma-separated macro names on whose values +% the appearance of the arrow tip depends. When an arrow +% tip is used, these macros are expanded. If an +% arrow tip was already installed with the same macro +% names (and caching is true), the cached code is +% used. Note that when you use dimensions here, add \the. +% +% Inside the setup code, the following macros are available: +% +% \pgfarrowssettipend +% The code should draw an arrow pointing "right along the x +% axis". The "tip" key specifies how far the arrow goes +% along the x axis, that is, it should be the x coordinate +% of the very tip of the arrow. In previous versions this +% was called the "right extend". The value passed to this +% key should be some code that sets the dimension +% "\pgfarrowresult", which is \let to be equal to +% \pgf@x. A \relax will be added after the code provided +% here, so you can write things like "\pgfarrowresult=1pt". +% \pgfarrowssetbackend +% The leftmost x-coordinate that is still part of the +% arrow tip (the "back end" of the arrow"). This coordinate +% will be used when multiple arrow tips are +% composed. Defaults to 0pt. +% \pgfarrowssetlineend +% The x-coordinate where a line should stop inside the arrow +% tip so that it gets "obscured" by the arrow. Defaults to 0pt. +% \pgfarrowssetvisualtipend +% When the arrow tip is drawn in flex mode, it is rotated +% such that the x-coordinates of "visual tip end" and "visual +% back end" lie on the path. Defaults to \pgfarrowssettipend. +% \pgfarrowssetvisualbackend +% See above. Defaults to \pgfarrowssetbackend + +\def\pgfdeclarearrow#1{% + \let\pgf@decl@arrow@defaults\pgfutil@empty% + \let\pgf@decl@arrow@means\relax% + \let\pgf@decl@arrow@code\relax% + \pgfkeys{/pgf/@arrows decl/.cd, + name=, + setup code=, + cache=true, + bending mode=orthogonal, + parameters=,% + #1% + }% + \ifx\pgf@decl@arrow@name@end\pgfutil@empty% + \pgferror{Declaring unnamed arrow}% + \else% + \pgf@arrow@letter{name@end}% + \pgf@arrow@letter{name@start}% + \expandafter\let\csname pgf@ar@start@\pgf@decl@arrow@name@start\endcsname\pgf@decl@arrow@name@end% + \expandafter\let\expandafter\pgf@old@code\csname pgf@ar@code@\pgf@decl@arrow@name@end\endcsname% + \expandafter\let\expandafter\pgf@old@means\csname pgf@ar@means@\pgf@decl@arrow@name@end\endcsname% + \ifx\pgf@decl@arrow@code\relax% + \ifx\pgf@decl@arrow@means\relax% + \pgferror{You must set either the 'means' or the drawing code' keys for arrow tip '\pgf@decl@arrow@name@end'}% + \else% + \ifx\pgf@old@code\relax% + \let\pgf@arrow@tip@sequence\pgfutil@empty% + \let\pgf@arrow@translate\relax% + \expandafter\let\expandafter\pgf@arrows@direct\csname pgf@arrows@direct@name@end@\pgf@decl@arrow@means\endcsname% + \ifx\pgf@arrows@direct\relax% + \let\pgf@arrows@options\pgfutil@empty% + \expandafter\pgfarrows@initial@parser\pgf@decl@arrow@means[]\pgf@stop% + \else% + \let\pgf@arrow@tip@sequence\pgf@arrows@direct% + \fi% + \pgf@arrow@letter@\pgf@arrow@tip@sequence{means}% + \expandafter\let\csname pgf@ar@code@\pgf@decl@arrow@name@end\endcsname\relax% + \else% + \pgferror{Arrow tip '\pgf@decl@arrow@name@end' was already + defined with key 'drawing code' previously and you cannot change this}% + \fi% + \fi% + \else% + \ifx\pgf@decl@arrow@means\relax% + \ifx\pgf@old@means\relax% + \pgf@arrow@letter{code}% + \pgf@arrow@letter{defaults}% + \pgf@arrow@letter{setup}% + \pgf@arrow@letter{bending@mode}% + \pgf@arrow@letter{par}% + \expandafter\let\csname pgf@ar@do@cache@\pgf@decl@arrow@name@end\endcsname\pgf@decl@arrow@cache% + \else% + \pgferror{Arrow tip '\pgf@decl@arrow@name@end' was already + defined with key 'means' previously and you cannot change this}% + \fi% + \else% + \pgferror{You cannot set both the 'means' and also the 'drawing code' + keys for arrow tip '\pgf@decl@arrow@name@end'}% + \fi% + \fi% + \fi% +} + +\def\pgf@arrow@letter#1{% + \expandafter\pgf@arrow@letter@\expandafter{\csname pgf@decl@arrow@#1\endcsname}{#1}% +} +\def\pgf@arrow@letter@#1#2{% + \expandafter\let\csname pgf@ar@#2@\pgf@decl@arrow@name@end\endcsname#1% +} + +\pgfkeys{ + /pgf/@arrows decl/.cd, + name/.code={% + \pgfutil@in@-{#1}% + \ifpgfutil@in@% + \pgf@arrows@name@decomp#1\pgf@stop% + \else% + \def\pgf@decl@arrow@name@end{#1}\let\pgf@decl@arrow@name@start\pgf@decl@arrow@name@end% + \fi}, + means/.store in=\pgf@decl@arrow@means, + setup code/.store in=\pgf@decl@arrow@setup, + drawing code/.store in=\pgf@decl@arrow@code, + cache/.store in=\pgf@decl@arrow@cache, + bending mode/.is choice, + bending mode/none/.code=\let\pgf@decl@arrow@bending@mode\pgfutil@empty, + bending mode/orthogonal/.code=\def\pgf@decl@arrow@bending@mode{\pgfpointcurvilinearbezierorthogonal}, + bending mode/polar/.code=\def\pgf@decl@arrow@bending@mode{\pgfpointcurvilinearbezierpolar}, + parameters/.store in=\pgf@decl@arrow@par, + defaults/.code={% + \let\pgf@arrows@options\pgfutil@empty% + \pgfkeys{/pgf/arrow keys/.cd,#1}% + \let\pgf@decl@arrow@defaults\pgf@arrows@options% + } +} + +\def\pgf@arrows@name@decomp#1-#2\pgf@stop{% + \def\pgf@decl@arrow@name@start{#1}% + \def\pgf@decl@arrow@name@end{#2}% +} + + +% Handler for defining arrow tips: +% +% Description: +% +% When you write "my name/.tip = arrow spec", this has the same +% effect as writing \pgfdeclarearrow{name = my name, means = arrow spec}. + +\pgfkeys{/handlers/.tip/.code=% + \expandafter\expandafter\expandafter\pgf@arrows@unravel\pgfkeyscurrentpath/\pgf@stop% + \expandafter\pgf@arrows@key@call\expandafter{\pgf@arrows@unravelled}{#1}} +\def\pgf@arrows@unravel#1/{\pgfutil@ifnextchar\pgf@stop{\def\pgf@arrows@unravelled{#1}\pgfutil@gobble}{\pgf@arrows@unravel}} +\def\pgf@arrows@key@call#1#2{\pgfdeclarearrow{name={#1},means={#2}}} + + + + +% Draw an arrow +% +% #1 = arrow specification +% +% Description: +% +% Draws the arrow in the given specification (and "end" +% specification). The arrow will be drawn such that it touches the +% origin "from the left", that is, the arrow will lie completely in +% the half plane with negative $x$ values and the tip will end exactly +% at the origin. + +\def\pgfarrowdraw#1{% + {% + \pgfsetarrowsend{#1}% + \pgf@arrow@compute@shortening\pgf@end@tip@sequence% + \pgf@arrow@draw@arrow\pgf@end@tip@sequence\pgf@xb% + }% +} + + + +% Compute the length of an arrow +% +% #1 = arrow specification +% +% Description: +% +% In \pgf@x, this will return the total length of the arrow given as +% #1, in \pgf@xa it will return the distance from the tip to the line +% end. + +\def\pgfarrowtotallength#1{% + {% + \pgfsetarrowsend{#1}% + \pgf@arrow@compute@shortening\pgf@end@tip@sequence% + \expandafter\expandafter\expandafter% + }% + \expandafter\expandafter\expandafter\pgf@x\expandafter\the\expandafter\pgf@xb\expandafter\pgf@xa\the\pgf@xa% +} + + + + + +% Sets the end arrow tip +% +% #1 = An arrow specification +% +% Description: +% +% An "arrow specification" is a sequence of names of meta arrow tips +% together with options in brackets. In detail: +% +% In #1, consider the text from the start up to the first bracket. If +% this text is the name of a (meta) arrow tip, we use this arrow tip +% with the provided options. If it is the name of a arrow tip +% shorthand, this shorthand is expanded and the options are applied to +% each arrow tip inside the shorthand. If the text is neither or the +% above, the first letter of text is treated as a shorthand without +% options. +% +% The special arrow tip "." is used to indicate the end of the line. +% +% \pgfsetarrowsend{stealth[reversed]} +% \pgfsetarrowsend{stealth[length=1pt] . stealth[length=2pt]} +% \pgfsetarrowsend{>>>} +% \pgfsetarrowsend{>.>} + +\def\pgfsetarrowsend#1{% + \let\pgf@arrow@tip@sequence\pgfutil@empty% + \pgf@arrows@translatefalse% + \expandafter\let\expandafter\pgf@arrows@direct\csname pgf@arrows@direct@name@end@#1\endcsname% + \ifx\pgf@arrows@direct\relax% + \edef\pgf@marshal{\noexpand\pgfarrows@initial@parser#1[]\noexpand\pgf@stop}% + \pgf@marshal% + \else% + \let\pgf@arrow@tip@sequence\pgf@arrows@direct% + \fi% + \let\pgf@end@tip@sequence\pgf@arrow@tip@sequence% +} + +\newif\ifpgf@arrows@translate + +\def\pgfarrows@initial@parser{% + \pgfutil@ifnextchar[\pgfarrows@initial@parser@{\pgfarrows@initial@parser@[]}}%} + +\def\pgfarrows@initial@parser@[#1]{% + \let\pgf@arrows@options\pgfutil@empty% + \pgfkeys{/pgf/arrow keys/.cd,#1}% + \let\pgf@arrows@options@initial\pgf@arrows@options% + \pgfarrows@parser% +} + +\def\pgfarrows@parser#1[{% + \pgfkeys@spdef\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty% + \let\pgf@next\pgf@arrows@empty% + \else% + \ifx\pgf@temp\pgf@dot@text% + \let\pgf@next\pgf@arrows@dot@parsed% + \else% + \let\pgf@untranslated\pgf@temp% + \ifpgf@arrows@translate% + \pgf@arrow@swapper% + \fi% + % Now, let's see what we do with this... + \expandafter\ifx\csname pgf@ar@code@\pgf@temp\endcsname\relax + \expandafter\ifx\csname pgf@ar@means@\pgf@temp\endcsname\relax + % #1 should start with a single-char shorthands + \let\pgf@next\pgf@arrows@single@char@parser% + \let\pgf@temp\pgf@untranslated% + \else% + % #1 is a shorthand! + \let\pgf@next\pgf@arrows@shorthand@parsed% + \fi% + \else% + % #1 is a meta arrow! + \let\pgf@next\pgf@arrows@meta@parsed% + \fi% + \fi% + \fi% + \expandafter\pgf@next\pgf@temp[% +} + +\def\pgf@arrows@empty[#1]{% + \pgfutil@ifnextchar\pgf@stop\pgf@arrows@parser@done\pgfarrows@parser% +} + +\def\pgf@arrows@single@char@parser#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@dot@text% + \let\pgf@next\pgf@arrows@dot@parsed% + \else% + \let\pgf@untranslated\pgf@temp% + \ifpgf@arrows@translate% + \pgf@arrow@swapper% + \fi% + \expandafter\ifx\csname pgf@ar@code@\pgf@temp\endcsname\relax + \expandafter\ifx\csname pgf@ar@means@\pgf@temp\endcsname\relax + \let\pgf@temp\pgf@untranslated% + \let\pgf@next\pgf@arrows@unknown% + \else% + \let\pgf@next\pgf@arrows@shorthand@parsed% + \fi% + \else% + \let\pgf@next\pgf@arrows@meta@parsed% + \fi + \fi + \expandafter\pgf@next\pgf@temp[]% +} +\def\pgf@arrows@unknown#1[]#2[#3]{% + \pgferror{Unknown arrow tip kind '#1#2'}% +} + +\def\pgf@arrows@meta@parsed#1[#2]{% + % Ok, run the keys #2. This will add commands to \pgf@arrows@options: + % + \let\pgf@arrows@options\pgf@arrows@options@initial% + \pgfkeys{/pgf/arrow keys/.cd,#2}% + % Append the arrow and its options to the arrow tip sequence: + \expandafter\pgf@arrows@meta@set\expandafter{\pgf@arrows@options}{#1}{\pgf@arrow@handle}% + \pgfutil@ifnextchar\pgf@stop\pgf@arrows@parser@done\pgfarrows@parser% +} + +\def\pgf@arrows@parser@done#1{% +} + +\def\pgf@arrows@dot@parsed#1[#2]{% + \pgf@arrows@append@to@tips{\pgf@arrow@handle@dot}% + \pgfutil@ifnextchar\pgf@stop\pgf@arrows@parser@done\pgfarrows@parser% +} + +\def\pgf@arrows@meta@set#1#2#3{% + \pgf@arrows@append@to@tips{#3{#2}{#1}}% +} +\def\pgf@arrows@append@to@tips#1{% + \let\pgf@tempa\pgf@arrow@tip@sequence% + \def\pgf@tempb{#1}% + \ifpgf@arrows@translate% + \let\pgf@tempa\pgf@tempb% + \let\pgf@tempb\pgf@arrow@tip@sequence% + \fi% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrow@tip@sequence% + \expandafter\expandafter\expandafter{\expandafter\pgf@tempa\pgf@tempb}% +} + +\def\pgf@arrows@shorthand@parsed#1[#2]{% + \let\pgf@arrows@options\pgf@arrows@options@initial% + \pgfkeys{/pgf/arrow keys/.cd,#2}% + \ifx\pgf@arrows@options\pgfutil@empty% + \expandafter\pgf@arrows@append@to@tips\expandafter{% + \expandafter\pgf@arrow@handle@shorthand@empty\expandafter{\csname pgf@ar@means@#1\endcsname}}% + \else% + \expandafter\expandafter\expandafter\pgf@arrows@meta@set\expandafter\expandafter\expandafter{% + \expandafter\pgf@arrows@options\expandafter}\expandafter{\csname pgf@ar@means@#1\endcsname}{\pgf@arrow@handle@shorthand}% + \fi% + \pgfutil@ifnextchar\pgf@stop\pgf@arrows@parser@done\pgfarrows@parser% +} + + +% General handler: + +\def\pgf@arrow@handle@shorthand@empty#1{#1} + +\def\pgf@arrow@handle@shorthand#1#2{% + \def\pgf@temp@opt{#2}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrows@nested@options@temp% + \expandafter\expandafter\expandafter{\expandafter\pgf@temp@opt\pgf@arrows@nested@options}% + \expandafter\let\expandafter\pgf@arrows@nested@options\expandafter\pgf@arrows@nested@options@temp% + \expandafter#1% all these expandafters to avoid creating groups, but having the options nest + \expandafter\def\expandafter\pgf@arrows@nested@options\expandafter{\pgf@arrows@nested@options}% +} + +\let\pgf@arrows@nested@options\pgfutil@empty + + + + +% Sets the start arrow tip +% +% #1 = An arrow specification +% +% Description: +% +% This works like \pgfsetarrowsend, only the order of the tips in the +% arrow specification is reversed and the "reversed names" are used. +% +% \pgfsetarrowsend{<<} +% \pgfsetarrowsend{>.>} + +\def\pgfsetarrowsstart#1{% + \let\pgf@arrow@tip@sequence\pgfutil@empty% + \pgf@arrows@translatetrue% + \expandafter\let\expandafter\pgf@arrows@direct\csname pgf@arrows@direct@name@start@#1\endcsname% + \ifx\pgf@arrows@direct\relax% + \edef\pgf@marshal{\noexpand\pgfarrows@initial@parser#1[]\noexpand\pgf@stop}% + \pgf@marshal% + \else% + \let\pgf@arrow@tip@sequence\pgf@arrows@direct% + \fi% + \let\pgf@start@tip@sequence\pgf@arrow@tip@sequence% +} + +\def\pgf@arrow@swapper{% + \expandafter\let\expandafter\pgf@temp\csname pgf@ar@start@\pgf@temp\endcsname% + \ifx\pgf@temp\relax% + \def\pgf@temp{undefined}% + \fi% +} + +\let\pgf@start@tip@sequence\pgfutil@empty +\let\pgf@end@tip@sequence\pgfutil@empty + + +\expandafter\def\csname pgf@arrows@direct@name@start@\endcsname{} +\expandafter\def\csname pgf@arrows@direct@name@end@\endcsname{} + + +% Predefined lengths and ifs + +\newdimen\pgfarrowsep + +\newif\ifpgfarrowswap +\newif\ifpgfarrowreversed +\newif\ifpgfarrowharpoon +\newif\ifpgfarrowopen + +\let\pgf@arrows@stroke@color\pgfutil@empty +\let\pgf@arrows@fill@color\pgfutil@empty + +\def\pgfarrows@length@scale{1} +\def\pgfarrows@width@scale{1} +\def\pgfarrows@slant{0} + +\let\pgfarrows@scale@list\pgfutil@empty +\def\pgfarrowsaddtolengthscalelist#1{\expandafter\def\expandafter\pgfarrows@scale@list\expandafter{\pgfarrows@scale@list#1\pgfarrows@length@scale#1}} +\def\pgfarrowsaddtowidthscalelist#1{\expandafter\def\expandafter\pgfarrows@scale@list\expandafter{\pgfarrows@scale@list#1\pgfarrows@width@scale#1}} + +\pgfkeys{ + /pgf/arrow keys/.cd, + scale/.code={% + \pgfmathparse{#1}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrows@length@scale\expandafter{\pgfmathresult}}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrows@width@scale\expandafter{\pgfmathresult}}% + }, + scale length/.code={\pgfmathparse{#1}\expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrows@length@scale\expandafter{\pgfmathresult}}}, + scale width/.code={\pgfmathparse{#1}\expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrows@width@scale\expandafter{\pgfmathresult}}}, + slant/.code={\pgfmathparse{#1}\expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrows@slant\expandafter{\pgfmathresult}}}, + sep/.code={ + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters\pgfarrowsep\pgf@x}% + }, + sep/.default=0.88pt .3 1, + % + swap/.code=\pgfarrowsaddtooptions{\ifpgfarrowswap\pgfarrowswapfalse\else\pgfarrowswaptrue\fi}, + reversed/.code=\pgfarrowsaddtooptions{\ifpgfarrowreversed\pgfarrowreversedfalse\else\pgfarrowreversedtrue\fi}, + harpoon/.is choice, + harpoon/.default=true, + harpoon/true/.code=\pgfarrowsaddtooptions{\pgfarrowharpoontrue}, + harpoon/false/.code=\pgfarrowsaddtooptions{\pgfarrowharpoonfalse}, + left/.style={harpoon}, + right/.style={harpoon,swap}, + % + color/.code=\pgfarrowsaddtooptions{\def\pgf@arrows@stroke@color{#1}}, + fill/.code={% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@nonetext% + \pgfarrowsaddtooptions{\pgfarrowopentrue} + \else + \pgfarrowsaddtooptions{\pgfarrowopenfalse\def\pgf@arrows@fill@color{#1}} + \fi + }, + fill/.value required, + open/.style={fill=none}, + .unknown/.code={ + \expandafter\pgfutil@in@\expandafter!\expandafter{\pgfkeyscurrentname}% + \ifpgfutil@in@% + % this is a color! + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgf@arrows@stroke@color\expandafter{\pgfkeyscurrentname}}% + \else% + \pgfutil@doifcolorelse{\pgfkeyscurrentname} + {% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgf@arrows@stroke@color\expandafter{\pgfkeyscurrentname}}% + } + {% + \edef\pgf@temp{\pgfkeyscurrentname}% + \pgfkeys{/errors/unknown key/.expand once=\expandafter{\pgf@temp}{#1}}% + } + \fi + } +} +\def\pgf@nonetext{none} + +\def\pgfarrowsaddtooptions#1{\expandafter\def\expandafter\pgf@arrows@options\expandafter{\pgf@arrows@options#1}} +\def\pgfarrowsaddtolateoptions#1{\expandafter\def\expandafter\pgf@arrows@options\expandafter{\pgf@arrows@options\pgf@arrows@add@to@late@options{#1}}} +\def\pgf@arrows@add@to@late@options#1{\expandafter\def\expandafter\pgf@arrows@late@options\expandafter{\pgf@arrows@late@options#1}} + + + +\def\pgfarrowsthreeparameters#1{% + \pgfarrowsthreeparameters@#1 +0 +0 +0 \pgf@stop% +} +\def\pgfarrowsthreeparameters@#1 #2 #3 #4\pgf@stop{% + \pgfmathsetlength\pgf@x{#1}% + \pgfmathsetmacro\pgf@temp@a{#2}% + \pgfmathsetmacro\pgf@temp@b{#3}% + \edef\pgfarrowstheparameters{{\the\pgf@x}{\pgf@temp@a}{\pgf@temp@b}}% +} + +\def\pgfarrowsfourparameters#1{% + \pgfarrowsfourparameters@#1 +0 +0 +0 \pgf@stop% +} +\def\pgfarrowsfourparameters@#1:#2 #3 #4 #5\pgf@stop{% + \pgfmathsetmacro\pgf@temp@z{#1}% + \pgfmathsetlength\pgf@x{#2}% + \pgfmathsetmacro\pgf@temp@a{#3}% + \pgfmathsetmacro\pgf@temp@b{#4}% + \edef\pgfarrowstheparameters{{\pgf@temp@z}{\the\pgf@x}{\pgf@temp@a}{\pgf@temp@b}}% +} + +\def\pgfarrows@angle@setup#1#2#3#4{% + \pgfarrowslinewidthdependent{#2}{#3}{#4} + \pgf@xc\pgf@x + \pgf@yc#1 pt% + \pgf@yc.5\pgf@yc% + \pgfpointpolar{\pgf@yc}{\pgf@xc} + \pgfarrowlength\pgf@x% + \pgf@y2\pgf@y% + \expandafter\pgf@arrows@add@to@late@options\expandafter{\expandafter\pgfarrowwidth\the\pgf@y}% +} + +\def\pgfarrows@angle@setup@prime#1{% + \pgf@yc#1 pt % + \pgf@yc=0.5\pgf@yc + \pgfmathtan@{\pgf@sys@tonumber\pgf@yc}% + \pgfarrowwidth\pgfmathresult\pgfarrowlength% + \pgfarrowwidth2\pgfarrowwidth% +} + +\def\pgfarrowslinewidthdependent#1#2#3{% + \pgf@x#1% + \ifdim\pgfinnerlinewidth>0pt% + \pgf@arrows@inner@line@width@dep{#2}{#3}% + \else% + \advance\pgf@x by#2\pgflinewidth% + \fi% +} +\def\pgf@arrows@inner@line@width@dep#1#2{% + % #1*((1-#2/2)*full line width - (#2/2) * inner line width) + % Compute "real" line width + \pgf@xa\pgflinewidth% + \pgf@xb-.5\pgflinewidth% + \pgf@xb#2\pgf@xb% + \advance\pgf@xa by\pgf@xb% + \pgf@xb\pgfinnerlinewidth% + \pgf@xb-.5\pgf@xb + \advance\pgf@xa by#2\pgf@xb% + \advance\pgf@x by#1\pgf@xa% +} + + +\def\pgfarrowslengthdependent#1#2#3#4{% + #4#1% + \advance#4by#2\pgfarrowlength% + \advance#4by#3\pgflinewidth% +} + + + +% Build the full name: + +\def\pgf@arrow@fullname#1{pgf@@ar@#1@\the\pgflinewidth @\pgfinnerlinewidth @\ifpgfarrowreversed r\fi @\pgf@arrows@stroke@color @\pgf@arrows@fill@color @\csname pgf@ar@par@#1\endcsname} +\def\pgf@arrow@id@count{0}% + +% Compute the arrow id of an arrow +% +% #1 = arrow name +% #2 = options +% +% Description: +% +% Returns the an id in \pgf@arrow@id that identifies the instantiation +% of the given arrow. If the arrow was not instantiated, this happens now. + +\def\pgfarrows@getid#1#2{% + % Execute options: + \let\pgf@arrows@late@options\pgfutil@empty% + % 1. Defaults: + \csname pgf@ar@defaults@#1\endcsname% + % 2. Scope: + \pgf@arrows@options@scope + % 3. Local: + #2\relax% + % 4. Nested: + \pgf@arrows@nested@options% + % 5. Last options: + \pgf@arrows@late@options% + % 6. Scaling: + \pgfarrows@scale@list% + % Now, test: + \expandafter\global\expandafter\let\expandafter\pgf@arrow@id\csname\pgf@arrow@fullname{#1}\endcsname\relax% + \ifx\pgf@arrow@id\relax% + \pgf@arrows@instantiate{#1} + \fi% +} + +\def\pgf@arrows@instantiate#1{% + % Not defined. Rats! + % Allocate new id: + \pgfutil@tempcnta\pgf@arrow@id@count\relax% + \advance\pgfutil@tempcnta by1\relax% + \xdef\pgf@arrow@id@count{\the\pgfutil@tempcnta}% + \expandafter\global\expandafter\let\csname\pgf@arrow@fullname{#1}\endcsname\pgf@arrow@id@count% + \global\let\pgf@arrow@id\pgf@arrow@id@count% + {% + \pgfclearid% + \csname pgf@ar@setup@#1\endcsname% + % Handle reversal + \ifpgfarrowreversed% + % Compute transformation: + \pgf@arrows@handle@reverse% + \fi% + % Save computed values + \expandafter\global\expandafter\let\csname pgf@ar@saves@\pgf@arrow@id\endcsname\pgf@arrows@saves% + \expandafter\global\expandafter\let\csname pgf@ar@hull@\pgf@arrow@id\endcsname\pgf@arrows@convexhull% + \expandafter\xdef\csname pgf@ar@ends@\pgf@arrow@id\endcsname{{\pgf@arrows@the@tipend}{\pgf@arrows@the@backend}{\pgf@arrows@the@lineend}}% + \expandafter\xdef\csname pgf@ar@visual@\pgf@arrow@id\endcsname{{\pgf@arrows@the@visualtipend}{\pgf@arrows@the@visualbackend}{}}% + % Save code (needed for bending) + \edef\pgf@arrow@code{% + \ifpgfarrowreversed\noexpand\pgftransformxscale{-1}\fi% + \expandafter\noexpand\csname pgf@ar@code@#1\endcsname% + }% + \expandafter\global\expandafter\let\csname pgf@ar@inst@code@\pgf@arrow@id\endcsname\pgf@arrow@code% + % Should we cache? + \expandafter\ifx\csname pgf@ar@do@cache@#1\endcsname\pgf@truetext% + \pgfsysprotocol@getcurrentprotocol\pgf@arrow@temp% + {% + \pgfinterruptpath% + \let\pgfusepath=\pgf@nousepath@here% + \pgf@relevantforpicturesizefalse% + \pgftransformreset% + \pgfsysprotocol@setcurrentprotocol\pgfutil@empty% + \pgfsysprotocol@bufferedtrue% + \pgfscope% + \pgf@arrow@code% + \endpgfscope% + \pgfsysprotocol@getcurrentprotocol\pgf@@arrow@temp% + \expandafter\gdef\expandafter\pgf@arrow@code\expandafter{\expandafter\pgfsysprotocol@literal\expandafter{\pgf@@arrow@temp}}% + \endpgfinterruptpath% + }% + \pgfsysprotocol@setcurrentprotocol\pgf@arrow@temp% + \fi% + \expandafter\global\expandafter\let\csname pgf@ar@cache@\pgf@arrow@id\endcsname\pgf@arrow@code% + }% +} +\def\pgf@truetext{true} + +% Ok, now run setup: +\def\pgf@arrows@copy@tipend{\pgf@arrows@the@tipend} +\def\pgf@arrows@copy@backend{\pgf@arrows@the@backend} +\def\pgf@arrows@copy@lineend{\pgf@arrows@the@lineend} +\def\pgf@arrows@zeropt{0pt}% + +\let\pgf@arrows@saves\pgfutil@empty% +\let\pgf@arrows@convexhull\pgfutil@empty% +\let\pgf@arrows@the@tipend\pgf@arrows@zeropt% +\let\pgf@arrows@the@backend\pgf@arrows@zeropt% +\let\pgf@arrows@the@lineend\pgf@arrows@zeropt% +\let\pgf@arrows@the@visualtipend\pgf@arrows@copy@tipend% +\let\pgf@arrows@the@visualbackend\pgf@arrows@copy@backend% + + +\def\pgf@arrows@handle@reverse{% + \pgf@x\pgf@arrows@the@visualtipend\pgf@x-\pgf@x% + \pgf@y\pgf@arrows@the@visualbackend\pgf@y-\pgf@y + \edef\pgf@arrows@the@visualtipend{\the\pgf@y}% + \edef\pgf@arrows@the@visualbackend{\the\pgf@x}% + \pgf@x\pgf@arrows@the@tipend\pgf@x-\pgf@x% + \pgf@y\pgf@arrows@the@backend\pgf@y-\pgf@y + \edef\pgf@arrows@the@tipend{\the\pgf@y}% + \edef\pgf@arrows@the@backend{\the\pgf@x}% + \pgf@x\pgf@arrows@the@lineend\pgf@x-\pgf@x\edef\pgf@arrows@the@lineend{\the\pgf@x}% + \let\pgf@temp\pgf@arrows@convexhull% + \let\pgf@arrows@convexhull\pgfutil@empty% + \let\pgf@arrow@hull@point\pgf@arrow@hull@point@reverse% + \pgf@temp% +} +\def\pgf@arrow@hull@point@reverse#1#2{% + \pgf@x#1% + \pgfarrowshullpoint{-\pgf@x}{#2}% +} + +\def\pgf@nousepath@here#1{\pgferror{The definition of an arrow may not use \string\pgfusepath}} + +\def\pgfarrowssavethe#1{% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrows@saves% + \expandafter\expandafter\expandafter{\expandafter\pgf@arrows@saves\expandafter#1\the#1\relax} +} + +\def\pgfarrowssave#1{% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrows@saves% + \expandafter\expandafter\expandafter{\expandafter\pgf@arrows@saves\expandafter\def\expandafter#1\expandafter{#1}} +} + +\def\pgfarrowshullpoint#1#2{% + \pgf@x#1\relax% + \pgf@y#2\relax% + \edef\pgf@arrows@temp{\noexpand\pgf@arrows@convexhull\noexpand\pgf@arrow@hull@point{\the\pgf@x}{\the\pgf@y}}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@arrows@convexhull\expandafter\expandafter\expandafter{\pgf@arrows@temp}% +} + +\def\pgfarrowsupperhullpoint#1#2{% + \pgf@x#1\relax% + \pgf@y#2\relax% + \ifdim\pgf@y>0pt + \edef\pgf@arrows@temp{\noexpand\pgf@arrows@convexhull\noexpand\pgf@arrow@hull@point{\the\pgf@x}{\the\pgf@y}\ifpgfarrowharpoon\else\noexpand\pgf@arrow@hull@point{\the\pgf@x}{-\the\pgf@y}\fi}% + \else + \edef\pgf@arrows@temp{\noexpand\pgf@arrows@convexhull\noexpand\pgf@arrow@hull@point{\the\pgf@x}{\the\pgf@y}}% + \fi + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@arrows@convexhull\expandafter\expandafter\expandafter{\pgf@arrows@temp}% +} + +\def\pgfarrowssettipend#1{\pgf@x#1\edef\pgf@arrows@the@tipend{\the\pgf@x}} +\def\pgfarrowssetbackend#1{\pgf@x#1\edef\pgf@arrows@the@backend{\the\pgf@x}} +\def\pgfarrowssetlineend#1{\pgf@x#1\edef\pgf@arrows@the@lineend{\the\pgf@x}} +\def\pgfarrowssetvisualtipend#1{\pgf@x#1\edef\pgf@arrows@the@visualtipend{\the\pgf@x}} +\def\pgfarrowssetvisualbackend#1{\pgf@x#1\edef\pgf@arrows@the@visualbackend{\the\pgf@x}} + + +% Internal computation of the line end (shortening) for an arrow +% +% #1 = arrow tip list +% +% Description: +% +% \pgf@xa will contain the necessary path shortening for the given +% arrow tip list, \pgf@xb will contain the total length of the arrow +% tip list (sum of the differences between tip end and back end plus +% the seps). + +\def\pgf@arrow@compute@shortening#1{% + \let\pgf@arrow@handle\pgf@arrow@compute@shortening@ + \let\pgf@arrow@handle@dot\pgf@arrow@after@line@endtrue% + \pgf@arrow@after@line@endfalse% + \pgf@xa0pt% + \pgf@xb0pt% + #1% +} +\newif\ifpgf@arrow@after@line@end + +\def\pgf@arrow@compute@shortening@#1#2{% + {\pgfarrows@getid{#1}{#2}\ifnum\pgf@arrow@flex@mode>0\relax\global\pgf@precise@shorteningtrue\fi\expandafter}\expandafter\pgf@x\the\pgfarrowsep% + \expandafter\expandafter\expandafter\pgf@arrow@cont@short\csname pgf@ar@ends@\pgf@arrow@id\endcsname% +} +\def\pgf@dot@text{.} + +\def\pgf@arrow@cont@short#1#2#3{% tip end, back end, line end, sep + \advance\pgf@xb by#1% + \pgf@xc#2% + \advance\pgf@xb by-\pgf@xc% + \advance\pgf@xb by\pgf@x% + \ifpgf@arrow@after@line@end% + \advance\pgf@xa by#1% + \advance\pgf@xa by\pgf@x% + \pgf@xc#2% + \advance\pgf@xa by-\pgf@xc% + \else% + \pgf@xa#1% + \advance\pgf@xa by\pgf@x% + \pgf@xc#3% + \advance\pgf@xa by-\pgf@xc% + \fi% +} + + + +\def\pgf@arrow@rigid@arrow#1#2{% + {% + \pgf@xb=#2% + \pgftransformxshift{-\pgf@xb}% + \let\pgf@arrow@handle\pgf@arrow@rigid + \let\pgf@arrow@handle@dot\relax% + #1% + }% +} + + +\def\pgf@arrow@rigid#1#2{% + % Prepare: + {% + \pgfarrows@getid{#1}{#2}% + % Do shift: + \expandafter\expandafter\expandafter\pgf@arrow@drawer@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname% + % Do slant: + \ifdim\pgfarrows@slant pt=0pt% + \else% + \pgftransformxslant{\pgfarrows@slant}% + \fi% + % do swap: + \ifpgfarrowswap% + \pgftransformyscale{-1}% + \fi% + {% + \csname pgf@ar@saves@\pgf@arrow@id\endcsname% + \pgf@arrows@rigid@hull% + }% + \expandafter}% + % Transform to next tip: + \expandafter\pgftransformxshift\expandafter{\the\pgf@xc}% +} + + + + +% Draw an arrow +% +% #1 = arrow tip list +% #2 = total length of the arrow (the value of \pgf@xb computed by +% \pgf@arrow@compute@shortening) +% +% Description: +% +% Draws an arrow tip list. The coordinate system must have been +% transformed so that the to-be-drawn arrow points right and should +% "end" at the origin. + +\def\pgf@arrow@draw@arrow#1#2{% + {% + \pgf@xb=#2% + \pgftransformxshift{-\pgf@xb}% + \let\pgf@arrow@handle\pgf@arrow@drawer + \let\pgf@arrow@handle@dot\relax% + #1% + }% +} + + +\def\pgf@arrow@drawer#1#2{% + % Prepare: + {% + \pgfarrows@getid{#1}{#2}% + % Do shift: + \expandafter\expandafter\expandafter\pgf@arrow@drawer@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname% + % Do slant: + \ifdim\pgfarrows@slant pt=0pt% + \else% + \pgftransformxslant{\pgfarrows@slant}% + \fi% + % do swap: + \ifpgfarrowswap% + \pgftransformyscale{-1}% + \fi% + {% + \csname pgf@ar@saves@\pgf@arrow@id\endcsname% + \pgfscope% + \pgf@arrows@color@setup% + \pgflowlevelsynccm\csname pgf@ar@cache@\pgf@arrow@id\endcsname% + \endpgfscope% + \pgf@arrows@rigid@hull% + }% + \expandafter}% + % Transform to next tip: + \expandafter\pgftransformxshift\expandafter{\the\pgf@xc}% +} + +\def\pgf@arrows@color@setup@restore@std@colors{% + % we want to allow 'arrows={fill=pgffillcolor}'. To this end, we have to ensure that \string\color@pgffillcolor is known. + % we can safely keep the macro in the current TeX group since it has global character anyway. + % + % Note that declaring \string\color@pgfstrokecolor as \global macro causes save stack issues and should be avoided. + \pgfutil@namelet{\string\color@pgfstrokecolor}{pgf@strokecolor@global}% + \pgfutil@namelet{\string\color@pgffillcolor}{pgf@fillcolor@global}% + % +}% + +\def\pgf@arrows@color@setup{% + \ifx\pgf@arrows@stroke@color\pgfutil@empty\else\pgfsetstrokecolor{\pgf@arrows@stroke@color}\fi% + \ifx\pgf@arrows@fill@color\pgfutil@empty% + \ifx\pgf@strokecolor@global\pgf@fillcolor@global + \else + \pgf@arrows@color@setup@restore@std@colors + \pgfsetfillcolor{pgfstrokecolor}% + \fi% + \else% + \pgf@arrows@color@setup@restore@std@colors + \pgfsetfillcolor{\pgf@arrows@fill@color}% + \fi% +} + +\def\pgf@arrow@drawer@shift#1#2#3{% tip end, back end, line end, sep + \pgf@xb#2\pgftransformxshift{-\pgf@xb}% + \pgf@xc#1% + \advance\pgf@xc by\pgfarrowsep% + \advance\pgf@xc by-\pgf@xb% +} + +\def\pgf@arrows@rigid@hull{% + \ifpgf@relevantforpicturesize% + % Do bb update: + \expandafter\let\expandafter\pgf@temp\csname pgf@ar@hull@\pgf@arrow@id\endcsname% + \ifx\pgf@temp\pgfutil@empty\else% + \let\pgf@arrow@hull@point\pgf@arrow@hull@point@first% + \pgf@temp% + \pgf@arrow@update@bb% + \fi% + \fi +} + + +% Convex hull stuff: + +\def\pgf@arrow@hull@point@first#1#2{% +% {\pgfsys@beginscope\pgfpathcircle{\pgfqpoint{#1}{#2}}{0.5pt}\pgfusepathqfill\pgfsys@endscope}% + \pgf@x#1\pgf@y#2% + \pgf@xa\pgf@pt@aa\pgf@x% + \advance\pgf@xa by\pgf@pt@ba\pgf@y% + \pgf@ya\pgf@pt@ab\pgf@x% + \advance\pgf@ya by\pgf@pt@bb\pgf@y% + \pgf@xb\pgf@xa\pgf@yb\pgf@ya% + \let\pgf@arrow@hull@point\pgf@arrow@hull@point@other% +} +\def\pgf@arrow@hull@point@other#1#2{% +% {\pgfsys@beginscope\pgfpathcircle{\pgfqpoint{#1}{#2}}{0.5pt}\pgfusepathqfill\pgfsys@endscope}% + \pgfutil@tempdima#1\pgfutil@tempdimb#2% + \pgf@x\pgf@pt@aa\pgfutil@tempdima% + \advance\pgf@x by\pgf@pt@ba\pgfutil@tempdimb% + \pgf@y\pgf@pt@ab\pgfutil@tempdima% + \advance\pgf@y by\pgf@pt@bb\pgfutil@tempdimb% + \ifdim\pgf@x<\pgf@xa\pgf@xa\pgf@x\else\ifdim\pgf@x>\pgf@xb\pgf@xb\pgf@x\fi\fi% + \ifdim\pgf@y<\pgf@ya\pgf@ya\pgf@y\else\ifdim\pgf@y>\pgf@yb\pgf@yb\pgf@y\fi\fi% +} + +\def\pgf@arrow@update@bb{% + \advance\pgf@xa by\pgf@pt@x% + \advance\pgf@ya by\pgf@pt@y% + \advance\pgf@xb by\pgf@pt@x% + \advance\pgf@yb by\pgf@pt@y% + \ifdim\pgf@picmaxx=-16000pt\relax% + \global\pgf@picminx\pgf@xa% + \global\pgf@picmaxx\pgf@xb% + \global\pgf@picminy\pgf@ya% + \global\pgf@picmaxy\pgf@yb% + \else% + \ifdim\pgf@xa<\pgf@picminx\global\pgf@picminx\pgf@xa\fi% + \ifdim\pgf@ya<\pgf@picminy\global\pgf@picminy\pgf@ya\fi% + \ifdim\pgf@xb>\pgf@picmaxx\global\pgf@picmaxx\pgf@xb\fi% + \ifdim\pgf@yb>\pgf@picmaxy\global\pgf@picmaxy\pgf@yb\fi% + \fi% +} + + + +% Sets arrows +% +% #1 = An arrow specification of the form +% -. This will call \pgfsetstartarrow{start +% spec} and \pgfsetendarrow{end spec}. +% +% Alternatively, it may be of the form [options]. In this case, +% the arrow options are set for the local scope and all arrows in +% the current scope will have these options set. +% +% Example: +% +% \pgfsetarrows{-to} + +\def\pgfsetarrows#1{\pgf@arrows#1\pgf@stop} +\def\pgf@arrows{\pgfutil@ifnextchar[\pgf@arrows@test@opt\pgf@arrows@}%} +\def\pgf@arrows@#1-#2\pgf@stop{% + \pgfsetarrowsstart{#1}% + \pgfsetarrowsend{#2}% +} +\def\pgf@arrows@test@opt[{% + \pgfutil@ifnextchar-{\pgf@arrows@[}%} go back to normal reading for compat. reasons. + \pgf@arrows@test@opt@% +} +\def\pgf@arrows@test@opt@#1]{% + \pgfutil@ifnextchar\pgf@stop{% + \let\pgf@arrows@options\pgf@arrows@options@scope% + \pgfkeys{/pgf/arrow keys/.cd,#1}% + \let\pgf@arrows@options@scope\pgf@arrows@options% + % Ok, setup the options + \pgfutil@gobble% + }{% + \pgf@arrows@[#1]% Oops: go back to normal mode + }% +} + +\let\pgf@arrows@options@scope\pgfutil@empty + + + + +% +% Predefined arrows: +% + + +% A dot is used to indicate the end of the line: + +\pgfdeclarearrow{ + name = ., + drawing code = +} + + +% An underscore adds a space as in >_> or >_ >. However, it will be +% faster to say ">[sep] >" or ">[sep=2pt] >". + +\pgfdeclarearrow{ + name = _, + defaults = {sep}, + drawing code = +} + + + +% Default shorthands: + +\pgfdeclarearrow{ name = To, means = } % forward declaration +\pgfdeclarearrow{ name = Bar, means = } % forward declaration +\pgfkeys{ + <-> /.tip = {To}, + >-< /.tip = {>[reversed]}, + | /.tip = {Bar} +} + + + +% Compatibility with old arrow system: + +\pgfkeys {} + +\def\pgf@arrows@direct@def#1#2{\expandafter\pgf@arrows@direct@def@\expandafter{\csname pgf@ar@means@#2\endcsname}{#1}} +\def\pgf@arrows@direct@def@#1#2{\expandafter\def\csname pgf@arrows@direct@name@#2\endcsname{\pgf@arrow@handle@shorthand@empty{#1}}} +\pgf@arrows@direct@def{start@[}{]} +\pgf@arrows@direct@def{start@]}{[} +\pgf@arrows@direct@def{start@spaced [}{spaced ]} +\pgf@arrows@direct@def{start@spaced ]}{spaced [} +\pgf@arrows@direct@def{end@[}{[} +\pgf@arrows@direct@def{end@]}{]} +\pgf@arrows@direct@def{end@spaced [}{spaced [} +\pgf@arrows@direct@def{end@spaced ]}{spaced ]} + +\def\pgfsetarrowoptions#1#2{\expandafter\def\csname pgf@arrow@compat@opt@#1\endcsname{#2}} +\def\pgfgetarrowoptions#1{\csname pgf@arrow@compat@opt@#1\endcsname} +\def\pgfarrowsdeclare#1#2#3#4{% + \pgfdeclarearrow{ name ={#1}-{#2}, setup code ={#3}, drawing code={#4}, parameters/.expand once={\csname pgf@arrow@compat@opt@#2\endcsname}}% + \expandafter\def\csname pgf@arrow@compat@opt@#2\endcsname{0}} +\def\pgfarrowsleftextend#1{\pgfmathsetlength\pgf@xa{#1}\pgfarrowssetbackend{\pgf@xa}} +\def\pgfarrowsrightextend#1{\pgfmathsetlength\pgf@xb{#1}\pgfarrowssettipend{\pgf@xb}} +\def\pgfarrowsdeclarealias#1#2#3#4{\pgfdeclarearrow{ name ={#1}-{#2}, means ={#4} } } +\def\pgfarrowsdeclarereversed#1#2#3#4{\pgfdeclarearrow{ name ={#1}-{#2}, means={{#4}[reversed]}}} +\def\pgfarrowsdeclarecombine{\pgfutil@ifnextchar*{\pgfarrowsdeclarecombine@star}{\pgf@@arrowsdeclarecombine}} +\def\pgf@@arrowsdeclarecombine{\pgfutil@ifnextchar[{\pgf@arrowsdeclarecombine}{\pgf@arrowsdeclarecombine[0pt]}} +\def\pgf@arrowsdeclarecombine[#1]#2#3#4#5#6#7{\def\pgf@@temp{#1}\ifx\pgf@@temp\pgf@linewidthtext\def\pgf@@temp{+0pt 1}\fi% + \pgfdeclarearrow{name ={#2}-{#3}, means={#5[sep/.expand once=\pgf@@temp]#6}}} +\def\pgf@linewidth@text{\pgflinewidth} +\def\pgfarrowsdeclarecombine@star*{\pgfutil@ifnextchar[{\pgf@arrowsdeclarecombine@star}{\pgf@arrowsdeclarecombine@star[0pt]}} +\def\pgf@arrowsdeclarecombine@star[#1]#2#3#4#5#6#7{\def\pgf@@temp{#1}\ifx\pgf@@temp\pgf@linewidthtext\def\pgf@@temp{+0pt 1}\fi% + \pgfdeclarearrow{name ={#2}-{#3}, means={#5[sep/.expand once=\pgf@@temp].#6}}} +\def\pgfarrowsdeclaredouble{\pgfutil@ifnextchar[{\pgf@arrowsdeclaredouble}{\pgf@arrowsdeclaredouble[0pt]}} +\def\pgf@arrowsdeclaredouble[#1]#2#3#4#5{\pgfarrowsdeclarecombine[#1]{#2}{#3}{#4}{#5}{#4}{#5}} +\def\pgfarrowsdeclaretriple{\pgfutil@ifnextchar[{\pgf@arrowsdeclaretriple}{\pgf@arrowsdeclaretriple[0pt]}} +\def\pgf@arrowsdeclaretriple[#1]#2#3#4#5{ \pgfarrowsdeclarecombine[#1]{pgf@trip@#2}{pgf@trip@#3}{#4}{#5}{#4}{#5}% + \pgfarrowsdeclarecombine[#1]{#2}{#3}{pgf@trip@#2}{pgf@trip@#3}{#4}{#5}} +\def\pgf@linewidthtext{\pgflinewidth} + +\pgfarrowsdeclare{stealth}{stealth} +{ + \pgfutil@tempdima=0.28pt% + \pgfutil@tempdimb=\pgflinewidth% + \ifdim\pgfinnerlinewidth>0pt% + \pgfmathsetlength\pgfutil@tempdimb{.6\pgflinewidth-.4*\pgfinnerlinewidth}% + \fi% + \advance\pgfutil@tempdima by.3\pgfutil@tempdimb% + \pgfarrowsleftextend{+-3\pgfutil@tempdima} + \pgfarrowsrightextend{+5\pgfutil@tempdima} +} +{ + \pgfutil@tempdima=0.28pt% + \pgfutil@tempdimb=\pgflinewidth% + \ifdim\pgfinnerlinewidth>0pt% + \pgfmathsetlength\pgfutil@tempdimb{.6\pgflinewidth-.4*\pgfinnerlinewidth}% + \fi% + \advance\pgfutil@tempdima by.3\pgfutil@tempdimb% + \pgfpathmoveto{\pgfqpoint{5\pgfutil@tempdima}{0pt}} + \pgfpathlineto{\pgfqpoint{-3\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointorigin} + \pgfpathlineto{\pgfqpoint{-3\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfusepathqfill +} +\pgfarrowsdeclarereversed{stealth reversed}{stealth reversed}{stealth}{stealth} +\pgfarrowsdeclare{to}{to} +{ + \pgfutil@tempdima=-0.84pt% + \advance\pgfutil@tempdima by-1.3\pgflinewidth% + \pgfutil@tempdimb=0.21pt% + \advance\pgfutil@tempdimb by.625\pgflinewidth% + \pgfarrowsleftextend{+\pgfutil@tempdima} + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetlinewidth{0.8\pgflinewidth} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{-3\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-2.75\pgfutil@tempdima}{2.5\pgfutil@tempdima}} + {\pgfqpoint{0pt}{0.25\pgfutil@tempdima}} + {\pgfqpoint{0.75\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{0pt}{-0.25\pgfutil@tempdima}} + {\pgfqpoint{-2.75\pgfutil@tempdima}{-2.5\pgfutil@tempdima}} + {\pgfqpoint{-3\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfusepathqstroke +} +\pgfkeys{To /.tip = to} +\pgfarrowsdeclare{to reversed}{to reversed} +{ + \pgfutil@tempdima=-0.21pt% + \advance\pgfutil@tempdima by-0.475\pgflinewidth% + \pgfutil@tempdimb=0.98pt% + \advance\pgfutil@tempdimb by1.45\pgflinewidth% + \pgfarrowsleftextend{+\pgfutil@tempdima} + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetlinewidth{+0.8\pgflinewidth} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{3.5\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{3.25\pgfutil@tempdima}{2.5\pgfutil@tempdima}} + {\pgfqpoint{0.5\pgfutil@tempdima}{0.25\pgfutil@tempdima}} + {\pgfqpoint{-0.25\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{0.5\pgfutil@tempdima}{-0.25\pgfutil@tempdima}} + {\pgfqpoint{3.25\pgfutil@tempdima}{-2.5\pgfutil@tempdima}} + {\pgfqpoint{3.5\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfusepathqstroke +} +\pgfarrowsdeclare{latex}{latex} +{ + \pgfutil@tempdima=0.28pt% + \pgfutil@tempdimb=\pgflinewidth% + \ifdim\pgfinnerlinewidth>0pt% + \pgfmathsetlength\pgfutil@tempdimb{.6\pgflinewidth-.4*\pgfinnerlinewidth}% + \fi% + \advance\pgfutil@tempdima by.3\pgfutil@tempdimb% + \pgfarrowsleftextend{+-1\pgfutil@tempdima} + \pgfarrowsrightextend{+9\pgfutil@tempdima} +} +{ + \pgfutil@tempdima=0.28pt% + \pgfutil@tempdimb=\pgflinewidth% + \ifdim\pgfinnerlinewidth>0pt% + \pgfmathsetlength\pgfutil@tempdimb{.6\pgflinewidth-.4*\pgfinnerlinewidth}% + \fi% + \advance\pgfutil@tempdima by.3\pgfutil@tempdimb% + \pgfpathmoveto{\pgfqpoint{9\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{6.3333\pgfutil@tempdima}{.5\pgfutil@tempdima}} + {\pgfqpoint{2\pgfutil@tempdima}{2\pgfutil@tempdima}} + {\pgfqpoint{-1\pgfutil@tempdima}{3.75\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-1\pgfutil@tempdima}{-3.75\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{2\pgfutil@tempdima}{-2\pgfutil@tempdima}} + {\pgfqpoint{6.3333\pgfutil@tempdima}{-.5\pgfutil@tempdima}} + {\pgfqpoint{9\pgfutil@tempdima}{0pt}} + \pgfusepathqfill +} +\pgfarrowsdeclarereversed{latex reversed}{latex reversed}{latex}{latex} +\pgfarrowsdeclare{@bar}{@bar} +{ + \pgfarrowsleftextend{+-0.25\pgflinewidth} + \pgfarrowsrightextend{+.75\pgflinewidth} +} +{ + \pgfutil@tempdima=2pt% + \advance\pgfutil@tempdima by1.5\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetrectcap + \pgfpathmoveto{\pgfqpoint{0.25\pgflinewidth}{-\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.25\pgflinewidth}{\pgfutil@tempdima}} + \pgfusepathqstroke +} +\pgfkeys{Bar /.tip = @bar} +\pgfarrowsdeclare{space}{space} +{ + \pgfutil@tempdima=0.88pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfarrowsleftextend{0pt} + \pgfarrowsrightextend{\pgfutil@tempdima} +} +{} + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoreexternal.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreexternal.code.tex new file mode 100644 index 0000000000..f6fef57755 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreexternal.code.tex @@ -0,0 +1,542 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoreexternal.code.tex} + + + +\newif\ifpgfexternal@aux@in@dpth +\newif\ifpgfexternal@info + +\pgfkeys{ + /pgf/images/include external/.code={\pgfimage{#1}}, + /pgf/images/aux in dpth/.is if=pgfexternal@aux@in@dpth, + /pgf/images/aux in dpth/.default=true, + /pgf/images/trim external/.code n args={4}{% + \def\pgf@external@kern@left{#1}% + \def\pgf@external@kern@bottom{#2}% + \def\pgf@external@kern@right{#3}% + \def\pgf@external@kern@top{#4}% + \ifx\pgf@external@kern@left\pgfutil@empty\def\pgf@external@kern@left{0sp}\fi% + \ifx\pgf@external@kern@bottom\pgfutil@empty\def\pgf@external@kern@bottom{0sp}\fi% + \ifx\pgf@external@kern@right\pgfutil@empty\def\pgf@external@kern@right{0sp}\fi% + \ifx\pgf@external@kern@top\pgfutil@empty\def\pgf@external@kern@top{0sp}\fi% + }, + /pgf/images/trim external={1truein}{1truein}{1truein}{1truein}, + /pgf/images/external info/.is if=pgfexternal@info, + /pgf/images/external info/.default=true, +} + +% The external read/write mechanism is used as follows: +% +% In your document, you put a number or all of your pgfpicture (or +% tikzpicture) environments inside a pair of \beginpgfexternal and +% \endpgfexternal. The \beginpgfexternal gets one parameter called the +% graphics name. +% +% Once this is done, the next step is to declare the names of your +% graphics in the document at the beginning using the +% \pgfdeclaregraphicname command. +% +% Now, when you typeset your document, each time a \beginpgfexternal +% command is encountered, it will be checked whether the corresponding +% graphics file exists. If this is the case, it will be included and +% the code between \beginpgfexternal and \endpgfexternal is +% ignored. Otherwise, the code is executed normally. +% +% Things change when you run tex on your file with the \jobname set to +% the name of a declared graphics name. In this case, only your +% graphic will be typeset, the rest of the document will be "thrown away". +% To be more precise, everything is gobbled up to the beginning +% of the first \beginpgfexternal with the given graphics name. Then, +% the content of the "environment" is put in a box (this "environment" +% need not contain a graphics, it may contain anything that can be put +% in a box). Then a single page is output whose size is exactly the +% size of the picture. +% +% So, once you have run tex repeatedly, each time with the jobname set +% to each of the graphics, you can then run tex on the whole document +% and this will cause all graphics to be included rather than begin +% typeset. +% +% Finally, once all the graphics have been created, you can also say +% \input pgfexternal.tex instead of including pgf/TikZ. + + +\newif\ifpgfexternalreadmainaux +\pgfexternalreadmainauxtrue + +% Tells pgf which jobname is the name of the real file +% +% #1 = name +% +% Description: +% +% This command is used to tell pgf that the file named #1 should be +% typeset normally. If \jobname is not equal to #1, only +% the graphic called \jobname will be typeset. +% +% Example: +% +% \pgfrealjobname{survey} +% +% Note that afterwards, \jobname will be set to the argument. In our +% example, \jobname will be 'survey'. This is to accomplish +% compatibility with aux-file generation. + +\def\pgfrealjobname#1{% + \global\let\pgfactualjobname=\jobname + \edef\pgf@tempa{\expandafter\string\csname #1\endcsname}% + \edef\pgf@tempb{\expandafter\string\csname\jobname\endcsname}% + \ifx\pgf@tempa\pgf@tempb% + \else% + \pgf@external@grabshipouttrue% + \pgfexternal@nofiles% see also \pgf@external@init@aux@in@dpth + \ifpgfexternalreadmainaux + % and reset the jobname. This should allow to handle any + % \label/\ref constructions which are stored in \jobname.aux (and + % which won't be found otherwise) + \gdef\jobname{#1}% + \fi + \ifpgfexternal@aux@in@dpth + \csname newwrite\endcsname\w@pgfexternal@auxout + \fi + \pgfexternal@geometry@compatibility + \fi% + \gdef\pgfrealjobname##1{}% avoid multiple calls. +} + +\def\pgfexternal@geometry@compatibility{% + % check if \usepackage{geometry} is loaded: + \pgfutil@ifundefined{geometry}{% + }{% + % The geometry package hooks into \begin{document}, evaluates + % its driver -- and generates \special instructions to set the + % paper size. + % + % Unfortunately, this confuses dvips utterly - and perhaps + % other drivers as well. + % + % Thus, if we currently about to generate some external + % graphics, we WANT to disable geometry (it has no purpose in + % this context anyway). + % + % This here works well: + \pgf@typeout{Package TikZ externalization: calling \string\geometry{driver=none} during externalization.^^J}% + \geometry{driver=none}% + }% +}% + +\def\pgfexternal@nofiles{% + % replace \relax. The \nofiles macros does + % \let\makeglossary=\relax + % but the glossary.sty calls \renewcommand\makeglossary (which + % will fail if \makeglossary=\relax). Stupid, but it works. + \let\pgfexternal@nofiles@=\relax + \def\relax{\relax}% + % + % suppress generation of LaTeX .aux, .toc etc files. + % generation of these files is not thread-safe. + % the \csname \endcsname yields \relax if \nofiles doesn't exist. + \csname nofiles\endcsname + % + \let\relax=\pgfexternal@nofiles@ +}% + +\newif\ifpgf@external@grabshipout +\newbox\pgfexternal@startupbox + +\pgfutil@ifundefined{AtBeginDocument}{}{% + \AtBeginDocument{% + \ifpgf@external@grabshipout% + \global\let\pgfexternal@originalshipout=\shipout% + \global\def\shipout{\setbox\pgfpic=}% + \maxdeadcycles=10000% + % Ok, gather everything we have seen up to now in a box. This box + % will contain any specials that have been used. + {% + \output{\global\setbox\pgfexternal@startupbox=\vbox{\csname @begindvi\endcsname\unvbox255}}% + \hbox{}\eject% + }% + \fi% + } +}% + +\pgfutil@ifundefined{AtEndDocument}{}{% + \AtEndDocument{% + \ifpgf@external@grabshipout + \pgfutil@ifundefined{pgfexternal@did@a@shipout}{% + \pgfexternal@error@no@shipout + }{}% + \fi + }% +} + +% This will be overwritten by the tikz external lib if it is loaded. +\def\pgfexternal@error@no@shipout{% + \pgferror{Sorry, image externalization failed: the resulting image was EMPTY. I tried to externalize '\pgfactualjobname'. Perhaps there was a typo somewhere? Please check that your document contains '\string\beginpgfgraphicnamed{\pgfactualjobname} ... \string\endpgfgraphicnamed'}% +}% + + +% "Environment" for an external graphic. +% +% #1 = graphic name +% +% Example: +% +% \beginpgfgraphicnamed{main-graphic2} +% \begin{tikzpicture} +% ... +% \end{tikzpicture} +% \endpgfgraphicnamed + +\def\pgf@externalbegin#1{% + % First, check whether we wish to grab this graphic: + \let\pgf@next=\pgf@external@normal% + \ifpgf@external@grabshipout% + \edef\pgf@tempa{\expandafter\string\csname #1\endcsname}% + \edef\pgf@tempb{\expandafter\string\csname\pgfactualjobname\endcsname}% + \ifx\pgf@tempa\pgf@tempb% + \let\pgf@next=\pgf@external@grab% + \fi% + \fi% + \pgf@next{#1}% +} + + +\AtBeginDocument{ + \let\beginpgfgraphicnamed=\pgf@externalbegin% overwrite definition of pgfexternal.tex if necessary + \let\endpgfgraphicnamed=\unskip +} + + +% Normal operation: Include an external graphic instead of the +% picture, if such an external picture exists. +\def\pgf@external@normal#1{% + \let\pgf@filename=\pgfutil@empty% + \expandafter\pgf@findfile\pgfsys@imagesuffixlist:+{#1}% + \ifx\pgf@filename\pgfutil@empty% + % Ok, no such image... Just typeset the picture normally. + \let\pgf@next=\relax% + \else% + \let\pgf@next=\pgf@replacepicturebygraphic% + \fi% + \pgf@next% +} + +\long\def\pgf@replacepicturebygraphic#1\endpgfgraphicnamed{% + \expandafter\pgfincludeexternalgraphics\expandafter{\pgf@filename}\unskip +} + +% This is almost the same as \includegraphics{#1}, but it checks +% whether '#1.dpth' exists. In such case, it restores the boxes depth +% stored in #1.dpth. +% +% Furthermore, the .dpth file may contain .aux related information +% collected for the external graphics (references). They start after +% the first line (if any). +\def\pgfincludeexternalgraphics#1{% + \begingroup + \pgfexternalreaddpth{#1}% + \pgfkeysifdefined{/pgf/images/include external/#1/.@cmd}{% + \pgfkeysgetvalue{/pgf/images/include external/#1/.@cmd}\pgf@tempa + \pgfkeyslet{/pgf/images/include external/.@cmd}\pgf@tempa + }{}% + \setbox1=\hbox{\pgfkeysvalueof{/pgf/images/include external/.@cmd}{#1}\pgfeov}% + \ifdim\pgfexternaltrimleft=0sp \else \kern\pgfexternaltrimleft\relax \fi + \ifdim\pgfexternaldepth=0pt + \box1 + \else + \dimen0=\pgfexternaldepth\relax + \hbox{\lower\dimen0 \box1 }% + \fi + \ifdim\pgfexternaltrimright=0sp \else \kern\pgfexternaltrimright\relax \fi + \endgroup +} + +% Reads the .dpth file which contains meta data of the external +% picture. +% +% This command handles the following stuff: +% - it defines \pgfexternaldepth . The macro contains the contents of +% a line which does not start with a control sequence (for example a +% line containing '50pt') +% - it defines \pgfexternaltrimleft and \pgfexternaltrimright +% - it checks if the .dpth file contains content stored by means of +% \pgfexternalstorecommand. If so, the argument of +% \pgfexternalstorecommand will be restored. +% - anything else will be appended to the main .aux file, assuming that +% it contains \label or \ref information (only if the LaTeX switch +% \if@filesw is \iftrue). +% +% +% #1: the image file name (such that #1.dpth exists) +\def\pgfexternalreaddpth#1{% + % no \begingroup. Handle that manually: + \edef\pgfexternalreaddpth@restore{% + \noexpand\endlinechar=\the\endlinechar\space + \noexpand\catcode`\noexpand\@=\the\catcode`\@\space + }% + % + \def\pgfexternaldepth{0sp}% + \def\pgfexternaltrimleft{0sp}% + \def\pgfexternaltrimright{0sp}% + \endlinechar=-1 % suppress white space at end + \catcode`\@=11 + \openin\r@pgf@reada=#1.dpth + \pgfincludeexternalgraphics@read@dpth + % + \pgfexternalreaddpth@restore +}% +% +% The .dpth consists of 0-N lines, where each is either a single +% dimension (the box' depth) or something which belongs to the .aux +% file (such lines will always start with a macro). +\def\pgfincludeexternalgraphics@read@dpth{% + \ifeof\r@pgf@reada + \closein\r@pgf@reada + \else + \read\r@pgf@reada to\pgfincludeexternalgraphics@auxline + \ifx\pgfincludeexternalgraphics@auxline\pgfutil@empty + \else + \expandafter\pgfincludeexternalgraphics@read@dpth@line\pgfincludeexternalgraphics@auxline\pgfincludeexternalgraphics@read@dpth@line@EOI + \fi + \expandafter\pgfincludeexternalgraphics@read@dpth + \fi +}% + +\def\pgfexternal@restore#1{#1}% + +\long\def\pgfincludeexternalgraphics@read@dpth@line@getfirst#1#2\pgfincludeexternalgraphics@read@dpth@line@EOI{% + \def\pgf@first{#1}% +}% +\long\def\pgfincludeexternalgraphics@read@dpth@line#1\pgfincludeexternalgraphics@read@dpth@line@EOI{% + \pgfincludeexternalgraphics@read@dpth@line@getfirst#1\pgfincludeexternalgraphics@read@dpth@line@EOI + \expandafter\ifcat\expandafter\noexpand\pgf@first\relax + % Ah -- the first token is a control sequence. It belongs to + % the .aux file. + % + \expandafter\ifx\pgf@first\pgfexternal@restore + % if the first line in the .dpth file starts with the + % magic string \pgfexternal@restore, the complete line + % will be executed as-is. Example: + % \pgfexternal@restore{\def\somevalue{1}} + #1% + \else + % do NOT execute #1! many LaTeX commands don't support it (\label for example) + \pgfutil@ifundefined{if@filesw}{% + % sorry, .aux file support only for latex + }{% + % append to main .aux file (for forward references) + \if@filesw + {% + \toks0={#1}% + % believe it or not, but the + % \def\dpthimport{...}\dpthimport *makes* a + % difference! In ensures any occurring `##' characters are properly expanded to `#'. + \immediate\write\@auxout{% + \noexpand\def\noexpand\dpthimport{\the\toks0}\noexpand\dpthimport}% + }% + \fi + }% + \fi + \else% it is the depth (which is simply a number for backwards compatibility) + \def\pgfexternaldepth{#1}% + \fi +}% + +% Stores '#1' (expanded!) into the .dpth file of the currently +% exported image. +% +% This command has only an effect if an image is being exported. +% +% The stored contents will be read in the context where +% /pgf/images/include external is active (i.e. by +% \pgfexternalreaddpth). +% +\def\pgfexternalstorecommand#1{% +}% +\def\pgfexternalstorecommand@isexporting#1{% + \immediate\write\w@pgfexternal@auxout{\noexpand\pgfexternal@restore{#1}}% +}% + + + +% Grab operation: If jobname matches the graphic name, typeset this +% picture normal. +% REMARK: +% this method is also invoked from within the tikz external library. +\def\pgf@external@grab#1{% + \def\pgf@filename{#1}% + \ifpgfexternal@aux@in@dpth + \begingroup + \pgf@external@init@aux@in@dpth + \let\G@refundefinedtrue=\pgf@external@grab@refundefinedtrue + \fi + \gdef\pgf@trimleft@final{0sp}% + \gdef\pgf@trimright@final{0sp}% + \setbox\pgfpic=\hbox\bgroup\bgroup% + \let\endpgfgraphicnamed=\pgf@externalend% +} + +{\catcode`\^=12 \gdef\pgfexternal@hat{^}} + +\expandafter\let\expandafter\pgf@external@grab@refundefinedtrue@orig\csname G@refundefinedtrue\endcsname + +\def\pgf@external@grab@refundefinedtrue{% + \pgf@external@grab@refundefinedtrue@orig + \begingroup + \def\n{\pgfexternal@hat\pgfexternal@hat J}% + \pgfexternalstorecommand{% + \pgf@external@grab@refundefinedtrue@code + \noexpand\immediate\noexpand\write16{\pgf@external@grab@refundefinedtrue@warning}% + \noexpand\G@refundefinedtrue + }% + \endgroup +}% + +% A hook. will be overwritten by \usetikzlibrary{external} +\def\pgf@external@grab@refundefinedtrue@code{} + +\def\pgf@external@grab@refundefinedtrue@warning{% + LaTeX Warning: External picture `\pgfactualjobname' contains undefined references\noexpand\on@line.\n +}% + +\let\pgf@external@@protected@write@orig=\protected@write +\long\def\pgf@external@@protected@write@immediate#1#2#3{% + \begingroup + \let\pgf@write@=\write + \def\write{\noexpand\immediate\pgf@write@}% + \pgf@external@@protected@write@orig{#1}{#2}{#3}% + \endgroup +}% + +\def\pgf@external@init@aux@in@dpth{% + \let\pgfexternalstorecommand=\pgfexternalstorecommand@isexporting + % + % tell LaTeX to write aux files... + \csname @fileswtrue\endcsname + % ... but redirect output to the .dpth file! + \immediate\openout\w@pgfexternal@auxout=\pgf@filename.dpth + \let\@auxout=\w@pgfexternal@auxout + % ... and disable the correct page numbers. I can't get that + % (because the correct page number is only available in the + % shipout routine). Use immediate output: + \let\protected@write=\pgf@external@@protected@write@immediate +}% + +\def\pgf@externalend@storeshifts#1{% + \immediate\write#1{\the\dp\pgfpic}% store the depth simply as number for backw. compat. + \ifx\pgf@trimleft@final\pgfutil@empty\else + \immediate\write#1{\noexpand\pgfexternal@restore{\noexpand\def\noexpand\pgfexternaltrimleft{\pgf@trimleft@final}}}% + \fi + \ifx\pgf@trimright@final\pgfutil@empty\else + \immediate\write#1{\noexpand\pgfexternal@restore{\noexpand\def\noexpand\pgfexternaltrimright{\pgf@trimright@final}}}% + \fi + \ifpgfexternal@info + \immediate\write#1{\noexpand\pgfexternal@restore{\noexpand\def\noexpand\pgfexternalwidth{\the\wd\pgfpic}}}% + \immediate\write#1{\noexpand\pgfexternal@restore{\noexpand\def\noexpand\pgfexternalheight{\the\dimen0}}}% + \fi +} +% REMARK: +% this method is also invoked from within the tikz external library. +\def\pgf@externalend{% + \unskip\egroup\egroup% + {% + \def\pgf@external@trim{0}% + \def\pgf@external@store@dpth{0}% + % + \ifpgf@trim@lowlevel + \gdef\pgf@trimleft@final{}% + \gdef\pgf@trimright@final{}% + \else + \ifdim\pgf@trimleft@final=0sp \gdef\pgf@trimleft@final{} \else\def\pgf@external@trim{1}\fi + \ifdim\pgf@trimright@final=0sp \gdef\pgf@trimright@final{} \else\def\pgf@external@trim{1}\fi + \if1\pgf@external@trim + % UNDO the trimming! export to pdf doesn't supported trimmed + % bounding boxes (has to do with the mediabox/trimbox etc). + % I'll keep the bounding box intact and store the trim information + % into the .dpth file. + \setbox\pgfpic=\hbox{% + \ifx\pgf@trimleft@final\pgfutil@empty\else\kern-\pgf@trimleft@final\fi + \box\pgfpic + \ifx\pgf@trimright@final\pgfutil@empty\else\kern-\pgf@trimright@final\fi + }% + \def\pgf@external@store@dpth{1}% + \fi + \fi + % + \parindent0pt % leave the space +% \leftmargin0pt% +% \rightmargin0pt% + \hoffset=0pt % reset to default + \voffset=0pt + \dimen0\ht\pgfpic% + \advance\dimen0\dp\pgfpic% + \ifdim\dp\pgfpic=0pt\relax + \else% store the picture's depth. Otherwise, it would be lost. + \def\pgf@external@store@dpth{1}% + \fi + \ifpgfexternal@info + \def\pgf@external@store@dpth{1}% + \fi + % + \if1\pgf@external@store@dpth + \ifpgfexternal@aux@in@dpth + \pgf@externalend@storeshifts\@auxout + \immediate\closeout\@auxout + \else + \immediate\openout\pgf@plotwrite=\pgf@filename.dpth + \pgf@externalend@storeshifts\pgf@plotwrite + \immediate\closeout\pgf@plotwrite + \fi + \fi + \pgfsys@prepare@papersize{\the\wd\pgfpic}{\the\dimen0}% + % + \setbox0=\vbox{% + % I admit that I don't know why there is this kerning: + \kern -\pgf@external@kern@top\relax% + \hbox{% + \kern -\pgf@external@kern@left\relax% + \hbox to0pt{% + \wd\pgfexternal@startupbox=0pt % + \ht\pgfexternal@startupbox=0pt % + \dp\pgfexternal@startupbox=0pt % + \box\pgfexternal@startupbox% + \pgfsys@atbegindocument\hss}% + \box\pgfpic% + \kern\pgf@external@kern@right\relax% + }% + \kern\pgf@external@kern@bottom\relax% + }% + % + % compatibility with eso-pic package: \nointerlineskip is not + % allowed here, but the eso-pic package uses \nointerlineskip in + % its shipout routine. + \let\pgfexternal@nointerlineskip@orig=\nointerlineskip + \let\nointerlineskip=\pgfexternal@nointerlineskip + % + \pgfexternal@originalshipout\box0 % + \gdef\pgfexternal@did@a@shipout{1}% + }% + \ifpgfexternal@aux@in@dpth + \endgroup + \fi +} + +\def\pgfexternal@nointerlineskip{% + \ifvmode + \pgfexternal@nointerlineskip@orig + \else + \relax% \nointerlineskip in horizontal mode not allowed. Silently ignore the error message. + \fi +}% + +\endinput +% vi: tabstop=4 shiftwidth=2 expandtab diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoregraphicstate.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoregraphicstate.code.tex new file mode 100644 index 0000000000..f7783dcd98 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoregraphicstate.code.tex @@ -0,0 +1,280 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoregraphicstate.code.tex} + +% Globals + +\newdimen\pgflinewidth + + +% Set the line width to #1. +% +% #1 = new line width. +% +% Example: +% +% \pgfsetlinewidth{3pt} + +\def\pgfsetlinewidth#1{% + \pgfmathsetlength\pgflinewidth{#1}% + \global\pgflinewidth=\pgflinewidth% + \pgfsys@setlinewidth{\the\pgflinewidth}% + \ignorespaces} + + +% Set the inner line width to #1. +% +% #1 = new inner line width. +% +% Description: +% +% The inner line width is the width of a second line that is drawn on +% top of the main stroked line. If the inner line width is 0pt, no +% inner line is drawn. The main use of inner lines is for creating +% "double" lines. +% +% Inner lines are not drawn when a path is used for clipping. +% +% The inner line width is local to the current TeX group, it is not +% part of the graphic state. +% +% Example: +% +% \pgfsetinnerlinewidth{1pt} + +\def\pgfsetinnerlinewidth#1{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgfinnerlinewidth{\the\pgf@x}% +} +\def\pgfinnerlinewidth{0pt} + + +% Set the inner line color to #1. +% +% #1 = color for the inner line +% +% Example: +% +% \pgfsetinnerlinecolor{green} % yikes! + +\def\pgfsetinnerstrokecolor#1{\def\pgfinnerstrokecolor{#1}} +\def\pgfinnerstrokecolor{white} + + +% Set the miter limit to #1. +% +% #1 = new miter limit factor. +% +% Example: +% +% \pgfsetmiterlimit{3} + +\def\pgfsetmiterlimit#1{% + \ifdim#1pt<1pt\pgferror{miter limit cannot be less than 1}\fi% + \pgfsys@setmiterlimit{#1}% + \ignorespaces} + + +% Set the dash pattern to #1 with phase #2/ +% +% #1 = a row of numbers of length of ``on'' and ``off'' points. +% #2 = a phase +% +% Example: +% +% \pgfsetdash{} {0pt} % solid line +% \pgfsetdash{{.1cm}} {0pt} % long dashes +% \pgfsetdash{{1pt}{1ex}}{0pt} % dotted + +\def\pgfsetdash#1#2{% + \def\pgf@temp{}% + \def\pgf@next{\pgf@strip}% + \pgf@strip#1{pgf@stop}% + \pgfmathsetlength\pgf@x{#2}% + \pgfsys@setdash{\pgf@temp}{\the\pgf@x}% + \ignorespaces} + +\def\pgf@strip#1{% + \def\pgf@@temp{#1}% + \ifx\pgf@@temp\pgf@stop% + \let\pgf@next=\relax% + \else% + \pgfmathsetlength\pgf@x{#1}% + \ifx\pgf@temp\pgfutil@empty% + \edef\pgf@temp{\the\pgf@x}% + \else% + \edef\pgf@temp{\pgf@temp,\the\pgf@x}% + \fi% + \fi\pgf@next} + +\def\pgf@stop{pgf@stop} + + +% Set color of strokes. This will overrule the normal color. +% +% Example: +% +% \pgfsetstrokecolor{red} + +\def\pgfsetstrokecolor#1{% + \pgfutil@colorlet{pgfstrokecolor}{#1}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgfstrokecolor}}% + \expandafter\let\expandafter\pgf@temp\csname\string\color@pgfstrokecolor\endcsname + % for arrow tips: + \global\let\pgf@strokecolor@global=\pgf@temp + \expandafter\pgf@setstrokecolor\pgf@temp% +} +\def\pgf@setstrokecolor#1#2#3#4#5{% + \expandafter\ifx\csname pgfsys@color@#4@stroke\endcsname\relax% + \pgferror{Unsupported color model `#4'. Sorry}% + \else% + \edef\pgf@colmarshal{\expandafter\noexpand\csname pgfsys@color@#4@stroke\endcsname}% + \pgf@uncomma#5,,% + \pgf@colmarshal% + \fi} + +\def\pgf@uncomma#1,{% + \def\pgf@coltest{#1}% + \ifx\pgf@coltest\pgfutil@empty% + \let\pgf@colnext=\relax% + \else% + \expandafter\def\expandafter\pgf@colmarshal\expandafter{\pgf@colmarshal{#1}}% + \let\pgf@colnext=\pgf@uncomma% + \fi% + \pgf@colnext% +} + + +% Set color of fills. This will overrule the normal color. +% +% Example: +% +% \pgfsetfillcolor{gray} + +\def\pgfsetfillcolor#1{% + \pgfutil@colorlet{pgffillcolor}{#1}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgffillcolor}}% + \expandafter\let\expandafter\pgf@temp\csname\string\color@pgffillcolor\endcsname + % for arrow tips: + \global\let\pgf@fillcolor@global=\pgf@temp + \expandafter\pgf@setfillcolor\pgf@temp +} +\def\pgf@setfillcolor#1#2#3#4#5{% + \expandafter\ifx\csname pgfsys@color@#4@fill\endcsname\relax% + \pgferror{Unsupported color model `#4'. Sorry}% + \else% + \edef\pgf@colmarshal{\expandafter\noexpand\csname pgfsys@color@#4@fill\endcsname}% + \pgf@uncomma#5,,% + \pgf@colmarshal% + \fi} + + + +% Sets both the stroke and fill color. +% +% Example: +% +% \pgfsetcolor{blue} + +\def\pgfsetcolor#1{% + \pgfutil@colorlet{pgfstrokecolor}{#1}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgfstrokecolor}}% + \expandafter\let\expandafter\pgf@temp\csname\string\color@pgfstrokecolor\endcsname + % for arrow tips: + \global\let\pgf@strokecolor@global=\pgf@temp + \global\let\pgf@fillcolor@global=\pgf@temp + \expandafter\pgf@setcolor\pgf@temp% +} +\def\pgf@setcolor#1#2#3#4#5{% + \expandafter\ifx\csname pgfsys@color@#4\endcsname\relax% + \pgferror{Unsupported color model `#4'. Sorry}% + \else% + \edef\pgf@colmarshal{\expandafter\noexpand\csname pgfsys@color@#4\endcsname}% + \pgf@uncomma#5,,% + \pgf@colmarshal% + \fi} + +% Code for ensuring the stroke/fill colors are correctly reset. +\def\XC@bcolor{\pgfsys@color@reset} + +% Set a butt line cap. +% +% Example: +% +% \pgfsetbuttcap + +\def\pgfsetbuttcap{\pgfsys@buttcap\ignorespaces} + + +% Set a round line cap. +% +% Example: +% +% \pgfsetroundcap + +\def\pgfsetroundcap{\pgfsys@roundcap\ignorespaces} + + +% Set a rectangular line cap. +% +% Example: +% +% \pgfsetrectcap + +\def\pgfsetrectcap{\pgfsys@rectcap\ignorespaces} + + +% Set a miter line join. +% +% Example: +% +% \pgfsetmiterjoin + +\def\pgfsetmiterjoin{\pgfsys@miterjoin\ignorespaces} + + +% Set a bevel line join. +% +% Example: +% +% \pgfsetbeveljoin + +\def\pgfsetbeveljoin{\pgfsys@beveljoin\ignorespaces} + + +% Set a round line join. +% +% Example: +% +% \pgfsetroundjoin + +\def\pgfsetroundjoin{\pgfsys@roundjoin\ignorespaces} + + +% Sets the even-odd rule for filling and clipping. +% +% Example: +% +% \pgfseteorule + +\def\pgfseteorule{\pgfsys@eoruletrue\ignorespaces} + + +% Sets the non-zero winding number rule for filling and clipping. +% +% Example: +% +% \pgfsetnonzerorule + +\def\pgfsetnonzerorule{\pgfsys@eorulefalse\ignorespaces} + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoreimage.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreimage.code.tex new file mode 100644 index 0000000000..fd1c0c48db --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreimage.code.tex @@ -0,0 +1,242 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoreimage.code.tex} + + + +% Declare an image +% +% #1 = optional argument: width, height, page specification +% #2 = name of the image for later use +% #4 = filename without extension, automatic extensions are .pdf, +% .jpg, and .png for PDF and .ps, .eps, .epsi for postscript. +% +% Description: +% +% This command declares an image file for later use. Even if the image +% is used several times in the document, in PDF it will only be stored +% once. +% +% Example: +% +% \pgfdeclareimage[width=2cm,page=2]{myimage}{imagefilename} + +\def\pgfdeclareimage{\pgfutil@ifnextchar[{\pgf@declareimage}{\pgf@declareimage[]}} +\def\pgf@declareimage[#1]#2#3{% + \pgfqkeys{/pgf/images}{height=,width=,page=,interpolate=false,mask=,#1}% + % Try to find the file + \gdef\pgf@filename{}% + % If page= parameter is not empty, try that file first: + \ifx\pgf@imagepage\pgfutil@empty% + \else% + \expandafter\pgf@findfile\pgfsys@imagesuffixlist:+{#3.page\pgf@imagepage}% + \fi% + \ifx\pgf@filename\pgfutil@empty% + \expandafter\pgf@findfile\pgfsys@imagesuffixlist:+{#3}% + \else% + \pgfkeys{/pgf/images/page=}% make page empty + \fi% + \ifx\pgf@filename\pgfutil@empty% + \pgfwarning% + {File "#3" not found when defining image "#2". + Tried all extensions in "\pgfsys@imagesuffixlist"}% + \pgf@declaredraftimage{#2}{#3}% + \else% + \ifpgf@draftmode% + \pgf@declaredraftimage{#2}{#3}% + \else% + \pgfsys@defineimage% + \fi% + \fi% + \expandafter\global\expandafter\let\csname pgf@image@#2!\endcsname=\pgf@image% +} + + +\pgfkeys{ + /pgf/images/draft/.is if=pgf@draftmode, + /pgf/images/draft/.default=true} +\pgfkeys{/pgf/images/width/.estore in=\pgf@imagewidth} +\pgfkeys{/pgf/images/height/.estore in=\pgf@imageheight} +\pgfkeys{/pgf/images/page/.estore in=\pgf@imagepage} +\pgfkeys{/pgf/images/interpolate/.cd,.code=\edef\pgf@imageinterpolate{#1},.default=true} +\let\pgf@imageinterpolate\pgfutil@empty +\pgfkeys{/pgf/images/mask/.code=% + {% + \edef\pgf@imagemask{#1}% + \ifx\pgf@imagemask\pgfutil@empty% + \else% + \pgfutil@ifundefined{pgf@mask@#1}% + {\pgferror{Undefined mask "#1".}% + \edef\pgf@imagemask{}}% + {\edef\pgf@imagemask{\csname pgf@mask@#1\endcsname}% + }% + \fi% + }} + + +\def\pgf@findfile#1:#2+#3{% + \pgfutil@IfFileExists{#3#1}% + {\xdef\pgf@filename{#3#1}}% + {\def\pgf@mightbeempty{#2}% + \ifx\pgf@mightbeempty\pgfutil@empty\else% + \pgf@findfile#2+{#3}% + \fi}} + +% #1: image name +% #2: file name +\def\pgf@declaredraftimage#1#2{% + \ifx\pgf@imagewidth\pgfutil@empty% + \pgfwarning{Missing width for image "#1" ("#2") in draft mode. Using 1cm instead}% + \edef\pgf@imagewidth{1cm}% + \fi% + \ifx\pgf@imageheight\pgfutil@empty% + \pgfwarning{Missing height for image "#1" ("#2") in draft mode. Using 1cm instead}% + \edef\pgf@imageheight{1cm}% + \fi% + \ifx\pgf@imagepage\pgfutil@empty\else\edef\pgf@imagepagetext{ page \pgf@imagepage}\fi% + \edef\pgf@image{% + \hbox to \pgf@imagewidth{% + \vrule\kern-0.4pt% + \vbox to \pgf@imageheight{% + \hrule\vfil% + \hbox to \pgf@imagewidth{\hskip-10cm\hfil\noexpand\pgfutil@font@tiny#2\pgf@imagepage\hfil\hskip-10cm}% + \vfil\hrule}% + \kern-0.4pt\vrule}% + }% +} + + + +% Declare a soft mask +% +% #1 = optional argument: matte specification. default matte is +% white. +% #2 = name of the mask for later use +% #3 = filename without extension, automatic extensions are .pdf, +% .jpg, and .png for PDF. Postscript is not supported. +% +% Description: +% +% This command declares a soft mask for later masking an image. The +% declared mask should be used together with an image of exactly the +% same height/width if matte is defined. Matte should be the +% preblended background color (see pdf spec for details). +% +% Example: +% +% \pgfdeclaremask[matte=white]{maskname}{maskfilename} +% \pgfdeclareimage[mask=maskname]{image}{imagefilename} + +\def\pgfdeclaremask{\pgfutil@ifnextchar[\pgf@declaremask{\pgf@declaremask[]}} +\def\pgf@declaremask[#1]#2#3{% + \pgfqkeys{/pgf/images/mask}{matte={1 1 1},#1}% defaults + \def\pgf@mask{}% + % Try to find the file + \gdef\pgf@filename{}% + \expandafter\pgf@findfile\pgfsys@imagesuffixlist:+{#3}% + \ifx\pgf@filename\pgfutil@empty% + \pgfwarning% + {File "#3" not found when defining mask "#2". + Tried all extensions in "\pgfsys@imagesuffixlist"}% + \else% + \pgfsys@definemask% + \fi% + \expandafter\global\expandafter\let\csname pgf@mask@#2\endcsname=\pgf@mask% +} + +\pgfkeys{/pgf/images/mask/matte/.cd,.estore in=\pgf@maskmatte,.value required} + + + +% Create an alias name for an image +% +% #1 = name of the alias +% #2 = name of the original +% +% Example: +% +% \pgfdeclareimage{image}{1cm}{1cm}{filename +% \pgfaliasimage{alias}{image} +% \pgfuseimage{alias} + +\def\pgfaliasimage#1#2{% + \expandafter\global\expandafter\let\expandafter\pgf@temp\expandafter=\csname pgf@image@#2!\endcsname% + \expandafter\global\expandafter\let\csname pgf@image@#1!\endcsname=\pgf@temp% + } + + +% Use an image +% +% #1 = name of a previously declared image +% +% Example: +% +% \pgfputat{\pgforigin}{\pgfbox[left,base]{\pgfuseimage{myimage}}} + +\def\pgfuseimage#1{% + \def\pgf@imagename{pgf@image@#1}% + \pgf@tryextensions{\pgf@imagename}{\pgfalternateextension}% + \expandafter\pgfutil@ifundefined\expandafter{\pgf@imagename}% + {\pgferror{Undefined image "#1"}}% + {{\leavevmode\csname\pgf@imagename\endcsname}}} + +\def\pgf@tryextensions#1#2{% + \edef\pgf@args{[#2!]}\expandafter\pgf@@tryextensions\pgf@args{#1}} +\def\pgf@@tryextensions[#1!#2]#3{% + \expandafter\pgfutil@ifundefined\expandafter{#3#1!#2}% + {\def\pgf@temp{#2}% + \ifx\pgf@temp\pgfutil@empty% + \edef#3{#3!}% + \else% + \pgf@@tryextensions[#2]{#3}% + \fi}% + {\edef#3{#3#1!#2}}} + + +% Alternate image +% +% Description: +% +% When an image is used, pgf first attempts to use the image with the +% alternate extension added. If this fails, the original image is +% used. If the alternate extension contains ``!'', then the text up to +% the ! is successively removed and the remainder is tried as an +% alternate extension. +% +% Example: +% +% \def\pgfalternateextension{20!white} + +\def\pgfalternateextension{} + + + +% Directly insert an image +% +% #1 = optional argument: width, height, page specification +% #2 = file name +% +% Description: +% +% Directly inserts an image without declaration. You can, however, +% still access this image using the name pgflastimage. By using +% pgfaliasimage, you can also save this image for later. +% +% Example: +% +% \pgfimage[height=2cm]{filename} + +\def\pgfimage{\pgfutil@ifnextchar[\pgf@imagecom{\pgf@imagecom[]}} +\def\pgf@imagecom[#1]#2{% + \pgfdeclareimage[#1]{pgflastimage}{#2}% + \pgfuseimage{pgflastimage}} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorelayers.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorelayers.code.tex new file mode 100644 index 0000000000..158f33d6ac --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorelayers.code.tex @@ -0,0 +1,210 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorelayers.code.tex} + + +% Creates a new pgf layer +% +% #1 = layer name +% +% Declares a new layer for pgf. +% +% Example: +% +% \pgfdeclarelayer{background} + +\def\pgfdeclarelayer#1{% + \pgfutil@ifundefined{pgf@layerbox@#1}{% + \expandafter\expandafter\csname pgf@newbox\endcsname\csname pgf@layerbox@#1\endcsname% + \expandafter\expandafter\csname pgf@newbox\endcsname\csname pgf@layerboxsaved@#1\endcsname% + }{}% +} +\let\pgf@newbox=\newbox % avoid plain TeX outer problem + +% Sets the layers that compose the picture +% +% #1 = List of layers +% +% Description: +% +% Sets the list of layers that make up the picture. The layers will be +% put on top of each other in the order given. +% +% This command can also be given inside of a picture in which case it +% applies only to that very picture. +% +% Example: +% +% \pgfsetlayers{background,main} + +\def\pgfsetlayers#1{% + \let\pgf@layerlist\pgfutil@empty% + \pgf@dosetlayer#1,,\relax% +} + +\def\pgf@dosetlayer#1,#2,\relax{% + \ifx\pgf@layerlist\pgfutil@empty% + \edef\pgf@layerlist{\pgfutil@trimspaces{#1}}% + \else + \edef\pgf@layerlist{\pgf@layerlist,\pgfutil@trimspaces{#1}}% + \fi + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \else% + \pgf@dosetlayer#2,\relax% + \fi% +} + +\pgfsetlayers{main} + +% Adds code to a layer +% +% #1 = layer name +% +% Note: +% +% You cannot add anything to the ``main'' layer using this command. +% +% Example: +% +% \begin{pgfonlayer}{background} +% \fill[red] (0,0) -- (1,1); +% \end{pgfonlayer} + +\def\pgfonlayer@name{main} + +\def\pgfonlayer#1{% + \pgfutil@ifundefined{pgf@layerbox@#1}{% + \pgferror{Sorry, the requested layer '#1' could not be found. Maybe you misspelled it?}% + \bgroup + \begingroup + }{% + \begingroup + \edef\pgf@temp{#1}% + \ifx\pgf@temp\pgfonlayer@name + % we are already on this layer. + \def\pgf@temp{% + \bgroup + \begingroup + }% + \else + \let\pgfonlayer@name=\pgf@temp + \pgfonlayer@assert@is@active + \def\pgf@temp{% + \expandafter\global\expandafter% + \setbox\csname pgf@layerbox@#1\endcsname=\hbox to 0pt% + \bgroup% + \expandafter\box\csname pgf@layerbox@#1\endcsname% + \begingroup% + }% + \fi + \pgfsetlinewidth{0.4pt}% always reset the line width + \pgf@temp + }% +} +\def\endpgfonlayer{% + \endgroup% + \hss + \egroup% + \endgroup +} + +\let\startpgfonlayer=\pgfonlayer +\let\stoppgfonlayer=\endpgfonlayer + +\def\pgfdiscardlayername{discard} + +\def\pgfonlayer@assert@is@active{% + \ifx\pgfonlayer@name\pgfdiscardlayername + % this special layer name can be used as /dev/null without + % warning. + \else + \begingroup + \def\pgfonlayer@isactive{0}% + \expandafter\pgf@assert@layer@is@active@loop\pgf@layerlist,,\relax% + \if0\pgfonlayer@isactive + \pgfonlayer@assert@fail + \fi + \endgroup + \fi +}% +\def\pgfonlayer@assert@fail{% + \pgferror{Sorry, the requested layer '\pgfonlayer@name' is not + part of the layer list. Please verify that you provided + \string\pgfsetlayers\space and that '\pgfonlayer@name' is part of this list}% +}% +\def\pgf@assert@layer@is@active@loop#1,#2,\relax{% + \edef\pgf@test{#1}% + \ifx\pgf@test\pgfonlayer@name + \def\pgfonlayer@isactive{1}% + \else + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \else% + \pgf@assert@layer@is@active@loop#2,\relax% + \fi% + \fi +} + +% Hooks into the scoping: + +\def\pgf@insertlayers{% + \expandafter\pgf@dolayer\pgf@layerlist,,\relax% +} +\def\pgf@maintext{main}% +\def\pgf@dolayer#1,#2,\relax{% + \def\pgf@test{#1}% + \ifx\pgf@test\pgf@maintext% + \box\pgf@layerbox@main% + \else% + \pgfsys@beginscope% + \expandafter\box\csname pgf@layerbox@#1\endcsname% + \pgfsys@endscope% + \fi% + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \else% + \pgf@dolayer#2,\relax% + \fi% +} + +\def\pgf@savelayers{% + \expandafter\pgf@dosavelayer\pgf@layerlist,,\relax% +} +\def\pgf@dosavelayer#1,#2,\relax{% + \def\pgf@test{#1}% + \ifx\pgf@test\pgf@maintext% + \else% + \setbox\csname pgf@layerboxsaved@#1\endcsname=\box\csname pgf@layerbox@#1\endcsname% + \fi% + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \else% + \pgf@dosavelayer#2,\relax% + \fi% +} + +\def\pgf@restorelayers{% + \expandafter\pgf@dorestorelayer\pgf@layerlist,,\relax% +} +\def\pgf@dorestorelayer#1,#2,\relax{% + \def\pgf@test{#1}% + \ifx\pgf@test\pgf@maintext% + \else% + \global\setbox\csname pgf@layerbox@#1\endcsname=\box\csname pgf@layerboxsaved@#1\endcsname% + \fi% + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \else% + \pgf@dorestorelayer#2,\relax% + \fi% +} + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoreobjects.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreobjects.code.tex new file mode 100644 index 0000000000..6906a9d987 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreobjects.code.tex @@ -0,0 +1,101 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoreobjects.code.tex} + + +% Object reuse + + +% Define a pgf object for reuse. Such objects will be stored +% efficiently internally. +% +% #1 = name for later reuse +% #2 = lower left corner point of bounding box +% #3 = upper right left corner point of bounding box +% #4 = pure pgf code (nothing too fancy!) +% +% Description: +% +% Used to define reusable objects. The object must be composed of +% basic pgf graphic primitives. Nothing fancy can be used. The +% created object will be stored as an xform object in pdf or as a +% postscript procedure in postscript. +% +% Example: +% +% \pgfdefobject{myrect}{\pgfpoint{-1pt}{-1pt}}{\pgfpoint{11pt}{11pt}} +% {\pgfpathqmoveto{0pt}{0pt} +% \pgfpathqmoveto{10pt}{0pt} +% \pgfpathqmoveto{10pt}{10pt} +% \pgfpathqmoveto{0pt}{10pt} +% \pgfpathclose +% \pgfusepath{stroke}} +% +% \begin{pgfpicture}{0cm}{0cm}{1cm}{1cm} +% \pgfuseobject{myrect} +% \end{pgfpicture} + +\def\pgfdefobject#1#2#3#4{% + \pgfinterruptpath% + \pgf@relevantforpicturesizefalse% + \pgfsys@defobject{#1}{#2}{#3}{#4}% + \endpgfinterruptpath% + \ignorespaces% +} + + +% Use an object that was previously defined using pgfdefobject +% +% #1 = name of previously defined object +% +% Example: +% +% \pgfdefobject{myrect}{\pgfpoint{-1pt}{-1pt}}{\pgfpoint{11pt}{11pt}} +% {\pgfqmoveto{0}{0} +% \pgfqmoveto{10}{0} +% \pgfqmoveto{10}{10} +% \pgfqmoveto{0}{10} +% \pgfclosestroke} +% +% \begin{pgfpicture}{0cm}{0cm}{1cm}{1cm} +% \pgfuseobject{myrect} +% \end{pgfpicture} + +\def\pgfuseobject#1{\pgfsys@beginscope\pgfsys@useobject{#1}{}\pgfsys@endscope} + + +% Use an object that was previously defined using pgfdefobject, but +% magnify the object by the current x and y register values +% +% #1 = name of previously defined object +% +% Example: +% +% \pgfdefobject{myrect}{\pgfpoint{-1pt}{-1pt}}{\pgfpoint{11pt}{11pt}} +% {\pgfqmoveto{0}{0} +% \pgfqmoveto{10}{0} +% \pgfqmoveto{10}{10} +% \pgfqmoveto{0}{10} +% \pgfclosestroke} +% +% \begin{pgfpicture}{0cm}{0cm}{1cm}{1cm} +% \pgf@x=2pt% Scale by factor two in x-direction +% \pgf@y=2pt% Scale by factor two in y-direction +% \pgfuseobjectmagnify{myrect} +% \end{pgfpicture} + +\def\pgfuseobjectmagnify#1{% + \pgfsys@beginscope% + \pgfsys@useobject{#1}{\pgfsys@transformxyscale{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}}% + \pgfsys@endscope% +} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathconstruct.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathconstruct.code.tex new file mode 100644 index 0000000000..cafc532938 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathconstruct.code.tex @@ -0,0 +1,1477 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorepathconstruct.code.tex} + + +\newdimen\pgf@path@lastx +\newdimen\pgf@path@lasty + +\let\pgfgetpath=\pgfsyssoftpath@getcurrentpath +\let\pgfsetpath=\pgfsyssoftpath@setcurrentpath + + + +% Replace corners by arcs. +% +% #1 = in-size of arc +% #2 = out-size of arc +% +% Description: +% +% This command influences path construction command like +% \pgfpathlineto or \pgfpatharc. It will cause the corners at the end +% of these commands to be replaced by little arcs. If the +% corner is a 90 degrees corner and if #1=#2, a quarter-circle of +% radius #1 is put in place of the corner. If #1 and #2 are different, +% the quarter circle will instead by a quarter ellipse. If the angle +% is different from 90 degrees, a deformed quarter circle will +% result, which may or may not be desirable. For a ``perfect'' arc you +% must use the \pgfpatharc command. +% +% +% Example: One rounded corner. +% +% \pgfpathmoveto{\pgfpointxy{0}{0}} +% \pgfsetcornersarced{4pt}{4pt} +% \pgfpathlineto{\pgfpointxy{0}{1}} +% \pgfpathlineto{\pgfpointxy{1}{1}} +% \pgfstroke +% +% Example: A rounded rectangle +% +% \pgfsetcornersarced{4pt}{4pt} +% \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{1cm}{1cm}} +% \pgfstroke +% +% Example: A rounded triangles +% +% \pgfsetcornersarced{4pt}{4pt} +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathlineto{\pgfpoint{1cm}{0cm}} +% \pgfpathlineto{\pgfpoint{1cm}{1cm}} +% \pgfpathclose +% \pgfstroke + +\newif\ifpgf@arccorners + +\def\pgfsetcornersarced#1{% + \pgf@process{#1}% + \edef\pgf@corner@arc{{\the\pgf@x}{\the\pgf@y}}% + \pgf@arccornerstrue% + \ifdim\pgf@x=0pt% + \ifdim\pgf@y=0pt\relax% + \pgf@arccornersfalse% + \fi% + \fi% +} + +\def\pgf@roundcornerifneeded{% + \ifpgf@arccorners\expandafter\pgfsyssoftpath@specialround\pgf@corner@arc\fi% +} + + + +% The following protocol the passed sizes and all the corresponding +% softpath commands. The nonlinear transformation (nlt) module +% overwrites these commands. + +\def\pgf@lt@moveto#1#2{% + \pgf@protocolsizes{#1}{#2}% + \pgfsyssoftpath@moveto{\the#1}{\the#2}% +} +\def\pgf@lt@lineto#1#2{% + \pgf@protocolsizes{#1}{#2}% + \pgfsyssoftpath@lineto{\the#1}{\the#2}% +} +\def\pgf@lt@curveto#1#2#3#4#5#6{% + \pgf@protocolsizes{#1}{#2}% + \pgf@protocolsizes{#3}{#4}% + \pgf@protocolsizes{#5}{#6}% + \pgfsyssoftpath@curveto{\the#1}{\the#2}{\the#3}{\the#4}{\the#5}{\the#6}% +} + +\let\pgf@lt@closepath\pgfsyssoftpath@closepath + +\let\pgf@nlt@moveto\pgf@lt@moveto +\let\pgf@nlt@lineto\pgf@lt@lineto +\let\pgf@nlt@curveto\pgf@lt@curveto +\let\pgf@nlt@closepath\pgf@lt@closepath + +\let\pgf@nlt@list\pgfutil@empty % If non-empty, the nlt module is active + + +% Move current point to #1. +% +% #1 = new current point +% +% Example: +% +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpathlineto{\pgfxy(0,1)} +% \pgfstroke + +\def\pgfpathmoveto#1{% + \pgfpointtransformed{#1}% + \pgf@nlt@moveto{\pgf@x}{\pgf@y}% + \global\pgf@path@lastx=\pgf@x% + \global\pgf@path@lasty=\pgf@y% +} + +\def\pgf@protocolsizes#1#2{% + \ifpgf@relevantforpicturesize% + \ifdim#1<\pgf@picminx\global\pgf@picminx#1\fi% + \ifdim#1>\pgf@picmaxx\global\pgf@picmaxx#1\fi% + \ifdim#2<\pgf@picminy\global\pgf@picminy#2\fi% + \ifdim#2>\pgf@picmaxy\global\pgf@picmaxy#2\fi% + \ifpgf@size@hooked% + \let\pgf@size@hook@x#1\let\pgf@size@hook@y#2\pgf@path@size@hook% + \fi% + \fi% + \ifdim#1<\pgf@pathminx\global\pgf@pathminx#1\fi% + \ifdim#1>\pgf@pathmaxx\global\pgf@pathmaxx#1\fi% + \ifdim#2<\pgf@pathminy\global\pgf@pathminy#2\fi% + \ifdim#2>\pgf@pathmaxy\global\pgf@pathmaxy#2\fi% +} +\newif\ifpgf@size@hooked +\let\pgf@path@size@hook=\pgfutil@empty% + +\def\pgf@resetpathsizes{% + \global\pgf@pathmaxx=-16000pt\relax% + \global\pgf@pathminx=16000pt\relax% + \global\pgf@pathmaxy=-16000pt\relax% + \global\pgf@pathminy=16000pt\relax% +} + +\def\pgf@getpathsizes#1{% + \edef#1{{\the\pgf@pathmaxx}{\the\pgf@pathminx}{\the\pgf@pathmaxy}{\the\pgf@pathminy}}% +} +\def\pgf@setpathsizes#1{% + \expandafter\pgf@@setpathsizes#1% +} +\def\pgf@@setpathsizes#1#2#3#4{% + \global\pgf@pathmaxx=#1\relax% + \global\pgf@pathminx=#2\relax% + \global\pgf@pathmaxy=#3\relax% + \global\pgf@pathminy=#4\relax% +} + + + + + +% Append a line from the current point to #1 to the current path. +% +% #1 = end of line +% +% Example: +% +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpathlineto{\pgfxy(0,1)} +% \pgfstroke + +\def\pgfpathlineto#1{% + \pgfpointtransformed{#1}% + \pgf@roundcornerifneeded% + \pgf@nlt@lineto{\pgf@x}{\pgf@y}% + \global\pgf@path@lastx=\pgf@x% + \global\pgf@path@lasty=\pgf@y% +} + + + +% Close the current path. +% +% Example: +% +% % Draws two triangles +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpathlineto{\pgfxy(0,1)} +% \pgfpathlineto{\pgfxy(1,0)} +% \pgfclosepath +% \pgfpathmoveto{\pgfxy(2,0)} +% \pgfpathlineto{\pgfxy(2,1)} +% \pgfpathlineto{\pgfxy(3,0)} +% \pgfpathclose +% \pgfstroke + +\def\pgfpathclose{% + \pgf@roundcornerifneeded% + \pgf@nlt@closepath% +} + + +% Append a cubic bezier spline from the current point to #3 with control +% points #1 and #2 to the current path. +% +% #1 = first control point +% #2 = second control point +% #3 = end point +% +% Example: +% +% \pgfpathmoveto{\pgfpointxy{0}{0}} +% \pgfpathcurveto{\pgfpointxy{0}{1}}{\pgfpointxy{1}{1}}{\pgfpointxy{1}{2}} +% \pgfstroke + +\def\pgfpathcurveto#1#2#3{% + \pgfpointtransformed{#3}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgfpointtransformed{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfpointtransformed{#1}% + \pgf@roundcornerifneeded% + \pgf@nlt@curveto{\pgf@x}{\pgf@y}{\pgf@xa}{\pgf@ya}{\pgf@xb}{\pgf@yb}% + \global\pgf@path@lastx=\pgf@xb% + \global\pgf@path@lasty=\pgf@yb% +} + + + +% Append a quadratic bezier spline from the current point to #2 with +% control point #1 to the current path. +% +% #1 = control point +% #2 = end point +% +% Example: +% +% \pgfpathmoveto{\pgfpointxy{0}{0}} +% \pgfpathquadraticcurveto{\pgfpointxy{1}{1}}{\pgfpointxy{2}{0}} +% \pgfstroke + +\def\pgfpathquadraticcurveto#1#2{% + \pgfpointtransformed{#2}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgfpointtransformed{#1}% + \pgf@xc=.6666666\pgf@x% + \pgf@yc=.6666666\pgf@y% + % compute second control point: + \pgf@xa=.33333333\pgf@xb% + \pgf@ya=.33333333\pgf@yb% + \advance\pgf@xa by\pgf@xc% + \advance\pgf@ya by\pgf@yc% + % compute first control point + \advance\pgf@xc by.3333333\pgf@path@lastx% + \advance\pgf@yc by.3333333\pgf@path@lasty% + \pgf@roundcornerifneeded% + \pgf@nlt@curveto{\pgf@xc}{\pgf@yc}{\pgf@xa}{\pgf@ya}{\pgf@xb}{\pgf@yb}% + \global\pgf@path@lastx=\pgf@xb% + \global\pgf@path@lasty=\pgf@yb% +} + + + + +% Append an arc to the current point, where the current point is at +% angle #1 and the end is at angle #2. If #2 > #1, the arc is drawn +% counter-clockwise, otherwise it is clockwise. +% +% #1 = angle of first point +% #2 = angle of second point +% #3 = radius or x-radius/y-radius +% +% Example: +% +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpatharc{0}{90}{2cm} +% \pgfstroke + +\def\pgfpatharc#1#2#3{% + {% + \pgfmathparse{#1}\let\pgf@temp@a=\pgfmathresult% + \pgfmathparse{#2}\let\pgf@temp@b=\pgfmathresult% + \pgfutil@in@{and }{#3}% + \ifpgfutil@in@% + \pgf@arc@get@radii#3\pgf@arc@stop% + \else + \pgf@arc@get@radii#3and #3\pgf@arc@stop% + \fi% + \pgf@arc@local@angle@a=\pgf@temp@a pt% + \pgf@arc@local@angle@b=\pgf@temp@b pt% + \loop% + \pgfutil@tempdima=\pgf@arc@local@angle@a% + \advance\pgfutil@tempdima by-\pgf@arc@local@angle@b\relax% + \ifdim\pgfutil@tempdima<0pt\relax% + \pgfutil@tempdima=-\pgfutil@tempdima\relax% + \fi% + \ifdim\pgfutil@tempdima>90pt\relax% + \ifdim\pgfutil@tempdima>115pt\relax% + \pgf@arc@temp=90pt% big skip + \else% + \pgf@arc@temp=60pt% smaller skip to ensure wide segments + % (important shortened end segments because + % of arrow tips) + \fi% + \ifdim\pgf@arc@local@angle@b>\pgf@arc@local@angle@a\relax% + {% + \pgf@arc@local@angle@b=\pgf@arc@local@angle@a\relax% + \advance\pgf@arc@local@angle@b by\pgf@arc@temp\relax% + \pgf@arc% + } + \advance\pgf@arc@local@angle@a by\pgf@arc@temp\relax% + \else + {% + \pgf@arc@local@angle@b=\pgf@arc@local@angle@a\relax% + \advance\pgf@arc@local@angle@b by-\pgf@arc@temp\relax% + \pgf@arc% + }% + \advance\pgf@arc@local@angle@a by-\pgf@arc@temp\relax% + \fi% + \repeat% + \pgf@roundcornerifneeded% + \pgf@arc% + }% +} +\dimendef\pgf@arc@local@angle@a=0 +\dimendef\pgf@arc@local@angle@b=1 +\dimendef\pgf@arc@temp=2 + +\def\pgf@arc@get@radii#1and #2\pgf@arc@stop{% + \pgfmathparse{#1}\let\pgf@arc@radius@a=\pgfmathresult% + \pgfmathparse{#2}\let\pgf@arc@radius@b=\pgfmathresult% +} + + +\def\pgf@arc{% + {% + \pgfutil@tempdima=\pgf@arc@radius@a pt% + \pgfutil@tempdimb=\pgf@arc@radius@b pt% + % + \pgf@xa=\pgf@arc@local@angle@a\relax% + \pgf@xb=\pgf@arc@local@angle@b\relax% + \advance\pgf@xb by-\pgf@xa\relax% + \ifdim\pgf@xb<0pt\relax% + \pgf@xb=-\pgf@xb\relax% + \fi% + \ifdim\pgf@xb=90.0pt% + \def\pgfmathresult{0.55228475}% + \else% + \pgfmathparse{1.333333333*tan(.25*\pgf@sys@tonumber{\pgf@xb})}% many thanks to Ken Starks + \fi% + \pgfutil@tempdima=\pgfmathresult\pgfutil@tempdima% + \pgfutil@tempdimb=\pgfmathresult\pgfutil@tempdimb% + %.. controls +(\pgf@xa+90:\pgfutil@tempdima) and +(\pgf@xb-90:\pgfutil@tempdima) .. +(-(#1:#3)+(#2:#3))% + % store first support vector in xa/ya: + \pgf@xa=\pgf@arc@local@angle@a\relax% + \ifdim\pgf@arc@local@angle@b>\pgf@arc@local@angle@a\relax% + \advance\pgf@xa by 90pt\relax% + \else% + \advance\pgf@xa by -90pt\relax% + \fi% + \edef\pgf@arc@angle{\pgf@sys@tonumber{\pgf@xa}}% + \pgfpointtransformed{\pgfpointpolar{\pgf@arc@angle}{\pgfutil@tempdima and \pgfutil@tempdimb}}% + \advance\pgf@x by-\pgf@pt@x% + \advance\pgf@y by-\pgf@pt@y% + \pgf@xa=\pgf@path@lastx% + \pgf@ya=\pgf@path@lasty% + \advance\pgf@xa by \pgf@x% + \advance\pgf@ya by \pgf@y% + % store target in xb/yb: + \pgfpointtransformed{\pgfpointpolar{\pgf@sys@tonumber{\pgf@arc@local@angle@a}}{\pgf@arc@radius@a pt and \pgf@arc@radius@b pt}}% + \pgf@xb=\pgf@path@lastx% + \pgf@yb=\pgf@path@lasty% + \advance\pgf@xb by -\pgf@x% + \advance\pgf@yb by -\pgf@y% + \pgfpointtransformed{\pgfpointpolar{\pgf@sys@tonumber{\pgf@arc@local@angle@b}}{\pgf@arc@radius@a pt and \pgf@arc@radius@b pt}}% + \advance\pgf@xb by \pgf@x% + \advance\pgf@yb by \pgf@y% + % store second support xc/yc: + \ifdim\pgf@arc@local@angle@b>\pgf@arc@local@angle@a\relax% + \advance\pgf@arc@local@angle@b by -90pt\relax% + \else% + \advance\pgf@arc@local@angle@b by 90pt\relax% + \fi% + \pgfpointtransformed{\pgfpointpolar{\pgf@sys@tonumber{\pgf@arc@local@angle@b}}{\pgfutil@tempdima and \pgfutil@tempdimb}}% + \advance\pgf@x by-\pgf@pt@x% + \advance\pgf@y by-\pgf@pt@y% + \pgf@xc=\pgf@xb\relax% + \pgf@yc=\pgf@yb\relax% + \advance \pgf@xc by \pgf@x\relax% + \advance \pgf@yc by \pgf@y\relax% + \pgf@nlt@curveto{\pgf@xa}{\pgf@ya}{\pgf@xc}{\pgf@yc}{\pgf@xb}{\pgf@yb}% + \global\pgf@path@lastx=\pgf@xb% + \global\pgf@path@lasty=\pgf@yb% + }% +} + + +% Append an arc to the current point, where the arc is on an ellipse +% given by two axis vectors. +% +% #1 = angle of first point +% #2 = angle of second point +% #3 = first axis +% #4 = second axis +% +% Example: +% +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpatharcaxes{0}{90}{\pgfpointxy{2}{0}}{\pgfpointxy{0}{2}} +% \pgfstroke + +\def\pgfpatharcaxes#1#2#3#4{% + {% + \pgftransformtriangle{\pgfpointorigin}{#3}{#4}% + \pgfpatharc{#1}{#2}{1pt}% + }% +} + + + +% Append an arc to the current point that ends at a given position. +% +% #1 = x-radius +% #2 = y-radius +% #3 = x-axis-rotation (in degrees) +% #4 = large-arc-sweep-flag (0 or 1) +% #5 = sweep-flag (0 or 1) +% #6 = target point +% +% Description: +% +% This command implements an arc drawing where a given target +% coordinate (#6) is given and the task is to draw an arc of an +% ellipse with the given radii. The center point of the ellipse is not +% give, but computed automatically. +% +% This kind of "endpoint parameterization" of an arc is exactly the +% same as the one specified by the SVG-specification for the "A" and +% "a" path commands. Please see the SVG-specification for details. +% +% Note that the problem is internally converted to drawing an arc +% using \pgfpatharc. This means that there may be a heavy loss of +% accuracy. +% +% Example: +% +% \pgfpathmoveto{\pgfpoint{1cm}{1cm}} +% \pgfpatharcto{1cm}{1cm}{0}{0}{0}{\pgfpoint{0cm}{2cm}} + +\def\pgfpatharcto#1#2#3#4#5#6{% + {% + % The following code is based on the transformation described in svg + % 1.1 specification Section F.6.5 + % + % Step 1: store the simple parameters (xa=x1 since TeX does not + % allow numbers in names) + % + \pgfmathsetmacro\pgf@arcto@rx{abs(#1)}% + \pgfmathsetmacro\pgf@arcto@ry{abs(#2)}% + \ifdim\pgf@arcto@rx pt=0pt% special rule: zero radius=straight line + \gdef\pgf@marshal{\pgfpathlineto{#6}}% + \else + \ifdim\pgf@arcto@ry pt=0pt% special rule: zero radius=straight line + \gdef\pgf@marshal{\pgfpathlineto{#6}}% + \else + \pgfmathsetmacro\pgf@arcto@phi{#3}% + \pgfmathsetmacro\pgf@arcto@fA{#4}% + \ifdim\pgf@arcto@fA pt=0pt + \else + \pgfmathsetmacro\pgf@arcto@fA{1.0} % Special rule: every non-zero value is 1. + \fi + \pgfmathsetmacro\pgf@arcto@fS{#5}% + \ifdim\pgf@arcto@fS pt=0pt + \else + \pgfmathsetmacro\pgf@arcto@fS{1.0} % Special rule: every non-zero value is 1. + \fi + \pgf@process{#6} + \edef\pgf@arcto@xb{\the\pgf@x}% + \edef\pgf@arcto@yb{\the\pgf@y}% + % + % Step 2: x1,y1 is more complicated to compute: It is given by lastx + % and lasty, but these are transformed coordinates, we need the + % untransformed ones. So, we inverse the transformation (arghh...) + % + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@path@lastx}{\pgf@path@lasty}}} + \edef\pgf@arcto@xa{\the\pgf@x} + \edef\pgf@arcto@ya{\the\pgf@y} + \edef\pgf@temp@a{\pgf@arcto@xa,\pgf@arcto@ya} + \edef\pgf@temp@b{\pgf@arcto@xb,\pgf@arcto@yb} + \ifx\pgf@temp@a\pgf@temp@b% special rule: skip! + \global\let\pgf@marshal\pgfutil@empty + \else + % + % Ok, now we got all the parameters setup. Now comes the + % computation... + % + % + % Step 3: Start with a new coordinate system and rotate everything + % by the negated phi. + % + \pgftransformreset + \pgftransformrotate{-\pgf@arcto@phi} + % Ok, using \pgfpointtransformed we now get transformed points... + % + % Step 4: Compute x1' and y1' (xaprime and yaprime) + % + \pgf@process{ + \pgfpointtransformed{\pgfpointscale{.5}{\pgfpointdiff + {\pgfqpoint{\pgf@arcto@xb}{\pgf@arcto@yb}} + {\pgfqpoint{\pgf@arcto@xa}{\pgf@arcto@ya}} + } + } + } + \edef\pgf@arcto@xaprime{\pgf@sys@tonumber\pgf@x} + \edef\pgf@arcto@yaprime{\pgf@sys@tonumber\pgf@y} + % + % Compute Lambda + % + \pgfmathsetmacro\pgf@arcto@frac@x{\pgf@arcto@xaprime/\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@frac@y{\pgf@arcto@yaprime/\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@lambda{ + \pgf@arcto@frac@x*\pgf@arcto@frac@x+\pgf@arcto@frac@y*\pgf@arcto@frac@y + } + \ifdim\pgf@arcto@lambda pt>1pt% + \pgfmathsetmacro\pgf@arcto@sqrt@lambda{sqrt(\pgf@arcto@lambda)} + \pgfmathsetmacro\pgf@arcto@rx{\pgf@arcto@sqrt@lambda*\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@ry{\pgf@arcto@sqrt@lambda*\pgf@arcto@ry} + \fi + % + % Do some scaling + % + \pgfmathsetmacro\pgf@arcto@xaprime@abs{abs(\pgf@arcto@xaprime)} + \pgfmathsetmacro\pgf@arcto@yaprime@abs{abs(\pgf@arcto@yaprime)} + \pgfmathmax@{\pgf@arcto@rx,\pgf@arcto@ry,\pgf@arcto@xaprime@abs,\pgf@arcto@yaprime@abs} + \pgfmathsetmacro\pgf@arcto@scaling{20/\pgfmathresult} + \pgfmathsetmacro\pgf@arcto@rx@scaled{\pgf@arcto@scaling*\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@ry@scaled{\pgf@arcto@scaling*\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@xaprime@scaled{\pgf@arcto@scaling*\pgf@arcto@xaprime} + \pgfmathsetmacro\pgf@arcto@yaprime@scaled{\pgf@arcto@scaling*\pgf@arcto@yaprime} + % + % Step 5: Now comes the messy computation of c1' and c2'. + % + \ifdim\pgf@arcto@rx pt>\pgf@arcto@ry pt% + \pgfmathsetmacro\pgf@arcto@rx@over@ry{\pgf@arcto@rx/\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@ry@over@rx{\pgf@arcto@ry/\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@temp{\pgf@arcto@ry@over@rx*\pgf@arcto@xaprime@scaled} + \pgfmathsetmacro\pgf@arcto@numerator{ + \pgf@arcto@ry@scaled*\pgf@arcto@ry@scaled- + \pgf@arcto@yaprime@scaled*\pgf@arcto@yaprime@scaled- + \pgf@arcto@temp*\pgf@arcto@temp + } + \pgfmathsetmacro\pgf@arcto@denominator{ + \pgf@arcto@yaprime@scaled*\pgf@arcto@yaprime@scaled+ + \pgf@arcto@temp*\pgf@arcto@temp + } + \else + \pgfmathsetmacro\pgf@arcto@rx@over@ry{\pgf@arcto@rx/\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@ry@over@rx{\pgf@arcto@ry/\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@temp{\pgf@arcto@rx@over@ry*\pgf@arcto@yaprime@scaled} + \pgfmathsetmacro\pgf@arcto@numerator{ + \pgf@arcto@rx@scaled*\pgf@arcto@rx@scaled- + \pgf@arcto@xaprime@scaled*\pgf@arcto@xaprime@scaled- + \pgf@arcto@temp*\pgf@arcto@temp + } + \pgfmathsetmacro\pgf@arcto@denominator{ + \pgf@arcto@xaprime@scaled*\pgf@arcto@xaprime@scaled+ + \pgf@arcto@temp*\pgf@arcto@temp + } + \fi + \pgfmathsetmacro\pgf@arcto@frac{ + \pgf@arcto@numerator/\pgf@arcto@denominator + } + \ifdim\pgf@arcto@frac pt<0pt + \pgfmathsetmacro\pgf@arcto@factor{0} + \else + \pgfmathsetmacro\pgf@arcto@factor{sqrt(\pgf@arcto@frac)} + \fi + \ifx\pgf@arcto@fA\pgf@arcto@fS + \pgfmathsetmacro\pgf@arcto@factor{-\pgf@arcto@factor} + \fi + \pgfmathsetmacro\pgf@arcto@cxprime{ + \pgf@arcto@factor*\pgf@arcto@rx@over@ry*\pgf@arcto@yaprime + } + \pgfmathsetmacro\pgf@arcto@cyprime{ + -\pgf@arcto@factor*\pgf@arcto@ry@over@rx*\pgf@arcto@xaprime + } + % + % Step 6: Ok, now compute cx,cy + % + \pgftransformreset + \pgftransformrotate{\pgf@arcto@phi} + \pgf@process{ + \pgfpointtransformed{\pgfqpoint{\pgf@arcto@cxprime pt}{\pgf@arcto@cyprime pt}} + } + \edef\pgf@arcto@temp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgf@process{\pgfpointadd{\pgf@arcto@temp}{ + \pgfpointscale{.5}{ + \pgfpointadd + {\pgfqpoint{\pgf@arcto@xa}{\pgf@arcto@ya}} + {\pgfqpoint{\pgf@arcto@xb}{\pgf@arcto@yb}} } + } + } + \edef\pgf@arcto@cx{\the\pgf@x} + \edef\pgf@arcto@cy{\the\pgf@y} + % + % Step 7: Compute start angle: + % + \pgfmathsetmacro\pgf@arcto@vec@x{(\pgf@arcto@xaprime-\pgf@arcto@cxprime)/\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@vec@y{(\pgf@arcto@yaprime-\pgf@arcto@cyprime)/\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@denominator{veclen(\pgf@arcto@vec@x,\pgf@arcto@vec@y)} + \pgfmathsetmacro\pgf@arcto@frac{\pgf@arcto@vec@x/\pgf@arcto@denominator} + \pgfmathsetmacro\pgf@arcto@theta@start{acos(\pgf@arcto@frac)} + \ifdim\pgf@arcto@vec@y pt<0pt + \pgfmathsetmacro\pgf@arcto@theta@start{-\pgf@arcto@theta@start} + \fi + % + % Step 8: Compute end angle: + % + \pgfmathsetmacro\pgf@arcto@vec@x{(-\pgf@arcto@xaprime-\pgf@arcto@cxprime)/\pgf@arcto@rx} + \pgfmathsetmacro\pgf@arcto@vec@y{(-\pgf@arcto@yaprime-\pgf@arcto@cyprime)/\pgf@arcto@ry} + \pgfmathsetmacro\pgf@arcto@denominator{veclen(\pgf@arcto@vec@x,\pgf@arcto@vec@y)} + \pgfmathsetmacro\pgf@arcto@frac{\pgf@arcto@vec@x/\pgf@arcto@denominator} + \pgfmathsetmacro\pgf@arcto@theta@end{acos(\pgf@arcto@frac)} + \ifdim\pgf@arcto@vec@y pt<0pt + \pgfmathsetmacro\pgf@arcto@theta@end{-\pgf@arcto@theta@end} + \fi + \pgfmathsetmacro\pgf@arcto@delta@theta{abs(\pgf@arcto@theta@start-\pgf@arcto@theta@end)} + \ifdim\pgf@arcto@fA pt=0pt% + \ifdim\pgf@arcto@delta@theta pt>180pt% + % Ok, we need to adjust the angle! + \ifdim\pgf@arcto@theta@end pt>\pgf@arcto@theta@start pt + \pgfmathsetmacro\pgf@arcto@theta@end{\pgf@arcto@theta@end-360} + \else + \pgfmathsetmacro\pgf@arcto@theta@end{\pgf@arcto@theta@end+360} + \fi + \fi + \else + \ifdim\pgf@arcto@delta@theta pt<180pt% + % Ok, we need to adjust the angle! + \ifdim\pgf@arcto@theta@end pt>\pgf@arcto@theta@start pt + \pgfmathsetmacro\pgf@arcto@theta@end{\pgf@arcto@theta@end-360} + \else + \pgfmathsetmacro\pgf@arcto@theta@end{\pgf@arcto@theta@end+360} + \fi + \fi + \fi + \xdef\pgf@marshal{\noexpand + \pgfpatharcaxes{\pgf@arcto@theta@start}{\pgf@arcto@theta@end} + {\noexpand\pgfpointpolar{\pgf@arcto@phi}{\pgf@arcto@rx}} + {\noexpand\pgfpointpolar{\pgf@arcto@phi+90}{\pgf@arcto@ry}} + } + \fi\fi\fi + } + \pgf@marshal +} + + + +% the quality of arc approximation by means of Bezier splines is +% controlled by a mesh width. +% +% The mesh width is provided in (full!) degrees. The smaller the mesh +% width, the more precise the arc approximation. +% +% Use an empty value to disable spline approximation (uses a single +% cubic polynomial for the complete arc). +% +% The value must be an integer! +\def\pgfpatharctomaxstepsize{45} + +% A specialized arc operation for an arc on an (axis--parallel) ellipse. +% +% In contrast to \pgfpatharc, it explicitly interpolates start- and end points. +% +% In contrast to \pgfpatharcto, this routine is numerically stable and +% quite fast since it relies on a lot of precomputed information. +% +% #1 center of ellipse +% #2 angle of last path position inside of the ellipse +% #3 end angle +% #4 end point (a \pgfpoint) +% #5 xradius +% #6 yradius +% #7 the ratio xradius/yradius of the ellipse +% #8 the ratio yradius/xradius of the ellipse +% Example: +% \def\cx{1cm}% center x +% \def\cy{1cm}% center y +% \def\startangle{0}% +% \def\endangle{45}% +% \def\a{5cm}% xradius +% \def\b{10cm}% yradius +% \pgfmathparse{\a/\b}\let\abratio=\pgfmathresult +% \pgfmathparse{\b/\a}\let\baratio=\pgfmathresult +% +% \pgfpathmoveto{\pgfpoint{\cx+\a*cos(\startangle)}{\cy+\b*sin(\startangle)}}% +% \pgfpatharctoprecomputed +% {\pgfpoint{\cx}{\cy}} +% {\startangle} +% {\endangle} +% {\pgfpoint{\cx+\a*cos(\endangle)}{\cy+\b*sin(\endangle)}}% +% {\a} +% {\b} +% {\abratio} +% {\baratio} +% +\def\pgfpatharctoprecomputed#1#2#3#4#5#6#7#8{% + \begingroup + % Implementation idea: + % + % let + % m = center (#1) + % \gamma_0 = start angle + % \gamma_1 = end angle + % a = x radius + % b = y radius + % + % an axis parallel ellipse is parameterized by + % C(\gamma) = m + ( a cos(\gamma), b sin(\gamma) ), \gamma in [0,360]. + % + % Now, consider the segment \gamma(t), + % \gamma:[0,1] -> [\gamma_0,\gamma_1], + % t -> \gamma_0 + t(\gamma_1 - \gamma_0) + % and + % C(\gamma(t)) which is defined on [0,1]. + % + % I'd like to approximate the arc by one or more cubic bezier + % splines which interpolate through the last and first provided + % points. + % + % In general, a Bezier spline C:[0,1] -> \R of order n fulfills + % C'(0) = n ( P_1 - P_0 ), + % C'(1) = n ( P_n - P_{n-1} ). + % For n=3 and given P_0 and P_3, I can directly compute P_1 and P_2 once I know + % the derivatives at t=0 and t=1. + % + % The derivatives in our case are + % ( C \circ \gamma )'(t) = C'[\gamma(t)] * \gamma'(t) + % = ( -a pi/180 sin(\gamma(t)), b pi/180 cos(\gamma(t)) ) * (\gamma_1 - \gamma_0). + % The pi/180 comes into play since we are working with degrees. + % + % Expression (C\circ\gamma)'(0) using P_0 and (C \circ \gamma)'(1) + % using P_3 yields the expressions + % (C \circ \gamma)'(0) = + % pi/180 * (\gamma_1 - \gamma_0)* [ - a/b(P_0^y - my), b/a (P_0^x - mx) ] + % (C \circ \gamma)'(1) = + % pi/180 * (\gamma_1 - \gamma_0)* [ - a/b(P_3^y - my), b/a (P_3^x - mx) ] + % + % defining + % scaleA = a/b * pi / (3*180) * (\gamma_1 - \gamma_0) + % and + % scaleB = b/a * pi / (3*180) * (\gamma_1 - \gamma_0) + % yields the direct expressions for the intermediate bezier + % control points + % + % P_1 = [ + % P_0^x - scaleA* ( P_0^y -my), + % P_0^y + scaleB* ( P_0^x -mx) ] + % and + % P_2 = [ + % P_3^x + scaleA* ( P_3^y -my), + % P_3^y - scaleB* ( P_3^x -mx) ]. + % + % This works fast, with few operations, if + % - a/b and b/a are known in advance + % - P_0 and P_3 are known in advance + % - \gamma_0 and \gamma_1 are known. + % + % It is also reliable if (\gamma_1 - \gamma_0) is small + % + \pgf@process{#1}% + \edef\pgfpath@center@x{\the\pgf@x}% + \edef\pgfpath@center@y{\the\pgf@y}% + \def\pgfpath@completearcend{#4}% + % compute scale (#3-#2) * pi/(3*180) = (#3 - #2) * pi/27 * 1/20 + % splitting pi/(3*180) into two scales has higher TeX accuracy + \pgf@xa=#2pt + \pgf@xb=#3pt + \edef\pgfpath@startangle{#2pt}% + \edef\pgfpath@endangle{\pgf@sys@tonumber\pgf@xb}% + % + \pgf@ya=\pgf@xb + \advance\pgf@ya by-\pgf@xa + % + \ifx\pgfpatharctomaxstepsize\pgfutil@empty + \def\pgfpath@N{1}% + \pgf@xc=\pgf@ya + \else + \pgf@xc=\pgf@ya% compute N = floor((gamma_1 - gamma_0) / max) +1 + \ifdim\pgf@xc<0pt + \multiply\pgf@xc by-1 + \fi + \divide\pgf@xc by\pgfpatharctomaxstepsize\relax + \afterassignment\pgfutil@gobble@until@relax + \c@pgf@counta=\the\pgf@xc\relax + \advance\c@pgf@counta by1 + \edef\pgfpath@N{\the\c@pgf@counta}% + % + \pgf@xc=\pgf@ya + \divide\pgf@xc by\c@pgf@counta + \fi + % + \edef\pgfpath@h{\pgf@sys@tonumber\pgf@xc}% + % +%\message{pgfpathellipse: using N =\pgfpath@N\space spline points y0 = \pgfpath@startangle, y0+i*h, yN=\pgfpath@endangle, i=1,...,(\pgfpath@N-1), with h=\pgfpath@h\space mesh width (total arc angle \pgf@sys@tonumber\pgf@ya).}% + % + % + \pgf@xc=0.116355283466289\pgf@xc % pi/27 + \divide\pgf@xc by20 + \pgf@xa=#7\pgf@xc + \edef\pgfpath@scale@A{\pgf@sys@tonumber\pgf@xa}% + \pgf@xa=#8\pgf@xc + \edef\pgfpath@scale@B{\pgf@sys@tonumber\pgf@xa}% + % + % compute intermediate spline segments for + % i = 1,...,N-1 + % this is a no-op for N=1. + \c@pgf@countd=1 + \pgfutil@loop + \ifnum\c@pgf@countd<\pgfpath@N\relax + % + \pgf@xa=\pgfpath@startangle % compute \pgf@xa = y_0 + i*h + \pgf@xb=\pgfpath@h pt + \multiply\pgf@xb by\c@pgf@countd + \advance\pgf@xa by\pgf@xb + \edef\pgfpath@angle@i{\pgf@sys@tonumber\pgf@xa}% +%\message{angle \the\c@pgf@countd: \pgfpath@angle@i...}% + % + \pgfpatharcofellipse@{% + \pgfpoint + {\pgfpath@center@x + #5*cos(\pgfpath@angle@i)} + {\pgfpath@center@y + #6*sin(\pgfpath@angle@i)}% + }% + % + \advance\c@pgf@countd by1 + \pgfutil@repeat + % + % compute final spline segment. It only differs insofar as the + % final point is already known explicitly and should be + % interpolated without additional math error. +%\message{angle \pgfpath@N: \pgfpath@endangle...}% + \pgfpatharcofellipse@{\pgfpath@completearcend}% + \endgroup +}% +\def\pgfpatharcofellipse@#1{% + \begingroup + \pgf@process{#1}% + \edef\pgfpath@endpt{\global\pgf@x=\the\pgf@x\space\global\pgf@y=\the\pgf@y\space}% + % + \pgfpathcurveto{ + \begingroup + \global\pgf@x=\pgf@path@lastx + \global\pgf@y=\pgf@path@lasty + \pgf@xa=\pgf@x \advance\pgf@xa by-\pgfpath@center@x + \pgf@ya=\pgf@y \advance\pgf@ya by-\pgfpath@center@y + \global\advance\pgf@x by-\pgfpath@scale@A\pgf@ya + \global\advance\pgf@y by \pgfpath@scale@B\pgf@xa + \endgroup + }{% + \begingroup + \pgfpath@endpt + \pgf@xa=\pgf@x \advance\pgf@xa by-\pgfpath@center@x + \pgf@ya=\pgf@y \advance\pgf@ya by-\pgfpath@center@y + \global\advance\pgf@x by \pgfpath@scale@A\pgf@ya + \global\advance\pgf@y by-\pgfpath@scale@B\pgf@xa + \endgroup + }{% + \pgfpath@endpt + }% + \endgroup +} + + + + + + + + + +% Append an ellipse to the current path. +% +% #1 = center +% #2 = first axis +% #3 = second axis +% +% Example: +% +% % Add a circle of radius 3cm around the origin +% \pgfpathellipse{\pgforigin}{\pgfxy(2,0)}{\pgfxy(0,1)} +% +% % Draw a non-filled circle of radius 1cm around the point (1,1) +% \pgfpathellipse{\pgfxy(1,1)}{\pgfxy(1,1)}{\pgfxy(-2,2)} +% \pgfstroke + +\def\pgfpathellipse#1#2#3{% + \pgfpointtransformed{#1}% store center in xc/yc + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfpointtransformed{#2}% + \pgf@xa=\pgf@x% store first axis in xa/ya + \pgf@ya=\pgf@y% + \advance\pgf@xa by-\pgf@pt@x% + \advance\pgf@ya by-\pgf@pt@y% + \pgfpointtransformed{#3}% + \pgf@xb=\pgf@x% store second axis in xb/yb + \pgf@yb=\pgf@y% + \advance\pgf@xb by-\pgf@pt@x% + \advance\pgf@yb by-\pgf@pt@y% + {% + \advance\pgf@xa by\pgf@xc% + \advance\pgf@ya by\pgf@yc% + \pgf@nlt@moveto{\pgf@xa}{\pgf@ya}% + }% + \pgf@x=0.55228475\pgf@xb% first arc + \pgf@y=0.55228475\pgf@yb% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \edef\pgf@temp{\pgf@xc\the\pgf@x\pgf@yc\the\pgf@y}% + \pgf@x=0.55228475\pgf@xa% + \pgf@y=0.55228475\pgf@ya% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + {% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \advance\pgf@xb by\pgf@xc% + \advance\pgf@yb by\pgf@yc% + \pgf@temp% + \pgf@nlt@curveto{\pgf@xc}{\pgf@yc}{\pgf@x}{\pgf@y}{\pgf@xb}{\pgf@yb}% + }% + \pgf@xa=-\pgf@xa% flip first axis + \pgf@ya=-\pgf@ya% + \pgf@x=0.55228475\pgf@xa% second arc + \pgf@y=0.55228475\pgf@ya% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \edef\pgf@temp{\pgf@xc\the\pgf@x\pgf@yc\the\pgf@y}% + \pgf@x=0.55228475\pgf@xb% + \pgf@y=0.55228475\pgf@yb% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + {% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \advance\pgf@xa by\pgf@xc% + \advance\pgf@ya by\pgf@yc% + \pgf@temp% + \pgf@nlt@curveto{\pgf@xc}{\pgf@yc}{\pgf@x}{\pgf@y}{\pgf@xa}{\pgf@ya}% + }% + \pgf@xb=-\pgf@xb% flip second axis + \pgf@yb=-\pgf@yb% + \pgf@x=0.55228475\pgf@xb% third arc + \pgf@y=0.55228475\pgf@yb% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \edef\pgf@temp{\pgf@xc\the\pgf@x\pgf@yc\the\pgf@y}% + \pgf@x=0.55228475\pgf@xa% + \pgf@y=0.55228475\pgf@ya% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + {% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \advance\pgf@xb by\pgf@xc% + \advance\pgf@yb by\pgf@yc% + \pgf@temp% + \pgf@nlt@curveto{\pgf@xc}{\pgf@yc}{\pgf@x}{\pgf@y}{\pgf@xb}{\pgf@yb}% + }% + \pgf@xa=-\pgf@xa% flip first axis once more + \pgf@ya=-\pgf@ya% + \pgf@x=0.55228475\pgf@xa% fourth arc + \pgf@y=0.55228475\pgf@ya% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \edef\pgf@temp{\pgf@xc\the\pgf@x\pgf@yc\the\pgf@y}% + \pgf@x=0.55228475\pgf@xb% + \pgf@y=0.55228475\pgf@yb% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + {% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \advance\pgf@xa by\pgf@xc% + \advance\pgf@ya by\pgf@yc% + \pgf@temp% + \pgf@nlt@curveto{\pgf@xc}{\pgf@yc}{\pgf@x}{\pgf@y}{\pgf@xa}{\pgf@ya}% + }% + \pgf@nlt@closepath% + \pgf@nlt@moveto{\pgf@xc}{\pgf@yc}% +} + + + +% Append a circle to the current path +% +% #1 = center +% #2 = radius +% +% Example: +% +% % Append a circle of radius 3cm around the point (1,1) +% \pgfpathcircle{\pgxy(1,1)}{3cm} + +\def\pgfpathcircle#1#2{\pgfpathellipse{#1}{\pgfpoint{#2}{0pt}}{\pgfpoint{0pt}{#2}}} + + + + +% Append a rectangle to the current path +% +% #1 = lower left corner point of rectangle +% #2 = width and height vector +% +% Example: +% +% % A rectangle with corners (2,2) and (3,3) +% \pgfpathrectangle{\pgfpointxy{2}{2}}{\pgfpointxy{1}{1}} + +\def\pgfpathrectangle{% + \let\pgfrect@next=\pgf@specialrect% + \ifpgf@pt@identity% + \ifpgf@arccorners% + \else% + \ifx\pgf@nlt@list\pgfutil@empty% + \let\pgfrect@next=\pgf@normalrect% + \fi% + \fi% + \fi% + \pgfrect@next% +} + +\def\pgf@normalrect#1#2{% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfpointtransformed{#1}% + \pgfsyssoftpath@rect{\the\pgf@x}{\the\pgf@y}{\the\pgf@xa}{\the\pgf@ya}% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% + \advance\pgf@x by\pgf@xa\relax% + \advance\pgf@y by\pgf@ya\relax% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% +} + +\def\pgf@specialrect#1#2{% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#1}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \advance\pgf@xa by\pgf@xb% + \advance\pgf@ya by\pgf@yb% + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}% + \pgfpathclose% + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}% +} + +% Append a rectangle to the current path +% +% #1 = one corner of the rectangle +% #2 = opposite corner of the rectangle +% +% Example: +% +% % A rectangle with corners (2,2) and (3,3) +% \pgfpathrectanglecorners{\pgfpointxy{2}{2}}{\pgfpointxy{3}{3}} + +\def\pgfpathrectanglecorners#1#2{% + \pgf@process{#2}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{#1}% + \advance\pgf@xc by-\pgf@x% + \advance\pgf@yc by-\pgf@y% + \pgfpathrectangle{#1}{\pgfqpoint{\pgf@xc}{\pgf@yc}}% +} + + +% Append a grid to the current path. +% +% #1 = first corner point of grid +% #2 = second corner point of grid +% +% Options: +% +% stepx = x-step dimension (default 1cm) +% stepy = y-step dimension (default 1cm) +% step = dimension vector +% +% Example: +% +% \pgfsetlinewidth{0.8pt} +% \pgfgrid{\pgfxy(0,0)}{\pgfxy(3,2)} +% \pgfsetlinewidth{0.4pt} +% \pgfgrid[stepx=1cm,stepy=1cm]{\pgfxy(0,0)}{\pgfxy(3,2)} + +\pgfkeys{ + /pgf/stepx/.initial=1cm, + /pgf/stepy/.initial=1cm, + /pgf/step/.code={\pgf@process{#1}\pgfkeysalso{/pgf/stepx/.expanded=\the\pgf@x,/pgf/stepy/.expanded=\the\pgf@y}}, + /pgf/step/.value required +} + +\def\pgfpathgrid{\pgfutil@ifnextchar[{\pgf@pathgrid}{\pgf@pathgrid[]}} +\def\pgf@pathgrid[#1]#2#3{% + \pgfset{#1}% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/stepx}}% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/stepy}}% + \pgf@process{#3}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % Swap coordinates if one of them is smaller than the other: + \ifdim\pgf@xa>\pgf@xb% + \pgf@x=\pgf@xb% + \pgf@xb=\pgf@xa% + \pgf@xa=\pgf@x% + \fi% + \ifdim\pgf@ya>\pgf@yb% + \pgf@y=\pgf@yb% + \pgf@yb=\pgf@ya% + \pgf@ya=\pgf@y% + \fi% + \ifdim \pgf@yc > .01pt\relax% if to draw horizontal lines + \c@pgf@counta=\pgf@ya\relax% + \c@pgf@countb=\pgf@yc\relax% + \divide\c@pgf@counta by\c@pgf@countb\relax% + \pgfutil@tempdima=\c@pgf@counta\pgf@yc\relax% + \ifdim\pgfutil@tempdima<\pgf@ya% + \advance\pgfutil@tempdima by\pgf@yc% + \fi% + \pgfutil@tempdimb\pgf@x + \pgfutil@loop% horizontal lines + {% + \pgf@xa=\pgfutil@tempdimb% + \pgf@ya=\pgfutil@tempdima% + \pgf@pos@transform{\pgf@xa}{\pgf@ya} + \pgf@nlt@moveto{\pgf@xa}{\pgf@ya}% + \pgf@xa=\pgf@xb% + \pgf@ya=\pgfutil@tempdima% + \pgf@pos@transform{\pgf@xa}{\pgf@ya} + \pgf@nlt@lineto{\pgf@xa}{\pgf@ya}% + }% + \advance\pgfutil@tempdima by\pgf@yc% + \ifdim\pgfutil@tempdima<\pgf@yb% + \pgfutil@repeat% + \advance\pgfutil@tempdima by-0.01pt\relax% + \ifdim\pgfutil@tempdima<\pgf@yb% + {% + \pgf@xa=\pgfutil@tempdimb% + \pgf@ya=\pgfutil@tempdima% + \pgf@pos@transform{\pgf@xa}{\pgf@ya} + \pgf@nlt@moveto{\pgf@xa}{\pgf@ya}% + \pgf@xa=\pgf@xb% + \pgf@ya=\pgfutil@tempdima% + \pgf@pos@transform{\pgf@xa}{\pgf@ya} + \pgf@nlt@lineto{\pgf@xa}{\pgf@ya}% + }% + \fi% + \fi% + \ifdim \pgf@xc > .01pt\relax% if to draw vertical lines + \c@pgf@counta=\pgf@xa\relax% + \c@pgf@countb=\pgf@xc\relax% + \divide\c@pgf@counta by\c@pgf@countb\relax% + \pgfutil@tempdimb=\c@pgf@counta\pgf@xc\relax% + \ifdim\pgfutil@tempdimb<\pgf@xa% + \advance\pgfutil@tempdimb by\pgf@xc% + \fi% + \pgfutil@loop% vertical lines + {% + \pgf@xc=\pgfutil@tempdimb% + \pgf@yc=\pgf@ya% + \pgf@pos@transform{\pgf@xc}{\pgf@yc} + \pgf@nlt@moveto{\pgf@xc}{\pgf@yc}% + \pgf@xc=\pgfutil@tempdimb% + \pgf@yc=\pgf@yb% + \pgf@pos@transform{\pgf@xc}{\pgf@yc} + \pgf@nlt@lineto{\pgf@xc}{\pgf@yc}% + }% + \advance\pgfutil@tempdimb by\pgf@xc% + \ifdim\pgfutil@tempdimb<\pgf@xb% + \pgfutil@repeat% + \advance\pgfutil@tempdimb by-0.01pt\relax% + \ifdim\pgfutil@tempdimb<\pgf@xb% + {% + \pgf@xc=\pgfutil@tempdimb% + \pgf@yc=\pgf@ya% + \pgf@pos@transform{\pgf@xc}{\pgf@yc} + \pgf@nlt@moveto{\pgf@xc}{\pgf@yc}% + \pgf@xc=\pgfutil@tempdimb% + \pgf@yc=\pgf@yb% + \pgf@pos@transform{\pgf@xc}{\pgf@yc} + \pgf@nlt@lineto{\pgf@xc}{\pgf@yc}% + }% + \fi% + \fi% + \pgf@process{#3}% + \pgf@pos@transform{\pgf@x}{\pgf@y}% + \pgf@nlt@moveto{\pgf@x}{\pgf@y}% +} + + + +% Append two half-parabolas to the path +% +% #1 = bend (relative to current point) +% #2 = end point (relative to bend point) +% +% Description: +% +% This command appends a half-parabola that starts at the current point +% and has its bend at #1+current point. Then, a second parabola is +% appended that starts at #1+current point, where it also has its +% minimum/maximum, and ends at #1+current point+#2, which becomes the +% new current point. +% +% By setting #2 = (0,0) you draw only a half parabola that goes from the +% current point to the bend; by setting #1 = (0,0) +% you draw a half parabola that going to current point + #2 and has its +% bend at the current point. +% +% Examples: +% +% % Half-parabola going ``up and right'' +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathparabola{\pgfpointorigin}{\pgfpoint{2cm}{4cm}} +% +% % Half-parabola going ``down and right'' +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathparabola{\pgfpoint{-2cm}{4cm}}}{\pgfpointorigin} +% +% % Full parabola +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathparabola{\pgfpoint{-2cm}{4cm}}{\pgfpoint{2cm}{4cm}} + +\def\pgfpathparabola#1#2{% + {% + \pgf@process{#2}% untransformed + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#1}% untransformed + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfutil@tempswatrue% + \ifdim\pgf@xb=0pt\relax% + \ifdim\pgf@yb=0pt\relax% + \pgfutil@tempswafalse% + \fi% + \fi% + {% + \ifpgfutil@tempswa% + \pgf@arccornersfalse + \else% + \fi% + \pgfutil@tempswatrue% + \ifdim\pgf@xc=0pt\relax% + \ifdim\pgf@yc=0pt\relax% + \pgfutil@tempswafalse% + \fi% + \fi% + \ifpgfutil@tempswa + {% + \pgf@pt@x=\pgf@path@lastx% + \pgf@pt@y=\pgf@path@lasty% + \pgfpathcurveto% + {\pgfqpoint{.1125\pgf@xc}{.225\pgf@yc}}% found by trial and error + {\pgfqpoint{.5\pgf@xc}{\pgf@yc}}% found by trial and error + {\pgfqpoint{\pgf@xc}{\pgf@yc}}% + }% + \fi% + }% + \ifpgfutil@tempswa% + \pgf@xc=\pgf@xb% + \pgf@yc=\pgf@yb% + {% + \pgf@pt@x=\pgf@path@lastx% + \pgf@pt@y=\pgf@path@lasty% + \pgfpathcurveto% + {\pgfqpoint{.5\pgf@xc}{0\pgf@yc}}% found by trial and error + {\pgfqpoint{.8875\pgf@xc}{.775\pgf@yc}}% found by trial and error + {\pgfqpoint{\pgf@xc}{\pgf@yc}}% + }% + \fi% + }% +} + + + + +% Append a sine curve between 0 and \pi/2 to the path. +% +% #1 = vector, describing the width and height of the curve +% +% Description: +% +% This command appends a sine curve in the interval 0 and \pi/2 to the +% current path. The sine curve ends at currentpoint+#1. +% +% Examples: +% +% % One complete sine in the interval [0,\pi] +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathsine{\pgfpoint{1.57cm}{1cm}} +% \pgfpathcosine{\pgfpoint{3.141cm}{0cm}} + +\def\pgfpathsine#1{% + {% + \pgf@process{#1}% untransformed + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@pt@x=\pgf@path@lastx% evil trickery to transform to the last point + \pgf@pt@y=\pgf@path@lasty% + \pgfpathcurveto% + {\pgfqpoint{.3260\pgf@xc}{.5120\pgf@yc}}% + {\pgfqpoint{.6380\pgf@xc}{\pgf@yc}}% + {\pgfqpoint{\pgf@xc}{\pgf@yc}}% + }% +} + +% Append a cosine curve between 0 and \pi/2 to the path. +% +% #1 = vector, describing the width and height of the curve +% +% Examples: +% +% % One complete sine in the interval [0,\pi] +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathsine{\pgfpoint{1.57cm}{1cm}} +% \pgfpathcosine{\pgfpoint{3.141cm}{0cm}} + +\def\pgfpathcosine#1{% + {% + \pgf@process{#1}% untransformed + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@pt@x=\pgf@path@lastx% evil trickery to transform to the last point + \pgf@pt@y=\pgf@path@lasty% + \pgfpathcurveto% + {\pgfqpoint{.3620\pgf@xc}{0pt}}% + {\pgfqpoint{.6740\pgf@xc}{.4880\pgf@yc}}% + {\pgfqpoint{\pgf@xc}{\pgf@yc}}% + }% +} + + + +% Draw part of a curve between two specified times s and t. +% +% #1 - a start time s. +% #2 - an end time t. +% #3 - start point of the curve +% #4 - first control +% #5 - second control +% #6 - end point of the curve +% +% There are two versions, \pgfpathcurvebetweentime and +% \pgfpathcurvebetweentimecontinue. The latter does not insert a +% moveto to the first point. +% +\def\pgfpathcurvebetweentime{\pgf@ignoremovetofalse\pgf@@pathcurvebetweentime} +\def\pgfpathcurvebetweentimecontinue{\pgf@ignoremovetotrue\pgf@@pathcurvebetweentime} +\newif\ifpgf@ignoremoveto + +\def\pgf@@pathcurvebetweentime#1#2#3#4#5#6{% + \pgfmathparse{#1}% + \let\pgf@time@s=\pgfmathresult% + \pgfmathparse{#2}% + \let\pgf@time@t=\pgfmathresult% + \ifdim\pgf@time@s pt>\pgf@time@t pt\relax% + \pgfmathsetmacro\pgf@time@s{1-#1}% + \pgfmathsetmacro\pgf@time@t{1-#2}% + \pgf@@@pathcurvebetweentime{\pgf@time@t}{#6}{#5}{#4}{#3}% + \else% + \pgf@@@pathcurvebetweentime{\pgf@time@t}{#3}{#4}{#5}{#6}% + \fi% +} + +\def\pgf@@@pathcurvebetweentime#1#2#3#4#5{% + % Q1 = P1. + \pgf@process{#2}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % Q2 = P1 + t*(P2-P1). + \pgf@process{% + \pgf@process{#3}% + \pgf@xa=#1\pgf@x% + \pgf@ya=#1\pgf@y% + \pgf@process{#2}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \advance\pgf@x by-#1\pgf@xb% + \advance\pgf@y by-#1\pgf@yb% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + }% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + % Q3 = Q2 + t*((P2 + t*(P3-P2)) - Q2). + \pgf@process{% + \pgf@process{#4}% + \pgf@xa=#1\pgf@x% + \pgf@ya=#1\pgf@y% + % + \pgf@process{#3}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xc by-#1\pgf@x% + \advance\pgf@yc by-#1\pgf@y% + % + \pgf@x=\pgf@xb% + \pgf@y=\pgf@yb% + \advance\pgf@x by#1\pgf@xa% + \advance\pgf@y by#1\pgf@ya% + \advance\pgf@x by-#1\pgf@xb% + \advance\pgf@y by-#1\pgf@yb% + \advance\pgf@x by#1\pgf@xc% + \advance\pgf@y by#1\pgf@yc% + }% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % Q4 = (1-t)^3*P1 + 3*t(1-t)^2*P2 + 3*t^2(1-t)*P3 + t^3*P4. + \pgf@process{\pgfpointcurveattime{#1}{#2}{#3}{#4}{#5}}% + \ifx#1\pgf@time@t% + % First time round... + \pgfmathdivide@{\pgf@time@s}{\pgf@time@t}% + \pgfmathadd@{-\pgfmathresult}{1}% + \let\pgf@time@s=\pgfmathresult% + \edef\pgf@marshal{% + \noexpand\pgf@@@pathcurvebetweentime{\noexpand\pgf@time@s}% + {\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + }% + \else% + % ...second time round. + \ifpgf@ignoremoveto% + \edef\pgf@marshal{% + \noexpand\pgfpathcurveto{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + }% + \else% + \edef\pgf@marshal{% + \noexpand\pgfpathmoveto{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \noexpand\pgfpathcurveto{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + }% + \fi% + \fi% + \pgf@marshal% +} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex new file mode 100644 index 0000000000..e33f0653ce --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex @@ -0,0 +1,563 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorepathprocessing.code.tex} + + +% Split a path at the last subpath of a path +% +% #1 = a macro that stores a path +% +% Description: +% +% This command will split the path into two parts: +% +% \pgfprocessresultpathprefix +% The part of the path before the last subpath. +% +% \pgfprocessresultpathsuffix +% The last subpath on the path. +% +% #1 will always be equal to the contents of the two above macros +% concatenated. Normally, your objective will be to modify the +% \pgfprocessresultpathsuffix and then concatenate the result. + +\def\pgfprocesssplitpath#1{% + \let\pgfprocessresultpathprefix\pgfutil@empty% + \let\pgfprocessresultpathsuffix\pgfutil@empty% + \let\pgf@next\pgf@process@split% + \expandafter\pgf@process@split#1\pgfsyssoftpath@movetotoken{}{}\pgf@stop% +} + +\def\pgf@process@split#1\pgfsyssoftpath@movetotoken#2#3#4{% + \ifx#4\pgf@stop% ok, end reached! + \expandafter\def\expandafter\pgfprocessresultpathsuffix\expandafter{\pgfprocessresultpathsuffix#1}% + \let\pgf@next\pgfutil@gobble% + \else% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgfprocessresultpathprefix% + \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathprefix\pgfprocessresultpathsuffix#1}% + \def\pgfprocessresultpathsuffix{\pgfsyssoftpath@movetotoken{#2}{#3}}% + \fi% + \pgf@next#4% +} + + + +% Split a subpath at the end +% +% #1 = a macro that stores an open subpath that contains at least two +% path commands (so, not just a moveto); +% +% Description: +% +% Splits the subpath into two parts: +% +% \pgfprocessresultsubpathsuffix +% This macro contains the last two "relevant" path commands: The end +% of the path command that led to the last path command and this +% last path command. In essence, this macro contains everything you +% "need to modify" if you wish to modify the end of the path. +% +% \pgfprocessresultsubpathprefix +% Everything before the previous macro on the subpath. + +\def\pgfprocesssplitsubpath#1{% + % First, we need to find the end: + \let\pgf@tempa\pgfutil@emtpy% + \let\pgf@tempb\pgfutil@emtpy% + \let\pgf@tempc\pgfutil@emtpy% + \let\pgf@tempd\pgfutil@emtpy% + \let\pgfprocessresultsubpathprefix\pgfutil@empty% + \let\pgfprocessresultsubpathsuffix\pgfutil@empty% + \let\pgf@next\pgf@split@subpath% + \expandafter\pgf@split@subpath#1\pgf@stop% +} + +\newif\ifpgf@split@move + +\def\pgf@split@subpath#1#2#3#4{% + \ifx#4\pgf@stop% + \expandafter\def\expandafter\pgfprocessresultsubpathsuffix\expandafter{\pgfprocessresultsubpathsuffix#1{#2}{#3}}% + \let\pgf@next\pgfutil@gobble% + \else% + \pgf@split@movetrue% + \ifx#1\pgfsyssoftpath@curvetosupportatoken% + \pgf@split@movefalse% + \else + \ifx#1\pgfsyssoftpath@curvetosupportbtoken% + \pgf@split@movefalse% + \fi% + \fi% + \ifpgf@split@move% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgfprocessresultsubpathprefix% + \expandafter\expandafter\expandafter{% + \expandafter\pgfprocessresultsubpathprefix\pgfprocessresultsubpathsuffix}% + \def\pgfprocessresultsubpathsuffix{#1{#2}{#3}}% + \else% + \expandafter\def\expandafter\pgfprocessresultsubpathsuffix\expandafter{\pgfprocessresultsubpathsuffix#1{#2}{#3}}% + \fi% + \fi% + \pgf@next#4% +} + + + + +% Extract start and end vectors of a path +% +% #1 = a macro that stores a path +% +% Description: +% +% This command will extract the first and second coordinate on the +% path as well as the last and second-last. These coordinates will be +% put in the pgfpoint-macros \pgfpointfirstonpath, +% \pgfpointsecondonpath, \pgfpointsecondlastonpath, and +% \pgfpointlastonpath. If the path is empty, these macros are set to +% \pgfpointorigin. +% +% Example: +% +% \pgfsyssoftpath@moveto{0}{0} +% \pgfsyssoftpath@lineto{10}{10} +% \pgfsyssoftpath@curveto{20}{20}{30}{30}{40}{40} +% \pgfsyssoftpath@getcurrentpath\mypath +% \pgfprocesspathextractpoints\mypath +% +% % \pgfpointfirstonpath is now \pgfpoint{0}{0} +% % \pgfpointsecondonpath is now \pgfpoint{10bp}{10bp} +% % \pgfpointsecondlastonpath is now \pgfpoint{30bp}{30bp} +% % \pgfpointlastonpath is now \pgfpoint{40bp}{40bp} + +\def\pgfprocesspathextractpoints#1{% + \ifx#1\pgfutil@empty% + \let\pgfpointfirstonpath=\pgfpointorigin% + \let\pgfpointsecondonpath=\pgfpointorigin% + \let\pgfpointsecondlastonpath=\pgfpointorigin% + \let\pgfpointlastonpath=\pgfpointorigin% + \else% + \expandafter\pgf@extractprocessorfirst#1\pgf@stop% + \fi% +} + +\def\pgf@extractprocessorfirst#1#2#3#4{% + \def\pgfpointfirstonpath{\pgfqpoint{#2}{#3}}% + \ifx#4\pgf@stop% + % pretty short path... + \let\pgfpointsecondonpath=\pgfpointfirstonpath% + \let\pgfpointsecondlastonpath=\pgfpointfirstonpath% + \let\pgfpointlastonpath=\pgfpointfirstonpath% + \let\next=\pgfutil@gobble% + \else + \let\next=\pgf@extractprocessorsecond% + \fi% + \next#4% +} + +\def\pgf@extractprocessorsecond#1{% + \ifx#1\pgfsyssoftpath@movetotoken% + % Reset things... + \let\pgf@next=\pgf@extractprocessorfirst% + \else% + \let\pgf@next=\pgf@@extractprocessorsecond% + \fi% + \pgf@next#1% +} +\def\pgf@@extractprocessorsecond#1#2#3#4{% + \def\pgfpointsecondonpath{\pgfqpoint{#2}{#3}}% + \let\pgfpointsecondlastonpath=\pgfpointfirstonpath% + \let\pgfpointlastonpath=\pgfpointsecondonpath% + \ifx#4\pgf@stop% + % short path... + \let\next=\pgfutil@gobble% + \else + \let\next=\pgf@extractprocessorother% + \fi% + \next#4% +} + +\def\pgf@extractprocessorother#1{% + \ifx#1\pgfsyssoftpath@movetotoken% + % Reset things... + \let\pgf@next=\pgf@extractprocessorfirst% + \else% + \let\pgf@next=\pgf@@extractprocessorother% + \fi% + \pgf@next#1% +} +\def\pgf@@extractprocessorother#1#2#3#4{% + \let\pgfpointsecondlastonpath=\pgfpointlastonpath% + \def\pgfpointlastonpath{\pgfqpoint{#2}{#3}}% + \ifx#4\pgf@stop% + % end! + \let\next=\pgfutil@gobble% + \fi% + \next#4% +} + + + +% Check for closepath and rectangles +% +% #1 = a macro that stores a path +% #2 = command to be executed when a closepath or a rectangle is encountered +% +% Example: +% +% \pgfsyssoftpath@moveto{0}{0} +% \pgfsyssoftpath@lineto{10}{10} +% \pgfsyssoftpath@curveto{20}{20}{30}{30}{40}{40} +% \pgfsyssoftpath@getcurrentpath\mypath +% \pgfprocesscheckclosed{\mypath}{\pgf@drawarrowsfalse} + +\def\pgfprocesscheckclosed#1#2{% + {% + \global\let\pgf@proc@todo=\relax% + \let\pgfsyssoftpath@movetotoken=\pgfutil@gobbletwo% + \let\pgfsyssoftpath@linetotoken=\pgfutil@gobbletwo% + \let\pgfsyssoftpath@curvetosupportatoken=\pgfutil@gobbletwo% + \let\pgfsyssoftpath@curvetosupportbtoken=\pgfutil@gobbletwo% + \let\pgfsyssoftpath@curvetotoken=\pgfutil@gobbletwo% + \def\pgfsyssoftpath@rectcornertoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}% + \def\pgfsyssoftpath@rectsizetoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}% + \def\pgfsyssoftpath@closepathtoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}% + #1% + }% + \pgf@proc@todo% +} + + +% Resolve specialround +% +% #1 = a macro that stores a path +% #2 = a macro that stores the new path +% +% Description: +% +% Resolves all specialround tokens. When such a token is encountered, +% the objective is to replace the next corner by a rounded corner. +% + +\def\pgfprocessround#1#2{% + % first, check whether #1 contains \pgfsyssoftpath@specialroundtoken. + % if not, do quick assignment! + \expandafter\pgf@processroundcheck\expandafter#1\expandafter#2#1\pgfsyssoftpath@specialroundtoken\pgf@stop% +} + +\def\pgf@processroundcheck#1#2#3\pgfsyssoftpath@specialroundtoken#4\pgf@stop{% + \def\pgf@test{#4}% + \ifx\pgf@test\pgfutil@empty% + % ok, nothing to be done! + \let#2=#1% + \else% + % very well... + \pgf@@processround#1#2% + \fi% +} + + +\def\pgf@@processround#1#2{% + \let\pgfprocess@newpath\pgfutil@empty% + \let\pgfprocess@moveto\pgfutil@empty% + \let\pgfprocess@firstto\pgfutil@empty% + \let\pgfprocess@segment\pgfutil@empty% + \pgf@xa=0pt% + \pgf@ya=0pt% + \expandafter\pgfprocess@round#1\pgf@stop{0pt}{0pt}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@moveto}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@segment}% + \let#2=\pgfprocess@newpath% +} + +\def\pgfprocess@round#1#2#3{% + \ifx#1\pgf@stop% + \let\next=\relax% + \else% + \ifx#1\pgfsyssoftpath@specialroundtoken% + \def\pgfprocess@savex{#2}% + \def\pgfprocess@savey{#3}% + \let\next=\pgfprocess@specialround% + \ifdim#2=0pt% + \ifdim#3=0pt% + \let\next=\pgfprocess@round% skip! + \fi% + \fi% + \else% + \ifx\pgfprocess@firstto\pgfutil@empty% + \def\pgfprocess@firstto{{#2}{#3}}% + \fi% + \pgf@xa=#2% + \pgf@ya=#3% + \ifx#1\pgfsyssoftpath@movetotoken% + % ok, move old segment to newpath + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@moveto}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@segment}% + \def\pgfprocess@moveto{#1{#2}{#3}}% + \let\pgfprocess@firstto=\pgfutil@empty% + \let\pgfprocess@segment=\pgfutil@empty% + \else% + \pgfutil@g@addto@macro\pgfprocess@segment{#1{#2}{#3}}% + \fi% + \let\next=\pgfprocess@round% + \fi% + \fi% + \next% +} + +\def\pgfprocess@specialround#1#2#3{% + \ifx\pgfprocess@firstto\pgfutil@empty% + \def\pgfprocess@firstto{{#2}{#3}}% + \fi% + \let\next=\pgfprocess@round% default: do nothing + \ifx#1\pgfsyssoftpath@linetotoken% + % Ok, round a lineto + \let\next=\pgfprocess@specialroundcope% + \else% + \ifx#1\pgfsyssoftpath@curvetosupportatoken% + % Ok, round a curveto. + \let\next=\pgfprocess@specialroundcurveto% + \else% + \ifx#1\pgfsyssoftpath@closepathtoken% + % Ok, round a closepath (this is tricky...) + \let\next=\pgfprocess@specialroundclose% + \fi% + \fi% + \fi% + \next#1{#2}{#3}% +}% + +\def\pgfprocess@specialroundcope#1#2#3#4#5#6{% + \let\next=\pgfprocess@round% do nothing by default + \let\pgfprocess@continueafterrounding=\pgfprocess@round% + \ifx#4\pgfsyssoftpath@linetotoken% + % ok, let's get kicking... + \pgf@xc=#5% + \pgf@yc=#6% + \let\next=\pgfprocess@@specialround% + \else% + \ifx#4\pgfsyssoftpath@curvetosupportatoken% + \pgf@xc=#5% + \pgf@yc=#6% + \let\next=\pgfprocess@@specialround% + \else% + \ifx#4\pgfsyssoftpath@closepathtoken% + \pgf@xc=#5% + \pgf@yc=#6% + \let\next=\pgfprocess@@specialround% + \else + \ifx#4\pgfsyssoftpath@specialroundtoken% + \let\next=\pgfprocess@@findrightcoordinates% + \fi% + \fi% + \fi% + \fi% + \next#1{#2}{#3}#4{#5}{#6}% +} + +\def\pgfprocess@@findrightcoordinates#1#2#3#4#5#6#7#8#9{% + \pgf@xc=#8% + \pgf@yc=#9% + \pgfprocess@@specialround#1{#2}{#3}#4{#5}{#6}#7{#8}{#9}% +} + +\def\pgfprocess@@specialround#1#2#3{% + \pgfutil@g@addto@macro\pgfprocess@segment{#1}% + % calculate start coordinate of the curve + \pgf@xb=#2% + \pgf@yb=#3% + % + \edef\pgf@marshal% + {\noexpand\pgfpointlineatdistance{\pgfprocess@savex}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}% + {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}}% + \pgf@process{\pgf@marshal}% + \pgf@xa=\pgf@x% save start point of added curve + \pgf@ya=\pgf@y% + \edef\pgfprocess@addition{{\the\pgf@x}{\the\pgf@y}}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}% + % + % now add curve + % + \edef\pgf@marshal% + {\noexpand\pgfpointlineatdistance{\pgfprocess@savey}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}% + {\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}}% + \pgf@process{\pgf@marshal}% + \pgf@xc=\pgf@x% save end point of added curve + \pgf@yc=\pgf@y% + % calculate first support: + {% + \pgf@x=\pgf@xb% + \pgf@y=\pgf@yb% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@y by-\pgf@ya% + \advance\pgf@xa by 0.5522847\pgf@x% + \advance\pgf@ya by 0.5522847\pgf@y% + \edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetosupportatoken{\the\pgf@xa}{\the\pgf@ya}}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}% + }% + % calculate second support: + {% + \pgf@x=\pgf@xb% + \pgf@y=\pgf@yb% + \advance\pgf@x by-\pgf@xc% + \advance\pgf@y by-\pgf@yc% + \advance\pgf@xc by 0.5522847\pgf@x% + \advance\pgf@yc by 0.5522847\pgf@y% + \edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetosupportbtoken{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}% + }% + % add end: + \edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetotoken{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}% + % + % continue! + % + \pgf@xa=#2% + \pgf@ya=#3% + \pgfprocess@continueafterrounding% +} + +\def\pgfprocess@specialroundcurveto#1#2#3#4#5#6{% + \pgfutil@g@addto@macro\pgfprocess@segment{#1{#2}{#3}#4{#5}{#6}}% supports + \pgf@xa=#5% + \pgf@ya=#6% + \pgfprocess@specialroundcope} + +\def\pgfprocess@specialroundclose{% + \let\next=\pgfprocess@round% + \ifx\pgfprocess@moveto\pgfutil@empty% + \else% + \ifx\pgfprocess@firstto\pgfutil@empty% + \else% + \expandafter\pgfprocess@@specialclosetarget\pgfprocess@firstto% + \let\pgfprocess@continueafterrounding=\pgfprocess@cleanupafterclose% + \edef\next{% + \noexpand\pgfprocess@@specialround% + \expandafter\expandafter\expandafter\noexpand\expandafter\pgfprocess@@specialclosemoveto\pgfprocess@moveto% + }% + \fi% + \fi% + \next% +} + +\def\pgfprocess@@specialclosetarget#1#2{% + \pgf@xc=#1% + \pgf@yc=#2% +} + +\def\pgfprocess@@specialclosemoveto#1#2#3{% + \pgfsyssoftpath@linetotoken{#2}{#3}% +} + + +\def\pgfprocess@cleanupafterclose#1#2#3{% + \edef\pgfprocess@moveto{\noexpand\pgfsyssoftpath@movetotoken{\the\pgf@xc}{\the\pgf@yc}}% + \edef\pgf@marshal{\noexpand\pgfprocess@round\noexpand\pgfsyssoftpath@closepathtoken{\the\pgf@xc}{\the\pgf@yc}}% + \pgf@marshal% +} + + +% Replace start and end coordinates of a path +% +% #1 = new start coordinate +% #2 = new end coordinate +% +% Description: +% +% This command will replace the first and last coordinates on a path +% by the given coordinates. +% +% Example: +% +% \pgfsyssoftpath@moveto{0}{0} +% \pgfsyssoftpath@lineto{10}{10} +% \pgfsyssoftpath@curveto{20}{20}{30}{10}{40}{0} +% \pgfsyssoftpath@getcurrentpath\mypath +% \pgfsetlinewidth{2pt} +% \pgfusepath{stroke} +% \pgfprocesspathextractpoints{\mypath} +% \pgfprocesspathreplacestartandend{\mypath} +% {\pgfpointlineatdistance{2pt}{\pgfpointfirstonpath}{\pgfpointsecondonpath}}% +% {\pgfpointlineatdistance{2pt}{\pgfpointlastonpath}{\pgfpointsecondlastonpath}}% +% \pgfsyssoftpath@setcurrentpath\mypath +% \pgfsetlinewidth{1pt} +% \color{red} +% \pgfusepath{stroke} + +\def\pgfprocesspathreplacestartandend#1#2#3{% + \ifx#1\pgfutil@empty% + \else% + {% + % We (mis)use the current path to store (in a buffered manner) the + % rest path. + \pgfsyssoftpath@getcurrentpath\pgf@replace@origpath% + \let\pgf@prepath=\pgfutil@empty% + \pgf@process{#3}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#2}% + \expandafter\pgf@replaceprocessfirst#1\pgf@stop% + \pgfsyssoftpath@getcurrentpath\pgf@restpath% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\gdef% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter\pgf@prepath% + \expandafter\pgf@newstart\pgf@restpath}% + % Restore current path + \pgfsyssoftpath@setcurrentpath\pgf@replace@origpath% + }% + \fi% +} + +\def\pgf@replaceprocessfirst#1#2#3#4{% + \def\pgf@origstart{#1{#2}{#3}}% + \edef\pgf@newstart{\noexpand#1{\the\pgf@x}{\the\pgf@y}}% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \ifx#4\pgf@stop% + \let\pgf@next=\pgfutil@gobble% + \else% + \let\pgf@next=\pgf@replaceprocessother% + \let\pgf@@next=\pgf@@replaceprocessother% + \fi% + \pgf@next#4% +} + +\def\pgf@replaceprocessother#1{% + \ifx#1\pgfsyssoftpath@movetotoken% + \pgf@replace@handle@move% + \fi% + \pgf@@next#1% +} +\def\pgf@@replaceprocessother#1#2#3#4{% + \ifx#4\pgf@stop% + \edef\pgf@restpathaddition{{\noexpand#1{\the\pgf@xa}{\the\pgf@ya}}}% + \expandafter\pgfsyssoftpath@addtocurrentpath\pgf@restpathaddition% + \let\pgf@next=\pgfutil@gobble% + \else% + \pgfsyssoftpath@addtocurrentpath{#1{#2}{#3}}% + \fi% + \pgf@next#4% +} + +\def\pgf@replace@handle@move{% + \pgfsyssoftpath@getcurrentpath\pgf@restpath% + % Arggghh! Must reset everything! + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\gdef% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\pgf@prepath% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter\pgf@prepath% + \expandafter\pgf@origstart\pgf@restpath}% + % Redo first. + \let\pgf@@next=\pgf@replaceprocessfirst% +} + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathusage.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathusage.code.tex new file mode 100644 index 0000000000..5a9c5fc22b --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathusage.code.tex @@ -0,0 +1,661 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorepathusage.code.tex} + + +% Stroke/fill/clip/etc. the current path. Depending on the options, +% the current path will be stroked/filled/clipped/etc. If no options +% are given, the path is stroked. If multiple options are given, all +% of them are performed (in a sensible order). +% +% #1 = action(s) to be applied to the current path. Valid actions are: +% stroke - strokes the path. +% draw - strokes the path and adds arrow tips. +% tips - adds arrow tips. +% fill - fills the path. +% clip - clip the path. +% discard - Discards the path. Same effect as having an empty +% options list. +% +% Example: +% +% % Draws an edge. +% \pgfpathmoveto{\pgfxy(0,0)} +% \pgfpathlineto{\pgfxy(0,1)} +% \pgfpathlineto{\pgfxy(1,0)} +% \pgfusepath{stroke} + +\pgfkeys{ + /pgf/stroke/.code=\let\pgf@up@stroke\pgf@up@stroke@text\pgf@up@path@neededtrue, + /pgf/draw/.code=\let\pgf@up@stroke\pgf@up@stroke@text\pgf@up@path@neededtrue, + /pgf/fill/.code=\let\pgf@up@fill\pgf@up@fill@text\pgf@up@path@neededtrue, + /pgf/clip/.code=\let\pgf@up@clip\pgf@up@clip@text\pgf@up@path@neededtrue, + /pgf/discard/.code=, + /pgf/use as bounding box/.code=\let\pgf@up@bb\pgf@do@up@bb, + /pgf/arrow keys/flex/.code=\pgferror{You need to say \string\usetikzlibrary{bending} for flexing and bending arrows}, + /pgf/arrow keys/flex'/.code=\pgferror{You need to say \string\usetikzlibrary{bending} for flexing and bending arrows}, + /pgf/arrow keys/bend/.code=\pgferror{You need to say \string\usetikzlibrary{bending} for flexing and bending arrows}, + /pgf/arrow keys/quick/.code=\pgfarrowsaddtooptions{\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@quick}, +} + +\pgfkeys{ + /pgf/.cd, + tips/.is choice, + tips/.default=true, + tips/proper/.code=\let\pgf@tips@mode\pgf@tips@mode@onproper, + tips/on proper draw/.code=\let\pgf@tips@mode\pgf@tips@mode@onproperdraw, + tips/true/.code=\let\pgf@tips@mode\pgf@tips@mode@true, + tips/on draw/.code=\let\pgf@tips@mode\pgf@tips@mode@ondraw, + tips/never/.code=\let\pgf@tips@mode\pgf@tips@mode@false, + tips/false/.code=\let\pgf@tips@mode\pgf@tips@mode@false, +} +\def\pgf@tips@mode@onproper{4} +\def\pgf@tips@mode@onproperdraw{3} +\def\pgf@tips@mode@true{2} +\def\pgf@tips@mode@ondraw{1} +\def\pgf@tips@mode@false{0} +\let\pgf@tips@mode\pgf@tips@mode@ondraw + + +% The following can only be set to "true" using the options in the +% module "bending" +\newif\ifpgf@precise@shortening +\def\pgf@arrow@mode@is@quick{0} +\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@quick + +\newif\ifpgf@up@path@needed +\newif\ifpgf@up@draw@arrows +\def\pgf@up@stroke@text{stroke} +\def\pgf@up@fill@text{fill} +\def\pgf@up@clip@text{clip} +\def\pgf@do@up@bb{\pgf@relevantforpicturesizefalse} + +\def\pgfusepath#1{% + \pgf@up@path@neededfalse% + \pgf@up@draw@arrowsfalse% + \let\pgf@up@stroke\pgfutil@empty% + \let\pgf@up@fill\pgfutil@empty% + \let\pgf@up@clip\pgfutil@empty% + \let\pgf@up@bb\pgfutil@empty% + \pgfset{#1}% + \expandafter\def\expandafter\pgf@up@action\expandafter{\csname pgfsys@\pgf@up@fill\pgf@up@stroke\endcsname}% + \ifnum\pgf@tips@mode=2\relax% + \pgf@up@path@neededtrue% + \fi% + \ifnum\pgf@tips@mode=4\relax% + \pgf@up@path@neededtrue% + \fi% + \ifpgf@up@path@needed% + \else% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \fi% + \ifx\pgf@up@stroke\pgfutil@empty% + \ifx\pgf@up@fill\pgfutil@empty% + \let\pgf@up@action=\pgfutil@empty% + \ifx\pgf@up@clip\pgfutil@empty% + \else% + % only clipping + \let\pgf@up@action=\pgfsys@discardpath% + \fi% + \fi% + \fi% + \pgfsyssoftpath@getcurrentpath\pgf@last@processed@path + \pgfprocessround{\pgf@last@processed@path}{\pgf@last@processed@path}% change the path + \pgfsyssoftpath@setcurrentpath\pgf@last@processed@path% + % + % Check whether the path is stroked. If so, add half the line width + % to the bounding box. + % + \ifpgf@relevantforpicturesize% + \ifx\pgf@up@stroke\pgfutil@empty% + \else% + \ifdim\pgf@picmaxx=-16000pt\relax% + \else% + \pgf@x=\pgf@pathminx\advance\pgf@x by-.5\pgflinewidth% + \ifdim\pgf@x<\pgf@picminx\global\pgf@picminx\pgf@x\fi% + \pgf@y=\pgf@pathminy\advance\pgf@y by-.5\pgflinewidth% + \ifdim\pgf@y<\pgf@picminy\global\pgf@picminy\pgf@y\fi% + \pgf@x=\pgf@pathmaxx\advance\pgf@x by.5\pgflinewidth% + \ifdim\pgf@x>\pgf@picmaxx\global\pgf@picmaxx\pgf@x\fi% + \pgf@y=\pgf@pathmaxy\advance\pgf@y by.5\pgflinewidth% + \ifdim\pgf@y>\pgf@picmaxy\global\pgf@picmaxy\pgf@y\fi% + \fi% + \fi% + \fi% + % + \ifx\pgf@up@clip\pgfutil@empty% + \ifx\pgf@up@stroke\pgfutil@empty% + \ifx\pgf@up@action\pgfutil@empty% + \ifnum\pgf@tips@mode=2\relax% + \pgf@up@draw@arrows@only% + \fi% + \ifnum\pgf@tips@mode=4\relax% + \pgf@up@draw@arrows@only% + \fi% + \else% + \pgfsyssoftpath@invokecurrentpath% + \pgf@up@action% + \fi% + \else% + \pgfgetpath\pgf@arrowpath% + \pgf@path@setup@tempswa% + \pgfprocesscheckclosed{\pgf@arrowpath}{\pgfutil@tempswafalse}% + \pgf@path@check@proper% + \ifpgfutil@tempswa% + \pgf@check@for@arrow@and@animation% + \pgf@prepare@end@of@path% + \begingroup% + \pgf@prepare@start@of@path% + \fi% + \pgfsyssoftpath@invokecurrentpath% + \pgf@up@action% + \ifdim\pgfinnerlinewidth>0pt\relax% + \pgf@stroke@inner@line% + \fi% + \ifpgfutil@tempswa% + \pgf@add@arrow@at@start% + \endgroup% + \pgf@add@arrow@at@end% + \fi% + \fi% + \else% + \pgfsyssoftpath@invokecurrentpath% + \pgfsys@clipnext% + \pgf@up@action% + \pgf@relevantforpicturesizefalse% + \fi% + \pgf@up@bb% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \pgf@resetpathsizes% + \ignorespaces% +} +\def\pgf@path@setup@tempswa{% + \ifnum\pgf@tips@mode>0\relax + \pgfutil@tempswatrue% + \else + \pgfutil@tempswafalse% + \fi% +} +\def\pgf@up@draw@arrows@only{% + \pgfgetpath\pgf@arrowpath% + \pgfutil@tempswatrue% + \pgfprocesscheckclosed{\pgf@arrowpath}{\pgfutil@tempswafalse}% + \pgf@path@check@proper% + \ifpgfutil@tempswa% + \pgf@check@for@arrow@and@animation% + \pgf@prepare@end@of@path% + \begingroup% + \pgf@prepare@start@of@path% + \pgf@add@arrow@at@start% + \endgroup% + \pgf@add@arrow@at@end% + \fi% +} + +\def\pgf@check@for@arrow@and@animation{\pgfsys@if@fresh@currentid{\pgf@check@for@arrow@and@animation@}{}}% +\def\pgf@check@for@arrow@and@animation@{% + \expandafter\ifx\csname pgfsysanim@path@is@animated@\pgf@sys@id@current@id @\pgfsys@current@type\endcsname\pgfutil@empty% + % Ok, an animation is here! + \ifx\pgf@end@tip@sequence\pgfutil@empty% + \ifx\pgf@start@tip@sequence\pgfutil@empty% + \else% + \pgf@check@for@arrow@and@animation@error% + \fi% + \else% + \pgf@check@for@arrow@and@animation@error% + \fi% + \fi% +} +\def\pgf@check@for@arrow@and@animation@error{\pgferror{Animated path may not have normal arrow tips. Use a base path with arrow tips}} + +\def\pgf@path@check@proper{% + \ifpgfutil@tempswa% + \ifnum\pgf@tips@mode>2\relax% + \pgf@path@check@proper@% + \fi% + \fi% +} + +\def\pgf@path@check@proper@{% + {% + \pgf@x0pt\pgf@y\pgf@x% + \pgfutil@tempswatrue% + \let\pgfsyssoftpath@movetotoken\pgf@path@proper@init% + \let\pgfsyssoftpath@linetotoken\pgf@path@proper@test%% + \let\pgfsyssoftpath@curvetosupportatoken\pgf@path@proper@test% + \let\pgfsyssoftpath@curvetosupportbtoken=\pgf@path@proper@test% + \let\pgfsyssoftpath@curvetotoken\pgf@path@proper@test% + \let\pgfsyssoftpath@rectcornertoken\pgf@path@proper@test% + \let\pgfsyssoftpath@rectsizetoken\pgf@path@proper@zero@test% + \let\pgfsyssoftpath@closepathtoken\pgf@path@proper@test% + % Execute the path: + \pgf@arrowpath% + \expandafter + }% + \ifpgfutil@tempswa\pgfutil@tempswafalse\else\pgfutil@tempswatrue\fi% +} + +\def\pgf@path@proper@init#1#2{\pgfutil@tempswatrue\pgf@x#1\pgf@y#2}% +\def\pgf@path@proper@test#1#2{% + \ifdim\pgf@x=#1\relax\else\pgfutil@tempswafalse\fi% + \ifdim\pgf@y=#2\relax\else\pgfutil@tempswafalse\fi} +\def\pgf@path@proper@zero@test#1#2{% + \ifdim\pgf@x=0pt\relax\else\pgfutil@tempswafalse\fi% + \ifdim\pgf@y=0pt\relax\else\pgfutil@tempswafalse\fi} + + + + +\def\pgf@stroke@inner@line{% + \let\pgf@temp@save=\pgf@strokecolor@global + \pgfsys@beginscope% + {% + \pgfsys@setlinewidth{\pgfinnerlinewidth}% + \pgfsetstrokecolor{\pgfinnerstrokecolor}% + \pgfsyssoftpath@invokecurrentpath% + \pgfsys@stroke% + }% + \pgfsys@endscope% + \global\let\pgf@strokecolor@global=\pgf@temp@save +} + +\let\pgf@prepare@start@of@path\relax% + + + + +% Shorten start/end of paths by a certain amount. +% +% #1 = amount by which paths should be shortened. +% +% Example: +% +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathlineto{\pgfpoint{10pt}{0pt} +% +% % The following has the same effect: +% \pgfsetshortenstart{1pt} +% \pgfpathmoveto{\pgfpointorigin} +% \pgfpathlineto{\pgfpoint{11pt}{0pt} + +\def\pgfsetshortenstart#1{\pgfmathsetlength\pgf@shorten@start@additional{#1}} +\def\pgfsetshortenend#1{\pgfmathsetlength\pgf@shorten@end@additional{#1}} + +\newdimen\pgf@shorten@end@additional +\newdimen\pgf@shorten@start@additional + + + +% +% +% Handling the end of a path +% +% +% The "handling" consists of first testing whether we need to do +% anything at all, namely because either an arrow tip should be drawn +% at the end or because the path should be shortened at the end. If +% so, we shorten the path if needed and, later on, add the arrow tip. +% + +\newif\ifpgf@worry + + +% Prepare the end of the path: Test whether anything must be done +% (step 0) and, if so, split the path (step 1), extract the interesting points from +% the path (step 2), prepare further computations (step 3), shorten +% the path (step 4) if necessary, and add the arrow tip (step 4 in +% macro \pgf@add@arrow@at@end, which is called later). + +\def\pgf@prepare@end@of@path{% + \let\pgfprocessresultpathsuffix\relax% flag that nothing has happened... + \let\pgfprocessresultsubpathsuffix\relax% + \pgfsyssoftpath@getcurrentpath\pgf@arrowpath% + % + % Step 0 start: + % + % Do we need to worry about the end? + % + \ifx\pgf@arrowpath\pgfutil@empty\else% + \pgf@worryfalse% + \ifx\pgf@end@tip@sequence\pgfutil@empty% + \else% + \pgf@worrytrue% Yes, worry if we have to draw an arrow + \fi% + \pgf@precise@shorteningfalse% + \pgf@arrow@compute@shortening\pgf@end@tip@sequence% + \advance\pgf@xa by\pgf@shorten@end@additional% + \advance\pgf@xb by\pgf@shorten@end@additional% + \ifdim\pgf@xa=0pt\relax\else\pgf@worrytrue\fi% Also, worry if shortening is requested + \edef\pgf@path@shortening@distance{\the\pgf@xa}% + \edef\pgf@arrow@tip@total@length{\the\pgf@xb}% + % + % Step 0 done. + % + \ifpgf@worry% + % Ok, need to "worry" about the end, either because we need to + % shorten it or to draw an arrow head. + % + % Step 1: Split + % + \pgfprocesssplitpath{\pgf@arrowpath}% + \pgfprocesssplitsubpath{\pgfprocessresultpathsuffix}% + % + % Step 2: extract + % + \expandafter\pgf@parse@end\pgfprocessresultsubpathsuffix\pgf@stop\pgf@stop\pgf@stop% + % + % Step 3: prep + % + \pgf@prep@end% + % + % Step 4: shorten + % + \ifdim\pgf@path@shortening@distance=0pt\else\pgf@do@shorten@end\fi% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrowpath% + \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathprefix\pgfprocessresultpathsuffix}% + \pgfsyssoftpath@setcurrentpath\pgf@arrowpath% + \fi% + \fi% +} + +\def\pgf@parse@end#1#2#3#4#5#6{% + \ifx#4\pgf@stop% Only a moveto! -> do nothing! + \def\pgfpointlastonpath{\pgfqpoint{#2}{#3}}% + \let\pgf@next\relax% + \let\pgf@do@shorten@end\relax% + \let\pgf@do@draw@end\pgf@do@draw@straightend% + \let\pgf@prep@end\pgf@prep@movetoend% + \else\ifx#4\pgfsyssoftpath@curvetosupportatoken% A curve -> this will get complicated... + \def\pgfsubpathfourthlasttoken{#1}% + \def\pgfpointfourthlastonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointthirdlastonpath{\pgfqpoint{#5}{#6}}% + \ifpgf@precise@shortening% + \let\pgf@do@shorten@end\pgf@do@shorten@curvedend% + \let\pgf@do@draw@end\pgf@do@draw@curvedend% + \let\pgf@prep@end\pgf@prep@curveend% + \else% + \def\pgfsubpathstart{\noexpand#1{#2}{#3}\noexpand#4{#5}{#6}}% + \let\pgf@do@shorten@end\pgf@do@shorten@straightend% + \let\pgf@do@draw@end\pgf@do@draw@straightend% + \let\pgf@prep@end\pgf@prep@straightend% + \fi% + \let\pgf@next\pgf@parse@end@curve@cont% + \else% A straight line -> great! + \def\pgfsubpathstart{\noexpand#1{#2}{#3}\noexpand#4}% + \def\pgfpointsecondlastonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointlastonpath{\pgfqpoint{#5}{#6}}% + \let\pgfpointfourthlastonpath\relax% + \let\pgfpointthirdlastonpath\relax% + \let\pgf@next\pgf@parse@end@gobble@three% + \let\pgf@do@shorten@end\pgf@do@shorten@straightend% + \let\pgf@do@draw@end\pgf@do@draw@straightend% + \let\pgf@prep@end\pgf@prep@straightend% + \fi\fi% + \pgf@next% Needed for reading rest of path... +} + +\def\pgf@parse@end@gobble@three#1#2#3{}% +\def\pgf@parse@end@curve@cont#1#2#3#4#5#6#7#8#9{% + \def\pgfpointsecondlastonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointlastonpath{\pgfqpoint{#5}{#6}}% + \ifpgf@precise@shortening% + \else% + \expandafter\def\expandafter\pgfsubpathstart\expandafter{\pgfsubpathstart\noexpand#1{#2}{#3}\noexpand#4}% + \fi% +} + +% +% Preps +% +\def\pgf@prep@movetoend{% + \pgf@process{\pgfpointlastonpath}% + \pgf@xb\pgf@x + \pgf@yb\pgf@y + \pgf@xc\pgf@x + \pgf@yc\pgf@y +} +\def\pgf@prep@straightend{% + \let\pgf@ref\pgfpointsecondlastonpath + \ifx\pgfpointlastonpath\pgfpointsecondlastonpath% degenerate! + \ifx\pgfpointthirdlastonpath\relax% cannot help it: really a zero-length path + \else% + \ifx\pgfpointlastonpath\pgfpointthirdlastonpath% double degenerate! + \let\pgf@ref\pgfpointfourthlastonpath% Use third point for reference. + \else + \let\pgf@ref\pgfpointthirdlastonpath% Use third point for reference. + \fi% + \fi% + \fi% + \pgfpointlineatdistance{\pgf@path@shortening@distance}{\pgfpointlastonpath}{\pgf@ref}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% +} + + +% +% Line shortening for straight lines: +% +\def\pgf@do@shorten@straightend{% + \edef\pgfprocessresultsubpathsuffix{\pgfsubpathstart{\the\pgf@xa}{\the\pgf@ya}}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgfprocessresultpathsuffix% + \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultsubpathprefix\pgfprocessresultsubpathsuffix}% +} + + +% +% Draw an end arrow by calling an appropriate subfunction, if necessary +% + +\def\pgf@add@arrow@at@end{% + \ifx\pgf@arrowpath\pgfutil@empty\else% + \ifx\pgf@end@tip@sequence\pgfutil@empty\else% + \pgf@do@draw@end% + \fi% + \fi% +} + +% +% Draw an end arrow at the end of a straight line +% +\def\pgf@do@draw@straightend{% + {% + \pgftransformreset% + \pgftransformarrow{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgf@arrow@draw@arrow\pgf@end@tip@sequence\pgf@arrow@tip@total@length% + }% +} + + + + + +% +% +% Handling the start of a path +% +% +% The "handling" is similar to the case for the start of the path. We +% may be able to skip the splitting if that was done already for the +% end. Otherwise, things are basically the same. +% + +% Prepare the start of the path: Test whether anything must be done +% (step 0) and, if so, split the path (step 1) if necessary, extract +% the interesting points from the path (step 2), prepare computations +% (step 3) needed for both shortening and tip adding, shorten the path +% (step 4), and add the arrow tip (step 5 in macro +% \pgf@add@arrow@at@start, which is called later). + +\def\pgf@prepare@start@of@path{% + % + % Step 0 start: + % + % Do we need to worry about the start? + % + \ifx\pgf@arrowpath\pgfutil@empty\else% + \pgf@worryfalse% + \ifx\pgf@start@tip@sequence\pgfutil@empty\else\pgf@worrytrue\fi% Yes, worry if we have to draw an arrow + \pgf@precise@shorteningfalse% + \pgf@arrow@compute@shortening\pgf@start@tip@sequence% + \advance\pgf@xa by\pgf@shorten@start@additional% + \advance\pgf@xb by\pgf@shorten@start@additional% + \ifdim\pgf@xa=0pt\relax\else\pgf@worrytrue\fi% Also, worry if shortening is requested + \edef\pgf@path@shortening@distance{\the\pgf@xa}% + \edef\pgf@arrow@tip@total@length{\the\pgf@xb}% + % + % Step 0 done. + % + \ifpgf@worry% + % Ok, need to "worry" about the start, either because we need to + % shorten it or to draw an arrow head. + % + % Step 1: Split + % + \ifx\pgfprocessresultpathsuffix\relax% + % Ok, still need to compute the split: + \pgfprocesssplitpath{\pgf@arrowpath}% + \fi% + % + % Step 2: extract + % + \expandafter\pgf@parse@start\pgfprocessresultpathsuffix\pgf@stop\pgf@stop\pgf@stop% + % + % Step 3: prep + % + \pgf@prep@start% + % + % Step 4: shorten + % + \ifdim\pgf@path@shortening@distance=0pt\else\pgf@do@shorten@start\fi% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@arrowpath% + \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathprefix\pgfprocessresultpathsuffix}% + \pgfsyssoftpath@setcurrentpath\pgf@arrowpath% + \fi% + \fi% +} + +\def\pgf@parse@start#1#2#3#4#5#6{% + \def\pgfpointfirstonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointsecondonpath{\pgfqpoint{#5}{#6}}% + \let\pgfpointthirdonpath\relax% + \let\pgfpointfourthonpath\relax% + \def\pgfsubpathfirsttoken{\noexpand#1}% + \def\pgfsubpathsecondtoken{\noexpand#4}% + \ifx#4\pgf@stop% Only a moveto! -> do nothing! + \let\pgf@next\relax% + \let\pgf@do@shorten@start\relax% + \let\pgf@prep@start\pgf@prep@movetostart% + \let\pgf@do@draw@start\pgf@do@draw@straightstart% + \else\ifx#4\pgfsyssoftpath@curvetosupportatoken% A curve -> this will get complicated... + \ifpgf@precise@shortening% + \let\pgf@next\pgf@parse@start@curve@cont% + \let\pgf@do@shorten@start\pgf@do@shorten@curvedstart% + \let\pgf@do@draw@start\pgf@do@draw@curvedstart% + \let\pgf@prep@start\pgf@prep@curvedstart% + \else% can treat the end like a straight line... + \let\pgf@next\pgf@parse@start@curve@cont@straight% + \let\pgf@do@shorten@start\pgf@do@shorten@straightstart% + \let\pgf@do@draw@start\pgf@do@draw@straightstart% + \let\pgf@prep@start\pgf@prep@straightstart% + \fi% + \else% A straight line -> great! + \let\pgf@next\pgf@parse@start@till@stop% + \let\pgf@do@shorten@start\pgf@do@shorten@straightstart% + \let\pgf@do@draw@start\pgf@do@draw@straightstart% + \let\pgf@prep@start\pgf@prep@straightstart% + \fi\fi% + \pgf@next% Needed for reading rest of path... +} + +\def\pgf@parse@start@till@stop#1\pgf@stop\pgf@stop\pgf@stop{\def\pgfsubpathend{#1}}% + +\def\pgf@parse@start@curve@cont#1#2#3#4#5#6#7\pgf@stop\pgf@stop\pgf@stop{% + \def\pgfpointthirdonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointfourthonpath{\pgfqpoint{#5}{#6}}% + \def\pgfsubpathend{#7}% +} + +\def\pgf@parse@start@curve@cont@straight#1#2#3#4#5#6#7\pgf@stop\pgf@stop\pgf@stop{% + \def\pgfpointthirdonpath{\pgfqpoint{#2}{#3}}% + \def\pgfpointfourthonpath{\pgfqpoint{#5}{#6}}% + \def\pgfsubpathend{#1{#2}{#3}#4{#5}{#6}#7}% +} + +% +% Preps +% +\def\pgf@prep@movetostart{% + \pgf@process{\pgfpointfirstonpath}% + \pgf@xb\pgf@x + \pgf@yb\pgf@y + \pgf@xc\pgf@x + \pgf@yc\pgf@y +} +\def\pgf@prep@straightstart{% + \let\pgf@ref\pgfpointsecondonpath + \ifx\pgfpointfirstonpath\pgfpointsecondonpath% degenerate! + \ifx\pgfpointthirdonpath\relax% cannot help it: really a zero-length path + \else% + \ifx\pgfpointfirstonpath\pgfpointthirdonpath% double degenerate! + \let\pgf@ref\pgfpointfourthonpath% Use third point for reference. + \else + \let\pgf@ref\pgfpointthirdonpath% Use third point for reference. + \fi% + \fi% + \fi% + \pgfpointlineatdistance{\pgf@path@shortening@distance}{\pgfpointfirstonpath}{\pgf@ref}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% +} + +% +% Line shortening for straight lines: +% +\def\pgf@do@shorten@straightstart{% + \edef\pgfprocessresultpathsuffix{\pgfsubpathfirsttoken{\the\pgf@xa}{\the\pgf@ya}\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgfprocessresultpathsuffix% + \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathsuffix\pgfsubpathend}% +} + + +% +% Draw a start arrow by calling an appropriate subfunction, if necessary +% + +\def\pgf@add@arrow@at@start{% + \ifx\pgf@arrowpath\pgfutil@empty\else% + \ifx\pgf@start@tip@sequence\pgfutil@empty\else% + \pgf@do@draw@start% + \fi% + \fi% +} + +% +% Draw an start arrow at the start of a straight line +% +\def\pgf@do@draw@straightstart{% + {% + \pgftransformreset% + \pgftransformarrow{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgf@arrow@draw@arrow\pgf@start@tip@sequence\pgf@arrow@tip@total@length% + }% +} + + + +\let\pgf@shorten@end=\pgfutil@empty +\let\pgf@shorten@start=\pgfutil@empty + + +\endinput% diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepatterns.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepatterns.code.tex new file mode 100644 index 0000000000..c2e438dfc4 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepatterns.code.tex @@ -0,0 +1,301 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorepatterns.code.tex} + +% Creates a new uncolored pattern +% +% [#1] = optional list of variables. +% #2 = pattern name +% #3 = lower left of bounding box +% #4 = upper right of bounding box +% #5 = step vector +% #6 = pattern code +% +% Description: +% +% Declares a new uncolored pattern. An uncolored pattern is a pattern +% that has no inherent color. When the pattern is used, a color for +% the pattern must be supplied. +% +% See the pdf-manual for more details on uncolored patterns. +% +% Specifying a variable list makes the pattern ``mutable''. +% +% The bounding box must be a bounding box of the pattern cell. +% +% The step vector must provide the x- and y-step by which the cells +% are spaced. +% +% The pattern code should be pgf code that can be protocolled. +% +% The transformation matrix will be reset prior to invoking the +% pattern code. +% +% Example: +% +% \pgfdeclarepatternformonly{stars}{\pgfpointorigin}{\pgfpoint{1cm}{1cm}} +% {\pgfpoint{1cm}{1cm}}{ +% \pgftransformshift{\pgfpoint{.5cm}{.5cm}} +% \pgfpathmoveto{\pgfpointpolar{0}{4mm}} +% \pgfpathlineto{\pgfpointpolar{144}{4mm}} +% \pgfpathlineto{\pgfpointpolar{288}{4mm}} +% \pgfpathlineto{\pgfpointpolar{72}{4mm}} +% \pgfpathlineto{\pgfpointpolar{216}{4mm}} +% \pgfpathclose% +% \pgfusepath{stroke} +% } +% +\def\pgfdeclarepatternformonly{% + \def\pgf@pattern@type{formonly}% + \pgfutil@ifnextchar[{\pgf@declarepattern@checkarg}{\pgf@declarepattern@checkarg[]}% +} + + +% Creates a new colored pattern +% +% [#1] = optional list of variables. +% #2 = pattern name +% #3 = lower left of bounding box +% #4 = upper right of bounding box +% #5 = step vector +% #6 = pattern code +% +% Description: +% +% Declares a new colored pattern. Such patterns have a one or more +% fixed inherent colors. See the pdf-manual for more details on +% uncolored patterns. +% +% The parameters have the same effect as for uncolored patterns. +% +% Example: +% +% \pgfdeclarepatterninherentlycolored{red stars}{\pgfpointorigin}{\pgfpoint{1cm}{1cm}} +% {\pgfpoint{1cm}{1cm}}{ +% \pgfsetfillcolor{red} +% \pgfsetstrokecolor{black} +% \pgftransformshift{\pgfpoint{.5cm}{.5cm}} +% \pgfpathmoveto{\pgfpointpolar{0}{4mm}} +% \pgfpathlineto{\pgfpointpolar{144}{4mm}} +% \pgfpathlineto{\pgfpointpolar{288}{4mm}} +% \pgfpathlineto{\pgfpointpolar{72}{4mm}} +% \pgfpathlineto{\pgfpointpolar{216}{4mm}} +% \pgfpathclose% +% \pgfusepath{stroke,fill} +% } +% +\def\pgfdeclarepatterninherentlycolored{% + \def\pgf@pattern@type{inherentlycolored}% + \pgfutil@ifnextchar[{\pgf@declarepattern@checkarg}{\pgf@declarepattern@checkarg[]}% +} + + + + + +\def\pgf@declarepattern@checkarg[#1]{% + \def\pgf@pattern@tempvars{#1}% + \ifx\pgf@pattern@tempvars\pgfutil@empty% + \expandafter\let\expandafter\pgf@next\csname pgf@declarepattern\pgf@pattern@type\endcsname% + \else% + \expandafter\let\expandafter\pgf@next\csname pgf@declarepattern\pgf@pattern@type @mutable\endcsname% + \fi% + \pgf@next} + +\long\def\pgf@declarepatternformonly#1#2#3#4#5{\pgf@declarepattern{#1}{#2}{#3}{#4}{#5}{0}} + +\long\def\pgf@declarepatterninherentlycolored#1#2#3#4#5{\pgf@declarepattern{#1}{#2}{#3}{#4}{#5}{1}} + +\long\def\pgf@declarepatternformonly@mutable#1#2#3#4#5{% + \def\pgf@marshal{\pgf@declarepatternmutable{#1}}% + \expandafter\pgf@marshal\expandafter{\pgf@pattern@tempvars}{#2}{#3}{#4}{#5}{2}% +} + +\long\def\pgf@declarepatterninherentlycolored@mutable#1#2#3#4#5#6{% + \def\pgf@marshal{\pgf@declarepatternmutable{#1}}% + \expandafter\pgf@marshal\expandafter{\pgf@pattern@tempvars}{#2}{#3}{#4}{#5}{3}% +} + +\def\pgfsys@patternmatrix{{1.0}{0.0}{0.0}{1.0}{0.0pt}{0.0pt}} +\def\pgf@declarepattern#1#2#3#4#5#6{% + \pgfutil@ifundefined{pgf@pattern@name@#1}{% + \pgfsysprotocol@getcurrentprotocol\pgf@pattern@temp% + {% + \pgfinterruptpath% + \pgfpicturetrue% + \pgf@relevantforpicturesizefalse% + \pgftransformreset% + \pgfsysprotocol@setcurrentprotocol\pgfutil@empty% + \pgfsysprotocol@bufferedtrue% + \pgfsys@beginscope% + \pgfsetarrows{-}% + #5% + \pgfsys@endscope% + \pgfsysprotocol@getcurrentprotocol\pgf@pattern@code% + \global\let\pgf@pattern@code=\pgf@pattern@code% + \endpgfinterruptpath% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#3}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#4}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % Now, build a name for the pattern + \pgfutil@tempcnta=\pgf@pattern@number% + \advance\pgfutil@tempcnta by1\relax% + \xdef\pgf@pattern@number{\the\pgfutil@tempcnta}% + \expandafter\xdef\csname pgf@pattern@name@#1\endcsname{\the\pgfutil@tempcnta}% + \expandafter\gdef\csname pgf@pattern@type@#1\endcsname{#6}% + \xdef\pgf@marshal{\noexpand\pgfsys@declarepattern + {\csname pgf@pattern@name@#1\endcsname}% name + {\the\pgf@xa}{\the\pgf@ya}{\the\pgf@xb}{\the\pgf@yb}% bbox + {\the\pgf@xc}{\the\pgf@yc}% x/y step + \pgfsys@patternmatrix% transformation matrix + {\pgf@pattern@code}{#6}}% + }% + \pgfsysprotocol@setcurrentprotocol\pgf@pattern@temp% + \expandafter\global\expandafter\let\csname pgf@pattern@instantiate@#1\endcsname=\pgf@marshal% + } + {% + \pgferror{Pattern `#1' already defined}% + }% +} + +\def\pgf@pattern@number{0}% + +\def\pgf@declarepatternmutable#1#2#3#4#5#6#7{% + \pgfutil@ifundefined{pgf@pattern@name@#1}{% + \expandafter\gdef\csname pgf@pattern@name@#1\endcsname{#1}% + \expandafter\gdef\csname pgf@pattern@variables@#1\endcsname{#2}% + \expandafter\gdef\csname pgf@pattern@lowerleft@#1\endcsname{#3}% + \expandafter\gdef\csname pgf@pattern@upperright@#1\endcsname{#4}% + \expandafter\gdef\csname pgf@pattern@tilesize@#1\endcsname{#5}% + \expandafter\long\expandafter\gdef\csname pgf@pattern@code@#1\endcsname{#6}% + \expandafter\gdef\csname pgf@pattern@type@#1\endcsname{#7}% + }{\pgferror{The pattern `#1' is already defined}}% +} + +\def\pgf@ifpatternisinherentlycolored#1#2#3{% + \expandafter\ifodd\csname pgf@pattern@type@#1\endcsname\relax#2\else#3\fi% +} + +\def\pgf@ifpatternismutable#1#2#3{% + \expandafter\ifnum\csname pgf@pattern@type@#1\endcsname>1\relax#2\else#3\fi% +} + +\def\pgfpatternreleasename#1{\expandafter\let\csname pgf@pattern@name@#1\endcsname\relax} + + + + + + +% Set an pattern as fill color +% +% #1 = Name of the pattern +% #2 = Color to be used for the pattern. If the pattern is already +% colored, this parameter is ignored. +% +% Description: +% +% Sets the pattern for subsequent filling operations. +% +% Example: +% +% \pgfsetfillpattern{stars}{red} +% +\def\pgfsetfillpattern#1#2{% + \pgfutil@ifundefined{pgf@pattern@name@#1}% + {% + \pgferror{Undefined pattern `#1'}% + }% + {% + \pgf@ifpatternismutable{#1}% + {% + % So, a mutable pattern. Check to see if the pattern + % has been used with the current variable values... + \let\pgf@pattern@tempvars\pgfutil@empty% + \expandafter\expandafter\expandafter\pgf@pattern@check@vars% + \csname pgf@pattern@variables@#1\endcsname,\pgf@stop,% + \edef\pgf@pattern@nametemp{pgf@pattern@#1@\pgf@pattern@tempvars}% + \expandafter\pgfutil@ifundefined\expandafter{\pgf@pattern@nametemp}% + {% + % ...Nope. So declare a new instance of the mutable pattern. + \pgf@ifpatternisinherentlycolored{#1}% + {\let\pgf@set@fillpattern@declare\pgfdeclarepatterninherentlycolored}% + {\let\pgf@set@fillpattern@declare\pgfdeclarepatternformonly}% + \pgf@set@fillpattern@declare% + {\pgf@pattern@nametemp}% + {\csname pgf@pattern@lowerleft@#1\endcsname}% + {\csname pgf@pattern@upperright@#1\endcsname}% + {\csname pgf@pattern@tilesize@#1\endcsname}% + {\csname pgf@pattern@code@#1\endcsname}% + }% + {% + % ...Yep. So do nothing. + }% + \expandafter\pgf@set@fillpattern\expandafter{\pgf@pattern@nametemp}{#2}% + \expandafter\gdef\csname\pgf@pattern@nametemp\endcsname{#1}% + }% + {% + % A non-mutable pattern. + \pgf@set@fillpattern{#1}{#2}% + }% + }% +} + + +\def\pgf@set@fillpattern#1#2{% + \pgfutil@ifundefined{pgf@pattern@name@#1}{% + \pgferror{Undefined pattern `#1'}} + {% + \csname pgf@pattern@instantiate@#1\endcsname% + \expandafter\global\expandafter\let\csname pgf@pattern@instantiate@#1\endcsname=\relax% + \pgf@ifpatternisinherentlycolored{#1}{% + \pgfsys@setpatterncolored{\csname pgf@pattern@name@#1\endcsname}% + }{% + \pgfutil@colorlet{pgf@tempcolor}{#2}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgf@tempcolor}}% + \pgfutil@extractcolorspec{pgf@tempcolor}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{rgb}{\pgf@rgbcolor}% + \expandafter\pgf@set@fill@patternuncolored\pgf@rgbcolor\relax{#1}% + }% + }% +} + +\def\pgf@set@fill@patternuncolored#1,#2,#3\relax#4{% + \pgfsys@setpatternuncolored{\csname pgf@pattern@name@#4\endcsname}{#1}{#2}{#3}% +} + +\def\pgf@pattern@check@vars#1,{% + \ifx#1\pgf@stop% + \let\pgf@next\relax% + \else% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\let\expandafter\pgf@pattern@char#1#1\pgfmath@% + \ifx\pgf@pattern@char/% + \edef\pgf@pattern@tempvar{(\pgfkeysvalueof{#1})}% + \else% + \expandafter\ifcat\pgf@pattern@char\relax% + \edef\pgf@pattern@tempvar{(\the#1)}% + \else% + \edef\pgf@pattern@tempvar{(#1)}% + \fi% + \fi% + \edef\pgf@pattern@tempvars{\pgf@pattern@tempvars\pgf@pattern@tempvar}% + \let\pgf@next\pgf@pattern@check@vars% + \fi% + \pgf@next% +} + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepoints.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepoints.code.tex new file mode 100644 index 0000000000..6c28f20b73 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepoints.code.tex @@ -0,0 +1,1212 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorepoints.code.tex} + +\newdimen\pgf@picminx +\newdimen\pgf@picmaxx +\newdimen\pgf@picminy +\newdimen\pgf@picmaxy + +\newdimen\pgf@pathminx +\newdimen\pgf@pathmaxx +\newdimen\pgf@pathminy +\newdimen\pgf@pathmaxy + +\newif\ifpgf@relevantforpicturesize + +\def\pgf@process#1{{#1\global\pgf@x=\pgf@x\global\pgf@y=\pgf@y}} + +% Save a point. +% +% #1 = macro for storing point. +% #2 = code for point (should define x and y) +% +% Example: +% +% \pgfextract@process\mypoint{\pgf@x=10pt \pgf@y10pt} +% \pgfextract@process\myarcpoint{\pgfpointpolar{30}{5cm and 2cm}} + +\def\pgfextract@process#1#2{% + \pgf@process{#2}% + \edef#1{\noexpand\global\pgf@x=\the\pgf@x\noexpand\relax\noexpand\global\pgf@y=\the\pgf@y\noexpand\relax}% +} +% This needed until old shapes code changed. +\let\pgfsavepgf@process\pgfextract@process% + + +% Return a point +% +% #1 = x-coordinate of the point +% #2 = y-coordinate of the point +% +% x = #1 +% y = #2 +% +% Example: +% +% \pgfpathmoveto{\pgfpoint{2pt+3cm}{3cm}} + +\def\pgfpoint#1#2{% + \pgfmathsetlength\pgf@x{#1}% + \pgfmathsetlength\pgf@y{#2}\ignorespaces} + + +% Quickly a point +% +% #1 = x-coordinate of the point (no calculations done) +% #2 = y-coordinate of the point (no calculations done) +% +% x = #1 +% y = #2 +% +% Example: +% +% \pgfpathmoveto{\pgfqpoint{2pt}{3cm}} + +\def\pgfqpoint#1#2{\global\pgf@x=#1\relax\global\pgf@y=#2\relax} + + + +% Return the origin. +% +% x = 0 +% y = 0 +% +% Example: +% +% \pgfpathmoveto{\pgfpointorigin} + +\def\pgfpointorigin{\global\pgf@x=0pt \global\pgf@y=\pgf@x\ignorespaces} + + + +% Return a transformed point +% +% #1 = a point +% +% Description: +% +% This command applies pgf's current transformation matrix to the +% given point. Normally, this is done automatically by commands like +% lineto or moveto, but sometimes you may wish to access a transformed +% point yourself. In the below example, this command is used for a low level +% coordinate system shift. +% +% Example: +% +% \begin{pgflowleveltransformshiftscope}{\pgfpointtransformed{\pgfpointorigin}} +% \pgfbox[center,center]{Hi!} +% \end{pgflowleveltransformshiftscope} + +\def\pgfpointtransformed#1{% + \pgf@process{% + #1% + \pgf@pos@transform@glob% + }% +} + + +% Return the difference vector of two points. +% +% #1 = start of vector +% #2 = end of vector +% +% x = x-component of difference +% y = y-component of difference +% +% Example: +% +% \pgfpathmoveto{\pgfpointdiff{\pgfpointxy{1}{1}}{\pgfpointxy{2}{3}}} + +\def\pgfpointdiff#1#2{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#2}% + \global\advance\pgf@x by-\pgf@xa\relax% + \global\advance\pgf@y by-\pgf@ya\relax\ignorespaces} + +% Add two vectors. +% +% #1 = first vector +% #2 = second vector +% +% x = x-component of addition +% y = y-component of addition +% +% Example: +% +% \pgfpathmoveto{\pgfpointadd{\pgfpointxy{0}{1}}{\pgfpointxy{2}{3}}} + +\def\pgfpointadd#1#2{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#2}% + \global\advance\pgf@x by\pgf@xa% + \global\advance\pgf@y by\pgf@ya} + + + +% Multiply a vector by a factor. +% +% #1 = factor +% #2 = vector +% +% Example: +% +% \pgfpointscale{2}{\pgfpointxy{0}{1}} + +\def\pgfpointscale#1#2{% + \pgf@process{#2}% + \pgfmathparse{#1}% + \global\pgf@x=\pgfmathresult\pgf@x% + \global\pgf@y=\pgfmathresult\pgf@y% +} +% A "quick" variant of \pgfpointscale which doesn't invoke the math parser for '#1'. +% #1 must be a number without units, no registers are accepted. +\def\pgfqpointscale#1#2{% + \pgf@process{#2}% + \global\pgf@x=#1\pgf@x% + \global\pgf@y=#1\pgf@y% +} + + +% The intersection of two lines +% +% #1 = point on first line +% #2 = another point on first line +% #3 = point on second line +% #4 = another point on second line +% +% Returns the intersection of the two lines. If there is no +% intersection or if the points #1 and #2 or the points #3 and #4 are +% identical, the behaviour is not specified. +% +% Example: +% +% \pgfpointintersectionoflines{\pgfpointxy{0}{1}}{\pgfpointxy{1}{0}}{\pgfpointxy{2}{2}}{\pgfpointxy{3}{4}} + +\def\pgfpointintersectionoflines#1#2#3#4{% + {% + % + % Compute orthogonal vector to #1--#2 + % + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#1}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \pgf@ya=-\pgf@ya% + % Normalise a bit + \c@pgf@counta=\pgf@xa% + \ifnum\c@pgf@counta<0\relax% + \c@pgf@counta=-\c@pgf@counta\relax% + \fi% + \c@pgf@countb=\pgf@ya% + \ifnum\c@pgf@countb<0\relax% + \c@pgf@countb=-\c@pgf@countb\relax% + \fi% + \advance\c@pgf@counta by\c@pgf@countb\relax% + \divide\c@pgf@counta by 65536\relax% + \ifnum\c@pgf@counta>0\relax% + \divide\pgf@xa by\c@pgf@counta\relax% + \divide\pgf@ya by\c@pgf@counta\relax% + \fi% + % + % Compute projection + % + \pgf@xc=\pgf@sys@tonumber{\pgf@ya}\pgf@x% + \advance\pgf@xc by\pgf@sys@tonumber{\pgf@xa}\pgf@y% + % + % The orthogonal vector is (\pgf@ya,\pgf@xa) + % + % + % Compute orthogonal vector to #3--#4 + % + \pgf@process{#4}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#3}% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + \pgf@yb=-\pgf@yb% + % Normalise a bit + \c@pgf@counta=\pgf@xb% + \ifnum\c@pgf@counta<0\relax% + \c@pgf@counta=-\c@pgf@counta\relax% + \fi% + \c@pgf@countb=\pgf@yb% + \ifnum\c@pgf@countb<0\relax% + \c@pgf@countb=-\c@pgf@countb\relax% + \fi% + \advance\c@pgf@counta by\c@pgf@countb\relax% + \divide\c@pgf@counta by 65536\relax% + \ifnum\c@pgf@counta>0\relax% + \divide\pgf@xb by\c@pgf@counta\relax% + \divide\pgf@yb by\c@pgf@counta\relax% + \fi% + % + % Compute projection + % + \pgf@yc=\pgf@sys@tonumber{\pgf@yb}\pgf@x% + \advance\pgf@yc by\pgf@sys@tonumber{\pgf@xb}\pgf@y% + % + % The orthogonal vector is (\pgf@yb,\pgf@xb) + % + % Setup transformation matrix (this is just to use the matrix + % inversion) + % + \pgfsettransform{{\pgf@sys@tonumber\pgf@ya}{\pgf@sys@tonumber\pgf@yb}{\pgf@sys@tonumber\pgf@xa}{\pgf@sys@tonumber\pgf@xb}{0pt}{0pt}}% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{\pgfpoint{\pgf@xc}{\pgf@yc}}}% + }% +} + + +% The intersection of two circles +% +% #1 = center of first circle +% #2 = center of second circle +% #3 = radius of first circle +% #4 = radius of second circle +% #5 = solution number +% +% Returns the intersection of the two circles. If #5 is to "1", the +% first intersection is returned, otherwise the second. If the circles +% do not intersect, an error may occur. +% +% Example: +% +% \pgfpointintersectionofcircles{\pgfpointxy{0}{1}}{\pgfpointxy{1}{0}}{1cm}{1cm}{1} + +\def\pgfpointintersectionofcircles#1#2#3#4#5{% + {% + % Store first point in (xa,ya) and radius in xc. + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfmathsetlength{\pgf@xc}{#3}% + % Store second point in (xb,yb) and radius in yc. + \pgf@process{#2}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgfmathsetlength{\pgf@yc}{#4}% + % + % Ok, now make numbers smaller, in case they are too large + % + \c@pgf@counta=1\relax% + \loop% + \pgf@scale@downfalse% + \ifdim\pgf@xc>50pt\relax% + \pgf@scale@downtrue% + \fi% + \ifdim\pgf@yc>50pt\relax% + \pgf@scale@downtrue% + \fi% + \ifpgf@scale@down% + \multiply\c@pgf@counta by2\relax% + \divide\pgf@xa by2\relax% + \divide\pgf@ya by2\relax% + \divide\pgf@xb by2\relax% + \divide\pgf@yb by2\relax% + \divide\pgf@xc by2\relax% + \divide\pgf@yc by2\relax% + \repeat% + % The following code is taken from the Dr. Math internet forum: + % + % Let the centers be: (a,b), (c,d) + % Let the radii be: r, s + % + % e = c - a [difference in x coordinates] + % f = d - b [difference in y coordinates] + % p = sqrt(e^2 + f^2) [distance between centers] + % k = (p^2 + r^2 - s^2)/(2p) [distance from center 1 to line + % joining points of intersection] + % x = a + ek/p + (f/p)sqrt(r^2 - k^2) + % y = b + fk/p - (e/p)sqrt(r^2 - k^2) + % OR + % x = a + ek/p - (f/p)sqrt(r^2 - k^2) + % y = b + fk/p + (e/p)sqrt(r^2 - k^2) + % + % Since we are running low on registers, use + % \dimen0 for e + % \dimen1 for f + % \dimen2 for p + % \dimen3 for p^2 + % \dimen4 for k + % \dimen5 for 1/p + % \dimen6 for sqrt(r^2 - k^2) + % \dimen7 for k^2 + % \dimen8 for k/p + % \dimen9 for sqrt(r^2 - k^2)/p + % Also note that: + % \pgf@xa for a + % \pgf@ya for b + % \pgf@xb for c + % \pgf@yb for d + % \pgf@xc for r + % \pgf@yc for s + % + % Now: + % e = c - a + \dimen0=\pgf@xb% + \advance\dimen0 by-\pgf@xa% + % f = d - b + \dimen1=\pgf@yb% + \advance\dimen1 by-\pgf@ya% + % p^2 = e^2 + f^2 + \pgf@x=\dimen0\relax% + \pgf@x=\pgf@sys@tonumber{\pgf@x}\pgf@x% + \dimen3=\pgf@x% + \pgf@x=\dimen1\relax% + \advance\dimen3 by\pgf@sys@tonumber{\pgf@x}\pgf@x% + % p = sqrt(p^2) + \pgfmathparse{sqrt(\the\dimen3)}% + \dimen2=\pgfmathresult pt% + % 1/p = 1/p + \pgfmathreciprocal@{\pgfmathresult}% + \dimen5=\pgfmathresult pt% + % k = (p^2 + r^2 - s^2)/(2p) + \dimen4=\dimen3\relax% + \pgf@x=\pgf@xc% + \advance\dimen4 by\pgf@sys@tonumber{\pgf@x}\pgf@x\relax% + \pgf@x=\pgf@yc% + \advance\dimen4 by-\pgf@sys@tonumber{\pgf@x}\pgf@x\relax% + \dimen4=.5\dimen4% + \dimen4=\pgf@sys@tonumber{\dimen5}\dimen4% + % dimen7 is k^2 + \dimen7=\pgf@sys@tonumber{\dimen4}\dimen4\relax% + % dimen6 is sqrt(r^2 - k^2) + \pgfmathparse{sqrt(\pgf@sys@tonumber{\pgf@xc}\pgf@xc-\the\dimen7)}% + \dimen6=\pgfmathresult pt% + % dimen8 is k/p + \dimen8=\pgf@sys@tonumber{\dimen4}\dimen5\relax% + % dimen9 is sqrt(r^2 - k^2)/p + \dimen9=\pgf@sys@tonumber{\dimen6}\dimen5\relax% + \ifnum#5=1\relax% + % x = a + ek/p + (f/p)sqrt(r^2 - k^2) + \pgf@x=\pgf@xa% + \advance\pgf@x by\pgf@sys@tonumber{\dimen0}\dimen8\relax% + \advance\pgf@x by\pgf@sys@tonumber{\dimen1}\dimen9\relax% + % y = b + fk/p - (e/p)sqrt(r^2 - k^2) + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@sys@tonumber{\dimen1}\dimen8\relax% + %temp + \pgf@xb=\pgf@sys@tonumber{\dimen0}\dimen9% + \pgf@xb=-\pgf@xb% + \advance\pgf@y by\pgf@xb\relax% + \else% + % x = a + ek/p - (f/p)sqrt(r^2 - k^2) + \pgf@x=\pgf@xa% + \advance\pgf@x by\pgf@sys@tonumber{\dimen0}\dimen8\relax% + %temp + \pgf@xb=\pgf@sys@tonumber{\dimen1}\dimen9% + \pgf@xb=-\pgf@xb% + \advance\pgf@x by\pgf@xb\relax% + % y = b + fk/p + (e/p)sqrt(r^2 - k^2) + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@sys@tonumber{\dimen1}\dimen8\relax% + \advance\pgf@y by\pgf@sys@tonumber{\dimen0}\dimen9\relax% + \fi% + \pgf@x=\c@pgf@counta\pgf@x% + \pgf@y=\c@pgf@counta\pgf@y% + \pgf@process{}% get results outside + }% +} +\newif\ifpgf@scale@down + + +% Returns point on a line from #2 to #3 at time #1. +% +% #1 = a time, where 0 is the start and 1 is the end +% #2 = start point +% #3 = end point +% +% x = x-component of #1*start + (1-#1)*end +% y = y-component of #1*start + (1-#1)*end +% xa/ya = #1*start + (1-#1)*end +% xb/yb = start point +% xc/yc = end point +% +% Example: +% +% % Middle of (1,1) and (2,3) +% \pgfpathmoveto{\pgfpointlineattime{0.5}{\pgfpointxy{0}{1}}{\pgfpointxy{2}{3}}} + +\def\pgfpointlineattime#1#2#3{% + \pgf@process{#3}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgf@xc\pgf@x% + \pgf@yc\pgf@y% + \pgf@process{#2}% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgfmathsetmacro\pgf@temp{#1}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \global\advance\pgf@x by\pgf@temp\pgf@xa% + \global\advance\pgf@y by\pgf@temp\pgf@ya% +} + + +% Move point #2 #1 many units in the direction of #3. +% +% #1 = a distance +% #2 = start point +% #3 = end point +% +% Description: +% +% Computes +% +% x/y = start + #1*(normalise(end-start)) +% +% and additionally +% +% xa/ya = #1*(normalise(end-start)) +% xb/yb = start +% xc/yc = end +% +% Example: +% +% \pgfpathmoveto{\pgfpointlineatdistance{2pt}{\pgfpointxy{0}{1}}{\pgfpointxy{2}{3}}} +% \pgfpathlineto{\pgfpointlineatdistance{3pt}{\pgfpointxy{2}{3}}{\pgfpointxy{0}{1}}} + +\def\pgfpointlineatdistance#1#2#3{% + \pgfmathsetlength\pgf@xa{#1}% + \pgf@process{#2}% + \pgf@xb\pgf@x% xb/yb = start point + \pgf@yb\pgf@y% + \pgf@process{#3}% + \pgf@xc\pgf@x% + \pgf@yc\pgf@y% + \global\advance\pgf@x by-\pgf@xb\relax% + \global\advance\pgf@y by-\pgf@yb\relax% + \pgf@process{\pgfpointnormalised{}}% x/y = normalised vector + \pgf@ya=\pgf@xa\relax% + \pgf@xa=\pgf@sys@tonumber{\pgf@x}\pgf@xa% + \pgf@ya=\pgf@sys@tonumber{\pgf@y}\pgf@ya% + \global\pgf@x=\pgf@xb\relax% + \global\pgf@y=\pgf@yb\relax% + \global\advance\pgf@x by\pgf@xa\relax% + \global\advance\pgf@y by\pgf@ya\relax% +} + + +% Returns point on a curve from #2 to #5 with controls #3 and #4 at time #1. +% +% #1 = a time +% #2 = start point +% #3 = first control point +% #4 = second control point +% #5 = end point +% +% x = x-component of place on the curve at time t +% y = y-component of place on the curve at time t +% +% Additionally, (\pgf@xa,\pgf@ya) and (\pgf@xb,\pgf@yb) will be on a +% tangent to the point on the curve (this can be useful for computing +% a label rotation). (\pgf@xc,\pgf@yc) will be equal to the end +% point. \pgf@time@s will equal the value of #1 and \pgf@time@t will +% equal 1-#1. +% +% Example: +% +% % Middle of (1,1) and (2,3) +% \pgfpathmoveto{\pgfpointcurveattime{0.5}{\pgfpointxy{0}{1}}{\pgfpointxy{1}{1}}{\pgfpointxy{1}{1}}{\pgfpointxy{2}{3}}} + +\def\pgfpointcurveattime#1#2#3#4#5{% + \pgfmathparse{#1}% + \let\pgf@time@s=\pgfmathresult% + \global\pgf@x=\pgfmathresult pt% + \global\pgf@x=-\pgf@x% + \advance\pgf@x by 1pt% + \edef\pgf@time@t{\pgf@sys@tonumber{\pgf@x}}% + \pgf@process{#5}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{#4}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#3}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#2}% + % First iteration: + \global\pgf@x=\pgf@time@t\pgf@x\global\advance\pgf@x by\pgf@time@s\pgf@xa% + \global\pgf@y=\pgf@time@t\pgf@y\global\advance\pgf@y by\pgf@time@s\pgf@ya% + \pgf@xa=\pgf@time@t\pgf@xa\advance\pgf@xa by\pgf@time@s\pgf@xb% + \pgf@ya=\pgf@time@t\pgf@ya\advance\pgf@ya by\pgf@time@s\pgf@yb% + \pgf@xb=\pgf@time@t\pgf@xb\advance\pgf@xb by\pgf@time@s\pgf@xc% + \pgf@yb=\pgf@time@t\pgf@yb\advance\pgf@yb by\pgf@time@s\pgf@yc% + % Second iteration: + \global\pgf@x=\pgf@time@t\pgf@x\global\advance\pgf@x by\pgf@time@s\pgf@xa% + \global\pgf@y=\pgf@time@t\pgf@y\global\advance\pgf@y by\pgf@time@s\pgf@ya% + \pgf@xa=\pgf@time@t\pgf@xa\advance\pgf@xa by\pgf@time@s\pgf@xb% + \pgf@ya=\pgf@time@t\pgf@ya\advance\pgf@ya by\pgf@time@s\pgf@yb% + % Save x/y + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + % Third iteration: + \global\pgf@x=\pgf@time@t\pgf@x\global\advance\pgf@x by\pgf@time@s\pgf@xa% + \global\pgf@y=\pgf@time@t\pgf@y\global\advance\pgf@y by\pgf@time@s\pgf@ya% +} + + + +% Returns point on an arc at a certain "time" +% +% #1 = a time +% #2 = center of a ellipse +% #3 = 0-degree axis of the ellipse +% #4 = 90-degree axis of the ellipse +% #5 = start angle of an arc on the ellipse +% #6 = end angle of an arc on the ellipse +% +% Result: +% +% \pgf@x = x-component of place on the arc at time t +% \pgf@y = y-component of place on the arc at time t +% +% Additionally, (\pgf@xa,\pgf@ya) will be a tangent to the +% point on the arc (this can be useful for computing a label rotation). +% +% Example: +% +% \pgfpointarcaxesattime{0.25}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}{\pgfpoint{0cm}{1cm}}{1cm}{30}{40} + +\def\pgfpointarcaxesattime#1#2#3#4#5#6{% + \pgfmathsetmacro\pgf@angle@start{#5}% + \pgfmathsetmacro\pgf@angle@end{#6}% + \pgfmathparse{#1}% + \global\pgf@x=\pgfmathresult pt% + \global\pgf@x=-\pgf@x% + \advance\pgf@x by 1pt% + \pgfmathsetmacro\pgf@angle@mid{\pgf@angle@end*\pgfmathresult+\pgf@angle@start*\pgf@sys@tonumber{\pgf@x}}% + \pgfmathcos@{\pgf@angle@mid}% + \let\pgf@angle@cos\pgfmathresult% + \pgfmathsin@{\pgf@angle@mid}% + \let\pgf@angle@sin\pgfmathresult% + \pgf@process{#3}% + \edef\pgf@angle@zero@axis{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgf@process{#4}% + \edef\pgf@angle@ninety@axis{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + % Compute tangent + \pgf@process{\pgfpointadd{\pgfpointscale{\pgf@angle@sin}{\pgf@angle@zero@axis}}% + {\pgfpointscale{-\pgf@angle@cos}{\pgf@angle@ninety@axis}}}% + \ifdim\pgf@angle@start pt>\pgf@angle@end pt% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \else% + \pgf@xa=-\pgf@x% + \pgf@ya=-\pgf@y% + \fi% + % Compute position + \pgf@process{\pgfpointadd{#2}{% + \pgfpointadd{\pgfpointscale{\pgf@angle@cos}{\pgf@angle@zero@axis}}% + {\pgfpointscale{\pgf@angle@sin}{\pgf@angle@ninety@axis}}}}% +} + + + +% Internal registers +\newdimen\pgf@xx +\newdimen\pgf@xy +\newdimen\pgf@yx +\newdimen\pgf@yy +\newdimen\pgf@zx +\newdimen\pgf@zy + + + +% A polar coordinate +% +% #1 = a degree +% #2 = a radius -- either a dimension or two dimensions separated by +% " and ". +% +% x = (first dimension in #2) * cos(#1) +% y = (second dimension in #2) * sin(#2) +% +% Example: +% +% \pgfpathmoveto{\pgfpointpolar{30}{1cm}} +% \pgfpathlineto{\pgfpointpolar{30}{1cm and 2cm}} + +\def\pgfpointpolar#1#2{% + \pgfutil@in@{and }{#2}% + \ifpgfutil@in@% + \pgf@polar@#2\@@% + \else% + \pgf@polar@#2 and #2\@@% + \fi% + \pgfmathparse{#1}% + \let\pgfpoint@angle=\pgfmathresult% + \pgfmathcos@{\pgfpoint@angle}% + \global\pgf@x=\pgfmathresult\pgf@x% + \pgfmathsin@{\pgfpoint@angle}% + \global\pgf@y=\pgfmathresult\pgf@y% +} + +\def\pgf@polar@#1and #2\@@{% + \pgfmathsetlength{\pgf@y}{#2}% + \pgfmathsetlength{\pgf@x}{#1}% +} + +% Quick version of the polar coordinate method + +\def\pgfqpointpolar#1#2{% + \global\pgf@x=#2% + \global\pgf@y=\pgf@x% + \pgfmathcos@{#1}% + \global\pgf@x=\pgfmathresult\pgf@x% + \pgfmathsin@{#1}% + \global\pgf@y=\pgfmathresult\pgf@y\relax% +} + + + + +% A polar coordinate in the xy plane. +% +% #1 = a degree +% #2 = a radius given as a number or two radii +% +% result = (first dim in #2) * x-vector * cos(#1) + +% (second dim in #2) * y-vector * sin(#1) +% +% Example: +% +% \pgfpathmoveto{\pgfpointpolarxy{30}{2}} + +\def\pgfpointpolarxy#1#2{% + \pgfutil@in@{and }{#2}% + \ifpgfutil@in@% + \pgf@polarxy@#2\@@% + \else% + \pgf@polarxy@#2and #2\@@% + \fi% + \pgfmathparse{#1}% + \let\pgfpoint@angle=\pgfmathresult% + \pgfmathcos@{\pgfpoint@angle}% + \pgf@xa=\pgfmathresult\pgf@xa% + \pgfmathsin@{\pgfpoint@angle}% + \pgf@ya=\pgfmathresult\pgf@ya% + \global\pgf@x=\pgf@sys@tonumber{\pgf@xa}\pgf@xx% + \global\advance\pgf@x by \pgf@sys@tonumber{\pgf@ya}\pgf@yx% + \global\pgf@y=\pgf@sys@tonumber{\pgf@xa}\pgf@xy% + \global\advance\pgf@y by \pgf@sys@tonumber{\pgf@ya}\pgf@yy} + +\def\pgf@polarxy@#1and #2\@@{% + \pgfmathsetlength{\pgf@xa}{#1}% + \pgfmathsetlength{\pgf@ya}{#2}% +} + + + +% A cylindrical coordinate. +% +% #1 = a degree +% #2 = a radius given as a number +% #3 = a height given as a number +% +% result = #2*(x-vector * cos(#1) + y-vector * sin(#1)) + #3*z-vector +% +% Example: +% +% \pgfpathmoveto{\pgfpointcylindrical{30}{2}{1}} + +\def\pgfpointcylindrical#1#2#3{% + \pgfpointpolarxy{#1}{#2}% + \pgfmathparse{#3}% + \global\advance\pgf@x by \pgfmathresult\pgf@zx% + \global\advance\pgf@y by \pgfmathresult\pgf@zy} + + +% A spherical coordinate. +% +% #1 = a longitude +% #2 = a latitude +% #3 = a radius +% +% result = #3*(cos(#2)*(x-vector * cos(#1) + y-vector * sin(#1)) + sin(#2)*z-vector) +% +% Example: +% +% \pgfpathmoveto{\pgfpointspherical{30}{30}{2}} + +\def\pgfpointspherical#1#2#3{% + \pgfmathparse{#1}% + \let\pgfpoint@angle=\pgfmathresult% + \pgfmathsin@{\pgfpoint@angle}% + \pgf@xb=\pgfmathresult\pgf@xx% + \pgf@yb=\pgfmathresult\pgf@xy% + \pgfmathcos@{\pgfpoint@angle}% + \advance\pgf@xb by \pgfmathresult\pgf@yx% + \advance\pgf@yb by \pgfmathresult\pgf@yy% + % + \pgfmathparse{#2}% + \let\pgfpoint@angle=\pgfmathresult% + \pgfmathcos@{\pgfpoint@angle}% + \pgf@xc=\pgfmathresult\pgf@xb% + \pgf@yc=\pgfmathresult\pgf@yb% + \pgfmathsin@{\pgfpoint@angle}% + \advance\pgf@xc by \pgfmathresult\pgf@zx% + \advance\pgf@yc by \pgfmathresult\pgf@zy% + \pgfmathparse{#3}% + \global\pgf@x=\pgfmathresult\pgf@xc% + \global\pgf@y=\pgfmathresult\pgf@yc\relax% +} + + +% Store the vector #1 * x-vec + #2 * y-vec +% +% #1 = a factor for the x-vector +% #2 = a factor for the y-vector +% +% x = x-component of result vector +% y = y-component of result vector +% +% Description: +% +% This command can be used to create a new coordinate system +% without using the rotate/translate/scale commands. This +% may be useful, if you do not want arrows and line width to +% be scaled/transformed together with the coordinate system. +% +% Example: +% +% % Create a slanted rectangle +% +% \pgfsetxvec{\pgfpoint{1cm}{1cm}} +% \pgfsetyvec{\pgfpoint{0cm}{1cm}} +% +% \pgfpathmoveto{\pgfpointxy{0}{0}} +% \pgfpathlineto{\pgfpointxy{1}{0}} +% \pgfpathlineto{\pgfpointxy{1}{1}} +% \pgfpathlineto{\pgfpointxy{0}{1}} +% \pgfclosestroke + +\def\pgfpointxy#1#2{% + \pgfmathparse{#1}% + \let\pgftemp@x=\pgfmathresult% + \pgfmathparse{#2}% + \let\pgftemp@y=\pgfmathresult% + \global\pgf@x=\pgftemp@x\pgf@xx% + \global\advance\pgf@x by \pgftemp@y\pgf@yx% + \global\pgf@y=\pgftemp@x\pgf@xy% + \global\advance\pgf@y by \pgftemp@y\pgf@yy} + + +% "Quick" variant for \pgfpointxy. +% +% Only numbers without unit are allowed here. +\def\pgfqpointxy#1#2{% + \global\pgf@x=#1\pgf@xx% + \global\advance\pgf@x by #2\pgf@yx% + \global\pgf@y=#1\pgf@xy% + \global\advance\pgf@y by #2\pgf@yy} + +% Store the vector #1 * x-vec + #2 * y-vec + #3 * z-vec +% +% #1 = a factor for the x-vector +% #2 = a factor for the y-vector +% #3 = a factor for the z-vector +% +% x = x-component of result vector +% y = y-component of result vector +% +% +% Description: +% +% This command allows you to use a 3d coordinate system. +% +% +% Example: +% +% % Draw a cubus +% +% \pgfline{\pgfpointxyz{0}{0}{0}}{\pgfpointxyz{0}{0}{1}} +% \pgfline{\pgfpointxyz{0}{1}{0}}{\pgfpointxyz{0}{1}{1}} +% \pgfline{\pgfpointxyz{1}{0}{0}}{\pgfpointxyz{1}{0}{1}} +% \pgfline{\pgfpointxyz{1}{1}{0}}{\pgfpointxyz{1}{1}{1}} +% \pgfline{\pgfpointxyz{0}{0}{0}}{\pgfpointxyz{0}{1}{0}} +% \pgfline{\pgfpointxyz{0}{0}{1}}{\pgfpointxyz{0}{1}{1}} +% \pgfline{\pgfpointxyz{1}{0}{0}}{\pgfpointxyz{1}{1}{0}} +% \pgfline{\pgfpointxyz{1}{0}{1}}{\pgfpointxyz{1}{1}{1}} +% \pgfline{\pgfpointxyz{0}{0}{0}}{\pgfpointxyz{1}{0}{0}} +% \pgfline{\pgfpointxyz{0}{0}{1}}{\pgfpointxyz{1}{0}{1}} +% \pgfline{\pgfpointxyz{0}{1}{0}}{\pgfpointxyz{1}{1}{0}} +% \pgfline{\pgfpointxyz{0}{1}{1}}{\pgfpointxyz{1}{1}{1}} + +\def\pgfpointxyz#1#2#3{% + \pgfmathparse{#1}% + \let\pgftemp@x=\pgfmathresult% + \pgfmathparse{#2}% + \let\pgftemp@y=\pgfmathresult% + \pgfmathparse{#3}% + \let\pgftemp@z=\pgfmathresult% + \global\pgf@x=\pgftemp@x\pgf@xx% + \global\advance\pgf@x by \pgftemp@y\pgf@yx% + \global\advance\pgf@x by \pgftemp@z\pgf@zx% + \global\pgf@y=\pgftemp@x\pgf@xy% + \global\advance\pgf@y by \pgftemp@y\pgf@yy% + \global\advance\pgf@y by \pgftemp@z\pgf@zy} + +% "Quick" variant for \pgfpointxyz. +% +% Only numbers without unit are allowed. +\def\pgfqpointxyz#1#2#3{% + \global\pgf@x=#1\pgf@xx% + \global\advance\pgf@x by #2\pgf@yx% + \global\advance\pgf@x by #3\pgf@zx% + \global\pgf@y=#1\pgf@xy% + \global\advance\pgf@y by #2\pgf@yy% + \global\advance\pgf@y by #3\pgf@zy} + + + +% Set the x-vector +% +% #1 = a point the is the new x-vector +% +% Example: +% +% \pgfsetxvec{\pgfpoint{1cm}{0cm}} + +\def\pgfsetxvec#1{% + \pgf@process{#1}% + \pgf@xx=\pgf@x% + \pgf@xy=\pgf@y% + \ignorespaces} + + +% Set the y-vector +% +% #1 = a point the is the new y-vector +% +% Example: +% +% \pgfsetyvec{\pgfpoint{0cm}{1cm}} + +\def\pgfsetyvec#1{% + \pgf@process{#1}% + \pgf@yx=\pgf@x% + \pgf@yy=\pgf@y% + \ignorespaces} + + +% Set the z-vector +% +% #1 = a point the is the new z-vector +% +% Example: +% +% \pgfsetzvec{\pgfpoint{-0.385cm}{-0.385cm}} + +\def\pgfsetzvec#1{% + \pgf@process{#1}% + \pgf@zx=\pgf@x% + \pgf@zy=\pgf@y% + \ignorespaces} + + + +% Default values +\pgfsetxvec{\pgfpoint{1cm}{0cm}} +\pgfsetyvec{\pgfpoint{0cm}{1cm}} +\pgfsetzvec{\pgfpoint{-0.385cm}{-0.385cm}} + + + + +% Normalise a point. +% +% #1 = point with coordinates (a,b) +% +% x = a/\sqrt(a*a+b*b) +% y = b/\sqrt(a*a+b*b) +% +% Example: +% +% \pgfpointnormalised{\pgfpointxy{2}{1}} + +\def\pgfpointnormalised#1{% + \pgf@process{#1}% + \pgfmathatantwo{\the\pgf@y}{\the\pgf@x}% + \let\pgf@tmp=\pgfmathresult% + \pgfmathcos@{\pgf@tmp}% + \pgf@x=\pgfmathresult pt\relax% + \pgfmathsin@{\pgf@tmp}% + \pgf@y=\pgfmathresult pt\relax% +} + + + + + +% A point on a rectangle in a certain direction. +% +% #1 = a point pointing in some direction (length should be about 1pt, +% but need not be exact) +% #2 = upper right corner of a rectangle centered at the origin +% +% Returns the intersection of a line starting at the origin going in +% the given direction and the rectangle's border. +% +% Example: +% +% \pgfpointborderrectangle{\pgfpointnormalised{\pgfpointxy{2}{1}} +% {\pgfpoint{1cm}{2cm}} + +\def\pgfpointborderrectangle#1#2{% + \pgf@process{#2}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#1}% + % Ok, let's find out about the direction: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \ifnum\pgf@xa<0\relax% move into first quadrant + \global\pgf@x=-\pgf@x% + \fi% + \ifnum\pgf@ya<0\relax% + \global\pgf@y=-\pgf@y% + \fi% + \pgf@xc=.125\pgf@x% + \pgf@yc=.125\pgf@y% + \c@pgf@counta=\pgf@xc% + \c@pgf@countb=\pgf@yc% + \ifnum\c@pgf@countb<\c@pgf@counta% + \ifnum\c@pgf@counta<255\relax% + \global\pgf@y=\pgf@yb\relax% + \global\pgf@x=0pt\relax% + \else% + \pgf@xc=8192pt% + \divide\pgf@xc by\c@pgf@counta% \pgf@xc = 1/\pgf@x + \global\pgf@y=\pgf@sys@tonumber{\pgf@xc}\pgf@y% + \global\pgf@y=\pgf@sys@tonumber{\pgf@xb}\pgf@y% + \ifnum\pgf@y<\pgf@yb% + \global\pgf@x=\pgf@xb% + \else% rats, calculate intersection on upper side + \ifnum\c@pgf@countb<255\relax% + \global\pgf@x=\pgf@xb\relax% + \global\pgf@y=0pt\relax% + \else% + \pgf@yc=8192pt% + \divide\pgf@yc by\c@pgf@countb% \pgf@xc = 1/\pgf@x + \global\pgf@x=\pgf@sys@tonumber{\pgf@yc}\pgf@x% + \global\pgf@x=\pgf@sys@tonumber{\pgf@yb}\pgf@x% + \global\pgf@y=\pgf@yb% + \fi% + \fi% + \fi% + \else% + \ifnum\c@pgf@countb<255\relax% + \global\pgf@x=\pgf@xb\relax% + \global\pgf@y=0pt\relax% + \else% + \pgf@yc=8192pt% + \divide\pgf@yc by\c@pgf@countb% \pgf@xc = 1/\pgf@x + \global\pgf@x=\pgf@sys@tonumber{\pgf@yc}\pgf@x% + \global\pgf@x=\pgf@sys@tonumber{\pgf@yb}\pgf@x% + \ifnum\pgf@x<\pgf@xb% + \global\pgf@y=\pgf@yb% + \else% + \ifnum\c@pgf@counta<255\relax% + \global\pgf@y=\pgf@yb\relax% + \global\pgf@x=0pt\relax% + \else% + \pgf@xc=8192pt% + \divide\pgf@xc by\c@pgf@counta% \pgf@xc = 1/\pgf@x + \global\pgf@y=\pgf@sys@tonumber{\pgf@xc}\pgf@y% + \global\pgf@y=\pgf@sys@tonumber{\pgf@xb}\pgf@y% + \global\pgf@x=\pgf@xb% + \fi% + \fi% + \fi% + \fi% + \ifnum\pgf@xa<0\relax\global\pgf@x=-\pgf@x\fi% + \ifnum\pgf@ya<0\relax\global\pgf@y=-\pgf@y\fi% +} + + + + +% An approximation to a point on an ellipse in a certain +% direction. Will be exact only if the ellipse is a circle. +% +% #1 = a point pointing in some direction +% #2 = upper right corner of a bounding box for the ellipse +% +% Returns the intersection of a line starting at the origin going in +% the given direction and the ellipses border. +% +% Example: +% +% \pgfpointborderellipse{\pgfpointnormalised{\pgfpointxy{2}{1}} +% {\pgfpoint{1cm}{2cm}} + +\def\pgfpointborderellipse#1#2{% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \ifdim\pgf@xa=\pgf@ya% circle. that's easy! + \pgf@process{\pgfpointnormalised{#1}}% + \global\pgf@x=\pgf@sys@tonumber{\pgf@xa}\pgf@x% + \global\pgf@y=\pgf@sys@tonumber{\pgf@xa}\pgf@y% + \else% + \ifdim\pgf@xa<\pgf@ya% + % Ok, first, let's compute x/y: + \c@pgf@countb=\pgf@ya% + \divide\c@pgf@countb by65536\relax% + \global\divide\pgf@x by\c@pgf@countb% + \global\divide\pgf@y by\c@pgf@countb% + \pgf@xc=\pgf@x% + \pgf@yc=8192pt% + \global\pgf@y=.125\pgf@y% + \c@pgf@countb=\pgf@y% + \divide\pgf@yc by\c@pgf@countb% + \pgf@process{#1}% + \global\pgf@y=\pgf@sys@tonumber{\pgf@yc}\pgf@y% + \global\pgf@y=\pgf@sys@tonumber{\pgf@xc}\pgf@y% + \pgf@process{\pgfpointnormalised{}}% + \global\pgf@x=\pgf@sys@tonumber{\pgf@xa}\pgf@x% + \global\pgf@y=\pgf@sys@tonumber{\pgf@ya}\pgf@y% + \else% + % Ok, now let's compute y/x: + \c@pgf@countb=\pgf@xa% + \divide\c@pgf@countb by65536\relax% + \global\divide\pgf@x by\c@pgf@countb% + \global\divide\pgf@y by\c@pgf@countb% + \pgf@yc=\pgf@y% + \pgf@xc=8192pt% + \global\pgf@x=.125\pgf@x% + \c@pgf@countb=\pgf@x% + \divide\pgf@xc by\c@pgf@countb% + \pgf@process{#1}% + \global\pgf@x=\pgf@sys@tonumber{\pgf@yc}\pgf@x% + \global\pgf@x=\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \pgf@process{\pgfpointnormalised{}}% + \global\pgf@x=\pgf@sys@tonumber{\pgf@xa}\pgf@x% + \global\pgf@y=\pgf@sys@tonumber{\pgf@ya}\pgf@y% + \fi% + \fi% +} + + + + + +% Extract the x-coordinate of a point to a dimensions +% +% #1 = a TeX dimension +% #2 = a point +% +% Example: +% +% \newdimen\mydim +% \pgfextractx{\mydim}{\pgfpoint{2cm}{4pt}} +% % \mydim is now 2cm + +\def\pgfextractx#1#2{% + \pgf@process{#2}% + #1=\pgf@x\relax} + + +% Extract the y-coordinate of a point to a dimensions +% +% #1 = a TeX dimension +% #2 = a point +% +% Example: +% +% \newdimen\mydim +% \pgfextracty{\mydim}{\pgfpoint{2cm}{4pt}} +% % \mydim is now 4pt + +\def\pgfextracty#1#2{% + \pgf@process{#2}% + #1=\pgf@y\relax} + + +% Stores the most recently used (x,y) coordinates into two macros, #1 and #2. +\def\pgfgetlastxy#1#2{% + \edef#1{\the\pgf@x}% + \edef#2{\the\pgf@y}% +}% + + +\def\pgf@def#1#2#3{\expandafter\def\csname pgf@#1#2\endcsname{#3}} +\pgf@def{cosfrac}{0}{1} +\pgf@def{cosfrac}{1}{0.99995} \pgf@def{cosfrac}{2}{0.9998} +\pgf@def{cosfrac}{3}{0.99955} \pgf@def{cosfrac}{4}{0.999201} +\pgf@def{cosfrac}{5}{0.998752} \pgf@def{cosfrac}{6}{0.998205} +\pgf@def{cosfrac}{7}{0.997559} \pgf@def{cosfrac}{8}{0.996815} +\pgf@def{cosfrac}{9}{0.995974} \pgf@def{cosfrac}{10}{0.995037} +\pgf@def{cosfrac}{11}{0.994004} \pgf@def{cosfrac}{12}{0.992877} +\pgf@def{cosfrac}{13}{0.991656} \pgf@def{cosfrac}{14}{0.990342} +\pgf@def{cosfrac}{15}{0.988936} \pgf@def{cosfrac}{16}{0.987441} +\pgf@def{cosfrac}{17}{0.985856} \pgf@def{cosfrac}{18}{0.984183} +\pgf@def{cosfrac}{19}{0.982424} \pgf@def{cosfrac}{20}{0.980581} +\pgf@def{cosfrac}{21}{0.978653} \pgf@def{cosfrac}{22}{0.976644} +\pgf@def{cosfrac}{23}{0.974555} \pgf@def{cosfrac}{24}{0.972387} +\pgf@def{cosfrac}{25}{0.970143} \pgf@def{cosfrac}{26}{0.967823} +\pgf@def{cosfrac}{27}{0.965429} \pgf@def{cosfrac}{28}{0.962964} +\pgf@def{cosfrac}{29}{0.960429} \pgf@def{cosfrac}{30}{0.957826} +\pgf@def{cosfrac}{31}{0.955157} \pgf@def{cosfrac}{32}{0.952424} +\pgf@def{cosfrac}{33}{0.949629} \pgf@def{cosfrac}{34}{0.946773} +\pgf@def{cosfrac}{35}{0.943858} \pgf@def{cosfrac}{36}{0.940887} +\pgf@def{cosfrac}{37}{0.937862} \pgf@def{cosfrac}{38}{0.934784} +\pgf@def{cosfrac}{39}{0.931655} \pgf@def{cosfrac}{40}{0.928477} +\pgf@def{cosfrac}{41}{0.925252} \pgf@def{cosfrac}{42}{0.921982} +\pgf@def{cosfrac}{43}{0.918669} \pgf@def{cosfrac}{44}{0.915315} +\pgf@def{cosfrac}{45}{0.911922} \pgf@def{cosfrac}{46}{0.90849} +\pgf@def{cosfrac}{47}{0.905024} \pgf@def{cosfrac}{48}{0.901523} +\pgf@def{cosfrac}{49}{0.89799} \pgf@def{cosfrac}{50}{0.894427} +\pgf@def{cosfrac}{51}{0.890835} \pgf@def{cosfrac}{52}{0.887217} +\pgf@def{cosfrac}{53}{0.883573} \pgf@def{cosfrac}{54}{0.879905} +\pgf@def{cosfrac}{55}{0.876216} \pgf@def{cosfrac}{56}{0.872506} +\pgf@def{cosfrac}{57}{0.868777} \pgf@def{cosfrac}{58}{0.865031} +\pgf@def{cosfrac}{59}{0.861269} \pgf@def{cosfrac}{60}{0.857493} +\pgf@def{cosfrac}{61}{0.853704} \pgf@def{cosfrac}{62}{0.849903} +\pgf@def{cosfrac}{63}{0.846092} \pgf@def{cosfrac}{64}{0.842271} +\pgf@def{cosfrac}{65}{0.838444} \pgf@def{cosfrac}{66}{0.834609} +\pgf@def{cosfrac}{67}{0.83077} \pgf@def{cosfrac}{68}{0.826927} +\pgf@def{cosfrac}{69}{0.82308} \pgf@def{cosfrac}{70}{0.819232} +\pgf@def{cosfrac}{71}{0.815383} \pgf@def{cosfrac}{72}{0.811534} +\pgf@def{cosfrac}{73}{0.807687} \pgf@def{cosfrac}{74}{0.803842} +\pgf@def{cosfrac}{75}{0.8} \pgf@def{cosfrac}{76}{0.796162} +\pgf@def{cosfrac}{77}{0.792329} \pgf@def{cosfrac}{78}{0.788502} +\pgf@def{cosfrac}{79}{0.784682} \pgf@def{cosfrac}{80}{0.780869} +\pgf@def{cosfrac}{81}{0.777064} \pgf@def{cosfrac}{82}{0.773268} +\pgf@def{cosfrac}{83}{0.769481} \pgf@def{cosfrac}{84}{0.765705} +\pgf@def{cosfrac}{85}{0.761939} \pgf@def{cosfrac}{86}{0.758185} +\pgf@def{cosfrac}{87}{0.754443} \pgf@def{cosfrac}{88}{0.750714} +\pgf@def{cosfrac}{89}{0.746997} \pgf@def{cosfrac}{90}{0.743294} +\pgf@def{cosfrac}{91}{0.739605} \pgf@def{cosfrac}{92}{0.735931} +\pgf@def{cosfrac}{93}{0.732272} \pgf@def{cosfrac}{94}{0.728628} +\pgf@def{cosfrac}{95}{0.724999} \pgf@def{cosfrac}{96}{0.721387} +\pgf@def{cosfrac}{97}{0.717792} \pgf@def{cosfrac}{98}{0.714213} +\pgf@def{cosfrac}{99}{0.710651} \pgf@def{cosfrac}{100}{0.707107} + + + + +% Forward declarations for nonlinear stuff (have no effect till module +% nonlineartransformations is loaded) + +\let\pgfpointtransformednonlinear\pgfpointtransformed + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorequick.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorequick.code.tex new file mode 100644 index 0000000000..4180440b00 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorequick.code.tex @@ -0,0 +1,134 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorequick.code.tex} + +% Quick version of basic drawing commands. Most high-level commands +% are not available if these commands are used. + +% Move current point to (#1,#2). +% +% #1 = x dimension of new current point +% #2 = y dimension of new current point +% +% Example: +% +% \pgfpathqmoveto{0pt}{0pt} +% \pgfpathqlineto{1pt}{1pt} +% \pgfpathqcurveto{2pt}{1pt}{2pt}{2pt}{3pt}{2pt} +% \pgfqstroke + +\def\pgfpathqmoveto#1#2{\pgfsyssoftpath@moveto{#1}{#2}} + + +% Append a line to (#1,#2) to the current path. +% +% #1 = x dimension of target +% #2 = y dimension of target +% +% Example: +% +% \pgfpathqmoveto{0pt}{0pt} +% \pgfpathqlineto{1pt}{1pt} +% \pgfpathqcurveto{2pt}{1pt}{2pt}{2pt}{3pt}{2pt} +% \pgfqstroke + +\def\pgfpathqlineto#1#2{\pgfsyssoftpath@lineto{#1}{#2}} + + +% Append a bezier spline to the current path. +% +% #1 = x dimension of first support point +% #2 = y dimension of first support point +% #3 = x dimension of second support point +% #4 = y dimension of second support point +% #5 = x dimension of target point +% #6 = y dimension of target point +% +% Example: +% +% \pgfpathqmoveto{0pt}{0pt} +% \pgfpathqlineto{1pt}{1pt} +% \pgfpathqcurveto{2pt}{1pt}{2pt}{2pt}{3pt}{2pt} +% \pgfqstroke + +\def\pgfpathqcurveto#1#2#3#4#5#6{\pgfsyssoftpath@curveto{#1}{#2}{#3}{#4}{#5}{#6}} + + + + +% Append a circle of the given radius around the origin. +% +% #1 = radius +% +% Example: +% +% \pgfpathqcircle{10pt} +% is quicker than +% \pgfpathcircle{\pgforigin}{10pt} + +\def\pgfpathqcircle#1{% + {% + \pgf@x=#1% + \pgf@y=0.5522847\pgf@x% + \pgfsyssoftpath@moveto{\the\pgf@x}{0pt}% + \pgfsyssoftpath@curveto{\the\pgf@x}{\the\pgf@y}{\the\pgf@y}{\the\pgf@x}{0pt}{\the\pgf@x}% + \pgfsyssoftpath@curveto{-\the\pgf@y}{\the\pgf@x}{-\the\pgf@x}{\the\pgf@y}{-\the\pgf@x}{0pt}% + \pgfsyssoftpath@curveto{-\the\pgf@x}{-\the\pgf@y}{-\the\pgf@y}{-\the\pgf@x}{0pt}{-\the\pgf@x}% + \pgfsyssoftpath@curveto{\the\pgf@y}{-\the\pgf@x}{\the\pgf@x}{-\the\pgf@y}{\the\pgf@x}{0pt}% + \pgfsyssoftpath@closepath% + }% +} + + + +% Stroke current path. No hooks called. +% +% Example: +% +% \pgfpathqmoveto{0cm}{0cm} +% \pgfpathqlineto{1cm}{1cm} +% \pgfpathqcurveto{2cm}{1cm}{2cm}{2cm}{3cm}{2cm} +% \pgfqstroke + +\def\pgfusepathqstroke{% + \pgfsyssoftpath@flushcurrentpath% + \pgfsys@stroke% + \pgf@resetpathsizes% +} + + +% Quickly fill current path. + +\def\pgfusepathqfill{% + \pgfsyssoftpath@flushcurrentpath% + \pgfsys@fill% + \pgf@resetpathsizes% +} + + +% Quickly fill and stroke current path. + +\def\pgfusepathqfillstroke{% + \pgfsyssoftpath@flushcurrentpath% + \pgfsys@fillstroke% + \pgf@resetpathsizes% +} + +% Quickly clip current path. + +\def\pgfusepathqclip{% + \pgfsyssoftpath@flushcurrentpath% + \pgfsys@clipnext% + \pgfsys@discardpath% + \pgf@resetpathsizes% +} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorerdf.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorerdf.code.tex new file mode 100644 index 0000000000..1069318a4b --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorerdf.code.tex @@ -0,0 +1,228 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorerdf.code.tex} + + + +% +% +% The Resource Description Framework (RDF) is a method of enriching +% output files with semantic information. In PGF, you can use the +% following commands to create RDF information that will be inserted +% into the output, provided the output format allows this (SVG +% does). You call any of these commands before an ID-scope and it will +% attach the attribute(s) to this id scope. +% +% +% Example: +% +% ... +% \pgfrdftypeof{http://purl.org/dc/dcmitype/Image} +% \pgfrdfresource{/paper/figures/1} +% \pgfidscope +% % This ID scope will be flagged as the resource "/paper/figures/1" +% % and typeof "Image" from the Dublin Core. +% ... +% \endidscope + + + + + +% Adds the rdf attribute "about" with value #1 to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "a SafeCURIEorCURIEorIRI, used for stating what +% the data is about (a 'subject' in RDF terminology);" + +\def\pgfrdfabout#1{\pgfsys@rdf@about{#1}} + + + +% Adds the rdf attribute content with value #1 to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "a CDATA string, for supplying machine-readable +% content for a literal (a 'literal object', in RDF terminology);" + +\def\pgfrdfcontent#1{\pgfsys@rdf@content{#1}} + + + +% Adds the rdf attribute datatype with value #1 to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "a TERMorCURIEorAbsIRI representing a datatype, +% to express the datatype of a literal;" + +\def\pgfrdfdatatype#1{\pgfsys@rdf@datatype{#1}} + + + +% Adds the rdf attribute href with value #1 to the next idscope +% The RDF-spec says: "a traditionally navigable IRI for +% expressing the partner resource of a relationship (a 'resource object', in RDF terminology);" + +\def\pgfrdfhref#1{\pgfsys@rdf@href{#1}} + + + +% Adds the rdf attribute inlist to the next idscope. +% +% Description: +% +% The RDF-spec says: "An attribute used to indicate that the object +% associated with a rel or property attribute on the same element is +% to be added to the list for that predicate. Presence of this +% attribute causes a list to be created if it does not already exist." + +\def\pgfrdfinlist{\pgfsys@rdf@inlist} + + + + +% Adds #1 to the list of the rdf prefix attribute to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% Can be called several times, in which case all values of #1 are +% concatenated with whitespaces. The RDF-spec says: "a white space +% separated list of prefix-name IRI pairs of the form NCName ':' ' '+ +% xsd:anyURI" + +\def\pgfrdfprefix#1{\pgfsys@rdf@prefix{#1}} + + + + +% Adds #1 to the list of the rdf property attribute to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% Can be called repeatedly. The RDF-spec says: "a white space +% separated list of TERMorCURIEorAbsIRIs, used for expressing +% relationships between a subject and either a resource object if +% given or some literal text (also a 'predicate');" + +\def\pgfrdfproperty#1{\pgfsys@rdf@property{#1}} + + + +% Adds #1 to the list of the rdf rel attribute to the next +% next idscope. +% +% #1 = A URL +% +% Description: +% +% Can be called repeatedly. The RDF-spec says: "a white space +% separated list of TERMorCURIEorAbsIRIs, used for expressing +% relationships between two resources ('predicates' in RDF +% terminology);" + +\def\pgfrdfrel#1{\pgfsys@rdf@rel{#1}} + + +% Adds the rdf attribute resource with value #1 to the next idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "a SafeCURIEorCURIEorIRI for expressing the +% partner resource of a relationship that is not intended to be +% navigable (e.g., a 'clickable' link) (also an 'object');" + +\def\pgfrdfresource#1{\pgfsys@rdf@resource{#1}} + + + + +% Adds #1 to the list of the rdf rev attribute to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% Can be called repeatedly. The RDF-spec says: "a white space +% separated list of TERMorCURIEorAbsIRIs, used for expressing reverse +% relationships between two resources (also 'predicates'); + +\def\pgfrdfrev#1{\pgfsys@rdf@rev{#1}} + + + + +% Adds an rdf attribute src with value #1 to the next idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "an IRI for expressing the partner resource of a +% relationship when the resource is embedded (also a 'resource object');" + +\def\pgfrdfsrc#1{\pgfsys@rdf@src{#1}} + + + + +% Adds #1 to the list of the rdf typeof attribute to the next +% idscope. +% +% #1 = A URL +% +% Description: +% +% Can be called repeatedly. The RDF-spec says: "a white space +% separated list of TERMorCURIEorAbsIRIs that indicate the RDF type(s) +% to associate with a subject;" + +\def\pgfrdftypeof#1{\pgfsys@rdf@typeof{#1}} + + + + +% Adds an rdf attribute vocab with value #1 to the next idscope. +% +% #1 = A URL +% +% Description: +% +% The RDF-spec says: "an IRI that defines the mapping to use when a +% TERM is referenced in an attribute value. See General Use of Terms +% in Attributes and the section on Vocabulary Expansion." + +\def\pgfrdfvocab#1{\pgfsys@rdf@vocab{#1}} + + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorescopes.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorescopes.code.tex new file mode 100644 index 0000000000..75cb1b587d --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorescopes.code.tex @@ -0,0 +1,771 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcorescopes.code.tex} + +% Globals + +\newbox\pgfpic +\newbox\pgf@hbox + +\newbox\pgf@layerbox@main + +\newcount\pgf@picture@serial@count + + + +% This if decides whether the position of pictures on the page is +% protocolled or not. Normally, +% this is switched off as it works only with certain drivers and it +% causes external files to be written. When switched on, the position +% of pgfpictures are protocolled and can be referenced using +% \pgfsys@getposition{XXX} where XXX is the value of \pgfpictureid +% inside the picture. +\newif\ifpgfrememberpicturepositiononpage + + + + +% Scopes + + +% Pgf scope environment. All changes of the graphic state are local to +% the scope. +% +% Example: +% +% \begin{pgfscope} +% \pgfsetlinewidth{3pt} +% \pgfline{\pgfxy(0,0)}{\pgfxy(3,3)} +% \end{pgfscope} + +\def\pgfscope{% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \pgfsys@beginscope% + \pgf@resetpathsizes% + \edef\pgfscope@linewidth{\the\pgflinewidth}% + \let\pgfscope@stroke@color=\pgf@strokecolor@global% + \let\pgfscope@fill@color=\pgf@fillcolor@global% + \begingroup} +\def\endpgfscope{% + \endgroup% + \global\pgflinewidth=\pgfscope@linewidth% + \global\let\pgf@strokecolor@global=\pgfscope@stroke@color% + \global\let\pgf@fillcolor@global=\pgfscope@fill@color% + \pgfsys@endscope} + + + + +% Quickly insert a box can contain normal TeX text at the origin. +% +% #1 = box of width/height and depth 0pt +% +% Example: +% +% \pgfqbox{\mybox} + +\def\pgfqbox#1{% + \pgfsys@hbox#1% +} + + +% Insert a box that can contain normal TeX text at the origin, but +% with the current coordinate transformation matrix synced with the +% low-level transformation matrix. +% +% #1 = box of width/height and depth 0pt +% +% In essence, this command does the same as if you first said +% \pgflowlevelsynccm and then \pgfqbox. However, pgf will use a +% ``TeX-translation'' for the translation part of the transformation +% cm. This will ensure that hyperlinks ``survive'' at least +% translations. +% +% Example: +% +% \pgfqboxsynced{\mybox} + +\def\pgfqboxsynced#1{% + \pgfsys@hboxsynced#1% +} + + +% Puts some text in a box and inserts it with the current +% transformations applied. +% +% #1 = List of optional positioning. Possible values are ``left'', ``right'', +% ``top'', ``bottom'' and ``base''. +% #2 = TeX text. May contain verbatims. +% +% Example: +% +% \pgftransformshift{\pgfpoint{1cm}{0cm}} +% \pgftext{Hello World!} + +\def\pgftext{\pgfutil@ifnextchar[\pgf@text{\pgf@text[]}}% +\def\pgf@text[#1]{% + \def\pgf@text@options{#1}% + \pgf@maketext\pgf@after@text} +\def\pgf@after@text{% + {% + \def\pgf@text@hshift{center}% + \def\pgf@text@vshift{center}% + \expandafter\pgf@text@setkeys\expandafter{\pgf@text@options}% + \csname pgf@halign\pgf@text@hshift\endcsname% + \csname pgf@valign\pgf@text@vshift\endcsname% + % + \pgfapproximatenonlineartransformation% + % Protocol sizes: + \pgf@process{\pgfpointtransformed{\pgfqpoint{0pt}{\dp\pgf@hbox}}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\wd\pgf@hbox}{\dp\pgf@hbox}}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% + \pgf@process{\pgfpointtransformed{\pgfqpoint{0pt}{\ht\pgf@hbox}}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\wd\pgf@hbox}{\ht\pgf@hbox}}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y}% + \pgfqboxsynced{\pgf@hbox}% + }% +} +\def\pgf@text@setkeys{\pgfqkeys{/pgf/text}}% + +\pgfkeys{/pgf/text/left/.code=\def\pgf@text@hshift{left}} +\pgfkeys{/pgf/text/center/.code=} +\pgfkeys{/pgf/text/right/.code=\def\pgf@text@hshift{right}} +\pgfkeys{/pgf/text/top/.code=\def\pgf@text@vshift{top}} +\pgfkeys{/pgf/text/bottom/.code=\def\pgf@text@vshift{bottom}} +\pgfkeys{/pgf/text/base/.code=\def\pgf@text@vshift{base}} +\pgfkeys{/pgf/text/at/.cd,.code=\pgftransformshift{#1},.value required} +\pgfkeys{/pgf/text/x/.cd,.code=\pgftransformxshift{#1},.value required} +\pgfkeys{/pgf/text/y/.cd,.code=\pgftransformyshift{#1},.value required} +\pgfkeys{/pgf/text/rotate/.cd,.code=\pgftransformrotate{#1},.value required} + +\def\pgf@halignleft{}% do nothing +\def\pgf@haligncenter{\pgftransformxshift{+-.5\wd\pgf@hbox}} +\def\pgf@halignright{\pgftransformxshift{+-\wd\pgf@hbox}}% +\def\pgf@valignbase{}% do nothing +\def\pgf@valignbottom{\pgftransformyshift{+\dp\pgf@hbox}}% +\def\pgf@valigncenter{\pgftransformyshift{+.5\dp\pgf@hbox}\pgftransformyshift{+-.5\ht\pgf@hbox}}% +\def\pgf@valigntop{\pgftransformyshift{+-\ht\pgf@hbox}}% + + +% Internal function for creating a hbox. +\def\pgf@maketext#1{% + \def\pgf@@maketextafter{#1}% + \setbox\pgf@hbox=\hbox\bgroup% + \pgfinterruptpicture% + \bgroup% + \aftergroup\pgf@collectresetcolor% + \let\next=% +} +\def\pgf@collectresetcolor{% + \pgfutil@ifnextchar\reset@color% + {\reset@color\afterassignment\pgf@collectresetcolor\let\pgf@temp=}% + {\pgf@textdone}% +} +\def\pgf@textdone{% + \endpgfinterruptpicture% + \egroup% + \pgf@@maketextafter% +} + +\long\def\pgf@makehbox#1{% + \setbox\pgf@hbox=\hbox{{% + \pgfinterruptpicture% + #1% + \endpgfinterruptpicture% + }}} + + + +% Picture environment +% +% Example: +% +% \begin{pgfpicture} +% \pgfsetendarrow{\pgfarrowto} +% \pgfpathmoveto{\pgfpointxy{-0.9}{0.2}} +% \pgfpathlineto{\pgfpointxy{0.9}{0.4}} +% \pgfusepath{stroke} +% \end{pgfpicture} + +\def\pgfresetboundingbox{% + \global\pgf@picmaxx=-16000pt\relax% + \global\pgf@picminx=16000pt\relax% + \global\pgf@picmaxy=-16000pt\relax% + \global\pgf@picminy=16000pt\relax% +}% + +\def\pgfpicture{% + \begingroup% + \pgfpicturetrue% + \global\advance\pgf@picture@serial@count by1\relax% + \edef\pgfpictureid{pgfid\the\pgf@picture@serial@count}% + \let\pgf@nodecallback=\pgfutil@gobble% + \pgf@picmaxx=-16000pt\relax% + \pgf@picminx=16000pt\relax% + \pgf@picmaxy=-16000pt\relax% + \pgf@picminy=16000pt\relax% + \pgf@relevantforpicturesizetrue% + \pgf@resetpathsizes% + \pgfutil@ifnextchar\bgroup\pgf@oldpicture\pgf@picture} +\def\pgf@oldpicture#1#2#3#4{% + \pgfmathsetlength\pgf@picminx{#1}% + \pgfmathsetlength\pgf@picminy{#2}% + \pgfmathsetlength\pgf@picmaxx{#3}% + \pgfmathsetlength\pgf@picmaxy{#4}% + \pgf@relevantforpicturesizefalse% + \pgf@picture} + +\def\pgf@picture{% + \setbox\pgfpic\hbox to0pt\bgroup% + \begingroup% + \pgfsys@beginpicture% + \pgfsys@beginscope% + \begingroup% + \pgfsetcolor{.}% + \pgfsetlinewidth{0.4pt}% + \pgftransformreset% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \begingroup% + \let\pgf@setlengthorig=\setlength% + \let\pgf@addtolengthorig=\addtolength% + \let\pgf@selectfontorig=\selectfont% + \let\setlength=\pgf@setlength% + \let\addtolength=\pgf@addtolength% + \let\selectfont=\pgf@selectfont% + \nullfont\spaceskip0pt\xspaceskip0pt% + \tracinglostchars=% + \ifnum\tracinglostchars>2 2\else\tracinglostchars\fi + \setbox\pgf@layerbox@main\hbox to0pt\bgroup% + \begingroup% + } +\def\endpgfpicture{% + \ifpgfrememberpicturepositiononpage% + \hbox to0pt{\pgfsys@markposition{\pgfpictureid}}% + \fi% + % ok, now let's position the box + \ifdim\pgf@picmaxx=-16000pt\relax% + % empty picture. make size 0. + \global\pgf@picmaxx=0pt\relax% + \global\pgf@picminx=0pt\relax% + \global\pgf@picmaxy=0pt\relax% + \global\pgf@picminy=0pt\relax% + \fi% + % Shift baseline outside: + \pgf@relevantforpicturesizefalse% + \pgf@process{\pgf@baseline}% + \xdef\pgf@shift@baseline{\the\pgf@y}% + % + \pgf@process{\pgf@trimleft}% + \global\advance\pgf@x by-\pgf@picminx + % prepare \hskip\pgf@trimleft@final. + % note that \pgf@trimleft@final is also queried + % by the pgf image externalization. + \xdef\pgf@trimleft@final{-\the\pgf@x}% + % + \pgf@process{\pgf@trimright}% + \global\advance\pgf@x by-\pgf@picmaxx + % prepare \hskip\pgf@trimright@final. + % note that \pgf@trimright@final is also queried + % by the pgf image externalization. + \xdef\pgf@trimright@final{\the\pgf@x}% + % + \pgf@remember@layerlist@globally + \endgroup% + \hss% + \egroup% + \pgf@restore@layerlist@from@global + \pgf@insertlayers% + \endgroup% + \pgfsys@discardpath% + \endgroup% + \pgfsys@endscope% + \pgfsys@endpicture% + \endgroup% + \hss + \egroup% + \pgfsys@typesetpicturebox\pgfpic% + \endgroup% +} + +\def\pgf@remember@layerlist@globally{% + \global\let\pgf@layerlist@=\pgf@layerlist +}% +\def\pgf@restore@layerlist@from@global{% + \let\pgf@layerlist=\pgf@layerlist@ +}% +\def\pgf@insertlayers{% + \box\pgf@layerbox@main% +} + +\def\pgf@selectfont{\pgf@selectfontorig\nullfont} + +\def\pgf@setlength#1#2{% these will be used only when \nullfont is active + \begingroup% keep font setting local + \pgfutil@selectfont% restore font + \pgf@setlengthorig#1{#2}% calculate dimension (possibly using calc) + \expandafter% + \endgroup% + \expandafter#1\expandafter=\the#1\relax} +\def\pgf@addtolength#1#2{% + \begingroup% keep font setting local + \pgfutil@selectfont% restore font + \pgf@addtolengthorig#1{#2}% calculate dimension (possibly using calc) + \expandafter% + \endgroup% + \expandafter#1\expandafter=\the#1\relax} + + +% Sets the baseline at the y-coordinate of a given point +% +% #1 = point +% +% Sets the baseline of the picture to the y-coordinate of a given +% point. However, the point will be evaluated *at the end of the +% picture*. +% +% Example: +% +% \pgfsetbaselinepointlater{\pgfpointanchor{mynode}{base}} + +\def\pgfsetbaselinepointlater#1{\def\pgf@baseline{#1}} + + +% Sets the baseline at the y-coordinate of a given point, now +% +% #1 = point +% +% Sets the baseline of the picture to the y-coordinate of a given +% point. +% +% Example: +% +% \pgfsetbaselinepointnow{\pgfpoint{1cm}{2pt}} + +\def\pgfsetbaselinepointnow#1{% + \pgf@process{#1}% + \edef\pgf@setter@baseline{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfsetbaselinepointlater{\pgf@setter@baseline}% +} + +\def\pgf@default@text{default}% + +% Sets the baseline +% +% #1 = baseline +% +% Sets the baseline of the picture. Default is the lower border, which +% is the same as \pgf@picminy +% +% Example: +% +% \pgfsetbaseline{1cm+2pt} +% \pgfsetbaseline{default}% resets to default value + +\def\pgfsetbaseline#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@default@text + \pgfsetbaseline{\pgf@picminy}% + \else + \pgfsetbaselinepointlater{\pgfpoint{0pt}{#1}}% + \fi +} +\pgfsetbaseline{\pgf@picminy} + +% controls how the image externalization implements trim: +\newif\ifpgf@trim@lowlevel +\pgfkeys{ + /pgf/trim lowlevel/.is if=pgf@trim@lowlevel, + /pgf/trim lowlevel/.default=true, +} + +% Same as the y-baseline for horizontal alignment. +% The effect is different, though: it is some kind of trimming which +% leaves the bounding box intact. +\def\pgfsettrimleftpointlater#1{\def\pgf@trimleft{#1}} +\def\pgfsettrimleftpointnow#1{% + \pgf@process{#1}% + \edef\pgf@setter@baseline{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfsettrimleftpointlater{\pgf@setter@baseline}% +} +% \pgfsettrimleft{} +% or +% \pgfsettrimleft{default} +\def\pgfsettrimleft#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@default@text + \pgfsettrimleft{\pgf@picminx} + \else + \pgfsettrimleftpointlater{\pgfpoint{#1}{0pt}}% + \fi +} +\pgfsettrimleft{\pgf@picminx} + +\def\pgfsettrimrightpointlater#1{\def\pgf@trimright{#1}} +\def\pgfsettrimrightpointnow#1{% + \pgf@process{#1}% + \edef\pgf@setter@baseline{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfsettrimrightpointlater{\pgf@setter@baseline}% +} +% \pgfsettrimright{} +% or +% \pgfsettrimright{default} +\def\pgfsettrimright#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@default@text + \pgfsettrimright{\pgf@picmaxx}% + \else + \pgfsettrimrightpointlater{\pgfpoint{#1}{0pt}}% + \fi +} +\pgfsettrimright{\pgf@picmaxx} + + +% Interrupt path +% +% Description: +% +% The environment can be used to insert some drawing commands while +% constructing a path. The drawing commands inside the environment +% will not interfere with the path being constructed ``outside.'' +% However, you must ward against graphic state changes using a scope. +% +% Example: Draw two parallel lines +% +% \pgfmoveto{\pgfpoint{0cm}{0cm}} +% \begin{pgfinterruptpath} +% \pgfmoveto{\pgfpoint{1cm}{0cm}} +% \pgfmoveto{\pgfpoint{1cm}{1cm}} +% \pgfusepath{stroke} +% \end{pgfinterruptpath} +% \pgflineto{\pgfpoint{0cm}{1cm}} +% \pgfusepath{stroke} + +\def\pgfinterruptpath +{% + \begingroup% + % save all sorts of things... + \edef\pgf@interrupt@savex{\the\pgf@path@lastx}% + \edef\pgf@interrupt@savey{\the\pgf@path@lasty}% + \pgf@getpathsizes\pgf@interrupt@pathsizes% + \pgfsyssoftpath@getcurrentpath\pgf@interrupt@path% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \let\pgf@interrupt@lastmoveto=\pgfsyssoftpath@lastmoveto% + \begingroup% +} +\def\endpgfinterruptpath +{% + \endgroup% + \pgfsyssoftpath@setcurrentpath\pgf@interrupt@path% + \pgf@setpathsizes\pgf@interrupt@pathsizes% + \global\pgf@path@lastx\pgf@interrupt@savex% + \global\pgf@path@lasty\pgf@interrupt@savey% + \global\let\pgfsyssoftpath@lastmoveto\pgf@interrupt@lastmoveto% + \endgroup% +} + + + +% Interrupt bounding box +% +% Description: +% +% The environment can be used to temporarily setup a new bounding box +% computation. The bounding box will be made empty at the beginning of +% the environment and will be reset to its old value after the +% environment. +% +% Example: +% +% \begin{pgfinterruptboundinbox} +% \pgfmoveto{\pgfpoint{1cm}{0cm}} +% \pgfmoveto{\pgfpoint{1cm}{1cm}} +% \pgfusepath{stroke} +% \end{pgfinterruptboundinbox} + +\def\pgfinterruptboundingbox +{% + \begingroup% + \edef\pgf@interrupt@savemaxx{\the\pgf@picmaxx}% + \edef\pgf@interrupt@saveminx{\the\pgf@picminx}% + \edef\pgf@interrupt@savemaxy{\the\pgf@picmaxy}% + \edef\pgf@interrupt@saveminy{\the\pgf@picminy}% + \pgf@picmaxx=-16000pt\relax% + \pgf@picminx=16000pt\relax% + \pgf@picmaxy=-16000pt\relax% + \pgf@picminy=16000pt\relax% + \pgf@size@hookedfalse% + \let\pgf@path@size@hook=\pgfutil@empty% +} +\def\endpgfinterruptboundingbox +{% + \global\pgf@picmaxx=\pgf@interrupt@savemaxx% + \global\pgf@picmaxy=\pgf@interrupt@savemaxy% + \global\pgf@picminx=\pgf@interrupt@saveminx% + \global\pgf@picminy=\pgf@interrupt@saveminy% + \endgroup% +} + + + + +% Creates an id scope. +% +% Description: +% +% An id scope is not (conceptually) a graphic scope, but a scope that +% has a unique name or "id". This id can be used as a reference point +% for instance for a hyperlink or for an animation (currently, only +% SVG supports ids, all other drivers ignore id scopes). +% +% Prior to using \pgfidscope, call \pgfuseid to install an +% id (and possibly \pgfusetype). The scope will then get this id and, +% likely, a graphic scope is installed. If \pgfuseid has not been +% called or if you try to call \pgfidscope again for the same id, +% nothing happens (except for a \TeX\ group being established). + +\def\pgfidscope{\pgfsys@begin@idscope} +\def\endpgfidscope{\pgfsys@end@idscope} + +\let\startpgfidscope\pgfidscope +\let\stoppgfidscope\pgfendidscope + + + + +% Use an id on the next graphic object +% +% #1 = a name +% +% The next scope or path can be the target of an animation command or +% a hyperlink. + +\def\pgfuseid#1{% + \edef\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgf@lookup@id{#1}% + \pgfsys@use@id{\pgf@next@id}% + \expandafter\xdef\csname pgf@id@names@#1\endcsname{{\pgf@next@id}{}}% + \fi% +} + +\def\pgf@lookup@id#1{% + \expandafter\let\expandafter\pgf@id@name\csname pgf@id@names@#1\endcsname% + \ifx\pgf@id@name\relax% + \let\pgf@prev@id\pgfutil@empty% + \let\pgf@next@id\pgfutil@empty% + \else% + \expandafter\pgf@id@parse\pgf@id@name% + \fi% + \ifx\pgf@next@id\pgfutil@empty% + \pgfsys@new@id\pgf@next@id% + \expandafter\xdef\csname pgf@id@names@#1\endcsname{{\pgf@prev@id}{\pgf@next@id}}% + \fi% +} +\def\pgf@id@parse#1#2{% + \def\pgf@prev@id{#1}% + \def\pgf@next@id{#2}% +} + + + +% Clear the current id +% +% Description: +% +% Sets the current id to be empty so that it cannot be referenced. + +\def\pgfclearid{% + \pgfsys@clear@id% +} + + +% Get the id that will be given to a name upon the next use +% +% #1 = a macro +% #2 = a name +% +% Description: +% +% #1 will get the id that will be used by \pgfuseid next time for the +% given name. + +\def\pgfidrefnextuse#1#2{% + \edef\pgf@temp{#2}\ifx\pgf@temp\pgfutil@empty\pgferror{Missing name reference for ``\string#1''}\fi% + \pgf@lookup@id{#2}% + \let#1\pgf@next@id% +} + + +% Get the id was last used +% +% #1 = a macro +% #2 = a name +% +% Description: +% +% #1 will get the id that was last used by \pgfuseid for #2. + +\def\pgfidrefprevuse#1#2{% + \edef\pgf@temp{#2}\ifx\pgf@temp\pgfutil@empty\pgferror{Missing name reference for ``\string#1''}\fi% + \pgf@lookup@id{#2}% + \let#1\pgf@prev@id% +} + + +% Use a type +% +% #1 = an id type; when starting with a dot, it is added to the +% current type. +% +% The next scope or path can be the target of an animation command or +% a hyperlink. + +\def\pgfusetype#1{% + \edef\pgf@temp{#1}% + \expandafter\pgfutil@ifnextchar\expandafter.\expandafter\pgf@id@use@type@add\expandafter\pgf@id@use@type@replace\pgf@temp\pgf@stop +} +\def\pgf@id@use@type@add.#1\pgf@stop{\pgfsys@append@type{#1}} +\def\pgf@id@use@type@replace#1\pgf@stop{\pgfsys@use@type{#1}} + +% Push the current type on a global stack +% +% Description: +% +% The current type is pushed onto a global type stack. It can be +% restored using \pgfpoptype. + +\def\pgfpushtype{\pgfsys@push@type} + + +% Pop a type from the type stack +% +% Description: +% +% Restores the most current value from the type stack. + +\def\pgfpoptype{\pgfsys@pop@type} + + + + +% Alias an id locally or globally +% +% #1 = the alias name +% #2 = a existing id name +% +% Description: +% +% Creates an alias of a name + +\def\pgfaliasid#1#2{% + \expandafter\let\expandafter\pgf@temp\csname pgf@id@names@#2\endcsname% + \expandafter\let\csname pgf@id@names@#1\endcsname\pgf@temp% +} +\def\pgfgaliasid#1#2{% + \expandafter\let\expandafter\pgf@temp\csname pgf@id@names@#2\endcsname% + \expandafter\global\expandafter\let\csname pgf@id@names@#1\endcsname\pgf@temp% +} + + +% Check whether a name has been forward-referenced +% +% #1 = a name +% #2 = what to do, when has been forward-referenced +% #3 = what to do otherwise +% +% Description: +% +% Depending on whether #1 has been forward-referenced, #2 or #3 will be executed. + +\def\pgfifidreferenced#1#2#3{% + \expandafter\let\expandafter\pgf@id@name\csname pgf@id@names@#1\endcsname% + \ifx\pgf@id@name\relax% + #3% + \else + \expandafter\pgf@id@parse\pgf@id@name% + \ifx\pgf@next@id\pgfutil@empty% + #3% + \else% + #2% + \fi% + \fi% +} + + +% Interrupts a picture +% +% Description: +% +% This environment interrupts a picture and temporarily returns to +% normal TeX mode. All sorts of things are saved and restored by this +% environment. +% +% WARNING: Using this environment in conjunction with low level +% transformations can *strongly* upset the typesetting. Typically, the +% contents of this environment should have size/height/depth 0pt in +% the end. +% +% WARNING: This environment should only be used inside typesetting a +% box and this box must in turn be inserted using \pgfqbox. +% +% Example: Draw two parallel lines +% +% \pgfmoveto{\pgfpoint{0cm}{0cm}} +% \setbox\mybox=\hbox{ +% \begin{pgfinterruptpicture} +% This is normal text. +% \begin{pgfpicture} % a subpicture +% \pgfmoveto{\pgfpoint{1cm}{0cm}} +% \pgfmoveto{\pgfpoint{1cm}{1cm}} +% \pgfusepath{stroke} +% \end{pgfpicture} +% More text. +% \end{pgfinterruptpicture} +% } +% \ht\mybox=0pt +% \wd\mybox=0pt +% \dp\mybox=0pt +% \pgfqbox{\mybox}% +% \pgfpathlineto{\pgfpoint{0cm}{1cm}} +% \pgfusepath{stroke} + +\def\pgfinterruptpicture +{% + \begingroup% + \csname tikz@inside@picturefalse\endcsname% + \pgfinterruptboundingbox% + \pgftransformreset% + \pgfinterruptpath% + \ifx\pgf@selectfontorig\@undefined% + \else% + \let\setlength\pgf@setlengthorig% + \let\addtolength\pgf@addtolengthorig% + \let\selectfont\pgf@selectfontorig% + \fi% + \pgfutil@selectfont% + \pgfpicturefalse% + \let\pgf@positionnodelater@macro\relax% + \pgf@savelayers% +} +\def\endpgfinterruptpicture +{% + \pgf@restorelayers% + \endpgfinterruptpath% + \endpgfinterruptboundingbox% + \endgroup% +} + +\let\pgf@savelayers=\relax +\let\pgf@restorelayers=\relax + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoreshade.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreshade.code.tex new file mode 100644 index 0000000000..39a40c54ee --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoreshade.code.tex @@ -0,0 +1,974 @@ +% Copyright 2019 by Till Tantau +% CMYK and grayscale shadings adaptation copyright 2019 by David Purton +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoreshade.code.tex} + +% +% Parsing functions +% +\newdimen\pgf@max +\newcount\pgf@sys@shading@range@num +\def\pgf@parsefunc#1{% + \edef\temp{{#1}}% + \expandafter\pgf@convertstring\temp% + \edef\temp{{\pgf@conv}}% + \expandafter\pgf@@parsefunc\temp} +\def\pgf@@parsefunc#1{% + \let\pgf@bounds=\pgfutil@empty% + \let\pgf@funcs=\pgfutil@empty% + \let\pgf@psfuncs=\pgfutil@empty% + \let\pgf@encode=\pgfutil@empty% + \let\pgf@sys@shading@ranges=\pgfutil@empty% + \pgf@sys@shading@range@num=0\relax% + \csname pgf@parsefirst\pgf@shading@model\endcsname[#1; ]% + \csname pgf@parselastdom\pgf@shading@model\endcsname[#1; ]% + \csname pgf@parsemid\pgf@shading@model\endcsname[#1; ]% + \ifx\pgf@bounds\pgfutil@empty% + \edef\pgf@pdfparseddomain{0 1}% + \edef\pgf@pdfparsedfunction{\pgf@singlefunc\space}% + \else% + \edef\pgf@pdfparseddomain{\pgf@doma\space\pgf@domb}% + \edef\pgf@pdfparsedfunction{% + << /FunctionType 3 /Domain [\pgf@doma\space\pgf@domb] /Functions + [\pgf@funcs\space] /Bounds [\pgf@bounds] /Encode [0 1 \pgf@encode] + >> }% << + \fi% + \xdef\pgf@psfuncs{\pgf@psfuncs}% + } +\def\pgf@parsefirstrgb[rgb(#1)=(#2,#3,#4)#5]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@start@pos{\the\pgf@x}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@doma{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getrgbtuplewithmixin{#2}{#3}{#4}% + \edef\pgf@sys@shading@start@rgb{\pgf@sys@rgb}% + \let\pgf@sys@prevcolor=\pgf@sys@shading@start@rgb% + \let\pgf@sys@prevpos=\pgf@sys@shading@start@pos% + \edef\pgf@prevcolor{\pgf@rgb}% + \edef\pgf@firstcolor{\pgf@rgb}} +\def\pgf@parselastdomrgb[rgb(#1)=(#2,#3,#4); {% + \pgfutil@ifnextchar]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@end@pos{\the\pgf@x}% + \pgf@max=\pgf@x\relax% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@domb{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getrgbtuplewithmixin{#2}{#3}{#4}% + \edef\pgf@sys@shading@end@rgb{\pgf@sys@rgb}% + \pgfutil@gobble}{\pgf@parselastdomrgb[}} +\def\pgf@parsemidrgb[rgb(#1)=(#2,#3,#4); {\pgf@parserestrgb[} +\def\pgf@parserestrgb[rgb(#1)=(#2,#3,#4); {% + \advance\pgf@sys@shading@range@num by1\relax% + \pgfutil@ifnextchar]{% + \pgf@getrgbtuplewithmixin{#2}{#3}{#4}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@rgb] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@rgb] /N 1 >> }% << + \edef\pgf@psfuncs{\pgf@prevx\space \pgf@rgb\space \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{{\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@rgb}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@rgb% + \pgfutil@gobble}{% + \pgfmathsetlength\pgf@x{#1}% + \pgf@getrgbtuplewithmixin{#2}{#3}{#4}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{{\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@rgb}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@rgb% + \edef\pgf@psfuncs{\pgf@prevx\space \pgf@rgb\space \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@bounds{\pgf@bounds\space\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@encode{\pgf@encode\space0 1}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@rgb] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@rgb] /N 1 >> }% << + \edef\pgf@prevcolor{\pgf@rgb}% + \pgf@parserestrgb[}} + +\def\pgf@getrgbtuplewithmixin#1#2#3{% + \pgfutil@definecolor{pgfshadetemp}{rgb}{#1,#2,#3}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgfshadetemp}}% + \pgfutil@extractcolorspec{pgfshadetemp}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{rgb}{\pgf@rgbcolor}% + \expandafter\pgf@getrgb@@\pgf@rgbcolor!} +\def\pgf@getrgb@@#1,#2,#3!{% + \def\pgf@rgb{#1 #2 #3}% + \def\pgf@sys@rgb{{#1}{#2}{#3}}% +} + +\def\pgf@parsefirstcmyk[cmyk(#1)=(#2,#3,#4,#5)#6]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@start@pos{\the\pgf@x}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@doma{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getcmyktuplewithmixin{#2}{#3}{#4}{#5}% + \edef\pgf@sys@shading@start@cmyk{\pgf@sys@cmyk}% + \let\pgf@sys@prevcolor=\pgf@sys@shading@start@cmyk% + \let\pgf@sys@prevpos=\pgf@sys@shading@start@pos% + \edef\pgf@prevcolor{\pgf@cmyk}% + \edef\pgf@firstcolor{\pgf@cmyk}} +\def\pgf@parselastdomcmyk[cmyk(#1)=(#2,#3,#4,#5); {% + \pgfutil@ifnextchar]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@end@pos{\the\pgf@x}% + \pgf@max=\pgf@x\relax% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@domb{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getcmyktuplewithmixin{#2}{#3}{#4}{#5}% + \edef\pgf@sys@shading@end@cmyk{\pgf@sys@cmyk}% + \pgfutil@gobble}{\pgf@parselastdomcmyk[}} +\def\pgf@parsemidcmyk[cmyk(#1)=(#2,#3,#4,#5); {\pgf@parserestcmyk[} +\def\pgf@parserestcmyk[cmyk(#1)=(#2,#3,#4,#5); {% + \advance\pgf@sys@shading@range@num by1\relax% + \pgfutil@ifnextchar]{% + \pgf@getcmyktuplewithmixin{#2}{#3}{#4}{#5}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@cmyk] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@cmyk] /N 1 >> }% << + \edef\pgf@psfuncs{\pgf@prevx\space + \pgf@cmyk\space \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{% + {\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@cmyk}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@cmyk% + \pgfutil@gobble}{% + \pgfmathsetlength\pgf@x{#1}% + \pgf@getcmyktuplewithmixin{#2}{#3}{#4}{#5}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{% + {\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@cmyk}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@cmyk% + \edef\pgf@psfuncs{\pgf@prevx\space \pgf@cmyk\space + \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@bounds{\pgf@bounds\space\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@encode{\pgf@encode\space0 1}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@cmyk] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@cmyk] /N 1 >> }% << + \edef\pgf@prevcolor{\pgf@cmyk}% + \pgf@parserestcmyk[}} + +\def\pgf@getcmyktuplewithmixin#1#2#3#4{% + \pgfutil@definecolor{pgfshadetemp}{cmyk}{#1,#2,#3,#4}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgfshadetemp}}% + \pgfutil@extractcolorspec{pgfshadetemp}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{cmyk}{\pgf@cmykcolor}% + \expandafter\pgf@getcmyk@@\pgf@cmykcolor!} +\def\pgf@getcmyk@@#1,#2,#3,#4!{% + \def\pgf@cmyk{#1 #2 #3 #4}% + \def\pgf@sys@cmyk{{#1}{#2}{#3}{#4}}% +} + +\def\pgf@parsefirstgray[gray(#1)=(#2)#3]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@start@pos{\the\pgf@x}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@doma{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getgraytuplewithmixin{#2}% + \edef\pgf@sys@shading@start@gray{\pgf@sys@gray}% + \let\pgf@sys@prevcolor=\pgf@sys@shading@start@gray% + \let\pgf@sys@prevpos=\pgf@sys@shading@start@pos% + \edef\pgf@prevcolor{\pgf@gray}% + \edef\pgf@firstcolor{\pgf@gray}} +\def\pgf@parselastdomgray[gray(#1)=(#2); {% + \pgfutil@ifnextchar]{% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@end@pos{\the\pgf@x}% + \pgf@max=\pgf@x\relax% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@domb{\pgf@sys@tonumber{\pgf@x}}% + \pgf@getgraytuplewithmixin{#2}% + \edef\pgf@sys@shading@end@gray{\pgf@sys@gray}% + \pgfutil@gobble}{\pgf@parselastdomgray[}} +\def\pgf@parsemidgray[gray(#1)=(#2); {\pgf@parserestgray[} +\def\pgf@parserestgray[gray(#1)=(#2); {% + \advance\pgf@sys@shading@range@num by1\relax% + \pgfutil@ifnextchar]{% + \pgf@getgraytuplewithmixin{#2}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@gray] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@gray] /N 1 >> }% << + \edef\pgf@psfuncs{\pgf@prevx\space \pgf@gray\space + \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgfmathsetlength\pgf@x{#1}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{% + {\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@gray}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@gray% + \pgfutil@gobble}{% + \pgfmathsetlength\pgf@x{#1}% + \pgf@getgraytuplewithmixin{#2}% + \edef\pgf@sys@shading@ranges{\pgf@sys@shading@ranges{% + {\pgf@sys@prevpos}{\the\pgf@x}{\pgf@sys@prevcolor}{\pgf@sys@gray}}}% + \edef\pgf@sys@prevpos{\the\pgf@x}% + \let\pgf@sys@prevcolor=\pgf@sys@gray% + \edef\pgf@psfuncs{\pgf@prevx\space \pgf@gray\space + \pgf@prevcolor\space pgfshade \pgf@psfuncs}% + \pgf@sys@bp@correct\pgf@x% + \edef\pgf@prevx{\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@bounds{\pgf@bounds\space\pgf@sys@tonumber{\pgf@x}}% + \edef\pgf@encode{\pgf@encode\space0 1}% + \edef\pgf@singlefunc{\space% + << /FunctionType 2 /Domain [0 1] /C0 + [\pgf@prevcolor] /C1 [\pgf@gray] /N 1 >> }% << + \edef\pgf@funcs{\pgf@funcs\space% + << /FunctionType 2 /Domain [\pgf@doma\space\pgf@domb] /C0 + [\pgf@prevcolor] /C1 [\pgf@gray] /N 1 >> }% << + \edef\pgf@prevcolor{\pgf@gray}% + \pgf@parserestgray[}} + +\def\pgf@getgraytuplewithmixin#1{% + \pgfutil@definecolor{pgfshadetemp}{gray}{#1}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgfshadetemp}}% + \pgfutil@extractcolorspec{pgfshadetemp}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{gray}{\pgf@graycolor}% + \expandafter\pgf@getgray@@\pgf@graycolor!} +\def\pgf@getgray@@#1!{% + \def\pgf@gray{#1}% + \def\pgf@sys@gray{{#1}}% +} + +% Normalized a argument for shadings into a +% series of color specifications in the current xcolor color model and write +% the result into \pgf@conv. +% +% Example: +% \pgf@convertstring{rgb(0cm)=(1,0,0); rgb(2cm)=(0,1,0); cmyk(4cm)=(1,0,0,0); gray(1cm)=(3); color(2cm)=(green); } +% -> +% \pgf@conv = macro:->'rgb(0cm)=(1,0,0); rgb(2cm)=(0,1,0); rgb(4cm)=(0,1,1); rgb(1cm)=(3,3,3); rgb(2cm)=(0,1,0); ' +\def\pgf@convertstring#1{% + \def\pgf@conv{}% + \pgf@convert#1]% + } +\def\pgf@convert{% + \pgfutil@ifnextchar]{\pgfutil@gobble}%done! + {% + \pgfutil@ifnextchar;{\pgf@grabsemicolor}% + {% + \pgfutil@ifnextchar c{\pgf@gobblec}% + {% + \pgfutil@ifnextchar g{\pgf@grabgray}% + {% + \pgfutil@ifnextchar o{\pgf@grabcolor}% + {% + \pgfutil@ifnextchar m{\pgf@grabcmyk}% + {% + \pgfutil@ifnextchar r{\pgf@grabrgb}% + {\pgferror{Illformed shading + specification}\pgf@convert}% + }% + }% + }% + }% + }% + }% +} +\def\pgf@savecolor#1{% + \pgfutil@extractcolorspec{pgf@tempcol}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor + {\pgf@shading@model}{\pgf@color}% + \expandafter\pgf@convget@\expandafter{\pgf@color}{#1}% +} +\def\pgf@grabsemicolor;{% + \edef\pgf@conv{\pgf@conv; }\pgf@convert} +\def\pgf@gobblec c{\pgf@convert} +\def\pgf@grabrgb rgb(#1)=(#2,#3,#4){% + \pgfutil@definecolor{pgf@tempcol}{rgb}{#2,#3,#4}% + \pgf@savecolor{#1}% +} +\def\pgf@grabcmyk myk(#1)=(#2,#3,#4,#5){% + \pgfutil@definecolor{pgf@tempcol}{cmyk}{#2,#3,#4,#5}% + \pgf@savecolor{#1}% +} +\def\pgf@grabgray gray(#1)=(#2){% + \pgfutil@definecolor{pgf@tempcol}{gray}{#2}% + \pgf@savecolor{#1}% +} +\def\pgf@grabcolor olor(#1)=(#2){% + \pgfutil@colorlet{pgf@tempcol}{#2}% + \pgf@savecolor{#1}% +} +\def\pgf@convget@#1#2{% + \edef\pgf@conv{\pgf@conv \pgf@shading@model(#2)=(#1)}\pgf@convert} + + +\newcount\pgf@shadingcount +\pgf@shadingcount=0 +{ + \catcode`\/=0 + \catcode`\\=12 + /gdef/pgf@shadingnum{\/the/pgf@shadingcount\} +} + +% Set up shading properties based on the current xcolor color model. This is +% called when shadings are declared and used. \ifpgfshadingmodelrgb, +% \ifpgfshadingmodelcmyk, and \ifpgfshadingmodelgray are set so that the type +% 4 function in functional shadings can be converted to the current color +% model. See \pgffuncshading*to* macros. + +\newif\ifpgfshadingmodelrgb +\newif\ifpgfshadingmodelcmyk +\newif\ifpgfshadingmodelgray +\def\pgf@setup@shading@model{% + \pgfshadingmodelrgbtrue + \pgfshadingmodelcmykfalse + \pgfshadingmodelgrayfalse + \XC@sdef\pgf@mod@test{\XC@tgt@mod{natural}}% + \def\pgf@shading@device{/DeviceRGB}% + \def\pgf@shading@ps@device{setrgbcolor}% + \def\pgf@shading@functional@range{0 1 0 1 0 1}% + \def\pgf@shading@model{rgb}% + \ifx\pgf@mod@test\XC@mod@cmyk + \def\pgf@shading@device{/DeviceCMYK}% + \def\pgf@shading@ps@device{setcmykcolor}% + \def\pgf@shading@functional@range{0 1 0 1 0 1 0 1}% + \def\pgf@shading@model{cmyk}% + \pgfshadingmodelrgbfalse + \pgfshadingmodelcmyktrue + \fi + \ifx\pgf@mod@test\XC@mod@gray + \def\pgf@shading@device{/DeviceGray}% + \def\pgf@shading@ps@device{setgray}% + \def\pgf@shading@functional@range{0 1}% + \def\pgf@shading@model{gray}% + \pgfshadingmodelrgbfalse + \pgfshadingmodelgraytrue + \fi + \edef\pgf@sys@driver@dvisvgm{pgfsys-dvisvgm.def}% + \ifx\pgfsysdriver\pgf@sys@driver@dvisvgm + \def\pgf@shading@model{rgb}% + \fi + \edef\pgf@sys@driver@texforht{pgfsys-tex4ht.def}% + \ifx\pgfsysdriver\pgf@sys@driver@texforht + \def\pgf@shading@model{rgb}% + \fi +} + + +% Declares a horizontal shading for later use. The shading is a +% horizontal bar that changes its color. +% +% #1 = optional dependencies +% #2 = name of the shading for later use +% #3 = height of the shading +% #4 = color specification in the following format: A list of colors +% that the bar should have at certain points. If the bar should +% be red at 1cm, this is specified as +% "rgb(1cm)=(1,0,0)". Multiple specifications are separated by a +% semicolon and a space. At least two specifications must be +% given. The specified positions must be given in increasing +% order. +% +% Description: +% +% The optional dependencies have the following effect: If present, it +% should consist of a list of colors, separated by commas. Each time +% the shading is used, these colors will be reevaluated. It will be +% checked whether the colors still have their "original meaning". If +% the colors have changed, a new shading will be created internally to +% reflect the changed color's values. +% +% Example: +% +% \pgfdeclarehorizontalshading{redtogreentoblue}{1cm}{% +% rgb(0cm)=(1,0,0); % red +% rgb(1cm)=(0,1,0); % green +% rgb(2cm)=(0,0,1)} +% +% \begin{document} +% The following bar is 2cm long: \pgfuseshading{redtogreentoblue}. +% \end{document} + +\def\pgfdeclarehorizontalshading{% + \pgf@setup@shading@model + \pgfutil@ifnextchar[% + \pgf@declarehorizontalshading{\pgf@declarehorizontalshading[]}} +\def\pgf@declarehorizontalshading[#1]#2#3#4{% + \expandafter\def\csname pgf@deps@pgfshading#2!\endcsname{#1}% + \expandafter\ifx\csname pgf@deps@pgfshading#2!\endcsname\pgfutil@empty% + \global\expandafter\let\csname pgf@num@pgfshading#2!\endcsname\pgfutil@empty + \pgfsys@horishading{#2}{#3}{#4}% + \else% + \global\advance\pgf@shadingcount 1\relax + \global\expandafter\edef\csname pgf@num@pgfshading#2!\endcsname{\pgf@shadingnum}% + \expandafter\def\csname pgf@func@pgfshading#2!\endcsname{\pgfsys@horishading}% + \expandafter\def\csname pgf@args@pgfshading#2!\endcsname{{#3}{#4}}% + \expandafter\let\csname @pgfshading#2!\endcsname=\pgfutil@empty% + \fi} + + +% Declares a vertical shading for later use. +% +% #1 = optional dependencies +% #2 = name of the shading for later use +% #3 = height of the shading +% #4 = color specification +% +% Example: +% +% \pgfdeclareverticalshading{redtogreentoblue}{1cm}{% +% rgb(0cm)=(1,0,0); % red +% rgb(1cm)=(0,1,0); % green +% rgb(2cm)=(0,0,1)} +% +% \begin{document} +% The following bar is 2cm high: \pgfuseshading{redtogreentoblue}. +% \end{document} + +\def\pgfdeclareverticalshading{% + \pgf@setup@shading@model + \pgfutil@ifnextchar[% + \pgf@declareverticalshading{\pgf@declareverticalshading[]}} +\def\pgf@declareverticalshading[#1]#2#3#4{% + \expandafter\def\csname pgf@deps@pgfshading#2!\endcsname{#1}% + \expandafter\ifx\csname pgf@deps@pgfshading#2!\endcsname\pgfutil@empty% + \global\expandafter\let\csname pgf@num@pgfshading#2!\endcsname=\pgfutil@empty + \pgfsys@vertshading{#2}{#3}{#4}% + \else% + \global\advance\pgf@shadingcount 1\relax + \global\expandafter\edef\csname pgf@num@pgfshading#2!\endcsname{\pgf@shadingnum}% + \expandafter\def\csname pgf@func@pgfshading#2!\endcsname{\pgfsys@vertshading}% + \expandafter\def\csname pgf@args@pgfshading#2!\endcsname{{#3}{#4}}% + \expandafter\let\csname @pgfshading#2!\endcsname=\pgfutil@empty% + \fi} + + +% Declares a radial shading for later use. +% +% #1 = optional dependencies +% #2 = name of the shading for later use +% #3 = center of inner circle +% #4 = color specification +% +% Description: +% +% A radial shading creates a smooth color transition between two +% circles. The center of the inner circle is at the give position. Its +% radius is the start of the color specification. The +% center of the outer circle is at the center of the whole shading, +% whose radius is the end of the color specification. For example, +% suppose the color specification is "rgb(1cm)=(1,1,1); rgb(2cm)=(0,0,0)". +% Then the shading would be 4cm times 4cm large. The inner circle would +% have diameter 1cm and the outer circle would have diameter 2cm. The +% outer circle would be centered in the middle of the shading, whereas +% the outer circle would be centered at the given position. +% +% Example: +% +% \pgfdeclareradialshading{redtogreentoblue}{\pgfpoint{2cm}{2cm}}{% +% rgb(10pt)=(1,0,0); % red +% rgb(2cm)=(0,1,0); % green +% rgb(3cm)=(0,0,1)} +% +% \begin{document} +% The following ball has diameter 3cm: \pgfuseshading{redtogreentoblue}. +% \end{document} + +\def\pgfdeclareradialshading{% + \pgf@setup@shading@model + \pgfutil@ifnextchar[% + \pgf@declareradialshading{\pgf@declareradialshading[]}} +\def\pgf@declareradialshading[#1]#2#3#4{% + \expandafter\def\csname pgf@deps@pgfshading#2!\endcsname{#1}% + \expandafter\ifx\csname pgf@deps@pgfshading#2!\endcsname\pgfutil@empty% + \global\expandafter\let\csname pgf@num@pgfshading#2!\endcsname=\pgfutil@empty + \pgfsys@radialshading{#2}{#3}{#4}% + \else% + \global\advance\pgf@shadingcount 1\relax + \global\expandafter\edef\csname pgf@num@pgfshading#2!\endcsname{\pgf@shadingnum}% + \expandafter\def\csname pgf@func@pgfshading#2!\endcsname{\pgfsys@radialshading}% + \expandafter\def\csname pgf@args@pgfshading#2!\endcsname{{#3}{#4}}% + \expandafter\let\csname @pgfshading#2!\endcsname=\pgfutil@empty% + \fi} + + + + +% Declares a functional shading for later use. +% +% #1 = optional dependencies +% #2 = name of the shading for later use +% #3 = lower left corner of the shading as a pgfpoint. +% #4 = upper right corner of the shading as a pgfpoint. +% #5 = Preparation code +% #6 = a PDF type 4 function (restricted Postscript function), see the +% PDF-specification 1.7, section 3.9.4 +% +% Description: +% +% This command creates a so-called functional shading. For such a +% shading the color of each point is calculated by calling a function +% for each point that gets the coordinates as input and yields the +% color as an output. Note that the function is evaluated by the +% *renderer*, not by PGF or TeX or someone else at compile-time. This +% means that the evaluation of this function has to be done *extremely +% quickly* and the function should be *very simple*. For this reason, +% only a very restricted set of operations are possible in the +% function (see 3.9.4 of the PDF-spec 1.7). Also functions should be +% kept small. Any errors in the function will only be noticed by the +% renderer. +% +% The function gets the coordinates of a point as input (as bp). This +% input consists of the top two elements of an otherwise empty +% (virtual, PostScript) stack. The function should then replace these +% two values by one value representing the gray color of the point for a +% grayscale shading, three values, representing the red, green, and blue color +% of the point for an RGB shading, or four values, representing the cyan, +% magenta, yellow, and black color of the point for a CMYK shading. The +% numbers should be real values, not integers since Apple's PDF renderer is +% broken in this regard (use cvr at the end if necessary). +% +% Conceptually, the function will be evaluated once for each point of +% the rectangle (#3) to (#4). A renderer may choose to evaluate the +% function at less points, but, in principle, the function will be +% evaluated for each pixel independently. +% +% Because of the rather difficult PostScript syntax, use this macro +% only *if you know what you are doing* (or if you are adventurous, of +% course). +% +% As for other shadings, the optional dependencies argument is used to +% determine whether a shading needs to be recalculated when a color +% has changed. +% +% The code #5 is executed each time a shading is +% (re)calculated. Typically, it will contain code to extract +% coordinates from colors (see below). +% +% Inside the PostScript function #6 you cannot use colors +% directly. Rather, you must push the color components on the +% stack. For this, it is useful to call \pgfshadecolortorgb, +% \pgfshadecolortocmyk, or \pgfshadecolortogray in the startup +% code #4. The macro takes a color name as input and stores the color's +% component real numbers between 0.0 and 1.0 separated +% by spaces (which is exactly what you need if you want to push it on +% a stack) in a macro. +% +% Example: +% +%\pgfdeclarefunctionalshading{twospots}{\pgfpointorigin}{\pgfpoint{200bp}{200bp}}{}{ +% 2 copy +% 90 sub dup mul exch +% 80 sub dup mul add sqrt +% dup mul neg 1.0005 exch exp 1.0 exch sub +% 3 1 roll +% 120 sub dup mul exch +% 100 sub dup mul add sqrt +% dup mul neg 1.002 exch exp 1.0 exch sub +% 1.0 +%} +% +% \pgfdeclarefunctionalshading[mycol]{sweep}{\pgfpointorigin}{\pgfpoint{100bp}{100bp}} +% {\pgfshadecolortorgb{mycol}{\myrgb}}{ +% add 150 div % not very useful... +% dup +% \myrgb % push mycol +% 5 4 roll % multiply all components by calculated value +% mul +% 3 1 roll +% 3 index +% mul +% 3 1 roll +% 4 3 roll +% mul +% 3 1 roll +% } +% +% \begin{document} +% Have a look at this: \pgfuseshading{twospots}. +% Here is \colorlet{mycol}{green!50}\pgfuseshading{sweep} in green +% and in \colorlet{mycol}{red!50!blue}\pgfuseshading{sweep} in red/blue. +% \end{document} + +\def\pgfdeclarefunctionalshading{% + \pgf@setup@shading@model + \pgfutil@ifnextchar[% + \pgf@declarefunctionalshading{\pgf@declarefunctionalshading[]}} +\def\pgf@declarefunctionalshading[#1]#2#3#4#5#6{% + \expandafter\def\csname pgf@deps@pgfshading#2!\endcsname{#1}% + \expandafter\ifx\csname pgf@deps@pgfshading#2!\endcsname\pgfutil@empty% + \global\expandafter\let\csname pgf@num@pgfshading#2!\endcsname=\pgfutil@empty + \pgfshade@functionaldo{#2}{#3}{#4}{#5}{#6}% + \else% + \global\advance\pgf@shadingcount 1\relax + \global\expandafter\edef\csname pgf@num@pgfshading#2!\endcsname{\pgf@shadingnum}% + \expandafter\def\csname pgf@func@pgfshading#2!\endcsname{\pgfshade@functionaldo}% + \expandafter\def\csname pgf@args@pgfshading#2!\endcsname{{#3}{#4}{#5}{#6}}% + \expandafter\let\csname @pgfshading#2!\endcsname=\pgfutil@empty% + \fi} +\def\pgfshade@functionaldo#1#2#3#4#5{% + \begingroup + #4% + \pgfsys@functionalshading{#1}{#2}{#3}{#5}% + \expandafter\pgfmath@smuggleone\csname @pgfshading#1!\endcsname + \endgroup +} + +\def\pgfshadecolortorgb#1#2{% + \pgfutil@colorlet{pgf@tempcol}{#1}% + \pgfutil@extractcolorspec{pgf@tempcol}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{rgb}{\pgf@rgbcolor}% + \expandafter\pgfshading@rgb\pgf@rgbcolor\relax% + \edef#2{\pgf@sys@tonumber{\pgf@xa}\space\pgf@sys@tonumber{\pgf@xb}\space\pgf@sys@tonumber{\pgf@xc}\space}% + \c@pgf@counta\escapechar% + \escapechar-1\relax% + \expandafter\edef\csname\string#2red\endcsname{\pgf@sys@tonumber{\pgf@xa}\space}% + \expandafter\edef\csname\string#2green\endcsname{\pgf@sys@tonumber{\pgf@xb}\space}% + \expandafter\edef\csname\string#2blue\endcsname{\pgf@sys@tonumber{\pgf@xc}\space}% + \escapechar\c@pgf@counta% +} +\def\pgfshading@rgb#1,#2,#3\relax{% + \pgf@xa=#1pt% + \pgf@xb=#2pt% + \pgf@xc=#3pt% +} + +\def\pgfshadecolortocmyk#1#2{% + \pgfutil@colorlet{pgf@tempcol}{#1}% + \pgfutil@extractcolorspec{pgf@tempcol}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{cmyk}{\pgf@cmykcolor}% + \expandafter\pgfshading@cmyk\pgf@cmykcolor\relax% + \edef#2{\pgf@sys@tonumber{\pgf@xa}\space\pgf@sys@tonumber{\pgf@xb}\space + \pgf@sys@tonumber{\pgf@xc}\space\pgf@sys@tonumber{\pgf@xd}\space}% + \c@pgf@counta\escapechar% + \escapechar-1\relax% + \expandafter\edef\csname\string#2cyan\endcsname{% + \pgf@sys@tonumber{\pgf@xa}\space}% + \expandafter\edef\csname\string#2magenta\endcsname{% + \pgf@sys@tonumber{\pgf@xb}\space}% + \expandafter\edef\csname\string#2yellow\endcsname{% + \pgf@sys@tonumber{\pgf@xc}\space}% + \expandafter\edef\csname\string#2black\endcsname{% + \pgf@sys@tonumber{\pgf@xd}\space}% + \escapechar\c@pgf@counta +} +\def\pgfshading@cmyk#1,#2,#3,#4\relax{% + \pgf@xa=#1pt% + \pgf@xb=#2pt% + \pgf@xc=#3pt% + \pgf@xd=#4pt% +} + +\def\pgfshadecolortogray#1#2{% + \pgfutil@colorlet{pgf@tempcol}{#1}% + \pgfutil@extractcolorspec{pgf@tempcol}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{gray}{\pgf@graycolor}% + \expandafter\pgfshading@gray\pgf@graycolor\relax + \edef#2{\pgf@sys@tonumber{\pgf@xa}\space}% + \c@pgf@counta\escapechar + \escapechar-1\relax + \expandafter\edef\csname\string#2gray\endcsname{% + \pgf@sys@tonumber{\pgf@xa}\space}% + \escapechar\c@pgf@counta +} +\def\pgfshading@gray#1\relax{% + \pgf@xa=#1pt% +} + +% Functions to convert between color models in the type 4 PostScript data of +% functional shadings. + +\def\pgffuncshadingrgbtocmyk{% + 1.0 exch sub 3 1 roll + 1.0 exch sub 3 1 roll + 1.0 exch sub 3 1 roll + 3 copy + 2 copy gt { exch } if pop + 2 copy gt { exch } if pop + dup 3 1 roll sub + 0.0 2 copy lt { exch } if pop + 1.0 2 copy gt { exch } if pop + 4 1 roll + dup 3 1 roll sub + 0.0 2 copy lt { exch } if pop + 1.0 2 copy gt { exch } if pop + 4 1 roll + dup 3 1 roll sub + 0.0 2 copy lt { exch } if pop + 1.0 2 copy gt { exch } if pop + 4 1 roll +} + +\def\pgffuncshadingrgbtogray{% + 0.11 mul exch 0.59 mul add exch 0.3 mul add +} + +\def\pgffuncshadingcmyktorgb{% + % covert to CMY + dup 3 1 roll add + 1.0 2 copy gt { exch } if pop + 4 1 roll + dup 3 1 roll add + 1.0 2 copy gt { exch } if pop + 4 1 roll + add + 1.0 2 copy gt { exch } if pop + 3 1 roll + % covert to RGB + 1.0 exch sub + 3 1 roll + 1.0 exch sub + 3 1 roll + 1.0 exch sub + 3 1 roll +} + +\def\pgffuncshadingcmyktogray{% + exch 0.11 mul add exch 0.59 mul add exch 0.3 mul add + 1.0 2 copy gt { exch } if pop + 1.0 exch sub +} + +\def\pgffuncshadinggraytorgb{% + dup dup +} + +\def\pgffuncshadinggraytocmyk{% + 0.0 0.0 0.0 + 4 3 roll +} + +% Inserts a box into the text that contains a previously defined +% shading. +% +% #1 = Name of a shading +% +% Example: +% +% \pgfuseshading{redtogreentoblue} + +\def\pgfuseshading#1{% + \edef\pgf@shadingname{@pgfshading#1}% + \pgf@tryextensions{\pgf@shadingname}{\pgfalternateextension}% + \expandafter\pgfutil@ifundefined\expandafter{\pgf@shadingname}% + {\pgferror{Undefined shading "#1"}}% + {% + \edef\pgf@shade@adds{\csname pgf@num\pgf@shadingname\endcsname}% + \pgfutil@ifundefined{pgf@deps\pgf@shadingname}% + {}% + {% + \pgf@setup@shading@model + \begingroup + \pgfutil@globalcolorsfalse + \edef\@list{\csname pgf@deps\pgf@shadingname\endcsname}% + \pgfutil@for\@temp:=\@list\do{% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{\@temp}}% + \pgfutil@extractcolorspec{\@temp}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{\pgf@shading@model}{\pgf@color}% + \edef\pgf@shade@adds{\pgf@shade@adds,\pgf@color}% + }% + \pgfmath@smuggleone\pgf@shade@adds + \endgroup + }% + \expandafter\pgf@strip@shadename\pgf@shadingname!!% + \edef\pgf@shadingxname{@pgfshading\pgf@basename\pgf@shade@adds!}% + \pgfutil@ifundefined{\pgf@shadingxname}% + {% + \begingroup + \edef\@temp{\expandafter\noexpand\csname pgf@func\pgf@shadingname\endcsname}% + \edef\@args{{\pgf@basename\pgf@shade@adds}}% + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter\@@args + \expandafter\expandafter\expandafter{\csname pgf@args\pgf@shadingname\endcsname}% + \expandafter\expandafter\expandafter\@temp\expandafter\@args\@@args + \expandafter\pgfmath@smuggleone\csname\pgf@shadingxname\endcsname + \endgroup + }% + {}% + \pgf@invokeshading{\csname\pgf@shadingxname\endcsname}% + }% +} + +\def\pgf@strip@shadename @pgfshading#1!!!{\def\pgf@basename{#1}} + +\def\pgf@invokeshading#1{% + \ifpgfpicture% + \pgfsys@shadinginsidepgfpicture{#1}% + \else% + \pgfsys@shadingoutsidepgfpicture{#1}% + \fi% +} + + +% Create an alias name for a shading +% +% #1 = name of the alias +% #2 = name of the original +% +% Example: +% +% \pgfaliasshading{shading!25}{shadingshaded} + +\def\pgfaliasshading#1#2{% + \expandafter\let\expandafter\pgf@temp\expandafter=\csname @pgfshading#2!\endcsname% + \expandafter\let\csname @pgfshading#1!\endcsname=\pgf@temp% + \expandafter\let\expandafter\pgf@temp\expandafter=\csname pgf@num@pgfshading#2!\endcsname% + \expandafter\let\csname pgf@num@pgfshading#1!\endcsname=\pgf@temp% + \expandafter\let\expandafter\pgf@temp\expandafter=\csname pgf@deps@pgfshading#2!\endcsname% + \expandafter\let\csname pgf@deps@pgfshading#1!\endcsname=\pgf@temp% + \expandafter\let\expandafter\pgf@temp\expandafter=\csname pgf@func@pgfshading#2!\endcsname% + \expandafter\let\csname pgf@func@pgfshading#1!\endcsname=\pgf@temp% + \expandafter\let\expandafter\pgf@temp\expandafter=\csname pgf@args@pgfshading#2!\endcsname% + \expandafter\let\csname pgf@args@pgfshading#1!\endcsname=\pgf@temp% +} + + + + +% Shades the current path, but does not discard it. +% +% #1 - a shading (see below) +% #2 - an angle +% +% Description: +% +% \pgfshadepath ``tries'' to fill the +% current path with a shading. The shading's original size should +% completely cover the area between (0,0) and (100bp,100bp). The +% shading will be rotated by #2 and then rescaled so that it +% completely covers the path. Then the path will be used (locally) for +% clipping and the shading is drawn. +% +% In addition to the rotation, any transformation set by the +%\pgfsetadditionalshadetransform will also be applied. +% +% After all this, the path can still be used for the normal +% stroking/clipping operations. +% +% The shading is rotated around its middle. If no rotation occurs, the +% lower left corner of the path will lie on (25bp, 25bp), the upper +% right corner on (75bp, 75bp). +% +% Example: +% +% \pgfdeclareverticalshading{myshading}{100bp}{color(0pt)=(red); color(100bp)=(green)} +% +% \pgfpathmoveto{\pgforigin} +% \pgfpathlineto{\pgfxy(1,0)} +% \pgfpathlineto{\pgfxy(1,1)} +% \pgfshadepath{myshading}{0} +% \pgfusepath{stroke} + +\def\pgfshadepath#1#2{% + \ifdim\pgf@pathminx=16000pt% + \pgfwarning{No path specified that can be filled}% + \else% + \begingroup% + % Calculate center: + \pgf@xb=.5\pgf@pathmaxx% + \advance\pgf@xb by.5\pgf@pathminx% + \pgf@yb=.5\pgf@pathmaxy% + \advance\pgf@yb by.5\pgf@pathminy% + % Calculate rotation: + \pgfmathparse{#2}% + \let\pgfshade@angle=\pgfmathresult + \pgfmathsin@\pgfshade@angle + \let\pgfshade@sin=\pgfmathresult + \pgfmathcos@\pgfshade@angle + \let\pgfshade@cos=\pgfmathresult + % width and height of the bounding box + \pgf@xa=\pgf@pathmaxx + \advance\pgf@xa by-\pgf@pathminx + \pgf@ya=\pgf@pathmaxy + \advance\pgf@ya by-\pgf@pathminy + % Calculate scaling: + % xscale = 1pt/50bp * (w*|cos(a)|+h*|sin(a)|)/(|cos(a)|+|sin(a)|) + % yscale = 1pt/50bp * (w*|sin(a)|+h*|cos(a)|)/(|cos(a)|+|sin(a)|) + % 1pt/50bp = .01992528 + \pgfmathabs@\pgfshade@sin + \let\pgfshade@abssin=\pgfmathresult + \pgfmathabs@\pgfshade@cos + \let\pgfshade@abscos=\pgfmathresult + \pgf@xc=\pgfshade@abscos\pgf@xa + \advance\pgf@xc by\pgfshade@abssin\pgf@ya + \pgf@yc=\pgfshade@abssin\pgf@xa + \advance\pgf@yc by\pgfshade@abscos\pgf@ya + \pgfmathadd@\pgfshade@abscos\pgfshade@abssin + \pgfmathdivide@{.01992528}{\pgfmathresult}% + \pgf@xc=\pgfmathresult\pgf@xc + \pgf@yc=\pgfmathresult\pgf@yc + \ifdim\pgf@xc<0.0001pt + \ifdim\pgf@xc>-0.0001pt + \pgf@no@shadetrue + \fi + \fi + \ifdim\pgf@yc<0.0001pt + \ifdim\pgf@yc>-0.0001pt + \pgf@no@shadetrue + \fi + \fi + \ifpgf@no@shade\else + \pgfsys@beginscope + \pgfsyssoftpath@invokecurrentpath + \pgfsys@clipnext + \pgfsys@discardpath + % Compute new transformation matrix: + % shift + \pgfsys@transformcm{1}{0}{0}{1}{\the\pgf@xb}{\the\pgf@yb}% + % rotation + \pgf@x=\pgfshade@sin pt% + \pgf@xa=-\pgf@x% + \pgfsys@transformcm{\pgfshade@cos}{\pgfshade@sin}{\pgf@sys@tonumber{\pgf@xa}}{\pgfshade@cos}{0pt}{0pt}% + % scaling + \pgfsys@transformcm{\pgf@sys@tonumber{\pgf@xc}}{0}{0}{\pgf@sys@tonumber{\pgf@yc}}{0pt}{0pt}% + % This will actually be the first transformation of the shading. + % Should it be applied first so that it becomes the last one? + \ifx\pgf@shade@extra@transform\pgfutil@empty% + \else% + \pgflowlevel{\pgf@shade@extra@transform}% + \fi% + \pgfuseshading{#1}% + \pgfsys@endscope% + \fi% + \endgroup% + \fi% +} + +\newif\ifpgf@no@shade + +% Additionally transform shade paths +% +% #1 = Transformation code that is used in addition to the normal +% shading transformation. +% +% Example: +% +% \pgfsetadditionalshadetransform{\pgftransformrotate{30}} + +\def\pgfsetadditionalshadetransform#1{\def\pgf@shade@extra@transform{#1}} +\let\pgf@shade@extra@transform=\pgfutil@empty + + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransformations.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransformations.code.tex new file mode 100644 index 0000000000..be252065c1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransformations.code.tex @@ -0,0 +1,819 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoretransformations.code.tex} + + +% Position transformations + +\newdimen\pgf@pt@x +\newdimen\pgf@pt@y + +\newdimen\pgf@pt@temp + +\newif\ifpgf@pt@identity +\pgf@pt@identitytrue + +\def\pgf@pt@aa{1.0} \def\pgf@pt@ab{0.0} +\def\pgf@pt@ba{0.0} \def\pgf@pt@bb{1.0} + + + +% Store the current transformation matrix in a macro. +% +% #1 = macro name +% +% Example: +% +% \pgfgettransform\mytransform + +\def\pgfgettransform#1{% + \edef#1{{\pgf@pt@aa}{\pgf@pt@ab}{\pgf@pt@ba}{\pgf@pt@bb}{\the\pgf@pt@x}{\the\pgf@pt@y}}% +} + +% Store the current transformation matrix in a set of macros, one for +% each single entry. +% +% #1-#4 are macro which store the matrix entries (0,0), (0,1), (1,0), +% (1,1) (in this order). It is the same order as for \pgftransformcm. +% +% #5 is a macro which will be filled with the x shift and +% #6 is a macro which will be filled with the y shift. +% +% Example: +% \pgfgettransformentries\aa\ab\ba\bb\shiftx\shifty +% +% -> +% +% \pgftransformcm\aa\ab\ba\bb{\pgfqpoint{\shiftx}{\shifty}} +% +% or +% +% \pgfsettransformentries\aa\ab\ba\bb\shiftx\shifty +\def\pgfgettransformentries#1#2#3#4#5#6{% + \edef#1{\pgf@pt@aa}% + \edef#2{\pgf@pt@ab}% attention: this is (1,0), i.e. the point which is usually labelled 'ba'! + \edef#3{\pgf@pt@ba}% attention: this is (0,1), i.e. the point which is usually labelled 'ab'! + \edef#4{\pgf@pt@bb}% + \edef#5{\the\pgf@pt@x}% + \edef#6{\the\pgf@pt@y}% +}% +\def\pgfsettransformentries#1#2#3#4#5#6{% + \pgfsettransform{{#1}{#2}{#3}{#4}{#5}{#6}}% +}% + +% Restore the current transformation matrix from a macro. +% +% #1 = macro name, previously used with \pgfgettransform +% +% Example: +% +% \pgfsettransform\mytransform + +\def\pgfsettransform#1{% + \edef\pgf@temp{#1}% + \expandafter\pgf@settransform\pgf@temp% +} +\def\pgf@settransform#1#2#3#4#5#6{% + \def\pgf@pt@aa{#1}% + \def\pgf@pt@ab{#2}% + \def\pgf@pt@ba{#3}% + \def\pgf@pt@bb{#4}% + \pgf@pt@x=#5% + \pgf@pt@y=#6% + \edef\pgf@idtest{#1,#2,#3,#4}% + \ifx\pgf@idtest\pgf@idmatrixtext% + \pgf@pt@identitytrue% + \else% + \pgf@pt@identityfalse% + \fi% +} + +\def\pgf@idmatrixtext{1.0,0.0,0.0,1.0} +\def\pgf@zerozerotext{0.0,0.0} +\def\pgf@one@text{1.0} +\def\pgf@zero@text{0.0} + +% Transformation command +% +% #1 = x dimension +% #2 = y dimension +% +% Description: +% +% Applies the pgfs transformation matrix to the point (#1,#2). The +% result is once more stored in the point. +% +% +% Example: +% +% \pgf@pos@transform{\pgf@x}{\pgf@y} + +\def\pgf@pos@transform#1#2{% + \ifpgf@pt@identity% + \else% + \pgf@pt@temp=#1% + #1=\pgf@pt@aa#1% + \advance#1 by\pgf@pt@ba#2% + #2=\pgf@pt@bb#2% + \advance#2 by\pgf@pt@ab\pgf@pt@temp% + \fi% + \advance#1 by\pgf@pt@x% + \advance#2 by\pgf@pt@y% +} +\def\pgf@pos@transform@glob{% + \ifpgf@pt@identity% + \else% + \pgf@pt@temp=\pgf@x% + \global\pgf@x=\pgf@pt@aa\pgf@x% + \global\advance\pgf@x by\pgf@pt@ba\pgf@y% + \global\pgf@y=\pgf@pt@bb\pgf@y% + \global\advance\pgf@y by\pgf@pt@ab\pgf@pt@temp% + \fi% + \global\advance\pgf@x by\pgf@pt@x% + \global\advance\pgf@y by\pgf@pt@y% +} + + +% Invert the current transformation matrix +% +% Description: +% +% This command replaces the current transformation matrix by its +% inverse. The inversion is not very exact if the matrix is nearly +% singular. +% +% Example: +% +% \pgftransforminvert + +\def\pgftransforminvert{% + % First, invert the shift. That's easy + \pgf@pt@x=-\pgf@pt@x + \pgf@pt@y=-\pgf@pt@y + \ifpgf@pt@identity% + \else% + % Sigh. Have to calculate the inverse of the matrix. + % Perhaps we are lucky and ba and bb are zero? + \edef\pgf@zerotest{\pgf@pt@ab,\pgf@pt@ba}% + \ifx\pgf@zerotest\pgf@zerozerotext% + % Ha! Just invert aa and bb + \pgfmathreciprocal@{\pgf@pt@aa}% + \let\pgf@pt@aa\pgfmathresult% + \pgfmathreciprocal@{\pgf@pt@bb}% + \let\pgf@pt@bb\pgfmathresult% + \else% + % Start with determinant + % Matrix = (aa ab + % ba bb) + {% + \pgfutil@tempdima=\pgf@pt@aa pt% + \pgfutil@tempdima=\pgf@pt@bb\pgfutil@tempdima% aa * bb + \pgfutil@tempdimb=\pgf@pt@ba pt% + \pgfutil@tempdimb=\pgf@pt@ab\pgfutil@tempdimb% ba * ab + \advance\pgfutil@tempdima by -\pgfutil@tempdimb% aa*bb - ba*ab + % Invert + \pgfmathreciprocal@{\pgf@sys@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdima=\pgfmathresult pt% + \pgf@x=\pgf@pt@bb\pgfutil@tempdima% bb/(det A) + \xdef\pgf@new@pt@aa{\pgf@sys@tonumber{\pgf@x}}% + \pgf@x=\pgf@pt@aa\pgfutil@tempdima% aa/(det A) + \xdef\pgf@new@pt@bb{\pgf@sys@tonumber{\pgf@x}}% + \pgfutil@tempdima=-\pgfutil@tempdima% + \pgf@x=\pgf@pt@ba\pgfutil@tempdima% -ba/(det A) + \xdef\pgf@new@pt@ba{\pgf@sys@tonumber{\pgf@x}}% + \pgf@x=\pgf@pt@ab\pgfutil@tempdima% -ab/(det A) + \xdef\pgf@new@pt@ab{\pgf@sys@tonumber{\pgf@x}}% + }% + \let\pgf@pt@aa\pgf@new@pt@aa% + \let\pgf@pt@ab\pgf@new@pt@ab% + \let\pgf@pt@ba\pgf@new@pt@ba% + \let\pgf@pt@bb\pgf@new@pt@bb% + \fi% + \pgf@pt@temp=\pgf@pt@x% + \pgf@pt@x=\pgf@pt@aa\pgf@pt@x% + \advance\pgf@pt@x by\pgf@pt@ba\pgf@pt@y% + \pgf@pt@y=\pgf@pt@bb\pgf@pt@y% + \advance\pgf@pt@y by\pgf@pt@ab\pgf@pt@temp% + \fi% +} + + + + +% PGF-Level concatenation of the transformation matrix with a given +% matrix. +% +% #1 - #5 = a concatenation matrix (see pdf spec). Entry #5 is a +% translation point. +% +% Description: +% +% All coordinates given to subsequent path construction commands will +% be transformed additionally by the given transformation matrix. If +% the command is followed by a 6th argument, the transformation is +% only applied to this argument. +% +% +% Example: +% +% \pgftransformcm{1}{0}{0}{1}{\pgfpoint{100pt}{0pt}} % 100pt to the right. +% +% \pgftransformcm{2}{0}{0}{2}{\pgfpointorigin} % double in size +% \pgfpathmoveto{\pgfpoint{0cm}{0cm}} +% \pgfpathlineto{\pgflineto{1cm}{1cm}} % actually 2cm/2cm + +\def\pgftransformcm#1#2#3#4#5{% + \edef\pgf@marshal{\noexpand\pgf@transformcm{#1}{#2}{#3}{#4}}% + \pgf@marshal{#5}% +} +\def\pgf@transformcm#1#2#3#4#5{% + {% + \pgf@process{#5}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % + \pgfmathsetlength\pgf@x{#1}% + \pgfmathsetlength\pgf@y{#2}% + % + \pgf@xa=\pgf@pt@aa\pgf@x% + \advance\pgf@xa by \pgf@pt@ba\pgf@y% + % + \pgf@ya=\pgf@pt@ab\pgf@x% + \advance\pgf@ya by \pgf@pt@bb\pgf@y% + % + \pgfmathsetlength\pgf@x{#3}% + \pgfmathsetlength\pgf@y{#4}% + % + \pgf@xb=\pgf@pt@aa\pgf@x% + \advance\pgf@xb by \pgf@pt@ba\pgf@y% + % + \pgf@yb=\pgf@pt@ab\pgf@x% + \advance\pgf@yb by \pgf@pt@bb\pgf@y% + % + \pgf@x=\pgf@pt@aa\pgf@xc% + \advance\pgf@x by\pgf@pt@ba\pgf@yc% + \advance\pgf@x by\pgf@pt@x% + % + \pgf@y=\pgf@pt@ab\pgf@xc% + \advance\pgf@y by\pgf@pt@bb\pgf@yc% + \advance\pgf@y by\pgf@pt@y% + % + \global\pgf@x=\pgf@x% + \global\pgf@y=\pgf@y% + \xdef\pgf@tempaa{\pgf@sys@tonumber{\pgf@xa}}% + \xdef\pgf@tempab{\pgf@sys@tonumber{\pgf@ya}}% + \xdef\pgf@tempba{\pgf@sys@tonumber{\pgf@xb}}% + \xdef\pgf@tempbb{\pgf@sys@tonumber{\pgf@yb}}% + }% + \pgf@pt@x=\pgf@x% + \pgf@pt@y=\pgf@y% + \let\pgf@pt@aa=\pgf@tempaa% + \let\pgf@pt@ba=\pgf@tempba% + \let\pgf@pt@ab=\pgf@tempab% + \let\pgf@pt@bb=\pgf@tempbb% + \edef\pgf@idtest{\pgf@pt@aa,\pgf@pt@ba,\pgf@pt@ab,\pgf@pt@bb}% + \ifx\pgf@idtest\pgf@idmatrixtext% + \pgf@pt@identitytrue% + \else% + \pgf@pt@identityfalse% + \fi% +} + + + +% Transformation into a given triangle. The three corners of the +% triangle are called "origin", "x" and "y" are given. After this +% transformation has been applied, the canvas origin is at "origin", +% the vector (1pt,0pt) lies at "x" and the vector (0pt,1pt) lies at +% "y". +% +% #1 = origin +% #2 = x +% #3 = y +% +% Example: +% +% \pgftransformtriangle{\pgfpointorigin}{\pgfpoint{1cm}{1cm}}{\pgfpoint{-1cm}{1cm}} + +\def\pgftransformtriangle#1#2#3{% + \pgf@process{#2}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#3}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{#1}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber\pgf@xa}{\pgf@sys@tonumber\pgf@ya}% + {\pgf@sys@tonumber\pgf@xb}{\pgf@sys@tonumber\pgf@yb}% + {\pgfpoint{\pgf@x}{\pgf@y}}% +} + + + +% Undo all transformations +% +% Example: +% +% \pgftansformreset + +\def\pgftransformreset{% + \pgf@pt@x=0pt% + \pgf@pt@y=0pt% + \let\pgf@pt@aa\pgf@one@text% + \let\pgf@pt@ba\pgf@zero@text% + \let\pgf@pt@ab\pgf@zero@text% + \let\pgf@pt@bb\pgf@one@text% + \pgf@pt@identitytrue% +} + + +% Undo all slanting/rotation, but not translations +% +% Example: +% +% \pgftransformresetnontranslations + +\def\pgftransformresetnontranslations{% + \let\pgf@pt@aa\pgf@one@text% + \let\pgf@pt@ba\pgf@zero@text% + \let\pgf@pt@ab\pgf@zero@text% + \let\pgf@pt@bb\pgf@one@text% + \pgf@pt@identitytrue% +} + + + + +% Shifting command and environment +% +% #1 = vector by which all subsequent points should be moved. +% +% Example: +% +% \pgftansformshift{\pgfpoint{1cm}{1cm}} + +\def\pgftransformshift#1{\pgftransformcm{1}{0}{0}{1}{#1}} +\def\pgftransformxshift#1{\pgftransformcm{1}{0}{0}{1}{\pgfpoint{#1}{+0pt}}} +\def\pgftransformyshift#1{\pgftransformcm{1}{0}{0}{1}{\pgfpoint{+0pt}{#1}}} + + + + +% Scaling commands +% +% #1 = scaling for all subsequent points. +% +% Example: +% +% \pgftransformscale{2} +% \pgftransformxscale{2} +% \pgftransformyscale{2} + +\def\pgftransformscale#1{\pgftransformcm{#1}{0}{0}{#1}{\pgfpointorigin}} +\def\pgftransformxscale#1{\pgftransformcm{#1}{0}{0}{1.0}{\pgfpointorigin}} +\def\pgftransformyscale#1{\pgftransformcm{1.0}{0}{0}{#1}{\pgfpointorigin}} + + + +% Slanting commands +% +% #1 = slanting in x-direction. 1 means 45 degrees. +% +% Example: +% +% \pgftransformxslant{2} +% \pgftransformyslant{2} + +\def\pgftransformxslant#1{\pgftransformcm{1.0}{0}{#1}{1.0}{\pgfpointorigin}} +\def\pgftransformyslant#1{\pgftransformcm{1.0}{#1}{0}{1.0}{\pgfpointorigin}} + + + +% Rotation commands +% +% #1 = degrees for the rotation +% +% Example: +% +% \pgftransformrotate{30} + +\def\pgftransformrotate#1{% + \pgfmathparse{#1}% + \let\pgftransform@angle=\pgfmathresult% + \pgfmathsin@{\pgftransform@angle}% + \let\pgftransform@sin=\pgfmathresult% + \pgfmathcos@{\pgftransform@angle}% + \let\pgftransform@cos=\pgfmathresult% + \pgf@x=\pgftransform@sin pt% + \pgf@xa=-\pgf@x% + \pgftransformcm{\pgftransform@cos}{\pgftransform@sin}{\pgf@sys@tonumber{\pgf@xa}}{\pgftransform@cos}{\pgfpointorigin}% +} + + + +% The following if's have the following effect: +% +% \ifpgfslopedattime decides whether the coordinate system of an +% xxxattime transformation command should be rotated such that text +% drawn on the line should be tangent to the line +% +% \ifpgfallowupsidedowattime decides whether the transformation should +% be done in such a way that the text is always ``upright,'' that is, +% text drawn in this coordinate system is never upside-down. +% +% \ifpgfresetnontranslationattime decides whether the coordinate +% system of an xxxattime transformation command should be reset +% (concerning the non-translations) before a possible rotation is +% applied. This is useful, for example, if the main coordinate system +% is scaled by, say, a factor of 2 and you do not want that to apply +% to the text, but you do want the rotation to apply. + +\newif\ifpgfslopedattime +\newif\ifpgfallowupsidedownattime +\newif\ifpgfresetnontranslationattime + + +% Transform to the coordinate system of a point on a line +% +% #1 = a time fraction of line where to put the label, where 0 means start, +% 1 means end, and for example 0.5 means the middle. +% #2 = start of line +% #3 = end of line +% +% Example: +% +% { +% \pgftransformlineattime{.5}{\pgfxy(0,0)}{\pgfxy(3,2)} +% \pgftext{Hi!} +% } +% +% { +% \pgftransformlineattime{.75}{\pgfxy(0,0)}{\pgfxy(3,2)} +% \pgftransformresetnontranslations +% \pgftext{Hi!} +% } +% +\def\pgftransformlineattime#1#2#3{% + \pgf@process{#2}% + \pgf@xb=\pgf@x% xb/yb = start point + \pgf@yb=\pgf@y% + \pgf@process{#3}% + \pgf@xc=\pgf@x% xc/yc = end point + \pgf@yc=\pgf@y% + \pgftransformshift{\pgfpointlineattime{#1}{\pgfqpoint{\pgf@xb}{\pgf@yb}}{\pgfqpoint{\pgf@xc}{\pgf@yc}}}% + \ifpgfresetnontranslationattime% + \pgftransformresetnontranslations% + \fi% + \ifpgfslopedattime% + \advance\pgf@xc by-\pgf@xb% + \advance\pgf@yc by-\pgf@yb% + \ifpgfallowupsidedownattime% + \else% + \ifdim\pgf@xc<0pt% + \pgf@xc=-\pgf@xc% + \pgf@yc=-\pgf@yc% + \fi% + \fi% + \pgf@x=\pgf@xc% + \pgf@y=\pgf@yc% + \pgfpointnormalised{}% x/y = normalised vector + \pgf@ya=-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfpointorigin}% + \fi% +} + + +% Transform to the coordinate system of a point on an arc +% +% #1 = a time fraction of line where to put the label, where 0 means start, +% 1 means end, and for example 0.5 means the middle. +% #2 = center of an ellipse +% #3 = 0-degree axis of the ellipse +% #4 = 90-degree axis of the ellipse +% #4 = start angle of the arc on this ellipse +% #5 = end angle of the arc on this ellipse +% +% Example: +% +% { +% \pgftransformlineattime{.5}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}{\pgfpoint{0cm}{1cm}}{30}{40} +% \pgftext{Hi!} +% } + +\def\pgftransformarcaxesattime#1#2#3#4#5#6{% + \pgfpointarcaxesattime{#1}{#2}{#3}{#4}{#5}{#6}% + \pgftransformshift{\pgfqpoint{\pgf@x}{\pgf@y}}% + \ifpgfresetnontranslationattime% + \pgftransformresetnontranslations% + \fi% + \ifpgfslopedattime% + \pgf@x=\pgf@xa% + \pgf@y=\pgf@ya% + \pgf@process{\pgfpointnormalised{}}% + \ifpgfallowupsidedownattime% + \else% + \ifdim\pgf@x<0pt% + \pgf@x=-\pgf@x% + \pgf@y=-\pgf@y% + \fi% + \fi% + \pgf@ya=-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfpointorigin}% + \fi% +} + + + + +% Transform to the coordinate system of a point on a curve +% +% #1 = a time fraction of line where to put the label, where 0 means start, +% 1 means end, and for example 0.5 means the middle. +% #2 = start of line +% #3 = first control +% #4 = second control +% #5 = end of line +% +% Example: +% +% { +% \pgftransformcurveattime{.5}{\pgfxy(0,0)}{\pgfxy(3,2)} +% \pgftext{Hi!} +% } +% +% { +% \pgftransformcurveattime{.75}{\pgfxy(0,0)}{\pgfxy(3,2)} +% \pgftransformresetnontranslations +% \pgftext{Hi!} +% } +% +\def\pgftransformcurveattime#1#2#3#4#5{% + \pgfpointcurveattime{#1}{#2}{#3}{#4}{#5}% + \pgftransformshift{\pgfqpoint{\pgf@x}{\pgf@y}}% + \ifpgfresetnontranslationattime% + \pgftransformresetnontranslations% + \fi% + \ifpgfslopedattime% + \pgf@x=\pgf@xa% + \pgf@y=\pgf@ya% + \advance\pgf@x by-\pgf@xb% + \advance\pgf@y by-\pgf@yb% + \ifpgfallowupsidedownattime% + \else% + \ifdim\pgf@x<0pt% + \pgf@x=-\pgf@x% + \pgf@y=-\pgf@y% + \fi% + \fi% + \pgfpointnormalised{}% x/y = normalised vector + \pgf@ya=-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfpointorigin}% + \fi% +} + + + + + +% Transform to the coordinate system of an arrow at the end of the +% line going from point #1 to point #2 with the correct rotation. +% +% #1 = a start point an (invisible) line +% #2 = an end point an (invisible) line +% +% Example: +% +% \pgftransformarrow{\pgfpointorigin}{\pgfpoint{1cm}{0cm}} + +\def\pgftransformarrow#1#2{% + \pgf@process{#2}% + \pgftransformshift{}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#1}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \pgf@x=\pgf@xa% + \pgf@y=\pgf@ya% + \pgfpointnormalised{}% + \pgf@ya=-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfqpoint{0pt}{0pt}}% +} + + + + +% Computes transformations adjustments for the current transformation +% matrix +% +% Description: +% +% This command is used when you install a transformation matrix that +% scales everything by a certain factor, but you still wish to draw +% something with "an absolute size". Suppose for instance that you +% install a transformation matrix that scales everything by a factor +% of 4 and you now wish to draw a horizontal line of length 1cm. Then, +% if you do not reset the transformation matrix, you can draw a line +% of logical length 2.5mm, which will then get scaled to a line of +% 1cm. +% +% Things get more difficult in case you scale things only, say, +% vertically. In this case, the adjustment necessary for horizontal +% lines is different from the one needed for vertical lines. +% +% This function computes the necessary scaling factors and puts them +% in the macros \pgfhorizontaltransformationadjustment and +% \pgfverticaltransformationadjustment. +% +% Note that the "right" way to draw a line of absolute length 1cm in a +% transformed coordinate system is to first compute the start point +% and to then reset the transformation matrix. The transformation +% adjustments computed here are important only in situations where you +% cannot do this, for instance when an "outer xsep" must be set. + +\def\pgftransformationadjustments{% + \ifpgf@pt@identity% + \let\pgfhorizontaltransformationadjustment\pgf@one@text% + \let\pgfverticaltransformationadjustment\pgf@one@text% + \else% + {% + \pgf@pt@x0pt% + \pgf@pt@y0pt% + \pgfpointtransformed{\pgfqpoint{1pt}{0pt}}% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgfmathreciprocal@{\pgfmathresult}% + \global\let\pgf@temp@hori\pgfmathresult + \pgfpointtransformed{\pgfqpoint{0pt}{1pt}}% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgfmathreciprocal@{\pgfmathresult}% + \global\let\pgf@temp@vert\pgfmathresult + \xdef\pgf@marshal@b{\def\noexpand\pgfverticaltransformationadjustment{\pgfmathresult}} + }% + \let\pgfhorizontaltransformationadjustment\pgf@temp@hori% + \let\pgfverticaltransformationadjustment\pgf@temp@vert% + \fi% +} + +\let\pgfhorizontaltransformationadjustment\pgf@one@text +\let\pgfverticaltransformationadjustment\pgf@one@text + + +% Low-level transformations + +% Causes the current high-level transformation command to be applied +% to the low-level. +% +% Description: +% +% All subsequent drawing will be transformed additionally by the +% current high-level transformation. Thus, the high-level +% transformation becomes the low-level transformation. The high-level +% transformation is reset at this point. + +\def\pgflowlevelsynccm{% + \pgfsys@transformcm% + {\pgf@pt@aa}{\pgf@pt@ab}% + {\pgf@pt@ba}{\pgf@pt@bb}% + {\pgf@pt@x}{\pgf@pt@y}% + \pgftransformreset% + \pgf@relevantforpicturesizefalse% +} + + + +% Causes a transformation command to be applied to the ``lowlevel'' +% transformation matrix. +% +% #1 - a high-level transformation command +% +% Description: +% +% All subsequent drawing will be transformed additionally by the given +% transformation matrix. Note that PGF will no longer be able to +% ``keep track'' of the coordinates. Also, transformations are applied +% to *everything*, including line thickness and line endings. Most +% often, this is not desirable. +% +% Example: +% +% \pgflowlevel{\pgftransformcm{1}{0}{0}{1}{\pgfpoint{100pt}{0pt}}} % 100bp to the right. +% +% \begin{pgflowlevelscope}{\pgftransformcm{2}{0}{0}{2}{\pgfpointorigin}} % double in size +% \pgfmoveto{\pgfpoint{0cm}{0cm}} +% \pgflineto{\pgflineto{1cm}{1cm}} % actually 2cm/2cm +% \end{pgflowlevelscope} + +\def\pgflowlevel#1{% + {% + \pgftransformreset% + #1% + \pgflowlevelsynccm% + }% + \pgf@relevantforpicturesizefalse% +} + +\def\pgflowlevelscope#1{\pgfscope\pgflowlevel{#1}} +\def\endpgflowlevelscope{\endpgfscope} + +\long\def\pgflowlevelobj#1#2{\pgfscope{\pgflowlevel{#1}#2}\endpgfscope} + + + +% View boxes + +% Establishes a view box scope +% +% #1 and #2 = two opposite corners of the source rectangle +% #3 and #4 = two opposite corners of the target rectangle +% #5 = "meet" or "slice" +% +% Description: +% +% Inside the viewbox scope, the source rectangle will be translated +% and scaled so that it becomes centered on the target rectangle and +% will, for "meet", be as large as possible so that it fits inside the +% target and, for "slice", be as small as possible so that it +% encompasses the target. + +\def\pgfviewboxscope#1#2#3#4#5{% + {% Compute rectangle corners + \pgf@process{#1}% + \pgf@pos@transform@glob + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#2}% + \pgf@pos@transform@glob + \ifdim\pgf@x<\pgf@xa% + \pgf@xb\pgf@x% + \pgf@xc\pgf@xa% + \else% + \pgf@xb\pgf@xa% + \pgf@xc\pgf@x% + \fi% + \ifdim\pgf@y<\pgf@ya% + \pgf@yb\pgf@y% + \pgf@yc\pgf@ya% + \else% + \pgf@yb\pgf@ya% + \pgf@yc\pgf@y% + \fi% + \pgf@process{#3}% + \pgf@pos@transform@glob + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{#4}% + \pgf@pos@transform@glob + \ifdim\pgf@x<\pgf@xa% + \else% + \pgfutil@tempdima\pgf@x + \pgf@x\pgf@xa% + \pgf@xa\pgfutil@tempdima% + \fi% + \ifdim\pgf@y<\pgf@ya% + \else% + \pgfutil@tempdima\pgf@y + \pgf@y\pgf@ya% + \pgf@ya\pgfutil@tempdima% + \fi% + \pgfusetype{.view}% + \edef\pgf@marshal{\expandafter\noexpand\csname pgfsys@viewbox#5\endcsname{\the\pgf@x}{\the\pgf@y}{\the\pgf@xa}{\the\pgf@ya}{\the\pgf@xb}{\the\pgf@yb}{\the\pgf@xc}{\the\pgf@yc}}% + \pgf@marshal% + }% + \pgf@relevantforpicturesizefalse% +} + +\def\endpgfviewboxscope{\pgfsys@endviewbox} + +\let\startpgfviewboxscope=\pgfviewboxscope +\let\stoppgfviewboxscope=\endpgfviewboxscope + +% Forward declarations for nonlinear stuff (have no effect till module +% nonlineartransformations is loaded) + +\let\pgfapproximatenonlineartranslation\relax +\let\pgfapproximatenonlineartransformation\relax +\def\pgftransformnonlinear#1{\pgferror{You need to say + \string\usepgfmodule{nonlineartransformations} to use nonlinear transformations}} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransparency.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransparency.code.tex new file mode 100644 index 0000000000..7da8f5a378 --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcoretransparency.code.tex @@ -0,0 +1,312 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfcoretransparency.code.tex} + + +% Sets the opacity of stroking operations. +% +% #1 = opacity, where 1 means fully opaque and 0 means fully +% transparent. +% +% Example: +% +% \pgfsetstrokeopacity{0.5} + +\def\pgfsetstrokeopacity#1{% + \pgfmathparse{#1}% + \expandafter\pgfsys@stroke@opacity\expandafter{\pgfmathresult}} + + +% Sets the opacity of stroking operations. +% +% #1 = opacity, where 1 means fully opaque and 0 means fully +% transparent. +% +% Example: +% +% \pgfsetfillopacity{0.5} + +\def\pgfsetfillopacity#1{% + \pgfmathparse{#1}% + \expandafter\pgfsys@fill@opacity\expandafter{\pgfmathresult}} + + + +% Sets the current blend mode. See Section 7.2.4 of the PDF +% Specification 1.7 for an introduction to blend modes in general. +% +% #1 = One of the following modes, see also section 7.2.4 of the +% PDF Specification 1.7. (The PGF names, which are all lowercase with +% spaces as usual, must be mapped to the PDF or SVG by the drivers.) +% +% normal +% multiply +% screen +% overlay +% darken +% lighten +% color dodge +% color burn +% hard light +% soft light +% difference +% exclusion +% saturation +% color +% hue +% luminosity +% +% Example: +% +% \pgfsetblendmode{multiply} + +\def\pgfsetblendmode#1{\pgfsys@blend@mode{#1}} + + +% Declares a new fading based on the contents of a box. +% +% #1 = name of the fading +% #2 = content of a TeX box that specifies the fading +% +% Description: +% +% This command declares a new fading based on the contents of +% the TeX box. The mask can later be used to mask other graphics. +% +% The box is used to determine where the mask is opaque: At the +% beginning, the mask is completely transparent. Wherever the box +% contains something (like text or a picture or whatever), the +% luminosity of the text/graphic is used to determine how opaque the +% point will be. The greater the luminosity, the more opaque. The net +% effect is that white corresponds to "completely opaque" and black to +% "completely transparent". This is rather counterintuitive. Because +% of this, the special color "pgftransparent" is defined, which is the +% same as black. By setting the color to, say, +% \color{pgftransparent!10} you get something that is 10% transparent +% and \color{pgftransparent!90} gives you 90% transparency. +% +% By default, the drawing color is set to opaque. +% +% Example: +% +% \pgfdeclarefading{mymask}{ +% \fontsize{200}{200}\bfseries +% Ti\emph{k}Z +% } +% \pgfdeclarefading{myothermask}{ +% \tikz \shade [left color=transparent,right color=transparent!0] +% (0,0) rectangle (5,5); +% } + +\def\pgfdeclarefading#1#2{% + \setbox\pgfutil@tempboxa=\hbox{{\pgfsys@beginscope\pgfutil@color{white}\ignorespaces#2\pgfsys@endscope}}% + \pgfsys@fadingfrombox{#1}\pgfutil@tempboxa% +} + +\pgfutil@colorlet{pgftransparent}{black} + + +% Use a previously declared fading. +% +% #1 = name of the fading +% #2 = transformation code +% +% Description: +% +% The command should be used *inside* a pgfpicture to install a +% fading. The fading is a part of the graphic state. (This command +% works much like \pgfsetstrokeopacity). +% +% The mask will be centered on the origin. The transformation code #2 is +% applied to the mask (but not the contents of the actual picture). + +\def\pgfsetfading#1#2{% + {% + \pgftransformreset% + #2% + \pgfgettransform{\pgftrans@temp}% + \edef\pgf@marshal{\noexpand\pgfsys@usefading{#1}\pgftrans@temp}% + \pgf@marshal% + }% +} + + + +% Use a previously declared fading scaled for the current path. +% +% #1 - an fading +% #2 - extra transformations +% +% Description: +% +% This command works a bit like \pgfshadepath. "Works a bit like" +% means the following: The masks's original size should +% completely cover the area between (0,0) and (100bp,100bp). The +% mask is then rescaled so that it completely covers the path. Then +% the additional transformation #2 is applied. Finally, the mask is +% made part of the graphic state (as with \pgfsetfading). The path +% used for computation purposes only -- it is not drawn or otherwise +% used. +% +% If no transformations occur, the lower left corner of the path will +% lie on (25bp, 25bp), the upper right corner on (75bp, 75bp). +% +% If the path was empty, the fading will be used at its natural size, +% centered on the origin. +% +% Example: +% +% \pgfdeclarefading{fade right} +% {\tikz[left color=transparent!0,right color=transparent!100] +% (0,0) rectangle (100bp,100bp);} +% +% \pgfpathmoveto{\pgforigin} +% \pgfpathlineto{\pgfxy(1,0)} +% \pgfpathlineto{\pgfxy(1,1)} +% \pgfsetfadingforcurrentpath{fade right}{} +% \pgfusepath{fill} + +\def\pgfsetfadingforcurrentpath#1#2{% + \ifdim\pgf@pathminx=16000pt% + % Path was empty -> use natural size + \pgfsetfading{#1}{#2}% + \else% + \pgfsetfading{#1}{% + % Calculate center: + \pgf@xb=.5\pgf@pathmaxx% + \advance\pgf@xb by.5\pgf@pathminx% + \pgf@yb=.5\pgf@pathmaxy% + \advance\pgf@yb by.5\pgf@pathminy% + % Calculate scaling: + \pgf@xc=\pgf@pathmaxx% + \advance\pgf@xc by-\pgf@pathminx% + \ifdim\pgf@xc<0.1pt\pgf@xc=0.1pt\fi% + \pgf@yc=\pgf@pathmaxy% + \advance\pgf@yc by-\pgf@pathminy% + \ifdim\pgf@yc<0.1pt\pgf@yc=0.1pt\fi% + \pgf@xc=.02\pgf@xc% + \pgf@yc=.02\pgf@yc% + % Compute new transformation matrix: + \pgftransformcm{1}{0}{0}{1}{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgftransformcm{\pgf@sys@tonumber{\pgf@xc}}{0}{0}{\pgf@sys@tonumber{\pgf@yc}}{\pgfpointorigin}% + \pgfsys@clipfading% + #2% + }% + \fi% +} + + + + +% Use a previously declared fading scaled for the current path. +% +% #1 - an fading +% #2 - extra transformations +% +% Description: +% +% This command works like \pgfsetfadingforcurrentpath, only it takes +% the current line width into account: Before the path is considered, +% it is enlarged by half the line width in all directions. + +\def\pgfsetfadingforcurrentpathstroked#1#2{% + \ifdim\pgf@pathminx=16000pt% + % Path was empty -> use natural size + \pgfsetfading{#1}{#2}% + \else% + \pgfsetfading{#1}{% + % Calculate center: + \pgf@xb=.5\pgf@pathmaxx% + \advance\pgf@xb by.5\pgf@pathminx% + \pgf@yb=.5\pgf@pathmaxy% + \advance\pgf@yb by.5\pgf@pathminy% + % Calculate scaling: + \pgf@xc=\pgf@pathmaxx% + \advance\pgf@xc by-\pgf@pathminx% + \advance\pgf@xc by\pgflinewidth% + \ifdim\pgf@xc<0.1pt\pgf@xc=0.1pt\fi% + \pgf@yc=\pgf@pathmaxy% + \advance\pgf@yc by-\pgf@pathminy% + \advance\pgf@yc by\pgflinewidth% + \ifdim\pgf@yc<0.1pt\pgf@yc=0.1pt\fi% + \pgf@xc=.02\pgf@xc% + \pgf@yc=.02\pgf@yc% + % Compute new transformation matrix: + \pgftransformcm{1}{0}{0}{1}{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgftransformcm{\pgf@sys@tonumber{\pgf@xc}}{0}{0}{\pgf@sys@tonumber{\pgf@yc}}{\pgfpointorigin}% + \pgfsys@clipfading% + #2% + }% + \fi% +} + + +% Group things in a a transparency group +% +% Description: +% +% This takes groups pgf commands inside a pgfpicture in a transparency +% group. This means that any transparency settings apply to commands a +% whole. For instance, if a box contains two overlapping black +% circles and you draw them normally with 50% transparency, then the +% overlap will be darker than the rest. By comparison, if the circles +% are part of a transparency group, the overlap will get the same +% color as the rest. +% +% + +\def\pgftransparencygroup{% + \pgfutil@ifnextchar[{\pgftransparencygroup@}{\pgftransparencygroup@[]}% +} +\def\pgftransparencygroup@[#1]{% + \begingroup% + \pgfkeys{/pgf/transparency group options/.cd,% + isolated=false, + knockout=false, + #1}% + \setbox\pgfutil@tempboxa=\hbox\bgroup% +} +\pgfkeys{ + /pgf/transparency group options/.cd, + isolated/.is if=pgfsys@transparency@group@isolated, + knockout/.is if=pgfsys@transparency@group@knockout +} + +\def\endpgftransparencygroup{% + \egroup% + % Now compute the correct position. This is a bit tricky... + \ifdim\pgf@picminx=16000pt% + % Nothing needs to be done + \else% + % Safety margin to avoid clipping: + \advance\pgf@picminx by-1cm% + \advance\pgf@picmaxx by1cm% + \advance\pgf@picminy by-1cm% + \advance\pgf@picmaxy by1cm% + % Ok, set the box size to current picture size. + \setbox\pgfutil@tempboxa=\hbox{% + \vrule width0pt height\pgf@picmaxy depth-\pgf@picminy% + \hskip-\pgf@picminx% + \box\pgfutil@tempboxa% + \hskip\pgf@picmaxx% + }% + \pgfsys@transparencygroupfrombox\pgfutil@tempboxa% + \wd\pgfutil@tempboxa=0pt% + \ht\pgfutil@tempboxa=0pt% + \dp\pgfutil@tempboxa=0pt% + \hskip\pgf@picminx\box\pgfutil@tempboxa\hskip-\pgf@picminx% + \fi% + \endgroup% +} + +\let\startpgftransparencygroup=\pgftransparencygroup +\let\stoppgftransparencygroup=\endpgftransparencygroup + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.code.tex new file mode 100644 index 0000000000..1a9173fddc --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.code.tex @@ -0,0 +1,264 @@ +% Copyright 2019 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{calc,decorations.markings}% + + +% +% Indicate that the picture contains a circuit +% +\tikzset{ + circuit/.style={ + every circuit/.try, + /utils/exec=\tikz@lib@circ@on@tofalse, + execute at begin to={ + \tikz@lib@circ@on@totrue + \let\tikz@lib@circ@start@node\pgfutil@empty + \def\tikz@lib@circ@end{-- (\tikztotarget) \tikztonodes} + } + } +}% + +\newif\iftikz@lib@circ@on@to + + +% +% General management +% + +\tikzset{ + circuit handle symbol/.code={% + \global\advance\tikz@lib@circ@count by1\relax% + \iftikz@lib@circ@on@to + {% + % Compute the tikz@time... + \pgfkeys{ + /pgf/key filters/active families or no family/.install key filter={/pgf/key filters/false}{/pgf/key filters/false}, + /tikz/circuits/pos grabber/.activate family} + \pgfqkeysfiltered{/tikz}{pos=.5,#1}% + \expandafter% + }% + \expandafter\def\expandafter\tikz@lib@circ@pos\expandafter{\tikz@time}% + \pgfkeysalso{to path={ + \pgfextra{\tikz@lib@circ@on@tofalse} + decorate [decoration={markings,mark connection node=mark node}] + { + \tikz@lib@circ@start@node + \tikz@lib@circ@end + } + }} + \ifdim\tikz@lib@circ@pos pt=0pt\relax% + \def\tikz@lib@circ@start@node{% + {\pgfextra{\tikz@lib@circ@compute@direction{\tikz@lib@circ@start}}% + node[alias=tikz@lib@circ@node@start,at={(0,0)},#1,pos=]{}}(tikz@lib@circ@node@start)}% + \else% + \ifdim\tikz@lib@circ@pos pt=1pt\relax% + \def\tikz@lib@circ@end{ + {\pgfextra{\tikz@lib@circ@compute@direction{\tikz@lib@circ@target}}% + node[alias=tikz@lib@circ@node\the\tikz@lib@circ@count,at={(0,0)},#1,pos=]{}} + --(tikz@lib@circ@node\the\tikz@lib@circ@count)\tikztonodes + }% + \else% + \edef\tikz@marshal{mark=at position \tikz@lib@circ@pos\space with}% + \def\tikz@marshala{decoration=}% + \expandafter\expandafter\expandafter\tikzset% + \expandafter\expandafter\expandafter{\expandafter\tikz@marshala\expandafter{\tikz@marshal{\node[alias=mark node,#1,pos=]{};}}} + \fi% + \fi% + \else + \pgfkeysalso{#1} + \fi + } +}% +\newcount\tikz@lib@circ@count + +\def\tikz@lib@circ@compute@direction#1{% + \tikz@scan@one@point\tikz@lib@circ@save@start(\tikztostart)% + \tikz@scan@one@point\tikz@lib@circ@save@target(\tikztotarget)% + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\tikz@lib@circ@start}{\tikz@lib@circ@target}}}% + \pgf@ya=-\pgf@y% + \pgftransformcm{\the\pgf@x}{\the\pgf@y}{\the\pgf@ya}{\the\pgf@x}{#1}% +}% +\def\tikz@lib@circ@save@start#1{\def\tikz@lib@circ@start{#1}}% +\def\tikz@lib@circ@save@target#1{\def\tikz@lib@circ@target{#1}}% + +\tikzset{ + circuits/pos grabber/.is family, + pos/.belongs to family=/tikz/circuits/pos grabber, + at start/.belongs to family=/tikz/circuits/pos grabber, + very near start/.belongs to family=/tikz/circuits/pos grabber, + near start/.belongs to family=/tikz/circuits/pos grabber, + midway/.belongs to family=/tikz/circuits/pos grabber, + near end/.belongs to family=/tikz/circuits/pos grabber, + very near end/.belongs to family=/tikz/circuits/pos grabber, + at end/.belongs to family=/tikz/circuits/pos grabber +}% + + +% +% Declaring a new symbol +% +\tikzset{ + circuit declare symbol/.style args={#1}{ + % Declares a new circuit symbol. + % + % #1 = name + % #2 = factor for default minimum width + % #3 = factor for default minimum height + % + % The following styles are defined: + % + % #1 + % Can be given as an option to a "node" command or to a "to" + % command. It takes a set of options as parameter that will be + % passed to the option. + % + % set #1 graphic + % This keys can be set to the necessary options to make a normal + % node look like the symbol. For instance, for a resistor that is + % rendered as a rectangle, this keys can be set, basically, to + % "rectangle,draw". Set this key to use a different appearance for + % symbols of kind #1. + % + % every #1 + % This style will be included with every symbols of this kind and + % can be used to configure them further. + % + % every circuit symbol + % This style is also included with every symbol. + #1/.style={circuit handle symbol={ + inner sep=0.5pt, + every circuit symbol, + #1/graphic, + every #1/.try, + ##1} + }, + #1/graphic/.style={}, + set #1 graphic/.style={#1/graphic/.style={##1}} + }, + circuit symbol unit/.code=\pgfmathsetlength\tikzcircuitssizeunit{#1}, + circuit symbol size/.style args={width #1 height #2}{ + minimum width={(#1)*\tikzcircuitssizeunit}, + minimum height={(#2)*\tikzcircuitssizeunit} + }, + huge circuit symbols/.style={circuit symbol unit=10pt}, + large circuit symbols/.style={circuit symbol unit=8pt}, + medium circuit symbols/.style={circuit symbol unit=7pt}, + small circuit symbols/.style={circuit symbol unit=6pt}, + tiny circuit symbols/.style={circuit symbol unit=5pt}, +}% + +\newdimen\tikzcircuitssizeunit +\tikzcircuitssizeunit=7pt + + +% +% Annotations +% + +\tikzset{ + circuit declare annotation/.style args={#1#2#3}{% + #1/.style={ + append after command={% + \bgroup + [current point is local=true] + [every circuit annotation/.try] + [every #1/.try] + [shift={(\tikzlastnode.north)}] + [annotation arrow,->] + [label distance=#2,##1] + #3 + \tikz@after@path% + \egroup% + } + }, + #1'/.style={ + append after command={% + \bgroup + [current point is local=true] + [every circuit annotation/.try] + [every #1/.try] + [shift={(\tikzlastnode.south)},yscale=-1] + [annotation arrow,->] + [label distance=#2,##1] + #3 + \tikz@after@path% + \egroup% + } + } + }, + annotation arrow/.style = { + /utils/exec={\pgfsetarrowoptions{direction ee}{.4*\the\tikzcircuitssizeunit+.3*\the\pgflinewidth}}, + >=direction ee + } +}% + + + +% +% Rotating symbols +% +\tikzset{ + point up/.style={rotate=90}, + point down/.style={rotate=-90}, + point left/.style={rotate=180}, + point right/.style={} +}% + + + +% +% Basic theming +% + +\tikzset{ + every circuit symbol/.style={}, + circuit symbol open/.style={draw}, + circuit symbol filled/.style={draw,fill=black}, + circuit symbol lines/.style={draw}, + circuit symbol wires/.style={draw}, +}% + + + + + +% +% Labels +% + +\tikzset{ + info/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab@plain{\tikz@lib@circ@lab@plain[]}#1\pgf@stop},%} + info'/.code={\pgfutil@ifnextchar[\tikz@lib@circ@labp@plain{\tikz@lib@circ@labp@plain[]}#1\pgf@stop},%} + info sloped/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab@sloped@plain{\tikz@lib@circ@lab@sloped@plain[]}#1\pgf@stop},%} + info' sloped/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab@slopedp@plain{\tikz@lib@circ@lab@slopedp@plain[]}#1\pgf@stop},%} + circuit declare unit/.style 2 args={ + % + % Defines four styles that can be used to add labels to a node. + % + #1/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab{\tikz@lib@circ@lab[]}##1\pgf@stop{#2}{#1}},%} + #1 sloped/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab@sloped{\tikz@lib@circ@lab@sloped[]}##1\pgf@stop{#2}{#1}},%} + #1'/.code={\pgfutil@ifnextchar[\tikz@lib@circ@labp{\tikz@lib@circ@labp[]}##1\pgf@stop{#2}{#1}},%} + #1' sloped/.code={\pgfutil@ifnextchar[\tikz@lib@circ@lab@slopedp{\tikz@lib@circ@lab@slopedp[]}##1\pgf@stop{#2}{#1}}%} + } +}% + +\def\tikz@lib@circ@lab[#1]#2\pgf@stop#3#4{\tikzset{label={[every info/.try,every #4/.try,#1]$\mathrm{#2#3}$}}}% +\def\tikz@lib@circ@lab@sloped[#1]#2\pgf@stop#3#4{\tikzset{label={[every info/.try,every #4/.try,transform shape,#1]$\mathrm{#2#3}$}}}% +\def\tikz@lib@circ@labp[#1]#2\pgf@stop#3#4{\tikzset{label={[label position=below,every info/.try,every #4/.try,#1]$\mathrm{#2#3}$}}}% +\def\tikz@lib@circ@lab@slopedp[#1]#2\pgf@stop#3#4{\tikzset{label={[label position=below,every info/.try,every #4/.try,transform shape,#1]$\mathrm{#2#3}$}}}% + +\def\tikz@lib@circ@lab@plain[#1]#2\pgf@stop{\tikzset{label={[every info/.try,#1]#2}}}% +\def\tikz@lib@circ@lab@sloped@plain[#1]#2\pgf@stop{\tikzset{label={[every info/.try,transform shape,#1]#2}}}% +\def\tikz@lib@circ@labp@plain[#1]#2\pgf@stop{\tikzset{label={[label position=below,every info/.try,#1]#2}}}% +\def\tikz@lib@circ@lab@slopedp@plain[#1]#2\pgf@stop{\tikzset{label={[label position=below,every info/.try,transform shape,#1]#2}}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.IEC.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.IEC.code.tex new file mode 100644 index 0000000000..9d1cfcfcea --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.IEC.code.tex @@ -0,0 +1,442 @@ +% Copyright 2019 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{arrows}% +\usetikzlibrary{circuits.ee}% + +\usepgflibrary{shapes.gates.ee.IEC}% + + +% +% When this lib is loaded, all symbols default to IEC +% + +\tikzset{ + circuit ee IEC/.style= + { + circuit ee, + set resistor graphic = resistor IEC graphic, + set inductor graphic = inductor IEC graphic, + set capacitor graphic = capacitor IEC graphic, + set contact graphic = contact IEC graphic, + set ground graphic = ground IEC graphic, + set battery graphic = battery IEC graphic, + set diode graphic = diode IEC graphic, + set Zener diode graphic = Zener diode IEC graphic, + set tunnel diode graphic = tunnel diode IEC graphic, + set backward diode graphic = backward diode IEC graphic, + set Schottky diode graphic = Schottky diode IEC graphic, + set breakdown diode graphic = breakdown diode IEC graphic, + set bulb graphic = bulb IEC graphic, + set voltage source graphic = voltage source IEC graphic, + set current source graphic = current source IEC graphic, + set make contact graphic = make contact IEC graphic, + set break contact graphic = break contact IEC graphic, + set amperemeter graphic = amperemeter graphic, + set voltmeter graphic = voltmeter graphic, + set ohmmeter graphic = ohmmeter graphic, + set ac source graphic = ac source graphic, + set dc source graphic = dc source graphic, + }, +}% + + +% +% Resistors +% + +\tikzset{ + resistor IEC graphic/.style={ + circuit symbol open, + circuit symbol size=width 4 height 1, + shape=rectangle ee, + transform shape, + }, + var resistor IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width 4.8 height 0.8, + shape=var resistor IEC, + transform shape, + outer sep=0pt, + cap=round, + }, +}% + + + +% +% Inductors +% + +\tikzset{ + inductor IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width 4 height .5, + transform shape, + shape=inductor IEC, + outer sep=0pt, + cap=round, + }, + var inductor IEC graphic/.style={ + circuit symbol filled, + circuit symbol size=width 4 height 1, + transform shape, + shape=rectangle ee, + }, +}% + + + +% +% Capacitors +% + +\tikzset{ + capacitor IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width .5 height 2, + transform shape, + shape=capacitor IEC, + }, +}% + + + +% +% Ground +% + +\tikzset{ + ground IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width .75 height 2, + transform shape, + shape=ground IEC, + }, +}% + + + + +% +% Battery +% + +\tikzset{ + battery IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width .5 height 2.5, + transform shape, + shape=battery IEC, + transform shape, + }, +}% + + + +% +% Diodes +% + +\tikzset{ + % + % normal diode + % + diode IEC graphic/.style={ + circuit symbol open, + circuit symbol size=width 1.25 height 1.25, + transform shape, + shape=generic diode IEC, + /pgf/generic diode IEC/before background={ + \pgfpathmoveto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfusepathqstroke + }, + }, + var diode IEC graphic/.style={ + diode IEC graphic, + circuit symbol filled, + }, +}% + +\tikzset{ + % + % Zener diode + % + Zener diode IEC graphic/.style={ + diode IEC graphic, + /pgf/generic diode IEC/before background={ + \pgfpathmoveto{\pgfqpoint{-.5pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfusepathqstroke + }, + }, + var Zener diode IEC graphic/.style={ + Zener diode IEC graphic, + circuit symbol filled, + }, +}% + +\tikzset{ + % + % Schottky diode + % + Schottky diode IEC graphic/.style={ + diode IEC graphic, + /pgf/generic diode IEC/before background={ + \pgfpathmoveto{\pgfqpoint{-.4pt}{-.6pt}} + \pgfpathlineto{\pgfqpoint{-.4pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfpathlineto{\pgfqpoint{.4pt}{1pt}} + \pgfpathlineto{\pgfqpoint{.4pt}{.6pt}} + \pgfusepathqstroke + }, + }, + var Schottky diode IEC graphic/.style={ + Schottky diode IEC graphic, + circuit symbol filled, + }, +}% + +\tikzset{ + % + % tunnel diode + % + tunnel diode IEC graphic/.style={ + diode IEC graphic, + /pgf/generic diode IEC/before background={ + \pgfpathmoveto{\pgfqpoint{-.5pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfpathlineto{\pgfqpoint{-.5pt}{1pt}} + \pgfusepathqstroke + }, + }, + var tunnel diode IEC graphic/.style={ + tunnel diode IEC graphic, + circuit symbol filled, + }, +}% + +\tikzset{ + % + % backward diode + % + backward diode IEC graphic/.style={ + diode IEC graphic, + /pgf/generic diode IEC/before background={ + \pgfpathmoveto{\pgfqpoint{-.5pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{.5pt}{-1pt}} + \pgfpathmoveto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfpathmoveto{\pgfqpoint{-.5pt}{1pt}} + \pgfpathlineto{\pgfqpoint{.5pt}{1pt}} + \pgfusepathqstroke + }, + }, + var backward diode IEC graphic/.style={ + backward diode IEC graphic, + circuit symbol filled, + }, +}% + + +\tikzset{ + % + % breakdown diode + % + breakdown diode IEC graphic/.style={ + circuit symbol open, + circuit symbol size=width 2.5 height 1.25, + transform shape, + shape=breakdown diode IEC, + }, + var breakdown diode IEC graphic/.style={ + breakdown diode IEC graphic, + circuit symbol filled, + }, +}% + + + +% +% Contacts +% + +\tikzset{ + contact IEC graphic/.style={ + circuit symbol filled, + circuit symbol size=width .5 height .5, + shape=circle ee, + outer sep=.25\pgflinewidth, + }, +% connection IEC graphic/.style={ +% circuit symbol open, +% circuit symbol size=width 1 height 1, +% shape=circle ee, +% outer sep=.25\pgflinewidth, +% }, +}% + + +% +% Bulbs +% + +\tikzset{ + bulb IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width 1.5 height 1.5, + shape=generic circle IEC, + /pgf/generic circle IEC/before background={ + \pgfpathmoveto{\pgfpointpolar{-135}{1pt}} + \pgfpathlineto{\pgfpointpolar{45}{1pt}} + \pgfpathmoveto{\pgfpointpolar{-45}{1pt}} + \pgfpathlineto{\pgfpointpolar{135}{1pt}} + \pgfusepathqstroke + }, + transform shape, + }, +}% + + +% +% Current and voltage sources +% + +\tikzset{ + current source IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width 2 height 2, + shape=generic circle IEC, + /pgf/generic circle IEC/before background={ + \pgfpathmoveto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfusepathqstroke + }, + transform shape, + }, + voltage source IEC graphic/.style={ + circuit symbol lines, + circuit symbol size=width 2 height 2, + shape=generic circle IEC, + /pgf/generic circle IEC/before background={ + \pgfpathmoveto{\pgfqpoint{-1pt}{0pt}} + \pgfpathlineto{\pgfqpoint{1pt}{0pt}} + \pgfusepathqstroke + }, + transform shape, + }, +}% + + + +% +% Contacts +% + +\tikzset{ + make contact IEC graphic/.style={ + circuit symbol wires, + circuit symbol size=width 2 height 1, + transform shape, + shape=make contact IEC, + outer sep=0pt, + cap=round, + }, + var make contact IEC graphic/.style={ + circuit symbol wires, + circuit symbol size=width 2.4 height 1, + transform shape, + shape=var make contact IEC, + outer sep=0pt, + cap=round, + }, +}% + + +\tikzset{ + break contact IEC graphic/.style={ + circuit symbol wires, + circuit symbol size=width 2 height 1, + transform shape, + shape=break contact IEC, + outer sep=0pt, + cap=round, + }, +}% + + + +% +% Measurement devices +% + +\tikzset{ + amperemeter graphic/.style={ + circuit symbol open, + circuit symbol size=width 2 height 2, + transform shape, + shape=generic circle IEC, + info=center:A, + }, + voltmeter graphic/.style={ + circuit symbol open, + circuit symbol size=width 2 height 2, + transform shape, + shape=generic circle IEC, + info=center:V, + }, + ohmmeter graphic/.style={ + circuit symbol open, + circuit symbol size=width 2 height 2, + transform shape, + shape=generic circle IEC, + info=center:$\Omega$, + }, +}% + + + +% +% AC/DC +% + +\tikzset{ + ac source graphic/.style={ + circuit symbol lines, + circuit symbol size=width 2 height 2, + shape=generic circle IEC, + /pgf/generic circle IEC/before background={ + \pgfpathmoveto{\pgfqpoint{0.7pt}{0pt}} + \pgfpathquadraticcurveto{\pgfqpoint{ 0.35pt}{-0.5pt}}{\pgfqpoint{0pt}{0pt}} + \pgfpathquadraticcurveto{\pgfqpoint{-0.35pt}{ 0.5pt}}{\pgfqpoint{-0.7pt}{0pt}} + \pgfusepathqstroke + }, + transform shape, + }, + dc source graphic/.style={ + circuit symbol lines, + circuit symbol size=width 2 height 2, + shape=generic circle IEC, + /pgf/generic circle IEC/before background={ + \pgfpathmoveto{\pgfqpoint{ 0.7pt}{ 0.2pt}} + \pgfpathlineto{\pgfqpoint{-0.7pt}{ 0.2pt}} + \pgfusepathqstroke + \pgfpathmoveto{\pgfqpoint{ 0.7pt}{-0.2pt}} + \pgfpathlineto{\pgfqpoint{-0.7pt}{-0.2pt}} + \pgfusepathqstroke + }, + transform shape, + }, +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.code.tex new file mode 100644 index 0000000000..2e065d7dda --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.ee.code.tex @@ -0,0 +1,148 @@ + +% Copyright 2019 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{circuits}% +\usepgflibrary{shapes.gates.ee}% + + +% +% Setting up an ee circuit +% +\tikzset{ + circuit ee/.style={ + circuit, + every circuit ee/.try + } +}% + + +% +% The default symbols (you need to load a sublib to install the actual rendering). +% + +\tikzset{ + circuit declare symbol = resistor, + circuit declare symbol = inductor, + circuit declare symbol = capacitor, + circuit declare symbol = contact, + circuit declare symbol = ground, + circuit declare symbol = battery, + circuit declare symbol = diode, + circuit declare symbol = Zener diode, + circuit declare symbol = Schottky diode, + circuit declare symbol = tunnel diode, + circuit declare symbol = backward diode, + circuit declare symbol = breakdown diode, + circuit declare symbol = bulb, + circuit declare symbol = current source, + circuit declare symbol = voltage source, + circuit declare symbol = current direction, + circuit declare symbol = current direction', + circuit declare symbol = make contact, + circuit declare symbol = break contact, + circuit declare symbol = amperemeter, + circuit declare symbol = voltmeter, + circuit declare symbol = ohmmeter, + circuit declare symbol = ac source, + circuit declare symbol = dc source, + % + set current direction graphic = current direction ee graphic, + set current direction' graphic = current direction' ee graphic, +}% + + +% +% The default labels +% + +\tikzset{ + circuit declare unit={ampere}{A}, + circuit declare unit={volt}{V}, + circuit declare unit={ohm}{\Omega}, + circuit declare unit={siemens}{S}, + circuit declare unit={henry}{H}, + circuit declare unit={farad}{F}, + circuit declare unit={coulomb}{C}, + circuit declare unit={voltampere}{VA}, + circuit declare unit={watt}{W}, + circuit declare unit={hertz}{Hz}, +}% + + + +% +% The direction and arrow settings +% + +\tikzset{ + % These styles should set the end-arrow. + % + % This arrow will generally be used to indicate current directions in a circuit: + current direction arrow/.style = { + /utils/exec={\pgfsetarrowoptions{direction ee}{1.3065*.5*\the\tikzcircuitssizeunit+1.3065*.3*\the\pgflinewidth}}, + >=direction ee, + direction ee arrow = direction ee, + } +}% + + + + +\tikzset{ + current direction ee graphic/.style = { + shape=direction ee, + circuit symbol filled, + current direction arrow, + minimum width = .5*\the\tikzcircuitssizeunit+.3*\the\pgflinewidth, + minimum height = .5*\the\tikzcircuitssizeunit+.3*\the\pgflinewidth, + transform shape + }, + current direction' ee graphic/.style = { + current direction ee graphic, + rotate=180 + } +}% + + + +% +% Annotations +% + +\tikzset{ + circuit declare annotation={direction info}{.5\tikzcircuitssizeunit} + { + (-1.25\tikzcircuitssizeunit,.3333\tikzcircuitssizeunit) edge[line to] (1.25\tikzcircuitssizeunit,.3333\tikzcircuitssizeunit) + }, + circuit declare annotation={light emitting}{1.75\tikzcircuitssizeunit} + { + (-.2\tikzcircuitssizeunit,.65\tikzcircuitssizeunit) edge[line to] ++(45:1.25\tikzcircuitssizeunit) + (.2\tikzcircuitssizeunit,.25\tikzcircuitssizeunit) edge[line to] ++(45:1.25\tikzcircuitssizeunit) + }, + circuit declare annotation={light dependent}{1.75\tikzcircuitssizeunit} + { + [shift=(135:1.25\tikzcircuitssizeunit)] + (.2\tikzcircuitssizeunit,.65\tikzcircuitssizeunit) edge[line to] ++(-45:1.25\tikzcircuitssizeunit) + (-.2\tikzcircuitssizeunit,.25\tikzcircuitssizeunit) edge[line to] ++(-45:1.25\tikzcircuitssizeunit) + }, + circuit declare annotation={adjustable}{1.5\tikzcircuitssizeunit} + { + [shift=(\tikzlastnode.center)] + (-1.5\tikzcircuitssizeunit,-1.5\tikzcircuitssizeunit) edge[line to] (1.5\tikzcircuitssizeunit,1.5\tikzcircuitssizeunit) + }, + circuit declare annotation={adjustable'}{1.5\tikzcircuitssizeunit} + { + [shift=(\tikzlastnode.center)] + (-1.5\tikzcircuitssizeunit,1.5\tikzcircuitssizeunit) edge[line to] (1.5\tikzcircuitssizeunit,-1.5\tikzcircuitssizeunit) + } +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.CDH.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.CDH.code.tex new file mode 100644 index 0000000000..743bc24be8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.CDH.code.tex @@ -0,0 +1,28 @@ +% Copyright 2018 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{circuits.logic.US}% + +\tikzset{ + circuit logic CDH/.style = + { + circuit logic US, + set and gate graphic = and gate CDH graphic, + set nand gate graphic = nand gate CDH graphic, + } +}% + +\tikzset{ + circuit logic US make graphic=and gate CDH, + circuit logic US make graphic=nand gate CDH, +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.IEC.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.IEC.code.tex new file mode 100644 index 0000000000..3d74ccd197 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.IEC.code.tex @@ -0,0 +1,75 @@ +% Copyright 2018 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{circuits.logic}% +\usepgflibrary{shapes.gates.logic.IEC}% + + +% +% When this lib is loaded, all symbols default to IEC +% + +\tikzset{ + circuit logic IEC/.style= + { + circuit logic, + set and gate graphic = and gate IEC graphic, + set nand gate graphic = nand gate IEC graphic, + set or gate graphic = or gate IEC graphic, + set nor gate graphic = nor gate IEC graphic, + set xor gate graphic = xor gate IEC graphic, + set xnor gate graphic = xnor gate IEC graphic, + set not gate graphic = not gate IEC graphic, + set buffer gate graphic = buffer gate IEC graphic, + % + and gate IEC symbol = {$\scriptstyle\char`\&$}, + nand gate IEC symbol = {$\scriptstyle\char`\&$}, + or gate IEC symbol = {$\scriptstyle\geq1$}, + nor gate IEC symbol = {$\scriptstyle\geq1$}, + xor gate IEC symbol = {$\scriptstyle=1$}, + xnor gate IEC symbol = {$\scriptstyle=1$}, + not gate IEC symbol = {$\scriptstyle1$}, + buffer gate IEC symbol = {$\scriptstyle1$}, + }, +}% + + +% +% The logical gate graphics are all nearly identical, so we provide a +% simple style for creating them: +% +\tikzset{ + circuit logic IEC make graphic/.style= + { + #1 graphic/.style={ + circuit symbol open, + circuit symbol size=width 2.5 height 4, + shape=#1, + inner sep=.5ex + } + } +}% + + +\tikzset{ + circuit logic IEC make graphic=and gate IEC, + circuit logic IEC make graphic=nand gate IEC, + circuit logic IEC make graphic=or gate IEC, + circuit logic IEC make graphic=nor gate IEC, + circuit logic IEC make graphic=xor gate IEC, + circuit logic IEC make graphic=xnor gate IEC, + circuit logic IEC make graphic=not gate IEC, + circuit logic IEC make graphic=buffer gate IEC, + circuit logic IEC make graphic=and gate CDH, + circuit logic IEC make graphic=nand gate CDH, +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.US.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.US.code.tex new file mode 100644 index 0000000000..b20b4d58ba --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.US.code.tex @@ -0,0 +1,64 @@ +% Copyright 2018 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{circuits.logic}% +\usepgflibrary{shapes.gates.logic.US}% + + +% +% When this lib is loaded, all symbols default to IEC +% + +\tikzset{ + circuit logic US/.style= + { + circuit logic, + set and gate graphic = and gate US graphic, + set nand gate graphic = nand gate US graphic, + set or gate graphic = or gate US graphic, + set nor gate graphic = nor gate US graphic, + set xor gate graphic = xor gate US graphic, + set xnor gate graphic = xnor gate US graphic, + set not gate graphic = not gate US graphic, + set buffer gate graphic = buffer gate US graphic + } +}% + + +% +% The logical gate graphics are all nearly identical, so we provide a +% simple style for creating them: +% +\tikzset{ + circuit logic US make graphic/.style= + { + #1 graphic/.style={ + circuit symbol open, + circuit symbol size=width 0 height 2.5, + shape=#1, + transform shape + } + } +}% + + +\tikzset{ + circuit logic US make graphic=and gate US, + circuit logic US make graphic=nand gate US, + circuit logic US make graphic=or gate US, + circuit logic US make graphic=nor gate US, + circuit logic US make graphic=xor gate US, + circuit logic US make graphic=xnor gate US, + circuit logic US make graphic=not gate US, + circuit logic US make graphic=buffer gate US, +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.code.tex new file mode 100644 index 0000000000..390d022a8a --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/circuits/tikzlibrarycircuits.logic.code.tex @@ -0,0 +1,45 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{circuits}% + + + +% +% Provides a shortcut to the "logic gates inputs" key. +% + +\tikzset{ + circuit logic/.style={ + circuit, + inputs/.style={logic gate inputs={##1}}, + logic gate inverted radius=.25\tikzcircuitssizeunit, + every circuit logic/.try, + } +}% + + + +% +% The default symbols (you need to load a sublib to install the actual rendering). +% + +\tikzset{ + circuit declare symbol = and gate, + circuit declare symbol = nand gate, + circuit declare symbol = or gate, + circuit declare symbol = nor gate, + circuit declare symbol = xor gate, + circuit declare symbol = xnor gate, + circuit declare symbol = not gate, + circuit declare symbol = buffer gate +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.3d.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.3d.code.tex new file mode 100644 index 0000000000..df08b507d5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.3d.code.tex @@ -0,0 +1,79 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.3d.code.tex} + +\usetikzlibrary{datavisualization}% + + + +% The following is not yet really implement. But you might get the idea... + + + +% A 3d version of the school book plot + +\tikzdatavisualizationset{ + school book 3d plot/.style={ + xyz Cartesian, + x axis={ + visualize axis={y axis={goto=0},z axis={goto=0},styling/.style=->}, + visualize ticks={common={y axis={goto=0},z axis={goto=0},direction axis=y axis},only ticks={tick text at min extend}}, +% visualize ticks={common={y axis={goto=0},z axis={goto=0},direction axis=z axis}}, + }, + y axis={ + visualize axis={x axis={goto=0},z axis={goto=0},styling/.style=->}, + visualize ticks={common={x axis={goto=0},z axis={goto=0},direction axis=x axis},only ticks={tick text at min extend}}, +% visualize ticks={common={x axis={goto=0},z axis={goto=0},direction axis=z axis}}, + }, + z axis={ + visualize axis={x axis={goto=0},y axis={goto=0},styling/.style=->}, + visualize ticks={common={x axis={goto=0},y axis={goto=0},direction axis=x axis},only ticks={tick text at min extend}}, +% visualize ticks={common={x axis={goto=0},y axis={goto=0},direction axis=y axis}} + }, + new line plot, + every school book plot/.try, + }, +}% + + +% A 3d version of the scientific plot +% +% Here, a "length" is used for the length of the three +% axes, rather than a predetermined rectangle (this does not really +% make sense for the z-axis. You overrule these settings easily. + +\tikzdatavisualizationset{ + scientific 3d plot/length/.initial=100pt, + scientific 3d plot/.style={ + xyz Cartesian, + x axis={ + length=\pgfkeysvalueof{/tikz/data visualization/scientific 3d plot/length}, + visualize axis={y axis={goto=min},z axis={goto=min}}, + visualize axis={y axis={goto=max},z axis={goto=min}}, + visualize axis={y axis={goto=min},z axis={goto=max}}, + visualize axis={y axis={goto=max},z axis={goto=max}}, + }, + y axis={ + length=\pgfkeysvalueof{/tikz/data visualization/scientific 3d plot/length}, + visualize axis={x axis={goto=min},z axis={goto=min}}, + visualize axis={x axis={goto=max},z axis={goto=min}}, + visualize axis={x axis={goto=min},z axis={goto=max}}, + visualize axis={x axis={goto=max},z axis={goto=max}}, + }, + z axis={ + length=\pgfkeysvalueof{/tikz/data visualization/scientific 3d plot/length}, + visualize axis={x axis={goto=min},y axis={goto=min}}, + visualize axis={x axis={goto=max},y axis={goto=min}}, + visualize axis={x axis={goto=min},y axis={goto=max}}, + visualize axis={x axis={goto=max},y axis={goto=max}}, + }, + new line plot, + }, +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.barcharts.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.barcharts.code.tex new file mode 100644 index 0000000000..3780a4638a --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.barcharts.code.tex @@ -0,0 +1,43 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.barcharts.code.tex} + +\usetikzlibrary{datavisualization}% +\usepgflibrary{datavisualization.barcharts}% + + +\tikzdatavisualizationset{% + candle stick plot/.style={ + new object={ + store=/tikz/data visualization/count, + class=count, + arg1=day + }, + new axis=y axis, + y axis/source=dax, + y axis/source max=100, + y axis/vec=\pgfqpoint{0cm}{1cm}, + new object={ + store=/tikz/data visualization/x line trans, + class=line transformer, + arg1=day, + arg2=\pgfqpoint{3mm}{0mm} + }, + new object={ + store=/tikz/data visualization/index, + class=candle stick visualizer, + arg1 from key=index/source + }, + }, + index/source/.initial=index, +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.code.tex new file mode 100644 index 0000000000..04dae1e6b5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.code.tex @@ -0,0 +1,2733 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.code.tex} + +\usepgfmodule{datavisualization}% +\usetikzlibrary{backgrounds}% + + +\tikzset{/tikz/data visualization/.is family, + /tikz/data visualization/.unknown/.code={ + \let\tikz@dv@key\pgfkeyscurrentname% + \pgfkeys{/tikz/\tikz@dv@key/.try={#1}}% + \ifpgfkeyssuccess% + \else% + \edef\pgf@temp{/errors/unknown key={/tikz/data visualization/\tikz@dv@key}}% + \expandafter\pgfkeys\expandafter{\pgf@temp{#1}}% + \fi% + }, + /tikz/data visualization/data/.unknown/.code={% + % Redirect to /pgf/data + \let\tikz@dv@key\pgfkeyscurrentname% + \pgfkeys{/pgf/data/\tikz@dv@key/.try={#1}}% + \ifpgfkeyssuccess% + \else% + \edef\pgf@temp{/errors/unknown key={/pgf/data/\tikz@dv@key}}% + \expandafter\pgfkeys\expandafter{\pgf@temp{#1}}% + \fi% + }, +}% + +\def\tikzdatavisualizationset{\pgfqkeys{/tikz/data visualization}}% + + + + +% The main \datavisualization command +% +% This command must, as always, be given inside a tikz picture. It +% will add a data visualization to the picture; use "shift" option and +% friends to place the data visualization somewhere other than at the +% origin. +% +% The \datavisualization is followed by a sequence of blocks and ended +% with a semicolon. Each block may be one of the following: +% +% "data" blocks. +% +% Syntax: data [options] % options specify an external source +% Syntax: data [options] { inline data } +% +% The optional arguments may either specify an +% external data source or the data may follow inline. +% +% The options are executed for the path /pgf/data. The style +% /tikz/every data is executed for each data, which can be useful to +% generally set, say, a certain data format. +% +% +% "data set" blocks. +% +% Syntax: data set [options] {name} = { ... } +% Syntax: data set [options] {name} += { ... } +% Syntax: data set [options] {name} +% +% The first syntax allows you to define a data set. The data block +% inside {...} will be stored inside the data set +% "name". Subsequently, the data set can be referenced by using the +% third syntax. The second syntax allows you to extend the +% definition of an already defined data set. +% +% +% "info" and "info'" blocks. +% +% Syntax: info [options] {code} +% Syntax: info' [options] {code} +% +% A block starting with "info" or "info'" may contain any code. It +% will be executed after the visualization (info) or before the +% visualization (info'). +% +% +% Options blocks. +% +% Syntax: [options] +% +% The options will be executed immediately. +% +% Scope blocks. +% +% Syntax: scope[options] { blocks } +% +% The blocks are executed inside a scope for which the options are +% set. This can be used to group data blocks. +% +% Examples: +% +% \datavisualization[schoolbook plot] +% data [source=my_data_file.csv] +% ; +% +% \datavisualization[schoolbook plot] +% data [format=key value pairs] +% { +% x=0, y=0 +% x=1, y=1 +% x=2, y=4 +% x=3, y=9 +% }; +% +% \datavisualization[schoolbook plot] +% data [format=function] +% { +% var x: interval [0:3]; +% func y = \value x*\value x; +% } +% [at begin visualization={ +% \fill [black!10] (visualization cs:x=0,y=0) -- (visualization cs:x=3,y=9); +% }] +% info[red] +% { +% \draw (visualization cs:x=0,y=0) -- (visualization cs:x=3,y=9); +% }; +% +% \datavisualization[schoolbook plot] +% data [/data point/label=first experiment,source=file_1] +% data [/data point/label=second experiment,source=file_2] +% data [/data point/label=third experiment,source=file_3] +% data [/data point/label=prediction,format=function] +% { var x: interval [0,1]; func y = rand(\value x); } +% ; + +\def\tikz@lib@datavisualization{ + \begingroup% + \let\tikz@path@do@at@end=\relax% + % Ok, first, start a new data visualization + \pgfoonew \tikz@main@dv=new data visualization()% + % Next, create a scope for the dv + \pgfset{local bounding box=data visualization bounding box}% + % Clear the axis list + \pgfkeyslet{/tikz/data visualization/axes list}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/axes actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/label actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/legend actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/grid actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/major grid actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/minor grid actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/subminor grid actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/ticks actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/major ticks actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/minor ticks actions}\pgfutil@empty% + \pgfkeyslet{/tikz/data visualization/subminor ticks actions}\pgfutil@empty% + \tikz@main@dv.before visualization(% + )% + \tikz@main@dv.after visualization(% + \tikz@lib@dv@alias@dv@bb + \pgfkeysvalueof{/tikz/data visualization/grid actions} + \pgfkeysvalueof{/tikz/data visualization/subminor grid actions} + \pgfkeysvalueof{/tikz/data visualization/minor grid actions} + \pgfkeysvalueof{/tikz/data visualization/major grid actions} + \pgfkeysvalueof{/tikz/data visualization/ticks actions} + \pgfkeysvalueof{/tikz/data visualization/subminor ticks actions} + \pgfkeysvalueof{/tikz/data visualization/minor ticks actions} + \pgfkeysvalueof{/tikz/data visualization/major ticks actions} + \pgfkeysvalueof{/tikz/data visualization/axes actions} + \pgfkeysvalueof{/tikz/data visualization/label actions} + \pgfkeysvalueof{/tikz/data visualization/legend actions} + )% + % + \pgfset{/pgf/data/continue code=\tikz@lib@dv@parse@loop}% + % Now enter parse loop + \tikz@lib@dv@parse@loop +}% + +\def\tikz@lib@dv@parse@loop{% + \pgfutil@ifnextchar d\tikz@lib@dv@handle@data{% + \pgfutil@ifnextchar ;\tikz@lib@dv@parse@end{% + \pgfutil@ifnextchar \par\tikz@lib@dv@handle@par{% + \pgfutil@ifnextchar s\tikz@lib@dv@handle@beginscope{% + \pgfutil@ifnextchar i\tikz@lib@dv@handle@info{% + \pgfutil@ifnextchar [\tikz@lib@dv@handle@options{% + \pgfutil@ifnextchar \egroup\tikz@lib@dv@handle@endscope{% + \tikzerror{Semicolon expected}% + \endgroup% + }% + }% + }% + }% + }% + }% + }% +}% +\def\tikz@lib@dv@parse@end;{% + % Go! + \tikz@main@dv.survey()% + \tikz@main@dv.visualize()% + \endgroup% + \tikz@path@do@at@end% +}% +\def\tikz@lib@dv@handle@par\par{\tikz@lib@dv@parse@loop}% + +\def\tikz@lib@dv@handle@options[#1]{% + \tikzdatavisualizationset{#1}% + \tikz@lib@dv@parse@loop% +}% + +\def\tikz@lib@dv@handle@beginscope scope{% + \begingroup% + \pgfutil@ifnextchar[\tikz@lib@dv@beg@opt{\tikz@lib@dv@beg@opt[]}%} +}% +\def\tikz@lib@dv@beg@opt[#1]{% + \pgfkeys{/pgf/data/.cd,/pgf/every data/.try,#1}% + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data({{\begingroup\pgfkeys{/pgf/data/.cd,/pgf/every data/.try,#1}}})}% + \pgfutil@ifnextchar\bgroup{ + \afterassignment\tikz@lib@dv@parse@loop% + \let\tikz@dummy=%get rid of \bgroup + }{% + \tikzerror{Opening brace expected}% + \tikz@lib@dv@parse@loop% + }% +}% +\def\tikz@lib@dv@handle@endscope{% + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data(\endgroup)}% + \endgroup% + \afterassignment\tikz@lib@dv@parse@loop% + \let\tikz@dummy=%get rid of \egroup +}% + +\def\tikz@lib@dv@handle@data data{% + \pgfutil@ifnextchar g{\tikz@lib@dv@handle@data@group}{% + \pgfutil@ifnextchar p{\tikz@lib@dv@handle@data@point}{% + \pgfdata}}}% + +\def\tikz@lib@dv@handle@data@group group{\pgfutil@ifnextchar[{\tikz@lib@dv@handle@data@group@opt}{\tikz@lib@dv@handle@data@group@opt[]}}%}% + +\def\tikz@lib@dv@handle@data@group@opt[#1]#2{% + \pgfutil@ifnextchar={\tikz@lib@dv@handle@data@group@def{#1}{#2}}{% + \pgfutil@ifnextchar+{\tikz@lib@dv@handle@data@group@extend{#1}{#2}}{% + \tikz@lib@dv@handle@data@group@use{#1}{#2}}}}% + +\def\tikz@lib@dv@handle@data@group@def#1#2={% + \pgfkeys{/pgf/data/new group={#2}}% + \tikz@lib@dv@handle@data@group@extend{#1}{#2}+=% +}% + +\def\tikz@lib@dv@handle@data@group@extend#1#2+={% + \pgfutil@ifnextchar\bgroup{ + \begingroup% + \pgfkeys{/pgf/data/store in group={#2}}% + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data({{\begingroup\pgfkeys{/pgf/data/.cd,/pgf/every data/.try,#1}}})}% + \afterassignment\tikz@lib@dv@parse@loop% + \let\tikz@dummy=%get rid of \bgroup + }{% + \tikzerror{Opening brace expected}% + \tikz@lib@dv@parse@loop% + }% +}% + +\def\tikz@lib@dv@handle@data@group@use#1#2{% + \pgfdata[#1,use group=#2]% +}% + +\def\tikz@lib@dv@handle@data@point point{\pgfutil@ifnextchar[{\tikz@lib@dv@handle@data@point@opt}{\tikz@lib@dv@handle@data@point@opt[]}}%]% +\def\tikz@lib@dv@handle@data@point@opt[#1]{% + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data({{\bgroup\pgfkeys{/data point/.cd,#1}\pgfdatapoint\egroup}})}% + \tikz@lib@dv@parse@loop% +}% + +\def\tikz@lib@dv@handle@info info{% + \pgfutil@ifnextchar'{\tikz@lib@dv@handle@info@prime}{\tikz@lib@dv@handle@info@noprime}}% +\def\tikz@lib@dv@handle@info@noprime{% + \pgfutil@ifnextchar[{\tikz@lib@dv@handle@info@block@opt}{\tikz@lib@dv@handle@info@block@opt[]}}%}% +\def\tikz@lib@dv@handle@info@block@opt[#1]#2{% + \tikz@main@dv.after visualization({\scope[#1]#2\endscope})% + \tikz@lib@dv@parse@loop +}% +\def\tikz@lib@dv@handle@info@prime'{% + \pgfutil@ifnextchar[{\tikz@lib@dv@handle@info@block@opt@prime}{\tikz@lib@dv@handle@info@block@opt@prime[]}}%}% +\def\tikz@lib@dv@handle@info@block@opt@prime[#1]#2{% + \tikz@main@dv.before visualization({\scope[#1]#2\endscope})% + \tikz@lib@dv@parse@loop +}% + + +\pgfset{/pgf/every data/.style={/tikz/every data/.try,/tikz/data visualization/every data/.try}}% + + +% +% Performing before/after stuff via keys +% + +\tikzdatavisualizationset{ + before survey/.code=\tikz@main@dv.before survey({#1}), + after survey/.code=\tikz@main@dv.after survey({#1}), + before visualization/.code=\tikz@main@dv.before visualization({#1}), + after visualization/.code=\tikz@main@dv.after visualization({#1}), + at start survey/.code=\tikz@main@dv.at start survey({#1}), + at end survey/.code=\tikz@main@dv.at end survey({#1}), + at start visualization/.code=\tikz@main@dv.at start visualization({#1}), + at end visualization/.code=\tikz@main@dv.at end visualization({#1}), +}% + + +\def\tikz@lib@dv@alias@dv@bb{ + \pgfnodealias{data bounding box}{data visualization bounding box}% + \pgfkeys{/pgf/freeze local bounding box=data bounding box}% +}% + +% +% The data point key +% +\tikzdatavisualizationset{ + data point/.code={ + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data({{\bgroup\pgfkeys{/data point/.cd,#1}\pgfdatapoint\egroup}})}% + } +}% + + +% +% Object setup +% + +% The following key is used to create objects for the rendering +% pipeline. They cannot be created "directly" because when it is known +% that the objects needs to be created, in principle, many keys may +% not yet be known. +% +% The following options are used: +% +% store = key that will store the object (handle) +% class = class of the object +% arg1 = argument1 of the constructor +% ... +% arg8 = argument8 of the constructor +% when = specifies when the object will be created. Defaults to +% "before survey", other possible values are "after survey" and +% "before/after visualization" +% before creation = code to be executed just before the object is +% created +% after creation = code to be executed just after the object has been created +% +% The following styles may be useful: +% +% arg1 from key = use the contents of the given key as arg1. Similar +% for other args +% arg1 handle from key = the contents of the given key should contain +% an object. Then arg1 will be a handle to this +% object. Similar for other args + +\tikzdatavisualizationset{% + new object/.code={% + \def\tikz@dv@grabbed@when{before survey}% + \let\tikz@dv@grabbed@store\pgfutil@empty + \pgfkeys{/tikz/data visualization/new object/grab/.cd,#1}% + \ifx\tikz@dv@grabbed@store\pgfutil@empty + \else + \pgfkeyslet{\tikz@dv@grabbed@store}\pgfutil@empty% + \fi + \edef\tikz@marshal{\noexpand\tikz@main@dv.\tikz@dv@grabbed@when(\noexpand\tikz@dv@newobject{\tikz@dv@grabbed@store}}% + \tikz@marshal{#1})% + }, + new object/grab/store/.store in=\tikz@dv@grabbed@store, + new object/grab/when/.store in=\tikz@dv@grabbed@when, + new object/grab/.unknown/.code={},%ignore +}% + +\def\tikz@dv@newobject#1#2{% + \def\tikz@dv@new@obj@store{#1}% + \ifx\tikz@dv@new@obj@store\pgfutil@empty% + \let\tikz@dv@new@obj=\pgfutil@empty% + \else% + \pgfkeysgetvalue\tikz@dv@new@obj@store\tikz@dv@new@obj% + \fi% + \ifx\tikz@dv@new@obj\pgfutil@empty + \let\tikz@dv@arg@a=\tikz@lib@notused% + \let\tikz@dv@arg@b=\tikz@lib@notused% + \let\tikz@dv@arg@c=\tikz@lib@notused% + \let\tikz@dv@arg@d=\tikz@lib@notused% + \let\tikz@dv@arg@e=\tikz@lib@notused% + \let\tikz@dv@arg@f=\tikz@lib@notused% + \let\tikz@dv@arg@g=\tikz@lib@notused% + \let\tikz@dv@arg@h=\tikz@lib@notused% + \let\tikz@dv@new@after=\relax% + \pgfkeys{/tikz/data visualization/new object/parse/.cd,#2} + \edef\pgf@marshal{\noexpand\pgfoonew\noexpand\tikzdvobj=new \tikz@dv@new@class(}% + \tikz@dv@add@arg{}\tikz@dv@arg@a% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@b% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@c% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@d% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@e% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@f% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@g% + \tikz@dv@add@arg{\expandafter,}\tikz@dv@arg@h% + \expandafter\def\expandafter\pgf@marshal\expandafter{\pgf@marshal)}% + \pgf@marshal% + \tikzdvobj.default connects()% + \ifx\tikz@dv@new@obj@store\pgfutil@empty% + \else% + \pgfkeyslet\tikz@dv@new@obj@store\tikzdvobj% + \fi% + \tikz@dv@new@after% + \fi +}% +\def\tikz@lib@notused{\tikz@lib@notused}% + +\def\tikz@dv@add@arg#1#2{% + \ifx#2\tikz@lib@notused% + \else% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@marshal% + \expandafter\expandafter\expandafter{\expandafter\pgf@marshal#1#2}% + \fi% +}% + +\tikzdatavisualizationset{% + new object/parse/.cd, + store/.code=,% ignore + when/.code=,% ignore + class/.store in=\tikz@dv@new@class, + before creation/.code={#1}, + after creation/.store in=\tikz@dv@new@after, + arg1/.store in=\tikz@dv@arg@a, + arg2/.store in=\tikz@dv@arg@b, + arg3/.store in=\tikz@dv@arg@c, + arg4/.store in=\tikz@dv@arg@d, + arg5/.store in=\tikz@dv@arg@e, + arg6/.store in=\tikz@dv@arg@f, + arg7/.store in=\tikz@dv@arg@g, + arg8/.store in=\tikz@dv@arg@h, + arg1 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@a}, + arg2 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@b}, + arg3 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@c}, + arg4 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@d}, + arg5 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@e}, + arg6 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@f}, + arg7 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@g}, + arg8 from key/.code=\pgfkeysgetvalue{#1}{\tikz@dv@arg@h} + arg1 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@a}{\tikz@dv@arg@a}, + arg2 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@b}{\tikz@dv@arg@b}, + arg3 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@c}{\tikz@dv@arg@c}, + arg4 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@d}{\tikz@dv@arg@d}, + arg5 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@e}{\tikz@dv@arg@e}, + arg6 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@f}{\tikz@dv@arg@f}, + arg7 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@g}{\tikz@dv@arg@g}, + arg8 handle from key/.code=\tikz@dv@handle@from@key{#1}{\tikz@dv@handle@h}{\tikz@dv@arg@h} +}% + +\def\tikz@dv@handle@from@key#1#2#3{% + \pgfkeysvalueof{#1}.get handle(#2)% + \def#3{#2}% +}% + + + + +% +% Data visualization coordinate system +% +% +% This cs is used to refer to points in a datavisualization. The +% parameters are keys that are set in the /data point key +% directory. Then, a (virtual) data point is created and the +% calculated position is returned + +\tikzdeclarecoordinatesystem{visualization} +{% + \tikzset{/data point/.cd,#1}% + \pgfpointdvlocaldatapoint% +}% + + + + +% +% +% Axes +% +% + + + +% +% Axis base +% + +\tikzdatavisualizationset{% + new axis base/.style={ + new object={ + class=scaling mapper, + store=/tikz/data visualization/#1/scaling mapper, + before creation={ + \pgfkeysgetvalue{/tikz/data visualization/#1/scaling}\tikz@temp + \ifx\tikz@temp\pgfutil@empty% + \pgfkeysgetvalue{/tikz/data visualization/#1/scaling/default}\tikz@temp + \fi + \expandafter\tikz@dv@lib@parse@scaling\tikz@temp\pgf@stop% + \pgfkeyslet{/tikz/data visualization/#1/scaling}\tikz@temp + }, + arg1 from key=/tikz/data visualization/#1/attribute, + arg2/.expanded=\pgfkeysvalueof{/tikz/data visualization/#1/attribute}/scaled, + arg3 from key=/tikz/data visualization/#1/scaling, + arg4 from key=/tikz/data visualization/#1/function + }, + #1/attribute/.initial={#1}, + #1/function/.initial=, + #1/scaling/.initial=, + #1/scaling/default/.initial=0 at 0 and 1 at 1, + #1/ticks at/.initial=, + #1/default ticks at/.initial=, + #1/major ticks/.initial=, + #1/minor ticks/.initial=, + #1/subminor ticks/.initial=, + #1/grid at/.initial=, + #1/default grid at/.initial=, + #1/major grid/.initial=, + #1/minor grid/.initial=, + #1/subminor grid/.initial=, + #1/label/.initial=, + #1/padding min/.initial=, + #1/padding max/.initial=, + #1/.code={ + \let\tikz@temp\tikz@dv@axis% + \def\tikz@dv@axis{/tikz/data visualization/#1}% + \expandafter\tikz@do@axis@options\expandafter{\tikz@temp}{##1}% + }, + #1/@compute at positions/.initial=\tikz@lib@dv@compute@at@linear, + axes list/.append={\tikz@lib@dv@do@axis{#1}} + }, + all axes/.code={ + \def\tikz@lib@dv@args{#1}% + \pgfkeysvalueof{/tikz/data visualization/axes list}% + }, + % General styling + styling/.style=, + style/.style={styling/.append style={#1}}, + @node styling/.initial=, + node styling/.style={% + /utils/exec={\pgfkeysgetvalue{/tikz/data visualization/@node styling}\tikz@temp\expandafter\tikzset\expandafter{\tikz@temp}}}, + node style/.style={/tikz/data visualization/@node styling/.append={,#1}}, + % General extends (both axes, grid and ticks) + low/.initial=0, + high/.initial=0, + padded/.style={low=padded min,high=padded max}, + tick length/.style={low={-#1},high={#1}}, + % General tick and grid keys: + common/.initial=, + major/.initial=, + minor/.initial=, + subminor/.initial=, + @setup at setters/.style={ + common/.code=\tikz@lib@dv@add@{common}{##1}, + major/.code=\tikz@lib@dv@add@{major}{##1}, + minor/.code=\tikz@lib@dv@add@{minor}{##1}, + subminor/.code=\tikz@lib@dv@add@{subminor}{##1} + }, + @setup at setters, + % Tick keys + direction axis/.initial=, + % Tick text modifiers + tick text low even padding/.initial=0pt, + tick text high even padding/.initial=0pt, + tick text low odd padding/.initial=0pt, + tick text high odd padding/.initial=0pt, + tick text odd padding/.style={tick text low odd padding={-#1},tick text high odd padding={#1}}, + tick text even padding/.style={tick text low even padding={-#1},tick text high even padding={#1}}, + tick text padding/.style={tick text odd padding={#1},tick text even padding={#1}}, + stack/.style={tick text even padding={#1}}, + stack'/.style={tick text odd padding={#1}}, + stack/.default=1em, + stack'/.default=1em, + tick text at low/.is if=tikz@dv@min@tick@node, + tick text at high/.is if=tikz@dv@max@tick@node, + no tick text/.style={tick text at low=false,tick text at high=false}, + % + every major ticks/.style={style={line cap=round},tick length=2pt}, + every minor ticks/.style={style={solid, help lines,thin,line cap=round},tick length=1.4pt}, + every subminor ticks/.style={style={solid, help lines,line cap=round},tick length=0.8pt}, + clean ticks/.style={node style={fill=white}}, + % Default grid styles + every grid/.style={high=max,low=min}, + every major grid/.style={style={solid, help lines,thin,black!25}}, + every minor grid/.style={style={solid, help lines,black!25}}, + every subminor grid/.style={style={solid, help lines,black!10}}, + at default ticks/.code={% + \expandafter\pgfkeysalso\expandafter{\tikz@lib@dv@ticks@default@at}}, + at ticks/.code={% + \expandafter\pgfkeysalso\expandafter{\tikz@lib@dv@ticks@default@at}% + \expandafter\pgfkeysalso\expandafter{\tikz@lib@dv@ticks@at}}, +}% + +\def\tikz@lib@dv@add@#1#2{\pgfkeysaddvalue{/tikz/data visualization/#1}{}{,#2}}% + +\def\tikz@dv@lib@parse@scaling#1 at#2and #3 at#4\pgf@stop{% + \pgfmathsetmacro{\tikz@dv@lib@min@at}{#2} + \pgfmathsetmacro{\tikz@dv@lib@max@at}{#4} + \edef\tikz@temp{#1 at \tikz@dv@lib@min@at and #3 at \tikz@dv@lib@max@at}% +}% + + +% Ticks at +\tikzdatavisualizationset{ + at/.code={\def\tikz@dv@at@list{#1}}, + also at/.code={\expandafter\def\expandafter\tikz@dv@at@list\expandafter{\tikz@dv@at@list,#1}}, + major at/.style={major={at={#1}}}, + minor at/.style={minor={at={#1}}}, + subminor at/.style={subminor={at={#1}}}, + major also at/.style={major={also at={#1}}}, + minor also at/.style={minor={also at={#1}}}, + subminor also at/.style={subminor={also at={#1}}}, + options at/.code={\expandafter\def\expandafter\tikz@dv@style@at@list\expandafter{\tikz@dv@style@at@list,{#1}}}, + no tick text at/.style={options at={#1 as [no tick text]}} +}% + + +\def\tikz@lib@dv@do@axis#1{% + \def\tikz@marshal{#1=} + \expandafter\expandafter\expandafter\tikzdatavisualizationset% + \expandafter\expandafter\expandafter{\expandafter\tikz@marshal\expandafter{\tikz@lib@dv@args}} +}% + +\def\tikz@do@axis@options#1#2{ + \pgfkeys{/tikz/data visualization/axis options/.cd,#2} + \def\tikz@dv@axis{#1} +}% +\let\tikz@dv@axis\pgfutil@empty + +\tikzdatavisualizationset{ + every ticks/.style={ + node style={% + font=\pgfutil@font@footnotesize, + inner sep=1pt, + outer sep=.1666em, + rounded corners=1.5pt + } + }, + every data set label/.style={ + every ticks, + node style={ + font=\pgfutil@font@small, + } + }, + @color of visualizer labels/.style={text=black}, + every label in legend/.style={ + node style={ + fill=none, + } + }, + every axis label/.style={ + node style={% + font=\pgfutil@font@small, + } + } +}% + + +\tikzset{ + /tikz/data visualization/axis options/.cd, + % + % Basic setters + % + attribute/.style={\tikz@dv@axis/attribute={#1}}, + function/.style={\tikz@dv@axis/function={#1}}, + scaling/.style={\tikz@dv@axis/scaling={#1}}, + padding min/.style={\tikz@dv@axis/padding min={#1}}, + padding max/.style={\tikz@dv@axis/padding max={#1}}, + padding/.style={padding min={-#1},padding max={#1}}, + label/.code={% + \def\pgf@temp{#1}% + \ifx\pgf@temp\tikz@lib@dv@auto@attribute% + \tikzdatavisualizationset{\tikz@dv@axis/label/.expanded=$\noexpand\mathit{\pgfkeysvalueof{\tikz@dv@axis/attribute}}$}% + \else + \tikzdatavisualizationset{\tikz@dv@axis/label={#1}}% + \fi + }, + label/.default=\tikz@lib@dv@auto@attribute, + % + % Strategies + % + tick placement strategy/.style={\tikz@dv@axis/@compute at positions={#1}}, + linear steps/.style={tick placement strategy=\tikz@lib@dv@compute@at@linear}, + % + % Attribute setter + % + goto/.code={\tikz@dv@goto{\tikz@dv@axis}{#1}}, + goto pos/.code={\tikz@dv@goto@pos{\tikz@dv@axis}{#1}}, + anchor at min/.code={\tikz@lib@dv@special@at{\tikz@dv@axis}{\tikz@dv@min@anchor}}, + anchor at max/.code={\tikz@lib@dv@special@at{\tikz@dv@axis}{\tikz@dv@max@anchor}}, + % + % Visualization setters + % + visualize axis/.code=\expandafter\tikz@lib@dv@av\expandafter{\tikz@dv@axis}{#1}, + % + % Ticks settings + % + ticks/.style={\tikz@dv@axis/ticks at/.append={,#1}}, + ticks/.default=some, + visualize ticks/.code=\expandafter\tikz@lib@dv@tv\expandafter{\tikz@dv@axis}{#1}, + % + % Grid settings + % + grid/.style={\tikz@dv@axis/grid at/.append={,#1}}, + grid/.default=at default ticks, + visualize grid/.code=\expandafter\tikz@lib@dv@gv\expandafter{\tikz@dv@axis}{#1}, + % + ticks and grid/.style={\tikz@dv@axis/ticks at/.append={,#1},\tikz@dv@axis/grid at/.append={,#1}}, + % + % Visualizing axis labels + % + visualize label/.code=\expandafter\tikz@lib@dv@lv\expandafter{\tikz@dv@axis}{#1}, +}% + +\def\tikz@lib@dv@auto@attribute{\tikz@lib@dv@auto@attribute}% + + +% Range options +\tikzdatavisualizationset{ + axis options/.cd, + % + % Including a value in the range + % + include value/.style={% + /tikz/data visualization/before survey/.expanded={% + \noexpand\pgfkeysgetvalue{\tikz@dv@axis/scaling mapper}\noexpand\tikz@dv@axis@mapper% + \noexpand\foreach \noexpand\tikz@lib@dv@temp in {#1} {% + \noexpand\tikz@dv@axis@mapper.include in value(\noexpand\tikz@lib@dv@temp)% + }% + }% + }, + % + % Directly setting the min or max + % + min value/.style={ + /tikz/data visualization/at end survey/.expanded={% + \noexpand\pgfkeysgetvalue{\tikz@dv@axis/scaling mapper}\noexpand\tikz@dv@axis@mapper% + \noexpand\tikz@lib@dv@set\noexpand\tikz@dv@axis@mapper{#1}{min}% + } + }, + max value/.style={ + /tikz/data visualization/at end survey/.expanded={% + \noexpand\pgfkeysgetvalue{\tikz@dv@axis/scaling mapper}\noexpand\tikz@dv@axis@mapper% + \noexpand\tikz@lib@dv@set\noexpand\tikz@dv@axis@mapper{#1}{max}% + } + }, +}% + +\def\tikz@lib@dv@set#1#2#3{% + \pgfdvmathenter{\pgf@dv@value}{#2}% + #1.get in range interval()% + \pgfdvinrangeinterval.let #3(\pgf@dv@value)% +}% + +% Layer options +\tikzdatavisualizationset{ + axis layer/.style=on background layer, + ticks layer/.style=on background layer, + ticks node layer/.style=, + grid layer/.style=on background layer, +}% + + +% Axis visualization +% +% #1 = name of the to-be-visualized axis name +% #2 = options for the visualization + +\def\tikz@lib@dv@av#1#2{ + \tikzdatavisualizationset{ + axes actions/.append={\tikz@lib@dv@show@axis{#1}{#2}} + } +}% + +\def\tikz@lib@dv@show@axis#1#2{% + \scope[data visualization/axis layer,/tikz/data visualization/.cd,low=min,high=max,every axis/.try,#2] + \pgfkeysgetvalue{#1/scaling mapper}\tikz@dv@axis@mapper% + % Ok, calculate direction vector: + \tikzpointandanchordirection{\tikz@dv@axis@mapper.set in to(min)}{\tikz@dv@axis@mapper.set in to(max)} + \xdef\tikz@dv@axis@dir{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \path[draw,/tikz/data visualization/styling] + \pgfextra{ + { + \tikz@dv@goto{#1}{\pgfkeysvalueof{/tikz/data visualization/low}}% + \pgfpathdvmoveto% + } + { + \tikz@dv@goto{#1}{\pgfkeysvalueof{/tikz/data visualization/high}}% + \pgfpathdvlineto% + } + }; + \endscope +}% + +\def\tikz@dv@goto#1#2{% + \edef\pgf@@temp{#2}% + \ifx\pgf@@temp\tikz@lib@dv@padded@min@text% + \pgfkeysvalueof{#1/scaling mapper}.set in to(min)% + \pgfkeysvalueof{#1/scaling mapper}.get out()% + \pgfkeysgetvalue{#1/padding min}\pgf@temp% + \pgfmathparse{\pgf@temp}% + \pgfkeyslet{/data point/\pgfdvout/offset}\pgfmathresult% + \else% + \ifx\pgf@@temp\tikz@lib@dv@padded@max@text% + \pgfkeysvalueof{#1/scaling mapper}.set in to(max)% + \pgfkeysvalueof{#1/scaling mapper}.get out()% + \pgfkeysgetvalue{#1/padding max}\pgf@temp% + \pgfmathparse{\pgf@temp}% + \pgfkeyslet{/data point/\pgfdvout/offset}\pgfmathresult% + \else% + \pgfkeysvalueof{#1/scaling mapper}.set in to(#2)% + \fi% + \fi% +}% + +\def\tikz@dv@goto@pos#1#2{% + \pgfkeyssetvalue{/data point/\pgfkeysvalueof{#1/attribute}/out pos}{#2}% +}% + +\def\tikz@lib@dv@padded@min@text{padded min}% +\def\tikz@lib@dv@padded@max@text{padded max}% + +\def\tikz@lib@dv@special@at#1#2{% + % Ok, calculate direction vector: + \tikzpointandanchordirection{\pgfkeysvalueof{#1/scaling mapper}.set in to(min)}{\pgfkeysvalueof{#1/scaling mapper}.set in to(max)} + \tikzset{anchor/.expanded={#2}} +}% + + +% Ticks visualization +% +% #1 = name of axis on which ticks should be shown +% #2 = options for the visualization + +\def\tikz@lib@dv@tv#1#2{ + \tikzdatavisualizationset{ + ticks actions/.append={\tikz@lib@dv@default@action{ticks}{#1}{#2}}, + major ticks actions/.append={\tikz@lib@dv@show@ticks{major}{#1}{#2}}, + minor ticks actions/.append={\tikz@lib@dv@show@ticks{minor}{#1}{#2}}, + subminor ticks actions/.append={\tikz@lib@dv@show@ticks{subminor}{#1}{#2}} + } +}% + +\def\tikz@lib@dv@default@action#1#2#3{% + \let\tikz@marshal\pgfutil@empty% + {% + \let\tikz@lib@dv@ticks@at\pgfutil@empty% + \pgfkeysgetvalue{#2/ticks at}\tikz@lib@dv@ticks@default@at% + \pgfkeysgetvalue{#2/#1 at}\tikz@lib@dv@settings% + \pgfkeysgetvalue{#2/scaling mapper}\tikz@lib@dv@mapper + % Normal minor etc. have no effect. + \tikzdatavisualizationset{major/.code=,minor/.code=,subminor/.code=,common/.code=} + \expandafter\tikzdatavisualizationset\expandafter{\tikz@lib@dv@settings}% + \tikzdatavisualizationset{@setup at setters}% + \pgfkeysgetvalue{/tikz/data visualization/compute step}\tikz@temp@step% + \ifx\tikz@temp@step\pgfutil@empty% + % do nothing + \else% + \pgfkeysvalueof{#2/@compute at positions}% + \xdef\tikz@marshal{ + major={\pgfkeysvalueof{/tikz/data visualization/major}}, + minor={\pgfkeysvalueof{/tikz/data visualization/minor}}, + subminor={\pgfkeysvalueof{/tikz/data visualization/subminor}}} + \fi + }% + \pgfkeyslet{#2/default #1 at}\tikz@marshal +}% + +\def\tikz@lib@dv@show@ticks#1#2#3{% + % First, check whether there is anything to do at all: + \pgfkeysgetvalue{#2/default ticks at}\tikz@lib@dv@default@settings% + \ifx\tikz@lib@dv@default@settings\pgfutil@empty% + \pgfkeysgetvalue{#2/ticks at}\tikz@lib@dv@settings% + \else% + \pgfkeysgetvalue{#2/ticks at}\tikz@lib@dv@settings% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@dv@settings% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@dv@default@settings\expandafter,\tikz@lib@dv@settings} + \fi% + \ifx\tikz@lib@dv@settings\pgfutil@empty% + % Great, nothing to do + \else + {% + \let\tikz@dv@at@list\pgfutil@empty% + \let\tikz@dv@style@at@list\pgfutil@empty% + \pgfkeysgetvalue{#2/scaling mapper}\tikz@lib@dv@mapper + \scope[/tikz/data visualization/.cd,every ticks/.try,every #1 ticks/.try,#3]% + % Setup options + \expandafter\tikzdatavisualizationset\expandafter{\tikz@lib@dv@settings}% + \pgfkeysgetvalue{/tikz/data visualization/common}\tikz@temp + \expandafter\tikzdatavisualizationset\expandafter{\tikz@temp} + \pgfkeysgetvalue{/tikz/data visualization/#1}\tikz@temp + \expandafter\tikzdatavisualizationset\expandafter{\tikz@temp} + \pgfkeysgetvalue{/tikz/data visualization/\pgfkeysvalueof{/tikz/data visualization/direction axis}/scaling mapper}\pgf@dv@tick@dir@mapper + % Ok, now it's time to draw the ticks! + \foreach \tikz@dv@tick@pos[count=\tikz@dv@tick@count] in \tikz@dv@at@list + { + \ifx\tikz@dv@tick@pos\pgfutil@empty + \c@pgf@counta=\tikz@dv@tick@count\relax% + \advance\c@pgf@counta by-1\relax% + \edef\tikz@dv@tick@count{\the\c@pgf@counta}% + \else + \expandafter\tikz@lib@dv@parse\tikz@dv@tick@pos\pgf@stop% + \expandafter\tikzdatavisualizationset\expandafter{\tikz@lib@dv@tick@opt}% + \tikz@lib@dv@mapper.set in to(\tikz@dv@tick@pos)% + % First, compute position of tick: + \pgf@process{\pgfpointdvlocaldatapoint} + \xdef\pgf@dv@tick@origin{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + % Ok, calculate direction vector: + \tikzpointandanchordirection{\pgf@dv@tick@dir@mapper.set in to(min)}{\pgf@dv@tick@dir@mapper.set in to(max)} + \xdef\pgf@dv@tick@dir{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + % Now, show something: + \tikz@lib@handle@at@style% + \pgfkeysgetvalue{/tikz/data visualization/high}\tikz@dv@max@val% + \pgfkeysgetvalue{/tikz/data visualization/low}\tikz@dv@min@val% + \iftikz@dv@max@tick@node\pgfmathsetmacro\tikz@dv@max@val{% + \tikz@dv@max@val+(\pgfkeysvalueof{% + /tikz/data visualization/tick text high + \ifodd\tikz@dv@tick@count odd \else even \fi padding}% + )}% + \fi% + \iftikz@dv@min@tick@node\pgfmathsetmacro\tikz@dv@min@val{% + \tikz@dv@min@val+(\pgfkeysvalueof{% + /tikz/data visualization/tick text low + \ifodd\tikz@dv@tick@count odd \else even \fi padding}% + )}% + \fi% + \pgf@process{\pgfpointadd{\pgf@dv@tick@origin}{\pgfpointscale{\tikz@dv@max@val}{\pgf@dv@tick@dir}}} + \xdef\tikz@dv@max@tick{\the\pgf@x,\the\pgf@y} + \pgf@process{\pgfpointadd{\pgf@dv@tick@origin}{\pgfpointscale{\tikz@dv@min@val}{\pgf@dv@tick@dir}}} + \xdef\tikz@dv@min@tick{\the\pgf@x,\the\pgf@y} + \scope[data visualization/ticks layer] + \tikzdatavisualizationset{every \ifodd\tikz@dv@tick@count odd \else even \fi tick/.try} + \draw [/tikz/data visualization/styling] (\tikz@dv@min@tick) -- (\tikz@dv@max@tick); + \endscope + \iftikz@dv@min@tick@node + \scope[data visualization/ticks node layer] + \tikzdatavisualizationset{every \ifodd\tikz@dv@tick@count odd \else even \fi tick/.try} + \path [/tikz/data visualization/styling] (\tikz@dv@min@tick) \tikz@dv@handle@tick{\tikz@dv@min@anchor}; + \endscope + \fi + \iftikz@dv@max@tick@node + \scope[data visualization/ticks node layer] + \tikzdatavisualizationset{every \ifodd\tikz@dv@tick@count odd \else even \fi tick/.try} + \path [/tikz/data visualization/styling] (\tikz@dv@max@tick) \tikz@dv@handle@tick{\tikz@dv@max@anchor}; + \endscope + \fi + \fi + } + \endscope + } + \fi +}% + +\def\tikz@lib@dv@parse#1\pgf@stop{% + \pgfutil@in@{as}{#1}% + \ifpgfutil@in@% + \tikz@lib@dv@parse@as#1\pgf@stop% + \else% + \tikz@lib@dv@parse@as#1as\tikz@lib@dv@typeset\pgf@stop% + \fi% +}% +\def\tikz@lib@dv@parse@as#1as{% + \def\tikz@dv@tick@pos{#1}% + \pgfutil@ifnextchar[{\tikz@lib@dv@parse@as@opt}{\tikz@lib@dv@parse@as@opt[]}%] +}% +\def\tikz@lib@dv@parse@as@opt[#1]{% + \def\tikz@lib@dv@tick@opt{#1}% + \pgfutil@ifnextchar\pgf@stop{\tikz@lib@dv@parse@as@text\tikz@lib@dv@typeset}{\tikz@lib@dv@parse@as@text} +}% +\def\tikz@lib@dv@parse@as@text#1\pgf@stop{% + \def\tikz@lib@dv@tick@text{#1}% +}% + +\def\tikz@lib@dv@typeset{% + \pgfdvmathenter{\tikz@lib@dv@typesetnum}{\tikz@dv@tick@pos}% + \pgfdvmathexitbyscientificformat{\tikz@lib@dv@typesetnum}{\tikz@lib@dv@typesetnum}% hmm... not sure about this... + \pgfkeysvalueof{/tikz/data visualization/tick prefix}% + \pgfkeys{/tikz/data visualization/tick typesetter=\tikz@lib@dv@typesetnum}% + \pgfkeysvalueof{/tikz/data visualization/tick suffix}% +}% + +\newif\iftikz@dv@min@tick@node +\newif\iftikz@dv@max@tick@node + +\def\tikz@dv@handle@tick#1{% + \pgfextra{ + \ifx\tikz@lib@dv@tick@text\pgfutil@empty% + \global\let\tikz@dv@tick@marshal=\pgfutil@empty% Skip! + \else + \def\tikz@dv@tick@marshal{node[anchor=#1,/tikz/data visualization/node styling]}% + \expandafter\pgfutil@g@addto@macro\expandafter\tikz@dv@tick@marshal\expandafter{\expandafter{\tikz@lib@dv@tick@text}} + \fi + \expandafter}% + \tikz@dv@tick@marshal +}% + + +\def\tikz@lib@handle@at@style{% + \ifx\tikz@dv@style@at@list\pgfutil@empty% nothing to do + \else% + \let\tikz@dv@lib@this@at@style=\pgfutil@empty% + \pgfdvmathenter{\tikz@temp}{\tikz@dv@tick@pos}% + \pgfdvmathexitbyscientificformat{\tikz@dv@compare@to}{\tikz@temp}% + \foreach \tikz@dv@at@style in \tikz@dv@style@at@list {% + \ifx\tikz@dv@at@style\pgfutil@empty% + \else% + \expandafter\tikz@dv@lib@handle@one@at@style\tikz@dv@at@style\tikz@stop% + \fi% + } + \ifx\tikz@dv@lib@this@at@style\pgfutil@empty% + \else% + \expandafter\tikzdatavisualizationset\expandafter{\tikz@dv@lib@this@at@style}% + \fi% + \fi% +}% + +\def\tikz@dv@lib@handle@one@at@style#1as#2[#3]#4\tikz@stop{% + \pgfdvmathenter{\tikz@lib@dv@at@math@var}{#1}% + \pgfdvmathexitbyscientificformat{\tikz@dv@temp}{\tikz@lib@dv@at@math@var}% + \ifx\tikz@dv@temp\tikz@dv@compare@to% + % Bingo! + \expandafter\gdef\expandafter\tikz@dv@lib@this@at@style\expandafter{\tikz@dv@lib@this@at@style,#3}% + \fi% +}% + + +% Help function +\def\tikzpointandanchordirection#1#2{% + % This function works like pgfpointdvdirection, but also computes + % appropriate "min" and "max" anchors. + \pgf@process{\pgfpointdvdirection{#1}{#2}} + { + \pgf@ya=\pgf@y + \pgf@y=-\pgf@x + \pgf@x=\pgf@ya + \tikz@auto@anchor + \xdef\tikz@dv@max@anchor{\tikz@anchor} + \tikz@auto@anchor@prime + \xdef\tikz@dv@min@anchor{\tikz@anchor} + } +}% + + + + +% Grid visualization +% +% #1 = name of axis on which grid lines should be shown +% #2 = options for the visualization + +\def\tikz@lib@dv@gv#1#2{ + \tikzdatavisualizationset{ + grid actions/.append={\tikz@lib@dv@default@action{grid}{#1}{#2}}, + major grid actions/.append={\tikz@lib@dv@show@grid{major}{#1}{#2}}, + minor grid actions/.append={\tikz@lib@dv@show@grid{minor}{#1}{#2}}, + subminor grid actions/.append={\tikz@lib@dv@show@grid{subminor}{#1}{#2}}, + } +}% + +\def\tikz@lib@dv@show@grid#1#2#3{% + % First, check whether there is anything to do at all: + \pgfkeysgetvalue{#2/default grid at}\tikz@lib@dv@default@settings% + \ifx\tikz@lib@dv@default@settings\pgfutil@empty% + \pgfkeysgetvalue{#2/grid at}\tikz@lib@dv@settings% + \else% + \pgfkeysgetvalue{#2/grid at}\tikz@lib@dv@settings% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@dv@settings% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@dv@default@settings\expandafter,\tikz@lib@dv@settings} + \fi% + \ifx\tikz@lib@dv@settings\pgfutil@empty% + % Great, nothing to do + \else + {% + \let\tikz@dv@at@list\pgfutil@empty + \let\tikz@dv@style@at@list\pgfutil@empty + \pgfkeysgetvalue{#2/scaling mapper}\tikz@lib@dv@mapper + \let\tikz@lib@dv@ticks@default@at\pgfutil@empty% + \scope[data visualization/grid layer,/tikz/data visualization/.cd,every #1 grid/.try,every grid,#3] + % Setup options + \pgfkeysgetvalue{#2/ticks at}\tikz@lib@dv@ticks@at% + \expandafter\tikzdatavisualizationset\expandafter{\tikz@lib@dv@settings}% + \pgfkeysgetvalue{/tikz/data visualization/common}\tikz@temp + \expandafter\tikzdatavisualizationset\expandafter{\tikz@temp} + \pgfkeysgetvalue{/tikz/data visualization/#1}\tikz@temp + \expandafter\tikzdatavisualizationset\expandafter{\tikz@temp} + \edef\tikz@lib@dv@dir@axis{/tikz/data visualization/\pgfkeysvalueof{/tikz/data visualization/direction axis}}% + % Ok, now it's time to draw the grid! + \foreach \tikz@dv@grid@pos in \tikz@dv@at@list + { + \ifx\tikz@dv@grid@pos\pgfutil@empty + \else + \expandafter\tikz@lib@dv@parse\tikz@dv@grid@pos\pgf@stop% + \expandafter\tikzdatavisualizationset\expandafter{\tikz@lib@dv@tick@opt}% + \tikz@lib@dv@mapper.set in to(\tikz@dv@tick@pos)% + \draw[/tikz/data visualization/styling] + \pgfextra{ + % First, compute start of grid: + \tikz@dv@goto{\tikz@lib@dv@dir@axis}{\pgfkeysvalueof{/tikz/data visualization/low}}% + \pgfpathdvmoveto% + \tikz@dv@goto{\tikz@lib@dv@dir@axis}{\pgfkeysvalueof{/tikz/data visualization/high}}% + \pgfpathdvlineto% + }; + \fi + } + \endscope + } + \fi +}% + + + + + + + + + +% +% Label visualization +% + +\def\tikz@lib@dv@lv#1#2{ + \tikzdatavisualizationset{ + label actions/.append={\tikz@lib@dv@show@label{#1}{#2}} + } +}% + +\def\tikz@lib@dv@show@label#1#2{% + % First, check whether there is anything to do at all: + \pgfkeysgetvalue{#1/label}\tikz@dv@lib@label% + \ifx\tikz@dv@lib@label\pgfutil@empty% + % Great, nothing to do + \else + \scope[anchor=center,/tikz/data visualization/.cd,every axis label/.try,#2] + \expandafter\tikz@lib@dv@parse@node\tikz@dv@lib@label\pgf@stop + \endscope + \fi +}% + +\def\tikz@lib@dv@parse@node{\pgfutil@ifnextchar[\tikz@lib@dv@parse@node@opt{\tikz@lib@dv@parse@node@opt[]}}%}% +\def\tikz@lib@dv@parse@node@opt[#1]#2\pgf@stop{ + \tikzdatavisualizationset{#1} + \pgftransformshift{\pgfpointdvlocaldatapoint}% + \node [/tikz/data visualization/node styling] {#2}; +}% + + + +% +% Tick placement strategies +% + +\tikzdatavisualizationset{ + compute step/.initial=, + step/.style={compute step=\def\tikz@lib@dv@step{#1}}, + minor steps between steps/.initial=, + minor steps between steps/.default=9, + phase/.initial=0, + tick typesetter/.code=\pgfmathprintnumber{#1}, + tick prefix/.initial=, + tick suffix/.initial=, + tick unit/.style={tick suffix={$\,\pgfutil@font@normalfont#1$}},% this is an alias +}% + +\def\tikz@lib@dv@compute@at@linear{% + % Setup about: + \let\tikz@lib@dv@compute@about=\tikz@lib@dv@about@linear% + \let\tikz@lib@dv@step\relax% + \pgfkeysvalueof{/tikz/data visualization/compute step} + \ifx\tikz@lib@dv@step\relax% + \else% + % Gather interesting values + \tikz@lib@dv@mapper.get in range interval()% + \pgfdvinrangeinterval.get min and max()% + \pgfkeysgetvalue{/tikz/data visualization/phase}\tikz@temp + \pgfdvmathenter{\tikz@dv@lib@phase}{\tikz@temp} + \pgfdvmathenter{\tikz@dv@lib@step}{\tikz@lib@dv@step} + \pgfdvmathifless{\pgfdvmathalwayszero}{\tikz@dv@lib@step}{% + % Compute start: + \pgfdvmathsub{\tikz@dv@lib@temp}{\pgfdvmin}{\tikz@dv@lib@phase}% temp = dvmin - phase + \pgfdvmathdiv{\tikz@dv@lib@temp}{\tikz@dv@lib@temp}{\tikz@dv@lib@step}% temp = temp/step + \pgfdvmathfloor{\tikz@dv@lib@temp}{\tikz@dv@lib@temp}% temp = floor(temp) + \pgfdvmathmul{\tikz@lib@dv@current}{\tikz@dv@lib@temp}{\tikz@dv@lib@step}% current = temp*step ... + \pgfdvmathadd{\tikz@lib@dv@current}{\tikz@lib@dv@current}{\tikz@dv@lib@phase}% + phase + \let\tikz@lib@dv@ats\pgfutil@empty% + \let\tikz@lib@dv@minor@ats\pgfutil@empty% + \tikz@lib@dv@mapper.get function(\tikz@temp)% + \ifx\tikz@temp\pgfutil@empty% + \pgfdvmathenter{\tikz@one@hundreth}{0.001}% + \pgfdvmathsub{\tikz@lib@temp}{\pgfdvmax}{\pgfdvmin}% + \pgfdvmathmul{\tikz@lib@dv@epsilon}{\tikz@lib@temp}{\tikz@one@hundreth}% epsilon = (max - min)/1000 + \else + \let\tikz@lib@dv@epsilon\pgfdvmathalwayszero + \fi + \pgfdvmathsub{\tikz@lib@dv@min@minus@epsilon}{\pgfdvmin}{\tikz@lib@dv@epsilon}% + \pgfdvmathadd{\tikz@lib@dv@max@plus@epsilon}{\pgfdvmax}{\tikz@lib@dv@epsilon}% + \pgfkeysgetvalue{/tikz/data visualization/minor steps between steps}\tikz@lib@dv@substeps% + \ifx\tikz@lib@dv@substeps\pgfutil@empty + \else + \pgfmathsetmacro\tikz@temp{\tikz@lib@dv@substeps+1}% + \pgfdvmathenter{\tikz@dv@lib@substeps}{\tikz@temp}% + \pgfdvmathdiv{\tikz@lib@dv@substep}{\tikz@dv@lib@step}{\tikz@dv@lib@substeps}% + \fi + \loop% + \ifx\tikz@lib@dv@substeps\pgfutil@empty% + \else% + \let\tikz@lib@dv@subcurrent=\tikz@lib@dv@current% + \pgfmathsetcount{\c@pgf@counta}{\tikz@lib@dv@substeps}% + \let\tikz@lib@dv@next=\tikz@lib@dv@subloop% + \tikz@lib@dv@subloop + \fi% + \pgfdvmathifless{\tikz@lib@dv@current}{\tikz@lib@dv@min@minus@epsilon}{}{% + \pgfdvmathexitbyserializing{\tikz@temp}{\tikz@lib@dv@current}% + \edef\tikz@lib@dv@ats{\tikz@lib@dv@ats,\tikz@temp}% + } + \pgfdvmathadd{\tikz@lib@dv@current}{\tikz@lib@dv@current}{\tikz@dv@lib@step}% + \pgfdvmathifless{\tikz@lib@dv@current}{\tikz@lib@dv@max@plus@epsilon}{\tikz@lib@dv@continuetrue}{\tikz@lib@dv@continuefalse}% + \iftikz@lib@dv@continue% + \repeat% + \tikzdatavisualizationset{major/.expanded={at={\tikz@lib@dv@ats}},minor/.expanded={at={\tikz@lib@dv@minor@ats}}}% + }{% + \pgfdvmathexitbyserializing{\tikz@temp}{\pgfdvmin}% + \tikzdatavisualizationset{major/.expanded={at={\tikz@temp}}}% + }% + \fi% +}% +\newif\iftikz@lib@dv@continue + +\def\tikz@lib@dv@subloop{ + \pgfdvmathadd{\tikz@lib@dv@subcurrent}{\tikz@lib@dv@subcurrent}{\tikz@lib@dv@substep}% + \pgfdvmathifless{\tikz@lib@dv@subcurrent}{\pgfdvmin}{}{% + \pgfdvmathifless{\tikz@lib@dv@subcurrent}{\pgfdvmax}{% + \pgfdvmathexitbyserializing{\tikz@temp}{\tikz@lib@dv@subcurrent}% + \edef\tikz@lib@dv@minor@ats{\tikz@lib@dv@minor@ats,\tikz@temp} + }{}} + \advance\c@pgf@counta by-1\relax% + \ifnum\c@pgf@counta=0\relax% + \let\tikz@lib@dv@next=\relax + \fi + \tikz@lib@dv@next +}% + + + +% +% Ticks about settings +% + +\tikzdatavisualizationset{ + about/.style={compute step=\tikz@lib@dv@compute@about{#1}}, + about strategy/.initial=, + standard about strategy/.style={about strategy={1.5/1.0,2.3/2.0,4/2.5,7/5,11/10}}, + standard about strategy, + euro about strategy/.style={about strategy={1.5/1.0,3/2.0,7/5,11/10}}, + decimal about strategy/.style={about strategy={3/1.0,11/10}}, + half about strategy/.style={about strategy={2/1.0,7/5,11/10}}, + quarter about strategy/.style={about strategy={1.8/1.0,4/2.5,7/5,11/10}}, + int about strategy/.style={about strategy={1.5/1.0,2.5/2.0,3.5/3.0,4.5/4.0,7/5,11/10}}, + none/.style={compute step=}, + few/.style={about=3}, + some/.style={about=5}, + many/.style={about=10}, +}% + +\def\tikz@lib@dv@about@linear#1{% + \tikz@lib@dv@mapper.get in range interval()% + \pgfdvinrangeinterval.get min and max()% + \pgfdvmathsub{\tikz@lib@dv@diff}{\pgfdvmax}{\pgfdvmin} + \pgfdvmathenter{\tikz@lib@dv@about@val}{#1}% + \pgfdvmathdiv{\tikz@lib@dv@around}{\tikz@lib@dv@diff}{\tikz@lib@dv@about@val}% + % Make mantisse sensible + \pgfmathfloattomacro{\tikz@lib@dv@around}{\tikz@lib@dv@flags}{\tikz@lib@dv@mant}{\tikz@lib@dv@exp}% + \pgf@xc=\tikz@lib@dv@mant pt % + \pgfkeysgetvalue{/tikz/data visualization/about strategy}\tikz@lib@dv@strat + \foreach \tikz@lib@dv@threshold/\tikz@lib@replace in \tikz@lib@dv@strat + { + \ifdim\pgf@xc<\tikz@lib@dv@threshold pt% + \global\pgf@xc=\tikz@lib@replace pt% + \breakforeach + \fi + }% + \ifdim\pgf@xc<10pt% + \pgfmathfloatcreate{\tikz@lib@dv@flags}{\pgf@sys@tonumber{\pgf@xc}}{\tikz@lib@dv@exp}% + \else + \begingroup + \c@pgf@countd=\tikz@lib@dv@exp + \advance\c@pgf@countd by1 + \edef\tikz@lib@dv@exp{\the\c@pgf@countd}% + \pgfmath@smuggleone\tikz@lib@dv@exp + \endgroup + \divide\pgf@xc by 10\relax + \pgfmathfloatcreate{\tikz@lib@dv@flags}{\pgf@sys@tonumber{\pgf@xc}}{\tikz@lib@dv@exp}% + \fi + \pgfmathfloattofixed{\pgfmathresult}% + \let\tikz@lib@dv@step=\pgfmathresult +}% + + + + + +% +% Logarithmic axes +% + +\tikzset{ + /tikz/data visualization/axis options/.cd, + exponential steps/.style={tick placement strategy=\tikz@lib@dv@compute@at@log}, + % + % Basic setters + % + logarithmic/.style={ + \tikz@dv@axis/function=\pgfdvmathln{\pgfvalue}{\pgfvalue}, + \tikz@dv@axis/scaling/default=1 at 0 and 10 at 1, + exponential steps + } +}% + +\def\tikz@lib@dv@compute@at@log{% + % Setup about: + \let\tikz@lib@dv@compute@about=\tikz@lib@dv@about@log% + \let\tikz@lib@dv@step\relax% + \pgfkeysvalueof{/tikz/data visualization/compute step} + \ifx\tikz@lib@dv@step\relax% + \else% + % Gather interesting values + \tikz@lib@dv@mapper.get in range interval()% + \pgfdvinrangeinterval.get min and max()% + \pgfdvmathlog{\pgfdvminlog}{\pgfdvmin}% + \pgfdvmathlog{\pgfdvmaxlog}{\pgfdvmax}% + \pgfkeysgetvalue{/tikz/data visualization/phase}\tikz@temp + \pgfdvmathenter{\tikz@dv@lib@phase}{\tikz@temp} + \pgfdvmathenter{\tikz@dv@lib@step}{\tikz@lib@dv@step} + % Compute start: + \pgfdvmathsub{\tikz@dv@lib@temp}{\pgfdvminlog}{\tikz@dv@lib@phase}% temp = dvmin - phase + \pgfdvmathdiv{\tikz@dv@lib@temp}{\tikz@dv@lib@temp}{\tikz@dv@lib@step}% temp = temp/step + \pgfdvmathfloor{\tikz@dv@lib@temp}{\tikz@dv@lib@temp}% temp = floor(temp) + \pgfdvmathmul{\tikz@lib@dv@current}{\tikz@dv@lib@temp}{\tikz@dv@lib@step}% current = temp*step ... + \pgfdvmathadd{\tikz@lib@dv@current}{\tikz@lib@dv@current}{\tikz@dv@lib@phase}% + phase + \let\tikz@lib@dv@ats\pgfutil@empty% + \let\tikz@lib@dv@minor@ats\pgfutil@empty% + \pgfdvmathenter{\tikz@one@hundreth}{0.001}% + \pgfdvmathsub{\tikz@lib@temp}{\pgfdvmaxlog}{\pgfdvminlog}% + \pgfdvmathmul{\tikz@lib@dv@epsilon}{\tikz@lib@temp}{\tikz@one@hundreth}% epsilon = (max - min)/100 + \pgfdvmathsub{\tikz@lib@dv@min@minus@epsilon}{\pgfdvminlog}{\tikz@lib@dv@epsilon}% + \pgfdvmathadd{\tikz@lib@dv@max@plus@epsilon}{\pgfdvmaxlog}{\tikz@lib@dv@epsilon}% + \pgfkeysgetvalue{/tikz/data visualization/minor steps between steps}\tikz@lib@dv@substeps% + \ifx\tikz@lib@dv@substeps\pgfutil@empty + \else + \pgfmathsetmacro\tikz@temp{\tikz@lib@dv@substeps+1}% + \pgfdvmathenter{\tikz@dv@lib@substeps}{\tikz@temp}% + \fi + \loop% + \ifx\tikz@lib@dv@substeps\pgfutil@empty% + \else% + \let\tikz@lib@dv@subcurrent=\tikz@lib@dv@current% + \pgfdvmathadd{\tikz@lib@dv@subcurrent@next}{\tikz@lib@dv@subcurrent}{\tikz@dv@lib@step}% + \pgfdvmathpowten{\tikz@lib@dv@subcurrent}{\tikz@lib@dv@subcurrent}% + \pgfdvmathpowten{\tikz@lib@dv@subcurrent@max}{\tikz@lib@dv@subcurrent@next}% + \pgfdvmathsub{\tikz@lib@dv@subcurrent@diff}{\tikz@lib@dv@subcurrent@max}{\tikz@lib@dv@subcurrent}% + \pgfdvmathdiv{\tikz@lib@dv@substep}{\tikz@lib@dv@subcurrent@diff}{\tikz@dv@lib@substeps}% + \pgfmathsetcount{\c@pgf@counta}{\tikz@lib@dv@substeps}% + \let\tikz@lib@dv@next=\tikz@lib@dv@subloop% + \tikz@lib@dv@subloop + \fi% + \pgfdvmathifless{\tikz@lib@dv@current}{\tikz@lib@dv@min@minus@epsilon}{}{% + \pgfdvmathpowten{\tikz@lib@dv@current@pow}{\tikz@lib@dv@current}% + \pgfdvmathexitbyserializing{\tikz@temp}{\tikz@lib@dv@current@pow}% + \edef\tikz@lib@dv@ats{\tikz@lib@dv@ats,\tikz@temp}% + } + \pgfdvmathadd{\tikz@lib@dv@current}{\tikz@lib@dv@current}{\tikz@dv@lib@step}% + \pgfdvmathifless{\tikz@lib@dv@current}{\tikz@lib@dv@max@plus@epsilon}{\tikz@lib@dv@continuetrue}{\tikz@lib@dv@continuefalse}% + \iftikz@lib@dv@continue% + \repeat% + \tikzdatavisualizationset{major/.expanded={at={\tikz@lib@dv@ats}},minor/.expanded={at={\tikz@lib@dv@minor@ats}}}% + \fi% +}% + + +\def\tikz@lib@dv@about@log#1{% + \tikz@lib@dv@mapper.get in range interval()% + \pgfdvinrangeinterval.get min and max()% + \pgfdvmathlog{\pgfdvmin}{\pgfdvmin}% + \pgfdvmathlog{\pgfdvmax}{\pgfdvmax}% + \pgfdvmathsub{\tikz@lib@dv@diff}{\pgfdvmax}{\pgfdvmin} + \pgfdvmathenter{\tikz@lib@dv@about@val}{#1}% + \pgfdvmathdiv{\tikz@lib@dv@around}{\tikz@lib@dv@diff}{\tikz@lib@dv@about@val}% + % Make mantisse sensible + \pgfmathfloattomacro{\tikz@lib@dv@around}{\tikz@lib@dv@flags}{\tikz@lib@dv@mant}{\tikz@lib@dv@exp} + \ifdim\tikz@lib@dv@exp pt<0pt% + \pgfmathfloatcreate{1}{1.0}{0}% + \else + \pgf@xc=\tikz@lib@dv@mant pt\relax% + \ifdim\pgf@xc<2.5pt + \pgfmathfloatcreate{1}{1.0}{\tikz@lib@dv@exp} + \else\ifdim\pgf@xc<5.1pt + \pgfmathfloatcreate{1}{3.0}{\tikz@lib@dv@exp} + \else + \pgfmathfloatcreate{1}{6.0}{\tikz@lib@dv@exp} + \fi\fi + \fi% + \pgfmathfloattofixed{\pgfmathresult} + \let\tikz@lib@dv@step=\pgfmathresult +}% + + + + + + + +% +% Cartesian axes +% + +\tikzdatavisualizationset{% + new Cartesian axis/.style={ + new axis base={#1}, + new object={ + class=linear transformer, + store=/tikz/data visualization/#1/linear transformer, + arg1/.expanded=\pgfkeysvalueof{/tikz/data visualization/#1/attribute}/scaled, + arg2 from key=/tikz/data visualization/#1/unit vector, + }, + #1/scaling/default/.initial=0 at 0 and 1 at 1cm, + #1/unit vector/.initial=\pgfqpoint{1pt}{0pt}, + } +}% + +\tikzset{ + /tikz/data visualization/axis options/.cd, + unit vector/.code=\tikz@scan@one@point\tikz@lib@dv@uv#1, + length/.style={\tikz@dv@axis/scaling=min at 0 and max at {#1}}, + unit length/.code={\tikz@dv@parse@unit@length{#1}}, + power unit length/.style={\tikz@dv@axis/scaling=1 at 0 and 10 at {#1}} +}% + +\def\tikz@lib@dv@uv#1{% + \pgfkeyssetvalue{\tikz@dv@axis/unit vector}{#1} +}% + +\def\tikz@dv@parse@unit@length#1{ + \pgfutil@in@{per}{#1} + \ifpgfutil@in@% + \tikz@dv@parse@unit@length@#1\pgf@stop% + \else% + \tikz@dv@parse@unit@length@#1per1units\pgf@stop% + \fi% +}% +\def\tikz@dv@parse@unit@length@#1per#2units\pgf@stop{ + \pgfkeysalso{\tikz@dv@axis/scaling=0 at 0 and {#2} at {#1}} +}% + + +% +% Common visualizer interface +% + +\tikzdatavisualizationset{ + new visualizer/.style n args={3}{ + #1/.code={ + \def\tikz@visualizer{#1}% + \pgfkeys{/tikz/data visualization/visualizer options/.cd,##1} + \pgf@dv@do@adddata{\pgfkeysvalueof{/pgf/data visualization/obj}.add data(\pgfkeys{/data point/set={#1}})}% + }, + /utils/exec={ + \advance\tikzdvvisualizercounter by 1\relax + \edef\tikz@temp{/data point/set/#1/.initial=\the\tikzdvvisualizercounter} + \expandafter\tikzset\expandafter{\tikz@temp} + }, + /data point/#1/execute at begin/.initial={ + \pgfkeyssetvalue{/data point/set}{#1} + \scope[ + #2, + /tikz/data visualization/every visualizer/.try, + /tikz/data visualization/visualizers/#1/signal, + /tikz/data visualization/visualizers/#1/styling/.try] + }, + /data point/#1/execute at end/.initial={ + \path; % invokes every path implicitly + \endscope + }, + /tikz/data visualization/visualizers/#1/signal/.code=\pgf@signalstyle.emit(), + /tikz/data visualization/visualizers/#1/styling/.style=, + /tikz/data visualization/visualizers/#1/label in legend options/.style={#3}, + }, + style sheet/.style={/data point/set/.style sheet={#1}}, + /pgf/data/set/.style={/data point/set={#1}}, +}% + +\tikzdatavisualizationset{ + new sub visualizer/.style n args={4}{ + #4/#1/.code={ + \def\tikz@visualizer{#4/#1}% + \pgfkeys{/tikz/data visualization/visualizer options/.cd,##1} + }, + /data point/#4/#1/execute at begin/.initial={ + \pgfkeyssetvalue{/data point/set}{#4} + \scope[ + #2, + /tikz/data visualization/every visualizer/.try, + /tikz/data visualization/visualizers/#4/signal, + /tikz/data visualization/visualizers/#4/styling/.try, + /tikz/data visualization/visualizers/#4/#1/styling/.try] + }, + /data point/#4/#1/execute at end/.initial={ + \path; % invokes every path implicitly + \endscope + }, + /tikz/data visualization/visualizers/#4/#1/styling/.style=, + /tikz/data visualization/visualizers/#4/#1/label in legend options/.style={#3}, + } +}% + + +\def\tikz@do@visualizer#1#2{% + \tikzdatavisualizationset{ + #2={#1} + } +}% + +\newcount\tikzdvvisualizercounter + +\newif\iftikz@dv@visualizer@label@inline + +\tikzdatavisualizationset{visualizer options/.cd, + @set/.style 2 args={ + /tikz/data visualization/visualizers/\tikz@visualizer/styling/.append style={/utils/exec={\let\tikz@dv@plot@handler=#1}}, + /tikz/data visualization/visualizers/\tikz@visualizer/label in legend options/.append style={#2} + }, + no lines/.style={@set={\pgfplothandlerdiscard}{default label in legend mark}}, + smooth line/.style={@set={\pgfplothandlercurveto}{default label in legend path}}, + smooth cycle/.style={@set={\pgfplothandlerclosedcurve}{default label in legend closed path}}, + straight line/.style={@set={\pgfplothandlerlineto}{default label in legend path}}, + straight cycle/.style={@set={\pgfplothandlerpolygon}{default label in legend closed path}}, + polygon/.style={straight cycle},% alias + gap line/.style={@set={\pgfplothandlergaplineto}{default label in legend path}}, + gap cycle/.style={@set={\pgfplothandlergapcycle}{gap circular label in legend line}} +}% + + + +% +% Label visualizer +% + +\tikzdatavisualizationset{ + new label visualizer/.style 2 args={ + new object={ + when=before visualization, + class=label visualizer, + before creation={ + \begingroup + \def\tikz@visualizer{#1}% + \pgfkeys{/tikz/data visualization/visualizer label options/.cd, + #2} + \pgfkeysgetvalue{/tikz/data visualization/visualizer label options/text}\tikz@dv@temp@lab + \def\tikz@tempa{ + \scope[ + /utils/exec=\def\tikz@visualizer{#1},% + /tikz/data visualization/visualizer label options/.cd, + #2] + \tikzdatavisualizationset{every data set label/.try} + \path [ + /data point/set={#1},/utils/exec=\pgf@signalstyle.emit(), + /tikz/data visualization/.cd,every label in data/.try] + (label visualizer coordinate') -- + (label visualizer coordinate) + node [ + auto, + at end, + /tikz/data visualization/node styling] + } + \expandafter\def\expandafter\tikz@tempb\expandafter{\expandafter{\tikz@dv@temp@lab};}% + \expandafter\expandafter\expandafter\gdef% + \expandafter\expandafter\expandafter\tikz@dv@label@code% + \expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter\relax% + \expandafter\expandafter\expandafter{\expandafter\tikz@tempa\tikz@tempb\endscope}} + \global\let\tikz@dv@label@attribute=\tikz@dv@label@attribute + \global\let\tikz@dv@label@threshold=\tikz@dv@label@threshold + \endgroup + }, + arg1/.expand once=\tikz@dv@label@attribute, + arg2=\tikz@dv@label@threshold, + arg3/.expand once=\tikz@dv@label@code, + arg4=\pgfdvvisualizerfilter{#1} + }, + /utils/exec=\tikz@create@label@count{#1} + }, + % Label style + text colored/.style={node style={text=visualizer color}} +}% + +\def\tikz@create@label@count#1{ + \tikzdatavisualizationset{ + new object={ + when=before survey, + store=/tikz/data visualization/visualizers/#1/count/obj, + class=count, + arg1=set/#1/count, + after creation={\tikzdvobj.set filter(\pgfdvvisualizerfilter{#1})} + } + } +}% + +\pgfkeys{ + /tikz/data visualization/visualizer label options/.cd, + when/.code args={#1 is#2}{% + \def\tikz@dv@label@attribute{#1}% + \def\tikz@dv@label@threshold{#2}% + }, + index/.code={% + \edef\tikz@dv@label@attribute{set/\tikz@visualizer/count}% + \def\tikz@dv@label@threshold{#1}% + }, + pos/.code={% + \edef\tikz@dv@label@attribute{set/\tikz@visualizer/count}% + \pgfkeysvalueof{/tikz/data visualization/visualizers/\tikz@visualizer/count/obj}.get max(\tikz@lib@max) + \edef\tikz@dv@label@threshold{(#1*\tikz@lib@max)}% + }, + auto/.code={% + \edef\tikz@dv@label@attribute{set/\tikz@visualizer/count}% + \pgfkeysvalueof{/tikz/data visualization/visualizers/\tikz@visualizer/count/obj}.get max(\tikz@lib@max) + \edef\tikz@dv@label@threshold{({(\pgfkeysvalueof{/data point/set/\tikz@visualizer}-0.5)/\the\tikzdvvisualizercounter*\tikz@lib@max})} + }, + text/.initial=, + text'/.style={text={#1},node style=swap,/utils/exec=\def\tikz@lib@dv@pin@sign{-}}, + node style/.style={/tikz/data visualization/node style={#1}}, + text colored/.style=/tikz/data visualization/text colored, + pin angle/.store in=\tikz@lib@dv@pin@dir, + pin length/.style={node style={pin distance={#1}}}, +}% + +\let\tikz@lib@dv@pin@sign\pgfutil@empty + +\let\tikz@dv@label@attribute\pgfutil@empty +\let\tikz@dv@label@threshold\pgfutil@empty +\let\tikz@dv@label@code\pgfutil@empty + + + + +% +% Legend handling +% + +\tikzdatavisualizationset{ + new legend/.code={ + \pgfkeysifdefined{/tikz/data visualization/#1/at}{} + {\tikzdatavisualizationset{ + new object={ + class=legend, + store=/tikz/data visualization/#1/obj, + arg1 from key=/tikz/data visualization/#1/@columns or rows, + arg2 from key=/tikz/data visualization/#1/@ideal, + arg3 from key=/tikz/data visualization/#1/max entries, + arg4 from key=/tikz/data visualization/#1/@strategy, + after creation={ + \tikzdatavisualizationset{ + legend actions/.append={ + \pgfkeysgetvalue{/tikz/data visualization/#1/obj}\pgf@dv@legend% + { + \pgf@dv@legend.get arrangement(\pgf@dv@temp)% + \pgfkeysgetvalue{/tikz/data visualization/#1/at}\pgf@dv@at% + \pgfkeysgetvalue{/tikz/data visualization/#1/anchor}\pgf@dv@anchor% + \let\pgfdvnextcell=\pgfmatrixnextcell% + \let\pgfdvendrow=\pgfmatrixendrow% + \def\pgf@marshal{ + \matrix[at/.expand once=\pgf@dv@at,matrix anchor/.expand + once=\pgf@dv@anchor,/tikz/data visualization/#1/matrix node styling] + } + \expandafter\pgf@marshal\expandafter{\pgf@dv@temp}; + } + } + } + } + }, + #1/@columns or rows/.initial=columns, + #1/@ideal/.initial=1, + #1/max entries/.initial=100, + #1/@strategy/.initial=down then right, + #1/anchor/.initial=west, + #1/at/.initial=(data visualization bounding box.east), + #1/matrix node styling/.style={row sep=0pt,column sep=.8em}, + % + % + % + #1/.code={ + \let\tikz@temp\tikz@dv@legend% + \def\tikz@dv@legend{/tikz/data visualization/#1}% + \expandafter\tikz@do@legend@options\expandafter{\tikz@temp}{##1}% + }, + #1={every new legend} + }}}, + new legend/.default=main legend, + legend/.style={ + new legend, + main legend={#1} + } +}% + +\def\tikz@do@legend@options#1#2{ + \pgfkeys{/tikz/data visualization/legend options/.cd,#2} + \def\tikz@dv@legend{#1} +}% +\let\tikz@dv@legend\pgfutil@empty + + +\tikzset{ + /tikz/data visualization/legend options/.cd, + % + % How to arrange the entries in the legend + % + ideal number of columns/.style={\tikz@dv@legend/@columns or rows=columns,\tikz@dv@legend/@ideal={#1}}, + ideal number of rows/.style={\tikz@dv@legend/@columns or rows=rows,\tikz@dv@legend/@ideal={#1}}, + columns/.style={ideal number of columns={#1}},% alias + rows/.style={ideal number of rows={#1}},% alias + max rows/.style={\tikz@dv@legend/@columns or rows=columns,\tikz@dv@legend/max entries={#1}}, + max columns/.style={\tikz@dv@legend/@columns or rows=rows,\tikz@dv@legend/max entries={#1}}, + down then right/.style={\tikz@dv@legend/@strategy=down then right}, + down then left/.style={\tikz@dv@legend/@strategy=down then left}, + up then right/.style={\tikz@dv@legend/@strategy=up then right}, + up then left/.style={\tikz@dv@legend/@strategy=up then left}, + right then down/.style={\tikz@dv@legend/@strategy=right then down}, + left then down/.style={\tikz@dv@legend/@strategy=left then down}, + right then up/.style={\tikz@dv@legend/@strategy=right then up}, + left then up/.style={\tikz@dv@legend/@strategy=left then up}, + % + % Where to put the legend + % + anchor/.style={\tikz@dv@legend/anchor={#1}}, + at/.style={\tikz@dv@legend/at={#1}}, + % Outer placements + right/.style={east outside}, + left/.style={west outside}, + above/.style={north outside}, + below/.style={south outside}, + east outside/.style={ + columns=1, + at={([xshift=.8em]data visualization bounding box.east)}, + anchor=west, + }, + north east outside/.style={ + columns=1, + at={([xshift=.8em]data visualization bounding box.north east|- + data bounding box.north)}, + anchor=north west, + }, + south east outside/.style={ + columns=1, + at={([xshift=.8em]data visualization bounding box.south east |- + data bounding box.south)}, + anchor=south west, + }, + west outside/.style={ + columns=1, + label style=text left, + at={([xshift=-.8em]data visualization bounding box.west)}, + anchor=east, + }, + north west outside/.style={ + columns=1, + label style=text left, + at={([xshift=-.8em]data visualization bounding box.north west |- + data bounding box.north)}, + anchor=north east, + }, + south west outside/.style={ + columns=1, + label style=text left, + at={([xshift=-.8em]data visualization bounding box.south west |- + data bounding box.south)}, + anchor=south east, + }, + south outside/.style={ + rows=1, + at={([yshift=-.5em]data visualization bounding box.south)}, + anchor=north, + }, + north outside/.style={ + rows=1, + at={([yshift=.5em]data visualization bounding box.north)}, + anchor=south, + }, + every new legend/.style={east outside,label style=text right}, + % + % Inner placements + % + % First, styling + every legend inside/.style={ + opaque=white, + label style={node style={font=\pgfutil@font@footnotesize}} + }, + opaque/.style={ + matrix node style={ + inner sep=.333ex, + outer sep=.5ex, + rounded corners=3pt, + execute at begin cell={\tikzset{sharp corners}}, % get rid of + % rounded corners in cells of the + % legend matrix + fill=#1 + }, + }, + opaque/.default=white, + transparent/.style={matrix node style={fill=none}}, + % Second, the placements + north east inside/.style={ + columns=1, + at={([xshift=-.3em]data bounding box.north east)}, + anchor=north east, + every legend inside + }, + south west inside/.style={ + columns=1, + at={([xshift=.3em]data bounding box.south west)}, + anchor=south west, + every legend inside + }, + north west inside/.style={ + columns=1, + at={([xshift=.3em]data bounding box.north west)}, + anchor=north west, + every legend inside + }, + south east inside/.style={ + columns=1, + at={([xshift=-.3em]data bounding box.south east)}, + anchor=south east, + every legend inside + }, + west inside/.style={ + columns=1, + at={([xshift=.3em]data bounding box.west)}, + anchor=west, + every legend inside + }, + east inside/.style={ + columns=1, + at={([xshift=.3em]data bounding box.east)}, + anchor=east, + every legend inside + }, + north inside/.style={ + rows=1, + at={(data bounding box.north)}, + anchor=north, + every legend inside + }, + south inside/.style={ + rows=1, + at={(data bounding box.south)}, + anchor=south, + every legend inside + }, + % Additional inner placements + at values/.style={ + at={(visualization cs:#1)}, + anchor=center, + every legend inside + }, + right of/.style={ + at={(visualization cs:#1)}, + anchor=west, + every legend inside + }, + left of/.style={ + at={(visualization cs:#1)}, + anchor=east, + every legend inside + }, + above of/.style={ + at={(visualization cs:#1)}, + anchor=south, + every legend inside + }, + below of/.style={ + at={(visualization cs:#1)}, + anchor=north, + every legend inside + }, + above right of/.style={ + at={(visualization cs:#1)}, + anchor=south west, + every legend inside + }, + above left of/.style={ + at={(visualization cs:#1)}, + anchor=south east, + every legend inside + }, + below right of/.style={ + at={(visualization cs:#1)}, + anchor=north west, + every legend inside + }, + below left of/.style={ + at={(visualization cs:#1)}, + anchor=north east, + every legend inside + }, + % + % + % + % Label text styling + % + label style/.style={ + matrix node style={/tikz/data visualization/every label in legend/.append style={#1}} + }, + % + % Styling + % + matrix node style/.style={\tikz@dv@legend/matrix node styling/.append style={#1}}, +}% + + +\tikzdatavisualizationset{ + new legend entry/.code={ + \begingroup + \pgfkeys{/tikz/data visualization/legend entry options/.cd,#1} + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/legend}\tikz@dv@temp@legend + \global\let\tikz@dv@temp@legend\tikz@dv@temp@legend + \endgroup + \tikzdatavisualizationset{new legend/.expanded=\tikz@dv@temp@legend}% + \expandafter\tikz@dv@add@legend@entry\expandafter{\tikz@dv@temp@legend}{#1} + } +}% + +\def\tikz@dv@add@legend@entry#1#2{ + \tikz@main@dv.at start survey({ + \pgfkeysgetvalue{/tikz/data visualization/#1/obj}\pgf@temp + \pgf@temp.add entry(\tikz@dv@render@legend@entry{legend=#1,#2}) + }) +}% + +\def\tikz@dv@render@legend@entry#1{ + \pgfkeys{/tikz/data visualization/.cd,every data set label} + \pgfkeys{/tikz/data visualization/legend entry options/.cd, + /tikz/data visualization/every label in legend,#1}% + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/text}\tikz@dv@temp@lab + \pgfkeysgetvalue{/tikz/data visualization/@node styling}\tikz@dv@temp@style + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/setup}\tikz@dv@temp@setup + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/visualizer in legend styling}\tikz@dv@temp@visual@styling + \scope[/utils/exec=\expandafter\pgfkeysalso\expandafter{\tikz@dv@temp@setup}, + /utils/exec=\pgf@signalstyle.emit()] + \node[/tikz/data visualization/node styling, + /utils/exec=\expandafter\pgfkeysalso\expandafter{\tikz@dv@temp@style}] + {\tikz@dv@pre@height\tikz@dv@temp@lab\tikz@dv@post@height}; + \scope[/utils/exec=\expandafter\pgfkeysalso\expandafter{\tikz@dv@temp@visual@styling}] + \iftikz@lib@dv@text@only + \else + \pgfkeysvalueof{/tikz/data visualization/legend entry options/visualizer in legend} + \fi + \endscope + \endscope +}% + +\def\tikz@dv@pre@height{\hbox{\vrule height .75em width0pt}}% +\def\tikz@dv@post@height{\hbox{\vrule depth .25em width0pt}}% + + + +\pgfkeys{ + /tikz/data visualization/legend entry options/.cd, + % + % General options + % + text/.initial=, + node style/.style={/tikz/data visualization/node style={#1}}, + legend/.initial=main legend, + setup/.initial=, + visualizer in legend/.initial=, + visualizer in legend styling/.initial=, + visualizer in legend style/.style={visualizer in legend styling/.append={,#1}}, + % + % Legend visualizers for plots + % + text right/.style={ + node style={anchor=mid west,inner ysep=1pt,inner xsep=0pt,reset cm,xshift=.333em}, + visualizer in legend style={reset cm}, + }, + text left/.style={ + node style={anchor=mid east,inner ysep=1pt,inner xsep=0pt,reset + cm,xshift=-.333em,align=right}, + visualizer in legend style={reset cm,xscale=-1}, + }, + text only/.style={ + node style={anchor=mid west,inner ysep=1pt,inner xsep=0pt,reset cm,text=visualizer color}, + /utils/exec=\tikz@lib@dv@text@onlytrue + }, + text colored/.style=/tikz/data visualization/text colored, +}% +\let\tikz@lib@dv@pin@dir\pgfutil@empty +\newif\iftikz@lib@dv@text@only + +\pgfkeys{ + /tikz/data visualization/visualizer options/.cd, + label in legend/.code={\expandafter\tikz@dv@new@label@in@legend@for@visualizer\expandafter{\tikz@visualizer}{#1}}, + label in data/.code=\tikzdatavisualizationset{new label visualizer/.expand once=\expandafter{\tikz@visualizer}{auto,#1}}, + pin in data/.style={label in data={% + node style={% + /utils/exec={ + \ifx\tikz@lib@dv@pin@dir\pgfutil@empty + \pgf@process{\pgfpointnormalised{% + \pgfpointdiff% + {\pgfpointanchor{label visualizer coordinate}{center}}% + {\pgfpointanchor{label visualizer coordinate'}{center}}}}% + \pgf@x=-\pgf@x\relax% + \edef\tikz@lib@dv@temp@rot{\noexpand\pgfqpoint{\the\pgf@y}{\the\pgf@x}}% + \tikz@addtransform{\pgftransformshift{\pgfpointscale{\tikz@lib@dv@pin@sign\tikz@pin@distance}{\tikz@lib@dv@temp@rot}}} + \else% + \tikz@addtransform{\pgftransformshift{\pgfpointpolar{\tikz@lib@dv@pin@dir}{\tikz@lib@dv@pin@sign\tikz@pin@distance}}} + \fi% + }, + append after command={ + \bgroup + [current point is local=true] + (\tikzlastnode) edge [solid, every pin edge] (label visualizer coordinate) + \egroup% + }}, + ,#1}}, + style/.style={/tikz/data visualization/visualizers/\tikz@visualizer/styling/.append style={,#1}}, + label in legend options/.style={/tikz/data visualization/visualizers/\tikz@visualizer/label in legend options/.append style={,#1}}, + ignore style sheets/.style={/tikz/data visualization/visualizers/\tikz@visualizer/signal/.code=,/utils/exec=\advance\tikzdvvisualizercounter by -1\relax}, +}% + +\def\tikz@dv@new@label@in@legend@for@visualizer#1#2{ + \tikzdatavisualizationset{ + new legend entry={ + visualizer in legend style={/tikz/data visualization/visualizers/#1/styling/.try}, + /tikz/data visualization/every label in legend/.try, + /tikz/.cd, + every label/.try, + /tikz/data visualization/legend entry options/.cd, + setup={/data point/set={#1}}, + /tikz/data visualization/visualizers/#1/label in legend options/.try, + #2, + } + } +}% + +\def\tikz@dv@legend@entry@as@example{ + \pgfkeysgetvalue{/data point/set}{\tikz@visualizer} + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at begin} + \tikz@dv@plot@handler + \pgfplotstreamstart + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/label in legend line coordinates}{\tikz@dv@temp} + \foreach \coordinate in \tikz@dv@temp + { \pgfplotstreampoint{\expandafter\tikz@scan@one@point\expandafter\pgfutil@firstofone\coordinate} } + \pgfplotstreamend + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at end} + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at begin} + \tikz@dv@plot@mark@maker + \pgfplotstreamstart + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/label in legend mark coordinates}{\tikz@dv@temp} + \foreach \coordinate in \tikz@dv@temp + { \pgfplotstreampoint{\expandafter\tikz@scan@one@point\expandafter\pgfutil@firstofone\coordinate} } + \pgfplotstreamend + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at end} +}% + + +\tikzdatavisualizationset{ + legend entry options/.cd, + label in legend line coordinates/.initial=, + label in legend rectangle coordinates/.initial={(-1ex,-.5ex),(-1ex,0.968ex),(0ex,0.968ex),(0ex,-.5ex)}, + label in legend mark coordinates/.initial=, + label in legend one mark/.style={ + label in legend line coordinates={}, + label in legend mark coordinates={(0,0)}, + }, + label in legend three marks/.style={ + label in legend line coordinates={}, + label in legend mark coordinates={(-3ex,-.3ex),(-1.5ex,.3ex),(0,0)}, + }, + straight label in legend line/.style={ + label in legend line coordinates={(-2em,0),(-1.5em,0),(-.5em,0),(0,0)}, + label in legend mark coordinates={(-1.5em,0),(-.5em,0)}, + }, + zig zag label in legend line/.style={ + label in legend line coordinates={(-2em,0),(-1.5em,.3ex),(-.5em,-.3ex),(0,0)}, + label in legend mark coordinates={(-1.5em,.3ex),(-.5em,-.3ex)}, + }, + circular label in legend line/.style={ + label in legend line coordinates={% + ([xshift=-1em]0:.9em and .35ex),% + ([xshift=-1em]45:.9em and .35ex),% + ([xshift=-1em]90:.9em and .35ex),% + ([xshift=-1em]135:.9em and .35ex),% + ([xshift=-1em]180:.9em and .35ex),% + ([xshift=-1em]225:.9em and .35ex),% + ([xshift=-1em]270:.9em and .35ex),% + ([xshift=-1em]315:.9em and .35ex)},% + label in legend mark coordinates={([xshift=-1em]120:.9em and .35ex),([xshift=-1em]-60:.9em and .35ex)}, + }, + gap circular label in legend line/.style={ + label in legend line coordinates={% + ([xshift=-1em,yshift=.2ex]90:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]162:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]234:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]306:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]18:1.4ex and 0.9ex)}, + label in legend mark coordinates={ + ([xshift=-1em,yshift=.2ex]90:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]162:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]234:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]306:1.4ex and 0.9ex),% + ([xshift=-1em,yshift=.2ex]18:1.4ex and 0.9ex)} + }, + default label in legend path/.style={zig zag label in legend line}, + default label in legend closed path/.style={circular label in legend line}, + default label in legend mark/.style={label in legend one mark}, +}% + + +\def\tikz@dv@legend@entry@visualizer@visualizer{ +}% + + + +% +% Basic visualizers +% + +\tikzdatavisualizationset{ + visualize as line/.style={ + new object={ + when=after survey, + store=/tikz/data visualization/visualizers/#1, + class=plot handler visualizer, + arg1=#1, + arg2={\tikz@dv@plot@handler,\tikz@dv@plot@mark@maker} + }, + new visualizer={#1}{% + every path/.style={draw}, + style={every mark/.append style={color=visualizer color}}, + mark size=2pt, + semithick, + color=visualizer color, + mark=none, + /tikz/data visualization/every visualize as line/.try, + }{visualizer in legend=\tikz@dv@legend@entry@as@example}, + #1={straight line} + }, + visualize as line/.default=line, + visualize as smooth line/.style={ + visualize as line={#1}, + #1={smooth line} + }, + visualize as smooth line/.default=line, + visualize as smooth cycle/.style={ + visualize as smooth line={#1}, + #1={smooth cycle} + }, + visualize as smooth cycle/.default=line, + visualize as scatter/.style={ + new object={ + when=after survey, + store=/tikz/data visualization/visualizers/#1, + class=plot handler visualizer, + arg1=#1, + arg2={\tikz@dv@plot@mark@maker} + }, + new visualizer={#1}{% + mark=x, + mark size=2pt, + style={every mark/.append style={color=visualizer color}}, + /tikz/data visualization/every visualize as scatter/.try, + }{visualizer in legend=\tikz@dv@legend@entry@as@example}, + #1={no lines} + }, + visualize as scatter/.default=scatter +}% + +\def\tikz@dv@plot@mark@maker{ + \let\tikz@options=\pgfutil@empty% + \let\tikz@transform=\pgfutil@empty% + \tikzset{solid,shift only,every mark}% + \tikz@options% + \ifx\tikz@plot@mark\pgfutil@empty% + \pgfplothandlerdiscard + \else + \pgfplothandlermark{\tikz@transform\pgfuseplotmark{\tikz@plot@mark}} + \fi +}% + + + +% +% Rectangle visualizers +% + + +\tikzdatavisualizationset{ + visualize as rectangles/.style={ + new object={ + when=before survey, + store=/tikz/data visualization/visualizers/#1, + class=rectangle visualizer, + arg1=#1 + }, + /data point/#1/attribute 1/.initial=x, + /data point/#1/attribute 2/.initial=y, + new visualizer={#1}{% + every path/.style={draw}, + semithick, + color=visualizer color, + /tikz/data visualization/every visualize as rectangles/.try, + }{visualizer in legend=\tikz@dv@legend@entry@as@rectangle}, + #1={} + }, + visualize as rectangles/.default=rectangles, + % + % + % + visualizer options/.cd, + attribute 1/.style={/data point/\tikz@visualizer/attribute 1={#1}}, + attribute 2/.style={/data point/\tikz@visualizer/attribute 2={#1}}, +}% + + + +\def\tikz@dv@legend@entry@as@rectangle{ + \pgfkeysgetvalue{/data point/set}{\tikz@visualizer} + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at begin} + \pgfplothandlerpolygon + \pgfplotstreamstart + \pgfkeysgetvalue{/tikz/data visualization/legend entry options/label in legend rectangle coordinates}{\tikz@dv@temp} + \foreach \coordinate in \tikz@dv@temp + { \pgfplotstreampoint{\expandafter\tikz@scan@one@point\expandafter\pgfutil@firstofone\coordinate} } + \pgfplotstreamend + \pgfkeysvalueof{/data point/\tikz@visualizer/execute at end} +}% + + + + +% +% Style sheets +% + +% Style sheet handler + +\pgfkeysdef{/handlers/.style sheet}{% + \edef\pgf@marshal{ + \noexpand \pgfoonew \noexpand\tikz@dv@temp=new style attribute(\pgfkeyscurrentpath,#1) + \noexpand \tikz@dv@temp.default connects() + } + \pgf@marshal +}% + +\tikzset{ + visualizer color/.code=\colorlet{visualizer color}{#1}, + visualizer color=black +}% + +% Default style sheets + +\pgfdvdeclarestylesheet{vary thickness} +{ + default style/.style={line width={0.3pt+(#1)*0.2pt}} +}% + +\pgfdvdeclarestylesheet{vary dashing} +{ + default style/.style=solid, + 1/.style=solid, + 2/.style={dash pattern=on 5\pgflinewidth off 2\pgflinewidth}, + 3/.style={dash pattern=on 1.5\pgflinewidth off 1.5\pgflinewidth}, + 4/.style={dash pattern=on 5\pgflinewidth off 1.5\pgflinewidth on 1.5\pgflinewidth off 1.5\pgflinewidth}, + 5/.style={dash pattern=on 10\pgflinewidth off 3\pgflinewidth}, + 6/.style={dash pattern=on 10\pgflinewidth off 2\pgflinewidth on 2\pgflinewidth off 2\pgflinewidth}, + 7/.style={dash pattern=on 8\pgflinewidth off 2\pgflinewidth on + 1.5\pgflinewidth off 1.5\pgflinewidth on 1.5\pgflinewidth off + 1.5\pgflinewidth on 1.5\pgflinewidth off 1.5\pgflinewidth} +}% + +\pgfdvdeclarestylesheet{vary thickness and dashing} +{ + default style/.style=thin, + 1/.style=thin, + 2/.style=thick, + 3/.style={ + dash pattern=on 5\pgflinewidth off 2\pgflinewidth, + thin + }, + 4/.style={ + dash pattern=on 5\pgflinewidth off 2\pgflinewidth, + thick, + }, + 5/.style={ + dash pattern=on 1.5\pgflinewidth off 1.5\pgflinewidth, + thin + }, + 6/.style={ + dash pattern=on 1.5\pgflinewidth off 1.5\pgflinewidth, + thick + }, + 7/.style={ + dash pattern=on 5\pgflinewidth off 1.5\pgflinewidth on + 1.5\pgflinewidth off 1.5\pgflinewidth, + thin + }, + 8/.style={ + dash pattern=on 5\pgflinewidth off 1.5\pgflinewidth on + 1.5\pgflinewidth off 1.5\pgflinewidth, + thick + }, + 9/.style={ + dash pattern=on 10\pgflinewidth off 3\pgflinewidth, + thin + }, + 10/.style={ + dash pattern=on 10\pgflinewidth off 3\pgflinewidth, + thick + }, + 11/.style={ + dash pattern=on 10\pgflinewidth off 2\pgflinewidth on + 2\pgflinewidth off 2\pgflinewidth, + thin + }, + 12/.style={ + dash pattern=on 10\pgflinewidth off 2\pgflinewidth on + 2\pgflinewidth off 2\pgflinewidth, + thick + }, + 13/.style={ + dash pattern=on 8\pgflinewidth off 2\pgflinewidth on + 1.5\pgflinewidth off 1.5\pgflinewidth on 1.5\pgflinewidth off + 1.5\pgflinewidth on 1.5\pgflinewidth off 1.5\pgflinewidth, + thin + }, + 14/.style={ + dash pattern=on 8\pgflinewidth off 2\pgflinewidth on + 1.5\pgflinewidth off 1.5\pgflinewidth on 1.5\pgflinewidth off + 1.5\pgflinewidth on 1.5\pgflinewidth off 1.5\pgflinewidth, + thick + } +}% + + +\pgfdvdeclarestylesheet{strong colors} +{ + default style/.style={visualizer color=black}, + 1/.style={visualizer color=black}, + 2/.style={visualizer color=red!80!black}, + 3/.style={visualizer color=blue!80!black}, + 4/.style={visualizer color=green!60!black}, + 5/.style={visualizer color=orange!80!black}, + 6/.style={visualizer color=black!60} +}% + + +\pgfdvdeclarestylesheet{cross marks} +{ + default style/.style={mark=x,every mark/.append style=thin,mark size=2pt}, + 1/.style={mark=x,every mark/.append style=thin,mark size=2pt}, + 2/.style={mark=+,every mark/.append style=thin,mark size=2pt}, + 3/.style={mark=Mercedes star,every mark/.append style=thin,mark size=2pt}, + 4/.style={mark=Mercedes star flipped,every mark/.append style=thin,mark size=2pt}, + 5/.style={mark=star,every mark/.append style=thin,mark size=2pt}, + 6/.style={mark=10-pointed star,every mark/.append style={line width=.3pt,mark size=1.8pt}} +}% + + +\pgfdvdeclarestylesheet{* mark} +{ + default style/.style={mark=*,every mark/.append style=thin,mark size=1.4pt}, +}% + +\pgfdvdeclarestylesheet{dot mark} +{ + default style/.style={mark=*,every mark/.append style=thin,mark size=0.6pt}, +}% + + +\pgfdvdeclarestylesheet{o mark} +{ + default style/.style={mark=o,every mark/.append style=thin,mark size=1.4pt}, +}% + + + +% Declare a color series style sheet +% +% #1 = name of the style sheet +% #2 = color model +% #3 = initial color +% #4 = step +% +% Description: +% +% This function declares a style sheet that changes colors according +% to the value of the attribute. No test is made that the attribute is +% a number. + +\def\tikzdvdeclarestylesheetcolorseries#1#2#3#4{% + \definecolorseries{tikzdvcolorseries#1}{#2}{step}[#2]{#3}{#4}% + \resetcolorseries{tikzdvcolorseries#1}% + \pgfdvdeclarestylesheet{#1} + { + default style/.style={ + /utils/exec=\colorlet{tikz@dv@temp}[rgb]{tikzdvcolorseries#1!![##1]}, + visualizer color=tikz@dv@temp + } + }% +}% + +\tikzdvdeclarestylesheetcolorseries{vary hue}{hsb}{.4,0.9,0.8}{.213,0,0}% +\tikzdvdeclarestylesheetcolorseries{shades of blue}{hsb}{.65,1.4,1}{0,-.4,-.0}% +\tikzdvdeclarestylesheetcolorseries{shades of red}{hsb}{0,1.4,1}{0,-.4,-.0}% +\tikzdvdeclarestylesheetcolorseries{gray scale}{hsb}{0,0,-.34}{0,0,.34}% + + + + + +% +% Basic Axes & Coordinate Systems +% + + +% +% +% Basic axis systems +% +% + +\tikzdatavisualizationset{ + xy Cartesian/.style={ + new Cartesian axis=x axis, + x axis={attribute=x,unit vector={(1pt,0cm)}}, + new Cartesian axis=y axis, + y axis={attribute=y,unit vector={(0cm,1pt)}} + }, + Xy axes/.style={x axis={#1},y axis={#1}}, + uv Cartesian/.style={ + new Cartesian axis=u axis, + u axis={attribute=u,unit vector={(1pt,0cm)}}, + new Cartesian axis=v axis, + v axis={attribute=v,unit vector={(0cm,1pt)}} + }, + uv axes/.style={u axis={#1},v axis={#1}}, +}% + +\tikzdatavisualizationset{ + xyz Cartesian cabinet/.style={ + xy Cartesian, + new Cartesian axis=z axis, + z axis={attribute=z,unit vector={(-0.353553pt,-0.353553pt)}} + }, + xyz axes/.style={x axis={#1},y axis={#1},z axis={#1}}, + uvw Cartesian cabinet/.style={ + uv Cartesian, + new Cartesian axis=w axis, + w axis={attribute=w,unit vector={(-0.353553pt,-0.353553pt)}} + } + uvw axes/.style={u axis={#1},v axis={#1},w axis={#1}}, +}% + + + +% +% Create a new axis system +% + +\tikzdatavisualizationset{ + new axis system/.style n args={4}{ + #1/.style={ + #2, + #1/.cd, + #3, + /tikz/data visualization/every #1/.try, + ##1, + /tikz/data visualization/.cd, + #4, + } + } +}% + + +% The school book axes +% +% This coordinate system can be used to create plots that look like +% plots in a typical school book: There are two axes called "x axis" +% and "y axis" that meet at the origin, there are arrows at the ends +% of the axes, pointing in the directions of the positive axes. No +% scaling is done by default, rather one unit equals one 1cm. This +% ensures that the even when multiple plots are created, the same +% scaling will be used each time. +% +% To change the scaling, say "all axes={unit length=1mm}" for +% instance. + +\tikzdatavisualizationset{ + new axis system={school book axes}{% + xy Cartesian, + x axis={ + include value=0, + scaling=0 at 0 and \pgfkeysvalueof{/tikz/data visualization/school book axes/unit} at 1cm, + visualize axis={y axis={goto=0},style=->,padded}, + visualize ticks={common={y axis={goto=0},direction axis=y axis}, + major={tick text at low, + options at=0 as [{style={draw=none},no tick text}] + }}, + visualize grid={common={direction axis=y axis,padded}}, + ticks={step=\pgfkeysvalueof{/tikz/data visualization/school book axes/unit}}, + padding=0.75em + }, + y axis={ + include value=0, + scaling=0 at 0 and \pgfkeysvalueof{/tikz/data visualization/school book axes/unit} at 1cm, + visualize axis={x axis={goto=0},style=->,padded}, + visualize ticks={ + common={x axis={goto=0},direction axis=x axis}, + major={tick text at low,options at=0 as [{high=0,low=0,style={draw=none},node style={anchor=north east}}]} + }, + visualize grid={common={direction axis=x axis,padded}}, + ticks={step=\pgfkeysvalueof{/tikz/data visualization/school book axes/unit}}, + padding=0.75em + } + }{% + standard labels + }{% + @make labels + }, + school book axes/.cd, + % Possible axis positionings: + % + % Place labels at the ends of the axes + % + standard labels/.style={ + /tikz/data visualization/@make labels/.style={ + x axis={ + visualize label={ + x axis={goto=padded max, anchor at max}, + y axis={goto=0} + } + }, + y axis={ + visualize label={ + y axis={goto=padded max, anchor at max}, + x axis={goto=0} + } + } + } + }, + % + % Basic unit + % + unit/.initial=1, +}% + + + + +% The scientific axes +% +% The scientific axes is a 2d plot that has a predetermined width and +% height. The data is then scaled in such a way that it fits inside +% this given rectangle. + +\tikzdatavisualizationset{ + new axis system={scientific axes}{% + xy Cartesian, + every axis/.append style={style={draw=black!50}}, + every ticks/.append style={style={draw=black!50}}, + x axis={ + length=\pgfkeysvalueof{/tikz/data visualization/scientific axes/width}, + ticks + }, + y axis={ + length=\pgfkeysvalueof{/tikz/data visualization/scientific axes/height}, + ticks + } + }{% + standard labels, + outer ticks, + }{% + @make axes, + @make labels + }, + scientific axes/.cd, + width/.initial=5cm, + height/.initial=0.618*\pgfkeysvalueof{/tikz/data visualization/scientific axes/width},% golden ratio... + outer ticks/.style={ + /tikz/data visualization/@make axes/.style={ + x axis={ + visualize ticks={common={y axis={goto=padded min},direction axis=y axis,high=0pt},major={tick text at low}}, + visualize ticks={common={y axis={goto=padded max},direction axis=y axis,low=0pt}}, + visualize axis={y axis={goto=padded min},padded}, + visualize axis={y axis={goto=padded max},padded}, + visualize grid={common={direction axis=y axis,padded}}, + }, + y axis={ + visualize ticks={common={x axis={goto=padded min},direction axis=x axis,high=0pt},major={tick text at low}}, + visualize ticks={common={x axis={goto=padded max},direction axis=x axis,low=0pt}}, + visualize axis={x axis={goto=padded min},padded}, + visualize axis={x axis={goto=padded max},padded}, + visualize grid={common={direction axis=x axis,padded}}, + } + } + }, + inner ticks/.style={ + /tikz/data visualization/@make axes/.style={ + x axis={ + visualize ticks={common={y axis={goto=padded min},direction axis=y axis,low=0pt},major={tick text at low}}, + visualize ticks={common={y axis={goto=padded max},direction axis=y axis,high=0pt}}, + visualize axis={y axis={goto=padded min},padded}, + visualize axis={y axis={goto=padded max},padded}, + visualize grid={common={direction axis=y axis,padded}}, + }, + y axis={ + visualize ticks={common={x axis={goto=padded min},direction axis=x axis,low=0pt},major={tick text at low}}, + visualize ticks={common={x axis={goto=padded max},direction axis=x axis,high=0pt}}, + visualize axis={x axis={goto=padded min},padded}, + visualize axis={x axis={goto=padded max},padded}, + visualize grid={common={direction axis=x axis,padded}}, + } + } + }, + clean/.style={ + /tikz/data visualization/@make axes/.style={ + x axis={ + visualize ticks={common={y axis={goto=padded min},direction axis=y axis,high=0pt},major={tick text at low}}, + visualize axis={y axis={goto=padded min}}, + visualize axis={y axis={goto=min}, style={black!25, line cap=rect}}, + visualize axis={y axis={goto=max}, style={black!25, line cap=rect}}, + visualize grid={common={direction axis=y axis}}, + padding=.5em, + }, + y axis={ + visualize ticks={common={x axis={goto=padded min},direction axis=x axis,high=0pt},major={tick text at low}}, + visualize axis={x axis={goto=padded min}}, + visualize axis={x axis={goto=min}, style={black!25, line cap=rect}}, + visualize axis={x axis={goto=max}, style={black!25, line cap=rect}}, + visualize grid={common={direction axis=x axis}}, + padding=.5em + }, + } + }, + % Possible axis positionings: + % + % Place axes labels below and left, where left label is rotated + % + standard labels/.style={ + /tikz/data visualization/@make labels/.style={ + x axis={ + visualize label={ + x axis={goto pos=.5}, + % Vertical position comes from bounding box: + node style={ + at={(0,0 |- data visualization bounding box.south)}, + below + } + } + }, + y axis={ + visualize label={ + y axis={goto pos=.5}, + % Horizontal position comes from bounding box: + node style={ + at={(0,0 -| data visualization bounding box.west)}, + rotate=90, + above} + } + } + } + }, + % + % Place axes labels below and left, no rotation + % + upright labels/.style={ + /tikz/data visualization/@make labels/.style={ + x axis={ + visualize label={ + x axis={goto pos=.5}, + % Vertical position comes from bounding box: + node style={ + at={(0,0 |- data visualization bounding box.south)}, + below + } + } + }, + y axis={ + visualize label={ + y axis={goto pos=.5}, + % Horizontal position comes from bounding box: + node style={ + at={(0,0 -| data visualization bounding box.west)}, + left + } + } + } + } + }, + % + % Place axes at the ends of the axes + % + end labels/.style={ + /tikz/data visualization/@make labels/.style={ + x axis={ + visualize label={ + y axis={goto=padded min}, + % Vertical position comes from bounding box: + node style={ + at={(0,0 -| data visualization bounding box.east)}, + right + } + } + }, + y axis={ + visualize label={ + x axis={goto=padded min}, + % Horizontal position comes from bounding box: + node style={ + at={(0,0 |- data visualization bounding box.north)}, + above + } + } + } + } + } +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.formats.functions.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.formats.functions.code.tex new file mode 100644 index 0000000000..5a04c51646 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.formats.functions.code.tex @@ -0,0 +1,16 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.formats.functions.code.tex} + +\usetikzlibrary{datavisualization}% +\usepgflibrary{datavisualization.formats.functions}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.polar.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.polar.code.tex new file mode 100644 index 0000000000..5a37b82854 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.polar.code.tex @@ -0,0 +1,565 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.polar.code.tex} + +\usetikzlibrary{datavisualization}% +\usepgflibrary{datavisualization.polar}% + + +\tikzdatavisualizationset{% + new polar axes/.style 2 args={ + new axis base=#1, + #1={attribute=angle}, + new axis base=#2, + #2={attribute=radius}, + #2/scaling/default=0 at 0 and 1 at 1cm, + new object={ + store=/tikz/data visualization/#1/polar transformer, + class=polar transformer, + arg1/.expanded=\pgfkeysvalueof{/tikz/data visualization/angle axis/attribute}/scaled, + arg2/.expanded=\pgfkeysvalueof{/tikz/data visualization/radius axis/attribute}/scaled, + arg3 from key=/tikz/data visualization/#1/unit vector 0 degrees, + arg4 from key=/tikz/data visualization/#1/unit vector 90 degrees + }, + /tikz/data visualization/#1/unit vector 0 degrees/.initial=\pgfqpoint{1pt}{0pt}, + /tikz/data visualization/#1/unit vector 90 degrees/.initial=\pgfqpoint{0pt}{1pt}, + }, + new polar axes/.default={angle axis}{radius axis} +}% +\def\tikz@lib@dv@polar@a#1{ + \pgfkeyssetvalue{\tikz@dv@axis/unit vector 0 degrees}{#1} +}% +\def\tikz@lib@dv@polar@b#1{ + \pgfkeyssetvalue{\tikz@dv@axis/unit vector 90 degrees}{#1} +}% + + + +% +% Scientific polar axes +% + +\tikzset{ + /tikz/data visualization/axis options/.cd, + unit vectors/.code 2 args={ + \tikz@scan@one@point\tikz@lib@dv@polar@a#1 + \tikz@scan@one@point\tikz@lib@dv@polar@b#2 + }, + degrees/.style={\tikz@dv@axis/scaling=0 at 0 and 1 at 1}, + radians/.style={\tikz@dv@axis/scaling=0 at 0 and 0.03141592653589793 at 1.8}, +}% + + + +\tikzdatavisualizationset{ + new axis system={scientific polar axes}{% + new polar axes, + angle axis={attribute=angle}, + radius axis={attribute=radius}, + every axis/.append style={style={draw=black!50}}, + every ticks/.append style={style={draw=black!50}}, + }{% + 0 to 360,% + outer ticks, + }{% + @make axes, + scientific polar axes/@setup axes, + /utils/exec={ + \edef\pgf@marshal{\noexpand\tikzdatavisualizationset{\pgfkeysvalueof{/tikz/data visualization/@which visualize radius axis}/.list={\pgfkeysvalueof{/tikz/data visualization/\pgfkeysvalueof{/tikz/data visualization/@which radius axes at}}}}} + \pgf@marshal + }, + @make labels + }, + @which radius axes at/.initial=@inner radius axes at, + @which visualize radius axis/.initial=@visualize radius axis, + @inner radius axes at/.initial=, + @clean radius axes at/.initial=, + @visualize radius axis/.style 2 args={ + radius axis={ + visualize axis={angle axis={goto=#1},high=padded max,low=0}, + visualize ticks={ + common={angle axis={goto=#1}, direction axis=angle axis}, + major={tick text at #2, + options at=0 as [{style={draw=none},no tick text}] + } + } + } + }, + @visualize clean radius axis/.style n args={5}{ + radius axis={ + visualize axis={angle + axis={goto=#1},high=max,low=0,style={black!25,line cap=rect}}, + visualize axis={angle + axis={goto=#1},high=max,low=0,style={line cap=rect,#4}}, + visualize ticks={ + style={#4}, + common={angle axis={goto=#1}, direction axis=angle axis, #3=0}, + major={tick text at #2,#5} + } + } + }, + @visualize zero/.style={@inner visualize zero={#1}}, + @clean visualize zero/.style={}, + @inner visualize zero/.style={ + radius axis={ + visualize ticks={ + common={angle axis={goto=0}, direction axis=angle axis}, + major={tick text at low,low=0,high=0,at=0 as + [{style={draw=none},node style={anchor=#1}}] + } + } + } + }, + @degrees/.style={ + angle axis={degrees, ticks={step=15, tick suffix=$^\circ$, major={ + options at=360 as [{style={draw=none},no tick text}], + options at=-180 as [{style={draw=none},no tick text}]}}} + }, + @rad/.style={ + angle axis={radians, ticks={ + step=(pi/12), + node style={ + /pgf/number format/frac, + /pgf/number format/frac shift={1} + }, + tick typesetter/.code={% + \pgfmathsetmacro{\tikz@lib@dv@pol}{round(####1*3.819718634205488)/12}% + \pgfmathapproxequalto{\tikz@lib@dv@pol}{0}% + \ifdim\pgfmathresult pt=1.0pt% + $0$% + \else% + \pgfmathapproxequalto{\tikz@lib@dv@pol}{1}% + \ifdim\pgfmathresult pt=1.0pt% + $\pi$% + \else + \pgfmathapproxequalto{\tikz@lib@dv@pol}{-1}% + \ifdim\pgfmathresult pt=1.0pt% + $-\pi$% + \else% + \pgfmathprintnumber{\tikz@lib@dv@pol}$\pi$% + \fi% + \fi% + \fi% + }, + major={ + options at=6.2831985e0 as [{style={draw=none},no tick text}], + options at=6.2831192e0 as [{style={draw=none},no tick text}], + options at=6.2830794e0 as [{style={draw=none},no tick text}], + options at=6.2828787e0 as [{style={draw=none},no tick text}], + options at=6.2831598e0 as [{style={draw=none},no tick text}], + options at=-3.1415991e0 as [{style={draw=none},no tick text}], + options at=-3.1415802e0 as [{style={draw=none},no tick text}], + options at=-3.1415602e0 as [{style={draw=none},no tick text}], + options at=-3.14153961e0 as [{style={draw=none},no tick text}], + options at=-3.1414406e0 as [{style={draw=none},no tick text}], + } + } + } + }, + @make labels/.style={}, +}% + +\tikzdatavisualizationset{ + scientific polar axes/.cd, + % + % + % + outer ticks/.style={ + /tikz/data visualization/@make axes/.style={ + radius axis={ + min value=0, + length=\pgfkeysvalueof{/tikz/data visualization/scientific polar axes/radius}, + padding=0em, + ticks={few}, + visualize grid={common={direction axis=angle axis,low=min,high=max}}, + }, + angle axis={ + visualize axis={radius axis={goto=padded max},low=min,high=max}, + visualize ticks={common={radius axis={goto=padded max},direction + axis=radius axis},common={low=0},major={tick text at high}}, + visualize grid={common={direction axis=radius axis},low=0,high=padded max}, + } + }, + /tikz/data visualization/@which radius axes at=@inner radius axes at, + /tikz/data visualization/@which visualize radius axis=@visualize radius axis, + /tikz/data visualization/@visualize zero/.style={@inner visualize zero={##1}}, + }, + inner ticks/.style={ + /tikz/data visualization/@make axes/.style={ + radius axis={ + min value=0, + length=\pgfkeysvalueof{/tikz/data visualization/scientific polar axes/radius}, + padding=0em, + ticks={few}, + visualize grid={common={direction axis=angle axis,low=min,high=max}}, + }, + angle axis={ + visualize axis={radius axis={goto=padded max},low=min,high=max}, + visualize ticks={common={radius axis={goto=padded max},direction + axis=radius axis},common={high=0},major={tick text at high}}, + visualize grid={common={direction axis=radius axis},low=0,high=padded max}, + } + }, + /tikz/data visualization/@which radius axes at=@inner radius axes at, + /tikz/data visualization/@which visualize radius axis=@visualize radius axis, + /tikz/data visualization/@visualize zero/.style={@inner visualize zero={##1}}, + }, + clean/.style={ + /tikz/data visualization/@make axes/.style={ + radius axis={ + min value=0, + length=\pgfkeysvalueof{/tikz/data visualization/scientific polar axes/radius}, + padding=.5em, + ticks={few}, + visualize grid={common={direction axis=angle axis,low=min,high=max}}, + }, + angle axis={ + padding=.5em, + visualize axis={radius axis={goto=max}, style={black!25, line cap=rect},low=min,high=max}, + visualize axis={radius axis={goto=padded max}, style={line cap=rect}, low=min,high=max}, + visualize ticks={common={radius axis={goto=padded max}, direction axis=radius axis},common={low=0},major={tick text at high}}, + visualize grid={common={direction axis=radius axis},low=0,high=max}, + } + }, + /tikz/data visualization/@which radius axes at=@clean radius axes at, + /tikz/data visualization/@which visualize radius axis=@visualize clean radius axis, + /tikz/data visualization/@visualize zero/.style={@clean visualize zero={##1}}, + }, + radius/.initial=3.25cm, + % + % First quadrant + % + 0 to pi half/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=1.570796326794897}, + @rad, + @visualize zero=north east, + @inner radius axes at={{0}{low},{1.570796326794897}{high}}, + @clean radius axes at={% + {0}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {1.570796326794897}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + 0 to 90/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=90}, + @degrees, + @visualize zero=north east, + @inner radius axes at={{0}{low},{90}{high}}, + @clean radius axes at={% + {0}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {90}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + quadrant/.style={ + @setup axes/.style={ + angle axis={scaling=min at 0 and max at 90, ticks}, + @visualize zero=north east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + quadrant clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 90 and max at 0, ticks}, + @visualize zero=north east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {max}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {min}{low}{high}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + % + % Fourth quadrant + % + -pi half to 0/.style={ + @setup axes/.style={ + angle axis={min value=-1.570796326794897, max value=0}, + @rad, + @visualize zero=south east, + @inner radius axes at={{-1.570796326794897}{low},{0}{high}}, + @clean radius axes at={% + {-1.570796326794897}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {0}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + -90 to 0/.style={ + @setup axes/.style={ + angle axis={min value=-90, max value=0}, + @degrees, + @visualize zero=south east, + @inner radius axes at={{-90}{low},{0}{high}}, + @clean radius axes at={% + {-90}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {0}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + fourth quadrant/.style={ + @setup axes/.style={ + angle axis={scaling=min at -90 and max at 0, ticks}, + @visualize zero=south east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + fourth quadrant clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 0 and max at -90, ticks}, + @visualize zero=south east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {max}{high}{low}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {min}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding max}}{} + } + } + }, + % + % Upper half + % + 0 to pi/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=3.141592653589793}, + @rad, + @visualize zero=north, + @inner radius axes at={{0}{low},{1.570796326794897}{high},{3.141592653589793}{high}}, + @clean radius axes at={% + {0}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {3.141592653589793}{high}{low}{yshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + 0 to 180/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=180}, + @degrees, + @visualize zero=north, + @inner radius axes at={{0}{low},{90}{high},{180}{high}}, + @clean radius axes at={% + {0}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {180}{high}{low}{yshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + upper half/.style={ + @setup axes/.style={ + angle axis={scaling=min at 0 and max at 180, ticks}, + @visualize zero=north, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{yshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + upper half clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 180 and max at 0, ticks}, + @visualize zero=north, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{yshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{yshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + % + % Lower half + % + lower half/.style={ + @setup axes/.style={ + angle axis={scaling=min at -180 and max at 0, ticks}, + @visualize zero=south, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{yshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + lower half clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 0 and max at -180, ticks}, + @visualize zero=south, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{yshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{yshift=\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + % + % Right half + % + -pi half to pi half/.style={ + @setup axes/.style={ + @rad, + angle axis={min value=-1.570796326794897, max value=1.570796326794897}, + @visualize zero=east, + @inner radius axes at={{0}{low},{1.570796326794897}{low},{-1.570796326794897}{high}}, + @clean radius axes at={% + {-1.570796326794897}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {1.570796326794897}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + -90 to 90/.style={ + @setup axes/.style={ + angle axis={min value=-90, max value=90}, + @degrees, + @visualize zero=east, + @inner radius axes at={{-90}{low},{0}{low},{90}{high}}, + @clean radius axes at={% + {-90}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {90}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + right half/.style={ + @setup axes/.style={ + angle axis={scaling=min at -90 and max at 90, ticks}, + @visualize zero=east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + right half clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 90 and max at -90, ticks}, + @visualize zero=east, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{xshift=\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{xshift=-\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + % + % Left half + % + left half/.style={ + @setup axes/.style={ + angle axis={scaling=min at 90 and max at 270, ticks}, + @visualize zero=west, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{xshift=\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + left half clockwise/.style={ + @setup axes/.style={ + angle axis={scaling=min at 270 and max at 90, ticks}, + @visualize zero=west, + @inner radius axes at={{min}{low},{max}{high}}, + @clean radius axes at={% + {min}{low}{high}{xshift=-\pgfkeysvalueof{/tikz/data visualization/angle axis/padding min}}{},% + {max}{high}{low}{xshift=\pgfkeysvalueof{/tikz/data + visualization/angle axis/padding max}}{options at=0 as + [{style={draw=none}, no tick text}]} + } + } + }, + % + % Full circle + % + 0 to 2pi/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=6.283185307179586}, + @rad, + @visualize zero=north east, + @inner radius axes at={{0}{low},{1.570796326794897}{high},{3.141592653589793}{high},{4.71238898038469}{low}}, + @clean radius axes at={{0}{low}{high}{}{}} + } + }, + -pi to pi/.style={ + @setup axes/.style={ + angle axis={min value=-3.141592653589793, max value=3.141592653589793}, + @rad, + @visualize zero=north east, + @inner radius axes at={{0}{low},{1.570796326794897}{high},{3.141592653589793}{high},{-1.57079632679489}{low}}, + @clean radius axes at={{0}{low}{high}{}{}} + } + }, + 0 to 360/.style={ + @setup axes/.style={ + angle axis={min value=0, max value=360}, + @degrees, + @visualize zero=north east, + @inner radius axes at={{0}{low},{90}{high},{180}{high},{270}{low}}, + @clean radius axes at={{0}{low}{high}{}{}} + } + }, + -180 to 180/.style={ + @setup axes/.style={ + angle axis={min value=-180, max value=180}, + @degrees, + @visualize zero=north east, + @inner radius axes at={{0}{low},{90}{high},{180}{high},{-90}{low}}, + @clean radius axes at={{0}{low}{high}{}{}} + } + }, +}% + + + + +% +% Pie-charts -- still under construction... +% + +\tikzset{ + /tikz/data visualization/axis options/.cd, + percent/.style={\tikz@dv@axis/scaling=0 at 0 and 1 at 3.6}, + full circle/.style={\tikz@dv@axis/scaling=min at 0 and max at 360}, + half circle/.style={\tikz@dv@axis/scaling=min at 0 and max at 180}, + quarter circle/.style={\tikz@dv@axis/scaling=min at 0 and max at 90} +}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.sparklines.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.sparklines.code.tex new file mode 100644 index 0000000000..2e2e77ae0b --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/datavisualization/tikzlibrarydatavisualization.sparklines.code.tex @@ -0,0 +1,37 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarydatavisualization.sparklines.code.tex} + +\usetikzlibrary{datavisualization}% + + + + +% +% Sparklines (not yet usable...) +% + +\tikzdatavisualizationset{ + spark line/.style={ + xy Cartesian, + x axis={ + unit length={1pt} + }, + y axis={ + scaling={min at -0.2em and max at 0.8em} + }, + new line plot, + every spark line plot/.try + } +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex new file mode 100644 index 0000000000..20a1735807 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex @@ -0,0 +1,2674 @@ +% Copyright 2019 by Till Tantau +% Copyright 2019 by Jannis Pohlmann +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarygraphs.code.tex} + + +% +% Interface keys +% + +\def\tikzgraphsset{\pgfqkeys{/tikz/graphs}}% + +\tikzgraphsset{ + new ->/.code n args={4}{% + \path [->,every new ->/.try] + (#1\tikzgraphleftanchor) + edge[#3] #4 + (#2\tikzgraphrightanchor);}, + new --/.code n args={4}{ + \path [-,every new --/.try] + (#1\tikzgraphleftanchor) + edge[#3] #4 + (#2\tikzgraphrightanchor);}, + new <->/.code n args={4}{ + \path [<->,every new <->/.try] + (#1\tikzgraphleftanchor) + edge[#3] #4 + (#2\tikzgraphrightanchor);}, + new -!-/.code n args={4}{}, + new <-/.code n args={4}{% + \path [<-,every new <-/.try] + (#1\tikzgraphleftanchor) + edge[#3] #4 + (#2\tikzgraphrightanchor); + } +}% + + +\def\tikz@lib@graph@store@anchor#1#2{% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \let#2\tikz@temp% + \else% + \def\tikz@temp{.#1}% + \let#2\tikz@temp% + \fi% +}% + +\tikzgraphsset{ + default edge kind/.initial=--, + --/.style={default edge kind=--}, + ->/.style={default edge kind=->}, + <-/.style={default edge kind=<-}, + <->/.style={default edge kind=<->}, + -!-/.style={default edge kind=-!-}, + default edge operator/.initial=matching and star, + left anchor/.code=\tikz@lib@graph@store@anchor{#1}{\tikzgraphleftanchor}, + right anchor/.code=\tikz@lib@graph@store@anchor{#1}{\tikzgraphrightanchor}, + left anchor=, + right anchor= +}% + + +% +% Keys for using nodes declared outside a graph inside a graph as if +% it were declared there +% + +\tikzgraphsset{ + use existing nodes/.is if=tikz@lib@graph@all +}% + +\tikzset{ + new set/.code={ + \expandafter\global\expandafter\let\csname tikz@lg@node@set #1\endcsname\pgfutil@empty% + }, + set/.code={ + \tikz@fig@mustbenamed% + \ifcsname tikz@lg@node@set #1\endcsname\else + \tikzerror{Undefined set `#1'}% + \fi + \expandafter\def\expandafter\tikz@alias\expandafter{\tikz@alias% + \expandafter\def\expandafter\pgf@temp\expandafter{\csname tikz@lg@node@set #1\endcsname}% + \expandafter\expandafter\expandafter\pgfutil@g@addto@macro\expandafter\pgf@temp\expandafter{\expandafter\tikz@lg@do\expandafter{\tikz@fig@name}}% + }% + },% +}% + +\newif\iftikz@lib@graph@all + + +% +% Simple versus multi graphs +% +\tikzgraphsset{ + simple/.code={ + \iftikz@lib@graph@simple% + % is already simple, ignore + \else + \tikz@lib@graph@simpletrue% + \pgfkeysalso{operator=\tikz@lib@graph@simple@done}% + \fi% + }, + multi/.code={ + \tikz@lib@graph@simplefalse% + } +}% + +\newif\iftikz@lib@graph@simple + +\def\tikz@lib@graph@set@simple@edge#1#2#3#4#5{% + % #1 = kind (<-, ->, ...) + % #2 = from + % #3 = to + % #4 = options + % #5 = edge nodes + % + % Ok, first, test, whether edge exists: + \ifcsname tikz@lg@e@#3@#2\endcsname% + \expandafter\global\expandafter\let\csname tikz@lg@e@#3@#2\endcsname\relax% reset + \fi% + \expandafter\gdef\csname tikz@lg@e@#2@#3\endcsname{\tikz@lib@graph@make@simple@edge{#1}{#2}{#3}{#4}{#5}}% +}% + +\def\tikz@lib@graph@make@simple@edge#1#2#3#4#5{% + \pgfqkeys{/tikz/graphs}{new #1={#2}{#3}{#4}{#5}}% +}% + + +\def\tikz@lib@graph@simple@done{% + \tikz@lib@graph@pack@node@list% + {% + \let\tikz@lg@do\tikz@lib@graph@simple@node% + \tikz@lib@graph@node@list + }% +}% + +\def\tikz@lib@graph@simple@node#1{% + {% + \def\tikz@lib@graph@simple@from@node{#1}% + \let\tikz@lg@do\tikz@lib@graph@simple@other@node% + \tikz@lib@graph@node@list% + }% +}% + +\def\tikz@lib@graph@simple@other@node#1{% + \ifcsname tikz@lg@e@\tikz@lib@graph@simple@from@node @#1\endcsname% + \csname tikz@lg@e@\tikz@lib@graph@simple@from@node @#1\endcsname% + \expandafter\global\expandafter\let\csname tikz@lg@e@\tikz@lib@graph@simple@from@node @#1\endcsname\relax% + \fi% +}% + + +% +% Basic options +% + +\tikzgraphsset{ + @nodes styling/.style=, + nodes/.style={/tikz/graphs/@nodes styling/.append style={,#1}}, + @edges styling/.initial=, + edges/.style={/tikz/graphs/@edges styling/.append={,#1}}, + edge/.style={edges={#1}}, + @edges node/.initial=, + edge node/.style={/tikz/graphs/@edges node/.append={#1}}, + edge label/.style={/tikz/graphs/@edges node/.append={node[auto]{#1}}}, + edge label'/.style={/tikz/graphs/@edges node/.append={node[auto,swap]{#1}}}, + @operators/.initial=, + operator/.style={/tikz/graphs/@operators/.append={#1}}, + @extra group options/.style=, +}% + + +\def\tikzgraphinvokeoperator#1{% + {% + \pgfkeyslet{/tikz/graphs/@operators}\pgfutil@empty% + \pgfkeys{/tikz/graphs/.cd,#1}% + \pgfkeysgetvalue{/tikz/graphs/@operators}\tikz@lib@graph@temp% + \global\let\tikz@lib@graph@temp\tikz@lib@graph@temp% + }% + \tikz@lib@graph@temp% + \global\let\tikz@lib@graph@temp\relax% +}% + + +% +% The parser +% + +\def\tikz@lib@graph@parser{% + \pgfutil@ifnextchar[{\tikz@lib@graph@parser@}{\tikz@lib@graph@parser@[]}%] +}% + +\def\tikz@lib@graph@parser@[#1]{% + \setbox\tikz@whichbox=\hbox\bgroup% + \unhbox\tikz@whichbox% + \hbox\bgroup + \bgroup% + \pgfinterruptpath% + \scope[graphs/.cd,@graph drawing setup/.try,@operators=,every graph/.try,#1]% + \begingroup% + \iftikz@graph@quick% + \expandafter\tikz@lib@graphs@parse@quick@graph% + \else% + \expandafter\tikz@lib@graphs@normal@main% + \fi% +}% + +\long\def\tikz@lib@graphs@normal@main#1{% + \pgfkeysgetvalue{/tikz/graphs/@operators}\tikz@lib@graph@outer@operators% + \let\tikz@lib@graph@options\pgfutil@empty% + \let\tikz@lib@graph@node@list\pgfutil@empty% + \pgfkeyssetvalue{/tikz/graphs/placement/depth}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/width}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/level}{0}% + \tikz@lib@graph@start@hint@group% + \tikz@lib@graph@parse@group{#1}% + \tikz@lib@graph@end@hint@group + \tikz@lib@graph@outer@operators% + \let\tikz@lg@do=\tikz@lib@graph@cleanup% + \tikz@lib@graph@node@list% + \tikz@lib@graph@main@done% +}% + +\def\tikz@lib@graph@main@done{% + \endgroup% + \endscope% + \endpgfinterruptpath% + \egroup + \egroup% + \egroup% + \tikz@lib@graph@parser@done% +}% + + + + + +\def\tikz@lib@graph@start@hint@group{% + \pgfkeyssetvalue{/tikz/graphs/placement/local depth}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/local width}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/chain count}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/element count}{0}% +}% + +\def\tikz@lib@graph@end@hint@group{% + % Get local depth and width outside + \xdef\tikz@lib@graph@group@depth{\pgfkeysvalueof{/tikz/graphs/placement/local depth}} + \xdef\tikz@lib@graph@group@width{\pgfkeysvalueof{/tikz/graphs/placement/local width}} +}% + +\def\tikz@lib@graph@hint@aftergroup{% + \pgfkeysgetvalue{/tikz/graphs/placement/width}\tikz@temp@h% + \pgfkeysgetvalue{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeysgetvalue{/tikz/graphs/placement/local depth}\tikz@temp@lw% + \pgfmathsetmacro\tikz@temp@h{\tikz@lib@graph@group@width+\tikz@temp@h} + \pgfmathsetmacro\tikz@temp@lh{\tikz@lib@graph@group@width+\tikz@temp@lh} + \pgfmathsetmacro\tikz@temp@lw{max(\tikz@lib@graph@group@depth,\tikz@temp@lw)} + \pgfkeyslet{/tikz/graphs/placement/width}\tikz@temp@h% + \pgfkeyslet{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeyslet{/tikz/graphs/placement/local depth}\tikz@temp@lw% + % + \pgfkeysgetvalue{/tikz/graphs/placement/element count}\tikz@temp% + \c@pgf@counta=\tikz@temp\relax% + \advance\c@pgf@counta by1\relax% + \edef\tikz@temp{\the\c@pgf@counta}% + \pgfkeyslet{/tikz/graphs/placement/element count}\tikz@temp% +}% + +\def\tikz@lib@graph@placement@update{% + \pgfkeys{/tikz/graphs/placement/logical node depth/.expand once=\tikz@lib@graph@name} + \let\tikz@lib@graph@node@depth\pgfmathresult + \pgfkeys{/tikz/graphs/placement/logical node width/.expand once=\tikz@lib@graph@name} + \let\tikz@lib@graph@node@width\pgfmathresult + % This is a single node, so update the lengths accordingly + \pgfkeysgetvalue{/tikz/graphs/placement/width}\tikz@temp@h% + \pgfkeysgetvalue{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeysgetvalue{/tikz/graphs/placement/local depth}\tikz@temp@lw% + \pgfmathsetmacro\tikz@temp@h{\tikz@lib@graph@node@width+\tikz@temp@h} + \pgfmathsetmacro\tikz@temp@lh{\tikz@lib@graph@node@width+\tikz@temp@lh} + \pgfmathsetmacro\tikz@temp@lw{max(\tikz@lib@graph@node@depth,\tikz@temp@lw)} + \pgfkeyslet{/tikz/graphs/placement/width}\tikz@temp@h% + \pgfkeyslet{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeyslet{/tikz/graphs/placement/local depth}\tikz@temp@lw% + % + \pgfkeysgetvalue{/tikz/graphs/placement/element count}\tikz@temp% + \c@pgf@counta=\tikz@temp\relax% + \advance\c@pgf@counta by1\relax% + \edef\tikz@temp{\the\c@pgf@counta}% + \pgfkeyslet{/tikz/graphs/placement/element count}\tikz@temp% +}% + +\def\tikz@lib@graph@placement@after@chain@update{% + \pgfkeysgetvalue{/tikz/graphs/placement/depth}\tikz@temp@w% + \pgfkeysgetvalue{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeysgetvalue{/tikz/graphs/placement/local depth}\tikz@temp@lw% + \pgfmathsetmacro\tikz@temp@w{\tikz@lib@graph@chain@depth+\tikz@temp@w}% + \pgfmathsetmacro\tikz@temp@lw{\tikz@lib@graph@chain@depth+\tikz@temp@lw}% + \pgfmathsetmacro\tikz@temp@lh{max(\tikz@lib@graph@chain@width,\tikz@temp@lh)}% + \pgfkeyslet{/tikz/graphs/placement/depth}\tikz@temp@w% + \pgfkeyslet{/tikz/graphs/placement/local width}\tikz@temp@lh% + \pgfkeyslet{/tikz/graphs/placement/local depth}\tikz@temp@lw% + % + \pgfkeysgetvalue{/tikz/graphs/placement/chain count}\tikz@temp% + \c@pgf@counta=\tikz@temp\relax% + \advance\c@pgf@counta by1\relax% + \edef\tikz@temp{\the\c@pgf@counta}% + \pgfkeyslet{/tikz/graphs/placement/chain count}\tikz@temp% +}% + + +% +% Parse a group +% + +\long\def\tikz@lib@graph@parse@group#1{ + \let\tikz@lib@graph@group@qa\pgfutil@empty% + \let\tikz@lib@graph@group@q\pgfutil@empty% + \let\tikz@lib@graph@group@c\pgfutil@empty% + \let\tikz@lib@graph@group@cont\pgfutil@empty% + \let\tikz@lib@graph@group@conta\pgfutil@empty% + \tikz@lib@graph@group@check#1\par\pgf@stop@eogroup% +}% + + + +% +% Start of a group +% +\def\tikz@lib@graph@group@check{% + \pgfutil@ifnextchar[\tikz@lib@graph@group@opt{\tikz@lib@graph@group@opt[]}%] +}% + +\def\tikz@lib@graph@group@opt[#1]{% + \let\tikz@lib@graph@parse@extras\pgfutil@empty% + \tikzgraphsset{ + @operators=, + every group/.try, + @extra group options, + @extra group options/.style=,% + #1}% + \expandafter\tikz@lib@graph@par\tikz@lib@graph@parse@extras% +}% + +\tikzgraphsset{ + parse/.code={\expandafter\def\expandafter\tikz@lib@graph@parse@extras\expandafter{\tikz@lib@graph@parse@extras#1}}, +}% + + + +% +% Remove \par +% + +\def\tikz@lib@graph@par{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@par@@}{\tikz@lib@graph@par@}% +}% +\long\def\tikz@lib@graph@par@#1\par{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@quotes\tikz@lib@graph@group@c#1"}{% + \expandafter\def\expandafter\tikz@lib@graph@group@c\expandafter{\tikz@lib@graph@group@c#1}% + \tikz@lib@graph@par% + }% +}% +\long\def\tikz@lib@graph@par@@#1{% + \expandafter\def\expandafter\tikz@lib@graph@group@c\expandafter{\tikz@lib@graph@group@c{#1}}% + \tikz@lib@graph@par +}% + + + +% +% Replace ..."..."... by ..."{...}"... +% +\def\tikz@lib@graph@quotes{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@quotes@@}{\tikz@lib@graph@quotes@}% +}% +\def\tikz@lib@graph@quotes@#1"{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \tikz@lib@graph@passon{#1}% + }{% + \expandafter\def\expandafter\tikz@lib@graph@group@q\expandafter{\tikz@lib@graph@group@q#1"}% + \tikz@lib@graph@quotes@cont% + }% +}% + +\def\tikz@lib@graph@quotes@cont#1"#2"{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \tikz@lib@graph@passon{{#1}"#2}}{% + \expandafter\def\expandafter\tikz@lib@graph@group@q\expandafter{\tikz@lib@graph@group@q{#1}"#2"}% + \tikz@lib@graph@quotes@cont}% +}% + +\def\tikz@lib@graph@quotes@@#1{% + \expandafter\def\expandafter\tikz@lib@graph@group@q\expandafter{\tikz@lib@graph@group@q{#1}}% + \tikz@lib@graph@quotes% +}% + + + +% +% Replace ..."..."... by ..."{...}"... (active version) +% +{% + \catcode`\"=13\relax + + \gdef\tikz@lib@graph@passon#1{\expandafter\tikz@lib@graph@quotesactive\tikz@lib@graph@group@q#1"}% + + \gdef\tikz@lib@graph@quotesactive{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@quotesactive@@}{\tikz@lib@graph@quotesactive@}% + }% + \gdef\tikz@lib@graph@quotesactive@#1"{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@encloser\tikz@lib@graph@group@qa#1[% + }{% + \expandafter\def\expandafter\tikz@lib@graph@group@qa\expandafter{\tikz@lib@graph@group@qa#1"}% + \tikz@lib@graph@quotesactive@cont% + }% + }% + + \gdef\tikz@lib@graph@quotesactive@cont#1"#2"{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@encloser\tikz@lib@graph@group@qa{#1}"#2[}{% + \expandafter\def\expandafter\tikz@lib@graph@group@qa\expandafter{\tikz@lib@graph@group@qa{#1}"#2"}% + \tikz@lib@graph@quotesactive@cont}% + }% + + \gdef\tikz@lib@graph@quotesactive@@#1{% + \expandafter\def\expandafter\tikz@lib@graph@group@qa\expandafter{\tikz@lib@graph@group@qa{#1}}% + \tikz@lib@graph@quotesactive% + }% +}% + + + + +% +% Replace ...[...]... by ...[{...}]... +% +\def\tikz@lib@graph@encloser{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@encloser@@}{\tikz@lib@graph@encloser@}% +}% +\def\tikz@lib@graph@encloser@#1[{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@semi\tikz@lib@graph@group@cont#1;% + }{% + \expandafter\def\expandafter\tikz@lib@graph@group@cont\expandafter{\tikz@lib@graph@group@cont#1[}%] + \tikz@lib@graph@encloser@cont% + }% +}% + +\def\tikz@lib@graph@encloser@cont#1]#2[{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@semi\tikz@lib@graph@group@cont{#1}]#2;}{% + \expandafter\def\expandafter\tikz@lib@graph@group@cont\expandafter{\tikz@lib@graph@group@cont{#1}]#2[}% + \tikz@lib@graph@encloser@cont}% +}% + +\def\tikz@lib@graph@encloser@@#1{% + \expandafter\def\expandafter\tikz@lib@graph@group@cont\expandafter{\tikz@lib@graph@group@cont{#1}}% + \tikz@lib@graph@encloser% +}% + + + + +% +% Replace ; by , +% + +\def\tikz@lib@graph@semi{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@semi@@}{\tikz@lib@graph@semi@}% +}% +\def\tikz@lib@graph@semi@#1;{% + \pgfutil@ifnextchar\pgf@stop@eogroup{% + \expandafter\tikz@lib@graph@main@parser\tikz@lib@graph@group@conta#1,}{% + \expandafter\def\expandafter\tikz@lib@graph@group@conta\expandafter{\tikz@lib@graph@group@conta#1,}% + \tikz@lib@graph@semi% + }% +}% +\def\tikz@lib@graph@semi@@#1{% + \expandafter\def\expandafter\tikz@lib@graph@group@conta\expandafter{\tikz@lib@graph@group@conta{#1}}% + \tikz@lib@graph@semi% +}% + + +% +% Main parse +% + +\def\tikz@lib@graph@main@parser{% + \begingroup% + \pgfkeyssetvalue{/tikz/graphs/placement/local depth}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/local width}{0}% + \let\tikz@lib@graph@stored@actions\pgfutil@empty% + \let\tikz@lib@graph@node@list\pgfutil@empty% reset + \tikz@lib@graph@main@parser@start% +}% +\def\tikz@lib@graph@main@parser@start{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@protect@group}{\tikz@lib@graph@main@parser@cont}% +}% + +\def\tikz@lib@graph@protect@group#1{% skip space + \pgfutil@ifnextchar\relax{\tikz@lib@graph@main@parser@cont{{#1}}}{\tikz@lib@graph@main@parser@cont{{#1}}}% +}% + +\def\tikz@lib@graph@main@parser@cont{\tikz@lib@graph@check@quotes\tikz@lib@graph@main@parser@cont@normal}% +\def\tikz@lib@graph@main@parser@cont@normal#1,{% + \tikz@lib@graph@parse@one#1-\pgf@stop@eodashes% +}% + +\def\tikz@lib@graph@parse@one{% + \pgfutil@ifnextchar\bgroup\tikz@lib@graph@scope\tikz@lib@graph@node% +}% + + + +% Special quoted nodes + +\def\tikz@lib@graph@check@quotes#1{% + \let\tikz@lib@graph@cont@quote#1% + \pgfutil@ifnextchar"{\begingroup\pgfkeys@temptoks{}\pgfutil@empty\tikz@lib@graph@quote@parser}{\tikz@lib@graph@check@quotes@active}% +}% +{% + \catcode`\"=13\relax + \gdef\tikz@lib@graph@check@quotes@active{% + \pgfutil@ifnextchar"{\begingroup\pgfkeys@temptoks{}\pgfutil@empty\tikz@lib@graph@quote@parser@active}{\tikz@lib@graph@cont@quote}% + }% + \gdef\tikz@lib@graph@quote@parser@active"#1"{% + \pgfkeys@temptoks\expandafter{\the\pgfkeys@temptoks #1}% + \pgfutil@ifnextchar"{\pgfkeys@temptoks\expandafter{\the\pgfkeys@temptoks "}\tikz@lib@graph@quote@parser@active}{\tikz@lib@graph@quote@parser@done}% + }% +}% + +\def\tikz@lib@graph@quote@parser"#1"{% + \pgfkeys@temptoks\expandafter{\the\pgfkeys@temptoks #1}% + \pgfutil@ifnextchar"{\pgfkeys@temptoks\expandafter{\the\pgfkeys@temptoks "}\tikz@lib@graph@quote@parser}{\tikz@lib@graph@quote@parser@done}% +}% + +\def\tikz@lib@graph@quote@parser@done{% + {\expandafter\scantokens\expandafter{% + \expandafter\expandafter\expandafter\tikzlibgraphactivations\expandafter\expandafter\expandafter\tikzlibgraphdoedef\expandafter{\the\pgfkeys@temptoks}% + }}% + {\expandafter\scantokens\expandafter{\expandafter\tikzlibgraphactivationsbrace\expandafter\xdef\expandafter\tikzlibgraphreplaced\expandafter<\tikzlibgraphreplaced>\catcode`\}=2\relax}}% + \edef\tikzlibgraphreplaced{\expandafter\detokenize\expandafter{\tikzlibgraphreplaced}} + \pgfutil@ifnextchar/\tikz@lib@graph@quotes@slash\tikz@lib@graph@quotes@no@slash% +}% +\def\tikz@lib@graph@quotes@no@slash{% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \tikz@smuggle\expandafter\expandafter\expandafter{\expandafter\tikzlibgraphreplaced\expandafter/\expandafter{\the\pgfkeys@temptoks}}% + \expandafter\endgroup\expandafter\tikz@lib@graph@cont@quote\tikz@smuggle% +}% +\def\tikz@lib@graph@quotes@slash/{% + \pgfutil@ifnextchar/% Ah, double slash... + {\tikz@lib@graph@quotes@no@slash/}{\expandafter\endgroup\expandafter\tikz@lib@graph@cont@quote\tikzlibgraphreplaced/}% +}% +\def\tikzlibgraphdoedef{\xdef\tikzlibgraphreplaced}% + +\def\tikz@lib@prepare@active#1#2#3{% + {% + \catcode`#1=13\relax% + \scantokens{\gdef\tikzlibgraphactivator{\def#2{@#3@}}}% + }% + \pgfutil@g@addto@macro\tikzlibgraphactivations{\catcode`#1=13\relax}% + \expandafter\pgfutil@g@addto@macro\expandafter\tikzlibgraphactivations\expandafter{\tikzlibgraphactivator}% +}% + +\let\tikzlibgraphactivations\pgfutil@empty + +% +% Remove \outer from \+ for plain TeX +% + +\outer\def\tikz@lib@outer@test{\tabalign}% +\ifx\+\tikz@lib@outer@test + \def\+{\tabalign} +\fi + +\tikz@lib@prepare@active{\$}{$}{DOLLAR SIGN}% $ +\tikz@lib@prepare@active{\&}{&}{AMPERSAND}% +\tikz@lib@prepare@active{\^}{^}{CIRCUMFLEX ACCENT}% +\tikz@lib@prepare@active{\~}{~}{TILDE}% +\tikz@lib@prepare@active{\_}{_}{LOW LINE}% +\tikz@lib@prepare@active{\|}{|}{VERTICAL LINE}% +\tikz@lib@prepare@active{\[}{[}{LEFT SQUARE BRACKET}% +\tikz@lib@prepare@active{\]}{]}{RIGHT SQUARE BRACKET}% +\tikz@lib@prepare@active{\(}{(}{LEFT PARENTHESIS}% +\tikz@lib@prepare@active{\)}{)}{RIGHT PARENTHESIS}% +\tikz@lib@prepare@active{\/}{/}{SOLIDUS}% +\tikz@lib@prepare@active{\.}{.}{FULL STOP}% +\tikz@lib@prepare@active{\-}{-}{HYPHEN MINUS}% +\tikz@lib@prepare@active{\,}{,}{COMMA}% +\tikz@lib@prepare@active{\+}{+}{PLUS SIGN}% +\tikz@lib@prepare@active{\*}{*}{ASTERISK}% +\tikz@lib@prepare@active{\'}{'}{APOSTROPHE}% +\tikz@lib@prepare@active{\!}{!}{EXCLAMATION MARK}% +\tikz@lib@prepare@active{\"}{"}{QUOTATION MARK}% +\tikz@lib@prepare@active{\:}{:}{COLON}% +\tikz@lib@prepare@active{\;}{;}{SEMINCOLON}% +\tikz@lib@prepare@active{\<}{<}{LESS THAN SIGN}% +\tikz@lib@prepare@active{\=}{=}{EQUALS SIGN}% +\tikz@lib@prepare@active{\>}{>}{GREATER THAN SIGN}% +\tikz@lib@prepare@active{\?}{?}{QUESTION MARK}% +%\tikz@lib@prepare@active{\@}{@}{COMMERCIAL AT}% +\tikz@lib@prepare@active{\`}{`}{GRAVE ACCENT}% +{\catcode`\%=11\catcode`\#=11 +\tikz@lib@prepare@active{\%}{%}{PERCENT SIGN} +\tikz@lib@prepare@active{\#}{#}{NUMBER SIGN} +} + +\pgfutil@g@addto@macro\tikzlibgraphactivations{\catcode`\\=13\relax}% +{% + \catcode`\|=0\relax + \catcode`\\=13\relax + |pgfutil@g@addto@macro|tikzlibgraphactivations{|def\{@REVERSE SOLIDUS@}}% +}% +{% + \gdef\tikzlibgraphscommercialat{@COMMERCIAL AT@}% + \let\g=\pgfutil@g@addto@macro + \catcode`\@=13\relax + \g\tikzlibgraphactivations{\catcode`\@=13\relax\let@=\tikzlibgraphscommercialat}% +}% + +\def\tikzlibgraphactivationsbrace{% + \catcode`\{=13\relax% + \catcode`\}=13\relax% + \catcode`\<=1\relax% + \catcode`\>=2\relax% +}% +{% + \catcode`\{=13\relax% + \catcode`\}=13\relax% + \catcode`\<=1\relax% + \catcode`\>=2\relax% + \pgfutil@g@addto@macro\tikzlibgraphactivationsbrace<\def{<@LEFT CURLY BRACE@>> %} + \pgfutil@g@addto@macro\tikzlibgraphactivationsbrace<\def}<@RIGHT CURLY BRACE@>> %{ +>% + +% A normal node + +% First, check for special quote syntax: + +\def\tikz@lib@graph@node{\tikz@lib@graph@check@quotes\tikz@lib@graph@node@normal}% + +\def\tikz@lib@graph@node@normal{% + \pgfutil@ifnextchar({\tikz@lib@graph@node@dressed}{\tikz@lib@graph@node@naked}% +}% + +\def\tikz@lib@graph@node@dressed(#1){% + % Add extra braces around nodes to protect dashes + \tikz@lib@graph@node@naked{(#1)}% +}% + +\def\tikz@lib@graph@node@naked#1-{% + % Detect trailing < + \tikz@lib@graph@@node#1<\pgf@stop% +}% + +\def\tikz@lib@graph@@node#1<#2\pgf@stop% +{ + % + % #1 will be a node (not a group) + % + % Syntax: node name [options] + % + % Grab node name + \tikz@lib@graph@grab@name#1\pgf@stop% + \tikz@lib@graph@stored@actions% + \pgfutil@ifnextchar\pgf@stop@eodashes{% + \tikz@lib@graph@graph@done% + }{% + % + % Now, get arrow kind + % + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \expandafter\tikz@lib@graph@no@back@arrow% + \else% + \expandafter\tikz@lib@graph@back@arrow% + \fi% + }% +}% + +\def\tikz@lib@graph@no@back@arrow{% + \pgfutil@ifnextchar>\tikz@lib@graph@forward@arrow{% + \pgfutil@ifnextchar-\tikz@lib@graph@undirected@arrow{% + \pgfutil@ifnextchar!\tikz@lib@graph@no@arrow{% + \tikzerror{One of the arrow types <-, --, ->, -!- or <-> expected}% + \tikz@lib@graph@undirected@arrow% + }% + }% + }% +}% + +\def\tikz@lib@graph@undirected@arrow-{% + \def\tikz@lib@graph@arrow@type{--}% + \tikz@lib@graph@after@arrow% +}% + +\def\tikz@lib@graph@forward@arrow>{% + \def\tikz@lib@graph@arrow@type{->}% + \tikz@lib@graph@after@arrow% +}% + +\def\tikz@lib@graph@bi@arrow>{% + \def\tikz@lib@graph@arrow@type{<->}% + \tikz@lib@graph@after@arrow% +}% + +\def\tikz@lib@graph@no@arrow!-{% + \def\tikz@lib@graph@arrow@type{-!-}% + \tikz@lib@graph@after@arrow% +}% + +\def\tikz@lib@graph@back@arrow{% + \pgfutil@ifnextchar>{\tikz@lib@graph@bi@arrow}{% + \def\tikz@lib@graph@arrow@type{<-}% + \tikz@lib@graph@after@arrow% + }% +}% + +\def\tikz@lib@graph@after@arrow{% + \pgfutil@ifnextchar[{\tikz@lib@graph@after@arrow@opt}{\tikz@lib@graph@after@arrow@opt[]}%] +}% + +\def\tikz@lib@graph@after@arrow@opt[#1]{% + % + % Ok, first recolor + % + \tikzgraphinvokeoperator{recolor source by=source''} + \tikzgraphinvokeoperator{recolor target by=target'} + % Save action for next node + \expandafter\def\expandafter\tikz@lib@graph@stored@actions\expandafter{% + \expandafter\tikz@lib@graph@joiner\expandafter{\tikz@lib@graph@arrow@type}{#1}}% + % + \tikzgdeventgroupcallback{descendants}% + \tikz@lib@graph@parse@one% +}% + +\def\tikz@lib@graph@joiner#1#2{% + \tikzgraphinvokeoperator{recolor source by=source'} + \tikzgraphinvokeoperator{recolor source'' by=source} + {% + \tikz@enable@edge@quotes% + \pgfkeyssetvalue{/tikz/graphs/default edge kind}{#1}% + \pgfkeys{/tikz/graphs/.cd,@operators=,% + /tikz/graphs/.unknown/.code=\tikz@lib@graph@unknown@edge@option{##1},#2}% + \pgfkeysgetvalue{/tikz/graphs/@operators}\pgf@temp% + \ifx\pgf@temp\pgfutil@empty% + \edef\pgf@temp{\noexpand\pgfkeys{/tikz/graphs/.cd,\pgfkeysvalueof{/tikz/graphs/default edge operator}}}% + \pgf@temp% + \pgfkeysgetvalue{/tikz/graphs/@operators}\pgf@temp% + \fi% + \pgf@temp% + }% + \tikzgraphinvokeoperator{not source',not target'} +}% + +\def\tikz@lib@graph@unknown@edge@option#1{% + \def\tikz@temp{/tikz/graphs/@edges styling/.append=} + \expandafter\expandafter\expandafter\pgfkeys% + \expandafter\expandafter\expandafter{\expandafter\tikz@temp\expandafter{\expandafter,\pgfkeyscurrentname={#1}}} +}% + +\def\tikz@lib@graph@graph@done\pgf@stop@eodashes{% + % Get local depth and width outside + \xdef\tikz@lib@graph@chain@depth{\pgfkeysvalueof{/tikz/graphs/placement/local depth}} + \xdef\tikz@lib@graph@chain@width{\pgfkeysvalueof{/tikz/graphs/placement/local width}} + % Get node list outside... + \expandafter% + \endgroup% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@graph@node@list\tikz@lib@graph@node@list}% + % Compute new local depth and width of group... + \tikz@lib@graph@placement@after@chain@update + % + \pgfutil@ifnextchar\pgf@stop@eogroup% + \tikz@lib@graph@graph@group@done% + \tikz@lib@graph@main@parser% +}% + +\def\tikz@lib@graph@graph@group@done\pgf@stop@eogroup{% + \pgfkeysvalueof{/tikz/graphs/@operators}% +}% + + + +% +% Handle node +% +\def\tikz@lib@graph@grab@name{% + \pgfutil@ifnextchar\foreach\tikz@lib@graph@do@foreach\tikz@lib@graph@parse@node@text% +}% + +\def\tikz@lib@graph@do@foreach\foreach#1in{% + \pgfutil@ifnextchar\bgroup{\tikz@lib@graph@do@foreach@normal{#1}}{\def\tikz@temp{#1}\tikz@lib@graph@do@foreach@macro}% +}% +\def\tikz@lib@graph@do@foreach@macro#1{% + \expandafter\expandafter\expandafter\tikz@lib@graph@do@foreach@normal\expandafter\tikz@temp\expandafter{#1}% +}% + +\def\tikz@lib@graph@do@foreach@normal#1#2#3\pgf@stop{% + % Ok, we do a parse on a foreach loop. + \begingroup + \let\tikz@lib@graph@node@list@saved\pgfutil@empty% + \xdef\tikz@lib@graph@saved@placement{% + {\pgfkeysvalueof{/tikz/graphs/placement/local depth}}% + {\pgfkeysvalueof{/tikz/graphs/placement/local width}}% + {\pgfkeysvalueof{/tikz/graphs/placement/chain count}}% + {\pgfkeysvalueof{/tikz/graphs/placement/element count}}% + {\pgfkeysvalueof{/tikz/graphs/placement/width}}% + {\pgfkeysvalueof{/tikz/graphs/placement/depth}}% + }% + \foreach #1 in {#2}% + {% + \let\tikz@lib@graph@node@list\tikz@lib@graph@node@list@saved% + \expandafter\tikz@lib@graph@setup@placement\tikz@lib@graph@saved@placement% + \tikz@lib@graph@parse@group{#3}% + \xdef\tikz@lib@graph@saved@placement{% + {\pgfkeysvalueof{/tikz/graphs/placement/local depth}}% + {\pgfkeysvalueof{/tikz/graphs/placement/local width}}% + {\pgfkeysvalueof{/tikz/graphs/placement/chain count}}% + {\pgfkeysvalueof{/tikz/graphs/placement/element count}}% + {\pgfkeysvalueof{/tikz/graphs/placement/width}}% + {\pgfkeysvalueof{/tikz/graphs/placement/depth}}% + }% + % TODO: Need to also save hints! + \global\let\tikz@lib@graph@node@list@saved\tikz@lib@graph@node@list% + }% + \expandafter% + \endgroup% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@graph@node@list\tikz@lib@graph@node@list@saved}% + \expandafter\tikz@lib@graph@setup@placement\tikz@lib@graph@saved@placement% +}% + +\def\tikz@lib@graph@setup@placement#1#2#3#4#5#6{% + \pgfkeyssetvalue{/tikz/graphs/placement/local depth}{#1}% + \pgfkeyssetvalue{/tikz/graphs/placement/local width}{#2}% + \pgfkeyssetvalue{/tikz/graphs/placement/chain count}{#3}% + \pgfkeyssetvalue{/tikz/graphs/placement/element count}{#4}% + \pgfkeyssetvalue{/tikz/graphs/placement/width}{#5}% + \pgfkeyssetvalue{/tikz/graphs/placement/depth}{#6}% +}% + +\def\tikz@lib@graph@parse@node@text#1\pgf@stop{% + % + % Ok, first test whether #1 contains "//" + % + \pgfutil@in@{//}{#1 } + \ifpgfutil@in@% + % Ok, a layout node: + \tikz@lib@parse@layout@node#1\pgf@stop% + \else% + \tikz@lib@graph@fake@nodefalse + \let\tikz@lib@graph@node@parsed\tikz@lib@graph@node@opt@normal% + \def\tikz@lib@graph@empty@node@parsed{\tikzgdeventcallback{node}{}}% + \tikz@lib@parse@normal@node#1[\pgf@stop% + \fi% +}% + +\newif\iftikzgraphsautonumbernodes +\newcount\tikz@lib@auto@number + +\def\tikz@lib@do@autonumber{% + \ifx\tikz@lib@graph@name@only\pgfutil@empty% + \else% + \edef\tikz@lib@graph@name@only{\tikz@lib@graph@name@only\tikz@lib@auto@sep\the\tikz@lib@auto@number}% + \global\advance\tikz@lib@auto@number by1\relax% + \fi% +}% + +% +% Parse the normal part of a node (name and, possibly, text after slash) +% + +\def\tikz@lib@parse@normal@node#1[{ + % + % Test whether #1 contains "/" or "__" + % + \pgfutil@in@{/}{#1}% + \ifpgfutil@in@% + \tikz@lib@parse@node@with@slash#1\pgf@stop% + \else + \pgfutil@in@{__}{#1}% + \ifpgfutil@in@% + \tikz@lib@parse@node@with@doubleunder#1\pgf@stop% + \else + \edef\pgf@marshal{\noexpand\pgfkeys@spdef\noexpand\tikz@lib@graph@name@only{#1}}% + \pgf@marshal% + \let\tikz@lib@graph@node@text\tikz@lib@graph@name@only% + \edef\tikz@lib@graph@name{\tikz@lib@graph@path\tikz@lib@graph@name@only}% + \fi% + \fi% + \tikz@lib@graph@handle@node@cont% +}% + +\def\tikz@lib@parse@node@with@slash#1/{ + \pgfkeys@spdef\tikz@lib@graph@name@only{#1}% + \ifx\tikz@lib@graph@name@only\pgfutil@empty% + \global\advance\tikz@fig@count by1\relax + \edef\tikz@lib@graph@name@only{tikz@f@\the\tikz@fig@count}% + \fi% + \edef\tikz@lib@graph@name{\tikz@lib@graph@path\tikz@lib@graph@name@only}% + \pgfutil@ifnextchar"\tikz@lg@slash@quote{\pgfutil@ifnextchar\tikz@active@quotes@token\tikz@lg@slash@quote@active\tikz@lg@slash@cont} +}% +\def\tikz@lg@slash@quote"#1"#2\pgf@stop{% + \iftikz@handle@active@nodes% + \def\tikz@lib@graph@node@text{\scantokens{#1}}% + \else + \def\tikz@lib@graph@node@text{#1}% + \fi% +}% +{\catcode`\"=13\relax + \gdef\tikz@lg@slash@quote@active"#1"#2\pgf@stop{% + \iftikz@handle@active@nodes% + \def\tikz@lib@graph@node@text{\scantokens{#1}}% + \else + \def\tikz@lib@graph@node@text{#1}% + \fi% + }% +}% +\def\tikz@lg@slash@cont#1\pgf@stop{% + \iftikz@handle@active@nodes% + \def\tikz@lib@graph@node@text{\scantokens{#1}}% + \else + \def\tikz@lib@graph@node@text{#1}% + \fi% +}% + +\def\tikz@lib@parse@node@with@doubleunder#1__{\tikz@lib@parse@node@with@slash{#1}/}% + +\def\tikz@lg@find@fresh@name{% + \edef\tikz@lib@graph@name@only{\tikz@lib@graph@name@only'}% + \edef\tikz@lib@graph@name{\tikz@lib@graph@path\tikz@lib@graph@name@only}% + \tikz@lg@if@local@node{\tikz@lib@graph@name}{\tikz@lg@find@fresh@name}{}% +}% + + +% +% We have now parsed everything up to the opening "[". We continue +% + +\def\tikz@lib@graph@handle@node@cont{% + \iftikzgraphsautonumbernodes% + \tikz@lib@do@autonumber% + \fi% + \iftikz@lib@graph@fresh@node% + \tikz@lg@if@local@node{\tikz@lib@graph@name}{\tikz@lg@find@fresh@name}{}% + \fi% + \let\tikzgraphnodeas\tikzgraphnodeas@default% + \pgfutil@ifnextchar\pgf@stop{% + \ifx\tikz@lib@graph@name@only\pgfutil@empty% + \expandafter\tikz@lib@graph@node@empty@done% + \else + \expandafter\tikz@lib@graph@node@opt\expandafter[\expandafter]\expandafter[% + \fi% + }{\tikz@lib@graph@node@opt[}% +}% + +\def\tikzgraphnodeas@default{% + \tikz@lib@graph@typesetter% +}% + +\let\tikz@lib@graph@empty@node@parsed\relax% + +\def\tikz@lib@graph@node@opt[#1]#2[\pgf@stop{% + \tikz@lib@graph@node@parsed{#1}% +}% + +\def\tikz@lib@graph@node@empty@done\pgf@stop{\tikz@lib@graph@empty@node@parsed}% + +% +% Parse a layout node +% + +\def\tikz@lib@parse@layout@node#1//{% + \pgf@lib@graph@empty@layout@nodefalse% + \let\tikz@lib@graph@node@parsed\tikz@lib@layout@node@parsed% + \let\tikz@lib@graph@empty@node@parsed\tikz@lib@graph@empty@layout@node@parsed + \tikz@lib@parse@normal@node#1[\pgf@stop% +}% + +\newif\ifpgf@lib@graph@empty@layout@node + +\def\tikz@lib@layout@node@parsed{% + \tikz@lib@layout@parse@rest% +}% + +\def\tikz@lib@graph@empty@layout@node@parsed{% + \pgf@lib@graph@empty@layout@nodetrue + \tikz@lib@layout@parse@rest{}% +}% + +\def\tikz@lib@layout@parse@rest#1{% + \def\tikz@lib@layout@node@options{#1}% + \pgfutil@ifnextchar[{\tikz@lib@layout@node@opt}{\tikz@lib@layout@node@opt[]}%} +}% + +\def\tikz@lib@layout@node@parsed#1{% + \def\tikz@lib@layout@node@options{#1}% + \pgfutil@ifnextchar[{\tikz@lib@layout@node@opt}{\tikz@lib@layout@node@opt[]}%} +}% + +\def\tikz@lib@layout@node@opt[#1]{% + \def\tikz@lib@layout@options{#1}% + \pgfutil@ifnextchar\bgroup{\tikz@lib@layout@start}{\tikzerror{Opening brace at beginning of sublayout expected}}% +}% + + +% +% Typeset a normal node +% + +\def\tikz@lib@graph@node@opt@normal#1{% + \expandafter\tikz@lib@graph@test@use@list\tikz@lib@graph@name@only\pgf@stop + \iftikz@lib@graph@use@list% + % Ok, make a list of the nodes stored in #1: + \let\tikz@lg@temp\pgfutil@empty% + \foreach \tikz@lg@node@name in \tikz@lib@graph@use@list {\expandafter\tikz@lib@graph@handle@use\expandafter{\tikz@lg@node@name}} + % Ok, now add the nodes to the node list + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{% + \expandafter\tikz@lib@graph@node@list\tikz@lg@temp}% + % Then color and initialize them: + \let\tikz@lg@do\tikz@lib@graph@do@use% + \tikz@lg@temp% + \else% + \edef\tikz@lib@graph@name{\tikz@lib@graph@path\tikz@lib@graph@name@only}% + \expandafter\ifx\csname tikz@lib@graph@def@\tikz@lib@graph@name@only\endcsname\relax% + \pgfkeysgetvalue{/tikz/graphs/placement/level}\tikz@temp% + \c@pgf@counta=\tikz@temp\relax% + \advance\c@pgf@counta by1\relax% + \edef\tikz@temp{\the\c@pgf@counta}% + \pgfkeyslet{/tikz/graphs/placement/level}\tikz@temp% + \tikzgraphsset{ + level/.try=\pgfkeysvalueof{/tikz/graphs/placement/level}, + level \pgfkeysvalueof{/tikz/graphs/placement/level}/.try + } + {% + \edef\tikz@lib@graph@node@list{\noexpand\tikz@lg@do{\tikz@lib@graph@name}}% + \global\tikz@lib@graph@node@createdfalse% + \pgfkeyslet{/tikz/graphs/@operators}\pgfutil@empty% + \tikz@lib@activate@source@target@edge@syntax% + \tikz@lg@if@local@node{\tikz@lib@graph@name}% + {\tikz@lg@local@node@handle{#1}}% + {% + \tikz@lg@init@color{\tikz@lib@graph@name}{\tikz@lgc@all@true\tikz@lgc@source@true\tikz@lgc@target@true}% + \iftikz@lib@graph@all% + \tikzgraphsset{#1}\pgfkeysvalueof{/tikz/graphs/@operators}% + \else% + \pgfkeys{/tikz/graphs/placement/place}% + \let\tikzgraphnodetext\tikz@lib@graph@node@text% + \let\tikzgraphnodename\tikz@lib@graph@name@only% + \let\tikzgraphnodepath\tikz@lib@graph@path% + \let\tikzgraphnodefullname\tikz@lib@graph@name% + \iftikz@lib@graph@fake@node% + {% run options in protected mode... + \pgfkeys{ + /tikz/graphs/.cd,% + .unknown/.code=, + /tikz/graphs/@nodes styling,% + #1}% + \pgfkeysgetvalue{/tikz/graphs/@operators}\tikz@lib@graph@op@save% + \global\let\tikz@lib@graph@op@save\tikz@lib@graph@op@save% + }% + \else% + \node [% + name=\tikz@lib@graph@name,% + execute at end node={% + \pgfkeysgetvalue{/tikz/graphs/@operators}\tikz@lib@graph@op@save% + \global\let\tikz@lib@graph@op@save\tikz@lib@graph@op@save% + },% + graphs/redirect unknown to tikz, + /tikz/graphs/.cd,% + /tikz/graphs/@nodes styling,% + #1]% + {% + \tikzgraphnodeas% + };% + \fi% + \tikz@lib@graph@op@save\global\let\tikz@lib@graph@op@save\relax%% + \global\tikz@lib@graph@node@createdtrue% + \fi + }% + }% + \iftikz@lib@graph@node@created\tikz@lib@graph@placement@update\fi% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{% + \expandafter\tikz@lib@graph@node@list\expandafter\tikz@lg@do\expandafter{\tikz@lib@graph@name}}% + \iftikz@lib@graph@trie\tikzgraphsset{name=\tikz@lib@graph@name@only}\fi% + \else + % The name of the node is a graph name + \tikz@lib@graph@handle@graph{#1}% + \fi + \fi% +}% + +\newif\iftikz@lib@graph@fake@node + +\newif\iftikz@lib@graph@use@list +\def\tikz@lib@graph@test@use@list{% + \pgfutil@ifnextchar({\tikz@lib@graph@use@list@grap}{\tikz@lib@graph@test@use@list@done}%) +}% + +\def\tikz@lib@graph@test@use@list@done#1\pgf@stop{\tikz@lib@graph@use@listfalse}% +\def\tikz@lib@graph@use@list@grap(#1)\pgf@stop{\def\tikz@lib@graph@use@list{#1}\tikz@lib@graph@use@listtrue}% + + +% +% Typeset a layout node +% + +\def\tikz@lib@layout@start#1#2\pgf@stop{% + \tikz@lib@ensure@gd@loaded% + % Parameters are: + % + % Node name is \tikz@lib@graph@name@only + % Node text is \tikz@lib@graph@node@text + % Node options are \tikz@lib@layout@node@options + % Layout options are \tikz@lib@layout@options + % Layout is #1 + % Rest is #2 (should be empty or just whitespace) + \tikz@lib@graph@fake@nodefalse% + \ifpgf@lib@graph@empty@layout@node% + \else% + \ifx\tikz@lib@graph@name\pgfutil@empty% + \tikzerror{Internal error: Node has no name, but it should!}% + \else + \tikz@lib@graph@fake@nodetrue% + \expandafter\tikz@lib@graph@node@opt@normal\expandafter{\tikz@lib@layout@node@options}% + \fi% + \fi% + \edef\tikz@lib@graph@name{\tikz@lib@graph@path\tikz@lib@graph@name@only}% + % + % Prepare tikz node options + % + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@layout@node@options\expandafter\expandafter\expandafter{\expandafter\tikz@lib@layout@startup@node@options\tikz@lib@layout@node@options,}% + \begingroup + % Create a subgraph node, if name is given. + \iftikz@lib@graph@fake@node% + \expandafter\expandafter\expandafter% + \expandafter\expandafter\expandafter\expandafter\tikz@lib@make@subgraph@node% + \expandafter\expandafter\expandafter% + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter\tikz@lib@graph@name% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\tikz@lib@graph@node@text\expandafter}\expandafter{\tikz@lib@layout@node@options} + \fi% + % + % Here comes the scope: + % + \expandafter\expandafter\expandafter\scope\expandafter\expandafter\expandafter[\expandafter\tikz@lib@layout@node@options@prefix\tikz@lib@layout@options] + \tikzgdeventgroupcallback{array}% + \let\tikz@lib@graph@node@list\pgfutil@empty% + \tikz@lib@graph@start@hint@group% + \tikz@lib@graph@parse@group{#1}% + \tikz@lib@graph@end@hint@group% + \def\tikz@lg@old@col{\tikz@lgc@source@true}% + \let\tikz@lg@new@col\pgfutil@empty% + \let\tikz@lg@do\tikz@lg@change@color% + \tikz@lib@graph@node@list% + \def\tikz@lg@old@col{\tikz@lgc@target@true}% + \tikz@lib@graph@node@list% + \expandafter% + \endscope\expandafter% + \endgroup% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@graph@node@list\tikz@lib@graph@node@list}% + \tikz@lib@graph@hint@aftergroup% +}% +\def\tikz@lib@make@subgraph@node#1#2#3{% + \pgfgdsubgraphnode{#1}{#3}{\pgfgdsubgraphnodecontents{#2}}% +}% +\def\tikz@lib@layout@startup@node@options{% + /utils/exec=\tikzlibignorecomparisonsINTERNAL, + /tikz/graphs/.cd,% + redirect unknown to tikz,% + anchor=base,% + /tikz/every subgraph node/.try,% +}% +\def\tikzlibignorecomparisonsINTERNAL{% + \pgfkeys{/handlers/first char syntax=true} + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string>}{\pgfutil@gobble}% + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string<}{\pgfutil@gobble}% +}% +\def\tikz@lib@layout@node@options@prefix{graphs/.cd,}% + +\ifx\tikz@lib@ensure@gd@loaded\pgfutil@undefined% +\def\tikz@lib@ensure@gd@loaded{\tikzerror{You must say \string\usetikzlibrary{graphdrawing} to use the (sub)layout syntax}}% +\fi + +\def\tikz@lg@local@node@handle#1{% + % + % Handle late options and operators + \tikzgraphsset{source,target,.unknown/.code=,#1}% + \tikzgdlatenodeoptionacallback{\tikz@pp@name\tikz@lib@graph@name}% + \node also[graphs/redirect unknown to tikz,/tikz/graphs/.cd,#1](\tikz@lib@graph@name);% + \pgfkeysvalueof{/tikz/graphs/@operators}% +}% + +\tikzgraphsset{redirect unknown to tikz/.style={ + /tikz/graphs/.unknown/.code={% + \let\tikz@key\pgfkeyscurrentname% + \pgfkeys{tikz/.cd,\tikz@key={##1},/tikz/graphs/.cd}% + }} +}% + +\def\tikz@lib@activate@source@target@edge@syntax{% + \pgfkeys{/handlers/first char syntax=true} + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string>}{\tikz@lg@parse@more}% + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string<}{\tikz@lg@parse@less}% +}% + +\def\tikz@lg@parse@less#1{\tikz@lg@parse@less@#1\pgf@stop}% +\def\tikz@lg@parse@less@<{\pgfutil@ifnextchar"{\tikz@lg@parse@quote{source}}{\tikz@lg@parse@noquote{source}}}% +\def\tikz@lg@parse@more#1{\tikz@lg@parse@more@#1\pgf@stop}% +\def\tikz@lg@parse@more@>{\pgfutil@ifnextchar"{\tikz@lg@parse@quote{target}}{\tikz@lg@parse@noquote{target}}}% + +\def\tikz@lg@parse@noquote#1#2\pgf@stop{{\tikzgraphsset{#1 edge style={#2}}}}% +\def\tikz@lg@parse@quote#1#2\pgf@stop{% + {\tikzgraphsset{/tikz/node quotes mean={#1 edge node={node [every edge quotes,##2]{##1}}},/utils/exec=\tikz@enable@node@quotes,#2}}% +}% + +\tikzgraphsset{ + clear >/.style=target edge clear, + clear , -!-, or <-> expected}% + }% + }% +}% + +\def\tikz@lib@graph@scope@minus-{ + \pgfutil@ifnextchar>\tikz@lib@graph@forward@arrow{% + \pgfutil@ifnextchar-\tikz@lib@graph@undirected@arrow{% + \pgfutil@ifnextchar!\tikz@lib@graph@no@arrow{% + \pgfutil@ifnextchar\pgf@stop@eodashes\tikz@lib@graph@graph@done{% + \tikzerror{One of the arrow types <-, --, ->, -!-, or <-> expected}% + \tikz@lib@graph@undirected@arrow% + }% + }% + }% + }% +}% + +\def\tikz@lib@graph@scope@less<-{\tikz@lib@graph@back@arrow}% + + + + +% +% Predefining graphs +% + +\tikzgraphsset{ + declare/.code 2 args={\expandafter\def\csname tikz@lib@graph@def@#1\endcsname{\tikz@lib@graph@do@graph{#2}}}% +}% + +\def\tikz@lib@graph@handle@graph#1{% + \begingroup% + \let\tikz@lib@graph@node@list\pgfutil@empty% + \tikzgraphsset{@extra group options/.style={#1}}% + \tikz@lib@graph@start@hint@group% + \csname tikz@lib@graph@def@\tikz@lib@graph@name@only\endcsname% + \tikz@lib@graph@end@hint@group% + \expandafter% + \endgroup% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@lib@graph@node@list% + \expandafter\expandafter\expandafter{\expandafter\tikz@lib@graph@node@list\tikz@lib@graph@node@list}% + \tikz@lib@graph@hint@aftergroup% +}% + +\def\tikz@lib@graph@do@graph#1{% + \tikz@lib@graph@parse@group{#1}% +}% + +\let\tikz@lib@graph@path\pgfutil@empty + +\tikzgraphsset{ + name separator/.store in=\tikz@lib@graph@name@separator, + name separator=\space, + name/.code={% + \edef\tikz@lib@graph@path{\tikz@lib@graph@path#1\tikz@lib@graph@name@separator}% + }% +}% + + +% +% Colors +% +\def\tikz@lg@newif{\csname newif\endcsname}% +\tikzgraphsset{ + as/.code=\def\tikzgraphnodeas{#1},% + color class/.style={% + /utils/exec=\expandafter\tikz@lg@newif\csname iftikz@lgc@#1@\endcsname, + #1/.style={operator={% + \edef\tikz@lg@col{\expandafter\noexpand\csname tikz@lgc@#1@true\endcsname}% + \let\tikz@lg@do\tikz@lg@colorize% + \tikz@lib@graph@node@list% + }}, + not #1/.style={operator={% + \edef\tikz@lg@old@col{\expandafter\noexpand\csname tikz@lgc@#1@true\endcsname}% + \let\tikz@lg@new@col\pgfutil@empty% + \let\tikz@lg@do\tikz@lg@change@color% + \tikz@lib@graph@node@list% + }}, + recolor #1 by/.style={operator={% + \edef\tikz@lg@old@col{\expandafter\noexpand\csname tikz@lgc@#1@true\endcsname}% + \edef\tikz@lg@new@col{\expandafter\noexpand\csname tikz@lgc@##1@true\endcsname}% + \let\tikz@lg@do\tikz@lg@change@color% + \tikz@lib@graph@node@list% + }}, + !#1/.style=not #1, + }, + color class=source, + color class=source', + color class=source'', + color class=target, + color class=target', + color class=all +}% + +\def\tikz@lg@init@color#1#2{% + \expandafter\gdef\csname tikz@lgc@#1\endcsname{#2}% +}% + +\def\tikz@lib@graph@cleanup#1{% + \expandafter\global\expandafter\let\csname tikz@lgc@#1\endcsname\relax% + \ifcsname tikz@lgca@@#1\endcsname\expandafter\global\expandafter\let\csname tikz@lgca@@#1\endcsname\relax\fi% + \ifcsname tikz@lgcb@@#1\endcsname\expandafter\global\expandafter\let\csname tikz@lgcb@@#1\endcsname\relax\fi% +}% + +\def\tikz@lg@colorize#1{% + \expandafter\let\expandafter\pgf@temp\csname tikz@lgc@#1\endcsname% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@temp% + \expandafter\expandafter\expandafter{% + \expandafter\tikz@lg@col\pgf@temp}% + \expandafter\global\expandafter\let\csname tikz@lgc@#1\endcsname\pgf@temp% +}% + +\def\tikz@lg@change@color#1{% + \def\tikz@lg@temp@save{#1}% + \let\tikz@lg@collect\pgfutil@empty% + \expandafter\let\expandafter\pgf@temp\csname tikz@lgc@#1\endcsname% + \expandafter\tikz@lg@change@check\pgf@temp\pgf@stop% +}% +\def\tikz@lg@change@check#1{% + \ifx#1\pgf@stop% + \tikz@lg@change@write@back% + \else% + \def\pgf@temp{#1}% + \ifx\pgf@temp\tikz@lg@old@col% + \expandafter\tikz@lg@change@add\expandafter{\tikz@lg@new@col}% Found! + \else% + \tikz@lg@change@add{#1}% + \fi% + \expandafter\tikz@lg@change@check + \fi% +}% +\def\tikz@lg@change@add#1{% + \expandafter\def\expandafter\tikz@lg@collect\expandafter{\tikz@lg@collect#1}% +}% + +\def\tikz@lg@change@write@back{% + \expandafter\global\expandafter\let\csname tikz@lgc@\tikz@lg@temp@save\endcsname\tikz@lg@collect% +}% + + + +\def\tikz@lg@if@has@color#1#2#3#4{% + {% + \csname tikz@lgc@#1\endcsname% + \expandafter\let\expandafter\pgf@temp\csname iftikz@lgc@#2@\endcsname% + \ifx\pgf@temp\relax% + \tikz@lib@reset@temp% + \fi% + \pgf@temp% + \global\tikz@color@testtrue% + \else% + \global\tikz@color@testfalse% + \fi% + }% + \iftikz@color@test#3\else#4\fi% +}% +\newif\iftikz@color@test + +\def\tikz@lg@if@local@node#1#2#3{\expandafter\ifx\csname tikz@lgc@#1\endcsname\relax#3\else#2\fi}% + +\def\tikz@lib@reset@temp{\let\pgf@temp\iffalse}% + +% +% Handle connection annotations +% +\def\tikz@lib@annotate@#1#2#3#4{% + \expandafter\ifx\csname tikz@lgc#1@@#2\endcsname\relax% + \expandafter\gdef\csname tikz@lgc#1@@#2\endcsname{{#3}{#4}}% + \else% + \expandafter\expandafter\expandafter\tikz@lib@annotate@read\csname tikz@lgc#1@@#2\endcsname{#3}{#4}% + \expandafter\global\expandafter\let\csname tikz@lgc#1@@#2\endcsname\pgf@temp% + \fi% +}% +\def\tikz@lib@annotate@read#1#2#3#4{\def\pgf@temp{{#1,#3}{#2#4}}}% + +\tikzgraphsset{ + source edge style/.code=\tikz@lib@annotate@{a}{\tikz@lib@graph@name}{#1}{}, + source edge node/.code=\tikz@lib@annotate@{a}{\tikz@lib@graph@name}{}{#1}, + source edge clear/.code={ + \expandafter\global\expandafter\let\csname tikz@lgca@@\tikz@lib@graph@name\endcsname\relax% + }, + target edge style/.code=\tikz@lib@annotate@{b}{\tikz@lib@graph@name}{#1}{}, + target edge node/.code=\tikz@lib@annotate@{b}{\tikz@lib@graph@name}{}{#1}, + target edge clear/.code={% + \expandafter\global\expandafter\let\csname tikz@lgcb@@\tikz@lib@graph@name\endcsname\relax% + } +}% + + + +% Packing a node list: Replace the node list by a new node list where +% each node is mentioned at most once. + +\def\tikz@lib@graph@pack@node@list{% + {% + \let\tikz@lg@packed\pgfutil@empty% + \let\tikz@lg@do\tikz@lg@packer% + \tikz@lib@graph@node@list% + \expandafter + }\expandafter% + \def\expandafter\tikz@lib@graph@node@list\expandafter{\tikz@lg@packed}% +}% + +\def\tikz@lg@packer#1{% + \expandafter\ifx\csname tikz@lg@p@#1\endcsname\pgf@stop% + \else% + \expandafter\let\csname tikz@lg@p@#1\endcsname\pgf@stop% + \expandafter\def\expandafter\tikz@lg@packed\expandafter{\tikz@lg@packed\tikz@lg@do{#1}} + \fi +}% + +% +% Color functions +% + +% Do something for all nodes having a certain color +% +% #1 = the color name +% #2 = a macro +% +% Description: +% +% For each node having color #1, the macro #2 will be called. This +% macro should take a single parameter, which will be set +% to the node's name. + +\def\tikzgraphforeachcolorednode#1#2{% + \tikz@lib@graph@pack@node@list% + \expandafter\def\expandafter\iftikz@lib@graph@color@picker\expandafter{\csname iftikz@lgc@#1@\endcsname}% + \let\tikz@lib@graph@action#2% + \let\tikz@lg@do\tikz@lg@pick% + \tikz@lib@graph@node@list% +}% +\def\tikz@lg@pick#1{ + {% + \csname tikz@lgc@#1\endcsname% + \iftikz@lib@graph@color@picker + \global\tikz@color@testtrue% + \else% + \global\tikz@color@testfalse% + \fi% + }% + \iftikz@color@test\tikz@lib@graph@action{#1}\fi% +}% + + + +% Prepare a color +% +% #1 is the color name +% #2 is a counter +% #3 is a prefix +% +% Description: +% +% You can call this function inside a connector. It will do the +% following: First, its counts how many nodes exist that have color +% #1. This number is stored in the counter passed as #2. Furthermore, +% let be the name of the -th vertex that has color #1. Then, a +% macro called \#3 will store . For instance, if #1 is "red" +% and the third red node is called foo and if #3 is "bar", then a +% macro called "\bar3" is set to "foo" as if you had said +% "\expandafter\def\csname bar3\endcsname{foo}". +% +% The bottom line of all this is that after a preparation you can +% easily iterate over nodes having a certain color. If you wish to +% iterate over a single color, it will be quicker and easier to call +% \tikzgraphforeachcolorednode, but if you need to iterate over two +% colors simultaneously, it will be better to first prepare the color. + +\def\tikzgraphpreparecolor#1#2#3{% + \let\tikz@lib@graph@count#2% + \tikz@lib@graph@count0\relax + \def\tikz@lib@graph@prefix{#3}% + \tikzgraphforeachcolorednode{#1}\tikz@lib@graph@prepare% +}% + +\def\tikz@lib@graph@prepare#1{% + \advance\tikz@lib@graph@count by1\relax% + \expandafter\def\csname\tikz@lib@graph@prefix\the\tikz@lib@graph@count\endcsname{#1}% +}% + + + + +% +% The bipartite connector +% + +\tikzgraphsset{ + complete bipartite/.style 2 args={operator={ + \def\tikz@lg@shoreb{#2}% + \tikzgraphforeachcolorednode{#1}\tikz@lib@graph@bipartite@outer + }}, + complete bipartite/.default={target'}{source'}, + induced complete bipartite/.style 2 args={ + induced independent set={#1}, + induced independent set={#2}, + complete bipartite={#1}{#2} + }, + induced complete bipartite/.default={target'}{source'}, +}% + +\def\tikz@lib@graph@bipartite@outer#1{% + \def\tikz@lib@graph@from{#1}% + {% + \tikzgraphforeachcolorednode{\tikz@lg@shoreb}\tikz@lib@graph@bipartite@inner% + }% +}% + +\def\tikz@lib@graph@bipartite@inner#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\tikz@lib@graph@from\else% + \tikz@lib@graph@default@new@edge{\tikz@lib@graph@from}{#1}% + \fi% +}% + +\def\tikz@lib@graph@default@new@edge#1#2{% + \pgfkeysgetvalue{/tikz/graphs/@edges styling}\pgf@temp + \pgfkeysgetvalue{/tikz/graphs/@edges node}\pgf@temp@b + \let\tikz@lib@add@temp\pgfutil@empty% + \tikz@lib@graph@add@edge@annotations{a}{#1} + \tikz@lib@graph@add@edge@annotations{b}{#2} + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@temp% + \expandafter\expandafter\expandafter{\expandafter\pgf@temp\tikz@lib@add@temp}% + \expandafter\expandafter\expandafter\tikz@lib@graph@default@new@edge@% + \expandafter\expandafter\expandafter{\expandafter\pgf@temp\expandafter}\expandafter{\pgf@temp@b}{#1}{#2}% +}% +\def\tikz@lib@graph@default@new@edge@#1#2#3#4{% + \iftikz@lib@graph@simple% + \edef\tikz@temp{{\pgfkeysvalueof{/tikz/graphs/default edge kind}}{#3}{#4}} + \expandafter\tikz@lib@graph@set@simple@edge\tikz@temp{#1}{#2}% + \else% + \pgfkeys{/tikz/graphs/.cd,new \pgfkeysvalueof{/tikz/graphs/default edge kind}={#3}{#4}{#1}{#2}}% + \fi% +}% +\def\tikz@lib@graph@add@edge@annotations#1#2{% + \ifcsname tikz@lgc#1@@#2\endcsname% + \expandafter\let\expandafter\tikz@lg@temp@\csname tikz@lgc#1@@#2\endcsname% + \ifx\tikz@lg@temp@\relax\else + \expandafter\tikz@lib@graph@add@edge@annotations@\tikz@lg@temp@% + \let\tikz@lib@add@temp\tikz@lib@final@edge@style + \fi% + \fi% +}% +\def\tikz@lib@graph@add@edge@annotations@#1#2{ + \expandafter\def\expandafter\pgf@temp\expandafter{\pgf@temp,#1}% + \expandafter\def\expandafter\pgf@temp@b\expandafter{\pgf@temp@b#2}% +}% +\def\tikz@lib@final@edge@style{,after source and target edge/.try}% + +% +% The clique connector +% + +\tikzgraphsset{ + clique/.style={operator={ + \tikzgraphpreparecolor{#1}\c@pgf@counta{tikz@lg}% + \tikz@lg@clique@loop% + }}, + clique/.default=all +}% + +\def\tikz@lg@clique@loop{% + \ifnum\c@pgf@counta=0\relax% + \else + \c@pgf@countb=\c@pgf@counta\relax% + \tikz@lg@clique@loop@inner% + \advance\c@pgf@counta by-1\relax% + \expandafter\tikz@lg@clique@loop% + \fi% +}% + +\def\tikz@lg@clique@loop@inner{% + \advance\c@pgf@countb by-1\relax% + \ifnum\c@pgf@countb>0\relax% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countb\endcsname}{\csname tikz@lg\the\c@pgf@counta\endcsname}% + \expandafter\tikz@lg@clique@loop@inner% + \fi% +}% + + +% +% The independent set connector +% + +\tikzgraphsset{ + induced independent set/.style={operator={ + \pgfkeysgetvalue{/tikz/graphs/default edge kind}\tikz@lg@default% + \pgfkeyssetvalue{/tikz/graphs/default edge kind}{-!-}% + \tikzgraphpreparecolor{#1}\c@pgf@counta{tikz@lg}% + \tikz@lg@indep@loop% + \pgfkeyslet{/tikz/graphs/default edge kind}\tikz@lg@default% + }}, + induced independent set/.default=all +}% + +\def\tikz@lg@indep@loop{% + \ifnum\c@pgf@counta=0\relax% + \else + \c@pgf@countb=\c@pgf@counta\relax% + \tikz@lg@indep@loop@inner% + \advance\c@pgf@counta by-1\relax% + \expandafter\tikz@lg@indep@loop% + \fi% +}% + +\def\tikz@lg@indep@loop@inner{% + \advance\c@pgf@countb by-1\relax% + \ifnum\c@pgf@countb>0\relax% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@counta\endcsname}{\csname tikz@lg\the\c@pgf@countb\endcsname}% + \expandafter\tikz@lg@indep@loop@inner% + \fi% +}% + + +% +% The path connector +% + +\tikzgraphsset{ + path/.style={operator={% + \let\tikz@lg@prev\relax% + \tikzgraphforeachcolorednode{#1}\tikz@lib@graph@path@do% + }}, + path/.default=all, + induced path/.style={induced independent set={#1},path={#1}}, + induced path/.default=all, +}% + +\def\tikz@lib@graph@path@do#1{% + \ifx\tikz@lg@prev\relax% + \else% + \tikz@lib@graph@default@new@edge{\tikz@lg@prev}{#1}% + \fi + \def\tikz@lg@prev{#1}% +}% + + +% +% The cycle connector +% + +\tikzgraphsset{ + cycle/.style={operator={% + \let\tikz@lg@prev\relax% + \let\tikz@lg@first\relax% + \tikzgraphforeachcolorednode{#1}\tikz@lib@graph@cycle@do% + \ifx\tikz@lg@first\relax% + \else% + \tikz@lib@graph@default@new@edge{\tikz@lg@prev}{\tikz@lg@first}% + \fi% + }}, + cycle/.default=all, + induced cycle/.style={induced independent set={#1},cycle={#1}}, + induced cycle/.default=all, +}% + +\def\tikz@lib@graph@cycle@do#1{% + \ifx\tikz@lg@prev\relax% + \def\tikz@lg@prev{#1}% + \let\tikz@lg@first\tikz@lg@prev% + \else% + \tikz@lib@graph@default@new@edge{\tikz@lg@prev}{#1}% + \def\tikz@lg@prev{#1}% + \fi% +}% + + + + +% +% The matching and star connector +% + +\tikzgraphsset{ + matching and star/.style 2 args={operator=% + {% + \tikzgraphpreparecolor{#1}\c@pgf@counta{tikz@lg} + \c@pgf@countb=0\relax% + \let\tikz@lg@prev\relax + \tikzgraphforeachcolorednode{#2}\tikz@lib@graph@flow@do% + \tikz@lib@graph@flow@rest% + }% + }, + matching and star/.default={target'}{source'} +}% + +\def\tikz@lib@graph@flow@do#1{% + \advance\c@pgf@countb by1\relax% + \ifnum\c@pgf@countb>\c@pgf@counta\relax% + \c@pgf@countb=\c@pgf@counta\relax% + \fi% + \ifnum\c@pgf@countb>0\relax% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countb\endcsname}{#1}% + \fi% + \def\tikz@lg@prev{#1}% +}% + +\def\tikz@lib@graph@flow@rest{% + \ifnum\c@pgf@countb<\c@pgf@counta\relax% + \ifnum\c@pgf@countb>0\relax% + \advance\c@pgf@countb by1\relax% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countb\endcsname}{\tikz@lg@prev}% + \expandafter\tikz@lib@graph@flow@rest% + \fi% + \fi% +}% + + + +% +% The matching connector +% + +\tikzgraphsset{ + matching/.style 2 args={operator= + {% + \tikzgraphpreparecolor{#1}\c@pgf@counta{tikz@lg} + \c@pgf@countb=0\relax% + \tikzgraphforeachcolorednode{#2}\tikz@lib@graph@matching@do% + }% + }, + matching/.default={target'}{source'} +}% + +\def\tikz@lib@graph@matching@do#1{% + \advance\c@pgf@countb by1\relax% + \ifnum\c@pgf@countb>\c@pgf@counta\relax% + \else% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countb\endcsname}{#1}% + \fi% +}% + + + + + +% +% The butterfly connector +% + +\tikzgraphsset{ + butterfly/.style={operator= + {}{% + \pgfkeys{/tikz/graphs/butterfly/.cd,#1}% + \ifnum\pgfkeysvalueof{/tikz/graphs/butterfly/level}=0\relax% + \tikzgraphinvokeoperator{matching and star={\pgfkeysvalueof{/tikz/graphs/butterfly/from}}{\pgfkeysvalueof{/tikz/graphs/butterfly/to}}}% + \else% + {% + \tikzgraphpreparecolor{\pgfkeysvalueof{/tikz/graphs/butterfly/from}}\c@pgf@counta{tikz@lg} + \c@pgf@countb=0\relax% + \tikzgraphforeachcolorednode{\pgfkeysvalueof{/tikz/graphs/butterfly/to}}\tikz@lib@graph@butterfly@do% + }% + \iftikz@butterfly@prime\else\tikzgraphinvokeoperator{matching and star={\pgfkeysvalueof{/tikz/graphs/butterfly/from}}{\pgfkeysvalueof{/tikz/graphs/butterfly/to}}}\fi% + \fi% + }% + }, + butterfly/.default=, + butterfly/level/.initial=1, + butterfly/from/.initial=target', + butterfly/to/.initial=source', + butterfly'/.style={operator={}{\tikz@butterfly@primetrue\pgfkeysalso{butterfly={#1}}}}, + butterfly'/.default=, +}% + +\newif\iftikz@butterfly@prime + +\def\tikz@lib@graph@butterfly@do#1{% + \advance\c@pgf@countb by1\relax% + % Compute other side... + \c@pgf@countc=\pgfkeysvalueof{/tikz/graphs/butterfly/level}\relax% + {% + % Computer countb mod (2level) + \count0=\c@pgf@countc\relax% + \multiply\count0 by2\relax% + \count1=\c@pgf@countb\relax% + \advance\count1 by-1\relax% + \count2=\count1\relax% + \count3=\count1\relax% + \divide\count1 by\count0\relax% + \multiply\count1 by\count0\relax% + \advance\count2 by-\count1\relax% + % count0 = 2*level + % count2 = countb mod (2level) (starting with 0) + % count1 = countb - count2 (starting with 0) + \ifnum\count2<\c@pgf@countc\relax% + \advance\count3 by \c@pgf@countc\relax% + \else% + \advance\count3 by -\c@pgf@countc\relax% + \fi% + \expandafter% + }% + \expandafter\c@pgf@countc\the\count3\relax% + \advance\c@pgf@countc by1\relax% + \ifnum\c@pgf@countc>\c@pgf@counta\relax% + \c@pgf@countc=\c@pgf@counta\relax% + \fi% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countc\endcsname}{#1}% +}% + + + + +% +% The no edges connector +% +\tikzgraphsset{no edges/.style={operator=\relax}}% + + + + +% +% The grid connector +% +\tikzgraphsset{ + grid/.style={operator={ + \tikzgraphpreparecolor{#1}\c@pgf@counta{tikz@lg}% + \c@pgf@countb=0\relax% + \tikzgraphpreparewrapafter% + \tikz@lg@grid@loop% + }% + }, + grid/.default=all +}% + +\def\tikzgraphpreparewrapafter{% + \pgfkeysgetvalue{/tikz/graphs/wrap after}\tikz@temp% + \ifnum\tikz@temp=0\relax% + \pgfmathparse{sqrt(\tikzgraphVnum)}% + \pgfmathint{\pgfmathresult}% + \edef\tikzgraphwrapafter{\pgfmathresult}% + \else% + \edef\tikzgraphwrapafter{\tikz@temp} + \fi% +}% + +\def\tikz@lg@grid@loop{% + \ifnum\c@pgf@counta=0\relax% + \else% + \advance\c@pgf@countb by 1\relax% + \pgfmathmod{\c@pgf@countb-1}{\tikzgraphwrapafter}% + \pgfmathint{\pgfmathresult}% + \ifnum\pgfmathresult>0% + \pgfmathsubtract{\c@pgf@countb}{1}% + \pgfmathint{\pgfmathresult}% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\the\c@pgf@countb\endcsname}{\csname tikz@lg\pgfmathresult\endcsname}% + \fi% + \pgfmathparse{\c@pgf@countb <= \tikzgraphwrapafter}% + \ifnum\pgfmathresult=0% + \pgfmathsubtract{\c@pgf@countb}{\tikzgraphwrapafter}% + \pgfmathint{\pgfmathresult}% + \tikz@lib@graph@default@new@edge{\csname tikz@lg\pgfmathresult\endcsname}{\csname tikz@lg\the\c@pgf@countb\endcsname}% + \fi% + \advance\c@pgf@counta by-1\relax% + \expandafter\tikz@lg@grid@loop% + \fi% +}% + + + + +% Positioning +% +% It is not the job of the graph library to compute good positions for +% nodes in a graph. However, some basic support is provided for simple +% cases. +% +% The idea is at follows: Graphs are specified hierarchically. For +% instance, consider the following graph specification: +% +% graph { a, b, c -> d -> {e -> f -> g, h} -> i, j -> k } +% +% Here, we have the *group* {e->f->g,h} inside the larger graph +% specification. Each group consists of sequence of *chains* like +% e->f->g or j->k. +% +% In order to facilitate the automatic positioning of nodes, the graph +% library will provide you with information about the position of +% nodes inside their groups and chains. +% +% As a chain is being parsed, a counter stored in +% /tikz/graphs/placement/element count is available that is advanced for +% each element in the chain. +% +% Additionally, a counter stored in placement/width is +% available. This "logical" width is defined recursively as follows: The +% width of a single node is computed by calling the key +% placement/logical node width, which should return a real or logical +% width of the node passed as a parameter in the macro \pgfmathresult. The +% width of a chain is the sum of the widths of its elements. The +% width of a group is the maximum of the widths of its elements. +% +% +% Symmetrically, as a group is being constructed, a counter stored in +% placement/chain count is available that is advanced for each chain +% in the group. The number placement/depth is the defined +% recursively as follows: For a single node, the depth is +% computed by the key placement/logical node depth. The depth +% of a group is the sum of the depths of its elements. The depth of a +% chain is the maximum of the depth of its elements. +% +% +% The above keys get updated automatically. You should setup the key +% placement/compute position such that it uses the above keys to +% compute a good position for a new node based on the above +% keys. Typically, this key should execute node={shift=(...)} to setup +% the necessary shift for a new node. +% +% The key placement/compute position should not be called +% directly. Instead, the key placement/place should be used. This key +% has two effects: First, it calls placement/compute position. Second, +% it resets the length and normal counters. It will setup a completely +% new counting of lengths and counters inside the current scope. +% +% The placmenet/place key is executed automatically whenever a new +% node is automatically created. Furthermore, placement strategies +% will call this key. + +\tikzgraphsset{ + placement/.cd, + compute position/.code=\tikz@lib@graph@linear@pos, + place/.code={% + \pgfkeys{/tikz/graphs/placement/compute position}% + \aftergroup\tikz@lib@graph@reset@locals% + \pgfkeyssetvalue{/tikz/graphs/placement/element count}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/chain count}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/depth}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/width}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/local depth}{0}% + \pgfkeyssetvalue{/tikz/graphs/placement/local width}{0}% + }, + element count/.initial=0, + chain count/.initial=0, + depth/.initial=0, + width/.initial=0, + level/.initial=0, + logical node depth/.code=\def\pgfmathresult{1}, + logical node width/.code=\def\pgfmathresult{1}, +}% + +\def\tikz@lib@graph@reset@locals{% + \gdef\tikz@lib@graph@group@depth{0}% + \gdef\tikz@lib@graph@group@width{0}% +}% + + +% Arrange nodes evenly +% +% This strategy works as follows: You specify a "chain shift vector" +% and a "group shift vector". Then each new element on a chain is +% shifted by the chain shift vector relative to the previous element +% on the chain. Similarly for each new element of a group. + +\tikzgraphsset{ + Cartesian placement/.style={ + placement/place, + placement/compute position/.code=\tikz@lib@graph@linear@pos% + }, + chain shift/.initial={(1,0)}, + group shift/.initial={(0,-1)}, + grow right/.style={ + placement/place, + chain shift={(#1,0)}, + @auto anchor horizontal=center, + placement/logical node width/.code=\def\pgfmathresult{1} + }, + grow right/.default=1, + grow left/.style={ + placement/place, + chain shift={(-#1,0)}, + @auto anchor horizontal=center, + placement/logical node width/.code=\def\pgfmathresult{1} + }, + grow left/.default=1, + grow up/.style={ + placement/place, + chain shift={(0,#1)}, + @auto anchor horizontal=center, + placement/logical node width/.code=\def\pgfmathresult{1} + }, + grow up/.default=1, + grow down/.style={ + placement/place, + chain shift={(0,-#1)}, + @auto anchor vertical=center, + placement/logical node width/.code=\def\pgfmathresult{1} + }, + grow down/.default=1, + branch right/.style={ + placement/place, + group shift={(#1,0)}, + @auto anchor horizontal=center, + placement/logical node depth/.code=\def\pgfmathresult{1} + }, + branch right/.default=1, + branch left/.style={ + placement/place, + group shift={(-#1,0)}, + @auto anchor horizontal=center, + placement/logical node depth/.code=\def\pgfmathresult{1} + }, + branch left/.default=1, + branch up/.style={ + placement/place, + group shift={(0,#1)}, + @auto anchor vertical=center, + placement/logical node depth/.code=\def\pgfmathresult{1} + }, + branch up/.default=1, + branch down/.style={ + placement/place, + group shift={(0,-#1)}, + @auto anchor vertical=center, + placement/logical node depth/.code=\def\pgfmathresult{1} + }, + branch down/.default=1, + % + % Sep shifts + % + grow right sep/.style={ + Cartesian placement, + chain shift={(1pt,0)}, + @auto anchor horizontal=west, + placement/logical node width/.code=\tikz@lib@graph@width@sep{##1}{#1} + }, + grow right sep/.default=1em, + grow left sep/.style={ + Cartesian placement, + chain shift={(-1pt,0)}, + @auto anchor horizontal=east, + placement/logical node width/.code=\tikz@lib@graph@width@sep{##1}{#1} + }, + grow left sep/.default=1em, + grow up sep/.style={ + Cartesian placement, + chain shift={(0,1pt)}, + @auto anchor vertical=south, + placement/logical node width/.code=\tikz@lib@graph@depth@sep{##1}{#1} + }, + grow up sep/.default=1em, + grow down sep/.style={ + Cartesian placement, + chain shift={(0,-1pt)}, + @auto anchor vertical=north, + placement/logical node width/.code=\tikz@lib@graph@depth@sep{##1}{#1} + }, + grow down sep/.default=1em, + grow right sep/.style={ + Cartesian placement, + chain shift={(1pt,0)}, + @auto anchor horizontal=west, + placement/logical node width/.code=\tikz@lib@graph@width@sep{##1}{#1} + }, + % + branch right sep/.style={ + Cartesian placement, + group shift={(1pt,0)}, + @auto anchor horizontal=west, + placement/logical node depth/.code=\tikz@lib@graph@width@sep{##1}{#1} + }, + branch right sep/.default=1em, + branch left sep/.style={ + Cartesian placement, + group shift={(-1pt,0)}, + @auto anchor horizontal=east, + placement/logical node depth/.code=\tikz@lib@graph@width@sep{##1}{#1} + }, + branch left sep/.default=1em, + branch up sep/.style={ + Cartesian placement, + group shift={(0,1pt)}, + @auto anchor vertical=south, + placement/logical node depth/.code=\tikz@lib@graph@depth@sep{##1}{#1} + }, + branch up sep/.default=1em, + branch down sep/.style={ + Cartesian placement, + group shift={(0,-1pt)}, + @auto anchor vertical=north, + placement/logical node depth/.code=\tikz@lib@graph@depth@sep{##1}{#1} + }, + branch down sep/.default=1em, + % + @auto anchor horizontal/.style={ + nodes={anchor=\csname tikz@lib@graph@auto@\tikz@lib@graph@auto@h @\tikz@lib@graph@auto@v\endcsname}, + /utils/exec=\def\tikz@lib@graph@auto@h{#1} + }, + @auto anchor vertical/.style={ + nodes={anchor=\csname tikz@lib@graph@auto@\tikz@lib@graph@auto@h @\tikz@lib@graph@auto@v\endcsname}, + /utils/exec=\def\tikz@lib@graph@auto@v{#1} + }, + % + % + no placement/.style={ + placement/place, + placement/compute position/.code=% + } +}% + +\def\tikz@lib@graph@auto@h{center}% +\def\tikz@lib@graph@auto@v{center}% + +\def\tikz@lib@graph@auto@center@center{center}% +\def\tikz@lib@graph@auto@west@center{west}% +\def\tikz@lib@graph@auto@east@center{east}% +\def\tikz@lib@graph@auto@center@north{north}% +\def\tikz@lib@graph@auto@west@north{north west}% +\def\tikz@lib@graph@auto@east@north{north east}% +\def\tikz@lib@graph@auto@center@south{south}% +\def\tikz@lib@graph@auto@west@south{south west}% +\def\tikz@lib@graph@auto@east@south{south east}% + +\def\tikz@lib@graph@linear@pos{% + \pgfkeysgetvalue{/tikz/graphs/chain shift}\tikz@temp + \expandafter\tikz@scan@one@point\expandafter\pgf@process\tikz@temp + \pgf@process{\pgfpointscale{\pgfkeysvalueof{/tikz/graphs/placement/width}}{}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfkeysgetvalue{/tikz/graphs/group shift}\tikz@temp + \expandafter\tikz@scan@one@point\expandafter\pgf@process\tikz@temp + \pgf@process{\pgfpointscale{\pgfkeysvalueof{/tikz/graphs/placement/depth}}{}}% + \advance\pgf@xa by\pgf@x% + \advance\pgf@ya by\pgf@y% + \edef\tikz@lib@graph@shift{(\the\pgf@xa,\the\pgf@ya)} + \pgfkeys{/tikz/graphs/nodes/.expanded={shift={\tikz@lib@graph@shift}}} +}% + + +\def\tikz@lib@graph@width@sep#1#2{% + \pgf@process{\pgfpointdiff{\pgfpointanchor{#1}{west}}{\pgfpointanchor{#1}{east}}}% + \pgfmathparse{#2+\the\pgf@x}% +}% + +\def\tikz@lib@graph@depth@sep#1#2{% + \pgf@process{\pgfpointdiff{\pgfpointanchor{#1}{south}}{\pgfpointanchor{#1}{north}}}% + \pgfmathparse{#2+\the\pgf@y}% +}% + + +% Circular arrangements +% +% This strategy works a bit like the arrange evenly strategy, but in +% polar coordinates. Both for the chains and the groups you specify a +% polar shift, which must be in the form "(delta degree:delta +% distance)". For each element in a chain, the delta degree is added +% to the chain degree, likewise for each element the delta distance is +% added. Similarly for groups. +% +% There is an initial degree and radius, stored in the key "phase" and +% "radius". + +\tikzgraphsset{, + circular placement/.style={ + placement/place, + placement/compute position/.code=\tikz@lib@graph@circular@pos,% + placement/logical node depth/.code=\def\pgfmathresult{1}, + placement/logical node width/.code=\def\pgfmathresult{1}, + }, + clockwise/.style={ + circular placement, + group polar shift={(-360/#1:0)} + }, + clockwise/.default=\tikzgraphVnum, + counterclockwise/.style={ + circular placement, + group polar shift={(360/#1:0)} + }, + counterclockwise/.default=\tikzgraphVnum, + chain polar shift/.initial={(0:1cm)}, + group polar shift/.initial={(60:0)}, + radius/.initial=1cm, + phase/.initial=90, +}% + +\def\tikz@lib@graph@circular@pos{% + \pgfkeysgetvalue{/tikz/graphs/chain polar shift}\tikz@temp + \expandafter\tikz@lib@graph@decompose@polar\tikz@temp% + \pgf@process{\pgfpointscale{\pgfkeysvalueof{/tikz/graphs/placement/width}}{}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfkeysgetvalue{/tikz/graphs/group polar shift}\tikz@temp + \expandafter\tikz@lib@graph@decompose@polar\tikz@temp% + \pgf@process{\pgfpointscale{\pgfkeysvalueof{/tikz/graphs/placement/depth}}{}}% + \advance\pgf@xa by\pgf@x% + \advance\pgf@ya by\pgf@y% + \pgfmathparse{\pgfkeysvalueof{/tikz/graphs/radius}}% + \advance\pgf@ya by\pgfmathresult pt% + \pgfmathsetmacro\tikz@temp{\the\pgf@xa+\pgfkeysvalueof{/tikz/graphs/phase}}% + \edef\tikz@lib@graph@shift{(\tikz@temp:\the\pgf@ya)} + \pgfkeys{/tikz/graphs/nodes/.expanded={shift={\tikz@lib@graph@shift}}} +}% + + +\def\tikz@lib@graph@decompose@polar(#1:#2){% + \pgfmathsetlength\pgf@x{#1}% + \pgfmathsetlength\pgf@y{#2}% +}% + + +% Grid arrangements +% +\tikzgraphsset{ + grid placement/.style={ + placement/place, + placement/compute position/.code=\tikz@lib@graph@grid@pos,% + }, +}% + + +\def\tikz@lib@graph@grid@pos{% + % + % Make sure to set \tikzgraphwrapafter before we compute + % the positions of nodes in the grid + % + \tikzgraphpreparewrapafter% + % + % find out the coordinate in the grid + % + \pgfkeysgetvalue{/tikz/graphs/placement/depth}\tikz@temp@depth% + \pgfkeysgetvalue{/tikz/graphs/placement/width}\tikz@temp@width% + \pgfmathsetmacro{\tikz@temp}{max(\tikz@temp@depth, \tikz@temp@width)}% + \pgfmathsetmacro{\tikz@temp@col}{mod(\tikz@temp,\tikzgraphwrapafter)}% + \pgfmathsetmacro{\tikz@temp@row}{div(\tikz@temp,\tikzgraphwrapafter)}% + % + % multiply row by the group shift and col by the chain shift + % + \pgfkeysgetvalue{/tikz/graphs/group shift}\tikz@temp% + \expandafter\tikz@scan@one@point\expandafter\tikz@lib@graph@grid@pos@a\tikz@temp% + \pgfkeysgetvalue{/tikz/graphs/chain shift}\tikz@temp% + \expandafter\tikz@scan@one@point\expandafter\tikz@lib@graph@grid@pos@b\tikz@temp% + % + % apply the shift + % + \edef\tikz@lib@graph@shift{(\the\pgf@xa,\the\pgf@ya)} + \pgfkeys{/tikz/graphs/nodes/.expanded={shift={\tikz@lib@graph@shift}}} +}% + +\def\tikz@lib@graph@grid@pos@a#1{\pgf@process{\pgfpointscale{\tikz@temp@row}{#1}}\pgf@xa=\pgf@x\relax\pgf@ya=\pgf@y\relax}% +\def\tikz@lib@graph@grid@pos@b#1{\pgf@process{\pgfpointscale{\tikz@temp@col}{#1}}% + \advance\pgf@xa by\pgf@x\relax + \advance\pgf@ya by\pgf@y\relax}% + +\tikzgraphsset{ + % Grids: + wrap after/.initial=0, + % Node sets: + V/.code={% + \def\tikzgraphV{#1}% + \c@pgf@counta=0\foreach \tikz@dummy in {#1} {\global\advance\c@pgf@counta by1\relax}% + \edef\tikzgraphVnum{\the\c@pgf@counta} + }, + V={1}, + n/.style={V={1,...,#1},name shore V/.style={name=V}}, + W/.code={% + \def\tikzgraphW{#1}% + \c@pgf@counta=0\foreach \tikz@dummy in {#1} {\global\advance\c@pgf@counta by1\relax}% + \edef\tikzgraphWnum{\the\c@pgf@counta} + }, + W={1}, + m/.style={W={1,...,#1},name shore W/.style={name=W}}, + % Shores: + name shore V/.style=, + name shore W/.style=, +}% + + + +% +% Quick graphs +% +% Parsing the graph syntax can take a lot of time for large +% graphs. This is mainly due to the transformation of commas and +% semicolons and all the internal bookkeeping. +% +% For large graphs, the quick graph syntax offers a greatly reduced +% syntax that will be processed much more quickly. This syntax is +% compatible with the normal graph syntax in the sense that all +% specifications written in the reduced syntax are also legal in the +% normal syntax, but not the other way round. +% +% The following rules apply: +% +% 1) A quick graph consists of a sequence of either nodes, edges sequences, or +% groups. These are separated by commas or semicolons. +% +% 2) Every node is of the form +% +% "node name"/"node text"[options] +% +% Here, the quotation marks are mandatory. The part '/"node text"' may +% be missing, in which case the node name is used as the node +% text. The options may also be missing. The node name may not contain +% any "funny" characters (unlike in the normal graph command). +% +% 3) Every edge is of the form +% +% ... ; +% +% Here, the are node specifications as described above, +% the is one of the four connectors "->", "<-", "--", and +% "<->", followed by optional options in square +% brackets. The semicolon may be replaced by a comma. +% +% 4) Every group is of the form +% +% { [options] lines }; +% +% The options are compulsory, the lines must be a sequence of nodes, +% edges, and groups as described above. The semicolon can, again, be +% replaced by a comma. +% +% +% Things that are allowed in the normal syntax, but not in the quick +% syntax, include: +% +% - Connecting a node and a group as in a->{b,c}. +% - Node names without quotation marks. +% - Using subgraphs (graph macros). +% - Using graph sets. +% - Using graph color classes. +% - Using anonymous nodes. +% - Using the "fresh nodes" option. +% - Using sublayouts. +% - Using the -!- edge connector. +% - Using the "simple" option. +% - Using edge annotations. +% +% Example: +% +% \graph [quick] { +% "a"/"$a$"[red] -> "b"[blue] -> "c"; +% "b" -> "d"; +% "c" ->[thick] "e"; +% { [same layer] "c", "d" }; +% }; +% +% + +\tikzgraphsset{quick/.is if=tikz@graph@quick}% +\newif\iftikz@graph@quick + +\def\tikz@lib@graphs@parse@quick@graph{ + % Ok, we are before the initial brace. We open a group and start + % setting up some bookkeeping + \begingroup% + \global\tikz@qnode@count0\relax% + \let\tikzgraphnodepath\pgfutil@empty% + \tikz@q@outertrue% + \afterassignment\tikz@lib@graphs@quick@main\let\pgf@temp=% +}% + +\newcount\tikz@qnode@count +\newif\iftikz@q@outer + +\def\tikz@lib@graphs@quick@main{% + \afterassignment\tikz@lib@graphs@quick@handle\let\pgf@let@token=% +}% +\def\tikz@lib@graphs@quick@handle{% + \ifx\pgf@let@token"% + \expandafter\tikz@lib@graphs@quick@first@node% + \else% + \expandafter\tikz@lib@graphs@quick@other% + \fi% +}% +\def\tikz@lib@graphs@quick@other{% + \let\tikz@next\tikz@lib@graphs@quick@error% + \ifx\pgf@let@token\egroup% + \let\tikz@next\tikz@lib@graphs@quick@end@group% + \else% + \ifx\pgf@let@token\bgroup% + \let\tikz@next\tikz@lib@graphs@quick@start@group% + \else% + \ifx\pgf@let@token\par% + \let\tikz@next\tikz@lib@graphs@quick@main% + \fi% + \fi + \fi% + \tikz@next% +}% + +\def\tikz@lib@graphs@quick@error#1{\tikzerror{Unexpected token '\string#1' in quick graph syntax}\tikz@lib@graphs@quick@main}% +\def\tikz@lib@graphs@quick@start@group{% + \pgfutil@ifnextchar[\tikz@lib@graphs@quick@start@group@{\tikzerror{Group + in quick graph syntax must start with options.}} +}% + +\def\tikz@lib@graphs@quick@start@group@[#1]{% + \begingroup% + \tikz@q@outerfalse% + \tikzgraphsset{#1}% + \tikz@lib@graphs@quick@main% +}% +\def\tikz@lib@graphs@quick@end@group{% + \iftikz@q@outer% + \endgroup% + % Ok, cleanup! + \pgfutil@loop% + \ifnum\tikz@qnode@count>0\relax% + \expandafter\global\expandafter\let\csname tikz@gr@q@@\csname tikz@gr@qn@@\the\tikz@qnode@count\endcsname\endcsname\relax% + \expandafter\global\expandafter\let\csname tikz@gr@qn@@\the\tikz@qnode@count\endcsname\relax% + \global\advance\tikz@qnode@count by-1\relax% + \pgfutil@repeat% + \expandafter\tikz@lib@graph@main@done% + \else% + \endgroup% + \expandafter\tikz@lib@graphs@end@group@% + \fi% +}% +\def\tikz@lib@graphs@end@group@{% + \pgfutil@ifnextchar;{\expandafter\tikz@lib@graphs@quick@main\pgfutil@gobble}{% + \pgfutil@ifnextchar,{\expandafter\tikz@lib@graphs@quick@main\pgfutil@gobble}{% + \tikzerror{Graph groups in quick syntax must be followed by a semicolon or a comma.}% + }% + }% +}% + + +\def\tikz@lib@graphs@quick@first@node{% + \let\tikz@quick@prev@node\relax% + \tikz@lib@graphs@quick@node% +}% + +\def\tikz@lib@graphs@quick@node#1"{% + \def\tikzgraphnodename{#1}% + \let\tikzgraphnodetext\tikzgraphnodename% + \iftikzgraphsautonumbernodes + \edef\tikzgraphnodename{\tikzgraphnodename\tikz@lib@auto@sep\the\tikz@lib@auto@number}% + \global\advance\tikz@lib@auto@number by1\relax% + \fi + \pgfutil@ifnextchar/\tikz@lib@graphs@quick@text\tikz@lib@graphs@quick@opt% +}% +\def\tikz@lib@graphs@quick@text/"#1"{% + \def\tikzgraphnodetext{#1}% + \tikz@lib@graphs@quick@opt% +}% +\def\tikz@lib@graphs@quick@opt{% + \pgfutil@ifnextchar[\tikz@lib@graphs@quick@withopt{\tikz@lib@graphs@quick@withopt[]}%] +}% +\def\tikz@lib@graphs@quick@withopt[#1]{% + % Test, whether node already exists + \expandafter\ifx\csname tikz@gr@q@@\tikzgraphnodename\endcsname\relax% + % New node + \global\advance\tikz@qnode@count by1\relax% + \expandafter\global\expandafter\let\csname tikz@gr@q@@\tikzgraphnodename\endcsname\pgfutil@empty% not relax + \expandafter\global\expandafter\let\csname tikz@gr@qn@@\the\tikz@qnode@count\endcsname\tikzgraphnodename% back pointer + \let\tikzgraphnodefullname\tikzgraphnodename% + \let\tikzgraphnodeas\tikzgraphnodeas@default% + \node [% + name=\tikzgraphnodename,% + graphs/redirect unknown to tikz, + /tikz/graphs/.cd,% + /tikz/graphs/@nodes styling,% + #1]% + {% + \tikzgraphnodeas% + };% + \else% + % + % Handle late options and operators + \tikzgdlatenodeoptionacallback{\tikzgraphnodename}% + \node also[graphs/redirect unknown to tikz,/tikz/graphs/.cd,#1](\tikzgraphnodename);% + \fi% + % Connect, if necessary + \tikz@lig@graph@quikc@make@edge@if@necessary% + \tikz@lib@graphs@quick@scan@after@node% +}% + +\def\tikz@lig@graph@quikc@make@edge@if@necessary{% + \ifx\tikz@quick@prev@node\relax% + \else% + \tikz@lib@graphs@quick@make@edge% + \fi% +}% + +\def\tikz@lib@graphs@quick@scan@after@node{% + \pgfutil@ifnextchar,\tikz@lib@graphs@quick@comma{% + \pgfutil@ifnextchar;\tikz@lib@graphs@quick@semi{% + \pgfutil@ifnextchar\egroup{\tikz@lib@graphs@quick@semi;}{% + \pgfutil@ifnextchar\par{\expandafter\tikz@lib@graphs@quick@scan@after@node\tikz@lib@graphs@quick@gobble@par}% + \tikz@lib@graphs@quick@connector}}}% +}% +\long\def\tikz@lib@graphs@quick@gobble@par#1{}% + +\def\tikz@lib@graphs@quick@comma,{\tikz@lib@graphs@quick@main}% +\def\tikz@lib@graphs@quick@semi;{\tikz@lib@graphs@quick@main}% +\def\tikz@lib@graphs@quick@connector#1#2{% + \def\tikz@lib@graphs@quick@edge@kind{#1#2}% + \pgfutil@ifnextchar>\tikz@lib@graphs@back@edge{% + \pgfutil@ifnextchar[\tikz@lib@graphs@quick@connector@handle@opt{\tikz@lib@graphs@quick@connector@handle@opt[]}%] + }% +}% +\def\tikz@lib@graphs@back@edge#1{% + \expandafter\def\expandafter\tikz@lib@graphs@quick@edge@kind\expandafter{\tikz@lib@graphs@quick@edge@kind#1}% + \pgfutil@ifnextchar[\tikz@lib@graphs@quick@connector@handle@opt{\tikz@lib@graphs@quick@connector@handle@opt[]}%] +}% +\def\tikz@lib@graphs@quick@connector@handle@opt[#1]{% + \def\tikz@lib@graphs@quick@edge@options{#1}% + \let\tikz@quick@prev@node\tikzgraphnodename% + \tikz@lib@graphs@quick@scan@after@connector% +}% +\def\tikz@lib@graphs@quick@scan@after@connector{% + \pgfutil@ifnextchar\par{\expandafter\tikz@lib@graphs@quick@scan@after@connector\tikz@lib@graphs@quick@gobble@par}{% + \pgfutil@ifnextchar"{\expandafter\tikz@lib@graphs@quick@node\pgfutil@gobble}{% + \tikzerror{Quotation marks expected after edge connector}% + }% + }% +}% + +\def\tikz@lib@graphs@quick@make@edge{% + { + \expandafter\tikz@lib@graphs@quick@make@edge@styling\expandafter{\tikz@lib@graphs@quick@edge@options}% + \expandafter\expandafter\expandafter\tikz@lib@graphs@quick@make@edge@for% + \expandafter\expandafter\expandafter{\expandafter\tikz@quick@prev@node\expandafter}\expandafter{\tikzgraphnodename}% + } +}% + +\def\tikz@lib@graphs@quick@make@edge@styling#1{% + \tikz@enable@edge@quotes% + \tikzgraphsset{.unknown/.code=\tikz@lib@graph@unknown@edge@option{##1},#1}% +}% + +\def\tikz@lib@graphs@quick@make@edge@for#1#2{% + \pgfkeysgetvalue{/tikz/graphs/@edges styling}\pgf@tempa + \pgfkeysgetvalue{/tikz/graphs/@edges node}\pgf@temp@b + \expandafter\expandafter\expandafter\tikz@lib@graphs@quick@make@edge@for@with% + \expandafter\expandafter\expandafter{\expandafter\pgf@tempa\expandafter}\expandafter{\pgf@temp@b}{#1}{#2}% +}% + +\def\tikz@lib@graphs@quick@make@edge@for@with#1#2#3#4{% + \tikzgraphsset{new \tikz@lib@graphs@quick@edge@kind={#3}{#4}{#1}{#2}}% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.standard.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.standard.code.tex new file mode 100644 index 0000000000..4cac3e51eb --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.standard.code.tex @@ -0,0 +1,109 @@ +% Copyright 2019 by Till Tantau +% Copyright 2019 by Jannis Pohlmann +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarygraphs.standard.code.tex} + +\usetikzlibrary{graphs}% + +% +% Basic graphs +% + + +\tikzgraphsset{ + % + % An independent set $V$ of nodes. + % + declare={subgraph I_n}% + { + \foreach \tikz@lib@graph@node@num in \tikzgraphV + { \tikz@lib@graph@node@num } + }, + % + % An two-shore independent set $V$ with shores V and W. + % + declare={subgraph I_nm}% + { + subgraph I_n [name shore V] -- [no edges] + subgraph I_n [name shore W, V/.expand once=\tikzgraphW] + }, + % + % The complete clique on $V$. + % + declare={subgraph K_n}% + { + [clique] + subgraph I_n + }, + % + % A complete bipartite graph with shores V and W. + % + declare={subgraph K_nm}% + { + [color class=shore V, + color class=shore W, + complete bipartite={shore V}{shore W}] + subgraph I_n [name shore V, shore V] -- [no edges] + subgraph I_n [name shore W, V/.expand once=\tikzgraphW, shore W] + }, + % + % A cycle with n nodes. + % + declare={subgraph C_n}% + { + [cycle] + subgraph I_n + }, + % + % A path with n nodes. + % + declare={subgraph P_n}% + { + [path] + subgraph I_n + }, + % + % A grid with n nodes. + % + declare={subgraph Grid_n}% + { + [grid] + subgraph I_n + }, + % + % A random graph according to the G_{n,p} model: For each pair of + % vertices there is an edge between them with probability p. + % + p/.initial=0.5, + declare={subgraph G_np}% + { + [/utils/exec={ + \pgfmathsetmacro\tikz@lib@lg@p{\pgfkeysvalueof{/tikz/graphs/p}} + \let\tikz@lib@gnp@edges\pgfutil@empty% + \foreach \tikz@lib@graph@node@a [count=\tikz@lib@g@count@a] in \tikzgraphV + \foreach \tikz@lib@graph@node@b [count=\tikz@lib@g@count@b] in \tikzgraphV + { + \ifnum\tikz@lib@g@count@a<\tikz@lib@g@count@b\relax + \pgfmathparse{rnd} + \ifdim\pgfmathresult pt<\tikz@lib@lg@p pt% + \ifx\tikz@lib@gnp@edges\pgfutil@empty + \xdef\tikz@lib@gnp@edges{\tikz@lib@graph@node@a--\tikz@lib@graph@node@b}% + \else + \xdef\tikz@lib@gnp@edges{\tikz@lib@gnp@edges,\tikz@lib@graph@node@a--\tikz@lib@graph@node@b}% + \fi + \fi + \fi + } + }] + \foreach \tikz@lg@temp in \tikz@lib@gnp@edges { + [parse/.expand once=\tikz@lg@temp] + } + }, +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzexternalshared.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzexternalshared.code.tex new file mode 100644 index 0000000000..2ff5aa2d38 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzexternalshared.code.tex @@ -0,0 +1,1714 @@ +% Copyright 2008-2020 by Christian Feuersaenger +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. +% +% ****************************** +% This here is the shared implementation of TeX-dialect specific files +% tikzlibraryexternal.code.tex +% ****************************** +% +% +% This file provides a high-level automatic export feature for tikz pictures. +% It allows to export EACH SINGLE FIGURE into a separate PDF. +% +% The simplest way is to use the 'convert with system call' option; it simply converts every figure using the write18 method. If that is not possible, a list of figure file names is generated and you need to generate these figures manually (or with a script). +% +% +% It replaces \tikzpicture/ \endtikzpicture and \tikz and invokes \beginpgfgraphicnamed ... \endpgfgraphicnamed +% commands if necessary. + +% handle with extreme care and only in small, local groups: +\toksdef\t@tikzexternal@tmpa=0 +\toksdef\t@tikzexternal@tmpb=1 + +\newif\iftikzexternal@nestedflag +\newif\iftikzexternal@verboseuptodate +\newif\iftikzexternal@verboseio +\newif\iftikzexternal@genfigurelist +\newif\iftikzexternal@onlynamed +\newif\iftikzexternal@file@isuptodate +\newif\iftikzexternal@force@remake +\newif\iftikzexternal@optimize +\newif\iftikzexternal@export@enabled +\tikzexternal@export@enabledtrue + +% must be numeric! +\gdef\c@tikzexternal@version{2} + +% This 'if' can be used as part of the public user interface. +% +% It is set by the 'remake next' key. +% +% It disables any up-to-date checks for the *next* picture, forcing a +% remake of it. +% +% It applies only to *one* picture. +\newif\iftikzexternalremakenext +\newif\iftikzexternal@verbose@optimize +\tikzexternal@verbose@optimizetrue + +% A global boolean which can be used to skip single figures. +\newif\iftikzexternalexportnext +\tikzexternalexportnexttrue + +% Invokes '#1' if the external lib is currently externalizing +% something and '#2' if not. +% +% This command must be called *after* \tikzexternalize. +\def\tikzifexternalizing#1#2{% + \ifpgf@external@grabshipout #1\else #2\fi +}% +% Invokes '#1' if the external lib is currently externalizing the NEXT FOLLOWING +% tikzpicture. It invokes '#2' if that is not the case. +\def\tikzifexternalizingnext#1#2{% + \ifpgf@external@grabshipout + \tikzexternalgetnextfilename\tikzexternal@temp + \tikzifexternaljobnamematches\tikzexternal@temp{#1}{#2}% + \else + #2% + \fi +}% +% Invokes '#1' if the external lib is currently externalizing the +% current picture. It invokes '#2' if that is not the case. +% +% If the command is invoked outside of a picture, '#2' will be +% invoked. +\def\tikzifexternalizingcurrent#1#2{% + \ifpgf@external@grabshipout + \tikzexternalgetcurrentfilename\tikzexternal@temp + \ifx\tikzexternal@temp\pgfutil@empty + #2% + \else + \tikzifexternaljobnamematches\tikzexternal@temp{#1}{#2}% + \fi + \else + #2% + \fi +}% + +% Invokes '#2' if \jobname equals '#1' and '#3' if not. +% I suppose that '#1' is a macro containing the file name. +% +\def\tikzifexternaljobnamematches#1#2#3{% + \edef\pgf@tempa{\expandafter\string\csname#1\endcsname}% + \edef\pgf@tempb{\expandafter\string\csname\pgfactualjobname\endcsname}% + \ifx\pgf@tempa\pgf@tempb #2\else#3 \fi% +}% + + +\pgfutil@IfUndefined{pdfshellescape}{% + % let's hope that \usepackage{pdftexcmds} has been used... + \pgfutil@IfUndefined{pdf@shellescape}{% + \def\tikzexternalcheckshellescape{0}% + }{% + \let\tikzexternalcheckshellescape=\pdf@shellescape + }% +}{% + \let\tikzexternalcheckshellescape=\pdfshellescape +}% +\ifnum\tikzexternalcheckshellescape=1 + \def\tikzexternalcheckshellescape{\pgfkeysvalueof{/tikz/external/shell escape}\space}% +\else + \def\tikzexternalcheckshellescape{}% +\fi + +\newif\iftikzexternal@auto@detect@jobname + +\pgfqkeys{/tikz/external}{ + figure list/.is if=tikzexternal@genfigurelist, + aux in dpth/.style={/pgf/images/aux in dpth={#1}},% + disable dependency files/.code={% + \let\tikzexternalfiledependsonfile@ACTIVE=\tikzexternalfiledependsonfile + }, + % 'mode' applies only if \jobname==real job name. + mode/.is choice, + mode/only graphics/.code = {% + \def\tikzexternal@opmode{0}% + \pgfkeysalso{/pgf/images/aux in dpth=true}% + }, + mode/no graphics/.code = {\def\tikzexternal@opmode{1}}, + % an alias for 'no graphics:' + mode/only pictures/.code = {\def\tikzexternal@opmode{1}}, + mode/graphics if exists/.code= {% + \def\tikzexternal@opmode{2}% + \pgfkeysalso{/pgf/images/aux in dpth=true}% + }, + mode/list only/.code = {\def\tikzexternal@opmode{3}\tikzexternal@genfigurelisttrue}, + mode/convert with system call/.code={% + \def\tikzexternal@opmode{4}% + \pgfkeysalso{/tikz/external/figure list=false,/pgf/images/aux in dpth=true}% + }, + mode/list and make/.code = {% + \def\tikzexternal@opmode{5}% + \pgfkeysalso{/tikz/external/figure list=true,/pgf/images/aux in dpth=true}% + }, + mode=convert with system call, + force remake/.is if=tikzexternal@force@remake, + force remake/.default=true, + % + % DEPRECATED: this here will work out-of-the box (provided that + % 'aux in dpth' is active): + failed ref warnings for/.initial={\ref,\cite,\pageref}, + export next/.is if=tikzexternalexportnext, + export/.is if=tikzexternal@export@enabled, + remake next/.is if=tikzexternalremakenext, + remake next/.default=true, + verbose IO/.is if=tikzexternal@verboseio, + verbose IO/.default=true, + verbose IO=true, + verbose optimize/.is if=tikzexternal@verbose@optimize, + verbose up to date/.is if=tikzexternal@verboseuptodate, + verbose/.style={ + verbose IO=#1, + verbose optimize=#1, + verbose up to date=#1, + }, + shell escape/.initial=-shell-escape, + read main aux/.is if=pgfexternalreadmainaux, + image discarded text/.initial={% + [[ \textsc{Image Discarded Due To} \texttt{`/tikz/external/% + \ifcase\tikzexternal@opmode\relax + mode=only graphics% + \or + mode=no graphics% + \or + mode=graphics if exists% + \or + mode=list only% + \or + mode=convert with system call% + \or + mode=list and make% + \fi + '}~]]% + \pgfutil@ifundefined{tikzexternal@warning@at@end}{% + \pgfutil@ifundefined{AtEndDocument}{}{% + \AtEndDocument{% + \message{! Package tikz Warning: Some images are not up-to-date and need to be generated. }% + }% + }% + \gdef\tikzexternal@warning@at@end{1}% + }{}% + }, + optimize/.is choice, + optimize/true/.code={% + \tikzexternal@optimizetrue + \iftikzexternal@optimize + \ifpgf@external@grabshipout + % we have already started the externalization! Install + % optimization commands to activate the new one: + \tikzexternal@optimize@REPLACE + \fi + \fi + }, + optimize/false/.code={% + \tikzexternal@optimizefalse% + \tikzexternal@optimize@RESTORE + },% + optimize=true, + optimize away text/.code={[ \textsc{\string#1\ optimized away because it does not contribute to exported PDF}]}, + optimize/install/.code={},% + optimize/restore/.code={},% + % Expects two arguments, the command name and (optionally) a count + % of expected arguments. + % Example: + % 'optimize command away=\includegraphics' + % 'optimize command away={\mycommand}{3}' + % + % It accepts commands which have '[]' arguments and whose first + % argument always begins with '{'. + % + % #1: the command name + % #2: either empty or a number of EXPECTED arguments. It will be checked + % for one optional argument in square brackets as well. + optimize command away/.code 2 args={% + \expandafter\global\expandafter\let\csname\string#1@ORIG\endcsname=#1% + \pgfkeysalso{% + /tikz/external/optimize/install/.append code={% + \def#1{\tikzexternal@optimize@away@cmd{#1}{#2}}% + }, + /tikz/external/optimize/restore/.append code={% + \expandafter\let\expandafter#1\csname\string#1@ORIG\endcsname + } + }% + \iftikzexternal@optimize + \ifpgf@external@grabshipout + % we have already started the externalization! Install + % optimization commands to activate the new one: + \tikzexternal@optimize@REPLACE + \fi + \fi + }, + optimize command away=\includegraphics, + optimize command away=\pgfincludeexternalgraphics, + % EXPERIMENTAL (UNTESTED): + optimize latex env away/.code={% + \expandafter\let\expandafter\pgf@tempa\csname #1\endcsname + \expandafter\global\expandafter\let\csname #1@ORIG\endcsname=\pgf@tempa% + \pgfkeysalso{% + /tikz/external/optimize/install/.append code={% + \pgfutil@namedef{#1}{\tikzexternal@optimize@away@latex@env{#1}}% + }, + /tikz/external/optimize/restore/.append code={% + \pgfutil@namelet{#1}{#1@ORIG}% + }% + }% + }, + only named/.is if=tikzexternal@onlynamed, + only named/.default=true, + figure name/.initial=\tikzexternal@realjob-figure, + reset counter/.code={% + \expandafter\gdef\csname c@tikzext@no@#1\endcsname{0}% + },% + prefix/.code={\tikzsetexternalprefix{#1}}, + up to date check/.is choice, + up to date check/simple/.code={\def\tikzexternal@uptodate@mode{0}}, + % md5 relies on \pdfmdfivesum of pdftex. It uses 'diff' as fallback if we do not have that command. + up to date check/md5/.code={\def\tikzexternal@uptodate@mode{1}}, + up to date check/diff/.code={\def\tikzexternal@uptodate@mode{2}}, + up to date check=md5, +} + +\expandafter\def\csname tikzexternal@driver@pgfsys-luatex.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + lualatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"% + }% +}% +\expandafter\def\csname tikzexternal@driver@pgfsys-pdftex.def\endcsname{% + \pgfutil@IfUndefined{directlua}{% + \pgfkeyssetvalue{/tikz/external/system call}{% + pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"% + }% + }{% + \pgfkeyssetvalue{/tikz/external/system call}{% + lualatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"% + }% + }% +}% +%-------------------------------------------------- +% \expandafter\def\csname tikzexternal@driver@pgfsys-dvipdfm.def\endcsname{% +% \pgfkeyssetvalue{/tikz/external/system call}{% +% latex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"% +% && dvipdfm "\image".dvi % +% }% +% }% +%-------------------------------------------------- +\expandafter\def\csname tikzexternal@driver@pgfsys-xetex.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + xelatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"% + }% +}% +\expandafter\def\csname tikzexternal@driver@pgfsys-dvips.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + latex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource" % + && dvips -o "\image".ps "\image".dvi % + }% +}% + +% Auto-select a suitable default value fo 'system call': +\pgfutil@ifundefined{tikzexternal@driver@\pgfsysdriver}{% + % fallback. We do not know the driver here. + \csname tikzexternal@driver@pgfsys-pdftex.def\endcsname +}{% + \csname tikzexternal@driver@\pgfsysdriver\endcsname +}% + + +\def\tikzsetfigurename#1{\pgfkeyssetvalue{/tikz/external/figure name}{#1}}% +\def\tikzappendtofigurename#1{\pgfkeys{/tikz/external/figure name/.add={}{#1}}} + +% This method sets the file name prefix used for every import/export. +% +% It is invoked by the '/tikz/external/prefix' key. +\def\tikzsetexternalprefix#1{\def\tikzexternal@filenameprefix{#1}} +\tikzsetexternalprefix{} + +% This method initialises automatic externalization. +% +% The command does need any argument, but it has two optional ones: +% +% 1. \tikzexternalize[] +% +% 2. \tikzexternalize{} +% +% 3. \tikzexternalize[]{} +% +% The is the job's file name, without the suffix +% .tex . +% If the is omitted, it will be deduced +% automatically. +% +% The effect is: +% 1. automatically surround EVERY tikzpicture by \beginpgfgraphicnamed % sections. +% 2. in case that the job's real name and the current \jobname differ, +% it will process ONLY the matching tikzpicture. +\def\tikzexternalize{% + \pgfutil@ifnextchar[{% + \tikzexternalize@opt + }{% + \tikzexternalize@opt[]% + }% +}% +\def\tikzexternalize@opt[#1]{% + \pgfutil@ifnextchar\bgroup{% + \tikzexternal@auto@detect@jobnamefalse + \tikzexternalize@opt@withname[#1]% + }{% + \tikzexternal@auto@detect@jobnametrue + \pgfutil@ifundefined{tikzexternalrealjob}{% + % ok, \tikzexternalrealjob is not known. + % Assume we are currently *not* externalizing. + \let\tikzexternalrealjob=\jobname + }{}% + \def\pgf@tempa{\tikzexternalize@opt@withname[#1]}% + \expandafter\pgf@tempa\expandafter{\tikzexternalrealjob}% + }% +}% +\def\tikzexternalize@opt@withname[#1]#2{% + \gdef\tikzexternalrealjob{#2}% + \if1\tikzexternalize@hasbeencalled + \else + \pgfqkeys{/tikz/external}{#1}% + \def\tikzexternal@realjob{#2}% + \tikzexternalauxlock@init + \pgfrealjobname{#2}% + \def\tikzexternalize@hasbeencalled{1}% + \tikzexternalenable + \def\tikzexternal@determineimgextension##1:##2\relax{\gdef\tikzexternalimgextension{##1}}% + \xdef\pgf@tempa{\pgfsys@imagesuffixlist}% + \expandafter\tikzexternal@determineimgextension\pgf@tempa:\relax + \pgfutil@ifundefined{includegraphics}{% + \let\tikzexternal@orig@includegraphics=\relax + }{% + \let\tikzexternal@orig@includegraphics=\includegraphics + }% + \let\tikzexternalfiledependsonfile=\tikzexternalfiledependsonfile@ACTIVE + \let\tikzpicturedependsonfile=\tikzpicturedependsonfile@ACTIVE + \fi +} +\def\tikzexternalize@hasbeencalled{0}% + +\def\tikzifexternalizehasbeencalled#1#2{% + \if1\tikzexternalize@hasbeencalled + #1% + \else + #2% + \fi +}% + +% If mode=`convert with system call', the boolean \ifpgfexternalreadmainaux +% will be set depending on the current lock file. +% +% The idea is as follows: Suppose +% pdflatex -shell-escape mainjob.tex +% is running. +% +% While it runs, +% a) it modifies its mainjob.aux file, +% b) it issues pdflatex -jobname mainjob-figure0 mainjob.tex . +% +% The call (b) will try to read mainjob.aux in order to resolve \ref +% commands. This may fail since the aux +% file is not complete; it may be subject to output buffering. To +% avoid such failure, a locking mechanism is established. +% +% The locking mechanisms causes (a) to write a lock command into +% mainjob.auxlock +% just before (b) is called. Then, (b) will check it. After (b) has +% completed, the lock will be reset. +% +% Thus: mode=convert with system call does NOT support \ref commands +% inside of images. You will need to call the externalization command +% manually. In this case, it should work. +% +% The lock file allows to detect automatically whether an image is created by +% 'convert with system call' or if the user issued the required command manually. +% +% @PRECONDITION : this command must be invoked AFTER +% \tikzexternal@realjob has been defined but BEFORE \pgfrealjobname is +% called. +% +% @POSTCONDITION : If \ifpgfexternalreadmainaux=\iffalse, we won't do +% anything. Otherwise, it will be changed depending for 'mode=convert +% with system call' if necessary. +\def\tikzexternalauxlock@init{% + \if4\tikzexternal@opmode + % mode=convert with system call + \ifpgfexternalreadmainaux + % ohoh. This case needs care because the main.aux might + % not be ready at this time! + % check. + % + \edef\pgf@tempa{\expandafter\string\csname\tikzexternal@realjob\endcsname}% + \edef\pgf@tempb{\expandafter\string\csname\jobname\endcsname}% + \ifx\pgf@tempa\pgf@tempb + % we are *not* externalizing. Set lock into its + % initial "unlocked" state. + \tikzexternalauxlock@setlock{0}% + \else + % we are externalizing. Query the lock's value: + \tikzexternalauxlock@getlockvalue + \if1\tikzexternallocked + \pgfexternalreadmainauxfalse + % the main .aux file won't be read right now. + \else + \pgfexternalreadmainauxtrue + \fi + \fi + \else + % NO-OP. We won't read the main aux file anyway. + \def\tikzexternalauxlock@setlock##1{}% + \fi + \fi +} +% defines \tikzexternallocked to be either 0 or 1, depending on the +% lock file. +\def\tikzexternalauxlock@getlockvalue{% + \openin\r@pgf@reada=\tikzexternal@realjob.auxlock + \ifeof\r@pgf@reada + % no lock file. Unlock. + \def\tikzexternallocked{0}% + \else + % read first line... + \read\r@pgf@reada to\pgf@tempa + % ... and execute it. + \pgf@tempa + % it should contain a definition of \tikzexternallocked. If + % not, lock it anyway. + \pgfutil@ifundefined + {tikzexternallocked} + {\def\tikzexternallocked{1}}% + {}% + \fi + \closein\r@pgf@reada +}% +\def\tikzexternalauxlock@setlock#1{% + \immediate\openout\w@pgf@writea=\tikzexternal@realjob.auxlock + \immediate\write\w@pgf@writea{\noexpand\def\noexpand\tikzexternallocked{#1}}% + \immediate\closeout\w@pgf@writea +} + + +% this is a hook into pgfcoreexternal.code.tex: +\def\pgf@external@grab@refundefinedtrue@code{% + \gdef\noexpand\tikzexternal@systemcall@reschedule@to@end@document{1}% +}% + +% Expands to the default image extension (it is set by +% \tikzexternalize). +% +% This image extension may not resemble the correct one; you may need +% to overwrite this macro *after* \tikzexternalize in this case. +% +% The default setting uses the first registered image extension. +\def\tikzexternalimgextension{}% + +% can be used to (temporarily) disable the externalization. +\def\tikzexternaldisable{% + \tikzexternaldisable@nofading + \pgfutil@ifundefined{tikzexternal@orig@tikzfadingfrompicture} + {}% NOP + {% + \let\tikzfadingfrompicture=\tikzexternal@orig@tikzfadingfrompicture + \let\endtikzfadingfrompicture=\tikzexternal@orig@endtikzfadingfrompicture + \let\tikzfading=\tikzexternal@orig@tikzfading + }% +}% +\def\tikzexternaldisable@nofading{% + \let\tikz=\tikzexternal@origtikz + \tikzexternal@TEXDIALECT@restore@picture + \iftikzexternal@optimize + \ifpgf@external@grabshipout + \tikzexternal@optimize@RESTORE + \fi + \fi +} +% re-enables externalization after a \tikzexternalizedisable. +\def\tikzexternalenable{% + \if\tikzexternalize@hasbeencalled1% + \let\tikz=\tikzexternal@tikz@replacement + \tikzexternal@TEXDIALECT@installreplacement@picture + \pgfutil@ifundefined{tikzfadingfrompicture}% + {}% no special handling for 'fading lib' + {% + % oh, ok -- patch fading lib! + \pgfutil@ifundefined{tikzexternal@orig@tikzfadingfrompicture}{% + \let\tikzexternal@orig@tikzfadingfrompicture=\tikzfadingfrompicture + \let\tikzexternal@orig@endtikzfadingfrompicture=\endtikzfadingfrompicture + \let\tikzexternal@orig@tikzfading=\tikzfading + }{}% + \def\tikzfadingfrompicture{% + \begingroup + \tikzexternaldisable@nofading + \tikzexternal@orig@tikzfadingfrompicture}% + \def\endtikzfadingfrompicture{% + \tikzexternal@orig@endtikzfadingfrompicture + \endgroup}% + \def\tikzfading[##1]{% + \begingroup + \tikzexternaldisable@nofading + \tikzexternal@orig@tikzfading[##1]% + \endgroup}% + }% + \iftikzexternal@optimize + \ifpgf@external@grabshipout + \tikzexternal@optimize@REPLACE + \fi + \fi + \fi +}% + +% Sets the filename for the next tikzpicture or \tikz shortcommand. +% +% It will *only* be used for the next picture. +% +% If you don't call \tikzsetnextfilename for a picture, a file name +% will be assembled automatically. +% +% Please note that the global file prefix will be prepended anyway. +\def\tikzsetnextfilename#1{\gdef\tikzexternal@nextfile{#1}} +\tikzsetnextfilename{} + + +% These are few TeX dialect-specific commands which need to be overridden when used with +% something different than plain TeX: +% +% 1. this command collects a complete image into a macro, up to (but not including) the +% final TeX-dialect specific end-image command. +% This is really difficult for LaTeX because \end{tikzpicture} either involves dirty +% catcode-hacks to parse the braces or an ugly loop which loops until it +% finds \end followed by {tikzpicture}. +% +% #1: a macro which will be called with the collected environment contents. +% all following tokens: the environment contents. +\long\gdef\tikzexternal@TEXDIALECT@collectpicture#1#2\endtikzpicture{#1{#2}} +% +% 2. the following commands should expand to the TeX-dialect specific begin and end image command, i.e. +% \tikzpicture / \endtikzpicture +% or +% \begin{tikzpicture} / \end{tikzpicture} +% or +% \starttikzpicture / \stoptikzpicture +\def\tikzexternal@TEXDIALECT@begpicture{\tikzpicture} +\def\tikzexternal@TEXDIALECT@endpicture{\endtikzpicture}% +% +% 3. This installs the replacement macros: +\def\tikzexternal@TEXDIALECT@installreplacement@picture{% + \let\tikzpicture=\tikzexternal@tikzpicture@replacement +}% +\def\tikzexternal@TEXDIALECT@restore@picture{% + \let\tikzpicture=\tikzexternal@origpicture +}% + + + + +\let\tikzexternal@origtikz=\tikz +\let\tikzexternal@origpicture=\tikzpicture +\let\tikzexternal@origendpicture=\endtikzpicture +\let\tikzexternal@curfilename=\relax + +% Replacement for '\tikzpicture'. +% +% There are two different states in which this method is applied: +% - normal typesetting. Then, the 'mode' key controls its behavior. +% - externalize mode (i.e. jobname != real job name). Then, it will +% externalize the picture selected by 'jobname' (and only this picture). +\def\tikzexternal@tikzpicture@replacement{% + \leavevmode + \global\tikzexternal@file@isuptodatetrue% may be set to false during checks. + \tikzexternal@getnextfilename\tikzexternal@curfilename + \ifx\tikzexternal@curfilename\pgfutil@empty + \ifpgf@external@grabshipout + % This picture won't be externalized. + % But maybe we can optimize it away: + \iftikzexternal@optimize + % -> it won't be shipped out anyway, so save typesetting time! + \let\tikzexternal@next=\tikzexternal@skipfigure + \else + % include this graphics into the output (even if + % it will be discarded anyway). + \let\tikzexternal@next=\tikzexternal@normalpicture@nographics + \fi + \else + \let\tikzexternal@next=\tikzexternal@normalpicture@nographics + \fi + \else + \ifpgf@external@grabshipout + \tikzifexternaljobnamematches\tikzexternal@curfilename{% + % ok, this here IS the picture for which + % pdflatex --jobname + % has been invoked. + \let\tikzexternal@next=\tikzexternal@externalizefig + }{% + \iftikzexternal@optimize + % No, another picture should be exported. Simply skip this one + % -> it won't be shipped out anyway, so save typesetting time! + \let\tikzexternal@next=\tikzexternal@skipfigure + \else + % include this graphics into the output (even it + % it will be discarded anyway). + \let\tikzexternal@next=\tikzexternal@normalpicture@nographics + \fi + }% + \else + \ifcase\tikzexternal@opmode\relax + % 'mode=only graphics' + \let\tikzexternal@next=\tikzexternal@forcegraphics + \or + % 'mode=no graphics' + \let\tikzexternal@next=\tikzexternal@normalpicture@nographics + \or + % 'mode=graphics if exists' + \let\tikzexternal@next=\tikzexternal@externalizefig + \or + % 'mode=list only' + \let\tikzexternal@next=\tikzexternal@listmodepicture + \or + % 'mode=convert with system call' + \let\tikzexternal@next=\tikzexternal@externalizefig@systemcall + \or + % 'mode=list and make' + \let\tikzexternal@next=\tikzexternal@list@and@makefile@mode@picture + \fi + \fi + \fi + \tikzexternal@next +}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Replacement for \tikz short command: +\def\tikzexternal@tikz@replacement{% + \pgfutil@ifnextchar[{\tikzexternal@tikz@replacement@opt}{\tikzexternal@tikz@replacement@opt[]}% +}% +\def\tikzexternal@tikz@replacement@opt[#1]{% + \pgfutil@ifnextchar\bgroup{\tikzexternal@tikz@replacement@opt@{#1}}{\tikzexternal@tikz@replacement@opt@@{#1}}% +} +\long\def\tikzexternal@tikz@replacement@opt@#1#2{% + \tikzexternal@tikz@replacement@opt@process{#1}{#2}% +}% +\def\tikzexternal@tikz@replacement@opt@@#1{% + \def\tikz@next{\tikzexternal@tikz@replacement@collectnormalsemicolon{#1}}% + \ifnum\the\catcode`\;=\active\relax% + \def\tikz@next{\tikzexternal@tikz@replacement@collectactivesemicolon{#1}}% + \fi% + \tikz@next} +\long\def\tikzexternal@tikz@replacement@collectnormalsemicolon#1#2;{% + \tikzexternal@tikz@replacement@opt@process{#1}{#2;}% +}% +{ + \catcode`\;=\active + \long\gdef\tikzexternal@tikz@replacement@collectactivesemicolon#1#2;{% + \tikzexternal@tikz@replacement@opt@process{#1}{#2;}% + } +} +\long\def\tikzexternal@tikz@replacement@opt@process#1#2{% + \begingroup + \t@tikzexternal@tmpa=\expandafter{\tikzexternal@TEXDIALECT@begpicture[#1]#2}% + \t@tikzexternal@tmpb=\expandafter{\tikzexternal@TEXDIALECT@endpicture}% + \xdef\pgf@tempa{\the\t@tikzexternal@tmpa\the\t@tikzexternal@tmpb}% + \endgroup + \pgf@tempa +} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\tikzexternal@getnextfilename@advancecount{% + \begingroup + \c@pgf@counta=\csname c@tikzext@no@\tikzexternal@figurename\endcsname\relax + \advance\c@pgf@counta by1 + \expandafter\xdef\csname c@tikzext@no@\tikzexternal@figurename\endcsname{\the\c@pgf@counta}% + \endgroup +}% + +% Returns the file name which will be used for the next tikzpicture (based on the currently available information only, of course). +\def\tikzexternalgetnextfilename#1{% + \begingroup + \let\tikzexternal@getnextfilename@advancecount\relax% NOP + \let\tikzexternal@getnextfilename@resetglobals=\relax% NOP + \def\tikzexternal@protocol@to@file##1{}% NOP + \tikzexternal@getnextfilename#1% + \pgfmath@smuggleone#1% + \endgroup +}% + +% Returns the file name of the current picture. +% +% It returns the empty string in case the command is invoked outside +% of a picture. +% #1 the macro which will contain the file name. +% @see \tikzexternalgetnextfilename +\def\tikzexternalgetcurrentfilename#1{% + \ifx\tikzexternal@curfilename\relax + % we are outside of a picture. + \let#1=\pgfutil@empty + \else + % we are inside of a picture. + \let#1=\tikzexternal@curfilename + \fi +} + +% Fills #1 with a filename for the current picture. +% +% The filename will be generated automatically by appending '-figure' to the real jobname. +% +% This method deals with +% - \tikzsetnextfilename +% - \tikzexternalexportnextfalse +% +% It returns #1={} if the current figure shall NOT be exported. +% +% Please note that both, \tikzsetnextfilename and \tikzexternalexportnextfalse +% affect only ONE picture. They will be reset afterwards. +\def\tikzexternal@getnextfilename#1{% + \let#1=\pgfutil@empty + % determine next file name: + \iftikzexternal@export@enabled + \iftikzexternalexportnext + \begingroup + \t@tikzexternal@tmpa=\expandafter{\tikzexternal@filenameprefix}% + \ifx\tikzexternal@nextfile\pgfutil@empty + \iftikzexternal@onlynamed + \xdef\pgf@tempa{}% + \else + \pgfkeysgetvalue{/tikz/external/figure name}\tikzexternal@figurename + \pgfutil@ifundefined{c@tikzext@no@\tikzexternal@figurename}{% + % initialise on first usage: + \expandafter\gdef\csname c@tikzext@no@\tikzexternal@figurename\endcsname{0}% + }{}% + \t@tikzexternal@tmpb=\expandafter{\tikzexternal@figurename}% + \xdef\pgf@tempa{\the\t@tikzexternal@tmpa\the\t@tikzexternal@tmpb\csname c@tikzext@no@\tikzexternal@figurename\endcsname}% + % advance the counter for 'figure name': + \tikzexternal@getnextfilename@advancecount + \fi + \else + \t@tikzexternal@tmpb=\expandafter{\tikzexternal@nextfile}% + \xdef\pgf@tempa{\the\t@tikzexternal@tmpa\the\t@tikzexternal@tmpb}% + \fi + \endgroup + \let#1=\pgf@tempa + \fi + \fi + % + \tikzexternal@getnextfilename@resetglobals% + % + \tikzexternal@protocol@to@file#1% +}% + +\def\tikzexternal@getnextfilename@resetglobals{% + % Reset global flags: + \global\let\tikzexternal@nextfile=\pgfutil@empty + \global\tikzexternalexportnexttrue +}% + +% #1: the image file name which should be protocolled. (can be a +% macro) +\def\tikzexternal@protocol@to@file#1{% + \ifpgf@external@grabshipout% + \else + \iftikzexternal@genfigurelist + \edef\tikzexternal@temp{#1}% + \ifx\tikzexternal@temp\pgfutil@empty + \else + \pgfutil@ifundefined{tikzexternal@listmode@openedfile}{% + \message{Opening '\tikzexternal@realjob.figlist' for writing.}% + \begingroup + \globaldefs=1 + % this gets round '\outer\newwrite' in plain TeX: + \csname newwrite\endcsname\tikzexternal@outfile + \endgroup + \immediate\openout\tikzexternal@outfile=\tikzexternal@realjob.figlist\relax + \gdef\tikzexternal@listmode@openedfile{1}% + \if\tikzexternal@opmode5% mode='list and make' + \tikzexternal@list@and@make@prepare + \fi + }{}% + \iftikzexternal@verboseio + \pgf@typeout{Writing '#1' to '\tikzexternal@realjob.figlist'.}% + \fi + \immediate\write\tikzexternal@outfile{#1}% + \if\tikzexternal@opmode5% mode='list and make' + \tikzexternal@list@and@make@gentarget{#1}% + \fi + \fi + \fi + \fi +}% + +\def\tikzexternal@list@and@make@gentarget#1{% + \tikzexternal@assemble@systemcall{#1}{\pgf@tempa}% + \def\tikzexternal@tempb{\pgfutilstrreplace{^^J}{^^J\tikzexternal@TABchar}}% + \expandafter\tikzexternal@tempb\expandafter{\pgf@tempa}% + \let\pgf@tempa=\pgfretval + \iftikzexternal@verboseio + \pgf@typeout{Writing '#1' to '\tikzexternal@realjob.makefile'.}% + \fi + \global\tikzexternal@file@isuptodatetrue% only check for force remake: + \tikzexternal@checkforceremake% + \immediate\write\tikzexternal@outmakefile{#1\tikzexternalimgextension: \iftikzexternal@file@isuptodate\else FORCEREMAKE\fi}% + \immediate\write\tikzexternal@outmakefile{\tikzexternal@TABchar\pgf@tempa}% + \immediate\write\tikzexternal@outmakefile{}% +} + +\def\tikzexternal@list@and@make@prepare{% + \iftikzexternal@verboseio + \pgf@typeout{Opening '\tikzexternal@realjob.makefile' for writing.}% + \fi + \begingroup + % this makes \tikzexternal@outmakefile global: + \globaldefs=1 + % this gets round '\outer\newwrite' in plain TeX: + \csname newwrite\endcsname\tikzexternal@outmakefile + \endgroup + \immediate\openout\tikzexternal@outmakefile=\tikzexternal@realjob.makefile\relax + \immediate\write\tikzexternal@outmakefile{ALL_FIGURE_NAMES=\tikzexternal@DOLLARchar(shell cat \tikzexternal@realjob.figlist)}% + \immediate\write\tikzexternal@outmakefile{ALL_FIGURES=\tikzexternal@DOLLARchar(ALL_FIGURE_NAMES:\tikzexternal@PERCENTchar=\tikzexternal@PERCENTchar\tikzexternalimgextension)}% + \immediate\write\tikzexternal@outmakefile{}% + \immediate\write\tikzexternal@outmakefile{allimages: \tikzexternal@DOLLARchar(ALL_FIGURES)}% + \immediate\write\tikzexternal@outmakefile{\tikzexternal@TABchar @echo All images exist now. Use make -B to re-generate them.}% + \immediate\write\tikzexternal@outmakefile{}% + \immediate\write\tikzexternal@outmakefile{FORCEREMAKE:}% + \immediate\write\tikzexternal@outmakefile{}% + % + % support for .dep files and auto-dependencies: + \immediate\write\tikzexternal@outmakefile{-include $(ALL_FIGURE_NAMES:\tikzexternal@PERCENTchar=\tikzexternal@PERCENTchar.\tikzexternaldepext)}% + \immediate\write\tikzexternal@outmakefile{}% + \tikzexternalmakefiledefaultdeprule + \immediate\write\tikzexternal@outmakefile{}% + \tikzexternal@outmakefile@pendingcommands + \pgfutil@ifundefined{AtEndDocument}{}{% + \AtEndDocument{\pgf@typeout{===== mode=`list and make': Use 'make -f \tikzexternal@realjob.makefile' to generate all images. Then, re-run (pdf)latex \tikzexternal@realjob. =====}}% + }% +}% +\def\tikzexternaldepext{dep} + +\def\tikzexternalmakefiledefaultdeprule{% + \immediate\write\tikzexternal@outmakefile{\tikzexternal@PERCENTchar.\tikzexternaldepext:}% + \immediate\write\tikzexternal@outmakefile{\tikzexternal@TABchar mkdir -p \tikzexternal@normal@dq $(dir $@)\tikzexternal@normal@dq}% + \immediate\write\tikzexternal@outmakefile{\tikzexternal@TABchar touch \tikzexternal@normal@dq $@\tikzexternal@normal@dq\space \tikzexternal@HASHchar\space will be filled later.}% +}% + +% Invokes '#1' if a makefile is to be written and '#2' if not. +\def\tikzexternalifwritesmakefile#1#2{% + \if5\tikzexternal@opmode #1\else #2\fi +}% +\def\tikzexternal@outmakefile@pendingcommands{}% + +% Will write something to the make file. If the makefile is not yet +% opened, #1 will be written as soon as it *is* opened. +\def\tikzexternalwritetomakefile#1{% + \if\tikzexternal@opmode5% mode='list and make' + \pgfutil@ifundefined{tikzexternal@outmakefile}{% + \expandafter\gdef\expandafter\tikzexternal@outmakefile@pendingcommands\expandafter{% + \tikzexternal@outmakefile@pendingcommands + \immediate\write\tikzexternal@outmakefile{#1}% + }% + }{% + \immediate\write\tikzexternal@outmakefile{#1}% + }% + \fi +}% + +\def\tikzexternal@dep@file@name{} + +% Adds a dependency for the externalized picture file name `#1', +% namely another file `#2'. +% +% #1: the fully qualified path name (without image extension) of the +% external graphics for which we are adding a dependency. +% #2: a file name. If this file gets changed, #1 shall be remade. +% +% This command will be activated as soon as \tikzexternalize has been +% called. +\def\tikzexternalfiledependsonfile@ACTIVE#1#2{% + \begingroup + \def\tikzpicturedependsonfile@name{#1}% + \ifx\tikzpicturedependsonfile@name\pgfutil@empty + % could be auto-generated: empty file name means "picture + % won't be externalized". Skip it. + \else + % if we encounter any dependencies while we externalize a + % picture, we have to write these things into the image's .dep + % file. + \tikzifexternalizingcurrent + {\tikzexternalfiledependsonfile@append@to@dep@file{#1}{#2}}% + {\tikzexternalfiledependsonfile@append@to@makefile{#1}{#2}}% + \fi + \endgroup +}% +\def\tikzexternalfiledependsonfile#1#2{}% NO-OP until \tikzexternalize has been called. + +% sub-routine of \tikzexternalfiledependsonfile which appends stuff to +% the pictures .dep file. +% +% The file #1.dep is generated during the externalization of #1. If +% you change and/or overwrite it in any other context, its information +% might get lost (because #1 won't be regenerated). +% +% Consequently, this here has to be called if and only if #1 is about +% to be externalized. +\def\tikzexternalfiledependsonfile@append@to@dep@file#1#2{% + % write every dependency which is defined *INSIDE* of the current + % picture into the .dep file of the current picture: + \tikzexternalgetcurrentfilename\tikzpicturedependsonfile@name + \edef\tikzpicturedependsonfile@name{\tikzpicturedependsonfile@name.\tikzexternaldepext}% + %\edef\tikzpicturedependsonfile@name{#1.\tikzexternaldepext}% + \ifx\tikzexternal@dep@file@name\tikzpicturedependsonfile@name + % file is open and ready. + \else + % create new output file. + \pgfutil@ifundefined{tikzexternal@dep@file}{% + \begingroup + % this makes \tikzexternal@dep@file global: + \globaldefs=1 + % this gets round '\outer\newwrite' in plain TeX: + \csname newwrite\endcsname\tikzexternal@dep@file + \endgroup + }{}% + \ifx\tikzexternal@dep@file@name\pgfutil@empty + \else + % it is already open. Close it. + \immediate\closeout\tikzexternal@dep@file + \fi + \global\let\tikzexternal@dep@file@name=\tikzpicturedependsonfile@name + \immediate\openout\tikzexternal@dep@file=\tikzexternal@dep@file@name\relax + \fi + \immediate\write\tikzexternal@dep@file{#1\tikzexternalimgextension: #2}% +} + +% sub-routine of \tikzexternalfiledependsonfile which appends stuff to +% the makefile of the current \jobname . +% +% This is used for dependencies which are recomputed by every run of +% tex; we must not write them into #1.dep (for reasons explained in +% the documentation of +% \tikzexternalfiledependsonfile@append@to@dep@file) +\def\tikzexternalfiledependsonfile@append@to@makefile#1#2{% + \edef\tikzexternal@temp{#1\tikzexternalimgextension: #2}% + \expandafter\tikzexternalwritetomakefile\expandafter{\tikzexternal@temp}% +} + +% Adds a dependency for the NEXT picture which is about to be +% externalized. If we are currently inside of a picture, the +% dependency is added for this current picture. +% +% #1: a file name. If this file gets changed, the tikzpicture's +% externalized graphics shall be remade. +% +% This command will be activated as soon as \tikzexternalize has been +% called. +\def\tikzpicturedependsonfile@ACTIVE#1{% + \begingroup + \tikzexternalgetcurrentfilename\tikzpicturedependsonfile@name + \ifx\tikzpicturedependsonfile@name\pgfutil@empty + \tikzexternalgetnextfilename\tikzpicturedependsonfile@name + \fi + \expandafter\tikzexternalfiledependsonfile\expandafter{\tikzpicturedependsonfile@name}{#1}% + \endgroup +}% +\def\tikzpicturedependsonfile#1{}% NO-OP until \tikzexternalize has been called. + + +% This command is invoked +% if and only if ( (grab mode && --jobname matches) || 'mode=graphics if exists' ) +% +% It converts the current tikzpicture into an image in grab mode +% or processes the 'graphics if exist' mode. +\def\tikzexternal@externalizefig{% + \ifpgf@external@grabshipout% + % In this case, we already KNOW that the filename matches. + \expandafter\tikzexternal@externalizefig@GRAB% + \else + \expandafter\tikzexternal@externalizefig@mode@graphics@if@exists + \fi% +} +\def\tikzexternal@externalizefig@mode@graphics@if@exists{% + % check if there is already a file. + % In that case, use it. If not, typeset the picture normally. + \gdef\pgf@filename{}% + \xdef\pgf@tempa{\noexpand\pgf@findfile\pgfsys@imagesuffixlist:+{\tikzexternal@curfilename}}% + \pgf@tempa + \ifx\pgf@filename\pgfutil@empty% + % Note: since we have no 'GRAB' mode, we do not have to deal with optimization. + % there is no graphics. + \expandafter\tikzexternal@normalpicture@nographics + \else + \expandafter\tikzexternal@forcegraphics + \fi +}% + + +% Used by the optimization code. +% It will be called if GRAB mode is on. +% See the 'optimize command away' key. +\def\tikzexternal@optimize@away@cmd#1#2{% + \pgfutil@ifnextchar[{% + \tikzexternal@optimize@away@cmd@{#1}{#2}% + }{% + \tikzexternal@optimize@away@cmd@{#1}{#2}[]% + }% +}% +\def\tikzexternal@optimize@away@cmd@#1#2[#3]{% + \def\tikz@temp{#2}% + \ifx\tikz@temp\pgfutil@empty + \def\tikz@temp{\tikzexternal@optimize@away@cmd@auto{#1}{#3}}% + \else + \ifcase#2\relax + \def\tikzexternal@optimize@away@cmd@manual{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4##5{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}{##5}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4##5##6{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}{##5}{##6}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4##5##6##7{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4##5##6##7##8{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}}% + }% + \or + \def\tikzexternal@optimize@away@cmd@manual##1##2##3##4##5##6##7##8##9{% + \tikzexternal@optimize@away@cmd@@@{#1}{#3}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}}% + }% + \fi + \def\tikz@temp{\tikzexternal@optimize@away@cmd@manual}% + \fi + \tikz@temp +}% +\def\tikzexternal@optimize@away@cmd@auto#1#2{% + \pgfutil@ifnextchar\bgroup{% + \tikzexternal@optimize@away@cmd@auto@{#1}{#2}% + }{% + \tikzexternal@optimize@away@cmd@auto@{#1}{#2}{}% give empty argument. + } +}% + +\def\tikzexternal@optimize@away@cmd@auto@#1#2#3{% + \tikzexternal@optimize@away@cmd@@@{#1}{#2}{{#3}}% <-- provide braces +}% +\def\tikzexternal@optimize@away@cmd@@@#1#2#3{% + \begingroup + \toks0={#1[#2]#3}% + \iftikzexternal@verbose@optimize + \pgf@typeout{The command '\the\toks0' has been optimized away. Use '/tikz/external/optimize=false' to disable this.}% + \fi + \endgroup + \begingroup + \pgfkeysvalueof{/tikz/external/optimize away text/.@cmd}#1\pgfeov% + \endgroup +}% + +\def\tikzexternal@optimize@away@latex@env#1{% + \def\tikzexternal@optimize@away@latex@env@{#1}% + \begingroup + \def\tikzexternal@laTeX@collect@until@end@tikzpicturetikzpicturestring{#1}% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@optimize@away@latex@env@close +}% +\long\def\tikzexternal@optimize@away@latex@env@close#1{% + \iftikzexternal@verbose@optimize + \pgf@typeout{The complete contents of \string\begin{tikzexternal@optimize@away@latex@env@} up to the next \end{tikzexternal@optimize@away@latex@env@} has been optimized away because it does not contribute to the exported PDF. Use '/tikz/external/optimize=false' to disable this.}% + \fi + \endgroup + % we still need to invoke \end{} in latex because \begin{} + % starts a local group - that must be closed properly. Make sure then \end does nothing: + \expandafter\let\csname end\tikzexternal@optimize@away@latex@env@\endcsname=\relax + \expandafter\end\expandafter{\tikzexternal@optimize@away@latex@env@}% +}% + +\def\tikzexternal@optimize@REPLACE{% + \pgfkeysvalueof{/tikz/external/optimize/install/.@cmd}\pgfeov +}% + +\def\tikzexternal@optimize@RESTORE{% + \pgfkeysvalueof{/tikz/external/optimize/restore/.@cmd}\pgfeov +}% + +% Closes one 'tikzpicture' environment. This is only used for LaTeX, +% because the '\end{tikzpicture}' command would raise an exception otherwise. +% It does *not* call \endtikzpicture. +\def\tikzexternal@closeenvironments{% + \let\endtikzpicture=\relax + \tikzexternal@TEXDIALECT@endpicture + \let\endtikzpicture=\tikzexternal@origendpicture + \let\tikzexternal@curfilename=\relax +} + +% Throws a tikzpicture away - without further notice. +% Used if we are currently converting *another* picture. No need to waste time +% with expensive pictures if they are not shipped out anyway. +% +% See the 'optimize' key to disable this. +\def\tikzexternal@skipfigure{% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@skipfigure@@ +} +\long\def\tikzexternal@skipfigure@@#1{% + \iftikzexternal@verbose@optimize + \pgf@typeout{A tikzpicture has been optimized away. Use '/tikz/external/optimize=false' to disable this.}% + \fi + \tikzexternal@closeenvironments + \pgfkeysvalueof{/tikz/external/optimize away text/.@cmd}tikzpicture\pgfeov% +} + +% Processes tikzpicture normally; without any externalization. +% +% We need to do further work here to deal with NESTED tikzpicture environments +% because all of them shall also be typeset normally. +% +% Idea: +% 1. restore the original \tikzpicture macro +% 2. install the replacement \tikzpicture in \end{tikzpicture}. +% and keep track of nesting. +% +% FIXME: could it be possible that nested tikzpictures use other code anyway? +\def\tikzexternal@normalpicture@nographics{% + \tikzexternal@nestedflagfalse + \let\tikzpicture=\tikzexternal@normalpicture@begreplace + \let\endtikzpicture=\tikzexternal@normalpicture@endreplace + \tikzpicture +} +\def\tikzexternal@normalpicture@begreplace{% + \begingroup + \tikzexternal@nestedflagtrue + \tikzexternal@origpicture +} +\def\tikzexternal@normalpicture@endreplace{% + \tikzexternal@origendpicture + \endgroup + \iftikzexternal@nestedflag + \else + \let\tikzpicture=\tikzexternal@tikzpicture@replacement + \let\endtikzpicture=\tikzexternal@origendpicture + \fi +}% + +% Assumes there is an image on disk and reads it. The tikzpicture is thrown away. +\def\tikzexternal@forcegraphics{% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@forcegraphics@@ +} +\long\def\tikzexternal@forcegraphics@@#1{\tikzexternal@forcegraphics@@@}% +\def\tikzexternal@forcegraphics@@@{% + \if5\tikzexternal@opmode + \let\tikz@refundefinedtrue@@=\G@refundefinedtrue + \gdef\G@refundefinedtrue{% + \tikz@refundefinedtrue@@ + \tikzexternal@forceremake@undefined@reference@handler + }% + \fi + \expandafter\pgfincludeexternalgraphics\expandafter{\tikzexternal@curfilename}% + \if5\tikzexternal@opmode + \global\let\G@refundefinedtrue=\tikz@refundefinedtrue@@ + \fi + \tikzexternal@closeenvironments +} + +\def\tikzexternal@forceremake@undefined@reference@handler{% + \pgf@typeout{===== 'mode=list and make': encountered undefined reference in current picture. Adding dependency to FORCEREMAKE. Rerun make to update the picture.' ========^^J}% + \tikzpicturedependsonfile{FORCEREMAKE}% +}% + +% Simply replaces the complete picture by some placeholder text. +% It is used by 'mode=list only' to reduce runtime. +\def\tikzexternal@listmodepicture{% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@listmodepicture@@ +} +\long\def\tikzexternal@listmodepicture@@#1{\tikzexternal@listmodepicture@@@} +\def\tikzexternal@listmodepicture@@@{% + \pgfkeysvalueof{/tikz/external/image discarded text}% + \tikzexternal@closeenvironments +} + +% check if there is already a file. +% In that case, use it. If not, skip it. +\def\tikzexternal@list@and@makefile@mode@picture{% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@list@and@makefile@mode@picture@ +}% +\long\def\tikzexternal@list@and@makefile@mode@picture@#1{% + % + \tikzexternal@check@uptodate@mode{#1}% + % + \gdef\pgf@filename{}% + \xdef\pgf@tempa{\noexpand\pgf@findfile\pgfsys@imagesuffixlist:+{\tikzexternal@curfilename}}% + \pgf@tempa + \ifx\pgf@filename\pgfutil@empty% + % Note: since we have no 'GRAB' mode, we do not have to deal with optimization. + % there is no graphics. + \expandafter\tikzexternal@listmodepicture@@@ + \else + \expandafter\tikzexternal@forcegraphics@@@ + \fi +}% + +\def\tikzexternal@externalizefig@before@grab{% + \pgfutil@IfUndefined{TP@holdbox}{% + }{% + % \usepackage[absolute]{textpos} + % populates this box -- and would inject unwanted material into our images. Reset it: + \global\setbox\TP@holdbox\vbox{}% + }% +}% + +\def\tikzexternal@externalizefig@GRAB{% + \ifpgf@external@grabshipout + \iftikzexternal@optimize + \tikzexternal@optimize@RESTORE + \fi + \tikzexternal@externalizefig@before@grab + \fi + \def\tikzpicture{% + \def\tikzpicture{% make sure that nested \tikzpicture are processed normally. + \begingroup + \def\endtikzpicture{% + \tikzexternal@origendpicture + \endgroup + }% + \tikzexternal@origpicture + }% + \pgf@external@grab{\tikzexternal@curfilename}% + \tikzexternal@origpicture + }% + \def\endtikzpicture{% + \tikzexternal@origendpicture + \pgf@externalend + % + \tikzexternal@ensure@nonempty@floats + % + \let\tikzpicture=\tikzexternal@tikzpicture@replacement + \let\endtikzpicture=\tikzexternal@origendpicture + \iftikzexternal@optimize + \ifpgf@external@grabshipout + \tikzexternal@optimize@REPLACE + \fi + \fi + }% + \tikzpicture +}% + +% If a sequence of floats containing JUST tikzpictures is +% externalized, this results in EMPTY floats. Empty floats, in turn, +% can confuse latex; it thinks it did something wrong. +% +% Solution: Avoid empty floats by writing junk into it. +% +% Note that this method is only invoked if \ifpgf@external@grabshipout +% is true and if the text is OUTSIDE of the original shipout routine. +% In other words: this text is being thrown away. +% +% see +% http://tex.stackexchange.com/questions/54625/why-is-fixltx2e-incompatible-with-tikzexternalize +\def\tikzexternal@ensure@nonempty@floats{% + tikzexternal: picture has been externalized. This text is required to avoid empty floats. +}% + +% 1. Discards the current picture in this document. +% 2. Checks whether an image exists already. If that is the case: acquire it. +% 3. If no image exists: call '/tikz/external/system call'. This will +% process \tikzexternal@externalizefig. +% 4. Assert that finally an image exists and use it. +\def\tikzexternal@externalizefig@systemcall{% + \tikzexternal@TEXDIALECT@collectpicture\tikzexternal@externalizefig@systemcall@@ +} + +{ +\catcode`\"=12 +\catcode`\'=12 +\catcode`\;=12 +\catcode`\&=12 +\catcode`\-=12 +\xdef\tikzexternal@normal@dq{"} +\xdef\tikzexternal@normal@sq{'} +\xdef\tikzexternal@normal@semic{;} +\xdef\tikzexternal@normal@and{&} +\xdef\tikzexternal@normal@dash{-} +\catcode`\"=13 +\catcode`\'=13 +\catcode`\;=13 +\catcode`\&=13 +\catcode`\-=13 +\gdef\tikzexternal@activate@normal@dq{\let"=\tikzexternal@normal@dq} +\gdef\tikzexternal@activate@normal@sq{\let'=\tikzexternal@normal@sq} +\gdef\tikzexternal@activate@normal@semic{\let;=\tikzexternal@normal@semic} +\gdef\tikzexternal@activate@normal@and{\let&=\tikzexternal@normal@and} +\gdef\tikzexternal@activate@normal@dash{\let-=\tikzexternal@normal@dash} +\catcode`\|=0 +\catcode`\\=12 +|xdef|tikzexternal@normal@backslash{\}% +} +{ +\catcode`\^^I=12 +\catcode`\$=12 +\catcode`\%=12 +\catcode`\#=12 +\gdef\tikzexternal@HASHchar{#} +\gdef\tikzexternal@TABchar{^^I}\gdef\tikzexternal@PERCENTchar{%}\xdef\tikzexternal@DOLLARchar{$}} + +% Creates the '/tikz/external/system call' command as string and +% returns it into the (global!) macro #2. +% #1: the image file name (as returned by +% \tikzexternalgetnextfilename) +% #2: the global return value macro +% +\def\tikzexternal@assemble@systemcall#1#2{% + \begingroup + \def\image{#1}% + \iftikzexternal@auto@detect@jobname + \edef\texsource{\string\def\string\tikzexternalrealjob{\tikzexternal@realjob}\string\input{\tikzexternal@realjob}}% + \else + \let\texsource=\tikzexternal@realjob + \fi + \ifnum\the\catcode`\"=13 \tikzexternal@activate@normal@dq\fi + \ifnum\the\catcode`\'=13 \tikzexternal@activate@normal@sq\fi + \ifnum\the\catcode`\;=13 \tikzexternal@activate@normal@semic\fi + \ifnum\the\catcode`\-=13 \tikzexternal@activate@normal@dash\fi + \let\\=\tikzexternal@normal@backslash + \xdef#2{\pgfkeysvalueof{/tikz/external/system call}}% + \endgroup +}% +\long\def\tikzexternal@externalizefig@systemcall@@#1{% + \tikzexternal@externalizefig@systemcall@uptodatecheck{#1}% + \tikzexternal@assemble@systemcall{\tikzexternal@curfilename}{\pgf@tempa}% + \global\let\tikzexternal@cursyscall=\pgf@tempa + \gdef\tikzexternal@typeset@picture@on@failure{1}% + \iftikzexternal@file@isuptodate + \iftikzexternal@verboseio + \pgf@typeout{===== Image '\tikzexternal@curfilename' is up-to-date. ======}% + \fi + \let\pgf@filename=\tikzexternal@curfilename + \else + \begingroup + % no such image. Generate it! + % + \tikzexternalauxlock@setlock1% + \tikzexternal@externalizefig@systemcall@call{\tikzexternal@cursyscall}% + \tikzexternalauxlock@setlock0% + \expandafter\tikzexternal@externalizefig@systemcall@assertsuccess\expandafter{\tikzexternal@cursyscall}% + \pgfmath@smuggleone\pgf@filename + \endgroup + \fi + \ifx\pgf@filename\pgfutil@empty + \if1\tikzexternal@typeset@picture@on@failure + % error recovery: something did not work! Try to load it + % anyway. Perhaps it was just that shell-escape wasn't + % enabled. + \begingroup + \toks0={% + \tikzexternaldisable + }% + % FIXME : THIS WILL FAIL IF THERE IS '##' INSIDE OF '#1'! + % for example something like /.style={#1} in the picture environment *will* fail. + \toks1={% + \tikzpicture + #1% + }% + \toks2={% + \tikzexternal@TEXDIALECT@endpicture + \tikzexternalenable + }% + \xdef\tikzexternal@externalizefig@systemcall@next{% + \the\toks0 + % try reading them again as if they were in the input file. + \noexpand\scantokens{\the\toks1 }% + \the\toks2 + }% + \endgroup + \else + % Ah -- this picture failed, but the failure has already + % been handled somehow. Do not typeset it again! + % + % A use-case is that the picture has been rescheduled for + % \end{document}. + \gdef\tikzexternal@externalizefig@systemcall@next{\tikzexternal@closeenvironments}% + \fi + \else + % ok, take the image! + \gdef\tikzexternal@systemcall@reschedule@to@end@document{0}% + \expandafter\pgfincludeexternalgraphics\expandafter{\tikzexternal@curfilename}% + \if1\tikzexternal@systemcall@reschedule@to@end@document + \pgfutil@IfUndefined{AtVeryEndDocument}{% + }{% + \pgf@typeout{===== The previous system call resulted in undefined references inside of the output file. Rescheduling it for \string\end{document}. ========}% + \expandafter\tikzexternal@externalizefig@systemcall@reschedule\expandafter{\tikzexternal@cursyscall}% + }% + \fi + \gdef\tikzexternal@externalizefig@systemcall@next{\tikzexternal@closeenvironments}% + \fi + \tikzexternal@externalizefig@systemcall@next +}% + +\def\tikzexternal@externalizefig@systemcall@call#1{% + \iftikzexternal@verboseio + \pgf@typeout{===== 'mode=convert with system call': Invoking '#1' ========}% + \fi + \pgfutil@shellescape{#1}% +}% + +% Sets \iftikzexternal@file@isuptodate to false if one of the "force +% remake" things is active. +\def\tikzexternal@checkforceremake{% + \iftikzexternal@force@remake + \global\tikzexternal@file@isuptodatefalse + \else + \iftikzexternalremakenext + \global\tikzexternal@file@isuptodatefalse + \global\tikzexternalremakenextfalse + \fi + \fi +} + +\pgfutil@IfUndefined{pdfmdfivesum}{% +}{% + % predefine to this value. This does only make sense for pdftex. + % note that the latex library for 'external' loads \usepackage{pdftexcmds} which \let's this to \pdf@mdfivesum: + \let\tikzexternal@mdfivesum=\pdfmdfivesum +}% + +\long\def\tikzexternal@computemdfivesum#1{% + \t@tikzexternal@tmpb={#1}% + \edef\tikzexternal@temp{\the\t@tikzexternal@tmpb}% + % \meaning results in a string of catcode 12 - which is expandable. + \edef\pgfretval{\tikzexternal@mdfivesum{\meaning\tikzexternal@temp}}% +} +\long\def\tikzexternal@computemdfivesum@diff@fallback#1{% + \t@tikzexternal@tmpb={#1}% + \edef\tikzexternal@temp{\the\t@tikzexternal@tmpb}% + % \meaning results in a string of catcode 12 - which is expandable. + \edef\pgfretval{\meaning\tikzexternal@temp}% +} + +% Will be set dynamically, depending on 'up to date check'. +% +% It expands to code such that \tikzexternallastkey contains the +% serialized version of '#1'. +% +% It is used as argument for \write{..} +% +% #1 the hash key to serialize. +% \def\tikzexternal@hashfct@serialize +\long\def\tikzexternal@hashfct@serialize@std#1{% + \noexpand\def\noexpand\tikzexternallastkey{#1}% +}% + +% serializes using temporary token registers. Necessary if #1 contains +% executable code. +\long\def\tikzexternal@hashfct@serialize@tok#1{% + \noexpand\begingroup + % in order to allow '#' inside of the body, we have to use token registers: + \noexpand\toks0={#1}% + \noexpand\xdef\noexpand\tikzexternallastkey{\noexpand\the\noexpand\toks0 }% + \noexpand\endgroup +}% + +\def\tikzexternal@check@uptodate@ext{.md5} + +\def\tikzexternal@check@uptodate@mode@warn@fallback{% + \message{Package tikz Warning: The key 'up to date check=md5' is impossible, there is no macro to compute MD5. Falling back to 'up to date check=diff'.}% + % + % warn only once: + \global\let\tikzexternal@check@uptodate@mode@warn@fallback=\relax +}% + +% assigns the boolean \iftikzexternal@file@isuptodate +\long\def\tikzexternal@check@uptodate@mode#1{% + \if1\tikzexternal@uptodate@mode + % up to date check=md5: + % check if we CAN compute MD5 sums: + \pgfutil@IfUndefined{tikzexternal@mdfivesum}{% + % we cannot compute md5 sums - fallback to diff. + \tikzexternal@check@uptodate@mode@warn@fallback + \def\tikzexternal@uptodate@mode{2}% + }{}% + \fi + % + \ifcase\tikzexternal@uptodate@mode + % up to date check=simple + % nothing to do -- file existence is checked anyway. + \let\tikzexternal@hashfct=\pgfutil@empty + \let\tikzexternal@hashfct@serialize=\pgfutil@empty + \or + % up to date check=md5 + \let\tikzexternal@hashfct=\tikzexternal@computemdfivesum + \let\tikzexternal@hashfct@serialize=\tikzexternal@hashfct@serialize@std + \or + \let\tikzexternal@hashfct=\tikzexternal@computemdfivesum@diff@fallback + \let\tikzexternal@hashfct@serialize=\tikzexternal@hashfct@serialize@tok + \fi + \ifx\tikzexternal@hashfct\pgfutil@empty + \else + \tikzpicturedependsonfile{\tikzexternal@curfilename\tikzexternal@check@uptodate@ext}% + \tikzexternal@hashfct{#1}% + \let\tikzexternal@lastkey@new=\pgfretval + \begingroup + % no '@' token in this macro: avoid messing up the catcodes in input files: + \global\let\tikzexternallastkey=\pgfutil@empty + \openin\r@pgf@reada=\tikzexternal@curfilename\tikzexternal@check@uptodate@ext\relax % + \ifeof\r@pgf@reada + \else + % read first line... + \endlinechar=-1 % older versions did not have a '%' at the end-of-line. Avoid spurious spaces. + \read\r@pgf@reada to\pgf@tempa + % ... and execute it. + \pgf@tempa + % it should contain a definition of \tikzexternallastkey. + \fi + \closein\r@pgf@reada + % + \let\tikzexternal@lastkey=\tikzexternallastkey + \pgfmath@smuggleone\tikzexternal@lastkey + \endgroup + % normalize catcodes. Unfortunately, they cannot be expected to be the same. + % \meaning will use catcode 12 for each token: + \edef\tikzexternal@lastkey@normalized{\meaning\tikzexternal@lastkey}% + \edef\tikzexternal@lastkey@new@normalized{\meaning\tikzexternal@lastkey@new}% + \iftikzexternal@verboseuptodate + \pgf@typeout{Up-to-date check of \tikzexternal@curfilename: new \tikzexternal@lastkey@new@normalized; old \tikzexternal@lastkey@normalized.^^J}% + \fi + \ifx\tikzexternal@lastkey@normalized\tikzexternal@lastkey@new@normalized + \tikzexternal@file@isuptodatetrue + \else + \tikzexternal@file@isuptodatefalse + \immediate\openout\w@pgf@writea=\tikzexternal@curfilename\tikzexternal@check@uptodate@ext\relax% + \immediate\write\w@pgf@writea{\tikzexternal@hashfct@serialize{\tikzexternal@lastkey@new}\tikzexternal@PERCENTchar}% + \immediate\closeout\w@pgf@writea + \fi + \fi +} + +% Checks whether the current picture needs to be externalized. +% +% This is the case if +% a) there is no external image yet, +% b) the picture has been invalidated manually. +% +% It returns \iftikzexternal@file@isuptodate accordingly. +% #1: the picture-content +\long\def\tikzexternal@externalizefig@systemcall@uptodatecheck#1{% + \tikzexternal@check@uptodate@mode{#1}% + \tikzexternal@checkforceremake + \iftikzexternal@file@isuptodate + % check if there is already a file. + % In that case, use it. If that is not the case, generate it and include it afterwards. + \gdef\pgf@filename{}% + \xdef\pgf@tempa{\noexpand\pgf@findfile\pgfsys@imagesuffixlist:+{\tikzexternal@curfilename}}% + \pgf@tempa + \ifx\pgf@filename\pgfutil@empty% + \global\tikzexternal@file@isuptodatefalse + \fi + \fi +}% + +% \pgf@filename will be empty if the assertion failed. +\def\tikzexternal@externalizefig@systemcall@assertsuccess#1{% + % check if there is a file now and raise an error message if not. + \gdef\pgf@filename{}% + \xdef\pgf@tempa{\noexpand\pgf@findfile\pgfsys@imagesuffixlist:+{\tikzexternal@curfilename}}% + \pgf@tempa + \ifx\pgf@filename\pgfutil@empty% + \tikzexternal@externalizefig@systemcall@handleexception{#1}% + \fi +}% +\def\tikzexternal@externalizefig@systemcall@handleexception@msg#1{% + \tikzerror{Sorry, the system call '#1' did NOT result in a usable output file '\tikzexternal@curfilename' (expected one of \pgfsys@imagesuffixlist). Please verify that you have enabled system calls. For pdflatex, this is 'pdflatex -shell-escape'. Sometimes it is also named 'write 18' or something like that. Or maybe the command simply failed? Error messages can be found in '\tikzexternal@curfilename.log'. If you continue now, I'll try to typeset the picture}{}% +} +\def\tikzexternal@externalizefig@systemcall@handleexception@retry@later#1{% + \gdef\tikzexternal@systemcall@reschedule@to@end@document{0}% + \expandafter\pgfexternalreaddpth\expandafter{\tikzexternal@curfilename}% + \if1\tikzexternal@systemcall@reschedule@to@end@document + \pgfutil@IfUndefined{AtVeryEndDocument}{% + \tikzexternal@externalizefig@systemcall@handleexception@msg{#1}% + }{% + \pgf@typeout{===== The last system call resulted in an EMPTY output file. Maybe it is part of \string\ref. Rescheduling it for \string\end{document}. ========}% + \gdef\tikzexternal@typeset@picture@on@failure{0}% + \tikzexternal@externalizefig@systemcall@reschedule{#1}% + }% + \else + \tikzexternal@externalizefig@systemcall@handleexception@msg{#1}% + \fi +} + +% reschedules the externalization of the current file to +% \AtVeryEndDocument. +% +% This hook allows to execute code AFTER the main .aux file is +% finished; it will even re-read the main aux file. +\def\tikzexternal@externalizefig@systemcall@reschedule#1{% + \t@tikzexternal@tmpb={% + \global\let\tikzexternal@externalizefig@systemcall@handleexception=\tikzexternal@externalizefig@systemcall@handleexception@msg% + % ... no auxlocks! + \tikzexternal@externalizefig@systemcall@call{#1}% + \tikzexternal@externalizefig@systemcall@assertsuccess{#1}% + }% + \xdef\pgfutil@tempa{% + \noexpand\def\noexpand\tikzexternal@curfilename{\tikzexternal@curfilename}% + \the\t@tikzexternal@tmpb + }% + \expandafter\AtVeryEndDocument\expandafter{\pgfutil@tempa}% + \gdef\tikzexternal@has@rescheduled@something{1}% +}% +\let\tikzexternal@externalizefig@systemcall@handleexception=\tikzexternal@externalizefig@systemcall@handleexception@retry@later% + +\def\tikzexternal@has@rescheduled@something{0}% +\pgfutil@IfUndefined{AtVeryEndDocument}{}{% + \AtVeryEndDocument{% + \if1\tikzexternal@has@rescheduled@something + \pgf@typeout{===== tikzexternal: \string\end{document} reached. Working on rescheduled images to resolve references... ========}% + \fi + }% +} + +% Overwrite error message of pgf. +% This happens if the generated image was empty, i.e. if there was no \shipout. +\def\pgfexternal@error@no@shipout{% + \begingroup + \begingroup + % overwrite .dpth file in order to flag the file as "need to be scheduled + % for \AtVeryEndDocument" : + \immediate\openout\pgf@plotwrite=\pgfactualjobname.dpth + \let\w@pgfexternal@auxout=\pgf@plotwrite + \pgfexternalstorecommand@isexporting{\gdef\noexpand\tikzexternal@systemcall@reschedule@to@end@document{1}}% + \immediate\closeout\pgf@plotwrite + \endgroup + \tikzexternal@assemble@systemcall{\pgfactualjobname}{\pgf@tempa}% + \toks0=\expandafter{\pgf@tempa}% + \tikzerror{Sorry, image externalization failed: the resulting image was EMPTY. I tried to externalize '\pgfactualjobname', but it seems there is no such image in the document!? + \if\tikzexternal@opmode4 ^^J +\space\space You are currently using 'mode=convert with system call'. This problem can happen if the image (or one of the images preceding it) was declared inside of a \string\label{} (i.e. in the .aux file): 'convert with system call' has no access to the main aux file.^^J +\space\space Possible solutions in this case:^^J +\space\space (a) Try using 'mode=list and make',^^J +\space\space (b) Issue the externalization command '\the\toks0' *manually* (also check the preceding externalized images, perhaps the file name sequence is not correct).^^J +\space\space Repeat: the resulting image was EMPTY, your attention is required +\else + \if\tikzexternal@opmode5 ^^J +\space\space You are currently using 'mode=list and make'. Possible solutions:^^J +\space\space (a) Try to delete `\tikzexternal@realjob.makefile'. Perhaps it is not up-to-date.^^J +\space\space (b) Perhaps pictures are declared inside of \string\label{} and the .aux file is not up-to-date. Re-run latex, perhaps re-generate the graphics as well.^^J +\space\space Repeat: the resulting image was EMPTY, your attention is required + \fi +\fi}% + \endgroup +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrary3d.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrary3d.code.tex new file mode 100644 index 0000000000..f39eaee866 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrary3d.code.tex @@ -0,0 +1,108 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrary3d.code.tex} + + + +% New coordinate systems: + +\tikzdeclarecoordinatesystem{xyz cylindrical} +{% + \pgfset{/tikz/cs/.cd,angle=0,radius=0,z=0,#1}% + \pgfpointcylindrical{\tikz@cs@angle}{\tikz@cs@xradius}{\tikz@cs@z}% +}% + +\tikzdeclarecoordinatesystem{xyz spherical} +{% + \pgfset{/tikz/cs/.cd,angle=0,radius=0,latitude=0,longitude=0,#1}% + \pgfpointspherical{\tikz@cs@angle}{\tikz@cs@latitude}{\tikz@cs@xradius}% +}% + +\pgfset{/tikz/cs/longitude/.store in=\tikz@cs@angle}% +\pgfset{/tikz/cs/latitude/.store in=\tikz@cs@latitude}% + + +% Options for transforming into a plane: + +\tikzoption{plane origin}{\def\tikz@plane@origin{\tikz@scan@one@point\pgfutil@firstofone#1}}% +\tikzoption{plane x}{\def\tikz@plane@x{\tikz@scan@one@point\pgfutil@firstofone#1}}% +\tikzoption{plane y}{\def\tikz@plane@y{\tikz@scan@one@point\pgfutil@firstofone#1}}% + +\let\tikz@plane@origin=\pgfpointorigin +\def\tikz@plane@x{\pgfpointxy{1}{0}}% +\def\tikz@plane@y{\pgfpointxy{0}{1}}% + +\tikzoption{canvas is plane}[]{ + \tikz@canvas@is@plane +}% +\tikzoption{canvas is xy plane at z}[]{% + \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}% + \def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}% + \def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}% + \tikz@canvas@is@plane +}% +\tikzoption{canvas is yx plane at z}[]{% + \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}% + \def\tikz@plane@x{\pgfpointxyz{0}{1}{#1}}% + \def\tikz@plane@y{\pgfpointxyz{1}{0}{#1}}% + \tikz@canvas@is@plane +}% +\tikzoption{canvas is xz plane at y}[]{% + \def\tikz@plane@origin{\pgfpointxyz{0}{#1}{0}}% + \def\tikz@plane@x{\pgfpointxyz{1}{#1}{0}}% + \def\tikz@plane@y{\pgfpointxyz{0}{#1}{1}}% + \tikz@canvas@is@plane +}% +\tikzoption{canvas is zx plane at y}[]{% + \def\tikz@plane@origin{\pgfpointxyz{0}{#1}{0}}% + \def\tikz@plane@x{\pgfpointxyz{0}{#1}{1}}% + \def\tikz@plane@y{\pgfpointxyz{1}{#1}{0}}% + \tikz@canvas@is@plane +}% +\tikzoption{canvas is yz plane at x}[]{% + \def\tikz@plane@origin{\pgfpointxyz{#1}{0}{0}}% + \def\tikz@plane@x{\pgfpointxyz{#1}{1}{0}}% + \def\tikz@plane@y{\pgfpointxyz{#1}{0}{1}}% + \tikz@canvas@is@plane +}% +\tikzoption{canvas is zy plane at x}[]{% + \def\tikz@plane@origin{\pgfpointxyz{#1}{0}{0}}% + \def\tikz@plane@x{\pgfpointxyz{#1}{0}{1}}% + \def\tikz@plane@y{\pgfpointxyz{#1}{1}{0}}% + \tikz@canvas@is@plane +}% + + + +% Transformation code + +\def\tikz@canvas@is@plane{ + \pgf@process{\tikz@plane@x}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@plane@y}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\tikz@plane@origin}% + \edef\pgf@marshal{\noexpand\tikz@addtransform{% + \noexpand\pgftransformtriangle + {\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}} + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}} + \noexpand\pgftransformscale{0.035146}% + \noexpand\pgfsetxvec{\noexpand\pgfpoint{1cm}{0cm}}% + \noexpand\pgfsetyvec{\noexpand\pgfpoint{0cm}{1cm}}% + \noexpand\pgfsetzvec{\noexpand\pgfpoint{0cm}{0cm}}% + }}% + \pgf@marshal% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryangles.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryangles.code.tex new file mode 100644 index 0000000000..2d6abbd2e9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryangles.code.tex @@ -0,0 +1,100 @@ +% Copyright 2019 by Till Tantau +% Copyright 2019 by Kroum Tzanev +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryangles.code.tex} + + +\tikzset{ + pics/angle/.style = { + setup code = \tikz@lib@angle@parse#1\pgf@stop, + code = {}, + background code = \tikz@lib@angle@background#1\pgf@stop, + foreground code = \tikz@lib@angle@foreground#1\pgf@stop, + }, + pics/right angle/.style = { + setup code = \tikz@lib@angle@parse#1\pgf@stop, + code = {}, + background code = \tikz@lib@rightangle@background#1\pgf@stop, + foreground code = \tikz@lib@rightangle@foreground#1\pgf@stop, + }, + pics/angle/.default=A--B--C, + angle eccentricity/.initial=.6, + angle radius/.initial=5mm, +}% + +\def\tikz@lib@angle@background#1--#2--#3\pgf@stop{% + \path [name prefix ..] [pic actions, draw=none] (#2.center) + -- ++(\tikz@start@angle@temp:\tikz@lib@angle@rad pt) + arc [start angle=\tikz@start@angle@temp, end + angle=\tikz@end@angle@temp, radius=\tikz@lib@angle@rad pt] -- cycle; +}% + +\def\tikz@lib@angle@foreground#1--#2--#3\pgf@stop{% + \path [name prefix ..] [pic actions, fill=none, shade=none] + ([shift={(\tikz@start@angle@temp:\tikz@lib@angle@rad pt)}]#2.center) + arc [start angle=\tikz@start@angle@temp, end + angle=\tikz@end@angle@temp, radius=\tikz@lib@angle@rad pt]; + \ifx\tikzpictext\relax\else% + \def\pgf@temp{\node()[name prefix + ..,at={([shift={({.5*\tikz@start@angle@temp+.5*\tikz@end@angle@temp}:\pgfkeysvalueof{/tikz/angle + eccentricity}*\tikz@lib@angle@rad pt)}]#2.center)}]} + \expandafter\pgf@temp\expandafter[\tikzpictextoptions]{\tikzpictext};% + \fi +}% + +\def\tikz@lib@rightangle@background#1--#2--#3\pgf@stop{% + \path [name prefix ..] [pic actions, draw=none] (#2.center) + -- ++(\tikz@start@angle@temp:\tikz@lib@angle@rad pt) + -- ++(\tikz@end@angle@temp:\tikz@lib@angle@rad pt) + -- ++(\tikz@start@angle@temp:-\tikz@lib@angle@rad pt) + -- cycle; +}% + +\def\tikz@lib@rightangle@foreground#1--#2--#3\pgf@stop{% + \path [name prefix ..] [pic actions, fill=none, shade=none] + ([shift={(\tikz@start@angle@temp:\tikz@lib@angle@rad pt)}]#2.center) + -- ++(\tikz@end@angle@temp:\tikz@lib@angle@rad pt) + -- ++(\tikz@start@angle@temp:-\tikz@lib@angle@rad pt); + \ifx\tikzpictext\relax\else% + \def\pgf@temp{\node()[name prefix + ..,at={([shift={({.5*\tikz@start@angle@temp+.5*\tikz@end@angle@temp}:\pgfkeysvalueof{/tikz/angle + eccentricity}*1.4142136*\tikz@lib@angle@rad pt)}]#2.center)}]} + \expandafter\pgf@temp\expandafter[\tikzpictextoptions]{\tikzpictext};% + \fi +}% + +\def\tikz@lib@angle@parse#1--#2--#3\pgf@stop{% + % Compute radius: + \pgfmathsetmacro\tikz@lib@angle@rad{\pgfkeysvalueof{/tikz/angle radius}} + \ifdim\tikz@lib@angle@rad pt>0pt\else\def\tikz@lib@angle@rad{12}\fi% + % Compute first coordinate: + \pgf@process{\pgfpointanchor{#2}{center}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointanchor{#1}{center}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointanchor{#3}{center}}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by-\pgf@xa% + \advance\pgf@yc by-\pgf@ya% + \pgfmathsetmacro{\tikz@start@angle@temp}{atan2(\the\pgf@yb,\the\pgf@xb)} + \pgfmathsetmacro{\tikz@end@angle@temp}{atan2(\the\pgf@yc,\the\pgf@xc)} + \ifdim\tikz@end@angle@temp pt<\tikz@start@angle@temp pt% + \pgfmathsetmacro{\tikz@start@angle@temp}{\tikz@start@angle@temp-360}% + \fi% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryanimations.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryanimations.code.tex new file mode 100644 index 0000000000..7b3fc12bf1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryanimations.code.tex @@ -0,0 +1,904 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryanimations.code.tex} + +\usepgfmodule{animations}% + + + +% Scope syntax extension: + +\def\tikz@collect@scope@anims#1{% + \let\tikz@scope@anims\pgfutil@empty% + \let\tikz@collect@command#1% + \tikz@collect@scope@anims@parse% +}% +\def\tikz@collect@scope@anims@parse{% + \pgfutil@ifnextchar[{\tikz@collect@scope@anims@opt}{% + \pgfutil@ifnextchar:{\tikz@collect@scope@anims@go}{% + \tikz@collect@scope@anims@done}}%] +}% +\def\tikz@collect@scope@anims@done{% + \expandafter\tikz@collect@command\expandafter[\tikz@scope@anims]% +}% +\def\tikz@collect@scope@anims@opt[{%] + \expandafter\tikz@collect@command\expandafter[\tikz@scope@anims%] +}% +\def\tikz@collect@scope@anims@go:#1=#2{% + \expandafter\def\expandafter\tikz@scope@anims\expandafter{\tikz@scope@anims animate={myself:={:{#1}={#2}}},}% + \tikz@collect@scope@anims@parse% +}% + + + + +% +% The main keys: +% + +\def\tikzanimateset{\pgfqkeys{/tikz/animate}}% +\tikzanimateset{ + .code={ + \pgfkeys{/handlers/first char syntax=true} + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\tikz@animation@value}% + \def\tikz@anim@t{0}% + \def\tikz@anim@t@base{0}% + \def\tikz@anim@t@current{0}% + \tikzanimateset{#1} + }, + scope/.code=\tikz@anim@scope{#1}{}{}, + sync/.code=\tikz@anim@sync@scope{#1}{}{}, + entry/.code=\tikz@anim@make@entry, + object/.code=\tikz@anim@set@object{#1}, + attribute/.code=\tikz@anim@set@attr{#1}, + id/.code=\tikz@anim@set@id{#1}, + time/.code=\tikz@anim@set@time{#1}, + value/.code=\tikz@anim@add{\tikz@anim@value{#1}},% + remember/.code=\pgfmathadd@{\tikz@anim@t}{\tikz@anim@t@base}\global\let#1\pgfmathresult, + resume/.code=\tikz@anim@resume{#1}, + fork/.code={\tikz@anim@parse@time{#1}\pgfmathadd@\tikz@anim@t\tikz@anim@t@base\let\tikz@anim@t@base\pgfmathresult\def\tikz@anim@t{0}}, + fork/.default = 0later, + base/.style={scope={/utils/exec=\let\tikz@animation@time\tikz@anim@base@text,#1,entry}}, +}% + +\tikzset{ + make snapshot of/.code=\edef\tikz@temp{#1}\ifx\tikz@temp\pgfutil@empty\else\pgfsnapshot{#1}\fi, + make snapshot after/.code=\edef\tikz@temp{#1}\ifx\tikz@temp\pgfutil@empty\else\pgfsnapshotafter{#1}\fi, + make snapshot if necessary/.code=\ifpgfsysanimationsupported\else\pgfsnapshot{#1}\fi, + make snapshot if necessary/.default=0s, +}% + +\def\tikz@anim@scope#1#2#3{% + {#2\tikzanimateset{#1}#3}% +}% +\def\tikz@anim@sync@scope#1#2#3{% + {% + #2% + \tikzanimateset{#1}% + #3% + \pgfmathadd@{\tikz@anim@t}{\tikz@anim@t@base}% + \expandafter% + }\expandafter\pgfmathsubtract@\expandafter{\pgfmathresult}{\tikz@anim@t@base}% + \tikz@anim@set@time{\pgfmathresult}% +}% + +\def\tikz@anim@set@time#1{% + \tikz@anim@parse@time{#1}% + \let\tikz@anim@t@current\tikz@anim@t% + \pgfmathadd@\tikz@anim@t\tikz@anim@t@base% + \let\tikz@animation@time\pgfmathresult% +}% + +\def\tikz@anim@value#1{% + \def\tikz@anim@result{#1} + \ifx\tikz@anim@result\pgf@special@current@text% + \else% + \ifx\tikz@animation@parser\relax% + \else% + \tikz@animation@parser{#1}% + \fi% + \fi% +}% + + +\def\tikz@anim@resume#1{% + \pgfparsetime{#1}% + \pgfmathsubtract@{\pgftimeresult}{\tikz@anim@t@base}% + \tikz@anim@set@time{\pgfmathresult}% +}% + + +% The object--attribute entries are of the following forms: +% +% objects:attributes +% objects:attributes_id +% + +\def\tikz@animation@syntax@check#1#2{% + \def\tikz@animation@rest{#1}% + \expandafter\pgfutil@in@\expandafter:\expandafter{\tikz@key}% + \ifpgfutil@in@% + \expandafter\tikz@anim@parse@colon\tikz@key\pgf@stop% + \else% + #2% + \fi% +}% + +\def\tikz@anim@parse@colon#1:#2\pgf@stop{% + \expandafter\tikz@anim@sync@scope\expandafter{\tikz@animation@rest}{% + \tikz@anim@set@object{#1}% + \pgfutil@in@_{#2}% + \ifpgfutil@in@% + \tikz@anim@parse@under#2\pgf@stop% + \else% + \tikz@anim@parse@under#2_\pgf@stop% + \fi% + }{\tikz@anim@make@entry}% +}% + +\def\tikz@anim@parse@under#1_#2\pgf@stop{% + \tikz@anim@set@attr{#1}% + \tikz@anim@set@id{#2}% +}% + +\def\tikz@anim@set@attr#1{% + \pgfkeys@spdef\tikz@anim@a{#1}% + \ifx\tikz@anim@a\pgfutil@empty% + \else% + \let\tikz@anim@tl@attributes\tikz@anim@a% + \fi% +}% + +\def\tikz@anim@set@id#1{% + \pgfkeys@spdef\tikz@anim@a{#1}% + \ifx\tikz@anim@a\pgfutil@empty% + \else% + \let\tikz@anim@tl@id\tikz@anim@a% + \fi% +}% + +\def\tikz@anim@set@object#1{% + \pgfkeys@spdef\tikz@anim@a{#1}% + \ifx\tikz@anim@a\pgfutil@empty% + \else% + \let\tikz@anim@tl@objects\tikz@anim@a% + \fi% +}% + + +% +% Parsing of values +% + +\def\tikz@animation@value#1{% + \tikz@animation@value@parser#1\pgf@stop% +}% + +\def\tikz@animation@value@parser"#1"{% + \def\tikz@animation@value@head{#1}% + \pgfutil@ifnextchar\pgf@stop{\tikz@animation@value@rest=}{% + \pgfutil@ifnextchar b\tikz@animation@value@rest@base\tikz@animation@value@rest% + }% +}% +\def\tikz@animation@value@rest=#1\pgf@stop{% + \tikz@anim@sync@scope{#1}{\expandafter\tikz@anim@add\expandafter{\expandafter\tikz@anim@value\expandafter{\tikz@animation@value@head}}}{\tikz@anim@make@entry}% +}% + +\def\tikz@animation@value@rest@base base{% + \tikz@anim@sync@scope{}{\let\tikz@animation@time\tikz@anim@base@text\expandafter\tikz@anim@add\expandafter{\expandafter\tikz@anim@value\expandafter{\tikz@animation@value@head}}}{\tikz@anim@make@entry}% + \pgfutil@ifnextchar\pgf@stop{\tikz@animation@value@rest=}{\tikz@animation@value@rest}% +}% + + + + +% +% The parsers +% + +\def\tikz@anim@simple@parse#1{} % nothing to do, \def\tikz@anim@result{#1} is already done + +\def\tikz@anim@slant@parse#1{\pgfmathsetmacro\tikz@anim@result{atan(#1)}}% + +\def\tikz@anim@dashpattern@parse#1{% + \pgfmathsetmacro\tikz@anim@dash@phase{\tikz@dashphase}% + \def\tikz@dashpattern{}% + \expandafter\tikz@scandashon\pgfutil@gobble#1o\@nil% + \edef\tikz@anim@result{{\tikz@dashpattern}{\tikz@anim@dash@phase pt}}% +}% +\def\tikz@anim@dashoffset@parse#1{% + \pgfmathparse{#1}% + \edef\tikz@anim@result{{\tikz@dashpattern}{\pgfmathresult pt}}% +}% +\def\tikz@anim@dash@parse#1{% + \tikz@anim@dash@parse@#1\pgf@stop% +}% +\def\tikz@anim@dash@parse@#1phase#2\pgf@stop{% + \pgfmathsetmacro\tikz@anim@dash@phase{#2}% + \def\tikz@dashpattern{}% + \expandafter\tikz@scandashon\pgfutil@gobble#1o\@nil% + \edef\tikz@anim@result{{\tikz@dashpattern}{\tikz@anim@dash@phase pt}}% +}% + +\def\tikz@anim@xshift@parse#1{\pgfmathparse{#1}\edef\tikz@anim@result{\noexpand\pgfqpoint{\pgfmathresult pt}{0pt}}}% +\def\tikz@anim@yshift@parse#1{\pgfmathparse{#1}\edef\tikz@anim@result{\noexpand\pgfqpoint{0pt}{\pgfmathresult pt}}}% + +\def\tikz@anim@xscale@parse#1{\pgfmathparse{#1}\edef\tikz@anim@result{\pgfmathresult,1}}% +\def\tikz@anim@yscale@parse#1{\pgfmathparse{#1}\edef\tikz@anim@result{1,\pgfmathresult}}% + +\def\tikz@anim@shift@parse#1{\tikz@scan@one@point\tikz@anim@do@shift#1}% +\def\tikz@anim@do@shift#1{\def\tikz@anim@result{#1}}% + +\def\tikz@anim@position@parse#1{% + \begingroup% + \let\tikz@transform=\relax% + \pgf@xc-\pgf@pt@x% + \pgf@yc-\pgf@pt@y% + \pgfsettransform\tikz@anim@saved@transform% + \tikz@scan@one@point\tikz@anim@do@position#1}% +\def\tikz@anim@do@position#1{% + \pgf@process{\pgfpointtransformed{#1}}% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \xdef\tikz@anim@temp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \endgroup% + \let\tikz@anim@result\tikz@anim@temp% +}% + +\def\tikz@anim@view@parse#1{\tikz@anim@view@parse@#1\pgf@stop}% +\def\tikz@anim@view@parse@{% + \pgfutil@ifnextchar({\tikz@scan@one@point\tikz@anim@view@parse@a}{\tikz@anim@view@node}% +}% +\def\tikz@anim@view@parse@a#1{% + \def\tikz@anim@result{{#1}}% + \pgfutil@ifnextchar r{\tikz@anim@view@parsed@rec}{\tikz@scan@one@point\tikz@anim@view@parse@b}% +}% +\def\tikz@anim@view@parsed@rec rectangle{\tikz@scan@one@point\tikz@anim@view@parse@b}% +\def\tikz@anim@view@parse@b#1{% + \expandafter\def\expandafter\tikz@anim@result\expandafter{\tikz@anim@result{#1}}% + \pgfutil@ifnextchar\pgf@stop\pgfutil@gobble{\tikzerror{Wrong view syntax}}% +}% +\def\tikz@anim@view@node#1\pgf@stop{% + \expandafter\ifx\csname pgf@sh@ns@#1\endcsname\relax% + \tikzerror{Undefined node '#1'}% + \else% + % Compute a bounding box for the node: + {% + \pgf@process{\pgfpointanchor{#1}{west}}% + \pgf@xa\pgf@x \pgf@ya\pgf@y + \pgf@xb\pgf@x \pgf@yb\pgf@y + \pgf@process{\pgfpointanchor{#1}{north}}% + \ifdim\pgf@x<\pgf@xa \pgf@xa=\pgf@x\fi% + \ifdim\pgf@x>\pgf@xb \pgf@xb=\pgf@x\fi% + \ifdim\pgf@y<\pgf@ya \pgf@ya=\pgf@y\fi% + \ifdim\pgf@y>\pgf@yb \pgf@yb=\pgf@y\fi% + \pgf@process{\pgfpointanchor{#1}{south}}% + \ifdim\pgf@x<\pgf@xa \pgf@xa=\pgf@x\fi% + \ifdim\pgf@x>\pgf@xb \pgf@xb=\pgf@x\fi% + \ifdim\pgf@y<\pgf@ya \pgf@ya=\pgf@y\fi% + \ifdim\pgf@y>\pgf@yb \pgf@yb=\pgf@y\fi% + \pgf@process{\pgfpointanchor{#1}{east}}% + \ifdim\pgf@x<\pgf@xa \pgf@xa=\pgf@x\fi% + \ifdim\pgf@x>\pgf@xb \pgf@xb=\pgf@x\fi% + \ifdim\pgf@y<\pgf@ya \pgf@ya=\pgf@y\fi% + \ifdim\pgf@y>\pgf@yb \pgf@yb=\pgf@y\fi% + \xdef\tikz@anim@result{{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}} + }% + \fi% +}% + +\def\tikz@anim@path@parse#1{% + {% + \setbox0=\hbox{{% protext against side effects + \pgfinterruptpath% + \expandafter\tikz@scan@next@command#1\pgf@stop% + \pgfsyssoftpath@getcurrentpath\tikz@anim@result% + \pgfprocessround{\tikz@anim@result}{\tikz@anim@result}% + \global\let\tikz@anim@result\tikz@anim@result% + \endpgfinterruptpath% + }}% + }% +}% + +% The special along parser + + +\def\tikz@anim@along#1#2{% + % Parse the path... + {% + \setbox0=\hbox{{% protect against side effects + \pgfinterruptpath% + \pgf@relevantforpicturesizefalse% + \iftikz@anim@is@position% + \let\tikz@transform=\relax% + \pgf@x-\pgf@pt@x% + \pgf@y-\pgf@pt@y% + \edef\tikz@anim@along@shift{\pgf@xc\the\pgf@x\pgf@yc\the\pgf@y}% + \pgfsettransformentries#1% + \else% + \pgftransformreset% + \fi + \tikz@scan@next@command#2\pgf@stop% + \pgfsyssoftpath@getcurrentpath\tikz@anim@parsed@path% + \pgfprocessround{\tikz@anim@parsed@path}{\tikz@anim@parsed@path}% + \iftikz@anim@is@position% + \tikz@anim@shift@path% + \global\let\tikz@anim@parsed@path\tikz@anim@patched@path% + \else% + \global\let\tikz@anim@parsed@path\tikz@anim@parsed@path% + \fi% + \endpgfinterruptpath% + }}% + }% + \pgfanimationset{along softpath/.expand once=\tikz@anim@parsed@path}% +}% + +\def\tikz@anim@shift@path{% + \let\tikz@anim@patched@path\pgfutil@empty% + \tikz@anim@along@shift% + \expandafter\tikz@anim@shift@path@\tikz@anim@parsed@path\pgf@stop% +}% +\def\tikz@anim@shift@path@{% + \pgfutil@ifnextchar\pgf@stop\pgfutil@gobble{% + \pgfutil@ifnextchar\bgroup\tikz@anim@shift@path@sub\tikz@anim@shift@path@copy}% +}% +\def\tikz@anim@shift@path@copy#1{% + \expandafter\def\expandafter\tikz@anim@patched@path\expandafter{\tikz@anim@patched@path#1}% + \tikz@anim@shift@path@% +}% +\def\tikz@anim@shift@path@sub#1#2{% + \pgf@x#1% + \pgf@y#2% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \edef\tikz@temp{{\the\pgf@x}{\the\pgf@y}}% + \expandafter\tikz@anim@shift@path@copy\expandafter{\tikz@temp}% +}% + + + +\def\tikz@anim@parse@origin#1{% + \tikz@scan@one@point\tikz@anim@parse@origin@#1\relax% +}% +\def\tikz@anim@parse@origin@#1{\tikz@anim@add{\pgfanimationset{origin={#1}}}}% + + +% Internals + +\def\tikz@anim@tl@objects{}% +\def\tikz@anim@tl@attributes{}% +\def\tikz@anim@tl@id{default}% + +\let\tikz@anim@tl@exec@options\pgfutil@empty +\let\tikz@anim@tl@early@options\pgfutil@empty + +\def\tikz@anim@add@early#1{\expandafter\def\expandafter\tikz@anim@tl@early@options\expandafter{\tikz@anim@tl@early@options#1}}% +\def\tikz@anim@add@once@early#1{% + \global\advance\tikz@anim@once@count by1\relax% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\tikz@anim@tl@early@options% + \expandafter\expandafter\expandafter{\expandafter\tikz@anim@tl@early@options\expandafter\tikz@anim@exec@once\expandafter{\the\tikz@anim@once@count}{#1}}% +}% +\def\tikz@anim@add#1{\expandafter\def\expandafter\tikz@anim@tl@exec@options\expandafter{\tikz@anim@tl@exec@options#1}}% +\def\tikz@anim@add@once#1{% + \global\advance\tikz@anim@once@count by1\relax% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\tikz@anim@tl@exec@options% + \expandafter\expandafter\expandafter{\expandafter\tikz@anim@tl@exec@options\expandafter\tikz@anim@exec@once\expandafter{\the\tikz@anim@once@count}{#1}}% +}% +\newcount\tikz@anim@once@count% +\def\tikz@anim@exec@once#1#2{% + \expandafter\ifx\csname tikz@anim@once@#1\endcsname\pgf@stop% + \else% + \expandafter\let\csname tikz@anim@once@#1\endcsname\pgf@stop% + #2% + \fi% +}% + +\newif\iftikz@anim@do@entry + +\def\tikz@anim@make@entry{% + \tikz@anim@do@entrytrue% + \ifx\tikz@anim@tl@objects\pgfutil@empty\tikz@anim@do@entryfalse\fi% + \ifx\tikz@anim@tl@attributes\pgfutil@empty\tikz@anim@do@entryfalse\fi% + \ifx\tikz@anim@tl@exec@options\pgfutil@empty\ifx\tikz@anim@tl@early@options\pgfutil@empty\tikz@anim@do@entryfalse\fi\fi% + \iftikz@anim@do@entry% + \foreach\tikz@anim@tl@object in\tikz@anim@tl@objects{% + \expandafter\tikzanimationattributesset\expandafter{\tikz@anim@tl@attributes}% + }% + \fi% +}% + +\def\tikzanimationattributesset#1{\pgfqkeys{/tikz/animate/attributes}{#1}}% + +\tikzanimationattributesset{ + .unknown/.code={ + \let\tikz@anim@attribute@name\pgfkeyscurrentname + \expandafter\let\expandafter\pgf@temp\csname tikz@anim@def@pgf@attr@\tikz@anim@attribute@name\endcsname% + \ifx\pgf@temp\relax% + \tikzerror{Unknown animation attribute '\tikz@anim@attribute@name'}% + \else% + \expandafter\tikz@timeline@config\expandafter\tikz@anim@tl@object\expandafter\tikz@anim@attribute@name\expandafter\tikz@anim@tl@id\expandafter{\tikz@anim@configs}% + \edef\pgf@marshal{\noexpand\tikz@timeline@entry{\tikz@anim@tl@object}{\tikz@anim@attribute@name}{\tikz@anim@tl@id}}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@marshal\expandafter\expandafter\expandafter{\expandafter\pgf@marshal\expandafter{\tikz@anim@tl@early@options}}% + \expandafter\expandafter\expandafter\pgf@marshal\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter\tikz@anim@entry\expandafter\expandafter\expandafter{\expandafter\tikz@anim@tl@exec@options\expandafter\def\expandafter\tikz@animation@time\expandafter{\tikz@animation@time}}}% + \fi% + } +}% +\let\tikz@anim@configs\pgfutil@empty + +\def\tikz@anim@entry#1{% + % Reset splines and value: + \let\tikz@anim@result\pgfutil@empty% + \pgf@anim@reset@linear% + #1% + \ifx\tikz@anim@result\pgfutil@empty% + \else% + \ifx\tikz@animation@time\pgfutil@empty% + \else% + \ifx\tikz@animation@time\tikz@anim@base@text% + \expandafter\pgf@anim@base\expandafter{\tikz@anim@result}% + \else% + \expandafter\expandafter\expandafter\pgf@anim@entry% + \expandafter\expandafter\expandafter{\expandafter\tikz@animation@time\expandafter}\expandafter{\tikz@anim@result}% + \fi% + \fi% + \fi% +}% +\let\tikz@animation@time\pgfutil@empty% +\def\tikz@anim@base@text{base}% + +\tikzanimateset{ + .unknown/.code={% + \let\tikz@key\pgfkeyscurrentname% + \tikz@animation@syntax@check{#1}{\tikz@anim@options{#1}}% + } +}% + + +\def\tikz@anim@options#1{ + \let\tikz@anim@key\pgfkeyscurrentname% + \pgfqkeys{/tikz/animate/options}{\tikz@anim@key/.try={#1}}% + \ifpgfkeyssuccess% + \else% + \def\tikz@anim@unparsed@value{#1}% + \expandafter\tikz@anim@time@test\tikz@anim@key\pgf@stop% + \fi% +}% + +\tikzanimateset{ + options/.cd, + name/.code=\tikz@anim@add{\pgfanimationset{name={#1}}}, + forever/.code=\tikz@anim@add{\pgfanimationset{freeze at end}}, + freeze/.code=\tikz@anim@add{\pgfanimationset{freeze at end}}, + restart/.code=\tikz@anim@add{\pgfanimationset{restart={#1}}}, + repeats/.code=\tikz@anim@add{\pgfanimationset{repeats={#1}}}, + repeats/.default=, + repeat/.code=\tikz@anim@add{\pgfanimationset{repeats={#1}}}, + repeat/.default=, + begin/.code=\tikz@anim@add@once{\pgfanimationset{begin={#1}}}, + end/.code=\tikz@anim@add@once{\pgfanimationset{end={#1}}}, + begin on/.code=\tikz@anim@event{begin}{#1}, + end on/.code=\tikz@anim@event{begin}{#1}, + begin snapshot/.code=\tikz@anim@add{\pgfanimationset{begin snapshot={#1}}}, + origin/.code=\tikz@anim@parse@origin{#1}, + transform/.code=\tikz@anim@add{\pgfanimationset{transform={\let\tikz@transform\relax\tikzset{#1}}}}, + along/.code=\tikz@anim@handle@along#1\pgf@stop, + entry control/.code=\tikz@anim@add{\pgfanimationset{entry control={#1}}}, + exit control/.code=\tikz@anim@add{\pgfanimationset{exit control={#1}}}, + stay/.code=\tikz@anim@add{\pgfanimationset{stay}}, + jump/.code=\tikz@anim@add{\pgfanimationset{jump}}, + ease/.style={ + entry control={1-(#1)}{1}, + exit control={#1}{0} + }, + ease/.default=0.5, + ease in/.style={ + entry control={1-(#1)}{1}, + }, + ease in/.default=0.5, + ease out/.style={ + exit control={#1}{0}, + }, + ease out/.default=0.5, + arrows/.code=\tikz@anim@add@early{\pgfanimationset{arrows={#1}}}, + shorten >/.code=\tikz@anim@add@early{\pgfanimationset{shorten >={#1}}}, + shorten ,double=none,every accepting by arrow] + -- + ([shift=(\tikz@accepting@angle:\tikz@accepting@distance)]\tikztostart.\tikz@accepting@angle) + node [shape=rectangle,anchor=\tikz@accepting@anchor] {\tikz@accepting@text} + }] + edge () + } +}}}% +\tikzset{every accepting by arrow/.style={}}% +\tikzset{accepting by double/.style= {double,outer sep=.5\pgflinewidth+.3pt}} % .3pt is half double width distance + +\tikzset{initial by arrow/.style= {after node path= +{ + { + [to path= + { + [->,double=none,every initial by arrow] + ([shift=(\tikz@initial@angle:\tikz@initial@distance)]\tikztostart.\tikz@initial@angle) + node [shape=rectangle,anchor=\tikz@initial@anchor] {\tikz@initial@text} + -- (\tikztostart)}] + edge () + } +}}}% +\tikzset{every initial by arrow/.style={}}% + +\tikzset{initial by diamond/.style={shape=diamond}}% + + +\tikzoption{initial text}{\tikzaddafternodepathoption{\def\tikz@initial@text{#1}}}% +\tikzoption{accepting text}{\tikzaddafternodepathoption{\def\tikz@accepting@text{#1}}}% + +\tikzoption{initial where}{\tikzaddafternodepathoption{\csname tikz@initial@compute@#1\endcsname}}% +\tikzoption{accepting where}{\tikzaddafternodepathoption{\csname tikz@accepting@compute@#1\endcsname}}% + +\tikzoption{initial distance}{\tikzaddafternodepathoption{\def\tikz@initial@distance{#1}}}% +\tikzoption{accepting distance}{\tikzaddafternodepathoption{\def\tikz@accepting@distance{#1}}}% + +\def\tikz@initial@text{start}% +\def\tikz@accepting@text{}% + +\def\tikz@initial@distance{3ex}% +\def\tikz@accepting@distance{3ex}% + +\def\tikz@initial@compute@above{\def\tikz@initial@angle{90}\def\tikz@initial@anchor{south}}% +\def\tikz@initial@compute@below{\def\tikz@initial@angle{270}\def\tikz@initial@anchor{north}}% +\def\tikz@initial@compute@left{\def\tikz@initial@angle{180}\def\tikz@initial@anchor{east}}% +\def\tikz@initial@compute@right{\def\tikz@initial@angle{0}\def\tikz@initial@anchor{west}}% + +\def\tikz@initial@angle{180}% +\def\tikz@initial@anchor{east}% + +\def\tikz@accepting@compute@above{\def\tikz@accepting@angle{90}\def\tikz@accepting@anchor{south}}% +\def\tikz@accepting@compute@below{\def\tikz@accepting@angle{270}\def\tikz@accepting@anchor{north}}% +\def\tikz@accepting@compute@left{\def\tikz@accepting@angle{180}\def\tikz@accepting@anchor{east}}% +\def\tikz@accepting@compute@right{\def\tikz@accepting@angle{0}\def\tikz@accepting@anchor{west}}% + +\def\tikz@accepting@angle{0}% +\def\tikz@accepting@anchor{west}% + + +\tikzset{initial above/.style= {initial by arrow,initial where=above}}% +\tikzset{initial below/.style= {initial by arrow,initial where=below}}% +\tikzset{initial left/.style= {initial by arrow,initial where=left}}% +\tikzset{initial right/.style= {initial by arrow,initial where=right}}% + +\tikzset{accepting above/.style= {accepting by arrow,accepting where=above}}% +\tikzset{accepting below/.style= {accepting by arrow,accepting where=below}}% +\tikzset{accepting left/.style= {accepting by arrow,accepting where=left}}% +\tikzset{accepting right/.style= {accepting by arrow,accepting where=right}}% + + +% Defaults: + +\tikzset{state/.style= {state without output}}% +\tikzset{accepting/.style= {accepting by double}}% +\tikzset{initial/.style= {initial by arrow}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybabel.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybabel.code.tex new file mode 100644 index 0000000000..e24439f75f --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybabel.code.tex @@ -0,0 +1,17 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarybabel.code.tex} + +\tikzset{ + handle active characters in code, + handle active characters in nodes, +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex new file mode 100644 index 0000000000..1a42a4b40e --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex @@ -0,0 +1,148 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarybackgrounds.code.tex} + + +% Layers + +\pgfdeclarelayer{background}% +\pgfsetlayers{background,main}% + + +% Switch command +\tikzset{on background layer/.style={ + execute at begin scope={% + \pgfonlayer{background}% + \let\tikz@options=\pgfutil@empty% + \tikzset{every on background layer/.try,#1}% + \tikz@options}, + execute at end scope={\endpgfonlayer} + } +}% + + +% Main style + +\tikzset{background rectangle/.style= {draw}}% +\tikzset{background top/.style= {draw}}% +\tikzset{background bottom/.style= {draw}}% +\tikzset{background left/.style= {draw}}% +\tikzset{background right/.style= {draw}}% +\tikzset{background grid/.style= {help lines,draw}}% + +\tikzoption{inner frame sep}{\def\tikz@framexsep{#1}\def\tikz@frameysep{#1}}% +\tikzoption{inner frame xsep}{\def\tikz@framexsep{#1}}% +\tikzoption{inner frame ysep}{\def\tikz@frameysep{#1}}% +\def\tikz@framexsep{1ex}% +\def\tikz@frameysep{1ex}% + +\tikzoption{outer frame sep}{\def\tikz@outerframexsep{#1}\def\tikz@outerframeysep{#1}}% +\tikzoption{outer frame xsep}{\def\tikz@outerframexsep{#1}}% +\tikzoption{outer frame ysep}{\def\tikz@outerframeysep{#1}}% +\def\tikz@outerframexsep{0ex}% +\def\tikz@outerframeysep{0ex}% + + +% Looseness + +\tikzset{loose background/.style= {inner frame sep=2ex}}% +\tikzset{tight background/.style= {inner frame sep=0ex}}% + + + +% Showing background styles + +\tikzset{framed/.style= {style=show background rectangle}}% +\tikzset{gridded/.style= {style=show background grid}}% + +\tikzset{show background rectangle/.style={execute at end picture=\tikz@background@framed}}% +\tikzset{show background top/.style= {execute at end picture=\tikz@background@top}}% +\tikzset{show background bottom/.style= {execute at end picture=\tikz@background@bottom}}% +\tikzset{show background left/.style= {execute at end picture=\tikz@background@left}}% +\tikzset{show background right/.style= {execute at end picture=\tikz@background@right}}% +\tikzset{show background grid/.style= {execute at end picture=\tikz@background@grid}}% + + +% Implementation + +\def\tikz@background@save{% + \pgftransformreset% + \ifx\tikz@bg@minx\@undefined% + \pgf@xb=\pgf@picminx% + \pgf@yb=\pgf@picminy% + \pgf@xc=\pgf@picmaxx% + \pgf@yc=\pgf@picmaxy% + \pgfmathsetlength{\pgf@x}{\tikz@framexsep}% + \pgfmathsetlength{\pgf@y}{\tikz@frameysep}% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + \advance\pgf@xc by\pgf@x% + \advance\pgf@yc by\pgf@y% + \edef\tikz@bg@minx{\the\pgf@xb}% + \edef\tikz@bg@miny{\the\pgf@yb}% + \edef\tikz@bg@maxx{\the\pgf@xc}% + \edef\tikz@bg@maxy{\the\pgf@yc}% + \pgfmathsetlength{\pgf@x}{\tikz@outerframexsep}% + \pgfmathsetlength{\pgf@y}{\tikz@outerframeysep}% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + \advance\pgf@xc by\pgf@x% + \advance\pgf@yc by\pgf@y% + \edef\tikz@bg@outerminx{\the\pgf@xb}% + \edef\tikz@bg@outerminy{\the\pgf@yb}% + \edef\tikz@bg@outermaxx{\the\pgf@xc}% + \edef\tikz@bg@outermaxy{\the\pgf@yc}% + \fi% +}% + +\def\tikz@background@framed{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background rectangle] (\tikz@bg@minx,\tikz@bg@miny) rectangle (\tikz@bg@maxx,\tikz@bg@maxy); + \endpgfonlayer +}% + +\def\tikz@background@top{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background top] (\tikz@bg@outerminx,\tikz@bg@maxy) -- (\tikz@bg@outermaxx,\tikz@bg@maxy); + \endpgfonlayer +}% + +\def\tikz@background@bottom{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background bottom] (\tikz@bg@outerminx,\tikz@bg@miny) -- (\tikz@bg@outermaxx,\tikz@bg@miny); + \endpgfonlayer +}% + +\def\tikz@background@left{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background left] (\tikz@bg@minx,\tikz@bg@outerminy) -- (\tikz@bg@minx,\tikz@bg@outermaxy); + \endpgfonlayer +}% + +\def\tikz@background@right{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background right] (\tikz@bg@maxx,\tikz@bg@outerminy) -- (\tikz@bg@maxx,\tikz@bg@outermaxy); + \endpgfonlayer +}% + +\def\tikz@background@grid{% + \tikz@background@save% + \pgfonlayer{background} + \path[style=background grid] (\tikz@bg@minx,\tikz@bg@miny) grid (\tikz@bg@maxx,\tikz@bg@maxy); + \endpgfonlayer +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybending.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybending.code.tex new file mode 100644 index 0000000000..169995bcde --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarybending.code.tex @@ -0,0 +1,15 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarybending.code.tex} + +\usepgfmodule{bending}% +\tikzset{arrows=[flex]}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex new file mode 100644 index 0000000000..373ea7752d --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex @@ -0,0 +1,618 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarycalc.code.tex} + +% +% +% Part I: The let path command +% +% + + +% +% Syntax: let \p{name1} = (coord), \p{name2} = (coord), ... in ... +% +% Currently (this may get more fancy in the future), the (coord)s are +% evaluated one by one. If the first evaluates to, say, (10pt,20pt), +% the macro \p{name1} is set to "10pt,20pt" (without parentheses), the +% macro \x{name1} is set to "10pt" and the macro \y{name1} is set to +% "20pt". +% +% If you use a number for {name}, you need no parentheses, so you +% could write: +% +% \draw let +% \p1 = (1,1), +% \p2 = ($ 2.5*(3,2) $) +% in +% (\x1,\x2) -- (\y1,\y2); + +\def\tikz@let@command et{% + \let\p=\tikz@cc@dop% + \let\x=\tikz@cc@dox% + \let\y=\tikz@cc@doy% + \let\n=\tikz@cc@don% + \pgfutil@ifnextchar i{\tikz@cc@stop@let}{\tikz@cc@handle@line}% +}% +\def\tikz@cc@handle@line{% + \pgfutil@ifnextchar\p{% + \tikz@cc@handle@coor% + }{% + \pgfutil@ifnextchar\n{% + \tikz@cc@handle@num% + }{% + \pgfutil@ifnextchar i{% + \tikz@cc@stop@let + }{% + \tikzerror{``\string\p'' or ``\string\n'' expected}% + }% + }% + }% +}% +\def\tikz@cc@handle@num\n#1#2=#3{% + \pgfmathparse{#3}% + \expandafter\edef\csname tikz@cc@n@#1\endcsname{\pgfmathresult\ifpgfmathunitsdeclared pt\fi} + \pgfutil@ifnextchar,{\tikz@cc@handle@nextline}{\tikz@cc@stop@let}% +}% +\def\tikz@cc@handle@coor\p#1#2={% + \def\tikz@cc@coord@name{#1}% + \tikz@scan@one@point\tikz@cc@dolet% +}% +\def\tikz@cc@dolet#1{% + \pgf@process{#1}% + \expandafter\edef\csname tikz@cc@p@\tikz@cc@coord@name\endcsname{\the\pgf@x,\the\pgf@y}% + \expandafter\edef\csname tikz@cc@x@\tikz@cc@coord@name\endcsname{\the\pgf@x}% + \expandafter\edef\csname tikz@cc@y@\tikz@cc@coord@name\endcsname{\the\pgf@y}% + \pgfutil@ifnextchar,{\tikz@cc@handle@nextline}{\tikz@cc@stop@let}% +}% +\def\tikz@cc@handle@nextline,{% + \tikz@cc@handle@line% +}% +\def\tikz@cc@stop@let in{% + \tikz@scan@next@command% +}% + +\def\tikz@cc@dop#1{\csname tikz@cc@p@#1\endcsname}% +\def\tikz@cc@dox#1{\csname tikz@cc@x@#1\endcsname}% +\def\tikz@cc@doy#1{\csname tikz@cc@y@#1\endcsname}% +\def\tikz@cc@don#1{\csname tikz@cc@n@#1\endcsname}% + + + +% +% +% Part II: The ($...$) parser +% +% + +\def\tikz@parse@calculator#1(${%$ + \def\tikz@cc@command{#1}% + \begingroup% + % + % Parse main computation. It's a series of optional factors in front + % of coordinates. + % + \pgf@xa=0pt% We accumulate the result in here. + \pgf@ya=0pt% + \tikz@cc@parse+% +}% + +\def\tikz@cc@parse{% + \pgfutil@ifnextchar${%$ + % Ok, we found the end... + \tikz@cc@end% + } + {\pgfutil@ifnextchar+{% + % Ok, we found a coordinate... + \tikz@cc@add% + }{% + \pgfutil@ifnextchar-{% + \tikz@cc@sub% + }{% + \tikzerror{+ or - expected}% + \tikz@cc@end$%$ + }% + }% + }% +}% + +% +% The end is reached with $ +% +\def\tikz@cc@end$#1){%$ + \xdef\tikz@marshal{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \endgroup% + \expandafter\tikz@cc@command\expandafter{\tikz@marshal}% +}% + + +% +% Another coordinate with +/-, possibly with a factor +% +\def\tikz@cc@add+{% + \def\tikz@cc@factor{1}% + \tikz@cc@factororcoordinate% +}% +\def\tikz@cc@sub-{% + \def\tikz@cc@factor{-1}% + \tikz@cc@factororcoordinate% +}% + +% +% Check for a factor: If we see a (, its a coordinate... +% +\def\tikz@cc@factororcoordinate{% + \pgfutil@ifnextchar({%) + % Ok, found coordinate + \tikz@cc@coordinate% + }{% + \tikz@cc@parse@factor% + }% +}% + +% +% ... otherwise it's a factor. It ends at ...*( +% +\def\tikz@cc@parse@factor#1*({% + \pgfmathparse{#1*\tikz@cc@factor}% + \let\tikz@cc@factor=\pgfmathresult% + \tikz@cc@coordinate(%) +}% + +\def\tikz@cc@coordinate{% + \tikz@scan@absolute\tikz@cc@after@coordinate% +}% +\def\tikz@cc@after@coordinate#1{% + \pgf@process{#1}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \tikz@cc@mid@checks% +}% + + +% +% A coordinate can be followed by !...!(...) +% + +\def\tikz@cc@mid@checks{% + \ifnum\the\catcode`\!=\active\relax + \expandafter\tikz@cc@mid@checks@active + \else + \expandafter\tikz@cc@mid@checks@nonactive + \fi +}% + +\def\tikz@cc@mid@checks@nonactive{% + \pgfutil@ifnextchar!{% + \tikz@cc@mid@nonactive% + }{% + \advance\pgf@xa by\tikz@cc@factor\pgf@xb + \advance\pgf@ya by\tikz@cc@factor\pgf@yb + \tikz@cc@parse% + }% +}% + +\def\tikz@cc@mid@nonactive!{% + \pgfutil@ifnextchar({% + \tikz@scan@one@point\tikz@cc@project% + }{% + \tikz@cc@mid@num@nonactive% + }% +}% + +\begingroup + \catcode`\!=\active + \gdef\tikz@cc@mid@checks@active{% + \pgfutil@ifnextchar!{% + \tikz@cc@mid@active% + }{% + \advance\pgf@xa by\tikz@cc@factor\pgf@xb + \advance\pgf@ya by\tikz@cc@factor\pgf@yb + \tikz@cc@parse% + }% + }% + + \gdef\tikz@cc@mid@active!{% + \pgfutil@ifnextchar({% + \tikz@scan@one@point\tikz@cc@project% + }{% + \tikz@cc@mid@num@active% + }% + }% +\endgroup + +% +% Partway case: (coord a)!number!(coord b) +% +% Returns the position that is at fraction on the way from a +% to b. This, (a)!0!(b) is (a), (a)!.5!(b) is the middle and (a)!1!(b) +% is (b) +% + +\def\tikz@cc@mid@num@nonactive#1!{\tikz@cc@mid@num{#1}}% + +\begingroup + \catcode`\!=\active + \gdef\tikz@cc@mid@num@active#1!{\tikz@cc@mid@num{#1}}% +\endgroup + +\def\tikz@cc@mid@num#1{% + \pgfmathparse{#1}% + \ifpgfmathunitsdeclared% + \let\tikz@cc@mid@unit=\pgfmathresult% + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@unit% + \else% + \let\tikz@cc@mid@factor=\pgfmathresult% + \pgfmathparse{1-\tikz@cc@mid@factor}% + \let\tikz@cc@mid@factor@one=\pgfmathresult% + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@num% + \fi% +}% + +\def\tikz@cc@after@num#1{% + \pgf@process{#1}% + \pgf@xb=\tikz@cc@mid@factor@one\pgf@xb% + \pgf@yb=\tikz@cc@mid@factor@one\pgf@yb% + \advance\pgf@xb by\tikz@cc@mid@factor\pgf@x% + \advance\pgf@yb by\tikz@cc@mid@factor\pgf@y% + \tikz@cc@mid@checks% +}% + + + +% +% Distance case: (coord a)!dimension!(coord b) +% +% Returns the position that is at removed from (coord a) +% in the direction of (coord b). +% + +\def\tikz@cc@after@unit#1{% + \pgf@process{#1}% + \advance\pgf@x by-\pgf@xb% + \advance\pgf@y by-\pgf@yb% + \pgf@process{\pgfpointnormalised{}}% + \advance\pgf@xb by\tikz@cc@mid@unit\pgf@x% + \advance\pgf@yb by\tikz@cc@mid@unit\pgf@y% + \tikz@cc@mid@checks% +}% + +% +% Projection case: (a)!(p)!(b) +% +% Projection of p on line from a to b +% +\def\tikz@cc@project#1{% + \pgf@process{#1}% + % Save in c + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \begingroup + \ifnum\the\catcode`\!=\active + \def\tikz@next{% + \endgroup + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@project + \tikz@cc@scan@ex@active}% + \else + \def\tikz@next{% + \endgroup + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@project + \tikz@cc@scan@ex@nonactive}% + \fi + \tikz@next% +}% + +\def\tikz@cc@scan@ex@nonactive!{}% + +\begingroup + \catcode`\!=\active + \gdef\tikz@cc@scan@ex@active!{}% +\endgroup + +\def\tikz@cc@after@project#1{% + \pgf@process{#1}% + % Ok, now we need to project (xc,yc) on the line (xb,xc) to (x,y) + \advance\pgf@x by-\pgf@xb% + \advance\pgf@y by-\pgf@yb% + \advance\pgf@xc by-\pgf@xb% + \advance\pgf@yc by-\pgf@yb% + \pgf@process{\pgfpointnormalised{}}% + % Scalar product + \pgf@xc=\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@xc by\pgf@sys@tonumber{\pgf@yc}\pgf@y% + % and add + \advance\pgf@xb by\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@yb by\pgf@sys@tonumber{\pgf@xc}\pgf@y% + \tikz@cc@mid@checks% +}% + +% +% Rotational scanner: radius:(x) +% + +\def\tikz@cc@scan@rot#1{% + \pgfutil@ifnextchar({%) + \tikz@scan@one@point#1% normal + }% + {% + \def\tikz@cc@scan@rot@cmd{#1}% + \ifnum\the\catcode`\:=\active\relax + \expandafter\tikz@cc@scan@one@rot@active% + \else + \expandafter\tikz@cc@scan@one@rot@nonactive% + \fi + }% +}% + +\def\tikz@cc@scan@one@rot@nonactive#1:{% + \def\tikz@cc@scan@rot@angle{#1}% + \tikz@scan@one@point\tikz@cc@handle@rot% +}% + +\begingroup + \catcode`\:=\active + \gdef\tikz@cc@scan@one@rot@active#1:{% + \def\tikz@cc@scan@rot@angle{#1}% + \tikz@scan@one@point\tikz@cc@handle@rot% + }% +\endgroup + +\def\tikz@cc@handle@rot#1{% + \pgf@process{#1}% + % Ok, now we need to rotate x/y around xb/xb by ...rot@angle + {% + \pgftransformreset% + % Save them... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgftransformshift{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgftransformrotate{\tikz@cc@scan@rot@angle}% + \pgftransformshift{\pgfqpoint{-\pgf@xb}{-\pgf@yb}}% + \pgfpointtransformed{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \expandafter + }% + \edef\tikz@marshal{\noexpand\tikz@cc@scan@rot@cmd{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + \tikz@marshal% +}% + + + + +% +% +% Part III: Calculation coordinate systems +% +% + +% Tangent cs: Keys are a node and a point. Depending on the type of +% node, the appropriate tangent computation should be done. + +\tikzdeclarecoordinatesystem{tangent} +{% + \tikzset{cs/.cd,#1}% + \expandafter\ifx\csname tikz@tangent@\tikz@cs@type\endcsname\relax% + \tikzerror{I do not know how to compute the tangent to + a \tikz@cs@type}% + \pgfpointorigin% + \else% + \expandafter\tikz@scan@one@point\expandafter\tikz@lib@do@tangent\tikz@cs@point% + \fi% +}% + +\tikzset{cs/node/.code=\tikz@cs@unpack{\tikz@cs@node}{\tikz@cs@type}{#1}}% +\tikzset{cs/point/.store in=\tikz@cs@point}% + +\def\tikz@lib@do@tangent{\csname tikz@tangent@\tikz@cs@type\endcsname}% + +\def\tikz@tangent@coordinate#1{% + \pgfpointanchor{\tikz@cs@node}{center}% +}% + +\def\tikz@tangent@circle#1{% + {% + % Step 1: Compute the transformed position of the input: + \pgf@process{\pgfpointtransformed{#1}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % + % Step 2: Compute vector from center of circle to transformed #1 + % + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikz@cs@node}{center}}}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % + % Step 2: Reset transformations, they distract... + % + \pgftransformreset% + % + % Step 3: Transform to the center of the circle. + % + \pgftransformshift{\pgfpointanchor{\tikz@cs@node}{center}}% + % + % Step 4: Compute the radius + % + \pgf@process{\pgfpointanchor{\tikz@cs@node}{east}}% + \pgf@xc=\pgf@x% + % + % Now, (xa,ya) is a point. Compute the tangent from this point to + % a circle around the origin of radius xc. + % + % acos(radius/veclen(xa,ya)) is the angle of the tangent. + \pgfmathparse{veclen(\the\pgf@xa,\the\pgf@ya)} + \pgfmathparse{acos(\the\pgf@xc/\pgfmathresult)} + \ifnum\pgfkeysvalueof{/tikz/cs/solution}>1\relax% + \pgfmathparse{0-\pgfmathresult}% + \fi% + \let\tikz@lib@temp=\pgfmathresult% + % + % Now \pgfmathparse contains the desired angle. Use this to + % compute the correct position on the circle... + % + % But, first, rotate to the point. + \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + \pgf@ya=-\pgf@y% + \pgftransformcm{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfpointorigin}% + % Finally, rotate... + \pgf@process{\pgfpointtransformed{\pgfpointpolar{\tikz@lib@temp}{\the\pgf@xc}}}% + % + % Ok, undo transformations... + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +}% + + +% Implementation of intersections + + +\def\tikz@intersect@circle@and@circle{% + {% + \pgftransformreset% transformations only confuse us, here... + % + % Compute origin and radius of first circle + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@a}{center}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointanchor{\tikz@cs@node@a}{east}}% + \advance\pgf@x by-\pgf@xa% + \pgf@xc=\pgf@x% ok, pgf@xc is first radius, (xa,ya) is center + % + % Compute origin and radius of second circle + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{center}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{east}}% + \advance\pgf@x by-\pgf@xb% + \pgf@yc=\pgf@x% \pgf@yc is second radius, (xb,yb) is center + % + \pgf@process{% + \pgfpointintersectionofcircles{\pgfqpoint{\pgf@xa}{\pgf@ya}}{\pgfqpoint{\pgf@xb}{\pgf@yb}}{\pgf@xc}{\pgf@yc}{\pgfkeysvalueof{/tikz/cs/solution}}% + }% + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process, + % reinstall transformations... + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +}% + + +\def\tikz@intersect@line@and@circle{% + {% + % + % Step 1: Get line + % + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@line\tikz@cs@line@a% + \pgf@process{\pgfpointtransformed{}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@xc}{\pgf@yc}}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % + % Step 2: Subtract center of circle + % + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikz@cs@node@b}{center}}}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + % + % Step 3: Reset transformations, they distract... + % + \pgftransformreset% + % + % Step 4: Transform to the center of the circle. + % + \pgftransformshift{\pgfpointanchor{\tikz@cs@node@b}{center}}% + % + % Step 5: Compute the radius + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{east}}% + \edef\tikz@lib@saved@radius{\pgf@sys@tonumber{\pgf@x}}% + % + % Step 6: Compute projection of origin on line (xa,ya) -- (xb,yb), + % store in (xa,ya) + \pgf@x=\pgf@xb% + \pgf@y=\pgf@yb% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@y by-\pgf@ya% + \pgf@process{\pgfpointnormalised{}}% + % Scalar product + \pgf@xc=\pgf@sys@tonumber{\pgf@xa}\pgf@x% + \advance\pgf@xc by\pgf@sys@tonumber{\pgf@ya}\pgf@y% + \pgf@xc=-\pgf@xc% + % and add + \advance\pgf@xa by\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@ya by\pgf@sys@tonumber{\pgf@xc}\pgf@y% + % + % Now, we have a triangle with a right angle at (xa,ya). The + % second point of the triangle is the origin. The third point is + % sought. + % Save x/y + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % Square radius + \pgf@xb=\tikz@lib@saved@radius pt% + % + % First, make numbers smaller, in case they are too large + % + \c@pgf@counta=1\relax% + \loop% + \ifdim\pgf@xb>50pt% + \multiply\c@pgf@counta by2\relax% + \divide\pgf@xa by2\relax% + \divide\pgf@ya by2\relax% + \divide\pgf@xb by2\relax% + \repeat% + \pgf@xb=\pgf@sys@tonumber{\pgf@xb}\pgf@xb% + % Subtract xa^2 + ya^2 + \pgf@yb=\pgf@sys@tonumber{\pgf@xa}\pgf@xa% + \advance\pgf@xb by-\pgf@yb% + \pgf@yb=\pgf@sys@tonumber{\pgf@ya}\pgf@ya% + \advance\pgf@xb by-\pgf@yb% + % Square root + \ifdim\pgf@xb<0pt% + \pgf@xb=0pt% + \fi% + \pgfmathsqrt@{\pgf@sys@tonumber{\pgf@xb}}% + \pgfmathmultiply@{\pgfmathresult}{\the\c@pgf@counta}% + \multiply\pgf@xa by\c@pgf@counta\relax% + \multiply\pgf@ya by\c@pgf@counta\relax% + \ifnum\pgfkeysvalueof{/tikz/cs/solution}>1\relax% + \pgfmathsubtract{0}{\pgfmathresult}% + \fi% + % Ok, now add things... + \advance\pgf@xa by \pgfmathresult\pgf@xc% + \advance\pgf@ya by \pgfmathresult\pgf@yc% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + % Ok, undo transformations... + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +}% + +\def\tikz@intersect@circle@and@line{% + % Swap + {% + \let\tikz@cs@node@b=\tikz@cs@node@a% + \let\tikz@cs@line@a=\tikz@cs@line@b% + \tikz@intersect@line@and@circle% + }% +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalendar.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalendar.code.tex new file mode 100644 index 0000000000..98cdffe154 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarycalendar.code.tex @@ -0,0 +1,444 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarycalendar.code.tex} + + +\pgfutil@usemodule{pgfcalendar} + + +% +% General options (these options affect all calendars typeset unsind \calendar): +% +% Start, end, and code executed for each current date +% + +\tikzoption{dates}{\tikz@lib@cal@parse#1\relax} +\def\tikz@lib@cal@parse#1to#2\relax{% + \def\tikz@lib@cal@start{#1} + \def\tikz@lib@cal@end{#2}% +} +\tikzoption{execute at begin day scope}{\expandafter\def\expandafter\tikz@atbegin@day\expandafter{\tikz@atbegin@day#1}} +\tikzoption{execute at end day scope}{% + \def\pgf@temp{#1}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@atend@day% + \expandafter\expandafter\expandafter{\expandafter\pgf@temp\tikz@atend@day}} +\tikzoption{execute before day scope}{\expandafter\def\expandafter\tikz@before@day\expandafter{\tikz@before@day#1}} +\tikzoption{execute after day scope}{\expandafter\def\expandafter\tikz@after@day\expandafter{\tikz@after@day#1}} + +\let\tikz@atbegin@day=\pgfutil@empty +\let\tikz@atend@day=\pgfutil@empty +\let\tikz@before@day=\pgfutil@empty +\let\tikz@after@day=\pgfutil@empty + + + +% +% Options affecting some calendars: +% + +% +% Shifts and skips +% + +% Shift between days + +\tikzoption{day xshift}{\def\tikz@lib@cal@xshift{#1}} +\tikzoption{day yshift}{\def\tikz@lib@cal@yshift{#1}} + +\def\tikz@lib@cal@yshift{3ex} +\def\tikz@lib@cal@xshift{3.5ex} + + +% Shift between months + +\tikzoption{month xshift}{\def\tikz@lib@cal@month@xshift{#1}} +\tikzoption{month yshift}{\def\tikz@lib@cal@month@yshift{#1}} + +\def\tikz@lib@cal@month@yshift{9ex} +\def\tikz@lib@cal@month@xshift{9ex} + + + + +% Templates for typesetting days, month, years + +\tikzoption{day code}{\def\tikzdaycode{#1}} +\tikzoption{day text}{\def\tikzdaytext{#1}} +\tikzoption{days}{\tikzset{every day/.append style={#1}}} +\tikzset{every day/.style={anchor=base east}} + +\tikzoption{month code}{\def\tikzmonthcode{#1}} +\tikzoption{month text}{\def\tikzmonthtext{#1}} +\tikzset{every month/.style={}} + +\tikzoption{year code}{\def\tikzyearcode{#1}} +\tikzoption{year text}{\def\tikzyeartext{#1}} +\tikzset{every year/.style={}} + +\def\tikzdaycode{\node[name=\pgfcalendarsuggestedname,every day]{\tikzdaytext};} +\def\tikzmonthcode{\node[every month]{\tikzmonthtext};} +\def\tikzyearcode{\node[every year]{\tikzyeartext};} + +\def\tikzdaytext{\%d-} +\def\tikzmonthtext{\%mt} +\def\tikzyeartext{\%y0} + + +% Internal option for storing the "width" of a calendar as a number of +% days + +\tikzoption{tikz@lib@cal@width}{\def\tikz@lib@cal@width{#1}} + +\def\tikz@lib@cal@width{1} + +% +% Days on a line +% + +\tikzset{day list downward/.style={% + execute before day scope={ + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}% + \pgftransformyshift{-\pgf@y} + }% + }{}% + }, + execute after day scope={\pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}\pgftransformyshift{-\pgf@y}}, + tikz@lib@cal@width=1 +}} +\tikzset{day list upward/.style={% + execute before day scope={ + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgftransformyshift{\tikz@lib@cal@month@yshift}% + }% + }{}% + }, + execute after day scope={\pgftransformyshift\tikz@lib@cal@yshift}, + tikz@lib@cal@width=1 +}} +\tikzset{day list right/.style={% + execute before day scope={ + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgftransformxshift{\tikz@lib@cal@month@xshift}% + }% + }{}% + }, + execute after day scope={\pgftransformxshift\tikz@lib@cal@xshift}, + tikz@lib@cal@width=30% not quite right, but close enough in most cases... +}} + +\tikzset{day list left/.style={% + execute before day scope={ + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@month@xshift} + \pgftransformxshift{-\pgf@x}% + }% + }{}% + }, + execute after day scope={ + \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@xshift} + \pgftransformxshift{-\pgf@x}% + }, + tikz@lib@cal@width=30% not quite right, but close enough in most cases... +}} + + + +% +% Week list +% + +\tikzset{week list/.style={% + execute before day scope={% + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}% + \pgftransformyshift{-\pgf@y} + }% + }{}% + }, + execute at begin day scope={% + \pgfmathsetlength\pgf@x{\tikz@lib@cal@xshift}% + \pgf@x=\pgfcalendarcurrentweekday\pgf@x% + \pgftransformxshift{\pgf@x}% + }, + execute after day scope={% + \ifdate{Sunday}{% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{-\pgf@y} + }{}% + }, + tikz@lib@cal@width=7 +}} + + + +% +% Month list +% + +\tikzset{month list/.style={% + execute before day scope={% + \ifdate{day of month=1}{\ifdate{equals=\pgfcalendarbeginiso}{} + {% + % On first of month, except when first date in calendar. + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}% + \pgftransformyshift{-\pgf@y} + }% + }{}% + \ifdate{day of month=1} + {% + \edef\tikz@lib@cal@month@list@start{\pgfcalendarcurrentweekday}% + }{}% + \ifdate{equals=\pgfcalendarbeginiso}% + {% + % Computer day of week for start of month + {% + \c@pgf@counta=\pgfcalendarcurrentjulian% + \advance\c@pgf@counta by-\pgfcalendarcurrentday% + \advance\c@pgf@counta by1\relax% + \pgfcalendarjuliantoweekday{\c@pgf@counta}{\c@pgf@countb}% + \xdef\pgf@temp{\the\c@pgf@countb}% + }% + \let\tikz@lib@cal@month@list@start=\pgf@temp% + }{}% + }, + execute at begin day scope={% + \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}% + \pgf@xb=\pgfcalendarcurrentday\pgf@xa% + \advance\pgf@xb by\tikz@lib@cal@month@list@start\pgf@xa% + \advance\pgf@xb by-\pgf@xa\relax% + \pgftransformxshift{\pgf@xb}% + }, + tikz@lib@cal@width=37 +}} + + + + +% +% Month labels +% + +\tikzset{month label left/.style={% + execute before day scope={\ifdate{day of month=1}{\tikzmonthcode}{}}, + every month/.append style={anchor=base east,xshift=-3.5ex} +}} + +\tikzset{month label left vertical/.style={% + execute before day scope={\ifdate{day of month=1}{\tikzmonthcode}{}}, + every month/.append style={anchor=base east,xshift=-4.5ex,yshift=2.25ex,rotate=90} +}} + +\tikzset{month label right/.style={% +execute before day scope={\ifdate{day of month=1}{% + {% + \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% + \pgftransformxshift{\tikz@lib@cal@width\pgf@xa}% + \pgftransformxshift{-\pgf@xa}% + \tikzmonthcode% + }}{}}, + every month/.append style={anchor=base west,xshift=1ex} +}} + +\tikzset{month label right vertical/.style={% + execute before day scope={\ifdate{day of month=1}{% + {% + \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% + \pgftransformxshift{\tikz@lib@cal@width\pgf@xa}% + \pgftransformxshift{-\pgf@xa}% + \tikzmonthcode% + }}{}}, + every month/.append style={anchor=base west,xshift=2ex,yshift=2.25ex,rotate=-90} +}} + +\tikzset{month label above centered/.style={% + execute before day scope={% + \ifdate{day of month=1}{% + { + \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% + \pgf@xb=\tikz@lib@cal@width\pgf@xa% + \advance\pgf@xb by-\pgf@xa% + \pgf@xb=.5\pgf@xb% + \pgftransformxshift{\pgf@xb}% + \pgftransformxshift{-1.5ex}% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{1.25\pgf@y} + \tikzmonthcode% + } + }{}}, + every month/.append style={anchor=base} +}} + +\tikzset{month label above left/.style={% + execute before day scope={% + \ifdate{day of month=1}{% + { + \pgftransformxshift{-3.25ex}% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{1.25\pgf@y} + \tikzmonthcode% + } + }{}}, + every month/.append style={anchor=base west} +}} + + + +\tikzset{month label above right/.style={% + execute before day scope={% + \ifdate{day of month=1}{% + { + \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% + \pgf@xb=\tikz@lib@cal@width\pgf@xa% + \advance\pgf@xb by-\pgf@xa% + \pgftransformxshift{\pgf@xb}% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{1.25\pgf@y} + \tikzmonthcode% + } + }{}}, + every month/.append style={anchor=base east} +}} + +\tikzset{month label below centered/.style={% + execute before day scope={% + \ifdate{day of month=1}{% + { + \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% + \pgf@xb=\tikz@lib@cal@width\pgf@xa% + \advance\pgf@xb by-\pgf@xa% + \pgf@xb=.5\pgf@xb% + \pgftransformxshift{\pgf@xb}% + \pgftransformxshift{-1.5ex}% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{-1.25\pgf@y} + \tikzmonthcode% + } + }{}}, + every month/.append style={anchor=base} +}} + +\tikzset{month label below left/.style={% + execute before day scope={% + \ifdate{day of month=1}{% + { + \pgftransformxshift{-3.25ex}% + \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}% + \pgftransformyshift{-1.25\pgf@y} + \tikzmonthcode% + } + }{}}, + every month/.append style={anchor=base west} +}} + + + +% +% Code of the actual \calendar command (tikz.code.tex contains \let\calendar=\tikz@lib@cal@calendar): +% + +\def\tikz@lib@cal@calendar{% + \begingroup% + \let\tikz@lib@cal@ifs=\pgfutil@empty% + \tikz@resetexpandcount + \tikzset{name=,at={(0,0)}}% + \let\%=\pgfcalendarshorthand% + \tikzset{every calendar/.try}% + \tikz@lib@cal@scanner% +} + +\def\tikz@lib@cal@scanner{% + \afterassignment\tikz@lib@cal@handle\let\pgf@let@token=% +} + +\def\tikz@lib@cal@handle{% + \pgfutil@switch\pgfutil@ifx\pgf@let@token{% + {;}{\let\pgfutil@next\tikz@lib@cal@stop}% + {(}{\let\pgfutil@next\tikz@lib@cal@name}%) + {a}{\let\pgfutil@next\tikz@lib@cal@at}% + {[}{\let\pgfutil@next\tikz@lib@cal@option}%] + {i}{\let\pgfutil@next\tikz@lib@cal@if}% + }{\tikz@resetexpandcount\pgfutil@next}{\tikz@lib@cal@expand}% +} +\def\tikz@lib@cal@expand{% + \advance\tikz@expandcount by -1 + \ifnum\tikz@expandcount<0\relax% + \tikzerror{Giving up on this calendar}% + \let\pgfutil@next=\tikz@lib@cal@end% + \else% + \let\pgfutil@next=\tikz@lib@cal@@expand + \fi% + \pgfutil@next} + +\def\tikz@lib@cal@@expand{\expandafter\tikz@lib@cal@scanner\pgf@let@token} + + +\def\tikz@lib@cal@name#1){% + \tikzset{name=#1}% + \tikz@lib@cal@scanner% +} +\def\tikz@lib@cal@at t#1(#2){% + \tikzset{at={(#2)}}% + \tikz@lib@cal@scanner% +} +\def\tikz@lib@cal@option#1]{% + \tikzset{#1}% + \tikz@lib@cal@scanner% +} +\def\tikz@lib@cal@if f#1(#2){% + \pgfutil@ifnextchar[{\tikz@lib@cal@if@opt{#2}}{\tikz@lib@cal@if@code{#2}}}%} + +\def\tikz@lib@cal@if@opt#1[#2]{\tikz@lib@cal@if@code{#1}{\tikzset{#2}}} +\def\tikz@lib@cal@if@code#1#2{% + \pgfutil@ifnextchar e{\tikz@lib@cal@if@else{#1}{#2}}{\tikz@lib@cal@if@else{#1}{#2}else{}}} + +\def\tikz@lib@cal@if@else#1#2else{% + \pgfutil@ifnextchar[{\tikz@lib@cal@if@else@opt{#1}{#2}}{\tikz@lib@cal@if@else@code{#1}{#2}}}%} +\def\tikz@lib@cal@if@else@opt#1#2[#3]{\tikz@lib@cal@if@else@code{#1}{#2}{\tikzset{#3}}} +\def\tikz@lib@cal@if@else@code#1#2#3{% + \expandafter\def\expandafter\tikz@lib@cal@ifs\expandafter{\tikz@lib@cal@ifs\ifdate{#1}{#2}{#3}}% + \tikz@lib@cal@scanner% +} +\def\tikz@lib@cal@stop{% + \pgftransformshift{\tikz@node@at}% + \expandafter\pgfcalendar\expandafter{\tikz@fig@name}{\tikz@lib@cal@start}{\tikz@lib@cal@end}% + {% + \tikz@before@day% + \scope% + \tikz@atbegin@day% + \tikz@lib@cal@ifs% + \tikzdaycode% + \tikz@atend@day% + \endscope% + \tikz@after@day% + }% + \endgroup% +} + +\tikzoption{if}{% + \let\tikz@lib@cal@scanner@orig=\tikz@lib@cal@scanner% + \let\tikz@lib@cal@scanner=\relax% + \tikz@lib@cal@if f#1\relax% + \let\tikz@lib@cal@scanner=\tikz@lib@cal@scanner@orig} + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarychains.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarychains.code.tex new file mode 100644 index 0000000000..1d85b27c45 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarychains.code.tex @@ -0,0 +1,214 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarychains.code.tex} + +\usetikzlibrary{positioning}% + +\tikzset{start chain/.default=, + start chain/.code={% + \tikz@lib@chain@parse{#1}% + \ifx\tikz@lib@chain@name\pgfutil@empty% + \def\tikz@lib@chain@name{chain}% + \fi% + \ifx\tikz@lib@chain@direction\relax% + \let\tikz@lib@chain@direction=\tikz@lib@chain@default@direction% + \fi% + \expandafter\ifx\csname tikz@lib@chain@active@\tikz@lib@chain@name\endcsname\relax% + \expandafter\let\csname tikz@lib@chain@active@\tikz@lib@chain@name\endcsname=\pgfutil@empty% does not matter + \expandafter\global\expandafter\let\csname tikz@lib@chain@exists@\tikz@lib@chain@name\endcsname=\pgfutil@empty% does not matter + % Setup chain parameters + \expandafter\gdef\csname tikz@lib@chain@count@\tikz@lib@chain@name\endcsname{0}% + \expandafter\global\expandafter\let\csname tikz@lib@chain@dir@\tikz@lib@chain@name\endcsname\tikz@lib@chain@direction% + \let\tikz@lib@current@chain=\tikz@lib@chain@name% + \let\chainin=\tikz@lib@chainin% + \else% + \tikzerror{Chain ``\tikz@lib@chain@name'' is already active}% + \fi% + }, + continue chain/.default=, + continue chain/.code={% + \tikz@lib@chain@parse{#1}% + \ifx\tikz@lib@chain@name\pgfutil@empty% + \let\tikz@lib@chain@name\tikz@lib@current@chain% + \fi% + \expandafter\ifx\csname tikz@lib@chain@exists@\tikz@lib@chain@name\endcsname\relax% + \tikzerror{Unknown chain ``#1''}% + \else% + \let\tikz@lib@current@chain=\tikz@lib@chain@name% + \expandafter\let\csname tikz@lib@chain@active@\tikz@lib@chain@name\endcsname=\pgfutil@empty% does not matter + \ifx\tikz@lib@chain@direction\relax% + % Just restart... + \else% + % Setup chain parameters + \expandafter\global\expandafter\let\csname tikz@lib@chain@dir@\tikz@lib@chain@name\endcsname\tikz@lib@chain@direction% + \fi% + \fi% + }, + join/.code=\tikz@lib@parse@join{#1}, + join/.default={}% +}% + +\def\tikz@lib@chain@parse#1{% + \pgfutil@in@{going }{#1}% + \ifpgfutil@in@% + \tikz@lib@chain@going#1\pgf@stop% + \else% + \pgfutil@in@{placed }{#1}% + \ifpgfutil@in@% + \tikz@lib@chain@positioning#1\pgf@stop% + \else% + \def\tikz@lib@chain@name{#1}% + \let\tikz@lib@chain@direction\relax% + \fi% + \fi% +}% + +\def\tikz@lib@chain@going#1going #2\pgf@stop{% + \def\tikz@lib@chain@name{#1}% + \ifx\tikz@lib@chain@name\pgfutil@empty% + \else% + \tikz@lib@chain@strip#1\pgf@stop%% + \fi% + \tikz@lib@chain@is@goingtrue% + \def\tikz@lib@chain@direction{% + \ifx\tikzchainprevious\pgfutil@empty% + \else% + \tikz@lib@chain@place{#2}% + \fi% + }% +}% + +\def\tikz@lib@chain@positioning#1placed #2\pgf@stop{% + \def\tikz@lib@chain@name{#1}% + \ifx\tikz@lib@chain@name\pgfutil@empty% + \else% + \tikz@lib@chain@strip#1\pgf@stop%% + \fi% + \tikz@lib@chain@is@goingfalse% + \def\tikz@lib@chain@direction{\tikz@lib@chain@place{#2}}% +}% +\newif\iftikz@lib@chain@is@going + + +\tikzset{/tikz/chain default direction/.code=% + {% + \tikz@lib@chain@parse{#1}% + \let\tikz@lib@chain@default@direction=\tikz@lib@chain@direction% + },% + /tikz/chain default direction=going right +}% + +\def\tikz@lib@current@chain{chain}% + +\pgfutil@g@addto@macro\tikz@node@reset@hook{\let\tikz@lib@chain@caller=\relax}% +\pgfutil@g@addto@macro\tikz@node@begin@hook{\tikz@lib@chain@caller}% + +\tikzset{ + on chain/.default=, + on chain/.code=\tikz@lib@on@chain{#1}% +}% +\def\tikz@lib@on@chain#1{% + \tikz@lib@chain@parse{#1}% + \ifx\tikz@lib@chain@name\pgfutil@empty% + \let\tikz@lib@chain@name\tikz@lib@current@chain% + \fi% + \expandafter\ifx\csname tikz@lib@chain@exists@\tikz@lib@chain@name\endcsname\relax% + \tikzerror{Unknown chain ``\tikz@lib@chain@name''}% + \else% + \c@pgf@counta\csname tikz@lib@chain@count@\tikz@lib@chain@name\endcsname\relax% + \ifnum\c@pgf@counta=0\relax% + \global\let\tikzchainprevious=\pgfutil@empty% + \else + \xdef\tikzchainprevious{\tikz@lib@chain@name-\the\c@pgf@counta}% + \fi% + \advance\c@pgf@counta by1\relax% + \xdef\tikzchaincount{\the\c@pgf@counta}% + \ifx\tikz@lib@chain@direction\relax% + \csname tikz@lib@chain@dir@\tikz@lib@chain@name\endcsname% use default + \else% + \tikz@lib@chain@direction% + \fi% + \edef\tikz@lib@chain@caller{\noexpand\tikz@lib@chain@last@found{\tikz@lib@chain@name}}% + \fi% +}% +\def\tikz@lib@chain@last@found#1{% + % Increase the count and set name, if necessary. + \c@pgf@counta\csname tikz@lib@chain@count@#1\endcsname\relax% + \advance\c@pgf@counta by1\relax% + \xdef\tikzchaincurrent{#1-\the\c@pgf@counta}% + \expandafter\xdef\csname tikz@lib@chain@count@#1\endcsname{\the\c@pgf@counta}% + \ifnum\c@pgf@counta=1\relax% + \tikzset{alias/.expanded={#1-begin}} % Define pseudostart + \fi% + \tikzset{alias/.expanded={#1-end}} % Define pseudostart + \tikzset{alias/.expanded={#1-\the\c@pgf@counta}} % Define pseudostart + \tikz@lib@chain@direction% + \tikzset{every on chain/.try}% +}% + + +\def\tikz@lib@chain@place#1{% + \pgfutil@in@{=}{#1}% + \ifpgfutil@in@% + \tikzset{#1}% + \else% + \tikzset{#1=of \tikzchainprevious}% + \fi% +}% + +\def\tikz@lib@chain@strip#1 \pgf@stop{% + \def\tikz@lib@chain@name{#1}% +}% + +\def\tikz@lib@parse@join#1{% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \tikz@lib@parse@join@by by \pgf@stop% + \else% + \pgfutil@in@{with }{#1}% + \ifpgfutil@in@% + \pgfutil@in@{by }{#1}% + \ifpgfutil@in@% + \tikz@lib@parse@join@with@by#1\pgf@stop% + \else% + \tikz@lib@parse@join@with@by#1 by \pgf@stop% + \fi% + \else% + \tikz@lib@parse@join@by#1\pgf@stop% + \fi% + \fi% +}% +\def\tikz@lib@parse@join@with@by with #1 by #2\pgf@stop{% + \tikzset{after node path={(#1)edge[every join,#2](\tikzchaincurrent)}}% +}% +\def\tikz@lib@parse@join@by by #1\pgf@stop{% + \tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else (\tikzchainprevious)edge[every join,#1](\tikzchaincurrent)\fi}}% +}% +\tikzset{every join/.style=}% + + +\def\tikz@lib@chainin#1(#2){\pgfutil@ifnextchar[{\tikz@lib@chainin@{#2}}{\tikz@lib@chainin@{#2}[]}}%]% +\def\tikz@lib@chainin@#1[#2]{\path[late options={name=#1,on chain,every chain in/.try,#2}]}% + + +% +% Branches +% + +\tikzset{start branch/.code={% + % save last node on current chain: + \let\tikz@lib@save@current\tikz@lib@current@chain% + \pgfkeysalso{/tikz/start chain/.expand once=\tikz@lib@current@chain/#1}% + \path[late options={name=\tikz@lib@save@current-end,on chain}];% + }% +}% +\tikzset{continue branch/.style={continue chain/.expand once=\tikz@lib@current@chain/#1}}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.code.tex new file mode 100644 index 0000000000..bfe8863efc --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.code.tex @@ -0,0 +1,194 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + +% Define the basic decoration stuff for tikz. Load more libraries to +% "actually use" decorations + +\tikzset{decorate/.is if=tikz@decoratepath, + /pgf/decoration/name/.store in=\tikz@decoration@name, + /pgf/decoration/.unknown/.code=% + \pgfifdecoration{\pgfkeyscurrentname}{\edef\tikz@decoration@name{\pgfkeyscurrentname}} + {\pgfifmetadecoration{\pgfkeyscurrentname}{\edef\tikz@decoration@name{\pgfkeyscurrentname}} + % Fully expand `\pgfkeyscurrentname' before being used in first-arg of + % `/errors/unknown key'. + {\pgfkeys{/errors/unknown + key/.expanded={/pgf/decoration/\pgfkeyscurrentname}{\pgfutil@unexpanded{#1}}}}},% + /pgf/decoration/raise/.code={\def\tikz@dec@shift{\pgftransformyshift{#1}}\tikz@dec@trans}, + /pgf/decoration/mirror/.code={% + \csname if#1\endcsname + \def\tikz@dec@mirror{\pgftransformyscale{-1}}% + \else% + \let\tikz@dec@mirror=\relax% + \fi% + \tikz@dec@trans% + }, + /pgf/decoration/mirror/.default=true, + /pgf/decoration/transform/.code={% + {% + \pgftransformreset% + \def\tikz@transform{}% + \pgfkeysalso{/tikz/.cd, #1}% + \expandafter\gdef\expandafter\tikz@g@temptransform\expandafter{\tikz@transform}% + }% + \let\tikz@dec@user@transform=\tikz@g@temptransform% + \tikz@dec@trans% + },% + /pgf/decoration/pre/.initial=lineto, + /pgf/decoration/post/.initial=lineto, + /pgf/decoration/pre length/.initial=0pt, + /pgf/decoration/post length/.initial=0pt, +}% + +\let\tikz@decoration@name=\tikz@nonetext + +\def\tikz@dec@trans{\pgfsetdecorationsegmenttransformation{\tikz@dec@user@transform\tikz@dec@mirror\tikz@dec@shift}}% +\let\tikz@dec@user@transform=\relax +\let\tikz@dec@shift=\relax +\let\tikz@dec@mirror=\relax + +\pgfdeclaremetadecoration{tikz@internal}{pre}{% + \state{pre}[width=\pgfkeysvalueof{/pgf/decoration/pre length}, next state=main] + { + \tikz@dec@trans + \decoration{\pgfkeysvalueof{/pgf/decoration/pre}} + }% + \state{main}[width=\pgfmetadecoratedremainingdistance-\pgfkeysvalueof{/pgf/decoration/post length}, next state=final] + { + \tikz@dec@trans + \decoration{\tikz@decoration@name} + }% + \state{final} + { + \tikz@dec@trans + \decoration{\pgfkeysvalueof{/pgf/decoration/post}} + }% +}% + + +\newif\iftikz@metadecoration + +\def\tikz@lib@dec@addtomacro#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}% + +\def\tikz@lib@decoration[#1]{% + \begingroup% + % Just to be on the save side... + % + % Now, let's parse the options: + \tikzset{#1}% + % + \ifx\tikz@decoration@name\tikz@nonetext% + % Ok, let's forget about this decoration stuff... + \else + \expandafter\tikz@lib@do@dec% + \fi% + % Now, we expect a brace. + \pgfutil@ifnextchar\bgroup{% + \begingroup% + \tikz@auto@end@pathfalse% + \aftergroup\tikz@enddecoration% + \afterassignment\tikz@scan@next@command% + \let\tikz@lib@next% gobble \bgroup% + }% + {% + \tikzerror{A decoration must begin with a brace}% + \tikz@enddecoration% + }% +}% +\def\tikz@lib@do@dec{% + % Ok, now what? + \pgfifmetadecoration{\tikz@decoration@name}% + {\expandafter\pgfmetadecoration\expandafter{\tikz@decoration@name}}% + {% + \pgfifdecoration{\tikz@decoration@name}% + {\tikz@lib@dec@startdecoration}% + {\tikzerror{Unknown (meta-)decoration '\tikz@decoration@name'. Perhaps you + misspelled it?}}% + }% + \ifx\pgfdecorateexistingpath\pgfutil@empty% + \pgfpathmoveto{\pgfqpoint{\the\tikz@lastxsaved}{\the\tikz@lastysaved}}% + \fi% +}% +\newbox\tikz@lib@dec@box +\def\tikz@enddecoration{% + \global\setbox\tikz@lib@dec@box=\box\tikz@tempbox% + \ifx\tikz@decoration@name\tikz@nonetext% + % ignore this. + \else + % Ok, now what? + \iftikz@metadecoration% + \endpgfmetadecoration% + \else% + \tikz@lib@dec@stopdecoration% + \fi% + \fi + \endgroup% + \setbox\tikz@tempbox=\box\tikz@lib@dec@box% +}% + + +\def\tikz@lib@dec@decorate@path{% + \ifx\tikz@decoration@name\tikz@nonetext% + \else% + \pgfgetpath\tikz@lib@dec@currentpath% + \pgfsetpath\pgfutil@empty% + \pgfifmetadecoration{\tikz@decoration@name} + { + \expandafter\pgfmetadecoration\expandafter{\tikz@decoration@name}% + \pgfsetpath\tikz@lib@dec@currentpath% + \endpgfmetadecoration% + } + { + \pgfifdecoration{\tikz@decoration@name} + { + \tikz@lib@dec@startdecoration% + \pgfsetpath\tikz@lib@dec@currentpath% + \tikz@lib@dec@stopdecoration% + } + { + \tikzerror{Unknown (meta-)decoration '\tikz@decoration@name'. Perhaps + you misspelled it?} + } + } + \fi% +}% + +\def\tikz@lib@dec@zpttext{0pt}% + +\newif\iftikz@lib@dec@temp +\def\tikz@lib@dec@startdecoration{% + \pgfkeysgetvalue{/pgf/decoration/pre length}{\tikz@lib@pre}% + \pgfkeysgetvalue{/pgf/decoration/post length}{\tikz@lib@post}% + \tikz@lib@dec@tempfalse% + \ifx\tikz@lib@pre\tikz@lib@dec@zpttext% + \ifx\tikz@lib@post\tikz@lib@dec@zpttext% + \else% + \tikz@lib@dec@temptrue% + \fi% + \else% + \tikz@lib@dec@temptrue% + \fi% + \iftikz@lib@dec@temp% + \pgfmetadecoration{tikz@internal}% + \else% + \expandafter\pgfdecoration\expandafter{\expandafter{\tikz@decoration@name}{\pgfdecoratedpathlength}{}{}}% + \fi% +}% + +\def\tikz@lib@dec@stopdecoration{% + \iftikz@lib@dec@temp% + \endpgfmetadecoration% + \else% + \endpgfdecoration% + \fi% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.footprints.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.footprints.code.tex new file mode 100644 index 0000000000..10bc743f24 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.footprints.code.tex @@ -0,0 +1,13 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.footprints}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.fractals.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.fractals.code.tex new file mode 100644 index 0000000000..4ef2342784 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.fractals.code.tex @@ -0,0 +1,13 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.fractals}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.markings.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.markings.code.tex new file mode 100644 index 0000000000..04f3e571b1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.markings.code.tex @@ -0,0 +1,31 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.markings}% + +% Upgrade \arrow command +\def\pgf@lib@dec@doarrowhead{% + \pgfutil@ifnextchar[{\tikz@lib@dec@doarrowhead}{\tikz@lib@dec@doarrowhead[]}%] +}% +\def\tikz@lib@dec@doarrowhead[#1]#2{% + \scope[#1] + \pgf@lib@dec@arrowhead{1}{#2}% + \endscope +}% +\def\pgf@lib@dec@doarrowheadrev{% + \pgfutil@ifnextchar[{\tikz@lib@dec@doarrowheadrev}{\tikz@lib@dec@doarrowheadrev[]}%] +}% +\def\tikz@lib@dec@doarrowheadrev[#1]#2{% + \scope[#1] + \pgf@lib@dec@arrowhead{-1}{#2}% + \endscope +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathmorphing.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathmorphing.code.tex new file mode 100644 index 0000000000..5bc38b1dc8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathmorphing.code.tex @@ -0,0 +1,13 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.pathmorphing}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathreplacing.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathreplacing.code.tex new file mode 100644 index 0000000000..4f52ff9a1e --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.pathreplacing.code.tex @@ -0,0 +1,36 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.pathreplacing}% + + +\def\tikz@lib@dec@installinputsegmentpoints{% + \pgf@process{\pgf@decorate@inputsegment@first}% + \edef\tikzinputsegmentfirst{\the\pgf@x,\the\pgf@y}% + % + \pgf@process{\pgf@decorate@inputsegment@last}% + \edef\tikzinputsegmentlast{\the\pgf@x,\the\pgf@y}% + % + \pgf@process{\pgf@decorate@inputsegment@supporta}% + \edef\tikzinputsegmentsupporta{\the\pgf@x,\the\pgf@y}% + % + \pgf@process{\pgf@decorate@inputsegment@supportb}% + \edef\tikzinputsegmentsupportb{\the\pgf@x,\the\pgf@y}% +}% + +\pgfkeys{ + /pgf/decoration/.cd, + moveto code/.code=\def\pgfdecoratedinputsegmentmovetocode{\tikz@lib@dec@installinputsegmentpoints#1}, + lineto code/.code=\def\pgfdecoratedinputsegmentlinetocode{\tikz@lib@dec@installinputsegmentpoints#1}, + curveto code/.code=\def\pgfdecoratedinputsegmentcurvetocode{\tikz@lib@dec@installinputsegmentpoints#1}, + closepath code/.code=\def\pgfdecoratedinputsegmentclosepathcode{\tikz@lib@dec@installinputsegmentpoints#1} +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.shapes.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.shapes.code.tex new file mode 100644 index 0000000000..3074a03905 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.shapes.code.tex @@ -0,0 +1,13 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.shapes}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.text.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.text.code.tex new file mode 100644 index 0000000000..030135d8f5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarydecorations.text.code.tex @@ -0,0 +1,704 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{decorations}% +\usepgflibrary{decorations.text}% + + +% Code for the `text effects along path' decoration + +% Some text constants +% To do: merge these with existing text constants +\def\tikz@lib@dec@te@space@text{space}% +\def\tikz@lib@dec@align@left@text{left}% +\def\tikz@lib@dec@align@right@text{right}% +\def\tikz@lib@dec@align@center@text{center}% +\def\tikz@lib@dec@te@none@text{none}% + +% Some ifs +\newif\iftikz@lib@dec@te@pathfromtext% +\newif\iftikz@lib@dec@te@segmentfromwidth% +\newif\iftikz@lib@dec@te@scaletexttopath% +\newif\iftikz@lib@dec@te@fittexttopath% +\newif\iftikz@lib@dec@te@wordsep% +\newif\iftikz@lib@dec@te@finalletter% + + +% Utility macros +% To do: integrate with existing pgf macros +\def\tikz@lib@dec@te@addto@macro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +}% + +\def\tikz@lib@dec@te@namelet#1#2{% + \expandafter\expandafter\expandafter\let\expandafter\expandafter\csname\expandafter#1\expandafter\endcsname\expandafter=\csname#2\endcsname% +}% + +\def\tikz@lib@dec@te@advancecountmacro#1#2{% + \pgfutil@tempcnta=#1\relax% + \advance\pgfutil@tempcnta by#2\relax% + \edef#1{\the\pgfutil@tempcnta}% +}% + +\def\tikz@lib@dec@te@advancedimenmacro#1#2{% + \pgf@x=#1\relax% + \advance\pgf@x by#2\relax% + \edef#1{\the\pgf@x}% +}% + +% Macros for defining and updating text parameters +\def\tikz@lib@dec@te@start@parameters#1{% + \expandafter\let\csname tikz@lib@dec@te@character@#1\endcsname=\pgfutil@empty% +}% + +\def\tikz@lib@dec@te@addto@parameters#1#2{% + \expandafter\tikz@lib@dec@te@addto@macro\expandafter% + {\csname tikz@lib@dec@te@character@#1\endcsname}{#2}% +}% +\def\tikz@lib@dec@te@addmacroto@parameters#1#2{% + \def\tikz@lib@dec@te@marshal{\expandafter\tikz@lib@dec@te@addto@macro\expandafter% + {\csname tikz@lib@dec@te@character@#1\endcsname}}% + \expandafter\tikz@lib@dec@te@marshal\expandafter{\expandafter\def\expandafter#2\expandafter{#2}}% +}% + +\def\tikz@lib@dec@te@getparameters#1{\csname tikz@lib@dec@te@character@#1\endcsname}% + + + +\let\tikz@lib@dec@te@textoptions=\pgfutil@empty +\let\tikz@lib@dec@te@widthoptions=\pgfutil@empty +\let\tikz@lib@dec@te@charactercountvar=\pgfutil@empty +\let\tikz@lib@dec@te@charactertotalvar=\pgfutil@empty +\let\tikz@lib@dec@te@lettercountvar=\pgfutil@empty +\let\tikz@lib@dec@te@lettertotalvar=\pgfutil@empty +\let\tikz@lib@dec@te@wordcountvar=\pgfutil@empty +\let\tikz@lib@dec@te@wordctotalvar=\pgfutil@empty +\let\tikz@lib@dec@te@transformtext=\pgfutil@empty% + + +% Keys... lots of them... +\pgfkeys{/pgf/decoration/text effects/.cd, + .unknown/.code={\let\tikz@lib@dec@te@key@tmp=\pgfkeyscurrentname% + \pgfkeysalso{/tikz/\tikz@lib@dec@te@key@tmp={#1}}}, + path from text/.is if=tikz@lib@dec@te@pathfromtext, + path from text angle/.store in=\tikz@lib@dec@te@pathfromtextangle, + path from text angle=0, + fit text to path/.is if=tikz@lib@dec@te@fittexttopath, + characters/.style={/pgf/decoration/text effects/every character/.style={#1}}, + characters/.append/.code={\pgfkeysalso{/pgf/decoration/text effects/every character/.append style={#1}}}, + character widths/.code={\pgfkeysalso{/pgf/decoration/text effects/every character width/.style={#1}}}, + character widths/.append/.code={\pgfkeysalso{/pgf/decoration/text effects/every character width/.append style={#1}}}, + character count/.store in=\tikz@lib@dec@te@charactercountvar, + character count=, + character total/.store in=\tikz@lib@dec@te@charactertotalvar, + character total=, + letter count/.store in=\tikz@lib@dec@te@lettercountvar, + letter count=, + letter total/.store in=\tikz@lib@dec@te@lettertotalvar, + letter total=, + word count/.store in=\tikz@lib@dec@te@wordcountvar, + word count=, + word total/.store in=\tikz@lib@dec@te@wordtotalvar, + word total=, + % + style characters/.code args={#1 with #2}{\tikz@lib@dec@te@parse@stylecharacters{#1}{#2}}, + text along path/.style={ + inner xsep=0pt, + anchor=base, + transform shape + }, + segment from width/.is if=tikz@lib@dec@te@segmentfromwidth, + segment from width=true, + word separator/.code={% + \def\tikz@lib@dec@te@tmp{#1}% + \ifx\tikz@lib@dec@te@tmp\tikz@lib@dec@te@space@text% + \let\tikz@lib@dec@te@wordsep=\tikz@lib@dec@te@spacetoken% + \else% + \def\tikz@lib@dec@te@wordsep{#1} + \fi}, + word separator=space, + character command/.code={% + \def\tikz@lib@dec@te@tmp{#1}% + \ifx\tikz@lib@dec@te@tmp\pgfutil@empty% + \def\tikz@lib@dec@te@charactercommand{\tikz@lib@dec@te@charactertypesetonly}% + \else% + \def\tikz@lib@dec@te@charactercommand{#1}% + \fi% + }, + character command=, + every character width/.style={/pgf/decoration/text effects/every character/.try}, + every character/.style={}, + reverse text/.code={\tikz@lib@dec@te@addto@macro\tikz@lib@dec@te@transformtext% + {\tikz@lib@dec@te@reversetext}}, + group letters into words/.code={\tikz@lib@dec@te@addto@macro\tikz@lib@dec@te@transformtext% + {\tikz@lib@dec@te@groupletters}}, + group letters/.code={\tikz@lib@dec@te@addto@macro\tikz@lib@dec@te@transformtext% + {\tikz@lib@dec@te@groupletters}}, + replace characters/.code args={#1 with #2}{\tikz@lib@dec@te@parse@replacecharacters{#1}{#2}}, + scale text to path/.is if=tikz@lib@dec@te@scaletexttopath, + fit text to path/.is if=tikz@lib@dec@te@fittexttopath, + repeat text/.store in=\tikz@lib@dec@te@repeattext, + repeat text/.default=-1, + repeat text=0, +}% + + +\def\tikz@lib@dec@te@charactertypesetonly#1{#1}% + +\tikzset{% + text effects/.code={\pgfkeysalso{/pgf/decoration/text effects/.cd,#1}}, +}% + + + + + + +% Prepare the decoration text +% +% This sets up all the character/letter/word, counts/totals +% and calculates the default width of the characters/text +% (which may be modified later). +% +\def\tikz@lib@dec@te@preparetext{% + % Step 1: scan all the characters in the decoration text + \let\tikz@lib@dec@te@text=\pgfdecorationtext% + \tikz@lib@dec@te@scancharacters{% + \expandafter\let\csname tikz@lib@dec@te@character@\tikz@lib@dec@te@scancount @token\endcsname=% + \tikz@lib@dec@te@character% + }% + \let\tikz@lib@dec@te@charactertotalcount=\tikz@lib@dec@te@scancount% + % Step 2: reverse and/or group characters/letters. + \ifx\tikz@lib@dec@te@transformtext\pgfutil@empty% + \else% + \tikz@lib@dec@te@transformtext% + \fi% + % Step 3: get the character/letter/word counts + \def\tikz@lib@dec@te@charactercount{0}% + \def\tikz@lib@dec@te@wordcount{0}% + \def\tikz@lib@dec@te@wordsepcount{0}% + \def\tikz@lib@dec@te@lettercount{0}% + \def\tikz@lib@dec@te@lastcharacter{0}% + \pgfmathloop% + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \ifnum\tikz@lib@dec@te@lettercount>0\relax% + \tikz@lib@dec@te@addto@parameters{\tikz@lib@dec@te@lastcharactercount}{\tikz@lib@dec@te@finallettertrue}% + \fi + \else% + \expandafter\let\expandafter\tikz@lib@dec@te@character\expandafter=\csname tikz@lib@dec@te@character@\pgfmathcounter @token\endcsname% + \tikz@lib@dec@te@advancecountmacro{\tikz@lib@dec@te@charactercount}{1}% + \tikz@lib@dec@te@start@parameters{\tikz@lib@dec@te@charactercount}% + \tikz@lib@dec@te@addmacroto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@charactercount}% + \ifx\tikz@lib@dec@te@character\tikz@lib@dec@te@wordsep% + \tikz@lib@dec@te@advancecountmacro{\tikz@lib@dec@te@wordsepcount}{1}% + \ifnum\tikz@lib@dec@te@lettercount>0\relax% + \tikz@lib@dec@te@addto@parameters{\tikz@lib@dec@te@lastcharactercount}{\tikz@lib@dec@te@finallettertrue}% + \fi + \def\tikz@lib@dec@te@lettercount{0}% + \tikz@lib@dec@te@addto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@wordseptrue}% + \else + \ifnum\tikz@lib@dec@te@lettercount=0\relax% + \tikz@lib@dec@te@advancecountmacro\tikz@lib@dec@te@wordcount{1}% + \fi% + \tikz@lib@dec@te@addto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@finalletterfalse}% + \tikz@lib@dec@te@advancecountmacro{\tikz@lib@dec@te@lettercount}{1}% + \tikz@lib@dec@te@addto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@wordsepfalse}% + \expandafter\let\csname tikz@lib@dec@te@word \tikz@lib@dec@te@wordcount @lettercount\endcsname=\tikz@lib@dec@te@lettercount% + \fi% + \tikz@lib@dec@te@addmacroto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@lettercount}% + \tikz@lib@dec@te@addmacroto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@wordcount}% + \tikz@lib@dec@te@addmacroto@parameters{\tikz@lib@dec@te@charactercount}{\tikz@lib@dec@te@character}% + \let\tikz@lib@dec@te@lastcharactercount=\pgfmathcounter% + \repeatpgfmathloop% + \let\tikz@lib@dec@te@wordtotal=\tikz@lib@dec@te@wordcount% + % Step 4: add character/letter/word totals + \pgfmathloop + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \else% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@charactertotalcount}% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@wordtotal}% + \expandafter\let\expandafter\tikz@lib@dec@te@lettertotalcount\expandafter=\csname tikz@lib@dec@te@word \tikz@lib@dec@te@wordcount @lettercount\endcsname% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@lettertotalcount}% + \repeatpgfmathloop% + % Step 5: calculate the the text and character width + % but do not add to the parameters yet. + \def\tikz@lib@dec@te@textwidth{0pt}% + \pgfmathloop% + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \else% + \def\tikz@lib@dec@te@characterwidth{0pt}% + \tikz@lib@dec@te@getcharacterwidth{\pgfmathcounter}% + \expandafter\let\csname tikz@lib@dec@te@character@\pgfmathcounter @width\endcsname=\tikz@lib@dec@te@characterwidth% + \pgf@x=\tikz@lib@dec@te@characterwidth\relax% + \pgf@x=0.5\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @prewidth\endcsname{\the\pgf@x}% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @postwidth\endcsname{\the\pgf@x}% + \tikz@lib@dec@te@advancedimenmacro{\tikz@lib@dec@te@textwidth}{\tikz@lib@dec@te@characterwidth}% + \repeatpgfmathloop% +}% + +% Does the category code of the space matter? +\def\tikz@lib@dec@te@spacetoken{ }% + +\let\tikz@lib@dec@te@wordsep=\tikz@lib@dec@te@spacetoken + + +% Scan and count the characters in \tikz@lib@dec@te@text +% +% Create macros \tikz@lib@dec@te@character@@token containing +% the nth character. +% +% Total number of characters is store in +% \tikz@lib@dec@te@chractertotal@count +% +\def\tikz@lib@dec@te@scancharacters#1{% + \def\tikz@lib@dec@te@@@scancharacters@process{#1}% + \def\tikz@lib@dec@te@scancount{0}% + \expandafter\tikz@lib@dec@te@@scancharacters\tikz@lib@dec@te@text\tikz@lib@dec@te@scancharacters}% + +\def\tikz@lib@dec@te@@scancharacters{% + \futurelet\tikz@lib@dec@te@token\tikz@lib@dec@te@@@scancharacters}% + +\def\tikz@lib@dec@te@@@scancharacters{% + \ifx\tikz@lib@dec@te@token\tikz@lib@dec@te@scancharacters% + \let\tikz@lib@dec@te@next=\tikz@lib@dec@te@@@@scancharacters% + \else% + \tikz@lib@dec@te@advancecountmacro\tikz@lib@dec@te@scancount{1}% + \ifx\tikz@lib@dec@te@token\pgfutil@sptoken% + \let\tikz@lib@dec@te@next=\tikz@lib@dec@te@@@scancharacters@space% + \else% + \ifx\tikz@lib@dec@te@token\bgroup% + \let\tikz@lib@dec@te@next=\tikz@lib@dec@te@@@scancharacters@bgroup% + \else% + \let\tikz@lib@dec@te@next=\tikz@lib@dec@te@@@scancharacters@normal% + \fi% + \fi% + \fi% + \tikz@lib@dec@te@next% +}% + +\def\tikz@lib@dec@te@@@scancharacters@space{% + \let\tikz@lib@dec@te@character=\tikz@lib@dec@te@spacetoken% + \tikz@lib@dec@te@@@scancharacters@process% + \pgfutil@ifnextchar x\tikz@lib@dec@te@@scancharacters\tikz@lib@dec@te@@scancharacters% +}% + +\def\tikz@lib@dec@te@@@scancharacters@bgroup#1{% + \def\tikz@lib@dec@te@character{{#1}}% + \tikz@lib@dec@te@@@scancharacters@process% + \tikz@lib@dec@te@@scancharacters% +}% + +\def\tikz@lib@dec@te@@@scancharacters@normal#1{% + \def\tikz@lib@dec@te@character{#1}% + \tikz@lib@dec@te@@@scancharacters@process% + \tikz@lib@dec@te@@scancharacters% +}% + + +\def\tikz@lib@dec@te@@@@scancharacters#1\tikz@lib@dec@te@scancharacters{}% + + +% Reverse the order of the scanned characters in the text +% (Actually reverse the ordering of the macros containing the characters) +\def\tikz@lib@dec@te@reversetext{% + \c@pgf@counta=\tikz@lib@dec@te@charactertotalcount% + \pgfmathloop% + \ifnum\pgfmathcounter>\c@pgf@counta% + \else% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@tmp}{tikz@lib@dec@te@character@\pgfmathcounter @token}% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@character@\pgfmathcounter @token}{tikz@lib@dec@te@character@\the\c@pgf@counta @token}% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@character@\the\c@pgf@counta @token}{tikz@lib@dec@te@tmp}% + \advance\c@pgf@counta by-1\relax% + \repeatpgfmathloop% +}% + +% Group letters (i.e., anything that isn't the word separator) +% as single characters (words). +\def\tikz@lib@dec@te@groupletters{% + \c@pgf@counta=0\relax% + \let\tikz@lib@dec@te@tmp=\pgfutil@empty% + \let\tikz@lib@dec@te@@tmp=\pgfutil@empty% + \pgfmathloop% + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \ifx\tikz@lib@dec@te@@tmp\pgfutil@empty% + \else% + \advance\c@pgf@counta by1\relax% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@character@\the\c@pgf@counta @token}{tikz@lib@dec@te@@tmp}% + \fi% + \else% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@tmp}{tikz@lib@dec@te@character@\pgfmathcounter @token}% + \ifx\tikz@lib@dec@te@tmp\tikz@lib@dec@te@wordsep% + \advance\c@pgf@counta by1\relax% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@character@\the\c@pgf@counta @token}{tikz@lib@dec@te@@tmp}% + \let\tikz@lib@dec@te@@tmp=\pgfutil@empty% + \advance\c@pgf@counta by1\relax% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@character@\the\c@pgf@counta @token}{tikz@lib@dec@te@wordsep}% + \else% + \expandafter\tikz@lib@dec@te@addto@macro\expandafter{\expandafter\tikz@lib@dec@te@@tmp\expandafter}\expandafter{\tikz@lib@dec@te@tmp}% + \fi% + \repeatpgfmathloop% + \edef\tikz@lib@dec@te@charactertotalcount{\the\c@pgf@counta}% +}% + + +% Get width of node containing only the current character. +\def\tikz@lib@dec@te@getcharacterwidth#1{% + \csname tikz@lib@dec@te@character@#1\endcsname% + \tikz@lib@dec@te@getoptions{every character width/.try}% + \let\tikz@lib@dec@te@lastcharacterwidth=\tikz@lib@dec@te@characterwidth% + \pgfpositionnodelater\tikz@lib@dec@te@@getcharacterwidth% + \pgfutil@ifundefined{tikz@lib@dec@te@character@replacements@\meaning\tikz@lib@dec@te@character @code}{% + \expandafter\node\expandafter[\tikz@lib@dec@te@options,scale=\tikz@lib@dec@scaledcharacterwidthfactor]% + {\hbox{\tikz@lib@dec@te@charactercommand{\tikz@lib@dec@te@character}}};% + \let\tikz@lib@dec@te@characterwidth=\tikz@lib@dec@te@characterwidth@tmp% + }{% + \tikz@lib@dec@te@getcharacter@replacementwidth{\tikz@lib@dec@te@character}% + \let\tikz@lib@dec@te@characterwidth=\tikz@lib@dec@te@character@replacementwidth% + }% +}% + +% Update the character parameters with the widths. +\def\tikz@lib@dec@te@addwidthstoparameters{% + \pgfmathloop% + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \else% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@characterwidth}{tikz@lib@dec@te@character@\pgfmathcounter @width}% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@characterprewidth}{tikz@lib@dec@te@character@\pgfmathcounter @prewidth}% + \tikz@lib@dec@te@namelet{tikz@lib@dec@te@characterpostwidth}{tikz@lib@dec@te@character@\pgfmathcounter @postwidth}% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@characterwidth}% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@characterprewidth}% + \tikz@lib@dec@te@addmacroto@parameters{\pgfmathcounter}{\tikz@lib@dec@te@characterpostwidth}% + \repeatpgfmathloop% +}% + +% Get the options to applied to a character node. + +\def\tikz@lib@dec@te@addoptions#1{% + \expandafter\def\expandafter\tikz@lib@dec@te@options\expandafter{\tikz@lib@dec@te@options,#1}% +}% + +\def\tikz@lib@dec@te@getoptions#1{% + \let\tikz@lib@dec@te@lastcharactercommand=\tikz@lib@dec@te@charactercommand% + \def\tikz@lib@dec@te@options{/pgf/decoration/text effects/.cd}% + \tikz@lib@dec@te@addoptions{#1}% + \let\tikzdecorationcharactercount=\tikz@lib@dec@te@charactercount% + \let\tikzdecorationcharactertotal=\tikz@lib@dec@te@charactertotalcount% + \let\tikzdecorationlettercount=\tikz@lib@dec@te@lettercount% + \let\tikzdecorationlettertotal=\tikz@lib@dec@te@lettertotalcount% + \let\tikzdecorationwordcount=\tikz@lib@dec@te@wordcount% + \let\tikzdecorationwordtotal=\tikz@lib@dec@te@wordtotal% + \let\tikzdecorationcharacter=\tikz@lib@dec@te@character% + % + % Define the count variables (if required) + \ifx\tikz@lib@dec@te@charactercountvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@charactercountvar=\tikz@lib@dec@te@charactercount% + \fi% + % + \ifx\tikz@lib@dec@te@charactertotalvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@charactertotalvar=\tikz@lib@dec@te@charactertotalcount% + \fi% + % + \ifx\tikz@lib@dec@te@wordcountvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@wordcountvar=\tikz@lib@dec@te@wordcount% + \fi% + % + \ifx\tikz@lib@dec@te@wordtotalvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@wordtotalvar=\tikz@lib@dec@te@wordtotal% + \fi% + % + \ifx\tikz@lib@dec@te@lettercountvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@lettercountvar=\tikz@lib@dec@te@lettercount% + \fi% + % + \ifx\tikz@lib@dec@te@lettertotalvar\pgfutil@empty% + \else% + \expandafter\let\tikz@lib@dec@te@lettertotalvar=\tikz@lib@dec@te@lettetotal% + \fi% + % + \edef\tikz@lib@dec@te@tmp{character \tikz@lib@dec@te@charactercount/.try,% + character {\meaning\tikz@lib@dec@te@character}/.try}% + \expandafter\tikz@lib@dec@te@addoptions\expandafter{\tikz@lib@dec@te@tmp}% + \ifx\tikz@lib@dec@te@character\tikz@lib@dec@te@wordsep% + \tikz@lib@dec@te@addoptions{/pgf/decoration/text effects/every word separator/.try}% + \else% + \ifnum\tikz@lib@dec@te@wordcount>0\relax% + \edef\tikz@lib@dec@te@tmp{every word/.try, word \tikz@lib@dec@te@wordcount/.try}% + \expandafter\tikz@lib@dec@te@addoptions\expandafter{\tikz@lib@dec@te@tmp}% + \ifnum\tikz@lib@dec@te@lettercount>0\relax% + \edef\tikz@lib@dec@te@tmp{every letter/.try,every \tikz@lib@dec@te@lettercount\space letter/.try}% + \expandafter\tikz@lib@dec@te@addoptions\expandafter{\tikz@lib@dec@te@tmp}% + \ifnum\tikz@lib@dec@te@lettercount=1\relax% + \edef\tikz@lib@dec@te@tmp{every first letter/.try}% + \expandafter\tikz@lib@dec@te@addoptions\expandafter{\tikz@lib@dec@te@tmp}% + \fi% + \iftikz@lib@dec@te@finalletter% + \tikz@lib@dec@te@addoptions{every final letter/.try}% + \fi% + \fi% + \fi% + \fi% +}% + +% Called by `late positioning' of the node +% to get the width of the bounding box +% of a character. +\def\tikz@lib@dec@te@@getcharacterwidth{% + \iftikz@lib@dec@te@segmentfromwidth% + \pgf@x=\pgfpositionnodelatermaxx\relax% + \advance\pgf@x by-\pgfpositionnodelaterminx\relax% + \else% + \pgf@x=\pgfpositionnodelatermaxy\relax% + \advance\pgf@x by-\pgfpositionnodelaterminy\relax% + \fi% + \xdef\tikz@lib@dec@te@characterwidth@tmp{\the\pgf@x}% +}% + + +\def\tikz@lib@dec@te@drawcharacter{% + \csname tikz@lib@dec@te@character@\tikz@lib@dec@te@charactercount\endcsname% + \tikz@lib@dec@te@getoptions{every character/.try}% + \pgfpositionnodelater\relax% + \pgfutil@ifundefined{tikz@lib@dec@te@character@replacements@\meaning\tikz@lib@dec@te@character @code}{% + \expandafter\node\expandafter[\tikz@lib@dec@te@options, scale=\tikz@lib@dec@scaledcharacterwidthfactor]{\hbox{\tikz@lib@dec@te@charactercommand{\tikz@lib@dec@te@character}}};% + }{\tikz@lib@dec@te@drawcharacter@replacement{\tikz@lib@dec@te@character}}% +}% + +% Replace the character #1 with a character@replacement +% +\def\tikz@lib@dec@te@drawcharacter@replacement#1{% + \pgfscope% + \expandafter\tikzset\expandafter{\tikz@lib@dec@te@options}% + \csname tikz@lib@dec@te@character@replacements@\meaning#1@code\endcsname% + \endpgfscope% +}% + +% Get the width of the character@replacement associated with +% the character #1 +% +\newbox\tikz@lib@dec@te@box +\def\tikz@lib@dec@te@getcharacter@replacementwidth#1{% + \pgfinterruptpicture% + \setbox\tikz@lib@dec@te@box=\hbox{% + \pgfpicture + \expandafter\tikzset\expandafter{\tikz@lib@dec@te@options}% + \csname tikz@lib@dec@te@character@replacements@\meaning#1@code\endcsname% + \endpgfpicture}% + \xdef\tikz@lib@dec@te@character@replacementwidth{\the\wd\tikz@lib@dec@te@box}% + \endpgfinterruptpicture% +}% + +\def\tikz@lib@dec@scaledcharacterwidthfactor{1}% + +% Set up the decoration +\def\tikz@lib@dec@te@state@setup@precomputation{% + \def\tikz@lib@te@alignshift{0pt}% + \iftikz@lib@dec@te@pathfromtext% + % The width of the text and characters has already been calculated. + \else% + \let\tikz@lib@dec@te@text=\pgfdecorationtext% + % Get the character tokens and the total number of characters. + \tikz@lib@dec@te@preparetext% + \iftikz@lib@dec@te@scaletexttopath% + % OK, *scaling* text to path is easy. + % Simply divide the path length by the text width to + % obtain the scaling factor which will be applied + % "at the last minute"... + \pgfmathdivide{\pgfdecoratedpathlength}{\tikz@lib@dec@te@textwidth}% + \let\tikz@lib@dec@scaledcharacterwidthfactor=\pgfmathresult% + \expandafter\pgfkeys\expandafter{\tikz@lib@dec@te@tmp}% + % ... and recalculate the (pre and post) widths. + \pgfmathloop + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount% + \else% + \pgf@x=\csname tikz@lib@dec@te@character@\pgfmathcounter @prewidth\endcsname\relax% + \pgf@x=\tikz@lib@dec@scaledcharacterwidthfactor\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @prewidth\endcsname{\the\pgf@x}% + % + \pgf@x=\csname tikz@lib@dec@te@character@\pgfmathcounter @postwidth\endcsname\relax% + \pgf@x=\tikz@lib@dec@scaledcharacterwidthfactor\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @postwidth\endcsname{\the\pgf@x}% + \repeatpgfmathloop% + % Update parameters with thewidths. + \tikz@lib@dec@te@addwidthstoparameters% + \let\tikz@lib@dec@te@textwidth=\pgfdecoratedpathlength% + \else% + \iftikz@lib@dec@te@fittexttopath% + % *Fitting* text is less easy. + % The pre and post width of all except the first and last characters + % must be recalculated. + % Only the post width of the first character and the pre width + % of the final character are scaled as these characters should be + % fixed and the start and end of the path, respectively. + % + % We hope that the decoration engine is accurate enough to position + % the last word correctly. + \pgf@x=\pgfdecoratedpathlength% + \pgf@xa=\csname tikz@lib@dec@te@character@1@postwidth\endcsname\relax% + \pgf@xb=\csname tikz@lib@dec@te@character@\tikz@lib@dec@te@charactertotalcount @prewidth\endcsname\relax% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@x by-\pgf@xb% + \pgf@y=\tikz@lib@dec@te@textwidth\relax% + \advance\pgf@y by-\pgf@xa% + \advance\pgf@y by-\pgf@xb% + % + \pgfmathdivide{\the\pgf@x}{\the\pgf@y}% + \let\tikz@lib@dec@characterwidthscale=\pgfmathresult% + \pgfmathloop + \ifnum\pgfmathcounter>\tikz@lib@dec@te@charactertotalcount\relax% + \else% + \ifnum\pgfmathcounter>1\relax% + \pgf@x=\csname tikz@lib@dec@te@character@\pgfmathcounter @prewidth\endcsname\relax% + \pgf@x=\tikz@lib@dec@characterwidthscale\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @prewidth\endcsname{\the\pgf@x}% + \fi% + \ifnum\pgfmathcounter<\tikz@lib@dec@te@charactertotalcount\relax% + \pgf@x=\csname tikz@lib@dec@te@character@\pgfmathcounter @postwidth\endcsname\relax% + \pgf@x=\tikz@lib@dec@characterwidthscale\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\pgfmathcounter @postwidth\endcsname{\the\pgf@x}% + \fi% + \repeatpgfmathloop% + % Update parameters with widths. + \tikz@lib@dec@te@addwidthstoparameters% + \let\tikz@lib@dec@te@textwidth=\pgfdecoratedpathlength% + \else% + % Calculate the distance to move along the path for alignment. + \pgfkeysgetvalue{/pgf/decoration/text align/align}{\tikz@lib@dec@align}% + \ifx\tikz@lib@dec@align\tikz@lib@dec@align@center@text% + \pgf@x=\pgfdecoratedpathlength\relax% + \advance\pgf@x by-\tikz@lib@dec@te@textwidth\relax% + \ifdim\pgf@x<0pt\relax% + \pgf@x=0pt\relax% + \fi% + \divide\pgf@x by2\relax% + % Adjust the pre-width of the first character... + \pgf@xa=\csname tikz@lib@dec@te@character@1@prewidth\endcsname\relax% + \advance\pgf@xa by\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@1@prewidth\endcsname{\the\pgf@xa}% + % ...and the post-width of the last character. + \pgf@xa=\csname tikz@lib@dec@te@character@\tikz@lib@dec@te@charactertotalcount @postwidth\endcsname\relax% + \advance\pgf@xa by\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@\tikz@lib@dec@te@charactertotalcount @postwidth\endcsname{\the\pgf@xa}% + \else% + \ifx\tikz@lib@dec@align\tikz@lib@dec@align@right@text% + \pgf@x=\pgfdecoratedpathlength\relax% + \advance\pgf@x by-\tikz@lib@dec@te@textwidth\relax% + \ifdim\pgf@x<0pt\relax% + \pgf@x=0pt\relax% + \fi% + % Adjust the pre-width of the first character... + \pgf@xa=\csname tikz@lib@dec@te@character@1@prewidth\endcsname\relax% + \advance\pgf@xa by\pgf@x% + \expandafter\edef\csname tikz@lib@dec@te@character@1@prewidth\endcsname{\the\pgf@xa}% + \fi% + \fi% + \tikz@lib@dec@te@addwidthstoparameters% + \fi% + \fi% + \fi% +}% + + +% Evil hack into the decoration code. +% +% If the path contains single move to and the `path from text' +% key is set to true. The width of the text is calculated here +% and the (straight line) path automatically calculated. +% +\def\pgf@decorate@path@check@moveto#1{% + \expandafter\pgf@decorate@path@@check@moveto#1\pgf@decorate@stop\pgf@decorate@@stop}% + +\def\pgf@decorate@token@stop{\pgf@decorate@stop}% +\def\pgf@decorate@path@@check@moveto#1#2#3#4\pgf@decorate@@stop#5#6{% + \def\pgf@decorate@temp{#4}% + \pgf@x=#2\relax% + \pgf@y=#3\relax% + \ifx\pgf@decorate@temp\pgf@decorate@token@stop% + \iftikz@lib@dec@te@pathfromtext% + % Get the start position... + \pgfextract@process\tikz@lib@dec@te@pathstart{}% + \tikz@lib@dec@te@preparetext% + \tikz@lib@dec@te@addwidthstoparameters% + % ... and create a lineto path of the correct length. + \pgfsetpath\pgfutil@empty% + \pgfpathmoveto{\tikz@lib@dec@te@pathstart}% + \pgfpathlineto{\pgfpointadd{\tikz@lib@dec@te@pathstart}% + {\pgfpointpolar{\tikz@lib@dec@te@pathfromtextangle}{\tikz@lib@dec@te@textwidth}}}% + \pgfgetpath\pgfdecoratedpath% + \pgfsetpath\pgfutil@empty% + \else% + #5% + \fi% + \else% + \tikz@lib@dec@te@pathfromtextfalse% + #6% + \fi% +}% + + +\pgfdeclaredecoration{text effects along path}{setup}{% + \state{setup}[width=+0pt, next state=scan, persistent precomputation={% + \tikz@lib@dec@te@state@setup@precomputation% + \def\tikz@lib@dec@te@charactercount{0}% + }]{}% + % +\state{scan}[width=+0pt, next state=pre token, persistent precomputation={% + \tikz@lib@dec@te@advancecountmacro\tikz@lib@dec@te@charactercount{1}% + % Usual switch to final state is based on distance. + % Here we also need it to be on the number of the + % current character. + \ifnum\tikz@lib@dec@te@charactercount>\tikz@lib@dec@te@charactertotalcount\relax% + \ifnum\tikz@lib@dec@te@repeattext=0\relax% + \def\pgf@decorate@next@state{final}% + \else% + \tikz@lib@dec@te@advancecountmacro\tikz@lib@dec@te@repeattext{-1}% + \def\tikz@lib@dec@te@charactercount{1}% + \fi% + \fi% + % Install parameters for this character. + \csname tikz@lib@dec@te@character@\tikz@lib@dec@te@charactercount\endcsname% +}]{}% +% +\state{pre token}[width=+\tikz@lib@dec@te@characterprewidth, next state=token]{}% +\state{token}[width=+0pt, next state=post token] +{% + \tikz@lib@dec@te@drawcharacter% +}% +\state{post token}[width=+\tikz@lib@dec@te@characterpostwidth, next state=scan]{}% +}% + + +% Parse styles for individual characters +% #1 a string of characters (e.g., aieou{\"U}{\"a"}) +% #2 the options for to apply to each character. +% +\def\tikz@lib@dec@te@parse@stylecharacters#1#2{% + \def\tikz@lib@dec@te@text{#1}% + \tikz@lib@dec@te@scancharacters{% + \pgfkeysalso{/pgf/decoration/text effects/character {\meaning\tikz@lib@dec@te@character}/.style={#2}}% + }% +}% + +% Parse replacement code for for individual characters +% #1 a string of characters (e.g., aieou{\"U}{\"a"}) +% #2 the code to execute to each character. +% +\def\tikz@lib@dec@te@parse@replacecharacters#1#2{% + \def\tikz@lib@dec@te@text{#1}% + \tikz@lib@dec@te@scancharacters{% + \expandafter\def\csname tikz@lib@dec@te@character@replacements@\meaning\tikz@lib@dec@te@character @code\endcsname{#2}% + }% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryer.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryer.code.tex new file mode 100644 index 0000000000..acb9b04997 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryer.code.tex @@ -0,0 +1,40 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryer.code.tex} + +\usetikzlibrary{shapes.geometric}% + +% Styles for entity types: + +\tikzset{every entity/.style= {}}% +\tikzset{entity/.style= {rectangle,draw, + minimum height=2\baselineskip, + minimum width=4\baselineskip,every entity}}% + + +% Styles for relationship types: + +\tikzset{every relationship/.style= {}}% +\tikzset{relationship/.style= {diamond,draw, + minimum size=1.5\baselineskip, + inner sep=1pt, + every relationship}}% + + +% Styles for relationship types: + +\tikzset{every attribute/.style= {}}% +\tikzset{attribute/.style= {minimum size=1.5\baselineskip,ellipse,draw,every attribute}}% +\tikzset{key attribute/.style= {font=\itshape,attribute}}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfadings.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfadings.code.tex new file mode 100644 index 0000000000..bddc83cb5c --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfadings.code.tex @@ -0,0 +1,48 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryfadings.code.tex} + +\usepgflibrary{fadings}% + +% +% Environments for creating fadings +% + +\def\tikzfadingfrompicture{% + \begingroup% + \setbox\pgfpic=\hbox\bgroup% + \tikzpicture% +}% +\def\endtikzfadingfrompicture{% + \global\let\tikz@smuggle=\tikz@fig@name% + \endtikzpicture + \egroup% + \pgfdeclarefading{\tikz@smuggle}{\box\pgfpic}% + \endgroup% +}% + +% This makes it easier to maintain compatibility with the external lib: +\def\starttikzfadingfrompicture{\tikzfadingfrompicture}% +\def\stopttikzfadingfrompicture{\endtikzfadingfrompicture}% + +\def\tikzfading[#1]{% + {% + \setbox\pgfpic=\hbox{% + \tikzset{#1}% + \global\let\tikz@smuggle=\tikz@fig@name% + \tikz{% + \useasboundingbox(0,0) (100bp,100bp); + \node at (50bp,50bp) [rotate=\tikz@shade@angle] + {\pgfuseshading{\tikz@shading}}; + }% + }% + \pgfdeclarefading{\tikz@smuggle}{\box\pgfpic}% + }% +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex new file mode 100644 index 0000000000..b104a519c3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex @@ -0,0 +1,132 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryfit.code.tex} + +\pgfqkeys{/tikz}{% + fit/.code=\tikz@lib@fit{#1}, + rotate fit/.code={% + \pgfmathsetmacro\tikz@lib@fit@rotate{#1}% + \pgfkeysalso{/tikz/rotate=\tikz@lib@fit@rotate}% + }, +}% + +\def\tikz@lib@fit@rotate{0}% + +\def\tikz@lib@fit#1{% + \pgf@xb=-16000pt\relax% + \pgf@xa=16000pt\relax% + \pgf@yb=-16000pt\relax% + \pgf@ya=16000pt\relax% + % + % Now iterate over the coordinates + \tikz@lib@fit@scan#1\pgf@stop% + % Now, let's see what has happened + \ifdim\pgf@xa>\pgf@xa% + % Nothing... Ok, let's just ignore this. + \else% + % Ok, compute center and width and height + \pgf@x=\pgf@xb% + \advance\pgf@x by-\pgf@xa% + \pgf@y=\pgf@yb% + \advance\pgf@y by-\pgf@ya% + \advance\pgf@xa by.5\pgf@x% + \advance\pgf@ya by.5\pgf@y% + \ifdim\tikz@lib@fit@rotate pt=0pt\relax% + {% + \pgftransforminvert% + \pgf@pos@transform{\pgf@xa}{\pgf@ya}% + \global\pgf@xa\pgf@xa + \global\pgf@ya\pgf@ya + } + \else% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + {% + \pgf@xc=\pgf@xa% + \pgf@yc=\pgf@ya% + \pgftransforminvert% + \pgf@pos@transform{\pgf@xc}{\pgf@yc}% + \pgftransformreset% + \pgftransformrotate{\tikz@lib@fit@rotate}% + \pgf@pos@transform{\pgf@xc}{\pgf@yc}% + \global\pgf@x=\pgf@xc% + \global\pgf@y=\pgf@yc% + }% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@x=\pgf@xc% + \pgf@y=\pgf@yc% + \fi% + \edef\tikz@node@at{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \pgfkeysalso{/tikz/anchor=center,/tikz/text badly centered}% + \pgfkeysalso{/tikz/text width/.expanded=\the\pgf@x}% + \pgf@x=\pgf@y% + \pgf@y=.5\pgf@y% + \pgfkeysalso{ + /tikz/transform shape=false, + /tikz/text height/.expanded=\the\pgf@y-.5\dp\pgfnodeparttextbox, + /tikz/text depth/.expanded=\the\pgf@x-\noexpand\the\ht\pgfnodeparttextbox}% + \pgfkeysalso{every fit/.try}% + \fi% +}% + +\def\tikz@lib@fit@scan{% + \pgfutil@ifnextchar\pgf@stop{\pgfutil@gobble} + {\tikz@scan@one@point\tikz@lib@fit@scan@handle}}% + +\def\tikz@lib@fit@scan@handle#1{% + \iftikz@shapeborder% + % Ok, fit all four external anchors, if they exist + \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{west}}% + \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{east}}% + \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{north}}% + \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{south}}% + \else% + \tikz@lib@fit@adjust{#1}% + \fi% + \tikz@lib@fit@scan% +}% + +\def\tikz@lib@fit@adjust#1{% + \ifdim\tikz@lib@fit@rotate pt=0pt\relax% + \pgf@process{\pgfpointtransformed{#1}}% + \else% + {% + \pgf@process{\pgfpointtransformed{#1}}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfgettransform\tikz@lib@fit@transform% + \pgftransforminvert% + \pgf@pos@transform{\pgf@xc}{\pgf@yc}% + \pgftransformreset% + \pgftransformrotate{-\tikz@lib@fit@rotate}% + \pgf@pos@transform{\pgf@xc}{\pgf@yc}% + \pgfsettransform\tikz@lib@fit@transform% + \pgf@pos@transform{\pgf@xc}{\pgf@yc}% + \global\pgf@x=\pgf@xc% + \global\pgf@y=\pgf@yc% + }% + \fi% + \ifdim\pgf@x<\pgf@xa% + \pgf@xa=\pgf@x% + \fi% + \ifdim\pgf@y<\pgf@ya% + \pgf@ya=\pgf@y% + \fi% + \ifdim\pgf@x>\pgf@xb% + \pgf@xb=\pgf@x% + \fi% + \ifdim\pgf@y>\pgf@yb% + \pgf@yb=\pgf@y% + \fi% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfixedpointarithmetic.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfixedpointarithmetic.code.tex new file mode 100644 index 0000000000..76616a6ddd --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfixedpointarithmetic.code.tex @@ -0,0 +1,10 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{fixedpointarithmetic}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfolding.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfolding.code.tex new file mode 100644 index 0000000000..4974fffa50 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfolding.code.tex @@ -0,0 +1,2444 @@ +% Copyright 2018 by Till Tantau +% Copyright 2018 by Nico Van Cleemput +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryfolding.code.tex} + + +% +% Length of a standard line in a folding +% + +\tikzoption{folding line length}{\pgfmathsetlength\tikz@lib@fold@length{#1}}% +\newdimen\tikz@lib@fold@length +\tikz@lib@fold@length=2cm + + +% Faces +% ----- + +\def\tikz@lib@fold@triangle#1#2#3#4{% + \scope[xshift=.5\tikz@lib@fold@length,yshift=.28868\tikz@lib@fold@length] + #1 + \endscope + \scope[shift={(60:\tikz@lib@fold@length)},rotate=-60] + #2 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #3 + \endscope + \scope[rotate=60] + #4 + \endscope +}% + +\def\tikz@lib@fold@square#1#2#3#4#5{% + \scope[xshift=.5\tikz@lib@fold@length,yshift=.5\tikz@lib@fold@length] + #1 + \endscope + \scope[yshift=\tikz@lib@fold@length] + #2 + \endscope + \scope[xshift=\tikz@lib@fold@length,yshift=\tikz@lib@fold@length,rotate=-90] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=90] + #5 + \endscope +}% + +\def\tikz@lib@fold@squarerhombusr#1#2#3#4#5{% right leaning "square-of-two" rhombus + \scope[xshift=.63\tikz@lib@fold@length,yshift=.4755\tikz@lib@fold@length,xslant=0.34] + #1 + \endscope + \scope[shift={(70.529:\tikz@lib@fold@length)}] + #2 + \endscope + \scope[shift={(35.264:1.63299\tikz@lib@fold@length)},rotate=-109.471] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=70.529] + #5 + \endscope +}% + +\def\tikz@lib@fold@squarerhombusl#1#2#3#4#5{% left leaning "square-of-two" rhombus + \scope[xshift=.33\tikz@lib@fold@length,yshift=.4755\tikz@lib@fold@length,xslant=-0.34] + #1 + \endscope + \scope[shift={(109.471:\tikz@lib@fold@length)}] + #2 + \endscope + \scope[shift={(54.736:1.1547\tikz@lib@fold@length)},rotate=-70.529] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=109.471] + #5 + \endscope +}% + +\def\tikz@lib@fold@goldenrhombusr#1#2#3#4#5{% right leaning golden rhombus + \scope[xshift=.724\tikz@lib@fold@length,yshift=.447\tikz@lib@fold@length, xslant=0.447] + #1 + \endscope + \scope[shift={(63.435:\tikz@lib@fold@length)}] + #2 + \endscope + \scope[shift={(31.717:1.701\tikz@lib@fold@length)},rotate=-116.565] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=63.435] + #5 + \endscope +}% + +\def\tikz@lib@fold@goldenrhombusl#1#2#3#4#5{% left leaning golden rhombus + \scope[xshift=.276\tikz@lib@fold@length,yshift=.447\tikz@lib@fold@length, xslant=-0.447] + #1 + \endscope + \scope[shift={(116.565:\tikz@lib@fold@length)}] + #2 + \endscope + \scope[shift={(58.283:1.051\tikz@lib@fold@length)},rotate=-63.435] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=116.565] + #5 + \endscope +}% + +\def\tikz@lib@fold@pentagon#1#2#3#4#5#6{% + \scope[xshift=.5\tikz@lib@fold@length,yshift=0.68819\tikz@lib@fold@length] + #1 + \endscope + \scope[shift={(108:\tikz@lib@fold@length)},shift={(36:\tikz@lib@fold@length)},rotate=-36] + #2 + \endscope + \scope[xshift=\tikz@lib@fold@length,shift={(72:\tikz@lib@fold@length)},rotate=-108] + #3 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #4 + \endscope + \scope[rotate=108] + #5 + \endscope + \scope[shift={(108:\tikz@lib@fold@length)},rotate=36] + #6 + \endscope +}% + +\def\tikz@lib@fold@hexagon#1#2#3#4#5#6#7{% + \scope + [shift={(60:\tikz@lib@fold@length)}] + #1 + \endscope + \scope + [shift={(120:\tikz@lib@fold@length)}, + shift={(60:\tikz@lib@fold@length)}] + #2 + \endscope + \scope + [shift={(120:\tikz@lib@fold@length)}, + shift={(60:\tikz@lib@fold@length)}, + xshift=\tikz@lib@fold@length, + rotate=-60] + #3 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + shift={(60:\tikz@lib@fold@length)}, + rotate=-120] + #4 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + rotate=180] + #5 + \endscope + \scope + [rotate=120] + #6 + \endscope + \scope + [shift={(120:\tikz@lib@fold@length)}, + rotate=60] + #7 + \endscope +}% + +\def\tikz@lib@fold@octagon#1#2#3#4#5#6#7#8#9{% + \scope[xshift=.5\tikz@lib@fold@length,yshift=1.20711\tikz@lib@fold@length] + #1 + \endscope + \scope[yshift=2.41421\tikz@lib@fold@length] + #2 + \endscope + \scope[xshift=\tikz@lib@fold@length,yshift=2.41421\tikz@lib@fold@length,rotate=-45] + #3 + \endscope + \scope[xshift=1.70711\tikz@lib@fold@length,yshift=1.70711\tikz@lib@fold@length,rotate=-90] + #4 + \endscope + \scope[xshift=1.70711\tikz@lib@fold@length,yshift=.70711\tikz@lib@fold@length,rotate=-135] + #5 + \endscope + \scope[xshift=\tikz@lib@fold@length,rotate=180] + #6 + \endscope + \scope[rotate=135] + #7 + \endscope + \scope[xshift=-.70711\tikz@lib@fold@length,yshift=.70711\tikz@lib@fold@length,rotate=90] + #8 + \endscope + \scope[xshift=-.70711\tikz@lib@fold@length,yshift=1.70711\tikz@lib@fold@length,rotate=45] + #9 + \endscope +}% + +\def\tikz@lib@fold@decagon#1#2#3#4#5#6#7{% + \scope[shift={(72:1.61803\tikz@lib@fold@length)}] %decagon inside a circle with radius the golden ratio has side length 1 + #1 + \endscope + \scope + [shift={(36:\tikz@lib@fold@length)}, + shift={(72:\tikz@lib@fold@length)}, + shift={(108:\tikz@lib@fold@length)}, + shift={(144:\tikz@lib@fold@length)}] + #2 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + shift={(36:\tikz@lib@fold@length)}, + shift={(72:\tikz@lib@fold@length)}, + shift={(108:\tikz@lib@fold@length)}, + shift={(144:\tikz@lib@fold@length)}, + rotate=-36] + #3 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + shift={(36:\tikz@lib@fold@length)}, + shift={(72:\tikz@lib@fold@length)}, + shift={(108:\tikz@lib@fold@length)}, + rotate=-72] + #4 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + shift={(36:\tikz@lib@fold@length)}, + shift={(72:\tikz@lib@fold@length)}, + rotate=-108] + #5 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + shift={(36:\tikz@lib@fold@length)}, + rotate=-144] + #6 + \endscope + \scope + [xshift=\tikz@lib@fold@length, + rotate=180] + #7 + \endscope + \tikz@lib@fold@decagonbis +}% + +\def\tikz@lib@fold@decagonbis#1#2#3#4{% + \scope + [rotate=144] + #1 + \endscope + \scope + [shift={(144:\tikz@lib@fold@length)}, + rotate=108] + #2 + \endscope + \scope + [shift={(144:\tikz@lib@fold@length)}, + shift={(108:\tikz@lib@fold@length)}, + rotate=72] + #3 + \endscope + \scope + [shift={(144:\tikz@lib@fold@length)}, + shift={(108:\tikz@lib@fold@length)}, + shift={(72:\tikz@lib@fold@length)}, + rotate=36] + #4 + \endscope +}% + +\def\tikz@lib@fold@path{\draw[every fold](0,0) -- (\tikz@lib@fold@length,0pt);}% +\def\tikz@lib@fold@cut@path{\draw[every cut](0,0) -- (\tikz@lib@fold@length,0pt);}% +\def\tikz@lib@fold@ear@path{ + \path[every ear] (0,0) -- (.5\tikz@lib@fold@length,.2\tikz@lib@fold@length) --(\tikz@lib@fold@length,0pt) --(0,0) -- cycle; + \draw[every fold](0,0) -- (\tikz@lib@fold@length,0pt); + \draw[every cut] (0,0) -- (.5\tikz@lib@fold@length,.2\tikz@lib@fold@length) --(\tikz@lib@fold@length,0pt);}% +\def\tikz@lib@fold@ear@custom@left@path#1{ + \path[every ear] (0,0) -- (#1:.66\tikz@lib@fold@length) -- (\tikz@lib@fold@length,0pt) --(0,0) -- cycle; + \draw[every fold](0,0) -- (\tikz@lib@fold@length,0pt); + \draw[every cut] (0,0) -- (#1:.66\tikz@lib@fold@length) -- (\tikz@lib@fold@length,0pt);}% +\def\tikz@lib@fold@ear@custom@right@path#1{ + \path[every ear] (0,0) -- (\tikz@lib@fold@length,0pt) -- ++(-#1:-.66\tikz@lib@fold@length) --(0,0) -- cycle; + \draw[every fold](0,0) -- (\tikz@lib@fold@length,0pt); + \draw[every cut] (\tikz@lib@fold@length,0pt) -- ++(-#1:-.66\tikz@lib@fold@length) -- (0,0);}% + +\tikzset{every ear/.style={}}% +\tikzset{every cut/.style={}}% +\tikzset{every fold/.style={help lines}}% + +\tikzoption{face 1}{\def\tikz@lib@fold@face@A{#1}}% +\tikzoption{face 2}{\def\tikz@lib@fold@face@B{#1}}% +\tikzoption{face 3}{\def\tikz@lib@fold@face@C{#1}}% +\tikzoption{face 4}{\def\tikz@lib@fold@face@D{#1}}% +\tikzoption{face 5}{\def\tikz@lib@fold@face@E{#1}}% +\tikzoption{face 6}{\def\tikz@lib@fold@face@F{#1}}% +\tikzoption{face 7}{\def\tikz@lib@fold@face@G{#1}}% +\tikzoption{face 8}{\def\tikz@lib@fold@face@H{#1}}% +\tikzoption{face 9}{\def\tikz@lib@fold@face@I{#1}}% +\tikzoption{face 10}{\def\tikz@lib@fold@face@J{#1}}% +\tikzoption{face 11}{\def\tikz@lib@fold@face@K{#1}}% +\tikzoption{face 12}{\def\tikz@lib@fold@face@L{#1}}% +\tikzoption{face 13}{\def\tikz@lib@fold@face@M{#1}}% +\tikzoption{face 14}{\def\tikz@lib@fold@face@N{#1}}% +\tikzoption{face 15}{\def\tikz@lib@fold@face@O{#1}}% +\tikzoption{face 16}{\def\tikz@lib@fold@face@P{#1}}% +\tikzoption{face 17}{\def\tikz@lib@fold@face@Q{#1}}% +\tikzoption{face 18}{\def\tikz@lib@fold@face@R{#1}}% +\tikzoption{face 19}{\def\tikz@lib@fold@face@S{#1}}% +\tikzoption{face 20}{\def\tikz@lib@fold@face@T{#1}}% +\tikzoption{face 21}{\def\tikz@lib@fold@face@U{#1}}% +\tikzoption{face 22}{\def\tikz@lib@fold@face@V{#1}}% +\tikzoption{face 23}{\def\tikz@lib@fold@face@W{#1}}% +\tikzoption{face 24}{\def\tikz@lib@fold@face@X{#1}}% +\tikzoption{face 25}{\def\tikz@lib@fold@face@Y{#1}}% +\tikzoption{face 26}{\def\tikz@lib@fold@face@Z{#1}}% +\tikzoption{face 27}{\def\tikz@lib@fold@face@AA{#1}}% +\tikzoption{face 28}{\def\tikz@lib@fold@face@AB{#1}}% +\tikzoption{face 29}{\def\tikz@lib@fold@face@AC{#1}}% +\tikzoption{face 30}{\def\tikz@lib@fold@face@AD{#1}}% +\tikzoption{face 31}{\def\tikz@lib@fold@face@AE{#1}}% +\tikzoption{face 32}{\def\tikz@lib@fold@face@AF{#1}}% +\tikzoption{face 33}{\def\tikz@lib@fold@face@AG{#1}}% +\tikzoption{face 34}{\def\tikz@lib@fold@face@AH{#1}}% +\tikzoption{face 35}{\def\tikz@lib@fold@face@AI{#1}}% +\tikzoption{face 36}{\def\tikz@lib@fold@face@AJ{#1}}% +\tikzoption{face 37}{\def\tikz@lib@fold@face@AK{#1}}% +\tikzoption{face 38}{\def\tikz@lib@fold@face@AL{#1}}% +\tikzoption{face 39}{\def\tikz@lib@fold@face@AM{#1}}% +\tikzoption{face 40}{\def\tikz@lib@fold@face@AN{#1}}% +\tikzoption{face 41}{\def\tikz@lib@fold@face@AO{#1}}% +\tikzoption{face 42}{\def\tikz@lib@fold@face@AP{#1}}% +\tikzoption{face 43}{\def\tikz@lib@fold@face@AQ{#1}}% +\tikzoption{face 44}{\def\tikz@lib@fold@face@AR{#1}}% +\tikzoption{face 45}{\def\tikz@lib@fold@face@AS{#1}}% +\tikzoption{face 46}{\def\tikz@lib@fold@face@AT{#1}}% +\tikzoption{face 47}{\def\tikz@lib@fold@face@AU{#1}}% +\tikzoption{face 48}{\def\tikz@lib@fold@face@AV{#1}}% +\tikzoption{face 49}{\def\tikz@lib@fold@face@AW{#1}}% +\tikzoption{face 50}{\def\tikz@lib@fold@face@AX{#1}}% +\tikzoption{face 51}{\def\tikz@lib@fold@face@AY{#1}}% +\tikzoption{face 52}{\def\tikz@lib@fold@face@AZ{#1}}% +\tikzoption{face 53}{\def\tikz@lib@fold@face@BA{#1}}% +\tikzoption{face 54}{\def\tikz@lib@fold@face@BB{#1}}% +\tikzoption{face 55}{\def\tikz@lib@fold@face@BC{#1}}% +\tikzoption{face 56}{\def\tikz@lib@fold@face@BD{#1}}% +\tikzoption{face 57}{\def\tikz@lib@fold@face@BE{#1}}% +\tikzoption{face 58}{\def\tikz@lib@fold@face@BF{#1}}% +\tikzoption{face 59}{\def\tikz@lib@fold@face@BG{#1}}% +\tikzoption{face 60}{\def\tikz@lib@fold@face@BH{#1}}% +\tikzoption{face 61}{\def\tikz@lib@fold@face@BI{#1}}% +\tikzoption{face 62}{\def\tikz@lib@fold@face@BJ{#1}}% +\tikzoption{face 63}{\def\tikz@lib@fold@face@BK{#1}}% +\tikzoption{face 64}{\def\tikz@lib@fold@face@BL{#1}}% +\tikzoption{face 65}{\def\tikz@lib@fold@face@BM{#1}}% +\tikzoption{face 66}{\def\tikz@lib@fold@face@BN{#1}}% +\tikzoption{face 67}{\def\tikz@lib@fold@face@BO{#1}}% +\tikzoption{face 68}{\def\tikz@lib@fold@face@BP{#1}}% +\tikzoption{face 69}{\def\tikz@lib@fold@face@BQ{#1}}% +\tikzoption{face 70}{\def\tikz@lib@fold@face@BR{#1}}% +\tikzoption{face 71}{\def\tikz@lib@fold@face@BS{#1}}% +\tikzoption{face 72}{\def\tikz@lib@fold@face@BT{#1}}% +\tikzoption{face 73}{\def\tikz@lib@fold@face@BU{#1}}% +\tikzoption{face 74}{\def\tikz@lib@fold@face@BV{#1}}% +\tikzoption{face 75}{\def\tikz@lib@fold@face@BW{#1}}% +\tikzoption{face 76}{\def\tikz@lib@fold@face@BX{#1}}% +\tikzoption{face 77}{\def\tikz@lib@fold@face@BY{#1}}% +\tikzoption{face 78}{\def\tikz@lib@fold@face@BZ{#1}}% +\tikzoption{face 79}{\def\tikz@lib@fold@face@CA{#1}}% +\tikzoption{face 80}{\def\tikz@lib@fold@face@CB{#1}}% +\tikzoption{face 81}{\def\tikz@lib@fold@face@CC{#1}}% +\tikzoption{face 82}{\def\tikz@lib@fold@face@CD{#1}}% +\tikzoption{face 83}{\def\tikz@lib@fold@face@CE{#1}}% +\tikzoption{face 84}{\def\tikz@lib@fold@face@CF{#1}}% +\tikzoption{face 85}{\def\tikz@lib@fold@face@CG{#1}}% +\tikzoption{face 86}{\def\tikz@lib@fold@face@CH{#1}}% +\tikzoption{face 87}{\def\tikz@lib@fold@face@CI{#1}}% +\tikzoption{face 88}{\def\tikz@lib@fold@face@CJ{#1}}% +\tikzoption{face 89}{\def\tikz@lib@fold@face@CK{#1}}% +\tikzoption{face 90}{\def\tikz@lib@fold@face@CL{#1}}% +\tikzoption{face 91}{\def\tikz@lib@fold@face@CM{#1}}% +\tikzoption{face 92}{\def\tikz@lib@fold@face@CN{#1}}% + + +\let\tikz@lib@fold@face@A=\pgfutil@empty +\let\tikz@lib@fold@face@B=\pgfutil@empty +\let\tikz@lib@fold@face@C=\pgfutil@empty +\let\tikz@lib@fold@face@D=\pgfutil@empty +\let\tikz@lib@fold@face@E=\pgfutil@empty +\let\tikz@lib@fold@face@F=\pgfutil@empty +\let\tikz@lib@fold@face@G=\pgfutil@empty +\let\tikz@lib@fold@face@H=\pgfutil@empty +\let\tikz@lib@fold@face@I=\pgfutil@empty +\let\tikz@lib@fold@face@J=\pgfutil@empty +\let\tikz@lib@fold@face@K=\pgfutil@empty +\let\tikz@lib@fold@face@L=\pgfutil@empty +\let\tikz@lib@fold@face@M=\pgfutil@empty +\let\tikz@lib@fold@face@N=\pgfutil@empty +\let\tikz@lib@fold@face@O=\pgfutil@empty +\let\tikz@lib@fold@face@P=\pgfutil@empty +\let\tikz@lib@fold@face@Q=\pgfutil@empty +\let\tikz@lib@fold@face@R=\pgfutil@empty +\let\tikz@lib@fold@face@S=\pgfutil@empty +\let\tikz@lib@fold@face@T=\pgfutil@empty +\let\tikz@lib@fold@face@U=\pgfutil@empty +\let\tikz@lib@fold@face@V=\pgfutil@empty +\let\tikz@lib@fold@face@W=\pgfutil@empty +\let\tikz@lib@fold@face@X=\pgfutil@empty +\let\tikz@lib@fold@face@Y=\pgfutil@empty +\let\tikz@lib@fold@face@Z=\pgfutil@empty +\let\tikz@lib@fold@face@AA=\pgfutil@empty +\let\tikz@lib@fold@face@AB=\pgfutil@empty +\let\tikz@lib@fold@face@AC=\pgfutil@empty +\let\tikz@lib@fold@face@AD=\pgfutil@empty +\let\tikz@lib@fold@face@AE=\pgfutil@empty +\let\tikz@lib@fold@face@AF=\pgfutil@empty +\let\tikz@lib@fold@face@AG=\pgfutil@empty +\let\tikz@lib@fold@face@AH=\pgfutil@empty +\let\tikz@lib@fold@face@AI=\pgfutil@empty +\let\tikz@lib@fold@face@AJ=\pgfutil@empty +\let\tikz@lib@fold@face@AK=\pgfutil@empty +\let\tikz@lib@fold@face@AL=\pgfutil@empty +\let\tikz@lib@fold@face@AM=\pgfutil@empty +\let\tikz@lib@fold@face@AN=\pgfutil@empty +\let\tikz@lib@fold@face@AO=\pgfutil@empty +\let\tikz@lib@fold@face@AP=\pgfutil@empty +\let\tikz@lib@fold@face@AQ=\pgfutil@empty +\let\tikz@lib@fold@face@AR=\pgfutil@empty +\let\tikz@lib@fold@face@AS=\pgfutil@empty +\let\tikz@lib@fold@face@AT=\pgfutil@empty +\let\tikz@lib@fold@face@AU=\pgfutil@empty +\let\tikz@lib@fold@face@AV=\pgfutil@empty +\let\tikz@lib@fold@face@AW=\pgfutil@empty +\let\tikz@lib@fold@face@AX=\pgfutil@empty +\let\tikz@lib@fold@face@AY=\pgfutil@empty +\let\tikz@lib@fold@face@AZ=\pgfutil@empty +\let\tikz@lib@fold@face@BA=\pgfutil@empty +\let\tikz@lib@fold@face@BB=\pgfutil@empty +\let\tikz@lib@fold@face@BC=\pgfutil@empty +\let\tikz@lib@fold@face@BD=\pgfutil@empty +\let\tikz@lib@fold@face@BE=\pgfutil@empty +\let\tikz@lib@fold@face@BF=\pgfutil@empty +\let\tikz@lib@fold@face@BG=\pgfutil@empty +\let\tikz@lib@fold@face@BH=\pgfutil@empty +\let\tikz@lib@fold@face@BI=\pgfutil@empty +\let\tikz@lib@fold@face@BJ=\pgfutil@empty +\let\tikz@lib@fold@face@BK=\pgfutil@empty +\let\tikz@lib@fold@face@BL=\pgfutil@empty +\let\tikz@lib@fold@face@BM=\pgfutil@empty +\let\tikz@lib@fold@face@BN=\pgfutil@empty +\let\tikz@lib@fold@face@BO=\pgfutil@empty +\let\tikz@lib@fold@face@BP=\pgfutil@empty +\let\tikz@lib@fold@face@BQ=\pgfutil@empty +\let\tikz@lib@fold@face@BR=\pgfutil@empty +\let\tikz@lib@fold@face@BS=\pgfutil@empty +\let\tikz@lib@fold@face@BT=\pgfutil@empty +\let\tikz@lib@fold@face@BU=\pgfutil@empty +\let\tikz@lib@fold@face@BV=\pgfutil@empty +\let\tikz@lib@fold@face@BW=\pgfutil@empty +\let\tikz@lib@fold@face@BX=\pgfutil@empty +\let\tikz@lib@fold@face@BY=\pgfutil@empty +\let\tikz@lib@fold@face@BZ=\pgfutil@empty +\let\tikz@lib@fold@face@CA=\pgfutil@empty +\let\tikz@lib@fold@face@CB=\pgfutil@empty +\let\tikz@lib@fold@face@CC=\pgfutil@empty +\let\tikz@lib@fold@face@CD=\pgfutil@empty +\let\tikz@lib@fold@face@CE=\pgfutil@empty +\let\tikz@lib@fold@face@CF=\pgfutil@empty +\let\tikz@lib@fold@face@CG=\pgfutil@empty +\let\tikz@lib@fold@face@CH=\pgfutil@empty +\let\tikz@lib@fold@face@CI=\pgfutil@empty +\let\tikz@lib@fold@face@CJ=\pgfutil@empty +\let\tikz@lib@fold@face@CK=\pgfutil@empty +\let\tikz@lib@fold@face@CL=\pgfutil@empty +\let\tikz@lib@fold@face@CM=\pgfutil@empty +\let\tikz@lib@fold@face@CN=\pgfutil@empty + + +\tikzset{numbered faces/.style={% + face 1={\node{1};}, + face 2={\node{2};}, + face 3={\node{3};}, + face 4={\node{4};}, + face 5={\node{5};}, + face 6={\node{6};}, + face 7={\node{7};}, + face 8={\node{8};}, + face 9={\node{9};}, + face 10={\node{10};}, + face 11={\node{11};}, + face 12={\node{12};}, + face 13={\node{13};}, + face 14={\node{14};}, + face 15={\node{15};}, + face 16={\node{16};}, + face 17={\node{17};}, + face 18={\node{18};}, + face 19={\node{19};}, + face 20={\node{20};}, + face 21={\node{21};}, + face 22={\node{22};}, + face 23={\node{23};}, + face 24={\node{24};}, + face 25={\node{25};}, + face 26={\node{26};}, + face 27={\node{27};}, + face 28={\node{28};}, + face 29={\node{29};}, + face 30={\node{30};}, + face 31={\node{31};}, + face 32={\node{32};}, + face 33={\node{33};}, + face 34={\node{34};}, + face 35={\node{35};}, + face 36={\node{36};}, + face 37={\node{37};}, + face 38={\node{38};}, + face 39={\node{39};}, + face 40={\node{40};}, + face 41={\node{41};}, + face 42={\node{42};}, + face 43={\node{43};}, + face 44={\node{44};}, + face 45={\node{45};}, + face 46={\node{46};}, + face 47={\node{47};}, + face 48={\node{48};}, + face 49={\node{49};}, + face 50={\node{50};}, + face 51={\node{51};}, + face 52={\node{52};}, + face 53={\node{53};}, + face 54={\node{54};}, + face 55={\node{55};}, + face 56={\node{56};}, + face 57={\node{57};}, + face 58={\node{58};}, + face 59={\node{59};}, + face 60={\node{60};}, + face 61={\node{61};}, + face 62={\node{62};}, + face 63={\node{63};}, + face 64={\node{64};}, + face 65={\node{65};}, + face 66={\node{66};}, + face 67={\node{67};}, + face 68={\node{68};}, + face 69={\node{69};}, + face 70={\node{70};}, + face 71={\node{71};}, + face 72={\node{72};}, + face 73={\node{73};}, + face 74={\node{74};}, + face 75={\node{75};}, + face 76={\node{76};}, + face 77={\node{77};}, + face 78={\node{78};}, + face 79={\node{79};}, + face 80={\node{80};}, + face 81={\node{81};}, + face 82={\node{82};}, + face 83={\node{83};}, + face 84={\node{84};}, + face 85={\node{85};}, + face 86={\node{86};}, + face 87={\node{87};}, + face 88={\node{88};}, + face 89={\node{89};}, + face 90={\node{90};}, + face 91={\node{91};}, + face 92={\node{92};}}}% + +% The foldings defined here: + +\tikzset{ + pics/dodecahedron folding/.style = {code=\tikzfoldingdodecahedron[];}, + pics/tetrahedron folding/.style = {code=\tikzfoldingtetrahedron[];}, + pics/tetrahedron truncated folding/.style = {code=\tikzfoldingtruncatedtetrahedron[];}, + pics/cube folding/.style = {code=\tikzfoldingcube[];}, + pics/cube truncated folding/.style = {code=\tikzfoldingtruncatedcube[];}, + pics/octahedron folding/.style = {code=\tikzfoldingoctahedron[];}, + pics/octahedron truncated folding/.style = {code=\tikzfoldingtruncatedoctahedron[];}, + pics/dodecahedron folding/.style = {code=\tikzfoldingdodecahedron[];}, + pics/dodecahedron' folding/.style = {code=\tikzfoldingalternatedodecahedron[];}, + pics/dodecahedron rhombic folding/.style = {code=\tikzfoldingrhombicdodecahedron[];}, + pics/dodecahedron golden folding/.style = {code=\tikzfoldinggoldenrhombicdodecahedron[];}, + pics/cuboctahedron folding/.style = {code=\tikzfoldingcuboctahedron[];}, + pics/cuboctahedron truncated folding/.style = {code=\tikzfoldingtruncatedcuboctahedron[];}, + pics/icosahedron folding/.style = {code=\tikzfoldingicosahedron[];}, + pics/rhombicuboctahedron folding/.style = {code=\tikzfoldingrhombicuboctahedron[];}, + pics/snub cube folding/.style = {code=\tikzfoldingsnubcube[];}, + pics/icosidodecahedron folding/.style = {code=\tikzfoldingicosidodecahedron[];} +}% + + + +% Platonic solids +% --------------- + +\def\tikzfoldingdodecahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@pentagon + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%alternative dodecahedron: larger format possible + +\def\tikzfoldingalternatedodecahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@pentagon + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@pentagon + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + \endgroup +}% + + +%tetrahedron + +\def\tikzfoldingtetrahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@triangle + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%cube + +\def\tikzfoldingcube#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@square{\tikz@lib@fold@face@A} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@B} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + { + \tikz@lib@fold@square{\tikz@lib@fold@face@C} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@square{\tikz@lib@fold@face@D} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + { + \tikz@lib@fold@square{\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + + +%octahedron + +\def\tikzfoldingoctahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@triangle + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + \endgroup +}% + + +%icosahedron + +\def\tikzfoldingicosahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@triangle + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@O} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@P} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@Q} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@R} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@S} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@T} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + \endgroup +}% + +% Archimedean solids +% ------------------ + +%truncated tetrahedron + +\def\tikzfoldingtruncatedtetrahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@hexagon + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%cuboctahedron + +\def\tikzfoldingcuboctahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@square + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%truncated cube + +\def\tikzfoldingtruncatedcube#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@octagon + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + \endgroup +}% + + +%truncated octahedron + +\def\tikzfoldingtruncatedoctahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@hexagon + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + \endgroup +}% + + +%rhombicuboctahedron + +\def\tikzfoldingrhombicuboctahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@square + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@O} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@P} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@Q} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@R} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@S} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@T} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@U} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@V} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@W} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@triangle + {\tikz@lib@fold@face@X} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@square + {\tikz@lib@fold@face@Y} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@Z} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + \endgroup +}% + +%truncated cuboctahedron + +\def\tikzfoldingtruncatedcuboctahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@square + {\tikz@lib@fold@face@A} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@B} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@C} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@D} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@E} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@I} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@J} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@K} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@L} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@M} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@N} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@O} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@P} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@Q} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@R} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@S} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@T} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@U} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@V} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@W} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@square + {\tikz@lib@fold@face@X} + {\tikz@lib@fold@octagon + {\tikz@lib@fold@face@Y} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@hexagon + {\tikz@lib@fold@face@Z} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{15}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@custom@left@path{15}} + {\tikz@lib@fold@ear@path} + } + \endgroup +}% + +%snub cube + +\def\tikzfoldingsnubcube#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@square{\tikz@lib@fold@face@A} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@B} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@C} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@E} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@F} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@I} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@J} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@K} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@L} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@M} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@N} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@O} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@P} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@Q} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@R} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@S} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@T} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@U} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@V} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@W} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@X} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@Y} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@Z} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AA} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AB} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AC} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AD} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AE} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@AF} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AG} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AH} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AI} + { + \tikz@lib@fold@square{\tikz@lib@fold@face@AJ} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AK} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AL} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +% icosidodecahedron + +\def\tikzfoldingicosidodecahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@A} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@B} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@C} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@D} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@E} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@F} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@G} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@I} + {\tikz@lib@fold@ear@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@J} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@K} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@L} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@M} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@N} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@O} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@P} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@Q} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@R} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@S} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@T} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@U} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@V} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@W} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@X} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@Y} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@Z} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + } + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AA} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@AB} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AC} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { + \tikz@lib@fold@pentagon{\tikz@lib@fold@face@AD} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AE} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + { + \tikz@lib@fold@triangle{\tikz@lib@fold@face@AF} + {\tikz@lib@fold@ear@custom@right@path{24}} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%rhombic (Catalan) dodecahedron ("type 1" - spheric) +\def\tikzfoldingrhombicdodecahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@squarerhombusr{\tikz@lib@fold@face@B} + {\tikz@lib@fold@squarerhombusl{\scope[rotate=90]\tikz@lib@fold@face@C\endscope} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@squarerhombusr{\tikz@lib@fold@face@E} + {\tikz@lib@fold@squarerhombusl{\scope[rotate=90]\tikz@lib@fold@face@F\endscope} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@squarerhombusr{\scope[rotate=180]\tikz@lib@fold@face@D\endscope} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@squarerhombusl{\scope[rotate=-90]\tikz@lib@fold@face@H\endscope} + {\tikz@lib@fold@squarerhombusr{\scope[rotate=180]\tikz@lib@fold@face@G\endscope} + {\tikz@lib@fold@squarerhombusl{\scope[rotate=-90]\tikz@lib@fold@face@L\endscope} + {\tikz@lib@fold@squarerhombusr{\scope[rotate=180]\tikz@lib@fold@face@K\endscope} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@squarerhombusl{\scope[rotate=90]\tikz@lib@fold@face@J\endscope} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@squarerhombusl{\tikz@lib@fold@face@H} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@squarerhombusr{\tikz@lib@fold@face@F} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%golden rhombic dodecahedron ("type 2" - flattened) +\def\tikzfoldinggoldenrhombicdodecahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@A} + {\tikz@lib@fold@goldenrhombusl{\scope[rotate=180]\tikz@lib@fold@face@B\endscope} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@goldenrhombusr{\scope[rotate=180]\tikz@lib@fold@face@E\endscope} + {\tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@H} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@G} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@goldenrhombusl{\scope[rotate=180]\tikz@lib@fold@face@D\endscope} + {\tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@I} + {\tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@L} + {\tikz@lib@fold@goldenrhombusr{\scope[rotate=180]\tikz@lib@fold@face@K\endscope} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@goldenrhombusl{\scope[rotate=180]\tikz@lib@fold@face@J\endscope} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@F} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@goldenrhombusr{\scope[rotate=180]\tikz@lib@fold@face@C\endscope} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + \endgroup +}% + +%rhombic tricontahedron + +\def\tikzfoldingrhombictricontahedron#1[#2]#3;{% + \begingroup% + \tikzset{#2}% + \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@A} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@B} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@F} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@I} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@J} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@K} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@H} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@G} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@L} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@N} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@M} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@C} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@N} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@N} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@N} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@N} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@D} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@D} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@D} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@D} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@D} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + } + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@D} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@E} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@E} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@E} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@E} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@E} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@cut@path} + } + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@E} + { \tikz@lib@fold@goldenrhombusl{\tikz@lib@fold@face@E} + { \tikz@lib@fold@goldenrhombusr{\tikz@lib@fold@face@E} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@ear@path} + } + {\tikz@lib@fold@ear@path} + {\tikz@lib@fold@path} + {\tikz@lib@fold@path} + } + } + \endgroup +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfpu.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfpu.code.tex new file mode 100644 index 0000000000..36e0afe133 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryfpu.code.tex @@ -0,0 +1,10 @@ +% Copyright 2008/2018 by Christian Feuersaenger +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU General Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{fpu}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex new file mode 100644 index 0000000000..cf94f92367 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex @@ -0,0 +1,148 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Free Documentation License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{intersections}% + +% FIXME : the 'name path global' is not reset properly - and some +% following 'name path' will append to it rather that reset it. + +\pgfkeys{% + /tikz/name path global/.code={% + % reset any "old" variables inherited from some other path + % - we do not accidentally want to append to an old path with the + % same name (or if someone provided the option twice)... + \expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\relax + \tikz@key@name@path{#1}{\gdef}% + }, + /tikz/name path local/.code={% + \pgfkeys{/tikz/name path={#1}}% + }, + /tikz/name path/.code={% + % hm. Do we need this "reset old option" as in 'name path global' + % for this case as well? + \tikz@key@name@path{#1}{\def}% + }, +}% + +% #1: the name to assign. +% #2: one of '\def' or '\gdef'. +\def\tikz@key@name@path#1#2{% + \tikz@addmode{% + \pgfsyssoftpath@getcurrentpath\tikz@intersect@temppath@round% + \pgfprocessround\tikz@intersect@temppath@round\tikz@intersect@temppath% + \ifx\tikz@intersect@namedpaths\pgfutil@empty% + \else% + \tikz@intersect@namedpaths% + \fi% + \tikz@intersect@addto@path@names{#1}{#2}% + }% +}% + +% #1: the name to assign. +% #2: one of '\def' or '\gdef'. +\def\tikz@intersect@addto@path@names#1#2{% + \edef\tikz@marshal{#2\expandafter\noexpand\csname tikz@intersect@path@name@#1\endcsname}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\tikz@marshal% + \expandafter\expandafter\expandafter{\expandafter\tikz@marshal\expandafter{\tikz@intersect@temppath}}% + \expandafter\pgfutil@g@addto@macro\expandafter\tikz@intersect@namedpaths\expandafter{\tikz@marshal}% +}% + +% at the end of evey \path command ... +\let\tikz@finish@orig=\tikz@finish +\def\tikz@finish{% + \tikz@finish@orig% + \tikz@intersect@finish% +}% + +% ... make the named path variables available +\def\tikz@intersect@finish{% + \tikz@intersect@namedpaths% +}% + +\let\tikz@intersect@namedpaths=\pgfutil@empty +\let\tikz@intersect@path@a=\pgfutil@empty +\let\tikz@intersect@path@b=\pgfutil@empty +\let\tikz@intersect@name=\pgfutil@empty +\let\tikz@intersect@total=\pgfutil@empty + +\tikzset{ + every scope/.append style={ + execute at begin scope={\let\tikz@intersect@namedpaths@outside\tikz@intersect@namedpaths}, + execute at end scope={\global\let\tikz@intersect@namedpaths\tikz@intersect@namedpaths@outside}, + }, + name intersections/.code={% + \tikzset{/tikz/intersection/.cd, + by=, + #1}% + \pgfutil@ifundefined{tikz@intersect@path@name@\tikz@intersect@path@a}{% + \tikzerror{I do not know the path named `\tikz@intersect@path@a'. Perhaps you misspelt it}}% + {\pgfutil@ifundefined{tikz@intersect@path@name@\tikz@intersect@path@b}{% + \tikzerror{I do not know the path named `\tikz@intersect@path@b'. Perhaps you misspelt it}}% + {% + \pgfintersectionofpaths% + {% + \expandafter\pgfsetpath\csname tikz@intersect@path@name@\tikz@intersect@path@a\endcsname% + }% + {% + \expandafter\pgfsetpath\csname tikz@intersect@path@name@\tikz@intersect@path@b\endcsname% + }% + \ifx\tikz@intersect@total\pgfutil@empty% + \else% + \expandafter\let\tikz@intersect@total=\pgfintersectionsolutions% + \fi% + \ifx\tikz@intersect@name\pgfutil@empty% + \def\tikz@intersect@@name{intersection}% + \else% + \let\tikz@intersect@@name=\tikz@intersect@name% + \fi% + \pgfmathloop% + \ifnum\pgfmathcounter>\pgfintersectionsolutions\relax% + \else% + \path[reset cm]\pgfextra{\pgftransformshift{\pgfpointintersectionsolution{\pgfmathcounter}}}% + coordinate (\tikz@intersect@@name-\pgfmathcounter); + \repeatpgfmathloop% + \ifx\tikz@intersect@by\pgfutil@empty% + \else% + \foreach\tikz@intersect@name[count=\tikz@intersection@count] in \tikz@intersect@by% + {\expandafter\tikz@intersect@name@parse\tikz@intersect@name\pgf@stop}% + \fi% + }% + }% + },% + intersection/.cd, + of/.code=\tikz@intersect@path@names@parse#1\tikz@stop,% + name/.store in=\tikz@intersect@name, + total/.store in=\tikz@intersect@total, + by/.store in=\tikz@intersect@by, + sort by/.code=\edef\tikz@intersect@sort@by{#1}\tikz@intersect@check@sort@by% +}% + + +\def\tikz@intersect@check@sort@by{% + \ifx\tikz@intersect@sort@by\tikz@intersect@path@a% + \pgfintersectionsortbyfirstpath% + \else% + \ifx\tikz@intersect@sort@by\tikz@intersect@path@b% + \pgfintersectionsortbysecondpath% + \else% + \pgf@intersect@sortfalse% + \fi% + \fi% +}% +\def\tikz@intersect@path@names@parse#1 and #2\tikz@stop{% + \def\tikz@intersect@path@a{#1}% + \def\tikz@intersect@path@b{#2}% +}% + +\def\tikz@intersect@name@parse{\pgfutil@ifnextchar[\tikz@intersect@name@parse@opt{\tikz@intersect@name@parse@opt[]}}%} +\def\tikz@intersect@name@parse@opt[#1]#2\pgf@stop{% + \coordinate [#1] (#2) at (\tikz@intersect@@name-\tikz@intersection@count); +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarylindenmayersystems.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarylindenmayersystems.code.tex new file mode 100644 index 0000000000..6763c733e9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarylindenmayersystems.code.tex @@ -0,0 +1,81 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{lindenmayersystems}% + +\def\tikz@@lsystem-system{% + \pgfutil@ifnextchar[{\tikz@lsystem@options}{\tikz@lsystem@options[]}}% + +\def\tikz@lsystem indenmayer system{% + \pgfutil@ifnextchar[{\tikz@lsystem@options}{\tikz@lsystem@options[]}}% + +\def\tikz@lsystem@options[#1]{% + \tikzset{#1}% + \ifx\tikz@lsystem@rules\pgfutil@empty% + \else% + \tikz@lsystem@declare% + \def\tikz@lsystem@name{tikz@temp}% + \fi% + \ifx\tikz@lsystem@anchor\pgfutil@empty% + \pgfpathmoveto{\pgfqpoint{\tikz@lastxsaved}{\tikz@lastysaved}}% + \pgflindenmayersystem{\tikz@lsystem@name}{\tikz@lsystem@axiom}{\tikz@lsystem@order}% + \else% + \pgfextract@process\tikz@lsystem@pos{\pgfqpoint{\tikz@lastxsaved}{\tikz@lastysaved}}% + \setbox\pgfnodeparttextbox=\hbox{% + \pgfinterruptpicture% + \pgfpicture% + \pgfpathmoveto{\pgfpointorigin}% + \pgflindenmayersystem{\tikz@lsystem@name}{\tikz@lsystem@axiom}{\tikz@lsystem@order}% + \begingroup% + \tikz@finish% + \endpgfpicture% + \endpgfinterruptpicture% + }% + {% + \pgftransformshift{\tikz@lsystem@pos}% + \tikzset{inner sep=0pt, outer sep=0pt, minimum size=0pt}% + \pgfmultipartnode{rectangle}{\tikz@lsystem@anchor}{lindenmayer system}{\pgfusepath{discard}}% + }% + \fi% + \tikz@scan@next@command}% + +\tikzset{% + lindenmayer system/.style={/pgf/lindenmayer system/.cd, #1,/tikz/.cd}, + l-system/.style={lindenmayer system={#1}}, +}% +\pgfkeys{/pgf/lindenmayer system/.cd, + name/.code=\edef\tikz@lsystem@name{#1}\let\tikz@lsystem@rules=\pgfutil@empty,% + axiom/.store in=\tikz@lsystem@axiom,% + order/.store in=\tikz@lsystem@order, + .unknown/.code={% + \pgfutil@ifundefined{pgf@lsystem@\pgfkeyscurrentname}{% + \pgfkeys{/errors/unknown key={/pgf/lindenmayer system/\pgfkeyscurrentname}{#1}}% + \let\tikz@lsystem@name=\pgfutil@empty% + }% + {\edef\tikz@lsystem@name{\pgfkeyscurrentname}} + },% + anchor/.store in=\tikz@lsystem@anchor,% + rule set/.store in=\tikz@lsystem@rules +}% +\let\tikz@lsystem@anchor=\pgfutil@empty% +\let\tikz@lsystem@rules=\pgfutil@empty% + +\def\tikz@lsystem@declare{% + \expandafter\let\csname pgf@lsystem@tikz@temp\endcsname=\relax% + \pgfdeclarelindenmayersystem{tikz@temp}{% + \expandafter\tikz@lsystem@parse@rules\tikz@lsystem@rules,\tikz@stop,% + }% +}% +\def\tikz@lsystem@parse@rules#1,{% + \ifx#1\tikz@stop% + \else% + \rule{#1}% + \expandafter\tikz@lsystem@parse@rules% + \fi% +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymath.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymath.code.tex new file mode 100644 index 0000000000..ec00bc4b8a --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymath.code.tex @@ -0,0 +1,731 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usetikzlibrary{fpu} + +\edef\tikz@math@at@catcode{\the\catcode`\@}% +\catcode`\@=11 + +\def\tikz@math@gobblespaces#1{\pgfutil@ifnextchar x{#1}{#1}}% + +\def\tikz@math@meaning@macro{macro}% +\def\tikz@math@meaning@dimen{dimen}% +\def\tikz@math@meaning@count{count}% +\def\tikz@math@meaning@null{null}% + +\def\tikz@math@getmeaning#1{\expandafter\tikz@math@@getmeaning\meaning#1\tikz@math@getmeaning@stop}% + +\def\tikz@math@@getmeaning#1#2#3#4#5\tikz@math@getmeaning@stop{% + \if#1u% undefined + \let\tikz@math@meaning=\tikz@math@meaning@macro% + \else% + \if#1m% + \let\tikz@math@meaning=\tikz@math@meaning@macro% + \else% + \if#2d% + \let\tikz@math@meaning=\tikz@math@meaning@dimen% + \else% + \if#2c% + \let\tikz@math@meaning=\tikz@math@meaning@count% + \else% + \if#3k% A skip. Treat like a dimen. + \let\tikz@math@meaning=\tikz@math@meaning@dimen% + \else% + \let\tikz@math@meaning=\tikz@math@meaning@null% + \fi% + \fi% + \fi% + \fi% + \fi% +}% + +\def\tikz@math@firstoftwo#1#2{#1}% +\def\tikz@math@secondoftwo#1#2{#2}% + + +\def\tikz@math@getvarstring#1{% + \begingroup% + \escapechar=-1\relax% + \expandafter\tikz@math@@getvarstring\string#1\tikz@math}% + +\def\tikz@math@@getvarstring#1\tikz@math#2{% + \endgroup% + \def#2{#1}% +}% + +\long\def\tikz@math@collecttosemicolon@other#1#2;{% + \def\tikz@math@collected{#2}#1}% +\def\tikz@math@semicolon@other{;}% + +{\catcode`\;=13 +\long\gdef\tikz@math@collecttosemicolon@active#1#2;{% + \def\tikz@math@collected{#2}#1}% +\gdef\tikz@math@semicolon@active{;}% +}% + + +\def\tikz@math@setvartype#1#2{% + \expandafter\let\csname tikz@math@var@vartype@\string#1\endcsname=#2% +}% + + +\def\tikz@math@getvartype#1#2{% + \def\tikz@math@marshal{\let#1=}% + \expandafter\tikz@math@marshal\csname + tikz@math@var@vartype@\string#2\endcsname% +}% + + + +\def\tikz@math@ifvarcoordinate#1{% + \expandafter\ifx\csname + tikz@math@var@vartype@\string#1\endcsname\tikz@math@keyword@coordinate% + \let\tikz@math@next=\tikz@math@firstoftwo% + \else% + \let\tikz@math@next=\tikz@math@secondoftwo% + \fi% + \tikz@math@next% +}% + +\def\tikz@math@ifvarinteger#1{% + \expandafter\ifx\csname + tikz@math@var@vartype@\string#1\endcsname\tikz@math@keyword@integer% + \let\tikz@math@next=\tikz@math@firstoftwo% + \else% + \let\tikz@math@next=\tikz@math@secondoftwo% + \fi% + \tikz@math@next% +}% + + +\def\tikz@math@setvarindexed#1{% + \expandafter\let\csname + tikz@math@var@subtype@\string#1\endcsname=\tikz@math@subtype@indexed% +}% + +\def\tikz@math@clearvarindexed#1{% + \expandafter\let\csname tikz@math@var@subtype@\string#1\endcsname=\relax% +}% + +\def\tikz@math@ifvarindexed#1{% + \expandafter\ifx\csname tikz@math@var@subtype@\string#1\endcsname\relax% + \let\tikz@math@next=\tikz@math@secondoftwo% + \else% + \let\tikz@math@next=\tikz@math@firstoftwo% + \fi% + \tikz@math@next% +}% + +\def\tikz@math@stop{@}% + +\let\tikz@math@parse@hook@before=\pgfutil@empty +\let\tikz@math@parse@hook@after=\pgfutil@empty + +\def\tikz@math{% + \ifnum\catcode`\;=13\relax% + \let\tikz@math@semicolon=\tikz@math@semicolon@active% + \let\tikz@math@collecttosemicolon=\tikz@math@collecttosemicolon@active% + \else% + \let\tikz@math@semicolon=\tikz@math@semicolon@other% + \let\tikz@math@collecttosemicolon=\tikz@math@collecttosemicolon@other% + \fi% + \tikz@math@parse@hook@before% + \tikz@@math}% + + + + +\long\def\tikz@@math#1{% + \def\tikz@math@marshal{\tikz@math@parse#1}% + \expandafter\expandafter\expandafter\tikz@math@marshal\expandafter\tikz@math@stop\tikz@math@semicolon}% + +\def\tikz@math@parse{\pgfutil@ifnextchar\bgroup\tikz@math@@parse@bgroup\tikz@math@@parse@nobgroup}% + + +\def\tikz@math@@parse@bgroup{% + \tikz@math@collecttosemicolon{% + % MW: Don't know how reliable this test is. + \ifx\pgf@selectfontorig\tikz@math@undefined% + \begingroup\tikz@math@collected\endgroup% + \else% + \begingroup\csname nullfont\endcsname\tikz@math@collected\endgroup% + \fi\tikz@math@parse}}% + + + +\def\tikz@math@@parse@nobgroup{\tikz@math@collecttosemicolon{\tikz@math@@parse@@nobgroup}}% + +\def\tikz@math@@parse@@nobgroup{% + \let\tikz@math@tmp=\tikz@math@collected% + \ifx\tikz@math@tmp\tikz@math@stop% + \def\tikz@math@next{\expandafter\tikz@math@parse@finish\tikz@math@semicolon}% + \else% + \def\tikz@math@next{\expandafter\expandafter\expandafter\tikz@math@parse@keyword@check\expandafter\tikz@math@tmp\tikz@math@semicolon}% + \fi% + \tikz@math@next% +}% + +\def\tikz@math@parse@finish{% + \tikz@math@collecttosemicolon{\tikz@math@parse@hook@after}% +}% + + + +\newif\iftikz@math@let +\def\tikz@math@parse@keyword@check#1{% + \tikz@math@letfalse% + \tikz@math@getmeaning{#1}% + \ifx\tikz@math@meaning\tikz@math@meaning@null% + \let\tikz@math@next=\tikz@math@parse@keyword% + \else% + \let\tikz@math@next=\tikz@math@parse@nokeyword% + \fi% + \tikz@math@next#1}% + + +\def\tikz@math@parse@keyword{% + \let\tikz@math@parsed@keyword=\pgfutil@empty% + \futurelet\tikz@math@parse@token\tikz@math@@parse@keyword}% + +\def\tikz@math@@parse@keyword{% + \ifx\tikz@math@parse@token\pgfutil@sptoken% + \let\tikz@math@next=\tikz@math@@@parse@keyword% + \else% + \ifx\tikz@math@parse@token(% + \let\tikz@math@next=\tikz@math@@@parse@keyword% + \else% + \ifx\tikz@math@parse@token\bgroup% + \let\tikz@math@next=\tikz@math@@@parse@keyword% + \else% + \let\tikz@math@next=\tikz@math@@@@parse@keyword% + \fi% + \fi% + \fi% + \tikz@math@next}% + +\def\tikz@math@error#1{\pgfutil@packageerror{tikz}{tikz math library: #1}{}}% + +\def\tikz@math@@@parse@keyword{% + \expandafter\ifx\csname tikz@math@process@keyword@\tikz@math@parsed@keyword\endcsname\relax% + \expandafter\ifx\csname pgfmath\tikz@math@parsed@keyword\endcsname\relax% + \tikz@math@error{Unknown function or keyword '\tikz@math@parsed@keyword'}% + \else% + \def\tikz@math@next{\tikz@math@collecttosemicolon{\tikz@math@function@noassign}}% + \fi% + \else% + \expandafter\def\expandafter\tikz@math@next\expandafter{\csname tikz@math@process@keyword@\tikz@math@parsed@keyword\endcsname}% + \fi% + \tikz@math@next}% + +\def\tikz@math@@@@parse@keyword#1{% + \edef\tikz@math@parsed@keyword{\tikz@math@parsed@keyword#1}% + \futurelet\tikz@math@parse@token\tikz@math@@parse@keyword% +}% + +\def\tikz@math@function@noassign{% + \pgfmathparse{\tikz@math@parsed@keyword\tikz@math@collected}% + \tikz@math@parse% +}% + + + + +\def\tikz@math@process@keyword@count{\tikz@math@collecttosemicolon{\tikz@math@process@keyword@@count}}% +\def\tikz@math@process@keyword@@count{% +\def\tikz@math@assign@register{\csname newcount\endcsname}% +\expandafter\tikz@math@gobblespaces\expandafter\tikz@math@process@registers\tikz@math@collected,@,}% + +\def\tikz@math@process@keyword@length{\tikz@math@collecttosemicolon{\tikz@math@process@keyword@@length}}% +\def\tikz@math@process@keyword@@length{% +\def\tikz@math@assign@register{\csname newdimen\endcsname}% +\expandafter\tikz@math@gobblespaces\expandafter\tikz@math@process@registers\tikz@math@collected,@,}% + + +\def\tikz@math@process@registers#1#2,{% + \def\tikz@math@var{#1}% + \ifx\tikz@math@var\tikz@math@stop% + \let\tikz@math@next=\tikz@math@parse% + \else% + \tikz@math@assign@register#1\relax% + \let\tikz@math@next=\tikz@math@process@registers% + \fi% + \tikz@math@gobblespaces\tikz@math@next% +}% + + +\def\tikz@math@process@keyword@if#1then{% + \def\tikz@math@if@condition{#1}% + \tikz@math@gobblespaces\tikz@math@parse@if@iftrue% +}% +\def\tikz@math@parse@if@iftrue#1{% + \def\tikz@math@if@trueaction{#1}% + \pgfutil@ifnextchar e{\tikz@math@parse@else}{\tikz@math@if@doif}}% + +\def\tikz@math@parse@else else{\tikz@math@gobblespaces\tikz@math@if@doifelse}% + +\def\tikz@math@if@doif{\tikz@math@collecttosemicolon{\tikz@math@if@@doif}}% + +\def\tikz@math@if@@doif{% + \pgfmathparse{\tikz@math@if@condition}% + \ifpgfmathfloatparseactive% + \pgfmathfloattofixed{\pgfmathresult}% + \fi% + \ifdim\pgfmathresult pt=0pt\relax% + \else% + \expandafter\tikz@math\expandafter{\tikz@math@if@trueaction}% + \fi% + \tikz@math@parse% +}% +\def\tikz@math@if@doifelse{\tikz@math@collecttosemicolon{\tikz@math@if@@doifelse}}% +\def\tikz@math@if@@doifelse{% + \pgfmathparse{\tikz@math@if@condition}% + \ifpgfmathfloatparseactive% + \pgfmathfloattofixed{\pgfmathresult}% + \fi% + \let\tikz@math@if@falseaction=\tikz@math@collected% + \ifdim\pgfmathresult pt=0pt\relax% + \expandafter\tikz@math\expandafter{\tikz@math@if@falseaction}% + \else% + \expandafter\tikz@math\expandafter{\tikz@math@if@trueaction}% + \fi% + \tikz@math@parse% +}% +\def\tikz@math@process@keyword@let{% + \tikz@math@lettrue% + \tikz@math@gobblespaces\tikz@math@parse@nokeyword% +}% + + +\def\tikz@math@parse@nokeyword#1{% + \def\tikz@math@var{#1}% + \tikz@math@getvarstring{#1}\tikz@math@varstring% + \let\tikz@math@vartype=\pgfutil@empty% + \ifx\tikz@math@var\tikz@math@stop% + \let\tikz@math@next=\tikz@math@parse@finish% + \else% + \ifx\tikz@math@semicolon\tikz@math@var% + \let\tikz@math@next=\tikz@math@parse% + \else% + \let\tikz@math@next=\tikz@math@parse@index@check% + \fi% + \fi% + \tikz@math@next}% + +\def\tikz@math@parse@index@check{% + \pgfutil@ifnextchar={\tikz@math@parse@noindex}{\tikz@math@parse@index}}% + +\def\tikz@math@parse@noindex{% + \expandafter\tikz@math@clearvarindexed\tikz@math@var% + \let\tikz@math@current@index=\pgfutil@empty% + \tikz@math@parse@afterindex% +}% + +\def\tikz@math@parse@index#1{% + \def\tikz@math@tmp{#1}% + \expandafter\tikz@math@setvarindexed\tikz@math@var% {} + \edef\tikz@math@current@index{#1}% + \tikz@math@parse@afterindex% +}% +\def\tikz@math@parse@afterindex#1={\tikz@math@gobblespaces\tikz@math@parse@assignment}% + +\def\tikz@math@parse@assignment{\tikz@math@collecttosemicolon{\tikz@math@parse@@assignment}}% +\def\tikz@math@parse@@assignment{% + \expandafter\expandafter\expandafter\tikz@math@doassignment\expandafter\expandafter\expandafter% + {\expandafter\tikz@math@var\expandafter}\expandafter{\tikz@math@collected}% + \tikz@math@parse% +}% + +\def\tikz@math@dollar@char{$}% +\def\tikz@math@dollar@char{$}% For annoying syntax highlighters + +\def\tikz@math@doassignment#1#2{% + \tikz@math@ifvarcoordinate{#1}{% + \def\tikz@math@var{#1}% Unfortunately, we must do this again. + \tikz@math@getvarstring{#1}\tikz@math@varstring% And this + \expandafter\pgfutil@in@\tikz@math@dollar@char{#2}% + \edef\tikz@math@expression{#2}% + \ifpgfutil@in@% + \expandafter\tikz@scan@one@point\expandafter\tikz@math@assign@coordinate\tikz@math@expression% + \else% + \expandafter\ifx\csname tikz@library@calc@loaded\endcsname\relax% + \expandafter\tikz@scan@one@point\expandafter\tikz@math@assign@coordinate\tikz@math@expression% + \else% + \expandafter\tikz@scan@one@point\expandafter\tikz@math@assign@coordinate\expandafter% + (\expandafter$\tikz@math@expression$)% + \fi% + \fi% + }{% + \iftikz@math@let% Not really a let + \ifx\tikz@math@current@index\pgfutil@empty% + \edef#1{#2}% + \else% + \edef\tikz@math@tmp{#2}% + \expandafter\expandafter\expandafter\tikz@math@assign@index\expandafter\expandafter\expandafter% + {\expandafter\tikz@math@varstring\expandafter}\expandafter{\tikz@math@tmp}% + \fi% + \tikz@math@letfalse% + \else% + \ifx\tikz@math@current@index\pgfutil@empty% + \tikz@math@getmeaning{#1}% + \ifx\tikz@math@meaning\tikz@math@meaning@dimen% + \pgfmathsetlength{#1}{#2}% + \let\tikz@math@last@assigned@value=\pgfmathresult% + \else% + \ifx\tikz@math@meaning\tikz@math@meaning@count% + \pgfmathsetcount{#1}{#2}% + \let\tikz@math@last@assigned@value=\pgfmathresult% + \else% + \tikz@math@ifvarinteger{#1}{\pgfmathparse{int(#2)}}{\pgfmathparse{#2}}% + \let\tikz@math@last@assigned@value=\pgfmathresult% + \let#1=\pgfmathresult% + \fi% + \fi% + \else% + \tikz@math@ifvarinteger{#1}{\pgfmathparse{int(#2)}}{\pgfmathparse{#2}}% + \expandafter\tikz@math@assign@index\expandafter{\tikz@math@varstring}\pgfmathresult% + \let\tikz@math@last@assigned@value=\pgfmathresult% + \fi% + \fi% + }% +}% + + + +\def\tikz@math@assign@index#1#2{% + \expandafter\def\csname#1\endcsname##1{\csname + tikz@math@var@indexed@#1@##1\endcsname}% + \expandafter\edef\csname + tikz@math@var@indexed@#1@\tikz@math@current@index\endcsname{#2}\relax% +}% + + + +\def\tikz@math@assign@coordinate#1{% + \pgf@process{#1}% + \ifx\tikz@math@current@index\pgfutil@empty% + \expandafter\edef\csname\tikz@math@varstring\endcsname{\the\pgf@x,\the\pgf@y}% + \expandafter\edef\csname\tikz@math@varstring x\endcsname{\the\pgf@x}% + \expandafter\edef\csname\tikz@math@varstring y\endcsname{\the\pgf@y}% + \else% + \expandafter\tikz@math@assign@index\expandafter{\tikz@math@varstring}{\the\pgf@x,\the\pgf@y}% + \expandafter\tikz@math@assign@index\expandafter{\tikz@math@varstring x}{\the\pgf@x}% + \expandafter\tikz@math@assign@index\expandafter{\tikz@math@varstring y}{\the\pgf@y}% + \fi% +}% + + + +\def\tikz@math@keyword@coordinate{coordinate}% +\def\tikz@math@process@keyword@coordinate{% + \let\tikz@math@vartype=\tikz@math@keyword@coordinate% + \tikz@math@gobblespaces\tikz@math@process@vartypes% +}% + +\def\tikz@math@keyword@integer{integer}% +\def\tikz@math@process@keyword@integer{% + \let\tikz@math@vartype=\tikz@math@keyword@integer% + \tikz@math@gobblespaces\tikz@math@process@vartypes% +}% +\def\tikz@math@process@keyword@int{% + \tikz@math@process@keyword@integer% +}% + +\def\tikz@math@keyword@real{real}% +\def\tikz@math@process@keyword@real{% + \let\tikz@math@vartype=\tikz@math@keyword@real% + \tikz@math@gobblespaces\tikz@math@process@vartypes% +}% + +\def\tikz@math@process@keyword@point{\tikz@math@process@keyword@coordinate}% + + +\def\tikz@math@process@vartypes{\tikz@math@collecttosemicolon{\tikz@math@process@@vartypes}}% + +\def\tikz@math@process@@vartypes{% + \expandafter\tikz@math@@process@vartypes\tikz@math@collected,@,\tikz@math% +}% + +\def\tikz@math@@process@vartypes#1#2,{% + \def\tikz@math@var{#1}% + \tikz@math@getvarstring{#1}\tikz@math@varstring% + \ifx\tikz@math@var\tikz@math@stop% + \let\tikz@math@next=\tikz@math@@@process@vartypes% + \else% + \expandafter\tikz@math@setvartype\tikz@math@var\tikz@math@vartype% + \def\tikz@math@next{\tikz@math@gobblespaces\tikz@math@@process@vartypes}% + \fi% + \tikz@math@next% +}% + +\def\tikz@math@process@keyword@print{\tikz@math@collecttosemicolon{\tikz@math@process@keyword@@print}}% +\def\tikz@math@process@keyword@@print{% + \begingroup\tikz@math@collected\endgroup\tikz@math@parse% +}% + +\def\tikz@math@@@process@vartypes#1\tikz@math{% + \tikz@math@parse% +}% + +\newcount\tikz@math@for@depth + +\def\tikz@math@for@namedef#1{\expandafter\def\csname tikz@math@for@def@#1@\the\tikz@math@for@depth\endcsname}% +\def\tikz@math@for@nameedef#1{\expandafter\edef\csname tikz@math@for@def@#1@\the\tikz@math@for@depth\endcsname}% +\def\tikz@math@for@namelet#1{\expandafter\let\csname tikz@math@for@def@#1@\the\tikz@math@for@depth\endcsname}% + +\def\tikz@math@for@namegetvalue#1#2{% + \def\tikz@math@marshal{\let#2=}% + \expandafter\tikz@math@marshal\csname tikz@math@for@def@#1@\the\tikz@math@for@depth\endcsname}% + +\def\tikz@math@process@keyword@for{% + \tikz@math@for% +}% + +\def\tikz@math@for@external{% + \ifnum\catcode`\;=13\relax% + \let\tikz@math@semicolon=\tikz@math@semicolon@active% + \let\tikz@math@collecttosemicolon=\tikz@math@collecttosemicolon@active% + \else% + \let\tikz@math@semicolon=\tikz@math@semicolon@other% + \let\tikz@math@collecttosemicolon=\tikz@math@collecttosemicolon@other% + \fi + \advance\tikz@math@for@depth by1\relax% + \tikz@math@for@namedef{execute}{\tikz@math@for@external@execute}% + \tikz@math@for@namedef{finished}{\relax}% + \tikz@math@gobblespaces\tikz@math@for@parsevar}% + +\def\tikz@math@for@external@execute#1{#1}% + +\def\tikz@math@for{% + \advance\tikz@math@for@depth by1\relax% + \tikz@math@for@namedef{execute}{\tikz@math}% + \tikz@math@for@namedef{finished}{\tikz@math@parse}% + \tikz@math@gobblespaces\tikz@math@for@parsevar}% + + +\def\tikz@math@for@parsevar#1{% + \tikz@math@for@namedef{var}{#1}% + \tikz@math@for@parsein}% + +\def\tikz@math@getindex#1{% + \tikz@math@@getindex#1\tikz@math@getindex\tikz@math@@getindex% +}% + +\def\tikz@math@@getindex#1#2\tikz@math@@getindex{#1}% + +\def\tikz@math@for@parsein#1in{% + \def\tikz@math@tmp{#1}% + \ifx\tikz@math@tmp\pgfutil@empty% + \tikz@math@for@namedef{index}{}% + \else% + \tikz@math@for@nameedef{index}{\tikz@math@getindex{#1}}% + \fi% + \tikz@math@gobblespaces\tikz@math@for@parselist% +}% + + +\long\def\tikz@math@for@parselist#1{% + \edef\tikz@math@for@list{#1}% + \tikz@math@gobblespaces{% + \tikz@math@collecttosemicolon{\tikz@math@for@parseaction}}}% + +\def\tikz@math@for@parseaction{% + \tikz@math@for@namedef{prevvalue}{}% + \tikz@math@for@namedef{prevprevvalue}{}% + \tikz@math@for@namelet{action}=\tikz@math@collected% + \expandafter\tikz@math@for@scan\tikz@math@for@list,\tikz@math,\tikz@@math% +}% + +\def\tikz@math@token{\tikz@math}% + + +\def\tikz@math@for@scan#1,{% + \def\tikz@math@for@value{#1}% + \ifx\tikz@math@for@value\tikz@math@token% + \let\tikz@math@next=\tikz@math@for@scan@end% + \else% + \ifx\tikz@math@for@value\pgfutil@empty% + \let\tikz@math@next=\tikz@math@for@scan@end% + \else% + \pgfutil@in@{...}{#1}% + \ifpgfutil@in@% + \let\tikz@math@next=\tikz@math@for@scan@dots% + \else% + \tikz@math@for@namegetvalue{var}{\tikz@math@var}% + \tikz@math@for@namegetvalue{index}{\tikz@math@current@index}% + \tikz@math@for@namegetvalue{action}{\tikz@math@action}% + \expandafter\tikz@math@getvarstring\expandafter{\tikz@math@var}\tikz@math@varstring% + \expandafter\tikz@math@doassignment\expandafter{\tikz@math@var}{#1}% + \tikz@math@for@namelet{value}=\tikz@math@last@assigned@value% + \tikz@math@for@namegetvalue{execute}{\tikz@math@execute}% + \expandafter\tikz@math@execute\expandafter{\tikz@math@action}% + \tikz@math@for@namegetvalue{prevvalue}{\tikz@math@prevvalue}% + \tikz@math@for@namelet{prevprevvalue}=\tikz@math@prevvalue% + \tikz@math@for@namegetvalue{value}{\tikz@math@value}% + \tikz@math@for@namelet{prevvalue}=\tikz@math@value% + \let\tikz@math@next=\tikz@math@for@scan% + \fi% + \fi% + \fi% + \tikz@math@next% +}% + +\newdimen\tikz@math@dimen + +\def\tikz@math@for@scan@dots#1,{% + \pgfmathparse{#1}\let\tikz@math@value=\pgfmathresult% + \tikz@math@for@nameedef{endvalue}{\tikz@math@value}% + \tikz@math@for@namegetvalue{prevvalue}{\tikz@math@prevvalue}% + \tikz@math@for@namegetvalue{prevprevvalue}{\tikz@math@prevprevvalue}% + \tikz@math@dimen=\tikz@math@prevvalue pt\relax% + \ifx\tikz@math@prevprevvalue\pgfutil@empty% + \ifdim\tikz@math@prevvalue pt<\tikz@math@value pt\relax%% + \def\tikz@math@step{1pt}% + \else% + \def\tikz@math@step{-1pt}% + \fi% + \else% + \tikz@math@dimen=\tikz@math@prevvalue pt\relax% + \advance\tikz@math@dimen by-\tikz@math@prevprevvalue pt\relax% + \edef\tikz@math@step{\the\tikz@math@dimen}% + \fi% + \ifdim\tikz@math@step<0pt\relax% + \tikz@math@for@namedef{comparitor}{<}% + \else% + \tikz@math@for@namedef{comparitor}{>}% + \fi% + \tikz@math@for@nameedef{step}{\tikz@math@step}% + \tikz@math@for@doloop% +}% + +\def\tikz@math@for@doloop{% + \tikz@math@for@namegetvalue{prevvalue}{\tikz@math@prevvalue}% + \tikz@math@for@namegetvalue{step}{\tikz@math@step}% + \tikz@math@for@namegetvalue{comparitor}{\tikz@math@comparitor}% + \tikz@math@for@namegetvalue{endvalue}{\tikz@math@endvalue}% + \tikz@math@dimen=\tikz@math@prevvalue pt\relax% + \advance\tikz@math@dimen by\tikz@math@step\relax% + \ifdim\tikz@math@dimen\tikz@math@comparitor\tikz@math@endvalue pt\relax% + \let\tikz@math@next=\tikz@math@for@endloop% + \else% + \tikz@math@for@nameedef{value}{\pgfmath@tonumber{\tikz@math@dimen}}% + \tikz@math@for@namegetvalue{var}{\tikz@math@var}% + \expandafter\tikz@math@getvarstring\expandafter{\tikz@math@var}\tikz@math@varstring% + \tikz@math@for@namegetvalue{index}{\tikz@math@current@index}% + \tikz@math@for@namegetvalue{action}{\tikz@math@action}% + \tikz@math@for@namegetvalue{value}{\tikz@math@value}% + \expandafter\expandafter\expandafter\tikz@math@doassignment\expandafter\expandafter\expandafter% + {\expandafter\tikz@math@var\expandafter}\expandafter{\tikz@math@value}% + \tikz@math@for@namegetvalue{execute}{\tikz@math@execute}% + \expandafter\tikz@math@execute\expandafter{\tikz@math@action}% + \tikz@math@for@namegetvalue{prevvalue}{\tikz@math@prevvalue}% + \tikz@math@for@namelet{prevprevvalue}=\tikz@math@prevvalue% + \tikz@math@for@namegetvalue{value}{\tikz@math@value}% + \tikz@math@for@namelet{prevvalue}=\tikz@math@value% + \let\tikz@math@next=\tikz@math@for@doloop% + \fi% + \tikz@math@next% +}% + +\def\tikz@math@for@endloop{% +\tikz@math@for@scan}% + + + + +\def\tikz@math@for@scan@end#1\tikz@@math{% +\tikz@math@for@namegetvalue{finished}{\tikz@math@next}% +\advance\tikz@math@for@depth by-1\relax% +\tikz@math@next}% + + + + + +\def\tikz@math@process@keyword@return{% + \tikz@math@collecttosemicolon{\pgfmathparse{\tikz@math@collected}\tikz@math@parse}}% + +\def\tikz@math@process@keyword@function{\tikz@math@collecttosemicolon{\tikz@math@process@keyword@@function}}% +\def\tikz@math@process@keyword@@function{% + \let\tikz@math@function@name=\pgfutil@empty% + \let\tikz@math@function@arguments=\pgfutil@empty% + \let\tikz@math@function@body=\pgfutil@empty% + \expandafter\expandafter\expandafter\tikz@math@@declarefunction\expandafter\tikz@math@collected\tikz@math@semicolon% +}% + +\def\tikz@math@@declarefunction{% + \pgfutil@ifnextchar\bgroup\tikz@math@@@collectbody\tikz@math@@@declarefunction}% + + +\def\tikz@math@@@declarefunction#1{% + \if#1(%) + \let\tikz@math@next=\tikz@math@@@collectarguments% + \else% + \expandafter\def\expandafter\tikz@math@function@name\expandafter{\tikz@math@function@name#1}% + \let\tikz@math@next=\tikz@math@@declarefunction% + \fi% + \tikz@math@next% +}% +\def\tikz@math@@@collectarguments#1){% + \def\tikz@math@function@arguments{#1}% + \tikz@math@@declarefunction% +}% + +\newtoks\tikz@math@toks +\tikz@math@toks={#}% +\edef\tikz@math@char@hash{\the\tikz@math@toks}% +\tikz@math@toks={}% + +\def\tikz@math@@@collectbody{\tikz@math@collecttosemicolon{\tikz@math@@@@collectbody}}% + +\def\tikz@math@@@@collectbody{% + \tikz@math@toks={}% + \c@pgf@counta=0\relax% + \ifx\tikz@math@function@arguments\pgfutil@empty% + \else% + \expandafter\tikz@math@createargumentlist\tikz@math@function@arguments,,% + \expandafter\tikz@math@addto@toks\expandafter{\tikz@math@collected}% + \fi% + \edef\tikz@math@local@temp{% + \noexpand\pgfmathdeclarefunction{\tikz@math@function@name}{\the\c@pgf@counta}% + {\noexpand\def\noexpand\return{0}\noexpand\tikz@math{\the\tikz@math@toks}}% + }% + \tikz@math@local@temp + \tikz@math@parse% +}% + +\def\tikz@math@addto@toks#1{% + \expandafter\tikz@math@toks\expandafter{\the\tikz@math@toks#1}}% + +\def\tikz@math@createargumentlist{% + \pgfutil@ifnextchar + x\tikz@math@@createargumentlist\tikz@math@@createargumentlist}% + +\def\tikz@math@comma{,}% +\def\tikz@math@@createargumentlist#1,{% + \def\tikz@math@tmp{#1}% + \ifx\tikz@math@tmp\pgfutil@empty% + \let\tikz@math@next=\relax% + \else% + \advance\c@pgf@counta by1\relax% + \tikz@math@addto@toks{#1=}% + \expandafter\expandafter\expandafter\tikz@math@addto@toks\expandafter\expandafter\expandafter% + {\expandafter\tikz@math@char@hash\the\c@pgf@counta;}% + \let\tikz@math@next=\tikz@math@createargumentlist% + \fi% + \tikz@math@next% +}% + + + +\let\tikzmath=\tikz@math +\tikzset{evaluate/.code={\tikz@math{#1}}}% +\let\tikzmathfor=\tikz@math@for@external + + +\catcode`\@=\tikz@math@at@catcode\relax diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymatrix.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymatrix.code.tex new file mode 100644 index 0000000000..5118189376 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymatrix.code.tex @@ -0,0 +1,144 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarymatrix.code.tex} + + +% A matrix of nodes contains a node in each cell. + +\tikzset{matrix of nodes/.style={% + matrix,% + cells={anchor=base},% + execute at begin cell=\tikz@lib@matrix@start@cell,% + execute at end cell=\tikz@lib@matrix@end@cell,% + execute at empty cell=\tikz@lib@matrix@empty@cell, + execute at begin matrix=\iftikz@handle@active@code\tikz@orig@shorthands\fi,% +}}% + +\def\tikz@lib@matrix@empty@cell{\iftikz@lib@matrix@empty\node[name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn]{};\fi}% + +\newif\iftikz@lib@matrix@plain + +\def\tikz@lib@matrix@start@cell{% + \pgfutil@ifnextchar|{\tikz@lib@matrix@with@options}{\tikz@lib@matrix@normal@start@cell}}% + +\def\tikz@lib@matrix@with@options|#1|{\tikz@lib@matrix@plainfalse\node% + [name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn]#1\bgroup\tikz@lib@matrix@startup}% + + +\def\tikz@lib@matrix@normal@start@cell{\pgfutil@ifnextchar\let{\tikz@lib@matrix@check}{\tikz@lib@matrix@plainfalse\node + [name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn]\bgroup\tikz@lib@matrix@startup}}% + +\def\tikz@lib@matrix@check#1{% evil hackery to find out about start of path + \pgfutil@ifnextchar\tikz@signal@path{\tikz@lib@matrix@plaintrue\let}{\tikz@lib@matrix@plainfalse\node + [name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn]\bgroup\tikz@lib@matrix@startup\let}% +}% + +\def\tikz@lib@matrix@end@cell{% + \iftikz@lib@matrix@plain% + \else% + \expandafter\egroup\expandafter;% + \fi% +}% + +\def\tikz@lib@matrix@startup{% + \pgfutil@ifnextchar\bgroup{% + % Save meaning of \\: + \let\tikz@lib@matrix@saved@eol=\\% + % Now smuggle meaning inside following group. + \let\\=\pgfmatrixendrow% + \afterassignment\tikz@lib@matrix@smuggle% + \let\tikz@next} + {\let\\=\pgfmatrixendrow}% +}% +\def\tikz@lib@matrix@smuggle{% + \bgroup% + \let\\=\tikz@lib@matrix@saved@eol% +}% + + +% Fill empty nodes in a matrix of nodes + +\newif\iftikz@lib@matrix@empty + +\tikzoption{nodes in empty cells}[true]{\csname tikz@lib@matrix@empty#1\endcsname}% + + +% Same as a matrix of nodes, but switch on math mode in each cell +\tikzset{matrix of math nodes/.style={% + matrix of nodes, + nodes={% + execute at begin node=$,% + execute at end node=$% + }% +}}% + + + +% Provide a delimiter + +\tikzoption{left delimiter}{\tikzset{append after command={\tikz@delimiter% + {south east}% + {south west}% + {every delimiter,every left delimiter}% + {south}% + {north}% + {#1}% + {.}% + {\pgf@y}}}}% + +\tikzoption{right delimiter}{\tikzset{append after command={\tikz@delimiter% + {south west}% + {south east}% + {every delimiter,every right delimiter}% + {south}% + {north}% + {.}% + {#1}% + {\pgf@y}}}}% + +\tikzoption{above delimiter}{\tikzset{append after command={\tikz@delimiter% + {south east}% + {north west}% + {every delimiter,every above delimiter,rotate=-90}% + {west}% + {east}% + {#1}% + {.}% + {\pgf@x}}}}% + +\tikzoption{below delimiter}{\tikzset{append after command={\tikz@delimiter% + {south west}% + {south west}% + {every delimiter,every below delimiter,rotate=-90}% + {west}% + {east}% + {.}% + {#1}% + {\pgf@x}}}}% + +\def\tikz@delimiter#1#2#3#4#5#6#7#8{% + \bgroup + \pgfextra{\let\tikz@save@last@fig@name=\tikz@last@fig@name\tikz@node@is@a@labelfalse}% + node[outer sep=0pt,inner sep=0pt,draw=none,fill=none,anchor=#1,at=(\tikz@last@fig@name.#2),#3] + {% + {\nullfont\pgf@process{\pgfpointdiff{\pgfpointanchor{\tikz@last@fig@name}{#4}}{\pgfpointanchor{\tikz@last@fig@name}{#5}}}}% + $\left#6\vcenter{\hrule height .5#8 depth .5#8 width0pt}\right#7$% + } + \pgfextra{\global\let\tikz@last@fig@name=\tikz@save@last@fig@name}% + \egroup% +}% + +\tikzset{every delimiter/.style={}}% +\tikzset{every left delimiter/.style={}}% +\tikzset{every right delimiter/.style={}}% +\tikzset{every above delimiter/.style={}}% +\tikzset{every below delimiter/.style={}}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymindmap.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymindmap.code.tex new file mode 100644 index 0000000000..ff5959c4f3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarymindmap.code.tex @@ -0,0 +1,417 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarymindmap.code.tex} + + +\usetikzlibrary{trees,decorations}% + + +% A decoration for connecting circle nodes +% +% Parameters: start radius, end radius, amplitude, angle + +\pgfdeclaredecoration{circle connection bar}{initial} +{% + \state{initial}[width=0pt,next state=bar] + { + { + \pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/start radius}}% + \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}} + \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}} + \pgfutil@tempcnta=-\pgfdecorationsegmentangle\relax + \advance\pgfutil@tempcnta by90\relax + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}} + \pgfmathsetlength\pgfutil@tempdimb{\pgfdecorationsegmentamplitude} + \pgfpathcurveto + {\pgfpointadd + {\pgfpointpolar{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}} + {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}} + {\pgfqpoint{1.25\pgfutil@tempdima}{-.5\pgfutil@tempdimb}} + {\pgfqpoint{1.5\pgfutil@tempdima}{-.5\pgfutil@tempdimb}} + \pgfpathlineto{\pgfpoint{1.5\pgfutil@tempdima}{.5\pgfutil@tempdimb}} + \pgfutil@tempcnta=\pgfdecorationsegmentangle\relax + \advance\pgfutil@tempcnta by-90\relax + \pgfpathcurveto + {\pgfpoint{1.25\pgfutil@tempdima}{.5\pgfutil@tempdimb}} + {\pgfpointadd + {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}} + {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}} + {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}} + \pgfpathclose + } + }% + \state{bar}[width=0pt,next state=end] + { + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}}% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/decoration/end radius}}% + \pgfmathsetlength\pgf@xc{\pgfdecorationsegmentamplitude}% + \pgfpathrectangle + {\pgfqpoint{.5\pgfutil@tempdima}{-.5\pgf@xc}} + {\pgfpoint{\pgfdecoratedremainingdistance+-.5\pgfutil@tempdimb+-.5\pgfutil@tempdima}{\pgf@xc}} + }% + \state{end}[width=0pt,next state=final] + { + { + \pgftransformxshift{\pgfdecoratedremainingdistance}% + \pgftransformxscale{-1}% + \pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/end radius}}% + \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}} + \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}} + \pgfutil@tempcnta=-\pgfdecorationsegmentangle\relax + \advance\pgfutil@tempcnta by90\relax + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/end radius}} + \pgfmathsetlength\pgfutil@tempdimb{\pgfdecorationsegmentamplitude}% + \pgfpathcurveto + {\pgfpointadd + {\pgfpointpolar{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}} + {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}} + {\pgfqpoint{1.25\pgfutil@tempdima}{-.5\pgfutil@tempdimb}} + {\pgfqpoint{1.5\pgfutil@tempdima}{-.5\pgfutil@tempdimb}} + \pgfpathlineto{\pgfpoint{1.5\pgfutil@tempdima}{.5\pgfutil@tempdimb}} + \pgfutil@tempcnta=\pgfdecorationsegmentangle\relax + \advance\pgfutil@tempcnta by-90\relax + \pgfpathcurveto + {\pgfpoint{1.25\pgfutil@tempdima}{.5\pgfutil@tempdimb}} + {\pgfpointadd + {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}} + {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}} + {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}} + \pgfpathclose + } + }% + \state{final} + {}% +}% + + + +\pgfkeys{/pgf/decoration/angle=20}% + +% To paths for connecting circle nodes + +\tikzset{circle connection bar/.style= +{to path={ + \pgfextra{% + \tikz@lib@mindmap@check{\tikztostart}% + \tikz@compute@circle@radii\tikz@compute@segmentamplitude% + } + [every circle connection bar] + decorate [decoration=circle connection bar] + { -- (\tikztotarget) \tikztonodes} +}, +append after command={[fill=\tikz@concept@color,draw=none]} +}}% +\tikzset{every circle connection bar/.style={}}% + +\def\tikz@compute@circle@radii{% + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikztostart}{center}}}% + \pgf@xa=\pgf@x% + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikztostart}{west}}}% + \advance\pgf@xa by-\pgf@x% + \pgfkeys{/pgf/decoration/start radius/.expanded=\the\pgf@xa}% + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikztotarget}{center}}}% + \pgf@xa=\pgf@x% + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikztotarget}{west}}}% + \advance\pgf@xa by-\pgf@x% + \pgfkeys{/pgf/decoration/end radius/.expanded=\the\pgf@xa}% +}% +\def\tikz@compute@segmentamplitude{% + \pgf@x=\pgfkeysvalueof{/pgf/decoration/start radius}\relax% + \ifdim\pgf@x>\pgfkeysvalueof{/pgf/decoration/end radius}\relax% + \pgf@x=\pgfkeysvalueof{/pgf/decoration/end radius}\relax% + \fi% + \pgf@x=.175\pgf@x\relax% + \edef\pgfdecorationsegmentamplitude{\the\pgf@x}% +}% + + + +% Check whether start and end are nodes! + +\def\tikz@lib@mindmap@check#1{% + \pgfutil@ifundefined{pgf@sh@ns@#1}% + {\tikzerror{You are attempting to connect two things by a circle + connection bar where one is not a node}}{% + \expandafter\ifx\csname pgf@sh@ns@#1\endcsname\tikz@lib@coordinate@text% + \tikzerror{You are attempting to connect node of shape + 'coordinate' by a circle connection bar. The shape should be + 'circle' or something similar, instead.} + \fi% + } +}% + +\def\tikz@lib@coordinate@text{coordinate}% + + +% Switch color in a mindmap + +\tikzoption{circle connection bar switch color}{\tikz@parse@switch#1\pgf@unique}% +\def\tikz@parse@switch from (#1) to (#2)\pgf@unique{% + \tikzset{to path={% + \pgfextra{% + \tikz@lib@mindmap@check{\tikztostart}% + \tikz@compute@circle@radii\tikz@compute@segmentamplitude% + \global\let\tikz@lib@save@start=\tikztostart% + \global\let\tikz@lib@save@target=\tikztotarget% + \pgfkeysgetvalue{/pgf/decoration/start radius}\pgf@temp% + \global\let\tikz@lib@saved@start@radius=\pgf@temp% + \pgfkeysgetvalue{/pgf/decoration/end radius}\pgf@temp% + \global\let\tikz@lib@saved@end@radius=\pgf@temp% + }% + [every circle connection bar] + decorate [decoration=circle connection bar] + { -- (\tikztotarget) \tikztonodes} + }, + append after command={ + [fill=none,draw=none,path picture=\tikz@lib@shade@pic] + \pgfextra{ + \pgfutil@colorlet{tikz@switch@from}{#1}% + \pgfutil@colorlet{tikz@switch@to}{#2}% + }} + } +}% + +\def\tikz@lib@shade@pic{% + % We have to draw the shading... + % compute start point: + \pgftransformreset% + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\pgfpointanchor{\tikz@lib@save@start}{center}}{\pgfpointanchor{\tikz@lib@save@target}{center}}}}% + \edef\tikz@lib@mm@vec{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfmathsetlength\pgf@xc{\tikz@lib@saved@start@radius} + \pgf@process{\pgfpointadd{\pgfpointtransformed{\pgfpointanchor{\tikz@lib@save@start}{center}}} + {\pgfpointscale{\pgf@sys@tonumber{\pgf@xc}}{\tikz@lib@mm@vec}}} + \edef\tikz@lib@mm@start{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfmathsetlength\pgf@xc{\tikz@lib@saved@end@radius} + \pgf@process{\pgfpointdiff{\tikz@lib@mm@start}{\pgfpointadd{\pgfpointtransformed{\pgfpointanchor{\tikz@lib@save@target}{center}}} + {\pgfpointscale{-\pgf@sys@tonumber{\pgf@xc}}{\tikz@lib@mm@vec}}}} + \edef\tikz@lib@mm@end{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgftransformshift{\tikz@lib@mm@start} + \pgflowlevelsynccm + \pgf@process{\tikz@lib@mm@vec} + { + \pgf@xa=-\pgf@x% + \pgftransformcm{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@xa}}% + {\pgfpointorigin}% + \pgf@process{\pgfpointtransformed{\tikz@lib@mm@end}}% + \expandafter + } + \edef\tikz@lib@mm@length{\the\pgf@x}% + \pgf@process{\tikz@lib@mm@vec} + \pgf@ya=-\pgf@y% + \pgftransformcm{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}% + {\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}% + {\pgfpointorigin}% + % Y scale: + \pgfmathsetlength\pgf@y{\tikz@lib@saved@start@radius}% + \pgfmathsetlength\pgf@ya{\tikz@lib@saved@end@radius}% + \ifdim\pgf@y<\pgf@ya% + \pgf@y=\pgf@ya% + \fi% + \pgf@y=0.01992528\pgf@y% + \pgftransformyscale{\pgf@sys@tonumber{\pgf@y}}% + \pgfpathrectanglecorners + {\pgfpoint{-\tikz@lib@saved@start@radius}{-50bp}} + {\pgfpoint{1pt}{50bp}} + \pgfsetfillcolor{tikz@switch@from} + \pgfusepath{fill} + \pgfpathrectanglecorners + {\pgfpoint{\tikz@lib@mm@length+\tikz@lib@saved@end@radius}{-50bp}} + {\pgfpoint{\tikz@lib@mm@length-1pt}{50bp}} + \pgfsetfillcolor{tikz@switch@to} + \pgfusepath{fill} + % X scale: + \pgf@x=\tikz@lib@mm@length% + \pgf@x=0.009962\pgf@x% + \pgftransformxscale{\pgf@sys@tonumber{\pgf@x}}% + \pgftransformxshift{50bp} + \pgflowlevelsynccm% + \pgfuseshading{tikz@shade@bar} +}% + +\tikzoption{concept color}{% + \let\tikz@old@concept@color=\tikz@concept@color% + \def\tikz@edge@to@parent@path{ + (\tikzparentnode) + to[circle connection bar switch color=from (\tikz@old@concept@color) to (#1)] + (\tikzchildnode)} + \def\tikz@concept@color{#1}% +}% + +\pgfdeclarehorizontalshading[tikz@switch@from,tikz@switch@to]{tikz@shade@bar}{100bp}{% + color(0pt)=(tikz@switch@from); + color(100bp)=(tikz@switch@to)}% + + + + +% A concept node + +\tikzset{concept/.style= {circle,fill=\tikz@concept@color,draw=\tikz@concept@color,every concept}}% +\tikzset{every concept/.style= {}}% + +\def\tikz@concept@color{black}% + +\tikzset{tikz@concept@setting/.style={edge from parent path={(\tikzparentnode) to [circle connection bar] (\tikzchildnode)}}}% +\tikzset{tikz@concept@color@set/.style={}}% + + +\tikzset{extra concept/.style= {concept color=black!50,level 2 concept,concept,every extra concept}}% +\tikzset{every extra concept/.style={}}% + +\tikzset{concept connection/.style={line width=1mm,shorten <=2mm,shorten >=2mm,cap=round,draw=black!50}}% + + +% A mindmap + +\tikzset{mindmap/.style= + {fill,draw,very thick,outer sep=0pt,inner sep=1pt,% + every child/.append style={style=tikz@concept@setting,style=tikz@concept@color@set},% + root concept, + level 1/.append style={level 1 concept}, + level 2/.append style={level 2 concept}, + level 3/.append style={level 3 concept}, + level 4/.append style={level 4 concept}, + text centered,% + segment angle=20, + style=every mindmap, + }}% +\tikzset{every mindmap/.style={}}% + + +\tikzset{root concept/.style= {minimum size=4cm,text width=3.5cm,font=\pgfutil@font@large}}% +\tikzset{level 1 concept/.style={minimum size=2.25cm, + level distance=5cm, + text width=2cm, + sibling angle=60, + font=\pgfutil@font@small}}% +\tikzset{level 2 concept/.style={minimum size=1.75cm,% + level distance=2.9cm,% + text width=1.5cm,% + sibling angle=60,% + font=\pgfutil@font@footnotesize}}% +\tikzset{level 3 concept/.style={minimum size=1.15cm,% + text width=1cm,% + level distance=2.4cm,% + sibling angle=30,% + font=\pgfutil@font@tiny}}% +\tikzset{level 4 concept/.style={minimum size=0.9cm,% + text width=0.7cm, + level distance=1.85cm,% + sibling angle=30,% + font=\pgfutil@font@tiny}}% + +\tikzset{small mindmap/.style= + {% + root concept/.style={minimum size=2.3cm,text width=2.1cm,font=\pgfutil@font@footnotesize}, + level 1 concept/.style={% + minimum size=1.5cm, + level distance=2.8cm, + text width=1.4cm, + sibling angle=75, + font=\pgfutil@font@scriptsize},% + level 2 concept/.style={% + minimum size=1.1cm,% + level distance=2.2cm,% + text width=1.1cm,% + sibling angle=60,% + font=\pgfutil@font@tiny},% + level 3 concept/.style={% + level 2 concept, + sibling angle=30,% + font=\pgfutil@font@tiny},% + level 4 concept/.style={% + level 3 concept, + }, + mindmap,% + line width=2pt, + }}% + +\tikzset{large mindmap/.style= + {% + root concept/.style={minimum size=5.6cm,text width=4.5cm,font=\pgfutil@font@Large}, + level 1 concept/.style={% + minimum size=3.2cm, + level distance=7cm, + text width=2.8cm, + sibling angle=60, + font=},% + level 2 concept/.style={% + minimum size=2.45cm,% + level distance=4cm,% + text width=2.2cm,% + sibling angle=60,% + font=\pgfutil@font@small% + },% + level 3 concept/.style={% + minimum size=1.63cm,% + text width=1.4cm,% + level distance=3.38cm,% + sibling angle=30,% + font=\pgfutil@font@scriptsize},% + level 4 concept/.style={% + minimum size=1.27cm,% + text width=1cm, + level distance=2.60cm,% + sibling angle=30,% + font=\pgfutil@font@tiny},% + mindmap,% + line width=2pt, + }}% + +\tikzset{huge mindmap/.style= + {% + root concept/.style={minimum size=8cm,text width=7cm,font=\pgfutil@font@huge}, + level 1 concept/.style={% + minimum size=4.5cm, + level distance=10cm, + text width=4cm, + sibling angle=60, + font=\pgfutil@font@large},% + level 2 concept/.style={% + minimum size=3.5cm,% + level distance=5.8cm,% + text width=3cm,% + sibling angle=60,% + font=% + },% + level 3 concept/.style={% + minimum size=2.3cm,% + text width=2cm,% + level distance=4.8cm,% + sibling angle=30,% + font=\pgfutil@font@footnotesize},% + level 4 concept/.style={% + minimum size=1.7cm,% + text width=1.4cm, + level distance=3.7cm,% + sibling angle=30,% + font=\pgfutil@font@scriptsize},% + mindmap,% + line width=3pt, + }}% + + +% Annotations + +\tikzset{annotation/.style={shape=rectangle, + minimum size=0pt, + text width=3.5cm, + outer sep=1.5mm, + inner sep=1mm, + text badly ragged, + rounded corners, + font=\pgfutil@font@tiny, + every annotation}}% +\tikzset{every annotation/.style={}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.code.tex new file mode 100644 index 0000000000..8ef495bbba --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.code.tex @@ -0,0 +1,31 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarypatterns.code.tex} + +\usepgflibrary{patterns}% + +\tikzoption{pattern color}{\edef\tikz@pattern@color{#1}}% +\tikzoption{pattern}[]{% + \edef\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@fillfalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \tikz@addoption{\pgfsetfillpattern{#1}{\tikz@pattern@color}}% + \def\tikz@pattern{#1}% + \fi% + \tikz@addmode{\tikz@mode@filltrue}% + \fi% +}% +\def\tikz@pattern@color{black}% +\def\tikz@pattern{dots}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.meta.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.meta.code.tex new file mode 100644 index 0000000000..de96fd9093 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypatterns.meta.code.tex @@ -0,0 +1,98 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{patterns.meta}% + +\tikzset{% + pattern color/.code=\edef\tikz@pattern@color{#1}, + pattern/.code={% + \edef\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@fillfalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \tikz@addoption{\pgfsetfillpattern{#1}{\tikz@pattern@color}}% + \def\tikz@pattern{#1}% + \fi% + \tikz@addmode{\tikz@mode@filltrue}% + \fi% + } +}% + +\def\tikz@pattern@color{black}% +\def\tikz@pattern{}% + +\tikzset{patterns/.cd, + .unknown/.code={% + \let\tikz@pat@key=\pgfkeyscurrentname% + \pgfkeys{/pgf/patterns/\tikz@pat@key/.try={#1}}% + }, + bottom left/.style={/pgf/patterns/bottom left={\tikz@scan@one@point\pgf@pat@process#1}}, + top right/.style={/pgf/patterns/top right={\tikz@scan@one@point\pgf@pat@process#1}}, + bounding box/.style args={#1(#2)#3and#4(#5)#6}{% + /tikz/patterns/bottom left={(#2)}, + /tikz/patterns/top right={#4(#5)}, + }, + tile size/.style={/pgf/patterns/tile size={\tikz@scan@one@point\pgf@pat@process#1}}, + tile transformation/.style={/pgf/patterns/tile transformation={% + \let\tikz@transform=\relax\pgfkeys{/tikz/.cd,#1}}% + }, + infer tile bounding box/.code={ + \def\pgf@pat@codeafter{% + \xdef\tikz@pat@installbb{% + \noexpand\pgfkeys{/tikz/patterns/bounding box={% + (\the\pgf@picminx-#1,\the\pgf@picminy-#1) and + (\the\pgf@picmaxx+#1,\the\pgf@picmaxy+#1) + }, + /tikz/patterns/tile size={% + (\the\pgf@picmaxx-\the\pgf@picminx, + \the\pgf@picmaxy-\the\pgf@picminy)}}}% + }% + \let\pgf@pat@declarepost=\tikz@pat@installbb% + }, + infer tile bounding box/.default=0pt, +}% + +\def\tikzdeclarepattern#1{% + \begingroup% + \def\pgf@pat@codebefore{% + \let\tikz@transform=\relax% + \pgftransformreset% <- Hmm? + \tikz@declarepattern@install% + \ifnum\pgf@pat@type=0\relax% + \let\pgfsetstrokecolor=\pgfutil@gobble% + \let\pgfsetfillcolor=\pgfutil@gobble% + \fi% + \def\tikz@fig{\tikzerror{You cannot use `\string\node' inside a pattern}}% + \def\tikz@edge@plain{\tikzerror{You cannot use `edge' inside a pattern}}% + \def\tikz@to{\tikzerror{You cannot use `to' paths inside a pattern}}% + \tikzset{pattern/.code={\tikzerror{You cannot nest patterns}}, + pattern color/.style={pattern}}% + }% + \pgfdeclarepattern{/tikz/patterns/.cd,#1}% + \endgroup% + }% + +\def\tikz@declarepattern@install{% + \let\tikz@compat@color@set=\tikz@compat@color@set@insidepatttern% + \tikz@installcommands% +}% + +\let\tikz@compat@color@set@orig=\tikz@compat@color@set +\def\tikz@compat@color@set@insidepatttern#1{% + \tikz@compat@color@set@orig{#1}% + \pgfsetfillcolor{#1}\pgfsetstrokecolor{#1}% +}% + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryperspective.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryperspective.code.tex new file mode 100644 index 0000000000..f9651ea973 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryperspective.code.tex @@ -0,0 +1,111 @@ +% Copyright 2019 by Max Snippe +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryperspective.code.tex} + +% Initialize affine transformation matrix for perspective view +% [aa ab ac 0] +% [ba bb bc 0] +% [ca cb cc 0] +% [da db dc 1] +\pgfmathsetmacro\pgf@H@tpp@aa{+1} + \pgfmathsetmacro\pgf@H@tpp@ab{+0} + \pgfmathsetmacro\pgf@H@tpp@ac{+0} +\pgfmathsetmacro\pgf@H@tpp@ba{+0} + \pgfmathsetmacro\pgf@H@tpp@bb{+1} + \pgfmathsetmacro\pgf@H@tpp@bc{+0} +\pgfmathsetmacro\pgf@H@tpp@ca{+0} + \pgfmathsetmacro\pgf@H@tpp@cb{+0} + \pgfmathsetmacro\pgf@H@tpp@cc{+1} +\pgfmathsetmacro\pgf@H@tpp@da{+0} + \pgfmathsetmacro\pgf@H@tpp@db{+0} + \pgfmathsetmacro\pgf@H@tpp@dc{+0} + +\def\pgfpointperspectivexyz#1#2#3{% + \pgfmathsetmacro\pgf@pp@w% + { \pgf@H@tpp@da*(#1) + \pgf@H@tpp@db*(#2) + \pgf@H@tpp@dc*(#3) + 1} + \pgfmathsetmacro\pgf@pp@x% + {(\pgf@H@tpp@aa*(#1) + \pgf@H@tpp@ab*(#2) + \pgf@H@tpp@ac*(#3))/\pgf@pp@w} + \pgfmathsetmacro\pgf@pp@y% + {(\pgf@H@tpp@ba*(#1) + \pgf@H@tpp@bb*(#2) + \pgf@H@tpp@bc*(#3))/\pgf@pp@w} + \pgfmathsetmacro\pgf@pp@z% + {(\pgf@H@tpp@ca*(#1) + \pgf@H@tpp@cb*(#2) + \pgf@H@tpp@cc*(#3))/\pgf@pp@w} +% + \pgf@x=\pgf@pp@x\pgf@xx% + \advance\pgf@x by \pgf@pp@y\pgf@yx% + \advance\pgf@x by \pgf@pp@z\pgf@zx% + \pgf@y=\pgf@pp@x\pgf@xy% + \advance\pgf@y by \pgf@pp@y\pgf@yy% + \advance\pgf@y by \pgf@pp@z\pgf@zy} + +\tikzdeclarecoordinatesystem{three point perspective} +{% + \tikzset{cs/.cd,x=0,y=0,z=0,#1}% + \pgfpointperspectivexyz{\tikz@cs@x}{\tikz@cs@y}{\tikz@cs@z} +} +\tikzaliascoordinatesystem{tpp}{three point perspective} + +\pgfkeys{ + /perspective/.cd, + p/.code args={(#1,#2,#3)}{ + \pgfmathparse{ifthenelse(#1,int(1),int(0))} + \ifnum\pgfmathresult=0\else + \pgfmathsetmacro\pgf@H@tpp@ba{#2/#1} + \pgfmathsetmacro\pgf@H@tpp@ca{#3/#1} + \pgfmathsetmacro\pgf@H@tpp@da{ 1/#1} + \fi + }, + q/.code args={(#1,#2,#3)}{ + \pgfmathparse{ifthenelse(#2,int(1),int(0))} + \ifnum\pgfmathresult=0\else + \pgfmathsetmacro\pgf@H@tpp@ab{#1/#2} + \pgfmathsetmacro\pgf@H@tpp@cb{#3/#2} + \pgfmathsetmacro\pgf@H@tpp@db{ 1/#2} + \fi + }, + r/.code args={(#1,#2,#3)}{ + \pgfmathparse{ifthenelse(#3,int(1),int(0))} + \ifnum\pgfmathresult=0\else + \pgfmathsetmacro\pgf@H@tpp@ac{#1/#3} + \pgfmathsetmacro\pgf@H@tpp@bc{#2/#3} + \pgfmathsetmacro\pgf@H@tpp@dc{ 1/#3} + \fi + }, +} + +\tikzset{ + perspective/.append code={\pgfkeys{/perspective/.cd,#1}}, + perspective/.default={ + p={(10,0,0)}, + q={(0,10,0)}, + r={(0,0,20)}}, +} + +\tikzset{ + 3d view/.code 2 args={% + % Set elevation and azimuth angles + \pgfmathsetmacro\pgf@view@az{#1}% + \pgfmathsetmacro\pgf@view@el{#2}% + % Calculate projections of rotation matrix + \pgfmathsetmacro\pgf@xvec@x{cos(\pgf@view@az)}% + \pgfmathsetmacro\pgf@xvec@y{-sin(\pgf@view@az)*sin(\pgf@view@el)}% + \pgfmathsetmacro\pgf@yvec@x{sin(\pgf@view@az)}% + \pgfmathsetmacro\pgf@yvec@y{cos(\pgf@view@az)*sin(\pgf@view@el)}% + \pgfmathsetmacro\pgf@zvec@x{+0}% + \pgfmathsetmacro\pgf@zvec@y{cos(\pgf@view@el)}% + % Set base vectors + \pgfsetxvec{\pgfpoint{\pgf@xvec@x cm}{\pgf@xvec@y cm}}% + \pgfsetyvec{\pgfpoint{\pgf@yvec@x cm}{\pgf@yvec@y cm}}% + \pgfsetzvec{\pgfpoint{\pgf@zvec@x cm}{\pgf@zvec@y cm}}% + }, + 3d view/.default={-30}{15}, + isometric view/.style={3d view={-45}{atan(1/sqrt(2))}}, +} + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypetri.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypetri.code.tex new file mode 100644 index 0000000000..80c34c175e --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypetri.code.tex @@ -0,0 +1,146 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarypetri.code.tex} + + +% Styles for places: + +\tikzset{every place/.style= {}}% +\tikzset{place/.style= {circle,draw,inner sep=0pt, + minimum size=5ex, + every place}}% + + +% Styles for transition: + +\tikzset{every transition/.style= {}}% +\tikzset{transition/.style= {rectangle,draw,inner sep=0pt, + minimum size=4mm, + every transition}}% + + +% Styles for relationship types: + +\tikzset{pre/.style= {<-,shorten <=1pt}}% +\tikzset{post/.style= {->,shorten >=1pt}}% +\tikzset{pre and post/.style= {<->,shorten >=1pt,shorten <=1pt}}% + + + +% Styles for marks: + +\tikzset{every token/.style= {}}% +\tikzset{token/.style= {fill=black,draw=none,circle, + inner sep=0.5pt,minimum size=1ex, + text=white,font=\pgfutil@font@tiny,every token}}% + +\tikzoption{token distance}{\def\tikz@token@distance{#1}}% +\def\tikz@token@distance{1.5ex}% + +\tikzset{children are tokens/.style= {growth function=\tikz@grow@tokens,edge from parent path=}}% + +\tikzoption{tokens}{% + \ifnum#1>0\relax% + \tikzset{append after command={} + {[children are tokens]child foreach \tikz@dummy in {1,...,#1} {node[token]{}}}}% + \fi}% + +\tikzoption{colored tokens}{% + \tikzset{append after command={}% + {[children are tokens]child foreach \tikz@child@color in {#1} {node[token,\tikz@child@color]{}}}}% + }% + +\tikzoption{structured tokens}{% + \tikzset{append after command={}% + {[children are tokens]child foreach \tikzpetrichildname in {#1} {node[token]{\tikzpetrichildname}}}}% + }% + + +\def\tikz@grow@tokens{% + \pgfmathsetlength{\pgf@xa}{\tikz@token@distance}% + \pgfmathsetlength{\pgf@ya}{\tikz@token@distance}% + \pgf@xc=0pt% + \pgf@yc=0pt% + \csname tikz@grow@tokens@placer@\the\tikznumberofchildren @\the\tikznumberofcurrentchild\endcsname% + \pgftransformshift{\pgfqpoint{\pgf@xc}{\pgf@yc}}% +}% + +\def\tikz@def@grow@tokens#1#2#3#4{% + \expandafter\def\csname tikz@grow@tokens@placer@#1@#2\endcsname{% + \pgf@xc=#3\pgf@xa% + \pgf@yc=#4\pgf@ya}% +}% + + +% Single token +\tikz@def@grow@tokens{1}{1}{0}{0}% + +% Two tokens +\tikz@def@grow@tokens{2}{1}{-.5}{0}% +\tikz@def@grow@tokens{2}{2}{.5}{0}% + +% Three tokens +\tikz@def@grow@tokens{3}{1}{0} {0.57}% +\tikz@def@grow@tokens{3}{2}{-.5}{-.306025}% +\tikz@def@grow@tokens{3}{3}{.5} {-.306025}% + +% Four tokens +\tikz@def@grow@tokens{4}{1}{-.5}{.5}% +\tikz@def@grow@tokens{4}{2}{.5}{.5}% +\tikz@def@grow@tokens{4}{3}{-.5}{-.5}% +\tikz@def@grow@tokens{4}{4}{.5}{-.5}% + +% Five tokens +\tikz@def@grow@tokens{5}{1}{0}{.85}% +\tikz@def@grow@tokens{5}{2}{-0.808398}{0.26266}% +\tikz@def@grow@tokens{5}{3}{0.808398}{0.26266}% +\tikz@def@grow@tokens{5}{4}{-0.499617}{-0.687664}% +\tikz@def@grow@tokens{5}{5}{0.499617}{-0.687664}% + +% Six tokens +\tikz@def@grow@tokens{6}{1}{-1}{.5}% +\tikz@def@grow@tokens{6}{2}{0}{.5}% +\tikz@def@grow@tokens{6}{3}{1}{.5}% +\tikz@def@grow@tokens{6}{4}{-1}{-.5}% +\tikz@def@grow@tokens{6}{5}{0}{-.5}% +\tikz@def@grow@tokens{6}{6}{1}{-.5}% + +% Seven tokens +\tikz@def@grow@tokens{7}{1}{0}{1}% +\tikz@def@grow@tokens{7}{2}{-1}{.5}% +\tikz@def@grow@tokens{7}{3}{0}{0}% +\tikz@def@grow@tokens{7}{4}{1}{.5}% +\tikz@def@grow@tokens{7}{5}{-1}{-.5}% +\tikz@def@grow@tokens{7}{6}{0}{-1}% +\tikz@def@grow@tokens{7}{7}{1}{-.5}% + +% Eight tokens +\tikz@def@grow@tokens{8}{1}{-.5}{1}% +\tikz@def@grow@tokens{8}{2}{.5}{1}% +\tikz@def@grow@tokens{8}{3}{-1}{0}% +\tikz@def@grow@tokens{8}{4}{0}{0}% +\tikz@def@grow@tokens{8}{5}{1}{0}% +\tikz@def@grow@tokens{8}{6}{-1}{-1}% +\tikz@def@grow@tokens{8}{7}{0}{-1}% +\tikz@def@grow@tokens{8}{8}{1}{-1}% + +% Eight tokens +\tikz@def@grow@tokens{9}{1}{-1}{1}% +\tikz@def@grow@tokens{9}{2}{0}{1}% +\tikz@def@grow@tokens{9}{3}{1}{1}% +\tikz@def@grow@tokens{9}{4}{-1}{0}% +\tikz@def@grow@tokens{9}{5}{0}{0}% +\tikz@def@grow@tokens{9}{6}{1}{0}% +\tikz@def@grow@tokens{9}{7}{-1}{-1}% +\tikz@def@grow@tokens{9}{8}{0}{-1}% +\tikz@def@grow@tokens{9}{9}{1}{-1}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplothandlers.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplothandlers.code.tex new file mode 100644 index 0000000000..e6db2b62ff --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplothandlers.code.tex @@ -0,0 +1,14 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryplothandlers.code.tex} + +\usepgflibrary{plothandlers}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplotmarks.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplotmarks.code.tex new file mode 100644 index 0000000000..15eea57201 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryplotmarks.code.tex @@ -0,0 +1,14 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryplotmarks.code.tex} + +\usepgflibrary{plotmarks}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypositioning.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypositioning.code.tex new file mode 100644 index 0000000000..b410975c32 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarypositioning.code.tex @@ -0,0 +1,118 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarypositioning.code.tex} + + +\tikzset{above/.code=\tikz@lib@place@handle@{#1}{south}{0}{1}{north}{1}}% +\tikzset{above left/.code=\tikz@lib@place@handle@{#1}{south east}{-1}{1}{north west}{0.707106781}}% +\tikzset{above right/.code=\tikz@lib@place@handle@{#1}{south west}{1}{1}{north east}{0.707106781}}% +\tikzset{base left/.code =\tikz@lib@place@handle@{#1}{base east}{-1}{0}{base west}{1}}% +\tikzset{base right/.code=\tikz@lib@place@handle@{#1}{base west}{1}{0}{base east}{1}}% +\tikzset{below/.code=\tikz@lib@place@handle@{#1}{north}{0}{-1}{south}{1}}% +\tikzset{below left/.code=\tikz@lib@place@handle@{#1}{north east}{-1}{-1}{south west}{0.707106781}}% +\tikzset{below right/.code=\tikz@lib@place@handle@{#1}{north west}{1}{-1}{south east}{0.707106781}}% +\tikzset{left/.code =\tikz@lib@place@handle@{#1}{east}{-1}{0}{west}{1}}% +\tikzset{mid left/.code =\tikz@lib@place@handle@{#1}{mid east}{-1}{0}{mid west}{1}}% +\tikzset{mid right/.code=\tikz@lib@place@handle@{#1}{mid west}{1}{0}{mid east}{1}}% +\tikzset{right/.code=\tikz@lib@place@handle@{#1}{west}{1}{0}{east}{1}}% + +\newif\iftikz@lib@ignore@size + +% Hook into resets: +\pgfutil@g@addto@macro\tikz@node@reset@hook{\tikz@addtransform{\tikz@lib@pos@call}\let\tikz@lib@pos@call=\relax}% + +\tikzset{on grid/.is if=tikz@lib@ignore@size}% + +\tikzset{node distance=1cm and 1cm}% + +\def\tikz@lib@place@handle@#1#2#3#4#5#6{% + \def\tikz@anchor{#2}% + \let\tikz@do@auto@anchor=\relax% + \edef\tikz@temp{#1}% + \def\tikz@lib@place@single@factor{#6}% + \expandafter\tikz@lib@place@handle@@\expandafter{\tikz@temp}{#3}{#4}{#5}% +}% +\def\tikz@lib@place@handle@@#1#2#3#4{% + \pgfutil@in@{of }{#1}% + \ifpgfutil@in@% + \tikz@lib@place@of#1\tikz@stop{#4}% + \else% + \edef\tikz@lib@place@nums{#1}% + \fi% + \ifx\tikz@lib@place@nums\pgfutil@empty% + % Ok, nothing to do, we have set the anchor and we are happy... + \else% + \expandafter\tikz@lib@place@parse@nums\expandafter{\tikz@lib@place@nums}% + \pgf@x=#2\pgf@x% + \pgf@y=#3\pgf@y% + \edef\tikz@lib@pos@call{\noexpand\pgftransformshift{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + \fi% +}% + +\def\tikz@lib@place@parse@nums#1{% + \pgfutil@in@{and}{#1}% + \ifpgfutil@in@% + \tikz@lib@place@parse@nums@#1\tikz@stop% + \else% + \tikz@lib@place@parse@nums@#1and#1\tikz@stop% + \pgf@x=\tikz@lib@place@single@factor\pgf@x% + \pgf@y=\tikz@lib@place@single@factor\pgf@y% + \fi +}% +\def\tikz@lib@place@parse@nums@#1and#2\tikz@stop{% + \pgfmathparse{#2}% + \ifpgfmathunitsdeclared% + \pgf@xa=\pgfmathresult pt% + \pgf@ya=0pt% + \else% + \let\tikz@lib@temp=\pgfmathresult% + \pgf@process{\pgfpointxy{\tikz@lib@temp}{0}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \fi% + \pgfmathparse{#1}% + \ifpgfmathunitsdeclared% + \advance\pgf@ya by\pgfmathresult pt% + \else% + \let\tikz@lib@temp=\pgfmathresult% + \pgf@process{\pgfpointxy{0}{\tikz@lib@temp}}% + \advance\pgf@xa by\pgf@x% + \advance\pgf@ya by\pgf@y% + \fi% + \pgf@x=\pgf@xa% + \pgf@y=\pgf@ya% +}% + +\def\tikz@lib@place@of#1of #2\tikz@stop#3{% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \tikz@lib@place@of@{\tikz@node@distance}{#2}{#3}% + \else% + \tikz@lib@place@of@{#1}{#2}{#3}% + \fi% +}% +\def\tikz@lib@place@of@#1#2#3{% + \tikz@scan@one@point\tikz@lib@place@remember(#2)% + \iftikz@shapeborder% + % Ok, this is relative to a border. + \iftikz@lib@ignore@size% + \edef\tikz@node@at{\noexpand\pgfpointanchor{\tikz@shapeborder@name}{center}}% + \def\tikz@anchor{center}% + \else% + \edef\tikz@node@at{\noexpand\pgfpointanchor{\tikz@shapeborder@name}{#3}}% + \fi% + \fi% + \edef\tikz@lib@place@nums{#1}% +}% +\def\tikz@lib@place@remember#1{\def\tikz@node@at{#1}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryquotes.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryquotes.code.tex new file mode 100644 index 0000000000..41ce3faaf5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryquotes.code.tex @@ -0,0 +1,90 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryquotes.code.tex} + +\def\tikz@quote@parser#1{\tikz@quote@@parser#1\pgf@stop}% +\def\tikz@quote@@parser"#1"{% + \pgfutil@ifnextchar\bgroup{% + \tikz@quote@@parser@group{#1}}{% + \pgfutil@ifnextchar'{% + \tikz@quote@@parser@apo{#1}}{% + \tikz@quote@@parser@normal{#1}}}}% +\def\tikz@quote@@parser@apo#1'{% + \pgfutil@ifnextchar\bgroup{\tikz@quote@@parser@apo@group{#1}}{\tikz@quote@@parser@apo@normal{#1}}}% +\def\tikz@quote@@parser@group#1#2#3\pgf@stop{% + \expandafter\def\expandafter\tikz@temp\expandafter{\tikz@quotes@as{#1}{#2}}% + \expandafter\pgfkeysalso\expandafter{\tikz@temp}% +}% +\def\tikz@quote@@parser@normal#1#2\pgf@stop{% + \expandafter\def\expandafter\tikz@temp\expandafter{\tikz@quotes@as{#1}{#2}}% + \expandafter\pgfkeysalso\expandafter{\tikz@temp}% +}% +\def\tikz@quote@@parser@apo@group#1#2#3\pgf@stop{% + \expandafter\def\expandafter\tikz@temp\expandafter{\tikz@quotes@as{#1}{',#2}}% + \expandafter\pgfkeysalso\expandafter{\tikz@temp}% +}% +\def\tikz@quote@@parser@apo@normal#1#2\pgf@stop{% + \expandafter\def\expandafter\tikz@temp\expandafter{\tikz@quotes@as{#1}{',#2}}% + \expandafter\pgfkeysalso\expandafter{\tikz@temp}% +}% + +\pgfkeys{/handlers/first char syntax=true}% + +\def\tikz@enable@node@quotes{% + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\tikz@quote@parser}% + \let\tikz@quotes@as\tikz@node@quotes@as% +}% +\def\tikz@enable@edge@quotes{% + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\tikz@quote@parser}% + \let\tikz@quotes@as\tikz@edge@quotes@as% +}% +\def\tikz@enable@pic@quotes{% + \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\tikz@quote@parser}% + \let\tikz@quotes@as\tikz@pic@quotes@as% +}% + +\tikzset{ + node quotes mean/.code={\def\tikz@node@quotes@as##1##2{#1}}, + edge quotes mean/.code={\def\tikz@edge@quotes@as##1##2{#1}}, + pic quotes mean/.code={\def\tikz@pic@quotes@as##1##2{#1}}, + quotes mean pin/.style={node quotes mean={ + pin={[direction shorthands,every pin quotes/.try,##2]##1}}}, + quotes mean label/.style={node quotes mean={ + label={[direction shorthands,every label quotes/.try,##2]##1}}}, + quotes mean label, + edge quotes mean={edge node={node [every edge quotes,#2]{#1}}}, + pic quotes mean={pic text={#1},pic text options={every pic quotes/.try,#2}}, + every edge quotes/.style={auto}, + direction shorthands/.code={% + \pgfkeyslet{/tikz/centered/.@cmd}\tikz@label@@centered + \pgfkeyslet{/tikz/above/.@cmd}\tikz@label@@above + \pgfkeyslet{/tikz/below/.@cmd}\tikz@label@@below + \pgfkeyslet{/tikz/left/.@cmd}\tikz@label@@left + \pgfkeyslet{/tikz/right/.@cmd}\tikz@label@@right + \pgfkeyslet{/tikz/above left/.@cmd}\tikz@label@@above@left + \pgfkeyslet{/tikz/above right/.@cmd}\tikz@label@@above@right + \pgfkeyslet{/tikz/below left/.@cmd}\tikz@label@@below@left + \pgfkeyslet{/tikz/below right/.@cmd}\tikz@label@@below@right + } +}% + +\def\tikz@label@@centered#1\pgfeov{\pgfkeysalso{label position=center,pin position=center}}% +\def\tikz@label@@above#1\pgfeov{\pgfkeysalso{label position=90,pin position=90}}% +\def\tikz@label@@below#1\pgfeov{\pgfkeysalso{label position=-90,pin position=-90}}% +\def\tikz@label@@left#1\pgfeov{\pgfkeysalso{label position=180,pin position=180}}% +\def\tikz@label@@right#1\pgfeov{\pgfkeysalso{label position=0,pin position=0}}% +\def\tikz@label@@above@left#1\pgfeov{\pgfkeysalso{label position=135,pin position=135}}% +\def\tikz@label@@below@left#1\pgfeov{\pgfkeysalso{label position=-135,pin position=-135}}% +\def\tikz@label@@above@right#1\pgfeov{\pgfkeysalso{label position=45,pin position=45}}% +\def\tikz@label@@below@right#1\pgfeov{\pgfkeysalso{label position=-45,pin position=-45}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryrdf.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryrdf.code.tex new file mode 100644 index 0000000000..74e77ac3e2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryrdf.code.tex @@ -0,0 +1,291 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryrdf.code.tex} + + + +\def\tikz@add@rdf@pre@option#1{\expandafter\def\expandafter\tikz@rdf@pre@options\expandafter{\tikz@rdf@pre@options#1}}% +\def\tikz@add@rdf@post@option#1{\expandafter\def\expandafter\tikz@rdf@post@options\expandafter{\tikz@rdf@post@options#1}}% + +\let\tikz@rdf@pre@options\pgfutil@empty +\let\tikz@rdf@post@options\pgfutil@empty + +\tikzset{ + % + % Switching on the engine + % + rdf engine on/.code={% + \def\tikz@clear@rdf@options{\let\tikz@rdf@pre@options\pgfutil@empty\let\tikz@rdf@post@options\pgfutil@empty}% + \def\tikz@do@rdf@pre@options{\tikz@rdf@pre@options\let\tikz@rdf@pre@options\pgfutil@empty}% + \def\tikz@do@rdf@post@options{\tikz@rdf@post@options\let\tikz@rdf@post@options\pgfutil@empty}% + \pgfkeys{/tikz/rdf engine/.code=\tikz@add@rdf@pre@option{\pgfqkeys{/tikz/rdf engine}{##1}}}% + }, + rdf engine/.cd, + % + every statement/.style=, + % + % Namespaces + % + prefix/.code=\pgfrdfprefix{#1}, + % + % Core commands + % + statement/.code={% + {% + \pgfkeys{/tikz/rdf engine/every statement}% + \pgfqkeys{/tikz/rdf engine/statements}{#1}% + \iftikz@rdf@is@a@container\tikz@rdf@init@container\fi% + \iftikz@rdf@is@a@member\tikz@rdf@make@member\fi% + \tikz@rdf@make@triple% + \expandafter}\tikz@rdf@action% + }, + get scope curie/.code={% + \ifx\tikz@id@name\pgfutil@empty% + \def\tikz@id@name{@rdf}% + \fi% + \pgfidrefnextuse\tikz@temp{\tikz@id@name}% + \edef#1{\tikzrdfhashmark\tikz@temp}% + }, + get new resource curie/.code={% + \pgfsys@new@id\tikz@temp% + \edef#1{\tikzrdfhashmark\tikz@temp}% + }, + scope is new context/.style={get scope curie=\tikzrdfcontext} +}% + +\def\tikzrdfcontext{\tikzrdfhashmark}%empty by default + +\tikzset{ + rdf engine/statements/.cd, + % + % Core properties of statements + % + subject/.code={% + \def\tikz@rdf@target{\tikz@rdf@subject}% + \tikz@rdf@parse{#1}% + }, + predicate/.code={% + \def\tikz@rdf@target{\tikz@rdf@predicate}% + \tikz@rdf@parse{#1}% + }, + object/.code={% + \let\tikz@rdf@object@literal\relax% + \let\tikz@rdf@object\relax% + \def\tikz@temp{#1}% + \ifx\tikz@temp\tikz@rdf@current@scope@text% + \tikz@rdf@object@scope@contenttrue% + \else% + \tikz@rdf@object@scope@contentfalse% + \def\tikz@rdf@target{\tikz@rdf@object}% + \tikz@rdf@parse{#1}% + \fi% + }, + % + % Shorthands + % + has type/.style={predicate=rdf:type,object={#1}}, + % + % Containers + % + is a bag/.style={has type=rdf:Bag, is a container}, + is a sequence/.style={has type=rdf:Seq, is a container}, + is an alternative/.style={has type=rdf:Alt, is a container}, + % + is a container/.code={\tikz@rdf@is@a@containertrue}, + % + has as member/.code={\tikz@rdf@is@a@membertrue},% +}% + +\def\tikz@rdf@current@scope@text{scope content}% + +\let\tikz@rdf@subject\relax +\let\tikz@rdf@predicate\pgfutil@empty +\let\tikz@rdf@object\relax +\let\tikz@rdf@object@literal\relax +\let\tikz@rdf@container\relax + +\newif\iftikz@rdf@object@scope@content +\newif\iftikz@rdf@is@a@container +\newif\iftikz@rdf@is@a@member + + +\def\tikz@rdf@parse#1{% + \edef\tikz@temp{#1}% + \expandafter\tikz@rdf@parse@#1\relax% +}% + +\def\tikz@rdf@parse@{% + \pgfutil@ifnextchar({\tikz@rdf@parse@name}{%) + \pgfutil@ifnextchar"{\tikz@rdf@parse@literals}{% + \tikz@rdf@parse@curie% + }% + }% +}% + +\def\tikz@rdf@parse@name(#1)\relax{% + \pgfidrefprevuse\tikz@rdf@the@id{#1}\expandafter\edef\tikz@rdf@target{\tikzrdfhashmark\tikz@rdf@the@id}% +}% +\def\tikz@rdf@parse@literals"#1"{% + \ifx\tikz@rdf@target\tikz@rdf@object@name% + \def\tikz@rdf@object@literal{#1}% + \else% + \tikzerror{Only RDF objects can be literals}% + \fi% + \pgfutil@ifnextchar\relax\pgfutil@gobble\tikz@rdf@parse@literals@rest% +}% +\def\tikz@rdf@parse@literals@rest and scope content\relax{% + \tikz@rdf@object@scope@contenttrue% +}% + +\def\tikz@rdf@object@name{\tikz@rdf@object}% +\def\tikz@rdf@parse@curie#1\relax{% + \expandafter\def\tikz@rdf@target{#1}% +}% + +{% + \catcode`\#=11 + \gdef\tikzrdfhashmark{#}% +}% + + +\def\tikz@rdf@make@triple{% + % First, ensure that subject, predicate and object are set: + \ifx\tikz@rdf@subject\relax% + \tikzerror{RDF statement misses subject}% + \else% + \ifx\tikz@rdf@predicate\relax% + \tikzerror{RDF statement misses predicate}% + \else% + \iftikz@rdf@object@scope@content% + \edef\tikz@marshal{\noexpand\tikz@rdf@make@content@triple{\tikz@rdf@subject}{\tikz@rdf@predicate}{\tikz@rdf@object@literal}}% + \tikz@marshal% + \else% + \ifx\tikz@rdf@object\relax% + \ifx\tikz@rdf@object@literal\relax% + \tikzerror{RDF statement misses object}% + \else% + \edef\tikz@marshal{\noexpand\tikz@rdf@make@literal@triple{\tikz@rdf@subject}{\tikz@rdf@predicate}{\tikz@rdf@object@literal}}% + \tikz@marshal% + \fi% + \else% + \edef\tikz@marshal{\noexpand\tikz@rdf@make@normal@triple{\tikz@rdf@subject}{\tikz@rdf@predicate}{\tikz@rdf@object}}% + \tikz@marshal% + \fi% + \fi% + \fi% + \fi% +}% + +\def\tikz@rdf@make@content@triple#1#2#3{% + \def\tikz@rdf@action{% + \def\tikz@rdf@invoke@code{% + \def\tikz@temp{#3}% + \ifx\tikz@temp\tikz@rdf@object@literal@text\else% + \pgfrdfcontent{#3}% + \fi% + \pgfrdfabout{#1}% + \pgfrdfdatatype{rdf:XMLLiteral}% + \foreach \tikz@rdf@pred in {#2}{% + \ifx\tikz@rdf@pred\pgfutil@empty\else% + \expandafter\pgfrdfproperty\expandafter{\tikz@rdf@pred}% + \fi% + }% + }% + }% +}% + +\def\tikz@rdf@make@literal@triple#1#2#3{% + \def\tikz@rdf@action{% + \tikz@add@rdf@post@option{% + {% + \pgfrdfabout{#1}% + \foreach \tikz@rdf@pred in {#2}{% + \ifx\tikz@rdf@pred\pgfutil@empty\else% + \expandafter\pgfrdfproperty\expandafter{\tikz@rdf@pred}% + \fi% + }% + \pgfrdfcontent{#3}% + \pgfidscope% + \endpgfidscope% + }% + }% + }% +}% + +\def\tikz@rdf@make@normal@triple#1#2#3{% + \def\tikz@rdf@action{% + \tikz@add@rdf@post@option{% + {% + \pgfrdfabout{#1}% + \foreach \tikz@rdf@pred in {#2}{% + \ifx\tikz@rdf@pred\pgfutil@empty\else% + \expandafter\pgfrdfproperty\expandafter{\tikz@rdf@pred}% + \fi% + }% + \pgfrdfresource{#3}% + \pgfidscope% + \endpgfidscope% + }% + }% + }% +}% + +\def\tikz@rdf@object@literal@text{\tikz@rdf@object@literal}% + + + + +% Containers + +\def\tikz@rdf@init@container{% + \ifx\tikz@rdf@subject\relax% + \tikzerror{RDF statement misses subject}% + \else% + \expandafter\gdef\csname tikz@rdf@c@\tikz@rdf@subject\endcsname{0}% + \fi% +}% + + +\def\tikz@rdf@make@member{% + \ifx\tikz@rdf@subject\relax% + \tikzerror{RDF statement misses subject}% + \else% + % Get number: + \expandafter\let\expandafter\tikz@temp\csname tikz@rdf@c@\tikz@rdf@subject\endcsname% + \ifx\tikz@temp\relax% + \tikzerror{RDF subject is not a container}% + \else% + \c@pgf@counta\tikz@temp% + \advance\c@pgf@counta by1\relax% + \expandafter\xdef\csname tikz@rdf@c@\tikz@rdf@subject\endcsname{\the\c@pgf@counta}% + \edef\tikz@rdf@predicate{rdf:_\the\c@pgf@counta}% + \fi% + \fi% +}% + + + + + +% Hooks: + +\let\tikz@rdf@invoke@code\relax + +\def\tikz@rdf@id@hook{% + \tikz@rdf@invoke@code% + \let\tikz@rdf@invoke@code\relax% +}% + +% Add hook: +\expandafter\def\expandafter\tikz@id@hook\expandafter{\tikz@id@hook\tikz@rdf@id@hook}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryscopes.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryscopes.code.tex new file mode 100644 index 0000000000..68856d591e --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryscopes.code.tex @@ -0,0 +1,42 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryscopes.code.tex} + +% Redefine the after command hook... + +\def\tikz@lib@scope@check{% + \pgfutil@ifnextchar\tikz@intersect@finish{% + \tikz@intersect@finish\afterassignment\tikz@lib@scope@check\let\tikz@next% + }{% + \pgfutil@ifnextchar\par{% + \afterassignment\tikz@lib@scope@check\let\tikz@next% + }% + {\pgfutil@ifnextchar\bgroup{%gotcha + \afterassignment\tikz@lib@scope@gotcha\let\tikz@next% + }% + {}% + }% + }% +}% + +\def\tikz@lib@scope@gotcha{% + \pgfutil@ifnextchar[{%] + \tikz@lib@scope@action% + }{% + % false alarm + \bgroup% + }% +}% +\def\tikz@lib@scope@action[#1]{% + \scope[#1]\bgroup\aftergroup\endscope% + \tikz@lib@scope@check% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadings.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadings.code.tex new file mode 100644 index 0000000000..2cf08776f3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadings.code.tex @@ -0,0 +1,21 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshadings.code.tex} + +\usepgflibrary{shadings}% + +\tikzset{ + lower left/.style={shading=bilinear interpolation,/utils/exec=\colorlet{lower left}{#1}}, + upper left/.style={shading=bilinear interpolation,/utils/exec=\colorlet{upper left}{#1}}, + lower right/.style={shading=bilinear interpolation,/utils/exec=\colorlet{lower right}{#1}}, + upper right/.style={shading=bilinear interpolation,/utils/exec=\colorlet{upper right}{#1}} +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadows.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadows.code.tex new file mode 100644 index 0000000000..3bd60e99fa --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshadows.code.tex @@ -0,0 +1,146 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshadows.code.tex} + +\usetikzlibrary{fadings}% + + +% General options +\tikzset{ + /tikz/shadow scale/.initial=1, + /tikz/shadow xshift/.initial=0pt, + /tikz/shadow yshift/.initial=0pt, +}% + +% Basic shadow style +\tikzset{ + general shadow/.style={ + preaction={ + #1, + transform canvas={ + scale around=\pgfkeysvalueof{/tikz/shadow scale}:(current path bounding box.center), + shift={(\pgfkeysvalueof{/tikz/shadow xshift},\pgfkeysvalueof{/tikz/shadow yshift})} + }, + } + }, + every shadow/.style={} +}% + + + +% +% Adds a simple drop shadow to a path +% + +\tikzset{ + /tikz/drop shadow/.style={ + general shadow={% + shadow scale=1, + shadow xshift=.5ex, + shadow yshift=-.5ex, + opacity=.5, + fill=black!50, + every shadow, + #1 + } + } +}% + + +% +% Adds a circular drop shadow to a path +% + +\tikzset{ + /tikz/circular drop shadow/.style={ + general shadow={% + shadow scale=1.1, + shadow xshift=.3ex, + shadow yshift=-.3ex, + fill=black!50, + path fading={circle with fuzzy edge 15 percent}, + every shadow, + #1 + } + } +}% + + + +% +% Adds a circular glow to a path +% + +\tikzset{ + /tikz/circular glow/.style={ + general shadow={% + shadow scale=1.25, + shadow xshift=0pt, + shadow yshift=0pt, + fill=black!50, + path fading={circle with fuzzy edge 15 percent}, + every shadow, + #1, + } + } +}% + + + + + +% +% Adds a "copy" version of the path behind it. +% + +\tikzset{ + /tikz/copy shadow/.style={ + general shadow={% + /utils/exec={\let\tikz@lib@shadow@fill=\tikz@fillcolor\let\tikz@lib@shadow@draw=\tikz@strokecolor}, + shadow scale=1, + shadow xshift=.5ex, + shadow yshift=.5ex, + fill=\tikz@lib@shadow@fill, + draw=\tikz@lib@shadow@draw, + every shadow, + #1 + } + } +}% + + +% +% Adds two "copies" of the path behind it. +% + +\tikzset{ + /tikz/double copy shadow/.style={ + general shadow={% + /utils/exec={\let\tikz@lib@shadow@fill=\tikz@fillcolor\let\tikz@lib@shadow@draw=\tikz@strokecolor}, + shadow scale=1, + shadow xshift=.5ex, + shadow yshift=.5ex, + fill=\tikz@lib@shadow@fill, + draw=\tikz@lib@shadow@draw, + #1, + shadow xshift/.expanded=2*\pgfkeysvalueof{/tikz/shadow xshift}, + shadow yshift/.expanded=2*\pgfkeysvalueof{/tikz/shadow yshift}, + }, + general shadow={% + /utils/exec={\let\tikz@lib@shadow@fill=\tikz@fillcolor\let\tikz@lib@shadow@draw=\tikz@strokecolor}, + shadow scale=1, + shadow xshift=.5ex, + shadow yshift=.5ex, + fill=\tikz@lib@shadow@fill, + draw=\tikz@lib@shadow@draw, + #1, + }, + } +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.arrows.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.arrows.code.tex new file mode 100644 index 0000000000..c20e6a73cc --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.arrows.code.tex @@ -0,0 +1,16 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.arrows.code.tex} + +\usepgflibrary{shapes.arrows}% + +\pgfkeys{/tikz/arrow box arrows/.code={\pgf@lib@arrowbox@parsearrows{#1}}}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.callouts.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.callouts.code.tex new file mode 100644 index 0000000000..2a3de5548a --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.callouts.code.tex @@ -0,0 +1,35 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{shapes.callouts}% + +\pgfkeys{/tikz/callout absolute pointer/.code={% + \tikz@scan@one@point\tikz@lib@callout@checkforplus#1\relax% + }% +}% + +\def\tikz@lib@callout@checkforplus#1{% + \pgfutil@ifnextchar+{\def\tikz@lib@callout@originalpoint{#1}\tikz@lib@callout@scan@relative}% + {\pgf@lib@callout@makeabsolutepointer{#1}}}% + +\def\tikz@lib@callout@scan@relative+{% + \pgfutil@ifnextchar+{\tikz@lib@callout@scan@plusplus}{\tikz@lib@callout@scan@plus}}% +\def\tikz@lib@callout@scan@plusplus+{\tikz@scan@one@point\tikz@lib@callout@add}% +\def\tikz@lib@callout@scan@plus{\tikz@scan@one@point\tikz@lib@callout@add}% +\def\tikz@lib@callout@add#1{% + \expandafter\pgf@lib@callout@makeabsolutepointer\expandafter{% + \expandafter\pgfpointadd\expandafter{\tikz@lib@callout@originalpoint}{#1}}% +}% + +\pgfkeys{/tikz/callout relative pointer/.code={% + \tikz@scan@one@point\pgf@lib@callout@makerelativepointer#1\relax% + }% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.code.tex new file mode 100644 index 0000000000..2efb5c3308 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.code.tex @@ -0,0 +1,19 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.code.tex} + +\usetikzlibrary{shapes.geometric}% +\usetikzlibrary{shapes.misc}% +\usetikzlibrary{shapes.symbols}% +\usetikzlibrary{shapes.arrows}% +\usetikzlibrary{shapes.callouts}% +\usetikzlibrary{shapes.multipart}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.IEC.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.IEC.code.tex new file mode 100644 index 0000000000..c34229b137 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.IEC.code.tex @@ -0,0 +1,38 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.gates.logic.IEC.code.tex} + +\usepgflibrary{shapes.gates.logic.IEC}% + +\tikzset{% + use IEC style logic gates/.code={% + \tikzset{% + and gate/.style={shape=and gate IEC}, + nand gate/.style={shape=nand gate IEC}, + or gate/.style={shape=or gate IEC}, + nor gate/.style={shape=nor gate IEC}, + xor gate/.style={shape=xor gate IEC}, + xnor gate/.style={shape=xnor gate IEC}, + not gate/.style={shape=not gate IEC}, + buffer gate/.style={shape=buffer gate IEC}, + and gate symbol/.style={and gate IEC symbol={##1}}, + nand gate symbol/.style={nand gate IEC symbol={##1}}, + or gate symbol/.style={or gate IEC symbol={##1}}, + nor gate symbol/.style={nor gate IEC symbol={##1}}, + xor gate symbol/.style={xor gate IEC symbol={##1}}, + xnor gate symbol/.style={xnor gate IEC symbol={##1}}, + not gate symbol/.style={not gate IEC symbol={##1}}, + buffer gate symbol/.style={buffer gate IEC symbol={##1}}, + logic gate symbol align/.style={/pgf/logic gate IEC symbol align={##1}}, + logic gate symbol color/.style={/pgf/logic gate IEC symbol color={##1}} + }% + }% +}% +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.US.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.US.code.tex new file mode 100644 index 0000000000..66503414a0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.gates.logic.US.code.tex @@ -0,0 +1,40 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.gates.logic.US.code.tex} + +\usepgflibrary{shapes.gates.logic.US}% + +\tikzset{% + use US style logic gates/.code={% + \tikzset{% + and gate/.style={shape=and gate US}, + nand gate/.style={shape=nand gate US}, + or gate/.style={shape=or gate US}, + nor gate/.style={shape=nor gate US}, + xor gate/.style={shape=xor gate US}, + xnor gate/.style={shape=xnor gate US}, + not gate/.style={shape=not gate US}, + buffer gate/.style={shape=buffer gate US} + }% + }, + use CDH style logic gates/.code={% + \tikzset{% + and gate/.style={shape=and gate CDH}, + nand gate/.style={shape=nand gate CDH}, + or gate/.style={shape=or gate US}, + nor gate/.style={shape=nor gate US}, + xor gate/.style={shape=xor gate US}, + xnor gate/.style={shape=xnor gate US}, + not gate/.style={shape=not gate US}, + buffer gate/.style={shape=buffer gate US} + } + } +}% +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.geometric.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.geometric.code.tex new file mode 100644 index 0000000000..3e923b940f --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.geometric.code.tex @@ -0,0 +1,14 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.geometric.code.tex} + +\usepgflibrary{shapes.geometric}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.misc.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.misc.code.tex new file mode 100644 index 0000000000..617c5f4034 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.misc.code.tex @@ -0,0 +1,14 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.misc.code.tex} + +\usepgflibrary{shapes.misc}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.multipart.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.multipart.code.tex new file mode 100644 index 0000000000..91183aaf78 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.multipart.code.tex @@ -0,0 +1,36 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.multipart.code.tex} + +\usepgflibrary{shapes.multipart}% + +\pgfkeys{/tikz/rectangle split/parts/.code={% + \pgfkeys{/pgf/rectangle split parts={#1}}% + }% +}% + +\pgfkeys{/tikz/rectangle split use custom fill/.code={% + \pgfkeys{/pgf/rectangle split use custom fill={#1}}% + \pgfkeys{/tikz/fill=none}}% +}% + +\pgfkeys{/tikz/rectangle split draw splits/.is if=pgfrectanglesplitdrawsplits}% + +\pgfkeys{/tikz/rectangle split part align/.code={% + \pgfkeys{/pgf/rectangle split part align={#1}}% + }% +}% + +\pgfkeys{/tikz/rectangle split part fill/.code={% + \pgfkeys{/pgf/rectangle split part fill={#1}}% + }% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.symbols.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.symbols.code.tex new file mode 100644 index 0000000000..b616b54c88 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryshapes.symbols.code.tex @@ -0,0 +1,17 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryshapes.symbols.code.tex} + +\pgfkeysifdefined{/tikz/shape border uses incircle}{}{% + \pgfkeys{/tikz/shape border uses incircle/.is if=pgfshapeborderusesincircle}}% + +\usepgflibrary{shapes.symbols}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysnakes.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysnakes.code.tex new file mode 100644 index 0000000000..9acb6de915 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysnakes.code.tex @@ -0,0 +1,77 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarysnakes.code.tex} + +\pgfwarning{Snakes have been superseded by +decorations. Please use the decoration libraries instead of the snakes +library}% + +\usetikzlibrary{decorations.pathmorphing,decorations.pathreplacing,decorations.shapes}% + + +% Old snakes stuff: + +\tikzoption{snake}[]{% + \def\tikz@@snake{#1}% + \ifx\tikz@@snake\pgfutil@empty% + \tikz@snakedtrue% + \else% + \ifx\tikz@@snake\tikz@nonetext% + \tikz@snakedfalse% + \else% + \tikz@snakedtrue% + \let\tikz@snake=\tikz@@snake% + \fi% + \fi}% + +\tikzoption{raise snake}{\def\pgf@snake@raise{\pgftransformyshift{#1}}}% +\tikzoption{mirror snake}[true]{% + \csname if#1\endcsname + \def\pgf@snake@mirror{\pgftransformyscale{-1}}% + \else% + \let\pgf@snake@mirror=\pgfutil@empty% + \fi +}% + +\tikzoption{gap before snake}{\def\tikz@presnake{{moveto}{#1}{\noexpand\tikz@snake@install@trans}{}}}% +\tikzoption{line before snake}{\def\tikz@presnake{{lineto}{#1}{\noexpand\tikz@snake@install@trans}{}}}% + +\tikzoption{gap after snake}{\def\tikz@postsnake{{moveto}{#1}{\noexpand\tikz@snake@install@trans}{}}\def\tikz@mainsnakelength{\pgfsnakeremainingdistance-#1}}% +\tikzoption{line after snake}{\def\tikz@postsnake{{lineto}{#1}{\noexpand\tikz@snake@install@trans}{}}\def\tikz@mainsnakelength{\pgfsnakeremainingdistance-#1}}% + +\tikzoption{gap around snake}{% + \def\tikz@presnake{{moveto}{#1}{\noexpand\tikz@snake@install@trans}{}}% + \def\tikz@postsnake{{moveto}{#1}{\noexpand\tikz@snake@install@trans}{}}% + \def\tikz@mainsnakelength{\pgfsnakeremainingdistance-#1}% +}% +\tikzoption{line around snake}{% + \def\tikz@presnake{{lineto}{#1}{\noexpand\tikz@snake@install@trans}{}}% + \def\tikz@postsnake{{lineto}{#1}{\noexpand\tikz@snake@install@trans}{}}% + \def\tikz@mainsnakelength{\pgfsnakeremainingdistance-#1}% +}% +\let\pgf@snake@mirror=\pgfutil@empty +\let\pgf@snake@raise=\pgfutil@empty + +\def\tikz@snake@install@trans{\pgfsetsnakesegmenttransformation{\pgf@snake@mirror\pgf@snake@raise}}% + +\def\tikz@snake{zigzag}% + +\let\tikz@presnake=\pgfutil@empty +\let\tikz@postsnake=\pgfutil@empty +\def\tikz@mainsnakelength{\pgfsnakeremainingdistance}% + + +\tikzset{snake triangles 45/.style= {snake=triangles,segment object length=2.41421356\pgfsnakesegmentamplitude}}% +\tikzset{snake triangles 60/.style= {snake=triangles,segment object length=1.73205081\pgfsnakesegmentamplitude}}% +\tikzset{snake triangles 90/.style= {snake=triangles,segment object length=\pgfsnakesegmentamplitude}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryspy.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryspy.code.tex new file mode 100644 index 0000000000..a5fea2a79b --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryspy.code.tex @@ -0,0 +1,134 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryspy.code.tex} + + + +% Spy styles + +\tikzset{ + spy using outlines/.style={ + spy scope={ + every spy on node/.style={very thin,draw}, + every spy in node/.style={thick,draw}, + #1 + } + }, + spy using overlays/.style={ + spy scope={ + every spy on node/.style={fill,fill opacity=0.2,text opacity=1}, + every spy in node/.style={fill,fill opacity=0.2,text opacity=1}, + #1 + } + }, + connect spies/.style={ + spy connection path={\draw[thin] (tikzspyonnode) -- (tikzspyinnode);} + } +}% + +\newbox\tikz@lib@spybox + +\let\tikz@lib@spy@collection=\pgfutil@empty% + +\tikzset{spy scope/.style={ + size/.style={minimum size={##1}}, + height/.style={minimum height={##1}}, + width/.style={minimum width={##1}}, + execute at begin scope={% + \let\tikz@lib@spy@save=\tikz@lib@spy@collection% + \setbox\tikz@lib@spybox=\hbox\bgroup\bgroup% + \let\spy=\tikz@lib@spy@parse}, + execute at end scope={% + \egroup\egroup% + {% + \copy\tikz@lib@spybox% + \tikz@lib@spy@collection% + }% + \global\let\tikz@lib@spy@collection=\tikz@lib@spy@save% + },% + tikz@lib@spy@style/.style={#1}, + tikz@lib@reset@gs + }, + lens/.store in=\tikz@lib@spy@lens, + lens=, + magnification/.style={lens={scale={#1}}}, + spy connection path/.store in=\tikz@lib@spy@path, + spy connection path= +}% + +\tikzset{ + tikz@lib@reset@gs/.style={black,thin,solid,opaque,line cap=butt,line join=miter} +}% + +\def\tikz@lib@spy@parse{% + \pgfutil@ifnextchar[{\tikz@lib@spy@parse@opt}{\tikz@lib@spy@parse@opt[]}%] +}% +\def\tikz@lib@spy@parse@opt[#1]{ + \pgfutil@ifnextchar x{\tikz@lib@spy@parse@opta[#1]}{\tikz@lib@spy@parse@opta[#1]}%] +}% +\def\tikz@lib@spy@parse@opta[#1]on#2in node#3;{% + \pgfutil@g@addto@macro\tikz@lib@spy@collection{\tikz@lib@spy@do{#1}{#2}{#3}}% +}% + +\def\tikz@lib@spy@do#1#2#3{% + \scope[tikz@lib@spy@style,#1] + \node [alias=tikzspyonnode,inner sep=0pt,outer sep=0pt,every spy on node/.try, + /utils/exec={ + {% + \let\tikz@transform=\relax + \pgftransformreset% + \expandafter\tikzset\expandafter{\tikz@lib@spy@lens} + \pgftransforminvert% + \pgfgettransformentries\a\b\c\d\e\f% + \global\let\pgf@lib@svg@a=\a% + \global\let\pgf@lib@svg@b=\b% + \global\let\pgf@lib@svg@c=\c% + \global\let\pgf@lib@svg@d=\d% + }% + \tikz@addtransform{% + \tikz@scan@one@point\pgftransformshift#2% + \pgftransformcm{\pgf@lib@svg@a}{\pgf@lib@svg@b}{\pgf@lib@svg@c}{\pgf@lib@svg@d}{\pgfpointorigin}% + } + }]{}; + \expandafter\pgfutil@switch\expandafter\pgfutil@ifstrequal\expandafter{\tikz@anchor}{% + {north} {\def\tikz@spy@anchor{south}}% + {north east}{\def\tikz@spy@anchor{south west}}% + {east} {\def\tikz@spy@anchor{west}}% + {south east}{\def\tikz@spy@anchor{north west}}% + {south} {\def\tikz@spy@anchor{north}}% + {south west}{\def\tikz@spy@anchor{north east}}% + {west} {\def\tikz@spy@anchor{east}}% + {north west}{\def\tikz@spy@anchor{south east}}% + }{}{\def\tikz@spy@anchor{center}}% + \node [alias=tikzspyinnode,inner sep=0pt,outer sep=0pt,at={#2},every spy in node/.try, + path picture={\node[anchor=\tikz@spy@anchor,tikz@lib@reset@gs]{\nullfont% + \pgfpicture\relax\pgfsetbaseline{default}\pgfsettrimleft{default}\pgfsettrimright{default}% + \pgftransformreset% + \let\tikz@transform=\relax% + \expandafter\tikzset\expandafter{\tikz@lib@spy@lens}% + \pgflowlevelsynccm% + \tikz@scan@one@point\tikz@lib@spy@shift#2% + \pgflowlevelsynccm% + \copy\tikz@lib@spybox% + \endpgfpicture};}]#3{}; + \tikz@lib@spy@path + \endscope +}% + +\def\tikz@lib@spy@shift#1{% + \pgf@process{#1}% + \pgf@x=-\pgf@x% + \pgf@y=-\pgf@y% + \pgftransformshift{}% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysvg.path.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysvg.path.code.tex new file mode 100644 index 0000000000..521bf96b60 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarysvg.path.code.tex @@ -0,0 +1,33 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarysvg.path.code.tex} + +\usepgflibrary{svg.path}% + +\def\tikz@svg@path vg{\pgfutil@ifnextchar[\tikz@svg@@path{\tikz@svg@@path[]}}%}% + +\def\tikz@svg@@path[#1]{\pgfutil@ifnextchar"{\tikz@svg@@path@old{#1}}{\tikz@svg@@path@new{#1}}}% +\def\tikz@svg@@path@new#1#2{\tikz@svg@@path@old{#1}"#2"}% +\def\tikz@svg@@path@old#1"#2"{ + {% + \tikzset{#1}% + \pgfpathsvg{#2}% + }% + { + \pgftransforminvert + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@path@lastx}{\pgf@path@lasty}}} + } + \tikz@lastx=\pgf@x% + \tikz@lasty=\pgf@y% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \tikz@updatecurrenttrue% + \tikz@scan@next@command +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarythrough.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarythrough.code.tex new file mode 100644 index 0000000000..986235b75b --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarythrough.code.tex @@ -0,0 +1,36 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarythrough.code.tex} + + + +\tikzset{circle through/.code={% + \pgfkeysalso{shape=circle,inner sep=0pt,outer sep=0pt}% + % Save transformations (correct?) + \pgfgettransform{\tikz@lib@saved@transform}% + \tikz@scan@one@point\tikz@lib@circle@through#1% + }}% + +\def\tikz@lib@circle@through#1{% + \tikz@addoption{% + {% + \pgfsettransform{\tikz@lib@saved@transform}% + \pgf@process{\pgfpointtransformed{#1}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointtransformed{\tikz@node@at}}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \pgfmathparse{2*veclen(\the\pgf@xa,\the\pgf@ya)}% + \global\let\tikz@lib@circle@size=\pgfmathresult% + }% + \pgfset{/pgf/minimum size/.expanded=\tikz@lib@circle@size}% + }% +}% diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex new file mode 100644 index 0000000000..ecf850ab40 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex @@ -0,0 +1,381 @@ +% Copyright 2020 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarytopaths.code.tex} + + +% Move to + +\tikzset{move to/.style= {to path={(\tikztotarget) \tikztonodes}}} + + +% Straight to + +\tikzset{line to/.style= {to path={-- (\tikztotarget) \tikztonodes}}} + + +% Curved to + +\tikzset{every curve to/.style= {}} +\tikzset{curve to/.style= {to path=\tikz@to@curve@path}} + +\tikzoption{bend angle}{\pgfmathsetmacro\tikz@to@bend{#1}} + +\tikzoption{bend left}[]{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfmathsetmacro\tikz@to@bend{#1}% + \fi% + \let\tikz@to@out=\tikz@to@bend% + \pgfmathsetmacro\tikz@to@in{180-(\tikz@to@out)}% + \tikz@to@switch@on% + \tikz@to@relativetrue% +} + +\tikzoption{bend right}[]{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfmathsetmacro\tikz@to@bend{#1}% + \fi% + % Now, negate + \pgfmathsetmacro\tikz@to@out{-(\tikz@to@bend)} + \pgfmathsetmacro\tikz@to@in{180-(\tikz@to@out)} + \tikz@to@switch@on% + \tikz@to@relativetrue% +} + +\tikzoption{relative}[true]{\csname tikz@to@relative#1\endcsname} +\newif\iftikz@to@relative +\tikz@to@relativefalse + +\tikzoption{in}{\def\tikz@to@in{#1}\tikz@to@switch@on} +\tikzoption{out}{\def\tikz@to@out{#1}\tikz@to@switch@on} + +\tikzoption{in looseness}{\tikz@to@set@in@looseness{#1}} +\tikzoption{out looseness}{\tikz@to@set@out@looseness{#1}} +\tikzoption{looseness}{\tikz@to@set@in@looseness{#1}\tikz@to@set@out@looseness{#1}} + +\tikzoption{in control}{\tikz@to@set@in@control{#1}} +\tikzoption{out control}{\tikz@to@set@out@control{#1}} +\tikzoption{controls}{\tikz@to@parse@controls#1\pgf@stop} + +\tikzoption{in min distance}{\tikz@to@set@distances{#1}{}{}{}} +\tikzoption{in max distance}{\tikz@to@set@distances{}{#1}{}{}} +\tikzoption{in distance}{\tikz@to@set@distances{#1}{#1}{}{}} +\tikzoption{out min distance}{\tikz@to@set@distances{}{}{#1}{}} +\tikzoption{out max distance}{\tikz@to@set@distances{}{}{}{#1}} +\tikzoption{out distance}{\tikz@to@set@distances{}{}{#1}{#1}} +\tikzoption{min distance}{\tikz@to@set@distances{#1}{}{#1}{}} +\tikzoption{max distance}{\tikz@to@set@distances{}{#1}{}{#1}} +\tikzoption{distance}{\tikz@to@set@distances{#1}{#1}{#1}{#1}} + +\def\tikz@to@set@distances#1#2#3#4{% + \tikz@to@setifnotempy{#1}{\tikz@to@in@min}{\let\tikz@to@end@compute=\tikz@to@end@compute@looseness}% + \tikz@to@setifnotempy{#2}{\tikz@to@in@max}{\let\tikz@to@end@compute=\tikz@to@end@compute@looseness}% + \tikz@to@setifnotempy{#3}{\tikz@to@out@min}{\let\tikz@to@start@compute=\tikz@to@start@compute@looseness}% + \tikz@to@setifnotempy{#4}{\tikz@to@out@max}{\let\tikz@to@start@compute=\tikz@to@start@compute@looseness}% + \tikz@to@switch@on% +} + +\def\tikz@to@setifnotempy#1#2#3{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty\else\def#2{#1}#3\fi% +} + + +\def\tikz@to@set@in@looseness#1{% + \pgfmathsetmacro\tikz@to@in@looseness{#1}% + \let\tikz@to@end@compute=\tikz@to@end@compute@looseness% + \tikz@to@switch@on% +} +\def\tikz@to@set@out@looseness#1{% + \pgfmathsetmacro\tikz@to@out@looseness{#1}% + \let\tikz@to@start@compute=\tikz@to@start@compute@looseness% + \tikz@to@switch@on% +} + +\def\tikz@to@parse@controls#1and#2\pgf@stop{\tikz@to@set@in@control{#2}\tikz@to@set@out@control{#1}} + +\def\tikz@to@set@in@control#1{% + \def\tikz@to@in@control{#1}% + \let\tikz@to@end@compute=\tikz@to@end@compute@control% + \tikz@to@switch@on% +} +\def\tikz@to@set@out@control#1{% + \def\tikz@to@out@control{#1}% + \let\tikz@to@start@compute=\tikz@to@start@compute@control% + \tikz@to@switch@on% +} + + +\def\tikz@to@bend{30} + +\def\tikz@to@out{45} +\def\tikz@to@in{135} + +\def\tikz@to@out@looseness{1} +\def\tikz@to@in@looseness{1} + +\def\tikz@to@in@min{0pt} +\def\tikz@to@in@max{10000pt} +\def\tikz@to@out@min{0pt} +\def\tikz@to@out@max{10000pt} + +\def\tikz@to@switch@on{\let\tikz@to@path=\tikz@to@curve@path} + +\def\tikz@to@curve@path{% + [every curve to] + \pgfextra{\iftikz@to@relative\tikz@to@compute@relative\else\tikz@to@compute\fi} + \tikz@computed@path + \pgfextra{\tikz@updatenexttrue\tikz@updatecurrenttrue}% + \tikztonodes% +} + +\def\tikz@to@modify#1#2{% + \pgfutil@ifundefined{pgf@sh@ns@#1} + {}% + {\edef#1{#1.#2}} +}% + +\def\tikz@to@compute{% + \let\tikz@tofrom=\tikztostart% + \let\tikz@toto=\tikztotarget% + \tikz@to@modify\tikz@tofrom\tikz@to@out% + \tikz@to@modify\tikz@toto\tikz@to@in% + \ifx\tikz@to@start@compute\tikz@to@start@compute@looseness% + \tikz@to@compute@distance% + \else% + \ifx\tikz@from@start@compute\tikz@to@start@compute@looseness% + \tikz@to@compute@distance% + \fi% + \fi% + \tikz@to@start@compute% + \tikz@to@end@compute% + \edef\tikz@computed@path{.. controls \tikz@computed@start and \tikz@computed@end .. (\tikztotarget)} +} + +\def\tikz@to@compute@distance{\tikz@scan@one@point\tikz@@to@compute@distance(\tikz@tofrom)} +\def\tikz@@to@compute@distance#1{% + \def\tikz@first@point{#1}% + \tikz@scan@one@point\tikz@@@to@compute@distance(\tikz@toto)} +\def\tikz@@@to@compute@distance#1{% + \iftikz@updatecurrent\else + \tikz@updatenextfalse + \fi + \def\tikz@second@point{#1}% + \tikz@to@compute@distance@main% +} +\def\tikz@to@compute@distance@main{% + \pgf@process{\pgfpointdiff{\tikz@first@point}{\tikz@second@point}}% + \ifdim\pgf@x<0pt\pgf@xa=-\pgf@x\else\pgf@xa=\pgf@x\fi% + \ifdim\pgf@y<0pt\pgf@ya=-\pgf@y\else\pgf@ya=\pgf@y\fi% + % + % Calculate length of second to first vector: + % + \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + \ifdim\pgf@x>\pgf@y% + \c@pgf@counta=\pgf@x% + \ifnum\c@pgf@counta=0\relax% + \else% + \divide\c@pgf@counta by 255\relax% + \pgf@xa=16\pgf@xa\relax% + \divide\pgf@xa by\c@pgf@counta% + \pgf@xa=16\pgf@xa\relax% + \fi% + \else% + \c@pgf@counta=\pgf@y% + \ifnum\c@pgf@counta=0\relax% + \else% + \divide\c@pgf@counta by 255\relax% + \pgf@ya=16\pgf@ya\relax% + \divide\pgf@ya by\c@pgf@counta% + \pgf@xa=16\pgf@ya\relax% + \fi% + \fi% + \pgf@x=0.3915\pgf@xa% + \pgf@xa=\tikz@to@out@looseness\pgf@x% + \pgf@xb=\tikz@to@in@looseness\pgf@x% + % Adjust as necessary + \pgfmathsetlength{\pgf@ya}{\tikz@to@out@min} + \ifdim\pgf@xa<\pgf@ya% + \pgf@xa=\pgf@ya% + \fi% + \pgfmathsetlength{\pgf@ya}{\tikz@to@out@max} + \ifdim\pgf@xa>\pgf@ya% + \pgf@xa=\pgf@ya% + \fi% + \pgfmathsetlength{\pgf@ya}{\tikz@to@in@min} + \ifdim\pgf@xb<\pgf@ya% + \pgf@xb=\pgf@ya% + \fi% + \pgfmathsetlength{\pgf@ya}{\tikz@to@in@max} + \ifdim\pgf@xb>\pgf@ya% + \pgf@xb=\pgf@ya% + \fi% +} + +\def\tikz@to@start@compute@looseness{% + \edef\tikz@computed@start{([shift=({\tikz@to@out}:\the\pgf@xa)]\tikz@tofrom)}% +} +\def\tikz@to@end@compute@looseness{% + \edef\tikz@computed@end{([shift=({\tikz@to@in}:\the\pgf@xb)]\tikz@toto)}% +} +\def\tikz@to@start@compute@control{% + \let\tikz@computed@start=\tikz@to@out@control% +} +\def\tikz@to@end@compute@control{% + \let\tikz@computed@end=\tikz@to@in@control% +} + +\let\tikz@to@start@compute=\tikz@to@start@compute@looseness% +\let\tikz@to@end@compute=\tikz@to@end@compute@looseness% + + + + +% Relative curves + +\def\tikz@to@compute@relative{% + \tikz@scan@one@point\tikz@@to@compute@relative(\tikztostart)% +} +\def\tikz@@to@compute@relative#1{% + \def\tikz@tofrom{#1}% + \tikz@scan@one@point\tikz@@@to@compute@relative(\tikztotarget)% +} +\def\tikz@@@to@compute@relative#1{% + \def\tikz@toto{#1}% + \begingroup + % + % Adjust start and target so that they lie on the border in the + % rotated coordinate system. + % + \pgfutil@ifundefined{pgf@sh@ns@\tikztostart} + {% + \let\tikz@first@point=\tikz@tofrom% + \let\tikz@tostart@tikz=\pgfutil@empty + }% + {% + % Start computation of new start. + {% + \tikz@tofrom% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + {% + \pgftransformreset% + \pgftransformshift{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \pgftransformrotate{\tikz@to@out}% + \pgftransformshift{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}% + \pgf@process{\pgfpointtransformed{\tikz@toto}}% + }% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfpointshapeborder{\tikztostart}{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \xdef\tikz@tofrom@smuggle{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + }% + \let\tikz@first@point=\tikz@tofrom@smuggle% + \tikz@first@point% + \edef\tikz@tostart@tikz{(\the\pgf@x,\the\pgf@y)}% + }% + \pgfutil@ifundefined{pgf@sh@ns@\tikztotarget} + {% + \let\tikz@second@point=\tikz@toto% + }% + {% + % Start computation of new target. + {% + \tikz@toto% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + {% + \pgftransformreset% + \pgftransformshift{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \pgftransformrotate{180}% + \pgftransformrotate{\tikz@to@in}% + \pgftransformshift{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}% + \pgf@process{\pgfpointtransformed{\tikz@tofrom}}% + }% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfpointshapeborder{\tikztotarget}{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \xdef\tikz@toto@smuggle{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + }% + \let\tikz@second@point=\tikz@toto@smuggle% + }% + \tikz@second@point% + \edef\tikz@totarget@tikz{(\the\pgf@x,\the\pgf@y)}% + % + % Compute distances + % + \tikz@to@compute@distance@main% + \edef\tikz@to@first@distance{\the\pgf@xa}% + \edef\tikz@to@second@distance{\the\pgf@xb}% + % + % Next step: Establish a transformed coordinate system so that the (modified) + % start is at the origin and the (modified) target is at (1,0) + % + \pgftransformreset% + \pgf@process{\tikz@first@point}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@second@point}% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@y by-\pgf@ya% + \pgfpointnormalised{}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@xb=-\pgf@x% + \pgf@yb=-\pgf@y% + % + % Now compute the control points. + % + {% + \pgftransformshift{\tikz@first@point}% + \pgftransformcm{\pgf@sys@tonumber\pgf@xc}{\pgf@sys@tonumber\pgf@yc}{\pgf@sys@tonumber\pgf@yb}{\pgf@sys@tonumber\pgf@xc}% + {\pgfpointorigin}% + \pgf@process{\pgfpointtransformed{\pgfpointpolar{\tikz@to@out}{\tikz@to@first@distance}}}% + \xdef\tikz@computed@start{(\the\pgf@x,\the\pgf@y)}% + } + {% + \pgftransformshift{\tikz@second@point}% + \pgftransformcm{\pgf@sys@tonumber\pgf@xc}{\pgf@sys@tonumber\pgf@yc}{\pgf@sys@tonumber\pgf@yb}{\pgf@sys@tonumber\pgf@xc}% + {\pgfpointorigin}% + \pgf@process{\pgfpointtransformed{\pgfpointpolar{\tikz@to@in}{\tikz@to@second@distance}}}% + \xdef\tikz@computed@end{(\the\pgf@x,\the\pgf@y)}% + } + \xdef\tikz@computed@path{ + \tikz@tostart@tikz + .. controls \tikz@computed@start and \tikz@computed@end .. + \tikz@totarget@tikz}% + \endgroup +} + + + +% Loops + +\tikzset{loop/.style= {to path={ + \pgfextra{\let\tikztotarget=\tikztostart} + [looseness=8,min distance=5mm,every loop] + \tikz@to@curve@path + }}} + +\tikzset{every loop/.style= {->,shorten >=1pt}} + +\tikzset{loop right/.style= {right,out=15,in=-15,loop}} +\tikzset{loop above/.style= {above,out=105,in=75,loop}} +\tikzset{loop left/.style= {left,out=195,in=165,loop}} +\tikzset{loop below/.style= {below,out=285,in=255,loop}} + + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytrees.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytrees.code.tex new file mode 100644 index 0000000000..d457f979b9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibrarytrees.code.tex @@ -0,0 +1,109 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarytrees.code.tex} + + + +% +% Three point growth +% + +\tikzoption{grow via three points}{\let\tikz@grow=\tikz@grow@three\tikz@parse@three#1}% + +\def\tikz@parse@three one child at#1(#2)#3and two children at#4(#5)#6and#7(#8){% + \def\tikz@tree@one@child{\tikz@scan@one@point\pgf@process(#2)} + \def\tikz@tree@left@child{\tikz@scan@one@point\pgf@process(#5)} + \def\tikz@tree@right@child{\tikz@scan@one@point\pgf@process(#8)} +}% + +\def\tikz@grow@three{% + \pgf@process{\tikz@tree@one@child}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@tree@left@child}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \pgf@process{\tikz@tree@right@child}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xc by-\pgf@xa% + \advance\pgf@yc by-\pgf@ya% + \advance\pgf@xc by-\pgf@xb% + \advance\pgf@yc by-\pgf@yb% + \advance\tikznumberofchildren by-1\relax% + \pgf@xb=\tikznumberofchildren\pgf@xb\relax% + \pgf@yb=\tikznumberofchildren\pgf@yb\relax% + \advance\tikznumberofcurrentchild by-1\relax% + \pgf@xc=\tikznumberofcurrentchild\pgf@xc\relax% + \pgf@yc=\tikznumberofcurrentchild\pgf@yc\relax% + \advance\pgf@xa by\pgf@xb% + \advance\pgf@xa by\pgf@xc% + \advance\pgf@ya by\pgf@yb% + \advance\pgf@ya by\pgf@yc% + \edef\pgf@temp{\noexpand\pgftransformshift{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}}% + \pgf@temp% +}% + + + +% +% Circle grow +% + +\tikzset{ + grow cyclic/.style={ + edge from parent/.append style={reset cm}, + growth function=\tikz@grow@circle, + } +}% + +\tikzset{sibling angle/.initial=20}% + +\def\tikz@grow@circle{% + \pgftransformrotate{% + (\pgfkeysvalueof{/tikz/sibling angle})*(-.5-.5*\tikznumberofchildren+\tikznumberofcurrentchild)}% + \pgftransformxshift{\the\tikzleveldistance}% +}% + +\tikzoption{counterclockwise from}{\let\tikz@grow=\tikz@grow@circle@from\def\tikz@grow@circle@from@start{#1}}% + +\def\tikz@grow@circle@from{% + \pgftransformshift{\pgfpointpolar{\tikz@grow@circle@from@start+(\pgfkeysvalueof{/tikz/sibling angle})*(\tikznumberofcurrentchild-1)}{\the\tikzleveldistance}}% +}% + +\tikzoption{clockwise from}{\let\tikz@grow=\tikz@grow@circle@from@\def\tikz@grow@circle@from@start{#1}}% + +\def\tikz@grow@circle@from@{% + \pgftransformshift{\pgfpointpolar{\tikz@grow@circle@from@start-(\pgfkeysvalueof{/tikz/sibling angle})*(\tikznumberofcurrentchild-1)}{\the\tikzleveldistance}}% +}% + + + +% +% Connections +% + +\tikzset{edge from parent fork down/.style= + {edge from parent path={(\tikzparentnode\tikzparentanchor) -- +(0pt,-.5\tikzleveldistance) -| (\tikzchildnode\tikzchildanchor)}}}% + +\tikzset{edge from parent fork up/.style= + {edge from parent path={(\tikzparentnode\tikzparentanchor) -- +(0pt,.5\tikzleveldistance) -| (\tikzchildnode\tikzchildanchor)}}}% + +\tikzset{edge from parent fork left/.style= + {edge from parent path={(\tikzparentnode\tikzparentanchor) -- +(-.5\tikzleveldistance,0pt) |- (\tikzchildnode\tikzchildanchor)}}}% + +\tikzset{edge from parent fork right/.style= + {edge from parent path={(\tikzparentnode\tikzparentanchor) -- +(.5\tikzleveldistance,0pt) |- (\tikzchildnode\tikzchildanchor)}}}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryturtle.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryturtle.code.tex new file mode 100644 index 0000000000..889806f8d5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryturtle.code.tex @@ -0,0 +1,84 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryturtle.code.tex} + + +\tikzset{turtle/.style={/tikz/turtle/.cd,#1}}% + +% The current angle is stored in this key. +\tikzset{turtle/direction/.code=\gdef\tikz@lib@turtle@dir{#1},turtle/direction=90}% + +% The current angle is stored in this key. +\tikzset{turtle/distance/.initial=1cm}% + +% The to path options that are used to move the turtle +\tikzset{turtle/how/.style=}% + +% Let the turtle jump home +\tikzset{turtle/home/.style={/tikz/insert path={(0,0) [turtle/direction=90]}}}% + +% Moves the turtle forward by the given distance or, if no distance is +% given, by turtle distance +\tikzset{ + turtle/forward/.default=\pgfkeysvalueof{/tikz/turtle/distance}, + turtle/forward/.style={/tikz/insert path={to[/tikz/turtle/how]++({\tikz@lib@turtle@dir}:{#1})}} +}% + + + +% Moves the turtle backward by the given distance or, if no distance is +% given, by turtle distance +\tikzset{ + turtle/back/.default=\pgfkeysvalueof{/tikz/turtle/distance}, + turtle/back/.style={turtle forward={-(#1)}} +}% + + + +% Turns the turtle left by the given number of degrees +\tikzset{ + turtle/left/.default=90, + turtle/left/.code={% + \pgfmathparse{(#1)+(\tikz@lib@turtle@dir)}% + \ifdim\pgfmathresult pt>360pt\relax% + \pgfmathparse{\pgfmathresult-360}% + \fi% + \global\let\tikz@lib@turtle@dir\pgfmathresult + } +}% + + +% Turns the turtle left by the given number of degrees +\tikzset{ + turtle/right/.default=90, + turtle/right/.code={% + \pgfmathparse{#1} + \pgfmathparse{(\tikz@lib@turtle@dir)-\pgfmathresult}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathparse{\pgfmathresult+360}% + \fi% + \global\let\tikz@lib@turtle@dir\pgfmathresult + } +}% + + +% Shortcuts: +\tikzset{turtle/.cd, + fd/.style={forward={#1}}, + fd/.default=\pgfkeysvalueof{/tikz/turtle/distance}, + bk/.style={back={#1}}, + bk/.default=\pgfkeysvalueof{/tikz/turtle/distance}, + lt/.style={left={#1}}, + lt/.default=90, + rt/.style={right={#1}}, + rt/.default=90}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryviews.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryviews.code.tex new file mode 100644 index 0000000000..8ced1b64f3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/libraries/tikzlibraryviews.code.tex @@ -0,0 +1,45 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibraryviews.code.tex} + + +\tikzset{ + meet/.style={execute at begin scope={\tikz@lib@view@parse{meet}#1\pgf@stop},execute at end scope={\endpgfviewboxscope}}, + view/.style={meet = {#1}}, + slice/.style={execute at begin scope={\tikz@lib@view@parse{slice}#1\pgf@stop},execute at end scope={\endpgfviewboxscope}}, +}% + +\def\tikz@lib@view@parse#1#2\pgf@stop{% + \tikz@scan@one@point\tikz@lib@view@a#2\pgf@stop% + \pgfviewboxscope{\tikz@lib@view@stored@a}{\tikz@lib@view@stored@b}{\tikz@lib@view@stored@c}{\tikz@lib@view@stored@d}{#1}% +}% +\def\tikz@lib@view@a#1{% + \def\tikz@lib@view@stored@a{#1}% + \pgfutil@ifnextchar r{\tikz@lib@view@a@rec}{\tikz@scan@one@point\tikz@lib@view@b}% +}% +\def\tikz@lib@view@a@rec rectangle{\tikz@scan@one@point\tikz@lib@view@b}% +\def\tikz@lib@view@b#1{% + \def\tikz@lib@view@stored@b{#1}% + \pgfutil@ifnextchar\pgf@stop{% + \let\tikz@lib@view@stored@c\tikz@lib@view@stored@a% + \let\tikz@lib@view@stored@d\tikz@lib@view@stored@b% + \pgfutil@gobble% + }{\tikz@lib@view@b@at}% +}% +\def\tikz@lib@view@b@at at{\tikz@scan@one@point\tikz@lib@view@c}% +\def\tikz@lib@view@c#1{% + \def\tikz@lib@view@stored@c{#1}% + \pgfutil@ifnextchar r{\tikz@lib@view@c@rec}{\tikz@scan@one@point\tikz@lib@view@d}% +}% +\def\tikz@lib@view@c@rec rectangle{\tikz@scan@one@point\tikz@lib@view@d}% +\def\tikz@lib@view@d#1{\def\tikz@lib@view@stored@d{#1}\pgfutil@ifnextchar\pgf@stop\pgfutil@gobble{\tikzerror{Wrong syntax for meet or slice key}}}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/frontendlayer/tikz/tikz.code.tex b/graphics/pgf/base/tex/generic/frontendlayer/tikz/tikz.code.tex new file mode 100644 index 0000000000..9b76858b3a --- /dev/null +++ b/graphics/pgf/base/tex/generic/frontendlayer/tikz/tikz.code.tex @@ -0,0 +1,5599 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesPackageRCS{tikz.code.tex} + + +\def\tikzerror#1{\pgfutil@packageerror{tikz}{#1}{}} + +% Always-present libraries (|\usepgflibrary| defined in +% \file{pgfutil-common.tex}). +\usepgflibrary{plothandlers} + +\newdimen\tikz@lastx +\newdimen\tikz@lasty +\newdimen\tikz@lastxsaved +\newdimen\tikz@lastysaved +\newdimen\tikz@lastmovetox +\newdimen\tikz@lastmovetoy + +\newdimen\tikzleveldistance +\newdimen\tikzsiblingdistance + +\newbox\tikz@figbox +\newbox\tikz@figbox@bg +\newbox\tikz@tempbox +\newbox\tikz@tempbox@bg + +\newcount\tikztreelevel +\newcount\tikznumberofchildren +\newcount\tikznumberofcurrentchild + +\newcount\tikz@fig@count + +\newif\iftikz@node@is@a@label +\newif\iftikz@snaked +\newif\iftikz@decoratepath + +\let\tikz@options\pgfutil@empty +% |\tikz@addoption| adds \texttt{#1} at the end of the replacement +% text of |\tikz@options| without expansion. +\def\tikz@addoption#1{% + \expandafter\def\expandafter\tikz@options\expandafter{\tikz@options#1}}% +% Same as |tikz@addoption| for |\tikz@mode|. Note that |\tikz@mode| is +% initially let to |\pgfutil@empty| later (see path usage options). +\def\tikz@addmode#1{% + \expandafter\def\expandafter\tikz@mode\expandafter{\tikz@mode#1}}% +% Same as |tikz@addoption| for |\tikz@transform|. Works even if +% |\tikz@transform| is not defined. In that case, nothing is added to +% |\tikz@transform|: \texttt{#1} is expanded. +\def\tikz@addtransform#1{% + \ifx\tikz@transform\relax + #1% + \else + \expandafter\def\expandafter\tikz@transform\expandafter{\tikz@transform#1}% + \fi +}% + + +% TikZ options management. + +% Setting up the tikz key family (key management needs +% \file{pgfkeys.code.tex}); +\pgfkeys{/tikz/.is family}% + +% |\tikzset| is a shortcut to set keys that belongs to the tikz +% family. +\def\tikzset{\pgfqkeys{/tikz}}% + +% Note: |\tikzoption| is supported for compatibility only. |\tikzset| +% should be used instead. +\def\tikzoption#1{% + \pgfutil@ifnextchar[%] + {\tikzoption@opt{#1}}{\tikzoption@noopt{#1}}}% +\def\tikzoption@opt#1[#2]#3{% + \pgfkeysdef{/tikz/#1}{#3}% + \pgfkeyssetvalue{/tikz/#1/.@def}{#2}}% +\def\tikzoption@noopt#1#2{% + \pgfkeysdef{/tikz/#1}{#2}% + \pgfkeyssetvalue{/tikz/#1/.@def}{\pgfkeysvaluerequired}}% + +% Baseline options +\tikzoption{baseline}[0pt]{% + \pgfutil@ifnextchar(%) + {\tikz@baseline@coordinate}{\tikz@baseline@simple}#1\@nil}% +\def\tikz@baseline@simple#1\@nil{\pgfsetbaseline{#1}}% +\def\tikz@baseline@coordinate#1\@nil{% + \pgfsetbaselinepointlater{\tikz@scan@one@point\pgfutil@firstofone#1}}% + +\tikzoption{trim left}[0pt]{\pgfutil@ifnextchar({\tikz@trim@coordinate{left}}{\tikz@trim@simple{left}}#1\@nil}%)% +\tikzoption{trim right}{\pgfutil@ifnextchar({\tikz@trim@coordinate{right}}{\tikz@trim@simple{right}}#1\@nil}%)% +\def\tikz@trim@simple#1#2\@nil{\csname pgfsettrim#1\endcsname{#2}}% +\def\tikz@trim@coordinate#1#2\@nil{\csname pgfsettrim#1pointlater\endcsname{\tikz@scan@one@point\pgfutil@firstofone#2}}% + +% Draw options +\tikzoption{line width}{\tikz@semiaddlinewidth{#1}}% + +\def\tikz@semiaddlinewidth#1{\tikz@addoption{\pgfsetlinewidth{#1}}\pgfmathsetlength\pgflinewidth{#1}}% + +\tikzoption{cap}{\tikz@addoption{\csname pgfset#1cap\endcsname}}% +\tikzoption{join}{\tikz@addoption{\csname pgfset#1join\endcsname}}% +\tikzoption{line cap}{\tikz@addoption{\csname pgfset#1cap\endcsname}}% +\tikzoption{line join}{\tikz@addoption{\csname pgfset#1join\endcsname}}% +\tikzoption{miter limit}{\tikz@addoption{\pgfsetmiterlimit{#1}}}% + +\tikzoption{dash pattern}{% syntax: on 2pt off 3pt on 4pt ... + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \def\tikz@dashpattern{}% + \tikz@addoption{\pgfsetdash{}{0pt}}% + \else% + \def\tikz@dashpattern{}% + \expandafter\tikz@scandashon\pgfutil@gobble#1o\@nil% + \edef\tikz@temp{{\tikz@dashpattern}{\noexpand\tikz@dashphase}}% + \expandafter\tikz@addoption\expandafter{\expandafter\pgfsetdash\tikz@temp}% + \fi}% +\tikzoption{dash phase}{% + \def\tikz@dashphase{#1}% + \edef\tikz@temp{{\tikz@dashpattern}{\noexpand\tikz@dashphase}}% + \expandafter\tikz@addoption\expandafter{\expandafter\pgfsetdash\tikz@temp}% +}% +\tikzoption{dash}{\tikz@parse@full@dash#1\pgf@stop}% +\def\tikz@parse@full@dash#1phase#2\pgf@stop{% + \def\tikz@dashphase{#2}% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \def\tikz@dashpattern{}% + \tikz@addoption{\pgfsetdash{}{0pt}}% + \else% + \def\tikz@dashpattern{}% + \expandafter\tikz@scandashon\pgfutil@gobble#1o\@nil% + \edef\tikz@temp{{\tikz@dashpattern}{\noexpand\tikz@dashphase}}% + \expandafter\tikz@addoption\expandafter{\expandafter\pgfsetdash\tikz@temp}% + \fi% +}% +\def\tikz@dashphase{0pt}% +\def\tikz@dashpattern{}% + +\def\tikz@scandashon n#1o{% + \expandafter\def\expandafter\tikz@dashpattern\expandafter{\tikz@dashpattern{#1}}% + \pgfutil@ifnextchar\@nil{\pgfutil@gobble}{\tikz@scandashoff}}% +\def\tikz@scandashoff ff#1o{% + \expandafter\def\expandafter\tikz@dashpattern\expandafter{\tikz@dashpattern{#1}}% + \pgfutil@ifnextchar\@nil{\pgfutil@gobble}{\tikz@scandashon}}% + +% use a decoration to expand the `off' section of a dash pattern. +% https://tex.stackexchange.com/a/133357 +\tikzset{ + dash expand off/.code={% + \ifcsname tikz@library@decorations@loaded\endcsname\else + \tikzerror{You need \string\usetikzlibrary{decorations} for ``dash expand off''}% + \fi + \tikz@addoption{% + \pgfgetpath\currentpath + \pgfprocessround{\currentpath}{\currentpath}% + \pgf@decorate@parsesoftpath{\currentpath}{\currentpath}% + % All of \on, \off, \dashphase, \rest, and \onoff are unit-free. + % Parse \on and \off from the current path + \pgfmathsetmacro\on{\expandafter\pgfutil@firstoftwo\tikz@dashpattern}% + \pgfmathsetmacro\off{\expandafter\pgfutil@secondoftwo\tikz@dashpattern}% + % \dashphase = max(\on - \dashphase, 0) + \pgfmathsetmacro\tikz@dashphase{\tikz@dashphase}% + \pgfmathsubtract@{\on}{\tikz@dashphase}% + \pgfmathmax@{\pgfmathresult,0}% + \let\dashphase=\pgfmathresult + % \rest = \pgf@decorate@totalpathlength - \on + 2\dashphase + \edef\rest{\pgf@sys@tonumber\dimexpr\pgf@decorate@totalpathlength - \on pt + 2\dimexpr\dashphase pt\relax\relax}% + % \onoff = \on + \off + \edef\onoff{\pgf@sys@tonumber\dimexpr\on pt+\off pt\relax}% + % \nfullonoff = max(floor(\rest/\onoff), 1) + \pgfmathdivide@{\rest}{\onoff}% + \pgfmathfloor@{\pgfmathresult}% + \pgfmathmax@{\pgfmathresult,1}% + % \offexpand = max(\rest/\nfullonoff - \on, \off) + \pgfmathdivide@{\rest}{\pgfmathresult}% + \pgfmathsubtract@{\pgfmathresult}{\on}% + \pgfmathmax@{\pgfmathresult,\off}% + \edef\tikz@marshal{\noexpand\pgfsetdash{{+\on pt}{+\pgfmathresult pt}}{+\dashphase pt}}% + \tikz@marshal + }% + } +} + +\tikzoption{draw opacity}{\tikz@addoption{\pgfsetstrokeopacity{#1}}}% + +% Double draw options +\tikzoption{double}[]{% + \def\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@doublefalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \pgfsetinnerstrokecolor{#1}% + \fi% + \tikz@addmode{\tikz@mode@doubletrue}% + \tikzset{every double/.try}% + \fi}% +\tikzoption{double distance}{% + \pgfmathsetlength{\pgf@x}{#1}% + \edef\tikz@double@setup{% + \pgf@x=\the\pgf@x% + \advance\pgf@x by2\pgflinewidth% + \pgflinewidth=\pgf@x% + \noexpand\pgfsetlinewidth{\pgflinewidth}% + \noexpand\pgfsetinnerlinewidth{\the\pgf@x}% + }% + \tikzset{double}}% +\def\tikz@double@setup{% + \pgf@x=2\pgflinewidth% + \advance\pgf@x by0.6pt% + \pgflinewidth=\pgf@x% + \pgfsetlinewidth{\pgflinewidth}% + \pgfsetinnerlinewidth{0.6pt}% +}% +\tikzset{double distance between line centers/.code={ + \pgfmathsetlength{\pgf@x}{#1}% + \edef\tikz@double@setup{% + \pgf@x=\pgflinewidth% + \pgf@xa=\the\pgf@x% + \advance\pgf@x by\pgf@xa% + \advance\pgf@xa by-\pgflinewidth% + \pgflinewidth=\pgf@x% + \noexpand\pgfsetlinewidth{\pgflinewidth}% + \noexpand\pgfsetinnerlinewidth{\pgf@xa}% + }% + \tikzset{double}}}% +\tikzset{double equal sign distance/.style={double distance between line centers=0.45ex}}% + + + + +% Fill options + +\tikzoption{even odd rule}[]{\tikz@addoption{\pgfseteorule}}% +\tikzoption{nonzero rule}[]{\tikz@addoption{\pgfsetnonzerorule}}% + +\tikzoption{fill opacity}{\tikz@addoption{\pgfsetfillopacity{#1}}}% + + +% Joined fill/draw options + +\tikzoption{opacity}{\tikz@addoption{\pgfsetstrokeopacity{#1}\pgfsetfillopacity{#1}}}% + + +% Blend mode + +\tikzset{blend mode/.code={\tikz@addoption{\pgfsetblendmode{#1}}}}% + + +% Main color options +\tikzoption{color}{% + \tikz@addoption{% + \ifx\tikz@fillcolor\pgfutil@empty% + \ifx\tikz@strokecolor\pgfutil@empty% + \else% + \pgfsys@color@reset@inorderfalse% + \let\tikz@strokecolor\pgfutil@empty% + \let\tikz@fillcolor\pgfutil@empty% + \fi% + \else% + \pgfsys@color@reset@inorderfalse% + \let\tikz@strokecolor\pgfutil@empty% + \let\tikz@fillcolor\pgfutil@empty% + \fi% + \pgfutil@colorlet{tikz@color}{#1}% + \pgfutil@colorlet{.}{tikz@color}% + % + \pgfsetcolor{.}% + \pgfsys@color@reset@inordertrue% + }% + \def\tikz@textcolor{#1}}% + + + +% Rounding options +\tikzoption{rounded corners}[4pt]{\pgfsetcornersarced{\pgfpoint{#1}{#1}}}% +\tikzoption{sharp corners}[]{\pgfsetcornersarced{\pgfpointorigin}}% + +% Radii and arc options +\tikzset{x radius/.initial=0pt}% +\tikzset{y radius/.initial=0pt}% +\tikzset{% + radius/.code={% + \pgfmathparse{#1}% + \ifpgfmathunitsdeclared + \pgfkeyssetevalue{/tikz/x radius}{\pgfmathresult pt}% + \pgfkeyssetevalue{/tikz/y radius}{\pgfmathresult pt}% + \else + \pgfkeyssetevalue{/tikz/x radius}{\pgfmathresult}% + \pgfkeyssetevalue{/tikz/y radius}{\pgfmathresult}% + \fi + }% +}% +\tikzset{start angle/.initial=}% +\tikzset{end angle/.initial=}% +\tikzset{delta angle/.initial=}% + + +% Coordinate options +\tikzoption{x}{\tikz@handle@vec{\pgfsetxvec}{\tikz@handle@x}#1\relax}% +\tikzoption{y}{\tikz@handle@vec{\pgfsetyvec}{\tikz@handle@y}#1\relax}% +\tikzoption{z}{\tikz@handle@vec{\pgfsetzvec}{\tikz@handle@z}#1\relax}% + +\def\tikz@handle@vec#1#2{\pgfutil@ifnextchar({\tikz@handle@coordinate#1}{\tikz@handle@single#2}}% +\def\tikz@handle@coordinate#1{\tikz@scan@one@point#1}% +\def\tikz@handle@single#1#2\relax{#1{#2}}% +\def\tikz@handle@x#1{\pgfsetxvec{\pgfpoint{#1}{0pt}}}% +\def\tikz@handle@y#1{\pgfsetyvec{\pgfpoint{0pt}{#1}}}% +\def\tikz@handle@z#1{\pgfsetzvec{\pgfpoint{#1}{#1}}}% + + +% Transformation options +\tikzoption{scale}{\tikz@addtransform{\pgftransformscale{#1}}}% +\tikzoption{scale around}{\tikz@addtransform{\def\tikz@aroundaction{\pgftransformscale}\tikz@doaround{#1}}}% +\tikzoption{xscale}{\tikz@addtransform{\pgftransformxscale{#1}}}% +\tikzoption{xslant}{\tikz@addtransform{\pgftransformxslant{#1}}}% +\tikzoption{yscale}{\tikz@addtransform{\pgftransformyscale{#1}}}% +\tikzoption{yslant}{\tikz@addtransform{\pgftransformyslant{#1}}}% +\tikzoption{rotate}{\tikz@addtransform{\pgftransformrotate{#1}}}% +\tikzoption{rotate around}{\tikz@addtransform{\def\tikz@aroundaction{\pgftransformrotate}\tikz@doaround{#1}}}% +\def\tikz@doaround#1{% + \edef\tikz@temp{#1}% get rid of active stuff + \expandafter\tikz@doparseA\tikz@temp% +}% +\def\tikz@doparseA#1:{% + \def\tikz@temp@rot{#1}% + \tikz@scan@one@point\tikz@doparseB% +}% +\def\tikz@doparseB#1{% + \pgf@process{#1}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgftransformshift{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \tikz@aroundaction{\tikz@temp@rot}% + \pgftransformshift{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}% +}% + +\tikzoption{shift}{\tikz@addtransform{\tikz@scan@one@point\pgftransformshift#1\relax}}% +\tikzoption{xshift}{\tikz@addtransform{\pgftransformxshift{#1}}}% +\tikzoption{yshift}{\tikz@addtransform{\pgftransformyshift{#1}}}% +\tikzoption{cm}{\tikz@addtransform{\tikz@parse@cm#1\relax}}% +\tikzoption{reset cm}[]{\tikz@addtransform{\pgftransformreset}}% +\tikzoption{shift only}[]{\tikz@addtransform{\pgftransformresetnontranslations}}% + +\def\tikz@parse@cm#1,#2,#3,#4,{% + \def\tikz@p@cm{{#1}{#2}{#3}{#4}}% + \tikz@scan@one@point\tikz@parse@cmA}% +\def\tikz@parse@cmA#1{% + \expandafter\pgftransformcm\tikz@p@cm{#1}% +}% + +\tikzset{transform canvas/.code=% + {% + \tikz@addoption + {% + {% + \pgftransformreset% + \let\tikz@transform=\relax% + \tikzset{#1}% + \pgflowlevelsynccm% + }% + \pgf@relevantforpicturesizefalse% + }% + }% +}% + +\tikzset{turn/.code={% + \pgf@x=0pt% + \pgf@y\pgf@x% + \pgf@process{\tikz@tangent}% + \advance\pgf@x by-\tikz@lastx% + \advance\pgf@y by-\tikz@lasty% + \pgfpointnormalised{}% x/y = normalised vector + \pgf@x=-\pgf@x% + \pgf@ya=-\pgf@y% + \pgftransformcm% + {\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@ya}}% + {\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@x}}{\pgfqpoint{\tikz@lastx}{\tikz@lasty}}% + }% +}% + +\def\tikz@tangent@lookup{% + \pgfgetpath\tikz@temp% + \pgfprocesspathextractpoints\tikz@temp% + \pgfpointsecondlastonpath% +}% + +% Code for rotating the xyz coordinate system +% around the x, y, or z vector. +% +\def\tikz@xyz@rotate@let{% + \let\pgf@z=\pgf@yc% + \let\pgf@za=\pgf@xc% +}% + +\def\tikz@xyz@rotate@xyz@xaxis#1#2#3#4{% + \tikz@xyz@rotate@let% + \pgf@x=#1\relax% + \pgf@ya=#2\relax% + \pgf@za=#3\relax% + \pgfmathsin@{#4}\let\tikz@xyz@sin=\pgfmathresult% + \pgfmathcos@{#4}\let\tikz@xyz@cos=\pgfmathresult% + \pgf@y=\tikz@xyz@cos\pgf@ya% + \advance\pgf@y by-\tikz@xyz@sin\pgf@za% + \pgf@z=\tikz@xyz@sin\pgf@ya% + \advance\pgf@z by\tikz@xyz@cos\pgf@za% +}% + +\def\tikz@xyz@rotate@xyz@yaxis#1#2#3#4{% + \tikz@xyz@rotate@let% + \pgf@xa=#1\relax% + \pgf@y=#2\relax% + \pgf@za=#3\relax% + \pgfmathsin@{#4}\let\tikz@xyz@sin=\pgfmathresult% + \pgfmathcos@{#4}\let\tikz@xyz@cos=\pgfmathresult% + \pgf@x=\tikz@xyz@cos\pgf@xa% + \advance\pgf@x by\tikz@xyz@sin\pgf@za% + \pgf@z=-\tikz@xyz@sin\pgf@xa% + \advance\pgf@z by\tikz@xyz@cos\pgf@za% +}% + +\def\tikz@xyz@rotate@xyz@zaxis#1#2#3#4{% + \tikz@xyz@rotate@let% + \pgf@xa=#1\relax% + \pgf@ya=#2\relax% + \pgf@z=#3\relax% + \pgfmathsin@{#4}\let\tikz@xyz@sin=\pgfmathresult% + \pgfmathcos@{#4}\let\tikz@xyz@cos=\pgfmathresult% + \pgf@x=\tikz@xyz@cos\pgf@xa% + \advance\pgf@x by-\tikz@xyz@sin\pgf@ya% + \pgf@y=\tikz@xyz@sin\pgf@xa% + \advance\pgf@y by\tikz@xyz@cos\pgf@ya% +}% + +\tikzset{rotate around x/.code={% + \tikz@xyz@rotate@let% + \pgfmathparse{#1}\let\tikz@xyz@angle=\pgfmathresult% + \tikz@xyz@rotate@xyz@xaxis{0pt}{1pt}{0pt}{\tikz@xyz@angle}% + \pgfextract@process\tikz@xyz@rotate@yvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \tikz@xyz@rotate@xyz@xaxis{0pt}{0pt}{1pt}{\tikz@xyz@angle}% + \pgfsetzvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \pgfsetyvec{\tikz@xyz@rotate@yvec}% + }, + rotate around y/.code={% + \tikz@xyz@rotate@let% + \pgfmathparse{#1}\let\tikz@xyz@angle=\pgfmathresult% + \tikz@xyz@rotate@xyz@yaxis{1pt}{0pt}{0pt}{\tikz@xyz@angle}% + \pgfextract@process\tikz@xyz@rotate@xvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \tikz@xyz@rotate@xyz@yaxis{0pt}{0pt}{1pt}{\tikz@xyz@angle}% + \pgfsetzvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \pgfsetxvec{\tikz@xyz@rotate@xvec}% + }, + rotate around z/.code={% + \tikz@xyz@rotate@let% + \pgfmathparse{#1}\let\tikz@xyz@angle=\pgfmathresult% + \tikz@xyz@rotate@xyz@zaxis{1pt}{0pt}{0pt}{\tikz@xyz@angle}% + \pgfextract@process\tikz@xyz@rotate@xvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \tikz@xyz@rotate@xyz@zaxis{0pt}{1pt}{0pt}{\tikz@xyz@angle}% + \pgfsetyvec{\pgfpointxyz{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@z}}}% + \pgfsetxvec{\tikz@xyz@rotate@xvec}% + }, +}% + +% Grid options +\tikzoption{xstep}{\def\tikz@grid@x{#1}}% +\tikzoption{ystep}{\def\tikz@grid@y{#1}}% +\tikzoption{step}{\tikz@handle@vec{\tikz@step@point}{\tikz@step@single}#1\relax}% +\def\tikz@step@single#1{\def\tikz@grid@x{#1}\def\tikz@grid@y{#1}}% +\def\tikz@step@point#1{\pgf@process{#1}\edef\tikz@grid@x{\the\pgf@x}\edef\tikz@grid@y{\the\pgf@y}}% + +\def\tikz@grid@x{1cm}% +\def\tikz@grid@y{1cm}% + + +% Current point updates +\newif\iftikz@current@point@local +\tikzset{current point is local/.is if=tikz@current@point@local}% + +% Path usage options +\newif\iftikz@mode@double +\newif\iftikz@mode@fill +\newif\iftikz@mode@draw +\newif\iftikz@mode@clip +\newif\iftikz@mode@boundary +\newif\iftikz@mode@shade +\newif\iftikz@mode@fade@path +\newif\iftikz@mode@fade@scope +\let\tikz@mode=\pgfutil@empty + +\def\tikz@nonetext{none}% + +\tikzoption{path only}[]{\let\tikz@mode=\pgfutil@empty}% +\tikzset{ + shade/.is choice, + shade/.default=true, + shade/true/.code=\tikz@addmode{\tikz@mode@shadetrue}, + shade/false/.code=\tikz@addmode{\tikz@mode@shadefalse}, + shade/none/.code=\tikz@addmode{\tikz@mode@shadefalse}, +}% + +\tikzoption{fill}[]{% + \edef\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@fillfalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \tikz@addoption{\pgfsetfillcolor{#1}}% + \def\tikz@fillcolor{#1}% + \fi% + \tikz@addmode{\tikz@mode@filltrue}% + \fi% +}% +\tikzoption{draw}[]{% + \edef\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@drawfalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \tikz@addoption{\pgfsetstrokecolor{#1}}% + \def\tikz@strokecolor{#1}% + \fi% + \tikz@addmode{\tikz@mode@drawtrue}% + \fi% +}% +\tikzoption{clip}[]{\tikz@addmode{\tikz@mode@cliptrue}}% +\tikzoption{use as bounding box}[]{\tikz@addmode{\tikz@mode@boundarytrue}}% + +\tikzoption{save path}{\tikz@addmode{\pgfsyssoftpath@getcurrentpath#1\global\let#1=#1}}% +\tikzoption{use path}{\tikz@addmode{\pgfsyssoftpath@setcurrentpath#1}}% + +\let\tikz@fillcolor=\pgfutil@empty +\let\tikz@strokecolor=\pgfutil@empty + +% Insert a path using an option +\tikzset{insert path/.code=\tikz@scan@next@command#1\pgf@stop}% + +% Pattern options +\tikzset{pattern/.code=\tikzerror{You need to say \string\usetikzlibrary{patterns}}, + pattern color/.style=pattern}% + +% Path pictures +\tikzset{path picture/.code=\tikz@addmode{\def\tikz@path@picture{#1}}}% + +% Fading options +\tikzset{path fading/.code={ + \def\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@fade@pathfalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \def\tikz@path@fading{#1}% + \fi% + \tikz@addmode{\tikz@mode@fade@pathtrue}% + \fi% + }, + path fading/.default=, + scope fading/.code={ + \def\tikz@temp{#1}% + \ifx\tikz@temp\tikz@nonetext% + \tikz@addmode{\tikz@mode@fade@scopefalse}% + \else% + \ifx\tikz@temp\pgfutil@empty% + \else% + \def\tikz@scope@fading{#1}% + \fi% + \tikz@addmode{\tikz@mode@fade@scopetrue}% + \fi% + }, + scope fading/.default=}% +\tikzset{fit fading/.is if=tikz@fade@adjust}% +\tikzset{fading transform/.store in=\tikz@fade@transform}% +\tikzset{fading angle/.style={fading transform={rotate={#1}}}}% + +\newif\iftikz@fade@adjust% +\tikz@fade@adjusttrue% +\let\tikz@fade@transform\pgfutil@empty% + +\pgfutil@colorlet{transparent}{pgftransparent}% +\def\tikz@do@fade@transform{\let\tikz@transform=\relax\expandafter\tikzset\expandafter{\tikz@fade@transform}}% + + + +% Transparency groups +\newif\iftikz@transparency@group% +\tikzset{/tikz/transparency group/.code=\tikz@transparency@grouptrue\def\tikz@transparency@group@options{isolated=true,#1}\let\tikz@blend@group\pgfutil@empty}% +\tikzset{/tikz/blend group/.code=\tikz@transparency@grouptrue\def\tikz@transparency@group@options{isolated=true}\def\tikz@blend@group{\pgfsetblendmode{#1}}}% + +\let\tikz@blend@group\pgfutil@empty + +% Shading options +\tikzoption{shading}{\def\tikz@shading{#1}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{shading angle}{\def\tikz@shade@angle{#1}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{top color}{% + \pgfutil@colorlet{tikz@axis@top}{#1}% + \pgfutil@colorlet{tikz@axis@middle}{tikz@axis@top!50!tikz@axis@bottom}% + \def\tikz@shading{axis}\def\tikz@shade@angle{0}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{bottom color}{% + \pgfutil@colorlet{tikz@axis@bottom}{#1}% + \pgfutil@colorlet{tikz@axis@middle}{tikz@axis@top!50!tikz@axis@bottom}% + \def\tikz@shading{axis}\def\tikz@shade@angle{0}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{middle color}{% + \pgfutil@colorlet{tikz@axis@middle}{#1}% + \def\tikz@shading{axis}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{left color}{% + \pgfutil@colorlet{tikz@axis@top}{#1}% + \pgfutil@colorlet{tikz@axis@middle}{tikz@axis@top!50!tikz@axis@bottom}% + \def\tikz@shading{axis}\def\tikz@shade@angle{90}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{right color}{% + \pgfutil@colorlet{tikz@axis@bottom}{#1}% + \pgfutil@colorlet{tikz@axis@middle}{tikz@axis@top!50!tikz@axis@bottom}% + \def\tikz@shading{axis}\def\tikz@shade@angle{90}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{ball color}{\pgfutil@colorlet{tikz@ball}{#1}\def\tikz@shading{ball}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{inner color}{\pgfutil@colorlet{tikz@radial@inner}{#1}\def\tikz@shading{radial}\tikz@addmode{\tikz@mode@shadetrue}}% +\tikzoption{outer color}{\pgfutil@colorlet{tikz@radial@outer}{#1}\def\tikz@shading{radial}\tikz@addmode{\tikz@mode@shadetrue}}% + +\def\tikz@shading{axis}% +\def\tikz@shade@angle{0}% + +\pgfdeclareverticalshading[tikz@axis@top,tikz@axis@middle,tikz@axis@bottom]{axis}{100bp}{% + color(0bp)=(tikz@axis@bottom); + color(25bp)=(tikz@axis@bottom); + color(50bp)=(tikz@axis@middle); + color(75bp)=(tikz@axis@top); + color(100bp)=(tikz@axis@top)}% + +\pgfutil@colorlet{tikz@axis@top}{gray}% +\pgfutil@colorlet{tikz@axis@middle}{gray!50!white}% +\pgfutil@colorlet{tikz@axis@bottom}{white}% + +\pgfdeclareradialshading[tikz@ball]{ball}{\pgfqpoint{-10bp}{10bp}}{% + color(0bp)=(tikz@ball!15!white); + color(9bp)=(tikz@ball!75!white); + color(18bp)=(tikz@ball!70!black); + color(25bp)=(tikz@ball!50!black); + color(50bp)=(black)}% + +\pgfutil@colorlet{tikz@ball}{blue}% + +\pgfdeclareradialshading[tikz@radial@inner,tikz@radial@outer]{radial}{\pgfpointorigin}{% + color(0bp)=(tikz@radial@inner); + color(25bp)=(tikz@radial@outer); + color(50bp)=(tikz@radial@outer)}% + +\pgfutil@colorlet{tikz@radial@inner}{gray}% +\pgfutil@colorlet{tikz@radial@outer}{white}% + + +% Pin options +\tikzset{ + pin distance/.store in=\tikz@pin@distance, + pin distance=3ex, + pin position/.store in=\tikz@pin@default@pos, + pin position=above, + pin edge/.store in=\tikz@pin@edge@style, + pin edge={}, + tikz@pin@post/.code={\global\let\tikz@pin@edge@style@smuggle=\tikz@pin@edge@style}, + tikz@pre@pin@edge/.code={% + \toks0=\expandafter{\tikz@pin@edge@style@smuggle}% + \edef\pgf@marshal{\noexpand\tikzset{tikz@pin@options/.style={\the\toks0}}}% + \pgf@marshal + },% +}% + +\tikzset{% + pin/.code={% + \begingroup + \ifnum\the\catcode`\:=\active\relax + \def\tikz@next{% + \endgroup + \tikz@parse@pin@active@i{#1}}% + \else + \def\tikz@next{% + \endgroup + \pgfutil@ifnextchar[%] + {\tikz@parse@pin@nonactive} + {\tikz@parse@pin@nonactive[]}#1:\pgf@nil}% + \fi + \tikz@next}}% + +\begingroup + \catcode`\:=\active\relax + + \gdef\tikz@parse@pin@active@i#1{% + \pgfutil@ifnextchar[%] + {\tikz@parse@pin@active} + {\tikz@parse@pin@active[]}#1:\pgf@nil}% + + \long\gdef\tikz@parse@pin@active[#1]#2:#3\pgf@nil{% + \def\tikz@temp{#3}% + \ifx\tikz@temp\pgfutil@empty + % no position, use default + \tikz@@parse@pin@active[#1]\tikz@pin@default@pos:#2:\pgf@nil% + \else + \tikz@@parse@pin@active[#1]#2:#3\pgf@nil% + \fi}% + + \long\gdef\tikz@@parse@pin@active[#1]#2:#3:\pgf@nil{% + \tikzset{% + append after command = {% + \bgroup + [current point is local = true] + \pgfextra{\let\tikz@save@last@node=\tikzlastnode\tikz@node@is@a@labelfalse}% + node [tikz@label@angle = #2, + anchor=@auto, + every pin, + #1, + append after command = {% + (\tikz@save@last@node) + edge [every pin edge, + tikz@pre@pin@edge, + tikz@pin@options] + (\tikzlastnode)}, + tikz@label@post = \tikz@pin@distance, + tikz@pin@post] {#3} + \egroup}}}% +\endgroup + +\long\def\tikz@parse@pin@nonactive[#1]#2:#3\pgf@nil{% + \def\tikz@temp{#3}% + \ifx\tikz@temp\pgfutil@empty + % no position, use default + \tikz@@parse@pin@nonactive[#1]\tikz@pin@default@pos:#2:\pgf@nil% + \else + \tikz@@parse@pin@nonactive[#1]#2:#3\pgf@nil% + \fi}% + +\long\def\tikz@@parse@pin@nonactive[#1]#2:#3:\pgf@nil{% + \tikzset{% + append after command = {% + \bgroup + [current point is local = true] + \pgfextra{\let\tikz@save@last@node=\tikzlastnode\tikz@node@is@a@labelfalse}% + node [tikz@label@angle = #2, + anchor=@auto, + every pin, + #1, + append after command = {% + (\tikz@save@last@node) + edge [every pin edge, + tikz@pre@pin@edge, + tikz@pin@options] + (\tikzlastnode)}, + tikz@label@post = \tikz@pin@distance, + tikz@pin@post] {#3} + \egroup}}}% + +% Label and pin options + +\tikzset{ + label distance/.store in=\tikz@label@distance, + label distance=0pt, + label position/.store in=\tikz@label@default@pos, + label position=above, + absolute/.is if=tikz@absolute, + tikz@label@angle/.store in=\tikz@label@angle +}% + +\newif\iftikz@absolute +\def\tikz@on@text{center}% + +\tikzset{tikz@label@post/.code 2 args={ + \edef\tikz@label@angle{\tikz@label@angle}% + \expandafter\pgfkeys@spdef\expandafter\tikz@label@angle\expandafter{\tikz@label@angle}% + \csname tikz@label@angle@is@\tikz@label@angle\endcsname + \ifx\tikz@label@angle\tikz@on@text% + \def\tikz@node@at{\pgfpointanchor{\tikzlastnode}{center}}% + \def\tikz@anchor{center}% + \else% + \iftikz@absolute% + \pgftransformreset% + \pgf@process{% + \pgfpointshapeborder{\tikzlastnode}% + {\pgfpointadd{\pgfpointanchor{\tikzlastnode}{center}}{\pgfpointpolar{\tikz@label@angle}{1pt}}}}% + \edef\tikz@node@at{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \tikz@compute@direction{\tikz@label@angle}% + \tikz@addtransform{\pgftransformshift{\pgfpointpolar{\tikz@label@angle}{#1}}}% + \else% + \pgf@process{\pgfpointanchor{\tikzlastnode}{\tikz@label@angle}}% + \edef\tikz@node@at{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointanchor{\tikzlastnode}{center}}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \tikz@label@simplefalse% + \ifdim\pgf@xc=\pgf@xb\relax% + \ifdim\pgf@yc=\pgf@yb\relax% + \tikz@label@simpletrue% + \fi% + \fi% + \iftikz@label@simple% + \tikz@compute@direction{\tikz@label@angle}% + \tikz@addtransform{\pgftransformshift{\pgfpointpolar{\tikz@label@angle}{#1}}}% + \else% + \pgf@process{\pgfpointnormalised{% + \pgfpointdiff{\pgfpointtransformed{\pgfqpoint{\pgf@xc}{\pgf@yc}}}{\pgfpointtransformed{\pgfqpoint{\pgf@xb}{\pgf@yb}}}}}% + \edef\pgf@marshal{% + \noexpand\tikz@addtransform{\noexpand\pgftransformshift{\noexpand\pgfpointscale{#1}{ + \noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}}}% + \pgf@marshal% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@x=\pgf@yc% + \pgf@y=-\pgf@xc% + \ifx\tikz@anchor\tikz@auto@text% + \tikz@auto@anchor% + \fi% + \fi% + \fi% + \fi} +}% + +\newif\iftikz@label@simple% + +\tikzset{% + label/.code={% + \begingroup + \ifnum\the\catcode`\:=\active\relax + \def\tikz@next{% + \endgroup + \tikz@parse@label@active@i{#1}}% + \else + \def\tikz@next{% + \endgroup + \pgfutil@ifnextchar[%] + {\tikz@parse@label@nonactive} + {\tikz@parse@label@nonactive[]}#1:\pgf@nil}% + \fi + \tikz@next}}% + +\begingroup + \catcode`\:=\active\relax + + \gdef\tikz@parse@label@active@i#1{% + \pgfutil@ifnextchar[%] + {\tikz@parse@label@active} + {\tikz@parse@label@active[]}#1:\pgf@nil}% + + \gdef\tikz@parse@label@active[#1]#2:#3\pgf@nil{% + \def\tikz@temp{#3}% + \ifx\tikz@temp\pgfutil@empty + % no position, use default + \tikz@@parse@label@active[#1]\tikz@label@default@pos:#2:\pgf@nil% + \else + \def\tikz@temp{#2}% + \ifx\tikz@temp\pgfutil@empty + \tikz@@parse@label@active[#1]\tikz@label@default@pos:#3\pgf@nil% + \else + \tikz@@parse@label@active[#1]#2:#3\pgf@nil% + \fi + \fi + }% + + \gdef\tikz@@parse@label@active[#1]#2:#3:\pgf@nil{% + \tikzset{% + append after command = {% + \bgroup + [current point is local=true] + \pgfextra{\let\tikz@save@last@fig@name=\tikz@last@fig@name\tikz@node@is@a@labelfalse} + node [tikz@label@angle = #2, + anchor=@auto, + every label, + #1, + tikz@label@post = \tikz@label@distance] {\iftikz@handle@active@nodes\expandafter\scantokens\else\expandafter\pgfutil@firstofone\fi{#3\noexpand}} + \pgfextra{\global\let\tikz@last@fig@name=\tikz@save@last@fig@name} + \egroup}}}% +\endgroup + +\def\tikz@parse@label@nonactive[#1]#2:#3\pgf@nil{% + \def\tikz@temp{#3}% + \ifx\tikz@temp\pgfutil@empty + % no position, use default + \tikz@@parse@label@nonactive[#1]\tikz@label@default@pos:#2:\pgf@nil% + \else + \def\tikz@temp{#2}% + \ifx\tikz@temp\pgfutil@empty + \tikz@@parse@label@nonactive[#1]\tikz@label@default@pos:#3\pgf@nil% + \else + \tikz@@parse@label@nonactive[#1]#2:#3\pgf@nil% + \fi + \fi +}% + +\def\tikz@@parse@label@nonactive[#1]#2:#3:\pgf@nil{% + \tikzset{% + append after command = {% + \bgroup + [current point is local=true] + \pgfextra{\let\tikz@save@last@fig@name=\tikz@last@fig@name\tikz@node@is@a@labelfalse} + node [tikz@label@angle = #2, + anchor=@auto, + every label, + #1, + tikz@label@post = \tikz@label@distance] {\iftikz@handle@active@nodes\expandafter\scantokens\else\expandafter\pgfutil@firstofone\fi{#3\noexpand}} + \pgfextra{\global\let\tikz@last@fig@name=\tikz@save@last@fig@name} + \egroup}}}% + +\expandafter\def\csname tikz@label@angle@is@right\endcsname{\def\tikz@label@angle{0}}% +\expandafter\def\csname tikz@label@angle@is@above right\endcsname{\def\tikz@label@angle{45}}% +\expandafter\def\csname tikz@label@angle@is@above\endcsname{\def\tikz@label@angle{90}}% +\expandafter\def\csname tikz@label@angle@is@above left\endcsname{\def\tikz@label@angle{135}}% +\expandafter\def\csname tikz@label@angle@is@left\endcsname{\def\tikz@label@angle{180}}% +\expandafter\def\csname tikz@label@angle@is@below left\endcsname{\def\tikz@label@angle{225}}% +\expandafter\def\csname tikz@label@angle@is@below\endcsname{\def\tikz@label@angle{270}}% +\expandafter\def\csname tikz@label@angle@is@below right\endcsname{\def\tikz@label@angle{315}}% + +\def\tikz@compute@direction#1{% + \ifx\tikz@anchor\tikz@auto@text% + \let\tikz@do@auto@anchor=\relax + \pgfmathsetcount{\c@pgf@counta}{#1}% + \ifnum\c@pgf@counta<0\relax + \advance\c@pgf@counta by 360\relax% + \fi% + \ifnum\c@pgf@counta>359\relax + \advance\c@pgf@counta by-360\relax% + \fi% + \ifnum\c@pgf@counta<4\relax% + \def\tikz@anchor{west}% + \else\ifnum\c@pgf@counta<87\relax% + \def\tikz@anchor{south west}% + \else\ifnum\c@pgf@counta<94\relax% + \def\tikz@anchor{south}% + \else\ifnum\c@pgf@counta<177\relax% + \def\tikz@anchor{south east}% + \else\ifnum\c@pgf@counta<184\relax% + \def\tikz@anchor{east}% + \else\ifnum\c@pgf@counta<267\relax% + \def\tikz@anchor{north east}% + \else\ifnum\c@pgf@counta<274\relax% + \def\tikz@anchor{north}% + \else\ifnum\c@pgf@counta<357\relax% + \def\tikz@anchor{north west}% + \else% + \def\tikz@anchor{west}% + \fi\fi\fi\fi\fi\fi\fi\fi% + \fi% +}% +\def\tikz@auto@text{@auto}% + +% General node options +\tikzset{ + name/.code={\edef\tikz@fig@name{\tikz@pp@name{#1}}\let\tikz@id@name\tikz@fig@name},% + name prefix/.initial=,% + name suffix/.initial=,% + local bounding box/.style={/pgf/local bounding box/.expanded=\tikz@pp@name{#1}} +}% +\def\tikz@pp@name#1{\csname pgfk@/tikz/name prefix\endcsname#1\csname pgfk@/tikz/name suffix\endcsname}% + + +\tikzset{ + node contents/.code=\def\tikz@node@content{#1}, + pic type/.code=\def\tikz@node@content{#1}, % alias +}% + +\tikzset{ + behind path/.code=\def\tikz@whichbox{\tikz@figbox@bg}, + in front of path/.code=\def\tikz@whichbox{\tikz@figbox} +}% +\def\tikz@whichbox{\tikz@figbox}% + +\tikzoption{at}{\tikz@scan@one@point\tikz@set@at#1}% +\def\tikz@set@at#1{\def\tikz@node@at{#1}}% + +\tikzoption{shape}{\edef\tikz@shape{#1}}% + +\tikzoption{nodes}{\tikzset{every node/.append style={#1}}}% + +\tikzset{alias/.code={% + \tikz@fig@mustbenamed + \begingroup + \toks0=\expandafter{\tikz@alias}% + \edef\pgf@temp{\noexpand\pgfnodealias{\tikz@pp@name{#1}}{\noexpand\tikz@fig@name}}% + \toks1=\expandafter{\pgf@temp}% + \xdef\pgf@marshal{% + \noexpand\def\noexpand\tikz@alias{\the\toks0 \the\toks1 }% + }% + \endgroup + \pgf@marshal +}}% + +% deprecated: +\def\tikzaddafternodepathoption#1{#1\tikzset{prefix after command={\pgfextra{#1}}}}% +\tikzset{after node path/.style={append after command={#1}}}% + + +% Pic options +\tikzset{pic text/.store in=\tikzpictext}% +\let\tikzpictext\relax +\tikzset{pic text options/.store in=\tikzpictextoptions}% +\let\tikzpictextoptions\pgfutil@empty + + +% Anchoring + +\tikzoption{anchor}{\def\tikz@anchor{#1}\let\tikz@do@auto@anchor=\relax}% + +\tikzoption{left}[]{\def\tikz@anchor{east}\tikz@possibly@transform{x}{-}{#1}}% +\tikzoption{right}[]{\def\tikz@anchor{west}\tikz@possibly@transform{x}{}{#1}}% +\tikzoption{above}[]{\def\tikz@anchor{south}\tikz@possibly@transform{y}{}{#1}}% +\tikzoption{below}[]{\def\tikz@anchor{north}\tikz@possibly@transform{y}{-}{#1}}% +\tikzoption{above left}[]% + {\def\tikz@anchor{south east}% + \tikz@possibly@transform{x}{-}{#1}\tikz@possibly@transform{y}{}{#1}}% +\tikzoption{above right}[]% + {\def\tikz@anchor{south west}% + \tikz@possibly@transform{x}{}{#1}\tikz@possibly@transform{y}{}{#1}}% +\tikzoption{below left}[]% + {\def\tikz@anchor{north east}% + \tikz@possibly@transform{x}{-}{#1}\tikz@possibly@transform{y}{-}{#1}}% +\tikzoption{below right}[]% + {\def\tikz@anchor{north west}% + \tikz@possibly@transform{x}{}{#1}\tikz@possibly@transform{y}{-}{#1}}% +\tikzset{centered/.code=\def\tikz@anchor{center}}% + +\tikzoption{node distance}{\def\tikz@node@distance{#1}}% +\def\tikz@node@distance{1cm}% + +% The following are deprecated: +\tikzoption{above of}{\tikz@of{#1}{90}}% +\tikzoption{below of}{\tikz@of{#1}{-90}}% +\tikzoption{left of}{\tikz@of{#1}{180}}% +\tikzoption{right of}{\tikz@of{#1}{0}}% +\tikzoption{above left of}{\tikz@of{#1}{135}}% +\tikzoption{below left of}{\tikz@of{#1}{-135}}% +\tikzoption{above right of}{\tikz@of{#1}{45}}% +\tikzoption{below right of}{\tikz@of{#1}{-45}}% +\def\tikz@of#1#2{% + \def\tikz@anchor{center}% + \let\tikz@do@auto@anchor=\relax% + \tikz@addtransform{% + \expandafter\tikz@extract@node@dist\tikz@node@distance and\pgf@stop% + \pgftransformshift{\pgfpointpolar{#2}{\tikz@extracted@node@distance}}}% + \def\tikz@node@at{\pgfpointanchor{\tikz@pp@name{#1}}{center}}}% +\def\tikz@extract@node@dist#1and#2\pgf@stop{% + \def\tikz@extracted@node@distance{#1}}% + +\tikzset{ + transform shape nonlinear/.is choice, + transform shape nonlinear/.default=true, + transform shape nonlinear/true/.code=\let\tikz@nlt\relax, + transform shape nonlinear/false/.code=\def\tikz@nlt{\pgfapproximatenonlineartranslation}, + transform shape nonlinear=false, +}% + + +\tikzoption{transform shape}[true]{% + \csname tikz@fullytransformed#1\endcsname% + \iftikz@fullytransformed% + \pgfresetnontranslationattimefalse% + \else% + \pgfresetnontranslationattimetrue% + \fi% +}% + +\newif\iftikz@fullytransformed +\pgfresetnontranslationattimetrue% + +\def\tikz@anchor{center}% +\def\tikz@shape{rectangle}% + +\def\tikz@possibly@transform#1#2#3{% + \let\tikz@do@auto@anchor=\relax% + \def\tikz@test{#3}% + \ifx\tikz@test\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{#3}% + \pgf@x=#2\pgf@x\relax% + \edef\tikz@marshal{\noexpand\tikz@addtransform{% + \expandafter\noexpand\csname pgftransform#1shift\endcsname{\the\pgf@x}}}% + \tikz@marshal% + \fi% +}% + + +% Inter-picture options +\tikzoption{remember picture}[true]{\csname pgfrememberpicturepositiononpage#1\endcsname} +\tikzset{ + overlay/.is choice, + overlay/true/.code={\pgf@relevantforpicturesizefalse}, + overlay/false/.code={\pgf@relevantforpicturesizetrue}, + overlay/.default=true +} + + + +% Line/curve label placement options +\tikzoption{sloped}[true]{\csname pgfslopedattime#1\endcsname}% +\tikzoption{allow upside down}[true]{\csname pgfallowupsidedownattime#1\endcsname}% + +\tikzoption{pos}{\edef\tikz@time{#1}\ifx\tikz@time\pgfutil@empty\else\pgfmathsetmacro\tikz@time{\tikz@time}\fi}% + +\tikzoption{auto}[]{\csname tikz@install@auto@anchor@#1\endcsname}% +\tikzoption{swap}[]{% + \def\tikz@temp{left}% + \ifx\tikz@auto@anchor@direction\tikz@temp% + \def\tikz@auto@anchor@direction{right}% + \else% + \def\tikz@auto@anchor@direction{left}% + \fi% +}% +\tikzset{'/.style=swap}% shorthand + + +\def\tikz@install@auto@anchor@{\let\tikz@do@auto@anchor=\tikz@auto@anchor@on}% +\def\tikz@install@auto@anchor@false{\let\tikz@do@auto@anchor=\relax}% +\def\tikz@install@auto@anchor@left{\let\tikz@do@auto@anchor=\tikz@auto@anchor@on\def\tikz@auto@anchor@direction{left}}% +\def\tikz@install@auto@anchor@right{\let\tikz@do@auto@anchor=\tikz@auto@anchor@on\def\tikz@auto@anchor@direction{right}}% + +\let\tikz@do@auto@anchor=\relax% + +\def\tikz@auto@anchor@on{\csname tikz@auto@anchor@\tikz@auto@anchor@direction\endcsname} + +\def\tikz@auto@anchor@left{\tikz@auto@pre\tikz@auto@anchor\tikz@auto@post}% +\def\tikz@auto@anchor@right{\tikz@auto@pre\tikz@auto@anchor@prime\tikz@auto@post}% + +\def\tikz@auto@anchor@direction{left}% + +% Text options +\tikzoption{text}{\def\tikz@textcolor{#1}}% +\tikzoption{font}{\def\tikz@textfont{#1}}% +\tikzoption{node font}{\def\tikz@node@textfont{#1}}% +\tikzoption{text opacity}{\def\tikz@textopacity{#1}}% +\tikzoption{text width}{\def\tikz@text@width{#1}}% +\tikzoption{text height}{\def\tikz@text@height{#1}}% +\tikzoption{text depth}{\def\tikz@text@depth{#1}}% +\tikzoption{text ragged}[]% +{\def\tikz@text@action{\pgfutil@raggedright\rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax}}% +\tikzoption{text badly ragged}[]{\def\tikz@text@action{\pgfutil@raggedright\relax}}% +\tikzoption{text ragged left}[]% +{\def\tikz@text@action{\pgfutil@raggedleft\leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax}}% +\tikzoption{text badly ragged left}[]{\def\tikz@text@action{\pgfutil@raggedleft\relax}}% +\tikzoption{text justified}[]{\def\tikz@text@action{\leftskip0pt\rightskip0pt\relax}}% +\tikzoption{text centered}[]{\def\tikz@text@action{% + \leftskip0pt plus2em% + \rightskip0pt plus2em% + \spaceskip.3333em \xspaceskip.5em% + \parfillskip=0pt% + \iftikz@warn@for@narrow@centered\else\hbadness10000\fi% + \let\\=\@centercr% for latex + \relax}}% +\tikzoption{text badly centered}[]% +{\def\tikz@text@action{% + \let\\=\@centercr% for latex + \parfillskip=0pt% + \rightskip\pgfutil@flushglue% + \leftskip\pgfutil@flushglue\relax}}% +\tikzset{badness warnings for centered text/.is if=tikz@warn@for@narrow@centered}% +\newif\iftikz@warn@for@narrow@centered + +\def\tikz@text@reset{% + \let\tikz@text@width=\pgfutil@empty + \let\tikz@text@height=\pgfutil@empty + \let\tikz@text@depth=\pgfutil@empty + \let\tikz@textcolor=\pgfutil@empty + \let\tikz@textfont=\pgfutil@empty + \let\tikz@textopacity=\pgfutil@empty + \let\tikz@node@textfont=\pgfutil@empty + \def\tikz@text@action{\pgfutil@raggedright\rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax}% +} +\tikz@text@reset + + +% Alignment +\tikzset{ + node halign header/.initial=, + align/.is choice, + align/left/.style ={text ragged,node halign header=\tikz@align@left@header}, + align/flush left/.style ={text badly ragged,node halign header=\tikz@align@left@header}, + align/right/.style ={text ragged left,node halign header=\tikz@align@right@header}, + align/flush right/.style ={text badly ragged left,node halign header=\tikz@align@right@header}, + align/center/.style={text centered,node halign header=\tikz@align@center@header}, + align/flush center/.style={text badly centered,node halign header=\tikz@align@center@header}, + align/justify/.style ={text justified,node halign header=\tikz@align@left@header}, + align/none/.style ={text justified,node halign header=}, +}% +\def\tikz@align@left@header{##\hfil\cr}% +\def\tikz@align@right@header{\hfil##\cr}% +\def\tikz@align@center@header{\hfil##\hfil\cr}% + + + +% Arrow options +\tikzoption{arrows}{\tikz@processarrows{#1}}% + + +\tikzoption{>}{\pgfdeclarearrow{name=<->,means={#1}}}% +\pgfdeclarearrow{name=|<->|, means={>[sep=0pt].|}}% + +\tikzoption{shorten <}{\pgfsetshortenstart{#1}}% +\tikzoption{shorten >}{\pgfsetshortenend{#1}}% + +\def\tikz@processarrows#1{% + \def\tikz@current@arrows{#1}% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \else% + \pgfsetarrows{#1}% + \fi% +}% + +\def\tikz@current@arrows{-}% + +% Parabola options +\tikzoption{bend}{\tikz@scan@one@point\tikz@set@parabola@bend#1\relax}% +\tikzoption{bend pos}{\def\tikz@parabola@bend@factor{#1}}% +\tikzoption{parabola height}{% + \def\tikz@parabola@bend@factor{.5}% + \def\tikz@parabola@bend{\pgfpointadd{\pgfpoint{0pt}{#1}}{\tikz@last@position@saved}}}% + +\def\tikz@parabola@bend{\tikz@last@position@saved}% +\def\tikz@parabola@bend@factor{0}% + +\def\tikz@set@parabola@bend#1{\def\tikz@parabola@bend{#1}}% + +% Axis options +\tikzoption{domain}{\edef\tikz@plot@domain{#1}\expandafter\tikz@plot@samples@recalc\tikz@plot@domain\relax}% +\tikzoption{range}{\def\tikz@plot@range{#1}}% +\tikzoption{yrange}{\def\tikz@plot@range{#1}}% +\let\tikz@plot@range=\pgfutil@empty +\tikzoption{xrange}{\def\tikz@plot@xrange{#1}}% +\let\tikz@plot@xrange=\pgfutil@empty + +% Plot options +\tikzoption{smooth}[]{\let\tikz@plot@handler=\pgfplothandlercurveto}% +\tikzoption{smooth cycle}[]{\let\tikz@plot@handler=\pgfplothandlerclosedcurve}% +\tikzoption{sharp plot}[]{\let\tikz@plot@handler\pgfplothandlerlineto}% +\tikzoption{sharp cycle}[]{\let\tikz@plot@handler\pgfplothandlerpolygon}% + +\tikzoption{tension}{\pgfsetplottension{#1}}% + +\tikzoption{xcomb}[]{\let\tikz@plot@handler=\pgfplothandlerxcomb}% +\tikzoption{ycomb}[]{\let\tikz@plot@handler=\pgfplothandlerycomb}% +\tikzoption{polar comb}[]{\let\tikz@plot@handler=\pgfplothandlerpolarcomb}% +\tikzoption{ybar}[]{\let\tikz@plot@handler=\pgfplothandlerybar}% +\tikzoption{ybar interval}[]{\let\tikz@plot@handler=\pgfplothandlerybarinterval}% +\tikzoption{xbar interval}[]{\let\tikz@plot@handler=\pgfplothandlerxbarinterval}% +\tikzoption{xbar}[]{\let\tikz@plot@handler=\pgfplothandlerxbar}% +\tikzoption{const plot}[]{\let\tikz@plot@handler=\pgfplothandlerconstantlineto}% +\tikzoption{const plot mark left}[]{\let\tikz@plot@handler=\pgfplothandlerconstantlineto}% +\tikzoption{const plot mark right}[]{\let\tikz@plot@handler=\pgfplothandlerconstantlinetomarkright}% +\tikzoption{const plot mark mid}[]{\let\tikz@plot@handler=\pgfplothandlerconstantlinetomarkmid}% +\tikzoption{jump mark right}[]{\let\tikz@plot@handler=\pgfplothandlerjumpmarkright}% +\tikzoption{jump mark mid}[]{\let\tikz@plot@handler=\pgfplothandlerjumpmarkmid}% +\tikzoption{jump mark left}[]{\let\tikz@plot@handler=\pgfplothandlerjumpmarkleft}% + +\tikzoption{raw gnuplot}[true]{\csname tikz@plot@raw@gnuplot#1\endcsname}% +\tikzoption{prefix}{\def\tikz@plot@prefix{#1}}% +\tikzoption{id}{\def\tikz@plot@id{#1}}% + +\tikzoption{samples}{\pgfmathsetmacro\tikz@plot@samples{max(2,#1)}\expandafter\tikz@plot@samples@recalc\tikz@plot@domain\relax}% +\tikzoption{samples at}{\def\tikz@plot@samplesat{#1}}% +\tikzoption{parametric}[true]{\csname tikz@plot@parametric#1\endcsname}% + +\tikzoption{variable}{\def\tikz@plot@var{#1}}% + +\tikzoption{only marks}[]{\let\tikz@plot@handler\pgfplothandlerdiscard}% + +\tikzoption{mark}{% + \def\tikz@plot@mark{#1}% + \def\tikz@temp{none}% + \ifx\tikz@temp\tikz@plot@mark + \let\tikz@plot@mark=\pgfutil@empty + \fi +}% +\tikzset{ + no marks/.style={mark=none},% + no markers/.style={mark=none},% + every mark/.style={}, + mark options/.style={% + every mark/.style={#1}% + }}% +\tikzoption{mark size}{\pgfsetplotmarksize{#1}}% + +\tikzoption{mark indices}{\def\tikz@mark@list{#1}}% +\tikzoption{mark phase}{\pgfsetplotmarkphase{#1}}% +\tikzoption{mark repeat}{\pgfsetplotmarkrepeat{#1}}% + +\let\tikz@mark@list=\pgfutil@empty + +\let\tikz@plot@handler=\pgfplothandlerlineto +\let\tikz@plot@mark=\pgfutil@empty + +\def\tikz@plot@samples{25}% +\def\tikz@plot@domain{-5:5}% +\def\tikz@plot@var{\x}% +\def\tikz@plot@samplesat{-5,-4.5833333,...,5}% +\def\tikz@plot@samples@recalc#1:#2\relax{% + \begingroup + \pgfmathparse{#1}% + \let\tikz@temp@start=\pgfmathresult% + \pgfmathparse{#2}% + \let\tikz@temp@end=\pgfmathresult% + \pgfmathsetmacro\tikz@temp@diff{(\tikz@temp@end-\tikz@temp@start)/(\tikz@plot@samples-1)}% + % + % this particular item is for backwards compatibility. + % Pgfplots <= 1.8 called 'samples' in a context where the 'fpu' was + % active... and I fear there is no simple solution to replace the + % new \ifdim below. Sorry. + \pgfkeys{/pgf/fpu/output format/fixed/.try}% + % + \pgfmathsetmacro\tikz@temp@diff@abs{abs(\tikz@temp@diff)}% + \ifdim\tikz@temp@diff@abs pt<0.0001pt\relax% + \edef\tikz@plot@samplesat{\tikz@temp@start,\tikz@temp@end}% + \else% + \pgfmathparse{\tikz@temp@start+\tikz@temp@diff}% + \edef\tikz@plot@samplesat{\tikz@temp@start,\pgfmathresult,...,\tikz@temp@end}% + \fi% + \pgfmath@smuggleone\tikz@plot@samplesat + \endgroup +}% + + +\def\tikz@plot@prefix{\jobname.}% +\def\tikz@plot@id{pgf-plot}% + +\newif\iftikz@plot@parametric +\newif\iftikz@plot@raw@gnuplot + + +% +% To and edge options +% +\tikzoption{to path}{\def\tikz@to@path{#1}}% + +\def\tikz@to@path{-- (\tikztotarget) \tikztonodes}% + +\tikzset{edge macro/.store in=\tikz@edge@macro}% +\let\tikz@edge@macro\pgfutil@empty + +\tikzset{ + edge node/.code={ + \expandafter\def\expandafter\tikz@tonodes\expandafter{\tikz@tonodes #1} + }, + edge label/.style={/tikz/edge node={node[auto]{#1}}}, + edge label'/.style={/tikz/edge node={node[auto,swap]{#1}}}, +}% + + +% After command options +\tikzset{ + append after command/.code=\expandafter\def\expandafter\tikz@after@path\expandafter{\tikz@after@path#1}, + prefix after command/.code={% + \def\tikz@temp{#1}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@after@path% + \expandafter\expandafter\expandafter{% + \expandafter\tikz@temp\tikz@after@path}% + }, +}% +\let\tikz@after@path\pgfutil@empty + + +% Tree options +\newif\iftikz@child@missing +\pgfkeys{/tikz/missing/.is if=tikz@child@missing}% + +\tikzset{edge from parent macro/.initial=\tikz@edge@from@parent@macro}% +\def\tikz@edge@from@parent@macro#1#2{ + [style=edge from parent, #1, /utils/exec=\tikz@node@is@a@labeltrue] \tikz@edge@to@parent@path #2}% + +\tikzoption{edge from parent path}{\def\tikz@edge@to@parent@path{#1}}% + +\tikzoption{parent anchor}{\def\tikzparentanchor{.#1}\ifx\tikzparentanchor\tikz@border@text\let\tikzparentanchor\pgfutil@empty\fi}% +\tikzoption{child anchor}{\def\tikzchildanchor{.#1}\ifx\tikzchildanchor\tikz@border@text\let\tikzchildanchor\pgfutil@empty\fi}% + +\tikzoption{level distance}{\pgfmathsetlength\tikzleveldistance{#1}}% +\tikzoption{sibling distance}{\pgfmathsetlength\tikzsiblingdistance{#1}}% + +\tikzoption{growth function}{\let\tikz@grow=#1}% + +\tikzset{grow siblings on line/.style={growth function=\tikz@grow@direction}}% + +\tikzoption{growth parent anchor}{\def\tikz@growth@anchor{#1}}% +\tikzoption{grow}{\tikz@set@growth{#1}\edef\tikz@special@level{\the\tikztreelevel}}% +\tikzoption{grow'}{\tikz@set@growth{#1}\tikz@swap@growth\edef\tikz@special@level{\the\tikztreelevel}}% + +\def\tikz@growth@anchor{center}% + +\def\tikz@special@level{-1}% never + +\def\tikz@swap@growth{% + % Swap left and right + \let\tikz@temp=\tikz@angle@grow@right% + \let\tikz@angle@grow@right=\tikz@angle@grow@left% + \let\tikz@angle@grow@left=\tikz@temp% +}% + +\def\tikz@set@growth#1{% + \let\tikz@grow=\tikz@grow@direction% + \expandafter\ifx\csname tikz@grow@direction@#1\endcsname\relax% + \c@pgf@counta=#1\relax% + \else% + \c@pgf@counta=\csname tikz@grow@direction@#1\endcsname% + \fi% + \edef\tikz@angle@grow{\the\c@pgf@counta}% + \advance\c@pgf@counta by-90\relax% + \edef\tikz@angle@grow@left{\the\c@pgf@counta}% + \advance\c@pgf@counta by180\relax% + \edef\tikz@angle@grow@right{\the\c@pgf@counta}% +}% + +\def\tikz@border@text{.border}% +\let\tikzparentanchor=\pgfutil@empty +\let\tikzchildanchor=\pgfutil@empty +\def\tikz@edge@to@parent@path{(\tikzparentnode\tikzparentanchor) -- (\tikzchildnode\tikzchildanchor)}% + +\tikzleveldistance=15mm% +\tikzsiblingdistance=15mm% + +\def\tikz@grow@direction@down{-90}% +\def\tikz@grow@direction@up{90}% +\def\tikz@grow@direction@left{180}% +\def\tikz@grow@direction@right{0}% + +\def\tikz@grow@direction@south{-90}% +\def\tikz@grow@direction@north{90}% +\def\tikz@grow@direction@west{180}% +\def\tikz@grow@direction@east{0}% + +\expandafter\def\csname tikz@grow@direction@north east\endcsname{45}% +\expandafter\def\csname tikz@grow@direction@north west\endcsname{135}% +\expandafter\def\csname tikz@grow@direction@south east\endcsname{-45}% +\expandafter\def\csname tikz@grow@direction@south west\endcsname{-135}% + +\def\tikz@grow@direction{% + \pgftransformshift{\pgfpointpolar{\tikz@angle@grow}{\tikzleveldistance}}% + \ifnum\tikztreelevel=\tikz@special@level% + \else% + \pgf@xc=.5\tikzsiblingdistance% + \c@pgf@counta=\tikznumberofchildren% + \advance\c@pgf@counta by1\relax% + \pgfutil@tempdima=\c@pgf@counta\pgf@xc% + \pgftransformshift{\pgfpointpolar{\tikz@angle@grow@left}{\pgfutil@tempdima}}% + \pgftransformshift{\pgfpointpolar{\tikz@angle@grow@right}{\tikznumberofcurrentchild\tikzsiblingdistance}}% + \fi% +}% + +\tikzset{grow=down}% + + +% Snakes are in a lib: +\tikzset{snake/.code=\tikzerror{You need to say \string\usetikzlibrary{snakes}}}% + +% Decorations +\tikzset{decorate/.code=\tikzerror{You need to load a decoration library}}% + +% Matrix options +\usepgfmodule{matrix}% + +\tikzoption{matrix}[true]{\csname tikz@is@matrix#1\endcsname}% + +\tikzoption{matrix anchor}{\def\tikz@matrix@anchor{#1}}% + +\tikzoption{column sep}{\def\pgfmatrixcolumnsep{#1}}% +\tikzoption{row sep}{\def\pgfmatrixrowsep{#1}}% + +\tikzoption{cells}{\tikzset{every cell/.append style={#1}}}% + +\tikzoption{ampersand replacement}{\def\tikz@ampersand@replacement{#1}}% + +\newif\iftikz@is@matrix +\let\tikz@matrix@anchor=\pgfutil@empty +\let\tikz@ampersand@replacement=\pgfutil@empty + + +% Automatic shorthand management +\tikzset{% + handle active characters in code/.is if=tikz@handle@active@code, + handle active characters in nodes/.is if=tikz@handle@active@nodes, +}% +\newif\iftikz@handle@active@code +\newif\iftikz@handle@active@nodes + + +% Execute option +\tikzoption{execute at begin picture}{\expandafter\def\expandafter\tikz@atbegin@picture\expandafter{\tikz@atbegin@picture#1}}% +\tikzoption{execute at end picture}{\expandafter\def\expandafter\tikz@atend@picture\expandafter{\tikz@atend@picture#1}}% +\tikzoption{execute at begin scope}{\expandafter\def\expandafter\tikz@atbegin@scope\expandafter{\tikz@atbegin@scope#1}}% +\tikzoption{execute at end scope}{\expandafter\def\expandafter\tikz@atend@scope\expandafter{\tikz@atend@scope#1}}% +\tikzoption{execute at begin to}{\expandafter\def\expandafter\tikz@atbegin@to\expandafter{\tikz@atbegin@to#1}}% +\tikzoption{execute at end to}{\expandafter\def\expandafter\tikz@atend@to\expandafter{\tikz@atend@to#1}}% +\tikzoption{execute at begin node}{\expandafter\def\expandafter\tikz@atbegin@node\expandafter{\tikz@atbegin@node#1}}% +\tikzoption{execute at end node}{\expandafter\def\expandafter\tikz@atend@node\expandafter{\tikz@atend@node#1}}% +\tikzoption{execute at begin matrix}{\expandafter\def\expandafter\tikz@atbegin@matrix\expandafter{\tikz@atbegin@matrix#1}}% +\tikzoption{execute at end matrix}{\expandafter\def\expandafter\tikz@atend@matrix\expandafter{\tikz@atend@matrix#1}}% +\tikzoption{execute at begin cell}{\expandafter\def\expandafter\tikz@atbegin@cell\expandafter{\tikz@atbegin@cell#1}}% +\tikzoption{execute at end cell}{\expandafter\def\expandafter\tikz@atend@cell\expandafter{\tikz@atend@cell#1}}% +\tikzoption{execute at empty cell}{\expandafter\def\expandafter\tikz@at@emptycell\expandafter{\tikz@at@emptycell#1}}% + +\let\tikz@atbegin@picture=\pgfutil@empty +\let\tikz@atend@picture=\pgfutil@empty +\let\tikz@atbegin@scope=\pgfutil@empty +\let\tikz@atend@scope=\pgfutil@empty +\let\tikz@atbegin@to=\pgfutil@empty +\let\tikz@atend@to=\pgfutil@empty +\let\tikz@atbegin@node=\pgfutil@empty +\let\tikz@atend@node=\pgfutil@empty +\let\tikz@atbegin@cell=\pgfutil@empty +\let\tikz@atend@cell=\pgfutil@empty +\let\tikz@at@emptycell=\pgfutil@empty +\let\tikz@atbegin@matrix=\pgfutil@empty +\let\tikz@atend@matrix=\pgfutil@empty + + +% Pre and post actions +\tikzset{preaction/.code=\expandafter\def\expandafter\tikz@preactions\expandafter{\tikz@preactions\tikz@extra@preaction{#1}}}% +\tikzset{postaction/.code=\expandafter\def\expandafter\tikz@postactions\expandafter{\tikz@postactions\tikz@extra@postaction{#1}}}% +\let\tikz@preactions=\pgfutil@empty +\let\tikz@postactions=\pgfutil@empty + +% Styles +\tikzoption{set style}{\tikzstyle#1}% + +% Handled in a special way. +\def\tikzstyle{\pgfutil@ifnextchar\bgroup\tikz@style@parseA\tikz@style@parseB}% +\def\tikz@style@parseB#1={\tikz@style@parseA{#1}=}% +\def\tikz@style@parseA#1#2=#3[#4]{% check for an optional argument + \pgfutil@in@[{#2}%] + \ifpgfutil@in@% + \tikz@style@parseC{#1}#2={#4}% + \else% + \tikz@style@parseD{#1}#2={#4}% + \fi% +}% + +\def\tikz@style@parseC#1[#2]#3=#4{% + \pgfkeys{/tikz/#1/.default={#2}}% + \pgfutil@in@+{#3}% + \ifpgfutil@in@% + \pgfkeys{/tikz/#1/.append style={#4}}% + \else% + \pgfkeys{/tikz/#1/.style={#4}}% + \fi}% +\def\tikz@style@parseD#1#2=#3{% + \pgfutil@in@+{#2}% + \ifpgfutil@in@% + \pgfkeys{/tikz/#1/.append style={#3}}% + \else% + \pgfkeys{/tikz/#1/.style={#3}}% + \fi}% + + +% +% +% Predefined styles +% +% + +\tikzset{help lines/.style= {color=gray,line width=0.2pt}}% + +\tikzset{every picture/.style= {}}% +\tikzset{every path/.style= {}}% +\tikzset{every scope/.style= {}}% +\tikzset{every plot/.style= {}}% +\tikzset{every node/.style= {}}% +\tikzset{every child/.style= {}}% +\tikzset{every child node/.style= {}}% +\tikzset{every to/.style= {}}% +\tikzset{every cell/.style= {}}% +\tikzset{every matrix/.style= {}}% +\tikzset{every edge/.style= {draw}}% +\tikzset{every label/.style= {draw=none,fill=none}}% +\tikzset{every pin/.style= {draw=none,fill=none}}% +\tikzset{every pin edge/.style= {help lines}}% + +\tikzset{ultra thin/.style= {line width=0.1pt}}% +\tikzset{very thin/.style= {line width=0.2pt}}% +\tikzset{thin/.style= {line width=0.4pt}}% +\tikzset{semithick/.style= {line width=0.6pt}}% +\tikzset{thick/.style= {line width=0.8pt}}% +\tikzset{very thick/.style= {line width=1.2pt}}% +\tikzset{ultra thick/.style= {line width=1.6pt}}% + +\tikzset{solid/.style= {dash pattern=}}% +\tikzset{dotted/.style= {dash pattern=on \pgflinewidth off 2pt}}% +\tikzset{densely dotted/.style= {dash pattern=on \pgflinewidth off 1pt}}% +\tikzset{loosely dotted/.style= {dash pattern=on \pgflinewidth off 4pt}}% +\tikzset{dashed/.style= {dash pattern=on 3pt off 3pt}}% +\tikzset{densely dashed/.style= {dash pattern=on 3pt off 2pt}}% +\tikzset{loosely dashed/.style= {dash pattern=on 3pt off 6pt}}% +\tikzset{dashdotted/.style= {dash pattern=on 3pt off 2pt on \the\pgflinewidth off 2pt}}% +\tikzset{dash dot/.style= {dash pattern=on 3pt off 2pt on \the\pgflinewidth off 2pt}}% +\tikzset{densely dashdotted/.style= {dash pattern=on 3pt off 1pt on \the\pgflinewidth off 1pt}}% +\tikzset{densely dash dot/.style= {dash pattern=on 3pt off 1pt on \the\pgflinewidth off 1pt}}% +\tikzset{loosely dashdotted/.style= {dash pattern=on 3pt off 4pt on \the\pgflinewidth off 4pt}}% +\tikzset{loosely dash dot/.style= {dash pattern=on 3pt off 4pt on \the\pgflinewidth off 4pt}}% +\tikzset{dashdotdotted/.style= {dash pattern=on 3pt off 2pt on \the\pgflinewidth off 2pt on \the\pgflinewidth off 2pt}}% +\tikzset{densely dashdotdotted/.style= {dash pattern=on 3pt off 1pt on \the\pgflinewidth off 1pt on \the\pgflinewidth off 1pt}}% +\tikzset{loosely dashdotdotted/.style= {dash pattern=on 3pt off 4pt on \the\pgflinewidth off 4pt on \the\pgflinewidth off 4pt}}% +\tikzset{dash dot dot/.style= {dash pattern=on 3pt off 2pt on \the\pgflinewidth off 2pt on \the\pgflinewidth off 2pt}}% +\tikzset{densely dash dot dot/.style= {dash pattern=on 3pt off 1pt on \the\pgflinewidth off 1pt on \the\pgflinewidth off 1pt}}% +\tikzset{loosely dash dot dot/.style= {dash pattern=on 3pt off 4pt on \the\pgflinewidth off 4pt on \the\pgflinewidth off 4pt}}% + + +\tikzset{transparent/.style= {opacity=0}}% +\tikzset{ultra nearly transparent/.style={opacity=0.05}}% +\tikzset{very nearly transparent/.style= {opacity=0.1}}% +\tikzset{nearly transparent/.style= {opacity=0.25}}% +\tikzset{semitransparent/.style= {opacity=0.5}}% +\tikzset{nearly opaque/.style= {opacity=0.75}}% +\tikzset{very nearly opaque/.style= {opacity=0.9}}% +\tikzset{ultra nearly opaque/.style= {opacity=0.95}}% +\tikzset{opaque/.style= {opacity=1}}% + +\tikzset{at start/.style= {pos=0}}% +\tikzset{very near start/.style= {pos=0.125}}% +\tikzset{near start/.style= {pos=0.25}}% +\tikzset{midway/.style= {pos=0.5}}% +\tikzset{near end/.style= {pos=0.75}}% +\tikzset{very near end/.style= {pos=0.875}}% +\tikzset{at end/.style= {pos=1}}% + +\tikzset{bend at start/.style= {bend pos=0,bend={+(0,0)}}}% +\tikzset{bend at end/.style= {bend pos=1,bend={+(0,0)}}}% + +\tikzset{edge from parent/.style= {draw}}% + + + +% Animation callbacks +\tikzset{ + animate/.code=\tikzerror{You need to say \string\usetikzlibrary{animations} to use animations} +} + +% ID callbacks +\newif\iftikz@is@node +\let\tikz@id@name\pgfutil@empty +\let\tikz@id@hook\pgfutil@empty +\def\tikz@call@id@hook{\ifx\tikz@id@hook\pgfutil@empty\else\tikz@id@hook\pgfuseid{\tikz@id@name}\fi}% + + +% RDF stuff +\let\tikz@clear@rdf@options\relax +\let\tikz@do@rdf@post@options\relax +\let\tikz@do@rdf@pre@options\relax + + +% +% Setting keys +% + +\pgfkeys{/tikz/style/.style={#1}}% + +\pgfkeys{/tikz/.unknown/.code=% + % Is it a pgf key? + \let\tikz@key\pgfkeyscurrentname% + \pgfkeys{/pgf/\tikz@key/.try={#1}}% + \ifpgfkeyssuccess% + \else% + \expandafter\pgfutil@in@\expandafter!\expandafter{\tikz@key}% + \ifpgfutil@in@% + % this is a color! + \expandafter\tikz@addoption\expandafter{\expandafter\tikz@compat@color@set\expandafter{\tikz@key}}% + \edef\tikz@textcolor{\tikz@key}% + \else% + \pgfutil@doifcolorelse{\tikz@key} + {% + \expandafter\tikz@addoption\expandafter{\expandafter\tikz@compat@color@set\expandafter{\tikz@key}}% + \edef\tikz@textcolor{\tikz@key}% + }% + {% + % Ok, second chance: This might be an arrow specification: + \expandafter\pgfutil@in@\expandafter-\expandafter{\tikz@key}% + \ifpgfutil@in@% + % Ah, an arrow spec! + \expandafter\tikz@processarrows\expandafter{\tikz@key}% + \else% + % Ok, third chance: A shape! + \expandafter\ifx\csname pgf@sh@s@\tikz@key\endcsname\relax% + \pgfkeys{/errors/unknown key/.expand + once=\expandafter{\expandafter/\expandafter t\expandafter i\expandafter k\expandafter z\expandafter/\tikz@key}{#1}}% + \else% + \edef\tikz@shape{\tikz@key}% + \fi% + \fi% + }% + \fi% + \fi% +}% +\def\tikz@compat@color@set#1{% + \pgfutil@color{#1}\pgfutil@colorlet{pgffillcolor}{#1}% + \expandafter\let\expandafter\pgf@temp\csname\string\color@pgffillcolor\endcsname% + % for arrow tips: + \global\let\pgf@strokecolor@global=\pgf@temp + \global\let\pgf@fillcolor@global=\pgf@temp +}% + +\def\tikz@startup@env{% + \ifnum\the\catcode`\;=\active\relax\expandafter\let\expandafter\tikz@origsemi\expandafter=\tikz@activesemicolon\fi% + \ifnum\the\catcode`\:=\active\relax\expandafter\let\expandafter\tikz@origcolon\expandafter=\tikz@activecolon\fi% + \ifnum\the\catcode`\|=\active\relax\expandafter\let\expandafter\tikz@origbar\expandafter=\tikz@activebar\fi% + \tikz@deactivatthings% + \iftikz@handle@active@code% + \tikz@switchoff@shorthands% + \fi% +}% + +% +% Main TikZ Environment +% +\newif\iftikz@inside@picture +\tikz@inside@picturefalse +\def\tikz@check@inside@picture{% + \iftikz@inside@picture% + \pgfwarning{Nesting tikzpictures is NOT supported}% + \fi% + \tikz@inside@picturetrue% +} + +\def\tikzpicture{% + \begingroup% + \tikz@startup@env% + \tikz@collect@scope@anims\tikz@picture}% +\def\tikz@picture[#1]{% + %\tikz@check@inside@picture% + \pgfpicture% + \let\tikz@atbegin@picture=\pgfutil@empty% + \let\tikz@atend@picture=\pgfutil@empty% + \let\tikz@transform=\relax% + \def\tikz@time{.5}% + \tikz@installcommands% + \scope[every picture,#1]% + \iftikz@handle@active@code% + \tikz@switchoff@shorthands% + \fi% + \expandafter\tikz@atbegin@picture% + \tikz@lib@scope@check% +}% +\def\endtikzpicture{% + \tikz@atend@picture% + \global\let\pgf@shift@baseline@smuggle=\pgf@baseline% + \global\let\pgf@trimleft@final@smuggle=\pgf@trimleft% + \global\let\pgf@trimright@final@smuggle=\pgf@trimright% + \global\let\pgf@remember@smuggle=\ifpgfrememberpicturepositiononpage% + \pgf@remember@layerlist@globally + \endscope% + \let\pgf@baseline=\pgf@shift@baseline@smuggle% + \let\pgf@trimleft=\pgf@trimleft@final@smuggle% + \let\pgf@trimright=\pgf@trimright@final@smuggle% + \let\ifpgfrememberpicturepositiononpage=\pgf@remember@smuggle% + \pgf@restore@layerlist@from@global + \endpgfpicture\endgroup}% + + +% Inlined picture +% +% #1 - some code to be put in a tikzpicture environment. +% +% If the command is not followed by braces, everything up to the next +% semicolon is used as argument. +% +% Example: +% +% The rectangle \tikz{\draw (0,0) rectangle (1em,1ex)} has width 1em and +% height 1ex. + + +\def\tikz{% + \begingroup% + \tikz@startup@env% + \tikz@collect@scope@anims\tikz@opt}% +\def\tikz@opt[#1]{\tikzpicture[#1]\pgfutil@ifnextchar\bgroup{\tikz@}{\tikz@@single}}% +\def\tikz@{\bgroup\tikz@auto@end@pathtrue\aftergroup\endtikzpicture\aftergroup\endgroup\let\pgf@temp=}% +\def\tikz@@single#1{% + \expandafter\ifx\csname tikz@protected@command\string#1\endcsname\relax% + \expandafter\tikz@@% + \else% + \begingroup\def\tikz@path@do@at@end{\endgroup\endtikzpicture\endgroup}% + \fi% + #1% +}% + +\expandafter\let\csname tikz@protected@command\string\draw\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\pattern\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\fill\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\filldraw\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\shade\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\shadedraw\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\clip\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\graph\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\useasboundingbox\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\node\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\coordinate\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\matrix\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\datavisualization\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\path\endcsname\pgfutil@empty% +\expandafter\let\csname tikz@protected@command\string\pic\endcsname\pgfutil@empty% + +% Comment by TT: I hope I fixed the \tikz \foreach problem. The new +% version will take a conservative approach and will only do fancy +% stuff when the next keyword after \tikz is one of the following: +% \draw, \fill, \filldraw, \graph, \matrix, +\def\tikz@@{% + \let\tikz@next=\tikz@collectnormalsemicolon% + \ifnum\the\catcode`\;=\active\relax% + \let\tikz@next=\tikz@collectactivesemicolon% + \fi% + \tikz@next}% +\def\tikz@collectnormalsemicolon#1;{#1;\endtikzpicture\endgroup} +{ + \catcode`\;=\active + \gdef\tikz@collectactivesemicolon#1;{#1;\endtikzpicture\endgroup} +}% +% End old code + +% Invokes '#1' if the command is invoked within a tikzpicture and +% '#2' if not. +\def\tikzifinpicture#1#2{% + \pgfutil@ifundefined{filldraw}{#2}{#1}% TT: This is a wrong + % test! Who uses this?... +}% + + +\def\tikz@collect@scope@anims#1{% + \pgfutil@ifnextchar[#1{#1[]}%] +}% + +% +% Environment for scoping graphic state settings +% +\def\tikz@scope@env{% + \pgfscope% + \begingroup% + \let\tikz@atbegin@scope=\pgfutil@empty% + \let\tikz@atend@scope=\pgfutil@empty% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@mode=\pgfutil@empty% + \let\tikz@id@name=\pgfutil@empty% + \tikz@transparency@groupfalse% + \tikzset{every scope/.try}% + \tikz@collect@scope@anims\tikz@scope@opt% +}% +\def\tikz@scope@opt[#1]{% + \tikzset{#1}% + \tikz@options% + \tikz@do@rdf@pre@options% + \iftikz@transparency@group\expandafter\pgftransparencygroup\expandafter[\tikz@transparency@group@options]\tikz@blend@group\fi% + \tikz@is@nodefalse% + \tikz@call@id@hook% + \pgfidscope% + \tikz@do@rdf@post@options% + \begingroup% + \let\tikz@id@name\pgfutil@empty% + \expandafter\tikz@atbegin@scope% + \expandafter\pgfclearid% + \tikz@lib@scope@check% +}% +\def\endtikz@scope@env{% + \tikz@atend@scope% + \endgroup% + \endpgfidscope% + \iftikz@transparency@group\endpgftransparencygroup\fi% + \endgroup% + \endpgfscope% + \tikz@lib@scope@check% +}% + + +\def\tikz@scoped{\tikz@collect@scope@anims\tikz@scoped@opt}% +\def\tikz@scoped@opt[#1]{\scope[#1]\pgfutil@ifnextchar\bgroup{\tikz@scoped@}{\tikz@scoped@@single}}% +\def\tikz@scoped@{\bgroup\tikz@auto@end@pathtrue\aftergroup\endscope\let\pgf@temp=}% +\def\tikz@scoped@@single#1{% + \expandafter\ifx\csname tikz@scoped@protected@command\string#1\endcsname\relax% + \expandafter\tikz@scoped@@% + \else% + \begingroup\def\tikz@scoped@path@do@at@end{\endgroup\endscope}% + \fi% + #1% +}% +\def\tikz@scoped@@{% + \let\tikz@scoped@next=\tikz@scoped@collectnormalsemicolon% + \ifnum\the\catcode`\;=\active\relax% + \let\tikz@scoped@next=\tikz@scoped@collectactivesemicolon% + \fi% + \tikz@scoped@next}% +\def\tikz@scoped@collectnormalsemicolon#1;{#1;\endscope} +{ + \catcode`\;=\active + \gdef\tikz@scoped@collectactivesemicolon#1;{#1;\endscope} +}% + + +% Install a shortcut command which is only valid inside of a +% tikzpicture. +% +% It works in the same way as the '\path' shortcut does: it introduces +% a \let#1=#2 at the beginning of tikzpicture. +% +% #1: shortcut command inside of tikzpicture +% #2: real command name +\def\tikzaddtikzonlycommandshortcutlet#1#2{% + \expandafter\def\expandafter\tikz@installcommands\expandafter{\tikz@installcommands + \let#1=#2% + }% +}% + +% Has the same effect as \tikzaddtikzonlycommandshortcutlet but uses +% \def#1{#2} instead of \let. +\def\tikzaddtikzonlycommandshortcutdef#1#2{% + \expandafter\def\expandafter\tikz@installcommands\expandafter{\tikz@installcommands + \def#1{#2}% + }% +}% + +% +% Install the abbreviated commands +% +\def\tikz@installcommands{% + \let\tikz@origscope=\scope% + \let\tikz@origscoped=\scoped% + \let\tikz@origendscope=\endscope% + \let\tikz@origstartscope=\startscope% + \let\tikz@origstopscope=\stopscope% + \let\tikz@origpath=\path% + \let\tikz@origagainpath=\againpath% + \let\tikz@origdraw=\draw% + \let\tikz@origpattern=\pattern% + \let\tikz@origfill=\fill% + \let\tikz@origfilldraw=\filldraw% + \let\tikz@origshade=\shade% + \let\tikz@origshadedraw=\shadedraw% + \let\tikz@origclip=\clip% + \let\tikz@origuseasboundingbox=\useasboundingbox% + \let\tikz@orignode=\node% + \let\tikz@origpic=\pic% + \let\tikz@origcoordinate=\coordinate% + \let\tikz@origmatrix=\matrix% + \let\tikz@origcalendar=\calendar% + \let\tikz@origdv=\datavisualization% + \let\tikz@origgraph=\graph% + % + \let\scope=\tikz@scope@env% + \let\scoped=\tikz@scoped% + \let\endscope=\endtikz@scope@env% + \let\startscope=\scope% + \let\stopscope=\endscope% + \let\path=\tikz@command@path% + \let\againpath=\tikz@command@againpath% + % + \def\draw{\path[draw]}% + \def\pattern{\path[pattern]}% + \def\fill{\path[fill]}% + \def\filldraw{\path[fill,draw]}% + \def\shade{\path[shade]}% + \def\shadedraw{\path[shade,draw]}% + \def\clip{\path[clip]}% + \def\graph{\path graph}% + \def\useasboundingbox{\path[use as bounding box]}% + \def\node{\tikz@path@overlay{node}}% + \def\pic{\tikz@path@overlay{pic}}% + \def\coordinate{\tikz@path@overlay{coordinate}}% + \def\matrix{\tikz@path@overlay{node[matrix]}}% + \def\calendar{\tikz@lib@cal@calendar}% + \def\datavisualization{\tikz@lib@datavisualization}% +}% +\ifx\tikz@lib@cal@calendar\@undefined +\def\tikz@lib@cal@calendar{\tikzerror{You need to say \string\usetikzlibrary{calendar} to use the \string\calendar{} command}}% +\fi +\ifx\tikz@lib@datavisualization\@undefined +\def\tikz@lib@datavisualization{\tikzerror{You need to say \string\usetikzlibrary{datavisualization} to use the \string\datavisualization{} command}}% +\fi + +\def\tikz@path@overlay#1{% + \let\tikz@signal@path=\tikz@signal@path% for detection at begin of matrix cell + \pgfutil@ifnextchar<{\tikz@path@overlayed{#1}}{\path #1}}% +\def\tikz@path@overlayed#1<#2>{\path<#2> #1}% + +\def\tikz@uninstallcommands{% + \let\scope=\tikz@origscope% + \let\scoped=\tikz@origscoped% + \let\endscope=\tikz@origendscope% + \let\startscope=\tikz@origstartscope% + \let\stopscope=\tikz@origstopscope% + \let\path=\tikz@origpath% + \let\againpath=\tikz@origagainpath% + \let\draw=\tikz@origdraw% + \let\pattern=\tikz@origpattern% + \let\fill=\tikz@origfill% + \let\filldraw=\tikz@origfilldraw% + \let\shade=\tikz@origshade% + \let\shadedraw=\tikz@origshadedraw% + \let\clip=\tikz@origclip% + \let\useasboundingbox=\tikz@origuseasboundingbox% + \let\node=\tikz@orignode% + \let\pic=\tikz@origpic% + \let\coordinate=\tikz@origcoordinate% + \let\matrix=\tikz@origmatrix% + \let\calendar=\tikz@origcalendar% + \let\datavisualization=\tikz@origdv% + \let\graph=\tikz@origgraph% +}% + + +{% + \catcode`\;=12 + \gdef\tikz@nonactivesemicolon{;}% + \catcode`\:=12 + \gdef\tikz@nonactivecolon{:}% + \catcode`\|=12 + \gdef\tikz@nonactivebar{|}% + \catcode`\!=12 + \gdef\tikz@nonactiveexlmark{!}% + \catcode`\;=\active + \catcode`\:=\active + \catcode`\|=\active + \catcode`\"=\active + \catcode`\!=\active + \gdef\tikz@activesemicolon{;}% + \gdef\tikz@activecolon{:}% + \gdef\tikz@activebar{|}% + \gdef\tikz@activequotes{"}% + \global\let\tikz@active@quotes@token="% + \gdef\tikz@activeexlmark{!}% + \gdef\tikz@deactivatthings{% + \def;{\tikz@nonactivesemicolon}% + \def:{\tikz@nonactivecolon}% + \def|{\tikz@nonactivebar}% + \def!{\tikz@nonactiveexlmark}% + }% +}% + +\let\tikz@orig@shorthands\pgfutil@empty +\def\tikz@switchoff@shorthands{% + \ifx\tikz@orig@shorthands\pgfutil@empty% + \edef\tikz@orig@shorthands{% + \catcode\noexpand`\noexpand\;\the\catcode`\;\relax% + \catcode\noexpand`\noexpand\:\the\catcode`\:\relax% + \catcode\noexpand`\noexpand\|\the\catcode`\|\relax% + \catcode\noexpand`\noexpand\!\the\catcode`\!\relax% + \catcode\noexpand`\noexpand\,\the\catcode`\,\relax% + \catcode\noexpand`\noexpand\<\the\catcode`\<\relax% + \catcode\noexpand`\noexpand\>\the\catcode`\>\relax% + \catcode\noexpand`\noexpand\"\the\catcode`\"\relax% + \catcode\noexpand`\noexpand\'\the\catcode`\'\relax% + \catcode\noexpand`\noexpand\-\the\catcode`\-\relax% + \catcode\noexpand`\noexpand\=\the\catcode`\=\relax% + \catcode\noexpand`\noexpand\.\the\catcode`\.\relax% + \catcode\noexpand`\noexpand\$\the\catcode`\$\relax% + }% + \catcode`\;12\relax% + \catcode`\:12\relax% + \catcode`\|12\relax% + \catcode`\!12\relax% + \catcode`\,12\relax% + \catcode`\<12\relax% + \catcode`\>12\relax% + \catcode`\"12\relax% + \catcode`\'12\relax% + \catcode`\-12\relax% + \catcode`\=12\relax% + \catcode`\.12\relax% + \catcode`\$3\relax% + \fi% +}% + + + +% Constructs a path and draws/fills them according to the current +% settings. + +\def\tikz@command@path{% + \let\tikz@signal@path=\tikz@signal@path% for detection at begin of matrix cell + \pgfutil@ifnextchar[{\tikz@check@earg}%] + {\pgfutil@ifnextchar<{\tikz@doopt}{\tikz@@command@path}}}% +\pgfutil@protected\def\tikz@signal@path{\tikz@signal@path}% +\def\tikz@check@earg[#1]{% + \pgfutil@ifnextchar<{\tikz@swap@args[#1]}{\tikz@@command@path[#1]}} +\def\tikz@swap@args[#1]<#2>{\tikz@command@path<#2>[#1]}% + +\def\tikz@doopt{% + \let\tikz@next=\tikz@eargnormalsemicolon% + \ifnum\the\catcode`\;=\active\relax% + \let\tikz@next=\tikz@eargactivesemicolon% + \fi% + \tikz@next}% +\long\def\tikz@eargnormalsemicolon<#1>#2;{\alt<#1>{\tikz@@command@path#2;}{\tikz@path@do@at@end}}% +{ + \catcode`\;=\active + \long\global\def\tikz@eargactivesemicolon<#1>#2;{\alt<#1>{\tikz@@command@path#2;}{\tikz@path@do@at@end}}% +} + +\def\tikz@@command@path{% + \edef\tikzscope@linewidth{\the\pgflinewidth}% + \begingroup% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \let\tikz@path@do@at@end=\tikz@lib@scope@check% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@mode=\pgfutil@empty% + \let\tikz@moveto@waiting=\relax% + \let\tikz@timer=\relax% + \let\tikz@tangent=\relax% + \let\tikz@collected@onpath=\pgfutil@empty% + \let\tikz@preactions=\pgfutil@empty% + \let\tikz@postactions=\pgfutil@empty% + \tikz@snakedfalse% + \tikz@decoratepathfalse% + \tikz@node@is@a@labelfalse% + \tikz@resetexpandcount + \pgf@path@lastx=0pt% + \pgf@path@lasty=0pt% + \tikz@lastx=0pt% + \tikz@lasty=0pt% + \tikz@lastxsaved=0pt% + \tikz@lastysaved=0pt% + \tikzset{every path/.try}% + \tikz@scan@next@command% +}% +\def\tikz@scan@next@command{% + \ifx\tikz@collected@onpath\pgfutil@empty% + \else% + \tikz@invoke@collected@onpath% + \fi% + \afterassignment\tikz@handle\let\pgf@let@token=% +}% +\newcount\tikz@expandcount +\def\tikz@resetexpandcount{\tikz@expandcount=100\relax} +\let\tikz@collected@onpath=\pgfutil@empty% + +\edef\tikz@frozen@relax@token{\ifnum0=0\fi} + +% Central dispatcher for commands +\def\tikz@handle{% + \pgfutil@switch\pgfutil@ifx\pgf@let@token{% + {(}{\let\pgfutil@next\tikz@movetoabs}%) + {+}{\let\pgfutil@next\tikz@movetorel}% + {-}{\let\pgfutil@next\tikz@lineto}% + {.}{\let\pgfutil@next\tikz@dot}% + {r}{\let\pgfutil@next\tikz@rect}% + {n}{\let\pgfutil@next\tikz@fig}% + {[}{\let\pgfutil@next\tikz@parse@options}%] + {c}{\let\pgfutil@next\tikz@cchar}% + {\bgroup}{\let\pgfutil@next\tikz@beginscope}% + {\egroup}{\let\pgfutil@next\tikz@endscope}% + {;}{\let\pgfutil@next\tikz@finish}% + {a}{\let\pgfutil@next\tikz@a@char}% + {e}{\let\pgfutil@next\tikz@e@char}% + {g}{\let\pgfutil@next\tikz@g@char}% + {s}{\let\pgfutil@next\tikz@schar}% + {|}{\let\pgfutil@next\tikz@vh@lineto}% + {p}{\pgfsetmovetofirstplotpoint\let\pgfutil@next\tikz@pchar}% + {t}{\let\pgfutil@next\tikz@to}% + {\pgfextra}{\let\pgfutil@next\tikz@extra}% + {\foreach}{\let\pgfutil@next\tikz@foreach}% + {f}{\let\pgfutil@next\tikz@fchar}% + {\pgf@stop}{\let\pgfutil@next\relax}% + {\par}{\let\pgfutil@next\tikz@scan@next@command}% + {d}{\let\pgfutil@next\tikz@decoration}% + {l}{\let\pgfutil@next\tikz@l@char}% + {:}{\let\pgfutil@next\tikz@colon@char}% + {\relax}{\relax\let\pgfutil@next\tikz@scan@next@command}% + }{\tikz@resetexpandcount\pgfutil@next}{\tikz@expand}% +}% + +\def\tikz@l@char{% + \pgfutil@ifnextchar e{\tikz@let@command}{% + \pgfutil@ifnextchar i{\tikz@lsystem}{% + \pgfutil@ifnextchar-{\tikz@@lsystem}{\tikz@expand}% + }% + }% +}% + +\def\tikz@lsystem{% + \tikzerror{You need to say \string\usetikzlibrary{lindenmayersystems} to draw Lindenmayer systems} +}% + +\def\tikz@@lsystem{% + \tikzerror{You need to say \string\usetikzlibrary{lindenmayersystems} to draw L-systems} +}% + +\def\tikz@pchar{\pgfutil@ifnextchar l{\tikz@plot}{\pgfutil@ifnextchar i{\tikz@subpicture}{\tikz@parabola}}}% +\def\tikz@cchar{% + \pgfutil@ifnextchar i{\tikz@circle}% + {\pgfutil@ifnextchar h{\tikz@children}{\tikz@cochar}}}% +\def\tikz@cochar o{% + \pgfutil@ifnextchar o{\tikz@coordinate}{\tikz@cosine}}% +\def\tikz@e@char{% + \pgfutil@ifnextchar l{\tikz@ellipse}{\tikz@@e@char}}% +\def\tikz@a@char{% + \pgfutil@ifnextchar r{\tikz@arcA}{\tikzerror{Arc expected}}}% +\def\tikz@@e@char dge{% + \pgfutil@ifnextchar f{\tikz@edgetoparent}{\tikz@edge@plain}}% + +\def\tikz@schar{\pgfutil@ifnextchar i{\tikz@sine}{\tikz@svg@path}}% + +\def\tikz@g@char r{\pgfutil@ifnextchar i{\tikz@grid}{\tikz@graph}}% + +% svg syntax +% svg[options] {...} + +\def\tikz@svg@path{% + \tikzerror{You need to say \string\usetikzlibrary{svg.path} to use the svg path command} +}% + + +\def\tikz@finish{% + % Rendering pipeline + % + % Step 1: The path background box + % + \box\tikz@figbox@bg% + % + % Step 2: Decorate path + % + \iftikz@decoratepath% + \tikz@lib@dec@decorate@path% + \fi% + % + % Step 3: Preactions + % + \pgfsyssoftpath@getcurrentpath\tikz@actions@path% + \edef\tikz@restorepathsize{% + \global\pgf@pathmaxx=\the\pgf@pathmaxx% + \global\pgf@pathmaxy=\the\pgf@pathmaxy% + \global\pgf@pathminx=\the\pgf@pathminx% + \global\pgf@pathminy=\the\pgf@pathminy% + }% + \tikz@preactions% + % + % Step 4: Reset modes + % + \let\tikz@path@picture=\pgfutil@empty% + \tikz@mode@fillfalse% + \tikz@mode@drawfalse% + \tikz@mode@doublefalse% + \tikz@mode@clipfalse% + \tikz@mode@boundaryfalse% + \tikz@mode@fade@pathfalse% + \tikz@mode@fade@scopefalse% + \edef\tikz@pathextend{% + {\noexpand\pgfqpoint{\the\pgf@pathminx}{\the\pgf@pathminy}}% + {\noexpand\pgfqpoint{\the\pgf@pathmaxx}{\the\pgf@pathmaxy}}% + }% + \tikz@mode% installs the mode settings + % Path fading counts as an option: + \iftikz@mode@fade@path% + \tikz@addoption{% + \iftikz@fade@adjust% + \iftikz@mode@draw% + \pgfsetfadingforcurrentpathstroked{\tikz@path@fading}{\tikz@do@fade@transform}% + \else% + \pgfsetfadingforcurrentpath{\tikz@path@fading}{\tikz@do@fade@transform}% + \fi% + \else% + \pgfsetfading{\tikz@path@fading}{\tikz@do@fade@transform}% + \fi% + \tikz@mode@fade@pathfalse% no more fading... + }% + \fi% + % + % Step 5: Install scope fading + % + \iftikz@mode@fade@scope% + \iftikz@fade@adjust% + \iftikz@mode@draw% + \pgfsetfadingforcurrentpathstroked{\tikz@scope@fading}{\tikz@do@fade@transform}% + \else% + \pgfsetfadingforcurrentpath{\tikz@scope@fading}{\tikz@do@fade@transform}% + \fi% + \else% + \pgfsetfading{\tikz@scope@fading}{\tikz@do@fade@transform}% + \fi% + \tikz@mode@fade@scopefalse% + \fi% + % + % Step 5': Setup options + % + \ifx\tikz@options\pgfutil@empty% + \else% + \pgfsys@beginscope% + \let\pgfscope@stroke@color=\pgf@strokecolor@global% + \let\pgfscope@fill@color=\pgf@fillcolor@global% + \begingroup% + \tikz@options% + \fi% + \tikz@do@rdf@pre@options% + % + % Step 5'': Setup animations + % + \tikz@is@nodefalse% + \tikz@call@id@hook% + \iftikz@mode@clip\else% + \pgfidscope% + \tikz@do@rdf@post@options% + \begingroup% + \fi% open an animation scope here, unless clipping is done + % + % Step 6: Do a fill if shade or a path picture follows. + % + \iftikz@mode@fill% + \iftikz@mode@shade% + \pgfsyssoftpath@getcurrentpath\tikz@temppath + \pgfprocessround{\tikz@temppath}{\tikz@temppath}% change the path + \pgfsyssoftpath@setcurrentpath\tikz@temppath% + \pgfsyssoftpath@invokecurrentpath% + \pgfpushtype% + \pgfusetype{.path fill}% + \pgfsys@fill% + \pgfpoptype% + \tikz@mode@fillfalse% no more filling... + \else% + \ifx\tikz@path@picture\pgfutil@empty% + \else% + \pgfsyssoftpath@getcurrentpath\tikz@temppath + \pgfprocessround{\tikz@temppath}{\tikz@temppath}% change the path + \pgfsyssoftpath@setcurrentpath\tikz@temppath% + \pgfsyssoftpath@invokecurrentpath% + \pgfpushtype% + \pgfusetype{.path fill}% + \pgfsys@fill% + \pgfpoptype% + \tikz@mode@fillfalse% no more filling... + \fi% + \fi% + \fi% + % + % Step 7: Do a shade if necessary. + % + \iftikz@mode@shade% + \pgfsyssoftpath@getcurrentpath\tikz@temppath + \pgfprocessround{\tikz@temppath}{\tikz@temppath}% change the path + \pgfsyssoftpath@setcurrentpath\tikz@temppath% + \pgfpushtype% + \pgfusetype{.path shade}% + \pgfshadepath{\tikz@shading}{\tikz@shade@angle}% + \pgfpoptype% + \tikz@mode@shadefalse% no more shading... + \fi% + % + % Step 8: Do a path picture if necessary. + % + \ifx\tikz@path@picture\pgfutil@empty% + \else% + \begingroup% + \pgfusetype{.path picture}% + \pgfidscope% + \pgfsys@beginscope% + \let\tikz@id@name\pgfutil@empty% + \pgfclearid% + \pgfsyssoftpath@getcurrentpath\tikz@temppath + \pgfprocessround{\tikz@temppath}{\tikz@temppath}% change the path + \pgfsyssoftpath@setcurrentpath\tikz@temppath% + \pgfsyssoftpath@invokecurrentpath% + \pgfsys@clipnext% + \pgfsys@discardpath% + \pgf@relevantforpicturesizefalse% + \expandafter\def\csname pgf@sh@ns@path picture bounding box\endcsname{rectangle} + \expandafter\edef\csname pgf@sh@np@path picture bounding box\endcsname{% + \def\noexpand\southwest{\noexpand\pgfqpoint{\the\pgf@pathminx}{\the\pgf@pathminy}}% + \def\noexpand\northeast{\noexpand\pgfqpoint{\the\pgf@pathmaxx}{\the\pgf@pathmaxy}}% + } + \expandafter\def\csname pgf@sh@nt@path picture bounding box\endcsname{{1}{0}{0}{1}{0pt}{0pt}} + \expandafter\def\csname pgf@sh@pi@path picture bounding box\endcsname{\pgfpictureid} + \pgfinterruptpath% + \tikz@path@picture% + \endpgfinterruptpath% + \pgfsys@endscope% + \endpgfidscope% + \endgroup% + \let\tikz@path@picture=\pgfutil@empty% + \fi% + % + % Step 9: Double stroke, if necessary + % + \iftikz@mode@draw% + \iftikz@mode@double% + % Change line width + \begingroup% + \pgfsys@beginscope% + \tikz@double@setup% + \fi% + \fi% + % + % Step 10: Do stroke/fill/clip as needed + % + \pgfpushtype% + \edef\tikz@temp{\noexpand\pgfusepath{% + \iftikz@mode@fill fill,\fi% + \iftikz@mode@draw draw,\fi% + \iftikz@mode@clip clip\fi% + }}% + \pgfusetype{.path}% + \tikz@temp% + \pgfpoptype% + \tikz@mode@fillfalse% no more filling + % + % Step 11: Double stroke, if necessary + % + \iftikz@mode@draw% + \iftikz@mode@double% + \pgfsys@endscope% + \endgroup% + \fi% + \fi% + \tikz@mode@drawfalse% no more stroking + % + % Step 12: Postactions + % + \tikz@postactions% + % + % Step 13: Add labels and nodes + % + \box\tikz@figbox% + % + % Step 14: Close animations + % + \iftikz@mode@clip\else\endgroup\endpgfidscope\fi% + % + % Step 14: Close option brace + % + \ifx\tikz@options\pgfutil@empty% + \else% + \endgroup% + \global\let\pgf@strokecolor@global=\pgfscope@stroke@color% + \global\let\pgf@fillcolor@global=\pgfscope@fill@color% + \pgfsys@endscope% + \iftikz@mode@clip% + \tikzerror{Extra options not allowed for clipping path command.}% + \fi% + \fi% + \iftikz@mode@clip% + \aftergroup\pgf@relevantforpicturesizefalse% + \fi% + \iftikz@mode@boundary% + \aftergroup\pgf@relevantforpicturesizefalse% + \fi% + \endgroup% + \global\pgflinewidth=\tikzscope@linewidth% + \tikz@path@do@at@end% +}% +\let\tikz@lib@scope@check\pgfutil@empty% this is a hook for the scopes library +\def\tikz@path@do@at@end{\tikz@lib@scope@check}% +\def\tikz@@pathtext{@path}% + +\def\pgf@outer@auto@adjust@hook{% + {% + \tikz@mode@drawfalse% + \tikz@mode% + \expandafter% + }% + \iftikz@mode@draw\else% + \pgfkeyslet{/pgf/outer xsep}\pgf@zero@text + \pgfkeyslet{/pgf/outer ysep}\pgf@zero@text + \fi% +}% + +% Extra actions + +\def\tikz@extra@preaction#1{% + {% + \pgfsys@beginscope% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \path[#1];% do extra path + \pgfsyssoftpath@setcurrentpath\tikz@actions@path% restore + \tikz@restorepathsize% + \pgfsys@endscope% + }% +}% + +\def\tikz@extra@postaction#1{% + {% + \pgfsys@beginscope% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@restorepathsize% + \path[#1]\pgfextra{\pgfsyssoftpath@setcurrentpath\tikz@actions@path};% do extra path + \pgf@resetpathsizes% + \pgfsys@endscope% + }% +}% + + + +\def\tikz@skip#1{\tikz@scan@next@command#1}% +\def\tikz@expand{% + \advance\tikz@expandcount by -1 + \ifnum\tikz@expandcount<0\relax% + \expandafter\pgfutil@firstoftwo + \else + \expandafter\pgfutil@secondoftwo + \fi + {% + \tikzerror{Giving up on this path. Did you forget a semicolon?}% + % since the last token caused an error we should reinsert it and therefore save it + \global\let\tikz@expand@last@token=\pgf@let@token + \tikz@finish% + % + % To be combatible with `scopes` lib, which uses a redefined + % \tikz@lib@scope@check to check the next token, the reinsertion is done + % here, not at the end of (every) \tikz@finish. + % + \expandafter\let\expandafter\tikz@expand@last@token@\csname tikz@expand@last@token\endcsname + \global\let\tikz@expand@last@token=\relax + \tikz@expand@last@token@ + }{% + \tikz@@expand + }% +} + +\def\tikz@@expand{% + \expandafter\tikz@scan@next@command\pgf@let@token}% + + + +% Syntax for scopes: +% {scoped path commands} + +\newif\iftikz@auto@end@path + +\def\tikz@beginscope{\begingroup\tikz@auto@end@pathfalse\tikz@scan@next@command}% +\def\tikz@endscope{% + \iftikz@auto@end@path\expandafter\tikz@finish\expandafter\egroup\else\expandafter\tikz@@endscope\fi% +}% +\def\tikz@@endscope{% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \global\let\tikz@tangent@temp\tikz@tangent% + \edef\tikz@marshal{% + \tikz@lastx=\the\tikz@lastx% + \tikz@lasty=\the\tikz@lasty% + \iftikz@current@point@local% + \else% + \tikz@lastxsaved=\the\tikz@lastxsaved% + \tikz@lastysaved=\the\tikz@lastysaved% + \ifx\tikz@moveto@waiting\relax% + \let\tikz@moveto@waiting\relax% + \else% + \def\noexpand\tikz@moveto@waiting{\tikz@moveto@waiting}% + \fi% + \iftikz@shapeborder% + \noexpand\tikz@shapebordertrue% + \def\noexpand\tikz@shapeborder@name{\tikz@shapeborder@name}% + \else% + \noexpand\tikz@shapeborderfalse% + \fi% + \fi% + }% + \expandafter% + \endgroup\tikz@marshal% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \let\tikz@tangent\tikz@tangent@temp% + \tikz@scan@next@command}% + + +% Syntax for pgfextra: +% \pgfextra {normal tex text} +% \pgfextra normal tex text \endpgfextra + +\def\tikz@extra{\pgfutil@ifnextchar\bgroup\tikz@@extra\relax}% +\long\def\tikz@@extra#1{#1\tikz@scan@next@command}% +\let\endpgfextra=\tikz@scan@next@command + +\def\pgfextra{pgfextra}% + + +% Syntax for foreach: +% +% foreach \var in {list} {path text} +% +% or +% +% \foreach \var in {list} {path text} +% +% Example: +% +% \draw (0,0) \foreach \x in {1,2,3} {-- (\x,0) circle (1cm)} -- (5,5); + +\def\tikz@fchar oreach{\tikz@foreach}% + +\def\tikz@foreach{% + \def\pgffor@beginhook{% + \tikz@lastx=\tikz@foreach@save@lastx% + \tikz@lasty=\tikz@foreach@save@lasty% + \tikz@lastxsaved=\tikz@foreach@save@lastxsaved% + \tikz@lastysaved=\tikz@foreach@save@lastysaved% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \expandafter\tikz@scan@next@command\pgfutil@firstofone}% + \def\pgffor@endhook{\pgfextra{% + \xdef\tikz@foreach@save@lastx{\the\tikz@lastx}% + \xdef\tikz@foreach@save@lasty{\the\tikz@lasty}% + \xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}% + \xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \pgfutil@gobble}}% + \def\pgffor@afterhook{% + \tikz@lastx=\tikz@foreach@save@lastx% + \tikz@lasty=\tikz@foreach@save@lasty% + \tikz@lastxsaved=\tikz@foreach@save@lastxsaved% + \tikz@lastysaved=\tikz@foreach@save@lastysaved% + \let\pgffor@beginhook\relax% + \let\pgffor@endhook\relax% + \let\pgffor@afterhook\relax% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \tikz@scan@next@command}% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \xdef\tikz@foreach@save@lastx{\the\tikz@lastx}% + \xdef\tikz@foreach@save@lasty{\the\tikz@lasty}% + \xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}% + \xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}% + \foreach}% + + +% Syntax for againpath: +% \againpath \somepathname + +\def\tikz@command@againpath#1{% + \pgfextra{% + \pgfsyssoftpath@getcurrentpath\tikz@temp% + \expandafter\pgfutil@g@addto@macro\expandafter\tikz@temp\expandafter{#1}% + \pgfsyssoftpath@setcurrentpath\tikz@temp% + }% +}% + + +% animation syntax +% :attribute = {...} + +\def\tikz@colon@char#1=#2{% + \tikz@scan@next@command{[animate={myself:{#1}={#2}}]}% +}% + + + +% +% When this if is set, a just-scanned point is a shape and its border +% position still needs to be determined, depending on subsequent +% commands. +% + +\newif\iftikz@shapeborder + + +% Syntax for moveto: +% +\def\tikz@movetoabs{\tikz@moveto(}% +\def\tikz@movetorel{\tikz@moveto+}% +\def\tikz@moveto{% + \tikz@scan@one@point{\tikz@@moveto}}% +\def\tikz@@moveto#1{% + \tikz@make@last@position{#1}% + \iftikz@shapeborder% + % ok, the moveto will have to wait. flag that we have a moveto in + % waiting: + \edef\tikz@moveto@waiting{\tikz@shapeborder@name}% + \else% + \tikz@@movetosave{\tikz@last@position}% + \let\tikz@moveto@waiting=\relax% + \fi% + \tikz@scan@next@command% +}% + + % Wrapper around \pgfpathmoveto that adds a save +\def\tikz@@movetosave#1{% + {\pgftransformreset + \pgf@process{#1}% + \xdef\tikz@marshal{% + \tikz@lastmovetox=\the\pgf@x\relax% + \tikz@lastmovetoy=\the\pgf@y\relax% + }% + }% + \tikz@marshal + \pgfpathmoveto{#1}% +}% + + +\let\tikz@moveto@waiting=\relax % normally, nothing is waiting... + +\def\tikz@flush@moveto{% + \ifx\tikz@moveto@waiting\relax% + \else% + \tikz@@movetosave{\tikz@last@position}% + \fi% + \let\tikz@moveto@waiting=\relax% +}% + + +\def\tikz@flush@moveto@toward#1#2#3{% + % #1 = a point towards which the last moveto should be corrected + % #2 = a dimension to which the corrected x-coordinate should be stored + % #3 = a dimension for the corrected y-coordinate + \ifx\tikz@moveto@waiting\relax% + % do nothing + \else% + \pgf@process{\pgfpointshapeborder{\tikz@moveto@waiting}{#1}}% + #2=\pgf@x% + #3=\pgf@y% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \tikz@@movetosave{\pgfqpoint{\pgf@x}{\pgf@y}}% + \fi% + \let\tikz@moveto@waiting=\relax% +}% + + +% +% Collecting labels on the path +% + +\def\tikz@collect@coordinate@onpath#1c{% + \pgfutil@ifnextchar y{\tikz@cycle@expander@add#1}{\tikz@collect@coordinate@onpath@{#1}}}% +\def\tikz@collect@coordinate@onpath@#1oordinate{% + \pgfutil@ifnextchar[{\tikz@@collect@coordinate@opt#1}{\tikz@@collect@coordinate@opt#1[]}}%}% +\def\tikz@@collect@coordinate@opt#1[#2]{% + \pgfutil@ifnextchar({\tikz@@collect@coordinate#1[#2]}{% + \tikz@collect@label@onpath#1node[shape=coordinate,#2]{}}}%}% +\def\tikz@@collect@coordinate#1[#2](#3){% + \tikz@collect@label@onpath#1node[shape=coordinate,#2](#3){}}% + +\newif\iftikz@collect@pic + +\def\tikz@collect@label@onpath#1node{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath node}% + \let\tikz@collect@cont#1% + \tikz@collect@picfalse% + \tikz@collect@label@scan}% + +\def\tikz@collect@pic@onpath#1pic{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath pic}% + \let\tikz@collect@cont#1 + \tikz@collect@pictrue% + \tikz@collect@label@scan}% + +\def\tikz@collect@label@scan{% + \pgfutil@ifnextchar f{\tikz@collect@nodes}{% + \pgfutil@ifnextchar({\tikz@collect@paran}% + {\pgfutil@ifnextchar[{\tikz@collect@options}% + {\pgfutil@ifnextchar:{\tikz@collect@animation}% + {\pgfutil@ifnextchar\bgroup{\tikz@collect@arg}% + {\tikz@collect@cont}}}}}% +}%}}% + +\def\tikz@collect@nodes foreach#1in{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath foreach#1in}% + \pgfutil@ifnextchar\bgroup\tikz@collect@nodes@group\tikz@collect@nodes@one% +}% +\def\tikz@collect@nodes@one#1{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath #1}% + \tikz@collect@label@scan% +}% +\def\tikz@collect@nodes@group#1{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath{#1}}% + \tikz@collect@label@scan% +}% + +\def\tikz@collect@animation#1=#2{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath#1={#2}}% + \tikz@collect@label@scan% +}% +\def\tikz@collect@paran#1){% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath#1)}% + \tikz@collect@label@scan% +}% +\def\tikz@collect@options#1]{% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath#1]}% + \tikz@collect@label@scan% +}% +\def\tikz@collect@arg#1{% + \iftikz@handle@active@nodes% + \iftikz@collect@pic% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath{#1}}% + \else% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath{\scantokens{#1}}}% + \fi% + \else% + \expandafter\def\expandafter\tikz@collected@onpath\expandafter{\tikz@collected@onpath{#1}}% + \fi% + \tikz@collect@cont% +}% + +\def\tikz@invoke@collected@onpath{% + \tikz@node@is@a@labeltrue% + \let\tikz@temp=\tikz@collected@onpath% + \let\tikz@collected@onpath=\pgfutil@empty% + \expandafter\tikz@scan@next@command\tikz@temp\pgf@stop% + \tikz@node@is@a@labelfalse% +}% + + +% +% Macros for the cycle command +% + +\def\tikz@cycle@expander#1{\pgfutil@ifnextchar c{\tikz@cycle@expander@{#1}}{#1}}% +\def\tikz@cycle@expander@#1c{\pgfutil@ifnextchar y{\tikz@cycle@expander@add{#1}}{#1c}}% +\def\tikz@cycle@expander@add#1ycle{#1(current subpath start)--cycle}% + + + + +% Syntax for lineto: +% -- + +\def\tikz@lineto{% + \pgfutil@ifnextchar |% + {\expandafter\tikz@hv@lineto\pgfutil@gobble}% + {\expandafter\pgfutil@ifnextchar\tikz@activebar{\expandafter\tikz@hv@lineto\pgfutil@gobble}% + {\expandafter\tikz@lineto@mid\pgfutil@gobble}}}% +\def\tikz@lineto@mid{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@lineto@mid}% + {% + \pgfutil@ifnextchar c{\tikz@close}{% + \pgfutil@ifnextchar p{\tikz@lineto@plot@or@pic}{\tikz@scan@one@point{\tikz@@lineto}}}}}% +\def\tikz@lineto@plot@or@pic p{% + \pgfutil@ifnextchar i{\tikz@collect@pic@onpath\tikz@lineto@mid p}{% + \pgfsetlinetofirstplotpoint\tikz@plot}% +}% +\def\tikz@@lineto#1{% + % Record the starting point for later labels on the path: + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}} + \iftikz@shapeborder% + % ok, target is a shape. recalculate end + \pgf@process{\pgfpointshapeborder{\tikz@shapeborder@name}{\tikz@last@position}}% + \tikz@make@last@position{\pgfqpoint{\pgf@x}{\pgf@y}}% + \tikz@flush@moveto@toward{\tikz@last@position}\pgf@x\pgf@y% + \tikz@path@lineto{\tikz@last@position}% + \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \tikz@make@last@position{#1}% + \edef\tikz@moveto@waiting{\tikz@shapeborder@name}% + \else% + % target is a reasonable point... + % Record the starting point for later labels on the path: + \tikz@make@last@position{#1}% + \tikz@flush@moveto@toward{\tikz@last@position}\pgf@x\pgf@y% + \tikz@path@lineto{\tikz@last@position}% + \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \fi% + \let\tikz@timer=\tikz@timer@line% + \let\tikz@tangent\tikz@timer@start% + \tikz@scan@next@command% +}% + +% snake or lineto? +\def\tikz@path@lineto#1{% + \iftikz@snaked% + { + \pgfsyssoftpathmovetorelevantfalse% + \pgfpathsnakesto{\tikz@presnake,{\tikz@snake}{\tikz@mainsnakelength}{\noexpand\tikz@snake@install@trans}{},\tikz@postsnake}{#1}% + } + \else% + \pgfpathlineto{#1}% + \fi% +}% + +% snake or lineto? +\def\tikz@path@close#1{% + \iftikz@snaked% + {% + \pgftransformreset% + \pgfpathsnakesto{\tikz@presnake,{\tikz@snake}{\tikz@mainsnakelength}{\noexpand\tikz@snake@install@trans}{},\tikz@postsnake}{#1}% + }% + \fi% + \pgfpathclose% +}% + + +% Syntax for lineto horizontal/vertical: +% -| + +\def\tikz@hv@lineto{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@hv@lineto}{% + \pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@hv@lineto}% + {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@hv@lineto}% + {\tikz@scan@one@point{\tikz@@hv@lineto}}}}}% +\def\tikz@@hv@lineto#1{% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \pgf@yc=\tikz@lasty% + \tikz@make@last@position{#1}% + \edef\tikz@tangent{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\pgf@yc}}% + \tikz@flush@moveto@toward{\pgfqpoint{\tikz@lastx}{\pgf@yc}}\pgf@x\pgf@yc% + \iftikz@shapeborder% + % ok, target is a shape. have to work now: + {% + \pgf@process{\pgfpointshapeborder{\tikz@shapeborder@name}{\pgfqpoint{\tikz@lastx}{\pgf@yc}}}% + \tikz@make@last@position{\pgfqpoint{\pgf@x}{\pgf@y}}% + \tikz@path@lineto{\pgfqpoint{\tikz@lastx}{\pgf@yc}}% + \tikz@path@lineto{\tikz@last@position}% + \xdef\tikz@timer@end@temp{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% move out of group + }% + \let\tikz@timer@end=\tikz@timer@end@temp% + \edef\tikz@moveto@waiting{\tikz@shapeborder@name}% + \else% + \tikz@path@lineto{\pgfqpoint{\tikz@lastx}{\pgf@yc}}% + \tikz@path@lineto{\tikz@last@position}% + \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% move out of group + \fi% + \let\tikz@timer=\tikz@timer@hvline% + \tikz@scan@next@command% +}% + +% Syntax for lineto vertical/horizontal: +% |- + +\def\tikz@vh@lineto-{\tikz@vh@lineto@next}% +\def\tikz@vh@lineto@next{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@vh@lineto@next}{% + \pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@vh@lineto@next}% + {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@vh@lineto@next}% + {\tikz@scan@one@point\tikz@@vh@lineto}}}}% +\def\tikz@@vh@lineto#1{% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \pgf@xc=\tikz@lastx% + \tikz@make@last@position{#1}% + \edef\tikz@tangent{\noexpand\pgfqpoint{\the\pgf@xc}{\the\tikz@lasty}}% + \tikz@flush@moveto@toward{\pgfqpoint{\pgf@xc}{\tikz@lasty}}\pgf@xc\pgf@y% + \iftikz@shapeborder% + % ok, target is a shape. have to work now: + {% + \pgf@process{\pgfpointshapeborder{\tikz@shapeborder@name}{\pgfqpoint{\pgf@xc}{\tikz@lasty}}}% + \tikz@make@last@position{\pgfqpoint{\pgf@x}{\pgf@y}}% + \tikz@path@lineto{\pgfqpoint{\pgf@xc}{\tikz@lasty}}% + \tikz@path@lineto{\tikz@last@position}% + \xdef\tikz@timer@end@temp{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% move out of group + }% + \let\tikz@timer@end=\tikz@timer@end@temp% + \edef\tikz@moveto@waiting{\tikz@shapeborder@name}% + \else% + \tikz@path@lineto{\pgfqpoint{\pgf@xc}{\tikz@lasty}}% + \tikz@path@lineto{\tikz@last@position}% + \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \fi% + \let\tikz@timer=\tikz@timer@vhline% + \tikz@scan@next@command% +}% + +% Syntax for cycle: +% -- cycle +\def\tikz@close c{% + \pgfutil@ifnextchar o{\tikz@collect@coordinate@onpath\tikz@lineto@mid c}% oops, a coordinate + {\tikz@@close c}}% +\def\tikz@@close cycle{% + \tikz@flush@moveto% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}} + \tikz@make@last@position{\expandafter\pgfpoint\pgfsyssoftpath@lastmoveto}% + \tikz@path@close{\expandafter\pgfpoint\pgfsyssoftpath@lastmoveto}% + \def\pgfstrokehook{}% + \edef\tikz@timer@end{%\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \noexpand\pgfqpoint{\the\tikz@lastmovetox}{\the\tikz@lastmovetoy}}% + \let\tikz@timer=\tikz@timer@line% + \let\tikz@tangent\tikz@timer@start% + \tikz@scan@next@command% +}% + + +% Syntax for options: +% [options] +\def\tikz@parse@options#1]{% + \tikzset{#1}% + \tikz@scan@next@command% +}% + +% Syntax for edges: +% edge [options] (coordinate) +% edge [options] node {node text} (coordinate) +% edge :attribute={...} [options] node {node text} (coordinate) +\def\tikz@edge@plain{% + \begingroup% + \ifx\tikz@to@use@whom\pgfutil@undefined\else\tikz@to@use@whom\fi + \let\tikz@to@or@edge@function=\tikz@do@edge% + \let\tikz@@to@local@options\pgfutil@empty% + \let\tikz@collected@onpath=\pgfutil@empty% + \tikz@to@or@edge}% + +% Syntax for to paths: +% to [options] (coordinate) +% to [options] node {node text} (coordinate) +% to :attribute={...} [options] node {node text} (coordinate) +\def\tikz@to o{% + \tikz@to@use@last@coordinate% + \let\tikz@to@or@edge@function=\tikz@do@to% + \let\tikz@@to@local@options\pgfutil@empty% + \let\tikz@collected@onpath=\pgfutil@empty% + \tikz@to@or@edge}% + +\def\tikz@to@or@edge{% + \pgfutil@ifnextchar[{\tikz@to@or@edge@option}{% + \pgfutil@ifnextchar:{\tikz@to@or@edge@animation}{% + \tikz@@to@collect}}%] +}% +\def\tikz@to@or@edge@option[#1]{% + \expandafter\def\expandafter\tikz@@to@local@options\expandafter{\tikz@@to@local@options,#1}% + \tikz@to@or@edge% +}% +\def\tikz@to@or@edge@animation:#1=#2{% + \expandafter\def\expandafter\tikz@@to@local@options\expandafter{\tikz@@to@local@options,% + animate={myself:{#1}={#2}}}% + \tikz@to@or@edge% +}% +\def\tikz@@to@collect{% + \pgfutil@ifnextchar(\tikz@@to@or@edge@coordinate%) + {\pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@@to@collect}% + {\pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@@to@collect}% + {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@@to@collect}% + {\pgfutil@ifnextchar +{\tikz@scan@one@point\tikz@@to@or@edge@math}% + {\tikzerror{(, +, coordinate, pic, or node expected}%) + \tikz@@to@or@edge@coordinate()}}}}}% +}% + +\def\tikz@@to@or@edge@coordinate({% + \pgfutil@ifnextchar${%$ + % Ok, parse directly + \tikz@scan@one@point\tikz@@to@or@edge@math(% + }{% + \pgfutil@ifnextchar[{%] + \tikz@scan@one@point\tikz@@to@or@edge@math(% + }{% + \tikz@@to@or@edge@@coordinate(% + }% + }% +}% +\def\tikz@@to@or@edge@math#1{% + \pgf@process{#1}% + \iftikz@updatecurrent\else + \tikz@updatenextfalse + \fi + \edef\tikztotarget{\the\pgf@x,\the\pgf@y}% + \tikz@to@or@edge@function% +}% + +\def\tikz@@to@or@edge@@coordinate(#1){% + \def\tikztotarget{#1}% + \tikz@to@or@edge@function% +}% + +\def\tikz@do@edge{% + \ifx\tikz@edge@macro\pgfutil@empty% + \setbox\tikz@whichbox=\hbox\bgroup% + \unhbox\tikz@whichbox% + \hbox\bgroup + \bgroup% + \pgfinterruptpath% + \pgfscope% + \let\tikz@transform=\pgfutil@empty% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@tonodes=\tikz@collected@onpath% + \def\tikztonodes{{\pgfextra{\tikz@node@is@a@labeltrue}\tikz@tonodes}}% + \let\tikz@collected@onpath=\pgfutil@empty% + \tikz@options% + \tikz@do@rdf@pre@options% + \pgfidscope% + \tikz@do@rdf@post@options% + \tikz@transform% + \let\tikz@transform=\relax% + % Typeset node: + \let\tikz@after@path\pgfutil@empty% + \tikz@atbegin@to% + \tikz@enable@edge@quotes% + \path[style=every edge]\expandafter[\tikz@@to@local@options](\tikztostart)\tikz@to@path + \pgfextra{\global\let\tikz@after@path@smuggle=\tikz@after@path};% + \tikz@atend@to% + \endpgfidscope% + \endpgfscope% + \endpgfinterruptpath% + \egroup + \egroup% + \egroup% + \global\setbox\tikz@tempbox=\box\tikz@whichbox% + \expandafter\endgroup% + \expandafter\setbox\tikz@whichbox=\box\tikz@tempbox% + \else% + \expandafter\expandafter\expandafter\tikz@edge@macro% + \expandafter\expandafter\expandafter{\expandafter\tikz@@to@local@options\expandafter}\expandafter{\tikz@collected@onpath}% + \endgroup% + \let\tikz@after@path@smuggle=\pgfutil@empty% + \fi% + \expandafter\tikz@scan@next@command\tikz@after@path@smuggle% +}% + +\def\tikz@do@to{% + \let\tikz@tonodes=\tikz@collected@onpath% + \def\tikztonodes{{\pgfextra{\tikz@node@is@a@labeltrue}\tikz@tonodes}}% + \let\tikz@collected@onpath=\pgfutil@empty% + \tikz@scan@next@command% + {% + \pgfextra{\let\tikz@after@path\pgfutil@empty}% + \pgfextra{\tikz@atbegin@to}% + \pgfextra{\tikz@enable@edge@quotes}% + [style=every to]\expandafter[\tikz@@to@local@options]\tikz@to@path% + \pgfextra{\tikz@atend@to}% + \pgf@stop% + \expandafter\tikz@scan@next@command\expandafter% + }\tikz@after@path% + \pgfextra{\tikz@updatenexttrue\tikz@updatecurrenttrue}% +}% + + +\def\tikz@to@use@last@coordinate{% + \iftikz@shapeborder% + \edef\tikztostart{\tikz@shapeborder@name}% + \else% + \edef\tikztostart{\the\tikz@lastx,\the\tikz@lasty}% + \fi% +}% +\def\tikz@to@use@last@fig@name{% + \edef\tikztostart{\tikz@to@last@fig@name}% +}% + + + +% Syntax for graph path command: +% graph [options] {...} +% See the graph library for details + +\def\tikz@graph aph{\tikz@lib@graph@parser}% + +\def\tikz@lib@graph@parser{\pgfutil@ifnextchar[\tikz@graph@error{\tikz@graph@error[]}}%]% +\def\tikz@graph@error[#1]#2{% + \tikzerror{You need to say \string\usetikzlibrary{graphs} in order to use the graph syntax}% + \tikz@lib@graph@parser@done% +}% + +\def\tikz@lib@graph@parser@done{% + \tikz@scan@next@command% +}% + + + + +% Syntax for edge from parent: +% edge from parent [options] +\def\tikz@edgetoparent from parent{\pgfutil@ifnextchar[\tikz@@edgetoparent{\tikz@@edgetoparent[]}}%}% +\def\tikz@@edgetoparent[#1]{% + \let\tikz@edge@to@parent@needed=\pgfutil@empty% + \def\tikz@edgetoparent@options{#1}% + \begingroup% + \let\tikz@collected@onpath=\pgfutil@empty% + \tikz@edgetoparentcollect% +}% +\def\tikz@edgetoparentcollect{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@edgetoparentcollect}% + {% + \expandafter% + \endgroup% + \expandafter\tikz@edgetoparent@rollout\expandafter{\tikz@collected@onpath}% + }% +}% + +\def\tikz@edgetoparent@rollout#1{% + \pgfkeysgetvalue{/tikz/edge from parent macro}\tikz@etop@temp + \expandafter\tikz@scan@next@command\expandafter\tikz@etop@temp\expandafter{\tikz@edgetoparent@options}{#1}% +}% + + +% Syntax for bezier curves +% .. controls(point) and (point) .. (target) +% .. controls(point) .. (target) +% .. (target) % currently not supported + +\def\tikz@dot.{\tikz@@dot}% +\def\tikz@@dot{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@@dot}{% + \pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@@dot}% + {\pgfutil@ifnextchar c{\tikz@curveto@double}{\tikz@curveto@auto}}}% +}% + +\def\tikz@curveto@double co{% + \pgfutil@ifnextchar o{\tikz@collect@coordinate@onpath\tikz@@dot co} + {\tikz@cureveto@@double}}% +\def\tikz@cureveto@@double ntrols#1{% + \tikz@scan@one@point\tikz@curveA#1% +}% +\def\tikz@curveA#1{% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + {% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \tikz@make@last@position{#1}% + \xdef\tikz@curve@first{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + }% + \pgfutil@ifnextchar a + {\tikz@curveBand}% + {\let\tikz@curve@second\tikz@curve@first\tikz@curveCdots}% +}% +\def\tikz@curveBand and{% + \tikz@scan@one@point\tikz@curveB% +}% +\def\tikz@curveB#1{% + \def\tikz@curve@second{#1}% + \tikz@curveCdots} +\def\tikz@curveCdots{% + \afterassignment\tikz@curveCdot\let\pgfutil@next=}% +\def\tikz@curveCdot.{% + \ifx\pgfutil@next.% + \else% + \tikzerror{Dot expected}% + \fi% + \iftikz@updatenext + \tikz@updatecurrenttrue% + \fi + \tikz@curveCcheck% +}% +\def\tikz@curveCcheck{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@curveCcheck}{% + \pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@curveCcheck}% + {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@curveCcheck} + {\tikz@scan@one@point\tikz@curveC}}}% +}% +\def\tikz@curveC#1{% + \tikz@make@last@position{#1}% + \edef\tikz@curve@third{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + {% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \tikz@make@last@position{\tikz@curve@second}% + \xdef\tikz@curve@second{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + }% + % + % Start recalculating things in case start and end are shapes. + % + % First, the start: + \ifx\tikz@moveto@waiting\relax% + \else% + \pgf@process{\pgfpointshapeborder{\tikz@moveto@waiting}{\tikz@curve@first}}% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \tikz@@movetosave{\pgfqpoint{\pgf@x}{\pgf@y}}% + \fi% + \let\tikz@timer@cont@one=\tikz@curve@first% + \let\tikz@timer@cont@two=\tikz@curve@second% + % Second, the end: + \iftikz@shapeborder% + % ok, target is a shape. recalculate third + {% + \pgf@process{\pgfpointshapeborder{\tikz@shapeborder@name}{\tikz@curve@second}}% + \tikz@make@last@position{\pgfqpoint{\pgf@x}{\pgf@y}}% + \edef\tikz@curve@third{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \pgfpathcurveto{\tikz@curve@first}{\tikz@curve@second}{\tikz@curve@third}% + \global\let\tikz@timer@end@temp=\tikz@curve@third% move out of group + }% + \let\tikz@timer@end=\tikz@timer@end@temp% + \edef\tikz@moveto@waiting{\tikz@shapeborder@name}% + \else% + \pgfpathcurveto{\tikz@curve@first}{\tikz@curve@second}{\tikz@curve@third}% + \let\tikz@timer@end=\tikz@curve@third + \let\tikz@moveto@waiting=\relax% + \fi% + \let\tikz@timer=\tikz@timer@curve% + \let\tikz@tangent=\tikz@curve@second% + \tikz@scan@next@command% +}% + + +% Syntax for rectangles: +% rectangle +\def\tikz@rect ectangle{% + \tikz@flush@moveto% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \tikz@@rect}% +\def\tikz@@rect{% + \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@@rect}{% + \pgfutil@ifnextchar p{\tikz@collect@pic@onpath\tikz@@rect}% + {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@@rect}% + { + \pgf@xa=\tikz@lastx\relax% + \pgf@ya=\tikz@lasty\relax% + \tikz@scan@one@point\tikz@rectB}}}}% +\def\tikz@rectB#1{% + \tikz@make@last@position{#1}% + \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \let\tikz@timer=\tikz@timer@line% + \tikz@@movetosave{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \tikz@path@lineto{\pgfqpoint{\pgf@xa}{\tikz@lasty}}% + \tikz@path@lineto{\pgfqpoint{\tikz@lastx}{\tikz@lasty}}% + \tikz@path@lineto{\pgfqpoint{\tikz@lastx}{\pgf@ya}}% + \iftikz@snaked% + \tikz@path@lineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \fi% + \pgfpathclose% + \tikz@@movetosave{\pgfqpoint{\tikz@lastx}{\tikz@lasty}}% + \def\pgfstrokehook{}% + \let\tikz@tangent\relax% + \tikz@scan@next@command% +}% + + + +% Syntax for grids: +% grid +\def\tikz@grid id{% + \tikz@flush@moveto% + \pgf@xa=\tikz@lastx\relax% + \pgf@ya=\tikz@lasty\relax% + \pgfutil@ifnextchar[{\tikz@gridA}{\tikz@gridA[]}}%}% +\def\tikz@gridA[#1]{% + \def\tikz@grid@options{#1}% + \tikz@cycle@expander{\tikz@scan@one@point\tikz@gridB}}% +\def\tikz@gridB#1{% + \tikz@make@last@position{#1}% + \let\tikz@tangent\relax% + {% + \let\tikz@after@path\pgfutil@empty% + \expandafter\tikzset\expandafter{\tikz@grid@options} + \tikz@checkunit{\tikz@grid@x}% + \iftikz@isdimension% + \pgf@process{\pgfpoint{\tikz@grid@x}{0pt}}% + \else% + \pgf@process{\pgfpointxy{\tikz@grid@x}{0}}% + \fi% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \tikz@checkunit{\tikz@grid@y}% + \iftikz@isdimension% + \pgf@process{\pgfpoint{0pt}{\tikz@grid@y}}% + \else% + \pgf@process{\pgfpointxy{0}{\tikz@grid@y}}% + \fi% + \advance\pgf@xb by\pgf@x% + \advance\pgf@yb by\pgf@y% + \pgfpathgrid[stepx=\pgf@xb,stepy=\pgf@yb]% + {\pgfqpoint{\pgf@xa}{\pgf@ya}}{\pgfqpoint{\tikz@lastx}{\tikz@lasty}}% + \expandafter}% + \expandafter\tikz@scan@next@command\tikz@after@path% +}% + + + +% Syntax for plot: +% plot [local options] ... % starts with a moveto +% -- plot [local options] ... % starts with a lineto +\def\tikz@plot lot{% + \tikz@flush@moveto% + \pgfutil@ifnextchar[{\tikz@@plot}{\tikz@@plot[]}}%}% +\def\tikz@@plot[#1]{% + \let\tikz@tangent\tikz@tangent@lookup% + \begingroup% + \let\tikz@after@path\pgfutil@empty% + \let\tikz@options=\pgfutil@empty% + \tikzset{every plot/.try}% + \tikzset{#1}% + \pgfutil@ifnextchar f{\tikz@plot@f}% + {\pgfutil@ifnextchar c{\tikz@plot@scan@points}% + {\pgfutil@ifnextchar ({\tikz@plot@expression}{% + \tikzerror{Cannot parse this plotting data}% + \endgroup}}}}% +\def\tikz@plot@f f{\pgfutil@ifnextchar i{\tikz@plot@file}{\tikz@plot@function}}% + +\def\tikz@plot@file ile#1{\def\tikz@plot@data{\pgfplotxyfile{#1}}\tikz@@@plot}% +\def\tikz@plot@scan@points coordinates#1{% + \pgfplothandlerrecord\tikz@plot@data% + \pgfplotstreamstart% + \pgfutil@ifnextchar\pgf@stop{\pgfplotstreamend\expandafter\tikz@@@plot\pgfutil@gobble} + {\tikz@scan@one@point\tikz@plot@next@point}% + #1\pgf@stop% +}% +\def\tikz@plot@next@point#1{% + \pgfplotstreampoint{#1}% + \pgfutil@ifnextchar\pgf@stop{\pgfplotstreamend\expandafter\tikz@@@plot\pgfutil@gobble}% + {\tikz@scan@one@point\tikz@plot@next@point}% +}% +\def\tikz@plot@function unction#1{% + \def\tikz@plot@filename{\tikz@plot@prefix\tikz@plot@id}% + \iftikz@plot@raw@gnuplot% + \def\tikz@plot@data{\pgfplotgnuplot[\tikz@plot@filename]{#1}}% + \else% + \iftikz@plot@parametric% + \def\tikz@plot@data{\pgfplotgnuplot[\tikz@plot@filename]{% + set samples \tikz@plot@samples; + set parametric; + plot [t=\tikz@plot@domain] + [\tikz@plot@xrange] + [\tikz@plot@range] + #1}}% + \else% + \def\tikz@plot@data{\pgfplotgnuplot[\tikz@plot@filename]{% + set samples \tikz@plot@samples; + plot [x=\tikz@plot@domain] + \ifx\tikz@plot@range\pgfutil@empty\else[\tikz@plot@range]\fi + #1}}% + \fi% + \fi% + \tikz@@@plot% +}% + +\def\tikz@plot@no@resample{% + \pgfutil@IfFileExists{\tikz@plot@filename.table}% + {\def\tikz@plot@data{\pgfplotxyfile{\tikz@plot@filename.table}}}% + {}% +}% + +\def\tikz@plot@expression(#1){% + \edef\tikz@plot@data{\noexpand\pgfplotfunction{\expandafter\noexpand\tikz@plot@var}{\tikz@plot@samplesat}}% + \expandafter\def\expandafter\tikz@plot@data\expandafter{\tikz@plot@data{\tikz@scan@one@point\pgfutil@firstofone(#1)}}% + \tikz@@@plot% +}% + +\def\tikz@@@plot{% + \def\pgfplotlastpoint{\pgfpointorigin}% + \tikz@plot@handler% + \tikz@plot@data% + \global\let\tikz@@@temp=\pgfplotlastpoint% + \ifx\tikz@plot@mark\pgfutil@empty% + \else% + % Marks are drawn after the path. + \setbox\tikz@whichbox=\hbox{% + \unhbox\tikz@whichbox% + \hbox{{% + \pgfinterruptpath% + \pgfscope% + \let\tikz@options=\pgfutil@empty% + \let\tikz@transform=\pgfutil@empty% + \tikzset{every mark}% + \tikz@options% + \ifx\tikz@mark@list\pgfutil@empty% + \pgfplothandlermark{\tikz@transform\pgfuseplotmark{\tikz@plot@mark}}% + \else + \pgfplothandlermarklisted{\tikz@transform\pgfuseplotmark{\tikz@plot@mark}}{\tikz@mark@list}% + \fi + \tikz@plot@data% + \endpgfscope + \endpgfinterruptpath% + }}% + }% + \fi% + \global\setbox\tikz@tempbox=\box\tikz@whichbox% + \global\let\tikz@after@path@smuggle=\tikz@after@path + \expandafter\endgroup% + \expandafter\setbox\tikz@whichbox=\box\tikz@tempbox% + \tikz@make@last@position{\tikz@@@temp}% + \expandafter\tikz@scan@next@command\tikz@after@path@smuggle% +}% + + +\pgfdeclareplotmark{ball} +{% + \def\tikz@shading{ball}% + \shade (0pt,0pt) circle (\pgfplotmarksize);% +}% + + + + +% Syntax for cosine curves: +% cos +\def\tikz@cosine s{\tikz@cycle@expander{\tikz@scan@one@point\tikz@@cosine}} +\def\tikz@@cosine#1{% + \let\tikz@tangent\tikz@tangent@lookup% + \tikz@flush@moveto% + \pgf@process{#1}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xc by-\tikz@lastx% + \advance\pgf@yc by-\tikz@lasty% + \advance\tikz@lastx by\pgf@xc% + \advance\tikz@lasty by\pgf@yc% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \tikz@updatecurrenttrue% + \pgfpathcosine{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \tikz@scan@next@command% +}% + +% Syntax for sine curves: +% sin +\def\tikz@sine in{\tikz@cycle@expander{\tikz@scan@one@point\tikz@@sine}} +\def\tikz@@sine#1{% + \let\tikz@tangent\tikz@tangent@lookup% + \tikz@flush@moveto% + \pgf@process{#1}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xc by-\tikz@lastx% + \advance\pgf@yc by-\tikz@lasty% + \advance\tikz@lastx by\pgf@xc% + \advance\tikz@lasty by\pgf@yc% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \tikz@updatecurrenttrue% + \pgfpathsine{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \tikz@scan@next@command% +}% + +% Syntax for parabolas: +% parabola[options] bend +\def\tikz@parabola arabola{% + \let\tikz@tangent\tikz@tangent@lookup% + \pgfutil@ifnextchar[{\tikz@parabola@options}{\tikz@parabola@options[]}}%}% + +\def\tikz@parabola@options[#1]{% + \def\tikz@parabola@option{#1}% + \pgfutil@ifnextchar b{\tikz@parabola@scan@bend}{\tikz@cycle@expander{\tikz@scan@one@point\tikz@parabola@semifinal}}}% +\def\tikz@parabola@scan@bend bend{\tikz@scan@one@point\tikz@parabola@scan@bendB}% +\def\tikz@parabola@scan@bendB#1{% + \def\tikz@parabola@bend{#1}% + \tikz@cycle@expander{\tikz@scan@one@point\tikz@parabola@semifinal}% +}% +\def\tikz@parabola@semifinal#1{% + \tikz@flush@moveto% + % Save original start: + \pgf@xb=\tikz@lastx% + \pgf@yb=\tikz@lasty% + \tikz@make@last@position{#1}% + \pgf@xc=\tikz@lastx% + \pgf@yc=\tikz@lasty% + \begingroup% now calculate bend: + \let\tikz@after@path\pgfutil@empty% + \expandafter\tikzset\expandafter{\tikz@parabola@option}% + \tikz@lastxsaved=\tikz@parabola@bend@factor\tikz@lastx% + \tikz@lastysaved=\tikz@parabola@bend@factor\tikz@lasty% + \advance\tikz@lastxsaved by\pgf@xb% + \advance\tikz@lastysaved by\pgf@yb% + \advance\tikz@lastxsaved by-\tikz@parabola@bend@factor\pgf@xb% + \advance\tikz@lastysaved by-\tikz@parabola@bend@factor\pgf@yb% + \expandafter\tikz@make@last@position\expandafter{\tikz@parabola@bend}% + % Calculate delta from bend + \advance\pgf@xc by-\tikz@lastx% + \advance\pgf@yc by-\tikz@lasty% + % Ok, now calculate delta to bend + \advance\tikz@lastx by-\pgf@xb% + \advance\tikz@lasty by-\pgf@yb% + \xdef\tikz@parabola@b{{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}}% + \expandafter\endgroup% + \expandafter\expandafter\expandafter\pgfpathparabola\expandafter\tikz@parabola@b% + \expandafter\tikz@scan@next@command\tikz@after@path% +}% + + +% Syntax for circles: +% circle [options] % where options should set, at least, radius +% circle (radius) % deprecated +% +% Syntax for ellipses: +% ellipse [options] % identical to circle. +% ellipse (x-radius and y-radius) % deprecated +% +% radii can be dimensionless, then they are in the xy-system +\def\tikz@circle ircle{\tikz@flush@moveto\tikz@@circle}% +\def\tikz@ellipse llipse{\tikz@flush@moveto\tikz@@circle}% +\def\tikz@@circle{% + \let\tikz@tangent\relax% + \pgfutil@ifnextchar(\tikz@@@circle + {\pgfutil@ifnextchar[\tikz@circle@opt{%]) + \advance\tikz@expandcount by -10\relax% go down quickly + \ifnum\tikz@expandcount<0\relax% + \let\pgfutil@next=\tikz@@circle@normal% + \else% + \let\pgfutil@next=\tikz@@circle@scanexpand% + \fi% + \pgfutil@next% + }}% +}% +\def\tikz@@circle@scanexpand{\expandafter\tikz@@circle}% +\def\tikz@@circle@normal{\tikz@circle@opt[]}% + +\def\tikz@circle@opt[#1]{% + {% + \def\tikz@node@at{\tikz@last@position}% + \let\tikz@transform=\pgfutil@empty% + \tikzset{every circle/.try,#1}% + \pgftransformshift{\tikz@node@at}% + \tikz@transform% + \tikz@do@ellipse{\pgfkeysvalueof{/tikz/x radius}}{\pgfkeysvalueof{/tikz/y radius}} + }% + \tikz@scan@next@command% +}% + +\def\tikz@@@circle(#1){% + {% + \pgftransformshift{\tikz@last@position}% + \pgfutil@in@{ and }{#1}% + \ifpgfutil@in@% + \tikz@@ellipseB(#1)% + \else% + \tikz@do@circle{#1}% + \fi% + }% + \tikz@scan@next@command% +}% +\def\tikz@@ellipseB(#1 and #2){% + \tikz@do@ellipse{#1}{#2}% +}% +\def\tikz@do@circle#1{% + \pgfmathparse{#1}% + \let\tikz@ellipse@x=\pgfmathresult + \ifpgfmathunitsdeclared + \pgfpathellipse{\pgfpointorigin}% + {\pgfqpoint{\tikz@ellipse@x pt}{0pt}}% + {\pgfpoint{0pt}{\tikz@ellipse@x pt}}% + \else + \pgfpathellipse{\pgfpointorigin}% + {\pgfpointxy{\tikz@ellipse@x}{0}}% + {\pgfpointxy{0}{\tikz@ellipse@x}}% + \fi +} +\def\tikz@do@ellipse#1#2{ + \pgfmathparse{#1}% + \let\tikz@ellipse@x=\pgfmathresult% + \ifpgfmathunitsdeclared% + \pgfmathparse{#2}% + \let\tikz@ellipse@y=\pgfmathresult% + \ifpgfmathunitsdeclared% + \pgfpathellipse{\pgfpointorigin}{% + \pgfqpoint{\tikz@ellipse@x pt}{0pt}}{\pgfpoint{0pt}{\tikz@ellipse@y pt}}% + \else% + \tikzerror{You cannot mix dimensions and dimensionless values in an ellipse}% + \fi% + \else% + \pgfmathparse{#2}% + \let\tikz@ellipse@y=\pgfmathresult% + \ifpgfmathunitsdeclared% + \tikzerror{You cannot mix dimensions and dimensionless values in an ellipse}% + \else% + \pgfpathellipse{\pgfpointorigin}{% + \pgfpointxy{\tikz@ellipse@x}{0}}{\pgfpointxy{0}{\tikz@ellipse@y}}% + \fi% + \fi% +}% + +% Syntax for arcs: +% arc [options] +% +% (The syntax with parentheses is deprecated.) +\def\tikz@arcA rc{\tikz@flush@moveto\tikz@arc@cont}% +\def\tikz@arc@cont{% + \pgfutil@ifnextchar(%) + {\tikz@@arcto}{% + \pgfutil@ifnextchar[%] + {\tikz@arc@opt}% + {% + \advance\tikz@expandcount by -10\relax% go down quickly + \ifnum\tikz@expandcount<0\relax% + \let\pgfutil@next=\tikz@@arc@normal% + \else% + \let\pgfutil@next=\tikz@@arc@scanexpand% + \fi% + \pgfutil@next% + }% + }% +}% +\def\tikz@@arc@scanexpand{\expandafter\tikz@arc@cont}% +\def\tikz@@arc@normal{\tikz@arc@opt[]}% + + +\def\tikz@arc@opt[#1]{% + {% + \tikzset{every arc/.try,#1}% + \pgfkeysgetvalue{/tikz/start angle}\tikz@s + \pgfkeysgetvalue{/tikz/end angle}\tikz@e + \pgfkeysgetvalue{/tikz/delta angle}\tikz@d + \ifx\tikz@s\pgfutil@empty% + \pgfmathsetmacro\tikz@s{\tikz@e-\tikz@d} + \else + \ifx\tikz@e\pgfutil@empty% + \pgfmathsetmacro\tikz@e{\tikz@s+\tikz@d} + \fi% + \fi% + \xdef\pgf@marshal{\noexpand% + \tikz@do@arc{\tikz@s}{\tikz@e} + {\pgfkeysvalueof{/tikz/x radius}} + {\pgfkeysvalueof{/tikz/y radius}}}% + }% + \pgf@marshal% + \tikz@arcfinal% +}% + +\def\tikz@@arcto(#1){% + \edef\tikz@temp{(#1)}% + \expandafter\tikz@@@arcto@check@slashand\tikz@temp% +}% + +\def\tikz@@@arcto@check@slashand(#1:#2:#3){% + \pgfutil@in@{ and }{#3}% + \ifpgfutil@in@% + \tikz@parse@arc@and(#1:#2:#3)% + \else% + \tikz@parse@arc@and(#1:#2:{#3} and {#3})% + \fi% + \tikz@arcfinal% +}% + +\def\tikz@parse@arc@and(#1:#2:#3 and #4){% + \tikz@do@arc{#1}{#2}{#3}{#4}% +}% +\def\tikz@do@arc#1#2#3#4{% + \let\tikz@tangent\tikz@tangent@lookup% + \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \pgfmathsetmacro\tikz@timer@start@angle{#1}% + \pgfmathsetmacro\tikz@timer@end@angle{#2}% + \pgfmathparse{#3}% + \let\tikz@arc@x=\pgfmathresult% + \ifpgfmathunitsdeclared% + \pgfmathparse{#4}% + \let\tikz@arc@y=\pgfmathresult% + \ifpgfmathunitsdeclared% + \tikz@@@arcfinal{\pgfpatharc{\tikz@timer@start@angle}{\tikz@timer@end@angle}{\tikz@arc@x pt and \tikz@arc@y pt}} + {\pgfpointpolar{\tikz@timer@start@angle}{\tikz@arc@x pt and \tikz@arc@y pt}} + {\pgfpointpolar{\tikz@timer@end@angle}{\tikz@arc@x pt and \tikz@arc@y pt}}% + \edef\tikz@timer@zero@axis{\noexpand\pgfqpoint{\tikz@arc@x pt}{0pt}} + \edef\tikz@timer@ninety@axis{\noexpand\pgfqpoint{0pt}{\tikz@arc@y pt}} + \else% + \tikzerror{You cannot mix dimensions and dimensionless values in an arc}% + \fi% + \else% + \pgfmathparse{#4}% + \let\tikz@arc@y=\pgfmathresult% + \ifpgfmathunitsdeclared% + \tikzerror{You cannot mix dimensions and dimensionless values in an arc}% + \else% + \tikz@@@arcfinal{\pgfpatharcaxes{\tikz@timer@start@angle}{\tikz@timer@end@angle}{\pgfpointxy{\tikz@arc@x}{0}}{\pgfpointxy{0}{\tikz@arc@y}}} + {\pgfpointpolarxy{\tikz@timer@start@angle}{\tikz@arc@x and \tikz@arc@y}}{\pgfpointpolarxy{\tikz@timer@end@angle}{\tikz@arc@x and \tikz@arc@y}}% + \pgf@process{\pgfpointxy{\tikz@arc@x}{0}} + \edef\tikz@timer@zero@axis{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgf@process{\pgfpointxy{0}{\tikz@arc@y}} + \edef\tikz@timer@ninety@axis{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \fi% + \fi% +}% + +\def\tikz@@@arcfinal#1#2#3{% + #1% + \pgf@process{#2} + \xdef\tikz@arc@save@first{\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgf@process{#3} + \xdef\tikz@arc@save@second{\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% +}% + +\def\tikz@arcfinal{% + \pgf@process{\tikz@arc@save@first}% + \advance\tikz@lastx by-\pgf@x% + \advance\tikz@lasty by-\pgf@y% + \pgf@process{\tikz@arc@save@second}% + \advance\tikz@lastx by\pgf@x% + \advance\tikz@lasty by\pgf@y% + \tikz@lastxsaved=\tikz@lastx% + \tikz@lastysaved=\tikz@lasty% + \let\tikz@timer=\tikz@timer@arc% + \tikz@scan@next@command% +}% + + +% Syntax for coordinates: +% coordinate[options] (coordinate name) at (point) +% where ``at (point)'' is optional +\def\tikz@coordinate ordinate{% + \pgfutil@ifnextchar[{\tikz@@coordinate@opt}{\tikz@@coordinate@opt[]}}% +\def\tikz@@coordinate@opt[#1]{% + \pgfutil@ifnextchar({\tikz@@coordinate[#1]} + {\tikz@fig ode[shape=coordinate,#1]{}}}%}% +\def\tikz@@coordinate[#1](#2){% + \pgfutil@ifnextchar a{\tikz@@coordinate@at[#1](#2)} + {\tikz@fig ode[shape=coordinate,#1](#2){}}}% +\def\tikz@@coordinate@at[#1](#2)a{% + \pgfutil@ifnextchar t{\tikz@@coordinate@@at[#1](#2)a}% + {\tikz@fig ode[shape=coordinate,#1](#2){}a}% +}% +\def\tikz@@coordinate@@at[#1](#2)at#3({% + \def\tikz@coordinate@caller{\tikz@fig ode[shape=coordinate,#1](#2)at}% + \tikz@scan@one@point\tikz@@coordinate@at@math(% +}% +\def\tikz@@coordinate@at@math#1{% + \pgf@process{#1}% + \edef\tikz@temp{(\the\pgf@x,\the\pgf@y)}% + \expandafter\tikz@coordinate@caller\tikz@temp{}% +}% + + + +% Syntax for nodes: +% node foreach \var in {list} ... :attribute={...} [options] (node name) at (pos) {label text} +% +% all of :attribute, [options], (node name), at(pos), and foreach are +% optional. There can be multiple options and the ordering is not +% important as in node[draw] (a) [rotate=10] {text}, *except* that all +% foreach statements must come first. +% +% A label text always ``ends'' the node. +% +\def\tikz@fig ode{% + \pgfutil@ifnextchar a\tikz@test@also{% + \pgfutil@ifnextchar f{\tikz@nodes@start}\tikz@normal@fig}}% +\def\tikz@test@also a{\pgfutil@ifnextchar l\tikz@node@also{\tikz@normal@fig a}}% +\def\tikz@normal@fig{% + \edef\tikz@save@line@width{\the\pgflinewidth}% + \begingroup% + \let\tikz@fig@name=\pgfutil@empty% + \begingroup% + \tikz@is@matrixfalse% + \let\nodepart=\tikz@nodepart% + \let\tikz@atbegin@scope=\pgfutil@empty% + \let\tikz@atend@scope=\pgfutil@empty% + \let\tikz@do@after@node=\tikz@scan@next@command% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@id@name=\pgfutil@empty% + \let\tikz@after@path=\pgfutil@empty% + \let\tikz@transform=\pgfutil@empty% + \let\tikz@mode=\pgfutil@empty% + \tikz@decoratepathfalse% + \let\tikz@preactions=\pgfutil@empty% + \let\tikz@postactions=\pgfutil@empty% + \let\tikz@alias=\pgfutil@empty% + \def\tikz@node@at{\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}% + \let\tikz@time@for@matrix\tikz@time% + \let\tikz@node@content\relax% + \pgfgetpath\tikzpathuptonow% + \iftikz@node@is@a@label% + \else% + \let\tikz@time\pgfutil@empty% + \fi% + \tikz@node@reset@hook% + \tikzset{every node/.try}% + \tikz@@scan@fig}% +\def\tikz@@scan@fig{% + \pgfutil@ifnextchar a{\tikz@fig@scan@at} + {\pgfutil@ifnextchar({\tikz@fig@scan@name} + {\pgfutil@ifnextchar[{\tikz@fig@scan@options}% + {\pgfutil@ifnextchar:{\tikz@fig@scan@animation}% + {\pgfutil@ifnextchar\bgroup{\tikz@fig@main}% + {\tikzerror{A node must have a (possibly empty) label text}% + \tikz@fig@main{}}}}}}}%}}% +\def\tikz@fig@scan@at at{% + \tikz@scan@one@point\tikz@@fig@scan@at}% +\def\tikz@@fig@scan@at#1{% + \def\tikz@node@at{#1}\tikz@@scan@fig}% +\def\tikz@fig@scan@name(#1){% + \pgfkeysvalueof{/tikz/name/.@cmd}#1\pgfeov% CF : this is now ALWAYS consistent with 'name=' option; allows overrides. + \tikz@@scan@fig}% +% make it \long to allow \par in "pin" options etc: +\long\def\tikz@fig@scan@options[#1]{\iftikz@node@is@pic\tikz@enable@pic@quotes\else\tikz@enable@node@quotes\fi\tikzset{#1}\ifx\tikz@node@content\relax\expandafter\tikz@@scan@fig\else\tikz@expand@node@contents\fi}% +\def\tikz@fig@scan@animation:#1=#2{\tikzset{animate={myself:{#1}={#2}}}\tikz@@scan@fig}% +\def\tikz@expand@node@contents{% + \expandafter\tikz@@scan@fig\expandafter{\tikz@node@content}% +}% +\let\tikz@node@reset@hook=\pgfutil@empty% +\let\tikz@node@begin@hook=\pgfutil@empty% +\def\tikz@fig@main{% + \iftikz@node@is@pic% + \tikz@node@is@picfalse% + \expandafter\tikz@subpicture@handle% + \else% + \afterassignment\tikz@@fig@main\expandafter\let\expandafter\next\expandafter=% + \fi}% +\def\tikz@@fig@main{% + \pgfutil@ifundefined{pgf@sh@s@\tikz@shape}% + {\tikzerror{Unknown shape ``\tikz@shape.'' Using ``rectangle'' instead}% + \def\tikz@shape{rectangle}}% + {}% + \expandafter\xdef\csname tikz@dcl@coord@\tikz@fig@name\endcsname{% + \csname tikz@scan@point@coordinate\endcsname}% + \tikzset{every \tikz@shape\space node/.try}% + \tikz@node@textfont% + \tikz@node@begin@hook% + \iftikz@is@matrix% + \let\tikz@next=\tikz@do@matrix% + \else% + \let\tikz@next=\tikz@do@fig% + \fi% + \tikz@next% +}% +\let\tikz@nodepart@list\pgfutil@empty +\def\tikz@do@fig{% + % Ok, reset all node part boxes + \pgfutil@for\tikz@temp:=\tikz@nodepart@list\do{% + \expandafter\setbox\csname pgfnodepart\tikz@temp box\endcsname=\box\pgfutil@voidb@x% + }% + \setbox\pgfnodeparttextbox=\hbox% + \bgroup% + \pgfinterruptpicture% + \pgfsys@begin@text% + \pgfsys@text@to@black@hook% + \tikzset{every text node part/.try}% + \ifx\tikz@textopacity\pgfutil@empty% + \else% + \pgfsetfillopacity{\tikz@textopacity}% + \pgfsetstrokeopacity{\tikz@textopacity}% + \fi% + \ifx\tikz@text@width\pgfutil@empty% + \tikz@textfont% + \else% + \begingroup% + \pgfmathsetlength{\pgf@x}{\tikz@text@width}% + \pgfutil@minipage[t]{\pgf@x}\leavevmode\hbox{}% + \tikz@textfont% + \tikz@text@action% + \fi% + \tikz@atbegin@node% + \bgroup% + \aftergroup\unskip% + % Some color stuff has been moved from here to outside; this is + % necessary for support of dvisvgm and of animation + % snapshots. + \ifx\tikz@textcolor\pgfutil@empty% + \else% + \pgfutil@colorlet{.}{\tikz@textcolor}% + \pgfutil@color{\tikz@textcolor}% + \fi% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@uninstallcommands% + \iftikz@handle@active@code% + \tikz@orig@shorthands% + \let\tikz@orig@shorthands\pgfutil@empty% + \fi% + \ifnum\the\catcode`\;=\active\relax\expandafter\let\tikz@activesemicolon=\tikz@origsemi\fi% + \ifnum\the\catcode`\:=\active\relax\expandafter\let\tikz@activecolon=\tikz@origcolon\fi% + \ifnum\the\catcode`\|=\active\relax\expandafter\let\tikz@activebar=\tikz@origbar\fi% + \aftergroup\tikz@fig@collectresetcolor% + \tikz@signal@halign@check% + \tikz@text@reset% + \tikz@halign@check% + \ignorespaces% +}% +\def\tikz@fig@collectresetcolor{% + % Hacks for special packages that mess with \aftergroup + \pgfutil@ifnextchar\reset@color% hack for color package + {\reset@color\afterassignment\tikz@fig@collectresetcolor\let\tikz@temp=}\tikz@fig@boxdone% +}% +\def\tikz@fig@boxdone{% + \tikz@atend@node% + \ifx\tikz@text@width\pgfutil@empty% + \else% + \pgfutil@endminipage% + \endgroup% + \fi% + \pgfsys@end@text% + \endpgfinterruptpicture% + \egroup% + \pgfutil@ifnextchar c{\tikz@fig@mustbenamed\tikz@fig@continue}% + {\pgfutil@ifnextchar[{\tikz@fig@mustbenamed\tikz@fig@continue}% + {\pgfutil@ifnextchar t{\tikz@fig@mustbenamed\tikz@fig@continue} + {\pgfutil@ifnextchar e{\tikz@fig@mustbenamed\tikz@fig@continue} + {\ifx\tikz@after@path\pgfutil@empty\expandafter\tikz@fig@continue\else\expandafter\tikz@fig@mustbenamed\expandafter\tikz@fig@continue\fi}}}}}%}% + +\tikzset{ + matrix/inner style/every cell/.code={% + \tikzset{every cell/.try={\the\pgfmatrixcurrentrow}{\the\pgfmatrixcurrentcolumn}}% + }, + matrix/inner style/column/.code={% + \tikzset{column \the\pgfmatrixcurrentcolumn/.try}% + }, + matrix/inner style/even odd column/.code={ + \ifodd\pgfmatrixcurrentcolumn% + \tikzset{every odd column/.try}% + \else% + \tikzset{every even column/.try}% + \fi + }, + matrix/inner style/row/.code={% + \tikzset{row \the\pgfmatrixcurrentrow/.try}% + }, + matrix/inner style/even odd row/.code={% + \ifodd\pgfmatrixcurrentrow% + \tikzset{every odd row/.try}% + \else% + \tikzset{every even row/.try}% + \fi + }, + matrix/inner style/cell/.code={% + \tikzset{row \the\pgfmatrixcurrentrow\space column \the\pgfmatrixcurrentcolumn/.try}% + }, + matrix/inner style order/.store in=\tikz@common@matrix@code@styleorder, + matrix/inner style order={ + every cell, + column, + even odd column, + row, + even odd row, + cell + }, +}% + +\def\tikz@do@matrix{% + \tikzset{every matrix/.try}% + \tikz@node@transformations% + \tikz@fig@mustbenamed% + \setbox\tikz@whichbox=\hbox\bgroup% + \unhbox\tikz@whichbox% + \hbox\bgroup\bgroup% + \pgfinterruptpath% + \pgfscope% + \ifx\tikz@time\pgfutil@empty\let\tikz@time\tikz@time@for@matrix\fi% + \tikz@options% + \tikz@do@rdf@pre@options% + \tikz@is@nodefalse% + \tikz@call@id@hook% + \pgfidscope% + \tikz@do@rdf@post@options% + \begingroup% + \let\tikz@id@name\pgfutil@empty% + \pgfclearid% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \let\tikzmatrixname=\tikz@fig@name% + \edef\tikz@m@anchor{\ifx\tikz@matrix@anchor\pgfutil@empty\tikz@anchor\else\tikz@matrix@anchor\fi}% + \expandafter\pgfutil@in@\expandafter{\expandafter.\expandafter}\expandafter{\tikz@m@anchor}% + \ifpgfutil@in@% + \expandafter\tikz@matrix@split\tikz@m@anchor\relax% + \else% + \def\tikz@matrix@shift{\pgfpointorigin}% + \fi% + \let\tikz@transform=\relax% + \pgfmatrixbeforeassemblenode{\tikzset{every outer matrix/.try}}% + \pgfmatrix% + {\tikz@shape}% + {\tikz@m@anchor}% + {\tikz@fig@name}% + {% + \pgfutil@tempdima=\pgflinewidth% + {\begingroup\tikz@finish}% + \global\pgflinewidth=\pgfutil@tempdima% + }% + {\tikz@matrix@shift}% + {% + \tikz@matrix@make@active@ampersand% + \def\pgfmatrixbegincode{% + \pgfsys@beginscope% + \tikz@common@matrix@code% + \tikz@atbegin@cell% + }% + \def\tikz@common@matrix@code{% + \let\tikz@options=\pgfutil@empty% + \let\tikz@mode=\pgfutil@empty% + \pgfutil@for\pgf@temp:=\tikz@common@matrix@code@styleorder\do{% + \toks0=\expandafter{\romannumeral-`0\expandafter\pgfutil@trimspaces\expandafter{\pgf@temp}}% + \def\pgf@marshal{}% + \pgfutil@ifxempty\pgf@temp{}{% + \edef\pgf@marshal{\noexpand\tikzset{matrix/inner style/.cd,\the\toks0}}% + }% + \pgf@marshal + }% + \tikz@options% + }% + \def\pgfmatrixendcode{% + \tikz@atend@cell% + \pgfsys@endscope% + }% + \def\pgfmatrixemptycode{% + \pgfsys@beginscope% + \tikz@common@matrix@code% + \tikz@at@emptycell% + \pgfsys@endscope% + }% + \tikz@atbegin@matrix% + \aftergroup\tikz@do@matrix@cont}% + \bgroup% +}% +\def\tikz@do@matrix@cont{% + \tikz@atend@matrix% + \endgroup% + \endpgfidscope% + \endpgfscope + \endpgfinterruptpath% + \egroup\egroup% + \egroup% + % + \tikz@node@finish% +}% +{% + \catcode`\&=13 + \gdef\tikz@matrix@make@active@ampersand{% + \ifx\tikz@ampersand@replacement\pgfutil@empty% + \catcode`\&=13% + \let&=\pgfmatrixnextcell% + \else% + \expandafter\let\tikz@ampersand@replacement=\pgfmatrixnextcell% + \fi% + }% +}% + + +\def\tikz@matrix@split#1.#2\relax{% + \def\tikz@m@anchor{text}% + \def\tikz@matrix@shift{\pgfpointanchor{#1}{#2}}% +}% + +\def\tikz@fig@continue{% + \ifx\tikz@text@width\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@width}% + \wd\pgfnodeparttextbox=\pgf@x% + \fi% + \ifx\tikz@text@height\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@height}% + \ht\pgfnodeparttextbox=\pgf@x% + \fi% + \ifx\tikz@text@depth\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@depth}% + \dp\pgfnodeparttextbox=\pgf@x% + \fi% + % + % Node transformation + % + \tikz@node@transformations% + \tikz@nlt% + % + \setbox\tikz@whichbox=\hbox{% + \unhbox\tikz@whichbox% + \hbox{{% + \pgfinterruptpath% + \pgfscope% + \tikz@options% + \tikz@do@rdf@pre@options% + \tikz@is@nodetrue% + \tikz@call@id@hook% + \pgfidscope% + \tikz@do@rdf@post@options% + \let\tikz@id@name\pgfutil@empty% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + % Add color modifications to text box + \setbox\pgfnodeparttextbox=\hbox{{% + \pgfsys@begin@text% Colors moved here... + \ifx\tikz@textcolor\pgfutil@empty% + \else% + \pgfutil@colorlet{.}{\tikz@textcolor}% + \fi% + \pgfsetcolor{.}% + \pgfusetype{.text}% + \pgfidscope% + \box\pgfnodeparttextbox% + \endpgfidscope% + \pgfsys@end@text% + }}% + \pgfmultipartnode{\tikz@shape}{\tikz@anchor}{\tikz@fig@name}{% + \pgfutil@tempdima=\pgflinewidth% + {\begingroup\tikz@finish}% + \global\pgflinewidth=\pgfutil@tempdima% + }% + \endpgfidscope% + \endpgfscope% + \endpgfinterruptpath% + }}% + }% + % + \tikz@alias% + \tikz@node@finish% +}% + + +\def\tikz@fig@mustbenamed{% + \ifx\tikz@fig@name\pgfutil@empty% + % Assign a dummy name + \global\advance\tikz@fig@count by1\relax + \edef\tikz@fig@name{tikz@f@\the\tikz@fig@count}% + \let\tikz@id@name\tikz@fig@name% + \fi% +}% + +\def\tikz@node@transformations{% + % + % Possibly, we are ``online'' + % + \ifx\tikz@time\pgfutil@empty% + \pgftransformshift{\tikz@node@at}% + \iftikz@fullytransformed% + \else% + \pgftransformresetnontranslations% + \fi% + \else% + \tikz@do@auto@anchor% + \tikz@timer% + \fi% + % Invoke local transformations + \tikz@transform% +}% + +\def\tikz@node@finish{% + \global\let\tikz@last@fig@name=\tikz@fig@name% + \global\let\tikz@after@path@smuggle=\tikz@after@path% + % shift box outside group + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \endgroup\endgroup% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \global\pgflinewidth=\tikz@save@line@width% + \tikz@do@after@path@smuggle% + \tikz@node@is@picfalse + \tikz@do@after@node% +}% +\let\tikz@fig@continue@orig=\tikz@fig@continue + +\def\tikz@do@after@node{\tikz@scan@next@command}% + +\def\tikz@do@after@path@smuggle{% + \let\tikz@to@last@fig@name=\tikz@last@fig@name% + \let\tikz@to@use@whom=\tikz@to@use@last@fig@name% + \let\tikzlastnode=\tikz@last@fig@name% + \ifx\tikz@after@path@smuggle\pgfutil@empty% + \else% + \ifpgflatenodepositioning% + \expandafter\expandafter\expandafter\tikz@call@late% + \expandafter\expandafter\expandafter{\expandafter\tikz@last@fig@name\expandafter}\expandafter{\tikz@after@path@smuggle}% + \else% + \tikz@scan@next@command{\tikz@after@path@smuggle}\pgf@stop% + \fi% + \fi% +}% + +\def\tikz@call@late#1#2{\pgfnodepostsetupcode{#1}{\path[late options={name={#1},append after command={#2}}];}}% + +\newif\iftikz@do@align + +% Alignment handling +\def\tikz@signal@halign@check{% + \tikz@do@alignfalse + \ifx\tikz@text@width\pgfutil@empty% + \pgfkeysgetvalue{/tikz/node halign header}\tikz@align@header% + \ifx\tikz@align@header\pgfutil@empty% + \else% + \tikz@do@aligntrue% + \fi% + \fi% +} +\def\tikz@halign@check{% + \iftikz@do@align% + % Bingo + \setbox\tikz@align@aligned@box=\box\pgfutil@voidb@x% void + \let\\=\tikz@align@newline% + \expandafter\tikz@start@align% + \fi% +}% +\def\tikz@align@newline{\pgfutil@protect\tikz@align@newline@}% +\def\tikz@align@newline@{\unskip\pgfutil@ifnextchar[\tikz@@align@newline{\tikz@@align@newline[0pt]}}%}% +\def\tikz@@align@newline[#1]{\egroup\tikz@align@continue\pgfmathparse{#1}\let\tikz@align@temp=\pgfmathresult\tikz@start@align}% +% Two safe boxes for alignment: +\let\tikz@align@aligned@box=\pgfnodeparttextbox +\let\tikz@align@line@box=\tikz@figbox + +\def\tikz@start@align{% + % Start collecting text: + \setbox\tikz@align@line@box=\hbox\bgroup\bgroup% + \aftergroup\tikz@align@collectresetcolor\ignorespaces% +}% +\def\tikz@align@collectresetcolor{% + \pgfutil@ifnextchar\reset@color% + {\reset@color\afterassignment\tikz@align@collectresetcolor\let\tikz@temp=}% + {\tikz@align@end@check}% +}% +\def\tikz@align@end@check{% + \egroup% + \ifvoid\tikz@align@aligned@box% + \setbox\tikz@align@aligned@box=\box\tikz@align@line@box% + \else% + \setbox\tikz@align@aligned@box=\vbox{% + \expandafter\expandafter\expandafter\halign\expandafter\expandafter\expandafter{\tikz@align@header% + \box\tikz@align@aligned@box\cr% + \noalign{\vskip\tikz@align@temp pt}% + \unhbox\tikz@align@line@box\unskip\cr}}% + \fi% + \pgfutil@ifnextchar\tikz@align@continue{} + {% + % Main continue + \box\tikz@align@aligned@box% + \egroup% + }% +}% +\def\tikz@align@continue{\tikz@@align@continue}% +\let\tikz@@align@continue=\pgfutil@empty + + +\def\tikz@node@also lso{\pgfutil@ifnextchar[\tikz@node@also@opt{\tikz@node@also@opt[]}}% +\def\tikz@node@also@opt[#1]{ + \pgfutil@ifnextchar(%) + {\tikz@node@also@opt@cont[#1]}% + {\tikzerror{Syntax error in node also: ``('' expected.}% + \tikz@scan@next@command}% +}% +\def\tikz@node@also@opt@cont[#1](#2){\tikzset{late options={name=#2,#1}}\tikz@scan@next@command}% + + + +% Syntax for parts of nodes: +% node ... {... \nodepart[options]{name} ... \nodepart{name} ...} + +\def\tikz@nodepart{\pgfutil@ifnextchar[\tikz@@nodepart{\tikz@@nodepart[]}}%}% +\def\tikz@@nodepart[#1]#2{% + \tikz@atend@node% + \unskip% + \gdef\tikz@nodepart@options{#1}% + \gdef\tikz@nodepart@name{#2}% + \global\let\tikz@fig@continue=\tikz@nodepart@continue% + \pgfutil@ifnextchar x{\egroup\relax}{\egroup\relax}% gobble spaces +}% +\def\tikz@nodepart@continue{% + \global\let\tikz@fig@continue=\tikz@fig@continue@orig% + \ifx\tikz@nodepart@list\pgfutil@empty% + \let\tikz@nodepart@list\tikz@nodepart@name% + \else% + \edef\tikz@nodepart@list{\tikz@nodepart@list,\tikz@nodepart@name}% + \fi% + % Now start new box: + \expandafter\setbox\csname pgfnodepart\tikz@nodepart@name box\endcsname=\hbox% + \bgroup% + \pgfinterruptpicture% + \pgfsys@begin@text% + \pgfsys@text@to@black@hook% + \tikzset{every \tikz@nodepart@name\space node part/.try}% + \expandafter\tikzset\expandafter{\tikz@nodepart@options}% + \ifx\tikz@textopacity\pgfutil@empty% + \else% + \pgfsetfillopacity{\tikz@textopacity}% + \pgfsetstrokeopacity{\tikz@textopacity}% + \fi% + % Colors moved here... + \ifx\tikz@textcolor\pgfutil@empty% + \else% + \pgfutil@colorlet{.}{\tikz@textcolor}% + \fi% + \pgfsetcolor{.}% + \ifx\tikz@text@width\pgfutil@empty% + \tikz@textfont% + \else% + \begingroup% + \pgfmathsetlength{\pgf@x}{\tikz@text@width}% + \pgfutil@minipage[t]{\pgf@x}\leavevmode\hbox{}% + \tikz@textfont% + \tikz@text@action% + \fi% + \bgroup% + \aftergroup\unskip% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@uninstallcommands% + \iftikz@handle@active@code% + \tikz@orig@shorthands% + \let\tikz@orig@shorthands\pgfutil@empty% + \fi% + \ifnum\the\catcode`\;=\active\relax\expandafter\let\tikz@activesemicolon=\tikz@origsemi\fi% + \ifnum\the\catcode`\:=\active\relax\expandafter\let\tikz@activecolon=\tikz@origcolon\fi% + \ifnum\the\catcode`\|=\active\relax\expandafter\let\tikz@activebar=\tikz@origbar\fi% + \tikz@atbegin@node% + \aftergroup\tikz@fig@collectresetcolor% + \tikz@signal@halign@check% + \tikz@text@reset% + \tikz@halign@check% + \ignorespaces% +}% + + +% +% Node foreach +% + +\def\tikz@nodes@start{% + \let\tikz@nodes@list\pgfutil@empty% + \iftikz@node@is@pic% + \def\tikz@nodes@collect{pic }% + \else% + \def\tikz@nodes@collect{node }% + \fi% + \tikz@nodes% +}% +\def\tikz@nodes foreach{\pgfutil@ifnextchar x\tikz@nodes@\tikz@nodes@}% get rid of spaces +\def\tikz@nodes@#1in{% + \expandafter\def\expandafter\tikz@nodes@list\expandafter{\tikz@nodes@list\foreach#1in}% + \pgfutil@ifnextchar\bgroup\tikz@nodes@group\tikz@nodes@one% +}% +\def\tikz@nodes@one#1{% + \expandafter\def\expandafter\tikz@nodes@list\expandafter{\tikz@nodes@list#1}% + \pgfutil@ifnextchar f\tikz@nodes\tikz@nodes@scan% +}% +\def\tikz@nodes@group#1{% + \expandafter\def\expandafter\tikz@nodes@list\expandafter{\tikz@nodes@list{#1}}% + \pgfutil@ifnextchar f\tikz@nodes\tikz@nodes@scan% +}% +\def\tikz@nodes@scan{% + \pgfutil@ifnextchar a{\tikz@nodes@at}% + {\pgfutil@ifnextchar({\tikz@nodes@name}% + {\pgfutil@ifnextchar[{\tikz@nodes@opt}% + {\pgfutil@ifnextchar\bgroup{\tikz@nodes@main}% + {\tikzerror{Nodes must have a (possibly empty) label text}% + \tikz@fig@main{}}}}}}%}}% + +% Look ahead whether the next character is a (. If that is the case, we scan +% until ), otherwise we grab a single token and append. +\def\tikz@nodes@at at{\pgfutil@ifnextchar({\tikz@nodes@at@}{\tikz@nodes@at@@}}% +\def\tikz@nodes@at@#1){% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect at#1)}% + \tikz@nodes@scan}% +\def\tikz@nodes@at@@#1{% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect at#1}% + \tikz@nodes@scan}% + +\def\tikz@nodes@name#1){% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect#1)}% + \tikz@nodes@scan}% +\def\tikz@nodes@opt#1]{% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect#1]}% + \tikz@nodes@scan}% +\def\tikz@nodes@main#1{% + \iftikz@handle@active@nodes% + \iftikz@node@is@pic% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect{#1}}% + \else% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect{\scantokens{#1}}}% + \fi% + \else% + \expandafter\def\expandafter\tikz@nodes@collect\expandafter{\tikz@nodes@collect{#1}}% + \fi% + % Ok, got everything. + % Now, start building parse text. + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \tikz@nodes@list{% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \expandafter\tikz@scan@next@command\tikz@nodes@collect\pgfextra\relax% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + }% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \tikz@scan@next@command% +}% + + + +% +% "late" options can be used to "redo" a node +% +\tikzset{late options/.code=\tikz@late@options{#1}}% +\def\tikz@late@options#1{% + % Do a "virtual" node: + \begingroup% + \iftikz@shapeborder% + \let\tikz@fig@name=\tikz@shapeborder@name% + \else% + \let\tikz@fig@name=\pgfutil@empty% + \fi% + \tikz@is@matrixfalse% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@after@path=\pgfutil@empty% + \let\tikz@afternodepathoptions=\pgfutil@empty% + \let\tikz@alias=\pgfutil@empty% + \let\tikz@transform=\pgfutil@empty% + \tikz@decoratepathfalse% + \tikz@node@reset@hook% + \tikz@enable@node@quotes% + \tikzset{every node/.try,#1}% + \ifx\tikz@fig@name\pgfutil@empty% + \tikzerror{Late options must reference some existing node}% + \fi% + \tikz@node@begin@hook% + \tikz@alias% + \tikzgdlatenodeoptionacallback{\tikz@fig@name}% + \global\let\tikz@last@fig@name=\tikz@fig@name% + \global\let\tikz@after@path@smuggle=\tikz@after@path% + \endgroup% + \tikz@do@after@path@smuggle% +}% + + +% Auto placement + +\def\tikz@auto@pre{% + \begingroup + \pgfresetnontranslationattimefalse + \ifpgfslopedattime + \pgfslopedattimefalse% + \else + \pgfslopedattimetrue% + \fi + \pgfallowupsidedownattimetrue% + \tikz@timer% + \pgf@x=\pgf@pt@aa pt% + \pgf@y=\pgf@pt@ab pt% + \pgfpointnormalised{}% +}% + +\def\tikz@auto@post{% + \global\let\tikz@anchor@smuggle=\tikz@anchor% + \endgroup% + \let\tikz@anchor=\tikz@anchor@smuggle% +}% + +\def\tikz@auto@anchor{% + \ifdim\pgf@x>0.05pt% + \ifdim\pgf@y>0.05pt% + \def\tikz@anchor{south east}% + \else\ifdim\pgf@y<-0.05pt% + \def\tikz@anchor{south west}% + \else + \def\tikz@anchor{south}% + \fi\fi% + \else\ifdim\pgf@x<-0.05pt% + \ifdim\pgf@y>0.05pt% + \def\tikz@anchor{north east}% + \else\ifdim\pgf@y<-0.05pt% + \def\tikz@anchor{north west}% + \else + \def\tikz@anchor{north}% + \fi\fi% + \else% + \ifdim\pgf@y>0pt% + \def\tikz@anchor{east}% + \else% + \def\tikz@anchor{west}% + \fi% + \fi\fi% +}% + +\def\tikz@auto@anchor@prime{% + \ifdim\pgf@x>0.05pt% + \ifdim\pgf@y>0.05pt% + \def\tikz@anchor{north west}% + \else\ifdim\pgf@y<-0.05pt% + \def\tikz@anchor{north east}% + \else + \def\tikz@anchor{north}% + \fi\fi% + \else\ifdim\pgf@x<-0.05pt% + \ifdim\pgf@y>0.05pt% + \def\tikz@anchor{south west}% + \else\ifdim\pgf@y<-0.05pt% + \def\tikz@anchor{south east}% + \else + \def\tikz@anchor{south}% + \fi\fi% + \else% + \ifdim\pgf@y>0pt% + \def\tikz@anchor{west}% + \else% + \def\tikz@anchor{east}% + \fi% + \fi\fi% +}% + + +% +% Callbacks: Please see the documentation of the graph drawing +% lib for info on these callbacks +% +\def\tikzgdeventcallback#1#2{}% +\def\tikzgdeventgroupcallback#1{}% +\def\tikzgdlatenodeoptionacallback#1{}% + +% Syntax for trees: +% node {...} child [options] {...} child [options] {...} ... +% node {...} child [options] foreach \var in {list} [options] {...} ... + +\def\tikz@children{% + % Start collecting the children: + \let\tikz@children@list=\pgfutil@empty% + \tikznumberofchildren=0\relax% + \tikz@collect@children c}% + +\def\tikz@collect@children{\pgfutil@ifnextchar c{\tikz@collect@children@cchar}{\tikz@children@collected}}% +\def\tikz@collect@children@cchar c{\pgfutil@ifnextchar h{\tikz@collect@child}{\tikz@children@collected c}}% +\def\tikz@collect@child hild{\pgfutil@ifnextchar[{\tikz@collect@childA}{\tikz@collect@childA[]}}%}% +\def\tikz@collect@childA[#1]{\pgfutil@ifnextchar f{\tikz@collect@children@foreach[#1]}{\tikz@collect@childB[#1]}}% +\def\tikz@collect@childB[#1]{% + \advance\tikznumberofchildren by1\relax + \expandafter\def\expandafter\tikz@children@list\expandafter{\tikz@children@list \tikz@childnode[#1]}% + \pgfutil@ifnextchar\bgroup{\tikz@collect@child@code}{\tikz@collect@child@code{}}}% +\def\tikz@collect@child@code#1{% + \expandafter\def\expandafter\tikz@children@list\expandafter{\tikz@children@list{#1}}% + \tikz@collect@children% +}% +\def\tikz@collect@children@foreach[#1]foreach#2in#3{% + \pgfutil@ifnextchar\bgroup{\tikz@collect@children@foreachA{#1}{#2}{#3}}{\tikz@collect@children@foreachA{#1}{#2}{#3}{}}}% +\def\tikz@collect@children@foreachA#1#2#3#4{% + \expandafter\def\expandafter\tikz@children@list\expandafter + {\tikz@children@list\tikz@childrennodes[#1]{#2}{#3}{#4}}% + \c@pgf@counta=\tikznumberofchildren% + \foreach#2in{#3}% + {% + \global\advance\c@pgf@counta by1\relax% + }% + \tikznumberofchildren=\c@pgf@counta% + \tikz@collect@children% +}% +\long\def\tikz@children@collected{% + \begingroup% + \advance\tikztreelevel by 1\relax% + \tikzgdeventgroupcallback{descendants}% + \let\tikz@options=\pgfutil@empty% + \tikz@clear@rdf@options% + \let\tikz@transform=\pgfutil@empty% + \tikzset{level/.try=\the\tikztreelevel,level \the\tikztreelevel/.try}% + \tikz@transform% + \let\tikz@transform=\relax% + \let\tikzparentnode=\tikz@last@fig@name% + \ifx\tikz@grow\relax\else% + % Transform to center of node + \pgftransformshift{\pgfpointanchor{\tikzparentnode}{\tikz@growth@anchor}}% + \fi% + \tikznumberofcurrentchild=0\relax% + \tikz@children@list% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \endgroup% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \tikz@scan@next@command% +}% + +% Syntax for children: +% +% child [all children options] foreach \var in {values} [child options] {...} +\def\tikz@childrennodes[#1]#2#3#4{% + \c@pgf@counta=\tikznumberofcurrentchild\relax% + \setbox\tikz@tempbox=\box\tikz@figbox% + \setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + \foreach#2in{#3}{% + \tikznumberofcurrentchild=\c@pgf@counta\relax% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% + \tikz@childnode[#1]{#4}% + % we must now make the current child number and the figbox survive + % the group + \global\c@pgf@counta=\tikznumberofcurrentchild\relax% + \global\setbox\tikz@tempbox=\box\tikz@figbox% + \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg% + }% + \tikznumberofcurrentchild=\c@pgf@counta\relax% + \setbox\tikz@figbox=\box\tikz@tempbox% + \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg% +}% + + +% Syntax for child: +% +% child +% +% child[options] +% +% child[options] {node (name) {child node text} ... +% edge from parent[options] node {label text} node {label text}} + +\def\tikz@childnode[#1]#2{% + \advance\tikznumberofcurrentchild by1\relax% + {\tikzset{every child/.try,#1}\expandafter}% + \iftikz@child@missing% + \tikzgdeventcallback{node}{}% + \else% + \setbox\tikz@whichbox=\hbox\bgroup% + \unhbox\tikz@whichbox% + \hbox\bgroup\bgroup% + \pgfinterruptpath% + \pgfscope% + \let\tikz@transform=\pgfutil@empty% + \tikzset{every child/.try,#1}% + \tikz@options% + \tikz@transform% + \let\tikz@transform=\relax% + \tikz@grow% + % Typeset node: + \edef\tikz@parent@node@name{[name=\tikzparentnode-\the\tikznumberofcurrentchild,style=every child node]}% + \def\tikz@child@node@text{[shape=coordinate]{}} + \tikz@parse@child@node#2\pgf@stop% + \expandafter\expandafter\expandafter\node + \expandafter\tikz@parent@node@name + \tikz@child@node@text + \pgfextra{\global\let\tikz@childnode@name=\tikz@last@fig@name};% + \let\tikzchildnode=\tikz@childnode@name% + {% + \def\tikz@edge@to@parent@needed{edge from parent} + \ifx\tikz@child@node@rest\pgfutil@empty% + \path edge from parent;% + \else% + \path \tikz@child@node@rest \tikz@edge@to@parent@needed;% + \fi% + }% + \endpgfscope% + \endpgfinterruptpath% + \egroup\egroup% + \egroup% + \fi% +}% + +\def\tikz@parse@child@node{% + \pgfutil@ifnextchar n{\tikz@parse@child@node@n}% + {\pgfutil@ifnextchar c{\tikz@parse@child@node@c}% + {\pgfutil@ifnextchar\pgf@stop\tikz@parse@child@node@rest\tikz@parse@child@node@expand}}}% +\def\tikz@parse@child@node@expand{% + \advance\tikz@expandcount by-1\relax% + \ifnum\tikz@expandcount<0\relax% + \expandafter\tikz@parse@child@node@rest% + \else% + \expandafter\expandafter\expandafter\tikz@parse@child@node% + \fi% +}% +\def\tikz@parse@child@node@rest#1\pgf@stop{\tikz@resetexpandcount\def\tikz@child@node@rest{#1}}% +\def\tikz@parse@child@node@c c{\tikz@resetexpandcount\pgfutil@ifnextchar o{\tikz@parse@child@node@co}{\tikz@parse@child@node@rest c}}% +\def\tikz@parse@child@node@co o{\pgfutil@ifnextchar o{\tikz@parse@child@node@coordinate}{\tikz@parse@child@node@rest co}}% +\def\tikz@parse@child@node@coordinate ordinate{% + \pgfutil@ifnextchar ({\tikz@@parse@child@node@coordinate}{% + \def\tikz@child@node@text{[shape=coordinate]{}}% + \tikz@parse@child@node@rest}}%}% +\def\tikz@@parse@child@node@coordinate(#1){% + \pgfutil@ifnextchar a{\tikz@p@c@n@c@at(#1)}{% + \def\tikz@child@node@text{[shape=coordinate,name=#1]{}}% + \tikz@parse@child@node@rest}}% +\def\tikz@p@c@n@c@at(#1)at#2({% + \def\tikz@child@node@text@pre{[shape=coordinate,name=#1]at}% + \tikz@scan@one@point\tikz@p@c@n@c@at@math(% +}% +\def\tikz@p@c@n@c@at@math#1{% + \pgf@process{#1}% + \edef\tikz@marshal{(\the\pgf@x,\the\pgf@y){}}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@child@node@text% + \expandafter\expandafter\expandafter{\expandafter\tikz@child@node@text@pre\tikz@marshal}% + \tikz@parse@child@node@rest% +}% +\def\tikz@parse@child@node@n node{\tikz@resetexpandcount% + \let\tikz@child@node@text=\pgfutil@empty% + \tikz@p@c@s}% +\def\tikz@p@c@s{% + \pgfutil@ifnextchar a{\tikz@p@c@s@at} + {\pgfutil@ifnextchar ({\tikz@p@c@s@paran} + {\pgfutil@ifnextchar [{\tikz@p@c@s@bra} + {\pgfutil@ifnextchar \bgroup{\tikz@p@c@s@group} + {\tikzerror{Cannot parse this node}}}}}}%}}% +\def\tikz@p@c@s@at at#1({% + \tikz@scan@one@point\tikz@p@c@s@at@math(% +}% +\def\tikz@p@c@s@at@math#1{% + \pgf@process{#1}% + \edef\tikz@marshal{ at(\the\pgf@x,\the\pgf@y)}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\tikz@child@node@text% + \expandafter\expandafter\expandafter{\expandafter\tikz@child@node@text\tikz@marshal} + \tikz@p@c@s}% +\def\tikz@p@c@s@paran(#1){% + \expandafter\def\expandafter\tikz@child@node@text\expandafter{\tikz@child@node@text(#1)} + \tikz@p@c@s}% +\def\tikz@p@c@s@bra[#1]{% + \expandafter\def\expandafter\tikz@child@node@text\expandafter{\tikz@child@node@text[#1]} + \tikz@p@c@s}% +\def\tikz@p@c@s@group#1{% + \iftikz@handle@active@nodes% + \expandafter\def\expandafter\tikz@child@node@text\expandafter{\tikz@child@node@text{\scantokens{#1}}}% + \else% + \expandafter\def\expandafter\tikz@child@node@text\expandafter{\tikz@child@node@text{#1}} + \fi% + \tikz@parse@child@node@rest% +}% + + + +% +% Syntax for decorated subpaths: +% +% decorate [option] { subpath } +% +\def\tikz@decoration ecorate{% + \pgfutil@ifnextchar[{\tikz@lib@decoration}{\tikz@lib@decoration[]}%] +}% + +\def\tikz@lib@decoration[#1]#2{\tikzerror{You need to load a decoration library}}% + +% The decorate path command: +\def\tikz@lib@dec@decorate@path{\tikzerror{You need to load a decoration library}}% + + + +% +% Syntax for let : +% +% let \p1 = (coordinate), \p2 = (coordinate),... in +% +\def\tikz@let@command et#1in{% + \tikzerror{You need to say \string\usetikzlibrary{calc} to use the let command}% + \tikz@scan@next@command% +}% + + +% +% Syntax for pictures: +% +% as for nodes, but with "pic" instead of "node" +% +\newif\iftikz@node@is@pic +\def\tikz@subpicture ic{\tikz@node@is@pictrue\tikz@scan@next@command node}% +\def\tikz@subpicture@handle#1{% + \pgfkeys@spdef\tikz@temp{#1}% + \expandafter\tikz@subpicture@handle@\expandafter{\tikz@temp}% +}% +\def\tikz@subpicture@handle@#1{ + \pgfkeys{/tikz/pics/.cd,#1}% + \tikz@node@transformations% + \let\tikz@transform=\relax% + \let\tikz@picmode\tikz@mode% + \tikzset{name prefix ../.style/.expanded={/tikz/name prefix=\pgfkeysvalueof{/tikz/name prefix}}}% + \ifx\tikz@fig@name\pgfutil@empty\else% + \tikzset{name prefix/.expanded=\tikz@fig@name}% + \fi% + \pgfkeysvalueof{/tikz/pics/setup code}% + \pgfkeysgetvalue{/tikz/pics/code}{\tikz@pic@code} + \ifx\tikz@pic@code\pgfutil@empty\else% + \setbox\tikz@whichbox=\hbox\bgroup% + \unhbox\tikz@whichbox% + \hbox\bgroup + \bgroup% + \pgfinterruptpath% + \pgfscope% + \tikz@options% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@atbegin@scope% + \scope[every pic/.try]% + \tikz@pic@code% + \endscope% + \tikz@atend@scope% + \endpgfscope% + \endpgfinterruptpath% + \egroup + \egroup% + \egroup% + \fi% + \pgfkeysgetvalue{/tikz/pics/foreground code}{\tikz@pic@code} + \ifx\tikz@pic@code\pgfutil@empty\else% + \setbox\tikz@figbox=\hbox\bgroup% + \unhbox\tikz@figbox% + \hbox\bgroup + \bgroup% + \pgfinterruptpath% + \pgfscope% + \tikz@options% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@atbegin@scope% + \scope[every front pic/.try]% + \tikz@pic@code% + \endscope% + \tikz@atend@scope% + \endpgfscope% + \endpgfinterruptpath% + \egroup + \egroup% + \egroup% + \fi% + \pgfkeysgetvalue{/tikz/pics/background code}{\tikz@pic@code} + \ifx\tikz@pic@code\pgfutil@empty\else% + \setbox\tikz@figbox@bg=\hbox\bgroup% + \unhbox\tikz@figbox@bg% + \hbox\bgroup + \bgroup% + \pgfinterruptpath% + \pgfscope% + \tikz@options% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \setbox\tikz@figbox@bg=\box\pgfutil@voidb@x% + \tikz@atbegin@scope% + \scope[every behind pic/.try]% + \tikz@pic@code% + \endscope% + \tikz@atend@scope% + \endpgfscope% + \endpgfinterruptpath% + \egroup + \egroup% + \egroup% + \fi% + \tikz@node@finish% +}% +\tikzset{ + pic actions/.code=\tikz@addmode{\tikz@picmode} +}% + +% Setting up the picture codes: +\tikzset{ + pics/setup code/.initial=, + pics/code/.initial=, + pics/background code/.initial=, + pics/foreground code/.initial= +}% + +% Defining pictures: + +\def\tikzdeclarepic#1#2{\pgfkeys{/tikz/#1/.cd,#2}}% + +\pgfkeysdef{/handlers/.pic}{% + \edef\pgf@temp{\pgfkeyscurrentpath}% + \edef\pgf@temp{\expandafter\tikz@smuggle@pics@in\pgf@temp\pgf@stop}% + \expandafter\pgfkeys\expandafter{\pgf@temp/.style={code={#1}}}% +}% +\def\tikz@smuggle@pics@in/tikz/#1\pgf@stop{/tikz/pics/#1}% + +% +% Timers +% + +\def\tikz@timer@line{% + \pgftransformlineattime{\tikz@time}{\tikz@timer@start}{\tikz@timer@end}% +}% + +\def\tikz@timer@vhline{% + \ifdim\tikz@time pt<0.5pt% first half + \pgf@process{\tikz@timer@start}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@timer@end}% + \pgf@xb=\tikz@time pt% + \pgf@xb=2\pgf@xb% + \edef\tikz@marshal{\noexpand\pgftransformlineattime{\pgf@sys@tonumber{\pgf@xb}}{\noexpand\tikz@timer@start}{% + \noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@y}}}% + \tikz@marshal% + \else% second half + \pgf@process{\tikz@timer@start}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@timer@end}% + \pgf@xb=\tikz@time pt% + \pgf@xb=2\pgf@xb% + \advance\pgf@xb by-1pt% + \edef\tikz@marshal{\noexpand\pgftransformlineattime{\pgf@sys@tonumber{\pgf@xb}}% + {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@y}}{\noexpand\tikz@timer@end}}% + \tikz@marshal% + \fi% +}% + +\def\tikz@timer@hvline{% + \ifdim\tikz@time pt<0.5pt% first half + \pgf@process{\tikz@timer@start}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@timer@end}% + \pgf@xb=\tikz@time pt% + \pgf@xb=2\pgf@xb% + \edef\tikz@marshal{\noexpand\pgftransformlineattime{\pgf@sys@tonumber{\pgf@xb}}{\noexpand\tikz@timer@start}{% + \noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@ya}}}% + \tikz@marshal% + \else% second half + \pgf@process{\tikz@timer@start}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\tikz@timer@end}% + \pgf@xb=\tikz@time pt% + \pgf@xb=2\pgf@xb% + \advance\pgf@xb by-1pt% + \edef\tikz@marshal{\noexpand\pgftransformlineattime{\pgf@sys@tonumber{\pgf@xb}}% + {\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@ya}}{\noexpand\tikz@timer@end}}% + \tikz@marshal% + \fi% +}% + +\def\tikz@timer@curve{% + \pgftransformcurveattime{\tikz@time}{\tikz@timer@start}{\tikz@timer@cont@one}{\tikz@timer@cont@two}{\tikz@timer@end}% +}% + + +\def\tikz@timer@arc{% + \pgfmathcos@{\tikz@timer@start@angle}% + \let\tikz@angle@cos\pgfmathresult% + \pgfmathsin@{\tikz@timer@start@angle}% + \let\tikz@angle@sin\pgfmathresult% + \pgftransformarcaxesattime{\tikz@time}{% + \pgfpointdiff{% + \pgfpointadd{% + \pgfpointscale{\tikz@angle@cos}{\tikz@timer@zero@axis}% + }{% + \pgfpointscale{\tikz@angle@sin}{\tikz@timer@ninety@axis}% + }% + }% + {\tikz@timer@start}% + }% + {\tikz@timer@zero@axis}% + {\tikz@timer@ninety@axis}% + {\tikz@timer@start@angle}{\tikz@timer@end@angle}% +}% + + + +% +% Coordinate systems +% + +\def\tikzdeclarecoordinatesystem#1#2{% + \expandafter\def\csname tikz@parse@cs@#1\endcsname(##1){% + \pgf@process{% + #2% + \global\let\tikz@smubble@b=\tikz@shapeborder@name% + }% + \let\tikz@shapeborder@name=\tikz@smubble@b% + \edef\tikz@return@coordinate{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% +}% +\def\tikzaliascoordinatesystem#1#2{% + \edef\pgf@marshal{\noexpand\let\expandafter\noexpand\csname + tikz@parse@cs@#1\endcsname=\expandafter\noexpand\csname + tikz@parse@cs@#2\endcsname}% + \pgf@marshal% +}% + + +% Default coordinate systems: + +\tikzdeclarecoordinatesystem{canvas} +{% + \tikzset{cs/.cd,x=0pt,y=0pt,#1}% + \pgfpoint{\tikz@cs@x}{\tikz@cs@y}% +}% + +\tikzdeclarecoordinatesystem{canvas polar} +{% + \tikzset{cs/.cd,angle=0,radius=0cm,#1}% + \pgfpointpolar{\tikz@cs@angle}{\tikz@cs@xradius and \tikz@cs@yradius}% +}% + +\tikzdeclarecoordinatesystem{xyz} +{% + \tikzset{cs/.cd,x=0,y=0,z=0,#1}% + \pgfpointxyz{\tikz@cs@x}{\tikz@cs@y}{\tikz@cs@z}% +}% + +\tikzdeclarecoordinatesystem{xyz polar} +{% + \tikzset{cs/.cd,angle=0,radius=0,#1}% + \pgfpointpolarxy{\tikz@cs@angle}{\tikz@cs@xradius and \tikz@cs@yradius}% +}% +\tikzaliascoordinatesystem{xy polar}{xyz polar}% + + +\tikzdeclarecoordinatesystem{node} +{% + \tikzset{cs/.cd,name=,anchor=none,angle=none,#1}% + \ifx\tikz@cs@anchor\tikz@nonetext% + \ifx\tikz@cs@angle\tikz@nonetext% + \expandafter\ifx\csname pgf@sh@ns@\tikz@cs@node\endcsname\tikz@coordinate@text% + \else + \aftergroup\tikz@shapebordertrue% + \edef\tikz@shapeborder@name{\tikz@pp@name{\tikz@cs@node}}% + \fi% + \pgfpointanchor{\tikz@pp@name{\tikz@cs@node}}{center}% + \else% + \pgfpointanchor{\tikz@pp@name{\tikz@cs@node}}{\tikz@cs@angle}% + \fi% + \else% + \pgfpointanchor{\tikz@pp@name{\tikz@cs@node}}{\tikz@cs@anchor}% + \fi% +}% + +% Intersection coordinates +\tikzset{cs/first line/.code=\def\tikz@cs@line@a{#1}\def\tikz@cs@type@a{line}}% +\tikzset{cs/second line/.code=\def\tikz@cs@line@b{#1}\def\tikz@cs@type@b{line}}% + +\tikzset{cs/first node/.code=\tikz@cs@unpack{\tikz@cs@node@a}{\tikz@cs@type@a}{#1}}% +\tikzset{cs/second node/.code=\tikz@cs@unpack{\tikz@cs@node@b}{\tikz@cs@type@b}{#1}}% + +\def\tikz@cs@unpack#1#2#3{% + \expandafter\ifx\csname pgf@sh@ns@#3\endcsname\relax% + \tikzerror{Undefined node ``#3''}% + \else% + \def#1{#3}% + \edef#2{\csname pgf@sh@ns@#3\endcsname}% + \fi% +}% + +\tikzset{cs/solution/.initial=1}% + +\tikzset{cs/horizontal line through/.store in=\tikz@cs@hori@line}% +\tikzset{cs/vertical line through/.store in=\tikz@cs@vert@line}% + +\tikzdeclarecoordinatesystem{intersection} +{% + \tikzset{cs/.cd,#1}% + \expandafter\ifx\csname tikz@intersect@\tikz@cs@type@a @and@\tikz@cs@type@b\endcsname\relax% + \tikzerror{I do not know how to compute the intersection + of a \tikz@cs@type@a and a \tikz@cs@type@b. Try saying + \string\usetikzlibrary{calc}}% + \pgfpointorigin% + \else% + \csname tikz@intersect@\tikz@cs@type@a @and@\tikz@cs@type@b\endcsname% + \fi% +}% + +\def\tikz@intersect@line@and@line{% + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@line\tikz@cs@line@a% + \pgf@xa=\pgf@xc% + \pgf@ya=\pgf@yc% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@line\tikz@cs@line@b% + \edef\pgf@marshal{% + {\noexpand\pgfpointintersectionoflines% + {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}% + {\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + {\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}}% + \pgf@marshal% +}% + +\def\tikz@parse@line#1--{% + \pgf@process{#1}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \tikz@scan@one@point\pgf@process% +}% + + +\tikzdeclarecoordinatesystem{perpendicular} +{% + \tikzset{cs/.cd,#1}% + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@intersection@a\tikz@cs@hori@line% + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@intersection@b\tikz@cs@vert@line% + \pgfqpoint{\the\pgf@xb}{\the\pgf@ya} +}% + +\tikzdeclarecoordinatesystem{barycentric} +{% + {% + \pgf@xa=0pt% point + \pgf@ya=0pt% + \pgf@xb=0pt% sum + \tikz@bary@dolist#1,=,% + \pgfmathparse{1/\the\pgf@xb}% + \global\pgf@x=\pgfmathresult\pgf@xa% + \global\pgf@y=\pgfmathresult\pgf@ya% + }% +}% + +\def\tikz@bary@dolist#1=#2,{% + \def\tikz@temp{#1}% + \ifx\tikz@temp\pgfutil@empty% + \else + \pgf@process{\pgfpointanchor{#1}{center}}% + \pgfmathparse{#2}% + \advance\pgf@xa by\pgfmathresult\pgf@x% + \advance\pgf@ya by\pgfmathresult\pgf@y% + \advance\pgf@xb by\pgfmathresult pt% + \expandafter\tikz@bary@dolist% + \fi% +}% + +\tikzset{cs/x/.store in=\tikz@cs@x}% +\tikzset{cs/y/.store in=\tikz@cs@y}% +\tikzset{cs/z/.store in=\tikz@cs@z}% +\tikzset{cs/angle/.store in=\tikz@cs@angle}% +\tikzset{cs/x radius/.store in=\tikz@cs@xradius}% +\tikzset{cs/y radius/.store in=\tikz@cs@yradius}% +\tikzset{cs/radius/.style={/tikz/cs/x radius={#1},/tikz/cs/y radius={#1}}}% +\tikzset{cs/name/.store in=\tikz@cs@node}% +\tikzset{cs/anchor/.store in=\tikz@cs@anchor}% + + + +% +% Coordinate management +% + + +% Last position visited +\def\tikz@last@position{\pgfqpoint{\tikz@lastx}{\tikz@lasty}}% +\def\tikz@last@position@saved{\pgfqpoint{\tikz@lastxsaved}{\tikz@lastysaved}}% + +% Make given point the last position visited +\def\tikz@make@last@position#1{% + \pgf@process{#1}% + \tikz@lastx=\pgf@x\relax% + \tikz@lasty=\pgf@y\relax% + \iftikz@updatecurrent% + \tikz@lastxsaved=\pgf@x\relax% + \tikz@lastysaved=\pgf@y\relax% + \fi% + \iftikz@updatenext + \tikz@updatecurrenttrue% + \fi +}% + +\newif\iftikz@updatecurrent +\tikz@updatecurrenttrue +\newif\iftikz@updatenext +\tikz@updatenexttrue + + + +% Scanner: Scans a point or a relative point. +% It then calls the first parameter with the argument set to an +% appropriate pgf command representing that point. + +\def\tikz@scan@one@point#1{% + \let\tikz@to@use@whom=\tikz@to@use@last@coordinate% + \tikz@shapeborderfalse% + \pgfutil@ifnextchar+{\tikz@scan@relative#1}{\tikz@scan@absolute#1}}% +\def\tikz@scan@absolute#1{% + \pgfutil@ifnextchar({\tikz@scan@@absolute#1}%) + {% + \advance\tikz@expandcount by -1 + \ifnum\tikz@expandcount<0\relax% + \let\pgfutil@next=\tikz@@scangiveup% + \else% + \let\pgfutil@next=\tikz@@scanexpand% + \fi% + \pgfutil@next{#1}% + }% +}% +\def\tikz@@scanexpand#1{\expandafter\tikz@scan@one@point\expandafter#1}% +\def\tikz@@scangiveup#1{\tikzerror{Cannot parse this coordinate}#1{\pgfpointorigin}}% +\def\tikz@scan@@absolute#1({% + \pgfutil@ifnextchar[% uhoh... options! + {\def\tikz@scan@point@recall{#1}\tikz@scan@options}% + {\tikz@@@scan@@absolute#1(}% +}% + +\def\tikz@scan@options[#1]#2{% + \def\tikz@scan@point@options{#1}% + \tikz@@@scan@@absolute\tikz@scan@handle@options(#2% +}% + +\def\tikz@scan@handle@options#1{% + {% + % Ok, compute point with options set and zero transformation + % matrix: + \pgftransformreset% + \let\tikz@transform=\pgfutil@empty% + \expandafter\tikzset\expandafter{\tikz@scan@point@options}% + \tikz@transform% + \pgf@process{\pgfpointtransformed{#1}}% + \xdef\tikz@marshal{\expandafter\noexpand\tikz@scan@point@recall{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + }% + \tikz@marshal% +}% + +\def\tikz@@@scan@@absolute#1({% + \pgfutil@ifnextchar{$}%$ + {\tikz@parse@calculator#1(} + {\tikz@scan@no@calculator#1(}% +}% +\def\tikz@scan@no@calculator#1(#2){% + \edef\tikz@scan@point@coordinate{(#2)}% + \expandafter\tikz@@scan@@no@calculator\expandafter#1\tikz@scan@point@coordinate% +}% +\def\tikz@@scan@@no@calculator#1(#2){% + \pgfutil@in@{cs:}{#2}% + \ifpgfutil@in@% + \let\pgfutil@next\tikz@parse@coordinatesystem% + \else% + \pgfutil@in@{intersection }{#2}% + \ifpgfutil@in@% + \let\pgfutil@next\tikz@parse@intersection% + \else% + \pgfutil@in@|{#2}% + \ifpgfutil@in@ + \pgfutil@in@{-|}{#2}% + \ifpgfutil@in@ + \let\pgfutil@next\tikz@parse@hv% + \else% + \let\pgfutil@next\tikz@parse@vh% + \fi% + \else% + \pgfutil@in@:{#2}% + \ifpgfutil@in@ + \let\pgfutil@next\tikz@parse@polar% + \else% + \pgfutil@in@,{#2}% + \ifpgfutil@in@% + \let\pgfutil@next\tikz@parse@regular% + \else% + \let\pgfutil@next\tikz@parse@node% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgfutil@next#1(#2)% +}% + +\def\tikz@parse@calculator#1($#2$){% + \tikzerror{You need to say \string\usetikzlibrary{calc} for coordinate calculation}% + #1{\pgfpointorigin}% +}% + +\def\tikz@parse@coordinatesystem#1(#2 cs:#3){% + \let\tikz@return@coordinate=\pgfpointorigin% + \pgfutil@ifundefined{tikz@parse@cs@#2} + {\tikzerror{Unknown coordinate system '#2'}} + {\csname tikz@parse@cs@#2\endcsname(#3)}% + \expandafter#1\expandafter{\tikz@return@coordinate}% +}% + + +\newif\iftikz@isdimension +\def\tikz@checkunit#1{% + \pgfmathparse{#1}% + \let\iftikz@isdimension=\ifpgfmathunitsdeclared% +}% + +\def\tikz@parse@polar#1(#2:#3){% + \pgfutil@ifundefined{tikz@polar@dir@#2} + {\tikz@@parse@polar#1({#2}:{#3})} + {\tikz@@parse@polar#1(\csname tikz@polar@dir@#2\endcsname:{#3})}% +}% +\def\tikz@@parse@polar#1(#2:#3){% + \pgfutil@in@{ and }{#3}% + \ifpgfutil@in@% + \edef\tikz@args{({#2}:#3)}% + \else% + \edef\tikz@args{({#2}:{#3} and {#3})}% + \fi% + \expandafter\tikz@@@parse@polar\expandafter#1\tikz@args% +}% +\def\tikz@@@parse@polar#1(#2:#3 and #4){% + \tikz@checkunit{#3}% + \iftikz@isdimension% + \tikz@checkunit{#4}% + \iftikz@isdimension% + \def\tikz@next{#1{\pgfpointpolar{#2}{#3 and #4}}}% + \else% + \tikzerror{You cannot mix dimension and dimensionless values for polar coordinates} + \def\tikz@next{#1{\pgfpointorigin}}% + \fi% + \else% + \tikz@checkunit{#4}% + \iftikz@isdimension% + \tikzerror{You cannot mix dimension and dimensionless values for polar coordinates} + \def\tikz@next{#1{\pgfpointorigin}}% + \else% + \def\tikz@next{#1{\pgfpointpolarxy{#2}{#3 and #4}}}% + \fi% + \fi% + \tikz@next% +}% +\def\tikz@polar@dir@up{90}% +\def\tikz@polar@dir@down{-90}% +\def\tikz@polar@dir@left{180}% +\def\tikz@polar@dir@right{0}% +\def\tikz@polar@dir@north{90}% +\def\tikz@polar@dir@south{-90}% +\def\tikz@polar@dir@east{0}% +\def\tikz@polar@dir@west{180}% +\expandafter\def\csname tikz@polar@dir@north east\endcsname{45}% +\expandafter\def\csname tikz@polar@dir@north west\endcsname{135}% +\expandafter\def\csname tikz@polar@dir@south east\endcsname{-45}% +\expandafter\def\csname tikz@polar@dir@south west\endcsname{-135}% + + +% MW: +% Check to see if the y-coordinate is inside {}. If it is, scan it and +% reinsert it into the stream inside an extra group. +% +\def\tikz@parse@regular#1(#2,{% + \pgfutil@ifnextchar\bgroup{\tikz@@parse@regular#1{#2}}{\tikz@@@parse@regular#1{#2}}% +}% +\def\tikz@@parse@regular#1#2#3{% + \pgfutil@ifnextchar[{% Uh oh! An array index. + \tikz@@@parse@regular#1{#2}{#3}}% + {\tikz@@@parse@regular#1{#2}{{#3}}}}% + +% Originally \def\tikz@parse@regular#1(#2,#3){% +% +\def\tikz@@@parse@regular#1#2#3){% + \pgfutil@in@,{#3}% + \ifpgfutil@in@% + \tikz@parse@splitxyz{#1}{#2}#3,% + \else% + \tikz@checkunit{#2}% + \iftikz@isdimension% + \tikz@checkunit{#3}% + \iftikz@isdimension% + \def\pgfutil@next{#1{\pgfpoint{#2}{#3}}}% + \else% + \def\pgfutil@next{#1{\pgfpointadd{\pgfpoint{#2}{0pt}}{\pgfpointxy{0}{#3}}}}% + \fi% + \else% + \tikz@checkunit{#3}% + \iftikz@isdimension% + \def\pgfutil@next{#1{\pgfpointadd{\pgfpoint{0pt}{#3}}{\pgfpointxy{#2}{0}}}}% + \else% + \def\pgfutil@next{#1{\pgfpointxy{#2}{#3}}}% + \fi% + \fi% + \fi% + \pgfutil@next% +}% + +\def\tikz@parse@splitxyz#1#2#3,#4,{% + \def\pgfutil@next{#1{\pgfpointxyz{#2}{#3}{#4}}}% +}% + +\def\tikz@coordinate@text{coordinate}% + +\def\tikz@parse@node#1(#2){% + \pgfutil@in@.{#2}% Ok, flag this + \ifpgfutil@in@ + \tikz@calc@anchor#2\tikz@stop% + \else% + \tikz@calc@anchor#2.center\tikz@stop% to be on the save side, in + % case iftikz@shapeborder is ignored... + \ifcsname pgf@sh@ns@\tikz@pp@name{#2}\endcsname + \expandafter\ifx\csname pgf@sh@ns@\tikz@pp@name{#2}\endcsname\tikz@coordinate@text% + \else + \tikz@shapebordertrue% + \def\tikz@shapeborder@name{\tikz@pp@name{#2}}% + \fi% + \else\ifcsname pgf@sh@ns@#2\endcsname + \expandafter\ifx\csname pgf@sh@ns@#2\endcsname\tikz@coordinate@text% + \else + \tikz@shapebordertrue% + \def\tikz@shapeborder@name{#2}% + \fi% + \fi\fi + \fi% + \edef\tikz@marshal{\noexpand#1{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + \tikz@marshal% +}% + +\def\tikz@calc@anchor#1.#2\tikz@stop{% + % Check if a shape with name prefix exists, otherwise try the global name + % without prefix. + \ifcsname pgf@sh@ns@\tikz@pp@name{#1}\endcsname% + \pgfpointanchor{\tikz@pp@name{#1}}{#2}% + \else + \pgfpointanchor{#1}{#2}% + \fi +}% + + +\def\tikz@parse@hv#1(#2){% + \pgfutil@in@{ -| }{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@hvboth% + \else% + \pgfutil@in@{ -|}{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@hvleft% + \else% + \pgfutil@in@{-| }{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@hvright% + \else% + \let\tikz@next=\tikz@parse@hvdone% + \fi% + \fi% + \fi% + \tikz@next#1(#2)}% +\def\tikz@parse@hvboth#1(#2 -| #3){\tikz@parse@vhdone#1({#3}|-{#2})}% +\def\tikz@parse@hvleft#1(#2 -|#3){\tikz@parse@vhdone#1({#3}|-{#2})}% +\def\tikz@parse@hvright#1(#2-| #3){\tikz@parse@vhdone#1({#3}|-{#2})}% +\def\tikz@parse@hvdone#1(#2-|#3){\tikz@parse@vhdone#1({#3}|-{#2})}% + +\def\tikz@parse@vh#1(#2){% + \pgfutil@in@{ |- }{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@vhboth% + \else% + \pgfutil@in@{ |-}{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@vhleft% + \else% + \pgfutil@in@{|- }{#2}% + \ifpgfutil@in@% + \let\tikz@next=\tikz@parse@vhright% + \else% + \let\tikz@next=\tikz@parse@vhdone% + \fi% + \fi% + \fi% + \tikz@next#1(#2)}% +\def\tikz@parse@vhboth#1(#2 |- #3){\tikz@parse@vhdone#1({#2}|-{#3})}% +\def\tikz@parse@vhleft#1(#2 |-#3){\tikz@parse@vhdone#1({#2}|-{#3})}% +\def\tikz@parse@vhright#1(#2|- #3){\tikz@parse@vhdone#1({#2}|-{#3})}% +\def\tikz@parse@vhdone#1(#2|-#3){% + {% + \tikz@@@scan@@absolute\tikz@parse@vh@mid(#2)% + \tikz@@@scan@@absolute\tikz@parse@vh@end(#3)% + \xdef\tikz@marshal{\noexpand#1{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}}% + }% + \tikz@marshal% +}% +\def\tikz@parse@vh@mid#1{\pgf@process{#1}\pgf@xa=\pgf@x}% +\def\tikz@parse@vh@end#1{\pgf@process{#1}\pgf@ya=\pgf@y}% + +\def\tikz@parse@intersection#1(intersection{% + \pgfutil@ifnextchar o{% + \tikz@parse@main@intersection#1 1% + }{% + \tikz@parse@main@intersection#1% + }% +}% +\def\tikz@parse@main@intersection#1#2of #3 and #4){% + \tikzset{cs/solution={#2}}% + \pgfutil@in@{--}{#3}% + \ifpgfutil@in@% + \tikz@reparse@line{first}#3\pgf@stop% + \else% + \tikzset{cs/first node={#3}}% + \fi% + \pgfutil@in@{--}{#4}% + \ifpgfutil@in@% + \tikz@reparse@line{second}#4\pgf@stop% + \else% + \tikzset{cs/second node={#4}}% + \fi% + \tikz@parse@cs@intersection()% advanced hackery... + \edef\pgf@marshal{\noexpand#1{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + \pgf@marshal% +}% +\def\tikz@reparse@line#1#2--#3\pgf@stop{% + \tikzset{cs/#1 line={(#2)--(#3)}}% +}% + + +\def\tikz@parse@intersection@a#1{\pgf@process{#1}\pgf@xa=\pgf@x\pgf@ya=\pgf@y}% +\def\tikz@parse@intersection@b#1{\pgf@process{#1}\pgf@xb=\pgf@x\pgf@yb=\pgf@y}% + +\def\tikz@scan@relative#1+{% + \pgfutil@ifnextchar+{\tikz@scan@plusplus#1}{\tikz@scan@oneplus#1}}% + +\def\tikz@scan@plusplus#1+{% + \def\tikz@doafter{#1}% + \tikz@scan@absolute\tikz@add% +}% +\def\tikz@add#1{% + \tikz@doafter{\pgfpointadd{#1}{\tikz@last@position@saved}}% +}% +\def\tikz@scan@oneplus#1{% + \def\tikz@doafter{#1}% + \tikz@updatecurrentfalse% + \tikz@scan@absolute\tikz@add% +}% + + + +% +% Quote handling +% + +\let\tikz@enable@node@quotes\relax +\let\tikz@enable@edge@quotes\relax +\let\tikz@enable@pic@quotes\relax + + + +% Loading further libraries + +% Include a library file. +% +% #1 = List of names of library file. +% +% Description: +% +% This command includes a list of TikZ library files. For each file X in the +% list, the file tikzlibraryX.code.tex is included, provided this has +% not been done earlier. +% +% For the convenience of Context users, both round and square brackets +% are possible for the argument. +% +% If no file tikzlibraryX.code.tex exists, the file +% pgflibraryX.code.tex is tried instead. If this file, also, does not +% exist, an error message is printed. +% +% Example: +% +% \usetikzlibrary{arrows} +% \usetikzlibrary[patterns,topaths] + +\def\usetikzlibrary{\pgfutil@ifnextchar[{\use@tikzlibrary}{\use@@tikzlibrary}}%}% +\def\use@tikzlibrary[#1]{\use@@tikzlibrary{#1}}% +\def\use@@tikzlibrary#1{% + \edef\pgf@list{#1}% + \pgfutil@for\pgf@temp:=\pgf@list\do{% + \expandafter\pgfkeys@spdef\expandafter\pgf@temp\expandafter{\pgf@temp}% + \ifx\pgf@temp\pgfutil@empty + \else + \expandafter\ifx\csname tikz@library@\pgf@temp @loaded\endcsname\relax% + \expandafter\global\expandafter\let\csname tikz@library@\pgf@temp @loaded\endcsname=\pgfutil@empty% + \expandafter\edef\csname tikz@library@#1@atcode\endcsname{\the\catcode`\@} + \expandafter\edef\csname tikz@library@#1@barcode\endcsname{\the\catcode`\|} + \expandafter\edef\csname tikz@library@#1@dollarcode\endcsname{\the\catcode`\$} + \catcode`\@=11 + \catcode`\|=12 + \catcode`\$=3 + \pgfutil@InputIfFileExists{tikzlibrary\pgf@temp.code.tex}{}{ + \pgfutil@IfFileExists{pgflibrary\pgf@temp.code.tex}{% + \expandafter\usepgflibrary\expandafter{\pgf@temp}% + }{% + \tikzerror{I did not find the tikz library + '\pgf@temp'. I looked for files named + tikzlibrary\pgf@temp.code.tex and + pgflibrary\pgf@temp.code.tex, but neither + could be found in the current texmf trees.} + }}% + \catcode`\@=\csname tikz@library@#1@atcode\endcsname + \catcode`\|=\csname tikz@library@#1@barcode\endcsname + \catcode`\$=\csname tikz@library@#1@dollarcode\endcsname + \fi% + \fi + }% +}% + + +% Always-present libraries: + +\usetikzlibrary{topaths}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/LUA_CODING_STYLE b/graphics/pgf/base/tex/generic/graphdrawing/lua/LUA_CODING_STYLE new file mode 100644 index 0000000000..295a8b2ed1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/LUA_CODING_STYLE @@ -0,0 +1,27 @@ +Lua coding style for the graphdrawing library +============================================= + +General naming rules and indentation: + + * 2 spaces indentation + * variable_names_with_underscores + * namespaced.low_level_functions_with_underscores(foo, bar) + * CamelCaseClassNames + * CamelCaseClassNames.nameOfStaticFunctionLikeNewOrClone(foo, bar) + * CamelCaseClass:functionNamesLikeThis(foo, bar) + * never use global variables + * Use . for static functions and : for member functions + +LuaDoc comments: + + --- + -- A function to do this and that. + -- + -- @param first Description of the first parameter. + -- @param second Description of the second parameter. + -- + -- @return This function returns something. + -- + function myClass:myFunction(first, second) + ... + end diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf.lua new file mode 100644 index 0000000000..b0a3247616 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf.lua @@ -0,0 +1,72 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- The |pgf| namespace lies in the global namespace. It is the only +-- global table defined by \pgfname. The whole graph drawing system, +-- in turn, lies in the table |pgf.gd|. + +pgf = {} + + + +-- Forward +local tostring_table + +--- +-- Writes debug info on the \TeX\ output, separating the parameters +-- by spaces. The debug information will include a complete traceback +-- of the stack, allowing you to see ``where you are'' inside the Lua +-- program. +-- +-- Note that this function resides directly in the |pgf| table. The +-- reason for this is that you can ``always use it'' since |pgf| is +-- always available in the global name space. +-- +-- @param ... List of parameters to write to the \TeX\ output. + +function pgf.debug(...) + local stacktrace = debug.traceback("",2) + texio.write_nl(" ") + texio.write_nl("Debug called for: ") + -- this is to even print out nil arguments in between + local args = {...} + for i = 1, #args do + if i ~= 1 then texio.write(", ") end + texio.write(tostring_table(args[i], "", 5)) + end + texio.write_nl('') + for w in string.gmatch(stacktrace, "/.-:.-:.-%c") do + texio.write('by ', string.match(w,".*/(.*)")) + end +end + + +-- Helper function + +function tostring_table(t, prefix, depth) + if type(t) ~= "table" or (getmetatable(t) and getmetatable(t).__tostring) or depth <= 0 then + return type(t) == "string" and ('"' .. t .. '"') or tostring(t) + else + local r = "{\n" + for k,v in pairs(t) do + r = r .. prefix .. " " .. tostring(k) .. "=" .. + (v==t and "self" or tostring_table(v, prefix .. " ", depth-1)) .. ",\n" + end + return r .. prefix .. "}" + end +end + + + + +return pgf \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd.lua new file mode 100644 index 0000000000..20d8acafa5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd.lua @@ -0,0 +1,72 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + + +-- Declare the gd namespace + +local gd = {} +require("pgf").gd = gd + + + + + + + +-- Deprecated: +-- +-- +-- Helping function for creating new algorithm classes +-- +-- This function creates a new algorithm class. This class will have a +-- new method, that takes a graph and, optionally, a parent algorithm +-- as inputs. They will be stored in the "graph" and "parent_algorithm" +-- fields, respectively. +-- +-- @param info This table is used to configure the new class. It has +-- the following fields: First, there is the "properties" table. If +-- this table is present, it will be used as the default table. Second, +-- it can have a graph_parameters table. This table will be used in the +-- constructor to preload graph parameters from the pgf layer. For +-- this, each entry of the table should be of the form +-- +-- key = 'string' +-- +-- What happens is that upon the creation of a new algorithm object, +-- for each key we lookup the graph option 'string' and +-- store its value in the key of the new algorithm object. +-- +-- @return A table that is a class with a new function setup. + +function gd.new_algorithm_class (class) + class.__index = class + class.new = + function (initial) + + -- Create new object + local obj = {} + for k,v in pairs(initial) do + obj[k] = v + end + setmetatable(obj, class) + + return obj + end + class.preconditions = {} + class.postconditions = {} + + return class +end + + +return gd diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings.lua new file mode 100644 index 0000000000..410da3af45 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.bindings = {} + + +-- Done + +return pgf.gd.bindings \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/Binding.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/Binding.lua new file mode 100644 index 0000000000..6ffb4168f5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/Binding.lua @@ -0,0 +1,265 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local Storage = require "pgf.gd.lib.Storage" + + +--- +-- This class provides a (non-functional) default implementation of a +-- binding between a display layer and the algorithm layer. Subclasses +-- must implement most of the member functions declared in this class. +-- +-- A instance of a subclass of this class encapsulates the complete +-- implementation of all specific code needed for the communication +-- between the display layer and the graph drawing engine. +-- +-- Note that you never call the methods of a |Binding| object +-- directly, neither from the display layer nor from the algorithm +-- layer. Instead, you use the more powerful and more easy to use +-- functions from |InterfaceToDisplay| and +-- |InterfaceToAlgorithms|. They call the appropriate |Binding| +-- methods internally. +-- +-- Because of the above, in order to use the graph drawing system +-- inside a new display layer, you need to subclass |Binding| and +-- implement all the functions. Then you need to write the display +-- layer in such a way that it calls the appropriate functions from +-- |InterfaceToDisplay|. +-- +-- @field storage A |Storage| storing the information passed from the +-- display layer. The interpretation of this left to the actual +-- binding. + +local Binding = { + storage = Storage.newTableStorage () +} +Binding.__index = Binding + +-- Namespace +require("pgf.gd.bindings").Binding = Binding + + + + + +-- +-- This method gets called whenever the graph drawing coroutine should +-- be resumed. First, the binding layer should ask the display layer +-- to execute the |code|, then, after this is done, the function +-- |InterfaceToDisplay.resumeGraphDrawingCoroutine| should be called +-- by this function. +-- +-- @param code Some code to be executed by the display layer. + +function Binding:resumeGraphDrawingCoroutine(code) + -- Does nothing by default +end + + +--- +-- Declare a new key. This callback is called by |declare|. It is the job +-- of the display layer to make the parameter |t.key| available to the +-- parsing process. Furthermore, if |t.initial| is not |nil|, the +-- display layer must convert it into a value that is stored as the +-- initial value and call |InterfaceToDisplay.setOptionInitial|. +-- +-- @param t See |InterfaceToAlgorithms.declare| for details. + +function Binding:declareCallback(t) + -- Does nothing by default +end + + + + +-- Rendering + +--- +-- This function and, later on, |renderStop| are called whenever the +-- rendering of a laid-out graph starts or stops. See +-- |InterfaceToDisplay.render| for details. + +function Binding:renderStart() + -- Does nothing by default +end + +--- +-- See |renderStart|. + +function Binding:renderStop() + -- Does nothing by default +end + + + + + +--- +-- This function and the corresponding |...Stop...| functions are +-- called whenever a collection kind should be rendered. See +-- |InterfaceToDisplay.render_collections| for details. +-- +-- @param kind The kind (a string). +-- @param layer The kind's layer (a number). + +function Binding:renderCollectionStartKind(kind, layer) + -- Does nothing by default +end + + +--- +-- The counterpart to |renderCollectionStartKind|. +-- +-- @param kind The kind. +-- @param layer The kind's layer. + +function Binding:renderCollectionStopKind(kind, layer) + -- Does nothing by default +end + + +--- +-- Renders a single collection, see |renderCollectionStartKind| for +-- details. +-- +-- @param collection The collection object. + +function Binding:renderCollection(collection) + -- Does nothing by default +end + + + +--- +-- This function and the corresponding |...Stop...| functions are +-- called whenever a vertex should be rendered. See +-- |InterfaceToDisplay.render_vertices| for details. +-- + +function Binding:renderVerticesStart() + -- Does nothing by default +end + + +--- +-- The counterpart to |renderVerticesStop|. +-- + +function Binding:renderVerticesStop() + -- Does nothing by default +end + + +--- +-- Renders a single vertex, see |renderVertexStartKind| for +-- details. +-- +-- @param vertex The |Vertex| object. + +function Binding:renderVertex(vertex) + -- Does nothing by default +end + + + +--- +-- This method is called by the interface to the display layer after +-- the display layer has called |createVertex| to create a new +-- vertex. After having done its internal bookkeeping, the interface +-- calls this function to allow the binding to perform further +-- bookkeeping on the node. Typically, this will be done using the +-- information stored in |Binding.infos|. +-- +-- @param v The vertex. + +function Binding:everyVertexCreation(v) + -- Does nothing by default +end + + + + + +--- +-- This function and the corresponding |...Stop...| functions are +-- called whenever an edge should be rendered. See +-- |InterfaceToDisplay.render_edges| for details. +-- + +function Binding:renderEdgesStart() + -- Does nothing by default +end + + +--- +-- The counterpart to |renderEdgesStop|. +-- + +function Binding:renderEdgesStop() + -- Does nothing by default +end + + +--- +-- Renders a single vertex, see |renderEdgeStartKind| for +-- details. +-- +-- @param edge The |Edge| object. + +function Binding:renderEdge(edge) + -- Does nothing by default +end + + +--- +-- Like |everyVertexCreation|, only for edges. +-- +-- @param e The edge. + +function Binding:everyEdgeCreation(e) + -- Does nothing by default +end + + +--- +-- Generate a new vertex. This method will be called when the +-- \emph{algorithm} layer wishes to trigger the creation of a new +-- vertex. This call will be made while an algorithm is running. It is +-- now the job of the binding to cause the display layer to create the +-- node. This is done by calling the |yield| method of the scope's +-- coroutine. +-- +-- @param init A table of initial values for the node. The following +-- fields will be used: +-- % +-- \begin{itemize} +-- \item |name| If present, this name will be given to the +-- node. If not present, an internal name is generated. Note that, +-- unless the node is a subgraph node, this name may not be the name +-- of an already present node of the graph; in this case an error +-- results. +-- \item |shape| If present, a shape of the node. +-- \item |generated_options| A table that is passed back to the +-- display layer as a list of key--value pairs. +-- \item |text| The text of the node, to be passed back to the +-- higher layer. This is what should be displayed as the node's text. +-- \end{itemize} + +function Binding:createVertex(init) + -- Does nothing by default +end + + + + +return Binding \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua new file mode 100644 index 0000000000..5324a1652e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua @@ -0,0 +1,374 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +-- Imports +local Storage = require "pgf.gd.lib.Storage" + + +--- +-- This class, which is a subclass of |Binding|, binds the graph +-- drawing system to the \pgfname\ display system by overriding (that +-- is, implementing) the methods of the |Binding| class. As a typical +-- example, consider the implementation of the function |renderVertex|: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--function BindingToPGF:renderVertex(v) +-- local info = assert(self.infos[v], "thou shalt not modify the syntactic digraph") +-- tex.print( +-- string.format( +-- "\\pgfgdcallbackrendernode{%s}{%fpt}{%fpt}{%fpt}{%fpt}{%fpt}{%fpt}{%s}", +-- 'not yet positionedPGFINTERNAL' .. v.name, +-- info.x_min, +-- info.x_max, +-- info.y_min, +-- info.y_max, +-- v.pos.x, +-- v.pos.y, +-- info.box_count)) +--end +--\end{codeexample} +-- +-- As can be seen, the main job of this function is to call a function +-- on the \TeX\ layer that is called |\pgfgdcallbackrendernode|, which gets +-- several parameters like the name of the to-be-rendered node or the +-- (new) position for the node. For almost all methods of the +-- |Binding| class there is a corresponding ``callback'' macro on the +-- \TeX\ layer, all of which are implemented in the \pgfname\ library +-- |graphdrawing|. For details on these callbacks, +-- please consult the code of that file and of the class +-- |BindingToPGF| (they are not documented here since they are local +-- to the binding and should not be called by anyone other than the +-- binding class). + +local BindingToPGF = { + storage = Storage.newTableStorage () -- overwrite default storage +} +BindingToPGF.__index = BindingToPGF +setmetatable(BindingToPGF, require "pgf.gd.bindings.Binding") -- subclass of Binding + + +-- Namespace +require("pgf.gd.bindings").BindingToPGF = BindingToPGF + +-- Imports +local lib = require "pgf.gd.lib" + +local Coordinate = require "pgf.gd.model.Coordinate" +local Path = require "pgf.gd.model.Path" + +-- The implementation + +-- Forward +local table_in_pgf_syntax +local animations_in_pgf_syntax +local path_in_pgf_syntax +local coordinate_in_pgf_syntax + + + + +-- Scope handling + +function BindingToPGF:resumeGraphDrawingCoroutine(text) + tex.print(text) + tex.print("\\pgfgdresumecoroutinetrue") +end + + +-- Declarations + +function BindingToPGF:declareCallback(t) + tex.print("\\pgfgdcallbackdeclareparameter{" .. t.key .. "}{" .. (t.type or "nil") .. "}") +end + + + +-- Rendering + +function BindingToPGF:renderStart() + tex.print("\\pgfgdcallbackbeginshipout") +end + +function BindingToPGF:renderStop() + tex.print("\\pgfgdcallbackendshipout") +end + + +-- Rendering collections + +function BindingToPGF:renderCollection(collection) + tex.print("\\pgfgdcallbackrendercollection{".. collection.kind .. "}{" + .. table_in_pgf_syntax(collection.generated_options) .. "}") +end + +function BindingToPGF:renderCollectionStartKind(kind, layer) + tex.print("\\pgfgdcallbackrendercollectionkindstart{" .. kind .. "}{" .. tostring(layer) .. "}") +end + +function BindingToPGF:renderCollectionStopKind(kind, layer) + tex.print("\\pgfgdcallbackrendercollectionkindstop{" .. kind .. "}{" .. tostring(layer) .. "}") +end + +-- Printing points + +local function to_pt(x) + return string.format("%.12fpt", x) +end + + +-- Managing vertices (pgf nodes) + +local boxes = {} +local box_count = 0 + +function BindingToPGF:everyVertexCreation(v) + local info = self.storage[v] + + -- Save the box! + box_count = box_count + 1 + boxes[box_count] = node.copy_list(tex.box[info.tex_box_number]) + + -- Special tex stuff, should not be considered by gd algorithm + info.box_count = box_count +end + +function BindingToPGF:renderVertex(v) + local info = assert(self.storage[v], "thou shalt not modify the syntactic digraph") + tex.print( + string.format( + "\\pgfgdcallbackrendernode{%s}{%.12fpt}{%.12fpt}{%.12fpt}{%.12fpt}{%.12fpt}{%.12fpt}{%s}{%s}", + 'not yet positionedPGFINTERNAL' .. v.name, + info.x_min, + info.x_max, + info.y_min, + info.y_max, + v.pos.x, + v.pos.y, + info.box_count, + animations_in_pgf_syntax(v.animations))) +end + +function BindingToPGF:retrieveBox(index, box_num) + tex.box[box_num] = assert(boxes[index], "no box stored at given index") + boxes[index] = nil -- remove from memory +end + +function BindingToPGF:renderVerticesStart() + tex.print("\\pgfgdcallbackbeginnodeshipout") +end + +function BindingToPGF:renderVerticesStop() + tex.print("\\pgfgdcallbackendnodeshipout") +end + + +local function rigid(x) + if type(x) == "function" then + return x() + else + return x + end +end + + +-- Managing edges + +function BindingToPGF:renderEdge(e) + local info = assert(self.storage[e], "thou shalt not modify the syntactic digraph") + + local function get_anchor(e, anchor) + local a = e.options[anchor] + if a and a ~= "" then + return "." .. a + else + return "" + end + end + + local callback = { + '\\pgfgdcallbackedge', + '{', e.tail.name .. get_anchor(e, "tail anchor"), '}', + '{', e.head.name .. get_anchor(e, "head anchor"), '}', + '{', e.direction, '}', + '{', info.pgf_options or "", '}', + '{', info.pgf_edge_nodes or "", '}', + '{', table_in_pgf_syntax(e.generated_options), '}', + '{' + } + + local i = 1 + while i <= #e.path do + local c = e.path[i] + assert (type(c) == "string", "illegal path operand") + + if c == "lineto" then + i = i + 1 + local d = rigid(e.path[i]) + callback [#callback + 1] = '--(' .. to_pt(d.x) .. ',' .. to_pt(d.y) .. ')' + i = i + 1 + elseif c == "moveto" then + i = i + 1 + local d = rigid(e.path[i]) + callback [#callback + 1] = '(' .. to_pt(d.x) .. ',' .. to_pt(d.y) .. ')' + i = i + 1 + elseif c == "closepath" then + callback [#callback + 1] = '--cycle' + i = i + 1 + elseif c == "curveto" then + local d1, d2, d3 = rigid(e.path[i+1]), rigid(e.path[i+2]), rigid(e.path[i+3]) + i = i + 3 + callback [#callback + 1] = '..controls(' .. to_pt(d1.x) .. ',' .. to_pt(d1.y) .. ')and(' + .. to_pt(d2.x) .. ',' .. to_pt(d2.y) .. ')..' + callback [#callback + 1] = '(' .. to_pt(d3.x) .. ',' .. to_pt(d3.y) .. ')' + i = i + 1 + else + error("illegal operation in edge path") + end + end + + callback [#callback + 1] = '}' + callback [#callback + 1] = '{' .. animations_in_pgf_syntax(e.animations) .. '}' + + -- hand TikZ code over to TeX + tex.print(table.concat(callback)) +end + + +function BindingToPGF:renderEdgesStart() + tex.print("\\pgfgdcallbackbeginedgeshipout") +end + +function BindingToPGF:renderEdgesStop() + tex.print("\\pgfgdcallbackendedgeshipout") +end + + +-- Vertex creation + +function BindingToPGF:createVertex(init) + -- Now, go back to TeX... + coroutine.yield( + table.concat({ + "\\pgfgdcallbackcreatevertex{", init.name, "}", + "{", init.shape, "}", + "{", table_in_pgf_syntax(init.generated_options), ",", init.pgf_options or "", "}", + "{", (init.text or ""), "}" + })) + -- ... and come back with a new node! +end + + + +-- Local helpers + +function table_in_pgf_syntax (t) + local prefix = "/graph drawing/" + local suffix = "/.try" + return table.concat( lib.imap( t, function(table) + if table.value then + return prefix .. table.key .. suffix .. "={" .. tostring(table.value) .. "}" + else + return prefix .. table.key .. suffix + end + end), ",") +end + + +function animations_in_pgf_syntax (a) + return + table.concat( + lib.imap( + a, + function(animation) + return "\\pgfanimateattribute{" .. animation.attribute .. "}{whom=pgf@gd," .. + table.concat( + lib.imap ( + animation.entries, + function (entry) + return "entry={" .. entry.t .. "s}{" .. to_pgf(entry.value) .. "}" + end + ), ",") .. + "," .. + table.concat( + lib.imap( + animation.options or {}, + function(table) + if table.value then + return table.key .. "={" .. to_pgf(table.value) .. "}" + else + return table.key + end + end), ",") + .. "}" + end) + ) +end + + +function to_pgf(x) + if type (x) == "table" then + if getmetatable(x) == Coordinate then + return coordinate_in_pgf_syntax(x) + elseif getmetatable(x) == Path then + return path_in_pgf_syntax(x) + else + error("illegal table in value of a key to be passed back to pgf") + end + else + return tostring(x) + end +end + +function path_in_pgf_syntax (p) + + local s = {} + + local i = 1 + while i <= #p do + local c = p[i] + assert (type(c) == "string", "illegal path operand") + + if c == "lineto" then + i = i + 1 + local d = rigid(p[i]) + s [#s + 1] = '\\pgfpathlineto{\\pgfqpoint{' .. to_pt(d.x) .. '}{' .. to_pt(d.y) .. '}}' + i = i + 1 + elseif c == "moveto" then + i = i + 1 + local d = rigid(p[i]) + s [#s + 1] = '\\pgfpathmoveto{\\pgfqpoint{' .. to_pt(d.x) .. '}{' .. to_pt(d.y) .. '}}' + i = i + 1 + elseif c == "closepath" then + s [#s + 1] = '\\pgfpathclose' + i = i + 1 + elseif c == "curveto" then + local d1, d2, d3 = rigid(p[i+1]), rigid(p[i+2]), rigid(p[i+3]) + i = i + 3 + s [#s + 1] = '\\pgfpathcurveto{\\pgfqpoint{' .. to_pt(d1.x) .. '}{' .. to_pt(d1.y) .. '}}{\\pgfqpoint{' + .. to_pt(d2.x) .. '}{' .. to_pt(d2.y) .. '}}{\\pgfqpoint{' + .. to_pt(d3.x) .. '}{' .. to_pt(d3.y) .. '}}' + i = i + 1 + else + error("illegal operation in edge path") + end + end + + return table.concat(s) +end + +function coordinate_in_pgf_syntax(c) + return '\\pgfqpoint{'..to_pt(c.x) .. '}{'.. to_pt(c.y) .. '}' +end + + +return BindingToPGF diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular.lua new file mode 100644 index 0000000000..cddfd96dfd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular.lua @@ -0,0 +1,22 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +local circular = {} + +-- Declare namespace +require("pgf.gd").circular = circular + + +-- Done + +return circular \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua new file mode 100644 index 0000000000..bebb87ab3e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua @@ -0,0 +1,153 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +local routing = require("pgf.gd.routing") + +-- The algorithm class +local Tantau2012 = {} + +--- +declare { + key = "simple necklace layout", + algorithm = Tantau2012, + + postconditions = { + upward_oriented = true + }, + + documentation_in = "pgf.gd.circular.doc" +} + + + +-- Imports + +local Coordinate = require "pgf.gd.model.Coordinate" +local Hints = require "pgf.gd.routing.Hints" + +local lib = require "pgf.gd.lib" + + + + +-- The implementation + +function Tantau2012:run() + local g = self.ugraph + local vertices = g.vertices + local n = #vertices + + local sib_dists = self:computeNodeDistances () + local radii = self:computeNodeRadii() + local diam, adjusted_radii = self:adjustNodeRadii(sib_dists, radii) + + -- Compute total necessary length. For this, iterate over all + -- consecutive pairs and keep track of the necessary space for + -- this node. We imagine the nodes to be aligned from left to + -- right in a line. + local carry = 0 + local positions = {} + local function wrap(i) return (i-1)%n + 1 end + local ideal_pos = 0 + for i = 1,n do + positions[i] = ideal_pos + carry + ideal_pos = ideal_pos + sib_dists[i] + local node_sep = + lib.lookup_option('node post sep', vertices[i], g) + + lib.lookup_option('node pre sep', vertices[wrap(i+1)], g) + local arc = node_sep + adjusted_radii[i] + adjusted_radii[wrap(i+1)] + local needed = carry + arc + local dist = math.sin( arc/diam ) * diam + needed = needed + math.max ((radii[i] + radii[wrap(i+1)]+node_sep)-dist, 0) + carry = math.max(needed-sib_dists[i],0) + end + local length = ideal_pos + carry + + local radius = length / (2 * math.pi) + for i,vertex in ipairs(vertices) do + vertex.pos.x = radius * math.cos(2 * math.pi * (positions[i] / length + 1/4)) + vertex.pos.y = -radius * math.sin(2 * math.pi * (positions[i] / length + 1/4)) + end + + -- Add routing infos + local necklace = lib.icopy({g.vertices[1]}, lib.icopy(g.vertices)) + Hints.addNecklaceCircleHint(g, necklace, nil, true) +end + + +function Tantau2012:computeNodeDistances() + local sib_dists = {} + local sum_length = 0 + local vertices = self.digraph.vertices + for i=1,#vertices do + sib_dists[i] = lib.lookup_option('node distance', vertices[i], self.digraph) + sum_length = sum_length + sib_dists[i] + end + + local missing_length = self.digraph.options['radius'] * 2 * math.pi - sum_length + if missing_length > 0 then + -- Ok, the sib_dists to not add up to the desired minimum value. + -- What should we do? Hmm... We increase all by the missing amount: + for i=1,#vertices do + sib_dists[i] = sib_dists[i] + missing_length/#vertices + end + end + + sib_dists.total = math.max(self.digraph.options['radius'] * 2 * math.pi, sum_length) + + return sib_dists +end + + +function Tantau2012:computeNodeRadii() + local radii = {} + for i,v in ipairs(self.digraph.vertices) do + local min_x, min_y, max_x, max_y = v:boundingBox() + local w, h = max_x-min_x, max_y-min_y + if v.shape == "circle" or v.shape == "ellipse" then + radii[i] = math.max(w,h)/2 + else + radii[i] = math.sqrt(w*w + h*h)/2 + end + end + return radii +end + + +function Tantau2012:adjustNodeRadii(sib_dists,radii) + local total = 0 + local max_rad = 0 + for i=1,#radii do + total = total + 2*radii[i] + + lib.lookup_option('node post sep', self.digraph.vertices[i], self.digraph) + + lib.lookup_option('node pre sep', self.digraph.vertices[i], self.digraph) + max_rad = math.max(max_rad, radii[i]) + end + total = math.max(total, sib_dists.total, max_rad*math.pi) + local diam = total/(math.pi) + + -- Now, adjust the radii: + local adjusted_radii = {} + for i=1,#radii do + adjusted_radii[i] = (math.pi - 2*math.acos(radii[i]/diam))*diam/2 + end + + return diam, adjusted_radii +end + + +-- done + +return Tantau2012 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/doc.lua new file mode 100644 index 0000000000..9198885965 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/doc.lua @@ -0,0 +1,145 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + +-------------------------------------------------------------------- +key "simple necklace layout" + +summary +[[ +This simple layout arranges the nodes in a circle, which is +especially useful for drawing, well, circles of nodes. +]] + +documentation +[[ +The name |simple necklace layout| is reminiscent of the more general +``necklace layout'', a term coined by Speckmann and Verbeek in +their paper +% +\begin{itemize} + \item + Bettina Speckmann and Kevin Verbeek, + \newblock Necklace Maps, + \newblock \emph{IEEE Transactions on Visualization and Computer + Graphics,} 16(6):881--889, 2010. +\end{itemize} + +For a |simple necklace layout|, the centers of the nodes +are placed on a counter-clockwise circle, starting with the first +node at the |grow| direction (for |grow'|, the circle is +clockwise). The order of the nodes is the order in which they appear +in the graph, the edges are not taken into consideration, unless the +|componentwise| option is given. +% +\begin{codeexample}[ + preamble={\usetikzlibrary{arrows.meta,graphs,graphdrawing} + \usegdlibrary{circular}}] +\tikz[>={Stealth[round,sep]}] + \graph [simple necklace layout, grow'=down, node sep=1em, + nodes={draw,circle}, math nodes] + { + x_1 -> x_2 -> x_3 -> x_4 -> + x_5 -> "\dots"[draw=none] -> "x_{n-1}" -> x_n -> x_1 + }; +\end{codeexample} + +When you give the |componentwise| option, the graph will be +decomposed into connected components, which are then laid out +individually and packed using the usual component packing +mechanisms: +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{circular}}] +\tikz \graph [simple necklace layout] { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 +}; +\end{codeexample} +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{circular}}] +\tikz \graph [simple necklace layout, componentwise] { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 +}; +\end{codeexample} + +The nodes are placed in such a way that +% +\begin{enumerate} + \item The (angular) distance between the centers of consecutive + nodes is at least |node distance|, + \item the distance between the borders of consecutive nodes is at + least |node sep|, and + \item the radius is at least |radius|. +\end{enumerate} +% +The radius of the circle is chosen near-minimal such that the above +properties are satisfied. To be more precise, if all nodes are +circles, the radius is chosen optimally while for, say, rectangular +nodes there may be too much space between the nodes in order to +satisfy the second condition. +]] + +example +[[ +\tikz \graph [simple necklace layout, + node sep=0pt, node distance=0pt, + nodes={draw,circle}] +{ 1 -- 2 [minimum size=30pt] -- 3 -- + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; +]] + +example +[[ +\begin{tikzpicture}[radius=1.25cm] + \graph [simple necklace layout, + node sep=0pt, node distance=0pt, + nodes={draw,circle}] + { 1 -- 2 [minimum size=30pt] -- 3 -- + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; + + \draw [red] (0,-1.25) circle []; +\end{tikzpicture} +]] + +example +[[ +\tikz \graph [simple necklace layout, + node sep=0pt, node distance=1cm, + nodes={draw,circle}] +{ 1 -- 2 [minimum size=30pt] -- 3 -- + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; +]] + +example +[[ +\tikz \graph [simple necklace layout, + node sep=2pt, node distance=0pt, + nodes={draw,circle}] +{ 1 -- 2 [minimum size=30pt] -- 3 -- + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; +]] + +example +[[ +\tikz \graph [simple necklace layout, + node sep=0pt, node distance=0pt, + nodes={rectangle,draw}] +{ 1 -- 2 [minimum size=30pt] -- 3 -- + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/library.lua new file mode 100644 index 0000000000..016cfe483f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/circular/library.lua @@ -0,0 +1,30 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +--- +-- ``Circular'' graph drawing algorithms arrange the nodes of a graph +-- on one of more circles. +-- +-- @library + +local circular -- Library name + +-- Load declarations from: + +-- Load algorithms from: +require "pgf.gd.circular.Tantau2012" + + +-- General declarations diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control.lua new file mode 100644 index 0000000000..a3bec1fef3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.control = {} + + +-- Done + +return pgf.gd.control \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Anchoring.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Anchoring.lua new file mode 100644 index 0000000000..03a05ee627 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Anchoring.lua @@ -0,0 +1,104 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Anchoring a Graph} +-- +-- \label{subsection-library-graphdrawing-anchoring} +-- +-- A graph drawing algorithm must compute positions of the nodes of a +-- graph, but the computed positions are only \emph{relative} (``this +-- node is left of this node, but above that other node''). It is not +-- immediately obvious where the ``the whole graph'' should be placed +-- \emph{absolutely} once all relative positions have been computed. In +-- case that the graph consists of several unconnected components, the +-- situation is even more complicated. +-- +-- The order in which the algorithm layer determines the node at which +-- the graph should be anchored: +-- % +-- \begin{enumerate} +-- \item If the |anchor node=|\meta{node name} option given to the graph +-- as a whole, the graph is anchored at \meta{node name}, provided +-- there is a node of this name in the graph. (If there is no node of +-- this name or if it is misspelled, the effect is the same as if this +-- option had not been given at all.) +-- \item Otherwise, if there is a node where the |anchor here| option is +-- specified, the first node with this option set is used. +-- \item Otherwise, if there is a node where the |desired at| option is +-- set (perhaps implicitly through keys like |x|), the first such node +-- is used. +-- \item Finally, in all other cases, the first node is used. +-- \end{enumerate} +-- +-- In the above description, the ``first'' node refers to the node first +-- encountered in the specification of the graph. +-- +-- Once the node has been determined, the graph is shifted so that +-- this node lies at the position specified by |anchor at|. +-- +-- @end + + + +local Anchoring = {} + + +-- Namespace +require("pgf.gd.control").Anchoring = Anchoring + + +-- Imports +local Coordinate = require("pgf.gd.model.Coordinate") +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + + +--- +declare { + key = "desired at", + type = "coordinate", + documentation_in = "pgf.gd.control.doc" +} + +--- +declare { + key = "anchor node", + type = "string", + documentation_in = "pgf.gd.control.doc" +} + + +--- +declare { + key = "anchor at", + type = "canvas coordinate", + initial = "(0pt,0pt)", + documentation_in = "pgf.gd.control.doc" +} + + +--- +declare { + key = "anchor here", + type = "boolean", + documentation_in = "pgf.gd.control.doc" +} + + + + + +-- Done + +return Anchoring \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua new file mode 100644 index 0000000000..72a82be978 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua @@ -0,0 +1,540 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- +-- @section subsubsection {Aligning Components} +-- +-- When components are placed next to each from left to right, it +-- is not immediately clear how the components should be aligned +-- vertically. What happens is that in each component a horizontal line is +-- determined and then all components are shifted vertically so that the +-- lines are aligned. There are different strategies for choosing these +-- ``lines'', see the description of the options described later on. +-- When the |component direction| option is used to change the direction +-- in which components are placed, it certainly make no longer sense to +-- talk about ``horizontal'' and ``vertical'' lines. Instead, what +-- actually happens is that the alignment does not consider +-- ``horizontal'' lines, but lines that go in the direction specified by +-- |component direction| and aligns them by moving components along a +-- line that is perpendicular to the line. For these reasons, let us call +-- the line in the component direction the \emph{alignment line} and a +-- line that is perpendicular to it the \emph{shift line}. +-- +-- The first way of specifying through which point of a component the +-- alignment line should get is to use the option |align here|. +-- In many cases, however, you will not wish to specify an alignment node +-- manually in each component. Instead, you will use the +-- |component align| key to specify a \emph{strategy} that should be used to +-- automatically determine such a node. +-- +-- Using a combination of |component direction| and |component align|, +-- numerous different packing strategies can be configured. However, +-- since names like |counterclockwise| are a bit hard to remember and to +-- apply in practice, a number of easier-to-remember keys are predefined +-- that combine an alignment and a direction. +-- +-- @end + +--- + +declare { + key = "align here", + type = "boolean", + + summary = [[" + When this option is given to a node, this alignment line will go + through the origin of this node. If this option is passed to more + than one node of a component, the node encountered first in the + component is used. + "]], + examples = [[" + \tikz \graph [binary tree layout, nodes={draw}] + { a, b -- c[align here], d -- e[second, align here] -- f }; + "]] +} + +--- + +declare { + key = "component align", + type = "string", + initial = "first node", + + summary = [[" + Specifies a ``strategy'' for the alignment of components. + "]], + documentation = [[" + The following values are permissible: + % + \begin{itemize} + \item \declare{|first node|} + + In each component, the alignment line goes through the center of + the first node of the component encountered during specification + of the component. + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component align=first node] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % + \item \declare{|center|} + + The nodes of the component are projected onto the shift line. The + alignment line is now chosen so that it is exactly in the middle + between the maximum and minimum value that the projected nodes + have on the shift line. + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component align=center] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component direction=90, + component align=center] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % + \item \declare{|counterclockwise|} + + As for |center|, we project the nodes of the component onto the + shift line. The alignment line is now chosen so that it goes + through the center of the node whose center has the highest + projected value. + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component align=counterclockwise] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component direction=90, + component align=counterclockwise] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + The name |counterclockwise| is intended to indicate that the align + line goes through the node that comes last if we go from the + alignment direction in a counter-clockwise direction. + \item \declare{|clockwise|} + + Works like |counterclockwise|, only in the other direction: + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component align=clockwise] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [binary tree layout, nodes={draw}, + component direction=90, + component align=clockwise] + { a, b -- c, d -- e[second] -- f }; +\end{codeexample} + % + \item \declare{|counterclockwise bounding box|} + + This method is quite similar to |counterclockwise|, only the + alignment line does not go through the center of the node with a + maximum projected value on the shift line, but through the maximum + value of the projected bounding boxes. For a left-to-right + packing, this means that the components are aligned so that the + bounding boxes of the components are aligned at the top. + % +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [tree layout, nodes={draw, align=center}, + component sep=0pt, + component align=counterclockwise] + { a, "high\\node" -- b};\quad +\tikz \graph [tree layout, nodes={draw, align=center}, + component sep=0pt, + component align=counterclockwise bounding box] + { a, "high\\node" -- b}; +\end{codeexample} + % + \item \declare{|clockwise bounding box|} + + Works like |counterclockwise bounding box|. + \end{itemize} + "]] +} + +--- + +declare { + key = "components go right top aligned", + use = { + { key = "component direction", value = 0}, + { key = "component align", value = "counterclockwise"}, + }, + + summary = [[" + Shorthand for |component direction=right| and + |component align=counterclockwise|. This means that, as the name + suggest, the components will be placed left-to-right and they are + aligned such that their top nodes are in a line. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go right top aligned] + { a, "high\\node" -- b}; + "]] +} + +--- + +declare { + key = "components go right absolute top aligned", + use = { + { key = "component direction", value=0}, + { key = "component align", value = "counterclockwise bounding box"}, + }, + + summary = [[" + Like |components go right top aligned|, but with + |component align| set to |counterclockwise| |bounding box|. + This means that the components will be aligned with their bounding + boxed being top-aligned. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go right absolute top aligned] + { a, "high\\node" -- b}; + "]] +} + +--- + +declare { + key = "components go right bottom aligned", + use = { + { key = "component direction", value=0}, + { key = "component align", value = "clockwise"}, + }, + + summary = "See the other |components go ...| keys." +} + +--- +-- + +declare { + key = "components go right absolute bottom aligned", + use = { + { key = "component direction", value=0}, + { key = "component align", value = "clockwise bounding box"}, + }, + + summary = "See the other |components go ...| keys." +} + + +--- + +declare { + key = "components go right center aligned", + use = { + { key = "component direction", value=0}, + { key = "component align", value = "center"}, + }, + + summary = "See the other |components go ...| keys." +} + + +--- + +declare { + key = "components go right", + use = { + { key = "component direction", value=0}, + { key = "component align", value = "first node"}, + }, + + summary = [[" + Shorthand for |component direction=right| and + |component align=first node|. + "]] + } + + +--- + +declare { + key = "components go left top aligned", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "clockwise"}, + }, + + summary = "See the other |components go ...| keys.", + + examples = [[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go left top aligned] + { a, "high\\node" -- b}; + "]] +} + +--- +-- + +declare { + key = "components go left absolute top aligned", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "clockwise bounding box"}, + }, + + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go left bottom aligned", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "counterclockwise"}, + }, + + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go left absolute bottom aligned", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "counterclockwise bounding box"}, + }, + + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go left center aligned", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "center"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go left", + use = { + { key = "component direction", value=180}, + { key = "component align", value = "first node"}, + }, + summary = "See the other |components go ...| keys." +} + + + +--- + +declare { + key = "components go down right aligned", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "counterclockwise"}, + }, + summary = "See the other |components go ...| keys.", + + examples = {[[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go down left aligned] + { a, hello -- {world,s} }; + "]],[[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go up absolute left aligned] + { a, hello -- {world,s}}; + "]] + } +} + +--- +-- + +declare { + key = "components go down absolute right aligned", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "counterclockwise bounding box"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go down left aligned", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "clockwise"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go down absolute left aligned", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "clockwise bounding box"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go down center aligned", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "center"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go down", + use = { + { key = "component direction", value=270}, + { key = "component align", value = "first node"}, + }, + summary = "See the other |components go ...| keys." +} + +--- +-- + +declare { + key = "components go up right aligned", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "clockwise"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go up absolute right aligned", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "clockwise bounding box"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go up left aligned", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "counterclockwise"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go up absolute left aligned", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "counterclockwise bounding box"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go up center aligned", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "center"}, + }, + summary = "See the other |components go ...| keys." +} + + +--- +-- + +declare { + key = "components go up", + use = { + { key = "component direction", value=90}, + { key = "component align", value = "first node"}, + }, + summary = "See the other |components go ...| keys." +} + + + + +return Components diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua new file mode 100644 index 0000000000..f941ff226e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua @@ -0,0 +1,58 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- +-- @section subsubsection {Arranging Components in a Certain Direction} +-- +-- @end + +--- + +declare { + key = "component direction", + type = "direction", + initial = "0", + + summary = [[" + The \meta{angle} is used to determine the relative position of each + component relative to the previous one. The direction need not be a + multiple of |90|. As usual, you can use texts like |up| or + |right| instead of a number. + "]], + documentation = [[" + As the examples show, the direction only has an influence on the + relative positions of the components, not on the direction of growth + inside the components. In particular, the components are not rotated + by this option in any way. You can use the |grow| option or |orient| + options to orient individual components. + "]], + examples = {[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=left] + { a, b, c -- d -- e, f -- g }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=10] + { a, b, c -- d -- e, f -- g }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=up] + { a, b, c [grow=right] -- d -- e, f[grow=45] -- g }; + "]] + } +} + + +return Components \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua new file mode 100644 index 0000000000..a2d04a178f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua @@ -0,0 +1,108 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- +-- @section subsubsection {The Distance Between Components} +-- +-- Once the components of a graph have been oriented, sorted, aligned, +-- and a direction has been chosen, it remains to determine the distance +-- between adjacent components. Two methods are available for computing +-- this distance, as specified by the following option: +-- +-- @end + +--- + +declare { + key = "component packing", + type = "string", + initial = "skyline", + + documentation = [[" + Given two components, their distance is computed as follows in + dependence of \meta{method}: + % + \begin{itemize} + \item \declare{|rectangular|} + + Imagine a bounding box to be drawn around both components. They + are then shifted such that the padding (separating distance) + between the two boxes is the current value of |component sep|. + % + \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] + \tikz \graph [tree layout, nodes={draw}, component sep=0pt, + component packing=rectangular] + { a -- long text, longer text -- b}; + \end{codeexample} + % + \item \declare{|skyline|} + + The ``skyline method'' is used to compute the distance. It works + as follows: For simplicity, assume that the component direction is + right (other case work similarly, only everything is + rotated). Imaging the second component to be placed far right + beyond the first component. Now start moving the second component + back to the left until one of the nodes of the second component + touches a node of the first component, and stop. Again, the + padding |component sep| can be used to avoid the nodes actually + touching each other. + % + \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] + \tikz \graph [tree layout, nodes={draw}, component sep=0pt, + level distance=1.5cm, + component packing=skyline] + { a -- long text, longer text -- b}; + \end{codeexample} + + In order to avoid nodes of the second component ``passing through + a hole in the first component'', the actual algorithm is a bit + more complicated: For both components, a ``skyline'' is + computed. For the first component, consider an arbitrary + horizontal line. If there are one or more nodes on this line, the + rightmost point on any of the bounding boxes of these nodes will + be the point on the skyline of the first component for this + line. Similarly, for the second component, for each horizontal + level the skyline is given by the leftmost point on any of the + bounding boxes intersecting the line. + + Now, the interesting case are horizontal lines that do not + intersect any of the nodes of the first and/or second + component. Such lines represent ``holes'' in the skyline. For + them, the following rule is used: Move the horizontal line upward + and downward as little as possible until a height is reached where + there is a skyline defined. Then the skyline position on the + original horizontal line is the skyline position at the reached + line, minus (or, for the second component, plus) the distance by + which the line was moved. This means that the holes are ``filled + up by slanted roofs''. + % + \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] + \begin{tikzpicture} + \graph [tree layout, nodes={draw}, component sep=0pt, + component packing=skyline] + { a -- long text, longer text -- b}; + \draw[red] (long text.north east) -- ++(north west:1cm); + \end{tikzpicture} + \end{codeexample} + + \end{itemize} + "]] +} + + +return Components diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua new file mode 100644 index 0000000000..78537b614c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua @@ -0,0 +1,105 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + + + +--- +-- @section subsubsection {Ordering the Components} +-- +-- The different connected components of the graph are collected in a +-- list. The ordering of the nodes in this list can be configured using +-- the following key. +-- +-- @end + + +--- + +declare { + key = "component order", + type = "string", + initial = "by first specified node", + + summary = [[" + Selects a ``strategy'' for ordering the components. By default, + they are ordered in the way they appear in the input. + "]], + documentation = [[" + The following values are permissible for \meta{strategy} + % + \begin{itemize} + \item \declare{|by first specified node|} + + The components are ordered ``in the way they appear in the input + specification of the graph''. More precisely, for each component + consider the node that is first encountered in the description + of the graph. Order the components in the same way as these nodes + appear in the graph description. + \item \declare{|increasing node number|} + + The components are ordered by increasing number of nodes. For + components with the same number of nodes, the first node in each + component is considered and they are ordered according to the + sequence in which these nodes appear in the input. + + \item \declare{|decreasing node number|} + As above, but in decreasing order. + \end{itemize} + "]], + examples = {[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component order=by first specified node] + { a, b, c, f -- g, c -- d -- e }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component order=increasing node number] + { a, b, c -- d -- e, f -- g }; + "]] + } +} + + +--- + +declare { + key = "small components first", + use = { + { key = "component order", value = "increasing node number" } + }, + + summary = [[" + A shorthand for |component order=increasing node number|. + "]] + } + +--- + +declare { + key = "large components first", + use = { + { key = "component order", value = "decreasing node number" }, + }, + summary = [[" + A shorthand for |component order=decreasing node number|. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + large components first] + { a, b, c -- d -- e, f -- g }; + "]] +} + + +return Components \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Components.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Components.lua new file mode 100644 index 0000000000..c5019a56e2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Components.lua @@ -0,0 +1,127 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- +-- @section subsection {Packing of Connected Components} +-- +-- \label{subsection-gd-component-packing} +-- \label{section-gd-packing} +-- +-- Graphs may be composed of subgraphs or \emph{components} that are not +-- connected to each other. In order to draw these nicely, most graph +-- drawing algorithms split them into separate graphs, compute +-- their layouts with the same graph drawing algorithm independently and, +-- in a postprocessing step, arrange them next to each other. Note, +-- however, that some graph drawing algorithms can also arrange the nodes +-- of the graph in a uniform way even for unconnected components (the +-- |simple necklace layout| is a case in point); for such algorithms you can +-- choose whether they should be applied to each component individually +-- or not (if not, the following options do not apply). To configure +-- which is the case, use the |componentwise| key. +-- +-- The default method for placing the different components works as +-- follows: +-- % +-- \begin{enumerate} +-- \item For each component, a layout is determined and the component is +-- oriented as described +-- Section~\ref{subsection-library-graphdrawing-standard-orientation} +-- on the orientation of graphs. +-- \item The components are sorted as prescribed by the +-- |component order| key. +-- \item The first component is now placed (conceptually) at the +-- origin. (The final position of this and all other components will be +-- determined later, namely in the anchoring phase, but let us imagine +-- that the first component lies at the origin at this point.) +-- \item The second component is now positioned relative to the first +-- component. The ``direction'' in which the next component is placed +-- relative to the first one is determined by the |component direction| +-- key, so components can be placed from left to right or up to down or +-- in any other direction (even something like $30^\circ$). However, +-- both internally and in the following description, we assume that the +-- components are placed from left to right; other directions are +-- achieved by doing some (clever) rotating of the arrangement achieved +-- in this way. +-- +-- So, we now wish to place the second component to the right of the +-- first component. The component is first shifted vertically according +-- to some alignment strategy. For instance, it can be shifted so that +-- the topmost node of the first component and the topmost node of the +-- second component have the same vertical position. Alternatively, we +-- might require that certain ``alignment nodes'' in both components +-- have the same vertical position. There are several other strategies, +-- which can be configured using the |component align| key. +-- +-- One the vertical position has been fixed, the horizontal position is +-- computed. Here, two different strategies are available: First, image +-- rectangular bounding boxed to be drawn around both components. Then +-- we shift the second component such that the right border of the +-- bounding box of the first component touches the left border of the +-- bounding box of the second component. Instead of having the bounding +-- boxes ``touch'', we can also have a padding of |component sep| +-- between them. The second strategy is more involved and also known as +-- a ``skyline'' strategy, where (roughly) the components are +-- ``moved together as near as possible so that nodes do not touch''. +-- \item +-- After the second component has been placed, the third component is +-- considered and positioned relative to the second one, and so on. +-- \item +-- At the end, as hinted at earlier, the whole arrangement is rotate so +-- that instead of ``going right'' the component go in the direction of +-- |component direction|. Note, however, that this rotation applies only +-- to the ``shift'' of the components; the components themselves are +-- not rotated. Fortunately, this whole rotation process happens in the +-- background and the result is normally exactly what you would expect. +-- \end{enumerate} +-- +-- In the following, we go over the different keys that can be used to +-- configure the component packing. +-- +-- @end + + +--- + +declare { + key = "componentwise", + type = "boolean", + + summary = [[" + For algorithms that also support drawing unconnected graphs, use + this key to enforce that the components of the graph are, + nevertheless, laid out individually. For algorithms that do not + support laying out unconnected graphs, this option has no effect; + rather it works as if this option were always set. + "]], + examples = {[[" + \tikz \graph [simple necklace layout] + { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 + }; + "]],[[", + \tikz \graph [simple necklace layout, componentwise] + { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 + }; + "]] + } +} + + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Distances.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Distances.lua new file mode 100644 index 0000000000..6dc5a13018 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Distances.lua @@ -0,0 +1,454 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local lib = require "pgf.gd.lib" + +--- +-- @section subsection {Padding and Node Distances} +-- +-- \label{subsection-gd-dist-pad} +-- +-- In many drawings, you may wish to specify how ``near'' two nodes should +-- be placed by a graph drawing algorithm. Naturally, this depends +-- strongly on the specifics of the algorithm, but there are a number of +-- general keys that will be used by many algorithms. +-- +-- There are different kinds of objects for which you can specify +-- distances and paddings: +-- % +-- \begin{itemize} +-- \item You specify the ``natural'' distance between nodes +-- connected by an edge using |node distance|, which is also available in +-- normal \tikzname\ albeit for a slightly different purpose. However, +-- not every algorithm will (or can) honor the key; see the description +-- of each algorithm what it will ``make of this option''. +-- \item A number of graph drawing algorithms arrange nodes in layers +-- (or levels); we refer +-- to the nodes on the same layer as siblings (although, in a tree, +-- siblings are only nodes with the same parent; nevertheless we use +-- ``sibling'' loosely also for nodes that are more like ``cousins''). +-- \item When a graph consists of several connected component, many graph +-- drawing algorithms will layout these components individually. The +-- different components will then be arranged next to each other, see +-- Section~\ref{section-gd-packing} for the details, such that between +-- the nodes of any two components a padding is available. +-- \end{itemize} +-- +-- @end + + + + +--- + +declare { + key = "node distance", + type = "length", + initial = "1cm", + + summary = [[" + This is minimum distance that the centers of nodes connected by an + edge should have. It will not always be possible to satisfy this + desired distance, for instance in case the nodes are too big. In + this case, the \meta{length} is just considered as a lower bound. + "]], + examples = [[" + \begin{tikzpicture} + \graph [simple necklace layout, node distance=1cm, node sep=0pt, + nodes={draw,circle,as=.}] + { + 1 -- 2 [minimum size=2cm] -- 3 -- + 4 -- 5 -- 6 -- 7 --[orient=up] 8 + }; + \draw [red,|-|] (1.center) -- ++(0:1cm); + \draw [red,|-|] (5.center) -- ++(180:1cm); + \end{tikzpicture} + "]] +} + + +--- + +declare { + key = "node pre sep", + type = "length", + initial = ".333em", + + summary = [[" + This is a minimum ``padding'' or ``separation'' between the border + of nodes connected by an edge. Thus, if nodes are so big that nodes + with a distance of |node distance| would overlap (or + just come with \meta{dimension} distance of one another), their + distance is enlarged so that this distance is still satisfied. + The |pre| means that the padding is added to the node ``at the + front''. This make sense only for some algorithms, like for a + simple necklace layout. + "]], + examples = {[[" + \tikz \graph [simple necklace layout, node distance=0cm, nodes={circle,draw}] + { 1--2--3--4--5--1 }; + "]],[[" + \tikz \graph [simple necklace layout, node distance=0cm, node sep=0mm, + nodes={circle,draw}] + { 1--2--3[node pre sep=5mm]--4--5[node pre sep=1mm]--1 }; + "]] + } +} + +--- + +declare { + key = "node post sep", + type = "length", + initial = ".333em", + + summary = [[" + Works like |node pre sep|. + "]] +} + + + +--- +-- @param length A length. + +declare { + key = "node sep", + type = "length", + use = { + { key = "node pre sep", value = function(v) return v/2 end }, + { key = "node post sep", value = function(v) return v/2 end }, + }, + summary = [[" + A shorthand for setting both |node pre sep| and |node post sep| to + $\meta{length}/2$. + "]] +} + + +--- + +declare { + key = "level distance", + type = "length", + initial = "1cm", + + summary = [[" + This is minimum distance that the centers of nodes on one + level should have from the centers of nodes on the next level. It + will not always be possible to satisfy this desired distance, for + instance in case the nodes are too big. In this case, the + \meta{length} is just considered as a lower bound. + "]], + examples = [[" + \begin{tikzpicture}[inner sep=2pt] + \draw [help lines] (0,0) grid (3.5,2); + \graph [layered layout, level distance=1cm, level sep=0] + { 1 [x=1,y=2] -- 2 -- 3 -- 1 }; + \graph [layered layout, level distance=5mm, level sep=0] + { 1 [x=3,y=2] -- 2 -- 3 -- 1, 3 -- {4,5} -- 6 -- 3 }; + \end{tikzpicture} + "]] +} + +--- +declare { + key = "layer distance", + type = "length", + use = { + { key = "level distance", value = lib.id }, + }, + summary = "An alias for |level distance|" +} + +--- +declare { + key = "level pre sep", + type = "length", + initial = ".333em", + + summary = [[" + This is a minimum ``padding'' or ``separation'' between the border + of the nodes on a level to any nodes on the previous level. Thus, if + nodes are so big that nodes on consecutive levels would overlap (or + just come with \meta{length} distance of one another), their + distance is enlarged so that this distance is still satisfied. + If a node on the previous level also has a |level post sep|, this + post padding and the \meta{dimension} add up. Thus, these keys + behave like the ``padding'' keys rather + than the ``margin'' key of cascading style sheets. + "]], + examples = [[" + \begin{tikzpicture}[inner sep=2pt, level sep=0pt, sibling distance=0pt] + \draw [help lines] (0,0) grid (3.5,2); + \graph [layered layout, level distance=0cm, nodes=draw] + { 1 [x=1,y=2] -- {2,3[level pre sep=1mm],4[level pre sep=5mm]} -- 5 }; + \graph [layered layout, level distance=0cm, nodes=draw] + { 1 [x=3,y=2] -- {2,3,4} -- 5[level pre sep=5mm] }; + \end{tikzpicture} + "]] +} + +--- + +declare { + key = "level post sep", + type = "length", + initial = ".333em", + + summary = [[" + Works like |level pre sep|. + "]] +} + +--- +declare { + key = "layer pre sep", + type = "length", + use = { + { key = "level pre sep", value = lib.id }, + }, + summary = "An alias for |level pre sep|." +} + +--- +declare { + key = "layer post sep", + type = "length", + use = { + { key = "level post sep", value = lib.id }, + }, + summary = "An alias for |level post sep|." +} + + + + +--- +-- @param length A length + +declare { + key = "level sep", + type = "length", + use = { + { key = "level pre sep", value = function (v) return v/2 end }, + { key = "level post sep", value = function (v) return v/2 end }, + }, + + summary = [[" + A shorthand for setting both |level pre sep| and |level post sep| to + $\meta{length}/2$. Note that if you set |level distance=0| and + |level sep=1em|, you get a layout where any two consecutive layers + are ``spaced apart'' by |1em|. + "]] +} + + +--- +declare { + key = "layer sep", + type = "number", + use = { + { key = "level sep", value = lib.id }, + }, + summary = "An alias for |level sep|." +} + + +--- +declare { + key = "sibling distance", + type = "length", + initial = "1cm", + + summary = [[" + This is minimum distance that the centers of node should have to the + center of the next node on the same level. As for levels, this is + just a lower bound. + For some layouts, like a simple necklace layout, the \meta{length} is + measured as the distance on the circle. + "]], + examples = {[[" + \tikz \graph [tree layout, sibling distance=1cm, nodes={circle,draw}] + { 1--{2,3,4,5} }; + "]],[[" + \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, + nodes={circle,draw}] + { 1--{2,3,4,5} }; + "]],[[" + \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, + nodes={circle,draw}] + { 1--{2,3[sibling distance=1cm],4,5} }; + "]] + } +} + + +--- + +declare { + key = "sibling pre sep", + type = "length", + initial = ".333em", + + summary = [[" + Works like |level pre sep|, only for siblings. + "]], + examples = [[" + \tikz \graph [tree layout, sibling distance=0cm, nodes={circle,draw}, + sibling sep=0pt] + { 1--{2,3[sibling pre sep=1cm],4,5} }; + "]] +} + +--- + +declare { + key = "sibling post sep", + type = "length", + initial = ".333em", + + summary = [[" + Works like |sibling pre sep|. + "]] + } + + + +--- +-- @param length A length + +declare { + key = "sibling sep", + type = "length", + use = { + { key = "sibling pre sep", value = function(v) return v/2 end }, + { key = "sibling post sep", value = function(v) return v/2 end }, + }, + + summary = [[" + A shorthand for setting both |sibling pre sep| and |sibling post sep| to + $\meta{length}/2$. + "]] +} + + + + + + +--- +declare { + key = "part distance", + type = "length", + initial = "1.5cm", + + summary = [[" + This is minimum distance between the centers of ``parts'' of a + graph. What a ``part'' is depends on the algorithm. + "]] +} + + +--- + +declare { + key = "part pre sep", + type = "length", + initial = "1em", + summary = "A pre-padding for parts." +} + +--- + +declare { + key = "part post sep", + type = "length", + initial = "1em", + summary = "A post-padding for pars." + } + + + +--- +-- @param length A length + +declare { + key = "part sep", + type = "length", + use = { + { key = "part pre sep", value = function(v) return v/2 end }, + { key = "part post sep", value = function(v) return v/2 end }, + }, + + summary = [[" + A shorthand for setting both |part pre sep| and |part post sep| to + $\meta{length}/2$. + "]] +} + + + + +--- + +declare { + key = "component sep", + type = "length", + initial = "1.5em", + + summary = [[" + This is padding between the bounding boxes that nodes of different + connected components will have when they are placed next to each + other. + "]], + examples = {[[" + \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, + components go right top aligned, + component sep=1pt, nodes=draw] + { + 1 -> 2 -> {3->4[second]->5,6,7}; + a -> b[second] -> c[second] -> d -> e; + x -> y[second] -> z -> u[second] -> v; + }; + "]],[[" + \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, + components go right top aligned, + component sep=1em, nodes=draw] + { + 1 -> 2 -> {3->4[second]->5,6,7}; + a -> b[second] -> c[second] -> d -> e; + x -> y[second] -> z -> u[second] -> v; + }; + "]] + } +} + + + +--- + +declare { + key = "component distance", + type = "length", + initial = "2cm", + + summary = [[" + This is the minimum distance between the centers of bounding + boxes of connected components when they are placed next to each + other. (Not used, currently.) + "]] +} + + +return Distances diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/FineTune.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/FineTune.lua new file mode 100644 index 0000000000..87d67b5b56 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/FineTune.lua @@ -0,0 +1,164 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +local Coordinate = require "pgf.gd.model.Coordinate" +local lib = require "pgf.gd.lib" + +--- +-- @section subsection {Fine-Tuning Positions of Nodes} +-- +-- @end + + + +--- +declare { + key = "nudge", + type = "canvas coordinate", + + summary = [[" + This option allows you to slightly ``nudge'' (move) nodes after + they have been positioned by the given offset. The idea is that + this nudging is done after the position of the node has been + computed, so nudging has no influence on the actual graph + drawing algorithms. This, in turn, means that you can use + nudging to ``correct'' or ``optimize'' the positioning of nodes + after the algorithm has computed something. + "]], + + examples = [[" + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge=(up:2mm)]} -- e -- a; + }; + "]] +} + + +--- +-- @param distance A distance by which the node is nudges. + +declare { + key = "nudge up", + type = "length", + use = { + { key = "nudge", value = function (v) return Coordinate.new(0,v) end } + }, + + summary = "A shorthand for nudging a node upwards.", + examples = [[" + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge up=2mm]} -- e -- a; + }; + "]] +} + + +--- +-- @param distance A distance by which the node is nudges. + +declare { + key = "nudge down", + type = "length", + use = { + { key = "nudge", value = function (v) return Coordinate.new(0,-v) end } + }, + + summary = "Like |nudge up|, but downwards." +} + +--- +-- @param distance A distance by which the node is nudges. + +declare { + key = "nudge left", + type = "length", + use = { + { key = "nudge", value = function (v) return Coordinate.new(-v,0) end } + }, + + summary = "Like |nudge up|, but left.", + examples = [[" + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge left=2mm]} -- e -- a; + }; + "]] +} + +--- +-- @param distance A distance by which the node is nudges. + +declare { + key = "nudge right", + type = "length", + use = { + { key = "nudge", value = function (v) return Coordinate.new(v,0) end } + }, + + summary = "Like |nudge left|, but right." +} + + +--- +declare { + key = "regardless at", + type = "canvas coordinate", + + summary = [[" + Using this option you can provide a position for a node to wish + it will be forced after the graph algorithms have run. So, the node + is positioned normally and the graph drawing algorithm does not know + about the position specified using |regardless at|. However, + afterwards, the node is placed there, regardless of what the + algorithm has computed (all other nodes are unaffected). + "]], + examples = [[" + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b,c,d[regardless at={(1,0)}]} -- e -- a; + }; + "]] +} + + + + +--- +-- @param pos A canvas position (a coordinate). + +declare { + key = "nail at", + type = "canvas coordinate", + use = { + { key = "desired at", value = lib.id }, + { key = "regardless at", value = lib.id }, + }, + + summary = [[" + This option combines |desired at| and |regardless at|. Thus, the + algorithm is ``told'' about the desired position. If it fails to place + the node at the desired position, it will be put there + regardless. The name of the key is intended to remind one of a node + being ``nailed'' to the canvas. + "]], + examples = [[" + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b,c,d[nail at={(1,0)}]} -- e[nail at={(1.5,-1)}] -- a; + }; + "]] +} + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua new file mode 100644 index 0000000000..1c5e48b4c7 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua @@ -0,0 +1,1347 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- This class controls the running of graph drawing algorithms on +-- graphs. In particular, it performs pre- and posttransformations and +-- also invokes the collapsing of sublayouts. +-- +-- You do not call any of the methods of this class directly, the +-- whole class is included only for documentation purposes. +-- +-- Before an algorithm is applied, a number of transformations will +-- have been applied, depending on the algorithm's |preconditions| +-- field: +-- % +-- \begin{itemize} +-- \item |connected| +-- +-- If this property is set for an algorithm (that is, in the +-- |declare| statement for the algorithm the |predconditions| field +-- has the entry |connected=true| set), then the graph will be +-- decomposed into connected components. The algorithm is run on each +-- component individually. +-- \item |tree| +-- +-- When set, the field |spanning_tree| of the algorithm will be set +-- to a spanning tree of the graph. This option implies |connected|. +-- \item |loop_free| +-- +-- When set, all loops (arcs from a vertex to itself) will have been +-- removed when the algorithm runs. +-- +-- \item |at_least_two_nodes| +-- +-- When explicitly set to |false| (this precondition is |true| by +-- default), the algorithm will even be run if there is only a +-- single vertex in the graph. +-- \end{itemize} +-- +-- Once the algorithm has run, the algorithm's |postconditions| will +-- be processed: +-- % +-- \begin{itemize} +-- \item |upward_oriented| +-- +-- When set, the algorithm tells the layout pipeline that the graph +-- has been laid out in a layered manner with each layer going from +-- left to right and layers at a whole going upwards (positive +-- $y$-coordinates). The graph will then be rotated and possibly +-- swapped in accordance with the |grow| key set by the user. +-- \item |fixed| +-- +-- When set, no rotational postprocessing will be done after the +-- algorithm has run. Usually, a graph is rotated to meet a user's +-- |orient| settings. However, when the algorithm has already +-- ``ideally'' rotated the graph, set this postcondition. +-- \end{itemize} +-- +-- +-- In addition to the above-described always-present and automatic +-- transformations, users may also specify additional pre- and +-- posttransformations. This happens when users install additional +-- algorithms in appropriate phases. In detail, the following happens +-- in order: +-- % +-- \begin{enumerate} +-- \item If specified, the graph is decomposed into connected +-- components and the following steps are applied to each component +-- individually. +-- \item All algorithms in the phase stack for the phase +-- |preprocessing| are applied to the component. These algorithms are +-- run one after the other in the order they appear in the phase stack. +-- \item If necessary, the spanning tree is now computed and +-- rotational information is gathered. +-- \item The single algorithm in phase |main| is called. +-- \item All algorithms in the phase stack for the phase +-- |edge routing| are run. +-- \item All algorithms in the phase stack for phase |postprocessing| +-- are run. +-- \item Edge syncing, orientation, and anchoring are applied. +-- \end{enumerate} +-- +-- If sublayouts are used, all of the above (except for anchoring) +-- happens for each sublayout. + +local LayoutPipeline = {} + + +-- Namespace +require("pgf.gd.control").LayoutPipeline = LayoutPipeline + + +-- Imports +local Direct = require "pgf.gd.lib.Direct" +local Storage = require "pgf.gd.lib.Storage" +local Simplifiers = require "pgf.gd.lib.Simplifiers" +local LookupTable = require "pgf.gd.lib.LookupTable" +local Transform = require "pgf.gd.lib.Transform" + +local Arc = require "pgf.gd.model.Arc" +local Vertex = require "pgf.gd.model.Vertex" +local Digraph = require "pgf.gd.model.Digraph" +local Coordinate = require "pgf.gd.model.Coordinate" +local Path = require "pgf.gd.model.Path" + +local Sublayouts = require "pgf.gd.control.Sublayouts" + +local lib = require "pgf.gd.lib" + +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" + + + + +-- Forward definitions + +local prepare_events + + + +-- The main ``graph drawing pipeline'' that handles the pre- and +-- postprocessing for a graph. This method is called by the display +-- interface. +-- +-- @param scope A graph drawing scope. + +function LayoutPipeline.run(scope) + + -- The pipeline... + + -- Step 1: Preparations + + -- Prepare events + prepare_events(scope.events) + + -- Step 2: Recursively layout the graph, starting with the root layout + local root_layout = assert(scope.collections[InterfaceCore.sublayout_kind][1], "no layout in scope") + + scope.syntactic_digraph = + Sublayouts.layoutRecursively (scope, + root_layout, + LayoutPipeline.runOnLayout, + { root_layout }) + + -- Step 3: Anchor the graph + LayoutPipeline.anchor(scope.syntactic_digraph, scope) + + -- Step 4: Apply regardless transforms + Sublayouts.regardless(scope.syntactic_digraph) + + -- Step 5: Cut edges + LayoutPipeline.cutEdges(scope.syntactic_digraph) + +end + + + +-- +-- This method is called by the sublayout rendering pipeline when the +-- algorithm should be invoked for an individual graph. At this point, +-- the sublayouts will already have been collapsed. +-- +-- @param scope The graph drawing scope. +-- @param algorithm_class The to-be-applied algorithm class. +-- @param layout_graph A subgraph of the syntactic digraph which is +-- restricted to the current layout and in which sublayouts have +-- been contracted to single nodes. +-- @param layout The layout to which the graph belongs. +-- +function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout) + + if #layout_graph.vertices < 1 then + return + end + + -- The involved main graphs: + local layout_copy = Digraph.new (layout_graph) --Direct.digraphFromSyntacticDigraph(layout_graph) + for _,a in ipairs(layout_graph.arcs) do + local new_a = layout_copy:connect(a.tail,a.head) + new_a.syntactic_edges = a.syntactic_edges + end + + -- Step 1: Decompose the graph into connected components, if necessary: + local syntactic_components + if algorithm_class.preconditions.tree or algorithm_class.preconditions.connected or layout_graph.options.componentwise then + syntactic_components = LayoutPipeline.decompose(layout_copy) + LayoutPipeline.sortComponents(layout_graph.options['component order'], syntactic_components) + else + -- Only one component: The graph itself... + syntactic_components = { layout_copy } + end + + -- Step 2: For all components do: + for i,syntactic_component in ipairs(syntactic_components) do + + -- Step 2.1: Reset random number generator to make sure that the + -- same graph is always typeset in the same way. + lib.randomseed(layout_graph.options['random seed']) + + local digraph = Direct.digraphFromSyntacticDigraph(syntactic_component) + + -- Step 2.3: If requested, remove loops + if algorithm_class.preconditions.loop_free then + for _,v in ipairs(digraph.vertices) do + digraph:disconnect(v,v) + end + end + + -- Step 2.4: Precompute the underlying undirected graph + local ugraph = Direct.ugraphFromDigraph(digraph) + + -- Step 2.4a: Run preprocessor + for _,class in ipairs(layout_graph.options.algorithm_phases["preprocessing stack"]) do + class.new{ + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() + end + + -- Step 2.5: Create an algorithm object + local algorithm = algorithm_class.new{ + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + } + + -- Step 2.7: Compute a spanning tree, if necessary + if algorithm_class.preconditions.tree then + local spanning_algorithm_class = syntactic_component.options.algorithm_phases["spanning tree computation"] + algorithm.spanning_tree = + spanning_algorithm_class.new{ + ugraph = ugraph, + events = scope.events + }:run() + end + + -- Step 2.8: Compute growth-adjusted sizes + algorithm.rotation_info = LayoutPipeline.prepareRotateAround(algorithm.postconditions, syntactic_component) + algorithm.adjusted_bb = Storage.newTableStorage() + LayoutPipeline.prepareBoundingBoxes(algorithm.rotation_info, algorithm.adjusted_bb, syntactic_component, syntactic_component.vertices) + + -- Step 2.9: Finally, run algorithm on this component! + if #digraph.vertices > 1 or algorithm_class.run_also_for_single_node + or algorithm_class.preconditions.at_least_two_nodes == false then + -- Main run of the algorithm: + if algorithm_class.old_graph_model then + LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algorithm) + else + algorithm:run () + end + end + + -- Step 2.9a: Run edge routers + for _,class in ipairs(layout_graph.options.algorithm_phases["edge routing stack"]) do + class.new{ + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() + end + + -- Step 2.9b: Run postprocessor + for _,class in ipairs(layout_graph.options.algorithm_phases["postprocessing stack"]) do + class.new{ + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() + end + + -- Step 2.10: Sync the graphs + digraph:sync() + ugraph:sync() + if algorithm.spanning_tree then + algorithm.spanning_tree:sync() + end + + -- Step 2.11: Orient the graph + LayoutPipeline.orient(algorithm.rotation_info, algorithm.postconditions, syntactic_component, scope) + end + + -- Step 3: Packing: + LayoutPipeline.packComponents(layout_graph, syntactic_components) + +end + + + + + + +--- +-- This function is called internally to perform the graph anchoring +-- procedure described in +-- Section~\ref{subsection-library-graphdrawing-anchoring}. These +-- transformations are always performed. +-- +-- @param graph A graph +-- @param scope The scope + +function LayoutPipeline.anchor(graph, scope) + + -- Step 1: Find anchor node: + local anchor_node + + local anchor_node_name = graph.options['anchor node'] + if anchor_node_name then + anchor_node = scope.node_names[anchor_node_name] + end + + if not graph:contains(anchor_node) then + anchor_node = + lib.find (graph.vertices, function (v) return v.options['anchor here'] end) or + lib.find (graph.vertices, function (v) return v.options['desired at'] end) or + graph.vertices[1] + end + + -- Sanity check + assert(graph:contains(anchor_node), "anchor node is not in graph!") + + local desired = anchor_node.options['desired at'] or graph.options['anchor at'] + local delta = desired - anchor_node.pos + + -- Step 3: Shift nodes + for _,v in ipairs(graph.vertices) do + v.pos:shiftByCoordinate(delta) + end + for _,a in ipairs(graph.arcs) do + if a.path then a.path:shiftByCoordinate(delta) end + for _,e in ipairs(a.syntactic_edges) do + e.path:shiftByCoordinate(delta) + end + end +end + + + +--- +-- This method tries to determine in which direction the graph is supposed to +-- grow and in which direction the algorithm will grow the graph. These two +-- pieces of information together produce a necessary rotation around some node. +-- This rotation is returned in a table. +-- +-- Note that this method does not actually cause a rotation to happen; this is +-- left to other method. +-- +-- @param postconditions The algorithm's postconditions. +-- @param graph An undirected graph +-- @return A table containing the computed information. + +function LayoutPipeline.prepareRotateAround(postconditions, graph) + + -- Find the vertex from which we orient + local swap = true + + local v,_,grow = lib.find (graph.vertices, function (v) return v.options["grow"] end) + + if not v and graph.options["grow"] then + v,grow,swap = graph.vertices[1], graph.options["grow"], true + end + + if not v then + v,_,grow = lib.find (graph.vertices, function (v) return v.options["grow'"] end) + swap = false + end + + if not v and graph.options["grow'"] then + v,grow,swap = graph.vertices[1], graph.options["grow'"], false + end + + if not v then + v, grow, swap = graph.vertices[1], -90, true + end + + -- Now compute the rotation + local info = {} + local growth_direction = (postconditions.upward_oriented and 90) or (postconditions.upward_oriented_swapped and 90) + + if postconditions.upward_oriented_swapped then + swap = not swap + end + + if growth_direction == "fixed" then + info.angle = 0 -- no rotation + elseif growth_direction then + info.from_node = v + info.from_angle = growth_direction/360*2*math.pi + info.to_angle = grow/360*2*math.pi + info.swap = swap + info.angle = info.to_angle - info.from_angle + else + info.from_node = v + local other = lib.find_min( + graph:outgoing(v), + function (a) + if a.head ~= v and a:eventIndex() then + return a, a:eventIndex() + end + end) + info.to_node = (other and other.head) or + (graph.vertices[1] == v and graph.vertices[2] or graph.vertices[1]) + info.to_angle = grow/360*2*math.pi + info.swap = swap + info.angle = info.to_angle - math.atan2(info.to_node.pos.y - v.pos.y, info.to_node.pos.x - v.pos.x) + end + + return info +end + + + +--- +-- Compute growth-adjusted node sizes. +-- +-- For each node of the graph, compute bounding box of the node that +-- results when the node is rotated so that it is in the correct +-- orientation for what the algorithm assumes. +-- +-- The ``bounding box'' actually consists of the fields +-- % +-- \begin{itemize} +-- \item |sibling_pre|, +-- \item |sibling_post|, +-- \item |layer_pre|, and +-- \item |layer_post|, +-- \end{itemize} +-- % +-- which correspond to ``min x'', ``min y'', ``min y'', and ``max y'' +-- for a tree growing up. +-- +-- The computation of the ``bounding box'' treats a centered circle in +-- a special way, all other shapes are currently treated like a +-- rectangle. +-- +-- @param rotation_info The table computed by the function prepareRotateAround +-- @param packing_storage A storage in which the computed distances are stored. +-- @param graph An graph +-- @param vertices An array of to-be-prepared vertices inside graph + +function LayoutPipeline.prepareBoundingBoxes(rotation_info, adjusted_bb, graph, vertices) + + local angle = assert(rotation_info.angle, "angle field missing") + local swap = rotation_info.swap + + for _,v in ipairs(vertices) do + local bb = adjusted_bb[v] + local a = angle + + if v.shape == "circle" then + a = 0 -- no rotation for circles. + end + + -- Fill the bounding box field, + bb.sibling_pre = math.huge + bb.sibling_post = -math.huge + bb.layer_pre = math.huge + bb.layer_post = -math.huge + + local c = math.cos(angle) + local s = math.sin(angle) + for _,p in ipairs(v.path:coordinates()) do + local x = p.x*c + p.y*s + local y = -p.x*s + p.y*c + + bb.sibling_pre = math.min (bb.sibling_pre, x) + bb.sibling_post = math.max (bb.sibling_post, x) + bb.layer_pre = math.min (bb.layer_pre, y) + bb.layer_post = math.max (bb.layer_post, y) + end + + -- Flip sibling per and post if flag: + if swap then + bb.sibling_pre, bb.sibling_post = -bb.sibling_post, -bb.sibling_pre + end + end +end + + + + + +-- +-- Rotate the whole graph around a point +-- +-- Causes the graph to be rotated around \meta{around} so that what +-- used to be the |from_angle| becomes the |to_angle|. If the flag |swap| +-- is set, the graph is additionally swapped along the |to_angle|. +-- +-- @param graph The to-be-rotated (undirected) graph +-- @param around_x The $x$-coordinate of the point around which the graph should be rotated +-- @param around_y The $y$-coordinate +-- @param from An ``old'' angle +-- @param to A ``new'' angle +-- @param swap A boolean that, when true, requests that the graph is +-- swapped (flipped) along the new angle + +function LayoutPipeline.rotateGraphAround(graph, around_x, around_y, from, to, swap) + + -- Translate to origin + local t = Transform.new_shift(-around_x, -around_y) + + -- Rotate to zero degrees: + t = Transform.concat(Transform.new_rotation(-from), t) + + -- Swap + if swap then + t = Transform.concat(Transform.new_scaling(1,-1), t) + end + + -- Rotate to from degrees: + t = Transform.concat(Transform.new_rotation(to), t) + + -- Translate back + t = Transform.concat(Transform.new_shift(around_x, around_y), t) + + for _,v in ipairs(graph.vertices) do + v.pos:apply(t) + end + for _,a in ipairs(graph.arcs) do + for _,p in ipairs(a:pointCloud()) do + p:apply(t) + end + end +end + + + +-- +-- Orient the whole graph using two nodes +-- +-- The whole graph is rotated so that the line from the first node to +-- the second node has the given angle. If swap is set to true, the +-- graph is also flipped along this line. +-- +-- @param graph +-- @param first_node +-- @param seond_node +-- @param target_angle +-- @param swap + +function LayoutPipeline.orientTwoNodes(graph, first_node, second_node, target_angle, swap) + if first_node and second_node then + -- Compute angle between first_node and second_node: + local x = second_node.pos.x - first_node.pos.x + local y = second_node.pos.y - first_node.pos.y + + local angle = math.atan2(y,x) + LayoutPipeline.rotateGraphAround(graph, first_node.pos.x, + first_node.pos.y, angle, target_angle, swap) + end +end + + + +--- +-- Performs a post-layout orientation of the graph by performing the +-- steps documented in Section~\ref{subsection-library-graphdrawing-standard-orientation}. +-- +-- @param rotation_info The info record computed by the function |prepareRotateAround|. +-- @param postconditions The algorithm's postconditions. +-- @param graph A to-be-oriented graph. +-- @param scope The graph drawing scope. + +function LayoutPipeline.orient(rotation_info, postconditions, graph, scope) + + -- Sanity check + if #graph.vertices < 2 then return end + + -- Step 1: Search for global graph orient options: + local function f (orient, tail, head, flag) + if orient and head and tail then + local n1 = scope.node_names[tail] + local n2 = scope.node_names[head] + if graph:contains(n1) and graph:contains(n2) then + LayoutPipeline.orientTwoNodes(graph, n1, n2, orient/360*2*math.pi, flag) + return true + end + end + end + if f(graph.options["orient"], graph.options["orient tail"],graph.options["orient head"], false) then return end + if f(graph.options["orient'"], graph.options["orient tail"],graph.options["orient head"], true) then return end + local tail, head = string.match(graph.options["horizontal"] or "", "^(.*) to (.*)$") + if f(0, tail, head, false) then return end + local tail, head = string.match(graph.options["horizontal'"] or "", "^(.*) to (.*)$") + if f(0, tail, head, true) then return end + local tail, head = string.match(graph.options["vertical"] or "", "^(.*) to (.*)$") + if f(-90, tail, head, false) then return end + local tail, head = string.match(graph.options["vertical'"] or "", "^(.*) to (.*)$") + if f(-90, tail, head, true) then return end + + -- Step 2: Search for a node with the orient option: + for _, v in ipairs(graph.vertices) do + local function f (key, flag) + local orient = v.options[key] + local head = v.options["orient head"] + local tail = v.options["orient tail"] + + if orient and head then + local n2 = scope.node_names[head] + if graph:contains(n2) then + LayoutPipeline.orientTwoNodes(graph, v, n2, orient/360*2*math.pi, flag) + return true + end + elseif orient and tail then + local n1 = scope.node_names[tail] + if graph:contains(n1) then + LayoutPipeline.orientTwoNodes(graph, n1, v, orient/360*2*math.pi, flag) + return true + end + end + end + if f("orient", false) then return end + if f("orient'", true) then return end + end + + -- Step 3: Search for an edge with the orient option: + for _, a in ipairs(graph.arcs) do + if a:options("orient",true) then + return LayoutPipeline.orientTwoNodes(graph, a.tail, a.head, a:options("orient")/360*2*math.pi, false) + end + if a:options("orient'",true) then + return LayoutPipeline.orientTwoNodes(graph, a.tail, a.head, a:options("orient'")/360*2*math.pi, true) + end + end + + -- Step 4: Search two nodes with a desired at option: + local first, second, third + + for _, v in ipairs(graph.vertices) do + if v.options['desired at'] then + if first then + if second then + third = v + break + else + second = v + end + else + first = v + end + end + end + + if second then + local a = first.options['desired at'] + local b = second.options['desired at'] + return LayoutPipeline.orientTwoNodes(graph, first, second, math.atan2(b.y-a.y,b.x-a.x), false) + end + + -- Computed during preprocessing: + if rotation_info.from_node and postconditions.fixed ~= true then + local x = rotation_info.from_node.pos.x + local y = rotation_info.from_node.pos.y + local from_angle = rotation_info.from_angle or math.atan2(rotation_info.to_node.pos.y - y, rotation_info.to_node.pos.x - x) + + LayoutPipeline.rotateGraphAround(graph, x, y, from_angle, rotation_info.to_angle, rotation_info.swap) + end +end + + + + +--- +-- This internal function is called to decompose a graph into its +-- components. Whether or not this function is called depends on +-- whether the precondition |connected| is set for the algorithm class +-- and whether the |componentwise| key is used. +-- +-- @param graph A to-be-decomposed graph +-- +-- @return An array of graph objects that represent the connected components of the graph. + +function LayoutPipeline.decompose (digraph) + + -- The list of connected components (node sets) + local components = {} + + -- Remember, which graphs have already been visited + local visited = {} + + for _,v in ipairs(digraph.vertices) do + if not visited[v] then + -- Start a depth-first-search of the graph, starting at node n: + local stack = { v } + local component = Digraph.new { + syntactic_digraph = digraph.syntactic_digraph, + options = digraph.options + } + + while #stack >= 1 do + local tos = stack[#stack] + stack[#stack] = nil -- pop + + if not visited[tos] then + + -- Visit pos: + component:add { tos } + visited[tos] = true + + -- Push all unvisited neighbors: + for _,a in ipairs(digraph:incoming(tos)) do + local neighbor = a.tail + if not visited[neighbor] then + stack[#stack+1] = neighbor -- push + end + end + for _,a in ipairs(digraph:outgoing(tos)) do + local neighbor = a.head + if not visited[neighbor] then + stack[#stack+1] = neighbor -- push + end + end + end + end + + -- Ok, vertices will now contain all vertices reachable from n. + components[#components+1] = component + end + end + + if #components < 2 then + return { digraph } + end + + for _,c in ipairs(components) do + table.sort (c.vertices, function (u,v) return u.event.index < v.event.index end) + for _,v in ipairs(c.vertices) do + for _,a in ipairs(digraph:outgoing(v)) do + local new_a = c:connect(a.tail, a.head) + new_a.syntactic_edges = a.syntactic_edges + end + for _,a in ipairs(digraph:incoming(v)) do + local new_a = c:connect(a.tail, a.head) + new_a.syntactic_edges = a.syntactic_edges + end + end + end + + return components +end + + + + +-- Handling of component order +-- +-- LayoutPipeline are ordered according to a function that is stored in +-- a key of the |LayoutPipeline.component_ordering_functions| table +-- whose name is the graph option |component order|. +-- +-- @param component_order An ordering method +-- @param subgraphs A list of to-be-sorted subgraphs + +function LayoutPipeline.sortComponents(component_order, subgraphs) + if component_order then + local f = LayoutPipeline.component_ordering_functions[component_order] + if f then + table.sort (subgraphs, f) + end + end +end + + +-- Right now, we hardcode the functions here. Perhaps make this +-- dynamic in the future. Could easily be done on the tikzlayer, +-- actually. + +LayoutPipeline.component_ordering_functions = { + ["increasing node number"] = + function (g,h) + if #g.vertices == #h.vertices then + return g.vertices[1].event.index < h.vertices[1].event.index + else + return #g.vertices < #h.vertices + end + end, + ["decreasing node number"] = + function (g,h) + if #g.vertices == #h.vertices then + return g.vertices[1].event.index < h.vertices[1].event.index + else + return #g.vertices > #h.vertices + end + end, + ["by first specified node"] = nil, +} + + + + +local function compute_rotated_bb(vertices, angle, sep, bb) + + local r = Transform.new_rotation(-angle) + + for _,v in ipairs(vertices) do + -- Find the rotated bounding box field, + local t = Transform.concat(r,Transform.new_shift(v.pos.x, v.pos.y)) + + local min_x = math.huge + local max_x = -math.huge + local min_y = math.huge + local max_y = -math.huge + + for _,e in ipairs(v.path) do + if type(e) == "table" then + local c = e:clone() + c:apply(t) + + min_x = math.min (min_x, c.x) + max_x = math.max (max_x, c.x) + min_y = math.min (min_y, c.y) + max_y = math.max (max_y, c.y) + end + end + + -- Enlarge by sep: + min_x = min_x - sep + max_x = max_x + sep + min_y = min_y - sep + max_y = max_y + sep + + local _,_,_,_,c_x,c_y = v:boundingBox() + local center = Coordinate.new(c_x,c_y) + + center:apply(t) + + bb[v].min_x = min_x + bb[v].max_x = max_x + bb[v].min_y = min_y + bb[v].max_y = max_y + bb[v].c_y = center.y + end +end + + + +--- +-- This internal function packs the components of a graph. See +-- Section~\ref{subsection-gd-component-packing} for details. +-- +-- @param graph The graph +-- @param components A list of components + +function LayoutPipeline.packComponents(syntactic_digraph, components) + + local vertices = Storage.newTableStorage() + local bb = Storage.newTableStorage() + + -- Step 1: Preparation, rotation to target direction + local sep = syntactic_digraph.options['component sep'] + local angle = syntactic_digraph.options['component direction']/180*math.pi + + local mark = {} + for _,c in ipairs(components) do + + -- Setup the lists of to-be-considered nodes + local vs = {} + for _,v in ipairs(c.vertices) do + vs [#vs + 1] = v + end + + for _,a in ipairs(c.arcs) do + for _,p in ipairs(a:pointCloud()) do + vs [#vs + 1] = Vertex.new { pos = p } + end + end + vertices[c] = vs + + compute_rotated_bb(vs, angle, sep/2, bb) + end + + local x_shifts = { 0 } + local y_shifts = {} + + -- Step 2: Vertical alignment + for i,c in ipairs(components) do + local max_max_y = -math.huge + local max_center_y = -math.huge + local min_min_y = math.huge + local min_center_y = math.huge + + for _,v in ipairs(c.vertices) do + local info = bb[v] + max_max_y = math.max(info.max_y, max_max_y) + max_center_y = math.max(info.c_y, max_center_y) + min_min_y = math.min(info.min_y, min_min_y) + min_center_y = math.min(info.c_y, min_center_y) + end + + -- Compute alignment line + local valign = syntactic_digraph.options['component align'] + local line + if valign == "counterclockwise bounding box" then + line = max_max_y + elseif valign == "counterclockwise" then + line = max_center_y + elseif valign == "center" then + line = (max_max_y + min_min_y) / 2 + elseif valign == "clockwise" then + line = min_center_y + elseif valign == "first node" then + line = bb[c.vertices[1]].c_y + else + line = min_min_y + end + + -- Overruled? + for _,v in ipairs(c.vertices) do + if v.options['align here'] then + line = bb[v].c_y + break + end + end + + -- Ok, go! + y_shifts[i] = -line + + -- Adjust nodes: + for _,v in ipairs(vertices[c]) do + local info = bb[v] + info.min_y = info.min_y - line + info.max_y = info.max_y - line + info.c_y = info.c_y - line + end + end + + -- Step 3: Horizontal alignment + local y_values = {} + + for _,c in ipairs(components) do + for _,v in ipairs(vertices[c]) do + local info = bb[v] + y_values[#y_values+1] = info.min_y + y_values[#y_values+1] = info.max_y + y_values[#y_values+1] = info.c_y + end + end + + table.sort(y_values) + + local y_ranks = {} + local right_face = {} + for i=1,#y_values do + y_ranks[y_values[i]] = i + right_face[i] = -math.huge + end + + + + for i=1,#components-1 do + -- First, update right_face: + local touched = {} + + for _,v in ipairs(vertices[components[i]]) do + local info = bb[v] + local border = info.max_x + + for i=y_ranks[info.min_y],y_ranks[info.max_y] do + touched[i] = true + right_face[i] = math.max(right_face[i], border) + end + end + + -- Fill up the untouched entries: + local right_max = -math.huge + for i=1,#y_values do + if not touched[i] then + -- Search for next and previous touched + local interpolate = -math.huge + for j=i+1,#y_values do + if touched[j] then + interpolate = math.max(interpolate,right_face[j] - (y_values[j] - y_values[i])) + break + end + end + for j=i-1,1,-1 do + if touched[j] then + interpolate = math.max(interpolate,right_face[j] - (y_values[i] - y_values[j])) + break + end + end + right_face[i] = math.max(interpolate,right_face[i]) + end + right_max = math.max(right_max, right_face[i]) + end + + -- Second, compute the left face + local touched = {} + local left_face = {} + for i=1,#y_values do + left_face[i] = math.huge + end + for _,v in ipairs(vertices[components[i+1]]) do + local info = bb[v] + local border = info.min_x + + for i=y_ranks[info.min_y],y_ranks[info.max_y] do + touched[i] = true + left_face[i] = math.min(left_face[i], border) + end + end + + -- Fill up the untouched entries: + local left_min = math.huge + for i=1,#y_values do + if not touched[i] then + -- Search for next and previous touched + local interpolate = math.huge + for j=i+1,#y_values do + if touched[j] then + interpolate = math.min(interpolate,left_face[j] + (y_values[j] - y_values[i])) + break + end + end + for j=i-1,1,-1 do + if touched[j] then + interpolate = math.min(interpolate,left_face[j] + (y_values[i] - y_values[j])) + break + end + end + left_face[i] = interpolate + end + left_min = math.min(left_min, left_face[i]) + end + + -- Now, compute the shift. + local shift = -math.huge + + if syntactic_digraph.options['component packing'] == "rectangular" then + shift = right_max - left_min + else + for i=1,#y_values do + shift = math.max(shift, right_face[i] - left_face[i]) + end + end + + -- Adjust nodes: + x_shifts[i+1] = shift + for _,v in ipairs(vertices[components[i+1]]) do + local info = bb[v] + info.min_x = info.min_x + shift + info.max_x = info.max_x + shift + end + end + + -- Now, rotate shifts + for i,c in ipairs(components) do + local x = x_shifts[i]*math.cos(angle) - y_shifts[i]*math.sin(angle) + local y = x_shifts[i]*math.sin(angle) + y_shifts[i]*math.cos(angle) + + for _,v in ipairs(vertices[c]) do + v.pos.x = v.pos.x + x + v.pos.y = v.pos.y + y + end + end +end + + + + + + + +-- +-- Store for each begin/end event the index of +-- its corresponding end/begin event +-- +-- @param events An event list + +prepare_events = + function (events) + local stack = {} + + for i=1,#events do + if events[i].kind == "begin" then + stack[#stack + 1] = i + elseif events[i].kind == "end" then + local tos = stack[#stack] + stack[#stack] = nil -- pop + + events[tos].end_index = i + events[i].begin_index = tos + end + end + end + + + +--- +-- Cut the edges. This function handles the ``cutting'' of edges. The +-- idea is that every edge is a path going from the center of the from +-- node to the center of the target node. Now, we intersect this path +-- with the path of the start node and cut away everything before this +-- intersection. Likewise, we intersect the path with the head node +-- and, again, cut away everything following the intersection. +-- +-- These cuttings are not done if appropriate options are set. + +function LayoutPipeline.cutEdges(graph) + + for _,a in ipairs(graph.arcs) do + for _,e in ipairs(a.syntactic_edges) do + local p = e.path + p:makeRigid() + local orig = p:clone() + + if e.options['tail cut'] and e.tail.options['cut policy'] == "as edge requests" + or e.tail.options['cut policy'] == "all" then + + local vpath = e.tail.path:clone() + vpath:shiftByCoordinate(e.tail.pos) + + local x = p:intersectionsWith (vpath) + + if #x > 0 then + p:cutAtBeginning(x[1].index, x[1].time) + end + end + + if e.options['head cut'] and e.head.options['cut policy'] == "as edge requests" + or e.head.options['cut policy'] == "all" then + + local vpath = e.head.path:clone() + vpath:shiftByCoordinate(e.head.pos) + x = p:intersectionsWith (vpath) + if #x > 0 then + p:cutAtEnd(x[#x].index, x[#x].time) + else + -- Check whether there was an intersection with the original + --path: + local x2 = orig:intersectionsWith (vpath) + if #x2 > 0 then + -- Ok, after cutting the tail vertex, there is no longer + -- an intersection with the head vertex, but there used to + -- be one. This means that the vertices overlap and the + -- path should be ``inside'' them. Hmm... + if e.options['allow inside edges'] and #p > 1 then + local from = p[2] + local to = x2[1].point + p:clear() + p:appendMoveto(from) + p:appendLineto(to) + else + p:clear() + end + end + end + end + end + end +end + + + + + + +-- Deprecated stuff + +local Node = require "pgf.gd.deprecated.Node" +local Graph = require "pgf.gd.deprecated.Graph" +local Edge = require "pgf.gd.deprecated.Edge" +local Cluster = require "pgf.gd.deprecated.Cluster" + + + + + +local unique_count = 0 + +local function compatibility_digraph_to_graph(scope, g) + local graph = Graph.new() + + -- Graph options + graph.options = g.options + graph.orig_digraph = g + + -- Events + for i,e in ipairs(scope.events) do + graph.events[i] = e + end + + -- Nodes + for _,v in ipairs(g.vertices) do + if not v.name then + -- compat needs unique name + v.name = "auto generated node nameINTERNAL" .. unique_count + unique_count = unique_count + 1 + end + local minX, minY, maxX, maxY = v:boundingBox() + local node = Node.new{ + name = v.name, + tex = { + tex_node = v.tex and v.tex.stored_tex_box_number, + shape = v.shape, + minX = minX, + maxX = maxX, + minY = minY, + maxY = maxY, + }, + options = v.options, + event_index = v.event.index, + index = v.event.index, + orig_vertex = v, + } + graph:addNode(node) + graph.events[v.event.index or (#graph.events+1)] = { kind = 'node', parameters = node } + end + + -- Edges + local mark = Storage.new() + for _,a in ipairs(g.arcs) do + local da = g.syntactic_digraph:arc(a.tail, a.head) + if da then + for _,m in ipairs(da.syntactic_edges) do + if not mark[m] then + mark[m] = true + local from_node = graph:findNode(da.tail.name) + local to_node = graph:findNode(da.head.name) + local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) + edge.event_index = m.event.index + edge.orig_m = m + graph.events[m.event.index] = { kind = 'edge', parameters = edge } + end + end + end + local da = g.syntactic_digraph:arc(a.head, a.tail) + if da then + for _,m in ipairs(da.syntactic_edges) do + if not mark[m] then + mark[m] = true + local from_node = graph:findNode(da.tail.name) + local to_node = graph:findNode(da.head.name) + local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) + edge.event_index = m.event.index + edge.orig_m = m + graph.events[m.event.index] = { kind = 'edge', parameters = edge } + end + end + end + end + + table.sort(graph.edges, function(e1,e2) return e1.event_index < e2.event_index end) + for _,n in ipairs (graph.nodes) do + table.sort(n.edges, function(e1,e2) return e1.event_index < e2.event_index end) + end + + + -- Clusters + for _, c in ipairs(scope.collections['same layer'] or {}) do + cluster = Cluster.new("cluster" .. unique_count) + unique_count = unique_count+1 + graph:addCluster(cluster) + for _,v in ipairs(c.vertices) do + if g:contains(v) then + cluster:addNode(graph:findNode(v.name)) + end + end + end + + return graph +end + + +local function compatibility_graph_to_digraph(graph) + for _,n in ipairs(graph.nodes) do + n.orig_vertex.pos.x = n.pos.x + n.orig_vertex.pos.y = n.pos.y + end + for _,e in ipairs(graph.edges) do + if #e.bend_points > 0 then + local c = {} + for _,x in ipairs(e.bend_points) do + c[#c+1] = Coordinate.new (x.x, x.y) + end + e.orig_m:setPolylinePath(c) + end + end +end + + + + + +function LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algorithm) + + local graph = compatibility_digraph_to_graph(scope, digraph) + + algorithm.graph = graph + graph:registerAlgorithm(algorithm) + + -- If requested, remove loops + if algorithm_class.preconditions.loop_free then + Simplifiers:removeLoopsOldModel(algorithm) + end + + -- If requested, collapse multiedges + if algorithm_class.preconditions.simple then + Simplifiers:collapseMultiedgesOldModel(algorithm) + end + + if #graph.nodes > 1 then + -- Main run of the algorithm: + algorithm:run () + end + + -- If requested, expand multiedges + if algorithm_class.preconditions.simple then + Simplifiers:expandMultiedgesOldModel(algorithm) + end + + -- If requested, restore loops + if algorithm_class.preconditions.loop_free then + Simplifiers:restoreLoopsOldModel(algorithm) + end + + compatibility_graph_to_digraph(graph) +end + + + + +-- Done + +return LayoutPipeline diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua new file mode 100644 index 0000000000..80aa7ef420 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua @@ -0,0 +1,175 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + + +--- +-- @section subsection {Anchoring Edges} +-- +-- \label{section-gd-anchors} +-- +-- When a graph has been laid out completely, the edges between the +-- nodes must be drawn. Conceptually, an edge is ``between two +-- nodes'', but when we actually draw the node, we do not really want +-- the edge's path to start ``in the middle'' of the node; rather, we +-- want it to start ``on the border'' and also end there. +-- +-- Normally, computing such border positions for nodes is something we +-- would leave to the so-called display layer (which is typically +-- \tikzname\ and \tikzname\ is reasonably good at computing border +-- positions). However, different display layers may behave +-- differently here and even \tikzname\ fails when the node shapes are +-- very involved and the paths also. +-- +-- For these reasons, computing the anchor positions where edges start +-- and end is done inside the graph drawing system. As a user, you +-- specify a |tail anchor| and a |head anchor|, which are points +-- inside the tail and head nodes, respectively. The edge path will +-- then start and end at these points, however, they will usually be +-- shortened so that they actually start and end on the intersection +-- of the edge's path with the nodes' paths. + + +--- + +declare { + key = "tail anchor", + type = "string", + initial = "", + + summary = [[" + Specifies where in the tail vertex the edge should start. + "]], + + documentation = [[" + This is either a string or a number, interpreted as an angle + (with 90 meaning ``up''). If it is a string, when the start of + the edge is computed, we try to look up the anchor in the tail + vertex's table of anchors (some anchors get installed in this + table by the display system). If it is not found, we test + whether it is one of the special ``direction anchors'' like + |north| or |south east|. If so, we convert them into points on + the border of the node that lie in the direction of a line + starting at the center to a point on the bounding box of the + node in the designated direction. Finally, if the anchor is a + number, we use a point on the border of the node that is on a + line from the center in the specified direction. + + If the anchor is set to the empty string (which is the default), + the anchor is interpreted as the |center| anchor inside the + graph drawing system. However, a display system may choose to + make a difference between the |center| anchor and an empty + anchor (\tikzname\ does: for options like |bend left| if the + anchor is empty, the bend line starts at the border of the node, + while for the anchor set explicitly to |center| it starts at the + center). + + Note that graph drawing algorithms need not take the + setting of this option into consideration. However, the final + rendering of the edge will always take it into consideration + (only, the setting may not be very sensible if the algorithm + ignored it). + "]] +} + +--- + +declare { + key = "head anchor", + type = "string", + initial = "", + + summary = "See |tail anchor|" +} + + +--- + +declare { + key = "tail cut", + type = "boolean", + initial = true, + + summary = [[" + Decides whether the tail of an edge is ``cut'', meaning + that the edge's path will be shortened at the beginning so that + it starts only of the node's border rather than at the exact + position of the |tail anchor|, which may be inside the node. + "]] +} + + +--- + +declare { + key = "head cut", + type = "boolean", + initial = true, + + summary = "See |tail cut|." +} + + +--- + +declare { + key = "cut policy", + type = "string", + initial = "as edge requests", + + summary = "The policy for cutting edges entering or leaving a node.", + + documentation = [[" + This option is important for nodes only. It can have three + possible values: + % + \begin{itemize} + \item |as edge requests| Whether or not an edge entering or + leaving the node is cut depends on the setting of the edge's + |tail cut| and |head cut| options. This is the default. + \item |all| All edges entering or leaving the node are cut, + regardless of the edges' cut values. + \item |none| No edge entering or leaving the node is cut, + regardless of the edges' cut values. + \end{itemize} + "]] +} + + +--- +declare { + key = "allow inside edges", + type = "boolean", + initial = "true", + + summary = "Decides whether an edge between overlapping nodes should be drawn.", + + documentation = [[" + If two vertices overlap, it may happen that when you draw an + edge between them, this edges would be completely inside the two + vertices. In this case, one could either not draw them or one + could draw a sort of ``inside edge''. + "]], + + examples = { [[" + \tikz \graph [no layout, nodes={draw, minimum size=20pt}] { + a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] + }; + "]],[[" + \tikz \graph [no layout, nodes={draw, minimum size=20pt}, + allow inside edges=false] { + a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] + }; + "]] + } +} \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Orientation.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Orientation.lua new file mode 100644 index 0000000000..1890fa4f39 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Orientation.lua @@ -0,0 +1,303 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +--- +-- @section subsection {Orienting a Graph} +-- +-- \label{subsection-library-graphdrawing-standard-orientation} +-- +-- Just as a graph drawing algorithm cannot know \emph{where} a graph +-- should be placed on a page, it is also often unclear which +-- \emph{orientation} it should have. Some graphs, like trees, have a +-- natural direction in which they ``grow'', but for an ``arbitrary'' +-- graph the ``natural orientation'' is, well, arbitrary. +-- +-- There are two ways in which you can specify an orientation: First, +-- you can specify that the line from a certain vertex to another +-- vertex should have a certain slope. How these vertices and slopes +-- are specified in explained momentarily. Second, you can specify a +-- so-called ``growth direction'' for trees. +-- +-- @end + + +-- Namespace +require("pgf.gd.control").Orientation = Orientation + + + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- + +declare { + key = "orient", + type = "direction", + default = 0, + + summary = [[" + This key specifies that the straight line from the |orient tail| to + the |orient head| should be at an angle of \meta{direction} relative to + the right-going $x$-axis. Which vertices are used as tail an head + depends on where the |orient| option is encountered: When used with + an edge, the tail is the edge's tail and the head is the edge's + head. When used with a node, the tail or the head must be specified + explicitly and the node is used as the node missing in the + specification. When used with a graph as a whole, both the head and + tail nodes must be specified explicitly. + "]], + documentation = [[" + Note that the \meta{direction} is independent of the actual to-path + of an edge, which might define a bend or more complicated shapes. For + instance, a \meta{angle} of |45| requests that the end node is ``up + and right'' relative to the start node. + + You can also specify the standard direction texts |north| or |south east| + and so forth as \meta{direction} and also |up|, |down|, |left|, and + |right|. Also, you can specify |-| for ``right'' and \verb!|! for ``down''. + "]], + examples = {[[" + \tikz \graph [spring layout] + { + a -- { b, c, d, e -- {f, g, h} }; + h -- [orient=30] a; + }; + "]],[[" + \tikz \graph [spring layout] + { + a -- { b, c, d[> orient=right], e -- {f, g, h} }; + h -- a; + }; + "]] + } +} + + +--- + +declare { + key = "orient'", + type = "direction", + default = 0, + + summary = [[" + Same as |orient|, only the rest of the graph should be + flipped relative to the connection line. + "]], + examples = [[" + \tikz \graph [spring layout] + { + a -- { b, c, d[> orient'=right], e -- {f, g, h} }; + h -- a; + }; + "]] +} + +--- + +declare { + key = "orient tail", + type = "string", + + summary = [[" + Specifies the tail vertex for the orientation of a graph. See + |orient| for details. + "]], + examples = {[[" + \tikz \graph [spring layout] { + a [orient=|, orient tail=f] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [spring layout] { + a [orient=down, orient tail=h] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]] + } +} + + + + + +--- + +declare { + key = "orient head", + type = "string", + + summary = [[" + Specifies the head vertex for the orientation of a graph. See + |orient| for details. + "]], + examples = {[[" + \tikz \graph [spring layout] + { + a [orient=|, orient head=f] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, orient=10, + orient tail=a, orient head=b] { a -- b -- c -- a }; + "]] + } +} + +--- + +declare { + key = "horizontal", + type = "string", + + summary = [[" + A shorthand for specifying |orient tail|, |orient head| and + |orient=0|. The tail will be everything before the part ``| to |'' + and the head will be everything following it. + "]], + examples = [[" + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, horizontal=a to b] { a -- b -- c -- a }; + "]] +} + + + + +--- + +declare { + key = "horizontal'", + type = "string", + + summary = [[" + Like |horizontal|, but with a flip. + "]] +} + + + + + + + +--- + +declare { + key = "vertical", + type = "string", + + summary = [[" + A shorthand for specifying |orient tail|, |orient head| and |orient=-90|. + "]], + examples = [[" + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, vertical=a to b] { a -- b -- c -- a }; + "]] +} + + + + + +--- + +declare { + key = "vertical'", + type = "string", + + summary = [[" + Like |vertical|, but with a flip. + "]] +} + + + +--- + +declare { + key = "grow", + type = "direction", + + summary = [[" + This key specifies in which direction the neighbors of a node + ``should grow''. For some graph drawing algorithms, especially for + those that layout trees, but also for those that produce layered + layouts, there is a natural direction in which the ``children'' of + a node should be placed. For instance, saying |grow=down| will cause + the children of a node in a tree to be placed in a left-to-right + line below the node (as always, you can replace the \meta{angle} + by direction texts). The children are requested to be placed in a + counter-clockwise fashion, the |grow'| key will place them in a + clockwise fashion. + "]], + documentation = [[" + Note that when you say |grow=down|, it is not necessarily the case + that any particular node is actually directly below the current + node; the key just requests that the direction of growth is downward. + + In principle, you can specify the direction of growth for each node + individually, but do not count on graph drawing algorithms to + honor these wishes. + + When you give the |grow=right| key to the graph as a whole, it will + be applied to all nodes. This happens to be exactly what you want: + "]], + examples = {[[" + \tikz \graph [layered layout, sibling distance=5mm] + { + a [grow=right] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [layered layout, grow=right, sibling distance=5mm] + { + a -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz + \graph [layered layout, grow=-80] + { + {a,b,c} --[complete bipartite] {e,d,f} + --[complete bipartite] {g,h,i}; + }; + "]] + } +} + + +--- + +declare { + key = "grow'", + type = "direction", + + summary = "Same as |grow|, only with the children in clockwise order.", + examples = [[" + \tikz \graph [layered layout, sibling distance=5mm] + { + a [grow'=right] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]] +} + + +-- Done + +return Orientation \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Sublayouts.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Sublayouts.lua new file mode 100644 index 0000000000..970483193f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/Sublayouts.lua @@ -0,0 +1,536 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + +local function full_print(g, pref) + local s = "" + + for _,v in ipairs(g.vertices) do + s = s .. tostring(v) .. "[" .. tostring(v.pos) .. "]\n " + end + + s = s .. "\n" + + for _,a in ipairs(g.arcs) do + for _,e in ipairs(a.syntactic_edges) do + s = s .. tostring(e) .. "(" .. tostring(e.path) .. ")\n" + end + end + + pgf.debug((pref or "") .. s) +end + + +--- +-- The |Sublayouts| module handles graphs for which multiple layouts are defined. +-- +-- Please see Section~\ref{section-gd-sublayouts} for an overview of +-- sublayouts. +-- + +local Sublayouts = {} + +-- Namespace +require("pgf.gd.control").Sublayouts = Sublayouts + + +-- Includes + +local Digraph = require "pgf.gd.model.Digraph" +local Vertex = require "pgf.gd.model.Vertex" +local Coordinate = require "pgf.gd.model.Coordinate" +local Path = require "pgf.gd.model.Path" + +local lib = require "pgf.gd.lib" + +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" + +local Storage = require "pgf.gd.lib.Storage" + + + +-- Storages + +local subs = Storage.newTableStorage() +local already_nudged = Storage.new() +local positions = Storage.newTableStorage() + + + + +-- Offset a node by an offset. This will \emph{also} offset all +-- subnodes, which arise from sublayouts. +-- +-- @param vertex A vertex +-- @param pos A offset +-- +local function offset_vertex(v, delta) + v.pos:shiftByCoordinate(delta) + for _,sub in ipairs(subs[v]) do + offset_vertex(sub, delta) + end +end + + +-- Nudge positioning. You can call this function several times on the +-- same graph; nudging will be done only once. +-- +-- @param graph A graph +-- +local function nudge(graph) + for _,v in ipairs(graph.vertices) do + local nudge = v.options['nudge'] + if nudge and not already_nudged[v] then + offset_vertex(v, nudge) + already_nudged[v] = true + end + end +end + + + +-- Create subgraph nodes +-- +-- @param scope A scope +-- @param syntactic_digraph The syntactic digraph. +-- @param test Only for vertices whose subgraph collection passes this test will we create subgraph nodes +local function create_subgraph_node(scope, syntactic_digraph, vertex) + + local subgraph_collection = vertex.subgraph_collection + local binding = InterfaceCore.binding + + local cloud = {} + -- Add all points of n's collection, except for v itself, to the cloud: + for _,v in ipairs(subgraph_collection.vertices) do + if vertex ~= v then + assert(syntactic_digraph:contains(v), "the layout must contain all nodes of the subgraph") + for _,p in ipairs(v.path) do + if type(p) == "table" then + cloud[#cloud+1] = p + v.pos + end + end + end + end + for _,e in ipairs(subgraph_collection.edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + cloud[#cloud+1] = p:clone() + end + end + end + local x_min, y_min, x_max, y_max, c_x, c_y = Coordinate.boundingBox(cloud) + + -- Shift the graph so that it is centered on the origin: + for _,p in ipairs(cloud) do + p:unshift(c_x,c_y) + end + + local o = vertex.subgraph_info.generated_options + + o[#o+1] = { key = "subgraph point cloud", value = table.concat(lib.imap(cloud, tostring)) } + o[#o+1] = { key = "subgraph bounding box height", value = tostring(y_max-y_min) .. "pt" } + o[#o+1] = { key = "subgraph bounding box width", value = tostring(x_max-x_min) .. "pt" } + + -- And now, the "grand call": + binding:createVertex(vertex.subgraph_info) + + -- Shift it were it belongs + vertex.pos:shift(c_x,c_y) + + -- Remember all the subnodes for nudging and regardless + -- positioning + local s = {} + for _,v in ipairs(subgraph_collection.vertices) do + if v ~= vertex then + s[#s+1] = v + end + end + + subs[vertex] = s +end + + +-- Tests whether two graphs have a vertex in common +local function intersection(g1, g2) + for _,v in ipairs(g1.vertices) do + if g2:contains(v) then + return v + end + end +end + +-- Tests whether a graph is a set is a subset of another +local function special_vertex_subset(vertices, graph) + for _,v in ipairs(vertices) do + if not graph:contains(v) and not (v.kind == "subgraph node") then + return false + end + end + return true +end + + + +--- +-- The layout recursion. See \ref{section-gd-sublayouts} for details. +-- +-- @param scope The graph drawing scope +-- @param layout The to-be-laid-out collection +-- @param fun The to-be-called function for laying out the graph. +-- processed. This stack is important when a new syntactic vertex is +-- added by the algorithm: In this case, this vertex is added to all +-- layouts on this stack. +-- +-- @return A laid out graph. + +function Sublayouts.layoutRecursively(scope, layout, fun) + + -- Step 1: Iterate over all sublayouts of the current layout: + local resulting_graphs = {} + local loc = Storage.new() + + -- Now, iterate over all sublayouts + for i,child in ipairs(layout:childrenOfKind(InterfaceCore.sublayout_kind)) do + resulting_graphs[i] = Sublayouts.layoutRecursively(scope, child, fun) + loc[resulting_graphs[i]] = child + end + + -- Step 2: Run the merge process: + local merged_graphs = {} + + while #resulting_graphs > 0 do + + local n = #resulting_graphs + + -- Setup marked array: + local marked = {} + for i=1,n do + marked[i] = false + end + + -- Mark first graph and copy everything from there + marked[1] = true + local touched = Storage.new() + for _,v in ipairs(resulting_graphs[1].vertices) do + v.pos = positions[v][resulting_graphs[1]] + touched[v] = true + end + + -- Repeatedly find a node that is connected to a marked node: + local i = 1 + while i <= n do + if not marked[i] then + for j=1,n do + if marked[j] then + local v = intersection(resulting_graphs[i], resulting_graphs[j]) + if v then + -- Aha, they intersect at vertex v + + -- Mark the i-th graph: + marked[i] = true + connected_some_graph = true + + -- Shift the i-th graph: + local x_offset = v.pos.x - positions[v][resulting_graphs[i]].x + local y_offset = v.pos.y - positions[v][resulting_graphs[i]].y + + for _,u in ipairs(resulting_graphs[i].vertices) do + if not touched[u] then + touched[u] = true + u.pos = positions[u][resulting_graphs[i]]:clone() + u.pos:shift(x_offset, y_offset) + + for _,a in ipairs(resulting_graphs[i]:outgoing(u)) do + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shift(x_offset, y_offset) + end + end + end + end + end + end + + -- Restart + i = 0 + break + end + end + end + end + i = i + 1 + end + + -- Now, we can collapse all marked graphs into one graph: + local merge = Digraph.new {} + merge.syntactic_digraph = merge + local remaining = {} + + -- Add all vertices and edges: + for i=1,n do + if marked[i] then + merge:add (resulting_graphs[i].vertices) + for _,a in ipairs(resulting_graphs[i].arcs) do + local ma = merge:connect(a.tail,a.head) + for _,e in ipairs(a.syntactic_edges) do + ma.syntactic_edges[#ma.syntactic_edges+1] = e + end + end + else + remaining[#remaining + 1] = resulting_graphs[i] + end + end + + -- Remember the first layout this came from: + loc[merge] = loc[resulting_graphs[1]] + + -- Restart with rest: + merged_graphs[#merged_graphs+1] = merge + + resulting_graphs = remaining + end + + -- Step 3: Run the algorithm on the layout: + + local class = layout.options.algorithm_phases.main + assert (type(class) == "table", "algorithm selection failed") + + local algorithm = class + local uncollapsed_subgraph_nodes = lib.imap( + scope.collections[InterfaceCore.subgraph_node_kind] or {}, + function (c) + if c.parent_layout == layout then + return c.subgraph_node + end + end) + + + -- Create a new syntactic digraph: + local syntactic_digraph = Digraph.new { + options = layout.options + } + + syntactic_digraph.syntactic_digraph = syntactic_digraph + + -- Copy all vertices and edges from the collection... + syntactic_digraph:add (layout.vertices) + for _,e in ipairs(layout.edges) do + syntactic_digraph:add {e.head, e.tail} + local arc = syntactic_digraph:connect(e.tail, e.head) + arc.syntactic_edges[#arc.syntactic_edges+1] = e + end + + -- Find out which subgraph nodes can be created now and make them part of the merged graphs + for i=#uncollapsed_subgraph_nodes,1,-1 do + local v = uncollapsed_subgraph_nodes[i] + local vertices = v.subgraph_collection.vertices + -- Test, if all vertices of the subgraph are in one of the merged graphs. + for _,g in ipairs(merged_graphs) do + if special_vertex_subset(vertices, g) then + -- Ok, we can create a subgraph now + create_subgraph_node(scope, syntactic_digraph, v) + -- Make it part of the collapse! + g:add{v} + -- Do not consider again + uncollapsed_subgraph_nodes[i] = false + break + end + end + end + + -- Collapse the nodes that are part of a merged_graph + local collapsed_vertices = {} + for _,g in ipairs(merged_graphs) do + + local intersection = {} + for _,v in ipairs(g.vertices) do + if syntactic_digraph:contains(v) then + intersection[#intersection+1] = v + end + end + if #intersection > 0 then + -- Compute bounding box of g (this should actually be the convex + -- hull) Hmm...: + local array = {} + for _,v in ipairs(g.vertices) do + local min_x, min_y, max_x, max_y = v:boundingBox() + array[#array+1] = Coordinate.new(min_x + v.pos.x, min_y + v.pos.y) + array[#array+1] = Coordinate.new(max_x + v.pos.x, max_y + v.pos.y) + end + for _,a in ipairs(g.arcs) do + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + array[#array+1] = p + end + end + end + end + local x_min, y_min, x_max, y_max, c_x, c_y = Coordinate.boundingBox(array) + + -- Shift the graph so that it is centered on the origin: + for _,v in ipairs(g.vertices) do + v.pos:unshift(c_x,c_y) + end + for _,a in ipairs(g.arcs) do + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:unshift(c_x,c_y) + end + end + end + end + + x_min = x_min - c_x + x_max = x_max - c_x + y_min = y_min - c_y + y_max = y_max - c_y + + local index = loc[g].event.index + + local v = Vertex.new { + -- Standard stuff + shape = "none", + kind = "node", + path = Path.new { + "moveto", + x_min, y_min, + x_min, y_max, + x_max, y_max, + x_max, y_min, + "closepath" + }, + options = {}, + event = scope.events[index] + } + + -- Update node_event + scope.events[index].parameters = v + + local collapse_vertex = syntactic_digraph:collapse( + intersection, + v, + nil, + function (new_arc, arc) + for _,e in ipairs(arc.syntactic_edges) do + new_arc.syntactic_edges[#new_arc.syntactic_edges+1] = e + end + end) + + syntactic_digraph:remove(intersection) + collapsed_vertices[#collapsed_vertices+1] = collapse_vertex + end + end + + -- Sort the vertices + table.sort(syntactic_digraph.vertices, function(u,v) return u.event.index < v.event.index end) + + -- Should we "hide" the subgraph nodes? + local hidden_node + if not algorithm.include_subgraph_nodes then + local subgraph_nodes = lib.imap (syntactic_digraph.vertices, + function (v) if v.kind == "subgraph node" then return v end end) + + if #subgraph_nodes > 0 then + hidden_node = Vertex.new {} + syntactic_digraph:collapse(subgraph_nodes, hidden_node) + syntactic_digraph:remove (subgraph_nodes) + syntactic_digraph:remove {hidden_node} + end + end + + -- Now, we want to call the actual algorithm. This call may modify + -- the layout's vertices and edges fields, namely when new vertices + -- and edges are created. We then need to add these to our local + -- syntactic digraph. So, we remember the length of these fields + -- prior to the call and then add everything ``behind'' these + -- positions later on. + + -- Ok, everything setup! Run the algorithm... + fun(scope, algorithm, syntactic_digraph, layout) + + if hidden_node then + syntactic_digraph:expand(hidden_node) + end + + -- Now, we need to expand the collapsed vertices once more: + for i=#collapsed_vertices,1,-1 do + syntactic_digraph:expand( + collapsed_vertices[i], + function (c, v) + v.pos:shiftByCoordinate(c.pos) + end, + function (a, v) + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shiftByCoordinate(v.pos) + end + end + end + end + ) + for _,a in ipairs(syntactic_digraph:outgoing(collapsed_vertices[i])) do + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shiftByCoordinate(a.tail.pos) + p:unshiftByCoordinate(e.tail.pos) + end + end + end + end + end + syntactic_digraph:remove(collapsed_vertices) + + -- Step 4: Create the layout node if necessary + for i=#uncollapsed_subgraph_nodes,1,-1 do + if uncollapsed_subgraph_nodes[i] then + create_subgraph_node(scope, syntactic_digraph, uncollapsed_subgraph_nodes[i]) + end + end + + -- Now seems like a good time to nudge and do regardless positioning + nudge(syntactic_digraph) + + -- Step 5: Cleanup + -- Push the computed position into the storage: + for _,v in ipairs(syntactic_digraph.vertices) do + positions[v][syntactic_digraph] = v.pos:clone() + end + + return syntactic_digraph +end + + + + + +--- +-- Regardless positioning. +-- +-- @param graph A graph +-- +function Sublayouts.regardless(graph) + for _,v in ipairs(graph.vertices) do + local regardless = v.options['regardless at'] + if regardless then + offset_vertex(v, regardless - v.pos) + end + end +end + + + +-- Done + +return Sublayouts diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/doc.lua new file mode 100644 index 0000000000..19bfd52fdf --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/doc.lua @@ -0,0 +1,245 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "desired at" + +summary +[[ +When you add this key to a node in a graph, you ``desire'' +that the node should be placed at the \meta{coordinate} by the graph +drawing algorithm. +]] + +documentation +[[ +Now, when you set this key for a single node of a graph, +then, by shifting the graph around, this ``wish'' can obviously +always be fulfill: +% +\begin{codeexample}[preamble={ \usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{force}}] +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a [desired at={(1,2)}] -- b -- c -- a; + }; +\end{tikzpicture} +\end{codeexample} +% +\begin{codeexample}[preamble={ \usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{force}}] +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a -- b[desired at={(2,1)}] -- c -- a; + }; +\end{tikzpicture} +\end{codeexample} +% +Since the key's name is a bit long and since the many braces and +parentheses are a bit cumbersome, there is a special support for +this key inside a |graph|: The standard |/tikz/at| key is redefined +inside a |graph| so that it points to |/graph drawing/desired at| +instead. (Which is more logical anyway, since it makes no sense to +specify an |at| position for a node whose position it to be computed +by a graph drawing algorithm.) A nice side effect of this is that +you can use the |x| and |y| keys (see +Section~\ref{section-graphs-xy}) to specify desired positions: +% +\begin{codeexample}[preamble={ \usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{force}}] +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a -- b[x=2,y=0] -- c -- a; + }; +\end{tikzpicture} +\end{codeexample} +% +\begin{codeexample}[preamble={ \usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{layered}}] +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [layered layout] + { + a [x=1,y=2] -- { b, c } -- {e, f} -- a + }; +\end{tikzpicture} +\end{codeexample} + +A problem arises when two or more nodes have this key set, because +then your ``desires'' for placement and the positions computed by +the graph drawing algorithm may clash. Graph drawing algorithms are +``told'' about the desired positions. Most algorithms will simply +ignore these desired positions since they will be taken care of in +the so-called post-anchoring phase, see below. However, for some +algorithms it makes a lot of sense to fix the positions of some +nodes and only compute the positions of the other nodes relative +to these nodes. For instance, for a |spring layout| it makes perfect +sense that some nodes are ``nailed to the canvas'' while other +nodes can ``move freely''. +]] + +--[[ +% TODOsp: codeexamples: the following 3 examples need these libraries +% \usetikzlibrary{graphs,graphdrawing} +% \usegdlibrary{force} +--]] +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a[x=1] -- { b, c, d, e -- {f,g,h} }; + { h, g } -- a; + }; +\end{tikzpicture} +]] + +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a -- { b, c, d[x=0], e -- {f[x=2], g, h[x=1]} }; + { h, g } -- a; + }; +\end{tikzpicture} +]] + +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + \graph [spring layout] + { + a -- { b, c, d[x=0], e -- {f[x=2,y=1], g, h[x=1]} }; + { h, g } -- a; + }; +\end{tikzpicture} +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "anchor node" + +summary +[[ +This option can be used with a graph to specify a node that +should be used for anchoring the whole graph. +]] + +documentation +[[ +When this option is specified, after the layout has been computed, the +whole graph will be shifted in such a way that the \meta{node name} is +either +% +\begin{itemize} + \item at the current value of |anchor at| or + \item at the position that is specified in the form of a + |desired at| for the \meta{node name}. +\end{itemize} +% +Note how in the last example |c| is placed at |(1,1)| rather than +|b| as would happen by default. +]] + +--[[ +% TODOsp: codeexamples: the following 4 examples need these libraries +% \usetikzlibrary{graphs,graphdrawing} +% \usegdlibrary{layered} +--]] +example +[[ +\tikz \draw (0,0) + -- (1,0.5) graph [edges=red, layered layout, anchor node=a] { a -> {b,c} } + -- (1.5,0) graph [edges=blue, layered layout, + anchor node=y, anchor at={(2,0)}] { x -> {y,z} }; +]] + +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (3,2); + + \graph [layered layout, anchor node=c, edges=rounded corners] + { a -- {b [x=1,y=1], c [x=1,y=1] } -- d -- a}; +\end{tikzpicture} +]] +-------------------------------------------------------------------- + + + + +-------------------------------------------------------------------- +key "anchor at" + +summary +[[ +The coordinate at which the graph should be anchored when no +explicit anchor is given for any node. The initial value is the origin. +]] + +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (2,2); + + \graph [layered layout, edges=rounded corners, anchor at={(1,2)}] + { a -- {b, c [anchor here] } -- d -- a}; +\end{tikzpicture} +]] +-------------------------------------------------------------------- + + + + +-------------------------------------------------------------------- +key "anchor here" + +summary +[[ +This option can be passed to a single node (rather than the +graph as a whole) in order to specify that this node should be used +for the anchoring process. +]] + +documentation +[[ +In the example, |c| is placed at the origin since this is the +default |anchor at| position. +]] + +example +[[ +\begin{tikzpicture} + \draw [help lines] (0,0) grid (2,2); + + \graph [layered layout, edges=rounded corners] + { a -- {b, c [anchor here] } -- d -- a}; +\end{tikzpicture} +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/library.lua new file mode 100644 index 0000000000..df7ce68dd9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/control/library.lua @@ -0,0 +1,196 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Load declarations from: + +require "pgf.gd.control.FineTune" +require "pgf.gd.control.Anchoring" +require "pgf.gd.control.Sublayouts" +require "pgf.gd.control.Orientation" +require "pgf.gd.control.Distances" +require "pgf.gd.control.Components" +require "pgf.gd.control.ComponentAlign" +require "pgf.gd.control.ComponentDirection" +require "pgf.gd.control.ComponentDistance" +require "pgf.gd.control.ComponentOrder" +require "pgf.gd.control.NodeAnchors" + + +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local lib = require "pgf.gd.lib" + + + +--- + +declare { + key = "nodes behind edges", + type = "boolean", + + summary = "Specifies, that nodes should be drawn behind the edges", + documentation = [[" + Once a graph drawing algorithm has determined positions for the nodes, + they are drawn \emph{before} the edges are drawn; after + all, it is hard to draw an edge between nodes when their positions + are not yet known. However, we typically want the nodes to be + rendered \emph{after} or rather \emph{on top} of the edges. For + this reason, the default behavior is that the nodes at their + final positions are collected in a box that is inserted into the + output stream only after the edges have been drawn -- which has + the effect that the nodes will be placed ``on top'' of the + edges. + + This behavior can be changed using this option. When the key is + invoked, nodes are placed \emph{behind} the edges. + "]], + examples = [[" + \tikz \graph [simple necklace layout, nodes={draw,fill=white}, + nodes behind edges] + { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; + "]] +} + + +--- + +declare { + key = "edges behind nodes", + use = { + { key = "nodes behind edges", value = "false" }, + }, + + summary = [[" + This is the default placement of edges: Behind the nodes. + "]], + examples = [[" + \tikz \graph [simple necklace layout, nodes={draw,fill=white}, + edges behind nodes] + { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; + "]] +} + +--- +declare { + key = "random seed", + type = "number", + initial = "42", + + summary = [[" + To ensure that the same is always shown in the same way when the + same algorithm is applied, the random is seed is reset on each call + of the graph drawing engine. To (possibly) get different results on + different runs, change this value. + "]] +} + + +--- +declare { + key = "variation", + type = "number", + use = { + { key = "random seed", value = lib.id }, + }, + summary = "An alias for |random seed|." +} + + +--- +declare { + key = "weight", + type = "number", + initial = 1, + + summary = [[" + Sets the ``weight'' of an edge or a node. For many algorithms, this + number tells the algorithm how ``important'' the edge or node is. + For instance, in a |layered layout|, an edge with a large |weight| + will be as short as possible. + "]], + examples = {[[" + \tikz \graph [layered layout] { + a -- {b,c,d} -- e -- a; + }; + "]],[[" + \tikz \graph [layered layout] { + a -- {b,c,d} -- e --[weight=3] a; + }; + "]] + } +} + + + +--- +declare { + key = "length", + type = "length", + initial = 1, + + summary = [[" + Sets the ``length'' of an edge. Algorithms may take this value + into account when drawing a graph. + "]], + examples = {[[" + \tikz \graph [phylogenetic tree layout] { + a --[length=2] b --[length=1] {c,d}; + a --[length=3] e + }; + "]], + } +} + + +--- + +declare { + key = "radius", + type = "number", + initial = "0", + + summary = [[" + The radius of a circular object used in graph drawing. + "]] +} + +--- + +declare { + key = "no layout", + algorithm = { + run = + function (self) + for _,v in ipairs(self.digraph.vertices) do + if v.options['desired at'] then + v.pos.x = v.options['desired at'].x + v.pos.y = v.options['desired at'].y + end + end + end }, + summary = "This layout does nothing.", +} + + + +-- The following collection kinds are internal + +declare { + key = InterfaceCore.sublayout_kind, + layer = 0 +} + +declare { + key = InterfaceCore.subgraph_node_kind, + layer = 0 +} + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua new file mode 100644 index 0000000000..d7baed45da --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua @@ -0,0 +1,65 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The Cluster class defines a model of a cluster inside a graph. +-- +-- + +local Cluster = {} +Cluster.__index = Cluster + + +-- Namespace + + + +--- TODO Jannis: Add documentation for this class. +-- +function Cluster.new(name) + local cluster = { + name = name, + nodes = {}, + contains_node = {}, + } + setmetatable(cluster, Cluster) + return cluster +end + + + +function Cluster:getName() + return self.name +end + + + +function Cluster:addNode(node) + if not self:findNode(node) then + self.contains_node[node] = true + self.nodes[#self.nodes + 1] = node + end +end + + + +function Cluster:findNode(node) + return self.contains_node[node] +end + + + + +-- Done + +return Cluster \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Edge.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Edge.lua new file mode 100644 index 0000000000..7355597955 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Edge.lua @@ -0,0 +1,358 @@ +-- Copyright 2010 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +--- The Edge class +-- +-- + +local Edge = {} +Edge.__index = Edge + + +-- Namespace + +local lib = require "pgf.gd.lib" + + +-- Definitions + +Edge.UNDIRECTED = "--" +Edge.LEFT = "<-" +Edge.RIGHT = "->" +Edge.BOTH = "<->" +Edge.NONE = "-!-" + + +--- Creates an edge between nodes of a graph. +-- +-- @param values Values to override default edge settings. +-- The following parameters can be set:\par +-- |nodes|: TODO \par +-- |edge_nodes|: TODO \par +-- |options|: TODO \par +-- |tikz_options|: TODO \par +-- |direction|: TODO \par +-- |bend_points|: TODO \par +-- |bend_nodes|: TODO \par +-- |reversed|: TODO \par +-- +-- @return A newly-allocated edge. +-- +function Edge.new(values) + local defaults = { + nodes = {}, + edge_nodes = '', + options = {}, + tikz_options = {}, + direction = Edge.DIRECTED, + bend_points = {}, + bend_nodes = {}, + reversed = false, + algorithmically_generated_options = {}, + index = nil, + event_index = nil, + } + setmetatable(defaults, Edge) + if values then + for k,v in pairs(values) do + defaults[k] = v + end + end + return defaults +end + + + +--- Sets the edge option \meta{name} to \meta{value}. +-- +-- @param name Name of the option to be changed. +-- @param value New value for the edge option \meta{name}. +-- +function Edge:setOption(name, value) + self.options[name] = value +end + + + +--- Returns the value of the edge option \meta{name}. +-- +-- @param name Name of the option. +-- @param graph If this optional argument is given, +-- in case the option is not set as a node parameter, +-- we try to look it up as a graph parameter. +-- +-- @return The value of the edge option \meta{name} or |nil|. +-- +function Edge:getOption(name, graph) + return lib.lookup_option(name, self, graph) +end + + + +--- Checks whether or not the edge is a loop edge. +-- +-- An edge is a loop if it one node multiple times and no other node. +-- +-- @return |true| if the edge is a loop, |false| otherwise. +-- +function Edge:isLoop() + local nodes = self.nodes + for i=1,#nodes do + if nodes[i] ~= nodes[1] then + return false + end + end + return true +end + + + +--- Returns whether or not the edge is a hyperedge. +-- +-- A hyperedge is an edge with more than two adjacent nodes. +-- +-- @return |true| if the edge is a hyperedge. |false| otherwise. +-- +function Edge:isHyperedge() + return self:getDegree() > 2 +end + + + +--- Returns all nodes of the edge. +-- +-- Instead of calling |edge:getNodes()| the nodes can alternatively be +-- accessed directly with |edge.nodes|. +-- +-- @return All edges of the node. +-- +function Edge:getNodes() + return self.nodes +end + + + +--- Returns whether or not a node is adjacent to the edge. +-- +-- @param node The node to check. +-- +-- @return |true| if the node is adjacent to the edge. |false| otherwise. +-- +function Edge:containsNode(node) + return lib.find(self.nodes, function (other) return other == node end) ~= nil +end + + + +--- If possible, adds a node to the edge. +-- +-- @param node The node to be added to the edge. +-- +function Edge:addNode(node) + table.insert(self.nodes, node) + node:addEdge(self) +end + + + +--- Gets first neighbor of the node (disregarding hyperedges). +-- +-- @param node The node which first neighbor should be returned. +-- +-- @return The first neighbor of the node. +-- +function Edge:getNeighbour(node) + if node == self.nodes[1] then + return self.nodes[#self.nodes] + else + return self.nodes[1] + end +end + + + +--- Counts the nodes on this edge. +-- +-- @return The number of nodes on the edge. +-- +function Edge:getDegree() + return #self.nodes +end + + + +function Edge:getHead() + -- by default, the head of -> edges is the last node and the head + -- of <- edges is the first node + local head_index = (self.direction == Edge.LEFT) and 1 or #self.nodes + + -- if the edge should be assumed reversed, we simply switch head and + -- tail positions + if self.reversed then + head_index = (head_index == 1) and #self.nodes or 1 + end + + return self.nodes[head_index] +end + + + +function Edge:getTail() + -- by default, the tail of -> edges is the first node and the tail + -- of <- edges is the last node + local tail_index = (self.direction == Edge.LEFT) and #self.nodes or 1 + + -- if the edge should be assumed reversed, we simply switch head + -- and tail positions + if self.reversed then + tail_index = (tail_index == 1) and #self.nodes or 1 + end + + return self.nodes[tail_index] +end + + + +--- Checks whether a node is the head of the edge. Does not work for hyperedges. +-- +-- This method only works for edges with two adjacent nodes. +-- +-- Edges may be reversed internally, so their head and tail might be switched. +-- Whether or not this internal reversal is handled by this method +-- can be specified with the optional second \meta{ignore\_reversed} parameter +-- which is |false| by default. +-- +-- @param node The node to check. +-- +-- @return True if the node is the head of the edge. +-- +function Edge:isHead(node) + local result = false + + -- by default, the head of -> edges is the last node and the head + -- of <- edges is the first node + local head_index = (self.direction == Edge.LEFT) and 1 or #self.nodes + + -- if the edge should be assumed reversed, we simply switch head and + -- tail positions + if self.reversed then + head_index = (head_index == 1) and #self.nodes or 1 + end + + -- check if the head node equals the input node + if self.nodes[head_index].name == node.name then + result = true + end + + return result +end + + + +--- Checks whether a node is the tail of the edge. Does not work for hyperedges. +-- +-- This method only works for edges with two adjacent nodes. +-- +-- Edges may be reversed internally, so their head and tail might be switched. +-- Whether or not this internal reversal is handled by this method +-- can be specified with the optional second \meta{ignore\_reversed} parameter +-- which is |false| by default. +-- +-- @param node The node to check. +-- @param ignore_reversed Optional parameter. Set this to true if reversed edges +-- should not be considered reversed for this method call. +-- +-- @return True if the node is the tail of the edge. +-- +function Edge:isTail(node, ignore_reversed) + local result = false + + -- by default, the tail of -> edges is the first node and the tail + -- of <- edges is the last node + local tail_index = (self.direction == Edge.LEFT) and #self.nodes or 1 + + -- if the edge should be assumed reversed, we simply switch head + -- and tail positions + if self.reversed then + tail_index = (tail_index == 1) and #self.nodes or 1 + end + + -- check if the tail node equals the input node + if self.nodes[tail_index].name == node.name then + result = true + end + + return result +end + + + +--- Copies an edge (preventing accidental use). +-- +-- The nodes of the edge are not preserved and have to be added +-- to the copy manually if necessary. +-- +-- @return Shallow copy of the edge. +-- +function Edge:copy() + local result = lib.copy(self, Edge.new()) + result.nodes = {} + return result + end + + + + +local function reverse_values(source) + local copy = {} + for i = 1,#source do + copy[i] = source[#source-i+1] + end + return copy +end + + +--- Returns a readable string representation of the edge. +-- +-- @ignore This should not appear in the documentation. +-- +-- @return String representation of the edge. +-- +function Edge:__tostring() + local result = "Edge(" .. self.direction .. ", reversed = " .. tostring(self.reversed) .. ", " + if #self.nodes > 0 then + local node_strings = lib.imap(self.nodes, function (node) return node.name end) + result = result .. table.concat(node_strings, ', ') + end + --return result .. ")" + + -- Note: the following lines generate a shorter string representation + -- of the edge that is more readable and can be used for debugging. + -- So please don't remove this: + -- + local node_strings = lib.imap(self.nodes, function (node) return node.name end) + if self.reversed then + return table.concat(reverse_values(node_strings), ' ' .. self.direction .. ' ') + else + return table.concat(node_strings, ' ' .. self.direction .. ' ') + end +end + + + +-- Done + +return Edge \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Graph.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Graph.lua new file mode 100644 index 0000000000..161b89fd15 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Graph.lua @@ -0,0 +1,396 @@ +-- Copyright 2010 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +--- The Graph class +-- +-- + +local Graph = {} +Graph.__index = Graph + + +-- Namespace + +-- Imports +local Edge = require "pgf.gd.deprecated.Edge" + +local lib = require "pgf.gd.lib" + + +--- Creates a new graph. +-- +-- @param values Values to override default graph settings. +-- The following parameters can be set:\par +-- |nodes|: The nodes of the graph.\par +-- |edges|: The edges of the graph.\par +-- |clusters|: The node clusters of the graph.\par +-- |options|: A table of node options passed over from \tikzname. +-- |events|: A sequence of events signaled during the graph specification. +-- +-- @return A newly-allocated graph. +-- +function Graph.new(values) + local defaults = { + nodes = {}, + edges = {}, + clusters = {}, + options = {}, + events = {}, + } + setmetatable(defaults, Graph) + if values then + for k,v in pairs(values) do + defaults[k] = v + end + end + return defaults +end + + + +--- Prepares a graph for an algorithm. +-- +-- This method causes self, all its nodes, and all its edges to get +-- a new empty table for the key algorithm. This allows an algorithm to +-- store stuff with nodes and edges without them interfering with information +-- stored by other algorithms. +-- +-- @param An algorithm object. + +function Graph:registerAlgorithm(algorithm) + self[algorithm] = self[algorithm] or {} + + -- Add an algorithm field to all nodes, all edges, and the graph: + for _,n in pairs(self.nodes) do + n[algorithm] = n[algorithm] or {} + end + for _,e in pairs(self.edges) do + e[algorithm] = e[algorithm] or {} + end +end + + +--- Sets the graph option \meta{name} to \meta{value}. +-- +-- @param name Name of the option to be changed. +-- @param value New value for the graph option \meta{name}. +-- +function Graph:setOption(name, value) + self.options[name] = value +end + + + +--- Returns the value of the graph option \meta{name}. +-- +-- @param name Name of the option. +-- +-- @return The value of the graph option \meta{name} or |nil|. +-- +function Graph:getOption(name) + return self.options[name] +end + + + + +--- Creates a shallow copy of a graph. +-- +-- The nodes and edges of the original graph are not preserved in the copy. +-- +-- @return A shallow copy of the graph. +-- +function Graph:copy () + return Graph.new({options = self.options, events = self.events}) +end + + +--- Adds a node to the graph. +-- +-- @param node The node to be added. +-- +function Graph:addNode(node) + -- only add the node if it's not included in the graph yet + if not self:findNode(node.name) then + -- Does the node have an index, yet? + if not node.index then + node.index = #self.nodes + 1 + end + + table.insert(self.nodes, node) + end +end + + + +--- If possible, removes a node from the graph and returns it. +-- +-- @param node The node to remove. +-- +-- @return The removed node or |nil| if it was not found in the graph. +-- +function Graph:removeNode(node) + local _, index = lib.find(self.nodes, function (other) + return other.name == node.name + end) + if index then + table.remove(self.nodes, index) + return node + else + return nil + end +end + + + +--- If possible, looks up the node with the given name in the graph. +-- +-- @param name Name of the node to look up. +-- +-- @return The node with the given name or |nil| if it was not found in the graph. +-- +function Graph:findNode(name) + return self:findNodeIf(function (node) return node.name == name end) +end + + + +--- Looks up the first node for which the function \meta{test} returns |true|. +-- +-- @param test A function that takes one parameter (a |Node|) and returns +-- |true| or |false|. +-- +-- @return The first node for which \meta{test} returns |true|. +-- +function Graph:findNodeIf(test) + return lib.find(self.nodes, test) +end + + + +--- Like removeNode, but also deletes all adjacent edges of the removed node. +-- +-- This function also removes the deleted adjacent edges from all neighbors +-- of the removed node. +-- +-- @param node The node to be deleted together with its adjacent edges. +-- +-- @return The removed node or |nil| if the node was not found in the graph. +-- +function Graph:deleteNode(node) + local node = self:removeNode(node) + if node then + for _,edge in ipairs(node.edges) do + self:removeEdge(edge) + for _,other_node in ipairs(edge.nodes) do + if other_node.name ~= node.name then + other_node:removeEdge(edge) + end + end + end + node.edges = {} + end + return node +end + + + +-- Checks whether the edge already exists in the graph and returns it if possible. +-- +-- @param edge Edge to search for. +-- +-- @return The edge if it was found in the graph, |nil| otherwise. +-- +function Graph:findEdge(edge) + return lib.find(self.edges, function (other) return other == edge end) +end + + + +--- Adds an edge to the graph. +-- +-- @param edge The edge to be added. +-- +function Graph:addEdge(edge) + if not edge.index then + edge.index = #self.edges + 1 + end + + table.insert(self.edges, edge) +end + + + +--- If possible, removes an edge from the graph and returns it. +-- +-- @param edge The edge to be removed. +-- +-- @return The removed edge or |nil| if it was not found in the graph. +-- +function Graph:removeEdge(edge) + local _, index = lib.find(self.edges, function (other) return other == edge end) + if index then + table.remove(self.edges, index) + return edge + else + return nil + end +end + + + +--- Like removeEdge, but also removes the edge from its adjacent nodes. +-- +-- @param edge The edge to be deleted. +-- +-- @return The removed edge or |nil| if it was not found in the graph. +-- +function Graph:deleteEdge(edge) + local edge = self:removeEdge(edge) + if edge then + for _,node in ipairs(edge.nodes) do + node:removeEdge(edge) + end + end + return edge +end + + + +--- Removes an edge between two nodes and also removes it from these nodes. +-- +-- @param from Start node of the edge. +-- @param to End node of the edge. +-- +-- @return The deleted edge. +-- +function Graph:deleteEdgeBetweenNodes(from, to) + -- try to find the edge + local edge = lib.find(self.edges, function (edge) + return edge.nodes[1] == from and edge.nodes[2] == to + end) + + -- delete and return the edge + if edge then + return self:deleteEdge(edge) + else + return nil + end +end + + + +--- Creates and adds a new edge to the graph. +-- +-- @param first_node The first node of the new edge. +-- @param second_node The second node of the new edge. +-- @param direction The direction of the new edge. Possible values are +-- \begin{itemize} +-- \item |Edge.UNDIRECTED|, +-- \item |Edge.LEFT|, +-- \item |Edge.RIGHT|, +-- \item |Edge.BOTH| and +-- \item |Edge.NONE| (for invisible edges). +-- \end{itemize} +-- @param edge_nodes A string of \tikzname\ edge nodes that needs to be passed +-- back to the \TeX layer unmodified. +-- @param options The options of the new edge. +-- @param tikz_options A table of \tikzname\ options to be used by graph drawing +-- algorithms to treat the edge in special ways. +-- +-- @return The newly created edge. +-- +function Graph:createEdge(first_node, second_node, direction, edge_nodes, options, tikz_options) + local edge = Edge.new{ + direction = direction, + edge_nodes = edge_nodes, + options = options, + tikz_options = tikz_options + } + edge:addNode(first_node) + edge:addNode(second_node) + self:addEdge(edge) + return edge +end + + + +--- Returns the cluster with the given name or |nil| if no such cluster exists. +-- +-- @param name Name of the node cluster to look up. +-- +-- @return The cluster with the given name or |nil| if no such cluster is defined. +-- +function Graph:findClusterByName(name) + return lib.find(self.clusters, function (cluster) + return cluster.name == name + end) +end + + + +--- Tries to add a cluster to the graph. Returns whether or not this was successful. +-- +-- Clusters are supposed to have unique names. This function will add the given +-- cluster only if there is no cluster with this name already. It returns |true| +-- if the cluster was added and |false| otherwise. +-- +-- @param cluster Cluster to add to the graph. +-- +-- @return |true| if the cluster was added successfully, |false| otherwise. +-- +function Graph:addCluster(cluster) + if not self:findClusterByName(cluster.name) then + table.insert(self.clusters, cluster) + end +end + + + + + +--- Returns a string representation of this graph including all nodes and edges. +-- +-- @ignore This should not appear in the documentation. +-- +-- @return Graph as string. +-- +function Graph:__tostring() + local tmp = Graph.__tostring + Graph.__tostring = nil + local result = "Graph<" .. tostring(self) .. ">((" + Graph.__tostring = tmp + + local first = true + for _,node in ipairs(self.nodes) do + if first then first = false else result = result .. ", " end + result = result .. tostring(node) + end + result = result .. "), (" + first = true + for _,edge in ipairs(self.edges) do + if first then first = false else result = result .. ", " end + result = result .. tostring(edge) + end + + return result .. "))" +end + + + +-- Done + +return Graph diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua new file mode 100644 index 0000000000..903291a892 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua @@ -0,0 +1,91 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The Iterators class is a singleton object. +-- +-- It provides advanced iterators. + +local Iterators = {} + +-- Namespace + +local lib = require("pgf.gd.lib") + + + +--- Iterator for traversing a \meta{dag} using a topological sorting. +-- +-- A topological sorting of a directed graph is a linear ordering of its +-- nodes such that, for every edge |(u,v)|, |u| comes before |v|. +-- +-- Important note: if performed on a graph with at least one cycle a +-- topological sorting is impossible. Thus, the nodes returned from the +-- iterator are not guaranteed to satisfy the ``|u| comes before |v|'' +-- criterion. The iterator may even terminate early or loop forever. +-- +-- @param graph A directed acyclic graph. +-- +-- @return An iterator for traversing \meta{graph} in a topological order. +-- +function Iterators.topologicallySorted(dag) + -- track visited edges + local deleted_edges = {} + + -- collect all sources (nodes with no incoming edges) of the dag + local sources = lib.imap(dag.nodes, function (node) if node:getInDegree() == 0 then return node end end) + + -- return the iterator function + return function () + while #sources > 0 do + -- fetch the next sink from the queue + local source = table.remove(sources, 1) + + -- get its outgoing edges + local out_edges = source:getOutgoingEdges() + + -- iterate over all outgoing edges we haven't visited yet + for _,edge in ipairs(out_edges) do + if not deleted_edges[edge] then + -- mark the edge as visited + deleted_edges[edge] = true + + -- get the node at the other end of the edge + local neighbour = edge:getNeighbour(source) + + -- get a list of all incoming edges of the neighbor that have + -- not been visited yet + local in_edges = lib.imap(neighbour:getIncomingEdges(), + function (edge) if not deleted_edges[edge] then return edge end end) + + -- if there are no such edges then we have a new source + if #in_edges == 0 then + sources[#sources+1] = neighbour + end + end + end + + -- return the current source + return source + end + + -- the iterator terminates if there are no sources left + return nil + end +end + + + +-- Done + +return Iterators diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Node.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Node.lua new file mode 100644 index 0000000000..379a65fafd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Node.lua @@ -0,0 +1,280 @@ +-- Copyright 2010 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The Node class +-- +-- + +local Node = {} +Node.__index = Node + + +-- Namespace + +local lib = require "pgf.gd.lib" + + +-- Imports + +local Vector = require "pgf.gd.deprecated.Vector" + + + +--- Creates a new node. +-- +-- @param values Values to override default node settings. +-- The following parameters can be set:\par +-- |name|: The name of the node. It is obligatory to define this.\par +-- |tex|: Information about the corresponding \TeX\ node.\par +-- |edges|: Edges adjacent to the node.\par +-- |pos|: Initial position of the node.\par +-- |options|: A table of node options passed over from \tikzname. +-- +-- @return A newly allocated node. +-- +function Node.new(values) + local new = { + class = Node, + name = nil, + tex = { + -- texNode = nil, + -- maxX = nil, + -- minX = nil, + -- maxY = nil, + -- minY = nil + }, + edges = {}, + -- pos = nil, + options = {}, + -- growth_direction = nil, + -- index = nil, + -- event_index = nil, + kind = "node", + } + setmetatable(new, Node) + if values then + for k,v in pairs(values) do + new [k] = v + end + end + if not new.pos then + new.pos = Vector.new(2) + end + return new +end + + + +--- Sets the node option \meta{name} to \meta{value}. +-- +-- @param name Name of the node option to be changed. +-- @param value New value for the node option \meta{name}. +-- +function Node:setOption(name, value) + self.options[name] = value +end + + + +--- Returns the value of the node option \meta{name}. +-- +-- @param name Name of the node option. +-- @param graph If this optional argument is given, +-- in case the option is not set as a node parameter, +-- we try to look it up as a graph parameter. +-- +-- @return The value of the node option \meta{name} or |nil|. +-- +function Node:getOption(name, graph) + return lib.lookup_option(name, self, graph) +end + + + +--- Computes the width of the node. +-- +-- @return Width of the node. +-- +function Node:getTexWidth() + return math.abs(self.tex.maxX - self.tex.minX) +end + + + +--- Computes the height of the node. +-- +-- @return Height of the node. +-- +function Node:getTexHeight() + return math.abs(self.tex.maxY - self.tex.minY) +end + + + +--- Adds new edge to the node. +-- +-- @param edge The edge to be added. +-- +function Node:addEdge(edge) + table.insert(self.edges, edge) +end + + + +--- Removes an edge from the node. +-- +-- @param edge The edge to remove. +-- +function Node:removeEdge(edge) + self.edges = lib.imap (self.edges, function(other) if other ~= edge then return other end end) +end + + + +--- Counts the adjacent edges of the node. +-- +-- @return The number of adjacent edges of the node. +-- +function Node:getDegree() + return #self.edges +end + + + +--- Returns all edges of the node. +-- +-- Instead of calling |node:getEdges()| the edges can alternatively be +-- accessed directly with |node.edges|. +-- +-- @return All edges of the node. +-- +function Node:getEdges() + return self.edges +end + + + +--- Returns the incoming edges of the node. Undefined result for hyperedges. +-- +-- @param ignore_reversed Optional parameter to consider reversed edges not +-- reversed for this method call. Defaults to |false|. +-- +-- @return Incoming edges of the node. This includes undirected edges +-- and directed edges pointing to the node. +-- +function Node:getIncomingEdges(ignore_reversed) + return lib.imap(self.edges, + function (edge) + if edge:isHead(self, ignore_reversed) then return edge end + end) +end + + + +--- Returns the outgoing edges of the node. Undefined result for hyperedges. +-- +-- @param ignore_reversed Optional parameter to consider reversed edges not +-- reversed for this method call. Defaults to |false|. +-- +-- @return Outgoing edges of the node. This includes undirected edges +-- and directed edges leaving the node. +-- +function Node:getOutgoingEdges(ignore_reversed) + return lib.imap(self.edges, + function (edge) + if edge:isTail(self, ignore_reversed) then return edge end + end) +end + + + +--- Returns the number of incoming edges of the node. +-- +-- @see Node:getIncomingEdges(reversed) +-- +-- @param ignore_reversed Optional parameter to consider reversed edges not +-- reversed for this method call. Defaults to |false|. +-- +-- @return The number of incoming edges of the node. +-- +function Node:getInDegree(ignore_reversed) + return #self:getIncomingEdges(ignore_reversed) +end + + + +--- Returns the number of edges starting at the node. +-- +-- @see Node:getOutgoingEdges() +-- +-- @param ignore_reversed Optional parameter to consider reversed edges not +-- reversed for this method call. Defaults to |false|. +-- +-- @return The number of outgoing edges of the node. +-- +function Node:getOutDegree(ignore_reversed) + return #self:getOutgoingEdges(ignore_reversed) +end + + + +--- Creates a shallow copy of the node. +-- +-- Most notably, the edges adjacent are not preserved in the copy. +-- +-- @return Copy of the node. +-- +function Node:copy() + local result = lib.copy(self, Node.new()) + result.edges = {} + return result +end + + + +--- Compares two nodes by their name. +-- +-- @ignore This should not appear in the documentation. +-- +-- @param other Another node to compare with. +-- +-- @return |true| if both nodes have the same name. |false| otherwise. +-- +function Node:__eq(object) + return self.name == object.name +end + + + +--- Returns a formated string representation of the node. +-- +-- @ignore This should not appear in the documentation. +-- +-- @return String representation of the node. +-- +function Node:__tostring() + local tmp = Node.__tostring + Node.__tostring = nil + local result = "Node<" .. tostring(self) .. ">(" .. self.name .. ")" + Node.__tostring = tmp + return result +end + + + + +-- Done + +return Node diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Vector.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Vector.lua new file mode 100644 index 0000000000..8af7378154 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/deprecated/Vector.lua @@ -0,0 +1,256 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- Vector class +-- +-- This class augments a normal array so that: +-- +-- 1) Several functions like "plus" or "normalize" become available. +-- 2) You can access the ".x" and ".y" fields to get the fields [1] and [2]. + +local Vector = {} + + +-- Namespace: +local lib = require "pgf.gd.lib" +lib.Vector = Vector + + +-- Class setup +Vector.__index = + function (t, k) + if k == "x" then + return rawget(t,1) + elseif k == "y" then + return rawget(t,2) + else + return rawget(Vector,k) + end + end +Vector.__newindex = + function (t, k, v) + if k == "x" then + rawset(t,1,v) + elseif k == "y" then + rawset(t,2,v) + else + rawset(t,k,v) + end + end + + + +--- Creates a new vector with \meta{n} values using an optional \meta{fill\_function}. +-- +-- @param n The number of elements of the vector. (If omitted, then 2.) +-- @param fill_function Optional function that takes a number between 1 and \meta{n} +-- and is expected to return a value for the corresponding element +-- of the vector. If omitted, all elements of the vector will +-- be initialized with 0. +-- +-- @return A newly-allocated vector with \meta{n} elements. +-- +function Vector.new(n, fill_function) + -- create vector + local vector = { } + setmetatable(vector, Vector) + + local n = n or 2 + + if type(n) == 'table' then + for k,v in pairs(n) do + vector[k] = v + end + else + -- fill vector elements with values + if not fill_function then + for i = 1,n do + rawset(vector,i,0) + end + else + for i = 1,n do + rawset(vector,i,fill_function(i)) + end + end + end + + return vector +end + + + +--- Creates a copy of the vector that holds the same elements as the original. +-- +-- @return A newly-allocated copy of the vector holding exactly the same elements. +-- +function Vector:copy() + return Vector.new(#self, function (n) return self[n] end) +end + + + +--- Performs a vector addition and returns the result in a new vector. +-- +-- @param other The vector to add. +-- +-- @return A new vector with the result of the addition. +-- +function Vector:plus(other) + assert(#self == #other) + + return Vector.new(#self, function (n) return self[n] + other[n] end) +end + + + +--- Subtracts two vectors and returns the result in a new vector. +-- +-- @param other Vector to subtract. +-- +-- @return A new vector with the result of the subtraction. +-- +function Vector:minus(other) + assert(#self == #other) + + return Vector.new(#self, function (n) return self[n] - other[n] end) +end + + + +--- Divides a vector by a scalar value and returns the result in a new vector. +-- +-- @param scalar Scalar value to divide the vector by. +-- +-- @return A new vector with the result of the division. +-- +function Vector:dividedByScalar(scalar) + return Vector.new(#self, function (n) return self[n] / scalar end) +end + + + +--- Multiplies a vector by a scalar value and returns the result in a new vector. +-- +-- @param scalar Scalar value to multiply the vector with. +-- +-- @return A new vector with the result of the multiplication. +-- +function Vector:timesScalar(scalar) + return Vector.new(#self, function (n) return self[n] * scalar end) +end + + + +--- Performs the dot product of two vectors and returns the result in a new vector. +-- +-- @param other Vector to perform the dot product with. +-- +-- @return A new vector with the result of the dot product. +-- +function Vector:dotProduct(other) + assert(#self == #other) + + local product = 0 + for n = 1,#self do + product = product + self[n] * other[n] + end + return product +end + + + +--- Computes the Euclidean norm of the vector. +-- +-- @return The Euclidean norm of the vector. +-- +function Vector:norm() + return math.sqrt(self:dotProduct(self)) +end + + + +--- Normalizes the vector and returns the result in a new vector. +-- +-- @return Normalized version of the original vector. +-- +function Vector:normalized() + local norm = self:norm() + if norm == 0 then + return Vector.new(#self) + else + return self:dividedByScalar(self:norm()) + end +end + + + +--- Updates the values of the vector in-place. +-- +-- @param update_function A function that is called for each element of the +-- vector. The elements are replaced by the values +-- returned from this function. +-- +function Vector:update(update_function) + for i=1,#self do + self[i] = update_function(self[i]) + end +end + + + +--- Limits all elements of the vector in-place. +-- +-- @param limit_function A function that is called for each index/element +-- pair. It is supposed to return minimum and maximum +-- values for the element. The element is then clamped +-- to these values. +-- +function Vector:limit(limit_function) + for i=1,#self do + local min, max = limit_function(i, self[i]) + self[i] = math.max(min, math.min(max, value)) + end +end + + +--- Tests whether all elements of two vectors are the same +-- +-- @param other The other vector +-- +-- @return true or false +-- +function Vector:equals(other) + if #self ~= #other then + return false + end + + for n = 1, #self do + if self[n] ~= other[n] then + return false + end + end + + return true +end + + +function Vector:__tostring() + return '(' .. table.concat(self, ', ') .. ')' +end + + + + + +-- Done + +return Vector diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc.lua new file mode 100644 index 0000000000..78b68bbcb1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc.lua @@ -0,0 +1,124 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- The table doc is used for documentation purposes. It is used to +-- provide lazy documentation for keys, that is, to install +-- documentation for keys only when this information is requested and +-- when the documentation is kept in a separate file. +-- +-- Using the doc facility is easy: +-- % +-- \begin{enumerate} +-- \item In the |declare| statement of the key, you do not provide +-- fields like |documentation| or |summary|. Rather, you provide the +-- field |documentation_in|, which gets the name of a Lua file the +-- will be read whenever one of the fields |documentation|, |summary|, +-- or |examples| is requested for the key. +-- \item When the key is requested, |require| will be applied to the +-- filename given in the |documentation_in| field. +-- \item In this file, you start with the following code: +-- % +--\begin{codeexample}[code only] +--local doc = require 'pgf.gd.doc' +--local key = doc.key +--local documentation = doc.documentation +--local summary = doc.summary +--local example = doc.example +--\end{codeexample} +-- % +-- This will setup nice shortcuts for the commands you are going to +-- use in your file. +-- \item Next, for each to-be-lazily-documented key, add a block to +-- the file like the following: +-- % +--\begin{codeexample}[code only] +-- --- +-- key "my radius" +-- summary "This key specifies a radius." +-- documentation +-- [[ +-- This key is used, whenever... +-- ]] +-- example "\tikz \graph [foo layout, my radius=5] { a--b };" +-- example "\tikz \graph [foo layout, my radius=3] { c--d };" +--\end{codeexample} +-- +-- Note that |[[| and |]]| are used in Lua for raw multi-line strings. +-- +-- The effect of the above code will be that for the key |my radius| +-- the different field like |summary| or |documentation| get +-- updated. The |key| function simple ``selects'' a key and subsequent +-- commands like |summary| will update this key until a different key +-- is selected through another use of |key|. +-- \end{enumerate} + +local doc = {} + +local current_key + + +-- Namespace +require "pgf.gd".doc = doc + + +-- Imports +local keys = require "pgf.gd.interface.InterfaceCore".keys + +--- +-- Selects the key which will be subsequently updated by the other +-- functions of this class. +-- +-- @param key A key. + +function doc.key (key) + current_key = assert(keys[key], "trying to document not-yet-declared key") +end + + +--- +-- Updates (replaces) the summary field of the last key selected +-- through the |key| command. +-- +-- @param string A (new) summary string. + +function doc.summary (string) + current_key.summary = string +end + + +--- +-- Updates (replaces) the documentation field of the last key selected +-- through the |key| command. +-- +-- @param string A (new) documentation string. Typically, the |[[| +-- syntax will be used to specify this string. + +function doc.documentation (string) + current_key.documentation = string +end + + +--- +-- Adds an example to the |examples| field of the last key selected +-- through the |key| command. +-- +-- @param string An additional example string. + +function doc.example (string) + local examples = rawget(current_key, "examples") or {} + examples[#examples + 1] = string + current_key.examples = examples +end + + +return doc diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua new file mode 100644 index 0000000000..552dd00dc8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua @@ -0,0 +1,19 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Force-Based Algorithms} +-- +-- + +local _ \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua new file mode 100644 index 0000000000..fcd5b26fb0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua @@ -0,0 +1,129 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "FMMMLayout" +summary "The fast multipole multilevel layout algorithm." + +documentation +[[ +|FMMMLayout| implements a force-directed graph drawing +method suited also for very large graphs. It is based on a +combination of an efficient multilevel scheme and a strategy for +approximating the repulsive forces in the system by rapidly +evaluating potential fields. + +The implementation is based on the following publication: +% +\begin{itemize} + \item Stefan Hachul, Michael J\"unger: Drawing Large Graphs with + a Potential-Field-Based Multilevel Algorithm. \emph{12th + International Symposium on Graph Drawing 1998 (GD '04)}, + New York, LNCS 3383, pp. 285--295, 2004. +\end{itemize} +]] + +example +[[ +\tikz \graph [FMMMLayout] { a -- {b,c,d} -- e -- a }; +]] + + +example +[[ +\tikz [nodes={text height=.7em, text depth=.2em, + draw=black!20, thick, fill=white, font=\footnotesize}, + >={Stealth[round,sep]}, rounded corners, semithick] + \graph [FMMMLayout, node sep=1mm, variation=2] { + "5th Edition" -> { "6th Edition", "PWB 1.0" }; + "6th Edition" -> { "LSX", "1 BSD", "Mini Unix", "Wollongong", "Interdata" }; + "Interdata" ->[orient=down] "Unix/TS 3.0", + "Interdata" -> { "PWB 2.0", "7th Edition" }; + "7th Edition" -> { "8th Edition", "32V", "V7M", "Ultrix-11", "Xenix", "UniPlus+" }; + "V7M" -> "Ultrix-11"; + "8th Edition" -> "9th Edition"; + "1 BSD" -> "2 BSD" -> "2.8 BSD" -> { "Ultrix-11", "2.9 BSD" }; + "32V" -> "3 BSD" -> "4 BSD" -> "4.1 BSD" -> { "4.2 BSD", "2.8 BSD", "8th Edition" }; + "4.2 BSD" -> { "4.3 BSD", "Ultrix-32" }; + "PWB 1.0" -> { "PWB 1.2" -> "PWB 2.0", "USG 1.0" -> { "CB Unix 1", "USG 2.0" }}; + "CB Unix 1" -> "CB Unix 2" -> "CB Unix 3" -> { "Unix/TS++", "PDP-11 Sys V" }; + { "USG 2.0" -> "USG 3.0", "PWB 2.0", "Unix/TS 1.0" } -> "Unix/TS 3.0"; + { "Unix/TS++", "CB Unix 3", "Unix/TS 3.0" } -> + "TS 4.0" -> "System V.0" -> "System V.2" -> "System V.3"; + }; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "FMMMLayout.randSeed" +summary "Sets the random seed for the |FMMMLayout|." +documentation +[[ +By changing this number, you can vary the appearance of the generated +graph drawing. This key is an alias for |random seed|, which in turn +can be set by using the |variation| key. +]] + +example +[[ +\tikz \graph [FMMMLayout, variation=1] { a -- {b,c,d} -- e -- a }; +]] +example +[[ +\tikz \graph [FMMMLayout, variation=2] { a -- {b,c,d} -- e -- a }; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "FMMMLayout.unitEdgeLength" +summary "The ``ideal'' padding between two nodes." + +documentation +[[ +The algorithm will try to make the padding between any two vertices +this distance. Naturally, this is not always possible, so, normally, +distance will actually be different. This key is an alias for the more +natural |node sep|. +]] + +example +[[ +\tikz { + \graph [FMMMLayout, node sep=1cm] { subgraph C_n[n=6]; }; + + \draw [red, ultra thick, |-|] (1.south) -- ++(down:1cm); +} +]] +example +[[ +\tikz { + \graph [FMMMLayout, node sep=5mm] { subgraph C_n[n=6]; }; + + \draw [red, ultra thick, |-|] (1.south) -- ++(down:5mm); +} +]] +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua new file mode 100644 index 0000000000..453078b130 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua @@ -0,0 +1,51 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "FastMultipoleEmbedder" +summary "Implementation of a fast multipole embedder by Martin Gronemann." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "FastMultipoleEmbedder.numIterations" +summary "sets the maximum number of iterations" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "FastMultipoleEmbedder.multipolePrec" +summary "sets the number of coefficients for the expansions. default = 4" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "FastMultipoleEmbedder.defaultEdgeLength" +summary "" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "FastMultipoleEmbedder.defaultNodeSize" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua new file mode 100644 index 0000000000..d0b94c2bb7 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua @@ -0,0 +1,103 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "GEMLayout" +summary "The energy-based GEM layout algorithm." + +documentation [[ + The implementation used in |GEMLayout| is based on the following publication: + % + \begin{itemize} + \item Arne Frick, Andreas Ludwig, Heiko Mehldau: \emph{A Fast Adaptive Layout + Algorithm for Undirected Graphs.} Proc. Graph Drawing 1994, + LNCS 894, pp. 388-403, 1995. + \end{itemize} +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.numberOfRounds" +summary "Sets the maximal number of round per node." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.minimalTemperature" +summary "Sets the minimal temperature." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.initialTemperature" +summary "Sets the initial temperature; must be $\\ge$ |minimalTemperature|." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.gravitationalConstant" +summary "Sets the gravitational constant; must be $\\ge 0$." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.desiredLength" +summary "Sets the desired edge length; must be $\\ge 0$." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.maximalDisturbance" +summary "Sets the maximal disturbance; must be $\\ge 0$." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.rotationAngle" +summary "Sets the opening angle for rotations ($0 \\le x \\le \\pi / 2$)." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.oscillationAngle" +summary "Sets the opening angle for oscillations ($0 \\le x \\le \\pi / 2$)." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.rotationSensitivity" +summary "Sets the rotation sensitivity ($0 \\le x \\le 1$)." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.oscillationSensitivity" +summary "Sets the oscillation sensitivity ($0 \\le x \\le 1$)." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "GEMLayout.attractionFormula" +summary "sets the formula for attraction (1 = Fruchterman / Reingold, 2 = GEM)." +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua new file mode 100644 index 0000000000..6210c93941 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "MultilevelLayout" +summary "A wrapper for the multilevel layout computation using the modular multi-level mixer." + +example [[ +\tikz \graph [MultilevelLayout] { + a -- b -- c -- a -- d -- e -- f -- a +}; +]] +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua new file mode 100644 index 0000000000..ae3cf9c8ef --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua @@ -0,0 +1,53 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFR" +summary "The spring-embedder layout algorithm by Fruchterman and Reingold." + +documentation [[ + The implementation used in SpringEmbedderFR is based on the following + publication: + + Thomas M. J. Fruchterman, Edward M. Reingold: \emph{Graph Drawing by Force-directed + Placement}. Software - Practice and Experience 21(11), pp. 1129--1164, 1991. +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFR.iterations" +summary "Sets the number of iterations." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFR.noise" +summary "Sets the parameter noise." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFR.scaleFunctionFactor" +summary "Sets the scale function factor." +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua new file mode 100644 index 0000000000..6286e9f395 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua @@ -0,0 +1,57 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact" +summary "Declaration of Spring-Embedder (Fruchterman,Reingold) algorithm with exact force computations." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact.iterations" +summary "Sets the number of iterations." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact.noise" +summary "Sets the parameter noise." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact.coolingFunction" +summary "Sets the parameter coolingFunction to |factor| or to |logarithmic|." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact.idealEdgeLength" +summary "Sets the ideal edge length to a length." +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderFRExact.convTolerance" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua new file mode 100644 index 0000000000..a4fd46aa77 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua @@ -0,0 +1,62 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SpringEmbedderKK" +summary "The spring embedder of Kamada and Kawai" + +documentation [[ + The implementation used in |SpringEmbedderKK| is based on + the following publication: + + Tomihisa Kamada, Satoru Kawai: \emph{An Algorithm for Drawing + General Undirected Graphs.} Information Processing Letters 31, pp. 7--15, 1989. + + There are some parameters that can be tuned to optimize the + algorithm's behavior regarding runtime and layout quality. + First of all note that the algorithm uses all pairs shortest path + to compute the graph theoretic distance. This can be done either + with BFS (ignoring node sizes) in quadratic time or by using + e.g. Floyd's algorithm in cubic time with given edge lengths + that may reflect the node sizes. Also |m_computeMaxIt| decides + if the computation is stopped after a fixed maximum number of + iterations. The desirable edge length can either be set or computed + from the graph and the given layout. +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderKK.stopTolerance" +summary "Sets the value for the stop tolerance." +documentation [[ + Below this value, the system is regarded stable (balanced) and the + optimization stopped. +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SpringEmbedderKK.desLength" +summary "Sets desirable edge length directly" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua new file mode 100644 index 0000000000..e658a896bd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "BarycenterPlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "BarycenterPlacer.weightedPositionPriority" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua new file mode 100644 index 0000000000..e6f06add57 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua @@ -0,0 +1,45 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "CirclePlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "CirclePlacer.circleSize" +summary "" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "CirclePlacer.radiusFixed" +summary "" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "CirclePlacer.nodeSelection" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua new file mode 100644 index 0000000000..e8723272ee --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "EdgeCoverMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "EdgeCoverMerger.factor" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua new file mode 100644 index 0000000000..81e2f37db0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "IndependentSetMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "IndependentSetMerger.searchDepthBase" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua new file mode 100644 index 0000000000..7fbca25e81 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "LocalBiconnectedMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "LocalBiconnectedMerger.factor" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua new file mode 100644 index 0000000000..e966b49056 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "MatchingMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "MatchingMerger.selectByNodeMass" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua new file mode 100644 index 0000000000..0b9d967db9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua @@ -0,0 +1,27 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "MedianPlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua new file mode 100644 index 0000000000..71bdbc7340 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "RandomMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "RandomMerger.factor" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua new file mode 100644 index 0000000000..c26946d4e1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "RandomPlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "RandomPlacer.circleSize" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua new file mode 100644 index 0000000000..76b084fa67 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua @@ -0,0 +1,39 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SolarMerger" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SolarMerger.simple" +summary "" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "SolarMerger.massAsNodeRadius" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua new file mode 100644 index 0000000000..530ddbc0d8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua @@ -0,0 +1,27 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SolarPlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua new file mode 100644 index 0000000000..6f579d0a45 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua @@ -0,0 +1,33 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "ZeroPlacer" +summary "?" +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "ZeroPlacer.randomRange" +summary "" +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua new file mode 100644 index 0000000000..ffd3ea844d --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua @@ -0,0 +1,19 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Algorithms for Drawing Layered Graphs} +-- +-- + +local _ \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/BarycenterHeuristic.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/BarycenterHeuristic.lua new file mode 100644 index 0000000000..5e4138eece --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/BarycenterHeuristic.lua @@ -0,0 +1,23 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "BarycenterHeuristic" +summary "The barycenter heuristic for 2-layer crossing minimization." +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua new file mode 100644 index 0000000000..fd13e9bd4b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua @@ -0,0 +1,35 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "CoffmanGrahamRanking" +summary "The ranking algorithm due to Coffman and Graham." +documentation +[[ +|CoffmanGrahamRanking| implements a node ranking algorithm based on +the Coffman--Graham scheduling algorithm, which can be used as first +phase in |SugiyamaLayout|. The aim of the algorithm is to ensure that +the height of the ranking (the number of layers) is kept small. +]] +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "CoffmanGrahamRanking.width" +summary "A mysterious width parameter..." +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/DfsAcyclicSubgraph.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/DfsAcyclicSubgraph.lua new file mode 100644 index 0000000000..eced60b2ed --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/DfsAcyclicSubgraph.lua @@ -0,0 +1,27 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "DfsAcyclicSubgraph" +summary "DFS-based algorithm for computing a maximal acyclic subgraph." +documentation +[[ +The algorithm simply removes all DFS-backedges and works in linear-time. +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua new file mode 100644 index 0000000000..a7baad7e10 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua @@ -0,0 +1,99 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "FastHierarchyLayout" +summary "Coordinate assignment phase for the Sugiyama algorithm by Buchheim et al." +documentation +[[ +This class implements a hierarchy layout algorithm, that is, it +layouts hierarchies with a given order of nodes on each +layer. It is used as a third phase of the Sugiyama algorithm. + +All edges of the layout will have at most two +bends. Additionally, for each edge having exactly two bends, the +segment between them is drawn vertically. This applies in +particular to the long edges arising in the first phase of the +Sugiyama algorithm. + +The implementation is based on: +% +\begin{itemize} + \item + Christoph Buchheim, Michael Jünger, Sebastian Leipert: A Fast + Layout Algorithm for k-Level Graphs. \emph{Proc. Graph + Drawing 2000}, volume 1984 of LNCS, pages 229--240, 2001. +\end{itemize} +]] + +example +[[ +\tikz \graph [SugiyamaLayout, FastHierarchyLayout] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "FastHierarchyLayout.fixedLayerDistance" +summary "If true, the distance between neighbored layers is fixed, otherwise variable." +-------------------------------------------------------------------- + + + + +-------------------------------------------------------------------- +key "FastHierarchyLayout.layerDistance" +summary "Separation distance (padding) between two consecutive layers." + +documentation +[[ +Sets the (minimum?) padding between nodes on two consecutive +layers. It defaults to the sum of the keys +|level pre sep| and |level post sep|. +]] + +example +[[ +\tikz \graph [SugiyamaLayout, FastHierarchyLayout, + level sep=1cm] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- + +-------------------------------------------------------------------- +key "FastHierarchyLayout.nodeDistance" +summary "Separation distance (padding) between two consecutive nodes on the same layer." + +documentation +[[ +Sets the (minimum?) padding between sibling nodes. It defaults to the +sum of the keys |sibling pre sep| and |sibling post sep|. +]] + +example +[[ +\tikz \graph [SugiyamaLayout, FastHierarchyLayout, + sibling sep=5mm] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua new file mode 100644 index 0000000000..4af6daa620 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua @@ -0,0 +1,99 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "FastSimpleHierarchyLayout" +summary "Coordinate assignment phase for the Sugiyama algorithm by Ulrik Brandes and Boris Köpf." + +documentation +[[ +This class implements a hierarchy layout algorithm, that is, it +layouts hierarchies with a given order of nodes on each +layer. It is used as a third phase of the Sugiyama algorithm. + +The algorithm runs in three phases: +% +\begin{enumerate} + \item Alignment (4x) + \item Horizontal Compactation (4x) + \item Balancing +\end{enumerate} +% +The alignment and horizontal compactification phases are calculated +downward, upward, left-to-right and right-to-left. The four +resulting layouts are combined in a balancing step. + +Warning: The implementation is known to not always produce a +correct layout. Therefore this Algorithm is for testing purpose +only. + +The implementation is based on: +% +\begin{itemize} + \item + Ulrik Brandes, Boris Köpf: Fast and Simple Horizontal + Coordinate Assignment. \emph{LNCS} 2002, Volume 2265/2002, + pp. 33--36 +\end{itemize} +]] + +example +[[ +\tikz \graph [SugiyamaLayout, FastSimpleHierarchyLayout] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "FastSimpleHierarchyLayout.layerDistance" +summary "Distance between the centers of nodes of two consecutive layers." + +documentation +[[ +Sets the (minimum?) distance between nodes on two consecutive +layers. It defaults to the key |level distance|. +]] +example +[[ +\tikz \graph [SugiyamaLayout, FastSimpleHierarchyLayout, + level distance=2cm] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- + +-------------------------------------------------------------------- +key "FastSimpleHierarchyLayout.siblingDistance" +summary "Distance between the centers of nodes of sibling nodes." + +documentation +[[ +Sets the (minimum?) padding between sibling nodes. It defaults to +|sibling distance|. +]] +example +[[ +\tikz \graph [SugiyamaLayout, FastSimpleHierarchyLayout, + sibling distance=5mm] { + a -- {b,c,d} -- e -- a; +}; +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua new file mode 100644 index 0000000000..d2f1d8eeea --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua @@ -0,0 +1,27 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "GreedyCycleRemoval" +summary "Greedy algorithm for computing a maximal acyclic subgraph." +documentation +[[ + The algorithm applies a greedy heuristic to compute a maximal + acyclic subgraph and works in linear-time. +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyInsertHeuristic.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyInsertHeuristic.lua new file mode 100644 index 0000000000..a8cd94ef19 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyInsertHeuristic.lua @@ -0,0 +1,23 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "GreedyInsertHeuristic" +summary "The greedy-insert heuristic for 2-layer crossing minimization." +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua new file mode 100644 index 0000000000..3d98fbe9c6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua @@ -0,0 +1,57 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "LongestPathRanking" +summary "The longest-path ranking algorithm." +documentation +[[ + |LongestPathRanking| implements the well-known longest-path ranking + algorithm, which can be used as first phase in |SugiyamaLayout|. The + implementation contains a special optimization for reducing edge + lengths, as well as special treatment of mixed-upward graphs (for + instance, \textsc{uml} class diagrams). +]] +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "LongestPathRanking.separateDeg0Layer" +summary "If set to true, isolated nodes are placed on a separate layer." +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "LongestPathRanking.separateMultiEdges" +summary "If set to true, multi-edges will span at least two layers." +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "LongestPathRanking.optimizeEdgeLength" +summary +[[ + If set to true the ranking algorithm tries to reduce edge + length even if this might increase the height of the layout. Choose + false, if the longest-path ranking known from the literature should be + used. +]] +-------------------------------------------------------------------- + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/MedianHeuristic.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/MedianHeuristic.lua new file mode 100644 index 0000000000..b37480ac78 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/MedianHeuristic.lua @@ -0,0 +1,24 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "MedianHeuristic" +summary "The median heuristic for 2-layer crossing minimization." +-------------------------------------------------------------------- + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua new file mode 100644 index 0000000000..25a8dd5262 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua @@ -0,0 +1,35 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "OptimalRanking" +summary "The optimal ranking algorithm." +documentation +[[ + The |OptimalRanking| implements the LP-based algorithm for + computing a node ranking with minimal edge lengths, which can + be used as first phase in |SugiyamaLayout|. +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "OptimalRanking.separateMultiEdges" +summary "If set to true, multi-edges will span at least two layers." +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua new file mode 100644 index 0000000000..d0815a5b76 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua @@ -0,0 +1,34 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "SiftingHeuristic" +summary "The sifting heuristic for 2-layer crossing minimization." +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "SiftingHeuristic.strategy" +summary "Sets a so-called ``sifting strategy''." +documentation +[[ + The following values are permissible: |left_to_right|, |desc_degree|, + and |random|. +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SplitHeuristic.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SplitHeuristic.lua new file mode 100644 index 0000000000..1579c7153d --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SplitHeuristic.lua @@ -0,0 +1,24 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + + +-------------------------------------------------------------------- +key "SplitHeuristic" +summary "The split heuristic for 2-layer crossing minimization." +-------------------------------------------------------------------- + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua new file mode 100644 index 0000000000..ec75fa7e6e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua @@ -0,0 +1,113 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "SugiyamaLayout" +summary "The OGDF implementation of the Sugiyama algorithm." + +documentation [[ + This layout represents a customizable implementation of Sugiyama's + layout algorithm. The implementation used in |SugiyamaLayout| is based + on the following publications: + + \begin{itemize} + \item Emden R. Gansner, Eleftherios Koutsofios, Stephen + C. North, Kiem-Phong Vo: A technique for drawing directed + graphs. \emph{IEEE Trans. Software Eng.} 19(3):214--230, 1993. + \item Georg Sander: \emph{Layout of compound directed graphs.} + Technical Report, Universität des Saarlandes, 1996. + \end{itemize} +]] + +example +[[ +\tikz \graph [SugiyamaLayout] { a -- {b,c,d} -- e -- a }; +]] + +example +[[ +\tikz \graph [SugiyamaLayout, grow=right] { + a -- {b,c,d} -- e -- a +}; +]] + +example +[[ +\tikz [nodes={text height=.7em, text depth=.2em, + draw=black!20, thick, fill=white, font=\footnotesize}, + >={Stealth[round,sep]}, rounded corners, semithick] + \graph [SugiyamaLayout, FastSimpleHierarchyLayout, grow=-80, + level distance=1.5cm, sibling distance=7mm] { + "5th Edition" -> { "6th Edition", "PWB 1.0" }; + "6th Edition" -> { "LSX", "1 BSD", "Mini Unix", "Wollongong", "Interdata" }; + "Interdata" -> { "Unix/TS 3.0", "PWB 2.0", "7th Edition" }; + "7th Edition" -> { "8th Edition", "32V", "V7M", "Ultrix-11", "Xenix", "UniPlus+" }; + "V7M" -> "Ultrix-11"; + "8th Edition" -> "9th Edition"; + "1 BSD" -> "2 BSD" -> "2.8 BSD" -> { "Ultrix-11", "2.9 BSD" }; + "32V" -> "3 BSD" -> "4 BSD" -> "4.1 BSD" -> { "4.2 BSD", "2.8 BSD", "8th Edition" }; + "4.2 BSD" -> { "4.3 BSD", "Ultrix-32" }; + "PWB 1.0" -> { "PWB 1.2" -> "PWB 2.0", "USG 1.0" -> { "CB Unix 1", "USG 2.0" }}; + "CB Unix 1" -> "CB Unix 2" -> "CB Unix 3" -> { "Unix/TS++", "PDP-11 Sys V" }; + { "USG 2.0" -> "USG 3.0", "PWB 2.0", "Unix/TS 1.0" } -> "Unix/TS 3.0"; + { "Unix/TS++", "CB Unix 3", "Unix/TS 3.0" } -> + "TS 4.0" -> "System V.0" -> "System V.2" -> "System V.3"; + }; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "SugiyamaLayout.runs" +summary "Determines, how many times the crossing minimization is repeated." +documentation +[[ +Each repetition (except for the first) starts with +randomly permuted nodes on each layer. Deterministic behavior can +be achieved by setting |SugiyamaLayout.runs| to 1. +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "SugiyamaLayout.transpose" +documentation [[ + Determines whether the transpose step is performed + after each 2-layer crossing minimization; this step tries to + reduce the number of crossings by switching neighbored nodes on + a layer. +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "SugiyamaLayout.fails" +documentation [[ + The number of times that the number of crossings may + not decrease after a complete top-down bottom-up traversal, + before a run is terminated. +]] +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua new file mode 100644 index 0000000000..9f5f291461 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua @@ -0,0 +1,19 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Miscellaneous Algorithms for Graph Drawing} +-- +-- + +local _ \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua new file mode 100644 index 0000000000..2a250ecece --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua @@ -0,0 +1,48 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "BalloonLayout" +summary "A ``balloon layout''." + +documentation +[[ +This algorithm computes a radial (balloon) layout based on a +spanning tree. The algorithm is partially based on the paper +\emph{On Balloon Drawings of Rooted Trees} by Lin and Yen and on +\emph{Interacting with Huge Hierarchies: Beyond Cone Trees} by +Carriere and Kazman. +]] + +example +[[ +\tikz \graph [BalloonLayout] { a -- {b,c,d -- {e,f,h,h,i}, j -- k -- {l,m,n}} }; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "BalloonLayout.evenAngles" +summary "Subtrees may be assigned even angles or angles depending on their size." +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua new file mode 100644 index 0000000000..c5e2cf7a6c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua @@ -0,0 +1,95 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "CircularLayout" +summary "The circular layout algorithm." + +documentation +[[ +The implementation used in CircularLayout is based on the following publication: +% +\begin{itemize} + \item Ugur Dogrus\"oz, Brendan Madden, Patrick Madden: Circular + Layout in the Graph Layout Toolkit. \emph{Proc. Graph Drawing 1996,} + LNCS 1190, pp. 92--100, 1997. +\end{itemize} +]] + +example +[[ +\tikz \graph [CircularLayout] { + a -- b -- c -- a -- d -- e -- f -- g -- d; + b -- {x,y,z}; +}; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "CircularLayout.minDistCircle" +summary "The minimal padding between nodes on a circle." + +documentation "This is an alias for |part sep|." + +example +[[ +\tikz \graph [CircularLayout, part sep=1cm] { + a -- b -- c -- a -- d -- e -- f -- g -- d; + b -- {x,y,z}; +}; +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "CircularLayout.minDistLevel" +summary "The minimal padding between nodes on different levels." + +documentation "This is an alias for |layer sep| and |level sep|." + +example +[[ +\tikz \graph [CircularLayout, layer sep=1cm] { + a -- b -- c -- a -- d -- e -- f -- g -- d; + b -- {x,y,z}; +}; +]] +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +key "CircularLayout.minDistSibling" +summary "The minimal padding between sibling nodes." + +documentation "This is an alias for |sibling sep|." + +example +[[ +\tikz \graph [CircularLayout, sibling sep=1cm] { + a -- b -- c -- a -- d -- e -- f -- g -- d; + b -- {x,y,z}; +}; +]] +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/AcyclicSubgraphModule.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/AcyclicSubgraphModule.lua new file mode 100644 index 0000000000..b2bb7e1d24 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/AcyclicSubgraphModule.lua @@ -0,0 +1,18 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {Computing Acyclic Subgraphs Module} +-- + +local _ + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/HierarchyLayoutModule.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/HierarchyLayoutModule.lua new file mode 100644 index 0000000000..a0292530cd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/HierarchyLayoutModule.lua @@ -0,0 +1,17 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {The Hierarchy Layout Module} +-- + +local _ diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/InitialPlacer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/InitialPlacer.lua new file mode 100644 index 0000000000..328a2806db --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/InitialPlacer.lua @@ -0,0 +1,17 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {The Initial Placer Module} +-- + +local _ diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/MultilevelBuilder.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/MultilevelBuilder.lua new file mode 100644 index 0000000000..9604c98640 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/MultilevelBuilder.lua @@ -0,0 +1,17 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {The Multilevel Builder Module} +-- + +local _ diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/RankingModule.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/RankingModule.lua new file mode 100644 index 0000000000..8dce27a335 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/RankingModule.lua @@ -0,0 +1,17 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {The Ranking Module} +-- + +local _ diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/TwoLayerCrossMin.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/TwoLayerCrossMin.lua new file mode 100644 index 0000000000..877cba47f6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/module/TwoLayerCrossMin.lua @@ -0,0 +1,17 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {The Two Layer Crossing Minimization Module} +-- + +local _ diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua new file mode 100644 index 0000000000..fb1abb5ccd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua @@ -0,0 +1,19 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Algorithms for Drawing Planar Graphs} +-- +-- + +local _ \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua new file mode 100644 index 0000000000..e61f9281b9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua @@ -0,0 +1,66 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------------------- +key "PlanarizationLayout" +summary "The planarization layout algorithm." + +documentation +[[ + A |PlanarizationLayout| represents a customizable implementation + of the planarization approach for drawing graphs. The implementation + used in PlanarizationLayout is based on the following publication: + % + \begin{itemize} + \item C. Gutwenger, P. Mutzel: \emph{An Experimental Study of Crossing + Minimization Heuristics.} 11th International Symposium on Graph + Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13--24, 2004. + \end{itemize} +]] + +example +[[ +\tikz \graph [PlanarizationLayout] { a -- {b,c,d,e,f} -- g -- a }; +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "PlanarizationLayout.preprocessCliques" +summary "Configures, whether cliques are collapsed in a preprocessing step." +documentation +[[ + If set to true, a preprocessing for cliques (complete subgraphs) + is performed and cliques will be laid out in a special form (straight-line, + not orthogonal). The preprocessing may reduce running time and improve + layout quality if the input graphs contains dense subgraphs. +]] +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +key "PlanarizationLayout.minCliqueSize" +summary "The minimum size of cliques collapsed in preprocessing." +-------------------------------------------------------------------------------- + + +-- Local Variables: +-- mode:latex +-- End: \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples.lua new file mode 100644 index 0000000000..de33c0ed37 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.examples = {} + + +-- Done + +return pgf.gd.examples \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua new file mode 100644 index 0000000000..5acc28396b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua @@ -0,0 +1,32 @@ +local InterfaceToDisplay = require "pgf.gd.interface.InterfaceToDisplay" + +InterfaceToDisplay.bind(require "pgf.gd.examples.BindingToASCII") +require "pgf.gd.layered.library" +require "pgf.gd.force.library" + +local algorithm = io.read():match("%s*graph%s*%[(.-)%]") + +InterfaceToDisplay.pushPhase(algorithm, "main", 1) +InterfaceToDisplay.pushOption("level distance", 6, 2) +InterfaceToDisplay.pushOption("sibling distance", 8, 3) +InterfaceToDisplay.beginGraphDrawingScope(3) +InterfaceToDisplay.pushLayout(4) + +for line in io.lines() do + if line:match("}") then + break + elseif line:find("-") then + local n1, dir, n2 = string.match(line, "^%s*(.-)%s*(-.)%s*(.-)%s*;") + InterfaceToDisplay.createEdge(n1, n2, dir, 4) + else + local n1 = string.match(line, "^%s*(.-)%s*;") + InterfaceToDisplay.createVertex(n1, "rectangle", nil, 4) + end +end + +InterfaceToDisplay.runGraphDrawingAlgorithm() +InterfaceToDisplay.renderGraph() +InterfaceToDisplay.endGraphDrawingScope() + + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua new file mode 100644 index 0000000000..2b5c9cc0b6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua @@ -0,0 +1,87 @@ +local lib = require "pgf.gd.lib" + +-- Create a binding to ourselves +local BindingToASCII = lib.class { base_class = require "pgf.gd.bindings.Binding" } + +local canvas + +function BindingToASCII:renderStart() + canvas = {} + -- Clear the canvas + for x=-30,30 do + canvas [x] = {} + for y=-30,30 do + canvas[x][y] = ' ' + end + end +end + +function BindingToASCII:renderStop() + for y=10,-30,-1 do + local t = {} + for x=-30,30 do + local s = canvas[x][y] + for i=1,#s do + pos = x+30+i-math.floor(#s/2) + if not t[pos] or t[pos] == " " or t[pos] == "." then + t[pos] = string.sub(s,i,i) + end + end + end + print(table.concat(t)) + end +end + +function BindingToASCII:renderVertex(v) + canvas [math.floor(v.pos.x)][math.floor(v.pos.y)] = v.name +end + +function BindingToASCII:renderEdge(e) + + local function connect (p,q) + + local x1, y1, x2, y2 = math.floor(p.x+0.5), math.floor(p.y+0.5), math.floor(q.x+0.5), math.floor(q.y+0.5) + + -- Go upward with respect to x + if x2 < x1 then + x1, y1, x2, y2 = x2, y2, x1, y1 + end + + local delta_x = x2-x1 + local delta_y = y2-y1 + + if math.abs(delta_x) > math.abs(delta_y) then + local slope = delta_y/delta_x + for i=x1,x2 do + local x,y = i, math.floor(y1 + (i-x1)*slope + 0.5) + + if canvas[x][y] == " " then + canvas[x][y] = '.' + end + end + elseif math.abs(delta_y) > 0 then + local slope = delta_x/delta_y + for i=y1,y2,(y1 [red] f; % normal edge + + % Edges generated by the algorithm: + a[new edge to=b]; + b[new edge to=d]; + c[new edge to=f]; +}; +\end{codeexample} + + And the algorithm: + % +\begin{codeexample}[code only, tikz syntax=false] + -- File pgf.gd.examples.SimpleEdgeDemo + + -- Imports + local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" + local declare = InterfaceToAlgorithms.declare + + -- The class object + local SimpleEdgeDemo = {} + +declare { + key = "simple edge demo layout", + algorithm = SimpleEdgeDemo, + summary = "This algorithm shows...", +} +\end{codeexample} + + Next comes the declaration of the new option |new edge to|: + % +\begin{codeexample}[code only, tikz syntax=false] +declare { + key = "new edge to", + type = "string", + summary = "This option takes the name of a vertex..." +} +\end{codeexample} + + Finally, the algorithm's code: + % +\begin{codeexample}[code only, tikz syntax=false] +function SimpleEdgeDemo:run() + -- As in a SimpleDemo: + ... + -- Now add some edges: + for _,tail in ipairs(g.vertices) do + local name = tail.options['new edge to'] + if name then + local node = InterfaceToAlgorithms.findVertexByName(name) + if node and self.digraph:contains(node) then + InterfaceToAlgorithms.createEdge (self, tail, node) + end + end + end +end +\end{codeexample} + "]] +} + +--- +declare { + key = "new edge to", + type = "string", + + summary = [[" + This option takes the name of a vertex. An edge leading to this + vertex is added to the syntactic digraph. + "]] +} + + +function SimpleEdgeDemo:run() + + -- As in a SimpleDemo: + local g = self.digraph + local alpha = (2 * math.pi) / #g.vertices + + for i,vertex in ipairs(g.vertices) do + local radius = vertex.options['radius'] or g.options['radius'] + vertex.pos.x = radius * math.cos(i * alpha) + vertex.pos.y = radius * math.sin(i * alpha) + end + + -- Now add some edges: + for _,tail in ipairs(g.vertices) do + local name = tail.options['new edge to'] + if name then + local node = InterfaceToAlgorithms.findVertexByName(name) + if node and self.digraph:contains(node) then + InterfaceToAlgorithms.createEdge (self, tail, node) + end + end + end +end + +return SimpleEdgeDemo diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua new file mode 100644 index 0000000000..6aa9bffb72 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua @@ -0,0 +1,287 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- @section subsubsection {How To Generate Nodes Inside an Algorithm} +-- +-- @end + + + +-- Imports +local layered = require "pgf.gd.layered" +local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +-- The class +local SimpleHuffman = {} + + +--- + +declare { + key = "simple Huffman layout", + algorithm = SimpleHuffman, + + postconditions = { + upward_oriented = true + }, + + summary = [[" + This algorithm demonstrates how an algorithm can generate new nodes. + "]], + documentation = [[" + The input graph should just consist of some nodes (without + edges) and each node should have a |probability| key set. The nodes + will then be arranged in a line (as siblings) and a Huffman tree + will be constructed ``above'' these nodes. For the construction of + the Huffman tree, new nodes are created and connected. + + \pgfgdset{ + HuffmanLabel/.style={/tikz/edge node={node[fill=white,font=\footnotesize,inner sep=1pt]{#1}}}, + HuffmanNode/.style={/tikz/.cd,circle,inner sep=0pt,outer sep=0pt,draw,minimum size=3pt} + } + +\begin{codeexample}[preamble={ \usetikzlibrary{graphs,graphdrawing,quotes} + \usegdlibrary{examples}}] +\tikz \graph [simple Huffman layout, + level distance=7mm, sibling distance=8mm, grow'=up] +{ + a ["0.5", probability=0.5], + b ["0.12", probability=0.12], + c ["0.2", probability=0.2], + d ["0.1", probability=0.1], + e ["0.11", probability=0.11] +}; +\end{codeexample} + % + The file starts with some setups and declarations: + % +\begin{codeexample}[code only, tikz syntax=false] +-- File pgf.gd.examples.SimpleHuffman + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +-- The class +local SimpleHuffman = {} + +declare { + key = "simple Huffman layout", + algorithm = SimpleHuffman, + postconditions = { upward_oriented = true } + summary = "..." +} + +declare { + key = "probability", + type = "number", + initial = "1", + summary = "..." +} + +-- Import +local layered = require "pgf.gd.layered" +local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" +local Storage = require "pgf.gd.lib.Storage" + +local probability = Storage.new() +local layer = Storage.new() + +function SimpleHuffman:run() + -- Construct a Huffman tree on top of the vertices... +\end{codeexample} + + Next comes a setup, where we create the working list of vertices + that changes as the Huffman coding method proceeds: + % +\begin{codeexample}[code only, tikz syntax=false] + -- Shorthand + local function prop (v) + return probability[v] or v.options['probability'] + end + + -- Copy the vertex table, since we are going to modify it: + local vertices = {} + for i,v in ipairs(self.ugraph.vertices) do + vertices[i] = v + end +\end{codeexample} + + The initial vertices are arranged in a line on the last layer. The + function |ideal_sibling_distance| takes care of the rather + complicated handling of the (possibly rotated) bounding boxes and + separations. The |props| and |layer| are tables used by + algorithms to ``store stuff'' at a vertex or at an arc. The + table will be accessed by |arrange_layers_by_baselines| to + determine the ideal vertical placements. + % +\begin{codeexample}[code only, tikz syntax=false] + -- Now, arrange the nodes in a line: + vertices [1].pos.x = 0 + layer[ vertices [1] ] = #vertices + for i=2,#vertices do + local d = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, vertices[i-1], vertices[i]) + vertices [i].pos.x = vertices[i-1].pos.x + d + layer[ vertices [i] ] = #vertices + end +\end{codeexample} + + Now comes the actual Huffman algorithm: Always find the vertices + with a minimal probability\dots + % +\begin{codeexample}[code only, tikz syntax=false] + -- Now, do the Huffman thing... + while #vertices > 1 do + -- Find two minimum probabilities + local min1, min2 + + for i=1,#vertices do + if not min1 or prop(vertices[i]) < prop(vertices[min1]) then + min2 = min1 + min1 = i + elseif not min2 or prop(vertices[i]) < prop(vertices[min2]) then + min2 = i + end + end +\end{codeexample} + % + \dots and connect them with a new node. This new node gets the + option |HuffmanNode|. It is now the job of the higher layers to map + this option to something ``nice''. + % +\begin{codeexample}[code only, tikz syntax=false] + -- Create new node: + local p = prop(vertices[min1]) + prop(vertices[min2]) + local v = InterfaceToAlgorithms.createVertex(self, { generated_options = {{key="HuffmanNode"}}}) + probability[v] = p + layer[v] = #vertices-1 + v.pos.x = (vertices[min1].pos.x + vertices[min2].pos.x)/2 + vertices[#vertices + 1] = v + + InterfaceToAlgorithms.createEdge (self, v, vertices[min1], + {generated_options = {{key="HuffmanLabel", value = "0"}}}) + InterfaceToAlgorithms.createEdge (self, v, vertices[min2], + {generated_options = {{key="HuffmanLabel", value = "1"}}}) + + table.remove(vertices, math.max(min1, min2)) + table.remove(vertices, math.min(min1, min2)) + end +\end{codeexample} + % + Ok, we are mainly done now. Finish by computing vertical placements + and do formal cleanup. + % +\begin{codeexample}[code only, tikz syntax=false] + layered.arrange_layers_by_baselines(layers, self.adjusted_bb, self.ugraph) +end +\end{codeexample} + + In order to use the class, we have to make sure that, on the + display layer, the options |HuffmanLabel| and |HuffmanNode| are + defined. This is done by adding, for instance, the following to + \tikzname: + % +\begin{codeexample}[code only] +\pgfkeys{ + /graph drawing/HuffmanLabel/.style={ + /tikz/edge node={node[fill=white,font=\footnotesize,inner sep=1pt]{#1}} + }, + /graph drawing/HuffmanNode/.style={ + /tikz/.cd,circle,inner sep=0pt,outer sep=0pt,draw,minimum size=3pt + } +} +\end{codeexample} + "]] +} + + +--- + +declare { + key = "probability", + type = "number", + initial = "1", + + summary = [[" + The probability parameter. It is used by the Huffman algorithm to + group nodes. + "]] +} + +-- Imports + +local Storage = require 'pgf.gd.lib.Storage' + +-- Storages + +local probability = Storage.new() +local layer = Storage.new() + + +function SimpleHuffman:run() + -- Construct a Huffman tree on top of the vertices... + + -- Shorthand + local function prop (v) + return probability[v] or v.options['probability'] + end + + -- Copy the vertex table, since we are going to modify it: + local vertices = {} + for i,v in ipairs(self.ugraph.vertices) do + vertices[i] = v + end + + -- Now, arrange the nodes in a line: + vertices [1].pos.x = 0 + layer[vertices [1]] = #vertices + for i=2,#vertices do + local d = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, vertices[i-1], vertices[i]) + vertices [i].pos.x = vertices[i-1].pos.x + d + layer[vertices [i]] = #vertices + end + + -- Now, do the Huffman thing... + while #vertices > 1 do + -- Find two minimum probabilities + local min1, min2 + + for i=1,#vertices do + if not min1 or prop(vertices[i]) < prop(vertices[min1]) then + min2 = min1 + min1 = i + elseif not min2 or prop(vertices[i]) < prop(vertices[min2]) then + min2 = i + end + end + + -- Create new node: + local p = prop(vertices[min1]) + prop(vertices[min2]) + local v = InterfaceToAlgorithms.createVertex(self, { generated_options = {{key="HuffmanNode"}}}) + probability[v] = p + layer[v] = #vertices-1 + v.pos.x = (vertices[min1].pos.x + vertices[min2].pos.x)/2 + vertices[#vertices + 1] = v + + InterfaceToAlgorithms.createEdge (self, v, vertices[min1], + {generated_options = {{key="HuffmanLabel", value = "0"}}}) + InterfaceToAlgorithms.createEdge (self, v, vertices[min2], + {generated_options = {{key="HuffmanLabel", value = "1"}}}) + + table.remove(vertices, math.max(min1, min2)) + table.remove(vertices, math.min(min1, min2)) + end + + layered.arrange_layers_by_baselines(layer, self.adjusted_bb, self.ugraph) +end + +return SimpleHuffman diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/example_graph_for_ascii_displayer.txt b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/example_graph_for_ascii_displayer.txt new file mode 100644 index 0000000000..052ebdcdb8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/example_graph_for_ascii_displayer.txt @@ -0,0 +1,20 @@ +graph [layered layout] { + Alice; + Bob; + Charly; + Dave; + Eve; + Fritz; + George; + Alice -> Bob; + Alice -> Charly; + Charly -> Dave; + Bob -> Dave; + Dave -> Eve; + Eve -> Fritz; + Fritz -> Alice; + George -> Eve; + George -> Fritz; + Alice -> George; +} + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/library.lua new file mode 100644 index 0000000000..0c977600a7 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/examples/library.lua @@ -0,0 +1,30 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This package presents some examples of how different aspects of the +-- graph drawing engine can be used. In particular, the algorithms of +-- this package are not really meant to be used to layout graphs +-- (although they can be used, in principle); rather you are invited +-- to have a look at their implementation and to adapt them to your needs. +-- +-- @library + +local examples + + +-- Load algorithms from: +require "pgf.gd.examples.SimpleDemo" +require "pgf.gd.examples.SimpleEdgeDemo" +require "pgf.gd.examples.SimpleHuffman" + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua new file mode 100644 index 0000000000..31f8f27431 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua @@ -0,0 +1,638 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +-- +-- +-- @field.visible_objects An array which stores for each supernode a mapping +-- of snapshots to the related visible snapshot nodes. +-- Note that these mappings may differ from the supergraph +-- because if there are two snapshot nodes in consecutive snapshots +-- then the first can be shown for a longer time period to +-- put aside some fade animations. +-- @field is_first A table storing for each snapshot node or snapshot arc if it +-- appears in its snapshot. This means that in the previous snapshot +-- there is no corresponding arc or node. +-- @field is_last A table storing for each snapshot node or arc if there +-- is no representative in the next snapshot. +-- @field move_on_enter A table which stores for each snapshot object if it is in +-- motion while it appears in its snapshot. +-- @field move_on_leave A table which stores for each snapshot object if it is in +-- motion while switching to the next snapshot +-- @field last_rep +-- A table which stores for every snapshot node if the representing (visible) node +-- disappears with the next snapshot. +-- +-- @field previous_node The same as |next_node| just for the previous node +-- @field next_node A Storage to map each snapshot node to the next node in the +-- following snapshot related to the same supernode. +-- If in the next snapshot there is node following snapshot node +-- then the value is nil. +-- +local GraphAnimationCoordination = {} + +-- Imports +local lib = require "pgf.gd.lib" +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare +local Storage = require "pgf.gd.lib.Storage" +local Coordinate = require "pgf.gd.model.Coordinate" + + +declare { + key = "modified", + type = "boolean", + Initial = false, + documentation = [[" + This key specifies, if a supernode changed its + visual properties since the last snapshot. + The default value is |false| and prevent the algorithm + to produce a lot of unnecessary animations. + "]] +} + +declare { + key = "unmodified", + use = { + { key = "modified", boolean = false}, + }, +} + + +--- +declare { + key = "minimum rest time", + type = "number", + initial = 0.5, + documentation = [[" + This key specifies a minimum time in which a single node + has to be prohibited to be animated. + For a node with minimum rest time of 1s that exists in a snapshot + at time $t$ this means that all animations including movements and fadings + are only allowed before $t$-0.5s and after $t$+0.5s. + "]], +} + +declare { + key = "maximum motion time", + type = "number", + initial = math.huge, + documentation = [[" + Use this key if you want to limit the time during nodes are allowed to move + when they changing their positions. + "]], +} + +declare { + key = "overlapping transition", + type = "boolean", + initial = true, + documentation = [[" + Use this key if you want to allow that the fade animations for or + disappearing nodes may occurs while the mid time between two snapshots. + If false then the appearing ends on the midtime and the disappearing + starts in this moment. + "]] +} + +--- +declare { + key = "default evolving graph animation", + algorithm = GraphAnimationCoordination, + phase = "evolving graph animation", + phase_default = true, + summary = [[" + This phase animates all vertices including movements and + fade in or fade out animations given an evolving graph as sequence + of single snapshot graphs. + "]], + documentation = [[" + This phase animates all vertices including movements and + fade in or fade out animations given an evolving graph as sequence + of single snapshot graphs. + + Your algorithm needs to work on evolving graphs and has to use + the |evolving graph animation| phase. You do not need to use + this key by yourself then because this key starts the default + algorithm algorithm of the phase. + % + \begin{codeexample}[] + local ga_class = self.digraph.options.algorithm_phases['evolving graph animation'] + -- animate graph + ga_class.new { + main_algorithm = self, + supergraph = supergraph, + digraph = self.digraph, + ugraph = self.ugraph + }:run() + \end{codeexample} + + This algorithm and phase require a supergraph instance and the original + digraph and ugraph. Note that you have to set the layout of the snapshot + nodes before running algorithms of this is useful. + "]], +} + +-- Help functions + +-- +-- Appends a move animation to a given snapshot object such that the +-- object moves from one point to another on a straight line. Note +-- that the coordinates of the two points are given as relative +-- coordinates to the current origin of the object. +-- +-- This means if we want to move a node 1cm to the right the value of +-- |c_from| has to be (0,0) while |c_to| must be (1,0). The argument +-- |c_from| is useful for a node which has a position but its +-- previous node related to the same supervertex is at a different +-- position. Then we can use this argument to move the new node to +-- its origin position for smooth transitions. +-- +-- @field object The snapshot object which should be moved +-- +-- @field c_from The coordinate where the animation starts +-- +-- @field c_to The coordinate where the animation should end +-- +-- @field t_start The time when the movement starts. +-- +-- @field t_end The time when the animation stops. +local function append_move_animation(object, c_from, c_to, t_start, t_end) + if not object then return end + assert(object, "no object to animate") + if ((c_from.x~=c_to.x) or (c_from.y~=c_to.y))then + local animations = object.animations or {} + local c1 = Coordinate.new((2*c_from.x+c_to.x)/3,(2*c_from.y+c_to.y)/3) + local c2 = Coordinate.new((c_from.x+2*c_to.x)/3,(c_from.y+2*c_to.y)/3) + local t1 = (7*t_start + 5*t_end)/12 + local t2 = (5*t_start + 7*t_end)/12 + table.insert(animations, { + attribute = "translate", + entries = { + { t = t_start, value = c_from}, +-- { t = t1, value = c1 }, +-- { t = t2, value = c2 }, + { t = t_end, value = c_to } + }, + options = { { key = "freeze at end", }, +-- {key = "entry control", value="0}{1",} + } + }) + object.animations = animations + end +end + +local function append_fade_animation(object, v_start, v_end, t_start, t_end) + local animations = object.animations or {} + + if v_start == 0 then + table.insert(animations, { + attribute = "stage", + entries = { { t = t_start, value = "true"}, }, + options = { { key = "freeze at end" } } + }) + elseif v_end == 0 and nil then + table.insert(animations, { + attribute = "stage", + entries = { { t = t_end, value = "false"}, }, + options = { --{ key = "freeze at end" } + } + }) + end + + table.insert(animations, { + attribute = "opacity", + entries = { + { t = t_start, value = v_start }, + { t = t_end, value = v_end } }, + options = { { key = "freeze at end" } } + }) + object.animations = animations +end + +-- +-- check if the difference/vector between two pairs (a1,a2),(b1,b2) of points +-- is the same. +local function eq_offset(a1, a2, b1, b2) + local dx = ((a1.x-a2.x) - (b1.x-b2.x)) + local dy = ((a1.y-a2.y) - (b1.y-b2.y)) + if dx<0 then dx = -dx end + if dy<0 then dy = -dy end + return dx<0.001 and dy<0.001 +end + +-- +-- Check if two arcs connect a pair of nodes at the same position. +-- This can be used as an indicator that two consecutive arcs +-- can be represented by the same arc object. +-- +local function eq_arc(arc1, arc2) + if not arc1 or not arc2 then + return false + end + return eq_offset(arc1.tail.pos, arc1.head.pos, arc2.tail.pos, arc2.head.pos) +end + + +-- Implementation + +function GraphAnimationCoordination:run() + assert(self.supergraph, "no supergraph defined") + + self.is_first = Storage.new() + self.is_last = Storage.new() + self.last_rep = Storage.new() + self.move_on_enter = Storage.new() + self.move_on_leave = Storage.new() + self.previous_node = Storage.new() + self.next_node = Storage.new() + self.visible_objects = Storage.new() + + + self:precomputeNodes() + self:precomputeEdges() + self:animateNodeAppearing() + self:animateEdgeAppearing() + self:generateNodeMotions() + self:generateEdgeMotions() +end + +function GraphAnimationCoordination:generateNodeMotions(node_types) + local supergraph = self.supergraph + local graph = self.digraph + + for _, supervertex in ipairs(self.supergraph.vertices) do + local lj = -1 + local last_v = nil + local last_time = nil + for j, s in ipairs(supergraph.snapshots) do + local vertex = supergraph:getSnapshotVertex(supervertex, s) + + if lj == j-1 and vertex and last_v then + local mrt1 = last_v.options["minimum rest time"]/2 + local mrt2 = vertex.options["minimum rest time"]/2 + + local s1 = Coordinate.new(0,0) + local e1 = Coordinate.new(vertex.pos.x-last_v.pos.x,-vertex.pos.y+last_v.pos.y) + + local s2 = Coordinate.new(-vertex.pos.x+last_v.pos.x,vertex.pos.y-last_v.pos.y) + local e2 = Coordinate.new(0,0) + + local t_end = s.timestamp - math.max(0, mrt2) + local t_start = last_time + math.max(0,mrt1) + + local representative = self.visible_objects[supervertex][s] + if representative == vertex then + append_move_animation(vertex, s2, e2, t_start, t_end) + append_move_animation(last_v, s1, e1, t_start, t_end) + else + append_move_animation(representative,s1,e1,t_start,t_end) + end + end + last_time = s.timestamp + lj = j + last_v = vertex + end + end +end + + + + + +function GraphAnimationCoordination:generateEdgeMotions() + local supergraph = self.supergraph + local graph = self.digraph + + for i, arc in ipairs(supergraph.arcs) do + local head = arc.head + local tail = arc.tail + + local last_arc = nil + local last_time = nil + local last_v = nil + local last_w = nil + + for j, s in ipairs(supergraph.snapshots) do + local v = supergraph:getSnapshotVertex(tail,s) + local w = supergraph:getSnapshotVertex(head,s) + + if v and w then + local this_arc = graph:arc(v,w) --or graph:arc(w,v) + if this_arc then + if this_arc and last_arc then + local mrt1 = last_v.options["minimum rest time"]/2 + local mrt2 = v.options["minimum rest time"]/2 + + local s1 = Coordinate.new(0,0)--lv.pos + local e1 = Coordinate.new(v.pos.x-last_v.pos.x,-v.pos.y+last_v.pos.y) + + local s2 = Coordinate.new(-v.pos.x+last_v.pos.x,v.pos.y-last_v.pos.y) + local e2 = Coordinate.new(0,0) + + local t_end = s.timestamp - math.max(0,mrt2) + local t_start = last_time + math.max(0,mrt1) + + local representative = self.visible_objects[arc][s] + if representative == this_arc then + append_move_animation(last_arc, s1, e1, t_start,t_end) + append_move_animation(this_arc, s2, e2, t_start,t_end) + else + append_move_animation(representative,s1,e1,t_start,t_end) + end + this_arc = representative + end + last_arc = this_arc + last_v = v + last_time = s.timestamp + else + last_arc = nil + end + else + last_arc = nil + end + end + end +end + +-- +-- +-- @field t_transition The mid time between two snapshot times. +-- @field fade_duration The duration of the fade animation +-- @field overlapping A boolean defining if the animation occurs +-- before and after the mid time (true) or if it +-- starts/end only in one interval (false) +-- @field closing A boolean specifying if this is an outfading time +local function compute_fade_times(t_transition, fade_duration, overlapping, closing) + + if overlapping then + t_start = t_transition - fade_duration / 2 + t_end = t_transition + fade_duration / 2 + else + if closing then + t_start = t_transition - fade_duration + t_end = t_transition + else + t_start = t_transition + t_end = t_transition + fade_duration + end + end + return {t_start = t_start, t_end = t_end} +end + +function GraphAnimationCoordination:animateNodeAppearing() + local supergraph = self.supergraph + for i,vertex in ipairs(self.ugraph.vertices) do + local snapshot = supergraph:getSnapshot(vertex) + local interval = snapshot.interval + local supernode = supergraph:getSupervertex(vertex) + local representative = self.visible_objects[supernode][snapshot] + local overlapping_in = true -- init true for crossfading + local overlapping_out= true + local minimum_rest_time = math.max(0,vertex.options["minimum rest time"]) + local allow_overlapping = vertex.options["overlapping transition"] + local fadein_duration = 0.01 + local fadeout_duration = 0.01 + + if self.is_first[vertex] then + fadein_duration = self.ugraph.options["fadein time"] + overlapping_in = false or allow_overlapping + end + if self.is_last[vertex] then + fadeout_duration = self.ugraph.options["fadeout time"] + overlapping_out = false or allow_overlapping + end + + if fadein_duration == math.huge or fadein_duration<0 then + fadein_duration = (interval.to-interval.from-minimum_rest_time)/2 + if overlapping then fadein_duration = fadein_duration * 2 end + end + if fadeout_duration == math.huge or fadeout_duration<0 then + fadeout_duration = (interval.to-interval.from-minimum_rest_time)/2 + if overlapping then fadeout_duration = fadeout_duration*2 end + end + + local fin = compute_fade_times(interval.from, fadein_duration, overlapping_in, false) + local fout = compute_fade_times(interval.to, fadeout_duration, overlapping_out, true) + + vertex.animations = vertex.animations or {} + + if representative~= vertex then + table.insert(vertex.animations,{ + attribute = "stage", + entries = { { t = 0, value = "false"}, }, + options = {} + }) + end + + if interval.from > -math.huge and (vertex == representative or self.is_first[vertex]) then + -- only appears if the snapshot node is its own repr. or if in the prev snapshot is + -- no representative. + append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end) + end + if interval.to < math.huge and (self.is_last[vertex] or self.last_rep[vertex]) then + -- The snapshot node only disappears when the node is not visible + -- in the next or (this=)last snapshot: + append_fade_animation(representative, 1, 0, fout.t_start, fout.t_end) + end + end +end + + + +function GraphAnimationCoordination:animateEdgeAppearing() + local supergraph = self.supergraph + local graph = self.digraph + for _,edge in ipairs(graph.arcs) do + local snapshot = supergraph:getSnapshot(edge.head) + local int = snapshot.interval + local superarc = supergraph:getSuperarc(edge) + local representative = self.visible_objects[superarc][snapshot] or edge + + local minimum_rest_time = math.max(0,edge.head.options["minimum rest time"]/2, + edge.tail.options["minimum rest time"]/2) + + local appears = math.max(int.from, int.from) + local disappears = math.min(int.to, int.to) + + local overlapping_in = true -- init true for crossfading + local overlapping_out= true + local fadein_duration = 0.01 + local fadeout_duration = 0.01 + local allow_overlapping = (edge.tail.options["overlapping transition"] and edge.head.options["overlapping transition"]) + + if self.is_first[edge] and not self.move_on_enter[edge] and not self.move_on_enter[edge.head] then + fadein_duration = self.ugraph.options["fadein time"] + overlapping_in = false or allow_overlapping + end + + if self.is_last[edge] and not self.move_on_leave[edge] then + fadeout_duration = self.ugraph.options["fadeout time"] + overlapping_out = false or allow_overlapping + end + + + if self.is_first[edge] + and (self.move_on_enter[edge.head] + or self.move_on_enter[edge.tail] ) + then + appears = snapshot.timestamp - minimum_rest_time + end + if self.is_last[edge] and + (self.move_on_leave[edge.head] + or self.move_on_leave[edge.tail] + ) then + disappears = snapshot.timestamp + minimum_rest_time + end + + local fin = compute_fade_times(appears, fadein_duration, overlapping_in,false) + local fout = compute_fade_times(disappears,fadeout_duration,overlapping_out,true) + + edge.animations = edge.animations or {} + + if representative~=edge then + table.insert(edge.animations,{ + attribute = "stage", + entries = { { t = 0, value = "false"}, }, + options = {}}) + end + + -- Fade in: + if appears > -math.huge and (edge == representative or self.is_first[edge]) then + append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end ) + end + + -- Fade out: + if disappears < math.huge and (self.is_last[edge] or self.last_rep[edge])then + append_fade_animation(representative, 1, 0, fout.t_start,fout.t_end ) + end + end +end + +function GraphAnimationCoordination:precomputeNodes() + local supergraph = self.supergraph + + for _, supernode in ipairs(supergraph.vertices) do + + local vis_nodes = {} + self.visible_objects[supernode] = vis_nodes + + local any_previous_node = nil + local previous_representant = nil + local node_before = nil + + for i, s in ipairs(supergraph.snapshots) do + local node = supergraph:getSnapshotVertex(supernode, s) + + if node then + -- assume the node is the last node + self.is_last[node] = true + + if node.options["modified"] then + -- modified + vis_nodes[s] = node + previous_representant = node + if any_previous_node then + self.last_rep[any_previous_node] = true + end + else + -- unmodified + previous_representant = previous_representant or node + vis_nodes[s] = previous_representant + end + any_previous_node = node + + if node_before then + self.is_last[node_before] = false + self.previous_node[node] = node_before + self.next_node[node_before] = node + + local do_move = (( node.pos.x ~= node_before.pos.x ) + or (node.pos.y ~= node_before.pos.y)) + self.move_on_enter[node] = do_move + self.move_on_leave[node_before] = do_move + else + self.is_first[node] = true + end + node_before = node + else + node_before = nil + end + end + end +end + +function GraphAnimationCoordination:precomputeEdges() + -- 1. classify arcs (appearing, disappearing) + for _, arc in ipairs(self.digraph.arcs) do + local head = arc.head + local tail = arc.tail + if not ( self.is_first[head] or self.is_first[tail]) then + if not self.digraph:arc(self.previous_node[tail], self.previous_node[head]) then + -- new arc connects existing nodes + self.is_first[arc] = true + end + else + -- arc and at least one node is new. + self.is_first[arc] = true + end + if not ( self.is_last[head] or self.is_last[tail]) then + if not self.digraph:arc(self.next_node[tail],self.next_node[head]) then + -- arc disappears while nodes are still in the next snapshot + self.is_last[arc] = true + end + else + -- arc and at least one node disappears in the next snapshot + self.is_last[arc] = true + end + self.move_on_enter[arc] = self.move_on_enter[head] or self.move_on_enter[tail] + self.move_on_leave[arc] = self.move_on_leave[head] or self.move_on_leave[tail] + end + + -- 2. precompute the unmodified edges + local supergraph = self.supergraph + + for _, superarc in ipairs(supergraph.arcs) do + local vis_objects = {} + self.visible_objects[superarc] = vis_objects + + local previous_arc + local previous_representant + + for _, s in ipairs(supergraph.arc_snapshots[superarc]) do + local head = supergraph:getSnapshotVertex(superarc.head, s) + local tail = supergraph:getSnapshotVertex(superarc.tail, s) + -- use the digraph because the snapshot arc is not synced + local arc = self.digraph:arc(tail, head) + + local modified = false + local opt_array = arc:optionsArray('modified') + for i = 1,#opt_array.aligned do + modified = modified or opt_array[i] + end + + if modified or + not eq_arc(arc, previous_arc) or self.is_first[arc] then + --modified + previous_representant = arc + vis_objects[s] = arc + if previous_arc then + self.last_rep[previous_arc] = true + end + else + -- unmodified + previous_representant = previous_representant or arc + vis_objects[s] = previous_representant + end + previous_arc = arc + end + end +end +-- Done + +return GraphAnimationCoordination diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua new file mode 100644 index 0000000000..0c348bcc8f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua @@ -0,0 +1,177 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +local GreedyTemporalCycleRemoval = {} + +-- Imports +local lib = require "pgf.gd.lib" +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +local Vertex = require "pgf.gd.model.Vertex" +local Digraph = require "pgf.gd.model.Digraph" +local Coordinate = require "pgf.gd.model.Coordinate" + +local PriorityQueue = require "pgf.gd.lib.PriorityQueue" + +-- Keys + +--- + +declare { + key = "split critical arc head", + type = "boolean", + initial = true, + summary = "Specifies, that for a critical the tail node is separated" +} + +--- + +declare { + key = "split critical arc tail", + type = "boolean", + initial = true, + summary = "Specifies, that for a critical the tail node is separated" +} + +--- + +declare { + key = "greedy temporal cycle removal", + algorithm = GreedyTemporalCycleRemoval, + phase = "temporal cycle removal", + phase_default = true, + summary = [[" + A temporal dependency cycle is a cyclic path in the supergraph of + an evolving graph. Use this key if you want remove all temporal + dependency cycles by a greedy strategy which incrementally inserts + edge checks if this edge creates a cycle and splits at least one node + into two supernode at a given time. + "]], + documentation = [[" + See ToDo + "]] +} + +-- Help functions +local function reachable(graph, v, w) + local visited = {} + local queue = PriorityQueue.new() + queue:enqueue(v,1) + while not queue:isEmpty() do + local vertex = queue:dequeue() + if vertex==w then + return true + end + local outgoings = graph:outgoing(vertex) + for _, e in ipairs(outgoings) do + local head = e.head + if not visited[head] then + visited[head] = true + if head == w then + return true + else + queue:enqueue(head,1) + end + end + end + end + return false +end + +-- Implementation + +function GreedyTemporalCycleRemoval:run() + local supergraph = assert(self.supergraph, "no supergraph passed") + local digraph = assert(self.digraph, "no digraph passed to the phase") + local split_tail = digraph.options["split critical arc tail"] + local split_head = digraph.options["split critical arc head"] + assert(split_tail or split_head, "without splitting nodes dependency cycles cannot be removed.") + + self:iterativeCycleRemoval(supergraph, split_tail, split_head) +end + +-- +-- Resolves all dependencies by splitting supernodes into multiple supernodes. +-- To resolve a cycle each edge will be inserted into a dependency graph +-- successively. Each time such edge closes a cycle the head and tail will +-- be split at the related snapshot. +-- +-- @param supergraph +-- +function GreedyTemporalCycleRemoval:iterativeCycleRemoval(supergraph, split_tail, split_head) + -- Build up the global dependency graph + -- A supernode v directly depends on another supernode w if + -- there is a snapshot in which w is a child of w + local dependency_graph = Digraph.new(supergraph) + local stable_arcs = {} + for i, snapshot in ipairs(supergraph.snapshots) do + --local tree = snapshot.spanning_tree + for _,tree in ipairs(snapshot.spanning_trees) do + local new_arcs = {} + + for _, e in ipairs(tree.arcs) do + if e.head.kind ~= "dummy" and e.tail.kind~="dummy" then + table.insert(new_arcs, e) + + local sv = supergraph:getSupervertex(e.tail) + local sw = supergraph:getSupervertex(e.head) + local dep_arc = dependency_graph:arc(sv, sw) + + + if (not dep_arc) then + -- check if the edge v->w closes a cycle in the dependency graph + --pgf.debug{dependency_graph} + local cycle_arc = reachable(dependency_graph, sw, sv) + dep_arc = dependency_graph:connect(sv,sw) +-- texio.write("\ncheck ".. sv.name.."->" .. sw.name) + if cycle_arc then + if split_tail then + supergraph:splitSupervertex(sv, { [1]=snapshot }) + end + if split_head then + supergraph:splitSupervertex(sw, { [1]=snapshot }) + end + + -- rebuild dependency graph + dependency_graph = Digraph.new(supergraph) + + for _, arc in ipairs(stable_arcs) do + dependency_graph:connect(arc.tail, arc.head) + end + + for _, arc in ipairs(new_arcs) do + local sv = supergraph:getSupervertex(arc.tail) + local sw = supergraph:getSupervertex(arc.head) + dependency_graph:connect(sv, sw) + end + end -- end of resolve cycle_arc + end + end + end + -- Stable Arcs: + for _, arc in ipairs(new_arcs) do + + local sv = supergraph:getSupervertex(arc.tail) + local sw = supergraph:getSupervertex(arc.head) + local deparc = dependency_graph:arc(sv, sw) +-- if not deparc or not stable_arcs[deparc] then +-- stable_arcs[deparc] = true + table.insert(stable_arcs, deparc) +-- end + + end + end -- end for spanning_tree + end -- end for snapshot +end + + +-- Done + +return GreedyTemporalCycleRemoval diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua new file mode 100644 index 0000000000..2beec1e216 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua @@ -0,0 +1,875 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information +-- + +-- Imports +require "pgf.gd.trees.ChildSpec" + +local Digraph = require "pgf.gd.model.Digraph" +local Vertex = require "pgf.gd.model.Vertex" + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare +local layered = require "pgf.gd.layered" +local tlayered = require "pgf.gd.experimental.evolving.layered" +local SpanningTreeComputation = require "pgf.gd.trees.SpanningTreeComputation" +local lib = require "pgf.gd.lib" + +local Storage = require "pgf.gd.lib.Storage" +local PriorityQueue = require "pgf.gd.lib.PriorityQueue" + +local Supergraph = require "pgf.gd.experimental.evolving.Supergraph" + +local LayoutPipeline = require "pgf.gd.control.LayoutPipeline" +local Direct = require "pgf.gd.lib.Direct" + +-- +-- +local Skambath2016 = {} + + +--- +declare { + key = "animated tree layout", + algorithm = Skambath2016, + postconditions = { + upward_oriented = true + }, + documentation_in = "pgf.gd.evolving.doc" +} + +--- +declare { + key = "animated binary tree layout", + use = { + { key = "animated tree layout" }, + { key = "minimum number of children", value = 2 }, + { key = "significant sep", value = 0 }, + }, + + documentation_in = "pgf.gd.evolving.doc" +} + +--- +declare { + key = "extended animated binary tree layout", + use = { + { key = "animated tree layout" }, + { key = "minimum number of children", value=2 }, + { key = "missing nodes get space" }, + { key = "significant sep", value = 0 } + }, + documentation_in = "pgf.gd.evolving.doc" +} + + + + + +-- Help functions + +--- +-- Borders models the borderlines / the line of border vertices +-- of a tree or subtree structure which can change over time. +-- Each ordered and rooted tree or subtree has vertices per layer for which they +-- are on the outer places. On the left or respectively on the right. +-- The field |left| and |right| stores the both borderlines. +-- A \emph{borderline} is an array. This array contains for each layer of the tree +-- a table mapping a given snapshot to the related border-vertex of the layer +-- in the snapshot. +-- +-- @field left +-- @field right +-- +local Borders = {} +Borders.__index = Borders + + +-- Namespace + +--require("pgf.gd.experimental.evolving").Borders = Borders + + +--- Create a new tree border description. +-- +-- +function Borders.new() + return setmetatable( {left = {}, right = {}}, Borders ) +end + +function Borders:addBoth(layer, snapshot, vertex) + local lleft = self.left[layer] or {} + local lright = self.right[layer] or {} + assert(not lleft[snapshot] and not lright[snapshot], "borders already defined for given layer and snapshot") + lleft[snapshot] = vertex + lright[snapshot] = vertex + self.left[layer] = lleft + self.right[layer] = lright +end + +function Borders:appendBelow(level, borders) + assert(borders, "invalid argument for borders. Value must not be 'nil'.") + assert((#self.left == #self.right) and (#self.left == level), "cannot be appended") + local new_level = borders:getLevel() + for i = 1, new_level do + self.left[i + level] = borders.left[i] + self.right[i + level] = borders.right[i] + end +end + +--- +-- +-- @return the number of levels in which bordervertices exists. +function Borders:getLevel() + assert(#self.left == #self.right, "different levels") + return #self.left +end + +function Borders.copyBordersAtSnapshot(source, target, snapshot) + local source_level = source:getLevel() + for i = 1, source_level do + level_border_left = target.left[i] or {} + level_border_right = target.right[i] or {} + assert(not level_border_left[snapshot] and not level_border_right[snapshot], + "border for a given snapshot already defined") + level_border_left[snapshot] = source.left[i][snapshot] + level_border_right[snapshot] = source.right[i][snapshot] + target.left[i] = level_border_left + target.right[i] = level_border_right + end +end + +-- +-- Adapt existing borders with the borders of a group which will be +-- placed on the right next to the existing borders. For each level +-- and time in which the group has a border the borders on the right +-- will be replaced with this border. If it is not existing in the old +-- borders then also the left border will be adapted +-- +-- @param borders The existing borders. These will be modified with +-- the borders of +-- +-- @param group_borders The borders of the group +-- +-- @param snapshots All snapshots in which checking for distances is necessary. +-- +local function adapt_borders(borders, group_borders, snapshots, ignore_dummies) + for level = 1, group_borders:getLevel() do + local l = borders.left[level] or {} + local r = borders.right[level] or {} + for _, s in pairs(snapshots) do + if ignore_dummies then + local gls,grs = group_borders.left[level][s], group_borders.right[level][s] + if gls~=nil then + if gls.kind~="dummy" then + l[s] = l[s] or gls + end + end + if grs~=nil then + if grs.kind~="dummy" then + r[s] = grs or r[s] + end + end + else + l[s] = l[s] or group_borders.left[level][s] + r[s] = group_borders.right[level][s] or r[s] + end + + end + borders.left[level] = l + borders.right[level] = r + end + +end + +-- +-- Shift all vertices of a group and their descendants +-- for a certain length into horizontal direction. +-- +-- @param shift the length all involved vertices +-- should be shifted in horizontal direction +-- +-- +-- @param group A group of the spanning trees that should be shifted. +-- A group entry has to map snapshots to root nodes +-- +-- @param snapshots An array of at least all snapshots in which the group +-- has a vertex +-- +-- @param descendants A table or Storage storing the list of descendants +-- for each vertex +-- +-- @return the highest x-coordinate of vertices in the group after the shift. +-- If there is no vertex which was shifted then -math.huge +-- will be returned +-- +local function shift_group(shift, group, snapshots, descendants) + assert(group,"no group passed") + assert(shift~=math.huge and shift ~=-math.huge, + "shift must be a valid finite length") + local shifted = {} -- remember which vertex was shifted during this run + local anchor = -math.huge + for _, s in ipairs(snapshots) do + local v = group[s] + if not shifted[v] and v then + v.pos.x = v.pos.x + shift + shifted[v] = true + + -- also shift all descendants of the group vertex + for _, d in ipairs(descendants[v]) do + if not shifted[d] then + d.pos.x = d.pos.x + shift + shifted[d] = true + end + end + anchor = math.max(anchor, v.pos.x ) + end + end + return anchor +end + +-- +-- Traverse through the spanning tree |tree| of a snapshot and sort +-- the child nodes into groups. A group summarizes for a given parent +-- node all children node over time that are at the same child +-- position. The k-th child group groups[i] maps each snapshot to the +-- k-th node in the related snapshot. +-- +-- +-- @field supergraph the supergraph +-- +-- @field tree the tree or spanning tree to decide the indices of the +-- child nodes +-- +-- @field childgroups a Storage which contains the list of childgroups +-- for each supernode +-- +-- @field snapshot +-- +local function precompute_childgroups(supergraph, tree, node, childgroups, snapshot) + local outgoings = tree:outgoing(node) + if #outgoings > 0 then + local supervertex = supergraph:getSupervertex(node) + local groups = childgroups[supervertex] or {} + for i, e in ipairs(outgoings) do + + group = groups[i] or {} + assert(e.head, "no edge") + group[snapshot] = e.head + groups[i] = group + precompute_childgroups(supergraph, tree, e.head, childgroups, snapshot) + end + assert(supervertex, "no mv") + childgroups[supervertex] = groups + end +end + +-- +-- Use this function to compute the horizontal positions of all +-- vertices in a tree by accumulation of the relative shifts on the +-- path from the root to the vertex recursively. +-- +-- @param tree the tree in which the vertex's position should be +-- computed. +-- +-- @param vertex the next vertex that gets its absolute coordinate. +-- +-- @param shifts a Storage, which stores for each node the relative +-- shift between the vertex and its parent. +-- +-- @param abs_shift the sum of all relative shifts on the path from +-- the root to the vertex. +-- +local function accumulate_hpos(tree, vertex, shifts, abs_shift) + local new_shift = abs_shift + shifts[vertex] + local test = vertex.pos.x + vertex.pos.x = new_shift +-- if vertex.pos.x - test > 0.0001 then texio.write("X")end + local outgoings = tree:outgoing(vertex) + for _, e in ipairs(outgoings) do + accumulate_hpos(tree, e.head, shifts, new_shift) + end +end + + +local function get_next(border_pair, next) + local nl = next.left[border_pair.left] + local nr = next.right[border_pair.right] + assert ((nl and nr) or (not nl and not nr)) + return {left = nl, right = nr, + } +end + +local function add_shift(abs_shift, border_pair, next) + abs_shift.left = abs_shift.left + next.left_shift[border_pair.left] + abs_shift.right = abs_shift.right + next.right_shift[border_pair.right] +end + +-- +-- Given a tree, computes the required distance between the i-th and the (i+1)-th subtree +-- of the vertex |snapshot_vertex|. +-- +-- @param shifts a Storage, which contains for each vertex the relative horizontal shift +-- to its parent vertex. +-- +function Skambath2016:computeRequiredDistance(tree, vertex, i, shifts, next) + local outgoings = tree:outgoing(vertex) +-- texio.write("\n::"..vertex.name.. " "..i.."|"..(i+1)) + if #outgoings > 0 then + local clumb = {left = outgoings[1].head,right = outgoings[i].head} + if clumb.right.kind=="dummy" then shifts[clumb.right] = 0 end + local v0 = outgoings[i].head + local v1 = outgoings[i+1].head + local shift = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, v0, v1) + shifts[clumb.right] + local last0 = {left = clumb.left, right = clumb.right} + local last1 = {left = v1, right = v1} + local next0 = get_next(last0, next) + local next1 = get_next(last1, next) + local abs_shift0 = {left = shifts[clumb.left], right = shifts[clumb.right]} + local abs_shift1 = {left = 0, right = 0} + + while (next0.left and next1.left) do + add_shift(abs_shift0, last0, next) + add_shift(abs_shift1, last1, next) + + shift = math.max(shift, + layered.ideal_sibling_distance(self.adjusted_bb, + self.ugraph, + next0.right, + next1.left) + + abs_shift0.right - abs_shift1.left) +-- texio.write("\n | "..(next0.right.name or "dummy").."<->"..(next1.left.name or "dummy").." :\t"..shift) + last0, last1 = next0, next1 + next0 = get_next(next0, next) + next1 = get_next(next1, next) + end + return shift, {l0 = last0, l1 = last1, n0 = next0, n1 = next1,abs_shift1 = abs_shift1,abs_shift0=abs_shift0} + -- end + else + return 0 + end +end + +local function apply_shift(tree, vertex, i, shifts, next, border_ptr, shift) + local outgoings = tree:outgoing(vertex) +-- texio.write("\n" .. (vertex.name or "dummy")..": ".. shift ) + if #outgoings >= (i+1) then + assert(border_ptr, "unexpected error") + local last0 = border_ptr.l0 + local last1 = border_ptr.l1 + local next0 = border_ptr.n0 + local next1 = border_ptr.n1 + local abs0 = border_ptr.abs_shift0 + local abs1 = border_ptr.abs_shift1 + local vbase = outgoings[1].head -- before centering the 1st vertex is at x=0 + local v0 = outgoings[i].head + local v1 = outgoings[i+1].head + if v0.kind=="dummy" then shifts[v0] = 0 end + shifts[v1] = shifts[vbase] + shift + if next0.left then + assert(next0.right and next0.left, "failA") + -- pointer from T_i to T_{i+0} + next.right[last1.right] = next0.right + next.right_shift[last1.right] = - shift - abs1.right + (abs0.right + next.right_shift[last0.right]) + elseif next1.right then + assert(next1.right and next1.left, "") + -- pointer from T_{i+0} to T_i + -- texio.write(last0.left .." -> " ..next1.left) + next.left[last0.left] = next1.left +-- pgf.debug{last0,abs0,abs1,last1} + next.left_shift[last0.left] = shift - abs0.left + (abs1.left + next.left_shift[last1.left] ) + + else + -- both trees have the same height + end + end +end + +-- Implementation + +function Skambath2016:run() + local layers = Storage.new() + local descendants = Storage.new() + local childgroups = Storage.new() + + local phases = self.digraph.options.algorithm_phases + + local so_class = phases['supergraph optimization'] + local ga_class = phases['evolving graph animation'] + local cr_class = phases['temporal cycle removal'] + + self.extended_version = self.digraph.options['missing nodes get space'] + self.supergraph = Supergraph.generateSupergraph(self.digraph) + local supergraph_original = Supergraph.generateSupergraph(self.digraph) + + -- optimize graph by splitting nodes by trivial criteria + so_class.new { + main_algorithm = self, + supergraph = self.supergraph, + digraph = self.digraph, + ugraph = self.ugraph + }:run() + + + self:precomputeSpanningTrees() + + -- Resolve cyclic dependencies if exists. + cr_class.new { + main_algorithm = self, + supergraph = self.supergraph, + digraph = self.digraph, + }:run() + + + + self:precomputeDescendants(layers, descendants) + self:precomputeChildgroups(childgroups) + + self:computeHorizontalLayout(childgroups, descendants) +-- self:computeHorizontalLayoutFast() + + -- vertical positions + tlayered.arrange_layers_by_baselines(layers, + self.adjusted_bb, + self.ugraph, + self.supergraph.snapshots, + self.supergraph.vertex_snapshots) + + -- animate graph + ga_class.new { + main_algorithm = self, + supergraph = supergraph_original, + digraph = self.digraph, + ugraph = self.ugraph + }:run() +end + +-- +-- Compute the required shift value for a second tree to guarantee +-- a required node distance. +-- @field right_borders The Border data structure for the right border of +-- the left tree +-- @field left_borders The Border data structure for the left border of +-- the right tree +-- @field selected_snapshots if you set this value with an array of snapshots +-- only the predefined snapshots are used in the border +-- computation. +-- +function Skambath2016:computeMinShift(right_borders, left_borders, selected_snapshots) + local shift = -math.huge + local max_level = math.min(#right_borders, #left_borders) + local first_shift = 0 + local snapshots = selected_snapshots or self.supergraph.snapshots + + for layer = 1, max_level do + local rb, lb = right_borders[layer], left_borders[layer] + for _,s in ipairs(snapshots) do + + local v1,v2 = rb[s],lb[s] + if v1 and v2 then + local local_shift = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, v1, v2) + v1.pos.x - v2.pos.x + shift = math.max(shift, local_shift) + end + end + if layer == 1 then + first_shift = shift + end + end + + local is_significant = false + + if max_level > 1 and shift<=first_shift then + -- if the necessary shift of the subtrees + -- is the minimum required shift between two + -- nodes than a node is significant + is_significant = true + end + + if shift <= -math.huge then + shift = 0 + end + + if is_significant then + shift = shift + self.ugraph.options['significant sep'] + end + + return shift +end + + +-- +-- The main algorithm: This method computes the layout for each vertex. +-- For this all supervertices are visited in a topological order to their dependency. +-- If a . This requires the supergraph to be acyclic. If this is not the case +-- the calling process has to remove all cycles otherwise the x-coordinate will +-- not be computed for every vertex. +-- +function Skambath2016:computeHorizontalLayout(groups, descendants) + local subtree_borders = Storage.new() + local dep_counter = {} + local visited = {} + local queue = PriorityQueue.new() + local dependency_graph = Digraph.new() + for _, vertex in ipairs(self.supergraph.vertices) do + dep_counter[vertex] = 0 + dependency_graph:add {vertex} + end + + -- 1. Initialize Dependencies + + for _, snapshot in ipairs(self.supergraph.snapshots) do + for _, spanning_tree in ipairs(snapshot.spanning_trees) do + for _, arc in ipairs(spanning_tree.arcs) do + + local head = self.supergraph:getSupervertex(arc.head) + local tail = self.supergraph:getSupervertex(arc.tail) + + if(head and tail) then + if not dependency_graph:arc(tail, head) then + dependency_graph:connect(tail, head) + dep_counter[tail] = dep_counter[tail] + 1 + end + end + end + end + end + + -- 2. Find independent vertices + for _, vertex in ipairs(dependency_graph.vertices) do + local outgoings = dependency_graph:outgoing(vertex) + if #outgoings == 0 then + queue:enqueue(vertex, 1) + end + end + + -- 2. + while not queue:isEmpty() do + local vertex = queue:dequeue() + local vertex_snapshots = self.supergraph:getSnapshots(vertex) + + -- a. Resolve dependencies on this vertex: + local incomings = dependency_graph:incoming(vertex) + for _, e in ipairs(incomings) do + dep_counter[e.tail] = dep_counter[e.tail] - 1 + if dep_counter[e.tail] == 0 then + queue:enqueue(e.tail, 1) + end + end + + -- b. Compute borders of this supervertex: + local vertex_borders = Borders.new() + for _, s in ipairs(vertex_snapshots) do + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + vertex_borders:addBoth(1, s, snapshot_vertex) + snapshot_vertex.pos.x = 0 + snapshot_vertex.pos.y = 0 + end + + local vertex_groups = groups[vertex] + local last_pos_x = 0 + if vertex_groups then + -- c. Compute borders of groups: + local all_group_borders = {} + for i, group in ipairs(vertex_groups) do + local group_boders = Borders.new() + for _,s in ipairs(vertex_snapshots) do + local child = group[s] + if child then + local child_borders + if not (child.kind == "dummy") then + local superchild = self.supergraph:getSupervertex(child) + child_borders = subtree_borders[superchild] or Borders.new() + else + child_borders = Borders.new() + child_borders:addBoth(1, s, child) + end + assert(child.pos~=math.huge, "invalid child pos") + shift_group(-child.pos.x,{[s]=child},{[1]=s}, descendants) + Borders.copyBordersAtSnapshot(child_borders, group_boders, s) + end + end + all_group_borders[i] = group_boders + end + + -- d. Place groups and merge borders of groups: + local last_group = nil + last_pos_x = 0 + local merged_borders = Borders.new() + local final_borders = Borders.new() + for i, group in ipairs(vertex_groups) do + local group_borders = all_group_borders[i] + if last_group_borders then + -- i. compute minimal shift + + local shift + shift = self:computeMinShift(merged_borders.right, group_borders.left) + + + assert(shift ~= math.huge and shift~=-math.huge, "invalid shift") + + -- ii. shift group + local anchor = shift_group(shift, group,vertex_snapshots, descendants) + last_pos_x = anchor + end + last_group_borders = group_borders + + -- iii. adapt borders + adapt_borders(merged_borders, + group_borders, + self.supergraph.snapshots) + adapt_borders(final_borders, + group_borders, + self.supergraph.snapshots, + not self.extended_version) + end -- for (group) + vertex_borders:appendBelow(1, final_borders) + end + -- e. store borders: + assert(last_pos_x~=math.huge and last_pos_x~=-math.huge, "invalid position") + local x = ((last_pos_x) - 0)/2 + 0 + assert(x~=math.huge and x~=-math.huge, "invalid position") + for _,s in ipairs(vertex_snapshots) do + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + snapshot_vertex.pos.x = x + end + + subtree_borders[vertex] = vertex_borders + end + + -- align roots + for _, s in ipairs(self.supergraph.snapshots) do + local lastroot + local rborder + for i, spanning_tree in ipairs(s.spanning_trees) do + local root = spanning_tree.root + local rootborders = subtree_borders[self.supergraph:getSupervertex(root)] + shift_group(-root.pos.x,{[s]=root},{[1]=s}, descendants) + if i>1 then + local l = subtree_borders[self.supergraph:getSupervertex(lastroot)] + local r = rootborders + shift = math.max(self:computeMinShift(l.right, r.left, {[1]=s}), + self:computeMinShift(rborder.right,r.left, {[1]=s})) + shift_group(shift,{[s]=root},{[1]=s}, descendants) + else + rborder = Borders.new() + end + adapt_borders(rborder,rootborders,self.supergraph.snapshots,false) + lastroot = root + end + end +end + +-- +-- The main algorithm: This method computes the layout for each vertex. +-- For this all supervertices are visited in a topological order to their dependency. +-- If a . This requires the supergraph to be acyclic. If this is not the case +-- the calling process has to remove all cycles otherwise the x-coordinate will +-- not be computed for every vertex. +-- +function Skambath2016:computeHorizontalLayoutFast() + local all_trees = Storage.new() + local dep_counter = {} + local visited = {} + local queue = PriorityQueue.new() + local dependency_graph = Digraph.new() + local shifts = Storage.new() + local next = Storage.new() + for _, vertex in ipairs(self.supergraph.vertices) do + dep_counter[vertex] = 0 + dependency_graph:add {vertex} + end + + + -- I. Initialize Dependencies (Build Dependency Graph) + for _, snapshot in ipairs(self.supergraph.snapshots) do + for _, spanning_tree in ipairs(snapshot.spanning_trees) do + table.insert(all_trees, spanning_tree) + shifts[spanning_tree] = Storage.new() + next[spanning_tree] = {left= Storage.new(), + right= Storage.new(), + left_shift = Storage.new(), + right_shift = Storage.new() + } + + for _, arc in ipairs(spanning_tree.arcs) do + local head = self.supergraph:getSupervertex(arc.head) + local tail = self.supergraph:getSupervertex(arc.tail) + + if(head and tail) then + if not dependency_graph:arc(tail, head) then + dependency_graph:connect(tail, head) + dep_counter[tail] = dep_counter[tail] + 1 + end + end + end + end + end + + -- II. Visit vertices in topological ordering + -- Find independent vertices + for _, vertex in ipairs(dependency_graph.vertices) do + local outgoings = dependency_graph:outgoing(vertex) + if #outgoings == 0 then + queue:enqueue(vertex, 1) + end + end + + while not queue:isEmpty() do + -- Next node in topological order + local vertex = queue:dequeue() +-- texio.write("\n\n --- "..vertex.name .. " ---") + --pgf.debug{next} + local vertex_snapshots = self.supergraph:getSnapshots(vertex) + + -- a. Resolve dependencies on this vertex: + local incomings = dependency_graph:incoming(vertex) + for _, e in ipairs(incomings) do + dep_counter[e.tail] = dep_counter[e.tail] - 1 + if dep_counter[e.tail] == 0 then + queue:enqueue(e.tail, 1) + end + end + + -- b. Compute maximum number of children over time: + local num_children = 0 + for _, s in ipairs(vertex_snapshots) do + local v = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + num_children = math.max(num_children, #(tree:outgoing(v))) + shifts[tree][v] = 0 + end + + -- c. Shift all subtrees in all snapshots: + local hlp_ptr = Storage.new() + local max_shift = 0 + for i = 1, (num_children - 1) do + -- i) Compute the necessary shift between the i-th and (i+1)-th subtrees (per snapshot): + local min_shift = 0 + for t, s in ipairs(vertex_snapshots) do + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + local req_shift, hptr + req_shift, hptr = self:computeRequiredDistance(tree, + snapshot_vertex, + i, + shifts[tree], + next[tree] + ) + hlp_ptr[t] = hptr +-- texio.write(" -> \t"..req_shift) + min_shift = math.max(min_shift, req_shift) + end + +-- texio.write("\n \t\t".. min_shift ) + + -- ii) Synchronize distance between neighbored subtrees and apply shifts + for t, s in ipairs(vertex_snapshots) do + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + apply_shift(tree, snapshot_vertex, i, shifts[tree], next[tree], hlp_ptr[t], min_shift) + end + + max_shift = min_shift + end + + for t, s in ipairs(vertex_snapshots) do + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + local outgoings = tree:outgoing(snapshot_vertex) + +-- next[tree].left[snapshot_vertex] = outgoings[1].head + + + for i = 1,#outgoings do + if i==1 then + next[tree].left_shift[snapshot_vertex] = - max_shift / 2 + next[tree].left[snapshot_vertex]= outgoings[i].head + end + shifts[tree][outgoings[i].head] = shifts[tree][outgoings[i].head] - max_shift / 2 + next[tree].right[snapshot_vertex] = outgoings[i].head + next[tree].right_shift[snapshot_vertex] = shifts[tree][outgoings[i].head] + end + + end + + end -- end while (all vertices have been processed) + + -- III. Accumulate absolute horizontal coordinates + for _, tree in ipairs(all_trees) do + accumulate_hpos(tree, tree.root, shifts[tree], 0) + end +end + + + + +function Skambath2016:precomputeTreeDescendants(tree, node, depth, layers, descendants) + local my_descendants = { node } + + for _,arc in ipairs(tree:outgoing(node)) do + local head = arc.head + self:precomputeTreeDescendants(tree, head, depth+1, layers, descendants) + for _,d in ipairs(descendants[head]) do + my_descendants[#my_descendants + 1] = d + end + end + layers[node] = depth + descendants[node] = my_descendants +end + +function Skambath2016:precomputeDescendants(layers, descendants) + for _,snapshot in ipairs(self.supergraph.snapshots) do + for _, spanning_tree in ipairs(snapshot.spanning_trees) do + self:precomputeTreeDescendants(spanning_tree, spanning_tree.root, 1, layers, descendants) + end + end +end + + +-- +-- +-- +function Skambath2016:precomputeChildgroups(childgroups) + for _,s in ipairs(self.supergraph.snapshots) do + for _,spanning_tree in ipairs(s.spanning_trees) do + precompute_childgroups(self.supergraph, spanning_tree, spanning_tree.root, childgroups, s) + end + end +end + +-- +-- Compute a for each connected component of each +-- snapshot and appends the result for a snapshot s to +-- the array s.spanning_trees. +-- +function Skambath2016:precomputeSpanningTrees() + local events = assert(self.scope.events, + "no events found for the spanning tree computation") + + for i, s in ipairs(self.supergraph.snapshots) do + -- The involved snapshot graph: + local s_copy = Digraph.new(s) + for _,a in ipairs(s.arcs) do + local new_a = s_copy:connect(a.tail,a.head) + new_a.syntactic_edges = a.syntactic_edges + end + s.spanning_trees = s.spanning_trees or {} + -- Step 1: Decompose the snapshot into its connected components + local syntactic_components = LayoutPipeline.decompose(s_copy) + for i, syntactic_component in ipairs (syntactic_components) do + local tree = SpanningTreeComputation.computeSpanningTree(syntactic_component, true, events) + s.spanning_trees[i] = tree + end + end +end + +return Skambath2016 + + + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua new file mode 100644 index 0000000000..99e79919b5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua @@ -0,0 +1,571 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- + +-- Imports +local lib = require "pgf.gd.lib" + +local Vertex = require "pgf.gd.model.Vertex" +local Digraph = require "pgf.gd.model.Digraph" +local Storage = require "pgf.gd.lib.Storage" + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +--- +-- Each |Supergraph| instance is a |Digraph| instance which represents +-- the graph by union operation on all graphs G_i of an evolving graph +-- $G=(G_1, G_2, \dots, G_n)$. Additional to that all references to +-- the snapshot-graphs are shared such that is possible to get access +-- to all vertices for each snapshot graph in a sequence. A vertex of +-- an evolving graph may exists at different times, thus in in +-- different snapshots. Each vertex will be a vertex in the supergraph +-- and if there is a single snapshot in which two vertices are +-- connected by an edge they are connected in the supergraph. +-- +-- Note that in \tikzname\ a \emph{node} is more than a single dot. A node +-- has a content and different properties like background-color or a +-- shape. Formally this can be modeled by function mapping vertices +-- to their properties. For evolving graphs this could be done in the +-- same way. As this is difficult to be realized in PGF because there +-- is no basic support for time dependent properties on nodes, each +-- vertex will be displayed over time by different single +-- (snapshot-)nodes which can have different visual properties. This +-- means for a vertex which we call |supervertex| in the following we +-- will have a (snapshot-)node for each time stamp. +-- +-- \medskip +-- \noindent\emph{Snapshots.} +-- Since an evolving graph is a sequence of different snapshot-graphs +-- $G_i$ each snapshot is assigned to a time +-- +-- +-- @field vertex_snapshots This storage maps each pgf-node to the snapshots +-- in which they are visible. +-- +-- @field supervertices This storage maps each pgf-node to its supervertex +-- which represents all pgf-vertices assigned to the same node +-- +-- @field supervertices_by_id This storage maps a node identifier to the +-- related supervertex such that PGF-nodes which belonging to +-- the same superverticex can be identified +-- +-- @field snapshots An array of all snapshots. Sorted in ascending order +-- over the timestamps of the snapshots. +-- +-- @field arc_snapshots A table storing all snapshots of a supervertex in which +-- the related nodes are connected. Using a snapshot as key you can check +-- if a given snapshot is in the array. +-- +-- Assume we want to iterate over all snapshots +-- for a certain pair of supernodes in which they are connected +-- by an arc. The arc_snapshots storage helps in this case: +-- % +-- \begin{codeexample}[code only, tikz syntax=false] +-- local supergraph = Supergraph.generateSupergraph(self.digraph) +-- local u = supergraph.vertices[1] +-- local v = supergraph.vertices[2] +-- +-- local snapshots = supergraph.arc_snapshots[supergraph:arc(u, v)] +-- for _, snapshot in ipairs(snapshots) do +-- do_something(snapshot) +-- end +-- \end{codeexample} +-- +local Supergraph = lib.class { base_class = Digraph } + +-- Namespace +--require("pgf.gd.experimental.evolving").Supergraph = Supergraph + +Supergraph.__index = + function (t, k) + if k == "arcs" then + return Digraph.__index(t,k) + else + return rawget(Supergraph, k) or rawget(Digraph, k) + end + end + +function Supergraph.new(initial) + local supergraph = Digraph.new(initial) + setmetatable(supergraph, Supergraph) + + supergraph.vertex_snapshots = Storage.new() + supergraph.supervertices = Storage.new() + supergraph.supervertices_by_id = {} + supergraph.arc_snapshots = Storage.newTableStorage() + + return supergraph + +end + + +local get_snapshot + +--- +-- Generate or extract a snapshot instance for a given snapshot time. +-- +-- @param snapshots An array of all existing snapshots +-- @param timestamps A table which maps known timestamps to their +-- related snapshots +-- @param ugraph The ugraph of the underlying graph structure +-- @param snapshot_time +-- +-- @return The snapshot instance found in the snapshots array for the +-- wanted timestamp snapshot_time if it doesn't exists a new snapshot +-- will be generated and added to the arrays +-- +function get_snapshot(snapshots, timestamps, ugraph, snapshot_time) + local snapshot + local snapshot_idx = timestamps[snapshot_time] + + if not snapshot_idx then + -- store snapshot if it doesn't exists + snapshot_idx = timestamps.n + 1 + timestamps[snapshot_time] = snapshot_idx + timestamps.n = timestamps.n + 1 + snapshot = Digraph.new { + syntactic_digraph = ugraph.syntactic_digraph, + options = ugraph.options + } + snapshot.timestamp = snapshot_time + snapshots[snapshot_idx] = snapshot + else + snapshot = snapshots[snapshot_idx] + end + assert(snapshot~=nil, "an unexpected error occurred") + return snapshot +end + + +--- +-- Generate a new supergraph to describe the whole evolving graph by +-- collecting all temporal information from the digraph and the node +-- options. All nodes in the |digraph| require a |snapshot| and +-- a |supernode| option. To identify a (snapshot-)node with its +-- supernode and snapshot. +-- +-- @param digraph +-- +-- @return The supergraph which is a |Digraph| that has a supervertex +-- for each set of snapshot-vertices with the same |supernode| +-- attribute. +-- +function Supergraph.generateSupergraph(digraph) + local new_supergraph + new_supergraph = Supergraph.new { + syntactic_digraph = digraph.syntactic_digraph, + options = digraph.options, + digraph = digraph, + } + + -- array to store the supervertices for a given vertex name + local local_snapshots = {} -- array to store each snapshot graphs + + local timestamps = { n = 0 } -- set of snapshot times + + -- separate and assign vertices to their snapshots and supervertices + for i,vertex in ipairs(digraph.vertices) do + local snapshot_time = assert(vertex.options["snapshot"], "Missing option 'snapshot' for vertex ".. vertex.name ..". ") + local supernode_name = assert(vertex.options["supernode"], "Missing option 'supernode' for vertex"..vertex.name..". ") + + local snapshot = get_snapshot(local_snapshots, timestamps, digraph, snapshot_time) + local supervertex = new_supergraph.supervertices_by_id[supernode_name] + + if not supervertex then + -- first appearance of the supernode id + supervertex = Vertex.new { + kind = "super", + name = supernode_name + } + supervertex.snapshots = {} + supervertex.subvertex = {} + new_supergraph.supervertices_by_id[supernode_name] = supervertex + new_supergraph:add{supervertex} + + supervertex.options = {} + supervertex.options = vertex.options + end + + snapshot:add{vertex} + + new_supergraph.supervertices[vertex] = supervertex + new_supergraph.vertex_snapshots[vertex] = snapshot + new_supergraph:addSnapshotVertex(supervertex, snapshot, vertex) + end + + -- Create edges + for i, e in ipairs(digraph.arcs) do + local u,v = e.tail, e.head + local snapshot_tail = new_supergraph.vertex_snapshots[e.tail] + local snapshot_head = new_supergraph.vertex_snapshots[e.head] + + assert(snapshot_head == snapshot_tail, "Arcs must connect nodes that exist at the same time.") + + -- connect in the snapshot graph + local arc = snapshot_tail:connect(u,v) + + -- connect in the supergraph: + local super_tail = new_supergraph.supervertices[u] + local super_head = new_supergraph.supervertices[v] + + new_supergraph:assignToSuperarc(super_tail, super_head, snapshot_tail) + end + + -- snapshots in temporal order + table.sort(local_snapshots, + function(s1,s2) + return s1.timestamp < s2.timestamp + end ) + + local previous_snapshot + + for i,s in ipairs(local_snapshots) do + local start = -math.huge + if previous_snapshot then + start = (s.timestamp - previous_snapshot.timestamp) / 2 + previous_snapshot.timestamp + previous_snapshot.interval.to = start + end + s.interval = { from = start , to = math.huge } + previous_snapshot = s + end + + new_supergraph.snapshots = local_snapshots + new_supergraph.snapshots_indices = Storage.new() + + for i, s in ipairs(new_supergraph.snapshots) do + new_supergraph.snapshots_indices[s] = i + end + + return new_supergraph +end + + +function Supergraph:getSnapshotStaticDuration(snapshot) + assert(snapshot, "a snapshot as parameter expected, but got nil") + local idur = snapshot.interval.to - snapshot.interval.from + assert(idur, "unexpected nil-value") + local d1 = snapshot.interval.to - snapshot.timestamp + local d2 = snapshot.timestamp - snapshot.interval.from + local dm = math.min(d1,d2) + if (idur >= math.huge and dm < math.huge) then + return dm -- [-\infty,t] or [t,\infty] + elseif idur >= math.huge then + return 0 -- only one snapshot [-\infty,\infty] + else + return d1 + d2 -- [t_1, t_2] + end +end + +--- +-- Get the durations of the graph in which snapshots are given which is exactly +-- the time between the first and the last defined snapshot +-- +-- @return The time between the last and first snapshot in seconds +function Supergraph:getDuration() + local first_snapshot = self.snapshots[1] + local last_snapshot = self.snapshots[#self.snapshots] + return last_snapshot.timestamp - first_snapshot.timestamp +end + +--- +-- +-- @return The ratio of the time of a snapshot related to the global duration of the whole +-- evolving trees. (The time between the last and first snapshot) +function Supergraph:getSnapshotRelativeDuration(snapshot) + if self:getDuration() == 0 then + return 1 + else + return self:getSnapshotStaticDuration(snapshot) / self:getDuration() + end +end + +--- +-- Give the supervertex for a certain pgf-vertex (vertex of a snapshot) +-- +-- @param vertex A vertex of a snapshot. +-- +-- @return A supervertex in the supergraph for the given vertex, nil if no +-- supervertex was assigned before. +-- +function Supergraph:getSupervertex(vertex) + assert(vertex, "vertex required") + assert(self.supervertices, "supervertex table is not defined") + return self.supervertices[vertex] +end + +function Supergraph:getSuperarc(arc) + local superhead = self:getSupervertex(arc.head) + local supertail = self:getSupervertex(arc.tail) + local arc = assert(self:arc(supertail, superhead),"unexpected problem") + return arc +end + +function Supergraph:getSnapshots(supervertex) + return supervertex.snapshots +end + +--- +-- Find the snapshot-instance for a given pgf-vertex +-- (which is a vertex for one certain snapshot) +-- +-- @param vertex A vertex for which you want to get the related snapshot +-- +-- @return The snapshot which contains the given vertex as vertex. +function Supergraph:getSnapshot(vertex) + return self.vertex_snapshots[vertex] +end + +--- +-- For a given supervertex get the related vertex for a snapshot +-- +-- @param supervertex +-- +-- @param snapshot +-- +-- @return The vertex of the supervertex at the specified snapshot +-- +function Supergraph:getSnapshotVertex(supervertex, snapshot) + assert(supervertex, "supervertex must not be nil") + assert(snapshot, "snapshot must not be nil") + return supervertex.subvertex[snapshot] +end + + +function Supergraph:consecutiveSnapshots(snapshot1, snapshot2, n) + assert(snapshot1 and snapshot2, "no snapshot passed") + local idx1 = self.snapshots_indices[snapshot1] --or -1 + local idx2 = self.snapshots_indices[snapshot2] --or -1 + local d = n or 1 + + return (idx2-idx1 <= d) or (idx1-idx2 <= d) +end + +function Supergraph:consecutive(vertex1, vertex2, n) + local s1 = self:getSnapshot(vertex1) + local s2 = self:getSnapshot(vertex2) + return self:consecutiveSnapshots(s1, s2, n) +end + +--- +-- Write pack all position information to the nodes of each snapshot +-- such that all nodes with the same supervertex have the same position +-- +-- @param ugraph An undirected graph for which the vertices should get +-- their positions from the supergraph. +-- +function Supergraph:sharePositions(ugraph, ignore) + + for _,vertex in ipairs(ugraph.vertices) do + if not ignore then + vertex.pos.x = self.supervertices[vertex].pos.x + vertex.pos.y = self.supervertices[vertex].pos.y + else + if not ignore.x then + vertex.pos.x = self.supervertices[vertex].pos.x + end + if not ignore.y then + vertex.pos.y = self.supervertices[vertex].pos.y + end + end + + + end +end + +function Supergraph:onAllSnapshotvertices(f, ugraph) + for _,vertex in ipairs(ugraph.vertices) do + local snapshot_vertex = self.supertvertices[vertex] + if snapshot_vertex then + f(vertex, snapshot_vertex) + end + end +end + +--- +-- Split a supervertex into new supervertices such that +-- for a given snapshot there is a new pseudo-supervertex. +-- This pseudo-supervertex will be assigned to all snapshots +-- after the given snapshot. +-- All snapshots of a new pseudo-supervertex are removed from +-- the original vertex. +-- If a supervertex has no subvertices then it will not be added to the graph. +-- +-- @param supervertex The supervertex which should be split. +-- +-- @param snapshots An array of snapshots at which the supervertex +-- should be split into a new one with the corresponding pgf-vertices. +-- If there are more than one snapshots passed to the function +-- for each snapshot there will be a new pseudo-vertex +-- +function Supergraph:splitSupervertex(supervertex, snapshots) + assert(supervertex, "no supervertex defined") + -- snapshots in temporal order + table.sort(snapshots, + function(s1,s2) + return s1.timestamp < s2.timestamp + end ) + + assert(#snapshots~=0) + + local edit_snapshots = supervertex.snapshots + local first_removed = math.huge + local rem_arcs = {} + for i = 1, #snapshots do + local s_first = self.snapshots_indices[snapshots[i]] + first_removed = math.min(s_first,first_removed) + local s_last + if i==#snapshots then + s_last = #self.snapshots + else + s_last = self.snapshots_indices[snapshots[i+1]]-1 + end + + local pseudovertex = Vertex.new { + kind = "super", + name = supervertex.name.."*"..i, + subvertex = {}, + snapshots = {} + } + + local has_subvertices = false + + for j = s_first, s_last do + local s = self.snapshots[j] + local vertex = self:getSnapshotVertex(supervertex, s) + if vertex then + self.supervertices[vertex] = pseudovertex + self:addSnapshotVertex(pseudovertex, s, vertex) + self:removeSnapshotVertex(supervertex, s) + + if not has_subvertices then + has_subvertices = true + self:add{pseudovertex} + end + + -- update edges: + local incoming = self.digraph:incoming(vertex) + local outgoing = self.digraph:outgoing(vertex) + + for _, arc in ipairs(incoming) do + local tail = self.supervertices[arc.tail] + local head = self.supervertices[arc.head] + self:assignToSuperarc(tail, pseudovertex, s) + + local super_arc = self:arc(tail, supervertex) + if not rem_arcs[super_arc] then + table.insert(rem_arcs, {arc = super_arc, snapshot = s}) + rem_arcs[super_arc] = true + end + end + + for _, arc in ipairs(outgoing) do + local tail = self.supervertices[arc.tail] + local head = self.supervertices[arc.head] + self:assignToSuperarc(pseudovertex, head, s) + + local super_arc = self:arc(supervertex, head) + if not rem_arcs[super_arc] then + table.insert(rem_arcs, {arc = super_arc, snapshot = s}) + rem_arcs[super_arc] = true + end + end + end + end + end + + if first_removed ~= math.huge then + for _, removed_arc in ipairs(rem_arcs) do + local snapshots = self.arc_snapshots[removed_arc.arc] + for i=#snapshots,1,-1 do + local s = snapshots[i] + if s.timestamp >= removed_arc.snapshot.timestamp then + table.remove(snapshots, i) + end + end + + if #snapshots==0 then + self:disconnect(removed_arc.arc.tail, removed_arc.arc.head) + end + end + end +end + +-- function Supergraph:reloadArcSnapshots() +-- for _, arc in ipairs(self.digraph.arcs) do +-- local snapshot = self:getSnapshot(arc.head) +-- local superarc = self:getSuperarc(arc) +-- texio.write("\n"..arc.tail.name..">"..arc.head.name) +-- self.arc_snapshots[superarc] = snapshot +-- end +-- end + +--- +-- Remove the binding of a vertex at a certain snapshot from its assigned +-- supervertex. +-- This requires time $O(n)$ where $n$ is the number of nodes actually +-- assigned to the supervertex. +function Supergraph:removeSnapshotVertex(supervertex, snapshot) + assert(supervertex and snapshot,"missing argument: the supervertex and snapshot must not be nil") + + -- remove reference to snapshot + for i = #supervertex.snapshots,1,-1 do + if supervertex.snapshots[i] == snapshot then + table.remove(supervertex.snapshots, i) + end + end + -- remove vertex at snapshot + supervertex.subvertex[snapshot] = nil +end + +--- +-- Assign a vertex to a snapshot vertex of this supergraph. +-- This requires time $O(1)$ +-- @param supervertex +-- +-- @param snapshot +-- +-- @param vertex The vertex which should be assigned to the supervertex +-- for the given snapshot. +-- +function Supergraph:addSnapshotVertex(supervertex, snapshot, vertex) + supervertex.subvertex[snapshot] = vertex + table.insert(supervertex.snapshots, snapshot) +end + +--- +-- Assign a given snapshot to the superarc between two supernodes. +-- If still no arc between those nodes exists a new edges will +-- be created. +-- This requires time $O(n)$ where $n$ is the number of snapshots already +-- assigned to the given arc. +-- +-- @param super_tail The tail of the directed arc in the supergraph. +-- +-- @param super_head The head of the directed arc in the supergraph. +-- +-- @param snapshot A snapshot in which both nodes are connected. +-- +-- @return The arc which was created or updated. +-- +function Supergraph:assignToSuperarc(super_tail, super_head, snapshot) + assert(self:contains(super_tail) and self:contains(super_head), + "tried to connect supernodes not in the supergraph") + + local super_arc = self:arc(super_tail, super_head) + if not super_arc then + super_arc = self:connect(super_tail, super_head) + end + + table.insert(self.arc_snapshots[super_arc], snapshot) + self.arc_snapshots[super_arc][snapshot] = true + + return super_arc +end + +return Supergraph + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua new file mode 100644 index 0000000000..b5a4ea22c9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua @@ -0,0 +1,196 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +local SupergraphVertexSplitOptimization = {} + +-- Imports +local lib = require "pgf.gd.lib" +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +local Vertex = require "pgf.gd.model.Vertex" +local Digraph = require "pgf.gd.model.Digraph" +local Coordinate = require "pgf.gd.model.Coordinate" + +declare { + key = "split me", + type = "boolean", + initial = false +} + +declare { + key = "split on disappearing", + type = "boolean", + initial = true +} + +declare { + key = "split on disjoint neighbors", + type = "boolean", + initial = false +} + +declare { + key = "split on disjoint children", + type = "boolean", + initial = false +} + +declare { + key = "split on disjoint parents", + type = "boolean", + initial = false +} + +declare { + key = "split all supervertices", + type = "boolean", + initial = false +} + +declare { + key = "unbound vertex splitting", + algorithm = SupergraphVertexSplitOptimization, + phase = "supergraph optimization", + phase_default = true, + summary = [[" + Use this key if you want to disable animations. + Instead of producing animations the evolving graph animation phasephase animates all vertices including movements and + fade in or fade out animations. + "]], + documentation = [[" + See ToDo + "]] +} + + + +-- Help functions + + +-- Implementation + +function SupergraphVertexSplitOptimization:run() + local supergraph = assert(self.supergraph, "no supergraph passed") + + local split_on_dissapearing = self.digraph.options["split on disappearing"] + local split_on_no_common_neighbor = self.digraph.options["split on disjoint neighbors"] + local split_on_no_common_child = self.digraph.options["split on disjoint children"] + local split_on_no_common_parent = self.digraph.options["split on disjoint parents"] + local split_all = self.digraph.options["split all supervertices"] + + for _, supernode in ipairs(supergraph.vertices) do + -- follow trace of the supernode + local snapshots = supergraph:getSnapshots(supernode) + local splitsnapshots = {} + + for i=2, #snapshots do + local s = snapshots[i] + local s_prev = snapshots[i - 1] + local can_split = false + + if supergraph:consecutiveSnapshots(s_prev, s) then + local v1 = supergraph:getSnapshotVertex(supernode, s_prev) + local v2 = supergraph:getSnapshotVertex(supernode, s) + local is_child1 = {} + local is_parent1 = {} + local is_neighbor1 = {} + + local incoming1 = s_prev:incoming(v1) + local outgoing1 = s_prev:outgoing(v1) + + for _,e in ipairs(incoming1) do + local p = supergraph:getSupervertex(e.tail) + if p then + is_parent1[p] = true + is_neighbor1[p] = true + end + end + + for _,e in ipairs(outgoing1) do + local p = supergraph:getSupervertex(e.head) + if p then + is_child1[p] = true + is_neighbor1[p] = true + end + end + + local incoming2 = s:incoming(v2) + local outgoing2 = s:outgoing(v2) + + no_common_parent = true + no_common_child = true + no_common_neighbor = true + for _,e in ipairs(incoming2) do + local p = supergraph:getSupervertex(e.tail) + if p then + if is_neighbor1[p] then + no_common_neighbor = false + end + if is_parent1[p] then + no_common_parent = false + end + if (not no_common_neighbor) and (not no_common_parent) then + break + end + end + end + + for _,e in ipairs(outgoing2) do + local p = supergraph:getSupervertex(e.head) + if p then + if is_neighbor1[p] then + no_common_neighbor = false + end + if is_child1[p] then + no_common_child = false + end + if (not no_common_neighbor) and (not no_common_child) then + break + end + end + end + + + + if no_common_neighbor and split_on_no_common_neighbor then + can_split = true + --texio.write("[N@".. s.timestamp .."]") + end + if no_common_parent and split_on_no_common_parent then + can_split = true + --texio.write("[P@".. s.timestamp .."]") + end + if no_common_child and split_on_no_common_child then + can_split = true + --texio.write("[N@".. s.timestamp .."]") + end + if v2.options["split me"] then + can_split = true + end + else + can_split = true + --texio.write("[R@".. s.timestamp .."]") + end + if can_split or split_all then + table.insert(splitsnapshots, s) + end + end + if #splitsnapshots>0 then + supergraph:splitSupervertex(supernode, splitsnapshots) + end + end +end + + + + +-- Done + +return SupergraphVertexSplitOptimization diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua new file mode 100644 index 0000000000..2b2168da1a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua @@ -0,0 +1,62 @@ +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +--- + +declare { + key = "snapshot", + type = "time", + initial = "0s", + summary = "The time of the snapshot in which a PGF node should be visible.", + documentation = [[" + This option defines the time in seconds when respectively in which + state or snapshot of the graph the PGF represents a graph node. + "]], +} + +--- + +declare { + key = "supernode", + type = "string", + initial = "null", + summary = "A unique name for a node a given PGF node should be assigned to.", + documentation = [[" + Because it should be possible that nodes can change their + appearance, they are represented by separate PGF nodes in each + snapshot. To identify PGF nodes of the same supernode we have to + specify this key. + "]], +} + +--- + +declare { + key = "fadein time", + type = "time", + initial = "0.5s", + summary = [[" + The time in seconds it should take that a nodes will be fade in + when it disappears in the graph. + "]], +} + +--- + +declare { + key = "fadeout time", + type = "time", + initial = "0.5s", + summary = "", + documentation = "The same as |fadein time| but for disappearing nodes.", +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua new file mode 100644 index 0000000000..dbd8146275 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua @@ -0,0 +1,120 @@ +-- Copyright 2012 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "animated tree layout" + +summary "This layout uses the Reingold--Tilform method for drawing trees." + +documentation +[[ +A method to create layouts for evolving graphs as an SVG animation.The Reingold--Tilford method is a standard method for drawing +trees. It is described in: + +The algorithm, which is based on the Reingold--Tilford algorithm and +its implementation in |graphdrawing.trees|, is introduced in my Masthesis: +% +\begin{itemize} + \item + M.\ Skambath, + \newblock Algorithmic Drawing of Evolving Trees, Masterthesis, 2016 +\end{itemize} + +You can use the same known graph macros as for other graph drawing +algorithms in Ti\emph{k}Z. In addition all keys and features that +are available for the static tree algorithm can be used: +% +\begin{codeexample}[animation list={1,1.5,2,2.5,3,3.5,4}] + \tikz \graph[animated binary tree layout, + nodes={draw,circle}, auto supernode, + ] { + {[when=1] 15 -> {10 -> { ,11}, 20 }}, + {[when=2] 15 -> {10 -> {3,11}, 20 }}, + {[when=3] 15 -> {10 -> {3, }, 20 }}, + {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, + }; +\end{codeexample} +]] + + +example +[[ +\tikz[animated binary tree layout] + \graph[nodes={draw,circle}, auto supernode] { + {[when=1] 15 -> {10 -> { ,11}, 20 }}, + {[when=2] 15 -> {10 -> {3,11}, 20 }}, + {[when=3] 15 -> {10 -> {3, }, 20 }}, + {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- + +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "animated binary tree layout" + +summary +[[ A layout based on the Reingold--Tilford method for drawing +binary trees. +]] + +documentation +[[ +This key executes: +% +\begin{enumerate} + \item |animated tree layout|, thereby selecting the Reingold--Tilford method, + \item |minimum number of children=2|, thereby ensuring the all nodes + have (at least) two children or none at all, and +\end{enumerate} +]] + + +example +[[ +]] + +example +[[ +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "extended animated binary tree layout" + +summary +[[ This algorithm is similar to |animated binary tree layout|, only the +option \texttt{missing nodes get space} is executed and the +\texttt{significant sep} is zero. +]] + +example +[[ +]] +-------------------------------------------------------------------- + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua new file mode 100644 index 0000000000..15df9990f8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua @@ -0,0 +1,107 @@ +-- Copyright 2012 by Till Tantau +-- Copyright 2015 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + + + +local temporallayered = {} + +-- Namespace + +--require("pgf.gd").layered = layered +--require("pgf.gd.experimental.evolving").layered = layered + +-- Import +local lib = require "pgf.gd.lib" +local Storage = require "pgf.gd.lib.Storage" +local layered = require "pgf.gd.layered" + +-- +-- This file defines some basic functions to compute and/or set the +-- ideal distances between nodes of any kind of layered drawing of a +-- graph. + + + +--- +-- Position nodes in layers using baselines +-- +-- @param layers A |Storage| object assigning layers to vertices. +-- @param paddings A |Storage| object storing the computed distances +-- (paddings). +-- @param graph The graph in which the nodes reside +-- @param snapshots The list of snapshots over which the overlaying evolving +-- graph exists +function temporallayered.arrange_layers_by_baselines (layers, paddings, graph, snapshots, vertex_snapshots) + assert(vertex_snapshots, "vertex_snapshots must not be nil") + --local layer_vertices = Storage.newTableStorage() + local snapshots_layers = Storage.newTableStorage() + local count_layers = 0 + -- Decompose into layers: + for _,v in ipairs(graph.vertices) do + local layer_vertices = snapshots_layers[vertex_snapshots[v]] or {} + if layer_vertices[layers[v]] == nil then + assert( layers[v], "layer of node " .. v.name .. " has not been computed.") + layer_vertices[layers[v]] = {} + end + table.insert(layer_vertices[layers[v]], v) + count_layers = math.max(count_layers, layers[v]) + end + + if count_layers > 0 then + + + -- Now compute ideal distances and store + local height = 0 + + for _, s in ipairs(snapshots) do + local layer_vertices = snapshots_layers[s] + if #layer_vertices > 0 then -- sanity check + for _,v in ipairs(layer_vertices[1]) do + v.pos.y = 0 + end + end + end + + for i=2, count_layers do + local distance = 0 + for _, s in ipairs(snapshots) do + local layer_vertices = snapshots_layers[s] + if #layer_vertices >= i then + distance = math.max( + distance, + layered.baseline_distance( + paddings, + s, + layer_vertices[i-1], + layer_vertices[i])) + end + end + + height = height + distance + + for _, s in ipairs(snapshots) do + local layer_vertices = snapshots_layers[s] + if #layer_vertices >= i then + for _,v in ipairs(layer_vertices[i]) do + v.pos.y = height + end + end + end + end + end +end + + + + +-- Done + +return temporallayered diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/library.lua new file mode 100644 index 0000000000..bb50eaf2cb --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/experimental/evolving/library.lua @@ -0,0 +1,33 @@ +-- Copyright 2016 by Malte Skambath +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + + +-- @library + +local evolving -- Library name + +-- Load dependencies: +require "pgf.gd.trees.ChildSpec" +require "pgf.gd.trees.ReingoldTilford1981" +require "pgf.gd.layered" + +-- Load declarations from: +require "pgf.gd.experimental.evolving.TimeSpec" +require "pgf.gd.experimental.evolving.Supergraph" + +-- Load preprocessing/optimization phases from: +require "pgf.gd.experimental.evolving.SupergraphVertexSplitOptimization" +require "pgf.gd.experimental.evolving.GreedyTemporalCycleRemoval" + +-- Load postprocessing/graph animation phases from: +require "pgf.gd.experimental.evolving.GraphAnimationCoordination" + +-- Load algorithms from: +require "pgf.gd.experimental.evolving.Skambath2016" diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force.lua new file mode 100644 index 0000000000..71efda1b35 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.force = {} + + +-- Done + +return pgf.gd.force \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua new file mode 100644 index 0000000000..a4e51dfeff --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua @@ -0,0 +1,435 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- A class for handling "coarse" versions of a graph. Such versions contain +-- less nodes and edges than the original graph while retaining the overall +-- structure. + +local Graph = require "pgf.gd.deprecated.Graph" -- we subclass from here +local CoarseGraph = Graph.new() +CoarseGraph.__index = CoarseGraph + + + +-- Namespace: +local force = require "pgf.gd.force" +force.CoarseGraph = CoarseGraph + + +-- Imports +local Node = require "pgf.gd.deprecated.Node" +local Edge = require "pgf.gd.deprecated.Edge" + +local lib = require "pgf.gd.lib" + + +-- Class setup + +CoarseGraph.COARSEN_INDEPENDENT_EDGES = 0 -- TT: Remark: These uppercase constants are *ugly*. Why do people do this?! +CoarseGraph.COARSEN_INDEPENDENT_NODES = 1 +CoarseGraph.COARSEN_HYBRID = 2 + + + +--- Creates a new coarse graph derived from an existing graph. +-- +-- Generates a coarse graph for the input |Graph|. +-- +-- Coarsening describes the process of reducing the amount of nodes in a graph +-- by merging nodes into supernodes. There are different strategies, called +-- schemes, that can be applied, like merging nodes that belong to edges in a +-- maximal independent edge set or by creating supernodes based on a maximal +-- independent node set. +-- +-- Coarsening is not performed automatically. The functions |CoarseGraph:coarsen| +-- and |CoarseGraph:interpolate| can be used to further coarsen the graph or +-- to restore the previous state (while interpolating the node positions from +-- the coarser version of the graph). +-- +-- Note, however, that the input \meta{graph} is always modified in-place, so +-- if the original version of \meta{graph} is needed in parallel to its +-- coarse representations, a deep copy of \meta{graph} needs to be passed over +-- to |CoarseGraph.new|. +-- +-- @param graph An existing graph that needs to be coarsened. +-- @param scheme Coarsening scheme to use. Possible values are:\par +-- |CoarseGraph.COARSEN_INDEPENDENT_EDGES|: +-- Coarsen the input graph by computing a maximal independent edge set +-- and collapsing edges from this set. The resulting coarse graph has +-- at least 50% of the nodes of the input graph. This coarsening scheme +-- gives slightly better results than +-- |CoarseGraph.COARSEN_INDEPENDENT_NODES| because it is less aggressive. +-- However, this comes at higher computational cost.\par +-- |CoarseGraph.COARSEN_INDEPENDENT_NODES|: +-- Coarsen the input graph by computing a maximal independent node set, +-- making nodes from this set supernodes in the coarse graph, merging +-- adjacent nodes into the supernodes and connecting the supernodes +-- if their graph distance is no greater than three. This scheme gives +-- slightly worse results than |CoarseGraph.COARSEN_INDEPENDENT_EDGES| +-- but is computationally more efficient.\par +-- |CoarseGraph.COARSEN_HYBRID|: Combines the other schemes by starting +-- with |CoarseGraph.COARSEN_INDEPENDENT_EDGES| and switching to +-- |CoarseGraph.COARSEN_INDEPENDENT_NODES| as soon as the first scheme +-- does not reduce the amount of nodes by a factor of 25%. +-- +function CoarseGraph.new(graph, scheme) + local coarse_graph = { + graph = graph, + level = 0, + scheme = scheme or CoarseGraph.COARSEN_INDEPENDENT_EDGES, + ratio = 0, + } + setmetatable(coarse_graph, CoarseGraph) + return coarse_graph +end + + + +local function custom_merge(table1, table2, first_metatable) + local result = table1 and lib.copy(table1) or {} + local first_metatable = first_metatable == true or false + + for key, value in pairs(table2) do + if not result[key] then + result[key] = value + end + end + + if not first_metatable or not getmetatable(result) then + setmetatable(result, getmetatable(table2)) + end + + return result +end + + +local function pairs_by_sorted_keys (t, f) + local a = {} + for n in pairs(t) do a[#a + 1] = n end + table.sort (a, f) + local i = 0 + return function () + i = i + 1 + return a[i], t[a[i]] + end +end + + + +function CoarseGraph:coarsen() + -- update the level + self.level = self.level + 1 + + local old_graph_size = #self.graph.nodes + + if self.scheme == CoarseGraph.COARSEN_INDEPENDENT_EDGES then + local matching, unmatched_nodes = self:findMaximalMatching() + + for _,edge in ipairs(matching) do + -- get the two nodes of the edge that we are about to collapse + local u, v = edge.nodes[1], edge.nodes[2] + + assert(u ~= v, 'the edge ' .. tostring(edge) .. ' is a loop. loops are not supported by this algorithm') + + -- create a supernode + local supernode = Node.new{ + name = '(' .. u.name .. ':' .. v.name .. ')', + weight = u.weight + v.weight, + subnodes = { u, v }, + subnode_edge = edge, + level = self.level, + } + + -- add the supernode to the graph + self.graph:addNode(supernode) + + -- collect all neighbors of the nodes to merge, create a node -> edge mapping + local u_neighbours = lib.map(u.edges, function(edge) return edge, edge:getNeighbour(u) end) + local v_neighbours = lib.map(v.edges, function(edge) return edge, edge:getNeighbour(v) end) + + -- remove the two nodes themselves from the neighbor lists + u_neighbours = lib.map(u_neighbours, function (edge,node) if node ~= v then return edge,node end end) + v_neighbours = lib.map(v_neighbours, function (edge,node) if node ~= u then return edge,node end end) + + -- compute a list of neighbors u and v have in common + local common_neighbours = lib.map(u_neighbours, + function (edge,node) + if v_neighbours[node] ~= nil then return edge,node end + end) + + -- create a node -> edges mapping for common neighbors + common_neighbours = lib.map(common_neighbours, function (edge, node) + return { edge, v_neighbours[node] }, node + end) + + -- drop common edges from the neighbor mappings + u_neighbours = lib.map(u_neighbours, function (val,node) if not common_neighbours[node] then return val,node end end) + v_neighbours = lib.map(v_neighbours, function (val,node) if not common_neighbours[node] then return val,node end end) + + -- merge neighbor lists + local disjoint_neighbours = custom_merge(u_neighbours, v_neighbours) + + -- create edges between the supernode and the neighbors of the merged nodes + for neighbour, edge in pairs_by_sorted_keys(disjoint_neighbours, function (n,m) return n.index < m.index end) do + + -- create a superedge to replace the existing one + local superedge = Edge.new{ + direction = edge.direction, + weight = edge.weight, + subedges = { edge }, + level = self.level, + } + + -- add the supernode and the neighbor to the edge + if u_neighbours[neighbour] then + superedge:addNode(neighbour) + superedge:addNode(supernode) + + else + superedge:addNode(supernode) + superedge:addNode(neighbour) + + end + + -- replace the old edge + self.graph:addEdge(superedge) + self.graph:deleteEdge(edge) + end + + -- do the same for all neighbors that the merged nodes have + -- in common, except that the weights of the new edges are the + -- sums of the of the weights of the edges to the common neighbors + for neighbour, edges in pairs_by_sorted_keys(common_neighbours, function (n,m) return n.index < m.index end) do + local weights = 0 + for _,e in ipairs(edges) do + weights = weights + edge.weight + end + + local superedge = Edge.new{ + direction = Edge.UNDIRECTED, + weight = weights, + subedges = edges, + level = self.level, + } + + -- add the supernode and the neighbor to the edge + superedge:addNode(supernode) + superedge:addNode(neighbour) + + -- replace the old edges + self.graph:addEdge(superedge) + for _,edge in ipairs(edges) do + self.graph:deleteEdge(edge) + end + end + + -- delete the nodes u and v which were replaced by the supernode + assert(#u.edges == 1, 'node ' .. u.name .. ' is part of a multiedge') -- if this fails, then there is a multiedge involving u + assert(#v.edges == 1, 'node ' .. v.name .. ' is part of a multiedge') -- same here + self.graph:deleteNode(u) + self.graph:deleteNode(v) + end + else + assert(false, 'schemes other than CoarseGraph.COARSEN_INDEPENDENT_EDGES are not implemented yet') + end + + -- calculate the number of nodes ratio compared to the previous graph + self.ratio = #self.graph.nodes / old_graph_size +end + + + +function CoarseGraph:revertSuperedge(superedge) + -- TODO we can probably skip adding edges that have one or more + -- subedges with the same level. But that needs more testing. + + -- TODO we might have to pass the corresponding supernode to + -- this method so that we can move subnodes to the same + -- position, right? Interpolating seems to work fine without + -- though... + + if #superedge.subedges == 1 then + local subedge = superedge.subedges[1] + + if not self.graph:findNode(subedge.nodes[1].name) then + self.graph:addNode(subedge.nodes[1]) + end + + if not self.graph:findNode(subedge.nodes[2].name) then + self.graph:addNode(subedge.nodes[2]) + end + + if not self.graph:findEdge(subedge) then + subedge.nodes[1]:addEdge(subedge) + subedge.nodes[2]:addEdge(subedge) + self.graph:addEdge(subedge) + end + + if subedge.level and subedge.level >= self.level then + self:revertSuperedge(subedge) + end + else + for _,subedge in ipairs(superedge.subedges) do + if not self.graph:findNode(subedge.nodes[1].name) then + self.graph:addNode(subedge.nodes[1]) + end + + if not self.graph:findNode(subedge.nodes[2].name) then + self.graph:addNode(subedge.nodes[2]) + end + + if not self.graph:findEdge(subedge) then + subedge.nodes[1]:addEdge(subedge) + subedge.nodes[2]:addEdge(subedge) + self.graph:addEdge(subedge) + end + + if subedge.level and subedge.level >= self.level then + self:revertSuperedge(subedge) + end + end + end +end + + + +function CoarseGraph:interpolate() + -- FIXME TODO Jannis: This does not work now that we allow multi-edges + -- and loops! Reverting generates the same edges multiple times which leads + -- to distorted drawings compared to the awesome results we had before! + + local nodes = lib.copy(self.graph.nodes) + + for _,supernode in ipairs(nodes) do + assert(not supernode.level or supernode.level <= self.level) + + if supernode.level and supernode.level == self.level then + -- move the subnode to the position of the supernode and add it to the graph + supernode.subnodes[1].pos.x = supernode.pos.x + supernode.subnodes[1].pos.y = supernode.pos.y + + if not self.graph:findNode(supernode.subnodes[1].name) then + self.graph:addNode(supernode.subnodes[1]) + end + + -- move the subnode to the position of the supernode and add it to the graph + supernode.subnodes[2].pos.x = supernode.pos.x + supernode.subnodes[2].pos.y = supernode.pos.y + + if not self.graph:findNode(supernode.subnodes[2].name) then + self.graph:addNode(supernode.subnodes[2]) + end + + if not self.graph:findEdge(supernode.subnode_edge) then + supernode.subnodes[1]:addEdge(supernode.subnode_edge) + supernode.subnodes[2]:addEdge(supernode.subnode_edge) + self.graph:addEdge(supernode.subnode_edge) + end + + local superedges = lib.copy(supernode.edges) + + for _,superedge in ipairs(superedges) do + self:revertSuperedge(superedge) + end + + self.graph:deleteNode(supernode) + end + end + + -- Make sure that the nodes and edges are in the correct order: + table.sort (self.graph.nodes, function (a, b) return a.index < b.index end) + table.sort (self.graph.edges, function (a, b) return a.index < b.index end) + for _, n in pairs(self.graph.nodes) do + table.sort (n.edges, function (a, b) return a.index < b.index end) + end + + -- update the level + self.level = self.level - 1 +end + + + +function CoarseGraph:getSize() + return #self.graph.nodes +end + + + +function CoarseGraph:getRatio() + return self.ratio +end + + + +function CoarseGraph:getLevel() + return self.level +end + + + +function CoarseGraph:getGraph() + return self.graph +end + + + +function CoarseGraph:findMaximalMatching() + local matching = {} + local matched_nodes = {} + local unmatched_nodes = {} + + -- iterate over nodes in random order + for _,j in ipairs(lib.random_permutation(#self.graph.nodes)) do + local node = self.graph.nodes[j] + -- ignore nodes that have already been matched + if not matched_nodes[node] then + -- mark the node as matched + matched_nodes[node] = true + + -- filter out edges adjacent to neighbors already matched + local edges = lib.imap(node.edges, + function (edge) + if not matched_nodes[edge:getNeighbour(node)] then return edge end + end) + + -- FIXME TODO We use a light-vertex matching here. This is + -- different from the algorithm proposed by Hu which collapses + -- edges based on a heavy-edge matching... + if #edges > 0 then + -- sort edges by the weights of the node's neighbors + table.sort(edges, function (a, b) + return a:getNeighbour(node).weight < b:getNeighbour(node).weight + end) + + -- match the node against the neighbor with minimum weight + matched_nodes[edges[1]:getNeighbour(node)] = true + table.insert(matching, edges[1]) + end + end + end + + -- generate a list of nodes that were not matched at all + for _,j in ipairs(lib.random_permutation(#self.graph.nodes)) do + local node = self.graph.nodes[j] + if not matched_nodes[node] then + table.insert(unmatched_nodes, node) + end + end + + return matching, unmatched_nodes +end + + +-- done + +return CoarseGraph diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua new file mode 100644 index 0000000000..d69d5fc6c9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua @@ -0,0 +1,148 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + +--- +-- @section subsubsection {Coarsening} +-- +-- @end + + +--- + +declare { + key = "coarsen", + type = "boolean", + initial = "true", + + summary = [[" + Defines whether or not a multilevel approach is used that + iteratively coarsens the input graph into graphs $G_1,\dots,G_l$ + with a smaller and smaller number of nodes. The coarsening stops as + soon as a minimum number of nodes is reached, as set via the + |minimum coarsening size| option, or if, in the last iteration, the + number of nodes was not reduced by at least the ratio specified via + |downsize ratio|. + "]], + documentation = [[" + A random initial layout is computed for the coarsest graph $G_l$ first. + Afterwards, it is laid out by computing the attractive and repulsive + forces between its nodes. + + In the subsequent steps, the previous coarse graph $G_{l-1}$ is + restored and its node positions are interpolated from the nodes + in~$G_l$. The graph $G_{l-1}$ is again laid out by computing the forces + between its nodes. These steps are repeated with $G_{l-2},\dots,G_1$ until + the original input graph $G_0$ has been restored, interpolated + and laid out. + + The idea behind this approach is that, by arranging recursively + formed supernodes first and then interpolating and arranging their + subnodes step by step, the algorithm is less likely to settle in a + local energy minimum (of which there can be many, particularly for + large graphs). The quality of the drawings with coarsening enabled is + expected to be higher than graphics where this feature is not applied. + + The following example demonstrates how coarsening can improve the + quality of graph drawings generated with Walshaw's algorihtm + |spring electrical layout'|. + "]], + examples = [[" + \tikz \graph [spring electrical layout', coarsen=false, vertical=3 to 4] + { + { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } + }; + + \tikz \graph [spring electrical layout', coarsen, vertical=3 to 4] + { + { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } + }; + "]] +} + +--- + +declare { + key = "minimum coarsening size", + type = "number", + initial = 2, + + summary = [[" + Defines the minimum number of nodes down to which the graph is + coarsened iteratively. The first graph that has a smaller or equal + number of nodes becomes the coarsest graph $G_l$, where $l$ is the + number of coarsening steps. The algorithm proceeds with the steps + described in the documentation of the |coarsen| option. + "]], + documentation = [[" + In the following example the same graph is coarsened down to two + and four nodes, respectively. The layout of the original graph is + interpolated from the random initial layout and is not improved + further because the forces are not computed (0 iterations). Thus, + in the two graphs, the nodes are placed at exactly two and four + coordinates in the final drawing. + "]], + examples = [[" + \tikz \graph [spring layout, iterations=0, + minimum coarsening size=2] + { subgraph C_n [n=8] }; + + \tikz \graph [spring layout, iterations=0, + minimum coarsening size=4] + { subgraph C_n [n=8] }; + "]] +} + +--- + +declare { + key = "downsize ratio", + type = "number", + initial = "0.25", + + summary = [[" + Minimum ratio between 0 and 1 by which the number of nodes between + two coarse graphs $G_i$ and $G_{i+1}$ need to be reduced in order for + the coarsening to stop and for the algorithm to use $G_{i+1}$ as the + coarsest graph $G_l$. Aside from the input graph, the optimal value + of |downsize ratio| mostly depends on the coarsening scheme being + used. Possible schemes are |collapse independent edges| and + |connect independent nodes|. + "]], + documentation = [[" + Increasing this option possibly reduces the number of coarse + graphs computed during the coarsening phase as coarsening will stop as + soon as a coarse graph does not reduce the number of nodes + substantially. This may speed up the algorithm but if the size of the + coarsest graph $G_l$ is much larger than |minimum coarsening size|, the + multilevel approach may not produce drawings as good as with a lower + |downsize ratio|. + "]], + examples = [[" + % 1. ratio too high, coarsening stops early, benefits are lost + \tikz \graph [spring electrical layout', + downsize ratio=1.0, + node distance=7mm, vertical=3 to 4] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + + % 2. ratio set to default, coarsening benefits are visible + \tikz \graph [spring electrical layout', + downsize ratio=0.2, + node distance=7mm, vertical=3 to 4] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + "]] +} + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua new file mode 100644 index 0000000000..af209d2c78 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua @@ -0,0 +1,41 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Controlling and Configuring Force-Based Algorithms} +-- +-- All force-based algorithms are based on +-- a general pattern which we detail in the following. Numerous options +-- can be used to influence the behavior of this general pattern; more +-- specific options that apply only to individual algorithms are +-- explained along with these algorithms. +-- +-- The vertices are initially laid out in a random configuration. +-- Then the configuration is annealed to find a configuration of +-- minimal energy. To avoid getting stuck in a local minimum or at a +-- saddle point, random forces are added. All of this makes the final +-- layout extremely susceptible to changes in the random numbers. To +-- achieve a certain stability of the results, you should fix the +-- random seed. However, in the recent past Lua has switched its +-- random number generator, which means that you won't get the same +-- sequence of random numbers as in a previous version, even for +-- identical seed. If you rely on the long-term stability of vertex +-- placement, you should consider using a different layout. With the +-- spring layout you have to assume that the layout will be random. +-- +-- @end + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlElectric.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlElectric.lua new file mode 100644 index 0000000000..c9f129c28d --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlElectric.lua @@ -0,0 +1,105 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + +--- +-- @section subsubsection {Forces and Their Effects: Electrical +-- Repulsion} +-- +-- @end + + +--- + +declare { + key = "electric charge", + type = "number", + initial = 1, + + summary = [[" + Defines the electric charge of the node. The stronger the + |electric charge| of a node the stronger the repulsion between the + node and others in the graph. A negative |electric charge| means that + other nodes are further attracted to the node rather than repulsed, + although in theory this effect strongly depends on how the + |spring electrical layout| algorithm works. + Two typical effects of increasing the |electric charge| are distortion + of symmetries and an upscaling of the drawings. + "]], + examples = { + { + options = [["preamble={\usetikzlibrary{graphs,graphdrawing} \usegdlibrary{force}}"]], + code = [[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { 0 [electric charge=1] -- subgraph C_n [n=10] }; + "]] + },{ + code = [[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { 0 [electric charge=5] -- subgraph C_n [n=10] }; + "]] + },{ + code = [[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { [clique] 1 [electric charge=5], 2, 3, 4 }; + "]] + } + } +} + + +--- + +declare { + key = "electric force order", + type = "number", + initial = "1", + + summary = [[" + Sometimes, when drawing symmetric and mesh-like graphs, the + peripheral distortion caused by long-range electric forces may be + undesired. Some electric force models allow to reduce long-range + forces and distortion effects by increasing + the order (exponent) of electric forces. Values between 0 and 1 + increase long-range electric forces and the scaling of the + generated layouts. Value greater than 1 decrease long-range + electric forces and results in shrinking drawings. + "]] + } + + +--- + +declare { + key = "approximate remote forces", + type = "boolean", + + summary = [[" + Force based algorithms often need to compute a force for each pair + of vertices, which, for larger numbers of vertices, can lead to a + significant time overhead. This problem can be addressed by + approximating these forces: For a vertex far removed from a cluster + of vertices, instead of computing the force contribution of each + vertex of the cluster individually, we form a sort of + ``supervertex'' at the ``gravitational center'' of the cluster and + then compute only the force between this supervertex and the single + vertex. + + \emph{Remark:} Currently, the implementation seems to be broken, at + least the results are somewhat strange when this key is used. + "]] + } + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlIteration.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlIteration.lua new file mode 100644 index 0000000000..b8d96630cd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlIteration.lua @@ -0,0 +1,136 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + + +--- +-- @section subsubsection {The Iterative Process and Cooling} +-- +-- @end + + + +--- + +declare { + key = "iterations", + type = "number", + initial = "500", + + summary = [[" + Limits the number of iterations of algorithms for force-based + layouts to \meta{number}. + "]], + documentation = [[" + Depending on the characteristics of the input graph and the parameters + chosen for the algorithm, minimizing the system energy may require + many iterations. + + In these situations it may come in handy to limit the number of + iterations. This feature can also be useful to draw the same graph + after different iterations and thereby demonstrate how the spring or + spring-electrical algorithm improves the drawing step by step. + + The examples shows two drawings generated using two + different |iteration| limits. + "]], + examples = {[[" + \tikz \graph [spring layout, iterations=10] { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring layout, iterations=500] { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring electrical layout, iterations=10] + { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring electrical layout, iterations=500] + { subgraph K_n [n=4] }; + "]] + } +} + +--- + +declare { + key = "initial step length", + type = "length", + initial = "0", + + summary = [[" + This parameter specifies the amount by which nodes will be + displaced in each iteration, initially. If set to |0| (which is the + default), an appropriate value is computed automatically. + "]] + } + +--- + +declare { + key = "cooling factor", + type = "number", + initial = "0.95", + + summary = [[" + This parameter helps in controlling how layouts evolve over + time. It is used to gradually reduce the step size + between one iteration to the next. + "]], + documentation = [[" + A small positive cooling factor + $\ge 0$ means that the movement of nodes is quickly or abruptly + reduced, while a large cooling factor $\le 1$ allows for a smoother + step by step layout refinement at the cost of more iterations. The + following example demonstrates how a smaller cooling factor may + result in a less balanced drawing. By default, Hu2006 spring, + Hu2006 spring electrical, and Walshaw2000 spring electrical use a + cooling factor of |0.95|. + "]], + examples = {[[" + \tikz \graph [spring layout, cooling factor=0.1] + { a -> b -> c -> a }; + "]],[[" + \tikz \graph [spring layout, cooling factor=0.5] + { a -> b -> c -> a }; + "]] + } +} + +--- + +declare { + key = "convergence tolerance", + type = "number", + initial = "0.01", + + summary = [[" + All spring and spring-electrical algorithms implemented in the + thesis terminate as soon as the maximum movement of any node drops + below $k \cdot \meta{tolerance}$. This tolerance factor can be changed + with the convergence tolerance option: + "]], + examples = {[[" + \tikz \graph [spring layout, convergence tolerance=0.001] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + "]],[[" + \tikz \graph [spring layout, convergence tolerance=1.0] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + "]] + } +} + + + + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlSprings.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlSprings.lua new file mode 100644 index 0000000000..9b0c1071e3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlSprings.lua @@ -0,0 +1,59 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsubsection {Forces and Their Effects: Springs} +-- +-- The most important parameter of springs is their ``natural +-- length'', which can be configured using the general-purpose +-- |node distance| parameter. It is the ``equilibrium length'' of a +-- spring between two nodes in the graph. When an edge has this +-- length, no forces will ``push'' or ``pull'' along the edge. +-- +-- The following examples shows how a simple graph can be scaled by +-- changing the |node distance|: +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs.standard,graphdrawing} +-- \usegdlibrary{force}}] +-- \tikz \graph [spring layout, node distance=7mm] { subgraph C_n[n=3] }; +-- \tikz \graph [spring layout] { subgraph C_n[n=3] }; +-- \tikz \graph [spring layout, node distance=15mm]{ subgraph C_n[n=3] }; +-- \end{codeexample} +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs.standard,graphdrawing} +-- \usegdlibrary{force}}] +-- \tikz \graph [spring electrical layout, node distance=0.7cm] { subgraph C_n[n=3] }; +-- \tikz \graph [spring electrical layout] { subgraph C_n[n=3] }; +-- \tikz \graph [spring electrical layout, node distance=1.5cm] { subgraph C_n[n=3] }; +-- \end{codeexample} +-- +-- @end + + +--- + +declare { + key = "spring constant", + type = "number", + initial = "0.01", + + summary = [[" + The ``spring constant'' is a factor from Hooke's law describing the + ``stiffness'' of a spring. This factor is used inside spring-based + algorithms to determine how strongly edges ``pull'' and ``push'' at + the nodes they connect. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlStart.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlStart.lua new file mode 100644 index 0000000000..85a64b0a5a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/ControlStart.lua @@ -0,0 +1,41 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsubsection {Start Configuration} +-- +-- Currently, the start configuration for force-based algorithms is a +-- random distribution of the vertices. You can influence it by +-- changing the |random seed|: +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{force}}] +-- \tikz \graph [random seed=10, spring layout] { +-- a -- {b, c, d} -- e -- f -- {g,h} -- {a,b,e}; +-- }; +-- \end{codeexample} +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{force}}] +-- \tikz \graph [random seed=11, spring layout] { +-- a -- {b, c, d} -- e -- f -- {g,h} -- {a,b,e}; +-- }; +-- \end{codeexample} +-- +-- Other methods, like a planar preembedding, are not implemented +-- currently. +-- +-- @end diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/QuadTree.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/QuadTree.lua new file mode 100644 index 0000000000..3e1620dc21 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/QuadTree.lua @@ -0,0 +1,280 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- An implementation of a quad trees. +-- +-- The class QuadTree provides methods form handling quadtrees. +-- + +local QuadTree = { + -- Subclasses + Particle = {}, + Cell = {} +} +QuadTree.__index = QuadTree + +-- Namespace: +require("pgf.gd.force").QuadTree = QuadTree + +-- Imports: +local Vector = require "pgf.gd.deprecated.Vector" +local lib = require "pgf.gd.lib" + + +--- Creates a new quad tree. +-- +-- @return A newly-allocated quad tree. +-- +function QuadTree.new(x, y, width, height, max_particles) + local tree = { + root_cell = QuadTree.Cell.new(x, y, width, height, max_particles) + } + setmetatable(tree, QuadTree) + return tree +end + + + +--- Inserts a particle +-- +-- @param param A particle of type QuadTree.Particle +-- +function QuadTree:insert(particle) + self.root_cell:insert(particle) +end + + + +--- Computes the interactions of a particle with other cells +-- +-- @param particle A particle +-- @param test_func A test function, which on input of a cubical cell and a particle should +-- decide whether the cubical cell should be inserted into the result +-- @param cells An optional array of cells, to which the found cells will be added +-- +-- @return The cells array or a new array, if it was empty. +-- +function QuadTree:findInteractionCells(particle, test_func, cells) + local test_func = test_func or function (cell, particle) return true end + cells = cells or {} + + self.root_cell:findInteractionCells(particle, test_func, cells) + + return cells +end + + + + +--- Particle subclass +QuadTree.Particle.__index = QuadTree.Particle + + + +--- Creates a new particle. +-- +-- @return A newly-allocated particle. +-- +function QuadTree.Particle.new(pos, mass) + local particle = { + pos = pos:copy(), + mass = mass or 1, + subparticles = {}, + } + setmetatable(particle, QuadTree.Particle) + return particle +end + + + +--- A cell of a quadtree +-- +-- TT: Why is it called "cubical", by the way?! + +QuadTree.Cell.__index = QuadTree.Cell + + + +--- Creates a new cubicle cell. +-- +-- @return a newly-allocated cubicle cell. +-- +function QuadTree.Cell.new(x, y, width, height, max_particles) + local cell = { + x = x, + y = y, + width = width, + height = height, + max_particles = max_particles or 1, + subcells = {}, + particles = {}, + center_of_mass = nil, + mass = 0, + } + setmetatable(cell, QuadTree.Cell) + return cell +end + + + +function QuadTree.Cell:containsParticle(particle) + return particle.pos.x >= self.x and particle.pos.x <= self.x + self.width + and particle.pos.y >= self.y and particle.pos.y <= self.y + self.height +end + + + +function QuadTree.Cell:findSubcell(particle) + return lib.find(self.subcells, function (cell) + return cell:containsParticle(particle) + end) +end + + + +function QuadTree.Cell:createSubcells() + assert(type(self.subcells) == 'table' and #self.subcells == 0) + assert(type(self.particles) == 'table' and #self.particles <= self.max_particles) + + if #self.subcells == 0 then + for _,x in ipairs({self.x, self.x + self.width/2}) do + for _,y in ipairs({self.y, self.y + self.height/2}) do + local cell = QuadTree.Cell.new(x, y, self.width/2, self.height/2, self.max_particles) + table.insert(self.subcells, cell) + end + end + end +end + + + +function QuadTree.Cell:insert(particle) + -- check if we have a particle with the exact same position already + local existing = lib.find(self.particles, function (other) + return other.pos:equals(particle.pos) + end) + + if existing then + -- we already have a particle at the same position; splitting the cell + -- up makes no sense; instead we add the new particle as a + -- subparticle of the existing one + table.insert(existing.subparticles, particle) + else + if #self.subcells == 0 and #self.particles < self.max_particles then + table.insert(self.particles, particle) + else + if #self.subcells == 0 then + self:createSubcells() + end + + -- move particles to the new subcells + for _,existing in ipairs(self.particles) do + local cell = self:findSubcell(existing) + assert(cell, 'failed to find a cell for particle ' .. tostring(existing.pos)) + cell:insert(existing) + end + + self.particles = {} + + local cell = self:findSubcell(particle) + assert(cell) + cell:insert(particle) + end + end + + self:updateMass() + self:updateCenterOfMass() + + assert(self.mass) + assert(self.center_of_mass) +end + + + +function QuadTree.Cell:updateMass() + -- reset mass to zero + self.mass = 0 + + if #self.subcells == 0 then + -- the mass is the number of particles of the cell + for _,particle in ipairs(self.particles) do + self.mass = self.mass + particle.mass + for _,subparticle in ipairs(particle.subparticles) do + self.mass = self.mass + subparticle.mass + end + end + else + -- the mass is the sum of the masses of the subcells + for _,subcell in ipairs(self.subcells) do + self.mass = self.mass + subcell.mass + end + end +end + + + +function QuadTree.Cell:updateCenterOfMass() + -- reset center of mass, assuming the cell is empty + self.center_of_mass = nil + + if #self.subcells == 0 then + -- the center of mass is the average position of the particles + -- weighted by their masses + self.center_of_mass = Vector.new (2) + for _,p in ipairs(self.particles) do + for _,sp in ipairs(p.subparticles) do + self.center_of_mass = self.center_of_mass:plus(sp.pos:timesScalar(sp.mass)) + end + self.center_of_mass = self.center_of_mass:plus(p.pos:timesScalar(p.mass)) + end + self.center_of_mass = self.center_of_mass:dividedByScalar(self.mass) + else + -- the center of mass is the average of the weighted centers of mass + -- of the subcells + self.center_of_mass = Vector.new(2) + for _,sc in ipairs(self.subcells) do + if sc.center_of_mass then + self.center_of_mass = self.center_of_mass:plus(sc.center_of_mass:timesScalar(sc.mass)) + else + assert(sc.mass == 0) + end + end + self.center_of_mass = self.center_of_mass:dividedByScalar(self.mass) + end +end + + + +function QuadTree.Cell:findInteractionCells(particle, test_func, cells) + if #self.subcells == 0 or test_func(self, particle) then + table.insert(cells, self) + else + for _,subcell in ipairs(self.subcells) do + subcell:findInteractionCells(particle, test_func, cells) + end + end +end + + +function QuadTree.Cell:__tostring() + return '((' .. self.x .. ', ' .. self.y .. ') ' + .. 'to (' .. self.x + self.width .. ', ' .. self.y + self.height .. '))' + .. (self.particle and ' => ' .. self.particle.name or '') + .. (self.center_of_mass and ' mass ' .. self.mass .. ' at ' .. tostring(self.center_of_mass) or '') +end + + + +-- done + +return QuadTree diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua new file mode 100644 index 0000000000..a7230eb1f6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua @@ -0,0 +1,633 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local SpringElectricalHu2006 = {} + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + + +--- + +declare { + key = "spring electrical Hu 2006 layout", + algorithm = SpringElectricalHu2006, + + preconditions = { + connected = true, + loop_free = true, + simple = true, + }, + + old_graph_model = true, + + summary = [[" + Implementation of a spring electrical graph drawing algorithm based on + a paper by Hu. + "]], + documentation = [[" + \begin{itemize} + \item + Y. Hu. + \newblock Efficient, high-quality force-directed graph drawing. + \newblock \emph{The Mathematica Journal}, 2006. + \end{itemize} + + There are some modifications compared to the original algorithm, + see the Diploma thesis of Pohlmann for details. + "]] +} + +-- Imports + +local PathLengths = require "pgf.gd.lib.PathLengths" +local Vector = require "pgf.gd.deprecated.Vector" + +local QuadTree = require "pgf.gd.force.QuadTree" +local CoarseGraph = require "pgf.gd.force.CoarseGraph" + +local lib = require "pgf.gd.lib" + + +function SpringElectricalHu2006:run() + + -- Setup properties + local options = self.digraph.options + + self.iterations = options['iterations'] + self.cooling_factor = options['cooling factor'] + self.initial_step_length = options['initial step length'] + self.convergence_tolerance = options['convergence tolerance'] + + self.natural_spring_length = options['node distance'] + self.spring_constant = options['spring constant'] + + self.approximate_repulsive_forces = options['approximate remote forces'] + self.repulsive_force_order = options['electric force order'] + + self.coarsen = options['coarsen'] + self.downsize_ratio = options['downsize ratio'] + self.minimum_graph_size = options['minimum coarsening size'] + + -- Adjust types + self.downsize_ratio = math.max(0, math.min(1, self.downsize_ratio)) + self.graph_size = #self.graph.nodes + self.graph_density = (2 * #self.graph.edges) / (#self.graph.nodes * (#self.graph.nodes - 1)) + + -- validate input parameters + assert(self.iterations >= 0, 'iterations (value: ' .. self.iterations .. ') need to be greater than 0') + assert(self.cooling_factor >= 0 and self.cooling_factor <= 1, 'the cooling factor (value: ' .. self.cooling_factor .. ') needs to be between 0 and 1') + assert(self.initial_step_length >= 0, 'the initial step length (value: ' .. self.initial_step_length .. ') needs to be greater than or equal to 0') + assert(self.convergence_tolerance >= 0, 'the convergence tolerance (value: ' .. self.convergence_tolerance .. ') needs to be greater than or equal to 0') + assert(self.natural_spring_length >= 0, 'the natural spring dimension (value: ' .. self.natural_spring_length .. ') needs to be greater than or equal to 0') + assert(self.spring_constant >= 0, 'the spring constant (value: ' .. self.spring_constant .. ') needs to be greater or equal to 0') + assert(self.downsize_ratio >= 0 and self.downsize_ratio <= 1, 'the downsize ratio (value: ' .. self.downsize_ratio .. ') needs to be between 0 and 1') + assert(self.minimum_graph_size >= 2, 'the minimum coarsening size of coarse graphs (value: ' .. self.minimum_graph_size .. ') needs to be greater than or equal to 2') + + -- initialize node weights + for _,node in ipairs(self.graph.nodes) do + if node:getOption('electric charge') ~= nil then + node.weight = node:getOption('electric charge') + else + node.weight = 1 + end + end + + -- initialize edge weights + for _,edge in ipairs(self.graph.edges) do + edge.weight = 1 + end + + -- initialize the coarse graph data structure. note that the algorithm + -- is the same regardless whether coarsening is used, except that the + -- number of coarsening steps without coarsening is 0 + local coarse_graph = CoarseGraph.new(self.graph) + + -- check if the multilevel approach should be used + if self.coarsen then + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by + -- at least the downsize ratio configured by the user + while coarse_graph:getSize() > self.minimum_graph_size + and coarse_graph:getRatio() <= (1 - self.downsize_ratio) + do + coarse_graph:coarsen() + end + end + + if self.coarsen then + -- use the natural spring length as the initial natural spring length + local spring_length = self.natural_spring_length + + -- compute a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, spring_length) + + -- set the spring length to the average edge length of the initial layout + spring_length = 0 + for _,edge in ipairs(coarse_graph.graph.edges) do + spring_length = spring_length + edge.nodes[1].pos:minus(edge.nodes[2].pos):norm() + end + spring_length = spring_length / #coarse_graph.graph.edges + + -- additionally improve the layout with the force-based algorithm + -- if there are more than two nodes in the coarsest graph + if coarse_graph:getSize() > 2 then + self:computeForceLayout(coarse_graph.graph, spring_length, SpringElectricalHu2006.adaptive_step_update) + end + + -- undo coarsening step by step, applying the force-based sub-algorithm + -- to every intermediate coarse graph as well as the original graph + while coarse_graph:getLevel() > 0 do + + -- compute the diameter of the parent coarse graph + local parent_diameter = PathLengths.pseudoDiameter(coarse_graph.graph) + + -- interpolate the previous coarse graph from its parent + coarse_graph:interpolate() + + -- compute the diameter of the current coarse graph + local current_diameter = PathLengths.pseudoDiameter(coarse_graph.graph) + + -- scale node positions by the quotient of the pseudo diameters + for _,node in ipairs(coarse_graph.graph) do + node.pos:update(function (n, value) + return value * (current_diameter / parent_diameter) + end) + end + + -- compute forces in the graph + self:computeForceLayout(coarse_graph.graph, spring_length, SpringElectricalHu2006.conservative_step_update) + end + else + -- compute a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, self.natural_spring_length) + + -- set the spring length to the average edge length of the initial layout + spring_length = 0 + for _,edge in ipairs(coarse_graph.graph.edges) do + spring_length = spring_length + edge.nodes[1].pos:minus(edge.nodes[2].pos):norm() + end + spring_length = spring_length / #coarse_graph.graph.edges + + -- improve the layout with the force-based algorithm + self:computeForceLayout(coarse_graph.graph, spring_length, SpringElectricalHu2006.adaptive_step_update) + end +end + + + +function SpringElectricalHu2006:computeInitialLayout(graph, spring_length) + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is + -- fixated? + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + if #graph.nodes == 2 then + if not (graph.nodes[1].fixed and graph.nodes[2].fixed) then + local fixed_index = graph.nodes[2].fixed and 2 or 1 + local loose_index = graph.nodes[2].fixed and 1 or 2 + + if not graph.nodes[1].fixed and not graph.nodes[2].fixed then + -- both nodes can be moved, so we assume node 1 is fixed at (0,0) + graph.nodes[1].pos.x = 0 + graph.nodes[1].pos.y = 0 + end + + -- position the loose node relative to the fixed node, with + -- the displacement (random direction) matching the spring length + local direction = Vector.new{x = lib.random(1, spring_length), y = lib.random(1, spring_length)} + local distance = 3 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + local displacement = direction:normalized():timesScalar(distance) + + graph.nodes[loose_index].pos = graph.nodes[fixed_index].pos:plus(displacement) + else + -- both nodes are fixed, initial layout may be far from optimal + end + else + + -- use a random positioning technique + local function positioning_func(n) + local radius = 3 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + return lib.random(-radius, radius) + end + + -- compute initial layout based on the random positioning technique + for _,node in ipairs(graph.nodes) do + if not node.fixed then + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) + end + end + end +end + + + +function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_update_func) + -- global (=repulsive) force function + function accurate_repulsive_force(distance, weight) + -- note: the weight is taken into the equation here. unlike in the original + -- algorithm different electric charges are allowed for each node in this + -- implementation + return - weight * self.spring_constant * math.pow(spring_length, self.repulsive_force_order + 1) / math.pow(distance, self.repulsive_force_order) + end + + -- global (=repulsive, approximated) force function + function approximated_repulsive_force(distance, mass) + return - mass * self.spring_constant * math.pow(spring_length, self.repulsive_force_order + 1) / math.pow(distance, self.repulsive_force_order) + end + + -- local (spring) force function + function attractive_force(distance) + return (distance * distance) / spring_length + end + + -- define the Barnes-Hut opening criterion + function barnes_hut_criterion(cell, particle) + local distance = particle.pos:minus(cell.center_of_mass):norm() + return cell.width / distance <= 1.2 + end + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + -- adjust the initial step length automatically if desired by the user + local step_length = self.initial_step_length == 0 and spring_length or self.initial_step_length + + -- convergence criteria etc. + local converged = false + local energy = math.huge + local iteration = 0 + local progress = 0 + + while not converged and iteration < self.iterations do + -- remember old node positions + local old_positions = lib.map(graph.nodes, function (node) + return node.pos:copy(), node + end) + + -- remember the old system energy and reset it for the current iteration + local old_energy = energy + energy = 0 + + -- build the quadtree for approximating repulsive forces, if desired + local quadtree = nil + if self.approximate_repulsive_forces then + quadtree = self:buildQuadtree(graph) + end + + for _,v in ipairs(graph.nodes) do + if not v.fixed then + -- vector for the displacement of v + local d = Vector.new(2) + + -- compute repulsive forces + if self.approximate_repulsive_forces then + -- determine the cells that have a repulsive influence on v + local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) + + -- compute the repulsive force between these cells and v + for _,cell in ipairs(cells) do + -- check if the cell is a leaf + if #cell.subcells == 0 then + -- compute the forces between the node and all particles in the cell + for _,particle in ipairs(cell.particles) do + local real_particles = lib.copy(particle.subparticles) + table.insert(real_particles, particle) + + for _,real_particle in ipairs(real_particles) do + local delta = real_particle.pos:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + -- compute the distance between the node and the cell's center of mass + local delta = cell.center_of_mass:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + for _,u in ipairs(graph.nodes) do + if v ~= u then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + end + + -- compute attractive forces between v and its neighbors + for _,edge in ipairs(v.edges) do + local u = edge:getNeighbour(v) + + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the spring force vector between u and v + local attr_force = attractive_force(delta:norm()) + local force = delta:normalized():timesScalar(attr_force) + + -- move the node v accordingly + d = d:plus(force) + end + + -- really move the node now + -- TODO note how all nodes are moved by the same amount (step_length) + -- while Walshaw multiplies the normalized force with min(step_length, + -- d:norm()). could that improve this algorithm even further? + v.pos = v.pos:plus(d:normalized():timesScalar(step_length)) + + -- TODO Hu doesn't mention this but the energy of a particle is + -- typically considered as the product of its mass and the square of + -- its forces. This means we should probably take the weight of + -- the node v into the equation, doesn't it? + -- + -- update the energy function + energy = energy + math.pow(d:norm(), 2) + -- vector for the displacement of v + local d = Vector.new(2) + + -- compute repulsive forces + if self.approximate_repulsive_forces then + -- determine the cells that have a repulsive influence on v + local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) + + -- compute the repulsive force between these cells and v + for _,cell in ipairs(cells) do + -- check if the cell is a leaf + if #cell.subcells == 0 then + -- compute the forces between the node and all particles in the cell + for _,particle in ipairs(cell.particles) do + local real_particles = lib.copy(particle.subparticles) + table.insert(real_particles, particle) + + for _,real_particle in ipairs(real_particles) do + local delta = real_particle.pos:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + -- compute the distance between the node and the cell's center of mass + local delta = cell.center_of_mass:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + for _,u in ipairs(graph.nodes) do + if v ~= u then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + end + + -- compute attractive forces between v and its neighbours + for _,edge in ipairs(v.edges) do + local u = edge:getNeighbour(v) + + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the spring force vector between u and v + local attr_force = attractive_force(delta:norm()) + local force = delta:normalized():timesScalar(attr_force) + + -- move the node v accordingly + d = d:plus(force) + end + + -- really move the node now + -- TODO note how all nodes are moved by the same amount (step_length) + -- while Walshaw multiplies the normalized force with min(step_length, + -- d:norm()). could that improve this algorithm even further? + v.pos = v.pos:plus(d:normalized():timesScalar(step_length)) + + -- TODO Hu doesn't mention this but the energy of a particle is + -- typically considered as the product of its mass and the square of + -- its forces. This means we should probably take the weight of + -- the node v into the equation, doesn't it? + -- + -- update the energy function + energy = energy + math.pow(d:norm(), 2) + end + end + + -- update the step length and progress counter + step_length, progress = step_update_func(step_length, self.cooling_factor, energy, old_energy, progress) + + -- compute the maximum node movement in this iteration + local max_movement = 0 + for _,x in ipairs(graph.nodes) do + local delta = x.pos:minus(old_positions[x]) + max_movement = math.max(delta:norm(), max_movement) + end + + -- the algorithm will converge if the maximum movement is below a + -- threshold depending on the spring length and the convergence + -- tolerance + if max_movement < spring_length * self.convergence_tolerance then + converged = true + end + + -- increment the iteration counter + iteration = iteration + 1 + end +end + + + +-- Fixes nodes at their specified positions. +-- +function SpringElectricalHu2006:fixateNodes(graph) + local number_of_fixed_nodes = 0 + + for _,node in ipairs(graph.nodes) do + -- read the 'desired at' option of the node + local coordinate = node:getOption('desired at') + + if coordinate then + -- apply the coordinate + node.pos.x = coordinate.x + node.pos.y = coordinate.y + + -- mark the node as fixed + node.fixed = true + + number_of_fixed_nodes = number_of_fixed_nodes + 1 + end + end + if number_of_fixed_nodes > 1 then + self.growth_direction = "fixed" -- do not grow, orientation is now fixed + end +end + + + +function SpringElectricalHu2006:buildQuadtree(graph) + -- compute the minimum x and y coordinates of all nodes + local min_pos = graph.nodes[1].pos + for _,node in ipairs(graph.nodes) do + min_pos = Vector.new(2, function (n) return math.min(min_pos[n], node.pos[n]) end) + end + + -- compute maximum x and y coordinates of all nodes + local max_pos = graph.nodes[1].pos + for _,node in ipairs(graph.nodes) do + max_pos = Vector.new(2, function (n) return math.max(max_pos[n], node.pos[n]) end) + end + + -- make sure the maximum position is at least a tiny bit + -- larger than the minimum position + if min_pos:equals(max_pos) then + max_pos = max_pos:plus(Vector.new(2, function (n) + return 0.1 + lib.random() * 0.1 + end)) + end + + -- make sure to make the quadtree area slightly larger than required + -- in theory; for some reason Lua will otherwise think that nodes with + -- min/max x/y coordinates are outside the box... weird? yes. + min_pos = min_pos:minus({1,1}) + max_pos = max_pos:plus({1,1}) + + -- create the quadtree + quadtree = QuadTree.new(min_pos.x, min_pos.y, + max_pos.x - min_pos.x, + max_pos.y - min_pos.y) + + -- insert nodes into the quadtree + for _,node in ipairs(graph.nodes) do + local particle = QuadTree.Particle.new(node.pos, node.weight) + particle.node = node + quadtree:insert(particle) + end + + return quadtree +end + + + +function SpringElectricalHu2006.conservative_step_update(step, cooling_factor) + return cooling_factor * step, nil +end + + + +function SpringElectricalHu2006.adaptive_step_update(step, cooling_factor, energy, old_energy, progress) + if energy < old_energy then + progress = progress + 1 + if progress >= 5 then + progress = 0 + step = step / cooling_factor + end + else + progress = 0 + step = cooling_factor * step + end + return step, progress +end + + +-- done + +return SpringElectricalHu2006 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua new file mode 100644 index 0000000000..6ab74fc367 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua @@ -0,0 +1,54 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Spring Electrical Layouts} +-- +-- @end + + + +--- + +declare { + key = "spring electrical layout", + use = { + { key = "spring electrical Hu 2006 layout" }, + { key = "spring constant", value = "0.2" } + }, + + summary = [[" + This key selects Hu's 2006 spring electrical layout with + appropriate settings for some parameters. + "]] +} + + +--- + +declare { + key = "spring electrical layout'", + use = { + { key = "spring electrical Walshaw 2000 layout" }, + { key = "spring constant", value = "0.01" }, + { key = "convergence tolerance", value = "0.001" }, + }, + + summary = [[" + This key selects Walshaw's 2000 spring electrical layout with + appropriate settings for some parameters. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua new file mode 100644 index 0000000000..5f7978da4e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua @@ -0,0 +1,520 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +local SpringElectricalWalshaw2000 = {} + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + + +--- + +declare { + key = "spring electrical Walshaw 2000 layout", + algorithm = SpringElectricalWalshaw2000, + + preconditions = { + connected = true, + loop_free = true, + simple = true, + }, + + old_graph_model = true, + + summary = [[" + Implementation of a spring electrical graph drawing algorithm based on + a paper by Walshaw. + "]], + documentation = [[" + \begin{itemize} + \item + C. Walshaw. + \newblock A multilevel algorithm for force-directed graph drawing. + \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in + Computer Science, 1984:31--55, 2001. + \end{itemize} + + The following modifications compared to the original algorithm were applied: + % + \begin{itemize} + \item An iteration limit was added. + \item The natural spring length for all coarse graphs is computed based + on the formula presented by Walshaw, so that the natural spring + length of the original graph (coarse graph 0) is the same as + the value requested by the user. + \item Users can define custom node and edge weights. + \item Coarsening stops when $|V(G_i+1)|/|V(G_i)| < p$ where $p = 0.75$. + \item Coarsening stops when the maximal matching is empty. + \item The runtime of the algorithm is improved by use of a quadtree + data structure like Hu does in his algorithm. + \item A limiting the number of levels of the quadtree is not implemented. + \end{itemize} + "]] +} + +-- TODO Implement the following keys (or whatever seems appropriate +-- and doable for this algorithm): +-- - /tikz/desired at +-- - /tikz/influence cutoff distance +-- - /tikz/spring stiffness (could this be the equivalent to the electric +-- charge of nodes? +-- - /tikz/natural spring dimension per edge +-- +-- TODO Implement the following features: +-- - clustering of nodes using color classes +-- - different cluster layouts (vertical line, horizontal line, +-- normal cluster, internally fixed subgraph) + + + +local Vector = require "pgf.gd.deprecated.Vector" + +local QuadTree = require "pgf.gd.force.QuadTree" +local CoarseGraph = require "pgf.gd.force.CoarseGraph" + + +local lib = require "pgf.gd.lib" + + +function SpringElectricalWalshaw2000:run() + + -- Setup parameters + local options = self.digraph.options + + self.iterations = options['iterations'] + self.cooling_factor = options['cooling factor'] + self.initial_step_length = options['initial step length'] + self.convergence_tolerance = options['convergence tolerance'] + + self.natural_spring_length = options['node distance'] + self.spring_constant = options['spring constant'] + + self.approximate_repulsive_forces = options['approximate remote forces'] + self.repulsive_force_order = options['electric force order'] + + self.coarsen = options['coarsen'] + self.downsize_ratio = options['downsize ratio'] + self.minimum_graph_size = options['minimum coarsening size'] + + -- Adjust types + self.downsize_ratio = math.max(0, math.min(1, self.downsize_ratio)) + self.graph_size = #self.graph.nodes + self.graph_density = (2 * #self.graph.edges) / (#self.graph.nodes * (#self.graph.nodes - 1)) + + -- validate input parameters + assert(self.iterations >= 0, 'iterations (value: ' .. self.iterations .. ') need to be greater than 0') + assert(self.cooling_factor >= 0 and self.cooling_factor <= 1, 'the cooling factor (value: ' .. self.cooling_factor .. ') needs to be between 0 and 1') + assert(self.initial_step_length >= 0, 'the initial step length (value: ' .. self.initial_step_length .. ') needs to be greater than or equal to 0') + assert(self.convergence_tolerance >= 0, 'the convergence tolerance (value: ' .. self.convergence_tolerance .. ') needs to be greater than or equal to 0') + assert(self.natural_spring_length >= 0, 'the natural spring dimension (value: ' .. self.natural_spring_length .. ') needs to be greater than or equal to 0') + assert(self.spring_constant >= 0, 'the spring constant (value: ' .. self.spring_constant .. ') needs to be greater or equal to 0') + assert(self.downsize_ratio >= 0 and self.downsize_ratio <= 1, 'the downsize ratio (value: ' .. self.downsize_ratio .. ') needs to be between 0 and 1') + assert(self.minimum_graph_size >= 2, 'the minimum coarsening size of coarse graphs (value: ' .. self.minimum_graph_size .. ') needs to be greater than or equal to 2') + + -- initialize node weights + for _,node in ipairs(self.graph.nodes) do + if node:getOption('electric charge') ~= nil then + node.weight = node:getOption('electric charge') + else + node.weight = 1 + end + + -- a node is charged if its weight derives from the default setting + -- of 1 (where it has no influence on the forces) + node.charged = node.weight ~= 1 + end + + -- initialize edge weights + for _,edge in ipairs(self.graph.edges) do + edge.weight = 1 + end + + + -- initialize the coarse graph data structure. note that the algorithm + -- is the same regardless whether coarsening is used, except that the + -- number of coarsening steps without coarsening is 0 + local coarse_graph = CoarseGraph.new(self.graph) + + -- check if the multilevel approach should be used + if self.coarsen then + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by + -- at least the downsize ratio configured by the user + while coarse_graph:getSize() > self.minimum_graph_size + and coarse_graph:getRatio() < (1 - self.downsize_ratio) + do + coarse_graph:coarsen() + end + end + + -- compute the natural spring length for the coarsest graph in a way + -- that will result in the desired natural spring length in the + -- original graph + local spring_length = self.natural_spring_length / math.pow(math.sqrt(4/7), coarse_graph:getLevel()) + + if self.coarsen then + -- generate a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, spring_length) + + -- undo coarsening step by step, applying the force-based sub-algorithm + -- to every intermediate coarse graph as well as the original graph + while coarse_graph:getLevel() > 0 do + -- interpolate the previous coarse graph + coarse_graph:interpolate() + + -- update the natural spring length so that, for the original graph, + -- it equals the natural spring dimension configured by the user + spring_length = spring_length * math.sqrt(4/7) + + -- apply the force-based algorithm to improve the layout + self:computeForceLayout(coarse_graph.graph, spring_length) + end + else + -- generate a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, spring_length) + + -- apply the force-based algorithm to improve the layout + self:computeForceLayout(coarse_graph.graph, spring_length) + end +end + + + +function SpringElectricalWalshaw2000:computeInitialLayout(graph, spring_length) + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is + -- fixated? + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + if #graph.nodes == 2 then + if not (graph.nodes[1].fixed and graph.nodes[2].fixed) then + local fixed_index = graph.nodes[2].fixed and 2 or 1 + local loose_index = graph.nodes[2].fixed and 1 or 2 + + if not graph.nodes[1].fixed and not graph.nodes[2].fixed then + -- both nodes can be moved, so we assume node 1 is fixed at (0,0) + graph.nodes[1].pos.x = 0 + graph.nodes[1].pos.y = 0 + end + + -- position the loose node relative to the fixed node, with + -- the displacement (random direction) matching the spring length + local direction = Vector.new{x = lib.random(1, 2), y = lib.random(1, 2)} + local distance = 3 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + local displacement = direction:normalized():timesScalar(distance) + + graph.nodes[loose_index].pos = graph.nodes[fixed_index].pos:plus(displacement) + else + -- both nodes are fixed, initial layout may be far from optimal + end + else + -- function to filter out fixed nodes + local function nodeNotFixed(node) return not node.fixed end + + -- use the random positioning technique + local function positioning_func(n) + local radius = 3 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + return lib.random(-radius, radius) + end + + -- compute initial layout based on the random positioning technique + for _,node in ipairs(graph.nodes) do + if not node.fixed then + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) + end + end + end +end + + + +function SpringElectricalWalshaw2000:computeForceLayout(graph, spring_length) + -- global (=repulsive) force function + local function accurate_repulsive_force(distance, weight) + return - self.spring_constant * weight * math.pow(spring_length, self.repulsive_force_order + 1) / math.pow(distance, self.repulsive_force_order) + end + + -- global (=repulsive, approximated) force function + local function approximated_repulsive_force(distance, mass) + return - mass * self.spring_constant * math.pow(spring_length, self.repulsive_force_order + 1) / math.pow(distance, self.repulsive_force_order) + end + + -- local (spring) force function + local function attractive_force(distance, d, weight, charged, repulsive_force) + -- for charged nodes, never subtract the repulsive force; we want ALL other + -- nodes to be attracted more / repulsed less (not just non-adjacent ones), + -- depending on the charge of course + if charged then + return (distance - spring_length) / d - accurate_repulsive_force(distance, weight) + else + return (distance - spring_length) / d - (repulsive_force or 0) + end + end + + -- define the Barnes-Hut opening criterion + function barnes_hut_criterion(cell, particle) + local distance = particle.pos:minus(cell.center_of_mass):norm() + return cell.width / distance <= 1.2 + end + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + -- adjust the initial step length automatically if desired by the user + local step_length = self.initial_step_length == 0 and spring_length or self.initial_step_length + + -- convergence criteria + local converged = false + local i = 0 + + while not converged and i < self.iterations do + + -- assume that we are converging + converged = true + i = i + 1 + + -- build the quadtree for approximating repulsive forces, if desired + local quadtree = nil + if self.approximate_repulsive_forces then + quadtree = self:buildQuadtree(graph) + end + + local function nodeNotFixed(node) return not node.fixed end + + -- iterate over all nodes + for _,v in ipairs(graph.nodes) do + if not v.fixed then + -- vector for the displacement of v + local d = Vector.new(2) + + -- repulsive force induced by other nodes + local repulsive_forces = {} + + -- compute repulsive forces + if self.approximate_repulsive_forces then + -- determine the cells that have an repulsive influence on v + local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) + + -- compute the repulsive force between these cells and v + for _,cell in ipairs(cells) do + -- check if the cell is a leaf + if #cell.subcells == 0 then + -- compute the forces between the node and all particles in the cell + for _,particle in ipairs(cell.particles) do + -- build a table that contains the particle plus all its subparticles + -- (particles at the same position) + local real_particles = lib.copy(particle.subparticles) + table.insert(real_particles, particle) + + for _,real_particle in ipairs(real_particles) do + local delta = real_particle.pos:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- remember the repulsive force for the particle so that we can + -- subtract it later when computing the attractive forces with + -- adjacent nodes + repulsive_forces[real_particle.node] = repulsive_force + + -- move the node v accordingly + d = d:plus(force) + end + end + else + -- compute the distance between the node and the cell's center of mass + local delta = cell.center_of_mass:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- TODO for each neighbor of v, check if it is in this cell. + -- if this is the case, compute the quadtree force for the mass + -- 'node.weight / cell.mass' and remember this as the repulsive + -- force of the neighbor; (it is not necessarily at + -- the center of mass of the cell, so the result is only an + -- approximation of the real repulsive force generated by the + -- neighbor) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + for _,u in ipairs(graph.nodes) do + if u.name ~= v.name then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) + local force = delta:normalized():timesScalar(repulsive_force) + + -- remember the repulsive force so we can later subtract them + -- when computing the attractive forces + repulsive_forces[u] = repulsive_force + + -- move the node v accordingly + d = d:plus(force) + end + end + end + + -- compute attractive forces between v and its neighbors + for _,edge in ipairs(v.edges) do + local u = edge:getNeighbour(v) + + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the spring force between them + local attr_force = attractive_force(delta:norm(), #v.edges, u.weight, u.charged, repulsive_forces[u]) + local force = delta:normalized():timesScalar(attr_force) + + -- move the node v accordingly + d = d:plus(force) + end + + -- remember the previous position of v + old_position = v.pos:copy() + + if d:norm() > 0 then + -- reposition v according to the force vector and the current temperature + v.pos = v.pos:plus(d:normalized():timesScalar(math.min(step_length, d:norm()))) + end + + -- we need to improve the system energy as long as any of + -- the node movements is large enough to assume we're far + -- away from the minimum system energy + if v.pos:minus(old_position):norm() > spring_length * self.convergence_tolerance then + converged = false + end + end + end + + -- update the step length using the conservative cooling scheme + step_length = self.cooling_factor * step_length + end +end + + + +-- Fixes nodes at their specified positions. +-- +function SpringElectricalWalshaw2000:fixateNodes(graph) + local number_of_fixed_nodes = 0 + + for _,node in ipairs(graph.nodes) do + -- read the 'desired at' option of the node + local coordinate = node:getOption('desired at') + + if coordinate then + -- parse the coordinate + node.pos.x = coordinate.x + node.pos.y = coordinate.y + + -- mark the node as fixed + node.fixed = true + + number_of_fixed_nodes = number_of_fixed_nodes + 1 + end + end + if number_of_fixed_nodes > 1 then + self.growth_direction = "fixed" -- do not grow, orientation is now fixed + end +end + + + +function SpringElectricalWalshaw2000:buildQuadtree(graph) + -- compute the minimum x and y coordinates of all nodes + local min_pos = graph.nodes[1].pos + for _,node in ipairs(graph.nodes) do + min_pos = Vector.new(2, function (n) return math.min(min_pos[n], node.pos[n]) end) + end + + -- compute maximum x and y coordinates of all nodes + local max_pos = graph.nodes[1].pos + for _,node in ipairs(graph.nodes) do + max_pos = Vector.new(2, function (n) return math.max(max_pos[n], node.pos[n]) end) + end + + -- make sure the maximum position is at least a tiny bit + -- larger than the minimum position + if min_pos:equals(max_pos) then + max_pos = max_pos:plus(Vector.new(2, function (n) + return 0.1 + lib.random() * 0.1 + end)) + end + + -- make sure to make the quadtree area slightly larger than required + -- in theory; for some reason Lua will otherwise think that nodes with + -- min/max x/y coordinates are outside the box... weird? yes. + min_pos = min_pos:minusScalar(1) + max_pos = max_pos:plusScalar(1) + + -- create the quadtree + quadtree = QuadTree.new(min_pos.x, min_pos.y, + max_pos.x - min_pos.x, + max_pos.y - min_pos.y) + + -- insert nodes into the quadtree + for _,node in ipairs(graph.nodes) do + local particle = QuadTree.Particle.new(node.pos, node.weight) + particle.node = node + quadtree:insert(particle) + end + + return quadtree +end + + + +-- done + +return SpringElectricalWalshaw2000 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua new file mode 100644 index 0000000000..86b65abc83 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua @@ -0,0 +1,386 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local SpringHu2006 = {} + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + + +--- + +declare { + key = "spring Hu 2006 layout", + algorithm = SpringHu2006, + + preconditions = { + connected = true, + loop_free = true, + simple = true, + }, + + old_graph_model = true, + + summary = [[" + Implementation of a spring graph drawing algorithm based on + a paper by Hu. + "]], + documentation = [[" + \begin{itemize} + \item + Y. Hu. + \newblock Efficient, high-quality force-directed graph drawing. + \newblock \emph{The Mathematica Journal}, 2006. + \end{itemize} + + There are some modifications compared to the original algorithm, + see the Diploma thesis of Pohlmann for details. + "]] +} + + +-- Imports + +local PathLengths = require "pgf.gd.lib.PathLengths" +local Vector = require "pgf.gd.deprecated.Vector" + +local CoarseGraph = require "pgf.gd.force.CoarseGraph" + +local lib = require("pgf.gd.lib") + + + + +function SpringHu2006:run() + + -- Setup some parameters + local options = self.digraph.options + + self.iterations = options['iterations'] + self.cooling_factor = options['cooling factor'] + self.initial_step_length = options['initial step length'] + self.convergence_tolerance = options['convergence tolerance'] + + self.natural_spring_length = options['node distance'] + + self.coarsen = options['coarsen'] + self.downsize_ratio = options['downsize ratio'] + self.minimum_graph_size = options['minimum coarsening size'] + + + -- Setup + + self.downsize_ratio = math.max(0, math.min(1, tonumber(self.downsize_ratio))) + + self.graph_size = #self.graph.nodes + self.graph_density = (2 * #self.graph.edges) / (#self.graph.nodes * (#self.graph.nodes - 1)) + + -- validate input parameters + assert(self.iterations >= 0, 'iterations (value: ' .. self.iterations .. ') need to be greater than 0') + assert(self.cooling_factor >= 0 and self.cooling_factor <= 1, 'the cooling factor (value: ' .. self.cooling_factor .. ') needs to be between 0 and 1') + assert(self.initial_step_length >= 0, 'the initial step length (value: ' .. self.initial_step_length .. ') needs to be greater than or equal to 0') + assert(self.convergence_tolerance >= 0, 'the convergence tolerance (value: ' .. self.convergence_tolerance .. ') needs to be greater than or equal to 0') + assert(self.natural_spring_length >= 0, 'the natural spring dimension (value: ' .. self.natural_spring_length .. ') needs to be greater than or equal to 0') + assert(self.downsize_ratio >= 0 and self.downsize_ratio <= 1, 'the downsize ratio (value: ' .. self.downsize_ratio .. ') needs to be between 0 and 1') + assert(self.minimum_graph_size >= 2, 'the minimum coarsening size of coarse graphs (value: ' .. self.minimum_graph_size .. ') needs to be greater than or equal to 2') + + -- initialize node weights + for _,node in ipairs(self.graph.nodes) do + node.weight = 1 + end + + -- initialize edge weights + for _,edge in ipairs(self.graph.edges) do + edge.weight = 1 + end + + + -- initialize the coarse graph data structure. note that the algorithm + -- is the same regardless whether coarsening is used, except that the + -- number of coarsening steps without coarsening is 0 + local coarse_graph = CoarseGraph.new(self.graph) + + -- check if the multilevel approach should be used + if self.coarsen then + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by + -- at least the downsize ratio configured by the user + while coarse_graph:getSize() > self.minimum_graph_size + and coarse_graph:getRatio() <= (1 - self.downsize_ratio) + do + coarse_graph:coarsen() + end + end + + if self.coarsen then + -- use the natural spring length as the initial natural spring length + local spring_length = self.natural_spring_length + + -- compute a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, spring_length) + + -- set the spring length to the average edge length of the initial layout + spring_length = 0 + for _,edge in ipairs(coarse_graph.graph.edges) do + spring_length = spring_length + edge.nodes[1].pos:minus(edge.nodes[2].pos):norm() + end + spring_length = spring_length / #coarse_graph.graph.edges + + -- additionally improve the layout with the force-based algorithm + -- if there are more than two nodes in the coarsest graph + if coarse_graph:getSize() > 2 then + self:computeForceLayout(coarse_graph.graph, spring_length, SpringHu2006.adaptive_step_update) + end + + -- undo coarsening step by step, applying the force-based sub-algorithm + -- to every intermediate coarse graph as well as the original graph + while coarse_graph:getLevel() > 0 do + -- compute the diameter of the parent coarse graph + local parent_diameter = PathLengths.pseudoDiameter(coarse_graph.graph) + + -- interpolate the previous coarse graph from its parent + coarse_graph:interpolate() + + -- compute the diameter of the current coarse graph + local current_diameter = PathLengths.pseudoDiameter(coarse_graph.graph) + + -- scale node positions by the quotient of the pseudo diameters + for _,node in ipairs(coarse_graph.graph) do + node.pos:update(function (n, value) + return value * (current_diameter / parent_diameter) + end) + end + + -- compute forces in the graph + self:computeForceLayout(coarse_graph.graph, spring_length, SpringHu2006.conservative_step_update) + end + else + -- compute a random initial layout for the coarsest graph + self:computeInitialLayout(coarse_graph.graph, self.natural_spring_length) + + -- set the spring length to the average edge length of the initial layout + spring_length = 0 + for _,edge in ipairs(coarse_graph.graph.edges) do + spring_length = spring_length + edge.nodes[1].pos:minus(edge.nodes[2].pos):norm() + end + spring_length = spring_length / #coarse_graph.graph.edges + + -- improve the layout with the force-based algorithm + self:computeForceLayout(coarse_graph.graph, spring_length, SpringHu2006.adaptive_step_update) + end + + local avg_spring_length = 0 + for _,edge in ipairs(self.graph.edges) do + avg_spring_length = avg_spring_length + edge.nodes[1].pos:minus(edge.nodes[2].pos):norm() + end + avg_spring_length = avg_spring_length / #self.graph.edges +end + + + +function SpringHu2006:computeInitialLayout(graph, spring_length) + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is + -- fixated? + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + if #graph.nodes == 2 then + if not (graph.nodes[1].fixed and graph.nodes[2].fixed) then + local fixed_index = graph.nodes[2].fixed and 2 or 1 + local loose_index = graph.nodes[2].fixed and 1 or 2 + + if not graph.nodes[1].fixed and not graph.nodes[2].fixed then + -- both nodes can be moved, so we assume node 1 is fixed at (0,0) + graph.nodes[1].pos.x = 0 + graph.nodes[1].pos.y = 0 + end + + -- position the loose node relative to the fixed node, with + -- the displacement (random direction) matching the spring length + local direction = Vector.new{x = lib.random(1, spring_length), y = lib.random(1, spring_length)} + local distance = 1.8 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + local displacement = direction:normalized():timesScalar(distance) + + graph.nodes[loose_index].pos = graph.nodes[fixed_index].pos:plus(displacement) + else + -- both nodes are fixed, initial layout may be far from optimal + end + else + -- use a random positioning technique + local function positioning_func(n) + local radius = 2 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 + return lib.random(-radius, radius) + end + + -- compute initial layout based on the random positioning technique + for _,node in ipairs(graph.nodes) do + if not node.fixed then + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) + end + end + end +end + + + +function SpringHu2006:computeForceLayout(graph, spring_length, step_update_func) + -- global (=repulsive) force function + function repulsive_force(distance, graph_distance, weight) + --return (1/4) * (1/math.pow(graph_distance, 2)) * (distance - (spring_length * graph_distance)) + return (distance - (spring_length * graph_distance)) + end + + -- fixate all nodes that have a 'desired at' option. this will set the + -- node.fixed member to true and also set node.pos.x and node.pos.y + self:fixateNodes(graph) + + -- adjust the initial step length automatically if desired by the user + local step_length = self.initial_step_length == 0 and spring_length or self.initial_step_length + + -- convergence criteria etc. + local converged = false + local energy = math.huge + local iteration = 0 + local progress = 0 + + -- compute graph distance between all pairs of nodes + local distances = PathLengths.floydWarshall(graph) + + while not converged and iteration < self.iterations do + -- remember old node positions + local old_positions = lib.map(graph.nodes, function (node) return node.pos:copy(), node end) + + -- remember the old system energy and reset it for the current iteration + local old_energy = energy + energy = 0 + + for _,v in ipairs(graph.nodes) do + if not v.fixed then + -- vector for the displacement of v + local d = Vector.new(2) + + for _,u in ipairs(graph.nodes) do + if v ~= u then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + local graph_distance = (distances[u] and distances[u][v]) and distances[u][v] or #graph.nodes + 1 + + -- compute the repulsive force vector + local force = repulsive_force(delta:norm(), graph_distance, v.weight) + local force = delta:normalized():timesScalar(force) + + -- move the node v accordingly + d = d:plus(force) + end + end + + -- really move the node now + -- TODO note how all nodes are moved by the same amount (step_length) + -- while Walshaw multiplies the normalized force with min(step_length, + -- d:norm()). could that improve this algorithm even further? + v.pos = v.pos:plus(d:normalized():timesScalar(step_length)) + + -- update the energy function + energy = energy + math.pow(d:norm(), 2) + end + end + + -- update the step length and progress counter + step_length, progress = step_update_func(step_length, self.cooling_factor, energy, old_energy, progress) + + -- compute the maximum node movement in this iteration + local max_movement = 0 + for _,x in ipairs(graph.nodes) do + local delta = x.pos:minus(old_positions[x]) + max_movement = math.max(delta:norm(), max_movement) + end + + -- the algorithm will converge if the maximum movement is below a + -- threshold depending on the spring length and the convergence + -- tolerance + if max_movement < spring_length * self.convergence_tolerance then + converged = true + end + + -- increment the iteration counter + iteration = iteration + 1 + end +end + + + +-- Fixes nodes at their specified positions. +-- +function SpringHu2006:fixateNodes(graph) + local number_of_fixed_nodes = 0 + + for _,node in ipairs(graph.nodes) do + -- read the 'desired at' option of the node + local coordinate = node:getOption('desired at') + + if coordinate then + -- apply the coordinate + node.pos.x = coordinate.x + node.pos.y = coordinate.y + + -- mark the node as fixed + node.fixed = true + + number_of_fixed_nodes = number_of_fixed_nodes + 1 + end + end + if number_of_fixed_nodes > 1 then + self.growth_direction = "fixed" -- do not grow, orientation is now fixed + end +end + + + +function SpringHu2006.conservative_step_update(step, cooling_factor) + return cooling_factor * step, nil +end + + + +function SpringHu2006.adaptive_step_update(step, cooling_factor, energy, old_energy, progress) + if energy < old_energy then + progress = progress + 1 + if progress >= 5 then + progress = 0 + step = step / cooling_factor + end + else + progress = 0 + step = cooling_factor * step + end + return step, progress +end + + +-- done + +return SpringHu2006 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua new file mode 100644 index 0000000000..e3ac58d571 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua @@ -0,0 +1,36 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Spring Layouts} +-- +-- @end + + + +--- + +declare { + key = "spring layout", + use = { + { key = "spring Hu 2006 layout" }, + }, + + summary = [[" + This key selects Hu's 2006 spring layout with appropriate settings + for some parameters. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua new file mode 100644 index 0000000000..2450bba2a2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua @@ -0,0 +1,124 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +local SpringElectricNoCoarsenClass = {} + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local ForceController = require "pgf.gd.force.jedi.base.ForceController" +local ForceCanvasDistance = require "pgf.gd.force.jedi.forcetypes.ForceCanvasDistance" +local ForceGraphDistance = require "pgf.gd.force.jedi.forcetypes.ForceGraphDistance" +local Storage = require "pgf.gd.lib.Storage" + +--- +declare { + key = "spring electric no coarsen layout", + algorithm = SpringElectricNoCoarsenClass, + preconditions = { connected = true }, + postconditions = {fixed = true}, + + summary = [[ + This layout uses the algorithm proposed by Fruchterman and Reingold to draw graphs." + ]], + + documentation = [[ + The Fruchterman-Reingold algorithm is one if the oldest methods + for force-based graph drawing. It is described in: + % + \begin{itemize} + \item + Thomas M.~J.~ Fruchterman and Edward M.~ Reingold, + \newblock Graph Drawing by Force-directed Placement, + \newblock \emph{Software -- practice and experience,} + 21(1 1), 1129-1164, 1991. + \end{itemize} + % + Fruchterman and Reingold had to principles in graph drawing: + % + \begin{enumerate} + \item Vertices connected by an edge should be drawn close to another and + \item in general, vertices should not be drawn too close to each other. + \end{itemize} + % + The spring electric no coarsen layout uses spring forces as attractive + forces influencing vertex pairs connected by an edge and electric forces + as repulsive forces between all vertex pairs. The original algorithm + also contained a frame that stopped the vertices from drifting too far + apart, but this concept was not implemented. This algorithm will not be + affected by coarsening. This layout was implemented by using the Jedi + framework. + ]], + + example = + [[ + \tikz + \graph[spring electric no coarsen layout, speed = 0.35, node distance = 2.5cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = true, maximum step = 1]{ + a -- {b, c, d, e, f, g, h, i, j}, + b -- {c, d, e, f, g, h, i, j}, + c -- {d, e, f, g, h, i, j}, + d -- {e, f, g, h, i, j}, + e -- {f, g, h, i, j}, + f -- {g, h, i, j}, + g -- {h, i, j}, + h -- {i, j}, + i -- j + }; + ]], + + example = + [[ + \graph[spring electric no coarsen layout, speed = 0.25, node distance = 0.25cm, horizontal = c to l, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = false, maximum step = 1]{ + a -> b -> c -> {d1 -> e -> f -> g -> h -> i -> {j1 -> e, j2 -> l}, d2 -> l -> m}, m -> a + }; + ]] +} + + + + +-- Implementation starts here + +--define a local time function +local time_fun_1 +function time_fun_1 (t_total, t_now) + if t_now/t_total <= 0.5 then + return 0.5 + else + return 2 + end +end + +-- define storage table to add attributes if wanted +local fw_attributes = Storage.newTableStorage() + +function SpringElectricNoCoarsenClass:run() + -- add options to storage table + fw_attributes.options = self.ugraph.options + + --Generate new force class + local spring_electric_no_coarsen = ForceController.new(self.ugraph) + + spring_electric_no_coarsen:addForce{ + force_type = ForceCanvasDistance, + fun_u = function (data) return data.k*data.k/(data.d) end, + time_fun = time_fun_1, + epoch = {"after expand"} + } + spring_electric_no_coarsen:addForce{ + force_type = ForceGraphDistance, + fun_u = function (data) return -data.d*data.d/(data.k) end, + n = 1, + epoch = {"after expand"} + } + + -- run algorithm + spring_electric_no_coarsen:run() +end + +return SpringElectricNoCoarsenClass \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua new file mode 100644 index 0000000000..57cd1547b6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua @@ -0,0 +1,95 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +local HuClass = {} + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local ForceController = require "pgf.gd.force.jedi.base.ForceController" +local ForceCanvasDistance = require "pgf.gd.force.jedi.forcetypes.ForceCanvasDistance" +local ForceGraphDistance = require "pgf.gd.force.jedi.forcetypes.ForceGraphDistance" + +--- +declare { + key = "jedi spring electric layout", + algorithm = HuClass, + documentation_in = "documentation_hu_layout", + preconditions = { connected = true }, + postconditions = {fixed = true}, + + summary = "This layout uses the spring electric algorithm proposed by Hu to draw graphs.", + + documentation = [[ + The spring electric algorithm by Hu uses two kinds of forces and coarsening. + It is described in: + % + \begin{itemize} + \item + Yifan Hu, + \newblock Efficient, high quality force-directed graph drawing, + \newblock \emph{The Mathematica Journal,} + 10(1), 37--71, 2006. + \end{itemize} + % + This algorithm uses spring forces as attractive forces between vertices + connected by an edge and electric forces as repulsive forces between + all vertex pairs. Hu introduces coarsening, a procedure which repeatedly + merges vertices in order to obtain a smaller version of the graph, to + overcome local minima. He also uses the Barnes-Hut algorithm to enhance + the runtime of his algorithms. This algorithm is not used in this + implementation. This layout was implemented by using the Jedi framework. + ]], + + example = + [[ + \tikz + \graph[spring electric fw layout, speed = 0.35, node distance = 5cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, maximum displacement per step = 10]{ + a -- {b, c, d, e}, + b -- {c, d, e}, + c -- {d, e}, + d --e + }; + ]], + + example = + [[ + \tikz + \graph[spring electric fw layout, speed = 0.35, node distance = 1cm, horizontal = c to l, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, maximum displacement per step = 10]{ + a -> b -> c -> {d1 -> e -> f -> g -> h -> i -> {j1 -> e, j2 -> l}, d2 -> l -> m}, m -> a + }; + ]] +} + + + + +-- Implementation starts here: + +function HuClass:run() + -- Generate new force class + local hu = ForceController.new(self.ugraph) + + -- add all required forces + hu:addForce{ + force_type = ForceCanvasDistance, + fun_u = function (data) return (data.k*data.k)/data.d end, + epoch = {"during expand", "after expand"} + } + hu:addForce{ + force_type = ForceGraphDistance, + fun_u = function (data) return -(data.d*data.d)/data.k end, + n = 1, + epoch = {"during expand", "after expand"} + } + + -- run algorithm + hu:run() +end + +return HuClass \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua new file mode 100644 index 0000000000..4dbae2b1f4 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua @@ -0,0 +1,74 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +local SimpleSpringClass = {} + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local ForceController = require 'pgf.gd.force.jedi.base.ForceController' +local ForceGraphDistance = require "pgf.gd.force.jedi.forcetypes.ForceGraphDistance" + +--- +declare { + key = "trivial spring layout", + algorithm = SimpleSpringClass, + documentation_in = "pgf.gd.doc.jedi.algorithms.SimpleSpringLayout", + preconditions = { connected = true }, + postconditions = {fixed = true}, + + summary = "This layout uses only spring forces to draw graphs.", + + documentation = [[ + The simple spring algorithm only uses one force kind: A spring force + that serves as both attractive and repulsive force. The edges are modeled as + springs and act according to Hoke's law: They have an ideal length and will + expand if they are contracted below this length, pushing the adjacent + vertices away from each other, and contract if it is stretched, pulling the + adjacent vertices towards each other. This ideal length is given by the + parameter |node distance|. There is no force repelling vertices that are not + connected to each other, which can lead to vertices being placed at the same + point. It is not a very powerful layout and will probably fail with large + graphs, especially if they have few edges. It can however be used to + demonstrate the effect of spring forces. This layout was implemented by using + the Jedi framework. + ]], + + example = [[ + \tikz + \graph[simple spring layout, node distance = 3cm, speed = 2, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = true, maximum step = 1]{ + a -- {b, c, d, e}, + b -- {c, d, e}, + c -- {d, e}, + d --e + }; + ]] +} + + + + +-- Implementation starts here: + +function SimpleSpringClass:run() + --Generate new force class + simple_spring = ForceController.new(self.ugraph) + + --add all required forces + simple_spring:addForce{ + force_type = ForceGraphDistance, + fun_u = function (data) return data.k*(data.k-data.d) end, + n = 1, + epoch = {"after expand", "during expand"} + } + + -- run algorithm + simple_spring:run() +end + +return SimpleSpringClass \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua new file mode 100644 index 0000000000..1c8a1bb8d9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua @@ -0,0 +1,129 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +local SocialClass = {} + +--Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local ForceController = require 'pgf.gd.force.jedi.base.ForceController' +local ForceCanvasDistance = require "pgf.gd.force.jedi.forcetypes.ForceCanvasDistance" +local ForceCanvasPosition = require "pgf.gd.force.jedi.forcetypes.ForceCanvasPosition" +local ForceGraphDistance = require "pgf.gd.force.jedi.forcetypes.ForceGraphDistance" +local PathLengthsFW = require "pgf.gd.force.jedi.base.PathLengthsFW" +local Storage = require "pgf.gd.lib.Storage" + +--- +declare { + key = "social closeness layout", + algorithm = SocialClass, + postconditions = {fixed = true}, + + summary = [[ + This layout uses the social gravity algorithm proposed by Bannister + with closeness mass to draw graphs. + ]], + + documentation = [[ + Bannister et all described a social gravity algorithm that can be + implemented with different kinds of gravity. + It is described in: + % + \begin{itemize} + \item Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich + and Lowell Trott, + \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, + \newblock \emph{CoRR,} + abs/1209.0748, 2012. + \end{itemize} + % + This implementation uses the closeness mass to determine the gravity of each + vertex. There are three forces in this algorithm: A spring force as + attractive force between vertices connected by an edge, an electric force as + repulsive force between all vertex pairs, and a gravitational force pulling + all vertices closer to their midpoint. The gravitational force depends on + the social mass of a vertex, which can be determined in different ways. This + algorithm uses the closeness mass. The closeness of a vertex $u$ is the + reciprocal of the sum of the shortest path from $u$ to every other vertex + $v$. The gravitational force leads to more "important" vertices ending up + closer to the middle of the drawing, since the social mass of a vertex is + proportional to its importance. The social layouts work especially well on + unconnected graphs like forests. This layout was implemented by using the + Jedi framework. + ]], + + example = [[ + \tikz + \graph[social closeness layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ + a -- a1 -- a2 -- a, + b -- b1 -- b2 -- b, + c -- c1 -- c2 -- c, + d -- d1 -- d2 -- d, + e -- e1 -- e2 -- e, + f -- f1 -- f2 -- f, + g -- g1 -- g2 -- g, + h -- h1 -- h2 -- h, + i -- i1 -- i2 -- i, + j -- j1 -- j2 -- j, + a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a + }; + ]], + + example = [[ + \tikz + \graph[social closeness layout, speed = 0.35, node distance = 0.7cm, maximum step = 5, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 2]{ + a -- {a1 -- a2, a3}, + b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, + c -- {c1--c2}, + d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} + }; + ]] +} + +local fw_attributes = Storage.newTableStorage() + +function SocialClass:run() + local dist = PathLengthsFW:breadthFirstSearch(self.ugraph) + local tmp + for vertex, n in pairs(dist) do + tmp = fw_attributes[vertex] + local sum = 0 + for i, w in pairs(n) do + sum = sum + w + end + sum = sum / # self.ugraph.vertices + tmp.mass = 1/sum + end + + fw_attributes.options = self.ugraph.options + + --Generate new force class + social_gravity = ForceController.new(self.ugraph, fw_attributes) + + --add all required forces + social_gravity:addForce{ + force_type = ForceCanvasDistance, + fun_u = function (data) return data.k/(data.d*data.d) end, + epoch = {"after expand", "during expand"} + } + social_gravity:addForce{ + force_type = ForceCanvasPosition, + fun_u = function (data) return data.attributes[data.u].mass*data.attributes.options.gravity end, + epoch = {"after expand", "during expand"} + } + social_gravity:addForce{ + force_type = ForceGraphDistance, + fun_u = function (data) return -data.d/(data.k*data.k) end, + n = 1, + epoch = {"after expand", "during expand"} + } + + social_gravity:run() +end + +return SocialClass diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua new file mode 100644 index 0000000000..6408349107 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua @@ -0,0 +1,183 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local ForceController = require 'pgf.gd.force.jedi.base.ForceController' +local ForceCanvasDistance = require "pgf.gd.force.jedi.forcetypes.ForceCanvasDistance" +local ForceCanvasPosition = require "pgf.gd.force.jedi.forcetypes.ForceCanvasPosition" +local ForceGraphDistance = require "pgf.gd.force.jedi.forcetypes.ForceGraphDistance" +local Storage = require "pgf.gd.lib.Storage" + +local SocialClass = {} + +--- +declare { + key = "social degree layout", + algorithm = SocialClass, + postconditions = {fixed = true}, + + summary = [[ + This layout uses the social gravity algorithm proposed by Bannister + with closeness mass to draw graphs.]], + + documentation = [[ + Bannister et all described a social gravity algorithm that can be + implemented with different kinds of gravity. + It is described in: + % + \begin{itemize} + \item + Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich and + Lowell Trott, + \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, + \newblock \emph{CoRR,} abs/1209.0748, 2012. + \end{itemize} + % + This implementation uses the degree mass to determine the gravity of each + vertex. There are three forces in this algorithm: A spring force as + attractive force between vertices connected by an edge, an electric force as + repulsive force between all vertex pairs, and a gravitational force pulling + all vertices closer to their midpoint. The gravitational force depends on + the social mass of a vertex, which can be determined in different ways. This + algorithm uses the degree of each vertex as its mass. The gravitational + force leads to more "important" vertices ending up closer to the middle of + the drawing, since the social mass of a vertex is proportional to its + importance. The social layouts work especially well on unconnected graphs + like forests. This layout was implemented by using the Jedi framework. + ]], + + example = + [[ + \tikz + \graph[social degree layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ + a -- a1 -- a2 -- a, + b -- b1 -- b2 -- b, + c -- c1 -- c2 -- c, + d -- d1 -- d2 -- d, + e -- e1 -- e2 -- e, + f -- f1 -- f2 -- f, + g -- g1 -- g2 -- g, + h -- h1 -- h2 -- h, + i -- i1 -- i2 -- i, + j -- j1 -- j2 -- j, + a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a + }; + ]], + + example = + [[ + \tikz + \graph[social degree layout, speed = 0.35, node distance = 0.7cm, maximum step = 15, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 0.2]{ + a -- {a1 -- a2, a3}, + b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, + c -- {c1--c2}, + d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} + }; + ]] +} + +--- +declare { + key = "gravity", + type = "number", + initial = 0.2, + + summary = "The gravity key describes the magnitude of the gravitational force.", + + documentation = [[ + This parameter currently only affects the \lstinline{social degree layout} + and the \lstinline{social closeness layout}. The gravity key determines the + strength used to pull the vertices to the center of the canvas. + ]], + + example = + [[ + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, maximum step = 10]{ + a1[weight = 2] -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; + ]], + + example = [[ + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, gravity = 0.5, maximum step = 10]{ + a1 -- {a2 [mass = 2], a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; + ]] +} + + + + +-- Implementation starts here: + +-- define time functions +local time_fun_1, time_fun_2, time_fun_3 + +function time_fun_1 (t_total, t_now) + if t_now > 3*t_total/4 then + return t_now/t_total + end + return 0 +end + +function time_fun_3 (t_total, t_now) + if t_now >= t_total/2 then + return 2 + else + return 1 + end +end + +-- define table to store variables if needed +local fw_attributes = Storage.newTableStorage() + +function SocialClass:run() + --initialize masses + local tmp + for _, vertex in ipairs(self.ugraph.vertices) do + tmp = fw_attributes[vertex] + tmp.social_mass = #self.ugraph:incoming(vertex) + end + + -- add options to storage table + fw_attributes.options = self.ugraph.options + + -- generate new force class + local social_gravity = ForceController.new(self.ugraph, fw_attributes) + + -- add all required forces + social_gravity:addForce{ + force_type = ForceCanvasDistance, + fun_u = function (data) return 4*data.k/(data.d*data.d) end, + time_fun = time_fun_2, + epoch = {"after expand", "during expand"} + } + social_gravity:addForce{ + force_type = ForceCanvasPosition, + fun_u = function (data) return data.attributes[data.u].social_mass*data.attributes.options.gravity end, + time_fun = time_fun_1, + epoch = {"after expand", "during expand"} + } + social_gravity:addForce{ + force_type = ForceGraphDistance, + fun_u = function (data) return -data.d/(data.k*data.k) end, + n = 1, + time_fun = time_fun_3, + epoch = {"after expand", "during expand"} + } + + -- run algorithm + social_gravity:run() +end + +return SocialClass \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua new file mode 100644 index 0000000000..0487214654 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua @@ -0,0 +1,264 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- A class for creating and handling "coarse" versions of a graph. Such versions contain +-- less nodes and edges than the original graph while retaining the overall +-- structure. This class offers functions to create coarse graphs and to expand them +-- to regain their original size. + +-- Imports +local Digraph = require "pgf.gd.model.Digraph" +local Vertex = require "pgf.gd.model.Vertex" +local Arc = require "pgf.gd.model.Arc" + +local lib = require "pgf.gd.lib" + +local CoarseGraph = Digraph.new() +CoarseGraph.__index = CoarseGraph + +--- Creates a new coarse graph derived from an existing graph. +-- +-- Generates a coarse graph for the input |Digraph|. +-- +-- Coarsening describes the process of reducing the amount of vertices in a graph +-- by merging vertices into pseudo-vertices. There are different strategies, +-- to decide which vertices should be merged, like merging vertices that belong to edges in a +-- maximal independent edge set or by creating pseudo-vertices based on a maximal +-- independent node set. Those strategies are called +-- schemes. +-- +-- Coarsening is not performed automatically. The function |CoarseGraph:coarsen| +-- can be used to further coarsen the graph, or the function |CoarseGraph:uncoarsen| +-- can be used to restore the previous state. +-- +-- Note, however, that the input \meta{graph} is always modified in-place, so +-- if the original version of \meta{graph} is needed in parallel to its +-- coarse representations, a deep copy of \meta{graph} needs to be passed over +-- to |CoarseGraph.new|. +-- +-- @param graph An existing graph that needs to be coarsened. +-- @param fw_attributes The user defined attributes, possibly attached to vertices. + +function CoarseGraph.new(ugraph, fw_attributes) + local coarse_graph = { + ugraph = ugraph, + level = 0, + scheme = CoarseGraph.coarsen_independent_edges, + ratio = 0, + fw_attributes = fw_attributes, + collapsed_vertices = {} + } + setmetatable(coarse_graph, CoarseGraph) + return coarse_graph +end + +-- locals for performance +local find_maximal_matching, arc_function + +-- This function performs one coarsening step: It finds all independent vertex +-- set according to |scheme|, coarsens them and adds the newly created +-- vertices to the collapsed_vertices table, associating them with the current +-- level. +function CoarseGraph:coarsen() + -- update the level + self.level = self.level + 1 + + local vertices = self.ugraph.vertices + local old_graph_size = #vertices + local c = {} + local fw_attributes = self.fw_attributes + local ugraph = self.ugraph + + if self.scheme == CoarseGraph.coarsen_independent_edges then + local matching = find_matching(ugraph) + local collapse_vertex + + for _,arc in ipairs(matching) do + -- get the two nodes of the edge that we are about to collapse + local a_h = arc.head + local a_t = arc.tail + local collapse_vertices = {a_h, a_t} + collapse_vertex = Vertex.new {weight = 0, mass = 0} + + ugraph:collapse(collapse_vertices, + collapse_vertex, + function (a,b) + a.weight = a.weight + b.weight + a.mass = a.mass + b.mass + if fw_attributes then + for key,value in pairs(fw_attributes[b]) do + if fw_attributes.functions[key] then + fw_attributes.functions[key](a,b) + elseif type(value) == "number" then + local tmp = fw_attributes[a] + if not tmp[key] then + tmp[key] = 0 + end + tmp[key] = tmp[key] + value + end + end + end + end, + function (a,b) + if a.weight == nil then + a.weight = b.weight + else + a.weight = a.weight + b.weight + end + end) + + local c_v_p = collapse_vertex.pos + local a_h_p = a_h.pos + local a_t_p = a_t.pos + c_v_p.x = (a_h_p.x + a_t_p.x)/2 + c_v_p.y = (a_h_p.y + a_t_p.y)/2 + + c[#c+1] = collapse_vertex + ugraph:remove{a_h, a_t} + end + + -- Enter all collapsed vertices into a table to uncoarsen one level at a time + self.collapsed_vertices[self.level] = c + else + assert(false, 'schemes other than CoarseGraph.coarsen_independent_edges are not implemented yet') + end + -- calculate the number of nodes ratio compared to the previous graph + self.ratio = #vertices / old_graph_size +end + +-- This function expands all vertices associated with the current level, then +-- updates the level. +function CoarseGraph:uncoarsen() + local a = self.collapsed_vertices[self.level] + local ugraph = self.ugraph + local random = lib.random + local randomseed = lib.randomseed + + for j=#a,1,-1 do + randomseed(42) + local to_expand = a[j] + + ugraph:expand(to_expand, function(a,b) + b.pos.x = a.pos.x + random()*10 + b.pos.y = a.pos.y + random()*10 + end) + ugraph:remove{to_expand} + ugraph:sync() + end + + self.level = self.level - 1 +end + +-- Getters +function CoarseGraph:getSize() + return #self.ugraph.vertices +end + + +function CoarseGraph:getRatio() + return self.ratio +end + + +function CoarseGraph:getLevel() + return self.level +end + + +function CoarseGraph:getGraph() + return self.ugraph +end + +-- Private helper function to determine whether the second vertex in the +-- current arc has been matched already +-- +-- @param arc The arc in question +-- @param vertex One of the arc's endpoints, either head or tail +-- @param matched_vertices The table holding all matched vertices +-- +-- @return The arc if the other endpoint has not been matched yet +function arc_function (arc, vertex, matched_vertices) + local x + if arc.head ~= vertex then + x = arc.head + else + x = arc.tail + end + if not matched_vertices[x] then + return arc + end +end + +-- The function finding a maximum matching of independent arcs. +-- +-- @param ugraph The current graph +-- +-- @return A table of arcs which are in the matching +function find_matching(ugraph) + local matching = {} + local matched_vertices = {} + local unmatched_vertices = {} + local vertices = ugraph.vertices + + -- iterate over nodes in random order + for _,j in ipairs(lib.random_permutation(#vertices)) do + local vertex = vertices[j] + -- ignore nodes that have already been matched + if not matched_vertices[vertex] then + local arcs = {} + local all_arcs = {} + for _,v in pairs(ugraph:incoming(vertex)) do all_arcs[#all_arcs+1] = v end + for _,v in pairs(ugraph:outgoing(vertex)) do all_arcs[#all_arcs+1] = v end + -- mark the node as matched + matched_vertices[vertex] = true + + for _, a in ipairs(all_arcs) do + arcs[#arcs +1] = arc_function(a, vertex, matched_vertices) + end + + if #arcs > 0 then + -- sort edges by the weights of the adjacent vertices + table.sort(arcs, function (a, b) + local x, y + if a.head == vertex then + x = a.tail + else + x = a.head + end + if b.head == vertex then + y = b.tail + else + y = b.head + end + return x.weight < y.weight + end) + + -- match the node against the neighbor with minimum weight + matched_vertices[arcs[1].head] = true + matched_vertices[arcs[1].tail] = true + table.insert(matching, arcs[1]) + end + end + end + + -- generate a list of nodes that were not matched at all + for _,j in ipairs(lib.random_permutation(#vertices)) do + local vertex = vertices[j] + if not matched_vertices[vertex] then + table.insert(unmatched_vertices, vertex) + end + end + return matching +end + + +-- done + +return CoarseGraph diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua new file mode 100644 index 0000000000..ab30ada5b3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua @@ -0,0 +1,489 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This class is the most basic class for the Jedi framework. It manages the +-- forces, epochs, options and streamlines the graph drawing process. +-- In detail, the force template will do the following: +-- % +-- \begin{itemize} +-- \item Hold the table with all epochs currently defined, and provide +-- a function to add new ones +-- \item Hold the table associating forces with the epochs, and provide a +-- function to add new ones +-- \item Define all the non-algorithm-specific options provided by Jedi +-- \item Assert user options to catch exceptions +-- \item Save user options and library functions to local variables to enhance +-- runtime. +-- \item Add any forces that are indicated by set options +-- \item Find and call the initial positioning algorithm requested +-- \item Determine if coarsening is enabled, and manage coarsening process if so +-- \item Call the preprocessing function of each force to obtain a vertex list the +-- force will be applied to +-- \item Calculate the forces affecting each vertex. +-- \item Move the vertices, check for equilibria/used up iterations, update +-- virtual time +-- \end{itemize} + +local ForceController = {} +ForceController.__index = ForceController + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local Coordinate = require "pgf.gd.model.Coordinate" +local CoarseGraph = require 'pgf.gd.force.jedi.base.CoarseGraphFW' +local PriorityQueue = require "pgf.gd.lib.PriorityQueue" +local ForcePullToPoint = require "pgf.gd.force.jedi.forcetypes.ForcePullToPoint" +local ForcePullToGrid = require "pgf.gd.force.jedi.forcetypes.ForcePullToGrid" + +local epochs = { + [1] = "preprocessing", + [2] = "initial layout", + [3] = "start coarsening process", + [4] = "before coarsen", + [5] = "start coarsen", + [6] = "during coarsen", + [7] = "end coarsen", + [8] = "before expand", + [9] = "start expand", + [10] = "during expand", + [11] = "end expand", + [12] = "end coarsening process", + [13] = "after expand", + [14] = "postprocessing" +} + +-- Automatic parameter generation for epoch-variables +for _,e in ipairs(epochs) do + --- + declare { + key = "iterations " .. e, + type = "number" + } + + --- + declare { + key = "maximum displacement per step " .. e, + type = "number" + } + + --- + declare { + key = "global speed factor " .. e, + type = "length" + } + + --- + declare { + key = "maximum time " .. e, + type = "number" + } + + --- + declare { + key = "find equilibrium ".. e, + type = "boolean" + } + + --- + declare { + key = "equilibrium threshold ".. e, + type = "number" + } +end + +-- Implementation starts here + +--- Function allowing user to add an at the specified position +-- +-- @params epoch A string that names the epoch +-- @params position The position in the epoch array at which the epoch should be inserted + +function ForceController:addEpoch(epoch, position) + table.insert(epochs, position, epoch) +end + +--- Function allowing the user to find an epoch's position in the epoch table +-- +-- @params epoch The epoch who's position we are trying to find +-- +-- @return An integer value matching the epch's index, or $-1$ if epoch was not found + +function ForceController:findEpoch(epoch) + for j, e in ipairs(epochs) do + if e == epoch then + return j + end + end + return -1 +end + + +-- locals for performance +local net_forces = {} +local sqrt = math.sqrt +local abs = math.abs +local sum_up, options, move_vertices, get_net_force, preprocessing, epoch_forces + +--- Creating a new force algorithm +-- @params ugraph The ugraph object the graph drawing algorithm will run on +-- @params fw_attributes The storage object holding the additional attributes defined by +-- the engineer +-- +-- @returns A new instance of force template +function ForceController.new(ugraph, fw_attributes) + return setmetatable( + {epoch_forces = {}, + ugraph = ugraph, + fw_attributes = fw_attributes, + pull_to_point = false, + }, ForceController) +end + +--- Running the force algorithm + +function ForceController:run() + -- locals for performance + local ugraph = self.ugraph + local coarse_graph = CoarseGraph.new(ugraph, self.fw_attributes) + local vertices_initalized = false + options = ugraph.options + epoch_forces = self.epoch_forces + local minimum_graph_size = options["minimum coarsening size"] + local vertices = ugraph.vertices + local arcs = ugraph.arcs + local downsize_ratio = options["downsize ratio"] + local natural_spring_length = options["node distance"] + local snap_to_grid = options["snap to grid"] + local coarsen = options["coarsen"] + + -- Assert user input + assert(minimum_graph_size >= 2, 'the minimum coarsening size of coarse graphs (value: ' .. minimum_graph_size .. ') needs to be greater than or equal to 2') + assert(downsize_ratio >= 0 and downsize_ratio <=1, 'the downsize ratio of the coarse graphs (value: ' .. downsize_ratio .. ') needs to be greater than or equal to 0 and smaller than or equal to 1') + assert(natural_spring_length >= 0, 'the node distance (value: ' .. natural_spring_length .. ') needs to be greater than or equal to 0') + + -- initialize vertex and arc weights + for _,vertex in ipairs(vertices) do + vertex.weight = vertex.options["coarsening weight"] + vertex.mass = vertex.options.mass + end + + for _,arc in ipairs(arcs) do + arc.weight = 1 + end + + -- Initialize epoch_forces table entries as empty tables + for _, e in ipairs(epochs) do + if not self.epoch_forces[e] then + self.epoch_forces[e] = {} + end + end + + -- Find initial positioning algorithm + local initial_positioning_class = options.algorithm_phases['initial positioning force framework'] -- initial_types[self.initial_layout] + + -- If snap to grid option is set and no force was added yet, add an extra + -- force to post-processing + if snap_to_grid then + self:addForce{ + force_type = ForcePullToGrid, + cap = 1, + time_fun = function() return 40 end, + epoch = {"postprocessing"} + } + options["iterations postprocessing"] = options["iterations postprocessing"] or 200 + options["maximum time postprocessing"] = options["maximum time postprocessing"] or 200 + options["find equilibrium postprocessing"] = options["find equilibrium postprocessing"] or true + options["equilibrium threshold postprocessing"] = options["equilibrium threshold postprocessing"] or 1 + options["maximum displacement per step postprocessing"] = options["maximum displacement per step postprocessing"] or 1 + options["global speed factor postprocessing"] = options["global speed factor postprocessing"] or 1 + end + + -- Find marker epochs + local start_coarsening = self:findEpoch("start coarsening process") + local end_coarsening = self:findEpoch("end coarsening process") + local start_coarsen = self:findEpoch("start coarsen") + local end_coarsen = self:findEpoch("end coarsen") + local start_expand = self:findEpoch("start expand") + local end_expand = self:findEpoch("end expand") + + + -- iterate over epoch table + local i = 1 + while i <= #epochs do + local e = epochs[i] + + local iterations = options["iterations "..e] or options["iterations"] + -- assert input + assert(iterations >= 0, 'iterations (value: ' .. iterations .. ') needs to be greater than 0') + + -- Check for desired vertices and collect them in a table if any are found + local desired = false + local desired_vertices = {} + -- initialize node weights + for _,vertex in ipairs(vertices) do + if vertex.options then + if vertex.options["desired at"] then + desired = true + desired_vertices[vertex] = vertex.options["desired at"] + end + end + end + + -- Add pull to point force if desired vertices were found and engineer did not add + -- this force + if desired and not self.pull_to_point then + self:addForce{ + force_type = ForcePullToPoint, + time_fun = function(t_now, t_max) return 5 end + } + end + + -- initialize the coarse graph data structure. + if coarsen then + -- vertices = coarse_graph.ugraph.vertices + -- arcs = coarse_graph.ugraph.arcs + if i >= start_coarsening and i < end_coarsening then + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by + -- at least the downsize ratio configured by the user + if i >= start_coarsen and i < start_expand then + if coarse_graph:getSize() > minimum_graph_size and coarse_graph:getRatio() <= (1 - downsize_ratio) then + if i == start_coarsen then + coarse_graph:coarsen() + elseif i < end_coarsen then + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) + move_vertices(coarse_graph.ugraph.vertices, e) + else + i = start_coarsen - 1 + end + end + end + + -- between coarsening and expanding + if (i > end_coarsen) and (i < start_expand) then + -- use the natural spring length as the initial natural spring length + local spring_length = natural_spring_length + + if not vertices_initalized then + initial_positioning_class.new { vertices = coarse_graph.ugraph.vertices, + options = options, + desired_vertices = desired_vertices + }:run() + vertices_initalized = true + end + + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) + + -- set the spring length to the average arc length of the initial layout + local spring_length = 0 + for _,arc in ipairs(arcs) do + local x = abs(arc.head.pos.x - arc.tail.pos.x) + local y = abs(arc.head.pos.y - arc.tail.pos.y) + spring_length = spring_length + sqrt(x * x + y * y) + end + spring_length = spring_length / #arcs + + -- additionally improve the layout with the force-based algorithm + -- if there are more than two nodes in the coarsest graph + if coarse_graph:getSize() > 2 and end_coarsen and not start_expand then + move_vertices(coarse_graph.ugraph.vertices, e) + end + end + + -- undo coarsening step by step, applying the force-based sub-algorithm + -- to every intermediate coarse graph as well as the original graph + if i >= start_expand then + if coarse_graph:getLevel() > 0 then + if i == start_expand then + coarse_graph:uncoarsen() + elseif i < end_expand then + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) + move_vertices(coarse_graph.ugraph.vertices, e) + else + i = start_expand - 1 + end + else + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) + move_vertices(coarse_graph.ugraph.vertices, e) + end + end + -- Before and after the coarsening process + elseif i < start_coarsening or i > end_coarsening then + if not vertices_initalized then + initial_positioning_class.new { + vertices = coarse_graph.ugraph.vertices, + options = options, + desired_vertices = desired_vertices }:run() + vertices_initalized = true + end + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) + move_vertices(coarse_graph.ugraph.vertices, e) + end + else + -- Same without coarsen + if i < start_coarsening or i > end_coarsening then + if not vertices_initalized then + initial_positioning_class.new { + vertices = vertices, + options = options, + desired_vertices = desired_vertices }:run() + vertices_initalized = true + end + preprocessing(vertices, arcs, e, ugraph) + move_vertices(vertices, e, self.ugraph) + end + end + i = i + 1 + end +end + + +--- Preprocessing for all force types in force configuration +-- +-- @params v The vertices of the current graph +-- @params a The arcs of the current graph +-- @params epoch The preprocessing algorithm will only be applied to the forces +-- associated with this epoch. +-- @params ugraph The current graph object + +function preprocessing(v, a, epoch, ugraph) + for _, fc in ipairs(epoch_forces[epoch]) do + fc:preprocess(v, a, ugraph) + end +end + + +--- Adding forces to the algorithm. +-- +-- @params force_data A table containing force type, time function, force function, +-- capping thresholds and the epochs in which this force will be active + +function ForceController:addForce(force_data) + local t = force_data.force_type + if t == ForcePullToPoint then + self.pull_to_point = true + end + + local f = t.new {force = force_data, options = self.ugraph.options, fw_attributes = self.fw_attributes or {}} + if force_data.epoch == nil then + force_data.epoch = {} + end + for _,e in ipairs(force_data.epoch) do + local tab = self.epoch_forces[e] + if not tab then + tab = {} + end + tab[#tab +1] = f + self.epoch_forces[e] = tab + end +end + + +--- Moving vertices according to force functions until the maximum number of +-- iterations is reached +-- +-- @params vertices The vertices in the current graph +-- @params epoch The current epoch, to find the forces that are active + +function move_vertices(vertices, epoch, g) + if #epoch_forces[epoch] == 0 then + return + end + local iterations = options["iterations ".. epoch] or options["iterations"] + local find_equilibrium = options["find equilibrium ".. epoch] or options["find equilibrium"] + local epsilon = options["equilibrium threshold ".. epoch] or options["equilibrium threshold"] + local speed = options["global speed factor ".. epoch] or options["global speed factor"] + local max_step = options["maximum displacement per step ".. epoch] or options["maximum displacement per step"] + + assert(epsilon >= 0, 'the threshold for finding an equilibirum (equilibrium threshold) (value: ' .. epsilon .. ') needs to be greater than or equal to 0') + assert(speed > 0, 'the speed at which the vertices move (value: ' .. speed .. ') needs to be greater than 0') + assert(max_step > 0, 'the maximum displacement per step each vertex can move per iteration (value: ' .. max_step .. ') needs to be greater than 0') + + local max_time = options["maximum time ".. epoch] or options["maximum time"] + local d_t = max_time/iterations + local t_now = 0 + local random = lib.random + local randomseed = lib.randomseed + + for j = 1 , iterations do + t_now = t_now + d_t + net_forces = get_net_force(vertices, j, t_now, epoch) + + -- normalize the force vector if necessary + for v, c in pairs(net_forces) do + local n = sqrt(c.x*c.x+c.y*c.y) + if n > max_step then + local factor = max_step/n + c.x = c.x*factor + c.y = c.y*factor + end + end + + -- if not in equilibrium yet, apply forces + if not find_equilibrium or sum_up(net_forces)*d_t > epsilon then + local cool_down_dt = d_t + if cool_down_dt > 1 then + cool_down_dt = 1 + 1/d_t + end + for _, v in ipairs(vertices) do + local factor = 1/(v.mass or 1) + local c1 = net_forces[v] + local x = speed * cool_down_dt * c1.x * factor + local y = speed * cool_down_dt * c1.y * factor + local p = v.pos + p.x = p.x + x + p.y = p.y + y + end + else + break + end + end +end + + +-- calculate the net force for each vertex in one iteration +-- +-- @params vertices the vertices of the current graph +-- @params j The current iteration +-- @params t_now The current virtual time +-- @params epoch The current epoch +-- +-- @return A table of coordinate-objects associated with vertices. The +-- coordinate object hold the calculated net displacement for +-- the $x$ and $y$ coordinate. +function get_net_force(vertices, j, t_now, epoch) + local net_forces = {} + local natural_spring_length = options["node distance"] + + for _,v in ipairs(vertices) do + net_forces[v] = Coordinate.new(0,0) + end + + for _,force_class in ipairs(epoch_forces[epoch]) do + force_class:applyTo{net_forces = net_forces, options = options, j = j, t_now = t_now, k = natural_spring_length} + end + + return net_forces +end + +-- Helper function to sum up all calculated forces +-- +-- @params tab A table holding coordinate objects as values +-- +-- @returns The sum of the absolute $x$ and $y$ values in this table +function sum_up(tab) + local sum = 0 + for v, c in pairs(tab) do + sum = sum + abs(c.x) + abs(c.y) + end + return sum +end + +return ForceController diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua new file mode 100644 index 0000000000..29370fc029 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua @@ -0,0 +1,44 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is the parent class for forces. It provides a constructor and methods +-- stubs to be overwritten in the subclasses. + +-- Imports +local lib = require "pgf.gd.lib" + +local ForceTemplate = lib.class {} + +-- constructor +function ForceTemplate:constructor() + self.force = self.force + self.fw_attributes = self.fw_attributes + if not self.force.time_fun then + self.force.time_fun = function() return 1 end + end +end + +-- Method stub for preprocessing +-- +-- @param v The vertices the list will be build on + +function ForceTemplate:preprocess(v) +end + +-- Method stub for applying the forces +-- +-- @param data A table holding data like the table the forces are collected +-- in, the current iteration, the current time stamp, some options +-- or the natural spring length + +function ForceTemplate:applyTo(data) +end + +return ForceTemplate \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua new file mode 100644 index 0000000000..762717f64a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua @@ -0,0 +1,64 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is the parent class for initial layout algorithms. It provides a +-- constructor and methods stubs to be overwritten in the subclasses as well +-- as placing vertices which are |desired at| a certain point. + +-- Imports +local lib = require "pgf.gd.lib" + +local InitialTemplate = lib.class {} + +-- constructor +function InitialTemplate:constructor() + self.vertices = self.vertices + self.options = self.options + self.desired_vertices = self.desired_vertices +end + +-- Method placing |desired at| vertices at the point they are desired +-- +-- @params desired_vertices A table containing all the vertices where the +-- |desired at| option is set. +-- +-- @return |placed| A boolean array stating if vertices have been placed yet +-- @return |centroid_x| The x-coordinate of the midpoint of all placed vertices +-- @return |centroid_y| The y-coordinate of the midpoint of all placed vertices + +function InitialTemplate:desired(desired_vertices) + local placed = {} + + local centroid_x, centroid_y = 0, 0 + + local size = 0 + for v, da in pairs(desired_vertices) do + local p = v.pos + local x, y = da.x, da.y + p.x = x or 0 + p.y = y or 0 + centroid_x = centroid_x + x + centroid_y = centroid_y + y + placed[v] = true + size = size +1 + end + if size>0 then + centroid_x = centroid_x / size + centroid_y = centroid_y / size + end + + return placed, centroid_x, centroid_y +end + +-- Method stub for running the layout algorithm +function InitialTemplate:run() +end + +return InitialTemplate \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua new file mode 100644 index 0000000000..2d50677fa5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua @@ -0,0 +1,174 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This is a helper class providing different functions that deal with graph +-- distances. This class can be used by engineers and implementers if they +-- need to calculate anything regarding graph distances. + +local PathLengths = {} + +-- Imports +local PriorityQueue = require "pgf.gd.lib.PriorityQueue" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- This algorithm conducts a breadth first search on the graph it is given. +-- +-- @param ugraph The graph on which the search should be conducted +-- +-- @return A table holding every vertex $v$ as key and a table as value. The +-- value table holds all other vertices $u$ as keys and their shortest +-- distance to $v$ as value + +function PathLengths:breadthFirstSearch(ugraph) + local distances = {} + local vertices = ugraph.vertices + local arcs = ugraph.arcs + + for _,v in ipairs(vertices) do + distances[v] = {} + local dist = distances[v] + for _,w in ipairs(vertices) do + dist[w] = #vertices +1 + end + dist[v] = 0 + end + local n = 1 + local p = Preprocessing.overExactlyNPairs(vertices, arcs, n) + while (#p > 0) do + for _, v in ipairs(p) do + local tab = distances[v.tail] + tab[v.head] = n + end + n = n + 1 + p = Preprocessing.overExactlyNPairs(vertices, arcs, n) + end + return(distances) +end + + +-- This function performs Dijkstra's algorithm on the graph. +-- +-- @param ugraph The graph where the paths should be found +-- @param source The source vertex +-- +-- @return |distance| A table holding every vertex $v$ as key and a table as +-- value. The value table holds all other vertices $u$ as +-- keys and their shortest distance to $v$ as value +-- @return |levels| A table holding the levels of the graph as keys and a +-- table holding the vertices found on that level as values +-- @return |parent| A table holding each vertex as key and it's parent vertex +-- as value + +function PathLengths:dijkstra(ugraph, source) + local distance = {} + local levels = {} + local parent = {} + + local queue = PriorityQueue.new() + + -- reset the distance of all nodes and insert them into the priority queue + for _,v in ipairs(ugraph.vertices) do + if v == source then + distance[v] = 0 + parent[v] = nil + queue:enqueue(v, distance[v]) + else + distance[v] = #ugraph.vertices + 1 -- this is about infinity ;) + queue:enqueue(v, distance[v]) + end + end + + while not queue:isEmpty() do + local u = queue:dequeue() + + assert(distance[u] < #ugraph.vertices + 1, 'the graph is not connected, Dijkstra will not work') + + if distance[u] > 0 then + levels[distance[u]] = levels[distance[u]] or {} + table.insert(levels[distance[u]], u) + end + + + + for _,edge in ipairs(ugraph:outgoing(u)) do + local v = edge.head + local alternative = distance[u] + 1 + if alternative < distance[v] then + distance[v] = alternative + + parent[v] = u + + -- update the priority of v + queue:updatePriority(v, distance[v]) + end + end + end + + return distance, levels, parent +end + +-- This function finds the pseudo diameter of the graph, which is the longest +-- shortest path in the graph +-- +-- @param ugraph The graph who's pseudo diameter is wanted +-- +-- @ return |diameter| The pseudo diameter of the graph +-- @ return |start_node| The start node of the longest shortest path in the +-- graph +-- @ return |end_node| The end node of the longest shortest path in the graph + +function PathLengths:pseudoDiameter(ugraph) + + -- find a node with minimum degree + local start_node = ugraph.vertices[1] + for _,v in ipairs(ugraph.vertices) do + if #ugraph:incoming(v) + #ugraph:outgoing(v) < #ugraph:incoming(start_node) + #ugraph:outgoing(start_node) then + start_node = v + end + end + + assert(start_node) + + local old_diameter = 0 + local diameter = 0 + local end_node = nil + + while true do + local distance, levels = self:dijkstra(ugraph, start_node) + + -- the number of levels is the same as the distance of the nodes + -- in the last level to the start node + old_diameter = diameter + diameter = #levels + + -- abort if the diameter could not be improved + if diameter == old_diameter then + end_node = levels[#levels][1] + break + end + + -- select the node with the smallest degree from the last level as + -- the start node for the next iteration + start_node = levels[#levels][1] + for _,node in ipairs(levels[#levels]) do + if #ugraph:incoming(node)+#ugraph:outgoing(node) < #ugraph:incoming(start_node) + #ugraph:outgoing(start_node) then + start_node = node + end + end + + assert(start_node) + end + + assert(start_node) + assert(end_node) + + return diameter, start_node, end_node +end + +return PathLengths \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua new file mode 100644 index 0000000000..de59e0cb5c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua @@ -0,0 +1,122 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This file holds functions to create lists of vertex pairs. All +-- functions return a Graph object containing the vertices of the +-- original graph and an edge between the vertices forming a pair +-- under the specified conditions. The lists can be precomputed to +-- enhance performance. + +local PreprocessClass = {} + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local Digraph = require "pgf.gd.model.Digraph" + + +-- Creates a graph object with an arc between all pairwise disjoint vertex +-- pairs and returns the arc table +-- +-- @param vertices The vertices of the original graph +-- +-- @return An arc table + +function PreprocessClass.allPairs(vertices) + local aP = Digraph.new{} + for _, vertex in ipairs(vertices) do + for _, vertex2 in ipairs(vertices) do + if vertex ~= vertex2 then + if not aP:contains(vertex) then + aP:add {vertex} + end + if not aP:contains(vertex2) then + aP:add {vertex2} + end + if not aP:arc(vertex, vertex2) and not aP:arc(vertex2, vertex) then + aP:connect(vertex, vertex2) + end + end + end + end + return aP.arcs +end + + +-- Creates a graph object with an arc between all pairwise disjoint vertex +-- pairs that are connected by a shortest path of length n in the original +-- graph and returns the arc table +-- +-- @param vertices The vertices of the original graph +-- @param arcs The arcs of the original graph +-- @param n The length of the shortest path we are looking for +-- +-- @return An arc table + +function PreprocessClass.overExactlyNPairs(vertices, arcs, n) + local waste, p_full = PreprocessClass.overMaxNPairs(vertices, arcs, n) + local waste, p_small = PreprocessClass.overMaxNPairs(vertices, arcs, n-1) + for _, paar in ipairs(p_full.arcs) do + if p_small:arc(paar.head, paar.tail) ~= nil or p_small:arc(paar.tail, paar.head) ~= nil then + p_full:disconnect(paar.head, paar.tail) + p_full:disconnect(paar.tail, paar.head) + end + end + return p_full.arcs +end + + +-- Creates a graph object with an arc between all pairwise disjoint vertex +-- pairs that are connected by a shortest path of length n or shorter in the +-- original graph and returns the arc table +-- +-- @param vertices The vertices of the original graph +-- @param arcs The arcs of the original graph +-- @param n The length of the shortest path we are looking for +-- +-- @return An arc table + +function PreprocessClass.overMaxNPairs(vertices, arcs, n) + assert(n >= 0, 'n (value: ' .. n.. ') needs to be greater or equal 0') + local p = Digraph.new{} + local oneHop = Digraph.new{} + if n> 0 then + for _, arc in ipairs(arcs) do + local vertex = arc.head + local vertex2 = arc.tail + if not p:contains(vertex) then + p:add {vertex} + oneHop:add {vertex} + end + if not p:contains(vertex2) then + p:add {vertex2} + oneHop:add {vertex2} + end + if p:arc(vertex, vertex2) == nil and p:arc(vertex2, vertex) == nil then + p:connect(vertex, vertex2) + oneHop:connect(vertex, vertex2) + end + end + end + + n = n-1 + while n > 0 do + for _, paar in ipairs(p.arcs) do + for _, vertex in ipairs(vertices) do + if paar.head ~= vertex and p:arc(paar.head, vertex) == nil and p:arc(vertex, paar.head) == nil and (oneHop:arc(paar.tail, vertex) ~= nil or oneHop:arc(vertex, paar.tail) ~= nil) then + p:connect(paar.head, vertex) + end + end + end + n = n-1 + end + return p.arcs, p +end + +return PreprocessClass diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/doc.lua new file mode 100644 index 0000000000..19baca7333 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/doc.lua @@ -0,0 +1,377 @@ +-- Copyright 2014 by Ida Bruhns and Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- Imports +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "maximum step" + +summary +[[ +This option determines the maximum distance every vertex is allowed to travel +in one iteration. +]] + +documentation +[[ +No matter how large the forces influencing a vertex, the effect +on the drawing should be limited to avoid vertices "jumping" from one side of +the canvas to each other due to a strong force pulling them further than their +ideal destination. The amount of space a vertex is allowed to travel in one +iteration is limited by the \lstinline{maximum step} parameter. It is $5000$ +by default. That means by default, this parameter should not get in your way. +]] + + +example +[[ +\tikz + \graph[social degree layout, iterations = 2, maximum time = 2, maximum step = 6pt, coarsen = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 2, maximum time = 2, maximum step = 12pt, coarsen = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + + + +-------------------------------------------------------------------- +key "speed" + +summary +[[ +This is a factor every calculated step is multiplied by. +]] + +documentation +[[ +The speed is the distance a vertex travels if it is influenced by a force of +$1$N$\cdot\gamma$. The speed is only a factor that will influence the total +amount every vertex can move: Half the speed makes half the movement, twice +the speed doubles the distance traveled. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 1, maximum time = 1, maximum step = 100, speed = 0.2, coarsen = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 1, maximum time= 1, maximum step = 100, speed = 0.4, coarsen = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "maximum time" + +summary +[[ +The highest amount of virtual time the algorithm is allowed to take. +]] + +documentation +[[ +This option is part of the virtual time construct of Jedi. The virtual time +concept allows graph drawing algorithm engineers to switch forces on and of +after a relative or absolute amount of time has elapsed. If the iterations +stay the same, doubling the maximum time has the same effect as doubling the +speed: Vertices move faster, but it is possible they miss their intended +destination. Also increasing the iterations changes the "resolution" of the +graph drawing algorithm: More steps are simulated in the same time. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 20, maximum time = 100, coarsen = false, maximum step = 0.5, gravity = 2]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 20, maximum time = 200, coarsen = false, maximum step = 0.5, gravity = 2]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "find equilibrium" + +summary +[[ +If this option is |true|, the framework checks the vertex movement to detect +low movement near the equilibrium and stop the algorithm. +]] + +documentation +[[ +Since we often do not know how many iterations are enough, the framework will +detect when the vertices (almost) stop moving and stop the algorithm. After +each iteration, the framework adds up the net force influencing all the +vertices. If it falls below the threshold |epsilon|, the algorithm +will ignore the left over iterations and terminate. You can disable this +behavior by setting this parameter to |false|. Allowing the framework to find +the equilibrium usually saves you time, while allowing more iterations (or a +lower threshold) generates higher quality drawings. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 300, maximum time = 300, coarsen = false, maximum step = 10, epsilon = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 300, maximum time = 300, maximum step = 10, find equilibrium = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "epsilon" + +summary +[[ +The threshold for the |find equilibrium| option. +]] + +documentation +[[ +This key specifies the threshold for the |find equilibrium| option. The lower +epsilon, the longer the graph drawing algorithm will take, but the closer the +resulting drawing will be to the true energy minimum. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 200, maximum time = 200, maximum step = 10, coarsen = false, epsilon = 2]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 200, maximum time = 200, maximum step = 10, epsilon = 12, coarsen = false]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "snap to grid" + +summary +[[ +This option enables the post-processing step |snap to grid|. +]] + +documentation +[[ +This key is the on/off-switch for the grid forces. The |snap to grid| option +triggers a form of post-processing were all vertices are pulled to the closest +point on a virtual grid. Please note that there is no repulsive force between +the vertices, so it is possible that two vertices are pulled to the same grid +point. The grid size is determined by the parameters |grid x length| and +|grid y length|. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 100, maximum time = 100, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz{ + \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "grid x length" + +summary +[[ +This option determines the cell size in $x$ direction for the |snap to grid| +option. +]] + +documentation +[[ +The size of the cells of the virtual grid can be configured by the user. This +key allows a configuration of the horizontal cell width. +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 9mm, grid y length = 5mm, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "grid y length" + +summary +[[ +This option determines the cell size in $x$ direction for the |snap to grid| +option. +]] + +documentation +[[ +Same as |grid x length|, but in vertical direction (height of the cells). +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ +\tikz + \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 9mm, maximum step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "mass" + +summary +[[ + The mass of a vertex determines how fast it can move. Vertices + with higher mass move slower. +]] + +documentation +[[ + The mass of a vertex determines how fast this vertex + moves. Mass is directly inverse proportional to the distance the vertex + moves. In contrast to the global speed factor, mass usually only affects a + single vertex. A vertex with a higher mass will move slower if affected by + the same mass than a vertex with a lower mass. By default, each vertex has a + mass of $1$. +]] + +example +[[ + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, maximum displacement per step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; +]] + +example +[[ + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, maximum displacement per step = 10]{ + a1 -- {a2, a3, a4, a5}, + b1[mass = 4] -- {b2 -- {b3, b4}, b5} + }; +]] +-------------------------------------------------------------------- + + +-------------------------------------------------------------------- +key "coarsening weight" + +summary +[[ + The coarsening weight of a vertex determines when it will be + coarsened. +]] + +documentation +[[ + Vertices with higher coarsening weight are considered more important and + will be coarsened later, or not at all. +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua new file mode 100644 index 0000000000..4634b70123 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua @@ -0,0 +1,94 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices. Forces of this kind simply add an +-- absolute value set in the force data to each vertex' $x$ and $y$ coordinate + +-- Imports +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min + +-- Implementation starts here: + +local ForceAbsoluteValue = lib.class { base_class = ForceTemplate } + +function ForceAbsoluteValue:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + + +-- This force class works on a vertex array that is part of the force data +-- defined when adding the force. This array is copied into p. All vertices of +-- the graph are saved in the local variable |ver|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForceAbsoluteValue:preprocess(v) + self.ver = v + self.p = self.force.vertices +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForceAbsoluteValue:applyTo(data) + -- locals for speed + local cap = self.force.cap + local value = self.force.value + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local t_now = data.t_now + local p = self.p + local time_fun = self.force.time_fun + + -- Evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + for _,v in ipairs(self.ver) do + for _, i in ipairs (self.p) do + -- Is the vertex in the list? + if v.name == i then + + local f = value * time_factor + + -- cap effect if necessary + if cap then + if f <= 0 then + x = max(-cap, f) + else + x = min(cap, f) + end + end + + -- add calculated effect to net forces + local c1 = net_forces[v] + c1.x = c1.x + f + c1.y = c1.y + f + end + end + end +end + +return ForceAbsoluteValue \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua new file mode 100644 index 0000000000..8cea1aec6a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua @@ -0,0 +1,201 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is a subclass of ForceTemplate, which is used to implement forces between +-- vertex pairs. The forces depend on the canvas distance of the vertices in +-- the pair. This class is e.~g.~ used for electric forces. + +-- Imports +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min + +-- Implementation starts here: +local ForceCanvasDistance = lib.class { base_class = ForceTemplate } + +function ForceCanvasDistance:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + + +-- This force class works on all pairwise disjoint vertex pairs. This +-- function generates a new graph object containing all vertices from the +-- original graph and arcs between all pairwise disjoint vertex pairs. The +-- arcs-table of this new object will be saved in the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForceCanvasDistance:preprocess(v) + self.p = Preprocessing.allPairs(v) +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForceCanvasDistance:applyTo(data) + -- locals for speed + local cap = self.force.cap + local fun_u = self.force.fun_u + local fun_v = self.force.fun_v + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local t_now = data.t_now + local k = data.k + local p = self.p + local time_fun = self.force.time_fun + local fw_attributes = self.fw_attributes + + -- Evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + if not fun_v then + local data = { k = k, attributes = fw_attributes } + for _, i in ipairs(p) do + -- dereference + local p2 = i.head + local p1 = i.tail + local p2_pos = p2.pos + local p1_pos = p1.pos + + -- calculate distance between two points + local x = p2_pos.x - p1_pos.x + local y = p2_pos.y - p1_pos.y + local d = max(sqrt(x*x+y*y),0.1) + + -- apply force function + data.u = p2 + data.v = p1 + data.d = d + local e = fun_u(data) + + -- Include time function + local f = e * time_factor / d + + -- calculate effect on x/y + local g = x * f + local h = y * f + + -- cap effect if necessary + if cap then + if g <= 0 then + x = max(-cap, g) + else + x = min(cap, g) + end + + if h <= 0 then + y = max(-cap, h) + else + y = min(cap, h) + end + else + x = g + y = h + end + + -- add calculated effect to net forces + local c1 = net_forces[p1] + c1.x = c1.x - x + c1.y = c1.y - y + local c2 = net_forces[p2] + c2.x = c2.x + x + c2.y = c2.y + y + end + else + -- There are different functions for head and tail vertex + local data = { k = k, attributes = fw_attributes } + for _, i in ipairs(p) do + -- dereference + local p2 = i.head + local p1 = i.tail + local p2_pos = p2.pos + local p1_pos = p1.pos + + -- calculate distance between two points + local x = p2_pos.x - p1_pos.x + local y = p2_pos.y - p1_pos.y + local d = max(sqrt(x*x+y*y),0.1) + + -- apply force function to distance and k (natural spring length + data.u = p2 + data.v = p1 + data.d = d + local e_head = fun_u(data) + local e_tail = fun_v(data) + + -- Include time function + local f_head = time_factor * e_head / d + local f_tail = time_factor * e_tail / d + + -- calculate effect on x/y + local g_head = x * f_head + local g_tail = x * f_tail + local h_head = y * f_head + local h_tail = y * f_tail + + -- cap effect if necessary + local x_head, x_tail, y_head, y_tail + if cap then + if g_head <= 0 then + x_head = max(-cap, g_head) + else + x_head = min(cap, g_head) + end + + if g_tail <= 0 then + x_tail = max(-cap, g_tail) + else + x_tail = min(cap, g_tail) + end + + if h_head <= 0 then + y_head = max(-cap, h_head) + else + y_head = min(cap, h_head) + end + + if h_tail <= 0 then + y_tail = max(-cap, h_tail) + else + y_tail = min(cap, h_tail) + end + else + x_head = g_head + x_tail = g_tail + y_head = h_head + y_tail = h_tail + end + + -- add calculated effect to net forces + local c1 = net_forces[p1] + c1.x = c1.x - x_tail + c1.y = c1.y - y_tail + local c2 = net_forces[p2] + c2.x = c2.x + x_head + c2.y = c2.y + y_head + end + end +end + +return ForceCanvasDistance \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua new file mode 100644 index 0000000000..41edaba358 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua @@ -0,0 +1,117 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices. The forces depend on the canvas position +-- of the vertices. This class is e.~g.~ used for gravitational forces. + +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" + +local ForceCanvasPosition = lib.class { base_class = ForceTemplate } + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min + +-- Implementation starts here: + +function ForceCanvasPosition:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + + +-- This force class works on individual vertices and only depends on their +-- current position. Thus the vertex table of the current graph is simply +-- copied to the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForceCanvasPosition:preprocess(v) + self.p = v +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForceCanvasPosition:applyTo(data) + --localize + local cap = self.force.cap + local fun_u = self.force.fun_u + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local t_now = data.t_now + local p = self.p + local time_fun = self.force.time_fun + local initial_gravity = self.options["gravity"] + local fw_attributes = self.fw_attributes + + -- evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + -- Find midpoint of all vertices since they will be attracted to this point + local centroid_x, centroid_y = 0,0 + for _, v in ipairs(p) do + local pos = v.pos + centroid_x = centroid_x + pos.x + centroid_y = centroid_y + pos.y + end + centroid_x = centroid_x/#p + centroid_y = centroid_y/#p + + -- Iterate over the precomputed vertex list + for _, v in ipairs(p) do + -- localize + local p1 = v.pos + + -- apply force function + local factor = fun_u{attributes = fw_attributes, u = v} + + -- calculate distance between vertex and centroid + local x = centroid_x - p1.x + local y = centroid_y - p1.y + + -- calculate effect on x/y + local h = factor * time_factor + x = x * h + y = y * h + + -- cap effect if necessary + if cap then + if x <= 0 then + x = max(-cap, x) + else + x = min(cap, x) + end + if y <= 0 then + y = max(-cap, y) + else + y = min(cap, y) + end + end + + -- add calculated effect to net forces + local c = net_forces[v] + c.x = c.x + x + c.y = c.y + y + end +end + +return ForceCanvasPosition \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua new file mode 100644 index 0000000000..86d67f2678 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua @@ -0,0 +1,205 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is a subclass of ForceTemplate, which is used to implement forces between +-- vertex pairs. The forces depend on the graph distance of the vertices in +-- the pair. This class is e.\,g.\ used for spring forces. + + +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min + +-- Implementation starts here: + +local ForceGraphDistance = lib.class { base_class = ForceTemplate } + +function ForceGraphDistance:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + + +-- This force class works on all pairwise disjoint vertex pairs connected by +-- a path of length maximum $n$. The parameter $n$ is given by the engineer in +-- the force declaration. This function generates a new graph object +-- containing all vertices from the original graph and arcs between all +-- pairwise disjoint vertex pairs. The arcs-table of this new object will be +-- saved in the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForceGraphDistance:preprocess(v, a) + self.p = Preprocessing.overExactlyNPairs(v, a, self.force.n) +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForceGraphDistance:applyTo(data) + -- locals for speed + local cap = self.force.cap + local fun_u = self.force.fun_u + local fun_v = self.force.fun_v + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local t_now = data.t_now + local k = data.k + local p = self.p + local time_fun = self.force.time_fun + local fw_attributes = self.fw_attributes + + -- Evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + if not fun_v then + local data = { k = k, attributes = fw_attributes } + for _, i in ipairs(p) do + -- dereference + local p2 = i.head + local p1 = i.tail + local p2_pos = p2.pos + local p1_pos = p1.pos + + -- calculate distance between two points + local x = p2_pos.x - p1_pos.x + local y = p2_pos.y - p1_pos.y + local d = max(sqrt(x*x+y*y),0.1) + + -- apply force function to distance and k (natural spring length) + data.u = p2 + data.v = p1 + data.d = d + local e = fun_u(data) + + -- Include time function + local f = e * time_factor / d + + -- calculate effect on x/y + local g = x * f + local h = y * f + + -- cap effect if necessary + if cap then + if g <= 0 then + x = max(-cap, g) + else + x = min(cap, g) + end + + if g <= 0 then + y = max(-cap, h) + else + y = min(cap, h) + end + else + x = g + y = h + end + + -- add calculated effect to net forces + local c1 = net_forces[p1] + c1.x = c1.x - x + c1.y = c1.y - y + local c2 = net_forces[p2] + c2.x = c2.x + x + c2.y = c2.y + y + end + else + -- There are different functions for head and tail vertex + local data = { k = k, attributes = fw_attributes } + for _, i in ipairs(p) do + -- dereference + local p2 = i.head + local p1 = i.tail + local p2_pos = p2.pos + local p1_pos = p1.pos + + -- calculate distance between two points + local x = p2_pos.x - p1_pos.x + local y = p2_pos.y - p1_pos.y + + local d = max(sqrt(x*x+y*y),0.1) + + -- apply force function to distance and k (natural spring length + data.u = p2 + data.v = p1 + data.d = d + local e_head = fun_u(data) + local e_tail = fun_v(data) + + -- Include time function + local f_head = time_factor * e_head / d + local f_tail = time_factor * e_tail / d + + -- calculate effect on x/y + local g_head = x * f_head + local g_tail = x * f_tail + local h_head = y * f_head + local h_tail = y * f_tail + + -- cap effect if necessary + local x_head, x_tail, y_head, y_tail + if cap then + if g_head <= 0 then + x_head = max(-cap, g_head) + else + x_head = min(cap, g_head) + end + + if g_tail <= 0 then + x_tail = max(-cap, g_tail) + else + x_tail = min(cap, g_tail) + end + + if h_head <= 0 then + y_head = max(-cap, h_head) + else + y_head = min(cap, h_head) + end + + if h_tail <= 0 then + y_tail = max(-cap, h_tail) + else + y_tail = min(cap, h_tail) + end + else + x_head = g_head + x_tail = g_tail + y_head = h_head + y_tail = h_tail + end + + -- add calculated effect to net forces + local c1 = net_forces[p1] + c1.x = c1.x - x_tail + c1.y = c1.y - y_tail + local c2 = net_forces[p2] + c2.x = c2.x + x_head + c2.y = c2.y + y_head + end + end +end + +return ForceGraphDistance \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua new file mode 100644 index 0000000000..5f53f5da78 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua @@ -0,0 +1,123 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices and pulls them to a virtual grid with +-- cells of the size determined by the user options |grid x length| and +-- |grid y length|. The forces depend on the canvas position +-- of the vertices relative to th next grid point. This class is e.\,g.\ used +-- for the post-processing technique |snap to grid|. + + +-- Imports +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min +local floor = math.floor +local round +function round(number) + return floor((number * 10 + 0.5) / 10) +end + +-- Implementation starts here: + +local ForcePullToGrid = lib.class { base_class = ForceTemplate } + +function ForcePullToGrid:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + +-- This force class works on individual vertices and only depends on their +-- current position. Thus the vertex table of the current graph is simply +-- copied to the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForcePullToGrid:preprocess(v) + self.p = v +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForcePullToGrid:applyTo(data) + -- locals for speed + local cap = self.force.cap + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local grid_x_distance = self.options["grid x length"] + local grid_y_distance = self.options["grid y length"] + local t_now = data.t_now + local p = self.p + local time_fun = self.force.time_fun + local length = 5--self.options["node distance"] + + -- Evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + for _, v in ipairs(p) do + -- dereference + local p1 = v.pos + local p2_x = round(p1.x/grid_x_distance)*grid_x_distance + local p2_y = round(p1.y/grid_y_distance)*grid_y_distance + + -- calculate distance between vertex and grid point + local x = p1.x - p2_x + local y = p1.y - p2_y + local d = max(sqrt(x*x+y*y),0.1) + local l = -d/(length*length) + + -- Include time function + local h = l * time_factor + + -- scale effect according to direction + local f = x * h + local g = y * h + + -- cap effect if necessary + if cap then + if f <= 0 then + x = max(-cap, f) + else + x = min(cap, f) + end + + if g <= 0 then + y = max(-cap, g) + else + y = min(cap, g) + end + else + x = f + y = g + end + + -- add calculated effect to net forces + local c1 = net_forces[v] + c1.x = c1.x - x + c1.y = c1.y - y + end +end + +return ForcePullToGrid \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua new file mode 100644 index 0000000000..985b8eec2e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua @@ -0,0 +1,119 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices and pulls them to a specific point on the +-- canvas. This point is given by the |desired at| option. The forces depend +-- on the canvas position of the vertices relative to the canvas point it is +-- pulled to. + + +-- Imports +local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" +local lib = require "pgf.gd.lib" +local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" + +-- Localize math functions +local max = math.max +local sqrt = math.sqrt +local min = math.min + +-- Implementation starts here: + +local ForcePullToPoint = lib.class { base_class = ForceTemplate } + +function ForcePullToPoint:constructor () + ForceTemplate.constructor(self) + self.p = {} +end + +-- This force class works on individual vertices and depends on their +-- current position as well as the point it is desired at. Thus all vertices +-- where the |desired at| option is set are added to the table |p| together +-- with the point where they are wanted. +-- +-- @param v The vertices of the graph we are trying to find a layout for. + +function ForcePullToPoint:preprocess(v) + for _,vertex in ipairs(v) do + if vertex.options then + local da = vertex.options["desired at"] + if da then + self.p[vertex]= {da} + end + end + end +end + + +-- Applying the force to the vertices and adding the effect to the passed net +-- force array +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces + +function ForcePullToPoint:applyTo(data) + -- locals for speed + local cap = self.force.cap + local net_forces = data.net_forces + local t_max = self.options["maximum time"] + local t_now = data.t_now + local p = self.p + local time_fun = self.force.time_fun + + -- Evaluate time function + local time_factor = time_fun(t_max, t_now) + if time_factor == 0 then + return + end + + for v, point in pairs(p) do + -- dereference + local p1 = v.pos + local p2 = point[1] + + -- calculate distance between vertex and centroid + local x = p1.x - p2.x + local y = p1.y - p2.y + local d = max(sqrt(x*x+y*y),0.1) + + -- Include time function + local h = d * time_factor + + -- scale effect according to direction + local f = x * h + local g = y * h + + -- cap effect if necessary + if cap then + if f <= 0 then + x = max(-cap, f) + else + x = min(cap, f) + end + + if g <= 0 then + y = max(-cap, g) + else + y = min(cap, g) + end + else + x = f + y = g + end + + -- add calculated effect to net forces + local c1 = net_forces[v] + c1.x = c1.x - x + c1.y = c1.y - y + end +end + +return ForcePullToPoint \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua new file mode 100644 index 0000000000..ab8f1fad9a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua @@ -0,0 +1,60 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This class implements an initial position algorithm for graph drawing, placing the vertices on +-- a circle with th radius given by the |radius| key +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" +local lib = require "pgf.gd.lib" + +local CircularInitialPositioning = lib.class { base_class = InitialTemplate } + + +--- +declare { + key = "circular initial position", + algorithm = CircularInitialPositioning, + phase = "initial positioning force framework", + phase_default = true +} + +-- Implementation starts here: + +function CircularInitialPositioning:constructor () + InitialTemplate.constructor(self) +end + +function CircularInitialPositioning:run() + -- locals for speed + local vertices = self.vertices + local tmp = (self.options["node pre sep"] + self.options["node post sep"]) + + (self.options["sibling pre sep"] + self.options["sibling post sep"]) + local min_radius = tmp * #self.vertices/2/math.pi + local radius = math.max(self.options.radius, min_radius) + local desired_vertices = self.desired_vertices + -- place vertices where the |desired at | option has been set first + local placed, centroid_x, centroid_y = InitialTemplate:desired(desired_vertices) + local angle = 2*math.pi / #vertices + local a = angle + local sin = math.sin + local cos = math.cos + + for _, vertex in ipairs(vertices) do + -- place all other vertices with respect to the one already placed + if placed[vertex] == nil then + local p = vertex.pos + p.x = sin(a) * radius + centroid_x + p.y = cos(a) * radius + centroid_y + a = a + angle + end + end +end + + +return CircularInitialPositioning \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua new file mode 100644 index 0000000000..2b131e8ad9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua @@ -0,0 +1,60 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This class implements an initial position algorithm for graph drawing, +-- placing the vertices on a grid with square cells with width |node distance| +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" +local lib = require "pgf.gd.lib" + +local GridInitialPositioning = lib.class { base_class = InitialTemplate } + + +--- +declare { + key = "grid initial position", + algorithm = GridInitialPositioning, + phase = "initial positioning force framework", +} + +-- Implementation starts here: + +function GridInitialPositioning:constructor () + InitialTemplate.constructor(self) +end + +function GridInitialPositioning:run() + -- locals for speed + local vertices = self.vertices + local dist = self.options["node distance"] + local desired_vertices = self.desired_vertices + -- place vertices where the |desired at | option has been set first + local placed, centroid_x, centroid_y = InitialTemplate:desired(desired_vertices) + local n = math.ceil(math.sqrt(#vertices)) + local x = -dist + local y = 0 + + for i, vertex in ipairs(vertices) do + -- place all other vertices with respect to the one already placed + if placed[vertex] == nil then + if i <= (y/dist+1)*n then + x = x + dist + else + x = 0 + y = y + dist + end + local p = vertex.pos + p.x = x + centroid_x + p.y = y + centroid_y + end + end +end + + +return GridInitialPositioning \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua new file mode 100644 index 0000000000..ce3a40582c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua @@ -0,0 +1,49 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- This class implements an initial position algorithm for graph drawing, +-- placing the vertices at random positions. +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" +local lib = require "pgf.gd.lib" + +local RandomInitialPositioning = lib.class { base_class = InitialTemplate } + +--- +declare { + key = "random initial position", + algorithm = RandomInitialPositioning, + phase = "initial positioning force framework" +} + +-- Implementation starts here: + +function RandomInitialPositioning:constructor () + InitialTemplate.constructor(self) +end + +function RandomInitialPositioning:run() + -- locals for speed + local random = lib.random + local vertices = self.vertices + local desired_vertices = self.desired_vertices + -- place vertices where the |desired at | option has been set first + local placed, centroid_x, centroid_y = InitialTemplate:desired(desired_vertices) + + for _, vertex in ipairs(vertices) do + -- place all other vertices with respect to the one already placed + if placed[vertex] == nil then + p = vertex.pos + p.x = 100 * random() + centroid_x + p.y = 100 * random() + centroid_y + end + end +end + +return RandomInitialPositioning diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/library.lua new file mode 100644 index 0000000000..5d5554ce35 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/jedi/library.lua @@ -0,0 +1,115 @@ +-- Copyright 2014 by Ida Bruhns +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + + +--- The library providing the graph drawing framework Jedi +-- This library requires all graph drawing algorithms and initial +-- positioning algorithms provided with the first release of Jedi. +-- It also defines the mass key attached to all vertices. + +-- Library name +local jedi + +-- require initial positioning algorithms +require "pgf.gd.force.jedi.initialpositioning.CircularInitialPositioning" +require "pgf.gd.force.jedi.initialpositioning.RandomInitialPositioning" +require "pgf.gd.force.jedi.initialpositioning.GridInitialPositioning" + +-- require graph drawing algorithms +require "pgf.gd.force.jedi.algorithms.FruchtermanReingold" +require "pgf.gd.force.jedi.algorithms.HuSpringElectricalFW" +require "pgf.gd.force.jedi.algorithms.SimpleSpring" +require "pgf.gd.force.jedi.algorithms.SocialGravityCloseness" +require "pgf.gd.force.jedi.algorithms.SocialGravityDegree" + + +-- define parameter +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +--- +declare { + key = "maximum displacement per step", + type = "length", + initial = "100", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "global speed factor", + type = "length", + initial = "1", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "maximum time", + type = "number", + initial = "50", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "find equilibrium", + type = "boolean", + initial = true, + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "equilibrium threshold", + type = "number", + initial = "3", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "grid x length", + type = "length", + initial = "10pt", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "grid y length", + type = "length", + initial = "10pt", + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "snap to grid", + type = "boolean", + initial = false, + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "mass", + type = "number", + initial = "1", + + documentation_in = "pgf.gd.force.jedi.doc" +} + +--- +declare { + key = "coarsening weight", + type = "number", + initial = "1", + + documentation_in = "pgf.gd.force.jedi.doc" +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/library.lua new file mode 100644 index 0000000000..acfda34ffc --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/force/library.lua @@ -0,0 +1,126 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- Nature creates beautiful graph layouts all the time. Consider a +-- spider's web: Nodes are connected by edges in a visually most pleasing +-- manner (if you ignore the spider in the middle). The layout of a +-- spider's web is created just by the physical forces exerted by the +-- threads. The idea behind force-based graph drawing algorithms is to +-- mimic nature: We treat edges as threads that exert forces and simulate +-- into which configuration the whole graph is ``pulled'' by these +-- forces. +-- +-- When you start thinking about for a moment, it turns out that there +-- are endless variations of the force model. All of these models have +-- the following in common, however: +-- % +-- \begin{itemize} +-- \item ``Forces'' pull and push at the nodes in different directions. +-- \item The effect of these forces is simulated by iteratively moving +-- all the nodes simultaneously a little in the direction of the forces +-- and by then recalculating the forces. +-- \item The iteration is stopped either after a certain number of +-- iterations or when a \emph{global energy minimum} is reached (a very +-- scientific way of saying that nothing happens anymore). +-- \end{itemize} +-- +-- The main difference between the different force-based approaches is +-- how the forces are determined. Here are some ideas what could cause a +-- force to be exerted between two nodes (and there are more): +-- % +-- \begin{itemize} +-- \item If the nodes are connected by an edge, one can treat the edge as +-- a ``spring'' that has a ``natural spring dimension''. If the nodes +-- are nearer than the spring dimension, they are push apart; if they +-- are farther aways than the spring dimension, they are pulled together. +-- \item If two nodes are connected by a path of a certain length, the +-- nodes may ``wish to be at a distance proportional to the path +-- length''. If they are nearer, they are pushed apart; if they are +-- farther, they are pulled together. (This is obviously a +-- generalization of the previous idea.) +-- \item There may be a general force field that pushes nodes apart (an +-- electrical field), so that nodes do not tend to ``cluster''. +-- \item There may be a general force field that pulls nodes together (a +-- gravitational field), so that nodes are not too loosely scattered. +-- \item There may be highly nonlinear forces depending on the distance of +-- nodes, so that nodes very near to each get pushed apart strongly, +-- but the effect wears of rapidly at a distance. (Such forces are +-- known as strong nuclear forces.) +-- \item There rotational forces caused by the angles between the edges +-- leaving a node. Such forces try to create a \emph{perfect angular +-- resolution} (a very scientific way of saying that all angles +-- at a node are equal). +-- \end{itemize} +-- +-- Force-based algorithms combine one or more of the above ideas into a +-- single algorithm that uses ``good'' formulas for computing the +-- forces. +-- +-- Currently, three algorithms are implemented in this library, two of +-- which are from the first of the following paper, while the third is +-- from the third paper: +-- % +-- \begin{itemize} +-- \item +-- Y. Hu. +-- \newblock Efficient, high-quality force-directed graph drawing. +-- \newblock \emph{The Mathematica Journal}, 2006. +-- \item +-- C. Walshaw. +-- \newblock A multilevel algorithm for force-directed graph +-- drawing. +-- \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in +-- Computer Science, 1984:31--55, 2001. +-- \end{itemize} +-- +-- Our implementation is described in detail in the following +-- diploma thesis: +-- % +-- \begin{itemize} +-- \item +-- Jannis Pohlmann, +-- \newblock \emph{Configurable Graph Drawing Algorithms +-- for the \tikzname\ Graphics Description Language,} +-- \newblock Diploma Thesis, +-- \newblock Institute of Theoretical Computer Science, Universit\"at +-- zu L\"ubeck, 2011.\\[.5em] +-- \newblock Online at +-- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} +-- \end{itemize} +-- +-- In the future, I hope that most, if not all, of the force-based +-- algorithms become ``just configuration options'' of a general +-- force-based algorithm similar to the way the modular Sugiyama method +-- is implemented in the |layered| graph drawing library. +-- +-- @library + +local force -- Library name + +-- Load declarations from: +require "pgf.gd.force.ControlDeclare" +require "pgf.gd.force.ControlStart" +require "pgf.gd.force.ControlIteration" +require "pgf.gd.force.ControlSprings" +require "pgf.gd.force.ControlElectric" +require "pgf.gd.force.ControlCoarsening" + +require "pgf.gd.force.SpringLayouts" +require "pgf.gd.force.SpringElectricalLayouts" + +-- Load algorithms from: +require "pgf.gd.force.SpringHu2006" +require "pgf.gd.force.SpringElectricalHu2006" +require "pgf.gd.force.SpringElectricalWalshaw2000" + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface.lua new file mode 100644 index 0000000000..df2649521b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.interface = {} + + +-- Done + +return pgf.gd.interface \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua new file mode 100644 index 0000000000..8473eb3f10 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua @@ -0,0 +1,191 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This class provides the core functionality of the interface between +-- all the different layers (display layer, binding layer, and +-- algorithm layer). The two classes |InterfaceToAlgorithms| and +-- |InterfaceToDisplay| use, in particular, the data structures +-- provided by this class. +-- +-- @field binding This field stores the ``binding''. The graph drawing +-- system is ``bound'' to the display layer through such a binding (a +-- subclass of |Binding|). Such a binding can be thought of as a +-- ``driver'' in operating systems terminology: It is a small set of +-- functions needed to adapt the functionality to one specific display +-- system. Note that the whole graph drawing scope is bound to exactly +-- one display layer; to use several bindings you need to setup a +-- completely new Lua instance. +-- +-- @field scopes This is a stack of graph drawing scopes. All +-- interface methods refer to the top of this stack. +-- +-- @field collection_kinds This table stores which collection kinds +-- have been defined together with their properties. +-- +-- @field algorithm_classes A table that maps algorithm keys (like +-- |tree layout| to class objects). +-- +-- @field keys A lookup table of all declared keys. Each entry of this +-- table consists of the original entry passed to the |declare| +-- method. Each of these tables is both index at a number (so you can +-- iterate over it using |ipairs|) and also via the key's name. + +local InterfaceCore = { + -- The main binding. Set by |InterfaceToDisplay.bind| method. + binding = nil, + + -- The stack of Scope objects. + scopes = {}, + + -- The collection kinds. + collection_kinds = {}, + + -- The algorithm classes + algorithm_classes = {}, + + -- The declared keys + keys = {}, + + -- The phase kinds + phase_kinds = {}, + + -- Internals for handling the options stack + option_stack = {}, + option_cache_height = nil, + option_initial = { + algorithm_phases = { + ["preprocessing stack"] = {}, + ["edge routing stack"] = {}, + ["postprocessing stack"] = {}, + } + }, + option_aliases = { + [{}] = true -- Remove, once Lua Link Bug is fixed + }, + + -- Constant strings for special collection kinds. + sublayout_kind = "INTERNAL_sublayout_kind", + subgraph_node_kind = "INTERNAL_subgraph_node_kind", +} + +-- Namespace +require("pgf.gd.interface").InterfaceCore = InterfaceCore + + +InterfaceCore.option_initial.__index = InterfaceCore.option_initial +InterfaceCore.option_initial.algorithm_phases.__index = InterfaceCore.option_initial.algorithm_phases + + +-- Imports +local Coordinate = require "pgf.gd.model.Coordinate" + + +--- Returns the top scope +-- +-- @return The current top scope, which is the scope in which +-- everything should happen right now. + +function InterfaceCore.topScope() + return assert(InterfaceCore.scopes[#InterfaceCore.scopes], "no graph drawing scope open") +end + + + +local factors = { + cm=28.45274, + mm=2.84526, + pt=1.0, + bp=1.00374, + sp=0.00002, + pc=12.0, + em=10, + ex=4.30554, + ["in"]=72.27, + dd=1.07, + cc=12.8401, + [""]=1, +} + +local time_factors = { + s=1, + ms=0.001, + min=60, + h=3600 +} + +local directions = { + down = -90, + up = 90, + left = 180, + right = 0, + south = -90, + north = 90, + west = 180, + east = 0, + ["north east"] = 45, + ["north west"] = 135, + ["south east"] = -45, + ["south west"] = -135, + ["-"] = 0, + ["|"] = -90, +} + +--- +-- Converts parameters types. This method is used by both the +-- algorithm layer as well as the display layer to convert strings +-- into the different types of parameters. When a parameter +-- is pushed onto the option stack, you can either provide a value of +-- the parameter's type; but you can also provide a string. This +-- string can then be converted by this function to a value of the +-- correct type. +-- +-- @param s A parameter value or a string. +-- @param t The type of the parameter +-- +-- @return If |s| is not a string, it is just returned. If it is a +-- string, it is converted to the type |t|. + +function InterfaceCore.convert(s,t) + if type(s) ~= "string" then + return s + elseif t == "number" then + return tonumber(s) + elseif t == "length" then + local num, dim = string.match(s, "([%d.]+)(.*)") + return tonumber(num) * assert(factors[dim], "unknown unit") + elseif t == "time" then + local num, dim = string.match(s, "([%d.]+)(.*)") + return tonumber(num) * assert(time_factors[dim], "unknown time unit") + elseif t == "string" then + return s + elseif t == "canvas coordinate" or t == "coordinate" then + local x, y = string.match(s,"%(([%d.]+)pt,([%d.]+)pt%)") + return Coordinate.new(tonumber(x),tonumber(y)) + elseif t == "boolean" then + return s == "true" + elseif t == "raw" then + return loadstring(s)() + elseif t == "direction" then + return directions[s] or tonumber(s) + elseif t == "nil" or t == nil then + return nil + else + error ("unknown parameter type") + end +end + + +-- Done + +return InterfaceCore diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua new file mode 100644 index 0000000000..1187fbc313 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua @@ -0,0 +1,968 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This class provides the interface between the graph drawing system +-- and algorithms. Another class, |InterfaceToDisplay|, binds the +-- display layers (like \tikzname\ or a graph drawing editor) to the +-- graph drawing system ``from the other side''. +-- +-- The functions declared here can be used by algorithms to +-- communicate with the graph drawing system, which will usually +-- forward the ``requests'' of the algorithms to the display layers in +-- some way. For instance, when you declare a new parameter, this +-- parameter will become available on the display layer. + +local InterfaceToAlgorithms = {} + +-- Namespace +require("pgf.gd.interface").InterfaceToAlgorithms = InterfaceToAlgorithms + + +-- Imports +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" +local InterfaceToDisplay = require "pgf.gd.interface.InterfaceToDisplay" +local InterfaceToC = require "pgf.gd.interface.InterfaceToC" + +local LookupTable = require "pgf.gd.lib.LookupTable" +local LayoutPipeline = require "pgf.gd.control.LayoutPipeline" + +local Edge = require "pgf.gd.model.Edge" + +local lib = require "pgf.gd.lib" + +local doc = require "pgf.gd.doc" + +-- Forwards + +local declare_handlers + + + + +--- +-- Adds a handler for the |declare| function. The |declare| +-- command is just a ``dispatcher'' to one of many possible +-- declaration functions. Which function is used, depends on which +-- fields are present in the table passed to |declare|. For each +-- registered handler, we call the |test| function. If it returns +-- neither |nil| nor |false|, the |handler| field of this handler is +-- called. If it returns |true|, the handler immediately +-- finishes. Otherwise, the next handler is tried. + +function InterfaceToAlgorithms.addHandler(test, handler) + table.insert(declare_handlers, 1, { test = test, handler = handler }) +end + + + +-- Local stuff + +local key_metatable = {} + +--- +-- This function is the ``work-horse'' for declaring things. It allows +-- you to specify on the algorithmic layer that a key ``is available'' +-- for use on the display layer. There is just one function for +-- handling all declarations in order to make the declarations +-- easy-to-use since you just need to import a single function: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare +--\end{codeexample} +-- +-- You can now use |declare| it as follows: You pass it a table +-- containing information about the to-be-declared key. The table +-- \emph{must} have a field |key| whose value is unique and must be a +-- string. If the value of |key| is, say, |"foo"|, the +-- parameter can be set on the display layer such as, say, the +-- \tikzname\ layer, using |/graph drawing/foo|. Here is a typical +-- example of how a declaration is done: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "electrical charge", +-- type = "number", +-- initial = "1.0", +-- +-- summary = "The ``electrical charge'' is a property...", +-- documentation = [[...]], +-- examples = [[...]] +-- } +--\end{codeexample} +-- +-- \medskip\noindent\textbf{Inlining Documentation.} +-- The three keys |summary|, |documentation| and |examples| are +-- intended for the display layer to give the users information about +-- what the key does. The |summary| should be a string that succinctly +-- describes the option. This text will typically be displayed for +-- instance as a ``tool tip'' or in an option overview. The +-- |documentation| optionally provides more information and should be +-- typeset using \TeX. The |examples| can either be a single string or +-- an array of strings. Each should be a \tikzname\ example +-- demonstrating how the key is used. +-- +-- Note that you can take advantage of the Lua syntax of enclosing +-- very long multi-line strings in |[[| and |]]|. As a bonus, if the +-- summary, documentation, or an example starts and ends with a quote, +-- these two quotes will be stripped. This allows you to enclose the +-- whole multi-line string (additionally) in quotes, leading to better +-- syntax highlighting in editors. +-- +-- \medskip\noindent\textbf{External Documentation.} +-- It is sometimes more desirable to put the documentation of a key +-- into an external file. First, this makes the code leaner and, thus, +-- faster to read (both for humans and for computers). Second, for C +-- code, it is quite inconvenient to have long strings inside a C +-- file. In such cases, you can use the |documentation_in| field: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "electrical charge", +-- type = "number", +-- initial = "1.0", +-- documentation_in = "some_filename" +-- } +--\end{codeexample} +-- +-- The |some_filename| must be the name of a Lua file that will be +-- read ``on demand'', that is, whenever someone tries to access the +-- documentation, summary, or examples field of the key, this file +-- will be loaded using |require|. The file should then use +-- |pgf.gd.doc| to install the missing information in the keys. +-- +-- \medskip\noindent\textbf{The Use Field.} +-- When you declare a key, you can provide a |use| field. If present, +-- you must set it to an array of small tables which have two fields: +-- % +-- \begin{itemize} +-- \item |key| This is the name of another key or a function. +-- \item |value| This is either a value (like a string or a number) or +-- a function or |nil|. +-- \end{itemize} +-- +-- Here is an example: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "binary tree layout", +-- use = { +-- { key = "minimum number of children", value = 2 }, +-- { key = "significant sep", value = 12 }, +-- { key = "tree layout" } +-- }, +-- summary = "The |binary tree layout| places node...", +-- documentation = ..., +-- examples = ..., +-- } +--\end{codeexample} +-- +-- The effect of a |use| field is the following: Whenever the key is +-- encountered on the option stack, the key is first handled +-- normally. Then, we iterate over all elements of the |use| +-- array. For each element, we perform the action as if the |key| of +-- the array had been set explicitly to the value given by the |value| +-- field. If the |value| is a function, we pass a different value to +-- the key, namely the result of applying the function to the value +-- originally passed to the original key. Here is a typical example: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "level sep", +-- type = "length", +-- use = { +-- { key = "level pre sep", value = function (v) return v/2 end }, +-- { key = "level post sep", value = function (v) return v/2 end } +-- }, +-- summary = "..." +-- } +--\end{codeexample} +-- +-- Just like the value, the key itself can also be a function. In this +-- case, the to-be-used key is also computed by applying the function +-- to the value passed to the original key. +-- +-- As mentioned at the beginning, |declare| is a work-horse that will call +-- different internal functions depending on whether you declare a +-- parameter key or a new algorithm or a collection kind. Which kind +-- of declaration is being done is detected by the presence of certain +-- fields in the table passed to |t|. The different kind of +-- possible declarations are documented in the |declare_...| +-- functions. Note that these functions are internal and cannot be +-- called from outside; you must use the |declare| function. +-- +-- @param t A table contain the field |key| and other fields as +-- described. + +function InterfaceToAlgorithms.declare (t) + local keys = InterfaceCore.keys + + -- Sanity check: + assert (type(t.key) == "string" and t.key ~= "", "parameter key may not be the empty string") + if keys[t.key] or t.keys == "algorithm_phases" then + error("parameter '" .. t.key .. "' already declared") + end + + for _,h in ipairs (declare_handlers) do + if h.test(t) then + if h.handler(t) then + break + end + end + end + + -- Attach metatable: + setmetatable (t, key_metatable) + + -- Set! + keys[t.key] = t + keys[#keys + 1] = t +end + + +function key_metatable.__index (key_table, what) + if what == "documentation" or what == "summary" or what == "examples" then + local doc = rawget(key_table,"documentation_in") + if doc then + require (doc) + return rawget(key_table, what) + end + end +end + + + +--- +-- This function is called by |declare| for ``normal parameter keys'', +-- which are all keys for which no special field like |algorithm| or +-- |layer| is declared. You write +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "electrical charge", +-- type = "number", +-- initial = "1.0", +-- +-- summary = "The ``electrical charge'' is a property...", +-- documentation = [[...]], +-- examples = [[...]] +-- } +--\end{codeexample} +-- +-- When an author writes |my node[electrical charge=5-3]| in the +-- description of her graph, the object |vertex| corresponding to the +-- node |my node| will have a field |options| attached to it with +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--vertex.options["electrical charge"] == 2 +--\end{codeexample} +-- +-- The |type| field does not refer to Lua types. Rather, these types are +-- sensible types for graph drawing and they are mapped by the higher +-- layers to Lua types. In detail, the following types are available: +-- % +-- \begin{itemize} +-- \item |number| A dimensionless number. Will be mapped to a normal +-- Lua |number|. So, when the author writes |foo=5*2|, the |foo| key +-- of the |options| field of the corresponding object will be set to +-- |10.0|. +-- \item |length| A ``dimension'' in the sense of \TeX\ (a number with +-- a dimension like |cm| attached to it). It is the job of the display +-- layer to map this to a number in ``\TeX\ points'', that is, to a +-- multiple of $1/72.27$th of an inch. +-- \item |time| A ``time'' in the sense of |\pgfparsetime|. Examples +-- are |6s| or |0.1min| or |6000ms|, all of which will map to |6|. +-- \item |string| Some text. Will be mapped to a Lua |string|. +-- \item |canvas coordinate| A position on the canvas. Will be mapped +-- to a |model.Coordinate|. +-- \item |boolean| A Boolean value. +-- \item |raw| Some to-be-executed Lua text. +-- \item |direction| Normally, an angle; however, +-- the special values of |down|, |up|, |left|, |right| as well as the +-- directions |north|, |north west|, and so on are also legal on the +-- display layer. All of them will be mapped to a number. Furthermore, +-- a vertical bar (\verb!|!) will be mapped to |-90| and a minus sign +-- (|-|) will be mapped to |0|. +-- \item |hidden| A key of this type ``cannot be set'', that is, +-- users cannot set this key at all. However algorithms can still read +-- this key and, through the use of |alias|, can use the key as a +-- handle to another key. +-- \item |user value| The key stores a Lua user value (userdata). Such +-- keys can only be set from C since user values cannot be created in +-- Lua (let alone in \tikzname). +-- \end{itemize} +-- +-- If the |type| field is missing, it is automatically set to +-- |"string"|. +-- +-- A parameter can have an |initial| value. This value will be used +-- whenever the parameter has not been set explicitly for an object. +-- +-- A parameter can have a |default| value. This value will be used as +-- the parameter value whenever the parameter is explicitly set, but +-- no value is provided. For a key of type |"boolean"|, if no +-- |default| is provided, |"true"| will be used automatically. +-- +-- A parameter can have an |alias| field. This field must be set to +-- the name of another key or to a function. Whenever you access the +-- current key and this key is not set, the |alias| key is tried +-- instead. If it is set, its value will be returned (if the |alias| +-- key has itself an alias set, this is tried recursively). If the +-- alias is not set either and neither does it have an initial value, +-- the |initial| value is used. Note that in case the alias has its +-- |initial| field set, the |initial| value of the current key will +-- never be used. +-- +-- The main purpose of the current key is to allow algorithms to +-- introduce their own terminology for keys while still having access +-- to the standard keys. For instance, the |OptimalHierarchyLayout| +-- class uses the name |layerDistance| for what would be called +-- |level distance| in the rest of the graph drawing system. In this +-- case, we can declare the |layerDistance| key as follows: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- declare { +-- key = "layerDistance", +-- type = "length", +-- alias = "level distance" +-- } +--\end{codeexample} +-- +-- Inside the algorithm, we can write |...options.layerDistance| and +-- will get the current value of the |level distance| unless the +-- |layerDistance| has been set explicitly. Indeed, we might set the +-- |type| to |hidden| to ensure that \emph{only} the |level distance| +-- can and must set to set the layerDistance. +-- +-- Note that there is a difference between |alias| and the |use| +-- field: Suppose we write +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- declare { +-- key = "layerDistance", +-- type = "length", +-- use = { +-- { key = "level distance", value = lib.id } +-- } +-- } +--\end{codeexample} +-- +-- Here, when you say |layerDistance=1cm|, the |level distance| itself +-- will be modified. When the |level distance| is set, however, the +-- |layerDistance| will not be modified. +-- +-- If the alias is a function, it will be called with the option table +-- as its parameter. You can thus say things like +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- declare { +-- key = "layerDistance", +-- type = "length", +-- alias = function (option) +-- return option["layer pre dist"] + option["layer post dist"] +-- end +-- } +--\end{codeexample} +-- +-- As a special courtesy to C code, you can also set the key +-- |alias_function_string|, which allows you to put the function into +-- a string that is read using |loadstring|. +-- +-- (You cannot call this function directly, it is included for +-- documentation purposes only.) +-- +-- @param t The table originally passed to |declare|. + +local function declare_parameter (t) + + t.type = t.type or "string" + + if t.type == "boolean" and t.default == nil then + t.default = true + end + + -- Normal key + assert (type(t.type) == "string", "key type must be a string") + + -- Declare via the hub: + if t.type ~= "hidden" then + InterfaceCore.binding:declareCallback(t) + + -- Handle initials: + if t.initial then + InterfaceCore.option_initial[t.key] = InterfaceCore.convert(t.initial, t.type) + end + end + + if t.alias_function_string and not t.alias then + local count = 0 + t.alias = load ( + function () + count = count + 1 + if count == 1 then + return "return " + elseif count == 2 then + return t.alias_function_string + else + return nil + end + end)() + end + + if t.alias then + assert (type(t.alias) == "string" or type(t.alias == "function"), "alias must be a string or a function") + InterfaceCore.option_aliases[t.key] = t.alias + end + + return true +end + + + + +--- +-- This function is called by |declare| for ``algorithm +-- keys''. These keys are normally used without a value as in just +-- |\graph[tree layout]|, but you can optionally pass a value to +-- them. In this case, this value must be the name of a \emph{phase} +-- and the algorithm of this phase will be set (and not the +-- default phase of the key), see the description of phases below for +-- details. +-- +-- Algorithm keys are detected by the presence of the field |algorithm| +-- in the table |t| passed to |declare|. Here is an example of how it +-- is used: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- local ReingoldTilford1981 = {} +-- +-- --- +-- declare { +-- key = "tree layout", +-- algorithm = ReingoldTilford1981, +-- +-- preconditions = { +-- connected = true, +-- tree = true +-- }, +-- +-- postconditions = { +-- upward_oriented = true +-- }, +-- +-- summary = "The Reingold--Tilford method is...", +-- documentation = ..., +-- examples = ..., +-- } +-- +-- function ReingoldTilford1981:run() +-- ... +-- end +--\end{codeexample} +-- +-- The |algorithm| field expects either a table or a string as +-- value. If you provide a string, then |require| will be applied to +-- this string to obtain the table; however, this will happen only +-- when the key is actually used for the first time. This means that +-- you can declare (numerous) algorithms in a library without these +-- algorithms actually being loaded until they are needed. +-- +-- Independently of how the table is obtained, it will be ``upgraded'' +-- to a class by setting its |__index| field and installing a static +-- |new| function (which takes a table of initial values as +-- argument). Both these settings will only be done if they have not +-- yet been performed. +-- +-- Next, you can specify the fields |preconditions| and +-- |postconditions|. The preconditions are a table that tell the graph +-- drawing engine what kind of graphs your algorithm expects. If the +-- input graph is not of this kind, it will be automatically +-- transformed to meet this condition. Similarly, the postconditions +-- tell the engine about properties of your graph after the algorithm +-- has run. Again, additional transformations may be performed. +-- +-- You can also specify the field |phase|. This tells the graph +-- drawing engine which ``phase'' of the graph drawing process your +-- option applies to. Each time you select an algorithm later on +-- through use of the algorithm's key, the algorithm for this phase +-- will be set; algorithms of other phases will not be changed. +-- For instance, when an algorithm is part of the spanning tree +-- computation, its phase will be |"spanning tree computation"| and +-- using its key does not change the main algorithm, but only the +-- algorithm used during the computation of a spanning tree for the +-- current graph (in case this is needed by the main algorithm). In +-- case the |phase| field is missing, the phase |main| is used. Thus, +-- when no phase field is given, the key will change the main +-- algorithm used to draw the graph. +-- +-- Later on, the algorithm set for the current phase can be accessed +-- through the special |algorithm_phases| field of |options| +-- tables. The |algorithm_phases| table will contain two fields for each +-- phase for which some algorithm has been set: One field is the name +-- of the phase and its value will be the most recently set algorithm +-- (class) set for this phase. The other field is the name of the +-- phase followed by |" stack"|. It will contain an array of all +-- algorithm classes that have been set for this key with the most +-- recently at the end. +-- +-- The following example shows the declaration of an algorithm that is +-- the default for the phase |"spanning tree computation"|: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- --- +-- declare { +-- key = "breadth first spanning tree", +-- algorithm = { +-- run = +-- function (self) +-- return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events) +-- end +-- }, +-- phase = "spanning tree computation", +-- phase_default = true, +-- summary = ... +-- } +--\end{codeexample} +-- +-- The algorithm is called as follows during a run of the main +-- algorithms: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- local graph = ... -- the graph object +-- local spanning_algorithm_class = graph.options.algorithm_phases["spanning tree computation"] +-- local spanning_algorithm = +-- spanning_algorithm_class.new{ +-- ugraph = ugraph, +-- events = scope.events +-- } +-- local spanning_tree = spanning_algorithm:run() +--\end{codeexample} +-- +-- If you set the |phase_default| field of |t| to |true|, the algorithm will +-- be installed as the default algorithm for the phase. This can be +-- done only once per phase. Furthermore, for such a default algorithm +-- the |algorithm| key must be table, it may not be a string (in other +-- words, all default algorithms are loaded immediately). Accessing +-- the |algorithm_phases| table for a phase for which no algorithm has +-- been set will result in the default algorithm and the phase stack +-- will also contain this algorithm; otherwise the phase stack will be empty. +-- +-- (You cannot call this function directly, it is included for +-- documentation purposes only.) +-- +-- @param t The table originally passed to |declare|. + +local function declare_algorithm (t) + -- Algorithm declaration! + assert(type(t.algorithm) == "table" or type(t.algorithm) == "string") + + t.phase = t.phase or "main" + + local function make_class () + local class + + if type(t.algorithm) == "table" then + class = lib.class(t.algorithm) + else + class = lib.class(require(t.algorithm)) + end + + -- Now, save pre- and postconditions + class.preconditions = t.preconditions or {} + class.postconditions = t.postconditions or {} + + -- Save phase + class.phase = t.phase + + -- Compatibility + class.old_graph_model = t.old_graph_model + + return class + end + + -- Store this: + local store_me + if type(t.algorithm) == "table" then + store_me = make_class() + else + store_me = make_class + end + + -- Save in the algorithm_classes table: + InterfaceCore.algorithm_classes[t.key] = store_me + + assert(t.type == nil, "type may not be set for an algorithm key") + t.type = "string" + + -- Install! + InterfaceCore.binding:declareCallback(t) + + if t.phase_default then + assert (not InterfaceCore.option_initial.algorithm_phases[t.phase], + "default algorithm for phase already set") + assert (type(store_me) == "table", + "default algorithms must be loaded immediately") + InterfaceCore.option_initial.algorithm_phases[t.phase] = store_me + InterfaceCore.option_initial.algorithm_phases[t.phase .. " stack"] = { store_me } + else + InterfaceCore.option_initial.algorithm_phases[t.phase .. " stack"] = { + dummy = true -- Remove once Lua Link Bug is fixed + } + end + + return true +end + + + + +--- +-- This function is called by |declare| for ``collection kinds''. They +-- are detected by the presence of the field |layer| +-- in the table |t| passed to |declare|. See the class |Collection| +-- for details on what a collection and a collection kind is. +-- +-- The |key| field of the table |t| passed to this function is both +-- the name of the to-be-declared collection kind as well as the key +-- that is used on the display layer to indicate that a node or edge +-- belongs to a collection. +-- +-- \medskip +-- \noindent\textbf{The Display Layer.} +-- Let us first have a look at what happens on the display layer: +-- A key |t.key| is setup on the display layer that, when used inside +-- a graph drawing scope, starts a new collection of the specified +-- kind. ``Starts'' means that all nodes and edges mentioned in the +-- rest of the current option scope will belong to a new collection +-- of kind |t.key|. +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--declare { key = "hyper", layer = 1 } +--\end{codeexample} +-- % +-- you can say on the \tikzname\ layer +-- % +--\begin{codeexample}[code only] +-- \graph { +-- a, b, c, d; +-- { [hyper] a, b, c } +-- { [hyper] b, c, d } +-- }; +--\end{codeexample} +-- +-- In this case, the nodes |a|, |b|, |c| will belong to a collection of +-- kind |hyper|. The nodes |b|, |c|, and |d| will (also) belong to +-- another collection of the same kind |hyper|. You can nest +-- collections; in this case, nodes will belong to several +-- collections. +-- +-- The effect of declaring a collection kind on the algorithm layer +-- it, first of all, that |scope.collections| will have a field named +-- by the collection kind. This field will store an array that +-- contains all collections that were declared as part of the +-- graph. For instance, |collections.hyper| will contain all +-- hyperedges, each of which is a table with the following fields: The +-- |vertices| and |edges| fields each contain arrays of all objects +-- being part of the collection. The |sub| field is an array of +-- ``subcollections'', that is, all collections that were started +-- inside another collection. (For the collection kinds |hyper| and +-- |same layer| this makes no sense, but subgraphs could, for instance, +-- be nested.) +-- +-- \medskip +-- \noindent\textbf{Rendering of Collections.} +-- For some kinds of collections, it makes sense to \emph{render} them, +-- but only after the graph drawing algorithm has run. For this +-- purpose, the binding layer will use a callback for each collection +-- kind and each collection, see the |Binding| class for details. +-- Suppose, for instance, you would +-- like hyperedges to be rendered. In this case, a graph drawing +-- algorithm should iterate over all collections of type |hyper| and +-- compute some hints on how to render the hyperedge and store this +-- information in the |generated_options| table of the hyperedge. Then, +-- the binding layer will ask the display layer to run some some code +-- that is able to read key--value pairs passed to +-- it (which are the key--value pairs of the |generated_options| table) +-- and use this information to nicely draw the hyperedge. +-- +-- The number |t.layer| determines in which order the different +-- collection kinds are rendered. +-- +-- The last parameter, the layer number, is used to specify the order +-- in which the different collection kinds are rendered. The higher the +-- number, the later the collection will be rendered. Thus, if there is +-- a collection kind with layer number 10 and another with layer number +-- 20, all collections of the first kind will be rendered first, +-- followed by all collections of the second kind. +-- +-- Collections whose layer kinds are non-negative get rendered +-- \emph{after} the nodes and edges have already been rendered. In +-- contrast, collections with a negative layer number get shown +-- ``below'' the nodes and edges. +-- +-- (You cannot call this function directly, it is included for +-- documentation purposes only.) +-- +-- @param t The table originally passed to |declare|. + +local function declare_collection_kind (t) + assert (type(t.layer) == "number", "layer must be a number") + + local layer = t.layer + local kind = t.key + local kinds = InterfaceCore.collection_kinds + local new_entry = { kind = kind, layer = layer } + + -- Insert into table part: + kinds[kind] = new_entry + + -- Insert into array part: + local found + for i=1,#kinds do + if kinds[i].layer > layer or (kinds[i].layer == layer and kinds[i].kind > kind) then + table.insert(kinds, i, new_entry) + return + end + end + + kinds[#kinds+1] = new_entry + + -- Bind + InterfaceCore.binding:declareCallback(t) + + return true +end + + + +-- Build in handlers: + +declare_handlers = { + { test = function (t) return t.algorithm_written_in_c end, handler = InterfaceToC.declare_algorithm_written_in_c }, + { test = function (t) return t.algorithm end, handler = declare_algorithm }, + { test = function (t) return t.layer end, handler = declare_collection_kind }, + { test = function (t) return true end, handler = declare_parameter } +} + + + + + + + + +--- +-- Finds a node by its name. This method should be used by algorithms +-- for which a node name is specified in some option and, thus, needs +-- to be converted to a vertex object during a run of the algorithm. +-- +-- @param name A node name +-- +-- @return The vertex of the given name in the syntactic digraph or +-- |nil|. + +function InterfaceToAlgorithms.findVertexByName(name) + return InterfaceCore.topScope().node_names[name] +end + + + + + +-- Helper function +local function add_to_collections(collection,where,what) + if collection then + LookupTable.addOne(collection[where],what) + add_to_collections(collection.parent,where,what) + end +end + +local unique_count = 1 + +--- +-- Generate a new vertex in the syntactic digraph. Calling this method +-- allows algorithms to create vertices that are not present in the +-- original input graph. Using the graph drawing coroutine, this +-- function will pass back control to the display layer in order to +-- render the vertex and, thereby, create precise size information +-- about it. +-- +-- Note that creating new vertices in the syntactic digraph while the +-- algorithm is already running is a bit at odds with the notion of +-- treating graph drawing as a series of graph transformations: For +-- instance, when a new vertex is created, the graph will (at least +-- temporarily) no longer be connected; even though an algorithm may +-- have requested that it should only be fed connected +-- graphs. Likewise, more complicated requirements like insisting on +-- the graph being a tree also cannot be met. +-- +-- For these reasons, the following happens, when a new vertex is +-- created using the function: +-- % +-- \begin{enumerate} +-- \item The vertex is added to the syntactic digraph. +-- \item It is added to all layouts on the current layout stack. When +-- a graph drawing algorithm is run, it is not necessarily run on the +-- original syntactic digraph. Rather, a sequence / stack of nested +-- layouts may currently +-- be processed and the vertex is added to all of them. +-- \item The vertex is added to both the |digraph| and the |ugraph| of +-- the current algorithm. +-- \end{enumerate} +-- +-- @param algorithm An algorithm for whose syntactic digraph the node +-- should be added +-- @param init A table of initial values for the node that is passed +-- to |Binding:createVertex|, see that function for details. +-- +-- @return The newly created node +-- +function InterfaceToAlgorithms.createVertex(algorithm, init) + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + + -- Setup node + if not init.name then + init.name = "internal@gd@node@" .. unique_count + unique_count = unique_count + 1 + end + + -- Does vertex already exist? + assert (not scope.node_names[name], "node already created") + + if not init.shape or init.shape == "none" then + init.shape = "rectangle" + end + + -- Call binding + binding:createVertex(init) + + local v = assert(scope.node_names[init.name], "internal node creation failed") + + -- Add vertex to the algorithm's digraph and ugraph + algorithm.syntactic_component:add {v} + algorithm.digraph:add {v} + algorithm.ugraph:add {v} + + -- Compute bounding boxes: + LayoutPipeline.prepareBoundingBoxes(algorithm.rotation_info, algorithm.adjusted_bb, algorithm.digraph, {v}) + + -- Add the node to the layout stack: + add_to_collections(algorithm.layout, "vertices", v) + + algorithm.layout_graph:add { v } + + return v +end + + + +--- +-- Generate a new edge in the syntactic digraph. This method is quite +-- similar to |createVertex| and has the same effects with respect to +-- the edge: The edge is added to the syntactic digraph and also to +-- all layouts on the layout stack. Furthermore, appropriate edges are +-- added to the |digraph| and the |ugraph| of the algorithm currently +-- running. +-- +-- @param algorithm An algorithm for whose syntactic digraph the node should be added +-- @param tail A syntactic tail vertex +-- @param head A syntactic head vertex +-- @param init A table of initial values for the edge. +-- +-- The following fields are useful for |init|: +-- % +-- \begin{itemize} +-- \item |init.direction| If present, a direction for the edge. Defaults to "--". +-- \item |init.options| If present, some options for the edge. +-- \item |init.generated_options| A table that is passed back to the +-- display layer as a list of key-value pairs in the syntax of +-- |declare_parameter|. +-- \end{itemize} + +function InterfaceToAlgorithms.createEdge(algorithm, tail, head, init) + + init = init or {} + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + local syntactic_digraph = algorithm.layout_graph + local syntactic_component = algorithm.syntactic_component + + assert (syntactic_digraph:contains(tail) and + syntactic_digraph:contains(head), + "attempting to create edge between nodes that are not in the syntactic digraph") + + local arc = syntactic_digraph:connect(tail, head) + + local edge = Edge.new { + head = head, + tail = tail, + direction = init.direction or "--", + options = init.options or algorithm.layout.options, + path = init.path, + generated_options = init.generated_options + } + + -- Add to arc + arc.syntactic_edges[#arc.syntactic_edges+1] = edge + + local s_arc = syntactic_component:connect(tail, head) + s_arc.syntactic_edges = arc.syntactic_edges + + -- Create Event + local e = InterfaceToDisplay.createEvent ("edge", { arc, #arc.syntactic_edges }) + edge.event = e + + -- Make part of collections + for _,c in ipairs(edge.options.collections) do + LookupTable.addOne(c.edges, edge) + end + + -- Call binding + binding.storage[edge] = {} + binding:everyEdgeCreation(edge) + + -- Add edge to digraph and ugraph + local direction = edge.direction + if direction == "->" then + algorithm.digraph:connect(tail, head) + elseif direction == "<-" then + algorithm.digraph:connect(head, tail) + elseif direction == "--" or direction == "<->" then + algorithm.digraph:connect(tail, head) + algorithm.digraph:connect(head, tail) + end + algorithm.ugraph:connect(tail, head) + algorithm.ugraph:connect(head, tail) + + -- Add edge to layouts + add_to_collections(algorithm.layout, "edges", edge) + +end + + + + + +-- Done + +return InterfaceToAlgorithms diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua new file mode 100644 index 0000000000..282727b66a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua @@ -0,0 +1,78 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- This table contains functions that are used (on the Lua side) to +-- prepare a graph for use in C and, vice versa, to translate back the +-- results of C to Lua. + +local InterfaceToC = {} + +-- Imports + +local lib = require "pgf.gd.lib" + + +--- +-- This function is called by |declare| for ``algorithm +-- keys'' where the algorithm is not written in Lua, but rather in the +-- programming language C. You do not call this function yourself; +-- |InterfaceFromC.h| will do it for you. Nevertheless, if you +-- provide a table to |declare| with the field +-- |algorithm_written_in_c| set, the following happens: The table's +-- |algorithm| field is set to an algorithm class object whose |run| +-- method calls the function passed via the +-- |algorithm_written_in_c| field. It will be called with the +-- following parameters (in that order): +-- % +-- \begin{enumerate} +-- \item The to-be-laid out digraph. This will not be the whole layout +-- graph (syntactic digraph) if preprocessing like decomposition into +-- connected components is used. +-- \item An array of the digraph's vertices, but with the table part +-- hashing vertex objects to their indices in the array part. +-- \item An array of the syntactic edges of the digraph. Like the +-- array, the table part will hash back the indices of the edge objects. +-- \item The algorithm object. +-- \end{enumerate} +-- +-- @param t The table originally passed to |declare|. + +function InterfaceToC.declare_algorithm_written_in_c (t) + t.algorithm = { + run = function (self) + local back_table = lib.icopy(self.ugraph.vertices) + for i,v in ipairs(self.ugraph.vertices) do + back_table[v] = i + end + local edges = {} + for _,a in ipairs(self.ugraph.arcs) do + local b = self.layout_graph:arc(a.tail,a.head) + if b then + lib.icopy(b.syntactic_edges, edges) + end + end + for i=1,#edges do + edges[edges[i]] = i + end + collectgarbage("stop") -- Remove once Lua Link Bug is fixed + t.algorithm_written_in_c (self.digraph, back_table, edges, self) + collectgarbage("restart") -- Remove once Lua Link Bug is fixed + end + } +end + + + +-- Done + +return InterfaceToC diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua new file mode 100644 index 0000000000..23018efcaa --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua @@ -0,0 +1,1002 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This class provides the interface between a display +-- layer (like \tikzname\ or a graph editor) and graph drawing +-- system. Another class, |InterfaceToAlgorithms|, binds the algorithm +-- layer (which are written in Lua) to the graph drawing system. +-- +-- The functions declared here are independent of the actual display +-- layer. Rather, the differences between the layers are encapsulated +-- by subclasses of the |Binding| class, see that class for +-- details. Thus, when a new display layer is written, the present +-- class is \emph{used}, but not \emph{modified}. Instead, only a new +-- binding is created and all display layer specific interaction is +-- put there. +-- +-- The job of this class is to provide convenient methods that can be +-- called by the display layer. For instance, it provides methods for +-- starting a graph drawing scope, managing the stack of such scope, +-- adding a node to a graph and so on. + +local InterfaceToDisplay = {} + +-- Namespace +require("pgf.gd.interface").InterfaceToDisplay = InterfaceToDisplay + + +-- Imports +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" +local Scope = require "pgf.gd.interface.Scope" + +local Binding = require "pgf.gd.bindings.Binding" + +local Sublayouts = require "pgf.gd.control.Sublayouts" +local LayoutPipeline = require "pgf.gd.control.LayoutPipeline" + +local Digraph = require "pgf.gd.model.Digraph" +local Vertex = require "pgf.gd.model.Vertex" +local Edge = require "pgf.gd.model.Edge" +local Collection = require "pgf.gd.model.Collection" + +local Storage = require "pgf.gd.lib.Storage" +local LookupTable = require "pgf.gd.lib.LookupTable" +local Event = require "pgf.gd.lib.Event" + +local lib = require "pgf.gd.lib" + + +-- Forward declarations +local get_current_options_table +local render_collections +local push_on_option_stack +local vertex_created + +-- Local objects + +local phase_unique = {} -- a unique handle +local collections_unique = {} -- a unique handle +local option_cache = nil -- The option cache + + + + +--- +-- Initialize the binding. This function is called once by the display +-- layer at the very beginning. For instance, \tikzname\ does the +-- following call: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--InterfaceToDisplay.bind(require "pgf.gd.bindings.BindingToPGF") +--\end{codeexample} +-- +-- Inside this call, many standard declarations will be executed, that +-- is, the declared binding will be used immediately. +-- +-- Subsequently, the |binding| field of the |InterfaceCore| can be used. +-- +-- @param class A subclass of |Binding|. + +function InterfaceToDisplay.bind(class) + assert (not InterfaceCore.binding, "binding already initialized") + + -- Create a new object + InterfaceCore.binding = setmetatable({}, class) + + -- Load these libraries, which contain many standard declarations: + require "pgf.gd.model.library" + require "pgf.gd.control.library" +end + + + + +--- +-- Start a graph drawing scope. Note that this is not the same as +-- starting a subgraph / sublayout, which are local to a graph drawing +-- scope: When a new graph drawing scope is started, it is pushed on +-- top of a stack of graph drawing scopes and all other ``open'' +-- scopes are no longer directly accessible. All method calls to an +-- |Interface...| object will refer to this newly created scope until +-- either a new scope is opened or until the current scope is closed +-- once more. +-- +-- Each graph drawing scope comes with a syntactic digraph that is +-- build using methods like |addVertex| or |addEdge|. +-- +-- @param height The to-be-used height of the options stack. All +-- options above this height will be popped prior to attacking the +-- options to the syntactic digraph. + +function InterfaceToDisplay.beginGraphDrawingScope(height) + + -- Create a new scope table + local scope = Scope.new {} + + -- Setup syntactic digraph: + local g = scope.syntactic_digraph + + g.options = get_current_options_table(height) + g.syntactic_digraph = g + g.scope = scope + + -- Push scope: + InterfaceCore.scopes[#InterfaceCore.scopes + 1] = scope +end + + + +--- +-- Arranges the current graph using the specified algorithm and options. +-- +-- This function should be called after the graph drawing scope has +-- been opened and the syntactic digraph has been completely +-- specified. It will now start running the algorithm specified +-- through the |algorithm_phase| options. +-- +-- Internally, this function creates a coroutine that will run the current graph +-- drawing algorithm. Coroutines are needed since a graph drawing +-- algorithm may choose to create a new node. In this case, the +-- algorithm needs to be suspended and control must be returned back +-- to the display layer, so that the node can be typeset in order to +-- determine the precise size information. Once this is done, control +-- must be passed back to the exact point inside the algorithm where +-- the node was created. Clearly, all of these actions are exactly +-- what coroutines are for. +-- +-- @return Time it took to run the algorithm + +function InterfaceToDisplay.runGraphDrawingAlgorithm() + + -- Time things + local start = os.clock() + + -- Setup + local scope = InterfaceCore.topScope() + assert(not scope.coroutine, "coroutine already created for current gd scope") + + -- The actual drawing function + local function run () + if #scope.syntactic_digraph.vertices == 0 then + -- Nothing needs to be done + return + end + + LayoutPipeline.run(scope) + end + + scope.coroutine = coroutine.create(run) + + -- Run it: + InterfaceToDisplay.resumeGraphDrawingCoroutine() + + -- End timing: + local stop = os.clock() + + return stop - start +end + + +--- +-- Resume the graph drawing coroutine. +-- +-- This function is the work horse of the coroutine management. It +-- gets called whenever control passes back from the display layer to +-- the algorithm level. We resume the graph drawing coroutine so that the +-- algorithm can start/proceed. The tricky part is when the algorithm +-- yields, but is not done. In this case, the code needed for creating +-- a new node is passed back to the display layer through the binding, +-- which must then execute the code and then resuming the coroutine. +-- +function InterfaceToDisplay.resumeGraphDrawingCoroutine() + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + + -- Asserts + assert(scope.coroutine, "coroutine not created for current gd scope") + + -- Run + local ok, text = coroutine.resume(scope.coroutine) + assert(ok, text) + if coroutine.status(scope.coroutine) ~= "dead" then + -- Ok, ask binding to continue + binding:resumeGraphDrawingCoroutine(text) + end +end + + + +--- Ends the current graph drawing scope. +-- +function InterfaceToDisplay.endGraphDrawingScope() + assert(#InterfaceCore.scopes > 0, "no gd scope open") + InterfaceCore.scopes[#InterfaceCore.scopes] = nil -- pop +end + + + + +--- +-- Creates a new vertex in the syntactic graph of the current graph +-- drawing scope. The display layer should call this function for each +-- node of the graph. The |name| must be a unique string identifying +-- the node. The newly created vertex will be added to the syntactic +-- digraph. The binding function |everyVertexCreation| will then be +-- called, allowing the binding to store information regarding the newly +-- created vertex. +-- +-- For each vertex an event will be created in the event +-- sequence. This event will have the kind |"node"| and its +-- |parameter| will be the vertex. +-- +-- @param name Name of the vertex. +-- +-- @param shape The shape of the vertex such as |"circle"| or +-- |"rectangle"|. This shape may help a graph drawing algorithm +-- figuring out how the node should be placed. +-- +-- @param path A |Path| object representing the vertex's path. +-- +-- @param height The to-be-used height of the options stack. All +-- options above this height will be popped prior to attacking the +-- options to the syntactic digraph. +-- +-- @param binding_infos These options are passed to and are specific +-- to the current |Binding|. +-- +-- @param anchors A table of anchors (mapping anchor positions to +-- |Coordinates|). + + +function InterfaceToDisplay.createVertex(name, shape, path, height, binding_infos, anchors) + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + + -- Does vertex already exist? + local v = scope.node_names[name] + assert (not v or not v.created_on_display_layer, "node already created") + + -- Create vertex + if not v then + v = Vertex.new { + name = name, + shape = shape, + kind = "node", + path = path, + options = get_current_options_table(height), + anchors = anchors, + } + + vertex_created(v,scope) + else + assert(v.kind == "subgraph node", "subgraph node expected") + v.shape = shape + v.path = path + v.anchors = anchors + end + + v.created_on_display_layer = true + + -- Call binding + binding.storage[v] = binding_infos + binding:everyVertexCreation(v) +end + + +-- This is a helper function +function vertex_created(v,scope) + + -- Create Event + local e = InterfaceToDisplay.createEvent ("node", v) + v.event = e + + -- Create name lookup + scope.node_names[v.name] = v + + -- Add vertex to graph + scope.syntactic_digraph:add {v} + + -- Add to collections + for _,c in ipairs(v.options.collections) do + LookupTable.addOne(c.vertices, v) + end + +end + + + +--- +-- Creates a new vertex in the syntactic graph of the current graph +-- drawing scope that is a subgraph vertex. Such a vertex +-- ``surrounds'' the vertices of a subgraph. The special property of a +-- subgraph node opposed to a normal node is that it is created only +-- after the subgraph has been laid out. However, the difference to a +-- collection like |hyper| is that the node is available immediately as +-- a normal node in the sense that you can connect edges to it. +-- +-- What happens internally is that subgraph nodes get ``registered'' +-- immediately both on the display level and on the algorithm level, +-- but the actual node is only created inside the layout pipeline +-- using a callback of the binding. The present function is used to +-- perform this registering. The node creation happens when the +-- innermost layout in which the subgraph node is declared has +-- finished. For each subgraph node, a collection is created that +-- contains all vertices (and edges) being part of the subgraph. For +-- this reason, this method is a |push...| method, since it pushes +-- something on the options stack. +-- +-- The |init| parameter will be used during the creation of the node, +-- see |Binding:createVertex| for details on the fields. Note that +-- |init.text| is often not displayed for such ``vast'' nodes as those +-- created for whole subgraphs, but a shape may use it nevertheless +-- (for instance, one might display this text at the top of the node +-- or, in case of a \textsc{uml} package, in a special box above the +-- actual node). +-- +-- The |init.generated_options| will be augmented by additional +-- key--value pairs when the vertex is created: +-- % +-- \begin{itemize} +-- \item The key |subgraph point cloud| will have as its value a +-- string that is be a list of points (without separating commas) +-- like |"(10pt,20pt)(0pt,0pt)(30pt,40pt)"|, always in +-- this syntax. The list will contain all points inside the +-- subgraph. In particular, a bounding box around these points will +-- encompass all nodes and bend points of the subgraph. +-- The bounding box of this point cloud is guaranteed to be centered on +-- the origin. +-- \item The key |subgraph bounding box width| will have as its value +-- the width of a bounding box (in \TeX\ points, as a string with the +-- suffix |"pt"|). +-- \item The key |subgraph bounding box height| stores the height of a +-- bounding box. +-- \end{itemize} +-- +-- @param name The name of the node. +-- @param height Height of the options stack. Note that this method +-- pushes something (namely a collection) on the options stack. +-- @param info A table passed to |Binding:createVertex|, see that function. +-- +function InterfaceToDisplay.pushSubgraphVertex(name, height, info) + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + + -- Does vertex already exist? + assert (not scope.node_names[name], "node already created") + + -- Create vertex + local v = Vertex.new { + name = name, + kind = "subgraph node", + options = get_current_options_table(height-1) + } + + vertex_created(v,scope) + + -- Store info + info.generated_options = info.generated_options or {} + info.name = name + v.subgraph_info = info + + -- Create collection and link it to v + local _, _, entry = InterfaceToDisplay.pushOption(InterfaceCore.subgraph_node_kind, nil, height) + v.subgraph_collection = entry.value + v.subgraph_collection.subgraph_node = v + + -- Find parent collection in options stack: + local collections = v.options.collections + for i=#collections,1,-1 do + if collections[i].kind == InterfaceCore.sublayout_kind then + v.subgraph_collection.parent_layout = collections[i] + break + end + end +end + + + +--- +-- Add options for an already existing vertex. +-- +-- This function allows you to add options to an already existing +-- vertex. The options that will be added are all options on the +-- current options stack; they will overwrite existing options of the +-- same name. For collections, the vertex stays in all collections it +-- used to, it is only added to all collections that are currently on +-- the options stack. +-- +-- @param name Name of the vertex. +-- @param height The option stack height. + +function InterfaceToDisplay.addToVertexOptions(name, height) + + -- Setup + local scope = InterfaceCore.topScope() + + -- Does vertex already exist? + local v = assert (scope.node_names[name], "node is missing, cannot add options") + + v.options = get_current_options_table(height, v.options) + + -- Add to collections + for _,c in ipairs(v.options.collections) do + LookupTable.addOne(c.vertices, v) + end + +end + + + + + +--- +-- Creates a new edge in the syntactic graph of the current graph +-- drawing scope. The display layer should call this function for each +-- edge that is created. Both the |from| vertex and the |to| vertex +-- must exist (have been created through |createVertex|) prior to your +-- being able to call this function. +-- +-- After the edge has been created, the binding layer's function +-- |everyEdgeCreation| will be called, allowing the binding layer to +-- store information about the edge. +-- +-- For each edge an event is created, whose kind is |"edge"| and whose +-- |parameter| is a two-element array whose first entry is the edge's +-- arc in the syntactic digraph and whose second entry is the position +-- of the edge in the arc's array of syntactic edges. +-- +-- @param tail Name of the node the edge begins at. +-- @param head Name of the node the edge ends at. +-- @param direction Direction of the edge (e.g. |--| for an undirected edge +-- or |->| for a directed edge from the first to the second +-- node). +-- @param height The option stack height, see for instance |createVertex|. +-- +-- @param binding_infos These options will be stored in the |storage| +-- of the vertex at the field index by the binding. + +function InterfaceToDisplay.createEdge(tail, head, direction, height, binding_infos) + + -- Setup + local scope = InterfaceCore.topScope() + local binding = InterfaceCore.binding + + -- Does vertex already exist? + local h = scope.node_names[head] + local t = scope.node_names[tail] + assert (h and t, "attempting to create edge between nodes that are not in the graph") + + -- Create Arc object + local arc = scope.syntactic_digraph:connect(t, h) + + -- Create Edge object + local edge = Edge.new { + head = h, + tail = t, + direction = direction, + options = get_current_options_table(height) + } + + -- Add to arc + arc.syntactic_edges[#arc.syntactic_edges+1] = edge + + -- Create Event + local e = InterfaceToDisplay.createEvent ("edge", { arc, #arc.syntactic_edges }) + edge.event = e + + -- Make part of collections + for _,c in ipairs(edge.options.collections) do + LookupTable.addOne(c.edges, edge) + end + + -- Call binding + binding.storage[edge] = binding_infos + binding:everyEdgeCreation(edge) + +end + + + + + +--- +-- Push an option to the stack of options. +-- +-- As a graph is parsed, a stack of ``current options'' +-- is created. To add something to this table, the display layers may +-- call the method |pushOption|. To pop something from this stack, +-- just set the |height| value during the next push to the position to +-- which you actually wish to push something; everything above and +-- including this position will be popped from the stack. +-- +-- When an option is pushed, several additional options may also be +-- pushed, namely whenever the option has a |use| field set. These +-- additional options may, in turn, also push new options. Because of +-- this, this function returns a new stack height, representing the +-- resulting stack height. +-- +-- In addition to this stack height, this function returns a Boolean +-- value indicating whether a ``main algorithm phase was set''. This +-- happens whenever a key is executed (directly or indirectly through +-- the |use| field) that selects an algorithm for the ``main'' +-- algorithm phase. This information may help the caller to setup the +-- graph drawing scopes correctly. +-- +-- @param key A parameter (must be a string). +-- @param value A value (can be anything). If it is a string, it will +-- be converted to whatever the key expects. +-- @param height A stack height at which to insert the key. Everything +-- above this height will be removed. +-- +-- @return A new stack height +-- @return A Boolean that is |true| if the main algorithm phase was +-- set by the option or one option |use|d by it. +-- @return The newly created entry on the stack. If more entries are +-- created through the use of the |use| field, the original entry is +-- returned nevertheless. + + +function InterfaceToDisplay.pushOption(key, value, height) + assert(type(key) == "string", "illegal key") + + local key_record = assert(InterfaceCore.keys[key], "unknown key") + local main_phase_set = false + + if value == nil and key_record.default then + value = key_record.default + end + + -- Find out what kind of key we are pushing: + + if key_record.algorithm then + -- Push a phase + if type(InterfaceCore.algorithm_classes[key]) == "function" then + -- Call the constructor function + InterfaceCore.algorithm_classes[key] = InterfaceCore.algorithm_classes[key]() + end + + local algorithm = InterfaceCore.algorithm_classes[key] + + assert (algorithm, "algorithm class not found") + + push_on_option_stack(phase_unique, + { phase = value or key_record.phase, algorithm = algorithm }, + height) + + if key_record.phase == "main" then + main_phase_set = true + end + + elseif key_record.layer then + -- Push a collection + local stack = InterfaceCore.option_stack + local scope = InterfaceCore.topScope() + + -- Get the stack above "height": + local options = get_current_options_table(height-1) + + -- Create the collection event + local event = InterfaceToDisplay.createEvent ("collection", key) + + -- Create collection object: + local collection = Collection.new { kind = key, options = options, event = event } + + -- Store in collections table of current scope: + local collections = scope.collections[key] or {} + collections[#collections + 1] = collection + scope.collections[key] = collections + + -- Build collection tree + collection:registerAsChildOf(options.collections[#options.collections]) + + -- Push on stack + push_on_option_stack(collections_unique, collection, height) + + else + + -- A normal key + push_on_option_stack(key, InterfaceCore.convert(value, InterfaceCore.keys[key].type), height) + + end + + local newly_created = InterfaceCore.option_stack[#InterfaceCore.option_stack] + + -- Now, push use keys: + local use = key_record.use + if key_record.use then + local flag + for _,u in ipairs(InterfaceCore.keys[key].use) do + local use_k = u.key + local use_v = u.value + if type(use_k) == "function" then + use_k = use_k(value) + end + if type(use_v) == "function" then + use_v = use_v(value) + end + height, flag = InterfaceToDisplay.pushOption(use_k, use_v, height+1) + main_phase_set = main_phase_set or flag + end + end + + return height, main_phase_set, newly_created +end + + +--- +-- Push a layout on the stack of options. As long as this layout is on +-- the stack, all vertices and edges will be part of this layout. For +-- details on layouts, please see |Sublayouts|. +-- +-- @param height A stack height at which to insert the key. Everything +-- above this height will be removed. + +function InterfaceToDisplay.pushLayout(height) + InterfaceToDisplay.pushOption(InterfaceCore.sublayout_kind, nil, height) +end + + + +--- +-- Creates an event and adds it to the event string of the current scope. +-- +-- @param kind Name/kind of the event. +-- @param parameters Parameters of the event. +-- +-- @return The newly pushed event +-- +function InterfaceToDisplay.createEvent(kind, param) + local scope = InterfaceCore.topScope() + local n = #scope.events + 1 + local e = Event.new { kind = kind, parameters = param, index = n } + scope.events[n] = e + + return e +end + + + +--- +-- This method allows you to query the table of all declared keys. It +-- contains them both as an array and also as a table index by the +-- keys's names. In particular, you can then iterate over it using +-- |ipairs| and you can check whether a key is defined by accessing +-- the table at the key's name. Each entry of the table is the +-- original table passed to |InterfaceToAlgorithms.declare|. +-- +-- @return A lookup table of all declared keys. + +function InterfaceToDisplay.getDeclaredKeys() + return InterfaceCore.keys +end + + + + +--- +-- Renders the graph. +-- +-- This function is called after the graph has been laid out by the +-- graph drawing algorithms. It will trigger a sequence of calls to +-- the binding layer that will, via callbacks, start rendering the +-- whole graph. +-- +-- In detail, this function calls: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local binding = InterfaceCore.binding +-- +--binding:renderStart() +--render_vertices() +--render_edges() +--render_collections() +--binding:renderStop() +--\end{codeexample} +-- +-- Here, the |render_...| functions are local, internal functions that are, +-- nevertheless, documented here. +-- +-- @param name Returns the algorithm class that has been declared using +-- |declare| under the given name. + +function InterfaceToDisplay.renderGraph() + local scope = InterfaceCore.topScope() + local syntactic_digraph = scope.syntactic_digraph + + local binding = InterfaceCore.binding + + binding:renderStart() + render_vertices(syntactic_digraph.vertices) + render_edges(syntactic_digraph.arcs) + render_collections(scope.collections) + binding:renderStop() +end + + + + + +--- +-- Render the vertices after the graph drawing algorithm has +-- finished. This function is local and internal and included only for +-- documenting the call graph. +-- +-- When the graph drawing algorithm is done, the interface will start +-- rendering the vertices by calling appropriate callbacks of the +-- binding layer. +-- +-- Consider the following code: +-- % +--\begin{codeexample}[code only] +--\graph [... layout] { +-- a -- b -- c -- d; +--}; +--\end{codeexample} +-- +-- In this case, after the graph drawing algorithm has run, the +-- present function will call: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local binding = InterfaceCore.binding +-- +--binding:renderVerticesStart() +--binding:renderVertex(vertex_a) +--binding:renderVertex(vertex_b) +--binding:renderVertex(vertex_c) +--binding:renderVertex(vertex_d) +--binding:renderVerticesStop() +--\end{codeexample} +-- +-- @param vertices An array of all vertices in the syntactic digraph. + +function render_vertices(vertices) + InterfaceCore.binding:renderVerticesStart() + for _,vertex in ipairs(vertices) do + InterfaceCore.binding:renderVertex(vertex) + end + InterfaceCore.binding:renderVerticesStop() +end + + +--- +-- Render the collections whose layer is not |0|. This local, internal +-- function is called to render the different collection kinds. +-- +-- Collection kinds rendered in the order provided by the |layer| +-- field passed to |declare| during the declaration of the collection +-- kind, see also |declare_collection|. If several collection kinds +-- have the same layer, they are rendered in lexicographical ordering +-- (to ensure that they are always rendered in the same order). +-- +-- Consider the following code: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--declare { key = "hyper", layer = 1 } +--\end{codeexample} +-- you can say on the \tikzname\ layer +--\begin{codeexample}[code only] +--\graph { +-- a, b, c, d; +-- { [hyper] a, b, c } +-- { [hyper] b, c, d } +--}; +--\end{codeexample} +-- +-- In this case, after the graph drawing algorithm has run, the +-- present function will call: +-- +--\begin{codeexample}[code only, tikz syntax=false] +--local binding = InterfaceCore.binding +-- +--binding:renderCollectionStartKind("hyper", 1) +--binding:renderCollection(collection_containing_abc) +--binding:renderCollection(collection_containing_bcd) +--binding:renderCollectionStopKind("hyper", 1) +--\end{codeexample} +-- +-- @param collections The |collections| table of the current scope. + +function render_collections(collections) + local kinds = InterfaceCore.collection_kinds + local binding = InterfaceCore.binding + + for i=1,#kinds do + local kind = kinds[i].kind + local layer = kinds[i].layer + + if layer ~= 0 then + binding:renderCollectionStartKind(kind, layer) + for _,c in ipairs(collections[kind] or {}) do + binding:renderCollection(c) + end + binding:renderCollectionStopKind(kind, layer) + end + end +end + + +--- +-- Render the syntactic edges of a graph after the graph drawing +-- algorithm has finished. This function is local and internal and included only +-- for documenting the call graph. +-- +-- When the graph drawing algorithm is done, the interface will first +-- rendering the vertices using |render_vertices|, followed by calling +-- this function, which in turn calls appropriate callbacks to the +-- binding layer. +-- +-- Consider the following code: +-- % +--\begin{codeexample}[code only] +-- \graph [... layout] { +-- a -- b -- c -- d; +-- }; +--\end{codeexample} +-- +-- In this case, after the graph drawing algorithm has run, the +-- present function will call: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +-- local binding = InterfaceCore.binding +-- +-- binding:renderEdgesStart() +-- binding:renderEdge(edge_from_a_to_b) +-- binding:renderEdge(edge_from_b_to_c) +-- binding:renderEdge(edge_from_c_to_d) +-- binding:renderEdgesStop() +--\end{codeexample} +-- +-- @param arcs The array of arcs of the syntactic digraph. + +function render_edges(arcs) + InterfaceCore.binding:renderEdgesStart() + for _,a in ipairs(arcs) do + for _,e in ipairs (a.syntactic_edges) do + InterfaceCore.binding:renderEdge(e) + end + end + InterfaceCore.binding:renderEdgesStop() +end + + +local aliases = InterfaceCore.option_aliases +local option_initial = InterfaceCore.option_initial + +local option_metatable = { + __index = + function (t, key) + local k = aliases[key] + if k then + local v = (type(k) == "string" and t[k]) or (type(k) == "function" and k(t)) or nil + if v ~= nil then + return v + end + end + return option_initial[key] + end +} + + +--- +-- Get the current options table. +-- +-- An option table can be accessed like a normal table; however, there +-- is a global fallback for this table. If an index is not defined, +-- the value of this index in the global fallback table is used. (This +-- reduces the overall amount of option keys that need to be stored +-- with object.) +-- +-- (This function is local and internal and included only for documentation +-- purposes.) +-- +-- @param height The stack height for which the option table is +-- required. +-- @param table If non |nil|, the options will be added to this +-- table. +-- +-- @return The option table as described above. + +function get_current_options_table (height, table) + local stack = InterfaceCore.option_stack + assert (height >= 0 and height <= #stack, "height value out of bounds") + + if height == InterfaceCore.option_cache_height and not table then + return option_cache + else + -- Clear superfluous part of stack + for i=#stack,height+1,-1 do + stack[i] = nil + end + + -- Build options table + local cache + if not table then + cache = setmetatable( + { + algorithm_phases = setmetatable({}, InterfaceCore.option_initial.algorithm_phases), + collections = {} + }, option_metatable) + else + cache = lib.copy(table) + cache.algorithm_phases = lib.copy(cache.algorithm_phases) + cache.collections = lib.copy(cache.collections) + end + + local algorithm_phases = cache.algorithm_phases + local collections = cache.collections + local keys = InterfaceCore.keys + + local function handle (k, v) + if k == phase_unique then + algorithm_phases[v.phase] = v.algorithm + local phase_stack = v.phase .. " stack" + local t = rawget(algorithm_phases, phase_stack) + if not t then + t = algorithm_phases[phase_stack] + assert(type(t) == "table", "unknown phase") + t = lib.copy(t) + algorithm_phases[phase_stack] = t + end + t[#t + 1] = v.algorithm + elseif k == collections_unique then + LookupTable.addOne(collections, v) + else + cache[k] = v + end + end + + for _,s in ipairs(stack) do + handle (s.key, s.value) + end + + -- Cache it, if this was not added: + if not table then + InterfaceCore.option_cache_height = height + option_cache = cache + end + + return cache + end +end + + + +-- A helper function + +function push_on_option_stack(key, value, height) + local stack = InterfaceCore.option_stack + + assert (type(height) == "number" and height > 0 and height <= #stack + 1, + "height value out of bounds") + + -- Clear superfluous part of stack + for i=#stack,height+1,-1 do + stack[i] = nil + end + + stack[height] = { key = key, value = value } + InterfaceCore.option_cache_height = nil -- invalidate cache +end + + + +-- Done + +return InterfaceToDisplay diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/Scope.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/Scope.lua new file mode 100644 index 0000000000..a750308e69 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/interface/Scope.lua @@ -0,0 +1,92 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- In theory, graph drawing algorithms take graphs as input and +-- output graphs embedded into the plane as output. In practice, however, +-- the input to a graph drawing algorithm is not ``just'' the +-- graph. Rather, additional information about the graph, in particular +-- about the way the user specified the graph, is also important to many +-- graph drawing algorithms. +-- +-- The graph drawing system gathers both the original input graph as well +-- as all additional information that is provided in the graph drawing +-- scope inside a scope table. The object has a number of fields that +-- inform an algorithm about the input. +-- +-- For each graph drawing scope, a new |Scope| object is +-- created. Graph drawing scopes are kept track of using a stack, but +-- only the top of this stack is available to the interface classes. +-- +-- @field syntactic_digraph The syntactic digraph is a digraph that +-- faithfully encodes the way the input graph is represented +-- syntactically. However, this does not mean that the syntactic +-- digraph contains the actual textual representation of the input +-- graph. Rather, when an edge is specified as, say, |a <- b|, the +-- syntactic digraph will contains an arc from |a| to |b| with an edge +-- object attached to it that is labeled as a ``backward'' +-- edge. Similarly, an edge |a -- b| is also stored as a directed arc +-- from |a| to |b| with the label |--| attached to it. Algorithms will +-- often be more interested graphs derived from the syntactic digraph +-- such as its underlying undirected graph. These derived graphs are +-- made accessible by the graph drawing engine during the preprocessing. +-- +-- @field events An array of |Event| objects. These objects, see the +-- |Event| class for details, are created during the parsing of the +-- input graph. +-- +-- @field node_names A table that maps the names of nodes to node +-- objects. Every node must have a unique name. +-- +-- @field coroutine A Lua coroutine that is used internally to allow +-- callbacks to the display layer to be issued deep down during a run +-- of an algorithm. +-- +-- @field collections The collections specified inside the scope, see +-- the |Collection| class. + +local Scope = {} +Scope.__index = Scope + +-- Namespace +require("pgf.gd.interface").Scope = Scope + +-- Imports +local lib = require "pgf.gd.lib" +local Storage = require "pgf.gd.lib.Storage" + +local Digraph = require "pgf.gd.model.Digraph" + +--- +-- Create a new |Scope| object. +-- +-- @param initial A table of initial values for the newly created +-- |Scope| object. +-- +-- @return The new scope object. + +function Scope.new(initial) + return setmetatable(lib.copy(initial, + { + syntactic_digraph = Digraph.new{}, + events = {}, + node_names = {}, + coroutine = nil, + collections = {}, + }), Scope) +end + + +-- Done + +return Scope diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered.lua new file mode 100644 index 0000000000..6988e7a3d9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered.lua @@ -0,0 +1,159 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + +local layered = {} + +-- Namespace + +require("pgf.gd").layered = layered + + +local lib = require "pgf.gd.lib" +local Storage = require "pgf.gd.lib.Storage" + +-- +-- This file defines some basic functions to compute and/or set the +-- ideal distances between nodes of any kind of layered drawing of a +-- graph. + + +--- +-- Compute the ideal distance between two siblings +-- +-- @param paddings A |Storage| object in which the computed distances +-- (paddings) are stored. +-- @param graph The graph object +-- @param n1 The first node +-- @param n2 The second node + +function layered.ideal_sibling_distance (paddings, graph, n1, n2) + local ideal_distance + local sep + + local n1_is_node = n1.kind == "node" + local n2_is_node = n2.kind == "node" + + if not n1_is_node and not n2_is_node then + ideal_distance = graph.options['sibling distance'] + sep = graph.options['sibling post sep'] + + graph.options['sibling pre sep'] + else + if n1_is_node then + ideal_distance = lib.lookup_option('sibling distance', n1, graph) + else + ideal_distance = lib.lookup_option('sibling distance', n2, graph) + end + sep = (n1_is_node and lib.lookup_option('sibling post sep', n1, graph) or 0) + + (n2_is_node and lib.lookup_option('sibling pre sep', n2, graph) or 0) + end + + return math.max(ideal_distance, sep + + ((n1_is_node and paddings[n1].sibling_post) or 0) - + ((n2_is_node and paddings[n2].sibling_pre) or 0)) +end + + + +--- +-- Compute the baseline distance between two layers +-- +-- The "baseline" distance is the distance between two layers that +-- corresponds to the distance of the two layers if the nodes where +-- "words" on two adjacent lines. In this case, the distance is +-- normally the layer_distance, but will be increased such that if we +-- draw a horizontal line below the deepest character on the first +-- line and a horizontal line above the highest character on the +-- second line, the lines will have a minimum distance of layer sep. +-- +-- Since each node on the lines might have a different layer sep and +-- layer distance specified, the maximum over all the values is taken. +-- +-- @param paddings A |Storage| object in which the distances +-- (paddings) are stored. +-- @param graph The graph in which the nodes reside +-- @param l1 An array of the nodes of the first layer +-- @param l2 An array of the nodes of the second layer + +function layered.baseline_distance (paddings, graph, l1, l2) + + if #l1 == 0 or #l2 == 0 then + return 0 + end + + local layer_distance = -math.huge + local layer_pre_sep = -math.huge + local layer_post_sep = -math.huge + + local max_post = -math.huge + local min_pre = math.huge + + for _,n in ipairs(l1) do + layer_distance = math.max(layer_distance, lib.lookup_option('level distance', n, graph)) + layer_post_sep = math.max(layer_post_sep, lib.lookup_option('level post sep', n, graph)) + if n.kind == "node" then + max_post = math.max(max_post, paddings[n].layer_post) + end + end + + for _,n in ipairs(l2) do + layer_pre_sep = math.max(layer_pre_sep, lib.lookup_option('level pre sep', n, graph)) + if n.kind == "node" then + min_pre = math.min(min_pre, paddings[n].layer_pre) + end + end + + return math.max(layer_distance, layer_post_sep + layer_pre_sep + max_post - min_pre) +end + + + +--- +-- Position nodes in layers using baselines +-- +-- @param layers A |Storage| object assigning layers to vertices. +-- @param paddings A |Storage| object storing the computed distances +-- (paddings). +-- @param graph The graph in which the nodes reside + +function layered.arrange_layers_by_baselines (layers, paddings, graph) + + local layer_vertices = Storage.newTableStorage() + + -- Decompose into layers: + for _,v in ipairs(graph.vertices) do + table.insert(layer_vertices[layers[v]], v) + end + + if #layer_vertices > 0 then -- sanity check + -- Now compute ideal distances and store + local height = 0 + + for _,v in ipairs(layer_vertices[1]) do + v.pos.y = 0 + end + + for i=2,#layer_vertices do + height = height + layered.baseline_distance(paddings, graph, layer_vertices[i-1], layer_vertices[i]) + + for _,v in ipairs(layer_vertices[i]) do + v.pos.y = height + end + end + end +end + + + + +-- Done + +return layered diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua new file mode 100644 index 0000000000..da9ff9698c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua @@ -0,0 +1,342 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local CrossingMinimizationGansnerKNV1993 = {} + + +-- Imports + +local lib = require "pgf.gd.lib" +local DepthFirstSearch = require "pgf.gd.lib.DepthFirstSearch" + + + +function CrossingMinimizationGansnerKNV1993:run() + + self:computeInitialRankOrdering() + + local best_ranking = self.ranking:copy() + local best_crossings = self:countRankCrossings(best_ranking) + + for iteration=1,24 do + local direction = (iteration % 2 == 0) and 'down' or 'up' + + self:orderByWeightedMedian(direction) + self:transpose(direction) + + local current_crossings = self:countRankCrossings(self.ranking) + + if current_crossings < best_crossings then + best_ranking = self.ranking:copy() + best_crossings = current_crossings + end + end + + self.ranking = best_ranking:copy() + + return self.ranking +end + + + +function CrossingMinimizationGansnerKNV1993:computeInitialRankOrdering() + + local best_ranking = self.ranking:copy() + local best_crossings = self:countRankCrossings(best_ranking) + + for _,direction in ipairs({'down', 'up'}) do + + local function init(search) + for i=#self.graph.nodes,1,-1 do + local node = self.graph.nodes[i] + if direction == 'down' then + if node:getInDegree() == 0 then + search:push(node) + search:setDiscovered(node) + end + else + if node:getOutDegree() == 0 then + search:push(node) + search:setDiscovered(node) + end + end + end + end + + local function visit(search, node) + search:setVisited(node, true) + + local rank = self.ranking:getRank(node) + local pos = self.ranking:getRankSize(rank) + self.ranking:setRankPosition(node, pos) + + if direction == 'down' then + local out = node:getOutgoingEdges() + for i=#out,1,-1 do + local neighbour = out[i]:getNeighbour(node) + if not search:getDiscovered(neighbour) then + search:push(neighbour) + search:setDiscovered(neighbour) + end + end + else + local into = node:getIncomingEdges() + for i=#into,1,-1 do + local neighbour = into[i]:getNeighbour(node) + if not search:getDiscovered(neighbour) then + search:push(neighbour) + search:setDiscovered(neighbour) + end + end + end + end + + DepthFirstSearch.new(init, visit):run() + + local crossings = self:countRankCrossings(self.ranking) + + if crossings < best_crossings then + best_ranking = self.ranking:copy() + best_crossings = crossings + end + end + + self.ranking = best_ranking:copy() + +end + + + +function CrossingMinimizationGansnerKNV1993:countRankCrossings(ranking) + + local crossings = 0 + + local ranks = ranking:getRanks() + + for rank_index = 2, #ranks do + local nodes = ranking:getNodes(ranks[rank_index]) + for i = 1, #nodes-1 do + for j = i+1, #nodes do + local v = nodes[i] + local w = nodes[j] + + -- TODO Jannis: We are REQUIRED to only check edges that lead to nodes + -- on the next or previous rank, depending on the sweep direction!!!! + local cn_vw = self:countNodeCrossings(ranking, v, w, 'down') + + crossings = crossings + cn_vw + end + end + end + + return crossings +end + + + +function CrossingMinimizationGansnerKNV1993:countNodeCrossings(ranking, left_node, right_node, sweep_direction) + + local ranks = ranking:getRanks() + local _, rank_index = lib.find(ranks, function (rank) + return rank == ranking:getRank(left_node) + end) + local other_rank_index = (sweep_direction == 'down') and rank_index-1 or rank_index+1 + + assert(ranking:getRank(left_node) == ranking:getRank(right_node)) + assert(rank_index >= 1 and rank_index <= #ranks) + + -- 0 crossings if we're at the top or bottom and are sweeping down or up + if other_rank_index < 1 or other_rank_index > #ranks then + return 0 + end + + local left_edges = {} + local right_edges = {} + + if sweep_direction == 'down' then + left_edges = left_node:getIncomingEdges() + right_edges = right_node:getIncomingEdges() + else + left_edges = left_node:getOutgoingEdges() + right_edges = right_node:getOutgoingEdges() + end + + local crossings = 0 + + local function left_neighbour_on_other_rank(edge) + local neighbour = edge:getNeighbour(left_node) + return ranking:getRank(neighbour) == ranking:getRanks()[other_rank_index] + end + + local function right_neighbour_on_other_rank(edge) + local neighbour = edge:getNeighbour(right_node) + return ranking:getRank(neighbour) == ranking:getRanks()[other_rank_index] + end + + for _,left_edge in ipairs(left_edges) do + if left_neighbour_on_other_rank(left_edge) then + local left_neighbour = left_edge:getNeighbour(left_node) + + for _,right_edge in ipairs(right_edges) do + if right_neighbour_on_other_rank(right_edge) then + local right_neighbour = right_edge:getNeighbour(right_node) + + local left_position = ranking:getRankPosition(left_neighbour) + local right_position = ranking:getRankPosition(right_neighbour) + + local neighbour_diff = right_position - left_position + + if neighbour_diff < 0 then + crossings = crossings + 1 + end + end + end + end + end + + return crossings +end + + + +function CrossingMinimizationGansnerKNV1993:orderByWeightedMedian(direction) + + local median = {} + + local function get_index(n, node) return median[node] end + local function is_fixed(n, node) return median[node] < 0 end + + if direction == 'down' then + local ranks = self.ranking:getRanks() + + for rank_index = 2, #ranks do + median = {} + local nodes = self.ranking:getNodes(ranks[rank_index]) + for _,node in ipairs(nodes) do + median[node] = self:computeMedianPosition(node, ranks[rank_index-1]) + end + + self.ranking:reorderRank(ranks[rank_index], get_index, is_fixed) + end + else + local ranks = self.ranking:getRanks() + + for rank_index = 1, #ranks-1 do + median = {} + local nodes = self.ranking:getNodes(ranks[rank_index]) + for _,node in ipairs(nodes) do + median[node] = self:computeMedianPosition(node, ranks[rank_index+1]) + end + + self.ranking:reorderRank(ranks[rank_index], get_index, is_fixed) + end + end +end + + + +function CrossingMinimizationGansnerKNV1993:computeMedianPosition(node, prev_rank) + + local positions = lib.imap( + node.edges, + function (edge) + local n = edge:getNeighbour(node) + if self.ranking:getRank(n) == prev_rank then + return self.ranking:getRankPosition(n) + end + end) + + table.sort(positions) + + local median = math.ceil(#positions / 2) + local position = -1 + + if #positions > 0 then + if #positions % 2 == 1 then + position = positions[median] + elseif #positions == 2 then + return (positions[1] + positions[2]) / 2 + else + local left = positions[median-1] - positions[1] + local right = positions[#positions] - positions[median] + position = (positions[median-1] * right + positions[median] * left) / (left + right) + end + end + + return position +end + + + +function CrossingMinimizationGansnerKNV1993:transpose(sweep_direction) + + local function transpose_rank(rank) + + local improved = false + + local nodes = self.ranking:getNodes(rank) + + for i = 1, #nodes-1 do + local v = nodes[i] + local w = nodes[i+1] + + local cn_vw = self:countNodeCrossings(self.ranking, v, w, sweep_direction) + local cn_wv = self:countNodeCrossings(self.ranking, w, v, sweep_direction) + + if cn_vw > cn_wv then + improved = true + + self:switchNodePositions(v, w) + end + end + + return improved + end + + local ranks = self.ranking:getRanks() + + local improved = false + repeat + local improved = false + + if sweep_direction == 'down' then + for rank_index = 1, #ranks-1 do + improved = transpose_rank(ranks[rank_index]) or improved + end + else + for rank_index = #ranks-1, 1, -1 do + improved = transpose_rank(ranks[rank_index]) or improved + end + end + until not improved +end + + + +function CrossingMinimizationGansnerKNV1993:switchNodePositions(left_node, right_node) + assert(self.ranking:getRank(left_node) == self.ranking:getRank(right_node)) + assert(self.ranking:getRankPosition(left_node) < self.ranking:getRankPosition(right_node)) + + local left_position = self.ranking:getRankPosition(left_node) + local right_position = self.ranking:getRankPosition(right_node) + + self.ranking:switchPositions(left_node, right_node) + + local nodes = self.ranking:getNodes(self.ranking:getRank(left_node)) +end + + + +-- done + +return CrossingMinimizationGansnerKNV1993 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua new file mode 100644 index 0000000000..76deb8adaf --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua @@ -0,0 +1,74 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local CycleRemovalBergerS1990a = {} + +local lib = require("pgf.gd.lib") + + +function CycleRemovalBergerS1990a:run() + -- remember edges that were removed + local removed = {} + + -- remember edges that need to be reversed + local reverse = {} + + -- iterate over all nodes of the graph + for _,node in ipairs(self.graph.nodes) do + -- get all outgoing edges that have not been removed yet + local out_edges = lib.imap(node:getOutgoingEdges(), + function (edge) + if not removed[edge] then return edge end + end) + + -- get all incoming edges that have not been removed yet + local in_edges = lib.imap(node:getIncomingEdges(), + function (edge) + if not removed[edge] then return edge end + end) + + if #out_edges >= #in_edges then + -- we have more outgoing than incoming edges, reverse all incoming + -- edges and mark all incident edges as removed + + for _,edge in ipairs(out_edges) do + removed[edge] = true + end + for _,edge in ipairs(in_edges) do + reverse[edge] = true + removed[edge] = true + end + else + -- we have more incoming than outgoing edges, reverse all outgoing + -- edges and mark all incident edges as removed + + for _,edge in ipairs(out_edges) do + reverse[edge] = true + removed[edge] = true + end + for _,edge in ipairs(in_edges) do + removed[edge] = true + end + end + end + + -- mark edges as reversed + for edge in pairs(reverse) do + edge.reversed = true + end +end + + + +-- done + +return CycleRemovalBergerS1990a diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua new file mode 100644 index 0000000000..d8f28980c8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua @@ -0,0 +1,76 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local CycleRemovalBergerS1990b = {} + +local lib = require("pgf.gd.lib") + + +function CycleRemovalBergerS1990b:run() + -- remember edges that were removed + local removed = {} + + -- remember edges that need to be reversed + local reverse = {} + + -- iterate over all nodes of the graph + for _,j in ipairs(lib.random_permutation(#self.graph.nodes)) do + local node = self.graph.nodes[j] + -- get all outgoing edges that have not been removed yet + -- get all outgoing edges that have not been removed yet + local out_edges = lib.imap(node:getOutgoingEdges(), + function (edge) + if not removed[edge] then return edge end + end) + + -- get all incoming edges that have not been removed yet + local in_edges = lib.imap(node:getIncomingEdges(), + function (edge) + if not removed[edge] then return edge end + end) + + if #out_edges >= #in_edges then + -- we have more outgoing than incoming edges, reverse all incoming + -- edges and mark all incident edges as removed + + for _,edge in ipairs(out_edges) do + removed[edge] = true + end + for _,edge in ipairs(in_edges) do + reverse[edge] = true + removed[edge] = true + end + else + -- we have more incoming than outgoing edges, reverse all outgoing + -- edges and mark all incident edges as removed + + for _,edge in ipairs(out_edges) do + reverse[edge] = true + removed[edge] = true + end + for _,edge in ipairs(in_edges) do + removed[edge] = true + end + end + end + + -- mark edges as reversed + for edge in pairs(reverse) do + edge.reversed = true + end +end + + + +-- done + +return CycleRemovalBergerS1990b diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalEadesLS1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalEadesLS1993.lua new file mode 100644 index 0000000000..ffb919b209 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalEadesLS1993.lua @@ -0,0 +1,124 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +-- Declare +local CycleRemovalEadesLS1993 = {} + +-- Import +local lib = require "pgf.gd.lib" + + +function CycleRemovalEadesLS1993:run() + local copied_graph = self.graph:copy() + + local copied_node = {} + local origin_node = {} + local copied_edge = {} + local origin_edge = {} + + local preserve = {} + + for _,edge in ipairs(self.graph.edges) do + copied_edge[edge] = edge:copy() + origin_edge[copied_edge[edge]] = edge + + for _,node in ipairs(edge.nodes) do + if copied_node[node] then + copied_edge[edge]:addNode(copied_node[node]) + else + copied_node[node] = node:copy() + origin_node[copied_node[node]] = node + + copied_graph:addNode(copied_node[node]) + copied_edge[edge]:addNode(copied_node[node]) + end + end + end + + local function node_is_sink(node) + return node:getOutDegree() == 0 + end + + local function node_is_source(node) + return node:getInDegree() == 0 + end + + local function node_is_isolated(node) + return node:getDegree() == 0 + end + + while #copied_graph.nodes > 0 do + local sink = lib.find(copied_graph.nodes, node_is_sink) + while sink do + for _,edge in ipairs(sink:getIncomingEdges()) do + preserve[edge] = true + end + copied_graph:deleteNode(sink) + sink = lib.find(copied_graph.nodes, node_is_sink) + end + + local isolated_node = lib.find(copied_graph.nodes, node_is_isolated) + while isolated_node do + copied_graph:deleteNode(isolated_node) + isolated_node = lib.find(copied_graph.nodes, node_is_isolated) + end + + local source = lib.find(copied_graph.nodes, node_is_source) + while source do + for _,edge in ipairs(source:getOutgoingEdges()) do + preserve[edge] = true + end + copied_graph:deleteNode(source) + source = lib.find(copied_graph.nodes, node_is_source) + end + + if #copied_graph.nodes > 0 then + local max_node = nil + local max_out_edges = nil + local max_in_edges = nil + + for _,node in ipairs(copied_graph.nodes) do + local out_edges = node:getOutgoingEdges() + local in_edges = node:getIncomingEdges() + + if max_node == nil or (#out_edges - #in_edges > #max_out_edges - #max_in_edges) then + max_node = node + max_out_edges = out_edges + max_in_edges = in_edges + end + end + + assert(max_node and max_out_edges and max_in_edges) + + for _,edge in ipairs(max_out_edges) do + preserve[edge] = true + copied_graph:deleteEdge(edge) + end + for _,edge in ipairs(max_in_edges) do + copied_graph:deleteEdge(edge) + end + + copied_graph:deleteNode(max_node) + end + end + + for _,edge in ipairs(self.graph.edges) do + if not preserve[copied_edge[edge]] then + edge.reversed = true + end + end +end + +-- done + +return CycleRemovalEadesLS1993 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua new file mode 100644 index 0000000000..e52b0d38d1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua @@ -0,0 +1,52 @@ +-- Copyright 2011 by Jannis Pohlmann and 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local CycleRemovalGansnerKNV1993 = {} + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare +local Simplifiers = require "pgf.gd.lib.Simplifiers" + + +function CycleRemovalGansnerKNV1993:run () + -- merge nonempty sets into supernodes + -- + -- ignore self-loops + -- + -- merge multiple edges into one edge each, whose weight is the sum of the + -- individual edge weights + -- + -- ignore leaf nodes that are not part of the user-defined sets (their ranks + -- are trivially determined) + -- + -- ensure that supernodes S_min and S_max are assigned first and last ranks + -- reverse in-edges of S_min + -- reverse out-edges of S_max + -- + -- ensure the supernodes S_min and S_max are are the only nodes in these ranks + -- for all nodes with indegree of 0, insert temporary edge (S_min, v) with delta=0 + -- for all nodes with outdegree of 0, insert temporary edge (v, S_max) with delta=0 + + -- classify edges as tree/forward, cross and back edges using a DFS traversal + local tree_or_forward_edges, cross_edges, back_edges = Simplifiers:classifyEdges(self.graph) + + -- reverse the back edges in order to make the graph acyclic + for _,edge in ipairs(back_edges) do + edge.reversed = true + end +end + + +-- done + +return CycleRemovalGansnerKNV1993 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/EdgeRoutingGansnerKNV1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/EdgeRoutingGansnerKNV1993.lua new file mode 100644 index 0000000000..c451f74116 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/EdgeRoutingGansnerKNV1993.lua @@ -0,0 +1,22 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local EdgeRoutingGansnerKNV1993 = {} + + +function EdgeRoutingGansnerKNV1993:run() +end + + +-- done +return EdgeRoutingGansnerKNV1993 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua new file mode 100644 index 0000000000..0ccf7694ca --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua @@ -0,0 +1,898 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +--- This file contains an implementation of the network simplex method +--- for node ranking and x coordinate optimization in layered drawing +--- algorithms, as proposed in +--- +--- "A Technique for Drawing Directed Graphs" +-- by Gansner, Koutsofios, North, Vo, 1993. + + +local NetworkSimplex = {} +NetworkSimplex.__index = NetworkSimplex + +-- Namespace +local layered = require "pgf.gd.layered" +layered.NetworkSimplex = NetworkSimplex + + +-- Imports +local DepthFirstSearch = require "pgf.gd.lib.DepthFirstSearch" +local Ranking = require "pgf.gd.layered.Ranking" +local Graph = require "pgf.gd.deprecated.Graph" +local lib = require "pgf.gd.lib" + + + +-- Definitions + +NetworkSimplex.BALANCE_TOP_BOTTOM = 1 +NetworkSimplex.BALANCE_LEFT_RIGHT = 2 + + +function NetworkSimplex.new(graph, balancing) + local simplex = { + graph = graph, + balancing = balancing, + } + setmetatable(simplex, NetworkSimplex) + return simplex +end + + + +function NetworkSimplex:run() + + assert (#self.graph.nodes > 0, "graph must contain at least one node") + + -- initialize the tree edge search index + self.search_index = 1 + + -- initialize internal edge parameters + self.cut_value = {} + for _,edge in ipairs(self.graph.edges) do + self.cut_value[edge] = 0 + end + + -- reset graph information needed for ranking + self.lim = {} + self.low = {} + self.parent_edge = {} + self.ranking = Ranking.new() + + if #self.graph.nodes == 1 then + self.ranking:setRank(self.graph.nodes[1], 1) + else + self:rankNodes() + end +end + + + +function NetworkSimplex:rankNodes() + -- construct feasible tree of tight edges + self:constructFeasibleTree() + + -- iteratively replace edges with negative cut values + -- with non-tree edges (chosen by minimum slack) + local leave_edge = self:findNegativeCutEdge() + while leave_edge do + local enter_edge = self:findReplacementEdge(leave_edge) + + assert(enter_edge, 'no non-tree edge to replace ' .. tostring(leave_edge) .. ' could be found') + + -- exchange leave_edge and enter_edge in the tree, updating + -- the ranks and cut values of all nodes + self:exchangeTreeEdges(leave_edge, enter_edge) + + -- find the next tree edge with a negative cut value, if + -- there are any left + leave_edge = self:findNegativeCutEdge() + end + + if self.balancing == NetworkSimplex.BALANCE_TOP_BOTTOM then + -- normalize by setting the least rank to zero + self.ranking:normalizeRanks() + + -- move nodes to feasible ranks with the least number of nodes + -- in order to avoid crowding and to improve the overall aspect + -- ratio of the drawing + self:balanceRanksTopBottom() + elseif self.balancing == NetworkSimplex.BALANCE_LEFT_RIGHT then + self:balanceRanksLeftRight() + end +end + + + +function NetworkSimplex:constructFeasibleTree() + + self:computeInitialRanking() + + -- find a maximal tree of tight edges in the graph + while self:findTightTree() < #self.graph.nodes do + + local min_slack_edge = nil + + for _,node in ipairs(self.graph.nodes) do + local out_edges = node:getOutgoingEdges() + for _,edge in ipairs(out_edges) do + if not self.tree_edge[edge] and self:isIncidentToTree(edge) then + if not min_slack_edge or self:edgeSlack(edge) < self:edgeSlack(min_slack_edge) then + min_slack_edge = edge + end + end + end + end + + if min_slack_edge then + local delta = self:edgeSlack(min_slack_edge) + + if delta > 0 then + local head = min_slack_edge:getHead() + local tail = min_slack_edge:getTail() + + if self.tree_node[head] then + delta = -delta + end + + + for _,node in ipairs(self.tree.nodes) do + local rank = self.ranking:getRank(self.orig_node[node]) + self.ranking:setRank(self.orig_node[node], rank + delta) + end + end + end + end + + self:initializeCutValues() +end + + + +function NetworkSimplex:findNegativeCutEdge() + local minimum_edge = nil + + for n=1,#self.tree.edges do + local index = self:nextSearchIndex() + + local edge = self.tree.edges[index] + + if self.cut_value[edge] < 0 then + if minimum_edge then + if self.cut_value[minimum_edge] > self.cut_value[edge] then + minimum_edge = edge + end + else + minimum_edge = edge + end + end + end + + return minimum_edge +end + + + +function NetworkSimplex:findReplacementEdge(leave_edge) + local tail = leave_edge:getTail() + local head = leave_edge:getHead() + + local v = nil + local direction = nil + + if self.lim[tail] < self.lim[head] then + v = tail + direction = 'in' + else + v = head + direction = 'out' + end + + local search_root = v + local enter_edge = nil + local slack = math.huge + + -- TODO Jannis: Get rid of this recursion: + + local function find_edge(v, direction) + + if direction == 'out' then + local out_edges = self.orig_node[v]:getOutgoingEdges() + for _,edge in ipairs(out_edges) do + local head = edge:getHead() + local tree_head = self.tree_node[head] + + assert(head and tree_head) + + if not self.tree_edge[edge] then + if not self:inTailComponentOf(tree_head, search_root) then + if self:edgeSlack(edge) < slack or not enter_edge then + enter_edge = edge + slack = self:edgeSlack(edge) + end + end + else + if self.lim[tree_head] < self.lim[v] then + find_edge(tree_head, 'out') + end + end + end + + for _,edge in ipairs(v:getIncomingEdges()) do + if slack <= 0 then + break + end + + local tail = edge:getTail() + + if self.lim[tail] < self.lim[v] then + find_edge(tail, 'out') + end + end + else + local in_edges = self.orig_node[v]:getIncomingEdges() + for _,edge in ipairs(in_edges) do + local tail = edge:getTail() + local tree_tail = self.tree_node[tail] + + assert(tail and tree_tail) + + if not self.tree_edge[edge] then + if not self:inTailComponentOf(tree_tail, search_root) then + if self:edgeSlack(edge) < slack or not enter_edge then + enter_edge = edge + slack = self:edgeSlack(edge) + end + end + else + if self.lim[tree_tail] < self.lim[v] then + find_edge(tree_tail, 'in') + end + end + end + + for _,edge in ipairs(v:getOutgoingEdges()) do + if slack <= 0 then + break + end + + local head = edge:getHead() + + if self.lim[head] < self.lim[v] then + find_edge(head, 'in') + end + end + end + end + + find_edge(v, direction) + + return enter_edge +end + + + +function NetworkSimplex:exchangeTreeEdges(leave_edge, enter_edge) + + self:rerankBeforeReplacingEdge(leave_edge, enter_edge) + + local cutval = self.cut_value[leave_edge] + local head = self.tree_node[enter_edge:getHead()] + local tail = self.tree_node[enter_edge:getTail()] + + local ancestor = self:updateCutValuesUpToCommonAncestor(tail, head, cutval, true) + local other_ancestor = self:updateCutValuesUpToCommonAncestor(head, tail, cutval, false) + + assert(ancestor == other_ancestor) + + -- remove the old edge from the tree + self:removeEdgeFromTree(leave_edge) + + -- add the new edge to the tree + local tree_edge = self:addEdgeToTree(enter_edge) + + -- set its cut value + self.cut_value[tree_edge] = -cutval + + -- update DFS search tree traversal information + self:calculateDFSRange(ancestor, self.parent_edge[ancestor], self.low[ancestor]) +end + + + +function NetworkSimplex:balanceRanksTopBottom() + + -- available ranks + local ranks = self.ranking:getRanks() + + -- node to in/out weight mappings + local in_weight = {} + local out_weight = {} + + -- node to lowest/highest possible rank mapping + local min_rank = {} + local max_rank = {} + + -- compute the in and out weights of each node + for _,node in ipairs(self.graph.nodes) do + -- assume there are no restrictions on how to rank the node + min_rank[node], max_rank[node] = ranks[1], ranks[#ranks] + + for _,edge in ipairs(node:getIncomingEdges()) do + -- accumulate the weights of all incoming edges + in_weight[node] = (in_weight[node] or 0) + edge.weight + + -- update the minimum allowed rank (which is the maximum of + -- the ranks of all parent neighbors plus the minimum level + -- separation caused by the connecting edges) + local neighbour = edge:getNeighbour(node) + local neighbour_rank = self.ranking:getRank(neighbour) + min_rank[node] = math.max(min_rank[node], neighbour_rank + edge.minimum_levels) + end + + for _,edge in ipairs(node:getOutgoingEdges()) do + -- accumulate the weights of all outgoing edges + out_weight[node] = (out_weight[node] or 0) + edge.weight + + -- update the maximum allowed rank (which is the minimum of + -- the ranks of all child neighbors minus the minimum level + -- separation caused by the connecting edges) + local neighbour = edge:getNeighbour(node) + local neighbour_rank = self.ranking:getRank(neighbour) + max_rank[node] = math.min(max_rank[node], neighbour_rank - edge.minimum_levels) + end + + -- check whether the in- and outweight is the same + if in_weight[node] == out_weight[node] then + + -- check which of the allowed ranks has the least number of nodes + local min_nodes_rank = min_rank[node] + for n = min_rank[node] + 1, max_rank[node] do + if #self.ranking:getNodes(n) < #self.ranking:getNodes(min_nodes_rank) then + min_nodes_rank = n + end + end + + -- only move the node to the rank with the least number of nodes + -- if it differs from the current rank of the node + if min_nodes_rank ~= self.ranking:getRank(node) then + self.ranking:setRank(node, min_nodes_rank) + end + + end + end +end + + + +function NetworkSimplex:balanceRanksLeftRight() + for _,edge in ipairs(self.tree.edges) do + if self.cut_value[edge] == 0 then + local other_edge = self:findReplacementEdge(edge) + if other_edge then + local delta = self:edgeSlack(other_edge) + if delta > 1 then + if self.lim[edge:getTail()] < self.lim[edge:getHead()] then + self:rerank(edge:getTail(), delta / 2) + else + self:rerank(edge:getHead(), -delta / 2) + end + end + end + end + end +end + + + +function NetworkSimplex:computeInitialRanking() + + -- queue for nodes to rank next + local queue = {} + + -- convenience functions for managing the queue + local function enqueue(node) table.insert(queue, node) end + local function dequeue() return table.remove(queue, 1) end + + -- reset the two-dimensional mapping from ranks to lists + -- of corresponding nodes + self.ranking:reset() + + -- mapping of nodes to the number of unscanned incoming edges + local remaining_edges = {} + + -- add all sinks to the queue + for _,node in ipairs(self.graph.nodes) do + local edges = node:getIncomingEdges() + + remaining_edges[node] = #edges + + if #edges == 0 then + enqueue(node) + end + end + + -- run long as there are nodes to be ranked + while #queue > 0 do + + -- fetch the next unranked node from the queue + local node = dequeue() + + -- get a list of its incoming edges + local in_edges = node:getIncomingEdges() + + -- determine the minimum possible rank for the node + local rank = 1 + for _,edge in ipairs(in_edges) do + local neighbour = edge:getNeighbour(node) + if self.ranking:getRank(neighbour) then + -- the minimum possible rank is the maximum of all neighbor ranks plus + -- the corresponding edge lengths + rank = math.max(rank, self.ranking:getRank(neighbour) + edge.minimum_levels) + end + end + + -- rank the node + self.ranking:setRank(node, rank) + + -- get a list of the node's outgoing edges + local out_edges = node:getOutgoingEdges() + + -- queue neighbors of nodes for which all incoming edges have been scanned + for _,edge in ipairs(out_edges) do + local head = edge:getHead() + remaining_edges[head] = remaining_edges[head] - 1 + if remaining_edges[head] <= 0 then + enqueue(head) + end + end + end +end + + + +function NetworkSimplex:findTightTree() + + -- TODO: Jannis: Remove the recursion below: + + local marked = {} + + local function build_tight_tree(node) + + local out_edges = node:getOutgoingEdges() + local in_edges = node:getIncomingEdges() + + local edges = lib.copy(out_edges) + for _,v in ipairs(in_edges) do + edges[#edges + 1] = v + end + + for _,edge in ipairs(edges) do + local neighbour = edge:getNeighbour(node) + if (not marked[neighbour]) and math.abs(self:edgeSlack(edge)) < 0.00001 then + self:addEdgeToTree(edge) + + for _,node in ipairs(edge.nodes) do + marked[node] = true + end + + if #self.tree.edges == #self.graph.nodes-1 then + return true + end + + if build_tight_tree(neighbour) then + return true + end + end + end + + return false + end + + for _,node in ipairs(self.graph.nodes) do + self.tree = Graph.new() + self.tree_node = {} + self.orig_node = {} + self.tree_edge = {} + self.orig_edge = {} + + build_tight_tree(node) + + if #self.tree.edges > 0 then + break + end + end + + return #self.tree.nodes +end + + + +function NetworkSimplex:edgeSlack(edge) + -- make sure this is never called with a tree edge + assert(not self.orig_edge[edge]) + + local head_rank = self.ranking:getRank(edge:getHead()) + local tail_rank = self.ranking:getRank(edge:getTail()) + local length = head_rank - tail_rank + return length - edge.minimum_levels +end + + + +function NetworkSimplex:isIncidentToTree(edge) + -- make sure this is never called with a tree edge + assert(not self.orig_edge[edge]) + + local head = edge:getHead() + local tail = edge:getTail() + + if self.tree_node[head] and not self.tree_node[tail] then + return true + elseif self.tree_node[tail] and not self.tree_node[head] then + return true + else + return false + end +end + + + +function NetworkSimplex:initializeCutValues() + self:calculateDFSRange(self.tree.nodes[1], nil, 1) + + local function init(search) + search:push({ node = self.tree.nodes[1], parent_edge = nil }) + end + + local function visit(search, data) + search:setVisited(data, true) + + local into = data.node:getIncomingEdges() + local out = data.node:getOutgoingEdges() + + for i=#into,1,-1 do + local edge = into[i] + if edge ~= data.parent_edge then + search:push({ node = edge:getTail(), parent_edge = edge }) + end + end + + for i=#out,1,-1 do + local edge = out[i] + if edge ~= data.parent_edge then + search:push({ node = edge:getHead(), parent_edge = edge }) + end + end + end + + local function complete(search, data) + if data.parent_edge then + self:updateCutValue(data.parent_edge) + end + end + + DepthFirstSearch.new(init, visit, complete):run() +end + + + +--- DFS algorithm that calculates post-order traversal indices and parent edges. +-- +-- This algorithm performs a depth-first search in a directed or undirected +-- graph. For each node it calculates the node's post-order traversal index, the +-- minimum post-order traversal index of its descendants as well as the edge by +-- which the node was reached in the depth-first traversal. +-- +function NetworkSimplex:calculateDFSRange(root, edge_from_parent, lowest) + + -- global traversal index counter + local lim = lowest + + -- start the traversal at the root node + local function init(search) + search:push({ node = root, parent_edge = edge_from_parent, low = lowest }) + end + + -- visit nodes in depth-first order + local function visit(search, data) + -- mark node as visited so we only visit it once + search:setVisited(data, true) + + -- remember the parent edge + self.parent_edge[data.node] = data.parent_edge + + -- remember the minimum traversal index for this branch of the search tree + self.low[data.node] = lim + + -- next we push all outgoing and incoming edges in reverse order + -- to simulate recursive calls + + local into = data.node:getIncomingEdges() + local out = data.node:getOutgoingEdges() + + for i=#into,1,-1 do + local edge = into[i] + if edge ~= data.parent_edge then + search:push({ node = edge:getTail(), parent_edge = edge }) + end + end + + for i=#out,1,-1 do + local edge = out[i] + if edge ~= data.parent_edge then + search:push({ node = edge:getHead(), parent_edge = edge }) + end + end + end + + -- when completing a node, store its own traversal index + local function complete(search, data) + self.lim[data.node] = lim + lim = lim + 1 + end + + -- kick off the depth-first search + DepthFirstSearch.new(init, visit, complete):run() + + local lim_lookup = {} + local min_lim = math.huge + local max_lim = -math.huge + for _,node in ipairs(self.tree.nodes) do + assert(self.lim[node]) + assert(self.low[node]) + assert(not lim_lookup[self.lim[node]]) + lim_lookup[self.lim[node]] = true + min_lim = math.min(min_lim, self.lim[node]) + max_lim = math.max(max_lim, self.lim[node]) + end + for n = min_lim, max_lim do + assert(lim_lookup[n] == true) + end +end + + + +function NetworkSimplex:updateCutValue(tree_edge) + + local v = nil + if self.parent_edge[tree_edge:getTail()] == tree_edge then + v = tree_edge:getTail() + dir = 1 + else + v = tree_edge:getHead() + dir = -1 + end + + local sum = 0 + + local out_edges = self.orig_node[v]:getOutgoingEdges() + local in_edges = self.orig_node[v]:getIncomingEdges() + local edges = lib.copy(out_edges) + for _,v in ipairs(in_edges) do + edges[#edges + 1] = v + end + + for _,edge in ipairs(edges) do + local other = edge:getNeighbour(self.orig_node[v]) + + local f = 0 + local rv = 0 + + if not self:inTailComponentOf(self.tree_node[other], v) then + f = 1 + rv = edge.weight + else + f = 0 + + if self.tree_edge[edge] then + rv = self.cut_value[self.tree_edge[edge]] + else + rv = 0 + end + + rv = rv - edge.weight + end + + local d = 0 + + if dir > 0 then + if edge:isHead(self.orig_node[v]) then + d = 1 + else + d = -1 + end + else + if edge:isTail(self.orig_node[v]) then + d = 1 + else + d = -1 + end + end + + if f > 0 then + d = -d + end + + if d < 0 then + rv = -rv + end + + sum = sum + rv + end + + self.cut_value[tree_edge] = sum +end + + + +function NetworkSimplex:inTailComponentOf(node, v) + return (self.low[v] <= self.lim[node]) and (self.lim[node] <= self.lim[v]) +end + + + +function NetworkSimplex:nextSearchIndex() + local index = 1 + + -- avoid tree edge index out of bounds by resetting the search index + -- as soon as it leaves the range of edge indices in the tree + if self.search_index > #self.tree.edges then + self.search_index = 1 + index = 1 + else + index = self.search_index + self.search_index = self.search_index + 1 + end + + return index +end + + + +function NetworkSimplex:rerank(node, delta) + local function init(search) + search:push({ node = node, delta = delta }) + end + + local function visit(search, data) + search:setVisited(data, true) + + local orig_node = self.orig_node[data.node] + self.ranking:setRank(orig_node, self.ranking:getRank(orig_node) - data.delta) + + local into = data.node:getIncomingEdges() + local out = data.node:getOutgoingEdges() + + for i=#into,1,-1 do + local edge = into[i] + if edge ~= self.parent_edge[data.node] then + search:push({ node = edge:getTail(), delta = data.delta }) + end + end + + for i=#out,1,-1 do + local edge = out[i] + if edge ~= self.parent_edge[data.node] then + search:push({ node = edge:getHead(), delta = data.delta }) + end + end + end + + DepthFirstSearch.new(init, visit):run() +end + + + +function NetworkSimplex:rerankBeforeReplacingEdge(leave_edge, enter_edge) + local delta = self:edgeSlack(enter_edge) + + if delta > 0 then + local tail = leave_edge:getTail() + + if #tail.edges == 1 then + self:rerank(tail, delta) + else + local head = leave_edge:getHead() + + if #head.edges == 1 then + self:rerank(head, -delta) + else + if self.lim[tail] < self.lim[head] then + self:rerank(tail, delta) + else + self:rerank(head, -delta) + end + end + end + end +end + + + +function NetworkSimplex:updateCutValuesUpToCommonAncestor(v, w, cutval, dir) + + while not self:inTailComponentOf(w, v) do + local edge = self.parent_edge[v] + + if edge:isTail(v) then + d = dir + else + d = not dir + end + + if d then + self.cut_value[edge] = self.cut_value[edge] + cutval + else + self.cut_value[edge] = self.cut_value[edge] - cutval + end + + if self.lim[edge:getTail()] > self.lim[edge:getHead()] then + v = edge:getTail() + else + v = edge:getHead() + end + end + + return v +end + + + +function NetworkSimplex:addEdgeToTree(edge) + assert(not self.tree_edge[edge]) + + -- create the new tree edge + local tree_edge = edge:copy() + self.orig_edge[tree_edge] = edge + self.tree_edge[edge] = tree_edge + + -- create tree nodes if necessary + for _,node in ipairs(edge.nodes) do + local tree_node + + if self.tree_node[node] then + tree_node = self.tree_node[node] + else + tree_node = node:copy() + self.orig_node[tree_node] = node + self.tree_node[node] = tree_node + end + + self.tree:addNode(tree_node) + tree_edge:addNode(tree_node) + end + + self.tree:addEdge(tree_edge) + + return tree_edge +end + + + +function NetworkSimplex:removeEdgeFromTree(edge) + self.tree:deleteEdge(edge) + self.tree_edge[self.orig_edge[edge]] = nil + self.orig_edge[edge] = nil +end + + + + +-- Done + +return NetworkSimplex \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua new file mode 100644 index 0000000000..3e5a0f8f87 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua @@ -0,0 +1,154 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local NodePositioningGansnerKNV1993 = {} + + +-- Imports + +local layered = require "pgf.gd.layered" + +local Graph = require "pgf.gd.deprecated.Graph" +local Edge = require "pgf.gd.deprecated.Edge" +local Node = require "pgf.gd.deprecated.Node" + +local NetworkSimplex = require "pgf.gd.layered.NetworkSimplex" +local Storage = require "pgf.gd.lib.Storage" + + +function NodePositioningGansnerKNV1993:run() + local auxiliary_graph = self:constructAuxiliaryGraph() + + local simplex = NetworkSimplex.new(auxiliary_graph, NetworkSimplex.BALANCE_LEFT_RIGHT) + simplex:run() + local x_ranking = simplex.ranking + + local layers = Storage.new() + + local ranks = self.ranking:getRanks() + for _,rank in ipairs(ranks) do + local nodes = self.ranking:getNodes(rank) + for _,node in ipairs(nodes) do + node.pos.x = x_ranking:getRank(node.aux_node) + layers[node.orig_vertex] = rank + end + end + + layered.arrange_layers_by_baselines(layers, self.main_algorithm.adjusted_bb, self.main_algorithm.ugraph) + + -- Copy back + for _,rank in ipairs(ranks) do + local nodes = self.ranking:getNodes(rank) + for _,node in ipairs(nodes) do + node.pos.y = node.orig_vertex.pos.y + end + end +end + + + + +function NodePositioningGansnerKNV1993:constructAuxiliaryGraph() + + local aux_graph = Graph.new() + + local edge_node = {} + + for _,node in ipairs(self.graph.nodes) do + local copy = Node.new{ + name = node.name, + orig_node = node, + } + node.aux_node = copy + aux_graph:addNode(copy) + end + + for i=#self.graph.edges,1,-1 do + local edge = self.graph.edges[i] + local node = Node.new{ + name = '{' .. tostring(edge) .. '}', + } + + aux_graph:addNode(node) + + node.orig_edge = edge + edge_node[edge] = node + + local head = edge:getHead() + local tail = edge:getTail() + + local tail_edge = Edge.new{ + direction = Edge.RIGHT, + minimum_levels = 0, + weight = edge.weight * self:getOmega(edge), + } + tail_edge:addNode(node) + tail_edge:addNode(tail.aux_node) + aux_graph:addEdge(tail_edge) + + local head_edge = Edge.new{ + direction = Edge.RIGHT, + minimum_levels = 0, + weight = edge.weight * self:getOmega(edge), + } + head_edge:addNode(node) + head_edge:addNode(head.aux_node) + aux_graph:addEdge(head_edge) + end + + local ranks = self.ranking:getRanks() + for _,rank in ipairs(ranks) do + local nodes = self.ranking:getNodes(rank) + for n = 1, #nodes-1 do + local v = nodes[n] + local w = nodes[n+1] + + local separator_edge = Edge.new{ + direction = Edge.RIGHT, + minimum_levels = self:getDesiredHorizontalDistance(v, w), + weight = 0, + } + separator_edge:addNode(v.aux_node) + separator_edge:addNode(w.aux_node) + aux_graph:addEdge(separator_edge) + end + end + + return aux_graph +end + + + +function NodePositioningGansnerKNV1993:getOmega(edge) + local node1 = edge.nodes[1] + local node2 = edge.nodes[2] + + if (node1.kind == "dummy") and (node2.kind == "dummy") then + return 8 + elseif (node1.kind == "dummy") or (node2.kind == "dummy") then + return 2 + else + return 1 + end +end + + + +function NodePositioningGansnerKNV1993:getDesiredHorizontalDistance(v, w) + return layered.ideal_sibling_distance(self.main_algorithm.adjusted_bb, self.graph.orig_digraph, v.orig_vertex, w.orig_vertex) +end + + +-- done + +return NodePositioningGansnerKNV1993 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua new file mode 100644 index 0000000000..d6765ae2f0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua @@ -0,0 +1,159 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local NodeRankingGansnerKNV1993 = {} + + +-- Imports + +local Edge = require "pgf.gd.deprecated.Edge" +local Node = require "pgf.gd.deprecated.Node" + +local NetworkSimplex = require "pgf.gd.layered.NetworkSimplex" + + + +function NodeRankingGansnerKNV1993:run() + + local simplex = NetworkSimplex.new(self.graph, NetworkSimplex.BALANCE_TOP_BOTTOM) + simplex:run() + self.ranking = simplex.ranking + + return simplex.ranking +end + + + +function NodeRankingGansnerKNV1993:mergeClusters() + + self.cluster_nodes = {} + self.cluster_node = {} + self.cluster_edges = {} + + self.original_nodes = {} + self.original_edges = {} + + for _,cluster in ipairs(self.graph.clusters) do + + local cluster_node = Node.new{ + name = 'cluster@' .. cluster.name, + } + table.insert(self.cluster_nodes, cluster_node) + + for _,node in ipairs(cluster.nodes) do + self.cluster_node[node] = cluster_node + table.insert(self.original_nodes, node) + end + + self.graph:addNode(cluster_node) + end + + for _,edge in ipairs(self.graph.edges) do + local tail = edge:getTail() + local head = edge:getHead() + + if self.cluster_node[tail] or self.cluster_node[head] then + table.insert(self.original_edges, edge) + + local cluster_edge = Edge.new{ + direction = Edge.RIGHT, + weight = edge.weight, + minimum_levels = edge.minimum_levels, + } + table.insert(self.cluster_edges, cluster_edge) + + if self.cluster_node[tail] then + cluster_edge:addNode(self.cluster_node[tail]) + else + cluster_edge:addNode(tail) + end + + if self.cluster_node[head] then + cluster_edge:addNode(self.cluster_node[head]) + else + cluster_edge:addNode(head) + end + + end + end + + for _,edge in ipairs(self.cluster_edges) do + self.graph:addEdge(edge) + end + + for _,edge in ipairs(self.original_edges) do + self.graph:deleteEdge(edge) + end + + for _,node in ipairs(self.original_nodes) do + self.graph:deleteNode(node) + end +end + + + +function NodeRankingGansnerKNV1993:createClusterEdges() + for n = 1, #self.cluster_nodes-1 do + local first_cluster = self.cluster_nodes[n] + local second_cluster = self.cluster_nodes[n+1] + + local edge = Edge.new{ + direction = Edge.RIGHT, + weight = 1, + minimum_levels = 1, + } + + edge:addNode(first_cluster) + edge:addNode(second_cluster) + + self.graph:addEdge(edge) + + table.insert(self.cluster_edges, edge) + end +end + + + +function NodeRankingGansnerKNV1993:removeClusterEdges() +end + + + +function NodeRankingGansnerKNV1993:expandClusters() + + for _,node in ipairs(self.original_nodes) do + assert(self.ranking:getRank(self.cluster_node[node])) + self.ranking:setRank(node, self.ranking:getRank(self.cluster_node[node])) + self.graph:addNode(node) + end + + for _,edge in ipairs(self.original_edges) do + for _,node in ipairs(edge.nodes) do + node:addEdge(edge) + end + self.graph:addEdge(edge) + end + + for _,node in ipairs(self.cluster_nodes) do + self.ranking:setRank(node, nil) + self.graph:deleteNode(node) + end + + for _,edge in ipairs(self.cluster_edges) do + self.graph:deleteEdge(edge) + end +end + + +-- done + +return NodeRankingGansnerKNV1993 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua new file mode 100644 index 0000000000..644b99c28a --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua @@ -0,0 +1,47 @@ +-- Copyright 2011 by Jannis Pohlmann +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local NodeRankingMinimumHeight = {} + +-- Imports + +local Ranking = require "pgf.gd.layered.Ranking" +local Iterators = require "pgf.gd.deprecated.Iterators" + + +function NodeRankingMinimumHeight:run() + local ranking = Ranking.new() + + for node in Iterators.topologicallySorted(self.graph) do + local edges = node:getIncomingEdges() + + if #edges == 0 then + ranking:setRank(node, 1) + else + local max_rank = -math.huge + for _,edge in ipairs(edges) do + max_rank = math.max(max_rank, ranking:getRank(edge:getNeighbour(node))) + end + + assert(max_rank >= 1) + + ranking:setRank(node, max_rank + 1) + end + end + + return ranking +end + + +-- done + +return NodeRankingMinimumHeight diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Ranking.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Ranking.lua new file mode 100644 index 0000000000..6ed63b0249 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Ranking.lua @@ -0,0 +1,291 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The Ranking class is used by the Sugiyama algorithm to compute an +-- ordering on the nodes of a layer + +local Ranking = {} +Ranking.__index = Ranking + +-- Namespace +local layered = require "pgf.gd.layered" +layered.Ranking = Ranking + + +local lib = require "pgf.gd.lib" + + +-- TODO Jannis: document! + + +function Ranking.new() + local ranking = { + rank_to_nodes = {}, + node_to_rank = {}, + position_in_rank = {}, + } + setmetatable(ranking, Ranking) + return ranking +end + + + +function Ranking:copy() + local copied_ranking = Ranking.new() + + -- copy rank to nodes mapping + for rank, nodes in pairs(self.rank_to_nodes) do + copied_ranking.rank_to_nodes[rank] = lib.copy(self.rank_to_nodes[rank]) + end + + -- copy node to rank mapping + copied_ranking.node_to_rank = lib.copy(self.node_to_rank) + + -- copy node to position in rank mapping + copied_ranking.position_in_rank = lib.copy(self.position_in_rank) + + return copied_ranking +end + + + +function Ranking:reset() + self.rank_to_nodes = {} + self.node_to_rank = {} + self.position_in_rank = {} +end + + + +function Ranking:getRanks() + local ranks = {} + for rank, nodes in pairs(self.rank_to_nodes) do + table.insert(ranks, rank) + end + table.sort(ranks) + return ranks +end + + + +function Ranking:getRankSize(rank) + if self.rank_to_nodes[rank] then + return #self.rank_to_nodes[rank] + else + return 0 + end +end + + + +function Ranking:getNodeInfo(node) + return self:getRank(node), self:getRankPosition(node) +end + + + +function Ranking:getNodes(rank) + return self.rank_to_nodes[rank] or {} +end + + + +function Ranking:getRank(node) + return self.node_to_rank[node] +end + + + +function Ranking:setRank(node, new_rank) + local rank, pos = self:getNodeInfo(node) + + if rank == new_rank then + return + end + + if rank then + for n = pos+1, #self.rank_to_nodes[rank] do + local other_node = self.rank_to_nodes[rank][n] + self.position_in_rank[other_node] = self.position_in_rank[other_node]-1 + end + + table.remove(self.rank_to_nodes[rank], pos) + self.node_to_rank[node] = nil + self.position_in_rank[node] = nil + + if #self.rank_to_nodes[rank] == 0 then + self.rank_to_nodes[rank] = nil + end + end + + if new_rank then + self.rank_to_nodes[new_rank] = self.rank_to_nodes[new_rank] or {} + table.insert(self.rank_to_nodes[new_rank], node) + self.node_to_rank[node] = new_rank + self.position_in_rank[node] = #self.rank_to_nodes[new_rank] + end +end + + + +function Ranking:getRankPosition(node) + return self.position_in_rank[node] +end + + + +function Ranking:setRankPosition(node, new_pos) + local rank, pos = self:getNodeInfo(node) + + assert((rank and pos) or ((not rank) and (not pos))) + + if pos == new_pos then + return + end + + if rank and pos then + for n = pos+1, #self.rank_to_nodes[rank] do + local other_node = self.rank_to_nodes[rank][n] + self.position_in_rank[other_node] = self.position_in_rank[other_node]-1 + end + + table.remove(self.rank_to_nodes[rank], pos) + self.node_to_rank[node] = nil + self.position_in_rank[node] = nil + end + + if new_pos then + self.rank_to_nodes[rank] = self.rank_to_nodes[rank] or {} + + for n = new_pos+1, #self.rank_to_nodes[rank] do + local other_node = self.rank_to_nodes[rank][new_pos] + self.position_in_rank[other_node] = self.position_in_rank[other_node]+1 + end + + table.insert(self.rank_to_nodes[rank], node) + self.node_to_rank[node] = rank + self.position_in_rank[node] = new_pos + end +end + + + +function Ranking:normalizeRanks() + + -- get the current ranks + local ranks = self:getRanks() + + local min_rank = ranks[1] + local max_rank = ranks[#ranks] + + -- clear ranks + self.rank_to_nodes = {} + + -- iterate over all nodes and rerank them manually + for node in pairs(self.position_in_rank) do + local rank, pos = self:getNodeInfo(node) + local new_rank = rank - (min_rank - 1) + + self.rank_to_nodes[new_rank] = self.rank_to_nodes[new_rank] or {} + self.rank_to_nodes[new_rank][pos] = node + + self.node_to_rank[node] = new_rank + end +end + + + +function Ranking:switchPositions(left_node, right_node) + local left_rank = self.node_to_rank[left_node] + local right_rank = self.node_to_rank[right_node] + + assert(left_rank == right_rank, 'only positions of nodes in the same rank can be switched') + + local left_pos = self.position_in_rank[left_node] + local right_pos = self.position_in_rank[right_node] + + self.rank_to_nodes[left_rank][left_pos] = right_node + self.rank_to_nodes[left_rank][right_pos] = left_node + + self.position_in_rank[left_node] = right_pos + self.position_in_rank[right_node] = left_pos +end + + + +function Ranking:reorderRank(rank, get_index_func, is_fixed_func) + self:reorderTable(self.rank_to_nodes[rank], get_index_func, is_fixed_func) + + for n = 1, #self.rank_to_nodes[rank] do + self.position_in_rank[self.rank_to_nodes[rank][n]] = n + end +end + + + +function Ranking:reorderTable(input, get_index_func, is_fixed_func) + -- collect all allowed indices + local allowed_indices = {} + for n = 1, #input do + if not is_fixed_func(n, input[n]) then + table.insert(allowed_indices, n) + end + end + + -- collect all desired indices; for each of these desired indices, + -- remember by which element it was requested + local desired_to_real_indices = {} + local sort_indices = {} + for n = 1, #input do + if not is_fixed_func(n, input[n]) then + local index = get_index_func(n, input[n]) + if not desired_to_real_indices[index] then + desired_to_real_indices[index] = {} + table.insert(sort_indices, index) + end + table.insert(desired_to_real_indices[index], n) + end + end + + -- sort the desired indices + table.sort(sort_indices) + + -- compute the final indices by counting the final indices generated + -- prior to the current one and by mapping this number to the allowed + -- index with the same number + local final_indices = {} + local n = 1 + for _,index in ipairs(sort_indices) do + local real_indices = desired_to_real_indices[index] + for _,real_index in ipairs(real_indices) do + final_indices[real_index] = allowed_indices[n] + n = n + 1 + end + end + + -- flat-copy the input table so that we can still access the elements + -- using their real index while overwriting the input table in-place + local input_copy = lib.copy(input) + + -- move flexible elements to their final indices + for old_index, new_index in pairs(final_indices) do + input[new_index] = input_copy[old_index] + end +end + + + +-- Done + +return Ranking \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua new file mode 100644 index 0000000000..c91818dc30 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua @@ -0,0 +1,476 @@ +-- Copyright 2011 by Jannis Pohlmann, 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {The Modular Sugiyama Method} +-- +-- @end + +local Sugiyama = {} + +-- Namespace +require("pgf.gd.layered").Sugiyama = Sugiyama + +-- Imports +local layered = require "pgf.gd.layered" +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +local Ranking = require "pgf.gd.layered.Ranking" +local Simplifiers = require "pgf.gd.lib.Simplifiers" + +-- Deprecated stuff. Need to get rid of it! +local Edge = require "pgf.gd.deprecated.Edge" +local Node = require "pgf.gd.deprecated.Node" + +local Iterators = require "pgf.gd.deprecated.Iterators" +local Vector = require "pgf.gd.deprecated.Vector" + + + +--- + +declare { + key = "layered layout", + algorithm = Sugiyama, + + preconditions = { + connected = true, + loop_free = true, + }, + + postconditions = { + upward_oriented = true + }, + + old_graph_model = true, + + summary = [[" + The |layered layout| is the key used to select the modular Sugiyama + layout algorithm. + "]], + documentation = [[" + This algorithm consists of five consecutive steps, each of which can be + configured independently of the other ones (how this is done is + explained later in this section). Naturally, the ``best'' heuristics + are selected by default, so there is typically no need to change the + settings, but what is the ``best'' method for one graph need not be + the best one for another graph. + + As can be seen in the first example, the algorithm will not only + position the nodes of a graph, but will also perform an edge + routing. This will look visually quite pleasing if you add the + |rounded corners| option: + "]], + examples = {[[" + \tikz \graph [layered layout, sibling distance=7mm] + { + a -> { + b, + c -> { d, e, f } + } -> + h -> + a + }; + "]],[[" + \tikz [rounded corners] \graph [layered layout, sibling distance=7mm] + { + a -> { + b, + c -> { d, e, f } + } -> + h -> + a + }; + "]] + } +} + +--- + +declare { + key = "minimum layers", + type = "number", + initial = "1", + + summary = [[" + The minimum number of levels that an edge must span. It is a bit of + the opposite of the |weight| parameter: While a large |weight| + causes an edge to become shorter, a larger |minimum layers| value + causes an edge to be longer. + "]], + examples = [[" + \tikz \graph [layered layout] { + a -- {b [> minimum layers=3], c, d} -- e -- a; + }; + "]] +} + + +--- + +declare { + key = "same layer", + layer = 0, + + summary = [[" + The |same layer| collection allows you to enforce that several nodes + a on the same layer of a layered layout (this option is also known + as |same rank|). You use it like this: + "]], + examples = {[[" + \tikz \graph [layered layout] { + a -- b -- c -- d -- e; + + { [same layer] a, b }; + { [same layer] d, e }; + }; + "]],[[" + \tikz [rounded corners] \graph [layered layout] { + 1972 -> 1976 -> 1978 -> 1980 -> 1982 -> 1984 -> 1986 -> 1988 -> 1990 -> future; + + { [same layer] 1972, Thompson }; + { [same layer] 1976, Mashey, Bourne }, + { [same layer] 1978, Formshell, csh }, + { [same layer] 1980, esh, vsh }, + { [same layer] 1982, ksh, "System-V" }, + { [same layer] 1984, v9sh, tcsh }, + { [same layer] 1986, "ksh-i" }, + { [same layer] 1988, KornShell ,Perl, rc }, + { [same layer] 1990, tcl, Bash }, + { [same layer] "future", POSIX, "ksh-POSIX" }, + + Thompson -> { Mashey, Bourne, csh -> tcsh}, + Bourne -> { ksh, esh, vsh, "System-V", v9sh -> rc, Bash}, + { "ksh-i", KornShell } -> Bash, + { esh, vsh, Formshell, csh } -> ksh, + { KornShell, "System-V" } -> POSIX, + ksh -> "ksh-i" -> KornShell -> "ksh-POSIX", + Bourne -> Formshell, + + { [edge={draw=none}] + Bash -> tcl, + KornShell -> Perl + } + }; + "]] + } +} + + + +-- Implementation + +function Sugiyama:run() + if #self.graph.nodes <= 1 then + return + end + + local options = self.digraph.options + + local cycle_removal_algorithm_class = options.algorithm_phases['cycle removal'] + local node_ranking_algorithm_class = options.algorithm_phases['node ranking'] + local crossing_minimization_algorithm_class = options.algorithm_phases['crossing minimization'] + local node_positioning_algorithm_class = options.algorithm_phases['node positioning'] + local edge_routing_algorithm_class = options.algorithm_phases['layer edge routing'] + + self:preprocess() + + -- Helper function for collapsing multiedges + local function collapse (m,e) + m.weight = (m.weight or 0) + e.weight + m.minimum_levels = math.max((m.minimum_levels or 0), e.minimum_levels) + end + + -- Rank using cluster + + -- Create a subalgorithm object. Needed so that removed loops + -- are not stored on top of removed loops from main call. + local cluster_subalgorithm = { graph = self.graph } + self.graph:registerAlgorithm(cluster_subalgorithm) + + self:mergeClusters() + + Simplifiers:removeLoopsOldModel(cluster_subalgorithm) + Simplifiers:collapseMultiedgesOldModel(cluster_subalgorithm, collapse) + + cycle_removal_algorithm_class.new { main_algorithm = self, graph = self.graph }:run() + self.ranking = node_ranking_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() + self:restoreCycles() + + Simplifiers:expandMultiedgesOldModel(cluster_subalgorithm) + Simplifiers:restoreLoopsOldModel(cluster_subalgorithm) + + self:expandClusters() + + -- Now do actual computation + Simplifiers:collapseMultiedgesOldModel(cluster_subalgorithm, collapse) + cycle_removal_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() + self:insertDummyNodes() + + -- Main algorithm + crossing_minimization_algorithm_class.new{ + main_algorithm = self, + graph = self.graph, + ranking = self.ranking + }:run() + node_positioning_algorithm_class.new{ + main_algorithm = self, + graph = self.graph, + ranking = self.ranking + }:run() + + -- Cleanup + self:removeDummyNodes() + Simplifiers:expandMultiedgesOldModel(cluster_subalgorithm) + edge_routing_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() + self:restoreCycles() + +end + + + +function Sugiyama:preprocess() + -- initialize edge parameters + for _,edge in ipairs(self.graph.edges) do + -- read edge parameters + edge.weight = edge:getOption('weight') + edge.minimum_levels = edge:getOption('minimum layers') + + -- validate edge parameters + assert(edge.minimum_levels >= 0, 'the edge ' .. tostring(edge) .. ' needs to have a minimum layers value greater than or equal to 0') + end +end + + + +function Sugiyama:insertDummyNodes() + -- enumerate dummy nodes using a globally unique numeric ID + local dummy_id = 1 + + -- keep track of the original edges removed + self.original_edges = {} + + -- keep track of dummy nodes introduced + self.dummy_nodes = {} + + for node in Iterators.topologicallySorted(self.graph) do + local in_edges = node:getIncomingEdges() + + for _,edge in ipairs (in_edges) do + local neighbour = edge:getNeighbour(node) + local dist = self.ranking:getRank(node) - self.ranking:getRank(neighbour) + + if dist > 1 then + local dummies = {} + + for i=1,dist-1 do + local rank = self.ranking:getRank(neighbour) + i + + local dummy = Node.new{ + pos = Vector.new(), + name = 'dummy@' .. neighbour.name .. '@to@' .. node.name .. '@at@' .. rank, + kind = "dummy", + orig_vertex = pgf.gd.model.Vertex.new{} + } + + dummy_id = dummy_id + 1 + + self.graph:addNode(dummy) + self.ugraph:add {dummy.orig_vertex} + + self.ranking:setRank(dummy, rank) + + table.insert(self.dummy_nodes, dummy) + table.insert(edge.bend_nodes, dummy) + + table.insert(dummies, dummy) + end + + table.insert(dummies, 1, neighbour) + table.insert(dummies, #dummies+1, node) + + for i = 2, #dummies do + local source = dummies[i-1] + local target = dummies[i] + + local dummy_edge = Edge.new{ + direction = Edge.RIGHT, + reversed = false, + weight = edge.weight, -- TODO or should we divide the weight of the original edge by the number of virtual edges? + } + + dummy_edge:addNode(source) + dummy_edge:addNode(target) + + self.graph:addEdge(dummy_edge) + end + + table.insert(self.original_edges, edge) + end + end + end + + for _,edge in ipairs(self.original_edges) do + self.graph:deleteEdge(edge) + end +end + + + +function Sugiyama:removeDummyNodes() + -- delete dummy nodes + for _,node in ipairs(self.dummy_nodes) do + self.graph:deleteNode(node) + end + + -- add original edge again + for _,edge in ipairs(self.original_edges) do + -- add edge to the graph + self.graph:addEdge(edge) + + -- add edge to the nodes + for _,node in ipairs(edge.nodes) do + node:addEdge(edge) + end + + -- convert bend nodes to bend points for TikZ + for _,bend_node in ipairs(edge.bend_nodes) do + local point = bend_node.pos:copy() + table.insert(edge.bend_points, point) + end + + if edge.reversed then + local bp = edge.bend_points + for i=1,#bp/2 do + local j = #bp + 1 - i + bp[i], bp[j] = bp[j], bp[i] + end + end + + -- clear the list of bend nodes + edge.bend_nodes = {} + end +end + + + +function Sugiyama:mergeClusters() + + self.cluster_nodes = {} + self.cluster_node = {} + self.cluster_edges = {} + self.cluster_original_edges = {} + self.original_nodes = {} + + for _,cluster in ipairs(self.graph.clusters) do + + local cluster_node = cluster.nodes[1] + table.insert(self.cluster_nodes, cluster_node) + + for n = 2, #cluster.nodes do + local other_node = cluster.nodes[n] + self.cluster_node[other_node] = cluster_node + table.insert(self.original_nodes, other_node) + end + end + + for _,edge in ipairs(self.graph.edges) do + local tail = edge:getTail() + local head = edge:getHead() + + if self.cluster_node[tail] or self.cluster_node[head] then + local cluster_edge = Edge.new{ + direction = Edge.RIGHT, + weight = edge.weight, + minimum_levels = edge.minimum_levels, + } + + if self.cluster_node[tail] then + cluster_edge:addNode(self.cluster_node[tail]) + else + cluster_edge:addNode(tail) + end + + if self.cluster_node[head] then + cluster_edge:addNode(self.cluster_node[head]) + else + cluster_edge:addNode(head) + end + + table.insert(self.cluster_edges, cluster_edge) + table.insert(self.cluster_original_edges, edge) + end + end + + for n = 1, #self.cluster_nodes-1 do + local first_node = self.cluster_nodes[n] + local second_node = self.cluster_nodes[n+1] + + local edge = Edge.new{ + direction = Edge.RIGHT, + weight = 1, + minimum_levels = 1, + } + + edge:addNode(first_node) + edge:addNode(second_node) + + table.insert(self.cluster_edges, edge) + end + + for _,node in ipairs(self.original_nodes) do + self.graph:deleteNode(node) + end + for _,edge in ipairs(self.cluster_edges) do + self.graph:addEdge(edge) + end + for _,edge in ipairs(self.cluster_original_edges) do + self.graph:deleteEdge(edge) + end +end + + + +function Sugiyama:expandClusters() + + for _,node in ipairs(self.original_nodes) do + self.ranking:setRank(node, self.ranking:getRank(self.cluster_node[node])) + self.graph:addNode(node) + end + + for _,edge in ipairs(self.cluster_original_edges) do + for _,node in ipairs(edge.nodes) do + node:addEdge(edge) + end + self.graph:addEdge(edge) + end + + for _,edge in ipairs(self.cluster_edges) do + self.graph:deleteEdge(edge) + end +end + + +function Sugiyama:restoreCycles() + for _,edge in ipairs(self.graph.edges) do + edge.reversed = false + end +end + + + + + +-- done + +return Sugiyama diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua new file mode 100644 index 0000000000..54a1fafb23 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua @@ -0,0 +1,81 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Crossing Minimization (Node Ordering)} +-- +-- The number of edge crossings in a layered drawing is determined by +-- the ordering of nodes at each of its layers. Therefore, crossing +-- minimization is the problem of reordering the nodes at each layer +-- so that the overall number of edge crossings is minimized. The +-- crossing minimization step takes a proper layering where every edge +-- connects nodes in neighbored layers, allowing algorithms to +-- minimize crossings layer by layer rather than all at once. While +-- this does not reduce the complexity of the problem, it does make it +-- considerably easier to understand and implement. Techniques based +-- on such an iterative approach are also known as layer-by-layer +-- sweep methods. They are used in many popular heuristics due to +-- their simplicity and the good results they produce. +-- +-- Sweeping refers to moving up and down from one layer to the next, +-- reducing crossings along the way. In layer-by-layer sweep methods, +-- an initial node ordering for one of the layers is computed +-- first. Depending on the sweep direction this can either be the +-- first layer or the last; in rare occasions the layer in the middle +-- is used instead. Followed by this, the actual layer-by-layer sweep +-- is performed. Given an initial ordering for the first layer $L_1$, a +-- downward sweep first holds the nodes in $L_1$ fixed while reordering +-- the nodes in the second layer $L_2$ to reduce the number of +-- crossings between $L_1$ and $L_2$. It then goes on to reorder the +-- third layer while holding the second layer fixed. This is continued +-- until all layers except for the first one have been +-- examined. Upward sweeping and sweeping from the middle work +-- analogous. +-- +-- Obviously, the central aspect of the layer-by-layer sweep is how +-- the nodes of a specific layer are reordered using a neighbored +-- layer as a fixed reference. This problem is known as one-sided +-- crossing minimization, which unfortunately is NP-hard. In the +-- following various heuristics to solve this problem are +-- presented. +-- +-- For more details, please see Section 4.1.4 of Pohlmann's Diploma +-- thesis. +-- +-- @end + + + +--- + +declare { + key = "sweep crossing minimization", + algorithm = require "pgf.gd.layered.CrossingMinimizationGansnerKNV1993", + phase = "crossing minimization", + phase_default = true, + + summary = [[" + Gansner et al. combine an initial ordering based on a depth-first + search with the median and greedy switch heuristics applied in the + form of an alternating layer-by-layer sweep based on a weighted + median. + "]], + documentation = [[" + For more details, please see Section~4.1.4 of Pohlmann's Diploma + thesis. + + This is the default algorithm for crossing minimization. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua new file mode 100644 index 0000000000..18670df14e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua @@ -0,0 +1,136 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Cycle Removal} +-- +-- The Sugiyama method works only on directed \emph{acyclic} +-- graphs. For this reason, if the input graph is not (yet) acyclic, a +-- number of edges need to be redirected so that acyclicity arises. In +-- the following, the different options that allow you to fine-tune +-- this process are documented. +-- +-- @end + + + +--- + +declare { + key = "depth first cycle removal", + algorithm = require "pgf.gd.layered.CycleRemovalGansnerKNV1993", + phase = "cycle removal", + phase_default = true, + + summary = [[" + Selects a cycle removal algorithm that is especially + appropriate for graphs specified ``by hand''. + "]], + documentation = [[" + When graphs are created by humans manually, one can + make assumptions about the input graph that would otherwise not + be possible. For instance, it seems reasonable to assume that the + order in which nodes and edges are entered by the user somehow + reflects the natural flow the user has had in mind for the graph. + + In order to preserve the natural flow of the input graph, Gansner + et al.\ propose to remove cycles by performing a series of + depth-first searches starting at individual nodes in the order they + appear in the graph. This algorithm implicitly constructs a spanning + tree of the nodes reached during the searches. It thereby partitions + the edges of the graph into tree edges and non-tree edges. The + non-tree edges are further subdivided into forward edges, cross edges, + and back edges. Forward edges point from a tree nodes to one of their + descendants. Cross edges connect unrelated branches in the search tree. + Back edges connect descendants to one of their ancestors. It is not + hard to see that reversing back edges will not only introduce no new + cycles but will also make any directed graph acyclic. + Gansner et al.\ argue that this approach is more stable than others + in that fewer inappropriate edges are reversed compared to other + methods, despite the lack of a provable upper bound for the number + of reversed edges. + + See section~4.1.1 of Pohlmann's Diplom thesis for more details. + + This is the default algorithm for cycle removals. + "]] + } + +--- + +declare { + key = "prioritized greedy cycle removal", + algorithm = "pgf.gd.layered.CycleRemovalEadesLS1993", + phase = "cycle removal", + + summary = [[" + This algorithm implements a greedy heuristic of Eades et al.\ for + cycle removal that prioritizes sources and sinks. + "]], + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. + "]] +} + + +--- + +declare { + key = "greedy cycle removal", + algorithm = "pgf.gd.layered.CycleRemovalEadesLS1993", + phase = "cycle removal", + + summary = [[" + This algorithm implements a greedy heuristic of Eades et al.\ for + cycle removal that prioritizes sources and sinks. + "]], + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. + "]] + } + +--- + +declare { + key = "naive greedy cycle removal", + algorithm = "pgf.gd.layered.CycleRemovalBergerS1990a", + phase = "cycle removal", + + summary = [[" + This algorithm implements a greedy heuristic of Berger and Shor for + cycle removal. It is not really compared to the other heuristics and + only included for demonstration purposes. + "]], + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. + "]] + } + +--- + +declare { + key = "random greedy cycle removal", + algorithm = "pgf.gd.layered.CycleRemovalBergerS1990b", + phase = "cycle removal", + + summary = [[" + This algorithm implements a randomized greedy heuristic of Berger + and Shor for cycle removal. It, too, is not really compared to + the other heuristics and only included for demonstration purposes. + "]], + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. + "]] + } \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/edge_routing.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/edge_routing.lua new file mode 100644 index 0000000000..eb9939c74c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/edge_routing.lua @@ -0,0 +1,49 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Edge Routing} +-- +-- The original layered drawing method described by Eades and Sugiyama +-- in does not include the routing or shaping of edges as a main +-- step. This makes sense if all nodes have the same size and +-- shape. In practical scenarios, however, this assumption often does +-- not hold. In these cases, advanced techniques may have to be +-- applied in order to avoid overlaps of nodes and edges. +-- +-- For more details, please see Section~4.1.5 of Pohlmann's Diploma +-- thesis. +-- +-- @end + + + +--- + +declare { + key = "polyline layer edge routing", + algorithm = require "pgf.gd.layered.EdgeRoutingGansnerKNV1993", + phase = "layer edge routing", + phase_default = true, + + summary = [[" + This edge routing algorithm uses polygonal lines to connect nodes. + "]], + documentation = [[" + For more details, please see Section~4.1.5 of Pohlmann's Diploma thesis. + + This is the default algorithm for edge routing. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/library.lua new file mode 100644 index 0000000000..950e02ffa3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/library.lua @@ -0,0 +1,94 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- A ``layered'' layout of a graph tries to arrange the nodes in +-- consecutive horizontal layers (naturally, by rotating the graph, this +-- can be changed in to vertical layers) such that edges tend to be only +-- between nodes on adjacent layers. Trees, for instance, can always be +-- laid out in this way. This method of laying out a graph is especially +-- useful for hierarchical graphs. +-- +-- The method implemented in this library is often called the +-- \emph{Sugiyama method}, which is a rather advanced method of +-- assigning nodes to layers and positions on these layers. The same +-- method is also used in the popular GraphViz program, indeed, the +-- implementation in \tikzname\ is based on the same pseudo-code from the +-- same paper as the implementation used in GraphViz and both programs +-- will often generate the same layout (but not always, as explained +-- below). The current implementation is due to Jannis Pohlmann, who +-- implemented it as part of his Diploma thesis. Please consult this +-- thesis for a detailed explanation of the Sugiyama method and its +-- history: +-- % +-- \begin{itemize} +-- \item +-- Jannis Pohlmann, +-- \newblock \emph{Configurable Graph Drawing Algorithms +-- for the \tikzname\ Graphics Description Language,} +-- \newblock Diploma Thesis, +-- \newblock Institute of Theoretical Computer Science, Universit\"at +-- zu L\"ubeck, 2011.\\[.5em] +-- \newblock Available online via +-- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ +-- \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} +-- \\[.5em] +-- (Note that since the publication of this thesis some option names +-- have been changed. Most noticeably, the option name +-- |layered drawing| was changed to |layered layout|, which is somewhat +-- more consistent with other names used in the graph drawing +-- libraries. Furthermore, the keys for choosing individual +-- algorithms for the different algorithm phases, have all changed.) +-- \end{itemize} +-- +-- The Sugiyama methods lays out a graph in five steps: +-- % +-- \begin{enumerate} +-- \item Cycle removal. +-- \item Layer assignment (sometimes called node ranking). +-- \item Crossing minimization (also referred to as node ordering). +-- \item Node positioning (or coordinate assignment). +-- \item Edge routing. +-- \end{enumerate} +-- % +-- It turns out that behind each of these steps there lurks an +-- NP-complete problem, which means, in practice, that each step is +-- impossible to perform optimally for larger graphs. For this reason, +-- heuristics and approximation algorithms are used to find a ``good'' +-- way of performing the steps. +-- +-- A distinctive feature of Pohlmann's implementation of the Sugiyama +-- method for \tikzname\ is that the algorithms used for each of the +-- steps can easily be exchanged, just specify a different option. For +-- the user, this means that by specifying a different option and thereby +-- using a different heuristic for one of the steps, a better layout can +-- often be found. For the researcher, this means that one can very +-- easily test new approaches and new heuristics without having to +-- implement all of the other steps anew. +-- +-- @library + +local layered + + +-- Load declarations from: +require "pgf.gd.layered" + +-- Load algorithms from: +require "pgf.gd.layered.Sugiyama" +require "pgf.gd.layered.cycle_removal" +require "pgf.gd.layered.node_ranking" +require "pgf.gd.layered.crossing_minimization" +require "pgf.gd.layered.node_positioning" +require "pgf.gd.layered.edge_routing" + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_positioning.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_positioning.lua new file mode 100644 index 0000000000..e51382d642 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_positioning.lua @@ -0,0 +1,55 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Node Positioning (Coordinate Assignment)} +-- +-- The second last step of the Sugiyama method decides about the final +-- $x$- and $y$-coordinates of the nodes. The main objectives of this +-- step are to position nodes so that the number of edge bends is kept +-- small and edges are drawn as vertically as possible. Another goal +-- is to avoid node and edge overlaps which is crucial in particular +-- if the nodes are allowed to have non-uniform sizes. The +-- $y$-coordinates of the nodes have no influence on the number of +-- bends. Obviously, nodes need to be separated enough geometrically +-- so that they do not overlap. It feels natural to aim at separating +-- all layers in the drawing by the same amount. Large nodes, however, +-- may force node positioning algorithms to override this uniform +-- level distance in order to avoid overlaps. +-- +-- For more details, please see Section~4.1.2 of Pohlmann's Diploma thesis. +-- +-- @end + + + +--- + +declare { + key = "linear optimization node positioning", + algorithm = require "pgf.gd.layered.NodePositioningGansnerKNV1993", + phase = "node positioning", + phase_default = true, + + summary = [[" + This node positioning method, due to Gasner et al., is based on a + linear optimization problem. + "]], + documentation = [[" + For more details, please see Section~4.1.3 of Pohlmann's Diploma thesis. + + This is the default algorithm for layer assignments. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_ranking.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_ranking.lua new file mode 100644 index 0000000000..c663d9ce36 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/layered/node_ranking.lua @@ -0,0 +1,72 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + +--- +-- @section subsection {Layer Assignment (Node Ranking)} +-- +-- Algorithms for producing layered drawings place nodes on discrete +-- layers from top to bottom. Layer assignment is the problem of +-- finding a partition so that for all edges $e = (u,v) \in E(G)$ the +-- equation $\mathit{layer}(u) < \mathit{layer}(v)$ holds. Such a +-- partition is called a \emph{layering}. This definition can be extended by +-- introducing edge weights or priorities and minimum length +-- constraints which has practical applications and allows users to +-- fine-tune the results. +-- +-- For more details, please see Section~4.1.2 of Pohlmann's Diploma +-- thesis. +-- +-- @end + + + +--- + +declare { + key = "linear optimization layer assignment", + algorithm = require "pgf.gd.layered.NodeRankingGansnerKNV1993", + phase = "node ranking", + phase_default = true, + + summary = [[" + This layer assignment method, due to Gasner et al., is based on a + linear optimization problem. + "]], + documentation = [[" + For more details, please see Section~4.1.2 of Pohlmann's Diploma + thesis. + + This is the default algorithm for layer assignments. + "]] +} + + + +--- + +declare { + key = "minimum height layer assignment", + algorithm = "pgf.gd.layered.NodeRankingMinimumHeight", + phase = "node ranking", + + summary = [[" + This layer assignment method minimizes the height of the resulting graph. + "]], + documentation = [[" + For more details, please see Section~4.1.3 of Pohlmann's Diploma thesis. + "]] +} + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib.lua new file mode 100644 index 0000000000..cc39ddd607 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib.lua @@ -0,0 +1,435 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- Basic library functions + +local lib = {} + +-- Declare namespace + +require("pgf.gd").lib = lib + + +-- General lib functions: + + +--- +-- Finds the first value in the |array| for which |test| is true. +-- +-- @param array An array to search in. +-- @param test A function that is applied to each element of the +-- array together with the index of the element and the +-- whole table. +-- +-- @return The value of the first value where the test is true. +-- @return The index of the first value where the test is true. +-- @return The function value of the first value where the test is +-- true (only returned if test is a function). +-- +function lib.find(array, test) + for i=1,#array do + local t = array[i] + local result = test(t,i,array) + if result then + return t,i,result + end + end +end + + +--- +-- Finds the first value in the |array| for which a function +-- returns a minimal value +-- +-- @param array An array to search in. +-- @param f A function that is applied to each element of the +-- array together with the index of the element and the +-- whole table. It should return an integer and, possibly, a value. +-- +-- Among all elements for which a non-nil integer is returned, let |i| +-- by the index of the element where this integer is minimal. +-- +-- @return |array[i]| +-- @return |i| +-- @return The return value(s) of the function at |array[i]|. +-- +function lib.find_min(array, f) + local best = math.huge + local best_result + local best_index + for i=1,#array do + local t = array[i] + local result, p = f(t,i,array) + if result and p < best then + best = p + best_result = result + best_index = i + end + end + if best_index then + return array[best_index],best_index,best_result,best + end +end + + + + +--- +-- Copies a table while preserving its metatable. +-- +-- @param source The table to copy. +-- @param target The table to which values are to be copied or |nil| if a new +-- table is to be allocated. +-- +-- @return The |target| table or a newly allocated table containing all +-- keys and values of the |source| table. +-- +function lib.copy(source, target) + if not target then + target = {} + end + for key, val in pairs(source) do + target[key] = val + end + return setmetatable(target, getmetatable(source)) +end + + +--- +-- Copies an array while preserving its metatable. +-- +-- @param source The array to copy. +-- @param target The array to which values are to be copied or |nil| if a new +-- table is to be allocated. The elements of the +-- |source| array will be added at the end. +-- +-- @return The |target| table or a newly allocated table containing all +-- keys and values of the |source| table. +-- +function lib.icopy(source, target) + target = target or {} + for _, val in ipairs(source) do + target[#target+1] = val + end + return setmetatable(target, getmetatable(source)) +end + + + + +--- +-- Apply a function to all pairs of a table, resulting in a new table. +-- +-- @param source The table. +-- @param fun A function taking two arguments (|val| and |key|, in +-- that order). Should return two values (a |new_val| and a +-- |new_key|). This pair will be inserted into the new table. If, +-- however, |new_key| is |nil|, the |new_value| will be inserted at +-- the position |key|. This means, in particular, that if the |fun| +-- takes only a single argument and returns only a single argument, +-- you have a ``classical'' value mapper. Also note that if +-- |new_value| is |nil|, the value is removed from the table. +-- +-- @return The new table. +-- +function lib.map(source, fun) + local target = {} + for key, val in pairs(source) do + local new_val, new_key = fun(val, key) + if new_key == nil then + new_key = key + end + target[new_key] = new_val + end + return target +end + + + +--- +-- Apply a function to all elements of an array, resulting in a new +-- array. +-- +-- @param source The array. +-- @param fun A function taking two arguments (|val| and |i|, the +-- current index). This function is applied to all elements of the +-- array. The result of this function is placed at the end of a new +-- array, expect when the function returns |nil|, in which case the +-- element is skipped. If this function is not provided (is |nil|), +-- the identity function is used. +-- @param new The target array (if |nil|, a new array is create). +-- % +--\begin{codeexample}[code only] +-- local a = lib.imap(array, function(v) if some_test(v) then return v end end) +--\end{codeexample} +-- +-- The above code is a filter that will remove all elements from the +-- array that do not pass |some_test|. +-- % +--\begin{codeexample}[code only] +-- lib.imap(a, lib.id, b) +--\end{codeexample} +-- +-- The above code has the same effect as |lib.icopy(a,b)|. +-- +-- @return The new array +-- +function lib.imap(source, fun, new) + if not new then + new = { } + end + for i, v in ipairs(source) do + new[#new+1] = fun(v, i) + end + return new +end + + +--- +-- Generate a random permutation of the numbers $1$ to $n$ in time +-- $O(n)$. Knuth's shuffle is used for this. +-- +-- @param n The desired size of the table +-- @return A random permutation + +function lib.random_permutation(n) + local p = {} + for i=1,n do + p[i] = i + end + for i=1,n-1 do + local j = lib.random(i,n) + p[i], p[j] = p[i], p[j] + end + return p +end + + +--- +-- The identity function, so you can write |lib.id| instead of +-- |function (x) return x end|. +-- + +function lib.id(...) + return ... +end + + + +--- +-- Tries to find an option in different objects that have an +-- options field. +-- +-- This function iterates over all objects given as parameters. In +-- each, it tries to find out whether the options field of the object +-- contains the option |name| and, if so, +-- returns the value. The important point is that checking whether the +-- option table of an object contains the name field is done using +-- |rawget| for all but the last parameter. This means that when you +-- write +-- % +--\begin{codeexample}[code only] +--lib.lookup_option("foo", vertex, graph) +--\end{codeexample} +-- % +-- and if |/graph drawing/foo| has an initial value set, if the +-- parameter is not explicitly set in a vertex, you will get the value +-- set for the graph or, if it is not set there either, the initial +-- value. In contrast, if you write +-- % +--\begin{codeexample}[code only] +-- vertex.options["foo"] or graph.options["foo"] +--\end{codeexample} +-- % +-- what happens is that the first access to |.options| will +-- \emph{always} return something when an initial parameter has been +-- set for the option |foo|. +-- +-- @param name The name of the options +-- @param ... Any number of objects. Each must have an options +-- field. +-- +-- @return The found option + +function lib.lookup_option(name, ...) + local list = {...} + for i=1,#list-1 do + local o = list[i].options + if o then + local v = rawget(o, name) + if v then + return v + end + end + end + return list[#list].options[name] +end + + + +--- +-- Turns a table |t| into a class in the sense of object oriented +-- programming. In detail, this means that |t| is augmented by +-- a |new| function, which takes an optional table of |initial| values +-- and which outputs a new table whose metatable is the +-- class. The |new| function will call the function |constructor| if +-- it exists. Furthermore, the class object's |__index| is set to itself +-- and its meta table is set to the |base_class| field of the +-- table. If |t| is |nil|, a new table is created. +-- +-- Here is a typical usage of this function: +-- % +--\begin{codeexample}[code only] +--local Point = lib.class {} +-- +--function Point:length() +-- return math.sqrt(self.x*self.x + self.y*self.y) +--end +-- +--local p = Point.new { x = 5, y = 6 } +-- +--print(p:length()) +--\end{codeexample} +-- % +-- We can subclass this as follows: +-- % +--\begin{codeexample}[code only] +--local Point3D = lib.class { base_class = Point } +-- +--function Point3D:length() +-- local l = Point.length(self) -- Call base class's function +-- return math.sqrt(l*l + self.z*self.zdy) +--end +-- +--local p = Point3D.new { x = 5, y = 6, z = 6 } +-- +--print(p:length()) +--\end{codeexample} +-- +-- @param t A table that gets augmented to a class. If |nil|, a new +-- table is created. +-- @return The augmented table. + +function lib.class(t) + t = t or {} + + -- First, setup indexing, if necessary + if not t.__index then + t.__index = t + end + + -- Second, setup new method, if necessary + t.new = t.new or + function (initial) + + -- Create new object + local obj = {} + for k,v in pairs(initial or {}) do + obj[k] = v + end + setmetatable(obj, t) + + if obj.constructor then + obj:constructor() + end + + return obj + end + + -- Third, setup inheritance, if necessary + if not getmetatable(t) then + setmetatable(t, t.base_class) + end + + return t +end + + + +--- +-- Returns a method that is loaded only on demand for a class. +-- +-- The idea behind this function is that you may have a class (or just +-- a table) for which some methods are needed only seldomly. In this +-- case, you can put these methods in a separate file and then use +-- |ondemand| to indicate that the methods are found in a +-- another file. +-- % +--\begin{codeexample}[code only] +-- -- File Foo.lua +-- local Foo = {} +-- function Foo.bar () ... end +-- function Foo.bar2 () ... end +-- Foo.bar3 = lib.ondemand("Foo_extra", Foo, "bar3") +-- Foo.bar4 = lib.ondemand("Foo_extra", Foo, "bar4") +-- +-- return Foo +-- +-- -- Foo_extra.lua +-- local Foo = require "Foo" +-- function Foo.bar3 () ... end +-- function Foo.bar4 () ... end +--\end{codeexample} +-- +-- @param filename The name of the file when extra methods are +-- located. +-- @param table The table for which the missing functions should be +-- loaded when they are accessed. +-- @param method The name of the method. +-- +-- @return A function that, when called, loads the filename using +-- |require| and, then, forwards the call to the method. + +function lib.ondemand(filename, table, name) + return function(...) + require (filename) + return table[name] (...) + end +end + + + +--- +-- This implements the a random number generator similar to the one +-- provided by Lua, but based on the tex.uniformdeviate primitive to +-- avoid differences in random numbers due to platform specifics. +-- +-- @param l Lower bound +-- @param u Upper bound +-- @return A random number +function lib.random(l,u) + local fraction_one = 268435456 + local r = tex.uniform_rand(fraction_one)/fraction_one + if l and u then + assert(l <= u) + return math.floor(r*(u-l+1)) + l + elseif l then + assert(1.0 <= l) + return math.floor(r*l) + 1.0 + else + return r + end +end + +--- +-- Provide the seed for the random number generator +-- +-- @param seed random seed +function lib.randomseed(seed) + tex.init_rand(seed) +end + +-- Done + +return lib diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Bezier.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Bezier.lua new file mode 100644 index 0000000000..e4fe21d942 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Bezier.lua @@ -0,0 +1,160 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This library offers a number of methods for working with Bezi\'er +-- curves. + +local Bezier = {} + +-- Namespace +require("pgf.gd.lib").Bezier = Bezier + + +-- Imports + +local Coordinate = require 'pgf.gd.model.Coordinate' + + +--- +-- Compute a point ``along a curve at a time''. You provide the four +-- coordinates of the curve and a time. You get a point on the curve +-- as return value as well as the two support vector for curve +-- before this point and two support vectors for the curve after the +-- point. +-- +-- For speed reasons and in order to avoid superfluous creation of +-- lots of tables, all values are provided and returned as pairs of +-- values rather than as |Coordinate| objects. +-- +-- @param ax The coordinate where the curve starts. +-- @param ay +-- @param bx The first support point. +-- @param by +-- @param cx The second support point. +-- @param cy +-- @param dx The coordinate where the curve ends. +-- @param dy +-- @param t A time (a number). +-- +-- @return The point |p| on the curve at time |t| ($x$-part). +-- @return The point |p| on the curve at time |t| ($y$-part). +-- @return The first support point of the curve between |a| and |p| ($x$-part). +-- @return The first support point of the curve between |a| and |p| ($y$-part). +-- @return The second support point of the curve between |a| and |p| ($x$-part). +-- @return The second support point of the curve between |a| and |p| ($y$-part). +-- @return The first support point of the curve between |p| and |d| ($x$-part). +-- @return The first support point of the curve between |p| and |d| ($y$-part). +-- @return The second support point of the curve between |p| and |d| ($x$-part). +-- @return The second support point of the curve between |p| and |d| ($y$-part). + +function Bezier.atTime(ax,ay,bx,by,cx,cy,dx,dy,t) + + local s = 1-t + + local ex, ey = ax*s + bx*t, ay*s + by*t + local fx, fy = bx*s + cx*t, by*s + cy*t + local gx, gy = cx*s + dx*t, cy*s + dy*t + + local hx, hy = ex*s + fx*t, ey*s + fy*t + local ix, iy = fx*s + gx*t, fy*s + gy*t + + local jx, jy = hx*s + ix*t, hy*s + iy*t + + return jx, jy, ex, ey, hx, hy, ix, iy, gx, gy +end + + +--- +-- The ``coordinate version'' of the |atTime| function, where both the +-- parameters and the return values are coordinate objects. + +function Bezier.atTimeCoordinates(a,b,c,d,t) + local jx, jy, ex, ey, hx, hy, ix, iy, gx, gy = + Bezier.atTime(a.x,a.y,b.x,b.y,c.x,c.y,d.x,d.y,t) + + return + Coordinate.new(jx, jy), + Coordinate.new(ex, ey), + Coordinate.new(hx, hy), + Coordinate.new(ix, iy), + Coordinate.new(gx, gy) +end + + +--- +-- Computes the support points of a Bezier curve based on two points +-- on the curves at certain times. +-- +-- @param from The start point of the curve +-- @param p1 A first point on the curve +-- @param t1 A time when this point should be reached +-- @param p2 A second point of the curve +-- @param t2 A time when this second point should be reached +-- @param to The end of the curve +-- +-- @return sup1 A first support point of the curve +-- @return sup2 A second support point of the curve + +function Bezier.supportsForPointsAtTime(from, p1, t1, p2, t2, to) + + local s1 = 1 - t1 + local s2 = 1 - t2 + + local f1a = s1^3 + local f1b = t1 * s1^2 * 3 + local f1c = t1^2 * s1 * 3 + local f1d = t1^3 + + local f2a = s2^3 + local f2b = t2 * s2^2 * 3 + local f2c = t2^2 * s2 * 3 + local f2d = t2^3 + + -- The system: + -- p1.x - from.x * f1a - to.x * f1d = sup1.x * f1b + sup2.x * f1c + -- p2.x - from.x * f2a - to.x * f2d = sup1.x * f2b + sup2.x * f2c + -- + -- p1.y - from.y * f1a - to.y * f1d = sup1.y * f1b + sup2.y * f1c + -- p2.y - from.y * f2a - to.y * f2d = sup1.y * f2b + sup2.y * f2c + + local a = f1b + local b = f1c + local c = p1.x - from.x * f1a - to.x * f1d + local d = f2b + local e = f2c + local f = p2.x - from.x * f2a - to.x * f2d + + local det = a*e - b*d + local x1 = -(b*f - e*c)/det + local x2 = -(c*d - a*f)/det + + local c = p1.y - from.y * f1a - to.y * f1d + local f = p2.y - from.y * f2a - to.y * f2d + + local det = a*e - b*d + local y1 = -(b*f - e*c)/det + local y2 = -(c*d - a*f)/det + + return Coordinate.new(x1,y1), Coordinate.new(x2,y2) + +end + + + + + + +-- Done + +return Bezier \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/DepthFirstSearch.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/DepthFirstSearch.lua new file mode 100644 index 0000000000..564b8f6839 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/DepthFirstSearch.lua @@ -0,0 +1,125 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The DepthFirstSearch class implements a generic depth first function. It does not +-- require that it is run on graphs, but can be used for anything where a visit function and +-- a complete function is available. + +local DepthFirstSearch = {} +DepthFirstSearch.__index = DepthFirstSearch + +-- Namespace +require("pgf.gd.lib").DepthFirstSearch = DepthFirstSearch + +-- Imports +local Stack = require "pgf.gd.lib.Stack" + + + +-- TT: TODO Jannis: Please document... + +function DepthFirstSearch.new(init_func, visit_func, complete_func) + local dfs = { + init_func = init_func, + visit_func = visit_func, + complete_func = complete_func, + + stack = Stack.new(), + discovered = {}, + visited = {}, + completed = {}, + } + setmetatable(dfs, DepthFirstSearch) + return dfs +end + + + +function DepthFirstSearch:run() + self:reset() + self.init_func(self) + + while self.stack:getSize() > 0 do + local data = self.stack:peek() + + if not self:getVisited(data) then + if self.visit_func then + self.visit_func(self, data) + end + else + if self.complete_func then + self.complete_func(self, data) + end + self:setCompleted(data, true) + self.stack:pop() + end + end +end + + + +function DepthFirstSearch:reset() + self.discovered = {} + self.visited = {} + self.completed = {} + self.stack = Stack.new() +end + + + +function DepthFirstSearch:setDiscovered(data, discovered) + self.discovered[data] = discovered +end + + + +function DepthFirstSearch:getDiscovered(data) + return self.discovered[data] +end + + + +function DepthFirstSearch:setVisited(data, visited) + self.visited[data] = visited +end + + + +function DepthFirstSearch:getVisited(data) + return self.visited[data] +end + + + +function DepthFirstSearch:setCompleted(data, completed) + self.completed[data] = completed +end + + + +function DepthFirstSearch:getCompleted(data) + return self.completed[data] +end + + + +function DepthFirstSearch:push(data) + self.stack:push(data) +end + + + +-- Done + +return DepthFirstSearch \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Direct.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Direct.lua new file mode 100644 index 0000000000..81728a1a44 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Direct.lua @@ -0,0 +1,95 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- Direct is a class that collects algorithms for computing new +-- versions of a graph where arcs point in certain directions. + +local Direct = {} + +-- Namespace +require("pgf.gd.lib").Direct = Direct + +-- Imports +local Digraph = require "pgf.gd.model.Digraph" + + +--- Compute a digraph from a syntactic digraph. +-- +-- This function takes a syntactic digraph and compute a new digraph +-- where all arrow point in the "semantic direction" of the syntactic +-- arrows. For instance, while "a <- b" will cause an arc from a to be +-- to be added to the syntactic digraph, calling this function will +-- return a digraph in which there is an arc from b to a rather than +-- the other way round. In detail, "a <- b" is translated as just +-- described, "a -> b" yields an arc from a to b as expected, "a <-> b" +-- and "a -- b" yield arcs in both directions and, finally, "a -!- b" +-- yields no arc at all. +-- +-- @param syntactic_digraph A syntactic digraph, usually the "input" +-- graph as specified syntactically be the user. +-- +-- @return A new "semantic" digraph object. + +function Direct.digraphFromSyntacticDigraph(syntactic_digraph) + local digraph = Digraph.new(syntactic_digraph) -- copy + + -- Now go over all arcs of the syntactic_digraph and turn them into + -- arcs with the correct direction in the digraph: + for _,a in ipairs(syntactic_digraph.arcs) do + for _,m in ipairs(a.syntactic_edges) do + local direction = m.direction + if direction == "->" then + digraph:connect(a.tail, a.head) + elseif direction == "<-" then + digraph:connect(a.head, a.tail) + elseif direction == "--" or direction == "<->" then + digraph:connect(a.tail, a.head) + digraph:connect(a.head, a.tail) + end + -- Case -!-: No edges... + end + end + + return digraph +end + + +--- Turn an arbitrary graph into a directed graph +-- +-- Takes a digraph as input and returns its underlying undirected +-- graph, coded as a digraph. This means that between any two vertices +-- if there is an arc in one direction, there is also one in the other. +-- +-- @param digraph A directed graph +-- +-- @return The underlying undirected graph of digraph. + +function Direct.ugraphFromDigraph(digraph) + local ugraph = Digraph.new(digraph) + + -- Now go over all arcs of the syntactic_digraph and turn them into + -- arcs with the correct direction in the digraph: + for _,a in ipairs(digraph.arcs) do + ugraph:connect(a.head,a.tail) + ugraph:connect(a.tail,a.head) + end + + return ugraph +end + + + + +-- Done + +return Direct diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Event.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Event.lua new file mode 100644 index 0000000000..880796ce97 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Event.lua @@ -0,0 +1,98 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- Events are used to communicate ``interesting'' events from the +-- parser to the graph drawing algorithms. +-- +-- As a syntactic description of some graph is being parsed, vertices, +-- arcs, and a digraph object representing this graph get +-- constructed. However, even though syntactic annotations such as +-- options for the vertices and arcs are attached to them and can be +-- accessed through the graph objects, some syntactic information is +-- neither represented in the digraph object nor in the vertices and +-- the arcs. A typical example is a ``missing'' node in a tree: Since +-- it is missing, there is neither a vertex object nor arc objects +-- representing it. It is also not a global option of the graph. +-- +-- For these reasons, in addition to the digraph object itself, +-- additional information can be passed by a parser to graph drawing +-- algorithms through the means of events. Each |Event| consists of a +-- |kind| field, which is just some string, and a |parameters| field, +-- which stores additional, kind-specific information. As a graph is +-- being parsed, a string of events is accumulated and is later on +-- available through the |events| field of the graph drawing scope. +-- +-- The following events are created during the parsing process by the +-- standard parsers of \tikzname: +-- % +-- \begin{itemize} +-- \item[|node|] When a node of the input graph has been parsed and +-- a |Vertex| object has been created for it, an event with kind +-- |node| is created. The |parameter| of this event is the +-- just-created vertex. +-- +-- The same kind of event is used to indicate ``missing'' nodes. In +-- this case, the |parameters| field is |nil|. +-- \item[|edge|] When an edge of the input graph has been parsed, an +-- event is created of kind |edge|. The |parameters| field will store +-- an array with two entries: The first is the |Arc| object whose +-- |syntactic_edges| field stores the |edge|. The second is the index +-- of the edge inside the |syntactic_edges| field. +-- \item[|begin|] +-- Signals the beginning of a group, which will be ended with a +-- corresponding |end| event later on. The |parameters| field will +-- indicate the kind of group. Currently, only the string +-- |"descendants"| is used as |parameters|, indicating the start of +-- several nodes that are descendants of a given node. This +-- information can be used by algorithms for reconstructing the +-- input structure of trees. +-- \item[|end|] Signals the end of a group begun by a |begin| event +-- earlier on. +-- \end{itemize} +-- +-- @field kind A string representing the kind of the events. +-- @field parameters Kind-specific parameters. +-- @field index A number that stores the events logical position in +-- the sequence of events. The number need not be an integer array +-- index. +-- +local Event = {} +Event.__index = Event + + +-- Namespace +require("pgf.gd.lib").Event = Event + + + +--- +-- Create a new event object +-- +-- @param initial Initial fields of the new event. +-- +-- @return The new object + +function Event.new(values) + local new = {} + for k,v in pairs(values) do + new[k] = v + end + return setmetatable(new, Event) +end + + + +-- done + +return Event \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/LookupTable.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/LookupTable.lua new file mode 100644 index 0000000000..fc2043d523 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/LookupTable.lua @@ -0,0 +1,111 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This table provides two utility functions for managing ``lookup +-- tables''. Such a table is a mixture of an array and a hashtable: +-- It stores (only) tables. Each table is stored once in a normal +-- array position. Additionally, the lookup table is also indexed at +-- the position of the table (used as a key) and this position is set +-- to |true|. This means that you can test whether a table |t| is in the +-- lookup table |l| simply by testing whether |l[t]| is true. +-- +local LookupTable = {} + +-- Namespace +require("pgf.gd.lib").LookupTable = LookupTable + + + +--- +-- Add all elements in the |array| to a lookup table. If an element of +-- the array is already present in the table, it will not be added +-- again. +-- +-- This operation takes time $O(|\verb!array!|)$. +-- +-- @param l Lookup table +-- @param array An array of to-be-added tables. + +function LookupTable.add(l, array) + for i=1,#array do + local t = array[i] + if not l[t] then + l[t] = true + l[#l + 1] = t + end + end +end + + +--- +-- Add one element to a lookup table. If it is already present in the +-- table, it will not be added again. +-- +-- This operation takes time $O(1)$. +-- +-- @param l Lookup table +-- @param e The to-be-added element. + +function LookupTable.addOne(l, e) + if not l[e] then + l[e] = true + l[#l + 1] = e + end +end + + +--- +-- Remove tables from a lookup table. +-- +-- Note that this operation is pretty expensive insofar as it will +-- always cost a traversal of the whole lookup table. However, this is +-- also the maximum cost, even when a lot of entries need to be +-- deleted. Thus, it is much better to ``pool'' multiple remove +-- operations in a single one. +-- +-- This operation takes time $O(\max\{|\verb!array!|, |\verb!l!|\})$. +-- +-- @param l Lookup table +-- @param t An array of to-be-removed tables. + +function LookupTable.remove(l, array) + -- Step 1: Mark all to-be-deleted entries + for i=1,#array do + local t = array[i] + if l[t] then + l[t] = false + end + end + + -- Step 2: Collect garbage... + local target = 1 + for i=1,#l do + local t = l[i] + if l[t] == false then + l[t] = nil + else + l[target] = t + target = target + 1 + end + end + for i=#l,target,-1 do + l[i] = nil + end +end + + + +-- Done + +return LookupTable \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PathLengths.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PathLengths.lua new file mode 100644 index 0000000000..4bfa896ef9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PathLengths.lua @@ -0,0 +1,209 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This table provides algorithms for computing distances between +-- nodes of a graph (in the sense of path lengths). + +local PathLengths = {} + +-- Namespace +require("pgf.gd.lib").PathLengths = PathLengths + +-- Import +local PriorityQueue = require "pgf.gd.lib.PriorityQueue" + + + +--- +-- Performs the Dijkstra algorithm to solve the single-source shortest path problem. +-- +-- The algorithm computes the shortest paths from |source| to all nodes +-- in the graph. It also generates a table with distance level sets, each of +-- which contain all nodes that have the same corresponding distance to +-- |source|. Finally, a mapping of nodes to their parents along the +-- shortest paths is generated to allow the reconstruction of the paths +-- that were chosen by the Dijkstra algorithm. +-- +-- @param graph The graph to compute the shortest paths for. +-- @param source The node to compute the distances to. +-- +-- @return A mapping of nodes to their distance to |source|. +-- @return An array of distance level sets. The set at index |i| contains +-- all nodes that have a distance of |i| to |source|. +-- @return A mapping of nodes to their parents to allow the reconstruction +-- of the shortest paths chosen by the Dijkstra algorithm. +-- +function PathLengths.dijkstra(graph, source) + local distance = {} + local levels = {} + local parent = {} + + local queue = PriorityQueue.new() + + -- reset the distance of all nodes and insert them into the priority queue + for _,node in ipairs(graph.nodes) do + if node == source then + distance[node] = 0 + parent[node] = nil + queue:enqueue(node, distance[node]) + else + distance[node] = #graph.nodes + 1 -- this is about infinity ;) + queue:enqueue(node, distance[node]) + end + end + + while not queue:isEmpty() do + local u = queue:dequeue() + + assert(distance[u] < #graph.nodes + 1, 'the graph is not connected, Dijkstra will not work') + + if distance[u] > 0 then + levels[distance[u]] = levels[distance[u]] or {} + table.insert(levels[distance[u]], u) + end + + for _,edge in ipairs(u.edges) do + local v = edge:getNeighbour(u) + local alternative = distance[u] + 1 + if alternative < distance[v] then + distance[v] = alternative + + parent[v] = u + + -- update the priority of v + queue:updatePriority(v, distance[v]) + end + end + end + + return distance, levels, parent +end + + + + +--- +-- Performs the Floyd-Warshall algorithm to solve the all-source shortest path problem. +-- +-- @param graph The graph to compute the shortest paths for. +-- +-- @return A distance matrix +-- +function PathLengths.floydWarshall(graph) + local distance = {} + local infinity = math.huge + + for _,i in ipairs(graph.nodes) do + distance[i] = {} + for _,j in ipairs(graph.nodes) do + distance[i][j] = infinity + end + end + + for _,i in ipairs(graph.nodes) do + for _,edge in ipairs(i.edges) do + local j = edge:getNeighbour(i) + distance[i][j] = edge.weight or 1 + end + end + + for _,k in ipairs(graph.nodes) do + for _,i in ipairs(graph.nodes) do + for _,j in ipairs(graph.nodes) do + distance[i][j] = math.min(distance[i][j], distance[i][k] + distance[k][j]) + end + end + end + + return distance +end + + + + +--- +-- Computes the pseudo diameter of a graph. +-- +-- The diameter of a graph is the maximum of the shortest paths between +-- any pair of nodes in the graph. A pseudo diameter is an approximation +-- of the diameter that is computed by picking a starting node |u| and +-- finding a node |v| that is farthest away from |u| and has the smallest +-- degree of all nodes that have the same distance to |u|. The algorithm +-- continues with |v| as the new starting node and iteratively tries +-- to find an end node that is generates a larger pseudo diameter. +-- It terminates as soon as no such end node can be found. +-- +-- @param graph The graph. +-- +-- @return The pseudo diameter of the graph. +-- @return The start node of the corresponding approximation of a maximum +-- shortest path. +-- @return The end node of that path. +-- +function PathLengths.pseudoDiameter(graph) + + -- find a node with minimum degree + local start_node = graph.nodes[1] + for _,node in ipairs(graph.nodes) do + if node:getDegree() < start_node:getDegree() then + start_node = node + end + end + + assert(start_node) + + local old_diameter = 0 + local diameter = 0 + local end_node = nil + + while true do + local distance, levels = PathLengths.dijkstra(graph, start_node) + + -- the number of levels is the same as the distance of the nodes + -- in the last level to the start node + old_diameter = diameter + diameter = #levels + + -- abort if the diameter could not be improved + if diameter == old_diameter then + end_node = levels[#levels][1] + break + end + + -- select the node with the smallest degree from the last level as + -- the start node for the next iteration + start_node = levels[#levels][1] + for _,node in ipairs(levels[#levels]) do + if node:getDegree() < start_node:getDegree() then + start_node = node + end + end + + assert(start_node) + end + + assert(start_node) + assert(end_node) + + return diameter, start_node, end_node +end + + + + + +-- Done + +return PathLengths \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua new file mode 100644 index 0000000000..3fd29cdb74 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua @@ -0,0 +1,342 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- A PriorityQueue supports operations for quickly finding the minimum from a set of elements +-- +-- Its implementation is based on (simplified) Fibonacci heaps. +local PriorityQueue = {} +PriorityQueue.__index = PriorityQueue + + +-- Namespace +local lib = require "pgf.gd.lib" +lib.PriorityQueue = PriorityQueue + + + +-- Local declarations +local FibonacciHeap = {} +local FibonacciHeapNode = {} + + + + +--- Creates a new priority queue +-- +-- @return The newly created queue + +function PriorityQueue.new() + local queue = { + heap = FibonacciHeap.new(), + nodes = {}, + values = {}, + } + setmetatable(queue, PriorityQueue) + return queue +end + + + +--- Add an element with a certain priority to the queue +-- +-- @param value An object +-- @param priority Its priority + +function PriorityQueue:enqueue(value, priority) + local node = self.heap:insert(priority) + self.nodes[value] = node + self.values[node] = value +end + + + +--- Removes the element with the minimum priority from the queue +-- +-- @return The element with the minimum priority + +function PriorityQueue:dequeue() + local node = self.heap:extractMinimum() + + if node then + local value = self.values[node] + self.nodes[value] = nil + self.values[node] = nil + return value + else + return nil + end +end + + + +--- Lower the priority of an element of a queue +-- +-- @param value An object +-- @param priority A new priority, which must be lower than the old priority + +function PriorityQueue:updatePriority(value, priority) + local node = self.nodes[value] + assert(node, 'updating the priority of ' .. tostring(value) .. ' failed because it is not in the priority queue') + self.heap:updateValue(node, priority) +end + + + +--- Tests, whether the queue is empty +-- +-- @return True, if the queue is empty + +function PriorityQueue:isEmpty() + return #self.heap.trees == 0 +end + + + + + + +-- Internals: An implementation of Fibonacci heaps. +FibonacciHeap.__index = FibonacciHeap + + +function FibonacciHeap.new() + local heap = { + trees = trees or {}, + minimum = nil, + } + setmetatable(heap, FibonacciHeap) + return heap +end + + + +function FibonacciHeap:insert(value) + local node = FibonacciHeapNode.new(value) + local heap = FibonacciHeap.new() + table.insert(heap.trees, node) + self:merge(heap) + return node +end + + + +function FibonacciHeap:merge(other) + for _, tree in ipairs(other.trees) do + table.insert(self.trees, tree) + end + self:updateMinimum() +end + + + +function FibonacciHeap:extractMinimum() + if self.minimum then + local minimum = self:removeTableElement(self.trees, self.minimum) + + for _, child in ipairs(minimum.children) do + child.root = child + table.insert(self.trees, child) + end + + local same_degrees_found = true + while same_degrees_found do + same_degrees_found = false + + local degrees = {} + + for _, root in ipairs(self.trees) do + local degree = root:getDegree() + + if degrees[degree] then + if root.value < degrees[degree].value then + self:linkRoots(root, degrees[degree]) + else + self:linkRoots(degrees[degree], root) + end + + degrees[degree] = nil + same_degrees_found = true + break + else + degrees[degree] = root + end + end + end + + self:updateMinimum() + + return minimum + end +end + + + +function FibonacciHeap:updateValue(node, value) + local old_value = node.value + local new_value = value + + if new_value <= old_value then + self:decreaseValue(node, value) + else + assert(false, 'FibonacciHeap:increaseValue is not implemented yet') + end +end + + + +function FibonacciHeap:decreaseValue(node, value) + assert(value <= node.value) + + node.value = value + + if node.value < node.parent.value then + local parent = node.parent + self:cutFromParent(node) + + if not parent:isRoot() then + if parent.marked then + self:cutFromParent(parent) + else + parent.marked = true + end + end + end + + if node.value < self.minimum.value then + self.minimum = node + end +end + + + +function FibonacciHeap:delete(node) + self:decreaseValue(node, -math.huge) + self:extractMinimum() +end + + + +function FibonacciHeap:linkRoots(root, child) + child.root = root + child.parent = root + + child = self:removeTableElement(self.trees, child) + table.insert(root.children, child) + + return root +end + + + +function FibonacciHeap:cutFromParent(node) + local parent = node.parent + + node.root = node + node.parent = node + node.marked = false + + node = self:removeTableElement(parent.children, node) + table.insert(self.trees, node) +end + + + +function FibonacciHeap:updateMinimum() + self.minimum = self.trees[1] + + for _, root in ipairs(self.trees) do + if root.value < self.minimum.value then + self.minimum = root + end + end +end + + + +function FibonacciHeap:removeTableElement(input_table, element) + for i = 1, #input_table do + if input_table[i] == element then + return table.remove(input_table, i) + end + end +end + + + + +-- Now come the nodes + +FibonacciHeapNode.__index = FibonacciHeapNode + +function FibonacciHeapNode.new(value, root, parent) + local node = { + value = value, + children = {}, + marked = false, + root = nil, + parent = nil, + } + setmetatable(node, FibonacciHeapNode) + + if root then + node.root = root + node.parent = parent + else + node.root = node + node.parent = node + end + + return node +end + +function FibonacciHeapNode:addChild(value) + local child = FibonacciHeapNode.new(value, self.root, self) + table.insert(self.children, child) +end + +function FibonacciHeapNode:getDegree() + return #self.children +end + + + +function FibonacciHeapNode:setRoot(root) + self.root = root + + if root == self then + self.parent = root + end + + if #self.children > 0 then + for _, child in ipairs(self.children) do + child.root = root + end + end +end + + + +function FibonacciHeapNode:isRoot() + return self.root == self +end + + + + + + +-- done + +return PriorityQueue \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua new file mode 100644 index 0000000000..bcb7276190 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua @@ -0,0 +1,279 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- The Simplifiers class is a singleton object. +-- Its methods allow implement methods for simplifying graphs, for instance +-- for removing loops or multiedges or computing spanning trees. + +local Simplifiers = {} + +-- Namespace +local lib = require "pgf.gd.lib" +lib.Simplifiers = Simplifiers + + + + +-- Imports + +local Edge = require "pgf.gd.deprecated.Edge" +local Node = require "pgf.gd.deprecated.Node" + + + + + +--- Algorithm to classify edges of a DFS search tree. +-- +-- TODO Jannis: document this algorithm as soon as it is completed and bug-free. +-- TT: Replace this algorithm by something else, perhaps? +-- +function Simplifiers:classifyEdges(graph) + local discovered = {} + local visited = {} + local recursed = {} + local completed = {} + + local tree_and_forward_edges = {} + local cross_edges = {} + local back_edges = {} + + local stack = {} + + local function push(node) + table.insert(stack, node) + end + + local function peek() + return stack[#stack] + end + + local function pop() + return table.remove(stack) + end + + local initial_nodes = graph.nodes + + for i=#initial_nodes,1,-1 do + local node = initial_nodes[i] + push(node) + discovered[node] = true + end + + while #stack > 0 do + local node = peek() + local edges_to_traverse = {} + + visited[node] = true + + if not recursed[node] then + recursed[node] = true + + local out_edges = node:getOutgoingEdges() + for _,edge in ipairs(out_edges) do + local neighbour = edge:getNeighbour(node) + + if not discovered[neighbour] then + table.insert(tree_and_forward_edges, edge) + table.insert(edges_to_traverse, edge) + else + if not completed[neighbour] then + if not visited[neighbour] then + table.insert(tree_and_forward_edges, edge) + table.insert(edges_to_traverse, edge) + else + table.insert(back_edges, edge) + end + else + table.insert(cross_edges, edge) + end + end + end + + if #edges_to_traverse == 0 then + completed[node] = true + pop() + else + for i=#edges_to_traverse,1,-1 do + local neighbour = edges_to_traverse[i]:getNeighbour(node) + discovered[neighbour] = true + push(neighbour) + end + end + else + completed[node] = true + pop() + end + end + + return tree_and_forward_edges, cross_edges, back_edges +end + + + + + +-- +-- +-- Loops and Multiedges +-- +-- + + +--- Remove all loops from a graph +-- +-- This method will remove all loops from a graph. +-- +-- @param algorithm An algorithm object + +function Simplifiers:removeLoopsOldModel(algorithm) + local graph = algorithm.graph + local loops = {} + + for _,edge in ipairs(graph.edges) do + if edge:getHead() == edge:getTail() then + loops[#loops+1] = edge + end + end + + for i=1,#loops do + graph:deleteEdge(loops[i]) + end + + graph[algorithm].loops = loops +end + + + +--- Restore loops that were previously removed. +-- +-- @param algorithm An algorithm object + +function Simplifiers:restoreLoopsOldModel(algorithm) + local graph = algorithm.graph + + for _,edge in ipairs(graph[algorithm].loops) do + graph:addEdge(edge) + edge:getTail():addEdge(edge) + end + + graph[algorithm].loops = nil +end + + + + +--- Remove all multiedges. +-- +-- Every multiedge of the graph will be replaced by a single edge. +-- +-- @param algorithm An algorithm object + +function Simplifiers:collapseMultiedgesOldModel(algorithm, collapse_action) + local graph = algorithm.graph + local collapsed_edges = {} + local node_processed = {} + + for _,node in ipairs(graph.nodes) do + node_processed[node] = true + + local multiedge = {} + + local function handle_edge (edge) + + local neighbour = edge:getNeighbour(node) + + if not node_processed[neighbour] then + if not multiedge[neighbour] then + multiedge[neighbour] = Edge.new{ direction = Edge.RIGHT } + collapsed_edges[multiedge[neighbour]] = {} + end + + if collapse_action then + collapse_action(multiedge[neighbour], edge, graph) + end + + table.insert(collapsed_edges[multiedge[neighbour]], edge) + end + end + + for _,edge in ipairs(node:getIncomingEdges()) do + handle_edge(edge) + end + + for _,edge in ipairs(node:getOutgoingEdges()) do + handle_edge(edge) + end + + for neighbour, multiedge in pairs(multiedge) do + + if #collapsed_edges[multiedge] <= 1 then + collapsed_edges[multiedge] = nil + else + for _,subedge in ipairs(collapsed_edges[multiedge]) do + graph:deleteEdge(subedge) + end + + multiedge:addNode(node) + multiedge:addNode(neighbour) + + graph:addEdge(multiedge) + end + end + end + + graph[algorithm].collapsed_edges = collapsed_edges +end + + +--- Expand multiedges that were previously collapsed +-- +-- @param algorithm An algorithm object + +function Simplifiers:expandMultiedgesOldModel(algorithm) + local graph = algorithm.graph + for multiedge, subedges in pairs(graph[algorithm].collapsed_edges) do + assert(#subedges >= 2) + + graph:deleteEdge(multiedge) + + for _,edge in ipairs(subedges) do + + -- Copy bend points + for _,p in ipairs(multiedge.bend_points) do + edge.bend_points[#edge.bend_points+1] = p:copy() + end + + -- Copy options + for k,v in pairs(multiedge.algorithmically_generated_options) do + edge.algorithmically_generated_options[k] = v + end + + for _,node in ipairs(edge.nodes) do + node:addEdge(edge) + end + + graph:addEdge(edge) + end + end + + graph[algorithm].collapsed_edges = nil +end + + + + + +-- Done + +return Simplifiers diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Stack.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Stack.lua new file mode 100644 index 0000000000..75084b6e38 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Stack.lua @@ -0,0 +1,61 @@ +-- Copyright 2011 by Jannis Pohlmann +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- A Stack is a very simple wrapper around an array +-- +-- + +local Stack = {} +Stack.__index = Stack + + +-- Namespace +require("pgf.gd.lib").Stack = Stack + + +--- Create a new stack +function Stack.new() + local stack = {} + setmetatable(stack, Stack) + return stack +end + + +--- Push an element on top of the stack +function Stack:push(data) + self[#self+1] = data +end + + +--- Inspect (but not pop) the top element of a stack +function Stack:peek() + return self[#self] +end + + +--- Pop an element from the top of the stack +function Stack:pop() + return table.remove(self, #self) +end + + +--- Get the height of the stack +function Stack:getSize() + return #self +end + + + +-- done + +return Stack \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Storage.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Storage.lua new file mode 100644 index 0000000000..e029fdf7ff --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Storage.lua @@ -0,0 +1,110 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- A storage is an object that, as the name suggests, allows you to +-- ``store stuff concerning objects.'' Basically, it behaves like +-- table having weak keys, which means that once the objects for which +-- you ``store stuff'' go out of scope, they are also removed from the +-- storage. Also, you can specify that for each object of the storage +-- you store a table. In this case, there is no need to initialize +-- this table for each object; rather, when you write into such a +-- table and it does not yet exist, it is created ``on the fly''. +-- +-- The typical way you use storages is best explained with the +-- following example: Suppose you want to write a depth-first search +-- algorithm for a graph. This algorithm might wish to mark all nodes +-- it has visited. It could just say |v.marked = true|, but this might +-- clash with someone else also using the |marked| key. The solution is +-- to create a |marked| storage. The algorithm can first say +--\begin{codeexample}[code only, tikz syntax=false] +--local marked = Storage.new() +--\end{codeexample} +-- and then say +--\begin{codeexample}[code only, tikz syntax=false] +--marked[v] = true +--\end{codeexample} +-- to mark its objects. The |marked| storage object does not need to +-- be created locally inside a function, you can declare it as a local +-- variable of the whole file; nevertheless, the entries for vertices +-- no longer in use get removed automatically. You can also make it a +-- member variable of the algorithm class, which allows you make the +-- information about which objects are marked globally +-- accessible. +-- +-- Now suppose the algorithm would like to store even more stuff in +-- the storage. For this, we might use a table and can use the fact +-- that a storage will automatically create a table when necessary: +--\begin{codeexample}[code only, tikz syntax=false] +--local info = Storage.newTableStorage() +-- +--info[v].marked = true -- the "info[v]" table is +-- -- created automatically here +-- +--info[v].foo = "bar" +--\end{codeexample} +-- Again, once |v| goes out of scope, both it and the info table will +-- removed. + +local Storage = {} + +-- Namespace +require("pgf.gd.lib").Storage = Storage + + +-- The simple metatable + +local SimpleStorageMetaTable = { __mode = "k" } + +-- The advanced metatable for table storages: + +local TableStorageMetaTable = { + __mode = "k", + __index = + function(t, k) + local new = {} + rawset(t, k, new) + return new + end +} + + +--- +-- Create a new storage object. +-- +-- @return A new |Storage| instance. + +function Storage.new() + return setmetatable({}, SimpleStorageMetaTable) +end + + +--- +-- Create a new storage object which will install a table for every +-- entry automatically. +-- +-- @return A new |Storage| instance. + +function Storage.newTableStorage() + return setmetatable({}, TableStorageMetaTable) +end + + + + + + + +-- Done + +return Storage diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Transform.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Transform.lua new file mode 100644 index 0000000000..7695b1b239 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/lib/Transform.lua @@ -0,0 +1,120 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- The |Transform| table provides a set of static methods for +-- creating and handling canvas transformation matrices. Such a matrix +-- is actually just an array of six numbers. The idea is that +-- ``applying'' an array { a, b, c, d, e, f } a vector $(x,y)$ will +-- yield the new vector $(ax+by+e,cx+dy+f)$. For details on how such +-- matrices work, see Section~\ref{section-transform-cm} +-- +local Transform = {} + + +-- Namespace + +require("pgf.gd.model").Transform = Transform + + +--- Creates a new transformation array. +-- +-- @param a First component +-- @param b Second component +-- @param c Third component +-- @param d Fourth component +-- @param x The x shift +-- @param y The y shift +-- +-- @return A transformation object. +-- +function Transform.new(a,b,c,d,x,y) + return { a, b, c, d, x, y } +end + + +--- Creates a new transformation object that represents a shift. +-- +-- @param x An x-shift +-- @param y A y-shift +-- +-- @return A transformation object +-- +function Transform.new_shift(x,y) + return { 1, 0, 0, 1, x, y } +end + + +--- Creates a new transformation object that represents a rotation. +-- +-- @param angle An angle +-- +-- @return A transformation object +-- +function Transform.new_rotation(angle) + local c = math.cos(angle) + local s = math.sin(angle) + return { c, -s, s, c, 0, 0 } +end + + +--- Creates a new transformation object that represents a scaling. +-- +-- @param x The horizontal scaling +-- @param y The vertical scaling (if missing, the horizontal scaling is used) +-- +-- @return A transformation object +-- +function Transform.new_scaling(x_scale, y_scale) + return { x_scale, 0, 0, y_scale or x_scale, 0, 0 } +end + + + + +--- +-- Concatenate two transformation matrices, returning the new one. +-- +-- @param a The first transformation +-- @param b The second transformation +-- +-- @return The transformation representing first applying |b| and then +-- applying |a|. +-- +function Transform.concat(a,b) + local a1, a2, a3, a4, a5, a6, b1, b2, b3, b4, b5, b6 = + a[1], a[2], a[3], a[4], a[5], a[6], b[1], b[2], b[3], b[4], b[5], b[6] + return { a1*b1 + a2*b3, a1*b2 + a2*b4, + a3*b1 + a4*b3, a3*b2 + a4*b4, + a1*b5 + a2*b6 + a5, a3*b5 + a4*b6 + a6 } +end + + + +--- +-- Inverts a transformation matrix. +-- +-- @param t The transformation. +-- +-- @return The inverted transformation +-- +function Transform.invert(t) + local t1, t2, t3, t4 = t[1], t[2], t[3], t[4] + local idet = 1/(t1*t4 - t2*t3) + + return { t4*idet, -t2*idet, -t3*idet, t1*idet, -t[5], -t[6] } +end + + +-- Done + +return Transform diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model.lua new file mode 100644 index 0000000000..4a0130488b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.model = {} + + +-- Done + +return pgf.gd.model \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Arc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Arc.lua new file mode 100644 index 0000000000..e007e9b59b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Arc.lua @@ -0,0 +1,653 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- An arc is a light-weight object representing an arc from a vertex +-- in a graph to another vertex. You may not create an |Arc| by +-- yourself, which is why there is no |new| method, arc creation is +-- done by the Digraph class. +-- +-- Every arc belongs to exactly one graph. If you want the same arc in +-- another graph, you need to newly connect two vertices in the other graph. +-- +-- You may read the |head| and |tail| fields, but you may not write +-- them. In order to store data for an arc, use |Storage| objects. +-- +-- Between any two vertices of a graph there can be only one arc, so +-- all digraphs are always simple graphs. However, in the +-- specification of a graph (the syntactic digraph), there might +-- be multiple edges between two vertices. This means, in particular, +-- that an arc has no |options| field. Rather, it has several +-- |optionsXxxx| functions, that will search for options in all of the +-- syntactic edges that ``belong'' to an edge. +-- +-- In order to \emph{set} options of the edges, you can set the +-- |generated_options| field of an arc (which is |nil| by default), see +-- the |declare_parameter_sequence| function for the syntax. Similar +-- to the |path| field below, the options set in this table are +-- written back to the syntactic edges during a sync. +-- +-- Finally, there is also an |animations| field, which, similarly to +-- the |generated_options|, gets written back during a sync when it is +-- not |nil|. +-- +-- In detail, the following happens: Even though an arc has a |path|, +-- |generated_options|, and |animations| fields, setting these fields does +-- not immediately set the paths of the syntactic edges nor does it +-- generate options. Indeed, you will normally want to setup and +-- modify the |path| field of an arc during your algorithm and only at +-- the very end, ``write it back'' to the multiple syntactic edges +-- underlying the graph. For this purpose, the method |sync| is used, +-- which is called automatically for the |ugraph| and |digraph| of a +-- scope as well as for spanning trees. +-- +-- The bottom line concerning the |path| field is the following: If +-- you just want a straight line along an arc, just leave the field as +-- it is (namely, |nil|). If you want to have all edges along a path +-- to follow a certain path, set the |path| field of the arc to the +-- path you desire (typically, using the |setPolylinePath| or a +-- similar method). This will cause all syntactic edges underlying the +-- arc to be set to the specified path. In the event that you want to +-- set different paths for the edges underlying a single arc +-- differently, set the |path| fields of these edges and set the +-- |path| field of the arc to |nil|. This will disable the syncing for +-- the arc and will cause the edge |paths| to remain untouched. +-- +-- @field tail The tail vertex of the arc. +-- @field head The head vertex of the arc. May be the same as the tail +-- in case of a loop. +-- @field path If non-nil, the path of the arc. See the description +-- above. +-- @field generated_options If non-nil, some options to be passed back +-- to the original syntactic edges, see the description above. +-- @field animations If non-nil, some animations to be passed back +-- to the original syntactic edges. See the description of the +-- |animations| field for |Vertex| for details on the syntax. +-- @field syntactic_edges In case this arc is an arc in the syntactic +-- digraph (and only then), this field contains an array containing +-- syntactic edges (``real'' edges in the syntactic digraph) that +-- underly this arc. Otherwise, the field will be empty or |nil|. +-- +local Arc = {} +Arc.__index = Arc + + +-- Namespace + +require("pgf.gd.model").Arc = Arc + + +-- Imports + +local Path = require 'pgf.gd.model.Path' +local lib = require 'pgf.gd.lib' + + +--- +-- Get an array of options of the syntactic edges corresponding to an arc. +-- +-- An arc in a digraph is typically (but not always) present because +-- there are one or more edges in the syntactic digraph between the +-- tail and the head of the arc or between the head and the tail. +-- +-- Since for every arc there can be several edges present in the +-- syntactic digraph, an option like |length| may have +-- been given multiple times for the edges corresponding to the arc. +-- +-- If your algorithm gets confused by multiple edges, try saying +-- |a:options(your_option)|. This will always give the ``most +-- sensible'' choice of the option if there are multiple edges +-- corresponding to the same arc. +-- +-- @param option A string option like |"length"|. +-- +-- @return A table with the following contents: +-- % +-- \begin{enumerate} +-- \item It is an array of all values the option has for edges +-- corresponding to |self| in the syntactic digraph. Suppose, for +-- instance, you write the following: +-- % +--\begin{codeexample}[code only] +--graph { +-- tail -- [length=1] head, % multi edge 1 +-- tail -- [length=3] head, % mulit edge 2 +-- head -- [length=8] tail, % multi edge 3 +-- tail -- head, % multi edge 4 +-- head -- [length=7] tail, % multi edge 5 +-- tail -- [length=2] head, % multi edge 6 +--} +--\end{codeexample} +-- % +-- Suppose, furthermore, that |length| has been setup as an edge +-- option. Now suppose that |a| is the arc from the vertex |tail| to +-- the vertex |head|. Calling |a:optionsArray('length')| will +-- yield the array part |{1,3,2,8,7}|. The reason for the ordering is +-- as follows: First come all values |length| had for syntactic edges +-- going from |self.tail| to |self.head| in the order they appear in the +-- graph description. Then come all values the options has for syntactic +-- edges going from |self.head| to |self.tail|. The reason for this +-- slightly strange behavior is that many algorithms do not really +-- care whether someone writes |a --[length=1] b| or +-- |b --[length=1] a|; in both cases they would ``just'' like to know +-- that the length is~|1|. +-- +-- \item There is field called |aligned|, which is an array storing +-- the actual syntactic edge objects whose values can be found in the +-- array part of the returned table. However, |aligned| contains only +-- the syntactic edges pointing ``in the same direction'' as the arc, +-- that is, the tail and head of the syntactic edge are the same as +-- those of the arc. In the above example, this array would contain +-- the edges with the comment numbers |1|, |2|, and |6|. +-- +-- Using the length of this array and the fact that the ``aligned'' +-- values come first in the table, you can easily iterate over the +-- |option|'s values of only those edges that are aligned with the arc: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local a = g:arc(tail.head) -- some arc +--local opt = a:optionsArray('length') +--local sum = 0 +--for i=1,#opt.aligned do +-- sum = sum + opt[i] +--end +--\end{codeexample} +-- % +-- \item There is a field called |anti_aligned|, which is an array +-- containing exactly the edges in the array part of the table not +-- aligned with the arc. The numbering start at |1| as usual, so the +-- $i$th entry of this table corresponds to the entry at position $i + +-- \verb!#opt.aligned!$ of the table. +-- \end{enumerate} +-- +function Arc:optionsArray(option) + + local cache = self.option_cache + local t = cache[option] + if t then + return t + end + + -- Accumulate the edges for which the option is set: + local tail = self.tail + local head = self.head + local s_graph = self.syntactic_digraph + + local arc = s_graph:arc(tail, head) + local aligned = {} + if arc then + for _,m in ipairs(arc.syntactic_edges) do + if m.options[option] ~= nil then + aligned[#aligned + 1] = m + end + end + table.sort(aligned, function (a,b) return a.event.index < b.event.index end) + end + + local arc = head ~= tail and s_graph:arc(head, tail) + local anti_aligned = {} + if arc then + for _,m in ipairs(arc.syntactic_edges) do + if m.options[option] ~= nil then + anti_aligned[#anti_aligned + 1] = m + end + end + table.sort(anti_aligned, function (a,b) return a.event.index < b.event.index end) + end + + -- Now merge them together + local t = { aligned = aligned, anti_aligned = anti_aligned } + for i=1,#aligned do + t[i] = aligned[i].options[option] + end + for i=1,#anti_aligned do + t[#t+1] = anti_aligned[i].options[option] + end + cache[option] = t + + return t +end + + + +--- +-- Returns the first option, that is, the first entry of +-- |Arc:optionsArray(option)|. However, if the |only_aligned| +-- parameter is set to true and there is no option with any aligned +-- syntactic edge, |nil| is returned. +-- +-- @param option An option +-- @param only_aligned If true, only aligned syntactic edges will be +-- considered. +-- @return The first entry of the |optionsArray| +function Arc:options(option, only_aligned) + if only_aligned then + local opt = self:optionsArray(option) + if #opt.aligned > 0 then + return opt[1] + end + else + return self:optionsArray(option)[1] + end +end + + + + +--- +-- Get an accumulated value of an option of the syntactic edges +-- corresponding to an arc. +-- +-- @param option The option of interest +-- @param accumulator A function taking two values. When there are +-- more than one syntactic edges corresponding to |self| for which the +-- |option| is set, this function will be called repeatedly for the +-- different values. The first time it will be called for the first +-- two values. Next, it will be called for the result of this call and +-- the third value, and so on. +-- @param only_aligned A boolean. If true, only the aligned syntactic +-- edges will be considered. +-- +-- @return If the option is not set for any (aligned) syntactic edges +-- corresponding to |self|, |nil| is returned. If there is exactly one +-- edge, the value of this edge is returned. Otherwise, the result of +-- repeatedly applying the |accumulator| function as described +-- above. +-- +-- The result is cached, repeated calls will not invoke the +-- |accumulator| function again. +-- +-- @usage Here is typical usage: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local total_length = a:optionsAccumulated('length', function (a,b) return a+b end) or 0 +--\end{codeexample} +-- +function Arc:optionsAccumulated(option, accumulator, only_aligned) + local opt = self:options(option) + if only_aligned then + local aligned = opt.aligned + local v = aligned[accumulator] + if v == nil then + v = opt[1] + for i=2,#aligned do + v = accumulator(v, opt[i]) + end + align[accumulator] = v + end + return v + else + local v = opt[accumulator] + if v == nil then + v = opt[1] + for i=2,#opt do + v = accumulator(v, opt[i]) + end + opt[accumulator] = v + end + return v + end +end + + + +--- +-- Compute the syntactic head and tail of an arc. For this, we have a +-- look at the syntactic digraph underlying the arc. If there is at +-- least once syntactic edge going from the arc's tail to the arc's +-- head, the arc's tail and head are returned. Otherwise, we test +-- whether there is a syntactic edge in the other direction and, if +-- so, return head and tail in reverse order. Finally, if there is no +-- syntactic edge at all corresponding to the arc in either direction, +-- |nil| is returned. +-- +-- @return The syntactic tail +-- @return The syntactic head + +function Arc:syntacticTailAndHead () + local s_graph = self.syntactic_digraph + local tail = self.tail + local head = self.head + if s_graph:arc(tail, head) then + return tail, head + elseif s_graph:arc(head, tail) then + return head, tail + end +end + + +--- +-- Compute the point cloud. +-- +-- @return This method will return the ``point cloud'' of an arc, +-- which is an array of all points that must be rotated and shifted +-- along with the endpoints of an edge. +-- +function Arc:pointCloud () + if self.cached_point_cloud then + return self.cached_point_cloud -- cached + end + local cloud = {} + local a = self.syntactic_digraph:arc(self.tail,self.head) + if a then + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + cloud[#cloud + 1] = p + end + end + end + end + self.cached_point_cloud = cloud + return cloud +end + + + +--- +-- Compute an event index for the arc. +-- +-- @return The lowest event index of any edge involved +-- in the arc (or nil, if there is no syntactic edge). +-- +function Arc:eventIndex () + if self.cached_event_index then + return self.cached_event_index + end + local head = self.head + local tail = self.tail + local e = math.huge + local a = self.syntactic_digraph:arc(tail,head) + if a then + for _,m in ipairs(a.syntactic_edges) do + e = math.min(e, m.event.index) + end + end + local a = head ~= tail and self.syntactic_digraph:arc(head,tail) + if a then + for _,m in ipairs(a.syntactic_edges) do + e = math.min(e, m.event.index) + end + end + self.cached_event_index = e + return e +end + + + + +--- +-- The span collector +-- +-- This method returns the top (that is, smallest) priority of any +-- edge involved in the arc. +-- +-- The priority of an edge is computed as follows: +-- % +-- \begin{enumerate} +-- \item If the option |"span priority"| is set, this number +-- will be used. +-- \item If the edge has the same head as the arc, we lookup the key\\ +-- |"span priority " .. edge.direction|. If set, we use this value. +-- \item If the edge has a different head from the arc (the arc is +-- ``reversed'' with respect to the syntactic edge), we lookup the key +-- |"span priority reversed " .. edge.direction|. If set, we use this value. +-- \item Otherwise, we use priority 5. +-- \end{enumerate} +-- +-- @return The priority of the arc, as described above. +-- +function Arc:spanPriority() + if self.cached_span_priority then + return self.cached_span_priority + end + + local head = self.head + local tail = self.tail + local min + local g = self.syntactic_digraph + + local a = g:arc(tail,head) + if a then + for _,m in ipairs(a.syntactic_edges) do + local p = + m.options["span priority"] or + lib.lookup_option("span priority " .. m.direction, m, g) + + min = math.min(p or 5, min or math.huge) + end + end + + local a = head ~= tail and g:arc(head,tail) + if a then + for _,m in ipairs(a.syntactic_edges) do + local p = + m.options["span priority"] or + lib.lookup_option("span priority reversed " .. m.direction, m, g) + + min = math.min(p or 5, min or math.huge) + end + end + + self.cached_span_priority = min or 5 + + return min or 5 +end + + + + + + +--- +-- Sync an |Arc| with its syntactic edges with respect to the path and +-- generated options. It causes the following to happen: +-- If the |path| field of the arc is |nil|, nothing +-- happens with respect to the path. Otherwise, a copy of the |path| +-- is created. However, for every path element that is a function, +-- this function is invoked with the syntactic edge as its +-- parameter. The result of this call should now be a |Coordinate|, +-- which will replace the function in the |Path|. +-- +-- You use this method like this: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--... +--local arc = g:connect(s,t) +--arc:setPolylinePath { Coordinate.new(x,y), Coordinate.new(x1,y1) } +--... +--arc:sync() +--\end{codeexample} +-- +-- Next, similar to the path, the field |generated_options| is +-- considered. If it is not |nil|, then all options listed in this +-- field are appended to all syntactic edges underlying the arc. +-- +-- Note that this function will automatically be called for all arcs +-- of the |ugraph|, the |digraph|, and the |spanning_tree| of an +-- algorithm by the rendering pipeline. +-- +function Arc:sync() + if self.path then + local path = self.path + local head = self.head + local tail = self.tail + local a = self.syntactic_digraph:arc(tail,head) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + local clone = path:clone() + for i=1,#clone do + local p = clone[i] + if type(p) == "function" then + clone[i] = p(e) + if type(clone[i]) == "table" then + clone[i] = clone[i]:clone() + end + end + end + e.path = clone + end + end + local a = head ~= tail and self.syntactic_digraph:arc(head,tail) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + local clone = path:reversed() + for i=1,#clone do + local p = clone[i] + if type(p) == "function" then + clone[i] = p(e) + if type(clone[i]) == "table" then + clone[i] = clone[i]:clone() + end + end + end + e.path = clone + end + end + end + if self.generated_options then + local head = self.head + local tail = self.tail + local a = self.syntactic_digraph:arc(tail,head) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + for _,o in ipairs(self.generated_options) do + e.generated_options[#e.generated_options+1] = o + end + end + end + local a = head ~= tail and self.syntactic_digraph:arc(head,tail) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + for _,o in ipairs(self.generated_options) do + e.generated_options[#e.generated_options+1] = o + end + end + end + end + if self.animations then + local head = self.head + local tail = self.tail + local a = self.syntactic_digraph:arc(tail,head) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + for _,o in ipairs(self.animations) do + e.animations[#e.animations+1] = o + end + end + end + local a = head ~= tail and self.syntactic_digraph:arc(head,tail) + if a and #a.syntactic_edges>0 then + for _,e in ipairs(a.syntactic_edges) do + for _,o in ipairs(self.animations) do + e.animations[#e.animations+1] = o + end + end + end + end +end + + +--- +-- This method returns a ``coordinate factory'' that can be used as +-- the coordinate of a |moveto| at the beginning of a path starting at +-- the |tail| of the arc. Suppose you want to create a path starting +-- at the tail vertex, going to the coordinate $(10,10)$ and ending at +-- the head vertex. The trouble is that when you create the path +-- corresponding to this route, you typically do not know where the +-- tail vertex is going to be. Even if that \emph{has} already been +-- settled, you will still have the problem that different edges +-- underlying the arc may wish to start their paths at different +-- anchors inside the tail vertex. In such cases, you use this +-- method to get a function that will, later on, compute the correct +-- position of the anchor as needed. +-- +-- Here is the code you would use to create the above-mentioned path: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local a = g:connect(tail,head) +--... +--arc.path = Path.new() +--arc.path:appendMoveto(arc:tailAnchorForArcPath()) +--arc.path:appendLineto(10, 10) +--arc.path:appendLineto(arc:headAnchorForArcPath()) +--\end{codeexample} +-- +-- Normally, however, you will not write code as detailed as the above +-- and you would just write instead of the last three lines: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--arc:setPolylinePath { Coordinate.new (10, 10) } +--\end{codeexample} + +function Arc:tailAnchorForArcPath() + return function (edge) + local a = edge.options['tail anchor'] + if a == "" then + a = "center" + end + return self.tail:anchor(a) + self.tail.pos + end +end + +--- +-- See |Arc:tailAnchorForArcPath|. + +function Arc:headAnchorForArcPath() + return function (edge) + local a = edge.options['head anchor'] + if a == "" then + a = "center" + end + return self.head:anchor(a) + self.head.pos + end +end + + + +--- +-- Setup the |path| field of an arc in such a way that it corresponds +-- to a sequence of straight line segments starting at the tail's +-- anchor and ending at the head's anchor. +-- +-- @param coordinates An array of |Coordinates| through which the line +-- will go through. + +function Arc:setPolylinePath(coordinates) + local p = Path.new () + + p:appendMoveto(self:tailAnchorForArcPath()) + + for _,c in ipairs(coordinates) do + p:appendLineto(c) + end + + p:appendLineto(self:headAnchorForArcPath()) + + self.path = p +end + + + + +-- Returns a string representation of an arc. This is mainly for debugging +-- +-- @return The Arc as string. +-- +function Arc:__tostring() + return tostring(self.tail) .. "->" .. tostring(self.head) +end + + +-- Done + +return Arc diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Collection.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Collection.lua new file mode 100644 index 0000000000..abc454b7db --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Collection.lua @@ -0,0 +1,208 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- A collection is essentially a subgraph of a graph, that is, a +-- ``collection'' of some nodes and some edges of the graph. The name +-- ``collection'' was chosen over ``subgraph'' since the latter are +-- often thought of as parts of a graph that are rendered in a special +-- way (such as being surrounded by a rectangle), while collections +-- are used to model such diverse things as hyperedges, sets of +-- vertices that should be on the same level in a layered algorithm, +-- or, indeed, subgraphs that are rendered in a special way. +-- +-- Collections are grouped into ``kinds''. All collections of a given +-- kind can be accessed by algorithms through an array whose elements +-- are the collections. On the display layer, for each kind a separate +-- key is available to indicate that a node or an edge belongs to a +-- collection. +-- +-- Collections serve two purposes: First, they can be seen as ``hints'' +-- to graph drawing algorithms that certain nodes and/or edges ``belong +-- together''. For instance, collections of kind |same layer| are used +-- by the Sugiyama algorithm to group together nodes that should appear +-- at the same height of the output. Second, since collections are also +-- passed back to the display layer in a postprocessing step, they can be +-- used to render complicated concepts such as hyperedges (which are +-- just collections of nodes, after all) or subgraphs. +-- +-- @field kind The ``kind'' of the collection. +-- +-- @field vertices A lookup table of vertices (that is, both an array +-- with the vertices in the order in which they appear as well as a +-- table such that |vertices[vertex] == true| whenever |vertex| is +-- present in the table. +-- +-- @field edges A lookup table of edges (not arcs!). +-- +-- @field options An options table. This is the table of options that +-- was in force when the collection was created. +-- +-- @field child_collections An array of all collections that are +-- direct children of this collection (that is, +-- they were defined while the current collection was the most +-- recently defined collection on the options stack). However, you +-- should use the methods |children|, |descendants|, and so to access +-- this field. +-- +-- @field parent_collection The parent collection of the current +-- collection. This field may be |nil| in case a collection has no parent. +-- +-- @field event An |Event| object that was create for this +-- collection. Its |kind| will be |"collection"| while its |parameter| +-- will be the collection kind. + +local Collection = {} +Collection.__index = Collection + + +-- Namespace + +require("pgf.gd.model").Collection = Collection + + +-- Imports +local Storage = require "pgf.gd.lib.Storage" + + + +--- +-- Creates a new collection. You should not call this function +-- directly, it is called by the interface classes. +-- +-- @param t A table of initial values. The field |t.kind| must be a +-- nonempty string. +-- +-- @return The new collection +-- +function Collection.new(t) + assert (type(t.kind) == "string" and t.kind ~= "", "collection kind not set") + + return setmetatable( + { + vertices = t.vertices or {}, + edges = t.edges or {}, + options = t.options or {}, + generated_options = t.generated_options or {}, + kind = t.kind, + event = t.event, + child_collections = t.child_collections or {}, + }, Collection) +end + + + + +-- +-- An internal function for registering a collection as child of +-- another collection. The collection |self| will be made a child +-- collection of |parent|. +-- +-- @param parent A collection. + +function Collection:registerAsChildOf(parent) + self.parent = parent + if parent then + assert (getmetatable(parent) == Collection, "parent must be a collection") + parent.child_collections[#parent.child_collections+1] = self + end +end + + + +--- +-- A collection can have any number of \emph{child collections}, which +-- are collections nested inside the collection. You can access the +-- array of these children through this method. You may not modify +-- the array returned by this function. +-- +-- @return The array of children of |self|. +-- +function Collection:children() + return self.child_collections +end + + +--- +-- This method works like the |children| method. However, the tree of +-- collections is, conceptually, contracted by considering only these +-- collections that have the |kind| given as parameter. For instance, +-- if |self| has a child collection of a kind different from |kind|, +-- but this child collection has, in turn, a child collection of kind +-- |kind|, this latter child collection will be included in the array +-- -- but not any of its child collections. +-- +-- @param kind The collection kind to which the tree of collections +-- should be restricted. +-- +-- @return The array of children of |self| in this contracted tree. +-- +function Collection:childrenOfKind(kind) + local function rec (c, a) + for _,d in ipairs(c.child_collections) do + if d.kind == kind then + a[#a + 1] = d + else + rec (d, a) + end + end + return a + end + return rec(self, {}) +end + + +--- +-- The descendants of a collection are its children, plus their +-- children, plus their children, and so on. +-- +-- @return An array of all descendants of |self|. It will be in +-- preorder. + +function Collection:descendants() + local function rec (c, a) + for _,d in ipairs(c.child_collections) do + a[#a + 1] = d + rec (d, a) + end + return a + end + return rec(self, {}) +end + + + +--- +-- The descendants of a collection of the given |kind|. +-- +-- @param kind A collection kind. +-- +-- @return An array of all descendants of |self| of the given |kind|. + +function Collection:descendantsOfKind(kind) + local function rec (c, a) + for _,d in ipairs(c.child_collections) do + if d.kind == kind then + a[#a + 1] = d + end + rec (d, a) + end + return a + end + return rec(self, {}) +end + + + +-- Done + +return Collection diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Coordinate.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Coordinate.lua new file mode 100644 index 0000000000..3a4448ab08 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Coordinate.lua @@ -0,0 +1,306 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- A Coordinate models a position on the drawing canvas. +-- +-- It has an |x| field and a |y| field, which are numbers that will be +-- interpreted as \TeX\ points (1/72.27th of an inch). The $x$-axis goes +-- right and the $y$-axis goes up. +-- +-- @field x +-- @field y +-- +-- There is also a static field called |origin| that is always equal to the origin. + +local Coordinate = {} +Coordinate.__index = Coordinate + + +-- Namespace + +require("pgf.gd.model").Coordinate = Coordinate + + + + +--- Creates a new coordinate. +-- +-- @param x The $x$ value +-- @param y The $y$ value +-- +-- @return A coordinate +-- +function Coordinate.new(x,y) + return setmetatable( {x=x, y=y}, Coordinate) +end + + +Coordinate.origin = Coordinate.new(0,0) + + +--- Creates a new coordinate that is a copy of an existing one. +-- +-- @return A new coordinate at the same location as |self| +-- +function Coordinate:clone() + return setmetatable( { x = self.x, y = self.y }, Coordinate) +end + + + +--- Apply a transformation matrix to a coordinate, +-- see |pgf.gd.lib.Transform| for details. +-- +-- @param t A transformation. + +function Coordinate:apply(t) + local x = self.x + local y = self.y + self.x = t[1]*x + t[2]*y + t[5] + self.y = t[3]*x + t[4]*y + t[6] +end + + +--- Shift a coordinate +-- +-- @param a An $x$ offset +-- @param b A $y$ offset + +function Coordinate:shift(a,b) + self.x = self.x + a + self.y = self.y + b +end + + +--- +-- ``Unshift'' a coordinate (which is the same as shifting by the +-- inversed coordinate; only faster). +-- +-- @param a An $x$ offset +-- @param b A $y$ offset + +function Coordinate:unshift(a,b) + self.x = self.x - a + self.y = self.y - b +end + + +--- +-- Like |shift|, only for coordinate parameters. +-- +-- @param c Another coordinate. The $x$- and $y$-values of |self| are +-- increased by the $x$- and $y$-values of this coordinate. + +function Coordinate:shiftByCoordinate(c) + self.x = self.x + c.x + self.y = self.y + c.y +end + + +--- +-- Like |unshift|, only for coordinate parameters. +-- +-- @param c Another coordinate. + +function Coordinate:unshiftByCoordinate(c) + self.x = self.x - c.x + self.y = self.y - c.y +end + + +--- +-- Moves the coordinate a fraction of |f| along a straight line to |c|. +-- +-- @param c Another coordinate +-- @param f A fraction + +function Coordinate:moveTowards(c,f) + self.x = self.x + f*(c.x-self.x) + self.y = self.y + f*(c.y-self.y) +end + + + +--- Scale a coordinate by a factor +-- +-- @param s A factor. + +function Coordinate:scale(s) + self.x = s*self.x + self.y = s*self.y +end + + + + +--- +-- Add two coordinates, yielding a new coordinate. Note that it will +-- be a lot faster to call shift, whenever this is possible. +-- +-- @param a A coordinate +-- @param b A coordinate + +function Coordinate.__add(a,b) + return setmetatable({ x = a.x + b.x, y = a.y + b.y }, Coordinate) +end + + +--- +-- Subtract two coordinates, yielding a new coordinate. Note that it will +-- be a lot faster to call unshift, whenever this is possible. +-- +-- @param a A coordinate +-- @param b A coordinate + +function Coordinate.__sub(a,b) + return setmetatable({ x = a.x - b.x, y = a.y - b.y }, Coordinate) +end + + +--- +-- The unary minus (mirror the coordinate against the origin). +-- +-- @param a A coordinate + +function Coordinate.__unm(a) + return setmetatable({ x = - a.x, y = - a.y }, Coordinate) +end + + +--- +-- The multiplication operator. Its effect depends on the parameters: +-- If both are coordinates, their dot-product is returned. If exactly +-- one of them is a coordinate and the other is a number, the scalar +-- multiple of this coordinate is returned. +-- +-- @param a A coordinate or a scalar +-- @param b A coordinate or a scalar +-- @return The dot product or scalar product. + +function Coordinate.__mul(a,b) + if getmetatable(a) == Coordinate then + if getmetatable(b) == Coordinate then + return a.x * b.x + a.y * b.y + else + return setmetatable({ x = a.x * b, y = a.y *b }, Coordinate) + end + else + return setmetatable({ x = a * b.x, y = a * b.y }, Coordinate) + end +end + +--- +-- The division operator. Returns the scalar division of a coordinate +-- by a scalar. +-- +-- @param a A coordinate +-- @param b A scalar (not equal to zero). +-- @return The scalar product or a * (1/b). + +function Coordinate.__div(a,b) + return setmetatable({ x = a.x / b, y = a.y / b }, Coordinate) +end + + +--- +-- The norm function. Returns the norm of a coordinate. +-- +-- @param a A coordinate +-- @return The norm of the coordinate + +function Coordinate:norm() + return math.sqrt(self.x * self.x + self.y * self.y) +end + + +--- +-- Normalize a vector: Ensure that it has length 1. If the vector used +-- to be the 0-vector, it gets replaced by (1,0). +-- + +function Coordinate:normalize() + local x, y = self.x, self.y + if x == 0 and y == 0 then + self.x = 1 + else + local norm = math.sqrt(x*x+y*y) + self.x = x / norm + self.y = y / norm + end +end + + +--- +-- Normalized version of a vector: Like |normalize|, only the result is +-- returned in a new vector. +-- +-- @return Normalized version of |self| + +function Coordinate:normalized() + local x, y = self.x, self.y + if x == 0 and y == 0 then + return setmetatable({ x = 1, y = 0 }, Coordinate) + else + local norm = math.sqrt(x*x+y*y) + return setmetatable({ x = x/norm, y = y/norm }, Coordinate) + end +end + + + +--- +-- Compute a bounding box around an array of coordinates +-- +-- @param array An array of coordinates +-- +-- @return |min_x| The minimum $x$ value of the bounding box of the array +-- @return |min_y| The minimum $y$ value +-- @return |max_x| +-- @return |max_y| +-- @return |center_x| The center of the bounding box +-- @return |center_y| + +function Coordinate.boundingBox(array) + if #array > 0 then + local min_x, min_y = math.huge, math.huge + local max_x, max_y = -math.huge, -math.huge + + for i=1,#array do + local c = array[i] + local x = c.x + local y = c.y + if x < min_x then min_x = x end + if y < min_y then min_y = y end + if x > max_x then max_x = x end + if y > max_y then max_y = y end + end + + return min_x, min_y, max_x, max_y, (min_x+max_x) / 2, (min_y+max_y) / 2 + end +end + + + + +-- Returns a string representation of an arc. This is mainly for debugging +-- +-- @return The Arc as string. +-- +function Coordinate:__tostring() + return "(" .. self.x .. "pt," .. self.y .. "pt)" +end + + +-- Done + +return Coordinate \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Digraph.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Digraph.lua new file mode 100644 index 0000000000..30b600e308 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Digraph.lua @@ -0,0 +1,849 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +--- +-- Each |Digraph| instance models a \emph{directed, simple} +-- graph. ``Directed'' means that all edges ``point'' from a head node +-- to a tail node. ``Simple'' means that between any nodes there can be +-- (at most) one edge. Since these properties are a bit at odds with +-- the normal behavior of ``nodes'' and ``edges'' in \tikzname, +-- different names are used for them inside the |model| namespace: +-- The class modeling ``edges'' is actually called |Arc| to stress +-- that an arc has a specific ``start'' (the tail) and a specific +-- ``end'' (the head). The class modeling ``nodes'' is actually called +-- |Vertex|, just to stress that this is not a direct model of a +-- \tikzname\ |node|, but can represent a arbitrary vertex of a graph, +-- independently of whether it is an actual |node| in \tikzname. +-- +-- \medskip +-- \noindent\emph{Time Bounds.} +-- Since digraphs are constantly created and modified inside the graph +-- drawing engine, some care was taken to ensure that all operations +-- work as quickly as possible. In particular: +-- % +-- \begin{itemize} +-- \item Adding an array of $k$ vertices using the |add| method needs +-- time $O(k)$. +-- \item Adding an arc between two vertices needs time $O(1)$. +-- \item Accessing both the |vertices| and the |arcs| fields takes time +-- $O(1)$, provided only the above operations are used. +-- \end{itemize} +-- % +-- Deleting vertices and arcs takes more time: +-- % +-- \begin{itemize} +-- \item Deleting the vertices given in an array of $k$ vertices from a +-- graph with $n$ vertices takes time $O(\max\{n,c\})$ where $c$ is the +-- number of arcs between the to-be-deleted nodes and the remaining +-- nodes. Note that this time bound in independent of~$k$. In +-- particular, it will be much faster to delete many vertices by once +-- calling the |remove| function instead of calling it repeatedly. +-- \item Deleting an arc takes time $O(t_o+h_i)$ where $t_o$ is the +-- number of outgoing arcs at the arc's tail and $h_i$ is the number +-- of incoming arcs at the arc's head. After a call to |disconnect|, +-- the next use of the |arcs| field will take time $O(|V| + |E|)$, +-- while subsequent accesses take time $O(1)$ -- till the +-- next use of |disconnect|. This means that once you start deleting +-- arcs using |disconnect|, you should perform as many additional +-- |disconnect|s as possible before accessing |arcs| one more. +-- \end{itemize} +-- +-- \medskip +-- \noindent\emph{Stability.} The |vertices| field and the array +-- returned by |Digraph:incoming| and |Digraph:outgoing| are +-- \emph{stable} in the following sense: The ordering of the elements +-- when you use |ipairs| on the will be the ordering in which the +-- vertices or arcs were added to the graph. Even when you remove a +-- vertex or an arc, the ordering of the remaining elements stays the +-- same. +-- +-- @field vertices This array contains the vertices that are part of +-- the digraph. Internally, this array +-- is an object of type |LookupTable|, but you can mostly treat it as +-- if it were an array. In particular, you can iterate over its +-- elements using |ipairs|, but you may not modify the array; use the +-- |add| and |remove| methods, instead. +-- +-- \begin{codeexample}[code only, tikz syntax=false] +-- local g = Digraph.new {} +-- +-- g:add { v1, v2 } -- Add vertices v1 and v2 +-- g:remove { v2 } -- Get rid of v2. +-- +-- assert (g:contains(v1)) +-- assert (not g:contains(v2)) +-- \end{codeexample} +-- +-- It is important to note that although each digraph stores a +-- |vertices| array, the elements in this array are not exclusive to +-- the digraph: A vertex can be an element of any number of +-- digraphs. Whether or not a vertex is an element of digraph is not +-- stored in the vertex, only in the |vertices| array of the +-- digraph. To test whether a digraph contains a specific node, use the +-- |contains| method, which takes time $O(1)$ to perform the test (this +-- is because, as mentioned earlier, the |vertices| array is actually a +-- |LookupTable| and for each vertex |v| the field |vertices[v]| will +-- be true if, and only if, |v| is an element of the |vertices| array). +-- +-- Do not use |pairs(g.vertices)| because this may cause your graph +-- drawing algorithm to produce different outputs on different runs. +-- +-- A slightly annoying effect of vertices being able to belong to +-- several graphs at the same time is that the set of arcs incident to +-- a vertex is not a property of the vertex, but rather of the +-- graph. In other words, to get a list of all arcs whose tail is a +-- given vertex |v|, you cannot say something like |v.outgoings| or +-- perhaps |v:getOutgoings()|. Rather, you have to say |g:outgoing(v)| +-- to get this list: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--for _,a in ipairs(g:outgoing(v)) do -- g is a Digraph object. +-- pgf.debug ("There is an arc leaving " .. tostring(v) .. +-- " heading to " .. tostring(a.head)) +--end +--\end{codeexample} +-- % +-- Naturally, there is also a method |g:incoming()|. +-- +-- To iterate over all arcs of a graph you can say: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--for _,v in ipairs(g.vertices) do +-- for _,a in ipairs(g:outgoing(v)) do +-- ... +-- end +--end +--\end{codeexample} +-- +-- However, it will often be more convenient and, in case the there +-- are far less arcs than vertices, also faster to write +-- +--\begin{codeexample}[code only, tikz syntax=false] +--for _,a in ipairs(g.arcs) do +-- ... +--end +--\end{codeexample} +-- +-- @field arcs For any two vertices |t| and |h| of a graph, there may +-- or may not be +-- an arc from |t| to |h|. If this is the case, there is an |Arc| +-- object that represents this arc. Note that, since |Digraph|s are +-- always simple graphs, there can be at most one such object for every +-- pair of vertices. However, you can store any information you like for +-- an |Arc| through a |Storage|, see the |Storage| class for +-- details. Each |Arc| for an edge of the syntactic digraph stores +-- an array called |syntactic_edges| of all the multiple edges that +-- are present in the user's input. +-- +-- Unlike vertices, the arc objects of a graph are always local to a +-- graph; an |Arc| object can never be part of two digraphs at the same +-- time. For this reason, while for vertices it makes sense to create +-- |Vertex| objects independently of any |Digraph| objects, it is not +-- possible to instantiate an |Arc| directly: only the |Digraph| method +-- |connect| is allowed to create new |Arc| objects and it will return +-- any existing arcs instead of creating new ones, if there is already +-- an arc present between two nodes. +-- +-- The |arcs| field of a digraph contains a |LookupTable| of all arc +-- objects present in the |Digraph|. Although you can access this field +-- normally and use it in |ipairs| to iterate over all arcs of a graph, +-- note that this array is actually ``reconstructed lazily'' whenever +-- an arc is deleted from the graph. What happens is the following: As +-- long as you just add arcs to a graph, the |arcs| array gets updated +-- normally. However, when you remove an arc from a graph, the arc does +-- not get removed from the |arcs| array (which would be an expensive +-- operation). Instead, the |arcs| array is invalidated (internally set +-- to |nil|), allowing us to perform a |disconnect| in time +-- $O(1)$. The |arcs| array is then ignored until the next time it is +-- accessed, for instance when a user says |ipairs(g.arcs)|. At this +-- point, the |arcs| array is reconstructed by adding all arcs of all +-- nodes to it. +-- +-- The bottom line of the behavior of the |arcs| field is that (a) the +-- ordering of the elements may change abruptly whenever you remove an +-- arc from a graph and (b) performing $k$ |disconnect| operations in +-- sequence takes time $O(k)$, provided you do not access the |arcs| +-- field between calls. +-- +-- @field syntactic_digraph is a reference to the syntactic digraph +-- from which this graph stems ultimately. This may be a cyclic +-- reference to the graph itself. +-- @field options If present, it will be a table storing +-- the options set for the syntactic digraph. +-- +local Digraph = {} + +local function recalc_arcs (digraph) + local arcs = {} + local vertices = digraph.vertices + for i=1,#vertices do + local out = vertices[i].outgoings[digraph] + for j=1,#out do + arcs[#arcs + 1] = out[j] + end + end + digraph.arcs = arcs + return arcs +end + +Digraph.__index = + function (t, k) + if k == "arcs" then + return recalc_arcs(t) + else + return rawget(Digraph,k) + end + end + + + +-- Namespace +require("pgf.gd.model").Digraph = Digraph + +-- Imports +local Arc = require "pgf.gd.model.Arc" +local LookupTable = require "pgf.gd.lib.LookupTable" +local Vertex = require "pgf.gd.model.Vertex" + + + + + +--- +-- Graphs are created using the |new| method, which takes a table of +-- |initial| values as input (like most |new| methods in the graph +-- drawing system). It is permissible that this table of initial values +-- has a |vertices| field, in which case this array will be copied. In +-- contrast, an |arcs| field in the table will be ignored -- newly +-- created graphs always have an empty arcs set. This means that +-- writing |Digraph.new(g)| where |g| is a graph creates a new graph +-- whose vertex set is the same as |g|'s, but where there are no edges: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local g = Digraph.new {} +--g:add { v1, v2, v3 } +--g:connect (v1, v2) +-- +--local h = Digraph.new (g) +--assert (h:contains(v1)) +--assert (not h:arc(v1, v2)) +--\end{codeexample} +-- +-- To completely copy a graph, including all arcs, you have to write: +--\begin{codeexample}[code only, tikz syntax=false] +--local h = Digraph.new (g) +--for _,a in ipairs(g.arcs) do h:connect(a.tail, a.head) end +--\end{codeexample} +-- +-- This operation takes time $O(1)$. +-- +-- @param initial A table of initial values. It is permissible that +-- this array contains a |vertices| field. In this +-- case, this field must be an array and its entries +-- must be nodes, which will be inserted. If initial +-- has an |arcs| field, this field will be ignored. +-- The table must contain a field |syntactic_digraph|, +-- which should normally be the syntactic digraph of +-- the graph, but may also be the string |"self"|, in +-- which case it will be set to the newly created +-- (syntactic) digraph. +-- @return A newly-allocated digraph. +-- +function Digraph.new(initial) + local digraph = {} + setmetatable(digraph, Digraph) + + if initial then + for k,v in pairs(initial or {}) do + digraph [k] = v + end + end + + local vertices = digraph.vertices + digraph.vertices = {} + digraph.arcs = {} + + if vertices then + digraph:add(vertices) + end + return digraph +end + + +--- Add vertices to a digraph. +-- +-- This operation takes time $O(|\verb!array!|)$. +-- +-- @param array An array of to-be-added vertices. +-- +function Digraph:add(array) + local vertices = self.vertices + for i=1,#array do + local v = array[i] + if not vertices[v] then + vertices[v] = true + vertices[#vertices + 1] = v + v.incomings[self] = {} + v.outgoings[self] = {} + end + end +end + + +--- Remove vertices from a digraph. +-- +-- This operation removes an array of vertices from a graph. The +-- operation takes time linear in the number of vertices, regardless of +-- how many vertices are to be removed. Thus, it will be (much) faster +-- to delete many vertices by first compiling them in an array and to +-- then delete them using one call to this method. +-- +-- This operation takes time $O(\max\{|\verb!array!|, |\verb!self.vertices!|\})$. +-- +-- @param array The to-be-removed vertices. +-- +function Digraph:remove(array) + local vertices = self.vertices + + -- Mark all to-be-deleted nodes + for i=1,#array do + local v = array[i] + assert(vertices[v], "to-be-deleted node is not in graph") + vertices[v] = false + end + + -- Disconnect them + for i=1,#array do + self:disconnect(array[i]) + end + + LookupTable.remove(self.vertices, array) +end + + + +--- Test, whether a graph contains a given vertex. +-- +-- This operation takes time $O(1)$. +-- +-- @param v The vertex to be tested. +-- +function Digraph:contains(v) + return v and self.vertices[v] == true +end + + + + +--- +-- Returns the arc between two nodes, provided it exists. Otherwise, +-- |nil| is returned. +-- +-- This operation takes time $O(1)$. +-- +-- @param tail The tail vertex +-- @param head The head vertex +-- +-- @return The arc object connecting them +-- +function Digraph:arc(tail, head) + local out = tail.outgoings[self] + if out then + return out[head] + end +end + + + +--- +-- Returns an array containing the outgoing arcs of a vertex. You may +-- only iterate over his array using ipairs, not using pairs. +-- +-- This operation takes time $O(1)$. +-- +-- @param v The vertex +-- +-- @return An array of all outgoing arcs of this vertex (all arcs +-- whose tail is the vertex) +-- +function Digraph:outgoing(v) + return assert(v.outgoings[self], "vertex not in graph") +end + + + +--- +-- Sorts the array of outgoing arcs of a vertex. This allows you to +-- later iterate over the outgoing arcs in a specific order. +-- +-- This operation takes time $O(|\verb!outgoing!| \log |\verb!outgoings!|)$. +-- +-- @param v The vertex +-- @param f A comparison function that is passed to |table.sort| +-- +function Digraph:sortOutgoing(v, f) + table.sort(assert(v.outgoings[self], "vertex not in graph"), f) +end + + +--- +-- Reorders the array of outgoing arcs of a vertex. The parameter array +-- \emph{must} contain the same set of vertices as the outgoing array, +-- but possibly in a different order. +-- +-- This operation takes time $O(|\verb!outgoing!|)$, where |outgoing| +-- is the array of |v|'s outgoing arcs in |self|. +-- +-- @param v The vertex +-- @param vertices An array containing the outgoing vertices in some order. +-- +function Digraph:orderOutgoing(v, vertices) + local outgoing = assert (v.outgoings[self], "vertex not in graph") + assert (#outgoing == #vertices) + + -- Create back hash + local lookup = {} + for i=1,#vertices do + lookup[vertices[i]] = i + end + + -- Compute ordering of the arcs + local reordered = {} + for _,arc in ipairs(outgoing) do + reordered [lookup[arc.head]] = arc + end + + -- Copy back + for i=1,#outgoing do + outgoing[i] = assert(reordered[i], "illegal vertex order") + end +end + + + +--- See |outgoing|. +-- +function Digraph:incoming(v) + return assert(v.incomings[self], "vertex not in graph") +end + + +--- +-- See |sortOutgoing|. +-- +function Digraph:sortIncoming(v, f) + table.sort(assert(v.incomings[self], "vertex not in graph"), f) +end + + +--- +-- See |orderOutgoing|. +-- +function Digraph:orderIncoming(v, vertices) + local incoming = assert (v.incomings[self], "vertex not in graph") + assert (#incoming == #vertices) + + -- Create back hash + local lookup = {} + for i=1,#vertices do + lookup[vertices[i]] = i + end + + -- Compute ordering of the arcs + local reordered = {} + for _,arc in ipairs(incoming) do + reordered [lookup[arc.head]] = arc + end + + -- Copy back + for i=1,#incoming do + incoming[i] = assert(reordered[i], "illegal vertex order") + end +end + + + + + +--- +-- Connects two nodes by an arc and returns the newly created arc +-- object. If they are already connected, the existing arc is returned. +-- +-- This operation takes time $O(1)$. +-- +-- @param s The tail vertex +-- @param t The head vertex (may be identical to |tail| in case of a +-- loop) +-- +-- @return The arc object connecting them (either newly created or +-- already existing) +-- +function Digraph:connect(s, t) + assert (s and t and self.vertices[s] and self.vertices[t], "trying connect nodes not in graph") + + local s_outgoings = s.outgoings[self] + local arc = s_outgoings[t] + + if not arc then + -- Ok, create and insert new arc object + arc = { + tail = s, + head = t, + option_cache = {}, + syntactic_digraph = self.syntactic_digraph, + syntactic_edges = {} + } + setmetatable(arc, Arc) + + -- Insert into outgoings: + s_outgoings [#s_outgoings + 1] = arc + s_outgoings [t] = arc + + local t_incomings = t.incomings[self] + -- Insert into incomings: + t_incomings [#t_incomings + 1] = arc + t_incomings [s] = arc + + -- Insert into arcs field, if it exists: + local arcs = rawget(self, "arcs") + if arcs then + arcs[#arcs + 1] = arc + end + end + + return arc +end + + + + +--- +-- Disconnect either a single vertex |v| from all its neighbors (remove all +-- incoming and outgoing arcs of this vertex) or, in case two nodes +-- are given as parameter, remove the arc between them, if it exists. +-- +-- This operation takes time $O(|I_v| + |I_t|)$, where $I_x$ is the set +-- of vertices incident to $x$, to remove the single arc between $v$ and +-- $v$. For a single vertex $v$, it takes time $O(\sum_{y: \text{there is some +-- arc between $v$ and $y$ or $y$ and $v$}} |I_y|)$. +-- +-- @param v The single vertex or the tail vertex +-- @param t The head vertex +-- +function Digraph:disconnect(v, t) + if t then + -- Case 2: Remove a single arc. + local s_outgoings = assert(v.outgoings[self], "tail node not in graph") + local t_incomings = assert(t.incomings[self], "head node not in graph") + + if s_outgoings[t] then + -- Remove: + s_outgoings[t] = nil + for i=1,#s_outgoings do + if s_outgoings[i].head == t then + table.remove (s_outgoings, i) + break + end + end + t_incomings[v] = nil + for i=1,#t_incomings do + if t_incomings[i].tail == v then + table.remove (t_incomings, i) + break + end + end + self.arcs = nil -- invalidate arcs field + end + else + -- Case 1: Remove all arcs incident to v: + + -- Step 1: Delete all incomings arcs: + local incomings = assert(v.incomings[self], "node not in graph") + local vertices = self.vertices + + for i=1,#incomings do + local s = incomings[i].tail + if s ~= v and vertices[s] then -- skip self-loop and to-be-deleted nodes + -- Remove this arc from s: + local s_outgoings = s.outgoings[self] + s_outgoings[v] = nil + for i=1,#s_outgoings do + if s_outgoings[i].head == v then + table.remove (s_outgoings, i) + break + end + end + end + end + + -- Step 2: Delete all outgoings arcs: + local outgoings = v.outgoings[self] + for i=1,#outgoings do + local t = outgoings[i].head + if t ~= v and vertices[t] then + local t_incomings = t.incomings[self] + t_incomings[v] = nil + for i=1,#t_incomings do + if t_incomings[i].tail == v then + table.remove (t_incomings, i) + break + end + end + end + end + + if #incomings > 0 or #outgoings > 0 then + self.arcs = nil -- invalidate arcs field + end + + -- Step 3: Reset incomings and outgoings fields + v.incomings[self] = {} + v.outgoings[self] = {} + end +end + + + + +--- +-- An arc is changed so that instead of connecting |self.tail| +-- and |self.head|, it now connects a new |head| and |tail|. The +-- difference to first disconnecting and then reconnecting is that all +-- fields of the arc (other than |head| and |tail|, of course), will +-- be ``moved along''. Reconnecting an arc in the same way as before has no +-- effect. +-- +-- If there is already an arc at the new position, fields of the +-- to-be-reconnected arc overwrite fields of the original arc. This is +-- especially dangerous with a syntactic digraph, so do not reconnect +-- arcs of the syntactic digraph (which you should not do anyway). +-- +-- The |arc| object may no longer be valid after a reconnect, but the +-- operation returns the new arc object. +-- +-- This operation needs the time of a disconnect (if necessary). +-- +-- @param arc The original arc object +-- @param tail The new tail vertex +-- @param head The new head vertex +-- +-- @return The new arc object connecting them (either newly created or +-- already existing) +-- +function Digraph:reconnect(arc, tail, head) + assert (arc and tail and head, "connect with nil parameters") + + if arc.head == head and arc.tail == tail then + -- Nothing to be done + return arc + else + local new_arc = self:connect(tail, head) + + for k,v in pairs(arc) do + if k ~= "head" and k ~= "tail" then + new_arc[k] = v + end + end + + -- Remove old arc: + self:disconnect(arc.tail, arc.head) + + return new_arc + end +end + + + +--- +-- Collapse a set of vertices into a single vertex +-- +-- Often, algorithms will wish to treat a whole set of vertices ``as a +-- single vertex''. The idea is that a new vertex is then inserted +-- into the graph, and this vertex is connected to all vertices to +-- which any of the original vertices used to be connected. +-- +-- The |collapse| method takes an array of to-be-collapsed vertices as +-- well as a vertex. First, it will store references to the +-- to-be-collapsed vertices inside the vertex. Second, we iterate over +-- all arcs of the to-be-collapsed vertices. If this arc connects a +-- to-be-collapsed vertex with a not-to-be-collapsed vertex, the +-- not-to-be-collapsed vertex is connected to the collapse +-- vertex. Additionally, the arc is stored at the vertex. +-- +-- Note that the collapse vertex will be added to the graph if it is +-- not already an element. The collapsed vertices will not be removed +-- from the graph, so you must remove them yourself, if necessary. +-- +-- A collapse vertex will store the collapsed vertices so that you can +-- call |expand| later on to ``restore'' the vertices and arcs that +-- were saved during a collapse. This storage is \emph{not} local to +-- the graph in which the collapse occurred. +-- +-- @param collapse_vertices An array of to-be-collapsed vertices +-- @param collapse_vertex The vertex that represents the collapse. If +-- missing, a vertex will be created automatically and added to the graph. +-- @param vertex_fun This function is called for each to-be-collapsed +-- vertex. The parameters are the collapse vertex and the +-- to-be-collapsed vertex. May be |nil|. +-- @param arc_fun This function is called whenever a new arc is added +-- between |rep| and some other vertex. The arguments are the new arc +-- and the original arc. May be |nil|. +-- +-- @return The new vertex that represents the collapsed vertices. + +function Digraph:collapse(collapse_vertices, collapse_vertex, vertex_fun, arc_fun) + + + -- Create and add node, if necessary. + if not collapse_vertex then + collapse_vertex = Vertex.new {} + end + self:add {collapse_vertex} + + -- Copy the collapse_vertices and create lookup + local cvs = {} + for i=1,#collapse_vertices do + local v = collapse_vertices[i] + cvs[i] = v + cvs[v] = true + end + assert (cvs[collapse_vertex] ~= true, "collapse_vertex is in collapse_vertices") + + -- Connected collapse_vertex appropriately + local collapsed_arcs = {} + + if not arc_fun then + arc_fun = function () end + end + + for _,v in ipairs(cvs) do + if vertex_fun then + vertex_fun (collapse_vertex, v) + end + for _,a in ipairs(v.outgoings[self]) do + if cvs[a.head] ~= true then + arc_fun (self:connect(collapse_vertex, a.head), a) + collapsed_arcs[#collapsed_arcs + 1] = a + end + end + for _,a in ipairs(v.incomings[self]) do + if cvs[a.tail] ~= true then + arc_fun (self:connect(a.tail, collapse_vertex), a) + end + collapsed_arcs[#collapsed_arcs + 1] = a + end + end + + -- Remember the old vertices. + collapse_vertex.collapsed_vertices = cvs + collapse_vertex.collapsed_arcs = collapsed_arcs + + return collapse_vertex +end + + + +--- +-- Expand a previously collapsed vertex. +-- +-- If you have collapsed a set of vertices in a graph using +-- |collapse|, you can expand this set once more using this method. It +-- will add all vertices that were previously removed from the graph +-- and will also reinstall the deleted arcs. The collapse vertex is +-- not removed. +-- +-- @param vertex A to-be-expanded vertex that was previously returned +-- by |collapse|. +-- @param vertex_fun A function that is called once for each +-- reinserted vertex. The parameters are the collapse vertex and the +-- reinstalled vertex. May be |nil|. +-- @param arc_fun A function that is called once for each +-- reinserted arc. The parameter is the arc and the |vertex|. May be |nil|. +-- +function Digraph:expand(vertex, vertex_fun, arc_fun) + local cvs = assert(vertex.collapsed_vertices, "no expand information stored") + + -- Add all vertices: + self:add(cvs) + if vertex_fun then + for _,v in ipairs(cvs) do + vertex_fun(vertex, v) + end + end + + -- Add all arcs: + for _,arc in ipairs(vertex.collapsed_arcs) do + local new_arc = self:connect(arc.tail, arc.head) + + for k,v in pairs(arc) do + if k ~= "head" and k ~= "tail" then + new_arc[k] = v + end + end + + if arc_fun then + arc_fun(new_arc, vertex) + end + end +end + + + + + +--- +-- Invokes the |sync| method for all arcs of the graph. +-- +-- @see Arc:sync() +-- +function Digraph:sync() + for _,a in ipairs(self.arcs) do + a:sync() + end +end + + + +--- +-- Computes a string representation of this graph including all nodes +-- and edges. The syntax of this representation is such that it can be +-- used directly in \tikzname's |graph| syntax. +-- +-- @return |self| as string. +-- +function Digraph:__tostring() + local vstrings = {} + local astrings = {} + for i,v in ipairs(self.vertices) do + vstrings[i] = " " .. tostring(v) .. "[x=" .. math.floor(v.pos.x) .. "pt,y=" .. math.floor(v.pos.y) .. "pt]" + local out_arcs = v.outgoings[self] + if #out_arcs > 0 then + local t = {} + for j,a in ipairs(out_arcs) do + t[j] = tostring(a.head) + end + astrings[#astrings + 1] = " " .. tostring(v) .. " -> { " .. table.concat(t,", ") .. " }" + end + end + return "graph [id=" .. tostring(self.vertices) .. "] {\n {\n" .. + table.concat(vstrings, ",\n") .. "\n }; \n" .. + table.concat(astrings, ";\n") .. "\n}"; +end + + + + +-- Done + +return Digraph diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Edge.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Edge.lua new file mode 100644 index 0000000000..45cbc60f9f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Edge.lua @@ -0,0 +1,209 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- An |Edge| is a ``syntactic'' connection between two +-- vertices that represents a connection present in the syntactic +-- digraph. Unlike an |Arc|, |Edge| objects are not controlled by the +-- |Digraph| class. Also unlike |Arc| objects, there can be several +-- edges between the same vertices, namely whenever several such edges +-- are present in the syntactic digraph. +-- +-- In detail, the relationship between arcs and edges is as follows: +-- If there is an |Edge| between two vertices $u$ and $v$ in the +-- syntactic digraph, there will be an |Arc| from $u$ to $v$ and the +-- array |syntactic_edges| of this |Arc| object will contain the +-- |Edge| object. In particular, if there are several edges between +-- the same vertices, all of these edges will be part of the array in +-- a single |Arc| object. +-- +-- Edges, like arcs, are always directed from a |tail| vertex to a +-- |head| vertex; this is true even for undirected vertices. The +-- |tail| vertex will always be the vertex that came first in the +-- syntactic specification of the edge, the |head| vertex is the +-- second one. Whether +-- an edge is directed or not depends on the |direction| of the edge, which +-- may be one of the following: +-- % +-- \begin{enumerate} +-- \item |"->"| +-- \item |"--"| +-- \item |"<-"| +-- \item |"<->"| +-- \item |"-!-"| +-- \end{enumerate} +-- +-- +-- @field head The head vertex of this edge. +-- +-- @field tail The tail vertex of this edge. +-- +-- @field event The creation |Event| of this edge. +-- +-- @field options A table of options that contains user-defined options. +-- +-- @field direction One of the directions named above. +-- +-- @field path A |Path| object that describes the path of the +-- edge. The path's coordinates are interpreted \emph{absolutely}. +-- +-- @field generated_options This is an options array that is generated +-- by the algorithm. When the edge is rendered later on, this array +-- will be passed back to the display layer. The syntax is the same as +-- for the |declare_parameter_sequence| function, see +-- |InterfaceToAlgorithms|. +-- +-- @field animations An array of animations, see the |animations| +-- field of the |Vertex| class for the syntax. + +local Edge = {} +Edge.__index = Edge + + +-- Namespace + +require("pgf.gd.model").Edge = Edge + + +-- Imports + +local Path = require "pgf.gd.model.Path" + + +--- +-- Create a new edge. The |initial| parameter allows you to setup +-- some initial values. +-- +-- @usage +--\begin{codeexample}[code only, tikz syntax=false] +--local v = Edge.new { tail = v1, head = v2 } +--\end{codeexample} +-- +-- @param initial Values to override defaults. -- +-- @return A new edge object. +-- +function Edge.new(values) + local new = {} + for k,v in pairs(values) do + new[k] = v + end + new.generated_options = new.generated_options or {} + new.animations = new.animations or {} + if not new.path then + local p = Path.new () + p:appendMoveto(Edge.tailAnchorForEdgePath(new)) + p:appendLineto(Edge.headAnchorForEdgePath(new)) + new.path = p + end + + return setmetatable(new, Edge) +end + + + + +--- +-- This method returns a ``coordinate factory'' that can be used as +-- the coordinate of a |moveto| at the beginning of a path starting at +-- the |tail| of the arc. Suppose you want to create a path starting +-- at the tail vertex, going to the coordinate $(10,10)$ and ending at +-- the head vertex. The trouble is that when you create the path +-- corresponding to this route, you typically do not know where the +-- tail vertex is going to be. In this case, you use this +-- method to get a function that will, later on, compute the correct +-- position of the anchor as needed. +-- +-- Note that you typically do not use this function, but use the +-- corresponding function of the |Arc| class. Use this function only +-- if there are multiple edges between two vertices that need to be +-- routed differently. +-- +-- Here is the code you would use to create the above-mentioned path: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--local a = g:connect(tail,head) +--local e = a.syntactic_edges[1] +--... +--e.path = Path.new() +--e.path:appendMoveto(e:tailAnchorForEdgePath()) +--e.path:appendLineto(10, 10) +--e.path:appendLineto(e:headAnchorForEdgePath()) +--\end{codeexample} +-- +-- As for the |Arc| class, you can also setup a polyline more easily: +-- % +--\begin{codeexample}[code only, tikz syntax=false] +--e:setPolylinePath { Coordinate.new (10, 10) } +--\end{codeexample} + +function Edge:tailAnchorForEdgePath() + return function () + local a = self.options['tail anchor'] + if a == "" then + a = "center" + end + return self.tail:anchor(a) + self.tail.pos + end +end + +--- +-- See |Arc:tailAnchorForArcPath|. + +function Edge:headAnchorForEdgePath() + return function () + local a = self.options['head anchor'] + if a == "" then + a = "center" + end + return self.head:anchor(a) + self.head.pos + end +end + + + +--- +-- Setup the |path| field of an edge in such a way that it corresponds +-- to a sequence of straight line segments starting at the tail's +-- anchor and ending at the head's anchor. +-- +-- @param coordinates An array of |Coordinates| through which the line +-- will go through. + +function Edge:setPolylinePath(coordinates) + local p = Path.new () + + p:appendMoveto(self:tailAnchorForEdgePath()) + + for _,c in ipairs(coordinates) do + p:appendLineto(c) + end + + p:appendLineto(self:headAnchorForEdgePath()) + + self.path = p +end + + + +-- +-- Returns a string representation of an edge. This is mainly for debugging. +-- +-- @return The Edge as a string. +-- +function Edge:__tostring() + return tostring(self.tail) .. self.direction .. tostring(self.head) +end + + +-- Done + +return Edge diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Hyperedge.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Hyperedge.lua new file mode 100644 index 0000000000..cc265023fa --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Hyperedge.lua @@ -0,0 +1,56 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Hyperedges} +-- +-- @end + + +-- Includes + +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + + +--- + +declare { + key = "hyper", + layer = -10, + + summary = [[" + A \emph{hyperedge} of a graph does not connect just two nodes, but + is any subset of the node set (although a normal edge is also a + hyperedge that happens to contain just two nodes). Internally, a + collection of kind |hyper| is created. Currently, there is + no default renderer for hyper edges. + "]], + documentation = [[" +\begin{codeexample}[code only] +\graph { + % The nodes: + a, b, c, d; + + % The edges: + {[hyper] a,b,c}; + {[hyper] b,c,d}; + {[hyper] a,c}; + {[hyper] d} +}; +\end{codeexample} + "]] +} + +-- Done + +return Hyperedge \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path.lua new file mode 100644 index 0000000000..cbd0f079bf --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path.lua @@ -0,0 +1,1278 @@ +-- Copyright 2014 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- A Path models a path in the plane. +-- +-- Following the PostScript/\textsc{pdf}/\textsc{svg} convention, a +-- path consists of a series of path segments, each of which can be +-- closed or not. Each path segment, in turn, consists of a series of +-- Bézier curves and straight line segments; see +-- Section~\ref{section-paths} for an introduction to paths in +-- general. +-- +-- A |Path| object is a table whose array part stores +-- |Coordinate| objects, |strings|, and |function|s that +-- describe the path of the edge. The following strings are allowed in +-- this array: +-- % +-- \begin{itemize} +-- \item |"moveto"| The line's path should stop at the current +-- position and then start anew at the next coordinate in the array. +-- \item |"lineto"| The line should continue from the current position +-- to the next coordinate in the array. +-- \item |"curveto"| The line should continue form the current +-- position with a Bézier curve that is specified by the next three +-- |Coordinate| objects (in the usual manner). +-- \item |"closepath"| The line's path should be ``closed'' in the sense +-- that the current subpath that was started with the most recent +-- moveto operation should now form a closed curve. +-- \end{itemize} +-- +-- Instead of a |Coordinate|, a |Path| may also contain a function. In +-- this case, the function, when called, must return the |Coordinate| +-- that is ``meant'' by the position. This allows algorithms to +-- add coordinates to a path that are still not fixed at the moment +-- they are added to the path. + +local Path = {} +Path.__index = Path + + +-- Namespace + +require("pgf.gd.model").Path = Path + + +-- Imports + +local Coordinate = require "pgf.gd.model.Coordinate" +local Bezier = require "pgf.gd.lib.Bezier" + +local lib = require "pgf.gd.lib" + + +-- Private function + +function Path.rigid (x) + if type(x) == "function" then + return x() + else + return x + end +end + +local rigid = Path.rigid + + +--- +-- Creates an empty path. +-- +-- @param initial A table containing an array of strings and +-- coordinates that constitute the path. Coordinates may be given as +-- tables or as a pair of numbers. In this case, each pair of numbers +-- is converted into one coordinate. If omitted, a new empty path +-- is created. +-- +-- @return A empty Path +-- +function Path.new(initial) + if initial then + local new = {} + local i = 1 + local count = 0 + while i <= #initial do + local e = initial[i] + if type(e) == "string" then + assert (count == 0, "illformed path") + if e == "moveto" then + count = 1 + elseif e == "lineto" then + count = 1 + elseif e == "closepath" then + count = 0 + elseif e == "curveto" then + count = 3 + else + error ("unknown path command " .. e) + end + new[#new+1] = e + elseif type(e) == "number" then + if count == 0 then + new[#new+1] = "lineto" + else + count = count - 1 + end + new[#new+1] = Coordinate.new(e,initial[i+1]) + i = i + 1 + elseif type(e) == "table" or type(e) == "function" then + if count == 0 then + new[#new+1] = "lineto" + else + count = count - 1 + end + new[#new+1] = e + else + error ("invalid object on path") + end + i = i + 1 + end + return setmetatable(new, Path) + else + return setmetatable({}, Path) + end +end + + +--- +-- Creates a copy of a path. +-- +-- @return A copy of the path + +function Path:clone() + local new = {} + for _,x in ipairs(self) do + if type(x) == "table" then + new[#new+1] = x:clone() + else + new[#new+1] = x + end + end + return setmetatable(new, Path) +end + + + +--- +-- Returns the path in reverse order. +-- +-- @return A copy of the reversed path + +function Path:reversed() + + -- First, build segments + local subpaths = {} + local subpath = {} + + local function closepath () + if subpath.start then + subpaths [#subpaths + 1] = subpath + subpath = {} + end + end + + local prev + local start + + local i = 1 + while i <= #self do + local x = self[i] + if x == "lineto" then + subpath[#subpath+1] = { + action = 'lineto', + from = prev, + to = self[i+1] + } + prev = self[i+1] + i = i + 2 + elseif x == "moveto" then + closepath() + prev = self[i+1] + start = prev + subpath.start = prev + i = i + 2 + elseif x == "closepath" then + subpath [#subpath + 1] = { + action = "closepath", + from = prev, + to = start, + } + prev = nil + start = nil + closepath() + i = i + 1 + elseif x == "curveto" then + local s1, s2, to = self[i+1], self[i+2], self[i+3] + subpath [#subpath + 1] = { + action = "curveto", + from = prev, + to = to, + support_1 = s1, + support_2 = s2, + } + prev = self[i+3] + i = i + 4 + else + error ("illegal path command '" .. x .. "'") + end + end + closepath () + + local new = Path.new () + + for _,subpath in ipairs(subpaths) do + if #subpath == 0 then + -- A subpath that consists only of a moveto: + new:appendMoveto(subpath.start) + else + -- We start with a moveto to the end point: + new:appendMoveto(subpath[#subpath].to) + + -- Now walk backwards: + for i=#subpath,1,-1 do + if subpath[i].action == "lineto" then + new:appendLineto(subpath[i].from) + elseif subpath[i].action == "closepath" then + new:appendLineto(subpath[i].from) + elseif subpath[i].action == "curveto" then + new:appendCurveto(subpath[i].support_2, + subpath[i].support_1, + subpath[i].from) + else + error("illegal path command") + end + end + + -- Append a closepath, if necessary + if subpath[#subpath].action == "closepath" then + new:appendClosepath() + end + end + end + + return new +end + + +--- +-- Transform all points on a path. +-- +-- @param t A transformation, see |pgf.gd.lib.Transform|. It is +-- applied to all |Coordinate| objects on the path. + +function Path:transform(t) + for _,c in ipairs(self) do + if type(c) == "table" then + c:apply(t) + end + end +end + + +--- +-- Shift all points on a path. +-- +-- @param x An $x$-shift +-- @param y A $y$-shift + +function Path:shift(x,y) + for _,c in ipairs(self) do + if type(c) == "table" then + c.x = c.x + x + c.y = c.y + y + end + end +end + + +--- +-- Shift by all points on a path. +-- +-- @param x A coordinate + +function Path:shiftByCoordinate(x) + for _,c in ipairs(self) do + if type(c) == "table" then + c.x = c.x + x.x + c.y = c.y + x.y + end + end +end + + +--- +-- Makes the path empty. +-- + +function Path:clear() + for i=1,#self do + self[i] = nil + end +end + + +--- +-- Appends a |moveto| to the path. +-- +-- @param x A |Coordinate| or |function| or, if the |y| parameter is +-- not |nil|, a number that is the $x$-part of a coordinate. +-- @param y The $y$-part of the coordinate. + +function Path:appendMoveto(x,y) + self[#self + 1] = "moveto" + self[#self + 1] = y and Coordinate.new(x,y) or x +end + + +--- +-- Appends a |lineto| to the path. +-- +-- @param x A |Coordinate| or |function|, if the |y| parameter is not +-- |nil|, a number that is the $x$-part of a coordinate. +-- @param y The $y$-part of the coordinate. + +function Path:appendLineto(x,y) + self[#self + 1] = "lineto" + self[#self + 1] = y and Coordinate.new(x,y) or x +end + + + +--- +-- Appends a |closepath| to the path. + +function Path:appendClosepath() + self[#self + 1] = "closepath" +end + + +--- +-- Appends a |curveto| to the path. There can be either three +-- coordinates (or functions) as parameters (the two support points +-- and the target) or six numbers, where two consecutive numbers form a +-- |Coordinate|. Which case is meant is detected by the presence of a +-- sixth non-nil parameter. + +function Path:appendCurveto(a,b,c,d,e,f) + self[#self + 1] = "curveto" + if f then + self[#self + 1] = Coordinate.new(a,b) + self[#self + 1] = Coordinate.new(c,d) + self[#self + 1] = Coordinate.new(e,f) + else + self[#self + 1] = a + self[#self + 1] = b + self[#self + 1] = c + end +end + + + + + + +--- +-- Makes a path ``rigid'', meaning that all coordinates that are only +-- given as functions are replaced by the values these functions +-- yield. + +function Path:makeRigid() + for i=1,#self do + self[i] = rigid(self[i]) + end +end + + +--- +-- Returns an array of all coordinates that are present in a +-- path. This means, essentially, that all strings are filtered out. +-- +-- @return An array of all coordinate objects on the path. + +function Path:coordinates() + local cloud = {} + for i=1,#self do + local p = self[i] + if type(p) == "table" then + cloud[#cloud + 1] = p + elseif type(p) == "function" then + cloud[#cloud + 1] = p() + end + end + return cloud +end + + +--- +-- Returns a bounding box of the path. This will not necessarily be +-- the minimal bounding box in case the path contains curves because, +-- then, the support points of the curve are used for the computation +-- rather than the actual bounding box of the path. +-- +-- If the path contains no coordinates, all return values are 0. +-- +-- @return |min_x| The minimum $x$ value of the bounding box of the path +-- @return |min_y| The minimum $y$ value +-- @return |max_x| +-- @return |max_y| +-- @return |center_x| The center of the bounding box +-- @return |center_y| + +function Path:boundingBox() + if #self > 0 then + local min_x, min_y = math.huge, math.huge + local max_x, max_y = -math.huge, -math.huge + + for i=1,#self do + local c = rigid(self[i]) + if type(c) == "table" then + local x = c.x + local y = c.y + if x < min_x then min_x = x end + if y < min_y then min_y = y end + if x > max_x then max_x = x end + if y > max_y then max_y = y end + end + end + + if min_x ~= math.huge then + return min_x, min_y, max_x, max_y, (min_x+max_x) / 2, (min_y+max_y) / 2 + end + end + return 0, 0, 0, 0, 0, 0 +end + + +-- Forwards + +local segmentize, bb, boxes_intersect, intersect_curves + +local eps = 0.0001 + + + +--- +-- Computes all intersections of a path with another path and returns +-- them as an array of coordinates. The intersections will be sorted +-- ``along the path |self|''. The implementation uses a +-- divide-and-conquer approach that should be reasonably fast in +-- practice. +-- +-- @param path Another path +-- +-- @return Array of all intersections of |path| with |self| in the +-- order they appear on |self|. Each entry of this array is a table +-- with the following fields: +-- % +-- \begin{itemize} +-- \item |index| The index of the segment in |self| where +-- the intersection occurs. +-- \item |time| The ``time'' at which a point traveling along the +-- segment from its start point to its end point. +-- \item |point| The point itself. +-- \end{itemize} + +function Path:intersectionsWith(path) + + local p1 = segmentize(self) + local memo1 = prepare_memo(p1) + local p2 = segmentize(path) + local memo2 = prepare_memo(p2) + + local intersections = {} + + local function intersect_segments(i1, i2) + + local s1 = p1[i1] + local s2 = p2[i2] + local r = {} + + if s1.action == 'lineto' and s2.action == 'lineto' then + local a = s2.to.x - s2.from.x + local b = s1.from.x - s1.to.x + local c = s2.from.x - s1.from.x + local d = s2.to.y - s2.from.y + local e = s1.from.y - s1.to.y + local f = s2.from.y - s1.from.y + + local det = a*e - b*d + + if math.abs(det) > eps*eps then + local t, s = (c*d - a*f)/det, (b*f - e*c)/det + + if t >= 0 and t<=1 and s>=0 and s <= 1 then + local p = s1.from:clone() + p:moveTowards(s1.to, t) + return { { time = t, point = p } } + end + end + elseif s1.action == 'lineto' and s2.action == 'curveto' then + intersect_curves (0, 1, + s1.from.x, s1.from.y, + s1.from.x*2/3+s1.to.x*1/3, s1.from.y*2/3+s1.to.y*1/3, + s1.from.x*1/3+s1.to.x*2/3, s1.from.y*1/3+s1.to.y*2/3, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.support_1.x, s2.support_1.y, + s2.support_2.x, s2.support_2.y, + s2.to.x, s2.to.y, + r) + elseif s1.action == 'curveto' and s2.action == 'lineto' then + intersect_curves (0, 1, + s1.from.x, s1.from.y, + s1.support_1.x, s1.support_1.y, + s1.support_2.x, s1.support_2.y, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.from.x*2/3+s2.to.x*1/3, s2.from.y*2/3+s2.to.y*1/3, + s2.from.x*1/3+s2.to.x*2/3, s2.from.y*1/3+s2.to.y*2/3, + s2.to.x, s2.to.y, + r) + else + intersect_curves (0, 1, + s1.from.x, s1.from.y, + s1.support_1.x, s1.support_1.y, + s1.support_2.x, s1.support_2.y, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.support_1.x, s2.support_1.y, + s2.support_2.x, s2.support_2.y, + s2.to.x, s2.to.y, + r) + end + return r + end + + local function intersect (i1, j1, i2, j2) + + if i1 > j1 or i2 > j2 then + return + end + + local bb1 = bb(i1, j1, memo1) + local bb2 = bb(i2, j2, memo2) + + if boxes_intersect(bb1, bb2) then + -- Ok, need to do something + if i1 == j1 and i2 == j2 then + local intersects = intersect_segments (i1, i2) + for _,t in ipairs(intersects) do + intersections[#intersections+1] = { + time = t.time, + index = p1[i1].path_pos, + point = t.point + } + end + elseif i1 == j1 then + local m2 = math.floor((i2 + j2) / 2) + intersect(i1, j1, i2, m2) + intersect(i1, j1, m2+1, j2) + elseif i2 == j2 then + local m1 = math.floor((i1 + j1) / 2) + intersect(i1, m1, i2, j2) + intersect(m1+1, j1, i2, j2) + else + local m1 = math.floor((i1 + j1) / 2) + local m2 = math.floor((i2 + j2) / 2) + intersect(i1, m1, i2, m2) + intersect(m1+1, j1, i2, m2) + intersect(i1, m1, m2+1, j2) + intersect(m1+1, j1, m2+1, j2) + end + end + end + + -- Run the recursion + intersect(1, #p1, 1, #p2) + + -- Sort + table.sort(intersections, function(a,b) + return a.index < b.index or + a.index == b.index and a.time < b.time + end) + + -- Remove duplicates + local remains = {} + remains[1] = intersections[1] + for i=2,#intersections do + local next = intersections[i] + local prev = remains[#remains] + if math.abs(next.point.x - prev.point.x) + math.abs(next.point.y - prev.point.y) > eps then + remains[#remains+1] = next + end + end + + return remains +end + + +-- Returns true if two bounding boxes intersection + +function boxes_intersect (bb1, bb2) + return (bb1.max_x >= bb2.min_x - eps*eps and + bb1.min_x <= bb2.max_x + eps*eps and + bb1.max_y >= bb2.min_y - eps*eps and + bb1.min_y <= bb2.max_y + eps*eps) +end + + +-- Turns a path into a sequence of segments, each being either a +-- lineto or a curveto from some point to another point. It also sets +-- up a memorization array for the bounding boxes. + +function segmentize (path) + + local prev + local start + local s = {} + + local i = 1 + while i <= #path do + local x = path[i] + + if x == "lineto" then + x = rigid(path[i+1]) + s [#s + 1] = { + path_pos = i, + action = "lineto", + from = prev, + to = x, + bb = { + min_x = math.min(prev.x, x.x), + max_x = math.max(prev.x, x.x), + min_y = math.min(prev.y, x.y), + max_y = math.max(prev.y, x.y), + } + } + prev = x + i = i + 2 + elseif x == "moveto" then + prev = rigid(path[i+1]) + start = prev + i = i + 2 + elseif x == "closepath" then + s [#s + 1] = { + path_pos = i, + action = "lineto", + from = prev, + to = start, + bb = { + min_x = math.min(prev.x, start.x), + max_x = math.max(prev.x, start.x), + min_y = math.min(prev.y, start.y), + max_y = math.max(prev.y, start.y), + } + } + prev = nil + start = nil + i = i + 1 + elseif x == "curveto" then + local s1, s2, to = rigid(path[i+1]), rigid(path[i+2]), rigid(path[i+3]) + s [#s + 1] = { + action = "curveto", + path_pos = i, + from = prev, + to = to, + support_1 = s1, + support_2 = s2, + bb = { + min_x = math.min(prev.x, s1.x, s2.x, to.x), + max_x = math.max(prev.x, s1.x, s2.x, to.x), + min_y = math.min(prev.y, s1.y, s2.y, to.y), + max_y = math.max(prev.y, s1.y, s2.y, to.y), + } + } + prev = path[i+3] + i = i + 4 + else + error ("illegal path command '" .. x .. "'") + end + end + + return s +end + + +function prepare_memo (s) + + local memo = {} + + memo.base = #s + + -- Fill memo table + for i,e in ipairs (s) do + memo[i*#s + i] = e.bb + end + + return memo +end + + +-- This function computes the bounding box of all segments between i +-- and j (inclusively) + +function bb (i, j, memo) + local b = memo[memo.base*i + j] + if not b then + assert (i < j, "memorization table filled incorrectly") + + local mid = math.floor((i+j)/2) + local bb1 = bb (i, mid, memo) + local bb2 = bb (mid+1, j, memo) + b = { + min_x = math.min(bb1.min_x, bb2.min_x), + max_x = math.max(bb1.max_x, bb2.max_x), + min_y = math.min(bb1.min_y, bb2.min_y), + max_y = math.max(bb1.max_y, bb2.max_y) + } + memo[memo.base*i + j] = b + end + + return b +end + + + +-- Intersect two Bézier curves. + +function intersect_curves(t0, t1, + c1_ax, c1_ay, c1_bx, c1_by, + c1_cx, c1_cy, c1_dx, c1_dy, + c2_ax, c2_ay, c2_bx, c2_by, + c2_cx, c2_cy, c2_dx, c2_dy, + intersections) + + -- Only do something, if the bounding boxes intersect: + local c1_min_x = math.min(c1_ax, c1_bx, c1_cx, c1_dx) + local c1_max_x = math.max(c1_ax, c1_bx, c1_cx, c1_dx) + local c1_min_y = math.min(c1_ay, c1_by, c1_cy, c1_dy) + local c1_max_y = math.max(c1_ay, c1_by, c1_cy, c1_dy) + local c2_min_x = math.min(c2_ax, c2_bx, c2_cx, c2_dx) + local c2_max_x = math.max(c2_ax, c2_bx, c2_cx, c2_dx) + local c2_min_y = math.min(c2_ay, c2_by, c2_cy, c2_dy) + local c2_max_y = math.max(c2_ay, c2_by, c2_cy, c2_dy) + + if c1_max_x >= c2_min_x and + c1_min_x <= c2_max_x and + c1_max_y >= c2_min_y and + c1_min_y <= c2_max_y then + + -- Everything "near together"? + if c1_max_x - c1_min_x < eps and c1_max_y - c1_min_y < eps then + + -- Compute intersection of lines c1_a to c1_d and c2_a to c2_d + local a = c2_dx - c2_ax + local b = c1_ax - c1_dx + local c = c2_ax - c1_ax + local d = c2_dy - c2_ay + local e = c1_ay - c1_dy + local f = c2_ay - c1_ay + + local det = a*e - b*d + local t + + t = (c*d - a*f)/det + if t<0 then + t=0 + elseif t>1 then + t=1 + end + + intersections [#intersections + 1] = { + time = t0 + t*(t1-t0), + point = Coordinate.new(c1_ax + t*(c1_dx-c1_ax), c1_ay+t*(c1_dy-c1_ay)) + } + else + -- Cut 'em in half! + local c1_ex, c1_ey = (c1_ax + c1_bx)/2, (c1_ay + c1_by)/2 + local c1_fx, c1_fy = (c1_bx + c1_cx)/2, (c1_by + c1_cy)/2 + local c1_gx, c1_gy = (c1_cx + c1_dx)/2, (c1_cy + c1_dy)/2 + + local c1_hx, c1_hy = (c1_ex + c1_fx)/2, (c1_ey + c1_fy)/2 + local c1_ix, c1_iy = (c1_fx + c1_gx)/2, (c1_fy + c1_gy)/2 + + local c1_jx, c1_jy = (c1_hx + c1_ix)/2, (c1_hy + c1_iy)/2 + + local c2_ex, c2_ey = (c2_ax + c2_bx)/2, (c2_ay + c2_by)/2 + local c2_fx, c2_fy = (c2_bx + c2_cx)/2, (c2_by + c2_cy)/2 + local c2_gx, c2_gy = (c2_cx + c2_dx)/2, (c2_cy + c2_dy)/2 + + local c2_hx, c2_hy = (c2_ex + c2_fx)/2, (c2_ey + c2_fy)/2 + local c2_ix, c2_iy = (c2_fx + c2_gx)/2, (c2_fy + c2_gy)/2 + + local c2_jx, c2_jy = (c2_hx + c2_ix)/2, (c2_hy + c2_iy)/2 + + intersect_curves (t0, (t0+t1)/2, + c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, + c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, + intersections) + intersect_curves (t0, (t0+t1)/2, + c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, + c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, + intersections) + intersect_curves ((t0+t1)/2, t1, + c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, + c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, + intersections) + intersect_curves ((t0+t1)/2, t1, + c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, + c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, + intersections) + end + end +end + + +--- +-- Shorten a path at the beginning. We are given the index of a +-- segment inside the path as well as a point in time along this +-- segment. The path is now shortened so that everything before this +-- segment and everything in the segment before the given time is +-- removed from the path. +-- +-- @param index The index of a path segment. +-- @param time A time along the specified path segment. + +function Path:cutAtBeginning(index, time) + + local cut_path = Path:new () + + -- Ok, first, we need to find the segment *before* the current + -- one. Usually, this will be a moveto or a lineto, but things could + -- be different. + assert (type(self[index-1]) == "table" or type(self[index-1]) == "function", + "segment before intersection does not end with a coordinate") + + local from = rigid(self[index-1]) + local action = self[index] + + -- Now, depending on the type of segment, we do different things: + if action == "lineto" then + + -- Ok, compute point: + local to = rigid(self[index+1]) + + from:moveTowards(to, time) + + -- Ok, this is easy: We start with a fresh moveto ... + cut_path[1] = "moveto" + cut_path[2] = from + + -- ... and copy the rest + for i=index,#self do + cut_path[#cut_path+1] = self[i] + end + elseif action == "curveto" then + + local to = rigid(self[index+3]) + local s1 = rigid(self[index+1]) + local s2 = rigid(self[index+2]) + + -- Now, compute the support vectors and the point at time: + from:moveTowards(s1, time) + s1:moveTowards(s2, time) + s2:moveTowards(to, time) + + from:moveTowards(s1, time) + s1:moveTowards(s2, time) + + from:moveTowards(s1, time) + + -- Ok, this is easy: We start with a fresh moveto ... + cut_path[1] = "moveto" + cut_path[2] = from + cut_path[3] = "curveto" + cut_path[4] = s1 + cut_path[5] = s2 + cut_path[6] = to + + -- ... and copy the rest + for i=index+4,#self do + cut_path[#cut_path+1] = self[i] + end + + elseif action == "closepath" then + -- Let us find the start point: + local found + for i=index,1,-1 do + if self[i] == "moveto" then + -- Bingo: + found = i + break + end + end + + assert(found, "no moveto found in path") + + local to = rigid(self[found+1]) + from:moveTowards(to,time) + + cut_path[1] = "moveto" + cut_path[2] = from + cut_path[3] = "lineto" + cut_path[4] = to + + -- ... and copy the rest + for i=index+1,#self do + cut_path[#cut_path+1] = self[i] + end + else + error ("wrong path operation") + end + + -- Move cut_path back: + for i=1,#cut_path do + self[i] = cut_path[i] + end + for i=#cut_path+1,#self do + self[i] = nil + end +end + + + + +--- +-- Shorten a path at the end. This method works like |cutAtBeginning|, +-- only the path is cut at the end. +-- +-- @param index The index of a path segment. +-- @param time A time along the specified path segment. + +function Path:cutAtEnd(index, time) + + local cut_path = Path:new () + + -- Ok, first, we need to find the segment *before* the current + -- one. Usually, this will be a moveto or a lineto, but things could + -- be different. + assert (type(self[index-1]) == "table" or type(self[index-1]) == "function", + "segment before intersection does not end with a coordinate") + + local from = rigid(self[index-1]) + local action = self[index] + + -- Now, depending on the type of segment, we do different things: + if action == "lineto" then + + -- Ok, compute point: + local to = rigid(self[index+1]) + to:moveTowards(from, 1-time) + + for i=1,index do + cut_path[i] = self[i] + end + cut_path[index+1] = to + + elseif action == "curveto" then + + local s1 = rigid(self[index+1]) + local s2 = rigid(self[index+2]) + local to = rigid(self[index+3]) + + -- Now, compute the support vectors and the point at time: + to:moveTowards(s2, 1-time) + s2:moveTowards(s1, 1-time) + s1:moveTowards(from, 1-time) + + to:moveTowards(s2, 1-time) + s2:moveTowards(s1, 1-time) + + to:moveTowards(s2, 1-time) + + -- ... and copy the rest + for i=1,index do + cut_path[i] = self[i] + end + + cut_path[index+1] = s1 + cut_path[index+2] = s2 + cut_path[index+3] = to + + elseif action == "closepath" then + -- Let us find the start point: + local found + for i=index,1,-1 do + if self[i] == "moveto" then + -- Bingo: + found = i + break + end + end + + assert(found, "no moveto found in path") + + local to = rigid(self[found+1]:clone()) + to:moveTowards(from,1-time) + + for i=1,index-1 do + cut_path[i] = self[i] + end + cut_path[index] = 'lineto' + cut_path[index+1] = to + else + error ("wrong path operation") + end + + -- Move cut_path back: + for i=1,#cut_path do + self[i] = cut_path[i] + end + for i=#cut_path+1,#self do + self[i] = nil + end +end + + + + +--- +-- ``Pads'' the path. The idea is the following: Suppose we stroke the +-- path with a pen whose width is twice the value |padding|. The outer +-- edge of this stroked drawing is now a path by itself. The path will +-- be a bit longer and ``larger''. The present function tries to +-- compute an approximation to this resulting path. +-- +-- The algorithm used to compute the enlarged part does not necessarily +-- compute the precise new path. It should work correctly for polyline +-- paths, but not for curved paths. +-- +-- @param padding A padding distance. +-- @return The padded path. +-- + +function Path:pad(padding) + + local padded = self:clone() + padded:makeRigid() + + if padding == 0 then + return padded + end + + -- First, decompose the path into subpaths: + local subpaths = {} + local subpath = {} + local start_index = 1 + + local function closepath(end_index) + if #subpath >= 1 then + subpath.start_index = start_index + subpath.end_index = end_index + start_index = end_index + 1 + + local start = 1 + if (subpath[#subpath] - subpath[1]):norm() < 0.01 and subpath[2] then + start = 2 + subpath.skipped = subpath[1] + end + subpath[#subpath + 1] = subpath[start] + subpath[#subpath + 1] = subpath[start+1] + subpaths[#subpaths + 1] = subpath + subpath = {} + end + end + + for i,p in ipairs(padded) do + if p ~= "closepath" then + if type(p) == "table" then + subpath[#subpath + 1] = p + end + else + closepath (i) + end + end + closepath(#padded) + + -- Second, iterate over the subpaths: + for _,subpath in ipairs(subpaths) do + local new_coordinates = {} + local _,_,_,_,c_x,c_y = Coordinate.boundingBox(subpath) + local c = Coordinate.new(c_x,c_y) + + -- Find out the orientation of the path + local count = 0 + for i=1,#subpath-2 do + local d2 = subpath[i+1] - subpath[i] + local d1 = subpath[i+2] - subpath[i+1] + + local diff = math.atan2(d2.y,d2.x) - math.atan2(d1.y,d1.x) + + if diff < -math.pi then + count = count + 1 + elseif diff > math.pi then + count = count - 1 + end + end + + for i=2,#subpath-1 do + local p = subpath[i] + local d1 = subpath[i] - subpath[i-1] + local d2 = subpath[i+1] - subpath[i] + + local orth1 = Coordinate.new(-d1.y, d1.x) + local orth2 = Coordinate.new(-d2.y, d2.x) + + orth1:normalize() + orth2:normalize() + + if count < 0 then + orth1:scale(-1) + orth2:scale(-1) + end + + -- Ok, now we want to compute the intersection of the lines + -- perpendicular to p + padding*orth1 and p + padding*orth2: + + local det = orth1.x * orth2.y - orth1.y * orth2.x + + local c + if math.abs(det) < 0.1 then + c = orth1 + orth2 + c:scale(padding/2) + else + c = Coordinate.new (padding*(orth2.y-orth1.y)/det, padding*(orth1.x-orth2.x)/det) + end + + new_coordinates[i] = c+p + end + + for i=2,#subpath-1 do + local p = subpath[i] + local new_p = new_coordinates[i] + p.x = new_p.x + p.y = new_p.y + end + + if subpath.skipped then + local p = subpath[1] + local new_p = new_coordinates[#subpath-2] + p.x = new_p.x + p.y = new_p.y + end + + -- Now, we need to correct the curveto fields: + for i=subpath.start_index,subpath.end_index do + if self[i] == 'curveto' then + local from = rigid(self[i-1]) + local s1 = rigid(self[i+1]) + local s2 = rigid(self[i+2]) + local to = rigid(self[i+3]) + + local p1x, p1y, _, _, h1x, h1y = + Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, + to.x, to.y, 1/3) + + local p2x, p2y, _, _, _, _, h2x, h2y = + Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, + to.x, to.y, 2/3) + + local orth1 = Coordinate.new (p1y - h1y, -(p1x - h1x)) + orth1:normalize() + orth1:scale(-padding) + + local orth2 = Coordinate.new (p2y - h2y, -(p2x - h2x)) + orth2:normalize() + orth2:scale(padding) + + if count < 0 then + orth1:scale(-1) + orth2:scale(-1) + end + + local new_s1, new_s2 = + Bezier.supportsForPointsAtTime(padded[i-1], + Coordinate.new(p1x+orth1.x,p1y+orth1.y), 1/3, + Coordinate.new(p2x+orth2.x,p2y+orth2.y), 2/3, + padded[i+3]) + + padded[i+1] = new_s1 + padded[i+2] = new_s2 + end + end + end + + return padded +end + + + +--- +-- Appends an arc (as in the sense of ``a part of the circumference of +-- a circle'') to the path. You may optionally provide a +-- transformation matrix, which will be applied to the arc. In detail, +-- the following happens: We first invert the transformation +-- and apply it to the start point. Then we compute the arc +-- ``normally'', as if no transformation matrix were present. Then we +-- apply the transformation matrix to all computed points. +-- +-- @function Path:appendArc(start_angle,end_angle,radius,trans) +-- +-- @param start_angle The start angle of the arc. Must be specified in +-- degrees. +-- @param end_angle the end angle of the arc. +-- @param radius The radius of the circle on which this arc lies. +-- @param trans A transformation matrix. If |nil|, the identity +-- matrix will be assumed. + +Path.appendArc = lib.ondemand("Path_arced", Path, "appendArc") + + + +--- +-- Appends a clockwise arc (as in the sense of ``a part of the circumference of +-- a circle'') to the path such that it ends at a given point. If a +-- transformation matrix is given, both start and end point are first +-- transformed according to the inverted transformation, then the arc +-- is computed and then transformed back. +-- +-- @function Path:appendArcTo(target,radius_or_center,clockwise,trans) +-- +-- @param target The point where the arc should end. +-- @param radius_or_center If a number, it is the radius of the circle +-- on which this arc lies. If it is a |Coordinate|, this is the center +-- of the circle. +-- @param clockwise If true, the arc will be clockwise. Otherwise (the +-- default, if nothing or |nil| is given), the arc will be counter +-- clockwise. +-- @param trans A transformation matrix. If missing, +-- the identity matrix is assumed. + +Path.appendArcTo = lib.ondemand("Path_arced", Path, "appendArcTo") + + + + +-- +-- @return The Path as string. +-- +function Path:__tostring() + local r = {} + local i = 1 + while i <= #self do + local p = self[i] + + if p == "lineto" then + r [#r+1] = " -- " .. tostring(rigid(self[i+1])) + i = i + 1 + elseif p == "moveto" then + r [#r+1] = " " .. tostring(rigid(self[i+1]) ) + i = i + 1 + elseif p == "curveto" then + r [#r+1] = " .. controls " .. tostring(rigid(self[i+1])) .. " and " .. + tostring(rigid(self[i+2])) .. " .. " .. tostring(rigid(self[i+3])) + i = i + 3 + elseif p == "closepath" then + r [#r+1] = " -- cycle" + else + error("illegal path command") + end + i = i + 1 + end + return table.concat(r) +end + + + +-- Done + +return Path diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path_arced.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path_arced.lua new file mode 100644 index 0000000000..1875b8d1a5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Path_arced.lua @@ -0,0 +1,316 @@ +-- Copyright 2014 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local Path = require 'pgf.gd.model.Path' + +-- Imports + +local Coordinate = require "pgf.gd.model.Coordinate" +local Transform = require "pgf.gd.lib.Transform" + + + +-- Locals + +local rigid = Path.rigid + +local tan = math.tan +local sin = math.sin +local cos = math.cos +local sqrt = math.sqrt +local atan2 = math.atan2 +local abs = math.abs + +local to_rad = math.pi/180 +local to_deg = 180/math.pi +local pi_half = math.pi/2 + +local function sin_quarter(x) + x = x % 360 + if x == 0 then + return 0 + elseif x == 90 then + return 1 + elseif x == 180 then + return 0 + else + return -1 + end +end + +local function cos_quarter(x) + x = x % 360 + if x == 0 then + return 1 + elseif x == 90 then + return 0 + elseif x == 180 then + return -1 + else + return 0 + end +end + +local function atan2deg(y,x) + + -- Works like atan2, but returns the angle in degrees and, returns + -- exactly a multiple of 90 if x or y are zero + + if x == 0 then + if y < 0 then + return -90 + else + return 90 + end + elseif y == 0 then + if x < 0 then + return 180 + else + return 0 + end + else + return atan2(y,x) * to_deg + end + +end + +local function subarc (path, startx, starty, start_angle, delta, radius, trans, center_x, center_y) + + local end_angle = start_angle + delta + local factor = tan (delta*to_rad/4) * 1.333333333333333333333 * radius + + local s1, c1, s190, c190, s2, c2, s290, c290 + + if start_angle % 90 == 0 then + s1, c1, s190, c190 = sin_quarter(start_angle), cos_quarter(start_angle), sin_quarter(start_angle+90), cos_quarter(start_angle+90) + else + local a1 = start_angle*to_rad + s1, c1, s190, c190 = sin(a1), cos(a1), sin(a1+pi_half), cos(a1+pi_half) + end + + if end_angle % 90 == 0 then + s2, c2, s290, c290 = sin_quarter(end_angle), cos_quarter(end_angle), sin_quarter(end_angle-90), cos_quarter(end_angle-90) + else + local a2 = end_angle * to_rad + s2, c2, s290, c290 = sin(a2), cos(a2), sin(a2-pi_half), cos(a2-pi_half) + end + + local lastx, lasty = center_x + c2*radius, center_y + s2*radius + + path[#path + 1] = "curveto" + path[#path + 1] = Coordinate.new (startx + c190*factor, starty + s190*factor) + path[#path + 1] = Coordinate.new (lastx + c290*factor, lasty + s290*factor) + path[#path + 1] = Coordinate.new (lastx, lasty) + + if trans then + path[#path-2]:apply(trans) + path[#path-1]:apply(trans) + path[#path ]:apply(trans) + end + + return lastx, lasty, end_angle +end + + + +local function arc (path, start, start_angle, end_angle, radius, trans, centerx, centery) + + -- @param path is the path object + -- @param start is the start coordinate + -- @param start_angle is given in degrees + -- @param end_angle is given in degrees + -- @param radius is the radius + -- @param trans is an optional transformation matrix that gets applied to all computed points + -- @param centerx optionally: x-part of the center of the circle + -- @param centery optionally: y-part of the center of the circle + + local startx, starty = start.x, start.y + + -- Compute center: + centerx = centerx or startx - cos(start_angle*to_rad)*radius + centery = centery or starty - sin(start_angle*to_rad)*radius + + if start_angle < end_angle then + -- First, ensure that the angles are in a reasonable range: + start_angle = start_angle % 360 + end_angle = end_angle % 360 + + if end_angle <= start_angle then + -- In case the modulo has inadvertently moved the end angle + -- before the start angle: + end_angle = end_angle + 360 + end + + -- Ok, now create a series of arcs that are at most quarter-cycles: + while start_angle < end_angle do + if start_angle + 179 < end_angle then + -- Add a quarter cycle: + startx, starty, start_angle = subarc(path, startx, starty, start_angle, 90, radius, trans, centerx, centery) + elseif start_angle + 90 < end_angle then + -- Add 60 degrees to ensure that there are no small segments + -- at the end + startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) + else + subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) + break + end + end + + elseif start_angle > end_angle then + -- First, ensure that the angles are in a reasonable range: + start_angle = start_angle % 360 + end_angle = end_angle % 360 + + if end_angle >= start_angle then + -- In case the modulo has inadvertedly moved the end angle + -- before the start angle: + end_angle = end_angle - 360 + end + + -- Ok, now create a series of arcs that are at most quarter-cycles: + while start_angle > end_angle do + if start_angle - 179 > end_angle then + -- Add a quarter cycle: + startx, starty, start_angle = subarc(path, startx, starty, start_angle, -90, radius, trans, centerx, centery) + elseif start_angle - 90 > end_angle then + -- Add 60 degrees to ensure that there are no small segments + -- at the end + startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) + else + subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) + break + end + end + + -- else, do nothing + end +end + + +-- Doc see Path.lua + +function Path:appendArc(start_angle,end_angle,radius, trans) + + local start = rigid(self[#self]) + assert(type(start) == "table", "trying to append an arc to a path that does not end with a coordinate") + + if trans then + start = start:clone() + start:apply(Transform.invert(trans)) + end + + arc (self, start, start_angle, end_angle, radius, trans) +end + + + + +-- Doc see Path.lua + +function Path:appendArcTo (target, radius_or_center, clockwise, trans) + + local start = rigid(self[#self]) + assert(type(start) == "table", "trying to append an arc to a path that does not end with a coordinate") + + local trans_target = target + local centerx, centery, radius + + if type(radius_or_center) == "number" then + radius = radius_or_center + else + centerx, centery = radius_or_center.x, radius_or_center.y + end + + if trans then + start = start:clone() + trans_target = target:clone() + local itrans = Transform.invert(trans) + start:apply(itrans) + trans_target:apply(itrans) + if centerx then + local t = radius_or_center:clone() + t:apply(itrans) + centerx, centery = t.x, t.y + end + end + + if not centerx then + -- Compute center + local dx, dy = target.x - start.x, target.y - start.y + + if abs(dx) == abs(dy) and abs(dx) == radius then + if (dx < 0 and dy < 0) or (dx > 0 and dy > 0) then + centerx = start.x + centery = trans_target.y + else + centerx = trans_target.x + centery = start.y + end + else + local l_sq = dx*dx + dy*dy + if l_sq >= radius*radius*4*0.999999 then + centerx = (start.x+trans_target.x) / 2 + centery = (start.y+trans_target.y) / 2 + assert(l_sq <= radius*radius*4/0.999999, "radius too small for arc") + else + -- Normalize + local l = sqrt(l_sq) + local nx = dx / l + local ny = dy / l + + local e = sqrt(radius*radius - 0.25*l_sq) + + centerx = start.x + 0.5*dx - ny*e + centery = start.y + 0.5*dy + nx*e + end + end + end + + local start_dx, start_dy, target_dx, target_dy = + start.x - centerx, start.y - centery, + trans_target.x - centerx, trans_target.y - centery + + if not radius then + -- Center is given, compute radius: + radius_sq = start_dx^2 + start_dy^2 + + -- Ensure that the circle is, indeed, centered: + assert (abs(target_dx^2 + target_dy^2 - radius_sq)/radius_sq < 1e-5, "attempting to add an arc with incorrect center") + + radius = sqrt(radius_sq) + end + + -- Compute start and end angle: + local start_angle = atan2deg(start_dy, start_dx) + local end_angle = atan2deg(target_dy, target_dx) + + if clockwise then + if end_angle > start_angle then + end_angle = end_angle - 360 + end + else + if end_angle < start_angle then + end_angle = end_angle + 360 + end + end + + arc (self, start, start_angle, end_angle, radius, trans, centerx, centery) + + -- Patch last point to avoid rounding problems: + self[#self] = target +end + + + +-- Done + +return true diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Vertex.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Vertex.lua new file mode 100644 index 0000000000..677ea4fbd0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/Vertex.lua @@ -0,0 +1,296 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- A |Vertex| instance models a node of graphs. Each |Vertex| object can be an +-- element of any number of graphs (whereas an |Arc| object can only be an +-- element of a single graph). +-- +-- When a vertex is added to a digraph |g|, two tables are created in +-- the vertex' storage: An array of incoming arcs (with respect to +-- |g|) and an array of outgoing arcs (again, with respect to +-- |g|). The fields are managed by the |Digraph| class and should not +-- be modified directly. +-- +-- Note that a |Vertex| is an abstraction of \tikzname\ nodes; indeed +-- the objective is to ensure that, in principle, we can use them +-- independently of \TeX. For this reason, you will not find any +-- references to |tex| inside a |Vertex|; this information is only +-- available in the syntactic digraph. +-- +-- One important aspect of vertices are its anchors -- a concept well +-- familiar for users of \tikzname, but since we need to abstract from +-- \tikzname, a separate anchor management is available inside the +-- graph drawing system. It works as follows: +-- +-- First of all, every vertex has a path, which is a (typically +-- closed) line around the vertex. The display system will pass down +-- the vertex' path to the graph drawing system and this path will be +-- stored as a |Path| object in the |path| field of the vertex. This +-- path lives in a special ``local'' coordinate system, that is, all +-- coordinates of this path should actually be considered relative to +-- the vertex' |pos| field. Note that the path is typically, but not +-- always, ``centered'' on the origin. A graph drawing algorithm +-- should arrange the vertices in such a way that the origins in the +-- path coordinate systems are aligned. +-- +-- To illustrate the difference between the origin and the vertex +-- center, consider a tree drawing algorithm in which a node |root| has +-- three children |a|, |b|, and |g|. Now, if we were to simply center +-- these three letters vertically and arrange them in a line, the +-- letters would appear to ``jump up and down'' since the height of +-- the three letters are quite different. A solution is to shift the +-- letters (and, thus, the paths of the vertices) in such a way that +-- in all three letters the baseline of the letters is exactly at the +-- origin. Now, when a graph drawing algorithm aligns these vertices +-- along the origins, the letters will all have the same baseline. +-- +-- Apart from the origin, there may be other positions in the path +-- coordinate system that are of interest -- such as the center of +-- the vertex. As mentioned above, this need not be the origin and +-- although a graph drawing algorithm should align the origins, +-- \emph{edges} between vertices should head toward these vertex +-- centers rather that toward the origins. Other points of interest +-- might be the ``top'' of the node. +-- +-- All points of special interest are called ``anchors''. The |anchor| +-- method allows you to retrieve them. By default, you always have +-- access to the |center| anchor, but other anchors may or may not be +-- available also, see the |anchor| method for details. +-- +-- @field pos A coordinate object that stores the position where the +-- vertex should be placed on the canvas. The main objective of graph drawing +-- algorithms is to update this coordinate. +-- +-- @field name An optional string that is used as a textual representation +-- of the node. +-- +-- @field path The path of the vertex's shape. This is a path along +-- the outer line resulting from stroking the vertex's original +-- shape. For instance, if you have a quadratic shape of size 1cm and +-- you stroke the path with a pen of 2mm thickness, this |path| field +-- would store a path of a square of edge length 12mm. +-- +-- @field anchors A table of anchors (in the TikZ sense). The table is +-- indexed by the anchor names (strings) and the values are +-- |Coordinate|s. Currently, it is only guaranteed that the |center| +-- anchor is present. Note that the |center| anchor need not lie at +-- the origin: A graph drawing system should align nodes relative to +-- the origin of the path's coordinate system. However, lines going to +-- and from the node will head towards the |center| anchor. See +-- Section~\ref{section-gd-anchors} for details. +-- +-- @field options A table of options that contains user-defined options. +-- +-- @field animations An array of attribute animations for the +-- node. When an algorithm adds entries to this array, the display +-- layer should try to render these. The syntax is as follows: Each +-- element in the array is a table with a field |attribute|, which must +-- be a string like |"opacity"| or |"translate"|, a field |entries|, +-- which must be an array to be explained in a moment, and field +-- |options|, which must be a table of the same syntax as the +-- |options| field. For the |entries| array, each element must be +-- table with two field: |t| must be set to a number, representing a +-- time in seconds, and |value|, which must be set to a value that +-- the |attribute| should have at the given time. The entries and the +-- options will then be interpreted as described in \pgfname's basic +-- layer animation system, except that where a |\pgfpoint| is expected +-- you provide a |Coordinate| and a where a path is expected you +-- provide a |Path|. +-- +-- @field shape A string describing the shape of the node (like |rectangle| +-- or |circle|). Note, however, that this is more ``informative''; the +-- actual information that is used by the graph drawing system for +-- determining the extent of a node, its bounding box, convex hull, +-- and line intersections is the |path| field. +-- +-- @field kind A string describing the kind of the node. For instance, a +-- node of type |"dummy"| does not correspond to any real node in +-- the graph but is used by the graph drawing algorithm. +-- +-- @field event The |Event| when this vertex was created (may be |nil| +-- if the vertex is not part of the syntactic digraph). +-- +-- @field incomings A table indexed by |Digraph| objects. For each +-- digraph, the table entry is an array of all vertices from which +-- there is an |Arc| to this vertex. This field is internal and may +-- not only be accessed by the |Digraph| class. +-- +-- @field outgoings Like |incomings|, but for outgoing arcs. +-- +local Vertex = {} +Vertex.__index = Vertex + + +-- Namespace + +require("pgf.gd.model").Vertex = Vertex + + +-- Imports + +local Coordinate = require "pgf.gd.model.Coordinate" +local Path = require "pgf.gd.model.Path" +local Storage = require "pgf.gd.lib.Storage" + + +--- +-- Create a new vertex. The |initial| parameter allows you to setup +-- some initial values. +-- +-- @usage +--\begin{codeexample}[code only, tikz syntax=false] +--local v = Vertex.new { name = "hello", pos = Coordinate.new(1,1) } +--\end{codeexample} +-- +-- @param initial Values to override default node settings. The +-- following are permissible: +-- \begin{description} +-- \item[|pos|] Initial position of the node. +-- \item[|name|] The name of the node. It is optional to define this. +-- \item[|path|] A |Path| object representing the vertex's hull. +-- \item[|anchors|] A table of anchors. +-- \item[|options|] An options table for the vertex. +-- \item[|animations|] An array of generated animation attributes. +-- \item[|shape|] A string describing the shape. If not given, |"none"| is used. +-- \item[|kind|] A kind like |"node"| or |"dummy"|. If not given, |"dummy"| is used. +-- \end{description} +-- +-- @return A newly allocated node. +-- +function Vertex.new(values) + local new = { + incomings = Storage.new(), + outgoings = Storage.new() + } + for k,v in pairs(values) do + new[k] = v + end + new.path = new.path or Path.new { 0, 0 } + new.shape = new.shape or "none" + new.kind = new.kind or "dummy" + new.pos = new.pos or Coordinate.new(0,0) + new.anchors = new.anchors or { center = Coordinate.new(0,0) } + new.animations = new.animations or {} + return setmetatable (new, Vertex) +end + + + + +--- +-- Returns a bounding box of a vertex. +-- +-- @return |min_x| The minimum $x$ value of the bounding box of the path +-- @return |min_y| The minimum $y$ value +-- @return |max_x| +-- @return |max_y| +-- @return |center_x| The center of the bounding box +-- @return |center_y| + +function Vertex:boundingBox() + return self.path:boundingBox() +end + + + +local anchor_cache = Storage.new () + +local directions = { + north = function(min_x, min_y, max_x, max_y) + return (min_x+max_x)/2, max_y + end, + south = function(min_x, min_y, max_x, max_y) + return (min_x+max_x)/2, min_y + end, + east = function(min_x, min_y, max_x, max_y) + return max_x, (min_y+max_y)/2 + end, + west = function(min_x, min_y, max_x, max_y) + return min_x, (min_y+max_y)/2 + end, + ["north west"] = function(min_x, min_y, max_x, max_y) + return min_x, max_y + end, + ["north east"] = function(min_x, min_y, max_x, max_y) + return max_x, max_y + end, + ["south west"] = function(min_x, min_y, max_x, max_y) + return min_x, min_y + end, + ["south east"] = function(min_x, min_y, max_x, max_y) + return max_x, min_y + end, +} + +--- +-- Returns an anchor position in a vertex. First, we try to look +-- the anchor up in the vertex's |anchors| table. If it is not found +-- there, we test whether it is one of the direction strings |north|, +-- |south east|, and so on. If so, we consider a line from the center +-- of the node to the position on the bounding box that corresponds to +-- the given direction (so |south east| would be the lower right +-- corner). We intersect this line with the vertex's path and return +-- the result. Finally, if the above fails, we try to consider the +-- anchor as a number and return the intersection of a line starting +-- at the vertex's center with the number as its angle and the path of +-- the vertex. +-- +-- @param anchor An anchor as detailed above +-- @return A coordinate in the vertex's local coordinate system (so +-- add the |pos| field to arrive at the actual position). If the +-- anchor was not found, |nil| is returned + +function Vertex:anchor(anchor) + local c = self.anchors[anchor] + if not c then + local b + local d = directions [anchor] + if d then + b = Coordinate.new(d(self:boundingBox())) + else + local n = tonumber(anchor) + if n then + local x1, y1, x2, y2 = self:boundingBox() + local r = math.max(x2-x1, y2-y1) + b = Coordinate.new(r*math.cos(n/180*math.pi),r*math.sin(n/180*math.pi)) + b:shiftByCoordinate(self.anchors.center) + end + end + if not b then + return + end + local p = Path.new {'moveto', self.anchors.center, 'lineto', b} + local intersections = p:intersectionsWith(self.path) + if #intersections > 0 then + c = intersections[1].point + end + end + self.anchors[anchor] = c + return c +end + + + +-- +-- Returns a string representation of a vertex. This is mainly for debugging +-- +-- @return The Arc as string. +-- +function Vertex:__tostring() + return self.name or tostring(self.anchors) +end + + +-- Done + +return Vertex diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/library.lua new file mode 100644 index 0000000000..ad62faa0f3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/model/library.lua @@ -0,0 +1,15 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +-- Load declarations from: +require "pgf.gd.model.Hyperedge" diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf.lua new file mode 100644 index 0000000000..f7905f2418 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf.lua @@ -0,0 +1,26 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +-- Imports + +require "pgf" +require "pgf.gd" + + +-- Declare namespace +pgf.gd.ogdf = {} + + +-- Done + +return pgf.gd.ogdf \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf/library.lua new file mode 100644 index 0000000000..f91c75a4d6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/ogdf/library.lua @@ -0,0 +1,33 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- The Open Graph Drawing Framework (\textsc{ogdf}) is a large, +-- powerful graph drawing system written in C++. This library enables +-- its use inside \tikzname's graph drawing system by translating +-- back-and-forth between Lua and C++. +-- +-- Since C++ code is compiled and not interpreted (like Lua), in order +-- to use the present library, you need a compiled version of the +-- \pgfname\ interface code for the \textsc{ogdf} library +-- (|pgf/gd/ogdf/c/ogdf_script.so|) installed correctly for your particular +-- architecture. This is by no means trivial\dots +-- +-- @library + +local ogdf + + +-- Load the C++ code: + +require "pgf_gd_ogdf_c_ogdf_script" + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees.lua new file mode 100644 index 0000000000..95689e6379 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees.lua @@ -0,0 +1,21 @@ +-- Copyright 2015 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + +local pedigrees = {} + +-- Declare namespace +require("pgf.gd").pedigrees = tree + + +-- Done + +return pedigrees \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua new file mode 100644 index 0000000000..32927530a2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua @@ -0,0 +1,163 @@ +-- Copyright 2015 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local Koerner2015 = {} + + +-- Namespace +require("pgf.gd.pedigrees").Koerner2015 = Koerner2015 + +-- Imports +local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" +local Storage = require "pgf.gd.lib.Storage" +local Direct = require "pgf.gd.lib.Direct" + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "mate", + type = "boolean", + + summary = [[" + Edges of type |mate| join mates. + "]], +} + + +--- +declare { + key = "child", + type = "boolean", + + summary = [[" + Edges of type |child| join a parent to a child. The parent is the tail + of the edge, the child is the head. + "]], +} + +--- +declare { + key = "sibling", + type = "boolean", + + summary = [[" + Edges of type |sibling| join a siblings (persons with identical parents). + "]], +} + + +--- +declare { + key = "simple pedigree layout", + algorithm = Koerner2015, + + postconditions = { + upward_oriented = true + }, + + summary = [[" + A simple algorithm for drawing a pedigree. + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [simple pedigree layout, default edge operator=complete bipartite] + { + Eve -- [mate] Felix; + { Eve, Felix } -> [child] { George, Hank }; + + Alice -- [mate] Bob; + { Alice, Bob } -> [child] { Charly, Dave, Eve }; + }; + "]] +} + + +function Koerner2015:run() + + local g = self.digraph + + -- Compute ranks: + + local visited = {} + local ranks = {} + + local queue = { { g.vertices[1], 1 } } + + local queue_start = 1 + local queue_end = 1 + + local function put(v, r) + queue_end = queue_end + 1 + queue [queue_end] = { v, r } + end + + local function get() + local v = queue[queue_start][1] + local r = queue[queue_start][2] + queue_start = queue_start + 1 + return v,r + end + + while queue_start <= queue_end do + + -- Pop + local v, rank = get() + ranks[v] = rank + + visited [v] = true + + -- Follow mates: + for _,a in ipairs(g:outgoing(v)) do + if a:options("sibling") then + if not visited[a.head] then + put(a.head, rank) + end + end + end + for _,a in ipairs(g:incoming(v)) do + if a:options("child") then + if not visited[a.tail] then + put(a.tail, rank-1) + end + end + end + for _,a in ipairs(g:outgoing(v)) do + if a:options("child") then + if not visited[a.head] then + put(a.head, rank+1) + end + end + end + for _,a in ipairs(g:outgoing(v)) do + if a:options("mate") then + if not visited[a.head] then + put(a.head, rank) + end + end + end + end + + for i,v in ipairs(g.vertices) do + v.pos.x = i*50 + v.pos.y = ranks[v] * 50 + end + +end + +return Koerner2015 + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/library.lua new file mode 100644 index 0000000000..db3d4f9cf7 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/pedigrees/library.lua @@ -0,0 +1,21 @@ +-- Copyright 2015 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- A pedigree depicts parent--mate--sibling relationships between individuals. +-- +-- @library + +local pedigrees -- Library name + +require "pgf.gd.pedigrees.Koerner2015" diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics.lua new file mode 100644 index 0000000000..77c66de5b2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics.lua @@ -0,0 +1,21 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + +local phylogenetics = {} + +-- Declare namespace +require("pgf.gd").phylogenetics = tree + + +-- Done + +return phylogenetics \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua new file mode 100644 index 0000000000..04e1ca49f1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua @@ -0,0 +1,77 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +local AuthorDefinedPhylogeny = {} + + +-- Namespace +require("pgf.gd.phylogenetics").AuthorDefinedPhylogeny = AuthorDefinedPhylogeny + +-- Imports +local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" +local Direct = require "pgf.gd.lib.Direct" + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "phylogenetic tree by author", + algorithm = AuthorDefinedPhylogeny, + phase = "phylogenetic tree generation", + phase_default = true, + + summary = [[" + When this key is used, the phylogenetic tree must be specified + by the author (rather than being generated algorithmically). + "]], + documentation = [[" + A spanning tree of the input graph will be computed first (it + must be connected, otherwise errors will result). + The evolutionary length of the edges must be specified through + the use of the |length| key for each edge. + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout] { + a -- { + b [>length=2] --[length=1] { c, d }, + e [>length=3] + } + }; + "]] +} + + + +function AuthorDefinedPhylogeny:run() + + local spanning_tree = self.main_algorithm.digraph.options.algorithm_phases["spanning tree computation"].new { + ugraph = self.main_algorithm.ugraph, + events = {} -- no events + }:run() + + local phylogenetic_tree = Direct.ugraphFromDigraph(spanning_tree) + local lengths = self.lengths + + for _,a in ipairs(phylogenetic_tree.arcs) do + lengths[a.tail][a.head] = a:options('length') + end + + return phylogenetic_tree +end + + + +return AuthorDefinedPhylogeny diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua new file mode 100644 index 0000000000..ef40f0ee60 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua @@ -0,0 +1,593 @@ +-- Copyright 2013 by Sarah Mäusle and Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local BalancedMinimumEvolution = {} + + +-- Namespace +require("pgf.gd.phylogenetics").BalancedMinimumEvolution = BalancedMinimumEvolution + +-- Imports +local InterfaceToAlgorithms = require("pgf.gd.interface.InterfaceToAlgorithms") +local DistanceMatrix = require("pgf.gd.phylogenetics.DistanceMatrix") +local Storage = require("pgf.gd.lib.Storage") +local Digraph = require("pgf.gd.model.Digraph") +local lib = require("pgf.gd.lib") + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "balanced minimum evolution", + algorithm = BalancedMinimumEvolution, + phase = "phylogenetic tree generation", + + summary = [[" + The BME (Balanced Minimum Evolution) algorithm tries to minimize + the total tree length. + "]], + documentation = [[" + This algorithm is from Desper and Gascuel, \emph{Fast and + Accurate Phylogeny Reconstruction Algorithms Based on the + Minimum-Evolution Principle}, 2002. The tree is built in a way + that minimizes the total tree length. The leaves are inserted + into the tree one after another, creating new edges and new + nodes. After every insertion the distance matrix has to be + updated. + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, + balanced minimum evolution, + grow'=right, sibling distance=0pt, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + + + + +function BalancedMinimumEvolution:run() + + self.tree = Digraph.new(self.main_algorithm.digraph) + + self.distances = Storage.newTableStorage() + + local vertices = self.tree.vertices + + -- Sanity checks: + if #vertices == 2 then + self.tree:connect(vertices[1],vertices[2]) + return self.tree + elseif #vertices > 2 then + + -- Setup storages: + self.is_leaf = Storage.new() + + -- First, build the initial distance matrix: + local matrix = DistanceMatrix.graphDistanceMatrix(self.tree) + + -- Store distance information in the distance fields of the storages: + for _,u in ipairs(vertices) do + for _,v in ipairs(vertices) do + self.distances[u][v] = matrix[u][v] + end + end + + -- Run BME + self:runBME() + + -- Run postoptimizations + local optimization_class = self.tree.options.algorithm_phases['phylogenetic tree optimization'] + optimization_class.new { + main_algorithm = self.main_algorithm, + tree = self.tree, + matrix = self.matrix, + distances = self.distances, + is_leaf = self.is_leaf, + }:run() + end + + -- Finish + self:computeFinalLengths() + self:createFinalEdges() + + return self.tree +end + + + + +-- the BME (Balanced Minimum Evolution) algorithm +-- [DESPER and GASCUEL: Fast and Accurate Phylogeny Reconstruction +-- Algorithms Based on the Minimum-Evolution Principle, 2002] +-- +-- The tree is built in a way that minimizes the total tree length. +-- The leaves are inserted into the tree one after another, creating new edges and new nodes. +-- After every insertion the distance matrix has to be updated. +function BalancedMinimumEvolution:runBME() + local g = self.tree + local leaves = {} + local is_leaf = self.is_leaf + local distances = self.distances + + -- get user input + for i, vertex in ipairs (g.vertices) do + leaves[i] = vertex + is_leaf[vertex] = true + end + + -- create the new node which will be connected to the first three leaves + local new_node = InterfaceToAlgorithms.createVertex( + self.main_algorithm, + { + name = "BMEnode"..#g.vertices+1, + generated_options = { { key = "phylogenetic inner node" } } + } + ) + g:add {new_node} + -- set the distances of new_node to subtrees + local distance_1_2 = self:distance(leaves[1],leaves[2]) + local distance_1_3 = self:distance(leaves[1],leaves[3]) + local distance_2_3 = self:distance(leaves[2],leaves[3]) + distances[new_node][leaves[1]] = 0.5*(distance_1_2 + distance_1_3) + distances[new_node][leaves[2]] = 0.5*(distance_1_2 + distance_2_3) + distances[new_node][leaves[3]] = 0.5*(distance_1_3 + distance_2_3) + + --connect the first three leaves to the new node + for i = 1,3 do + g:connect(new_node, leaves[i]) + g:connect(leaves[i], new_node) + end + + for k = 4,#leaves do + -- compute distance from k to any subtree + local k_dists = Storage.newTableStorage() + for i = 1,k-1 do + -- note that the function called stores the k_dists before they are overwritten + self:computeAverageDistancesToAllSubtreesForK(g.vertices[i], { }, k,k_dists) + end + + -- find the best insertion point + local best_arc = self:findBestEdge(g.vertices[1],nil,k_dists) + local head = best_arc.head + local tail = best_arc.tail + + -- remove the old arc + g:disconnect(tail, head) + g:disconnect(head, tail) + + -- create the new node + local new_node = InterfaceToAlgorithms.createVertex( + self.main_algorithm, + { + name = "BMEnode"..#g.vertices+1, + generated_options = { + { key = "phylogenetic inner node" } + } + } + ) + g:add{new_node} + + -- gather the vertices that will be connected to the new node... + local vertices_to_connect = { head, tail, leaves[k] } + + -- ...and connect them + for _, vertex in pairs (vertices_to_connect) do + g:connect(new_node, vertex) + g:connect(vertex, new_node) + end + + if not is_leaf[tail] then + distances[leaves[k]][tail] = k_dists[head][tail] + end + if not is_leaf[head] then + distances[leaves[k]][head] = k_dists[tail][head] + end + -- insert distances from k to subtrees into actual matrix... + self:setAccurateDistancesForK(new_node,nil,k,k_dists,leaves) + + -- set the distance from k to the new node, which was created by inserting k into the graph + distances[leaves[k]][new_node] = 0.5*( self:distance(leaves[k], head) + self:distance(leaves[k],tail)) + + -- update the average distances + local values = {} + values.s = head -- s--u is the arc into which k has been inserted + values.u = tail + values.new_node = new_node -- the new node created by inserting k + self:updateAverageDistances(new_node, values,k,leaves) + end +end + +-- +-- Updates the average distances from k to all subtrees +-- +-- @param vertex The starting point of the recursion +-- @param values The values needed for the recursion +-- - s, u The nodes which span the edge into which k has been +-- inserted +-- - new_node The new_node which has been created to insert k +-- - l (l-1) is the number of edges between the +-- new_node and the current subtree Y +-- +-- values.new_node, values.u and values.s must be set +-- the depth first search must begin at the new node, thus vertex +-- must be set to the newly created node +function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leaves) + local g = self.tree + local leaf_k = leaves[k] + local y, z, x + if not values.visited then + values.visited = {} + values.visited[leaf_k] = leaf_k -- we don't want to visit k! + end + -- there are (l-1) edges between new_node and y + if not values.l then values.l = 1 end + if not values.new_node then values.new_node = g:outgoing(leaf_k)[1].head end + --values.s and values.u must be set + + -- the two nodes which connect the edge on which k was inserted: s,u + + local new_node = values.new_node + local l = values.l + local visited = values.visited + + visited[vertex] = vertex + + -- computes the distances to Y{k} for all subtrees X of Z + function loop_over_x( x, y, values ) + local l = values.l + local y1= values.y1 + + -- calculate distance between Y{k} and X + local old_distance -- the distance between Y{/k} and X needed for calculating the new distance + if y == new_node then -- this y didn't exist in the former tree; so use y1 (see below) + old_distance = self:distance(x,y1) + else + old_distance = self:distance(x,y) + end + + local new_distance = old_distance + math.pow(2,-l) * ( self:distance(leaf_k,x) - self:distance(x,y1) ) + self.distances[x][y] = new_distance + self.distances[y][x] = new_distance -- symmetric matrix + + values.x_visited[x] = x + --go deeper to next x + for _, x_arc in ipairs (self.tree:outgoing(x)) do + if not values.x_visited[x_arc.head] then + local new_x = x_arc.head + loop_over_x( new_x, y, values ) + end + end + end + + --loop over Z's + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not visited[arc.head] then + -- set y1, which is the node which was pushed further away from + -- subtree Z by inserting k + if arc.head == values.s then + values.y1 = values.u + elseif arc.head == values.u then + values.y1 = values.s + else + assert(values.y1,"no y1 set!") + end + + z = arc.head -- root of the subtree we're looking at + y = arc.tail -- the root of the subtree-complement of Z + + x = z -- the first subtree of Z is Z itself + values.x_visited = {} + values.x_visited[y] = y -- we don't want to go there, as we want to stay within Z + loop_over_x( z,y, values ) -- visit all possible subtrees of Z + + -- go to next Z + values.l = values.l+1 -- moving further away from the new_node + self:updateAverageDistances(z,values,k,leaves) + values.l = values.l-1 -- moving back to the new_node + end + end +end + + +-- +-- Computes the average distances of a node, which does not yet belong +-- to the graph, to all subtrees. This is done using a depth first +-- search +-- +-- @param vertex The starting point of the depth first search +-- @param values The values for the recursion +-- - distances The table in which the distances are to be +-- stored +-- - outgoing_arcs The table containing the outgoing arcs +-- of the current vertex +-- +-- @return The average distance of the new node #k to any subtree +-- The distances are stored as follows: +-- example: distances[center][a] +-- center is any vertex, thus if center is an inner vertex +-- it has 3 neighbors a,b and c, which can all be seen as the +-- roots of subtrees A,B,C. +-- distances[center][a] gives us the distance of the new +-- node k to the subtree A. +-- if center is a leaf, it has only one neighbor, which +-- can also be seen as the root of the subtree T\{center} +-- +function BalancedMinimumEvolution:computeAverageDistancesToAllSubtreesForK(vertex, values, k, k_dists) + local is_leaf = self.is_leaf + local arcs = self.tree.arcs + local vertices = self.tree.vertices + local center_vertex = vertex + -- for every vertex a table is created, in which the distances to all + -- its subtrees will be stored + + values.outgoing_arcs = values.outgoing_arcs or self.tree:outgoing(center_vertex) + for _, arc in ipairs (values.outgoing_arcs) do + local root = arc.head -- this vertex can be seen as the root of a subtree + if is_leaf[root] then -- we know the distance of k to the leaf! + k_dists[center_vertex][root] = self:distance(vertices[k], root) + else -- to compute the distance we need the root's neighboring vertices, which we can access by its outgoing arcs + local arc1, arc2 + local arc_back -- the arc we came from + for _, next_arc in ipairs (self.tree:outgoing(root)) do + if next_arc.head ~= center_vertex then + arc1 = arc1 or next_arc + arc2 = next_arc + else + arc_back = next_arc + end + end + + values.outgoing_arcs = { arc1, arc2, arc_back } + + -- go deeper, if the distances for the next center node haven't been set yet + if not (k_dists[root][arc1.head] and k_dists[root][arc2.head]) then + self:computeAverageDistancesToAllSubtreesForK(root, values, k,k_dists) + end + + -- set the distance between k and subtree + k_dists[center_vertex][root] = 1/2 * (k_dists[root][arc1.head] + k_dists[root][arc2.head]) + end + end +end + + +-- +-- Sets the distances from k to subtrees +-- In computeAverageDistancesToAllSubtreesForK the distances to ALL possible +-- subtrees are computed. Once k is inserted many of those subtrees don't +-- exist for k, as k is now part of them. In this function all +-- still accurate subtrees and their distances to k are +-- extracted. +-- +-- @param center The vertex serving as the starting point of the depth-first search; +-- should be the new_node + +function BalancedMinimumEvolution:setAccurateDistancesForK(center,visited,k,k_dists,leaves) + local visited = visited or {} + local distances = self.distances + + visited[center] = center + local outgoings = self.tree:outgoing(center) + for _,arc in ipairs (outgoings) do + local vertex = arc.head + if vertex ~= leaves[k] then + local distance + -- set the distance + if not distances[leaves[k]][vertex] and k_dists[center] then + distance = k_dists[center][vertex] -- use previously calculated distance + distances[leaves[k]][vertex] = distance + distances[vertex][leaves[k]] = distance + end + -- go deeper + if not visited[vertex] then + self:setAccurateDistancesForK(vertex,visited,k,k_dists,leaves) + end + end + end +end + + +-- +-- Find the best edge for the insertion of leaf #k, such that the +-- total tree length is minimized. This function uses a depth first +-- search. +-- +-- @param vertex The vertex where the depth first search is +-- started; must be a leaf +-- @param values The values needed for the recursion +-- - visited: The vertices that already have been visited +-- - tree_length: The current tree_length +-- - best_arc: The current best_arc, such that the tree +-- length is minimized +-- - min_length: The smallest tree_length found so far +function BalancedMinimumEvolution:findBestEdge(vertex, values, k_dists) + local arcs = self.tree.arcs + local vertices = self.tree.vertices + values = values or { visited = {} } + values.visited[vertex] = vertex + + local c -- the arc we came from + local unvisited_arcs = {} --unvisited arcs + --identify arcs + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] then + unvisited_arcs[#unvisited_arcs+1] = arc + else + c = arc.head --last visited arc + end + end + + for i, arc in ipairs (unvisited_arcs) do + local change_in_tree_length = 0 + -- set tree length to 0 for first insertion arc + if not values.tree_length then + values.tree_length = 0 + values.best_arc = arc + values.min_length = 0 + else -- compute new tree length for the case that k is inserted into this arc + local b = arc.head --current arc + local a = unvisited_arcs[i%2+1].head -- the remaining arc + local k_v = vertices[k] -- the leaf to be inserted + change_in_tree_length = 1/4 * ( ( self:distance(a,c) + + k_dists[vertex][b]) + - (self:distance(a,b) + + k_dists[vertex][c]) ) + values.tree_length = values.tree_length + change_in_tree_length + end + -- if the tree length becomes shorter, this is the new best arc + -- for the insertion of leaf k + if values.tree_length < values.min_length then + values.best_arc = arc + values.min_length = values.tree_length + end + + -- go deeper + self:findBestEdge(arc.head, values, k_dists) + + values.tree_length = values.tree_length - change_in_tree_length + end + return values.best_arc +end + +-- Calculates the total tree length +-- This is done by adding up all the edge lengths +-- +-- @return the tree length +function BalancedMinimumEvolution:calculateTreeLength() + local vertices = self.tree.vertices + local sum = 0 + + for index, v1 in ipairs(vertices) do + for i = index+1,#vertices do + local v2 = vertices[i] + local dist = self.lengths[v1][v2] + if dist then + sum = sum + dist + end + end + end + return sum +end + +-- generates edges for the final graph +-- +-- throughout the process of creating the tree, arcs have been +-- disconnected and connected, without truly creating edges. this is +-- done in this function +function BalancedMinimumEvolution:createFinalEdges() + local g = self.tree + local o_arcs = {} -- copy arcs since createEdge is going to modify the arcs array... + for _,arc in ipairs(g.arcs) do + if arc.tail.event.index < arc.head.event.index then + o_arcs[#o_arcs+1] = arc + end + end + for _,arc in ipairs(o_arcs) do + InterfaceToAlgorithms.createEdge( + self.main_algorithm, arc.tail, arc.head, + { generated_options = { + { key = "phylogenetic edge", value = tostring(self.lengths[arc.tail][arc.head]) } + }}) + end +end + + +-- Gets the distance between two nodes as specified in their options +-- or storage fields. +-- Note: this function implies that the distance from a to b is the +-- same as the distance from b to a. +-- +-- @param a,b The nodes +-- @return The distance between the two nodes + +function BalancedMinimumEvolution:distance(a, b) + if a == b then + return 0 + else + local distances = self.distances + return distances[a][b] or distances[b][a] + end +end + + +-- +-- computes the final branch lengths +-- +-- goes over all arcs and computes the final branch lengths, +-- as neither the BME nor the BNNI main_algorithm does so. +function BalancedMinimumEvolution:computeFinalLengths() + local is_leaf = self.is_leaf + local lengths = self.lengths + local g = self.tree + for _, arc in ipairs(g.arcs) do + local head = arc.head + local tail = arc.tail + local distance + local a,b,c,d + -- assert, that the length hasn't already been computed for this arc + if not lengths[head][tail] then + if not is_leaf[head] then + -- define subtrees a and b + for _, arc in ipairs (g:outgoing(head)) do + local subtree = arc.head + if subtree ~= tail then + a = a or subtree + b = subtree + end + end + end + if not is_leaf[tail] then + -- define subtrees c and d + for _, arc in ipairs (g:outgoing(tail)) do + local subtree = arc.head + if subtree ~= head then + c = c or subtree + d = subtree + end + end + end + -- compute the distance using the formula for outer or inner edges, respectively + if is_leaf[head] then + distance = 1/2 * ( self:distance(head,c) + + self:distance(head,d) + - self:distance(c,d) ) + elseif is_leaf[tail] then + distance = 1/2 * ( self:distance(tail,a) + + self:distance(tail,b) + - self:distance(a,b) ) + else --inner edge + distance = self:distance(head, tail) + -1/2 * ( self:distance(a,b) + + self:distance(c,d) ) + end + lengths[head][tail] = distance + lengths[tail][head] = distance + end + end + +end + + + +return BalancedMinimumEvolution diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua new file mode 100644 index 0000000000..1980afe7ad --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua @@ -0,0 +1,372 @@ +-- Copyright 2013 by Sarah Mäusle and Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local BalancedNearestNeighbourInterchange = {} + + +-- Namespace +require("pgf.gd.phylogenetics").BalancedNearestNeighbourInterchange = BalancedNearestNeighbourInterchange + +-- Imports +local InterfaceToAlgorithms = require("pgf.gd.interface.InterfaceToAlgorithms") +local DistanceMatrix = require("pgf.gd.phylogenetics.DistanceMatrix") +local lib = require("pgf.gd.lib") + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "balanced nearest neighbour interchange", + algorithm = BalancedNearestNeighbourInterchange, + phase = "phylogenetic tree optimization", + phase_default = true, + + summary = [[" + The BNNI (Balanced Nearest Neighbor Interchange) is a + postprocessing algorithm for phylogenetic trees. It swaps two + distant 3-subtrees if the total tree length is reduced by doing + so, until no such swaps are left. + "]], + documentation = [[" + This algorithm is from Desper and Gascuel, \emph{Fast and + Accurate Phylogeny Reconstruction Algorithms Based on the + Minimum-Evolution Principle}, 2002. + "]] +} + + +--- +declare { + key = "no phylogenetic tree optimization", + algorithm = { run = function(self) end }, + phase = "phylogenetic tree optimization", + + summary = [[" + Switches off any phylogenetic tree optimization. + "]], +} + + + +-- creates a binary heap, implementation as an array as described in +-- the respective wikipedia article +local function new_heap() + local heap = {} + + function heap:insert(element, value) + local object = { element = element, value = value } + heap[#heap+1]= object + + local i = #heap + local parent = math.floor(i/2) + + -- sort the new object into its correct place + while heap[parent] and heap[parent].value < heap[i].value do + heap[i] = heap[parent] + heap[parent] = object + i = parent + parent = math.floor(i/2) + end + end + + -- deletes the top element from the heap + function heap:remove_top_element() + -- replace first element with last and delete the last element + local element = heap[1].element + heap[1] = heap[#heap] + heap[#heap] = nil + + local i = 1 + local left_child = 2*i + local right_child = 2*i +1 + + -- sort the new top element into its correct place by swapping it + -- against its largest child + while heap[left_child] do + local largest_child = left_child + if heap[right_child] and heap[left_child].value < heap[right_child].value then + largest_child = right_child + end + + if heap[largest_child].value > heap[i].value then + heap[largest_child], heap[i] = heap[i], heap[largest_child] + i = largest_child + left_child = 2*i + right_child = 2*i +1 + else + return element + end + end + return element + end + + return heap +end + + +-- BNNI (Balanced Nearest Neighbor Interchange) +-- [DESPER and GASCUEL: Fast and Accurate Phylogeny Reconstruction Algorithms Based on the Minimum-Evolution Principle, 2002] +-- swaps two distant-3 subtrees if the total tree length is reduced by doing so, until no such swaps are left +-- +-- step 1: precomputation of all average distances between non-intersecting subtrees (already done by BME) +-- step 2: create heap of possible swaps +-- step 3: ( current tree with subtrees a,b,c,d: a--v-- {b, w -- {c, d}} ) +-- (a): edge (v,w) is the best swap on the heap. Remove (v,c) and (w,b) +-- (b), (c), (d) : update the distance matrix +-- (e): remove the edge (v,w) from the heap; check the four edges adjacent to it for new possible swaps +-- (d): if the heap is non-empty, return to (a) + +function BalancedNearestNeighbourInterchange:run() + local g = self.tree + -- create a heap of possible swaps + local possible_swaps = new_heap() + -- go over all arcs, look for possible swaps and add them to the heap [step 2] + for _, arc in ipairs (g.arcs) do + self:getBestSwap(arc, possible_swaps) + end + + -- achieve best swap and update the distance matrix, until there is + -- no more swap to perform + + while #possible_swaps > 0 do + -- get the best swap and delete it from the heap + local swap = possible_swaps:remove_top_element() --[part of step 3 (a)] + + -- Check if the indicated swap is still possible. Another swap may + -- have interfered. + if g:arc(swap.v, swap.subtree1) and g:arc(swap.w, swap.subtree2) and g:arc(swap.v, swap.w) and g:arc(swap.a, swap.v) and g:arc(swap.d, swap.w) then + -- insert new arcs and delete the old ones to perform the swap [part of step 3 (a)] + + -- disconnect old arcs + g:disconnect(swap.v, swap.subtree1) + g:disconnect(swap.subtree1, swap.v) + g:disconnect(swap.w, swap.subtree2) + g:disconnect(swap.subtree2, swap.w) + + -- connect new arcs + g:connect(swap.v, swap.subtree2) + g:connect(swap.subtree2, swap.v) + g:connect(swap.w, swap.subtree1) + g:connect(swap.subtree1, swap.w) + + --update distance matrix + self:updateBNNI(swap) + + -- update heap: check neighboring arcs for new possible swaps + -- [step 3 (e)] + self:getBestSwap(g:arc(swap.a,swap.v), possible_swaps) + self:getBestSwap(g:arc(swap.subtree2, swap.v), possible_swaps) + self:getBestSwap(g:arc(swap.d,swap.w), possible_swaps) + self:getBestSwap(g:arc(swap.subtree1, swap.w), possible_swaps) + end + end + +end + + +-- +-- Gets the distance between two nodes as specified in the distances +-- fields. Note: this function assumes that the distance from a to b +-- is the +-- same as the distance from b to a. +-- +-- @param a,b The nodes +-- @return The distance between the two nodes +function BalancedNearestNeighbourInterchange:distance(a, b) + if a == b then + return 0 + else + local distances = self.distances + return distances[a][b] or distances[b][a] + end +end + +-- updates the distance matrix after a swap has been performed [step3(b),(c),(d)] +-- +-- @param swap A table containing the information on the performed swap +-- subtree1, subtree2: the two subtrees, which +-- were swapped +-- a, d: The other two subtrees bordering the +-- swapping edge +-- v, w : the two nodes connecting the swapping edge + +function BalancedNearestNeighbourInterchange:updateBNNI(swap) + local g = self.tree + local b = swap.subtree1 + local c = swap.subtree2 + local a = swap.a + local d = swap.d + local v = swap.v + local w = swap.w + local distances = self.distances + + -- updates the distances in one of the four subtrees adjacent to the + -- swapping edge + function update_BNNI_subtree(swap, values) + local g = self.tree + local b = swap.farther + local c = swap.nearer + local a = swap.subtree + local v = swap.v + local d = swap.same + local w = swap.w + + if not values then + values = { + visited = {[v] = v}, + possible_ys = {v}, + x = a, + y = v + } + -- if we're looking at subtrees in one of the swapped subtrees, + -- then need the old root (w) for the calculations + if swap.swapped_branch then values.possible_ys = {w} end + end + local visited = values.visited + local x = values.x + local y = values.y + local ys = values.possible_ys + local l = 0 -- number of edges between y and v + + local dist_x_b = self:distance(x,b) + local dist_x_c = self:distance(x,c) + visited[x] = x --mark current x as visited + + -- loop over possible y's: + for _, y in ipairs (ys) do + -- update distance [step 3(b)] + local distance = self:distance(x,y) - 2^(-l-2)*dist_x_b + 2^(-l-2)*dist_x_c + + if y == w then y = v end -- the old distance w,x was used for the new distance calculation, but it needs to be + -- saved under its appropriate new name according to its new root. this case only arises when looking at x's + -- in one of the swapped subtrees (b or c) + + distances[x][y] = distance + distances[y][x] = distance + l = l+1 -- length + 1, as the next y will be further away from v + end + + -- update the distance between x and w (root of subtree c and d) + -- [step 3(c)] + local distance = 1/2 * (self:distance(x,b) + self:distance(x,d)) + distances[x][w] = distance + distances[w][x] = distance + + -- go to next possible x's + table.insert(ys, x) -- when we're at the next possible x, y can also be the current x + for _,arc in ipairs (g:outgoing(x)) do + if not visited[arc.head] then + values.x = arc.head + --go deeper + update_BNNI_subtree(swap, values) + end + end + end + + -- name the nodes/subtrees in a general way that allows the use of the function update_BNNI_subtree + local update_a = {subtree = a, farther = b, nearer = c, v = v, same = d, w = w} + local update_b = {subtree = b, farther = a, nearer = d, v = w, same = c, w = v, swapped_branch = true} + local update_c = {subtree = c, farther = d, nearer = a, v = v, same = b, w = w, swapped_branch = true} + local update_d = {subtree = d, farther = c, nearer = b, v = w, same = a, w = v} + + -- update the distances within the subtrees a,b,c,d respectively + update_BNNI_subtree(update_a) + update_BNNI_subtree(update_b) + update_BNNI_subtree(update_c) + update_BNNI_subtree(update_d) + + -- update the distance between subtrees v and w [step 3 (d)]: + local distance = 1/4*( self:distance(a,b) + self:distance(a,d) + self:distance(c,b) + self:distance(c,d) ) + distances[v][w] = distance + distances[w][v] = distance +end + + + +-- finds the best swap across an arc and inserts it into the heap of +-- possible swaps +-- +-- @param arc The arc, which is to be checked for possible swaps +-- @param heap_of_swaps The heap, containing all swaps, which +-- improve the total tree length +-- +-- the following data of the swap are saved: +-- v,w = the nodes connecting the arc, across which the swap is +-- performed +-- subtree1,2 = the roots of the subtrees that are to be swapped +-- a,d = the roots of the two remaining subtrees adjacent to the arc + +function BalancedNearestNeighbourInterchange:getBestSwap(arc, heap_of_swaps) + local g = self.tree + local possible_swaps = heap_of_swaps + local v = arc.tail + local w = arc.head + local is_leaf = self.is_leaf + + -- only look at inner edges: + if not is_leaf[v] and not is_leaf[w] then + -- get the roots of the adjacent subtrees + local a, b, c, d + for _,outgoing in ipairs (g:outgoing(v)) do + local head = outgoing.head + if head ~= w then + a = a or head + b = head + end + end + + for _,outgoing in ipairs (g:outgoing(w)) do + local head = outgoing.head + if head ~= v then + c = c or head + d = head + end + end + + -- get the distances between the four subtrees + local a_b = self:distance(a,b) + local a_c = self:distance(a,c) + local a_d = self:distance(a,d) + local b_c = self:distance(b,c) + local b_d = self:distance(b,d) + local c_d = self:distance(c,d) + + -- difference in total tree length between old tree (T) and new tree (T') + -- when nodes b and c are swapped + local swap1 = 1/4*(a_b + c_d - a_c - b_d ) + + -- difference in total tree length between old tree and new tree when nodes b and d are swapped + local swap2 = 1/4*(a_b + c_d - a_d - b_c) + + -- choose the best swap that reduces the total tree length most (T-T' > 0) + if swap1 > swap2 and swap1 > 0 then + -- v,w = the nodes connecting the edge across which the swap is performed + -- subtree1 = one of the nodes to be swapped; connected to v + -- subtree2 = the other node to be swapped; connected to w + -- a = other node connected to v + -- d = other node connected to w + local swap = { v = v, w = w, subtree1 = b, subtree2 = c, a = a, d = d } + -- insert the swap into the heap + possible_swaps:insert(swap, swap1) + elseif swap2 > 0 then + local swap = { v = v, w = w, subtree1 = b, subtree2 = d, d = c, a = a } + possible_swaps:insert(swap, swap2) + end + end +end + + + +return BalancedNearestNeighbourInterchange diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua new file mode 100644 index 0000000000..a65a83da17 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua @@ -0,0 +1,451 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +local DistanceMatrix = {} + + +-- Imports +local InterfaceToAlgorithms = require("pgf.gd.interface.InterfaceToAlgorithms") +local declare = InterfaceToAlgorithms.declare + + +--- + +declare { + key = "distance matrix vertices", + type = "string", + + summary = [[" + A list of vertices that are used in the parsing of the + |distance matrix| key. If this key is not used at all, all + vertices of the graph will be used for the computation of a + distance matrix. + "]], + + documentation = [[" + The vertices must be separated by spaces and/or + commas. For vertices containing spaces or commas, the vertex + names may be surrounded by single or double quotes (as in + Lua). Typical examples are |a, b, c| or |"hello world", 'foo'|. + "]] +} + + + +--- + +declare { + key = "distance matrix", + type = "string", + + summary = [[" + A distance matrix specifies ``desired distances'' between + vertices in a graph. These distances are used, in particular, in + algorithms for computing phylogenetic trees. + "]], + + documentation = [[" + When this key is parsed, the key |distance matrix vertices| is + considered first. It is used to determine a list of vertices + for which a distance matrix is computed, see that key for + details. Let $n$ be the number of vertices derived from that + key. + + The string passed to the |distance matrix| key is basically + a sequence of numbers that are used to fill an $n \times n$ + matrix. This works as follows: We keep track of a \emph{current + position $p$} in the matrix, starting at the upper left corner + of the matrix. We read the numbers in the string + one by one, write it to the current position of the matrix, and + advance the current position by going right one step; if we go + past the right end of the matrix, we ``wrap around'' by going + back to the left border of the matrix, but one line down. If we + go past the bottom of the matrix, we start at the beginning once + more. + + This basic behavior can be modified in different ways. First, + when a number is followed by a semicolon instead of a comma or a + space (which are the ``usual'' ways of indicating the end of a + number), we immediately go down to the next line. Second, + instead of a number you can directly provide a \emph{position} + in the matrix and the current position will be set to this + position. Such a position information is detected by a + greater-than sign (|>|). It must be followed by + % + \begin{itemize} + \item a number or a vertex name or + \item a number or a vertex name, a comma, and another number or + vertex name or + \item a comma and a number and a vertex name. + \end{itemize} + % + Examples of the respective cases are |>1|, |>a,b|, and + |>,5|. The semantics is as follows: In all cases, if a vertex + name rather than a number is given, it is converted into a + number (namely the index of the vertex inside the matrix). Then, + in the first case, the column of the current position is set to + the given number; in the second case, the columns is set to the + first number and the column is set to the second number; and in + the third case only the row is set to the given number. (This + idea is that following the |>|-sign comes a ``coordinate pair'' + whose components are separated by a comma, but part of that pair + may be missing.) If a vertex name contains special symbols like + a space or a comma, you must surround it by single or double + quotation marks (as in Lua). + + Once the string has been parsed completely, the matrix may be + filled only partially. In this case, for each missing entry + $(x,y)$, we try to set it to the value of the entry $(y,x)$, + provided that entry is set. If neither are set, the entry is set + to $0$. + + Let us now have a look at several examples that all produce the + same matrix. The vertices are |a|, |b|, |c|. + % +\begin{codeexample}[code only, tikz syntax=false] +0, 1, 2 +1, 0, 3 +2, 3, 0 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +0 1 2 1 0 3 2 3 0 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +; +1; +2 3 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +>,b 1; 2 3 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +>b 1 2 >c 3 +\end{codeexample} + "]] +} + + +--- + +declare { + key = "distances", + type = "string", + + summary = [[" + This key is used to specify the ``desired distances'' between + a vertex and the other vertices in a graph. + "]], + + documentation = [[" + This key works similar to the |distance matrix| key, only it is + passed to a vertex instead of to a whole graph. The syntax is + the same, only the notion of different ``rows'' is not + used. Here are some examples that all have the same effect, + provided the nodes are |a|, |b|, and |c|. + % +\begin{codeexample}[code only, tikz syntax=false] +0, 1, 2 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +0 1 2 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +>b 1 2 +\end{codeexample} + % +\begin{codeexample}[code only, tikz syntax=false] +>c 2, >b 1 +\end{codeexample} + "]] +} + + + +local function to_index(s, indices) + if s and s ~= "" then + if s:sub(1,1) == '"' then + local _, _, m = s:find('"(.*)"') + return indices[InterfaceToAlgorithms.findVertexByName(m)] + elseif s:sub(1,1) == "'" then + local _, _, m = s:find("'(.*)'") + return indices[InterfaceToAlgorithms.findVertexByName(m)] + else + local num = tonumber(s) + if not num then + return indices[InterfaceToAlgorithms.findVertexByName(s)] + else + return num + end + end + end +end + +local function compute_indices(vertex_string, vertices) + local indices = {} + + if not vertex_string then + for i,v in ipairs(vertices) do + indices[i] = v + indices[v] = i + end + else + -- Ok, need to parse the vertex_string. Sigh. + local pos = 1 + while pos <= #vertex_string do + local start = vertex_string:sub(pos,pos) + if not start:find("[%s,]") then + local _, vertex + if start == '"' then + _, pos, vertex = vertex_string:find('"(.-)"', pos) + elseif start == "'" then + _, pos, vertex = vertex_string:find("'(.-)'", pos) + else + _, pos, vertex = vertex_string:find("([^,%s'\"]*)", pos) + end + local v = assert(InterfaceToAlgorithms.findVertexByName(vertex), "unknown vertex name '" .. vertex .. "'") + indices [#indices + 1] = v + indices [v] = #indices + end + pos = pos + 1 + end + end + + return indices +end + + +--- +-- Compute a distance matrix based on the values of a +-- |distance matrix| and a |distance matrix vertices|. +-- +-- @param matrix_string A distance matrix string +-- @param vertex_string A distance matrix vertex string +-- @param vertices An array of all vertices in the graph. +-- +-- @return A distance matrix. This matrix will contain both a +-- two-dimensional array (accessed through numbers) and also a +-- two-dimensional hash table (accessed through vertex indices). Thus, +-- you can write both |m[1][1]| and also |m[v][v]| to access the first +-- entry of this matrix, provided |v == vertices[1]|. +-- @return An index vector. This is an array of the vertices +-- identified for the |vertex_string| parameter. + +function DistanceMatrix.computeDistanceMatrix(matrix_string, vertex_string, vertices) + -- First, we create a table of the vertices we need to consider: + local indices = compute_indices(vertex_string, vertices) + + -- Second, build matrix. + local n = #indices + local m = {} + for i=1,n do + m[i] = {} + end + + local x = 1 + local y = 1 + local pos = 1 + -- Start scanning the matrix_string + while pos <= #matrix_string do + local start = matrix_string:sub(pos,pos) + if not start:find("[%s,]") then + if start == '>' then + local _, parse + _, pos, parse = matrix_string:find(">([^%s>;]*)", pos) + local a, b + if parse:find(",") then + _,_,a,b = parse:find("(.*),(.*)") + else + a = parse + end + x = to_index(a, indices) or x + y = to_index(b, indices) or y + elseif start == ';' then + x = 1 + y = y + 1 + elseif start == ',' then + x = x + 1 + else + local _, n + _, pos, n = matrix_string:find("([^,;%s>]*)", pos) + local num = assert(tonumber(n), "number expected in distance matrix") + m[x][y] = num + x = x + 1 + -- Skip everything up to first comma: + _, pos = matrix_string:find("(%s*,?)", pos+1) + end + end + pos = pos + 1 + if x > n then + x = 1 + y = y + 1 + end + if y > n then + y = 1 + end + end + + -- Fill up + for x=1,n do + for y=1,n do + if not m[x][y] then + m[x][y] = m[y][x] or 0 + end + end + end + + -- Copy to index version + for x=1,n do + local v = indices[x] + m[v] = {} + for y=1,n do + local u = indices[y] + m[v][u] = m[x][y] + end + end + + return m, indices +end + + + + +--- +-- Compute a distance vector. See the key |distances| for details. +-- +-- @param vector_string A distance vector string +-- @param vertex_string A distance matrix vertex string +-- @param vertices An array of all vertices in the graph. +-- +-- @return A distance vector. Like a distance matrix, this vector will +-- double indexed, once by numbers and once be vertex objects. +-- @return An index vector. This is an array of the vertices +-- identified for the |vertex_string| parameter. + +function DistanceMatrix.computeDistanceVector(vector_string, vertex_string, vertices) + -- First, we create a table of the vertices we need to consider: + local indices = compute_indices(vertex_string, vertices) + + -- Second, build matrix. + local n = #indices + local m = {} + local x = 1 + local pos = 1 + -- Start scanning the vector_string + while pos <= #vector_string do + local start = vector_string:sub(pos,pos) + if not start:find("[%s,]") then + if start == '>' then + local _, parse + _, pos, parse = vector_string:find(">([^%s>;]*)", pos) + x = to_index(parse, indices) or x + elseif start == ',' then + x = x + 1 + else + local _, n + _, pos, n = vector_string:find("([^,;%s>]*)", pos) + local num = assert(tonumber(n), "number expected in distance matrix") + m[x] = num + x = x + 1 + -- Skip everything up to first comma: + _, pos = vector_string:find("(%s*,?)", pos+1) + end + end + pos = pos + 1 + if x > n then + x = 1 + end + end + + -- Fill up + for x=1,n do + m[x] = m[x] or 0 + m[indices[x]] = m[x] + end + + return m, indices +end + + + +--- +-- Compute a distance matrix for a graph that incorporates all +-- information stored in the different options of the graph and the +-- vertices. +-- +-- @param graph A digraph object. +-- +-- @return A distance matrix for all vertices of the graph. + +function DistanceMatrix.graphDistanceMatrix(digraph) + local vertices = digraph.vertices + local n = #vertices + local m = {} + for i,v in ipairs(vertices) do + m[i] = {} + m[v] = {} + end + + local indices = {} + for i,v in ipairs(vertices) do + indices[i] = v + indices[v] = i + end + + if digraph.options['distance matrix'] then + local sub, vers = DistanceMatrix.computeDistanceMatrix( + digraph.options['distance matrix'], + digraph.options['distance matrix vertices'], + vertices + ) + + for x=1,#vers do + for y=1,#vers do + m[vers[x]][vers[y]] = sub[x][y] + end + end + end + + for i,v in ipairs(vertices) do + if v.options['distances'] then + local sub, vers = DistanceMatrix.computeDistanceVector( + v.options['distances'], + v.options['distance matrix vertices'], + vertices + ) + + for x=1,#vers do + m[vers[x]][v] = sub[x] + end + end + end + + -- Fill up number versions: + for x,vx in ipairs(vertices) do + for y,vy in ipairs(vertices) do + m[x][y] = m[vx][vy] + end + end + + return m +end + + + +return DistanceMatrix diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua new file mode 100644 index 0000000000..a9acc48865 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua @@ -0,0 +1,778 @@ +-- Copyright 2013 by Sarah Mäusle and Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local Digraph = require 'pgf.gd.model.Digraph' +local Coordinate = require 'pgf.gd.model.Coordinate' +local Path = require 'pgf.gd.model.Path' + +local layered = require 'pgf.gd.layered' + +local lib = require 'pgf.gd.lib' + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + +-- Main class of this file: + +local Maeusle2012 = lib.class {} + +-- Namespace +require("pgf.gd.phylogenetics").Maeusle2012 = Maeusle2012 + + + + +--- +declare { + key = "rooted rectangular phylogram", + algorithm = { + base_class = Maeusle2012, + run = function (self) + local root = self:getRoot() + self:setPosForRectangularLayout(root) + end + }, + phase = "phylogenetic tree layout", + phase_default = true, + + summary = [[" + A rooted rectangular phylogram is... + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, + rooted rectangular phylogram, + balanced minimum evolution, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + +--- +declare { + key = "rectangular phylogram", + use = { { key = "rooted rectangular phylogram" } }, + summary = "An alias for |rooted rectangular phylogram|" +} + +--- +declare { + key = "rooted straight phylogram", + algorithm = { + base_class = Maeusle2012, + run = function (self) + local root = self:getRoot() + self:setXPos(root) + self:setYPosForStraightLayout(root) + end + }, + phase = "phylogenetic tree layout", + + summary = [[" + A rooted straight phylogram is... + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, + rooted straight phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]]} + +--- +declare { + key = "straight phylogram", + use = { { key = "rooted straight phylogram" } }, + summary = "An alias for |rooted straight phylogram|" +} + +--- +declare { + key = "unrooted rectangular phylogram", + algorithm = { + base_class = Maeusle2012, + run = function (self) + local root1, root2 = self:getRoot() + self:setPosForUnrootedRectangular(root2, root1) + end + }, + phase = "phylogenetic tree layout", + + summary = [[" + A unrooted rectangular phylogram is... + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, + unrooted rectangular phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + +--- +declare { + key = "unrooted straight phylogram", + algorithm = { + base_class = Maeusle2012, + run = function (self) + local root1, root2 = self:getRoot() + self:setPosForUnrootedStraight(root2, root1) + end + }, + phase = "phylogenetic tree layout", + + summary = [[" + A unrooted straight phylogram is... + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, + unrooted straight phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + + +--- +declare { + key = "evolutionary unit length", + type = "length", + initial = "1cm", + + summary = [[" + Specifies how long a ``unit'' of evolutionary time should be on + paper. For instance, if two nodes in a phylogenetic tree have an + evolutionary distance of 3 and this length is set to |1cm|, then + they will be |3cm| apart in a straight-line phylogram. + "]], + documentation = [[" + (This key used to be called |distance scaling factor|.) + "]], +} + + + +-- +-- Gets the edge length between two nodes +-- +-- @param vertex1, vertex2 The two nodes +-- +-- @return The length of the edge between the two nodes +function Maeusle2012:edgeLength(vertex1, vertex2) + return self.lengths[vertex1][vertex2] +end + + +-- Sets the x and y coordinates for all nodes, using a depth first +-- search +-- +-- @param vertex The starting point; should usually be the root +-- @param values Values needed for the recursion +-- @param vertex2 A node that will not be visited; this parameter should only be set +-- for an unrooted layout to ensure that only the half of the tree is set. +function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) + local arcs = self.tree.arcs + local vertices = self.tree.vertices + local adjusted_bb = self.main_algorithm.adjusted_bb + + values = values or { + length = 0, -- current path length + visited = {}, -- all nodes that have already been visited + leaves = {}, -- all leaves from left to right + } + + local vertex_is_leaf = true + values.visited[vertex] = true + + local children = {} -- a table containing all children of the + -- current vertex (for the later determination of inner vertices + -- x-positions) + + + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] and arc.head ~= vertex2 then + -- if arc.head hasn't been visited, the current vertex cannot be a leaf + vertex_is_leaf = false + local arc_length = self:edgeLength(vertex, arc.head) + + values.length = values.length + arc_length + + -- go deeper + self:setPosForRectangularLayout(arc.head, values, vertex2) + + -- get the children of the current vertex + children[#children+1] = arc.head + + values.length = values.length - arc_length + end + end + + if vertex_is_leaf then + -- subtract layer_pre, thus the leaf itself is NOT part of the + -- edge length + vertex.pos.y = - adjusted_bb[vertex].layer_pre + + values.leaves[#values.leaves+1] = vertex + + -- x coordinate: + -- the x coordinates of the leaves are the first to be set; the + -- first leave stays at x = 0, the x coordinates for the other + -- leaves is computed with help of the ideal_sibling_distance + -- function + if #values.leaves > 1 then + local left_sibling = values.leaves[#values.leaves-1] + local ideal_distance = layered.ideal_sibling_distance(adjusted_bb, self.tree, vertex, left_sibling ) + vertex.pos.x = left_sibling.pos.x + ideal_distance + end + + else -- the vertex is an inner node + -- the x position of an inner vertex is at the center of its children. + + -- determine the outer children + local left_child = children[1] + local right_child = left_child + for _, child in ipairs(children) do + if child.pos.x < left_child.pos.x then left_child = child end + if child.pos.x > right_child.pos.x then right_child = child end + end + + -- position between child with highest and child with lowest x-value, + -- if number of children is even + local index_of_middle_child = math.ceil(#children/2) + local even = #children/2 == index_of_middle_child + + if even then + vertex.pos.x = (left_child.pos.x + right_child.pos.x) / 2 + index_of_middle_child = 0 + else -- if number of children is odd, position above the middle child + vertex.pos.x = children[index_of_middle_child].pos.x + table.remove(children, index_of_middle_child) -- don't bend the edge to this node, as it it above it anyway + end + end + + -- set the node's y-coordinate, using the calculated length + -- and a scaling factor + vertex.pos.y = vertex.pos.y + (values.length * self.tree.options['evolutionary unit length']) + + -- if this is the second subtree to be set of an unrooted tree, have + -- it grow in the other direction + if values.second_subtree then + vertex.pos.y = -vertex.pos.y + end + + -- bend the edges for the rectangular layout + for i,child in ipairs(children) do + self:bendEdge90Degree(child, vertex) + end + + return values +end + + +-- Sets only the x-positions of all nodes using a depth-first search. +-- This is necessary for straight-edge layouts. +-- +-- @param vertex The starting point of the depth-first search; should usually be the root +-- @param values Values needed for the recursion +-- @param vertex2 A node that will not be visited; this parameter should only be set +-- for an unrooted layout to ensure that only the half of the tree is set. +function Maeusle2012:setXPos(vertex, values, vertex2) + local arcs = self.tree.arcs + local vertices = self.tree.vertices + if not values then + values = { + visited = {}, -- all nodes that have already been visited + leaves = {}, -- all leaves from left to right + } + end + + local vertex_is_leaf = true + values.visited[vertex] = true + local children = {} -- a table containing all children of the current vertex (for the later determination of inner vertices x-positions) + + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] and arc.head ~= vertex2 then + -- if arc.head hasn't been visited, the current vertex cannot be a leaf + vertex_is_leaf = false + + -- go deeper + self:setXPos(arc.head, values, vertex2) + + -- get the children of the current vertex + table.insert(children, arc.head) + end + end + + -- set the x-position of a leaf + if vertex_is_leaf then + + table.insert(values.leaves, vertex) + + if #values.leaves > 1 then + local left_sibling = values.leaves[#values.leaves-1] + local ideal_distance = layered.ideal_sibling_distance(self.main_algorithm.adjusted_bb, self.tree, vertex, left_sibling ) + vertex.pos.x = left_sibling.pos.x + ideal_distance + end + + -- set x position of an inner node, which is at the center of its + -- children + else + -- determine the outer children + local left_child = children[1] + local right_child = left_child + for _, child in ipairs(children) do + if child.pos.x < left_child.pos.x then left_child = child end + if child.pos.x > right_child.pos.x then right_child = child end + end + + -- position between child with highest and child with lowest x-value, + -- if number of children is even + local index_of_middle_child = math.ceil(#children/2) + local even = #children/2 == index_of_middle_child + + if even then + vertex.pos.x = (left_child.pos.x + right_child.pos.x) / 2 + else -- if number of children is odd, position above the middle child + vertex.pos.x = children[index_of_middle_child].pos.x + end + end + return values +end + + +-- +-- Sets only the y-positions of all nodes using a depth-first search. +-- This is needed for a straight-edge layout, as the x-positions have +-- to bet first so that the y-coordinates can be calculated correctly +-- here. +-- +-- @param vertex1 The starting point of the depth-first search +-- @param values Values needed for the recursion +-- @param vertex2 For unrooted layout only: The root of the second subtree. +-- This node and all its children will not be visited. +function Maeusle2012:setYPosForStraightLayout(vertex, values, vertex2) + local arcs = self.tree.arcs + local vertices = self.tree.vertices + local adjusted_bb = self.main_algorithm.adjusted_bb + + values = values or { + length = 0, -- current path length + visited = {}, -- all nodes that have already been visited + leaves = {}, -- all leaves from left to right + } + + local vertex_is_leaf = true + values.visited[vertex] = true + local children = {} -- a table containing all children of the current vertex (for the later determination of inner vertices x-positions) + + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] and arc.head ~= vertex2 then + -- if arc.head hasn't been visited, the current vertex cannot be a leaf + vertex_is_leaf = false + + -- calculate the arc length with the help of the Pythagorean + -- theorem + local a + local l = self:edgeLength(vertex, arc.head) * self.tree.options['evolutionary unit length'] + local b = math.abs(vertex.pos.x - arc.head.pos.x) + if b > l then + a = 0 + else + a = math.sqrt(l^2-b^2) + end + local arc_length = a + + + values.length = values.length + arc_length + + -- go deeper + self:setYPosForStraightLayout(arc.head, values, vertex2) + + -- get the children of the current vertex + table.insert(children, arc.head) + + values.length = values.length - arc_length + end + end + + if vertex_is_leaf then + -- subtract layer_pre, thus the leaf itself is NOT part of the + -- edge length + vertex.pos.y = - adjusted_bb[vertex].layer_pre + + table.insert(values.leaves, vertex) + end + + -- set the node's y-coordinate, using the calculated length + vertex.pos.y = vertex.pos.y + values.length + + -- if this is the second subtree to be set of an unrooted tree, have + -- it grow in the other direction + if values.second_subtree then vertex.pos.y = -vertex.pos.y end +end + +-- +-- Correct the x-positions in the unrooted layout for a more aesthetic result +-- +-- If the roots of the two subtrees have different x-positions, this is corrected +-- by shifting the x-positions of all nodes in one subtree by that difference. +-- +-- @param vertex1 The root of the first subtree +-- @param vertex2 The root of the second subtree. +function Maeusle2012:correctXPos(vertex1, vertex2, straight) + + -- correct the x-positions + -- + -- @param vertex Starting point of the depth-first search + -- @param values Values needed for the recursion + -- @param vertex2 The root of the subtree that will not be visited + local function x_correction(vertex, values, vertex2) + values.visited[vertex] = true + local children = {} + + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] and arc.head ~= vertex2 then + + table.insert(children, arc.head) + x_correction(arc.head, values, vertex2) + end + end + + vertex.pos.x = vertex.pos.x + values.diff + if not straight then + for i,child in ipairs(children) do + self:bendEdge90Degree(child, vertex) + end + end + + return values + end + + -- compute the difference of the x-positions of the two subtrees' + -- roots + local diff = vertex1.pos.x - vertex2.pos.x + local values = { visited = {} } + if diff < 0 then + values.diff = - diff + x_correction(vertex1, values, vertex2) + elseif diff > 0 then + values.diff = diff + x_correction(vertex2, values, vertex1) + end +end + + +-- +-- Sets the x- and y-positions of the vertices in an unrooted layout +-- +-- This is done using the function for setting the positions for a rooted layout: +-- Two neighboring vertices are chosen as roots; one half of the tree +-- is drawn in one direction, the other half 180° to the other +-- direction. +-- +-- @param vertex1, vertex2: The vertices functioning as roots +function Maeusle2012:setPosForUnrootedRectangular(vertex1, vertex2) + -- set positions for first half of the tree... + self:setPosForRectangularLayout(vertex2,false,vertex1) + local vals={ + length = self:edgeLength(vertex1, vertex2), -- the length between the two roots + visited={}, + leaves={}, + path={}, + second_subtree = true + } + -- ... and for the second half. + self:setPosForRectangularLayout(vertex1,vals,vertex2) + -- if the two roots have different x-values, correct the x-positions for nicer layout + self:correctXPos(vertex1, vertex2, false) +end + + +-- +-- Sets the x- and y-positions of the vertices in an unrooted straight layout +-- +-- This is done using the function for setting the positions for a rooted straight layout: +-- Two neighboring vertices are chosen as roots; one half of the tree +-- is drawn in one direction, the other half 180° to the other +-- direction. +-- +-- @param vertex1, vertex2: The vertices functioning as roots +function Maeusle2012:setPosForUnrootedStraight(vertex1, vertex2) + -- first set the x-positions of the two subtrees... + local vals = {visited = {}, leaves = {} } + self:setXPos(vertex2, vals, vertex1) + self:setXPos(vertex1, vals, vertex2) + + -- ... and then the y-positions + self:setYPosForStraightLayout(vertex2, false, vertex1) + local vals={ + length = self:edgeLength(vertex1, vertex2) * self.tree.options['evolutionary unit length'], + visited={}, + leaves={}, + path={}, + second_subtree = true + } + self:setYPosForStraightLayout(vertex1, vals, vertex2) + + -- if the two roots have different x-values, correct the x-positions for nicer layout + -- as the length between the roots of the two subtrees is set to the calculated value, + -- this step is mandatory for the unrooted, straight layout + self:correctXPos(vertex1, vertex2, true) +end + + + +-- Bends the arc between two nodes by 90 degree by updating the arc's +-- path +-- +-- @param head The head of the arc +-- @param tail The tail of the arc +function Maeusle2012:bendEdge90Degree(head, tail) + local arc = self.tree:arc(tail,head) + local syntactic_tail = arc:syntacticTailAndHead() + arc:setPolylinePath { Coordinate.new(head.pos.x, tail.pos.y) } +end + + + +-- Finds the longest path in a graph +-- +-- @ return A table containing the path (an array of nodes) and the +-- path length +function Maeusle2012:findLongestPath() + local starting_point = self.tree.vertices[1] -- begin at any vertex + -- get the path lengths from the starting point to all leaves: + local paths_to_leaves = self:getPathLengthsToLeaves(starting_point) + local path_lengths = paths_to_leaves.path_lengths + local paths = paths_to_leaves.paths + + -- looks for the longest path and identifies its end-point + local function find_head_of_longest_path(path_lengths, paths) + local longest_path + local node + -- to make sure that the same path is chosen every time, we go over all vertices with "ipairs"; if we would go over path_lengths directly, we could only use "pairs" + for _, vertex in ipairs(self.tree.vertices) do + local path_length = path_lengths[vertex] + if path_length then + -- choose longest path. if two paths have the same length, take the path with more nodes + if not longest_path or path_length > longest_path or (path_length == longest_path and #paths[vertex]>#paths[node]) then + longest_path = path_length + node = vertex + end + end + end + return node + end + + -- find the longest path leading away from the starting point and identify + -- the leaf it leads to. Use that leaf as the tail for the next path + -- search + local tail = find_head_of_longest_path(path_lengths, paths) + paths_to_leaves = self:getPathLengthsToLeaves(tail) -- gets new path information + -- paths_to leaves now has all paths starting at vertex "tail"; one of these paths is the + -- longest (globally) + path_lengths = paths_to_leaves.path_lengths + paths = paths_to_leaves.paths + local head = find_head_of_longest_path(path_lengths, paths) + + local path_information = + { path = paths_to_leaves.paths[head], -- longest path + length = path_lengths[head] } -- length of that path + + return path_information +end + + +-- a depth first search for getting all path lengths from a +-- starting point to all leaves +-- +-- @param vertex The vertex where the search is to start +-- @param values Table of values needed for the recursive computation +-- +-- @return A table containing: +-- a table of the leaves with corresponding path lengths +-- and a table containing the path to each leaf (an array of +-- nodes) +function Maeusle2012:getPathLengthsToLeaves(vertex, values) + local arcs = self.tree.arcs + local vertices = self.tree.vertices + if not values then + values = { + paths = {}, -- all paths we've found so far + path_lengths = {}, -- all path lengths that have so far been computed + length = 0, -- current path length + visited = {}, -- all nodes that have already been visited + path = {}, -- the current path we're on + leaves = {} -- all leaves from left to right + } + table.insert(values.path,vertex) + end + + local vertex_is_leaf = true + values.visited[vertex] = true + + for _, arc in ipairs (self.tree:outgoing(vertex)) do + if not values.visited[arc.head] then + -- the current vertex is not a leaf! note: if the starting vertex is a leaf, vertex_is_leaf + -- will be set to 'false' for it anyway. as we're not interested in the distance + -- of the starting vertex to itself, this is fine. + vertex_is_leaf = false + local arc_length = self.lengths[vertex][arc.head] + values.length = values.length + arc_length + + -- add arc.head to path... + table.insert(values.path,arc.head) + + -- ... and go down that path + self:getPathLengthsToLeaves(arc.head, values) + + -- remove arc.head again to go a different path + table.remove(values.path) + values.length = values.length - arc_length + end + end + + if vertex_is_leaf then -- we store the information gained on the path to this leaf + values.path_lengths[vertex] = values.length + values.paths[vertex] = {} + table.insert(values.leaves, vertex) + for i,k in pairs(values.path) do + values.paths[vertex][i] = k + end + end + -- the path_lengths and the paths are stored in one table and + -- returned together + local path_information = + { path_lengths = values.path_lengths, + paths = values.paths, + leaves = values.leaves } + return path_information +end + + +-- Gets the root of a tree +-- checks whether a tree is already rooted, if not, computeCenterOfPath() is +-- called, which defines a node in the center of the graph as the root +-- +-- @return The root +function Maeusle2012:getRoot() + -- check whether a root exists (vertex with degree 2) + local root = lib.find (self.tree.vertices, function(v) return #self.tree:outgoing(v) == 2 end) + if root then + return root, self.tree:outgoing(root)[1].head + else + return self:computeCenterOfPath() + end +end + + +-- +-- @return The newly computed root and its nearest neighbor +function Maeusle2012:computeCenterOfPath() + local longest_path = self:findLongestPath() + local path = longest_path.path + local root, neighbor_of_root + + local length = 0 --length between first vertex on the path and the current vertex we're looking at + for i = 1, #path-1 do + local node1 = path[i] + local node2 = path[i+1] + local node3 = path[i+2] + + local dist_node_1_2, dist_node_2_3 --distances between node1 and node2, and node2 and node3 + dist_node_1_2 = self:edgeLength(node1, node2) + if node3 then dist_node_2_3 = self:edgeLength(node2, node3) end + length = length + dist_node_1_2 -- length between first vertex on the path and current node2 + + if length == longest_path.length/2 then + root = node2 -- if there is a node exactly at the half of the path, use this node as root + + -- and find nearest neighbor of the root + if node3 == nil or dist_node_1_2 < dist_node_2_3 then -- neu 3.8 + neighbor_of_root = node1 + else + neighbor_of_root = node3 + end + break + + elseif length > longest_path.length/2 then + -- else find node closest to the center of the path and use it as the root; + local node2_length = math.abs(longest_path.length/2 - length) + local node1_length = math.abs(longest_path.length/2 - (length - dist_node_1_2)) + if node2_length < node1_length then + root = node2 + neighbor_of_root = node1 + -- if node3 is closer to node2 than node1 is, use node3 as neighbor! + if node3 and dist_node_2_3 < dist_node_1_2 then neighbor_of_root = node3 end + else + root = node1 + neighbor_of_root = node2 + --check if node i-1 is closer to node1 + local dist_node_0_1 + if i>1 then + node0 = path[i-1] + dist_node_0_1 = self:edgeLength(node0, node1) + if dist_node_0_1 < dist_node_1_2 then neighbor_of_root = node0 end + end + end + break + end + end + + return root, neighbor_of_root +end + + +return Maeusle2012 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua new file mode 100644 index 0000000000..242ccf183f --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua @@ -0,0 +1,91 @@ +-- Copyright 2013 by Sarah Mäusle and Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local PhylogeneticTree = {} + + +-- Namespace +require("pgf.gd.phylogenetics").PhylogeneticTree = PhylogeneticTree + +-- Imports +local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" +local Storage = require "pgf.gd.lib.Storage" +local Direct = require "pgf.gd.lib.Direct" + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "phylogenetic tree layout", + algorithm = PhylogeneticTree, + + postconditions = { + upward_oriented = true + }, + + summary = [[" + Layout for drawing phylogenetic trees. + "]], + documentation = [[" + ... + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, upgma, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + + +-- Computes a phylogenetic tree and/or visualizes it +-- - computes a phylogenetic tree according to what the "phylogenetic +-- algorithm" key is set to +-- - invokes a graph drawing algorithm according to what the +-- "phylogenetic layout" key is set to +function PhylogeneticTree:run() + + local options = self.digraph.options + + -- Two storages for some information computed by the phylogenetic + -- tree generation algorithm + local lengths = Storage.newTableStorage() + + -- First, compute the phylogenetic tree + local tree = options.algorithm_phases['phylogenetic tree generation'].new { + main_algorithm = self, + lengths = lengths + }:run() + + tree = Direct.ugraphFromDigraph(tree) + + -- Second, layout the tree + local layout_class = options.algorithm_phases['phylogenetic tree layout'] + layout_class.new { + main_algorithm = self, + distances = distances, + lengths = lengths, + tree = tree + }:run() + + tree:sync() +end + +return PhylogeneticTree diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua new file mode 100644 index 0000000000..6a665b6732 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua @@ -0,0 +1,261 @@ +-- Copyright 2013 by Sarah Mäusle and Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + + +local SokalMichener1958 = {} + + +-- Namespace +require("pgf.gd.phylogenetics").SokalMichener1958 = SokalMichener1958 + +-- Imports +local InterfaceToAlgorithms = require("pgf.gd.interface.InterfaceToAlgorithms") +local DistanceMatrix = require("pgf.gd.phylogenetics.DistanceMatrix") +local lib = require("pgf.gd.lib") +local Storage = require("pgf.gd.lib.Storage") +local Digraph = require("pgf.gd.model.Digraph") + +-- Shorthand: +local declare = InterfaceToAlgorithms.declare + + +--- +declare { + key = "unweighted pair group method using arithmetic averages", + algorithm = SokalMichener1958, + phase = "phylogenetic tree generation", + + summary = [[" + The UPGMA (Unweighted Pair Group Method using arithmetic + Averages) algorithm of Sokal and Michener, 1958. It generates a + graph on the basis of such a distance matrix by generating nodes + and computing the edge lengths. + "]], + documentation = [[" + This algorithm uses a distance matrix, ideally an ultrametric + one, to compute the graph. + "]], + examples = [[" + \tikz \graph [phylogenetic tree layout, sibling distance=0pt, sibling sep=2pt, + unweighted pair group method using arithmetic averages, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; + "]] +} + + +--- +declare { + key = "upgma", + use = { { key = "unweighted pair group method using arithmetic averages" } }, + summary = "An shorthand for |unweighted pair group method using arithmetic averages|" +} + + + + +-- +-- The run function of the upgma algorithm. +-- +-- You must setup the following fields: The |main_algorithm| must +-- store the main algorithm object (for phase |main|). The |distances| +-- field must be a |Storage| object that will get filled with the +-- distances computed by this algorithm. The |lengths| field must also +-- be a |Storage| for the computed distances. +-- + +function SokalMichener1958:run() + self.distances = Storage.newTableStorage() + + self.tree = Digraph.new(self.main_algorithm.digraph) + + -- store the phylogenetic tree object, containing all user-specified + -- graph information + self:runUPGMA() + self:createFinalEdges() + + return self.tree +end + + + +-- UPGMA (Unweighted Pair Group Method using arithmetic Averages) algorithm +-- (Sokal and Michener, 1958) +-- +-- this function generates a graph on the basis of such a distance +-- matrix by generating nodes and computing the edge lengths; the x- +-- and y-positions of the nodes must be set separately +-- +-- requirement: a distance matrix, ideally an ultrametric +function SokalMichener1958:runUPGMA() + local matrix = DistanceMatrix.graphDistanceMatrix(self.tree) + + local g = self.tree + local clusters = {} + + -- create the clusters + for _,v in ipairs(g.vertices) do + clusters[#clusters+1] = self:newCluster(v) + end + + -- Initialize the distances of these clusters: + for _,cx in ipairs(clusters) do + for _,cy in ipairs(clusters) do + cx.distances[cy] = matrix[cx.root][cy.root] + end + end + + -- search for clusters with smallest distance and merge them + while #clusters > 1 do + local minimum_distance = math.huge + local min_cluster1 + local min_cluster2 + for i, cluster in ipairs (clusters) do + for j = i+1,#clusters do + local cluster2 = clusters[j] + local cluster_distance = self:getClusterDistance(cluster, cluster2) + if cluster_distance < minimum_distance then + minimum_distance, min_cluster1, min_cluster2 = cluster_distance, i, j + end + end + end + self:mergeClusters(clusters, min_cluster1, min_cluster2, minimum_distance) + end +end + + +-- a new cluster is created +-- +-- @param vertex The vertex the cluster is initialized with +-- +-- @return The new cluster +function SokalMichener1958:newCluster(vertex) + return { + root = vertex, -- the root of the cluster + size = 1, -- the number of vertices in the cluster, + distances = {}, -- cached cluster distances to all other clusters + cluster_height = 0 -- this value is equivalent to half the distance of the last two clusters + -- that have been merged to form the current cluster; + -- necessary for determining the distances of newly generated nodes to their children. + } +end + + +-- gets the distance between two clusters +-- +-- @param cluster1, cluster2 The two clusters +-- +-- @return the distance between the clusters +function SokalMichener1958:getClusterDistance(c,d) + return c.distances[d] or d.distances[c] or 0 +end + + +-- merges two clusters by doing the following: +-- - deletes cluster2 from the clusters table +-- - adds all vertices from cluster2 to the vertices table of cluster1 +-- - updates the distances of the new cluster to all remaining clusters +-- - generates a new node, as the new root of the cluster +-- - computes the distance of the new node to the former roots (for +-- later computation of the y-positions) +-- - generates edges, connecting the new node to the former roots +-- - updates the cluster height +-- +-- @param clusters The array of clusters +-- @param index_of_first_cluster The index of the first cluster +-- @param index_of_second_cluster The index of the second cluster +-- @param distance The distance between the two clusters + +function SokalMichener1958:mergeClusters(clusters, index_of_first_cluster, index_of_second_cluster, distance) + + local g = self.tree + local cluster1 = clusters[index_of_first_cluster] + local cluster2 = clusters[index_of_second_cluster] + + --update cluster distances + for i,cluster in ipairs (clusters) do + if cluster ~= cluster1 and cluster ~= cluster2 then + local dist1 = self:getClusterDistance (cluster1, cluster) + local dist2 = self:getClusterDistance (cluster2, cluster) + local dist = (dist1*cluster1.size + dist2*cluster2.size)/ (cluster1.size+cluster2.size) + cluster1.distances[cluster] = dist + cluster.distances[cluster1] = dist + end + end + + -- delete cluster2 + table.remove(clusters, index_of_second_cluster) + + --add node and connect last vertex of each cluster with new node + local new_node = InterfaceToAlgorithms.createVertex( + self.main_algorithm, + { + name = "UPGMA-node ".. #self.tree.vertices+1, + generated_options = { { key = "phylogenetic inner node" } }, + } + ) + g:add{new_node} + -- the distance of the new node ( = the new root of the cluster) to its children (= the former roots) is + -- equivalent to half the distance between the two former clusters + -- minus the respective cluster height + local distance1 = distance/2-cluster1.cluster_height + self.distances[new_node][cluster1.root] = distance1 + local distance2 = distance/2-cluster2.cluster_height + self.distances[new_node][cluster2.root] = distance2 + + -- these distances are also the final edge lengths, thus: + self.lengths[new_node][cluster1.root] = distance1 + self.lengths[cluster1.root][new_node] = distance1 + + self.lengths[new_node][cluster2.root] = distance2 + self.lengths[cluster2.root][new_node] = distance2 + + g:connect(new_node, cluster1.root) + g:connect(new_node, cluster2.root) + + cluster1.root = new_node + cluster1.size = cluster1.size + cluster2.size + cluster1.cluster_height = distance/2 -- set new height of the cluster +end + + + +-- generates edges for the final graph +-- +-- throughout the process of creating the tree, arcs have been +-- disconnected and connected, without truly creating edges. this is +-- done in this function +function SokalMichener1958:createFinalEdges() + local g = self.tree + local o_arcs = {} -- copy arcs since createEdge is going to modify the arcs array... + for _,arc in ipairs(g.arcs) do + o_arcs[#o_arcs+1] = arc + end + for _,arc in ipairs(o_arcs) do + InterfaceToAlgorithms.createEdge( + self.main_algorithm, arc.tail, arc.head, + { generated_options = { + { key = "phylogenetic edge", value = tostring(self.lengths[arc.tail][arc.head]) } + }}) + end +end + + +return SokalMichener1958 diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/library.lua new file mode 100644 index 0000000000..5ab821c4a8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/phylogenetics/library.lua @@ -0,0 +1,35 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- A phylogenetic tree (or network) depicts the evolutionary history +-- of species or, more generally, so called taxa. The present library +-- includes a number of algorithms for drawing phylogenetic trees. +-- +-- @library + +local phylogenetics -- Library name + +-- Main layout: +require "pgf.gd.phylogenetics.PhylogeneticTree" + +-- Phylogenetic tree drawing: +require "pgf.gd.phylogenetics.Maeusle2012" + +-- Phylogenetic tree generation: +require "pgf.gd.phylogenetics.SokalMichener1958" +require "pgf.gd.phylogenetics.BalancedMinimumEvolution" +require "pgf.gd.phylogenetics.BalancedNearestNeighbourInterchange" +require "pgf.gd.phylogenetics.AuthorDefinedPhylogeny" + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar.lua new file mode 100644 index 0000000000..5d80de77cd --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar.lua @@ -0,0 +1,6 @@ +require "pgf" +require "pgf.gd" + +pgf.gd.planar = {} + +return pgf.gd.planar diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua new file mode 100644 index 0000000000..f587861d79 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua @@ -0,0 +1,678 @@ + +--[[ +---Data structures--- + +Vertices from the original ugraph are referred to as input vertices. +The tables that contain vertex data relevant to the algorithm +are referred to as vertices. +A vertex table may have the following keys: + +-sign +1 or -1, indicates whether this and all in the depth-first search +following vertices must be considered flipped +(i. e. adjacency lists reversed) in respect to the dfs parent + +-childlist +A linked list containing all dfs children of the vertex whose virtual roots +have not yet been merged into the vertex, sorted by lowpoint + +-adjlistlinks +A table with two fields with keys 0 and 1, containing the two half edges +of the vertex which lie on the external face of the graph +(if the vertex lies on the external face). +The half edge with key 0 lies in the 0-direction of the other half edge +and vice-versa +The two fields may hold the same half edge, if the vertex has degree one + +-pertinentroots +A linked list containing all virtual roots of this vertex that are +pertinent during the current step + +-inputvertex +The input vertex that corresponds to the vertex + +-dfi +The depth-first search index (number of the step in the dfs at which +the vertex was discovered) + +-dfsparent +The depth-first search parent (vertex from which the vertex was discovered +first in the dfs) + +-leastancestor +Dfi of the vertex with lowest dfi that can be reached using one back edge +(non-tree edge) + +-lowpoint +Dfi of the vertex with lowest dfi that can be reached using any number of +tree edges plus one back edge + + +A root vertex is a virtual vertex not contained in the original ugraph. +The root vertex represents another vertex in a biconnected component (block) +which is a child of the biconnected component the represented vertex is in. +The only field that it has in common with other vertices is the +adjacency list links array: + +-isroot +always true, indicates that this vertex is a virtual root + +-rootparent +The vertex which this root represents + +-rootchild +The only dfs child of the original vertex which is contained in the +root verticis biconnected component + +-adjlistlinks +See adjlistlinks of a normal vertex + + +A half edge is a table with the following fields: + +-links +A table with two fields with keys 0 and 1, containing the neighboring +half edges in the adjacency list of the vertex these edges originate from. + +-target +The vertex the half edge leads to + +-twin +The twin half edge which connects the two vertices in the opposite direction + +-shortcircuit +True if the half edge was inserted in order to make a short circuit for the +algorithm. The edge will be removed at the end. + +The BoyerMyrvold2004 class has the following fields: + +-inputgraph +The original ugraph given to the algorithm + +-numvertices +The number of vertices of the graph + +-vertices +The vertex table with depth-first search indices as keys + +-verticesbyinputvertex +The vertex table with input vertices as keys + +-verticesbylowpoint +The vertex table with low points as keys + +-shortcircuitedges +An array of all short circuit half edges +(which may not be in the original graph and will be removed at the end) + +--]] + +local BM = {} +require("pgf.gd.planar").BoyerMyrvold2004 = BM + +-- imports +local Storage = require "pgf.gd.lib.Storage" +local LinkedList = require "pgf.gd.planar.LinkedList" +local Embedding = require "pgf.gd.planar.Embedding" + +-- create class properties +BM.__index = BM + +function BM.new() + local t = {} + setmetatable(t, BM) + return t +end + +-- initializes some data structures at the beginning +-- takes the ugraph of the layout algorithm as input +function BM:init(g) + self.inputgraph = g + self.numvertices = #g.vertices + self.vertices = {} + self.verticesbyinputvertex = Storage.new() + self.verticesbylowpoint = Storage.newTableStorage() + self.shortcircuitedges = {} + for _, inputvertex in ipairs(self.inputgraph.vertices) do + local vertex = { + sign = 1, + childlist = LinkedList.new(), + adjlistlinks = {}, + pertinentroots = LinkedList.new(), + inputvertex = inputvertex, + } + setmetatable(vertex, Embedding.vertexmetatable) + self.verticesbyinputvertex[inputvertex] = vertex + end +end + +--[[ +local function nilmax(a, b) + if a == nil then return b end + if b == nil then return a end + return math.max(a, b) +end + +local function nilmin(a, b) + if a == nil then return b end + if b == nil then return a end + return math.min(a, b) +end +--]] + +-- the depth-first search of the preprocessing +function BM:predfs(inputvertex, parent) + local dfi = #self.vertices + 1 + local vertex = self.verticesbyinputvertex[inputvertex] + self.vertices[dfi] = vertex + -- set the dfs infos in the vertex + vertex.dfi = dfi + vertex.dfsparent = parent + vertex.leastancestor = dfi + vertex.lowpoint = dfi + -- find neighbors + for _, arc in ipairs(self.inputgraph:outgoing(inputvertex)) do + local ninputvertex = arc.head + assert(ninputvertex ~= inputvertex, "Self-loop detected!") + local nvertex = self.verticesbyinputvertex[ninputvertex] + if nvertex.dfi == nil then + -- new vertex discovered + self:predfs(ninputvertex, vertex) -- recursive call + vertex.lowpoint = math.min(vertex.lowpoint, nvertex.lowpoint) + elseif parent and ninputvertex ~= parent.inputvertex then + -- back edge found + vertex.leastancestor = math.min(vertex.leastancestor, nvertex.dfi) + vertex.lowpoint = math.min(vertex.lowpoint, nvertex.dfi) + end + end + -- put vertex into lowpoint sort bucket + table.insert(self.verticesbylowpoint[vertex.lowpoint], vertex) +end + +-- the preprocessing at the beginning of the algorithm +-- does the depth-first search and the bucket sort for the child lists +function BM:preprocess() + -- make dfs starting at an arbitrary vertex + self:predfs(self.inputgraph.vertices[1]) + -- create separated child lists with bucket sort + for i = 1, self.numvertices do + for _, vertex in ipairs(self.verticesbylowpoint[i]) do + if vertex.dfsparent then + vertex.childlistelement + = vertex.dfsparent.childlist:addback(vertex) + end + end + end +end + +-- adds tree edges and the corresponding virtual root vertices +-- of the currentvertex +function BM:add_trivial_edges(vertex) + -- find all dfs children + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfsparent == vertex then + -- create root vertex + local rootvertex = { + isroot = true, + rootparent = vertex, + rootchild = nvertex, + adjlistlinks = {}, + name = tostring(vertex) .. "^" .. tostring(nvertex) + } + setmetatable(rootvertex, Embedding.vertexmetatable) + nvertex.parentroot = rootvertex + -- create half edges + local halfedge1 = {target = nvertex, links = {}} + local halfedge2 = {target = rootvertex, links = {}} + halfedge1.twin = halfedge2 + halfedge2.twin = halfedge1 + -- create circular adjacency lists + halfedge1.links[0] = halfedge1 + halfedge1.links[1] = halfedge1 + halfedge2.links[0] = halfedge2 + halfedge2.links[1] = halfedge2 + -- create links to adjacency lists + rootvertex.adjlistlinks[0] = halfedge1 + rootvertex.adjlistlinks[1] = halfedge1 + nvertex.adjlistlinks[0] = halfedge2 + nvertex.adjlistlinks[1] = halfedge2 + end + end +end + +-- for the external face vertex which was entered through link vin +-- returns the successor on the external face and the link through +-- which it was entered +local function get_successor_on_external_face(vertex, vin) + local halfedge = vertex.adjlistlinks[1 - vin] + local svertex = halfedge.target + local sin + if vertex.adjlistlinks[0] == vertex.adjlistlinks[1] then + sin = vin + elseif svertex.adjlistlinks[0].twin == halfedge then + sin = 0 + else + sin = 1 + end + return svertex, sin +end + +-- the "walkup", used to identify the pertinent subgraph, +-- i. e. the subgraph that contains end points of backedges +-- for one backedge this function will mark all virtual roots +-- as pertinent that lie on the path between the backedge and the current vertex +-- backvertex: a vertex that is an endpoint of a backedge to the current vertex +-- currentvertex: the vertex of the current step +-- returns a root vertex of the current step, if one was found +local function walkup(backvertex, currentvertex) + local currentindex = currentvertex.dfi + -- set the backedgeflag + backvertex.backedgeindex = currentindex + -- initialize traversal variables for both directions + local x, xin, y, yin = backvertex, 1, backvertex, 0 + while x ~= currentvertex do + if x.visited == currentindex or y.visited == currentindex then + -- we found a path that already has the pertinent roots marked + return nil + end + -- mark vertices as visited for later calls + x.visited = currentindex + y.visited = currentindex + + -- check for rootvertex + local rootvertex + if x.isroot then + rootvertex = x + elseif y.isroot then + rootvertex = y + end + if rootvertex then + local rootchild = rootvertex.rootchild + local rootparent = rootvertex.rootparent + if rootvertex.rootparent == currentvertex then + -- we found the other end of the back edge + return rootvertex + elseif rootchild.lowpoint < currentindex then + -- the block we just traversed is externally active + rootvertex.pertinentrootselement + = rootparent.pertinentroots:addback(rootvertex) + else + -- the block we just traversed is internally active + rootvertex.pertinentrootselement + = rootparent.pertinentroots:addfront(rootvertex) + end + -- jump to parent block + x, xin, y, yin = rootvertex.rootparent, 1, rootvertex.rootparent, 0 + else + -- just continue on the external face + x, xin = get_successor_on_external_face(x, xin) + y, yin = get_successor_on_external_face(y, yin) + end + end +end + +-- inverts the adjacency of a vertex +-- i. e. reverses the order of the adjacency list and flips the links +local function invert_adjacency(vertex) + -- reverse the list + for halfedge in Embedding.adjacency_iterator(vertex.adjlistlinks[0]) do + halfedge.links[0], halfedge.links[1] + = halfedge.links[1], halfedge.links[0] + end + -- flip links + vertex.adjlistlinks[0], vertex.adjlistlinks[1] + = vertex.adjlistlinks[1], vertex.adjlistlinks[0] +end + +-- merges two blocks by merging the virtual root of the child block +-- into it's parent, while making sure the external face stays consistent +-- by flipping the root block if needed +-- mergeinfo contains four fields: +-- root - the virtual root vertex +-- parent - it's parent +-- rout - the link of the root through which we have exited it +-- during the walkdown +-- pin - the link of the parent through which we have entered it +-- during the walkdown +local function mergeblocks(mergeinfo) + local root = mergeinfo.root + local parent = mergeinfo.parent + local rout = mergeinfo.rootout + local pin = mergeinfo.parentin + if pin == rout then + -- flip required + invert_adjacency(root) + root.rootchild.sign = -1 + --rout = 1 - rout -- not needed + end + + -- redirect edges of the root vertex + for halfedge in Embedding.adjacency_iterator(root.adjlistlinks[0]) do + halfedge.twin.target = parent + end + + -- remove block from data structures + root.rootchild.parentroot = nil + parent.pertinentroots:remove(root.pertinentrootselement) + parent.childlist:remove(root.rootchild.childlistelement) + + -- merge adjacency lists + parent.adjlistlinks[0].links[1] = root.adjlistlinks[1] + parent.adjlistlinks[1].links[0] = root.adjlistlinks[0] + root.adjlistlinks[0].links[1] = parent.adjlistlinks[1] + root.adjlistlinks[1].links[0] = parent.adjlistlinks[0] + parent.adjlistlinks[pin] = root.adjlistlinks[pin] +end + +-- inserts a half edge pointing to "to" into the adjacency list of "from", +-- replacing the link "linkindex" +local function insert_half_edge(from, linkindex, to) + local halfedge = {target = to, links = {}} + halfedge.links[ linkindex] = from.adjlistlinks[ linkindex] + halfedge.links[1 - linkindex] = from.adjlistlinks[1 - linkindex] + from.adjlistlinks[ linkindex].links[1 - linkindex] = halfedge + from.adjlistlinks[1 - linkindex].links[ linkindex] = halfedge + from.adjlistlinks[linkindex] = halfedge + return halfedge +end + +-- connect the vertices x and y through the links xout and yin +-- if shortcircuit is true, the edge will be marked as a short circuit edge +-- and removed at the end of the algorithm +function BM:embed_edge(x, xout, y, yin, shortcircuit) + -- create half edges + local halfedgex = insert_half_edge(x, xout, y) + local halfedgey = insert_half_edge(y, yin, x) + halfedgex.twin = halfedgey + halfedgey.twin = halfedgex + -- short circuit handling + if shortcircuit then + halfedgex.shortcircuit = true + halfedgey.shortcircuit = true + table.insert(self.shortcircuitedges, halfedgex) + table.insert(self.shortcircuitedges, halfedgey) + end +end + +-- returns true if the given vertex is pertinent at the current step +local function pertinent(vertex, currentindex) + return vertex.backedgeindex == currentindex + or not vertex.pertinentroots:empty() +end + +-- returns true if the given vertex is externally active at the current step +local function externally_active(vertex, currentindex) + return vertex.leastancestor < currentindex + or (not vertex.childlist:empty() + and vertex.childlist:first().lowpoint < currentindex) +end + +-- the "walkdown", which merges the pertinent subgraph and embeds +-- back and short circuit edges +-- childrootvertex - a root vertex of the current vertex +-- which the walkdown will start at +-- currentvertex - the vertex of the current step +function BM:walkdown(childrootvertex, currentvertex) + local currentindex = currentvertex.dfi + local mergestack = {} + local numinsertededges = 0 -- to return the number for count check + -- two walkdowns into both directions + for vout = 0,1 do + -- initialize the traversal variables + local w, win = get_successor_on_external_face(childrootvertex, 1 - vout) + while w ~= childrootvertex do + if w.backedgeindex == currentindex then + -- we found a backedge endpoint + -- merge all pertinent roots we found + while #mergestack > 0 do + mergeblocks(table.remove(mergestack)) + end + -- embed the back edge + self:embed_edge(childrootvertex, vout, w, win) + numinsertededges = numinsertededges + 1 + w.backedgeindex = 0 -- this shouldn't be necessary + end + if not w.pertinentroots:empty() then + -- we found a pertinent vertex with child blocks + -- create merge info for the later merge + local mergeinfo = {} + mergeinfo.parent = w + mergeinfo.parentin = win + local rootvertex = w.pertinentroots:first() + mergeinfo.root = rootvertex + -- check both directions for active vertices + local x, xin = get_successor_on_external_face(rootvertex, 1) + local y, yin = get_successor_on_external_face(rootvertex, 0) + local xpertinent = pertinent(x, currentindex) + local xexternallyactive = externally_active(x, currentindex) + local ypertinent = pertinent(y, currentindex) + local yexternallyactive = externally_active(y, currentindex) + -- chose the direction with the best vertex + if xpertinent and not xexternallyactive then + w, win = x, xin + mergeinfo.rootout = 0 + elseif ypertinent and not yexternallyactive then + w, win = y, yin + mergeinfo.rootout = 1 + elseif xpertinent then + w, win = x, xin + mergeinfo.rootout = 0 + else + w, win = y, yin + mergeinfo.rootout = 1 + end + -- this is what the paper says, but it might cause problems + -- not sure though... + --[[if w == x then + mergeinfo.rootout = 0 + else + mergeinfo.rootout = 1 + end--]] + table.insert(mergestack, mergeinfo) + elseif not pertinent(w, currentindex) + and not externally_active(w, currentindex) then + -- nothing to see here, just continue on the external face + w, win = get_successor_on_external_face(w, win) + else + -- this is a stopping vertex, walkdown will end here + -- paper puts this into the if, + -- but this should always be the case, i think + assert(childrootvertex.rootchild.lowpoint < currentindex) + if #mergestack == 0 then + -- we're in the block we started at, so we embed a back edge + self:embed_edge(childrootvertex, vout, w, win, true) + end + break + end + end + if #mergestack > 0 then + -- this means, there is a pertinent vertex blocked by stop vertices, + -- so the graph is not planar and we can skip the second walkdown + break + end + end + return numinsertededges +end + +-- embeds the back edges for the current vertex +-- walkup and walkdown are called from here +-- returns true, if all back edges could be embedded +function BM:add_back_edges(vertex) + local pertinentroots = {} -- not in the paper + local numbackedges = 0 + -- find all back edges to vertices with lower dfi + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfi > vertex.dfi + and nvertex.dfsparent ~= vertex + and nvertex ~= vertex.dfsparent then + numbackedges = numbackedges + 1 + -- do the walkup + local rootvertex = walkup(nvertex, vertex) + if rootvertex then + -- remember the root vertex the walkup found, so we don't + -- have to call the walkdown for all root vertices + -- (or even know what the root vertices are) + table.insert(pertinentroots, rootvertex) + end + end + end + -- for all root vertices the walkup found + local insertededges = 0 + while #pertinentroots > 0 do + -- do the walkdown + insertededges = insertededges + + self:walkdown(table.remove(pertinentroots), vertex) + end + if insertededges ~= numbackedges then + -- not all back edges could be embedded -> graph is not planar + return false + end + return true +end + +-- the depth-first search of the postprocessing +-- flips the blocks according to the sign field +function BM:postdfs(vertex, sign) + sign = sign or 1 + local root = vertex.parentroot + if root then + sign = 1 + else + sign = sign * vertex.sign + end + + if sign == -1 then + -- number of flips is odd, so we need to flip here + invert_adjacency(vertex) + end + + -- for all dfs children + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfsparent == vertex then + -- recursive call + self:postdfs(nvertex, sign) + end + end +end + +-- the postprocessing at the end of the algorithm +-- calls the post depth-first search, +-- removes the short circuit edges from the adjacency lists, +-- adjusts the links of the vertices, +-- merges root vertices +-- and cleans up the vertices +function BM:postprocess() + -- flip components + self:postdfs(self.vertices[1]) + + -- unlink the short circuit edges + for _, halfedge in ipairs(self.shortcircuitedges) do + halfedge.links[0].links[1] = halfedge.links[1] + halfedge.links[1].links[0] = halfedge.links[0] + end + + -- vertex loop + local rootvertices = {} + local edgetoface = {} + for _, vertex in ipairs(self.vertices) do + -- check for root vertex and save it + local root = vertex.parentroot + if root then + table.insert(rootvertices, root) + end + + -- clean up links and create adjacency matrix + local link = vertex.adjlistlinks[0] + local adjmat = {} + vertex.adjmat = adjmat + if link then + -- make sure the link points to a half edge + -- that is no short circuit edge + while link.shortcircuit do + link = link.links[0] + end + -- create link + vertex.link = link + + -- create adjacency matrix + for halfedge in Embedding.adjacency_iterator(link) do + setmetatable(halfedge, Embedding.halfedgemetatable) + local target = halfedge.target + if target.isroot then + target = target.rootparent + end + adjmat[target] = halfedge + end + end + + -- clean up vertex + vertex.sign = nil + vertex.childlist = nil + vertex.adjlistlinks = nil + vertex.pertinentroots = nil + vertex.dfi = nil + vertex.dfsparent = nil + vertex.leastancestor = nil + vertex.lowpoint = nil + vertex.parentroot = nil + end + + -- root vertex loop + for _, root in ipairs(rootvertices) do + -- make sure the links point to a half edges + -- that are no short circuit edge + local link = root.adjlistlinks[0] + while link.shortcircuit do + link = link.links[0] + end + + -- merge into parent + local rootparent = root.rootparent + local parentlink = rootparent.link + local adjmat = rootparent.adjmat + for halfedge in Embedding.adjacency_iterator(link) do + setmetatable(halfedge, Embedding.halfedgemetatable) + halfedge.twin.target = rootparent + adjmat[halfedge.target] = halfedge + end + if parentlink == nil then + assert(rootparent.link == nil) + rootparent.link = link + else + -- merge adjacency lists + parentlink.links[0].links[1] = link + link.links[0].links[1] = parentlink + local tmp = link.links[0] + link.links[0] = parentlink.links[0] + parentlink.links[0] = tmp + end + end +end + +-- the entry point of the algorithm +-- returns the array of vertices +-- the vertices now only contain the inputvertex field +-- and a field named "link" which contains an arbitrary half edge +-- from the respective adjacency list +-- the adjacency lists are in a circular order in respect to the plane graph +function BM:run() + self:preprocess() + -- main loop over all vertices from lowest dfi to highest + for i = self.numvertices, 1, -1 do + local vertex = self.vertices[i] + self:add_trivial_edges(vertex) + if not self:add_back_edges(vertex) then + -- graph not planar + return nil + end + end + self:postprocess() + local embedding = Embedding.new() + embedding.vertices = self.vertices + return embedding +end + +return BM diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/Embedding.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/Embedding.lua new file mode 100644 index 0000000000..8d9d3b53b1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/Embedding.lua @@ -0,0 +1,788 @@ +local E = {} + +require("pgf.gd.planar").Embedding = E + +-- includes +local LinkedList = require("pgf.gd.planar.LinkedList") + +E.vertexmetatable = { + __tostring = function(v) + if v.name then + return v.name + elseif v.inputvertex then + return v.inputvertex.name + else + return tostring(v) + end + end +} + +E.halfedgemetatable = { + __tostring = function(e) + return tostring(e.twin.target) + .. " -> " + .. tostring(e.target) + end +} + +-- create class properties +E.__index = E + +function E.new() + local t = { + vertices = {}, + } + setmetatable(t, E) + return t +end + +function E:add_vertex(name, inputvertex, virtual) + virtual = virtual or nil + local vertex = { + adjmat = {}, + name = name, + inputvertex = inputvertex, + virtual = virtual, + } + setmetatable(vertex, E.vertexmetatable) + table.insert(self.vertices, vertex) + return vertex +end + +function E:add_edge(v1, v2, after1, after2, virtual) + assert(v1.link == nil or v1 == after1.twin.target) + assert(v2.link == nil or v2 == after2.twin.target) + assert(v1.adjmat[v2] == nil) + assert(v2.adjmat[v1] == nil) + + virtual = virtual or nil + + local halfedge1 = { + target = v2, + virtual = virtual, + links = {}, + } + local halfedge2 = { + target = v1, + virtual = virtual, + links = {}, + } + halfedge1.twin = halfedge2 + halfedge2.twin = halfedge1 + + setmetatable(halfedge1, E.halfedgemetatable) + setmetatable(halfedge2, E.halfedgemetatable) + + if v1.link == nil then + v1.link = halfedge1 + halfedge1.links[0] = halfedge1 + halfedge1.links[1] = halfedge1 + else + halfedge1.links[0] = after1.links[0] + after1.links[0].links[1] = halfedge1 + halfedge1.links[1] = after1 + after1.links[0] = halfedge1 + end + + if v2.link == nil then + v2.link = halfedge2 + halfedge2.links[0] = halfedge2 + halfedge2.links[1] = halfedge2 + else + halfedge2.links[0] = after2.links[0] + after2.links[0].links[1] = halfedge2 + halfedge2.links[1] = after2 + after2.links[0] = halfedge2 + end + + v1.adjmat[v2] = halfedge1 + v2.adjmat[v1] = halfedge2 + + return halfedge1, halfedge2 +end + +function E:remove_virtual() + local virtuals = {} + for i, v in ipairs(self.vertices) do + if v.virtual then + table.insert(virtuals, i) + else + local start = v.link + local current = start + repeat + current = current.links[0] + if current.virtual then + current.links[0].links[1] = current.links[1] + current.links[1].links[0] = current.links[0] + v.adjmat[current.target] = nil + current.target.adjmat[v] = nil + end + until current == start + end + end + for i = #virtuals, 1, -1 do + self.vertices[virtuals[i]] = self.vertices[#self.vertices] + table.remove(self.vertices) + end +end + +-- for the use in for-loops +-- iterates over the adjacency list of a vertex +-- given a half edge to start and a direction (0 or 1, default 0) +function E.adjacency_iterator(halfedge, direction) + direction = direction or 0 + local function next_edge(startedge, prevedge) + if prevedge == nil then + return startedge + else + local nextedge = prevedge.links[direction] + if nextedge ~= startedge then + return nextedge + else + return nil + end + end + end + return next_edge, halfedge, nil +end + +function E.face_iterator(halfedge, direction) + direction = direction or 0 + local function next_edge(startedge, prevedge) + if prevedge == nil then + return startedge + else + local nextedge = prevedge.twin.links[1 - direction] + if nextedge ~= startedge then + return nextedge + else + return nil + end + end + end + return next_edge, halfedge, nil +end + +function E:triangulate() + local visited = {} + for _, vertex in ipairs(self.vertices) do + for start in E.adjacency_iterator(vertex.link) do + if not visited[start] then + local prev = start + local beforestart = start.links[0].twin + local current = start.twin.links[1] + local next = current.twin.links[1] + visited[start] = true + visited[current] = true + visited[next] = true + while next ~= beforestart do + local halfedge1, halfedge2 + if vertex ~= current.target + and not vertex.adjmat[current.target] then + halfedge1, halfedge2 = self:add_edge( + vertex, current.target, + prev, next, + true + ) + + prev = halfedge1 + current = next + next = next.twin.links[1] + elseif not prev.target.adjmat[next.target] then + halfedge1, halfedge2 = self:add_edge( + prev.target, next.target, + current, next.twin.links[1], + true + ) + + current = halfedge1 + next = halfedge2.links[1] + else + local helper = next.twin.links[1] + halfedge1, halfedge2 = self:add_edge( + current.target, helper.target, + next, helper.twin.links[1], + true + ) + + next = halfedge1 + end + + visited[next] = true + visited[halfedge1] = true + visited[halfedge2] = true + end + end + end + end +end + +function E:canonical_order(v1, v2, vn) + local n = #self.vertices + local order = { v1 } + local marks = { [v1] = "ordered", [v2] = 0 } + local visited = {} + local vk = v1 + local candidates = LinkedList.new() + local listelements = {} + for k = 1, n-2 do + for halfedge in E.adjacency_iterator(vk.link) do + local vertex = halfedge.target + if vertex ~= vn then + local twin = halfedge.twin + visited[twin] = true + if marks[vertex] == nil then + marks[vertex] = "visited" + elseif marks[vertex] ~= "ordered" then + local neighbor1 = visited[twin.links[0]] + local neighbor2 = visited[twin.links[1]] + if marks[vertex] == "visited" then + if neighbor1 or neighbor2 then + marks[vertex] = 1 + listelements[vertex] = candidates:addback(vertex) + else + marks[vertex] = 2 + end + else + if neighbor1 == neighbor2 then + if neighbor1 and neighbor2 then + marks[vertex] = marks[vertex] - 1 + else + marks[vertex] = marks[vertex] + 1 + end + if marks[vertex] == 1 then + listelements[vertex] + = candidates:addback(vertex) + elseif listelements[vertex] then + candidates:remove(listelements[vertex]) + listelements[vertex] = nil + end + end + end + end + end + end + vk = candidates:popfirst() + order[k+1] = vk + marks[vk] = "ordered" + end + order[n] = vn + return order +end + +function E:get_biggest_face() + local number = 0 + local edge + local visited = {} + for _, vertex in ipairs(self.vertices) do + for start in E.adjacency_iterator(vertex.link) do + local count = 0 + if not visited[start] then + visited[start] = true + local current = start + repeat + count = count + 1 + current = current.twin.links[1] + until current == start + if count > number then + number = count + edge = start + end + end + end + end + return edge, number +end + +function E:surround_by_triangle(faceedge, facesize) + local divisor = 3 + if facesize > 3 then + divisor = 4 + end + local basenodes = math.floor(facesize / divisor) + local extranodes = facesize % divisor + local attachnodes = { basenodes, basenodes, basenodes } + if facesize > 3 then + attachnodes[2] = basenodes * 2 + end + for i = 1,extranodes do + attachnodes[i] = attachnodes[i] + 1 + end + + local v = { + self:add_vertex("$v_1$", nil, true), + self:add_vertex("$v_n$", nil, true), + self:add_vertex("$v_2$", nil, true) + } + for i = 1,3 do + local currentv = v[i] + local nextv = v[i % 3 + 1] + self:add_edge(currentv, nextv, currentv.link, nextv.link, true) + end + + local current = faceedge + local next = current.twin.links[1] + for i = 1,3 do + local vertex = v[i] + local otheredge = vertex.adjmat[v[i % 3 + 1]] + local previnserted = otheredge.links[1] + for count = 1, attachnodes[i] do + if not vertex.adjmat[current.target] then + previnserted, _ = self:add_edge( + vertex, current.target, + previnserted, next, + true + ) + end + + current = next + next = next.twin.links[1] + end + if not vertex.adjmat[current.target] then + previnserted, _ = self:add_edge( + vertex, current.target, + previnserted, next, + true + ) + current = previnserted + end + end + return v[1], v[3], v[2] +end + +function E:improve() + local pairdata = {} + local inpair = {} + for i, v1 in ipairs(self.vertices) do + for j = i + 1, #self.vertices do + local v2 = self.vertices[j] + local pd = self:find_pair_components(v1, v2) + if pd then + inpair[v1] = true + inpair[v2] = true + table.insert(pairdata, pd) + end + end + if not inpair[v1] then + local pd = self:find_pair_components(v1, nil) + if pd then + inpair[v1] = true + table.insert(pairdata, pd) + end + end + end + + local changed + local runs = 1 + local edgepositions = {} + repeat + changed = false + for i, pd in ipairs(pairdata) do + self:improve_separation_pair(pd) + end + -- check for changes + for i, v in ipairs(self.vertices) do + local start = v.link + local current = start + local counter = 1 + repeat + if counter ~= edgepositions[current] then + changed = true + edgepositions[current] = counter + end + counter = counter + 1 + current = current.links[0] + until current == start + end + runs = runs + 1 + until changed == false or runs > 100 +end + +function E:find_pair_components(v1, v2) + local visited = {} + local companchors = {} + local edgecomps = {} + local compvertices = {} + local islinear = {} + local edgeindices = {} + + local pair = { v1, v2 } + local start = v1.link + local current = start + local edgeindex = 1 + -- start searches from v1 + repeat + edgeindices[current] = edgeindex + edgeindex = edgeindex + 1 + if not edgecomps[current] then + local compindex = #companchors + 1 + local ca, il + edgecomps[current] = compindex + compvertices[compindex] = {} + local target = current.target + if target == v2 then + edgecomps[current.twin] = compindex + ca = 3 + il = true + else + ca, il = self:component_dfs( + target, + pair, + visited, + edgecomps, + compvertices[compindex], + compindex + ) + end + companchors[compindex] = ca + islinear[compindex] = il + end + current = current.links[0] + until current == start + + if v2 then + start = v2.link + current = start + local lastincomp = true + local edgeindex = 1 + -- now find the remaining blocks at v2 + repeat + edgeindices[current] = edgeindex + edgeindex = edgeindex + 1 + if not edgecomps[current] then + local compindex = #companchors + 1 + edgecomps[current] = compindex + compvertices[compindex] = {} + self:component_dfs( + current.target, + pair, + visited, + edgecomps, + compvertices[compindex], + compindex + ) + companchors[compindex] = 2 + end + current = current.links[0] + until current == start + end + + -- init compedges, tricomps, twocomps + local tricomps = {} + local twocomps = {{}, {}} + for i, anchors in ipairs(companchors) do + if anchors == 3 then + table.insert(tricomps, i) + else + table.insert(twocomps[anchors], i) + end + end + + local flipimmune = #tricomps == 2 + and (islinear[tricomps[1]] or islinear[tricomps[2]]) + if (#tricomps < 2 or flipimmune) + and (v2 ~= nil or #twocomps[1] < 2) then + return nil + end + + -- order tri comps cyclic + local function sorter(a, b) + return #compvertices[a] < #compvertices[b] + end + + table.sort(tricomps, sorter) + + -- determine order of comps + local numtricomps = #tricomps + local comporder = { {}, {} } + local bottom = math.ceil(numtricomps / 2) + local top = bottom + 1 + for i, comp in ipairs(tricomps) do + if i % 2 == 1 then + comporder[1][bottom] = comp + comporder[2][numtricomps - bottom + 1] = comp + bottom = bottom - 1 + else + comporder[1][top] = comp + comporder[2][numtricomps - top + 1] = comp + top = top + 1 + end + end + + local pairdata = { + pair = pair, + companchors = companchors, + edgecomps = edgecomps, + edgeindices = edgeindices, + compvertices = compvertices, + tricomps = tricomps, + twocomps = twocomps, + comporder = comporder, + } + return pairdata +end + +function E:component_dfs(v, pair, visited, edgecomps, compvertices, compindex) + visited[v] = true + local start = v.link + local current = start + local companchors = 1 + local numedges = 0 + local islinear = true + table.insert(compvertices, v) + repeat + numedges = numedges + 1 + local target = current.target + if target == pair[1] or target == pair[2] then + edgecomps[current.twin] = compindex + if target == pair[2] then + companchors = 3 + end + elseif not visited[target] then + local ca, il = self:component_dfs( + target, + pair, + visited, + edgecomps, + compvertices, + compindex + ) + if ca == 3 then + companchors = 3 + end + islinear = islinear and il + end + current = current.links[0] + until current == start + return companchors, islinear and numedges == 2 +end + +function E:improve_separation_pair(pairdata) + local pair = pairdata.pair + local companchors = pairdata.companchors + local edgecomps = pairdata.edgecomps + local edgeindices = pairdata.edgeindices + local compvertices = pairdata.compvertices + local tricomps = pairdata.tricomps + local twocomps = pairdata.twocomps + local comporder = pairdata.comporder + local v1 = pair[1] + local v2 = pair[2] + + local compedges = {} + for i = 1, #companchors do + compedges[i] = {{}, {}} + end + + local numtricomps = #tricomps + local numtwocomps = { #twocomps[1], #twocomps[2] } + + -- find compedges + for i = 1, #pair do + -- first find an edge that is the first of a triconnected component + local start2 + if v2 then + start = pair[i].link + current = start + local last + repeat + local comp = edgecomps[current] + if companchors[comp] == 3 then + if last == nil then + last = comp + elseif last ~= comp then + start2 = current + break + end + end + current = current.links[0] + until current == start + else + start2 = pair[i].link + end + -- now list the edges by components + current = start2 + repeat + table.insert(compedges[edgecomps[current]][i], current) + current = current.links[0] + until current == start2 + end + + -- count edges on each side of tri comps + local edgecount = {} + for _, comp in ipairs(tricomps) do + edgecount[comp] = {} + for i = 1, #pair do + local count = 1 + local current = compedges[comp][i][1] + local other = pair[3 - i] + while current.target ~= other do + count = count + 1 + current = current.twin.links[0] + end + edgecount[comp][i] = count + end + end + + -- determine which comps have to be flipped + local flips = {} + local numflips = 0 + local allflipped = true + for i, comp in ipairs(comporder[1]) do + local side1, side2 + if i > numtricomps / 2 then + side1 = edgecount[comp][1] + side2 = edgecount[comp][2] + else + side1 = edgecount[comp][2] + side2 = edgecount[comp][1] + end + if side1 > side2 then + numflips = numflips + 1 + flips[comp] = true + elseif side1 < side2 then + allflipped = false + end + end + + if allflipped then + for i, comp in ipairs(tricomps) do + flips[comp] = false + end + else + for i, comp in ipairs(tricomps) do + if flips[comp] then + for _, v in ipairs(compvertices[comp]) do + local start = v.link + local current = start + repeat + current.links[0], current.links[1] + = current.links[1], current.links[0] + current = current.links[1] + until current == start + end + end + end + end + + -- order edges cyclic per component (one cycle for all tri comps) + for i = 1, #pair do + if v2 then + local co + if allflipped then + co = comporder[3 - i] + else + co = comporder[i] + end + + local id = co[numtricomps] + lastedges = compedges[id][i] + if flips[id] then + lastedge = lastedges[1] + else + lastedge = lastedges[#lastedges] + end + + -- tri comps + for _, id in ipairs(co) do + local edges = compedges[id][i] + local from + local to + local step + if flips[id] then + from = #edges + to = 1 + step = -1 + else + from = 1 + to = #edges + step = 1 + end + for k = from, to, step do + local edge = edges[k] + lastedge.links[0] = edge + edge.links[1] = lastedge + lastedge = edge + end + end + end + + -- two comps + for _, id in ipairs(twocomps[i]) do + lastedges = compedges[id][i] + lastedge = lastedges[#lastedges] + for _, edge in ipairs(compedges[id][i]) do + lastedge.links[0] = edge + edge.links[1] = lastedge + lastedge = edge + end + end + end + + -- now merge the cycles + for i = 1, #pair do + local outeredges = {} + -- find the biggest face of the tri comps + if v2 then + local biggestedge + local biggestsize + local biggestindex + local start = compedges[tricomps[1]][i][1] + local current = start + repeat + local size = self:get_face_size(current) + if not biggestedge or size > biggestsize + or (size == biggestsize + and edgeindices[current] > biggestindex) then + biggestedge = current + biggestsize = size + biggestindex = edgeindices[current] + end + current = current.links[0] + until current == start + outeredges[1] = biggestedge + end + + -- now for every two comp + for _, id in ipairs(twocomps[i]) do + local biggestedge + local biggestsize + local biggestindex + local start = compedges[id][i][1] + local current = start + repeat + local size = self:get_face_size(current) + if not biggestedge or size > biggestsize + or (size == biggestsize + and edgeindices[current] > biggestindex) then + biggestedge = current + biggestsize = size + biggestindex = edgeindices[current] + end + current = current.links[0] + until current == start + table.insert(outeredges, biggestedge) + end + + -- now merge all comps at the outer edges + local lastedge = outeredges[#outeredges].links[0] + for _, edge in ipairs(outeredges) do + local nextlastedge = edge.links[0] + lastedge.links[1] = edge + edge.links[0] = lastedge + lastedge = nextlastedge + end + end +end + +function E:get_face_size(halfedge) + local size = 0 + local current = halfedge + repeat + size = size + 1 + current = current.twin.links[1] + until current == halfedge + return size +end + +return E diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/LinkedList.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/LinkedList.lua new file mode 100644 index 0000000000..35f8418fdf --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/LinkedList.lua @@ -0,0 +1,88 @@ +local LinkedList = {} + +LinkedList.__index = LinkedList + +function LinkedList.new() + local list = {elements = {}} + setmetatable(list, LinkedList) + return list +end + +function LinkedList:addback(payload) + if payload == nil then + error("Need a payload!", 2) + end + local element = { payload = payload } + if self.head then + local tail = self.head.prev + self.head.prev = element + tail.next = element + element.next = self.head + element.prev = tail + else + self.head = element + element.next = element + element.prev = element + end + self.elements[element] = true + return element +end + +function LinkedList:addfront(payload) + self.head = self:addback(payload) + return self.head +end + +function LinkedList:remove(element) + if self.elements[element] == nil then + error("Element not in list!", 2) + end + if self.head == element then + if element.next == element then + self.head = nil + else + self.head = element.next + end + end + element.prev.next = element.next + element.next.prev = element.prev + self.elements[element] = nil +end + +function LinkedList:popfirst() + if self.head == nil then + return nil + end + local element = self.head + if element.next == element then + self.head = nil + else + self.head = element.next + element.next.prev = element.prev + element.prev.next = element.next + end + self.elements[element] = nil + return element.payload +end + +function LinkedList:poplast() + if self.head == nil then + return nil + end + self.head = self.head.prev + return self:popfirst() +end + +function LinkedList:first() + return self.head and self.head.payload +end + +function LinkedList:last() + return self.head and self.head.prev.payload +end + +function LinkedList:empty() + return self.head == nil +end + +return LinkedList diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/List.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/List.lua new file mode 100644 index 0000000000..22a91e6571 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/List.lua @@ -0,0 +1,49 @@ +local List = {} + +List.__index = List + +function List.new() + local t = {first = 0, last = -1} + setmetatable(t, List) + return t +end + +function List:pushleft(value) + local first = self.first - 1 + self.first = first + self[first] = value +end + +function List:pushright(value) + local last = self.last + 1 + self.last = last + self[last] = value +end + +function List:popleft() + local first = self.first + if first > self.last then error("List is empty") end + local value = self[first] + self[first] = nil + self.first = first + 1 + return value +end + +function List:popright() + local last = self.last + if self.first > last then error("List is empty") end + local value = self[last] + self[last] = nil + self.last = last - 1 + return value +end + +function List:size() + return self.last - self.first + 1 +end + +function List:empty() + return self.last < self.first +end + +return List diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PDP.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PDP.lua new file mode 100644 index 0000000000..8c159cf61d --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PDP.lua @@ -0,0 +1,576 @@ + +local PDP = {} +require("pgf.gd.planar").PDP = PDP + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare +local Storage = require "pgf.gd.lib.Storage" +local Coordinate = require "pgf.gd.model.Coordinate" +local Path = require "pgf.gd.model.Path" +--- +PDP.__index = PDP + +function PDP.new(ugraph, embedding, + delta, gamma, coolingfactor, + expiterations, + startrepexp, endrepexp, + startattexp, endattexp, + appthreshold, stretchthreshold, + stresscounterthreshold, + numdivisions) + local t = { + ugraph = ugraph, + embedding = embedding, + delta = delta , + gamma = gamma, + coolingfactor = coolingfactor, + expiterations = expiterations, + startrepexp = startrepexp, + endrepexp = endrepexp, + startattexp = startattexp, + endattexp = endattexp, + appthreshold = appthreshold, + stretchthreshold = stretchthreshold, + stresscounterthreshold = stresscounterthreshold, + numdivisions = numdivisions, + posxs = {}, + posys = {}, + cvsxs = {}, + cvsys = {}, + embeddingedges = {}, + edgeids = {}, + numedgeids = 0, + vertexids = {}, + numvertexids = 0, + vertexpairs1 = {}, + vertexpairs2 = {}, + pairconnected = {}, + edgepairsvertex = {}, + edgepairsedge = {}, + edgevertex1 = {}, + edgevertex2 = {}, + edgedeprecated = {}, + subdivisionedges = {}, + subdivisionvertices = {}, + temperature = 1, + } + + setmetatable(t, PDP) + return t +end + +function PDP:run() + self:normalize_size() + self:find_force_pairs() + + local delta = self.delta + local gamma = self.gamma + local coolingfactor = self.coolingfactor + local expiterations = self.expiterations + local startrepexp = self.startrepexp + local endattexp = self.endattexp + local startattexp = self.startattexp + local endrepexp = self.endrepexp + + local vertexpairs1 = self.vertexpairs1 + local vertexpairs2 = self.vertexpairs2 + local pairconnected = self.pairconnected + local edgepairsvertex = self.edgepairsvertex + local edgepairsedge = self.edgepairsedge + local edgevertex1 = self.edgevertex1 + local edgevertex2 = self.edgevertex2 + local edgedeprecated = self.edgedeprecated + + local forcexs = {} + local forceys = {} + local posxs = self.posxs + local posys = self.posys + local cvsxs = self.cvsxs + local cvsys = self.cvsys + local numcvs = {} + for i, v in ipairs(self.embedding.vertices) do + cvsxs[i] = {} + cvsys[i] = {} + posxs[i] = v.inputvertex.pos.x + posys[i] = v.inputvertex.pos.y + end + + local numorigvertices = self.numvertexids + local numorigedges = self.numedgeids + local numdivisions = self.numdivisions + local divdelta = delta / (numdivisions + 1) + local stresscounter = {} + for i = 1, self.numedgeids do + stresscounter[i] = 0 + end + + local appthreshold = self.appthreshold + local stretchthreshold = self.stretchthreshold + local stresscounterthreshold = self.stresscounterthreshold + + for i = 1, numorigedges do + local iv1 = self.embedding.vertices[edgevertex1[i]].inputvertex + local iv2 = self.embedding.vertices[edgevertex2[i]].inputvertex + local arc = self.ugraph:arc(iv1, iv2) + --TODO subdivide edge if desired + --self:subdivide_edge(i) + end + + -- main loop + local iteration = 0 + repeat + iteration = iteration + 1 + local temperature = self.temperature + local ratio = math.min(1, iteration / expiterations) + local repexp = startrepexp + (endrepexp - startrepexp) * ratio + local attexp = startattexp + (endattexp - startattexp) * ratio + for i = 1, self.numvertexids do + forcexs[i] = 0 + forceys[i] = 0 + numcvs[i] = 0 + end + -- vertex-vertex forces + for i = 1, #vertexpairs1 do + local id1 = vertexpairs1[i] + local id2 = vertexpairs2[i] + local diffx = posxs[id2] - posxs[id1] + local diffy = posys[id2] - posys[id1] + local dist2 = diffx * diffx + diffy * diffy + local dist = math.sqrt(dist2) + local dirx = diffx / dist + local diry = diffy / dist + assert(dist ~= 0) + + local useddelta = delta + local hasdivvertex = id1 > numorigvertices or id2 > numorigvertices + + -- calculate attractive force + if pairconnected[i] then + if hasdivvertex then + useddelta = divdelta + end + local mag = (dist / useddelta) ^ attexp * useddelta + local fax = mag * dirx + local fay = mag * diry + forcexs[id1] = forcexs[id1] + fax + forceys[id1] = forceys[id1] + fay + forcexs[id2] = forcexs[id2] - fax + forceys[id2] = forceys[id2] - fay + elseif hasdivvertex then + useddelta = gamma + end + + -- calculate repulsive force + local mag = (useddelta / dist) ^ repexp * useddelta + local frx = mag * dirx + local fry = mag * diry + forcexs[id1] = forcexs[id1] - frx + forceys[id1] = forceys[id1] - fry + forcexs[id2] = forcexs[id2] + frx + forceys[id2] = forceys[id2] + fry + end + + -- edge-vertex forces and collisions + for i = 1, #edgepairsvertex do + local edgeid = edgepairsedge[i] + if not edgedeprecated[edgeid] then + local id1 = edgepairsvertex[i] + local id2 = edgevertex1[edgeid] + local id3 = edgevertex2[edgeid] + assert(id2 ~= id1 and id3 ~= id1) + + local abx = posxs[id3] - posxs[id2] + local aby = posys[id3] - posys[id2] + local dab2 = abx * abx + aby * aby + local dab = math.sqrt(dab2) + assert(dab ~= 0) + local abnx = abx / dab + local abny = aby / dab + local avx = posxs[id1] - posxs[id2] + local avy = posys[id1] - posys[id2] + local daiv = abnx * avx + abny * avy + local ivx = posxs[id2] + abnx * daiv + local ivy = posys[id2] + abny * daiv + local vivx = ivx - posxs[id1] + local vivy = ivy - posys[id1] + local dviv2 = vivx * vivx + vivy * vivy + local dviv = math.sqrt(dviv2) + local afactor, bfactor = 1, 1 + local cvx + local cvy + if daiv < 0 then + cvx = -avx / 2 + cvy = -avy / 2 + local norm2 = cvx * cvx + cvy * cvy + bfactor = 1 + (cvx * abx + cvy * aby) / norm2 + elseif daiv > dab then + cvx = (abx - avx) / 2 + cvy = (aby - avy) / 2 + local norm2 = cvx * cvx + cvy * cvy + afactor = 1 - (cvx * abx + cvy * aby) / norm2 + else + if edgeid < numorigedges + and dviv < gamma * appthreshold + and dab > delta * stretchthreshold then + stresscounter[edgeid] = stresscounter[edgeid] + 1 + end + assert(dviv > 0) + cvx = vivx / 2 + cvy = vivy / 2 + -- calculate edge repulsive force + local dirx = -vivx / dviv + local diry = -vivy / dviv + local mag = (gamma / dviv) ^ repexp * gamma + local fex = mag * dirx + local fey = mag * diry + local abratio = daiv / dab + forcexs[id1] = forcexs[id1] + fex + forceys[id1] = forceys[id1] + fey + forcexs[id2] = forcexs[id2] - fex * (1 - abratio) + forceys[id2] = forceys[id2] - fey * (1 - abratio) + forcexs[id3] = forcexs[id3] - fex * abratio + forceys[id3] = forceys[id3] - fey * abratio + end + local nv = numcvs[id1] + 1 + local na = numcvs[id2] + 1 + local nb = numcvs[id3] + 1 + numcvs[id1] = nv + numcvs[id2] = na + numcvs[id3] = nb + cvsxs[id1][nv] = cvx + cvsys[id1][nv] = cvy + cvsxs[id2][na] = -cvx * afactor + cvsys[id2][na] = -cvy * afactor + cvsxs[id3][nb] = -cvx * bfactor + cvsys[id3][nb] = -cvy * bfactor + end + end + + -- clamp forces + local scalefactor = 1 + local collision = false + for i = 1, self.numvertexids do + local forcex = forcexs[i] + local forcey = forceys[i] + forcex = forcex * temperature + forcey = forcey * temperature + forcexs[i] = forcex + forceys[i] = forcey + local forcenorm2 = forcex * forcex + forcey * forcey + local forcenorm = math.sqrt(forcenorm2) + scalefactor = math.min(scalefactor, delta * 3 * temperature / forcenorm) + local cvys = cvsys[i] + for j, cvx in ipairs(cvsxs[i]) do + local cvy = cvys[j] + local cvnorm2 = cvx * cvx + cvy * cvy + local cvnorm = math.sqrt(cvnorm2) + local projforcenorm = (cvx * forcex + cvy * forcey) / cvnorm + if projforcenorm > 0 then + local factor = cvnorm * 0.9 / projforcenorm + if factor < scalefactor then + scalefactor = factor + collision = true + end + end + end + end + local moved = false + for i = 1, self.numvertexids do + local forcex = forcexs[i] * scalefactor + local forcey = forceys[i] * scalefactor + posxs[i] = posxs[i] + forcex + posys[i] = posys[i] + forcey + local forcenorm2 = forcex * forcex + forcey * forcey + if forcenorm2 > 0.0001 * delta * delta then moved = true end + end + + -- subdivide stressed edges + if numdivisions > 0 then + for i = 1, numorigedges do + if stresscounter[i] > stresscounterthreshold then + self:subdivide_edge(i) + stresscounter[i] = 0 + end + end + end + self.temperature = self.temperature * coolingfactor + until not collision and not moved + print("\nfinished PDP after " .. iteration .. " iterations") + + -- write the positions back + for i, v in ipairs(self.embedding.vertices) do + v.inputvertex.pos.x = posxs[i] + v.inputvertex.pos.y = posys[i] + end + + -- route the edges + for i = 1, self.numedgeids do + if self.subdivisionvertices[i] then + local iv1 = self.embedding.vertices[self.edgevertex1[i]].inputvertex + local iv2 = self.embedding.vertices[self.edgevertex2[i]].inputvertex + local arc = self.ugraph:arc(iv1, iv2) + local p = Path.new() + p:appendMoveto(arc.tail.pos:clone()) + for _, vid in ipairs(self.subdivisionvertices[i]) do + p:appendLineto(self.posxs[vid], self.posys[vid]) + end + p:appendLineto(arc.head.pos:clone()) + arc.path = p + end + end +end + +function PDP:subdivide_edge(edgeid) + assert(self.subdivisionedges[edgeid] == nil) + local numdivisions = self.numdivisions + local subdivisionedges = {} + local subdivisionvertices = {} + local id1 = self.edgevertex1[edgeid] + local id2 = self.edgevertex2[edgeid] + local x1 = self.posxs[id1] + local y1 = self.posys[id1] + local x2 = self.posxs[id2] + local y2 = self.posys[id2] + local prevvertexid = id1 + for i = 1, numdivisions do + -- create new edge and vertex + local newvertexid1 = self.numvertexids + i + table.insert(subdivisionvertices, newvertexid1) + self.posxs[newvertexid1] = (x1 * (numdivisions + 1 - i) + x2 * i) + / (numdivisions + 1) + self.posys[newvertexid1] = (y1 * (numdivisions + 1 - i) + y2 * i) + / (numdivisions + 1) + self.cvsxs[newvertexid1] = {} + self.cvsys[newvertexid1] = {} + + local newedgeid = self.numedgeids + i + table.insert(subdivisionedges, newedgeid) + table.insert(self.edgevertex1, prevvertexid) + table.insert(self.edgevertex2, newvertexid1) + prevvertexid = newvertexid1 + + -- pair the new vertex + -- with first vertex of the edge being divided + table.insert(self.vertexpairs1, self.edgevertex1[edgeid]) + table.insert(self.vertexpairs2, newvertexid1) + table.insert(self.pairconnected, i == 1) + + -- with second vertex of the edge being divided + table.insert(self.vertexpairs1, self.edgevertex2[edgeid]) + table.insert(self.vertexpairs2, newvertexid1) + table.insert(self.pairconnected, i == numdivisions) + + -- with each other + for j = i + 1, numdivisions do + local newvertexid2 = self.numvertexids + j + table.insert(self.vertexpairs1, newvertexid1) + table.insert(self.vertexpairs2, newvertexid2) + table.insert(self.pairconnected, j == i + 1) + end + + -- with new edges + -- before vertex + for j = 1, i - 1 do + local newedgeid = self.numedgeids + j + table.insert(self.edgepairsvertex, newvertexid1) + table.insert(self.edgepairsedge, newedgeid) + end + -- after vertex + for j = i + 2, numdivisions + 1 do + local newedgeid = self.numedgeids + j + table.insert(self.edgepairsvertex, newvertexid1) + table.insert(self.edgepairsedge, newedgeid) + end + + -- pair the new edges with vertices of the edge being divided + if i > 1 then + table.insert(self.edgepairsvertex, id1) + table.insert(self.edgepairsedge, newedgeid) + end + table.insert(self.edgepairsvertex, id2) + table.insert(self.edgepairsedge, newedgeid) + end + -- create last edge + table.insert(subdivisionedges, self.numedgeids + numdivisions + 1) + table.insert(self.edgevertex1, prevvertexid) + table.insert(self.edgevertex2, id2) + + -- pair last edge with first vertex of the edge being divided + table.insert(self.edgepairsvertex, id1) + table.insert(self.edgepairsedge, self.numedgeids + numdivisions + 1) + + self.subdivisionedges[edgeid] = subdivisionedges + self.subdivisionvertices[edgeid] = subdivisionvertices + + -- pair new edges and vertices with existing edges and vertices + local sameface = false + local start = self.embeddingedges[edgeid] + local twin = start.twin + local donevertices = { [start.target] = true, [twin.target] = true } + local doneedges = { [start] = true, [twin] = true } + local current = start.twin.links[1] + for twice = 1, 2 do + while current ~= start do + if current == twin then + sameface = true + end + + -- pair edge with the new vertices + -- or pair subdivision of edge with new vertices and edges + if not doneedges[current] then + local currentedgeid = self.edgeids[current] + if self.subdivisionvertices[currentedgeid] then + for _, vid in ipairs(self.subdivisionvertices[currentedgeid]) do + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.vertexpairs1, vid) + table.insert(self.vertexpairs2, newvertexid) + self.pairconnected[#self.vertexpairs1] = false + end + for i = 1, numdivisions + 1 do + local newedgeid = self.numedgeids + i + table.insert(self.edgepairsvertex, vid) + table.insert(self.edgepairsedge, newedgeid) + end + end + for _, eid in ipairs(self.subdivisionedges[currentedgeid]) do + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.edgepairsvertex, newvertexid) + table.insert(self.edgepairsedge, eid) + end + end + else + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.edgepairsvertex, newvertexid) + table.insert(self.edgepairsedge, currentedgeid) + end + end + doneedges[current] = true + end + + -- pair target vertex with the new vertices and edges + local vertexid = self.vertexids[current.target] + if not donevertices[current.target] then + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.vertexpairs1, vertexid) + table.insert(self.vertexpairs2, newvertexid) + self.pairconnected[#self.vertexpairs1] = false + end + for i = 1, numdivisions + 1 do + local newedgeid = self.numedgeids + i + table.insert(self.edgepairsvertex, vertexid) + table.insert(self.edgepairsedge, newedgeid) + end + end + current = current.twin.links[1] + end + start = self.embeddingedges[edgeid].twin + current = start.twin.links[1] + if sameface then + break + end + end + + self.edgedeprecated[edgeid] = true + self.numvertexids = self.numvertexids + numdivisions + self.numedgeids = self.numedgeids + numdivisions + 1 +end + +function PDP:find_force_pairs() + local donevertices = {} + -- number all vertices + local vertexids = self.vertexids + for i, v in ipairs(self.embedding.vertices) do + vertexids[v] = i + end + self.numvertexids = #self.embedding.vertices + + local edgeids = self.edgeids + local numedgeids = 0 + -- number all edges + for _, v in ipairs(self.embedding.vertices) do + local id = vertexids[v] + local start = v.link + local current = start + repeat + local targetid = vertexids[current.target] + if edgeids[current] == nil then + table.insert(self.edgevertex1, id) + table.insert(self.edgevertex2, targetid) + numedgeids = numedgeids + 1 + edgeids[current] = numedgeids + edgeids[current.twin] = numedgeids + self.embeddingedges[numedgeids] = current + end + current = current.links[0] + until current == start + end + + -- find all force pairs + for _, v in ipairs(self.embedding.vertices) do + local id = vertexids[v] + donevertices[id] = true + local vertexset = {} + local edgeset = {} + local start = v.link + repeat + local targetid = vertexids[start.target] + if vertexset[targetid] == nil and not donevertices[targetid] then + table.insert(self.pairconnected, true) + table.insert(self.vertexpairs1, id) + table.insert(self.vertexpairs2, targetid) + vertexset[targetid] = true + end + local current = start.twin.links[1] + while current.target ~= v do + local targetid = vertexids[current.target] + if vertexset[targetid] == nil and not donevertices[targetid] then + table.insert(self.pairconnected, self.ugraph:arc(v.inputvertex, current.target.inputvertex) ~= nil) + table.insert(self.vertexpairs1, id) + table.insert(self.vertexpairs2, targetid) + vertexset[targetid] = true + end + if edgeset[current] == nil then + table.insert(self.edgepairsvertex, id) + table.insert(self.edgepairsedge, edgeids[current]) + edgeset[current] = true + edgeset[current.twin] = true + end + current = current.twin.links[1] + end + start = start.links[0] + until start == v.link + end + + self.numedgeids = numedgeids +end + +function PDP:normalize_size() + local minx = math.huge + local maxx = -math.huge + local miny = math.huge + local maxy = -math.huge + + for _, v in ipairs(self.ugraph.vertices) do + minx = math.min(minx, v.pos.x) + maxx = math.max(maxx, v.pos.x) + miny = math.min(miny, v.pos.y) + maxy = math.max(maxy, v.pos.y) + end + + local area = (maxx - minx) * (maxy - miny) + local gridarea = #self.ugraph.vertices * self.delta * self.delta + + local scale = math.sqrt(gridarea) / math.sqrt(area) + + for _, v in ipairs(self.ugraph.vertices) do + v.pos = v.pos * scale + end +end + +-- done + +return PDP diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua new file mode 100644 index 0000000000..9e5b8d72ec --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua @@ -0,0 +1,159 @@ + + +local PlanarLayout = {} +require("pgf.gd.planar").PlanarLayout = PlanarLayout + +-- imports +local Coordinate = require "pgf.gd.model.Coordinate" +local Storage = require "pgf.gd.lib.Storage" +local BoyerMyrvold = require "pgf.gd.planar.BoyerMyrvold2004" +local ShiftMethod = require "pgf.gd.planar.ShiftMethod" +local Embedding = require "pgf.gd.planar.Embedding" +local PDP = require "pgf.gd.planar.PDP" +local InterfaceToAlgorithms = require("pgf.gd.interface.InterfaceToAlgorithms") +local createEdge = InterfaceToAlgorithms.createEdge +local createVertex = InterfaceToAlgorithms.createVertex + +InterfaceToAlgorithms.declare { + key = "planar layout", + algorithm = PlanarLayout, + preconditions = { + connected = true, + loop_free = true, + simple = true, + }, + postconditions = { + fixed = true, + }, + summary = [[" + The planar layout draws planar graphs without edge crossings. + "]], + documentation = [[" + The planar layout is a pipeline of algorithms to produce + a crossings-free drawing of a planar graph. + First a combinatorical embedding of the graph is created using + the Algorithm from Boyer and Myrvold. + The combinatorical Embedding is then being improved by + by the Sort and Flip algorithm and triangulated afterwards. + To determine the actual node positions the shift method + by de Fraysseix, Pach and Pollack is used. + Finally the force based Planar Drawing Postprocessing improves the drawing. + "]], + examples = { + [[" + \tikz \graph [nodes={draw, circle}] { + a -- { + b -- { + d -- i, + e, + f + }, + c -- { + g, + h + } + }, + f --[no span edge] a, + h --[no span edge] a, + i --[no span edge] g, + f --[no span edge] g, + c --[no span edge] d, + e --[no span edge] c + } + "]] + } +} + +function PlanarLayout:run() + --local file = io.open("timing.txt", "a") + + local options = self.digraph.options + + -- get embedding + local bm = BoyerMyrvold.new() + bm:init(self.ugraph) + local embedding = bm:run() + + assert(embedding, "Graph is not planar") + + --local start = os.clock() + if options["use sf"] then + embedding:improve() + end + + -- choose external face + local exedge, exsize = embedding:get_biggest_face() + + -- surround graph with triangle + local v1, v2, vn = embedding:surround_by_triangle(exedge, exsize) + + -- make maximal planar + embedding:triangulate() + + if options["show virtual"] then + -- add virtual vertices to input graph + for _, vertex in ipairs(embedding.vertices) do + if vertex.virtual then + vertex.inputvertex = createVertex(self, { + name = nil,--vertex.name, + generated_options = {}, + text = vertex.name + }) + vertex.virtual = false + end + end + + -- add virtual edges to input graph + for _, vertex in ipairs(embedding.vertices) do + for halfedge in Embedding.adjacency_iterator(vertex.link) do + if halfedge.virtual then + createEdge( + self, + vertex.inputvertex, + halfedge.target.inputvertex + ) + end + halfedge.virtual = false + end + end + end + + -- create canonical ordering + local order = embedding:canonical_order(v1, v2, vn) + + local sm = ShiftMethod.new() + sm:init(order) + local gridpos = sm:run() + + local gridspacing = options["grid spacing"] + for _, v in ipairs(order) do + if not v.virtual then + local iv = v.inputvertex + iv.pos.x = gridpos[v].x * gridspacing + iv.pos.y = gridpos[v].y * gridspacing + end + end + + embedding:remove_virtual() + + --start = os.clock() + if options["use pdp"] then + local pdp = PDP.new( + self.ugraph, embedding, + options["node distance"], + options["node distance"], + options["pdp cooling factor"], + options["exponent change iterations"], + options["start repulsive exponent"], + options["end repulsive exponent"], + options["start attractive exponent"], + options["end attractive exponent"], + options["edge approach threshold"], + options["edge stretch threshold"], + options["stress counter threshold"], + options["edge divisions"] + ) + pdp:run() + end + +end diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua new file mode 100644 index 0000000000..c568ca5696 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua @@ -0,0 +1,128 @@ +local SM = {} +require("pgf.gd.planar").ShiftMethod = SM + +-- imports +local Embedding = require("pgf.gd.planar.Embedding") + +-- create class properties +SM.__index = SM + +function SM.new() + local t = {} + setmetatable(t, SM) + return t +end + +function SM:init(vertices) + self.vertices = vertices + self.xoff = {} + self.pos = {} + for _, v in ipairs(vertices) do + self.pos[v] = {} + end + self.left = {} + self.right = {} +end + +function SM:run() + local v1 = self.vertices[1] + local v2 = self.vertices[2] + local v3 = self.vertices[3] + + self.xoff[v1] = 0 + self.pos[v1].y = 0 + self.right[v1] = v3 + + self.xoff[v3] = 1 + self.pos[v3].y = 1 + self.right[v3] = v2 + + self.xoff[v2] = 1 + self.pos[v2].y = 0 + + local n = #self.vertices + for k = 4, n do + local vk = self.vertices[k] + local wplink, wqlink, wp1qsum + if k ~= n then + wplink, wqlink, wp1qsum = self:get_attachments(vk) + else + wplink, wqlink, wp1qsum = self:get_last_attachments(vk, v1, v2) + end + local wp, wq = wplink.target, wqlink.target + local wp1 = wplink.links[0].target + local wq1 = wqlink.links[1 - 0].target + self.xoff[wp1] = self.xoff[wp1] + 1 + self.xoff[wq] = self.xoff[wq] + 1 + wp1qsum = wp1qsum + 2 + self.xoff[vk] = (wp1qsum + self.pos[wq].y - self.pos[wp].y) / 2 + self.pos[vk].y = (wp1qsum + self.pos[wq].y + self.pos[wp].y) / 2 + -- = self.xoff[vk] + self.pos[wp].y ? + self.right[wp] = vk + if wp ~= wq1 then + self.left[vk] = wp1 + self.right[wq1] = nil + self.xoff[wp1] = self.xoff[wp1] - self.xoff[vk] + end + self.right[vk] = wq + self.xoff[wq] = wp1qsum - self.xoff[vk] + end + self.pos[v1].x = 0 + self:accumulate_offset(v1, 0) + return self.pos +end + +function SM:get_attachments(vk) + local wplink, wqlink + local wp1qsum = 0 + local start = vk.link + local startattach = self.xoff[start.target] ~= nil + local current = start.links[0] + local last = start + repeat + local currentattach = self.xoff[current.target] ~= nil + local lastattach = self.xoff[last.target] ~= nil + if currentattach ~= lastattach then + if currentattach then + wplink = current + else + wqlink = last + end + if currentattach == startattach and not startattach then + break + end + currentattach = lastattach + elseif currentattach then + wp1qsum = wp1qsum + self.xoff[current.target] + end + last = current + current = current.links[0] + until last == start + return wplink, wqlink, wp1qsum +end + +function SM:get_last_attachments(vn, v1, v2) + local wplink, wqlink + local wp1qsum = 0 + for halfedge in Embedding.adjacency_iterator(vn.link, ccwdir) do + local target = halfedge.target + if target == v1 then + wplink = halfedge + elseif target == v2 then + wqlink = halfedge + end + wp1qsum = wp1qsum + self.xoff[target] + end + return wplink, wqlink, wp1qsum +end + +function SM:accumulate_offset(v, x) + x = x + self.xoff[v] + self.pos[v].x = x + local l = self.left[v] + local r = self.right[v] + if l then self:accumulate_offset(l, x) end + if r then self:accumulate_offset(r, x) end +end + +return SM diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/library.lua new file mode 100644 index 0000000000..68c46898e3 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/library.lua @@ -0,0 +1,2 @@ +require "pgf.gd.planar.PlanarLayout" +require "pgf.gd.planar.parameters" diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/parameters.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/parameters.lua new file mode 100644 index 0000000000..603f2ee7cc --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/planar/parameters.lua @@ -0,0 +1,144 @@ +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +declare { + key = "use pdp", + type = "boolean", + initial = "true", + + summary = [[" + Whether or not to use the Planar Drawing Postprocessing + to improve the drawing. + "]] +} + +declare { + key = "use sf", + type = "boolean", + initial = "true", + + summary = [[" + Whether or not to use the Sort and Flip Algorithm + to improve the combinatorical embedding. + "]] +} + +declare { + key = "grid spacing", + type = "number", + initial = "10", + + summary = [[" + If the |use pdp| option is not set, + this sets the spacing of the grid used by the shift method. + A bigger grid spacing will result in a bigger drawing. + "]] +} + +declare { + key = "pdp cooling factor", + type = "number", + initial = "0.98", + + summary = [[" + This sets the cooling factor used by the Planar Drawing Postprocessing. + A higher cooling factor can result in better quality of the drawing, + but will increase the run time of the algorithm. + "]] +} + +declare { + key = "start repulsive exponent", + type = "number", + initial = "2", + + summary = [[" + Start value of the exponent used in the calculation of all repulsive forces in PDP + "]] +} + +declare { + key = "end repulsive exponent", + type = "number", + initial = "2", + + summary = [[" + End value of the exponent used in the calculation of all repulsive forces in PDP. + "]] +} + +declare { + key = "start attractive exponent", + type = "number", + initial = "2", + + summary = [[" + Start value of the exponent used in PDP's calculation of the attractive force between + nodes connected by an edge. + "]] +} + +declare { + key = "end attractive exponent", + type = "number", + initial = "2", + + summary = [[" + End value of the exponent used in PDP's calculation of the attractive force between + nodes connected by an edge. + "]] +} + +declare { + key = "exponent change iterations", + type = "number", + initial = "1", + + summary = [[" + The number of iterations over which to modify the force exponents. + In iteration one the exponents will have their start value and in iteration + |exponent change iterations| they will have their end value. + "]] +} + +declare { + key = "edge approach threshold", + type = "number", + initial = "0.3", + + summary = [[" + The maximum ration between the actual and the desired node-edge distance + which is required to count an edge as stressed. + "]] +} + +declare { + key = "edge stretch threshold", + type = "number", + initial = "1.5", + + summary = [[" + The minimum ration between the actual and the desired edge length + which is required to count an edge as stressed. + "]] +} + +declare { + key = "stress counter threshold", + type = "number", + initial = "30", + + summary = [[" + The number of iterations an edge has to be under stress before it will be subdivided. + "]] +} + +declare { + key = "edge divisions", + type = "number", + initial = "0", + + summary = [[" + The number of edges in which stressed edges will be subdivided. + "]] +} diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing.lua new file mode 100644 index 0000000000..77166c5cbf --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing.lua @@ -0,0 +1,22 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + + +local routing = {} + +-- Declare namespace +require("pgf.gd").routing = routing + + +-- Done + +return routing \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/Hints.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/Hints.lua new file mode 100644 index 0000000000..7d34726f47 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/Hints.lua @@ -0,0 +1,100 @@ +-- Copyright 2014 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +--- +-- The |Hints| class provides a way for graph drawing algorithms to +-- communicate certain possibilities concerning the routing of edges +-- to edge routing algorithms. This partly decouples the choice of the +-- vertex positioning algorithms from the choice of edge routing +-- algorithm. For instance, for a simple necklace routing, it is +-- unclear whether the edges on the necklace should be routing ``along +-- the necklace'' or not. Thus, necklace routing algorithms will +-- ``hint'' that a necklace is present and only when the +-- |necklace routing| algorithm is selected will these hints lead to +-- actual bending of edges. +-- +-- For each kind of hint, there are methods in this class for creating +-- the hints and other methods for reading them. Hints are always +-- local to the ugraph. + +local Hints = {} + +-- Namespace +require("pgf.gd.routing").Hints = Hints + +-- Imports +local Storage = require("pgf.gd.lib.Storage") +local Coordinate = require("pgf.gd.model.Coordinate") + + + + +-- The necklace storage + +local necklaces = Storage.new() + + +--- +-- Adds a necklace hint. In this case, the hint indicates that the +-- given sequence of vertices lie on a circle. +-- +-- The idea is that an algorithm may specify that in a +-- given graph certain sequences of nodes form a ``necklace'', which +-- is typically a circle. There may be more than one necklace inside a +-- given graph. For each necklace, +-- whenever an arc connects subsequent nodes on the necklace, they get +-- bend in such a way that they lie follow the path of the +-- necklace. If an arc lies on more than one necklace, the ``last one +-- wins''. +-- +-- @param ugraph The ugraph to which this hint is added +-- @param necklace The sequence of vertices that form the necklace. If +-- the necklace is closed, the last vertex must equal the first one. +-- @param center If provided, must be |Coordinate| that specifies the +-- center of the circle on which the vertices lie. If not provided, +-- the origin is assumed. +-- @param clockwise If |true|, the vertices are in clockwise order, +-- otherwise in counter-clockwise order. + +function Hints.addNecklaceCircleHint(ugraph, necklace, center, clockwise) + local a = necklaces[ugraph] or {} + necklaces[ugraph] = a + + a[#a+1] = { + necklace = necklace, + center = center or Coordinate.origin, + clockwise = clockwise + } +end + + +--- +-- Gets the necklace hints. +-- +-- This function will return an array whose entries are necklace +-- hints. Each entry in the array has a |necklace| field, which is the +-- field passed to the |addNecklaceXxxx| methods. For a circle +-- necklace, the |center| and |clockwise| fields will be set. (Other +-- necklaces are not yet implemented.) +-- +-- @param ugraph The ugraph for which the necklace hints are +-- requested. +-- @return The array of necklaces as described above. + +function Hints.getNecklaceHints(ugraph) + return necklaces[ugraph] or {} +end + +-- done + +return Hints + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua new file mode 100644 index 0000000000..defcf9f8c6 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua @@ -0,0 +1,90 @@ +-- Copyright 2014 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- The class; it processes necklace hints. + +local NecklaceRouting = {} + + +-- Namespace +require("pgf.gd.routing").NecklaceRouting = NecklaceRouting + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + +local Hints = require "pgf.gd.routing.Hints" +local Path = require "pgf.gd.model.Path" + + +--- +declare { + key = "necklace routing", + algorithm = NecklaceRouting, + + phase = "edge routing", + + summary = "Bends all edges of a graph that lie on ``necklaces'' along these necklaces.", + + documentation = [[" + Some graph drawing algorithms lay out some or all nodes along a + path, which is then called a \emph{necklace}. For instance, the + |simple necklace layout| places all nodes on a circle and that + circle is the ``necklace''. When the |necklace routing| edge + routing algorithm is selected, all edges that connect subsequent + nodes on such a necklace are bend in such a way that the + ``follow the necklace path''. In the example case, this will + cause all edges that connect adjacent nodes to become arcs on + of the circle on which the nodes lie. + + Note that local edge routing options for an edge may overrule + the edge routing computed by the algorithm as in the edge from 6 + to 7 in the example. + "]], + + examples = [[" + \tikz \graph [simple necklace layout, node distance=1.5cm, + necklace routing, + nodes={draw,circle}, edges={>={Stealth[round,sep,bend]}}] + { 1 -> 2 [minimum size=30pt] <- 3 <-> 4 -- + 5 -- 6 -- [bend left] 7 -- 1 -- 4 }; + "]] +} + + + +-- The implementation + +function NecklaceRouting:run() + local ugraph = self.ugraph + + for _,entry in ipairs(Hints.getNecklaceHints(ugraph)) do + assert (entry.center) -- no other necklace types, yet + local prev + for _,vertex in ipairs(entry.necklace) do + if prev then + local a = ugraph:arc(prev, vertex) + if a then + local p = Path.new() + p:appendMoveto(a.tail.pos:clone()) + p:appendArcTo(a.head.pos:clone(), entry.center, entry.clockwise) + a.path = p + end + end + prev = vertex + end + end +end + + +-- done + +return NecklaceRouting diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/library.lua new file mode 100644 index 0000000000..17c959d685 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/routing/library.lua @@ -0,0 +1,29 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +-- Imports +local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare + +--- +-- This library contains algorithms for routing edges through a graph. +-- +-- @library + +local routing -- Library name + +-- Load declarations from: + +-- Load algorithms from: +require "pgf.gd.routing.NecklaceRouting" + + +-- General declarations diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua new file mode 100644 index 0000000000..a0aee6501c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua @@ -0,0 +1,183 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This program generates a C wrap file around graph drawing +-- algorithms. The idea is that when you have a graph drawing +-- algorithm implemented in C and wish to invoke it from Lua, you need +-- a wrapper that manages the translation between Lua and C. This +-- program is intended to make it (reasonably) easy to produce such a +-- wrapper. + + + +-- Sufficient number of arguments? + +if #arg < 4 or arg[1] == "-h" or arg[1] == "-?" or arg[1] == "--help" then + print([[" +Usage: make_gd_wrap library1 library2 ... libraryn template library_name target_c_file + +This program will read all of the graph drawing library files using +Lua's require. Then, it will iterate over all declared algorithm keys +(declared using declare { algorithm_written_in_c = ... }) and will +produce the code for library for the required target C files based on +the template. +"]]) + os.exit() +end + + +-- Imports + +local InterfaceToDisplay = require "pgf.gd.interface.InterfaceToDisplay" +local InterfaceCore = require "pgf.gd.interface.InterfaceCore" + + +-- Ok, setup: + +InterfaceToDisplay.bind(require "pgf.gd.bindings.Binding") + + +-- Now, read all libraries: + +for i=1,#arg-3 do + require(arg[i]) +end + + +-- Now, read the template: + +local file = io.open(arg[#arg-2]) +local template = file:read("*a") +file:close() + +-- Let us grab the declaration: + +local functions_dec = (template:match("%$functions(%b{})") or ""):match("^{(.*)}$") +local functions_reg_dec = (template:match("%$functions_registry(%b{})") or ""):match("^{(.*)}$") +local factories_dec = (template:match("%$factories(%b{})") or ""):match("^{(.*)}$") +local factories_reg_dec = (template:match("%$factories_registry(%b{})") or ""):match("^{(.*)}$") + +-- Now, handle all keys with a algorithm_written_in_c field + +local keys = InterfaceCore.keys +local filename = arg[#arg] +local target = arg[#arg-1] + +local includes = {} +local functions = {} +local functions_registry = {} + +local factories = {} +local factories_reg = {} + +for _,k in ipairs(keys) do + + if k.algorithm_written_in_c and k.code then + + local library, fun_name = k.algorithm_written_in_c:match("(.*)%.(.*)") + + if target == library then + -- First, gather the includes: + if type(k.includes) == "string" then + if not includes[k.includes] then + includes[#includes + 1] = k.includes + includes[k.includes] = true + end + elseif type(k.includes) == "table" then + for _,i in ipairs(k.includes) do + if not includes[i] then + includes[#includes + 1] = i + includes[i] = true + end + end + end + + -- Second, create a code block: + functions[#functions+1] = functions_dec:gsub("%$([%w_]-)%b{}", + { + function_name = fun_name, + function_body = k.code + }) + + -- Third, create functions_registry entry + functions_registry[#functions_registry + 1] = functions_reg_dec:gsub("%$([%w_]-)%b{}", + { + function_name = fun_name, + function_body = k.code + }) + end + end + + + if k.module_class then + + -- First, gather the includes: + if type(k.includes) == "string" then + if not includes[k.includes] then + includes[#includes + 1] = k.includes + includes[k.includes] = true + end + elseif type(k.includes) == "table" then + for _,i in ipairs(k.includes) do + if not includes[i] then + includes[#includes + 1] = i + includes[i] = true + end + end + end + + -- Second, create a code block: + factories[#factories+1] = factories_dec:gsub( + "%$([%w_]-)%b{}", + { + factory_class = k.module_class, + factory_code = k.code, + factory_base = k.module_base, + factory_name = k.module_class .. '_factory' + }) + + -- Third, create factories_registry entry + factories_reg[#factories_reg + 1] = factories_reg_dec:gsub( + "%$([%w_]-)%b{}", + { + factory_class = k.module_class, + factory_code = k.code, + factory_base = k.module_base, + factory_name = k.module_class .. '_factory' + }) + end +end + + +local file = io.open(filename, "w") + +if not file then + print ("failed to open file " .. filename) + os.exit(-1) +end + +file:write ((template:gsub( + "%$([%w_]-)%b{}", + { + factories = table.concat(factories, "\n\n"), + factories_registry = table.concat(factories_reg, "\n"), + functions = table.concat(functions, "\n\n"), + functions_registry = table.concat(functions_registry, "\n"), + includes = table.concat(includes, "\n"), + library_c_name = target:gsub("%.", "_"), + library_name = target + }))) +file:close() + + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees.lua new file mode 100644 index 0000000000..8c45e912dc --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees.lua @@ -0,0 +1,21 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +--- @release $Header$ + + +local trees = {} + +-- Declare namespace +require("pgf.gd").trees = tree + + +-- Done + +return trees \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua new file mode 100644 index 0000000000..cc3c18d12c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua @@ -0,0 +1,226 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Specifying Missing Children} +-- \label{section-gd-missing-children} +-- +-- In the present section we discuss keys for specifying missing children +-- in a tree. For many certain kind of trees, in particular for binary +-- trees, there are not just ``a certain number of children'' at each +-- node, but, rather, there is a designated ``first'' (or ``left'') child +-- and a ``second'' (or ``right'') child. Even if one of these children +-- is missing and a node actually has only one child, the single child will +-- still be a ``first'' or ``second'' child and this information should +-- be taken into consideration when drawing a tree. +-- +-- The first useful key for specifying missing children is +-- |missing number of children| which allows you to state how many +-- children there are, at minimum. +-- +-- Once the minimum number of children has been set, we still need a way +-- of specifying ``missing first children'' or, more generally, missing +-- children that are not ``at the end'' of the list of children. For +-- this, there are three methods: +-- % +-- \begin{enumerate} +-- \item When you use the |child| syntax, you can use the |missing| key +-- with the |child| command to indicate a missing child: +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{trees}}] +-- \tikz [binary tree layout, level distance=5mm] +-- \node {a} +-- child { node {b} +-- child { node {c} +-- child { node {d} } +-- } } +-- child { node {e} +-- child [missing] +-- child { node {f} +-- child [missing] +-- child { node {g} +-- } } }; +-- \end{codeexample} +-- % +-- \item When using the |graph| syntax, you can use an ``empty node'', +-- which really must be completely empty and may not even contain a +-- slash, to indicate a missing node: +-- % +-- \begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{trees}}] +-- \tikz [binary tree layout, level distance=5mm] +-- \graph { a -> { b -> c -> d, e -> { , f -> { , g} } } }; +-- \end{codeexample} +-- % +-- \item You can simply specify the index of a child directly using +-- the key |desired child index|. +-- \end{enumerate} +-- +-- @end + + +-- Imports +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + +--- +-- +declare { + key = "minimum number of children", + type = "number", + initial = "0", + + summary = [[" + Specifies how many children a tree node must have at least. If + there are less, ``virtual'' children are added. + "]], + documentation = [[" + When this key is set to |2| or more, the following happens: We first + compute a spanning tree for the graph, see + Section~\ref{subsection-gd-spanning-tree}. Then, whenever a node is + not a leaf in this spanning tree (when it has at least one child), + we add ``virtual'' or ``dummy'' nodes as children of the node until + the total number of real and dummy children is at least + \meta{number}. If there where at least \meta{number} children at the + beginning, nothing happens. + + The new children are added after the existing children. This means + that, for instance, in a tree with \meta{number} set to |2|, for + every node with a single child, this child will be the first child + and the second child will be missing. + "]], + examples = [[" + \tikz \graph [binary tree layout,level distance=5mm] + { a -> { b->c->d, e->f->g } }; + "]] +} + +--- + +declare { + key = "desired child index", + type = "number", + + summary = [[" + Pass this key to a node to tell the graph drawing engine which child + number you ``desired'' for the node. Whenever all desires for the + children of a node are conflict-free, they will all be met; children + for which no desired indices were given will remain at their + position, whenever possible, but will ``make way'' for children with + a desired position. + "]], + documentation = [[" + In detail, the following happens: We first + determine the total number of children (real or dummy) needed, which + is the maximum of the actual number of children, of the + \texttt{minimum number of children}, and of the highest desired + child index. Then we go over all children that have a desired child + index and put they at this position. If the position is already + taken (because some other child had the same desired index), the + next free position is used with a wrap-around occurring at the + end. Next, all children without a desired index are place using the + same mechanism, but they want to be placed at the position they had + in the original spanning tree. + + While all of this might sound a bit complicated, the application of + the key in a binary tree is pretty straightforward: To indicate that + a node is a ``right'' child in a tree, just add \texttt{desired child index=2} + to it. This will make it a second child, possibly causing the first + child to be missing. If there are two nodes specified as children of + a node, by saying \texttt{desired child index=}\meta{number} for one + of them, you will cause it be first or second child, depending on + \meta{number}, and cause the \emph{other} child to become the other + child. + + Since |desired child index=2| is a bit long, the following shortcuts + are available: |first|, |second|, |third|, and |fourth|. + You might wonder why |second| is used rather than |right|. The + reason is that trees may also grow left and right and, additionally, + the |right| and |left| keys are already in use for + anchoring. Naturally, you can locally redefine them, if you want. + "]], + examples = {[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> b[second] }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[second], c} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b, c[first]} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[second], c[second]} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[third], c[first], d} }; + "]] + } +} + + +--- + +declare { + key = "first", + use = { + { key = "desired child index", value = 1}, + }, + + summary = [[" + A shorthand for setting the desired child number to |1|. + "]] + } + +--- + +declare { + key = "second", + use = { + { key = "desired child index", value = 2}, + }, + + summary = [[" + A shorthand for setting the desired child number to |2|. + "]] + } + + +--- + +declare { + key = "third", + use = { + { key = "desired child index", value = 3}, + }, + + summary = [[" + A shorthand for setting the desired child number to |3|. + "]] + } + + +--- + +declare { + key = "fourth", + use = { + { key = "desired child index", value = 4} + }, + + summary = [[" + A shorthand for setting the desired child number to |4|. + "]] + } diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua new file mode 100644 index 0000000000..69babd443c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua @@ -0,0 +1,211 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsubsection {The Reingold--Tilford Layout} +-- +-- @end + +local ReingoldTilford1981 = {} + +-- Imports +local layered = require "pgf.gd.layered" +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare +local Storage = require "pgf.gd.lib.Storage" + +--- +declare { + key = "tree layout", + algorithm = ReingoldTilford1981, + + preconditions = { + connected = true, + tree = true + }, + + postconditions = { + upward_oriented = true + }, + + documentation_in = "pgf.gd.trees.doc" +} + + +--- +declare { + key = "missing nodes get space", + type = "boolean", + documentation_in = "pgf.gd.trees.doc" +} + + + +--- +declare { + key = "significant sep", + type = "length", + initial = "0", + documentation_in = "pgf.gd.trees.doc" +} + + +--- +declare { + key = "binary tree layout", + use = { + { key = "tree layout" }, + { key = "minimum number of children" , value=2 }, + { key = "significant sep", value = 10 }, + }, + documentation_in = "pgf.gd.trees.doc" +} + +--- +declare { + key = "extended binary tree layout", + use = { + { key = "tree layout" }, + { key = "minimum number of children" , value=2 }, + { key = "missing nodes get space" }, + { key = "significant sep", value = 0 }, + }, + documentation_in = "pgf.gd.trees.doc" +} + + + + +-- Now comes the implementation: + +function ReingoldTilford1981:run() + + local root = self.spanning_tree.root + + local layers = Storage.new() + local descendants = Storage.new() + + self.extended_version = self.digraph.options['missing nodes get space'] + + self:precomputeDescendants(root, 1, layers, descendants) + self:computeHorizontalPosition(root, layers, descendants) + layered.arrange_layers_by_baselines(layers, self.adjusted_bb, self.ugraph) + +end + + +function ReingoldTilford1981:precomputeDescendants(node, depth, layers, descendants) + local my_descendants = { node } + + for _,arc in ipairs(self.spanning_tree:outgoing(node)) do + local head = arc.head + self:precomputeDescendants(head, depth+1, layers, descendants) + for _,d in ipairs(descendants[head]) do + my_descendants[#my_descendants + 1] = d + end + end + + layers[node] = depth + descendants[node] = my_descendants +end + + + +function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants) + + local children = self.spanning_tree:outgoing(node) + + node.pos.x = 0 + + local child_depth = layers[node] + 1 + + if #children > 0 then + -- First, compute positions for all children: + for i=1,#children do + self:computeHorizontalPosition(children[i].head, layers, descendants) + end + + -- Now, compute minimum distances and shift them + local right_borders = {} + + for i=1,#children-1 do + + local local_right_borders = {} + + -- Advance "right border" of the subtree rooted at + -- the i-th child + for _,d in ipairs(descendants[children[i].head]) do + local layer = layers[d] + local x = d.pos.x + if self.extended_version or not (layer > child_depth and d.kind == "dummy") then + if not right_borders[layer] or right_borders[layer].pos.x < x then + right_borders[layer] = d + end + if not local_right_borders[layer] or local_right_borders[layer].pos.x < x then + local_right_borders[layer] = d + end + end + end + + local left_borders = {} + -- Now left for i+1 st child + for _,d in ipairs(descendants[children[i+1].head]) do + local layer = layers[d] + local x = d.pos.x + if self.extended_version or not (layer > child_depth and d.kind == "dummy") then + if not left_borders[layer] or left_borders[layer].pos.x > x then + left_borders[layer] = d + end + end + end + + -- Now walk down the lines and try to find out what the minimum + -- distance needs to be. + + local shift = -math.huge + local first_dist = left_borders[child_depth].pos.x - local_right_borders[child_depth].pos.x + local is_significant = false + + for layer,n2 in pairs(left_borders) do + local n1 = right_borders[layer] + if n1 then + shift = math.max( + shift, + layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, n1, n2) + n1.pos.x - n2.pos.x + ) + end + if local_right_borders[layer] then + if layer > child_depth and + (left_borders[layer].pos.x - local_right_borders[layer].pos.x <= first_dist) then + is_significant = true + end + end + end + + if is_significant then + shift = shift + self.ugraph.options['significant sep'] + end + + -- Shift all nodes in the subtree by shift: + for _,d in ipairs(descendants[children[i+1].head]) do + d.pos.x = d.pos.x + shift + end + end + + -- Finally, position root in the middle: + node.pos.x = (children[1].head.pos.x + children[#children].head.pos.x) / 2 + end +end + + + +return ReingoldTilford1981 \ No newline at end of file diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua new file mode 100644 index 0000000000..dacf634865 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua @@ -0,0 +1,646 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- @section subsection {Spanning Tree Computation} +-- +-- \label{subsection-gd-spanning-tree} +-- Although the algorithms of this library are tailored to layout trees, +-- they will work for any graph as input. First, if the graph is not +-- connected, it is decomposed into connected components and these are +-- laid out individually. Second, for each component, a spanning tree of +-- the graph is computed first and the layout is computed for this +-- spanning tree; all other edges will still be drawn, but they have no +-- impact on the placement of the nodes. If the graph is already a tree, +-- the spanning tree will be the original graph. +-- +-- The computation of the spanning tree is a non-trivial process since +-- a non-tree graph has many different possible spanning trees. You can +-- choose between different methods for deciding on a spanning tree, it +-- is even possible to implement new algorithms. (In the future, the +-- computation of spanning trees and the cycle removal in layered graph +-- drawing algorithms will be unified, but, currently, they are +-- implemented differently.) +-- +-- Selects the (sub)algorithm that is to be used for computing spanning +-- trees whenever this is requested by a tree layout algorithm. The +-- default algorithm is |breadth first spanning tree|. +--% +--\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{trees}}] +--\tikz \graph [tree layout, breadth first spanning tree] +--{ +-- 1 -- {2,3,4,5} -- 6; +--}; +--\end{codeexample} +--% +--\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} +-- \usegdlibrary{trees}}] +--\tikz \graph [tree layout, depth first spanning tree] +--{ +-- 1 --[bend right] {2,3,4,5 [>bend left]} -- 6; +--}; +--\end{codeexample} +-- +-- @end + +local SpanningTreeComputation = {} + + + +-- Namespace +require("pgf.gd.trees").SpanningTreeComputation = SpanningTreeComputation + + +-- Imports +local lib = require "pgf.gd.lib" + +local Vertex = require "pgf.gd.model.Vertex" +local Digraph = require "pgf.gd.model.Digraph" + + +local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare + + + + +-- ------------------------- -- +-- General tree parameters -- +-- ------------------------- -- + + + + +--- +-- +declare { + key = "breadth first spanning tree", + algorithm = { + run = + function (self) + return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events) + end + }, + phase = "spanning tree computation", + phase_default = true, + + summary = [[" + This key selects ``breadth first'' as the (sub)algorithm for + computing spanning trees. Note that this key does not cause a graph + drawing scope to start; the key only has an effect in conjunction + with keys like |tree layout|. +"]], + documentation = [[" + The algorithm will be called whenever a graph drawing algorithm + needs a spanning tree on which to operate. It works as follows: + % + \begin{enumerate} + \item It looks for a node for which the |root| parameter is + set. If there are several such nodes, the first one is used. + If there are no such nodes, the first node is used. + + Let call the node determined in this way the \emph{root node}. + \item For every edge, a \emph{priority} is determined, which is a + number between 1 and 10. How this happens, exactly, will be + explained in a moment. Priority 1 means ``most important'' while + priority 10 means ``least important''. + \item Starting from the root node, we now perform a breadth first + search through the tree, thereby implicitly building a spanning + tree: Suppose for a moment that all edges have priority~1. Then, + the algorithm works just the way that a normal breadth first + search is performed: We keep a queue of to-be-visited nodes and + while this queue is not empty, we remove its first node. If this + node has not yet been visited, we add all its neighbors at the + end of the queue. When a node is taken out of the queue, we make + it the child of the node whose neighbor it was when it was + added. Since the queue follows the ``first in, first out'' + principle (it is a fifo queue), the children of the root will be + all nodes at distance $1$ form the root, their children will be + all nodes at distance $2$, and so on. + \item Now suppose that some edges have a priority different + from~1, in which case things get more complicated. We now keep + track of one fifo queue for each of the ten possible + priorities. When we consider the neighbors of a node, we actually + consider all its incident edges. Each of these edges has a certain + priority and the neighbor is put into the queue of the edge's + priority. Now, we still remove nodes normally from the queue for + priority~1; only if this queue is empty and there is still a node + in the queue for priority~2 we remove the first element from this + queue (and proceed as before). If the second queue is also empty, + we try the third, and so on up to the tenth queue. If all queues + are empty, the algorithm stops. + \end{enumerate} + + The effect of the ten queues is the following: If the edges of + priority $1$ span the whole graph, a spanning tree consisting solely + of these edges will be computed. However, if they do not, once we + have visited reachable using only priority 1 edges, we will extend + the spanning tree using a priority 2 edge; but then we once switch + back to using only priority 1 edges. If neither priority~1 nor + priority~2 edges suffice to cover the whole graph, priority~3 edges + are used, and so on. + "]] +} + +--- + +declare { + key = "depth first spanning tree", + algorithm = { + run = + function (self) + return SpanningTreeComputation.computeSpanningTree(self.ugraph, true, self.events) + end + }, + phase = "spanning tree computation", + + summary = [[" + Works exactly like |breadth first spanning tree| (same handling of + priorities), only the queues are now lifo instead of + fifo. + "]] +} + +--- +-- +declare { + key = "root", + type = "boolean", + default = true, + + summary = [[" + This Boolean parameter is used in the computation of spanning + trees. When can be set for a node, this node will be used as the + root for the spanning tree computation. If several nodes have this + option set, the first node will be used. + "]] +} + + +--- +-- +declare { + key = "span priority", + type = "number", + + summary = [[" + Explicitly sets the ``span priority'' of an edge to \meta{number}, which must be + a number between |1| and |10|. The priority of edges is used by + spanning tree computations, see |breadth first spanning tree|. + "]] +} + + + +--- +-- when it comes to choosing which edges are part of the spanning tree. +declare { + key = "span edge", + use = { + { key = "span priority", value = 1 }, + }, + + summary = [[" + An easy-to-remember shorthand for |span priority=1|. When this key + is used with an edge, it will always be preferred over other edges + "]] +} + + + + +--- +-- +declare { + key = "no span edge", + use = { + { key = "span priority", value = 10 }, + }, + + summary = [[" + An easy-to-remember shorthand for |span priority=10|. This causes + the edge to be used only as a last resort as part of a spanning + tree. + "]], + documentation = [[" + In the example, we add lots of edges that would normally be + preferred in the computation of the spanning tree, but use + |no span edge| to cause the algorithm to ignore these edges. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, + every group/.style={ + default edge kind=->, no span edge, + path=source}] + { + 5 -> { + "1,3" -> {0,2,4}, + 11 -> { + "7,9" -> { 6, 8, 10 } + } + } + }; + "]] +} + + + +--- +declare { + key = "span priority ->", + type = "number", + initial = "3", + + summary = [[" + This key stores the span priority of all edges whose direction is + |->|. There are similar keys for all other directions, such as + |span priority <-| and so on. + "]], + documentation = [[" + When you write + % +\begin{codeexample}[code only] +graph { a -> b -- c <- [span priority=2] d } +\end{codeexample} + % + the priority of the edge from |a| to |b| would be the current + value of the key |span priority ->|, the priority of the edge from + |b| to |c| would be the current value of |span priority --|, and + the priority of the edge from |c| to |d| would be |2|, regardless + of the value of |span priority <-|. + + The defaults for the priorities are: + % + \begin{itemize} + \item |span priority -> = 3| + \item |span priority -- = 5| + \item |span priority <-> = 5| + \item |span priority <- = 8| + \item |span priority -!- = 10| + \end{itemize} + "]] +} + + + +--- + +declare { + key = "span priority reversed ->", + type = "number", + initial = "9", + + documentation = [[" + This key stores the span priority of traveling across reversed + edges whose actual direction is |->| (again, there are similar keys + for all other directions). + "]], + documentation = [[" + When you write + % +\begin{codeexample}[code only] +graph { a -> b -- c <- [span priority=2] d } +\end{codeexample} + % + there are, in addition to the priorities indicated above, also + further edge priorities: The priority of the (reversed) edge |b| + to |a| is |span priority reversed ->|, the priority of the + (reversed) edge |c| to |b| is |span priority reversed --|, and the + span priority of the reversed edge |d| to |c| is |2|, regardless + of the value of |span priority reversed <-|. + + The defaults for the priorities are: + % + \begin{itemize} + \item |span priority reversed -> = 9| + \item |span priority reversed -- = 5| + \item |span priority reversed <-> = 5| + \item |span priority reversed <- = 7| + \item |span priority reversed -!- = 10| + \end{itemize} + + The default priorities are set in such a way, that non-reversed |->| + edges have top priorities, |--| and |<->| edges have the same + priorities in either direction, and |<-| edges have low priority in + either direction (but going |a <- b| from |b| to |a| is given higher + priority than going from |a| to |b| via this edge and also higher + priority than going from |b| to |a| in |a -> b|). + + Keys like |span using directed| change the priorities ``en bloc''. + "]] +} + + +declare { + key = "span priority <-", + type = "number", + initial = "8", +} + +declare { + key = "span priority reversed <-", + type = "number", + initial = "7", +} + +declare { + key = "span priority --", + type = "number", + initial = "5", +} + +declare { + key = "span priority reversed --", + type = "number", + initial = "5", +} + +declare { + key = "span priority <->", + type = "number", + initial = "5", +} + +declare { + key = "span priority reversed <->", + type = "number", + initial = "5", +} + +declare { + key = "span priority -!-", + type = "number", + initial= "10", +} + +declare { + key = "span priority reversed -!-", + type = "number", + initial= "10", +} + +--- + +declare { + key = "span using directed", + use = { + { key = "span priority reversed <-", value = 3}, + { key = "span priority <->", value = 3}, + { key = "span priority reversed <->", value = 3}, + }, + summary = [[" + This style sets a priority of |3| for all edges that are directed + and ``go along the arrow direction'', that is, we go from |a| to + |b| with a priority of |3| for the cases |a -> b|, |b <- a|, + |a <-> b|, and |b <-> a|. + This strategy is nice with trees specified with both forward and + backward edges. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, + span using directed] + { + 3 <- 5[root] -> 8, + 1 <- 3 -> 4, + 7 <- 8 -> 9, + 1 -- 4 -- 7 -- 9 + }; + "]] +} + +--- + +declare { + key = "span using all", + use = { + { key = "span priority <-", value = 5}, + { key = "span priority ->", value = 5}, + { key = "span priority <->", value = 5}, + { key = "span priority --", value = 5}, + { key = "span priority -!-", value = 5}, + { key = "span priority reversed <-", value = 5}, + { key = "span priority reversed ->", value = 5}, + { key = "span priority reversed <->", value = 5}, + { key = "span priority reversed --", value = 5}, + { key = "span priority reversed -!-", value = 5}, + }, + + summary = [[" + Assings a uniform priority of 5 to all edges. + "]] +} + + +-- The implementation + +-- +-- Compute a spanning tree of a graph +-- +-- The algorithm will favor nodes according to their priority. This is +-- determined through an edge priority function. +-- +-- @param ugraph An undirected graph for which the spanning tree +-- should be computed +-- @param dfs True if depth first should be used, false if breadth +-- first should be used. +-- +-- @return A new graph that is a spanning tree. + +function SpanningTreeComputation.computeSpanningTree (ugraph, dfs, events) + + local tree = Digraph.new (ugraph) -- copy vertices + + local edge_priorities = ugraph.options['/graph drawing/edge priorities'] + + local root = lib.find(ugraph.vertices, function (v) return v.options['root'] end) or ugraph.vertices[1] + + -- Traverse tree, giving preference to directed edges and, that + -- failing, to undirected and bidirected edges, and, that failing, + -- all other edges. + local marked = {} + + local stacks = { -- 10 stacks for 10 priorities, with 1 being the highest + { { parent = nil, node = root}, top = 1, bottom = 1 }, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1}, + { top = 0, bottom = 1} + } + + local function stack_is_non_empty (s) return s.top >= s.bottom end + + while lib.find(stacks, stack_is_non_empty) do + local parent, node + + for _,stack in ipairs(stacks) do + if stack_is_non_empty(stack) then + -- Pop + parent = stack[stack.top].parent + node = stack[stack.top].node + + stack[stack.top] = nil + stack.top = stack.top - 1 + + break + end + end + + if not marked[node] then + + -- The node is good! + marked[node] = true + + if parent then + tree:connect(parent,node) + end + + local arcs = ugraph:outgoing(node) + + for j=1,#arcs do + local arc = arcs[dfs and j or #arcs - j + 1] + local head = arc.head + + if not marked[head] then + local priority = arc:spanPriority() + local stack = assert(stacks[priority], "illegal edge priority") + if dfs then + stack.top = stack.top + 1 + stack[stack.top] = { parent = node, node = head} + else + stack.bottom = stack.bottom - 1 + stack[stack.bottom] = { parent = node, node = head} + end + end + end + end + end + + -- Now, copy vertex list + local copy = {} + for i,v in ipairs(tree.vertices) do + copy[i] = v + end + + -- Now, setup child lists + for _,v in ipairs(copy) do + + -- Children as they come from the spanning tree computation + tree:sortOutgoing(v, function (a,b) return a:eventIndex() < b:eventIndex() end) + local outgoings = tree:outgoing(v) + + -- Compute children as they come in the event list: + local children = {} + + local i = (v.event.index or 0)+1 + while i <= #events and events[i].kind == "edge" do + i = i + 1 + end + + if events[i] and events[i].kind == "begin" and events[i].parameters == "descendants" then + -- Ok, the node is followed by a descendants group + -- Now scan for nodes that are not inside a descendants group + local stop = events[i].end_index + local j = i+1 + while j <= stop do + if events[j].kind == "node" then + children[#children+1] = events[j].parameters + elseif events[j].kind == "begin" and events[j].parameters == "descendants" then + j = events[j].end_index + end + j = j + 1 + end + + -- Test, whether outgoings and children contain the same nodes: + local function same_elements() + local hash = {} + for v,c in ipairs(outgoings) do + hash[c.head] = true + end + local count = 0 + for _,c in pairs(children) do + if c ~= "" then + count = count + 1 + if not hash[c] or count > #outgoings then + return false + end + end + end + return count == #outgoings + end + + if same_elements() and #outgoings > 0 then + -- increase number of children, if necessary + local needed = math.max(#children, lib.lookup_option('minimum number of children', v, ugraph)) + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + needed = d and math.max(needed, d) or needed + end + end + + local new_children = {} + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + if d then + local target = d + + while new_children[target] do + target = 1 + (target % #children) + end + new_children[target] = children[i] + end + end + end + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + if not d then + local target = i + + while new_children[target] do + target = 1 + (target % #children) + end + new_children[target] = children[i] + end + end + end + for i=1,needed do + if not new_children[i] then + local new_child = Vertex.new{ kind = "dummy" } + new_children[i] = new_child + tree:add {new_child} + tree:connect(v,new_child) + end + end + + tree:orderOutgoing(v,new_children) + end + end + end + + tree.root = root + + return tree +end + + + +-- Done + +return SpanningTreeComputation diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/doc.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/doc.lua new file mode 100644 index 0000000000..a44fd47031 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/doc.lua @@ -0,0 +1,340 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + +local key = require 'pgf.gd.doc'.key +local documentation = require 'pgf.gd.doc'.documentation +local summary = require 'pgf.gd.doc'.summary +local example = require 'pgf.gd.doc'.example + + +-------------------------------------------------------------------- +key "tree layout" + +summary "This layout uses the Reingold--Tilform method for drawing trees." + +documentation +[[ +The Reingold--Tilford method is a standard method for drawing +trees. It is described in: +% +\begin{itemize} + \item + E.~M.\ Reingold and J.~S.\ Tilford, + \newblock Tidier drawings of trees, + \newblock \emph{IEEE Transactions on Software Engineering,} + 7(2), 223--228, 1981. +\end{itemize} +% +My implementation in |graphdrawing.trees| follows the following paper, which +introduces some nice extensions of the basic algorithm: +% +\begin{itemize} + \item + A.\ Br\"uggemann-Klein, D.\ Wood, + \newblock Drawing trees nicely with \TeX, + \emph{Electronic Publishing,} 2(2), 101--115, 1989. +\end{itemize} +% +As a historical remark, Br\"uggemann-Klein and Wood have implemented +their version of the Reingold--Tilford algorithm directly in \TeX\ +(resulting in the Tree\TeX\ style). With the power of Lua\TeX\ at +our disposal, the 2012 implementation in the |graphdrawing.tree| +library is somewhat more powerful and cleaner, but it really was an +impressive achievement to implement this algorithm back in 1989 +directly in \TeX. + +The basic idea of the Reingold--Tilford algorithm is to use the +following rules to position the nodes of a tree (the following +description assumes that the tree grows downwards, other growth +directions are handled by the automatic orientation mechanisms of +the graph drawing library): +% +\begin{enumerate} + \item For a node, recursively compute a layout for each of its children. + \item Place the tree rooted at the first child somewhere on the page. + \item Place the tree rooted at the second child to the right of the + first one as near as possible so that no two nodes touch (and such + that the |sibling sep| padding is not violated). + \item Repeat for all subsequent children. + \item Then place the root above the child trees at the middle + position, that is, at the half-way point between the left-most and + the right-most child of the node. +\end{enumerate} +% +The standard keys |level distance|, |level sep|, |sibling distance|, +and |sibling sep|, as well as the |pre| and |post| versions of these +keys, as taken into consideration when nodes are positioned. See also +Section~\ref{subsection-gd-dist-pad} for details on these keys. + +\noindent\textbf{Handling of Missing Children.} +As described in Section~\ref{section-gd-missing-children}, you can +specify that some child nodes are ``missing'' in the tree, but some +space should be reserved for them. This is exactly what happens: +When the subtrees of the children of a node are arranged, each +position with a missing child is treated as if a zero-width, +zero-height subtree were present at that positions: +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz [tree layout, nodes={draw,circle}] + \node {r} + child { node {a} + child [missing] + child { node {b} } + } + child[missing]; +\end{codeexample} +% +or in |graph| syntax: +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] + \tikz \graph [tree layout, nodes={draw,circle}] + { + r -> { + a -> { + , %missing + b}, + % missing + } + }; +\end{codeexample} +% +More than one child can go missing: +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [tree layout, nodes={draw,circle}, sibling sep=0pt] + { r -> { a, , ,b -> {c,d}, ,e} }; +\end{codeexample} +% +Although missing children are taken into consideration for the +computation of the placement of the children of a root node relative +to one another and also for the computation of the position of the +root node, they are usually \emph{not} considered as part of the +``outline'' of a subtree (the \texttt{minimum number of children} +key ensures that |b|, |c|, |e|, and |f| all have a missing right +child): +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [tree layout, minimum number of children=2, + nodes={draw,circle}] + { a -> { b -> c -> d, e -> f -> g } }; +\end{codeexample} +% +This behaviour of ``ignoring'' missing children in later stages of +the recursion can be changed using the key |missing nodes get space|. + +\noindent\textbf{Significant Pairs of Siblings.} +Br\"uggemann-Klein and Wood have proposed an extension of the +Reingold--Tilford method that is intended to better highlight the +overall structure of a tree. Consider the following two trees: +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz [baseline=(a.base), tree layout, minimum number of children=2, + sibling distance=5mm, level distance=5mm] + \graph [nodes={circle, inner sep=0pt, minimum size=2mm, fill, as=}]{ + a -- { b -- c -- { d -- e, f -- { g, h }}, i -- j -- k[second] } + };\quad +\tikz [baseline=(a.base), tree layout, minimum number of children=2, + sibling distance=5mm, level distance=5mm] + \graph [nodes={circle, inner sep=0pt, minimum size=2mm, fill, as=}]{ + a -- { b -- c -- d -- e, i -- j -- { f -- {g,h}, k } } + }; +\end{codeexample} +% +As observed by Br\"uggemann-Klein and Wood, the two trees are +structurally quite different, but the Reingold--Tilford method +places the nodes at exactly the same positions and only one edge +``switches'' positions. In order to better highlight the differences +between the trees, they propose to add a little extra separation +between siblings that form a \emph{significant pair}. They define +such a pair as follows: Consider the subtrees of two adjacent +siblings. There will be one or more levels where these subtrees have +a minimum distance. For instance, the following two trees the +subtrees of the nodes |a| and |b| have a minimum distance only at +the top level in the left example, and in all levels in the second +example. A \emph{significant pair} is a pair of siblings where the +minimum distance is encountered on any level other than the first +level. Thus, in the first example there is no significant pair, +while in the second example |a| and |b| form such a pair. +% +\begin{codeexample}[preamble={\usetikzlibrary{graphs,graphdrawing} + \usegdlibrary{trees}}] +\tikz \graph [tree layout, minimum number of children=2, + level distance=5mm, nodes={circle,draw}] + { / -> { a -> / -> /, b -> /[second] -> /[second] }}; + \quad +\tikz \graph [tree layout, minimum number of children=2, + level distance=5mm, nodes={circle,draw}] + { / -> { a -> / -> /, b -> / -> / }}; +\end{codeexample} +% +Whenever the algorithm encounters a significant pair, it adds extra +space between the siblings as specified by the |significant sep| +key. +]] + + +example +[[ +\tikz [tree layout, sibling distance=8mm] + \graph [nodes={circle, draw, inner sep=1.5pt}]{ + 1 -- { 2 -- 3 -- { 4 -- 5, 6 -- { 7, 8, 9 }}, 10 -- 11 -- { 12, 13 } } + }; +]] + + +example +[[ +\tikz [tree layout, grow=-30, + sibling distance=0mm, level distance=0mm,] + \graph [nodes={circle, draw, inner sep=1.5pt}]{ + 1 -- { 2 -- 3 -- { 4 -- 5, 6 -- { 7, 8, 9 }}, 10 -- 11 -- { 12, 13 } } + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "missing nodes get space" + +summary +[[ +When set to true, missing children are treated as if they where +zero-width, zero-height nodes during the whole tree layout process. +]] + + +example +[[ +\tikz \graph [tree layout, missing nodes get space, + minimum number of children=2, nodes={draw,circle}] +{ a -> { b -> c -> d, e -> f -> g } }; +]] +-------------------------------------------------------------------- + + + + + +-------------------------------------------------------------------- +key "significant sep" + +summary +[[ +This space is added to significant pairs by the modified +Reingold--Tilford algorithm. +]] + +example +[[ +\tikz [baseline=(a.base), tree layout, significant sep=1em, + minimum number of children=2, + sibling distance=5mm, level distance=5mm] + \graph [nodes={circle, inner sep=0pt, minimum size=2mm, fill, as=}]{ + a -- { b -- c -- { d -- e, f -- { g, h }}, i -- j -- k[second] } + };\quad +\tikz [baseline=(a.base), tree layout, significant sep=1em, + minimum number of children=2, + sibling distance=5mm, level distance=5mm] + \graph [nodes={circle, inner sep=0pt, minimum size=2mm, fill, as=}]{ + a -- { b -- c -- d -- e, i -- j -- { f -- {g,h}, k } } + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "binary tree layout" + +summary +[[ +A layout based on the Reingold--Tilford method for drawing +binary trees. +]] + +documentation +[[ +This key executes: +% +\begin{enumerate} + \item |tree layout|, thereby selecting the Reingold--Tilford method, + \item |minimum number of children=2|, thereby ensuring the all nodes + have (at least) two children or none at all, and + \item |significant sep=10pt| to highlight significant pairs. +\end{enumerate} +% +In the examples, the last one is taken from the paper of +Br\"uggemann-Klein and Wood. It demonstrates nicely the +advantages of having the full power of \tikzname's anchoring and the +graph drawing engine's orientation mechanisms at one's disposal. +]] + + +example +[[ +\tikz [grow'=up, binary tree layout, sibling distance=7mm, level distance=7mm] + \graph { + a -- { b -- c -- { d -- e, f -- { g, h }}, i -- j -- k[second] } + }; +]] + +--[[ +% TODOsp: codeexamples: the next example needs the library `arrows.meta` +--]] +example +[[ +\tikz \graph [binary tree layout] { + Knuth -> { + Beeton -> Kellermann [second] -> Carnes, + Tobin -> Plass -> { Lamport, Spivak } + } +};\qquad +\tikz [>={Stealth[round,sep]}] + \graph [binary tree layout, grow'=right, level sep=1.5em, + nodes={right, fill=blue!50, text=white, chamfered rectangle}, + edges={decorate,decoration={snake, post length=5pt}}] + { + Knuth -> { + Beeton -> Kellermann [second] -> Carnes, + Tobin -> Plass -> { Lamport, Spivak } + } + }; +]] +-------------------------------------------------------------------- + + + +-------------------------------------------------------------------- +key "extended binary tree layout" + +summary +[[ +This algorithm is similar to |binary tree layout|, only the +option \texttt{missing nodes get space} is executed and the +\texttt{significant sep} is zero. +]] + +example +[[ +\tikz [grow'=up, extended binary tree layout, + sibling distance=7mm, level distance=7mm] + \graph { + a -- { b -- c -- { d -- e, f -- { g, h }}, i -- j -- k[second] } + }; +]] +-------------------------------------------------------------------- diff --git a/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/library.lua b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/library.lua new file mode 100644 index 0000000000..a0019666ac --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/lua/pgf/gd/trees/library.lua @@ -0,0 +1,35 @@ +-- Copyright 2012 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- \tikzname\ offers several different syntax to specify trees (see +-- Sections \ref{section-library-graphs} +-- and~\ref{section-trees}). The job of the graph drawing algorithms from +-- this library is to turn the specification of trees into beautiful +-- layouts. +-- +-- We start this section with a description of algorithms, then we have a +-- look at how missing children can be specified and at what happens when +-- the input graph is not a tree. +-- +-- @library + +local trees -- Library name + +-- Load declarations from: +require "pgf.gd.trees.ChildSpec" +require "pgf.gd.trees.SpanningTreeComputation" + +-- Load algorithms from: +require "pgf.gd.trees.ReingoldTilford1981" + diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/experimental/tikzlibrarygraphdrawing.evolving.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/experimental/tikzlibrarygraphdrawing.evolving.code.tex new file mode 100644 index 0000000000..efa214a12e --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/experimental/tikzlibrarygraphdrawing.evolving.code.tex @@ -0,0 +1,21 @@ +% Copyright 2018 by Malte Skambath +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{graphdrawing} + +\usegdlibrary{evolving} + +\newcount\mycount +\tikzgraphsset{ + nodes = {supernode/.expanded=\tikzgraphnodename}, + when/.code = {\pgfparsetime{#1}\mycount=\pgftimeresult pt\tikzgraphsset{name/.expanded=\the\mycount,snapshot/.expanded=\the\mycount}} +} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex new file mode 100644 index 0000000000..2fec25131d --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex @@ -0,0 +1,16 @@ +% Copyright 2019 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.circular.code.tex} + + +\usegdlibrary{circular}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex new file mode 100644 index 0000000000..63efd352f1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex @@ -0,0 +1,1165 @@ +% Copyright 2018 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.code.tex} + + + +% check if luatex is running + +\ifx\directlua\relax% + \pgferror{You need to run LuaTeX to use the graph drawing library} + \expandafter\endinput +\fi +\ifx\directlua\undefined% + \pgferror{You need to run LuaTeX to use the graph drawing library} + \expandafter\endinput +\fi + + + + +% +% All graph drawing keys normally live in the following namespace: +% /graph drawing. +% + +\def\pgfgdset{\pgfqkeys{/graph drawing}}% + + +% Setup a key +% +% #1 = key +% +% Description: +% +% An internal macro that sets up #1 as a graph drawing key. + +\def\pgfgd@callbackkey#1{% + \pgf@gd@setup@forwards{#1}% + \pgfutil@g@addto@macro\pgf@gd@forwards@list{\pgf@gd@setup@forwards{#1}}% +}% +\def\pgf@gd@setup@forwards#1{% + \let\pgf@temp\pgfutil@empty + \foreach \pgf@gd@path in \pgf@gd@forwarding@list {% + \ifx\pgf@gd@path\pgfutil@empty\else% + \expandafter\pgfutil@g@addto@macro% + \expandafter\pgf@temp\expandafter{% + \expandafter\pgfkeys\expandafter{\pgf@gd@path#1/.forward to=/graph drawing/#1}}% + \fi% + }% + \pgf@temp +}% + +\let\pgf@gd@forwards@list\pgfutil@empty + + +% Append to the forwarding list: +% +% #1 = paths to append to the forwarding list +% +% Description: +% +% Append the paths in #1 (with trailing slashes) to the forwarding +% list. +% +% If algorithms have already been declared, forwarding will also be +% setup for them (using a bit of magic...). + +\def\pgfgdappendtoforwardinglist#1{% + \let\pgf@gd@forwarding@list@orig\pgf@gd@forwarding@list + \def\pgf@gd@forwarding@list{#1}% + \pgf@gd@forwards@list% + \expandafter\def\expandafter\pgf@gd@forwarding@list\expandafter{\pgf@gd@forwarding@list@orig,#1}% +}% +\let\pgf@gd@forwarding@list\pgfutil@empty + + + +% +% +% Callbacks +% +% The following macros are called *from* the binding layer. You do not +% call them from the pgf layer. +% +% + + +% Callback for declaring a graph parameter key +% +% #1 = Parameter key +% #2 = Parameter type +% +% Description: +% +% When a graph drawing algorithm starts working, a set of options, +% called "graph drawing parameters" in the following, can influence the +% way the algorithm works. For instance, an graph drawing parameter +% might be the average distance between vertices which the algorithm +% should take into account. Another example might be the fact the +% certain nodes are special nodes and that a certain edge should have +% a large label. +% +% These graph drawing parameters are different from "usual" pgf +% options: An algorithmic parameter influenced the way the algorithm +% works, while usual options normally only influence how the result +% looks like. For instance, the fact that a node is red is not an +% graph drawing parameter (usually, at least), while the shape of a node +% might be an graph drawing parameter. +% +% Graph drawing parameters are declared by the algorithmic layer +% (since only this layer "knows" which parameters there are). The +% binding to TeX will call the \pgfgddeclareparameter function +% internally. +% +% Specifying the set of graph drawing parameters for a given graph or +% node or edge works as follows: When the graph drawing engine is +% started for a graph (using \pgfgdbeginscope), a snapshot is taken of +% all graph drawing parameters currently setup at this +% point. Similarly, when a node is created inside such a scope, a +% snapshot is taken of the set of all graph drawing parameters in +% force at this point is taken and stored together with the +% node. Finally, when an edge is created, a snapshot of the setting of +% the graph drawing parameters is taken. + +\def\pgfgdcallbackdeclareparameter#1#2{% + \pgfkeysdef{/graph drawing/#1}{\pgf@gd@handle@parameter{#1}{#2}{##1}}% + \pgfgd@callbackkey{#1}% +}% +\def\pgf@gd@handle@parameter#1#2#3{% + \def\pgf@temp{#3}% + \ifx\pgf@temp\pgfkeysnovalue@text% + \let\pgfgdresult\pgfgd@niltext% + \else% + \pgfkeys{/graph drawing/conversions/#2={#3}}% + \fi% + \advance\pgf@gd@parameter@stack@height by1\relax% + \pgf@gd@parameter@stack@height\directlua{% + local new, main = pgf.gd.interface.InterfaceToDisplay.pushOption('\pgfutil@luaescapestring{#1}',\pgfgdresult,\the\pgf@gd@parameter@stack@height) + tex.print(new..'\pgfutil@luaescapestring{\relax}') + if main then + tex.print('\pgfutil@luaescapestring{\noexpand\pgfgdtriggerrequest}') + end}% +}% +\newcount\pgf@gd@parameter@stack@height + +\def\pgfgdtriggerrequest{\pgfgdset{@request scope and layout}}% + + +% Conversions are used to adapt the syntactic description of a +% parameter on the TikZ layer to the one expected by Lua. The set of +% permissible conversions is described in +% InterfaceToAlgorithms.declareParameter. + +\pgfgdset{ + conversions/string/.code=\def\pgfgdresult{'\pgfutil@luaescapestring{\detokenize{#1}}'}, + conversions/raw/.code=\def\pgfgdresult{#1}, + conversions/nil/.code=\let\pgfgdresult\pgfgd@niltext, + conversions/boolean/.code=\def\pgf@test{#1}\ifx\pgf@test\pgf@truetext\def\pgfgdresult{true}\else\ifx\pgf@test\pgfkeysnovalue@text\def\pgfgdresult{true}\else\def\pgfgdresult{false}\fi\fi, + conversions/number/.code=\pgfmathparse{#1}\let\pgfgdresult\pgfmathresult, + conversions/length/.code=\pgfmathparse{#1}\let\pgfgdresult\pgfmathresult, + conversions/time/.code=\pgfparsetime{#1}\let\pgfgdresult\pgftimeresult, + conversions/direction/.code=\pgf@lib@gd@grow@dir{#1}\let\pgfgdresult\pgfmathresult, + conversions/canvas coordinate/.code args={(#1pt,#2pt)}{\edef\pgfgdresult{pgf.gd.model.Coordinate.new(#1,#2)}}, + % deprecated, will be removed: + conversions/coordinate/.code args={(#1pt,#2pt)}{\edef\pgfgdresult{{#1,#2}}} +}% +\def\pgf@truetext{true}% +\def\pgfgd@niltext{nil}% + +\def\pgf@lib@gd@grow@dir#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@gd@lib@active@bar% + \def\pgfmathresult{-90} + \else% + \ifcsname pgf@orient@direction@#1\endcsname% + \expandafter\let\expandafter\pgfmathresult\csname pgf@orient@direction@#1\endcsname% + \else + \pgfmathparse{#1}% + \fi + \fi +}% + +\def\pgf@orient@direction@down{-90}% +\def\pgf@orient@direction@up{90}% +\def\pgf@orient@direction@left{180}% +\def\pgf@orient@direction@right{0}% + +\def\pgf@orient@direction@south{-90}% +\def\pgf@orient@direction@north{90}% +\def\pgf@orient@direction@west{180}% +\def\pgf@orient@direction@east{0}% + +\expandafter\def\csname pgf@orient@direction@north east\endcsname{45}% +\expandafter\def\csname pgf@orient@direction@north west\endcsname{135}% +\expandafter\def\csname pgf@orient@direction@south east\endcsname{-45}% +\expandafter\def\csname pgf@orient@direction@south west\endcsname{-135}% + +\expandafter\def\csname pgf@orient@direction@-\endcsname{0}% +\expandafter\def\csname pgf@orient@direction@|\endcsname{-90}% + +{% + \catcode`\|=13 + \gdef\pgf@gd@lib@active@bar{|}% +}% + + + + + +% Callback for starting the rendering of a collection kind +% +% #1 = Kind +% #2 = Layer +% +% Description: +% +% Executes /graph drawing/#1/begin rendering/.try +% + +\def\pgfgdcallbackrendercollectionkindstart#1#2{% + \ifnum#2<0\relax + \setbox\pgf@gd@prekind@box=\hbox\bgroup% + \unhbox\pgf@gd@prekind@box% + \else% + \setbox\pgf@gd@postkind@box=\hbox\bgroup% + \unhbox\pgf@gd@postkind@box% + \fi% + \pgfgdset{/graph drawing/#1/begin rendering/.try}% +}% + +% Callback for ending the rendering of a collection kind +% +% #1 = Kind +% #2 = Layer +% +% Description: +% +% Executes /graph drawing/#1/end rendering/.try +% + +\def\pgfgdcallbackrendercollectionkindstop#1#2{% + \pgfgdset{/graph drawing/#1/end rendering/.try}% + \egroup % close box +}% + + + +% Callback for rendering a collection +% +% #1 = Kind +% #2 = Options +% +% Description: +% +% Executes /graph drawing/#1/render/.try={#2} +% + +\def\pgfgdcallbackrendercollection#1#2{ + \pgfgdset{/graph drawing/#1/render/.try={#2}} +}% + + + + + +% Graph events +% +% Although a graph consists of nodes and edges, during the +% construction of the graph a lot of information concerning the +% structure of the graph is often available. For instance, as we +% specify a graph using the child-syntax, we do not only which edges +% are present, but we can implicitly specify an ordering on the +% nodes. Even more, there is even information available concerning +% nodes that are not present at all: A child[missing] is not present +% as a node or an edge, but a tree drawing algorithm will want to know +% about this child nevertheless. +% +% In order to communicate such information to the graph drawing +% engine, "events" are used. As a graph is created, in addition to +% nodes and edges, "events" may happen. The events come in a +% sequential order and they are stored together with the graph. For +% each node and each edge, its index in the event sequence is +% stored, that is, it is stored how many events happened before the +% node or edge was created. +% +% Internally, an event consists of a name and, possibly, some +% parameters. When the parameter is created on the tikz level, it will +% be a string that is passed down to Lua. Internally created events +% will also have parameters that are objects. +% +% Two events are a bit special since they get special internal +% support: The begin and end events. The first signals that some kind +% of group has started; which is closed by the corresponding end +% event. The "kind" of group is indicated by the parameter of the +% begin event. +% +% +% +% Standard events are: +% +% For each node entered into a graph, a "node" event is automatically +% created internally with the parameter being the node. However, you +% can also create this event yourself. In this case, the parameter +% will be a string and will mean that the node is "virtual" or +% "missing", but space should be reserved for it, if possible (this is +% use, for instance, by certain tree layouts). +% +% For each edge entered into a graph, an "edge" event is automatically +% created, with the edge as the parameter. Again, an event with a +% string parameter corresponds to a "non-existing" node. +% +% +% Standard event groups are: +% +% +% The "descendants" event group include a set of nodes that, at least +% inside the specification, are descendants of the last node +% +% begin descendants +% ... +% end +% +% +% The "array" event group collects together some nodes in an array of +% nodes. This can be used, for instance, to specify matrices. +% +% begin array +% ... +% end + + + +% Create a new event +% +% #1 = event name (should be a valid lua identifier name) +% #2 = parameter (some text) +% +% Description: +% +% Adds a new event to the event sequence of the graph + +\def\pgfgdevent#1#2{% + \directlua{pgf.gd.interface.InterfaceToDisplay.createEvent('\pgfutil@luaescapestring{#1}', '\pgfutil@luaescapestring{#2}')}% +}% + + +% Start an event group +% +% #1 = kind of event group +% +% Description: +% +% Creates a begin event with #1 as the parameter of the begin +% event. + +\def\pgfgdbegineventgroup#1{% + \pgfgdevent{begin}{#1}% +}% + +% End an event group +% +% Description: +% +% Creates an end event. + +\def\pgfgdendeventgroup{% + \pgfgdevent{end}{}% +}% + + +% Creates an event group for the current TeX group +% +% #1 = event group name +% +% Description: +% +% Issues a begin event for #1 and, using \aftergroup, adds an end +% event at the end of the current tex group. + +\def\pgfgdeventgroup#1{% + \pgfgdbegineventgroup{#1}% + \aftergroup\pgfgdendeventgroup% +}% + + + + + +% +% Nodes +% + + + +% +% Callback method for \pgfpositionnodelater +% +% This function is called by \pgfnode whenever a node has been newly +% created inside a graph drawing scope. It will create a new vertex on +% the Lua layer. +% +\def\pgf@gd@positionnode@callback{% + {% + % evaluate coordinates + \pgfmathsetmacro{\pgf@gd@node@minx}{\pgfpositionnodelaterminx}% + \pgfmathsetmacro{\pgf@gd@node@miny}{\pgfpositionnodelaterminy}% + \pgfmathsetmacro{\pgf@gd@node@maxx}{\pgfpositionnodelatermaxx}% + \pgfmathsetmacro{\pgf@gd@node@maxy}{\pgfpositionnodelatermaxy}% + % Assemble the Path object: + \directlua{pgf.temp = require 'pgf.gd.model.Path'.new ()}% + \let\pgfsyssoftpath@movetotoken\pgf@gd@movetotoken% + \let\pgfsyssoftpath@linetotoken\pgf@gd@linetotoken% + \let\pgfsyssoftpath@rectcornertoken\pgf@gd@rectcornertoken% + \let\pgfsyssoftpath@curvetosupportatoken\pgf@gd@curvetosupportatoken% + \let\pgfsyssoftpath@closepathtoken\pgf@gd@closepathtoken% + \pgfpositionnodelaterpath% + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + % + {% + \pgf@process{\pgfpointanchor{\pgfpositionnodelatername}{center}} + \pgfsettransform{\csname pgf@sh@nt@\pgfpositionnodelatername\endcsname}% + \pgf@pos@transform{\pgf@x}{\pgf@y}% + \global\pgf@x=\pgf@x% + \global\pgf@y=\pgf@y% + }% + % call lua system library to create a lua node object + \directlua{ + pgf.gd.interface.InterfaceToDisplay.createVertex( + string.sub('\pgfutil@luaescapestring{\pgfpositionnodelatername}',30), % strip "not yet positionedPGFINTERNAL" + '\pgfutil@luaescapestring{\csname pgf@sh@ns@\pgfpositionnodelatername\endcsname}', + pgf.temp:pad((\pgf@sys@tonumber\pgf@xa+\pgf@sys@tonumber\pgf@ya)/2), % Padded path + \the\pgf@gd@parameter@stack@height, % Stack height + {% Binding info + x_min = \pgf@gd@node@minx, + y_min = \pgf@gd@node@miny, + x_max = \pgf@gd@node@maxx, + y_max = \pgf@gd@node@maxy, + tex_box_number = \pgfpositionnodelaterbox + }, + {% Anchors + center = require 'pgf.gd.model.Coordinate'.new(\pgf@sys@tonumber\pgf@x,\pgf@sys@tonumber\pgf@y) + } + ) + pgf.temp = nil + } + }% +}% + + +\def\pgf@gd@movetotoken#1#2{\directlua{pgf.temp:appendMoveto(\Pgf@geT#1,\Pgf@geT#2)}}% +\def\pgf@gd@linetotoken#1#2{\directlua{pgf.temp:appendLineto(\Pgf@geT#1,\Pgf@geT#2)}}% +\def\pgf@gd@rectcornertoken#1#2#3#4#5{% + \directlua{% + local x,y,dx,dy=\Pgf@geT#1,\Pgf@geT#2,\Pgf@geT#4,\Pgf@geT#5 + pgf.temp:appendMoveto(x,y) + pgf.temp:appendLineto(x,y+dy) + pgf.temp:appendLineto(x+dx,y+dy) + pgf.temp:appendLineto(x+dx,y) + pgf.temp:appendClosepath()% + }% +}% +\def\pgf@gd@curvetosupportatoken#1#2#3#4#5#6#7#8{\directlua{pgf.temp:appendCurveto(\Pgf@geT#1,\Pgf@geT#2,\Pgf@geT#4,\Pgf@geT#5,\Pgf@geT#7,\Pgf@geT#8)}}% +\def\pgf@gd@closepathtoken#1#2{\directlua{pgf.temp:appendClosepath()}}% + + +% Set options for an already existing node +% +% #1 = node name +% +% These node parameters of #1 will be updated with the current values +% of the node parameters. The node #1 must previously have been passed +% to the gd engine. If some of the options have already been set for +% the node, these settings will be overruled. + +\def\pgfgdsetlatenodeoption#1{% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.addToVertexOptions('\pgfutil@luaescapestring{#1}',\the\pgf@gd@parameter@stack@height) + } +}% + + + +% +% A callback for rendering (finally positioning) a node +% +% #1 = name of the node +% #2 = x min of the bounding box +% #3 = x max of the bounding box +% #4 = y min of the bounding box +% #5 = y max of the bounding box +% #6 = desired x pos of the node +% #7 = desired y pos of the node +% #8 = box register number of the TeX node +% #9 = animation code +% +% This callback will be called by the engine for every original node +% when it finally needs to placed at a final position. + +\def\pgfgdcallbackrendernode#1#2#3#4#5#6#7#8#9{% + {% + \def\pgfpositionnodelatername{#1} + \def\pgfpositionnodelaterminx{#2} + \def\pgfpositionnodelatermaxx{#3} + \def\pgfpositionnodelaterminy{#4} + \def\pgfpositionnodelatermaxy{#5} + \directlua{pgf.gd.interface.InterfaceCore.binding:retrieveBox(#8,\pgfpositionnodelaterbox)} + \def\pgf@temp{#9}% + \ifx\pgf@temp\pgfutil@empty% + \pgfpositionnodenow{\pgfqpoint{#6}{#7}}% + \else% + \pgfset{every graphdrawing animation/.try}% + \pgfset{every graphdrawing node animation/.try}% + #9% + \pgfuseid{pgf@gd}% + \pgfidscope% + \pgfpositionnodenow{\pgfqpoint{#6}{#7}}% + \endpgfidscope% + \fi% + }% +}% + +\ifx\pgfanimateattribute\pgfutil@undefined + \def\pgfanimateattribute#1#2{\tikzerror{You need to say \string\usetikzlibrary{animations} for animated graphs}}% +\fi + + +% Adds an edge to the graph +% +% #1 = first node +% #2 = second node +% #3 = edge direction +% #4 = edge options (will be executed in a protected environment) +% #5 = aux stuff (curtesy for TikZ -- edge nodes) +% +% Description: +% +% Creating an edge means that you tell the graph drawing algorithm +% that #1 and #2 are connected. The "kind" of connection is indicated +% by #3, which may be one of the following: +% +% -> = a directed edge (also known as an arc) from #1 to #2 +% -- = an undirected edge between #1 and #2 +% <- = a directed edge from #2 to #1, but with the "additional hint" +% that this is a "backward" edge. A graph drawing algorithm may +% or may not take this hint into account +% <-> = a bi-directed edge between #1 and #2. +% +% +% The parameters #4 and #5 are a bit more tricky. When an edge between +% two vertices of a graph is created via \pgfgdedge, nothing is +% actually done immediately. After all, without knowing the final +% positions of the nodes #1 and #2, there is no way of +% creating the actual drawing commands for the edge. Thus, the actual +% drawing of the edge is done only when the graph drawing algorithm is +% done (namely in the macro \pgfgdcallbackedge, see later). +% +% Because of this "delayed" drawing of edges, options that influence +% the edge must be retained until the moment when the edge is actually +% drawn. Parameters #4 and #5 store such options. +% +% Let us start with #4. This parameter should be set to a list of +% key-value pairs like +% +% /tikz/.cd, color=red, very thick, this edge must be vertical +% +% Some of these options may be of interest to the graph drawing +% algorithm (like the last option) while others will +% only be important during the drawing of edge (like the first +% option). The options that are important for the graph drawing +% algorithm must be passed to the algorithm via setting keys that have +% been declared using the handler .edge parameter (see +% above). +% +% The tricky part is that options that are of interest to the graph +% drawing algorithm must be executed *before* the algorithm starts, +% but the options as a whole are usually only executed during the +% drawing of the edges, which is *after* the algorithm has finished. +% +% To overcome this problem, the following happens: +% +% The options in #4 are executed "tentatively" inside +% \pgfgdedge. However, this execution is done in a "heavily guarded +% sandbox" where all effects of the options (like changing the +% color or the line width) do not propagate beyond the sandbox. Only +% the changes of the graph drawing edge parameters leave the +% sandbox. These parameters are then passed down to the graph drawing +% engine. +% +% Later, when the edge is drawn using \pgfgdcallbackedge, the options #4 +% are available once more and then they are executed normally. +% +% Note that when the options in #4 are executed, no path is +% preset. Thus, you typically need to start it with, say, /tikz/.cd. +% +% +% The text in #5 is some "auxiliary" text that is simply stored away +% and later directly to \pgfgdcallbackedge. This is a curtesy to TikZ, +% which can use it to store its node labels. +% +% Example: +% +% \pgfgdedge{A}{B}{->}{red}{} +% +\def\pgfgdedge#1#2#3#4#5{% + % Ok, setup sandbox + \begingroup% + \setbox0=\hbox{{% + \pgfinterruptpath% + \pgfgdprepareedge% + \pgfkeys{#4}% + % create edge in Lua + \toks0={#4}% + \toks1={#5}% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.createEdge( + '\pgfutil@luaescapestring{#1}','\pgfutil@luaescapestring{#2}','\pgfutil@luaescapestring{#3}', + \the\pgf@gd@parameter@stack@height, + { pgf_options = '\pgfutil@luaescapestring{\the\toks0}', + pgf_edge_nodes = '\pgfutil@luaescapestring{\the\toks1}', + }) + }% + \endpgfinterruptpath% + }}% + \endgroup% +}% + +\let\pgfgdprepareedge=\pgfutil@empty +\def\pgfgdaddprepareedgehook#1{\expandafter\def\expandafter\pgfgdprepareedge\expandafter{\pgfgdprepareedge#1}}% + + +\newif\ifpgf@gd@nodes@behind@edges + + + +% Define a callback for rendering edges +% +% #1 = macro name +% +% Descriptions: +% +% This is a callback from the graph drawing engine. At the end of the +% creation of a graph, when the nodes have been positioned, this macro +% is called once for each edge. The macro should take the following +% parameters: +% +% #1 = from node, optionally followed by "." and the tail anchor +% #2 = to node, optionally followed by "." and the head anchor +% #3 = direction (<-, --, ->, or <->) +% #4 = original options +% #5 = aux text (typically edge nodes) +% #6 = algorithm-generated options +% #7 = bend information +% #8 = animations +% +% The first five parameters are the original values that were passed +% down to the \pgfgdedge command. +% +% #6 contains options that have been "computed by the algorithm". For +% instance, an algorithm might have determined, say, flow capacities +% for edges and it might now wish to communicate this information back +% to the upper layers. These options should be executed with the path +% /graph drawing. +% +% #7 contains algorithmically-computed information concerning how the +% edge should bend. This will be a text like +% "--(10pt,20pt)--(30pt,40pt)" in tikz-syntax, using the path +% operations "--", "..controls" and "--cycle". +% +% By default, a simple line is drawn between the nodes. Usually, you +% will wish to install a more "fancy" callback, here. + +\def\pgfgdsetedgecallback#1{\let\pgfgdcallbackedge=#1}% + +\def\pgfgddefaultedgecallback#1#2#3#4#5#6#7#8{% + {% + \def\pgf@temp{#8}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfset{every graphdrawing animation/.try}% + \pgfset{every graphdrawing edge animation/.try}% + #8% + \pgfuseid{pgf@gd}% + \pgfidscope% + \fi% + \pgfscope + \pgfpathmoveto{ + \pgfutil@in@.{#1}% + \ifpgfutil@in@ + \pgf@gd@unravel#1\relax% + \else + \pgfpointshapeborder{#1}{\pgfpointanchor{#2}{center}} + \fi + } + \pgfpathlineto{ + \pgfutil@in@.{#2}% + \ifpgfutil@in@ + \pgf@gd@unravel#2\relax% + \else + \pgfpointshapeborder{#2}{\pgfpointanchor{#1}{center}} + \fi + } + \pgfusepath{stroke} + \endpgfscope + \ifx\pgf@temp\pgfutil@empty% + \else% + \endpgfidscope% + \fi% + } +}% + +\pgfgdsetedgecallback{\pgfgddefaultedgecallback}% + +\def\pgf@gd@unravel#1.#2\relax{% + \pgfpointanchor{#1}{#2}% +}% + + + + +% Callbacks: Called before the shipout of nodes and edges starts +% +% First, the general begin shipout is called. Then, the node shipout +% starts, the nodes are created, and then the end of the node shipout +% is signaled. Next, the edge shipout starts and ends. Finally, the +% end shipout is called. + +\def\pgfgdcallbackbeginshipout{% + \pgfscope% + \catcode`\@=11\relax% + \setbox\pgf@gd@prekind@box=\box\pgfutil@voidb@x% + \setbox\pgf@gd@postkind@box=\box\pgfutil@voidb@x% +}% +\def\pgfgdcallbackendshipout{% + \box\pgf@gd@prekind@box% + \ifpgf@gd@nodes@behind@edges% + \box\pgf@gd@node@box% + \box\pgf@gd@edge@box% + \else% + \box\pgf@gd@edge@box% + \box\pgf@gd@node@box% + \fi% + \box\pgf@gd@postkind@box% + \endpgfscope +}% + +\newbox\pgf@gd@node@box +\newbox\pgf@gd@edge@box +\newbox\pgf@gd@prekind@box +\newbox\pgf@gd@postkind@box + +\def\pgfgdcallbackbeginnodeshipout{% + \setbox\pgf@gd@node@box=\hbox\bgroup% +}% +\def\pgfgdcallbackendnodeshipout{% + \egroup% +}% + +\def\pgfgdcallbackbeginedgeshipout{% + \setbox\pgf@gd@edge@box=\hbox\bgroup% +}% + +\def\pgfgdcallbackendedgeshipout{% + \egroup +}% + + + + +% Generate a node +% +% This callback is called from the engine whenever an algorithm +% generates a new node internally. +% +% #1 = name of the node +% #2 = shape of the node +% #3 = options generated by the algorithm in key-value syntax. The set +% of generated options is algorithm-dependent. +% #4 = text +% +% This is an internal function and will be called by the binding layer + +\def\pgfgdcallbackcreatevertex#1#2#3#4{% + { + \pgfkeys{#3} + \pgfnode{#2}{\pgfkeysvalueof{/graph drawing/generated + node/anchor}}{#4}{#1}{\pgfkeysvalueof{/graph drawing/generated + node/use path}} + } +}% + +\pgfkeys{ + /graph drawing/generated node/anchor/.initial=center, + /graph drawing/generated node/use path/.initial=\pgfusepath{} +}% + + + +% +% Sublayouts +% +% Description: For a general introduction to (sub)layouts, see +% Section~\ref{section-gd-sublayouts} in the manual. +% + +\def\pgfgdbeginlayout{ + \begingroup + \pgfgdlayoutscopeactivetrue + \advance\pgf@gd@parameter@stack@height by1\relax% + \directlua{pgf.gd.interface.InterfaceToDisplay.pushLayout(\the\pgf@gd@parameter@stack@height)} +}% + +\def\pgfgdendlayout{ + \endgroup% +}% + + + + +% Creates a subgraph node +% +% #1 = name +% #2 = node options +% #3 = node text +% +% Description: +% +% A subgraph node is a node that "surrounds" the nodes of a +% subgraph. The special property of a subgraph node opposed to a +% normal node is that it is created only after the subgraph has been +% laid out. However, the difference to a collection like "hyper" is +% that the node is available immediately as a normal node in the sense +% that you can connect edges to it. +% +% What happens internally is that subgraph nodes get "registered" +% immediately both on the pgf level and on the lua level, but the +% actual node is only created inside the layout pipeline using a +% callback. The actual node creation happens when the innermost layout +% in which the subgraph node is declared has finished. +% +% When you create a subgraph node using this macro, you also start a +% collection (of an internal kind) that stores the subgraph. All +% following nodes in the current TeX scope will become part of this +% collection. +% +% See |InterfaceToDisplay.pushSubgraphVertex| for details. + +\def\pgfgdsubgraphnode#1#2#3{% + \advance\pgf@gd@parameter@stack@height by1\relax% + {% + % create edge in Lua + \toks0={#2}% + \toks1={#3}% + \directlua{pgf.gd.interface.InterfaceToDisplay.pushSubgraphVertex% + ('\pgfutil@luaescapestring{#1}',\the\pgf@gd@parameter@stack@height, + { + shape = 'rectangle', % typically overwritten by the pgf_options: + pgf_options = '\pgfutil@luaescapestring{\the\toks0}', + text = '\pgfutil@luaescapestring{\the\toks1}', + }) + }% + } +}% + +\def\pgfgdsubgraphnodecontents#1{% helper function + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \vrule width0pt height\pgfkeysvalueof{/graph drawing/subgraph bounding box height}\hfil}% +}% + +\pgfgdset{ + subgraph point cloud/.initial=, + subgraph bounding box width/.initial=, + subgraph bounding box height/.initial=, +}% + + +% +% Requests +% +% Description: +% +% This key is used to ``request'' a graph drawing scope and a +% layout. The objective of this key is to make it easier for users and +% algorithm designers to control the slightly involved +% back-and-forth-calling between the different layers. +% +% This key does the following: When called inside a pgfpicture +% (otherwise, the call is "illegal"), it will call a call-back with +% two parameters. This callback will get passed some code that should +% be executed at the beginning of ``the next scope'' and some code +% that should be executed at the end of that scope. +% +% The code passed to the callbacks will have a different effect, +% depending on whether we are currently inside a layout scope or not +% (if no graph drawing scope is open, we are +% not inside a layout). If we are not inside a layout scope (or if the +% layout scope has been interrupted), the code will issue a +% \pgfgdbeginscope command in the opening code and a corresponding +% scope ending command in the closing code. Next, the two code pieces +% always contain \pgfgdbeginlayout and \pgfgdendlayout. +% +% Note that the "@request scope and layout" key will not immediately +% trigger a layout scope to be created; rather, the TikZ callback will +% call it only at the beginning of the scope, which will be after +% other options in the current list of options have been parsed. So, +% when you write \graph [binary tree layout, significant sep=2em] ..., +% the "significant sep" option has an effect despite being given +% *after* the "@request scope and layout" key since the actual opening +% of the scope happens only before the "..." part is parsed. + +\pgfgdset{@request scope and layout/.code=\pgfgd@requestcallback{\pgfgdbeginrequest}{\pgfgdendrequest}}% + +\def\pgfgd@requestcallback#1#2{% + #1\def\pgf@gd@after@request{#2\egroup}\bgroup\aftergroup\pgf@gd@after@request% +}% Default for basic layer + +\def\pgfgdbeginrequest{% + \ifpgfgdlayoutscopeactive% + \else% + \expandafter\pgfgdbeginscope% + \fi% + \pgfgdbeginlayout% +}% +\def\pgfgdendrequest{% + \pgfgdendlayout% + \ifpgfgdlayoutscopeactive% + \else% + \expandafter\pgfgdendscope% + \fi% +}% +\newif\ifpgfgdlayoutscopeactive + + +% Set the request callback +% +% #1 = A macro +% +% Description: +% +% Sets the request callback as described in the "@request scope and +% layout" key. + +\def\pgfgdsetrequestcallback#1{\let\pgfgd@requestcallback#1}% + + + + +% +% An if that is true exactly if we are inside a graph drawing scope +% + +\newif\ifpgfgdgraphdrawingscopeactive + + +% Begins a new graph drawing scope +% +% Description: +% +% Inside a graph drawing scope, all pgf nodes that are newly created +% are automatically passed to the graph drawing engine. In contrast, +% edges have to be indicated explicitly using the macro \pgfgdedge +% (this is because it is somewhat unclear what, exactly, should count +% as an edge). Naturally, users typically will not call \pgfgdedge +% explicitly, but have styles and keys invoke it internally. +% +% Usage: +% +% \pgfgdset{algorithm=somealgorithm} +% \pgfgdbeginscope +% \pgfnode{rectangle}{center}{A}{A}{} +% \pgfnode{rectangle}{center}{B}{B}{} +% \pgfnode{rectangle}{center}{C}{C}{} +% \pgfgdedge{A}{B}{->}{}{} +% \pgfgdedge{B}{C}{->}{}{} +% \pgfgdedge{C}{A}{->}{}{} +% \pgfgdendscope +% +% Naturally, users will typically use TikZ's somewhat simpler syntax: ' +% +% \tikz \graph [some algorithm] { A -> B -> C -> A }; + +\def\pgfgdbeginscope{% + \begingroup % Protecting scope + % get options + \directlua{ + pgf.gd.interface.InterfaceToDisplay.beginGraphDrawingScope(\the\pgf@gd@parameter@stack@height) + }% + \begingroup % Inner scope, the actual nodes will be inserted after + % this scope has been closed + % Indicate that we are now inside a graph drawing scope + \pgfgdgraphdrawingscopeactivetrue + % Switch on late positioning + \pgfpositionnodelater{\pgf@gd@positionnode@callback} + % Switch on late edges + \pgfgd@latecallback% + % Kill transformations (will be added by the position now + % macros) + \pgftransformreset +}% + + + +% The following is used to ensure that if we need to resume the graph +% drawing (through co-routines), we pass control back to TeX +% first. Otherwise, new text input levels are created and there may be +% only 15 of these... +\newif\ifpgfgdresumecoroutine + + +% Ends a graph drawing scope +% +% Description: +% +% This macro invokes the selected graph drawing algorithm and +% ships out all nodes within this scope +% +% See \pgfgdbeginscope + +\def\pgfgdendscope{% + \pgfgdresumecoroutinefalse% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.runGraphDrawingAlgorithm() + }% + \pgfutil@loop% + \ifpgfgdresumecoroutine% + \pgfgdresumecoroutinefalse% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.resumeGraphDrawingCoroutine() + }% + \pgfutil@repeat% + \endgroup% + % Late positioning has ended + \directlua{pgf.gd.interface.InterfaceToDisplay.renderGraph()}% + \directlua{pgf.gd.interface.InterfaceToDisplay.endGraphDrawingScope()}% + \endgroup% +}% + + + + + + +% Hook into graph specification +% +% #1 = code +% +% Description: +% +% Allows you to specify code that should be active while the graph +% drawing engine collects the information concerning the graph, but +% which should no longer be active when the graph is rendered. + +\def\pgfgdaddspecificationhook#1{ + \expandafter\def\expandafter\pgfgd@latecallback\expandafter{\pgfgd@latecallback#1} +}% +\let\pgfgd@latecallback\pgfutil@empty + + + + + + + + +% Loading further libraries + +% Include a graph drawing library file. +% +% #1 = List of names of library file. +% +% Description: +% +% This command includes a list of graph drawing library files. For +% each file X in the list, the file pgf.gd.X.lua is included using +% |require|. +% +% For the convenience of Context users, both round and square brackets +% are possible for the argument. +% +% +% Example: +% +% \usegdlibrary{trees} +% \usegdlibrary[force,circular] + +\def\usegdlibrary{\pgfutil@ifnextchar[{\use@gdlibrary}{\use@@gdlibrary}}%}% +\def\use@gdlibrary[#1]{\use@@gdlibrary{#1}}% +\def\use@@gdlibrary#1{% + \edef\pgf@list{#1}% + \pgfutil@for\pgf@temp:=\pgf@list\do{% + \expandafter\pgfkeys@spdef\expandafter\pgf@temp\expandafter{\pgf@temp}% + \ifx\pgf@temp\pgfutil@empty + \else + \directlua{if not pgf_lookup_and_require('\pgf@temp') then + tex.print('\pgfutil@luaescapestring{\noexpand\pgferror{Graph drawing library '\pgf@temp' not found}}') + end} + \fi + } +}% + +% LaTeX uses kpathsea for file lookup while ConTeXt uses its +% resolvers. Luckily, kpathsea is still accessible in ConTeXt in a +% subtable kpse.original which we use if kpse.find_file is nil. +{% +\catcode`\%=11 +\directlua{ + function pgf_lookup_and_require(name) + local sep = package.config:sub(1,1) + local function lookup(name) + local sub = name:gsub('%.',sep) + local find_file = context and + resolvers.findfile or + kpse.find_file + if find_file(sub, 'lua') then + require(name) + elseif find_file(sub, 'clua') then + collectgarbage('stop') + require(name) + collectgarbage('restart') + else + return false + end + return true + end + return + lookup('pgf.gd.' .. name .. '.library') or + lookup('pgf.gd.' .. name) or + lookup(name .. '.library') or + lookup(name) + end +} +}% + + +% +% Ok, fire up the system by creating the binding! +% +\directlua{ + require 'pgf.gd.interface.InterfaceToDisplay' + pgf.gd.interface.InterfaceToDisplay.bind(require 'pgf.gd.bindings.BindingToPGF') +}% + + + +% +% Special setup for keys that are declared by the above libraries, but +% that have a special meaning on the display layer. +% + +\pgfkeys{/graph drawing/nodes behind edges/.append code=\csname pgf@gd@nodes@behind@edges#1\endcsname}% +\pgfkeys{/graph drawing/nodes behind edges/.default=true}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex new file mode 100644 index 0000000000..3a1308320c --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex @@ -0,0 +1,17 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.examples.code.tex} + +\usepgflibrary{graphdrawing}% + +\usegdlibrary{examples}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex new file mode 100644 index 0000000000..a06d99c5d5 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex @@ -0,0 +1,136 @@ +% Copyright 2019 by Jannis Pohlmann +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.force.code.tex} + + + +\usepgflibrary{graphdrawing}% + +\usegdlibrary{force}% + +\endinput + + + +% +% Definition of spring algorithms as well as options to configure them. +% + +\pgfgdset{ + force based/.cd, + % + iterations/.graph parameter=number, + iterations/.parameter initial=500, + % + cooling factor/.graph parameter=number, + cooling factor/.parameter initial=0.95, + % + initial step dimension/.graph parameter=number, + initial step dimension/.parameter initial=0, + % + convergence tolerance/.graph parameter=number, + convergence tolerance/.parameter initial=0.01, + % + spring constant/.graph parameter=number, + spring constant/.parameter initial=0.01, + % + approximate electric forces/.graph parameter=boolean, + approximate electric forces/.parameter initial=false, + approximate electric forces/.default=true, + % + electric force order/.graph parameter=number, + electric force order/.parameter initial=1, + % + % Parameters related to the multilevel approach where the input graph + % is iteratively coarsened into graphs with fewer nodes, until either + % the number of nodes is small enough or the number of nodes in the + % could not be reduced by at least a user-defined ratio. + % + coarsen/.graph parameter=boolean, + coarsen/.parameter initial=true, + coarsen/.default=true, + % + coarsening/.code=\pgfkeys{ + /graph drawing/force based/coarsening/.cd, + #1 + }, + % + coarsening/downsize ratio/.graph parameter=number, + coarsening/downsize ratio/.parameter initial=0.25, + % + coarsening/minimum graph size/.graph parameter=number, + coarsening/minimum graph size/.parameter initial=2, + % + coarsening/collapse independent edges/.graph parameter=boolean, + coarsening/collapse independent edges/.parameter initial=true, + coarsening/collapse independent edges/.default=true, + % + coarsening/connect independent nodes/.graph parameter=boolean, + coarsening/connect independent nodes/.parameter initial=false, + coarsening/connect independent nodes/.default=true, + % + % Node parameters for spring algorithms. + % + % + % Edge parameters for spring algorithms. + % +}% + +\pgfgddeclareforwardedkeys{/graph drawing}{ + % + electric charge/.node parameter=number, + electric charge/.parameter initial=1, +} + + +% +% Spring algorithm based on the paper +% +% "Efficient, High-Quality Force-Directed Graph Drawing" +% Yifan Hu, 2006 +% +\pgfgddeclarealgorithmkey + {spring layout} + {force based} + { + algorithm=pgf.gd.force.SpringHu2006 + } + + +% +% Spring-electrical algorithm based on the paper +% +% "Efficient, High-Quality Force-Directed Graph Drawing" +% Yifan Hu, 2006 +% +\pgfgddeclarealgorithmkey + {spring electrical layout} + {force based} + { + algorithm=pgf.gd.force.SpringElectricalHu2006, + force based/spring constant=0.2, + } + + + +% +% Spring-electrical algorithm based on the paper +% +% "A Multilevel Algorithm for Force-Directed Graph Drawing" +% C. Walshaw, 2000 +% +\pgfgddeclarealgorithmkey + {spring electrical layout'} + {force based} + { + algorithm=pgf.gd.force.SpringElectricalWalshaw2000, + force based/spring constant=0.01, + force based/convergence tolerance=0.001, + } diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex new file mode 100644 index 0000000000..322296b11b --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex @@ -0,0 +1,17 @@ +% Copyright 2019 by Jannis Pohlmann +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.layered.code.tex} + +\usepgflibrary{graphdrawing}% + +\usegdlibrary{layered}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex new file mode 100644 index 0000000000..2c05576a86 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex @@ -0,0 +1,19 @@ +% Copyright 2019 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.trees.code.tex} + + +\usepgflibrary{graphdrawing}% +\usepgflibrary{graphdrawing.layered}% + +\usegdlibrary{trees}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/tikzlibrarygraphdrawing.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/tikzlibrarygraphdrawing.code.tex new file mode 100644 index 0000000000..aac7311e34 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/tikzlibrarygraphdrawing.code.tex @@ -0,0 +1,262 @@ +% Copyright 2018 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{tikzlibrarygraphdrawing.code.tex} + +\usepgflibrary{graphdrawing}% + +\def\tikz@lib@ensure@gd@loaded{}% + + +% Patch the level and sibling distances so that gd and plain tikz are +% in sync +\tikzset{level distance=1cm, sibling distance=1cm}% + +% Patch node distance because of its special syntax. + +\pgfkeysgetvalue{/graph drawing/node distance/.@cmd}\tikz@lib@gd@node@dist@path +\pgfkeyslet{/graph drawing/node distance/orig/.@cmd}\tikz@lib@gd@node@dist@path + +\pgfkeysdef{/graph drawing/node distance}{ + \pgfutil@in@{ and }{#1}% + \ifpgfutil@in@% + \tikz@gd@convert@and#1\pgf@stop% + \else% + \tikz@gd@convert@and#1 and #1\pgf@stop% + \fi% +}% +\def\tikz@gd@convert@and#1 and #2\pgf@stop{\pgfkeys{/graph drawing/node distance/orig={#1}}}% + + + + +% +% Setup graph drawing for tikz +% + +\def\tikz@gd@request@callback#1#2{% + \tikzset{ + execute at begin scope={ + \tikzset{ + --/.style={arrows=-}, + -!-/.style={draw=none,fill=none}, + } + \pgfgdsetedgecallback{\pgfgdtikzedgecallback}% + % + % Setup for plain syntax + % + \pgfgdaddspecificationhook{\tikz@lib@gd@spec@hook}% + #1 + \let\tikzgdeventcallback\pgfgdevent% + \let\tikzgdeventgroupcallback\pgfgdeventgroup% + \let\tikzgdlatenodeoptionacallback\pgfgdsetlatenodeoption% + }, + execute at end scope={% + #2% + } + }% +}% + +\pgfgdsetrequestcallback\tikz@gd@request@callback + + + +\pgfgdappendtoforwardinglist{/tikz/,/tikz/graphs/}% + +\def\tikz@lib@gd@spec@hook{% + \tikzset{ + edge macro=\tikz@gd@plain@edge@macro, + /tikz/at/.style={/graph drawing/desired at={##1}}, + % + % Setup for the tree syntax (do this late so that grow options + % are still valid after a layout has been chosen) + % + /tikz/growth function=\relax, + /tikz/edge from parent macro=\tikz@gd@edge@from@parent@macro, + % + % Setup for the graphs syntax + % + /tikz/graphs/new ->/.code n args={4}{\tikz@lib@gd@edge{##1}{##2}{->}{/tikz,##3}{##4}}, + /tikz/graphs/new <-/.code n args={4}{\tikz@lib@gd@edge{##1}{##2}{<-}{/tikz,##3}{##4}}, + /tikz/graphs/new --/.code n args={4}{\tikz@lib@gd@edge{##1}{##2}{--}{/tikz,##3}{##4}}, + /tikz/graphs/new <->/.code n args={4}{\tikz@lib@gd@edge{##1}{##2}{<->}{/tikz,##3}{##4}}, + /tikz/graphs/new -!-/.code n args={4}{\tikz@lib@gd@edge{##1}{##2}{-!-}{/tikz,##3}{##4}}, + /tikz/graphs/placement/compute position/.code=,% + } +}% + +% wrapper for \pgfgdedge +\def\tikz@lib@gd@edge#1#2{% + \pgfgdedge{\tikz@pp@name{#1}}{\tikz@pp@name{#2}}% +} + +\pgfgdaddprepareedgehook{ + \tikz@enable@edge@quotes% + \let\tikz@transform=\pgfutil@empty% + \let\tikz@options=\pgfutil@empty% + \let\tikz@tonodes=\pgfutil@empty% +}% + + +\tikzset{ + parent anchor/.forward to=/graph drawing/tail anchor, + child anchor/.forward to=/graph drawing/head anchor +}% + +\def\pgfgdtikzedgecallback#1#2#3#4#5#6#7#8{% + \def\pgf@temp{#8}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfscope% + \pgfset{every graphdrawing animation/.try}% + \pgfset{every graphdrawing edge animation/.try}% + #8% + \pgfuseid{pgf@gd}% + \pgfidscope% + \fi% + \begingroup + \draw (#1) + edge [to path={#7 \tikztonodes},#3,#4,/graph drawing/.cd,#6,/tikz/.cd] + #5 + (#2); + \endgroup + \ifx\pgf@temp\pgfutil@empty% + \else% + \endpgfidscope% + \endpgfscope% + \fi% +}% + +\def\tikz@gd@edge@from@parent@macro#1#2{ + [/utils/exec=\tikz@lib@gd@edge{\tikzparentnode}{\tikzchildnode}{--}{/tikz,#1}{#2}] +}% + +\def\tikz@gd@plain@edge@macro#1#2{ + \tikz@lib@gd@edge{\tikztostart}{\tikztotarget}{--}{/tikz,#1}{#2} +}% + + + +% +% Conversions: Convert coordinates into pairs of values surrounded by +% braces. +% + +\pgfgdset{ + conversions/canvas coordinate/.code={% + \tikz@scan@one@point\pgf@process#1% + \pgfmathsetmacro{\tikz@gd@temp@x}{\pgf@x} + \pgfmathsetmacro{\tikz@gd@temp@y}{\pgf@y} + \edef\pgfgdresult{pgf.gd.model.Coordinate.new(\tikz@gd@temp@x,\tikz@gd@temp@y)} + }, + conversions/coordinate/.code={% + \tikz@scan@one@point\pgf@process#1% + \pgfmathsetmacro{\tikz@gd@temp@x}{\pgf@x} + \pgfmathsetmacro{\tikz@gd@temp@y}{\pgf@y} + \edef\pgfgdresult{pgf.gd.model.Coordinate.new(\tikz@gd@temp@x,\tikz@gd@temp@y)} + } +}% + + + +% +% Overwrite node callback +% + +\def\pgfgdcallbackcreatevertex#1#2#3#4{% + \node[every generated node/.try,name={#1},shape={#2},/graph drawing/.cd,#3]{#4};% +}% + + +% +% Subgraph handling +% + +% "General" text placement for subgraph nodes that works with all node +% kinds. + +\tikzset{ + subgraph text top/.code=\tikz@lg@simple@contents@top{#1},% + subgraph text top/.default=text ragged, + subgraph text bottom/.code=\tikz@lg@simple@contents@bottom{#1},% + subgraph text bottom/.default=text ragged, + subgraph text sep/.initial=.1em, + subgraph text none/.code={ + \def\pgfgdsubgraphnodecontents##1{% + \pgf@y=\pgfkeysvalueof{/graph drawing/subgraph bounding box height}\relax% + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \vrule width0pt height.5\pgf@y depth.5\pgf@y\hfil}% + }% + }, +}% + +\def\tikz@lg@simple@contents@top#1{% + \def\pgfgdsubgraphnodecontents##1{% + \vbox{% + \def\pgf@temp{##1}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \ifx\pgf@temp\pgfutil@sptoken% + \else% + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \hsize=\pgfkeysvalueof{/graph drawing/subgraph bounding box width}\relax% + \vbox{\noindent\strut\tikzset{#1}\tikz@text@action\pgf@temp}% + }% + \fi% + \fi% + \pgfmathparse{\pgfkeysvalueof{/tikz/subgraph text sep}}% + \kern\pgfmathresult pt\relax% + \pgf@y=\pgfkeysvalueof{/graph drawing/subgraph bounding box height}\relax% + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \vrule width0pt height.5\pgf@y depth.5\pgf@y\hfil}% + }% + }% +}% + +\def\tikz@lg@simple@contents@bottom#1{% + \def\pgfgdsubgraphnodecontents##1{% + {% + \pgf@y=\pgfkeysvalueof{/graph drawing/subgraph bounding box height}\relax% + \setbox0=\vbox{% + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{\vrule width0pt height\pgf@y\hfil}% + \pgfmathparse{\pgfkeysvalueof{/tikz/subgraph text sep}}% + \kern\pgfmathresult pt\relax% + \def\pgf@temp{##1}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \ifx\pgf@temp\pgfutil@sptoken% + \else% + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \hsize=\pgfkeysvalueof{/graph drawing/subgraph bounding box width}\relax% + \vbox{\noindent\strut\tikzset{#1}\tikz@text@action\pgf@temp}% + }% + \fi% + \fi% + }% + \pgf@ya=\ht0\relax% + \advance\pgf@ya by-.5\pgf@y\relax% + \ht0=.5\pgf@y\relax% + \dp0=\pgf@ya\relax% + \box0\relax% + }% + }% +}% + +\tikzset{subgraph text top}% + +\tikzset{ + subgraph nodes/.style={/tikz/every subgraph node/.style={#1}}, + graphs/subgraph nodes/.style={/tikz/every subgraph node/.style={#1}}, + graphs/@graph drawing setup/.style={/graph drawing/anchor at={(\tikz@lastx,\tikz@lasty)}} +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.barcharts.code.tex b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.barcharts.code.tex new file mode 100644 index 0000000000..3ac0d476f9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.barcharts.code.tex @@ -0,0 +1,135 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarydatavisualization.barcharts.code.tex} + +\usepgfmodule{datavisualization}% + + +% +% This file defines additional data visualization classes. +% + + +\pgfooclass{candle stick visualizer} +{% + \attribute attribute;% + \attribute offset;% + \attribute use path rise=\pgfsetfillcolor{white}\pgfusepath{fill,stroke};% + \attribute use path fall=\pgfsetfillcolor{black}\pgfusepath{fill,stroke};% + \attribute use path wick=\pgfusepath{stroke};% + + \method candle stick visualizer(#1) { + \pgfooeset{attribute}{#1} + \pgfoothis.set stick width(4pt) + }% + + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,visualize,visualize datapoint signal) + }% + + \method set stick width(#1) { + \pgfmathparse{#1} + \pgfmathdivide{\pgfmathresult}{2} + \let\pgf@dv@lib@w=\pgfmathresult + % Compute the normalized vector: + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute}}{1} + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@lower% + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute}}{10} + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@upper% + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\pgf@dv@lib@upper}{\pgf@dv@lib@lower}}}% + % Rotate by 90 degrees + \pgf@xa=\pgf@x% + \pgf@x=-\pgf@dv@lib@w\pgf@y% + \pgf@y=\pgf@dv@lib@w\pgf@xa% + \edef\pgf@dv@lib@temp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfoolet{offset}\pgf@dv@lib@temp + }% + + \method set use path rise(#1) { + \pgfooset{use path rise}{#1} + }% + + \method set use path fall(#1) { + \pgfooset{use path fall}{#1} + }% + + \method visualize() { + { + \pgfooget{attribute}\pgf@lib@attribute% + \pgfkeysgetvalue{/data point/\pgf@lib@attribute/low}\pgf@lib@low + \pgfkeysgetvalue{/data point/\pgf@lib@attribute/high}\pgf@lib@high + \pgfkeysgetvalue{/data point/\pgf@lib@attribute/entry}\pgf@lib@entry + \pgfkeysgetvalue{/data point/\pgf@lib@attribute/exit}\pgf@lib@exit + \ifx\pgf@lib@low\pgfutil@empty\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@low\relax\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@high\pgfutil@empty\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@high\relax\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@entry\pgfutil@empty\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@entry\relax\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@exit\pgfutil@empty\pgf@dv@lib@cs@skiptrue\fi + \ifx\pgf@lib@exit\relax\pgf@dv@lib@cs@skiptrue\fi + \ifpgf@dv@lib@cs@skip% + \else% + \begin{pgfscope} + % Ok, compute low point + \pgfkeyssetvalue{/data point/\pgf@lib@attribute}\pgf@lib@low + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@lowpoint% + % Ok, compute hight point + \pgfkeyssetvalue{/data point/\pgf@lib@attribute}\pgf@lib@high + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@highpoint% + % Compute entry and exit + \pgfkeyssetvalue{/data point/\pgf@lib@attribute}\pgf@lib@entry + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@entrypoint% + \pgfkeyssetvalue{/data point/\pgf@lib@attribute}\pgf@lib@exit + \pgfcanvaspositionofdatapoint% + \pgfsettocanvasposition\pgf@dv@lib@exitpoint% + \ifdim\pgf@lib@entry pt<\pgf@lib@exit pt\relax% + \pgf@dv@lib@risetrue% + \fi% + \ifpgf@dv@lib@rise + \let\pgf@dv@lib@a=\pgf@dv@lib@entrypoint + \let\pgf@dv@lib@b=\pgf@dv@lib@exitpoint + \else + \let\pgf@dv@lib@a=\pgf@dv@lib@exitpoint + \let\pgf@dv@lib@b=\pgf@dv@lib@entrypoint + \fi + % Start drawing... + \pgfpathmoveto{\pgf@dv@lib@lowpoint} + \pgfpathlineto{\pgf@dv@lib@a} + \pgfpathmoveto{\pgf@dv@lib@highpoint} + \pgfpathlineto{\pgf@dv@lib@b} + \pgfoovalueof{use path wick} + \pgfpathmoveto{\pgfpointadd{\pgf@dv@lib@a}{\pgfoovalueof{offset}}} + \pgfpathlineto{\pgfpointadd{\pgf@dv@lib@b}{\pgfoovalueof{offset}}} + \pgfpathlineto{\pgfpointadd{\pgf@dv@lib@b}{\pgfpointscale{-1}{\pgfoovalueof{offset}}}} + \pgfpathlineto{\pgfpointadd{\pgf@dv@lib@a}{\pgfpointscale{-1}{\pgfoovalueof{offset}}}} + \pgfpathclose + \ifpgf@dv@lib@rise + \pgfoovalueof{use path rise} + \else + \pgfoovalueof{use path fall} + \fi + \end{pgfscope}% + \fi + } + }% + + \newif\ifpgf@dv@lib@cs@skip + \newif\ifpgf@dv@lib@rise +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.formats.functions.code.tex b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.formats.functions.code.tex new file mode 100644 index 0000000000..d1e87cb1f7 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.formats.functions.code.tex @@ -0,0 +1,209 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarydatavisualization.formats.functions.code.tex} + +\usepgfmodule{datavisualization}% + + + + +% Function evaluator +% +% (This uses TeX evaluation and is slow. *You have been warned*.) +% +% Description: +% +% The data contains the description of variables and functions. +% +% The format for the variables is +% +% var : interval "[":"]" [ step | samples ]; +% +% (The first two [ and ] are "real", the second pair means "optional", +% see the examples.) +% +% +% The format for the functions is +% +% func = ; +% +% Additionally, the variables and functions stored in the keys +% /pgf/data/vars and /pgf/data/funcs will also be used, the format for +% them is the same as above. +% +% The is always the name of a (data point) attribute. Inside +% the it can be accessed using the \value macro, which is +% defined locally, here. +% +% Newlines are not important, everything is gathered into a single +% line, the semicolons are used to detect the beginnings and ends of +% declarations. +% +% With everything setup in this way, for each variable, the variable +% ranges through the values between start and end, either with the +% given step or the given number of samples. If neither is given, the +% current value of /pgf/data visualization/samples is used. If there +% are multiple variables, they all range over their respective +% intervals independently. Thus, "var x = [0,1]; var y = [0:1];", +% assuming samples=25, gives you 625 data points. +% +% As the variables range over their respective values, the functions +% are evaluated using the function stored in /pgf/data/evaluator. By +% default this is set to \pgfmathparse, but +% you can use a different parser, if you like. +% +% Example: +% +% data [format=function] { +% +% % This is a parametric plot with the parameter called t. +% var t : interval [0:360] samples 60; +% +% % Let's draw a circle: +% func x = sin(\value t); +% func y = cos(\value t); +% } +% +% data [format=function] { +% +% % This a surface plot data... +% var x : interval [0:1]; +% var y : interval [0:1]; +% +% % Let's draw a circle: +% func height = \value x*\value x + \value y*\value y; +% } + +\pgfdeclaredataformat{function} +{ % no catcode code +} +{ % Startup + % Init collectors + \let\value=\relax% avoid expansion + \pgfkeysgetvalue{/pgf/data/vars}\pgf@lib@dv@collector +} +{% Line arguments + #1% +} +{ % Line action + \edef\pgf@lib@dv@collector{\pgf@lib@dv@collector\space #1}% +} +{% Ignore empty lines +} +{% + \edef\pgf@lib@dv@collector{\pgf@lib@dv@collector\space \pgfkeysvalueof{/pgf/data/funcs}}% + \let\pgf@lib@dv@parsed\pgfutil@empty% + % launch parser on the result + \expandafter\pgf@lib@dv@func@parse \pgf@lib@dv@collector\pgf@stop% + \let\value\pgf@lib@dv@getval + \pgf@lib@dv@parsed\pgfdatapoint\pgfutil@gobble\pgf@stop% +}% + +\pgfkeys{ + /pgf/data/vars/.initial=, + /pgf/data/funcs/.initial=, + /pgf/data/evaluator/.initial=\pgfmathparse, + /pgf/data/samples/.initial=25}% + +\def\pgf@lib@dv@getval#1{\pgfkeysvalueof{/data point/#1}}% + +\def\pgf@lib@dv@func@parse{% + \pgfutil@ifnextchar\pgf@stop{% done + \pgfutil@gobble% + } + {% + \pgfutil@ifnextchar v{% variable + \pgf@lib@dv@var% + }{% + \pgf@lib@dv@func% + }% + }% +}% + +\def\pgf@lib@dv@func func #1 =#2;{% + \expandafter\def\expandafter\pgf@lib@dv@parsed\expandafter{\pgf@lib@dv@parsed\pgf@lib@dv@eval@func{#1}{#2}} + \pgf@lib@dv@func@parse% +}% +\def\pgf@lib@dv@var var #1 :{\pgfutil@ifnextchar\bgroup{\pgf@lib@dv@var@group{#1}}{\pgf@lib@dv@var@int{#1}}}% +\def\pgf@lib@dv@var@group#1#2;{% + \expandafter\def\expandafter\pgf@lib@dv@parsed\expandafter{\pgf@lib@dv@parsed\pgf@lib@dv@group@var{#1}{#2}}% + \pgf@lib@dv@func@parse% +}% +\def\pgf@lib@dv@var@int#1#2[#3:#4]{% + \pgfutil@ifnextchar s{% + \pgf@lib@dv@samplesorsteps{#1}{#3}{#4}% + }{% + \expandafter\def\expandafter\pgf@lib@dv@parsed\expandafter{% + \pgf@lib@dv@parsed\pgf@lib@dv@samples@var{#1}{#3}{#4}{\pgfkeysvalueof{/pgf/data/samples}}}% + \expandafter\pgf@lib@dv@func@parse\pgfutil@gobble% + } +}% +\def\pgf@lib@dv@samplesorsteps#1#2#3s{% + \pgfutil@ifnextchar t{% step + \pgf@lib@dv@step{#1}{#2}{#3}% + }{% sample + \pgf@lib@dv@samples{#1}{#2}{#3}% + }% +}% +\def\pgf@lib@dv@step#1#2#3tep#4;{% + \expandafter\def\expandafter\pgf@lib@dv@parsed\expandafter{\pgf@lib@dv@parsed\pgf@lib@dv@step@var{#1}{#2}{#3}{#4}}% + \pgf@lib@dv@func@parse% +}% +\def\pgf@lib@dv@samples#1#2#3amples#4;{% + \expandafter\def\expandafter\pgf@lib@dv@parsed\expandafter{\pgf@lib@dv@parsed\pgf@lib@dv@samples@var{#1}{#2}{#3}{#4}}% + \pgf@lib@dv@func@parse% +}% + +% +% Executer... +% +\def\pgf@lib@dv@samples@var#1#2#3#4{% + \pgfmathparse{#3}% + \let\pgf@lib@dv@temp=\pgfmathresult% + \pgfmathparse{#2}% + \pgfmathparse{\pgf@lib@dv@temp-\pgfmathresult}% + \pgfmathparse{\pgfmathresult/(#4-1)}% + \let\pgf@lib@dv@temp=\pgfmathresult% + \pgf@lib@dv@step@var{#1}{#2}{#3}{\pgf@lib@dv@temp}% +}% + +\def\pgf@lib@dv@step@var#1#2#3#4#5\pgf@stop{% + {% + \def\pgf@loop@body{#5}% + \pgfmathparse{#2}% + \pgfkeyslet{/data point/#1}{\pgfmathresult}% + \pgfmathparse{#3}% + \let\pgf@loop@end\pgfmathresult% + \pgfmathparse{#4}% + \let\pgf@loop@step\pgfmathresult% + \pgfmathloop% + \pgfmathlessthan{\pgf@loop@end}{\pgfkeysvalueof{/data point/#1}} + \ifdim\pgfmathresult pt<1pt\relax% + \pgf@loop@body\pgf@stop% + \pgfmathparse{\pgfkeysvalueof{/data point/#1}+\pgf@loop@step}% + \pgfkeyslet{/data point/#1}{\pgfmathresult}% + \repeatpgfmathloop%% + }% +}% + +\def\pgf@lib@dv@group@var#1#2#3\pgf@stop{% + \foreach \pgf@lib@dv@iterator in {#2} {% + \pgfkeyslet{/data point/#1}{\pgf@lib@dv@iterator}% + #3\pgf@stop% + }% +}% + +\def\pgf@lib@dv@eval@func#1#2{% + \pgfkeysvalueof{/pgf/data/evaluator}{#2}% + \pgfkeyslet{/data point/#1}{\pgfmathresult}% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.polar.code.tex b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.polar.code.tex new file mode 100644 index 0000000000..a7d493491f --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/datavisualization/pgflibrarydatavisualization.polar.code.tex @@ -0,0 +1,198 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarydatavisualization.polar.code.tex} + +\usepgfmodule{datavisualization}% + +% This file defines code for doing plots involving polar +% coordinates. This includes not only standard polar plots, but also +% pie charts. + + + +\pgfooclass{polar transformer} +{% + % Class polar mapper + % + % A polar mapper is used to transform attributes given as (2d) polar + % coordinates to canvas coordinates. Note that no special ranges + % can be specified and that the angle must be given in degrees. You + % can, however, use a standard mapper to change these things. + + \attribute angle;% + % The attribute from which the angle is read. + + \attribute radius;% + % The attribute from which the radius is read. + + \attribute unit vector 0 degrees;% + % The unit vector 0 degrees + + \attribute unit vector 90 degrees;% + % The unit vector 90 degrees + + + + % Constructor + % + % #1 = angle attribute. Example: rotation. + % #2 = radius attribute. Example: height. + % #3 = unit vector 0 degrees + % #4 = unit vector 90 degrees + % + \method polar transformer(#1,#2,#3,#4) { + \pgfooset{angle}{#1} + \pgfooset{radius}{#2} + \pgfooset{unit vector 0 degrees}{#3} + \pgfooset{unit vector 90 degrees}{#4} + }% + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,transform,transform datapoint signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,path,path signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,direction,direction signal) + }% + + % Getters + \method get angle attribute(#1) { + \pgfooget{angle}{#1} + }% + + \method get radius attribute(#1) { + \pgfooget{radius}{#1} + }% + + + % Slot + % + % This slot should be connected to the transform datapoint + % signal. When this signal is emitted, the coordinate system will be + % shifted according to the current value of the attribute. + \method transform() { + \pgfkeysgetvalue{/data point/\pgfoovalueof{angle}/const}\pgf@dv@angle% + \ifx\pgf@dv@angle\relax + \pgfkeysgetvalue{/data point/\pgfoovalueof{angle}}\pgf@dv@angle% + \fi + \ifx\pgf@dv@angle\relax\else% + \ifx\pgf@dv@angle\pgfutil@empty\else% + \pgfkeysgetvalue{/data point/\pgfoovalueof{radius}/const}\pgf@dv@radius% + \ifx\pgf@dv@radius\relax + \pgfkeysgetvalue{/data point/\pgfoovalueof{radius}}\pgf@dv@radius% + \fi + \ifx\pgf@dv@radius\pgfutil@empty\else% + \ifx\pgf@dv@radius\relax\else% + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@angle}% + \pgfdvmathexitbyscientificformat{\pgf@dv@angle}{\pgf@dv@val}% + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@radius}% + \pgfdvmathexitbyscientificformat{\pgf@dv@radius}{\pgf@dv@val}% + \pgfmathsincos{\pgf@dv@angle}% + \pgfmathmultiply{\pgfmathresultx}{\pgf@dv@radius}% + \let\pgf@dv@polar@temp=\pgfmathresult + \pgftransformshift{\pgfpointscale{\pgf@dv@polar@temp}{\pgfoovalueof{unit vector 0 degrees}}}% + \pgfmathmultiply{\pgfmathresulty}{\pgf@dv@radius}% + \let\pgf@dv@polar@temp=\pgfmathresult + \pgftransformshift{\pgfpointscale{\pgf@dv@polar@temp}{\pgfoovalueof{unit vector 90 degrees}}}% + \fi% + \fi% + \fi% + \fi% + }% + + + + % Reaction to the path signal + % + % Here is what we do: When a pgfdvpathmoveto is done, the radius and + % the angle are recorded. When a pgfdvpathlineto is done, the saved + % radius and angle are compared with the new angle and radius. If, + % and only if, the radius is the same, but the angle is different, + % the lineto is caught and replaced by an arc from the previous + % position to the new position. + + \attribute prev angle;% + \attribute prev radius;% + + \method path(#1) {% + \ifpgfdvhandled% + \else% + \ifx#1\pgfdvpathlinetotoken + % Ok, let us have a look... + \pgfooget{prev radius}\pgf@dv@prev@rad + \pgfkeysgetvalue{/data point/\pgfoovalueof{radius}}\pgf@dv@current@rad + \ifx\pgf@dv@current@rad\relax + \else + \ifx\pgf@dv@current@rad\pgf@dv@prev@rad% + \pgfooget{prev angle}\pgf@dv@prev@angle + \pgfkeysgetvalue{/data point/\pgfoovalueof{angle}}\pgf@dv@current@angle + \ifx\pgf@dv@current@angle\relax + \else + \ifx\pgf@dv@current@angle\pgf@dv@prev@angle% + % do nothing + \else% + % Do arc: + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@prev@angle}% + \pgfdvmathexitbyscientificformat{\pgf@dv@prev@angle}{\pgf@dv@val}% + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@prev@rad}% + \pgfdvmathexitbyscientificformat{\pgf@dv@prev@rad}{\pgf@dv@val}% + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@current@angle}% + \pgfdvmathexitbyscientificformat{\pgf@dv@current@angle}{\pgf@dv@val}% + \pgfdvmathenter{\pgf@dv@val}{\pgf@dv@current@rad}% + \pgfdvmathexitbyscientificformat{\pgf@dv@current@rad}{\pgf@dv@val}% + \pgfpatharcaxes{\pgf@dv@prev@angle}{\pgf@dv@current@angle} + {\pgfpointscale{\pgf@dv@current@rad}{\pgfoovalueof{unit vector 0 degrees}}} + {\pgfpointscale{\pgf@dv@current@rad}{\pgfoovalueof{unit vector 90 degrees}}}% + \pgfdvhandledtrue% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + % No matter what, record the current position + \pgfooeset{prev angle}{\pgfkeysvalueof{/data point/\pgfoovalueof{angle}}} + \pgfooeset{prev radius}{\pgfkeysvalueof{/data point/\pgfoovalueof{radius}}} + }% + + % Method + % + % React to direction signals. See pgfpointdvdirection for an + % explanation + % + \method direction(#1) {% + \ifx#1\pgfdvdirectionfromtoken + % Record from angle and radius + \xdef\pgf@dv@polar@from@angle{\pgfkeysvalueof{/data point/\pgfoovalueof{angle}}} + \xdef\pgf@dv@polar@from@radius{\pgfkeysvalueof{/data point/\pgfoovalueof{radius}}} + \else\ifx#1\pgfdvdirectiontotoken% + % Record to angle and radius + \xdef\pgf@dv@polar@to@angle{\pgfkeysvalueof{/data point/\pgfoovalueof{angle}}} + \xdef\pgf@dv@polar@to@radius{\pgfkeysvalueof{/data point/\pgfoovalueof{radius}}} + \else% + \ifx\pgf@dv@polar@from@radius\pgf@dv@polar@to@radius% + \pgfdvmathenter{\pgf@dv@a}{\pgf@dv@polar@from@angle}% + \pgfdvmathenter{\pgf@dv@b}{\pgf@dv@polar@to@angle}% + \pgfdvmathifless{\pgf@dv@a}{\pgf@dv@b}{\def\pgf@dv@temp@sign{+}}{\def\pgf@dv@temp@sign{-}}% + \pgfkeysgetvalue{/data point/\pgfoovalueof{angle}}\pgf@temp% + \ifx\pgf@temp\relax% + \else% + \pgfdvmathenter{\pgf@dv@val}{\pgf@temp}% + \pgfdvmathexitbyscientificformat{\pgf@dv@polar@angle}{\pgf@dv@val}% + \pgf@process{\pgfpointpolar{\pgf@dv@polar@angle\pgf@dv@temp@sign90}{1pt}}% + \pgfdvhandledtrue% + \fi% + \fi% + \fi\fi% + }% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.footprints.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.footprints.code.tex new file mode 100644 index 0000000000..4fc6565c1b --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.footprints.code.tex @@ -0,0 +1,230 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% Parameters +\pgfset{ + % Length of a footprint: + /pgf/decoration/foot length/.initial=10pt, + % Distance between two footprints on the same side of the path + /pgf/decoration/stride length/.initial=30pt, + % Double distance between footprint and input path + /pgf/decoration/foot sep/.initial=4pt, + % Rotate feet by this much + /pgf/decoration/foot angle/.initial=10, + % What animal? + /pgf/decoration/foot of/.initial=human, +}% + + + +\pgfdeclaredecoration{footprints}{left} +{% + \state{left}[width=\pgfkeysvalueof{/pgf/decoration/stride length}/2,next state=right] + { + \pgftransformyshift{\pgfkeysvalueof{/pgf/decoration/foot sep}/2} + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/foot length}} + \pgftransformscale{\pgfmathresult} + \pgftransformrotate{\pgfkeysvalueof{/pgf/decoration/foot angle}} + \csname pgf@lib@foot@of@\pgfkeysvalueof{/pgf/decoration/foot of}\endcsname + }% + \state{right}[width=\pgfkeysvalueof{/pgf/decoration/stride length}/2,next state=left] + { + \pgftransformyscale{-1} + \pgftransformyshift{\pgfkeysvalueof{/pgf/decoration/foot sep}/2} + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/foot length}} + \pgftransformscale{\pgfmathresult} + \pgftransformrotate{\pgfkeysvalueof{/pgf/decoration/foot angle}} + \csname pgf@lib@foot@of@\pgfkeysvalueof{/pgf/decoration/foot of}\endcsname + }% +}% + + + +% Actual footprints. +% +% A footprint must be name \pgf@lib@foot@of@XXX, be a left foot and +% should fill a rectangle of (0,0) rectangle (1pt,1pt) (more or less) +% and point right. +% + + +\def\pgf@lib@foot@of@gnome{ + % Coordinates from a Gnome logo on wikimedia commons. LGPL + % license... Unknown author. + % + % Flip and rotate + \pgftransformcm{0}{-1}{-1}{0}{\pgfqpoint{1pt}{0.8pt}} + \pgftransformscale{0.83333} + \pgfpathmoveto{\pgfqpoint{.86068pt}{0pt}} + \pgfpathcurveto{\pgfqpoint{.61466pt}{0pt}}{\pgfqpoint{.56851pt}{.35041pt}}{\pgfqpoint{.70691pt}{.35041pt}} + \pgfpathcurveto{\pgfqpoint{.84529pt}{.35041pt}}{\pgfqpoint{1.10671pt}{0pt}}{\pgfqpoint{.86068pt}{0pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.45217pt}{.30699pt}} + \pgfpathcurveto{\pgfqpoint{.52586pt}{.31149pt}}{\pgfqpoint{.60671pt}{.02577pt}}{\pgfqpoint{.46821pt}{.04374pt}} + \pgfpathcurveto{\pgfqpoint{.32976pt}{.06171pt}}{\pgfqpoint{.37845pt}{.30249pt}}{\pgfqpoint{.45217pt}{.30699pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.11445pt}{.48453pt}} + \pgfpathcurveto{\pgfqpoint{.16686pt}{.46146pt}}{\pgfqpoint{.1212pt}{.23581pt}}{\pgfqpoint{.03208pt}{.29735pt}} + \pgfpathcurveto{\pgfqpoint{-.057pt}{.3589pt}}{\pgfqpoint{.06204pt}{.50759pt}}{\pgfqpoint{.11445pt}{.48453pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.26212pt}{.36642pt}} + \pgfpathcurveto{\pgfqpoint{.32451pt}{.3537pt}}{\pgfqpoint{.32793pt}{.09778pt}}{\pgfqpoint{.21667pt}{.14369pt}} + \pgfpathcurveto{\pgfqpoint{.10539pt}{.18961pt}}{\pgfqpoint{.19978pt}{.37916pt}}{\pgfqpoint{.26212pt}{.36642pt}} + \pgfpathlineto{\pgfqpoint{.26212pt}{.36642pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.58791pt}{.93913pt}} + \pgfpathcurveto{\pgfqpoint{.59898pt}{1.02367pt}}{\pgfqpoint{.52589pt}{1.06542pt}}{\pgfqpoint{.45431pt}{1.01092pt}} + \pgfpathcurveto{\pgfqpoint{.22644pt}{.83743pt}}{\pgfqpoint{.8316pt}{.75088pt}}{\pgfqpoint{.79171pt}{.51386pt}} + \pgfpathcurveto{\pgfqpoint{.7586pt}{.31712pt}}{\pgfqpoint{.15495pt}{.37769pt}}{\pgfqpoint{.08621pt}{.68553pt}} + \pgfpathcurveto{\pgfqpoint{.03968pt}{.89374pt}}{\pgfqpoint{.27774pt}{1.1826pt}}{\pgfqpoint{.52614pt}{1.1826pt}} + \pgfpathcurveto{\pgfqpoint{.64834pt}{1.1826pt}}{\pgfqpoint{.78929pt}{1.07226pt}}{\pgfqpoint{.81566pt}{.93248pt}} + \pgfpathcurveto{\pgfqpoint{.8358pt}{.82589pt}}{\pgfqpoint{.57867pt}{.8686pt}}{\pgfqpoint{.58791pt}{.93913pt}} + \pgfpathlineto{\pgfqpoint{.58791pt}{.93913pt}} + \pgfpathclose +}% + + + +\def\pgf@lib@foot@of@bird{ + % Coordinates derived from vector image created by Mark Wibrow. + % + \pgftransformcm{0}{.11}{.11}{0}{\pgfqpoint{.37pt}{.52pt}} + \pgfpathmoveto{\pgfqpoint{-.886pt}{1.652pt}} + \pgfpathcurveto{\pgfqpoint{-.4632pt}{2.669pt}}{\pgfqpoint{-.5092pt}{4.3712pt}}{\pgfqpoint{-.4512pt}{5.6734pt}} + \pgfpathcurveto{\pgfqpoint{-.4374pt}{5.9842pt}}{\pgfqpoint{-.3182pt}{6.0686pt}}{\pgfqpoint{-.2484pt}{5.644pt}} + \pgfpathcurveto{\pgfqpoint{-.0534pt}{4.459pt}}{\pgfqpoint{.087pt}{3.0132pt}}{\pgfqpoint{.5206pt}{1.8464pt}} + \pgfpathcurveto{\pgfqpoint{.714pt}{1.326pt}}{\pgfqpoint{.692pt}{1.416pt}}{\pgfqpoint{1.0864pt}{1.759pt}} + \pgfpathcurveto{\pgfqpoint{1.7662pt}{2.3504pt}}{\pgfqpoint{2.665pt}{3.1756pt}}{\pgfqpoint{3.2028pt}{4.02pt}} + \pgfpathcurveto{\pgfqpoint{3.4708pt}{4.4408pt}}{\pgfqpoint{3.4258pt}{4.0814pt}}{\pgfqpoint{3.3366pt}{3.8708pt}} + \pgfpathcurveto{\pgfqpoint{2.9068pt}{2.8562pt}}{\pgfqpoint{.8502pt}{.645pt}}{\pgfqpoint{.4808pt}{-.0864pt}} + \pgfpathcurveto{\pgfqpoint{.0808pt}{-.8788pt}}{\pgfqpoint{.1664pt}{-2.1246pt}}{\pgfqpoint{.0024pt}{-2.7868pt}} + \pgfpathcurveto{\pgfqpoint{-.172pt}{-3.4908pt}}{\pgfqpoint{-.2726pt}{-3.704pt}}{\pgfqpoint{-.3812pt}{-2.9558pt}} + \pgfpathcurveto{\pgfqpoint{-.5316pt}{-1.9202pt}}{\pgfqpoint{-.88pt}{-.256pt}}{\pgfqpoint{-1.332pt}{.128pt}} + \pgfpathcurveto{\pgfqpoint{-1.716pt}{.4542pt}}{\pgfqpoint{-3.7928pt}{2.3136pt}}{\pgfqpoint{-4.5044pt}{3.3524pt}} + \pgfpathcurveto{\pgfqpoint{-4.7618pt}{3.728pt}}{\pgfqpoint{-4.709pt}{3.7864pt}}{\pgfqpoint{-4.4212pt}{3.5818pt}} + \pgfpathcurveto{\pgfqpoint{-3.4844pt}{2.9162pt}}{\pgfqpoint{-2.6164pt}{1.654pt}}{\pgfqpoint{-1.454pt}{1.3886pt}} + \pgfpathcurveto{\pgfqpoint{-1.0876pt}{1.305pt}}{\pgfqpoint{-1.0296pt}{1.3066pt}}{\pgfqpoint{-.886pt}{1.652pt}} + \pgfpathclose +}% + + +\expandafter\def\csname pgf@lib@foot@of@felis silvestris\endcsname{ + % Coordinates derived from vector image created by Mark Wibrow, based + % on the forefoot of `felis silvestris' shown in + % Pearson, B. and Burton, J. A. (1980), `Wild Animals', Collins, 155. + % + \pgftransformcm{0}{.1}{.1}{0}{\pgfqpoint{.48pt}{.5pt}} + \pgfpathmoveto{\pgfqpoint{2.7312pt}{-1.992pt}} + \pgfpathcurveto{\pgfqpoint{1.8716pt}{-1.4226pt}}{\pgfqpoint{2.1404pt}{.0436pt}}{\pgfqpoint{.9202pt}{.0436pt}} + \pgfpathcurveto{\pgfqpoint{-.1146pt}{.0436pt}}{\pgfqpoint{-.7386pt}{.0178pt}}{\pgfqpoint{-1.319pt}{-1.0288pt}} + \pgfpathcurveto{\pgfqpoint{-1.7922pt}{-1.8822pt}}{\pgfqpoint{-2.072pt}{-1.5488pt}}{\pgfqpoint{-2.9638pt}{-1.968pt}} + \pgfpathcurveto{\pgfqpoint{-3.9244pt}{-2.4198pt}}{\pgfqpoint{-4.4394pt}{-3.348pt}}{\pgfqpoint{-4.1136pt}{-4.041pt}} + \pgfpathcurveto{\pgfqpoint{-3.3862pt}{-5.5882pt}}{\pgfqpoint{-1.6156pt}{-3.83pt}}{\pgfqpoint{-1.1684pt}{-4.312pt}} + \pgfpathcurveto{\pgfqpoint{-.5806pt}{-4.9454pt}}{\pgfqpoint{.5032pt}{-4.8822pt}}{\pgfqpoint{1.1748pt}{-4.2878pt}} + \pgfpathcurveto{\pgfqpoint{1.5822pt}{-3.9272pt}}{\pgfqpoint{2.6524pt}{-5.0652pt}}{\pgfqpoint{3.3506pt}{-4.1066pt}} + \pgfpathcurveto{\pgfqpoint{3.839pt}{-3.4356pt}}{\pgfqpoint{3.1192pt}{-2.249pt}}{\pgfqpoint{2.7312pt}{-1.992pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{5.0576pt}{.4996pt}} + \pgfpathcurveto{\pgfqpoint{4.6056pt}{.6536pt}}{\pgfqpoint{4.0596pt}{.2516pt}}{\pgfqpoint{3.8382pt}{-.398pt}} + \pgfpathcurveto{\pgfqpoint{3.6168pt}{-1.0478pt}}{\pgfqpoint{3.8038pt}{-1.6996pt}}{\pgfqpoint{4.2558pt}{-1.8536pt}} + \pgfpathcurveto{\pgfqpoint{4.7078pt}{-2.0076pt}}{\pgfqpoint{5.2538pt}{-1.6056pt}}{\pgfqpoint{5.4752pt}{-.9558pt}} + \pgfpathcurveto{\pgfqpoint{5.6966pt}{-.3062pt}}{\pgfqpoint{5.5096pt}{.3456pt}}{\pgfqpoint{5.0576pt}{.4996pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{3.1212pt}{3.5542pt}} + \pgfpathcurveto{\pgfqpoint{2.5874pt}{3.6726pt}}{\pgfqpoint{1.975pt}{3.1756pt}}{\pgfqpoint{1.7538pt}{2.4442pt}} + \pgfpathcurveto{\pgfqpoint{1.5324pt}{1.7128pt}}{\pgfqpoint{1.7858pt}{1.0238pt}}{\pgfqpoint{2.3196pt}{.9052pt}} + \pgfpathcurveto{\pgfqpoint{2.8534pt}{.7868pt}}{\pgfqpoint{3.4658pt}{1.2838pt}}{\pgfqpoint{3.6872pt}{2.0152pt}} + \pgfpathcurveto{\pgfqpoint{3.9084pt}{2.7466pt}}{\pgfqpoint{3.655pt}{3.4358pt}}{\pgfqpoint{3.1212pt}{3.5542pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{-.6182pt}{5.0456pt}} + \pgfpathcurveto{\pgfqpoint{-1.2132pt}{5.0456pt}}{\pgfqpoint{-1.6956pt}{4.3104pt}}{\pgfqpoint{-1.6956pt}{3.4038pt}} + \pgfpathcurveto{\pgfqpoint{-1.6956pt}{2.4972pt}}{\pgfqpoint{-1.2132pt}{1.7618pt}}{\pgfqpoint{-.6182pt}{1.7618pt}} + \pgfpathcurveto{\pgfqpoint{-.0232pt}{1.7618pt}}{\pgfqpoint{.4592pt}{2.4972pt}}{\pgfqpoint{.4592pt}{3.4038pt}} + \pgfpathcurveto{\pgfqpoint{.4592pt}{4.3104pt}}{\pgfqpoint{-.0232pt}{5.0456pt}}{\pgfqpoint{-.6182pt}{5.0456pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{-4.1176pt}{1.8248pt}} + \pgfpathcurveto{\pgfqpoint{-4.6334pt}{1.7534pt}}{\pgfqpoint{-4.9806pt}{1.0312pt}}{\pgfqpoint{-4.8928pt}{.212pt}} + \pgfpathcurveto{\pgfqpoint{-4.8052pt}{-.6072pt}}{\pgfqpoint{-4.3158pt}{-1.2136pt}}{\pgfqpoint{-3.8pt}{-1.1422pt}} + \pgfpathcurveto{\pgfqpoint{-3.2842pt}{-1.0708pt}}{\pgfqpoint{-2.9372pt}{-.3486pt}}{\pgfqpoint{-3.0248pt}{.4706pt}} + \pgfpathcurveto{\pgfqpoint{-3.1126pt}{1.2898pt}}{\pgfqpoint{-3.6018pt}{1.8962pt}}{\pgfqpoint{-4.1176pt}{1.8248pt}} + \pgfpathclose +}% + + + +\def\pgf@lib@foot@of@human{% + % Coordinates derived from vector image created by Mark Wibrow. + \pgftransformcm{0}{.5}{.5}{0}{\pgfqpoint{.48pt}{.2pt}} + % + % Draw main part of foot. + % + \pgfpathmoveto{\pgfqpoint{.20175pt}{-.72633pt}} + \pgfpathcurveto{\pgfqpoint{.16314pt}{-.88194pt}}{\pgfqpoint{.07386pt}{-1.0167pt}}{\pgfqpoint{-.08385pt}{-1.0167pt}} + \pgfpathcurveto{\pgfqpoint{-.24153pt}{-1.0167pt}}{\pgfqpoint{-.36942pt}{-.84897pt}}{\pgfqpoint{-.36942pt}{-.72633pt}} + \pgfpathcurveto{\pgfqpoint{-.36942pt}{-.60372pt}}{\pgfqpoint{-.32505pt}{-.54825pt}}{\pgfqpoint{-.27633pt}{-.51192pt}} + \pgfpathcurveto{\pgfqpoint{-.23937pt}{-.48435pt}}{\pgfqpoint{-.17031pt}{-.46539pt}}{\pgfqpoint{-.10611pt}{-.40323pt}} + \pgfpathcurveto{\pgfqpoint{-.04191pt}{-.3411pt}}{\pgfqpoint{.00495pt}{-.27783pt}}{\pgfqpoint{.00495pt}{-.14787pt}} + \pgfpathcurveto{\pgfqpoint{.00495pt}{-.01794pt}}{\pgfqpoint{-.08526pt}{.12648pt}}{\pgfqpoint{-.22194pt}{.22467pt}} + \pgfpathcurveto{\pgfqpoint{-.35862pt}{.32286pt}}{\pgfqpoint{-.40863pt}{.50226pt}}{\pgfqpoint{-.32703pt}{.5979pt}} + \pgfpathcurveto{\pgfqpoint{-.24543pt}{.69354pt}}{\pgfqpoint{-.00564pt}{.66543pt}}{\pgfqpoint{.17172pt}{.53484pt}} + \pgfpathcurveto{\pgfqpoint{.34908pt}{.40422pt}}{\pgfqpoint{.39363pt}{.27192pt}}{\pgfqpoint{.37416pt}{.10971pt}} + \pgfpathcurveto{\pgfqpoint{.35472pt}{-.0525pt}}{\pgfqpoint{.26736pt}{-.46203pt}}{\pgfqpoint{.20175pt}{-.72633pt}} + \pgfpathclose + % + % Draw toe.s + % + \pgfpathmoveto{\pgfqpoint{-.27138pt}{1.01451pt}} + \pgfpathcurveto{\pgfqpoint{-.21198pt}{1.01451pt}}{\pgfqpoint{-.1638pt}{.94509pt}}{\pgfqpoint{-.1638pt}{.8595pt}} + \pgfpathcurveto{\pgfqpoint{-.1638pt}{.77388pt}}{\pgfqpoint{-.21198pt}{.70446pt}}{\pgfqpoint{-.27138pt}{.70446pt}} + \pgfpathcurveto{\pgfqpoint{-.33078pt}{.70446pt}}{\pgfqpoint{-.37896pt}{.77388pt}}{\pgfqpoint{-.37896pt}{.8595pt}} + \pgfpathcurveto{\pgfqpoint{-.37896pt}{.94509pt}}{\pgfqpoint{-.33078pt}{1.01451pt}}{\pgfqpoint{-.27138pt}{1.01451pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{-.05769pt}{.90573pt}} + \pgfpathcurveto{\pgfqpoint{-.01659pt}{.90573pt}}{\pgfqpoint{.01674pt}{.86445pt}}{\pgfqpoint{.01674pt}{.81354pt}} + \pgfpathcurveto{\pgfqpoint{.01674pt}{.7626pt}}{\pgfqpoint{-.01659pt}{.72132pt}}{\pgfqpoint{-.05769pt}{.72132pt}} + \pgfpathcurveto{\pgfqpoint{-.09879pt}{.72132pt}}{\pgfqpoint{-.13209pt}{.7626pt}}{\pgfqpoint{-.13209pt}{.81354pt}} + \pgfpathcurveto{\pgfqpoint{-.13209pt}{.86445pt}}{\pgfqpoint{-.09879pt}{.90573pt}}{\pgfqpoint{-.05769pt}{.90573pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.10497pt}{.81636pt}} + \pgfpathcurveto{\pgfqpoint{.14214pt}{.81096pt}}{\pgfqpoint{.16722pt}{.77193pt}}{\pgfqpoint{.16104pt}{.72918pt}} + \pgfpathcurveto{\pgfqpoint{.15483pt}{.68646pt}}{\pgfqpoint{.11964pt}{.65619pt}}{\pgfqpoint{.08247pt}{.66159pt}} + \pgfpathcurveto{\pgfqpoint{.0453pt}{.66699pt}}{\pgfqpoint{.02019pt}{.70602pt}}{\pgfqpoint{.0264pt}{.74874pt}} + \pgfpathcurveto{\pgfqpoint{.03261pt}{.79149pt}}{\pgfqpoint{.0678pt}{.82176pt}}{\pgfqpoint{.10497pt}{.81636pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.24054pt}{.70842pt}} + \pgfpathcurveto{\pgfqpoint{.27513pt}{.70842pt}}{\pgfqpoint{.30318pt}{.67686pt}}{\pgfqpoint{.30318pt}{.63795pt}} + \pgfpathcurveto{\pgfqpoint{.30318pt}{.59904pt}}{\pgfqpoint{.27513pt}{.56751pt}}{\pgfqpoint{.24054pt}{.56751pt}} + \pgfpathcurveto{\pgfqpoint{.20598pt}{.56751pt}}{\pgfqpoint{.17793pt}{.59904pt}}{\pgfqpoint{.17793pt}{.63795pt}} + \pgfpathcurveto{\pgfqpoint{.17793pt}{.67686pt}}{\pgfqpoint{.20598pt}{.70842pt}}{\pgfqpoint{.24054pt}{.70842pt}} + \pgfpathclose + % + \pgfpathmoveto{\pgfqpoint{.35973pt}{.57501pt}} + \pgfpathcurveto{\pgfqpoint{.3918pt}{.57501pt}}{\pgfqpoint{.41781pt}{.54852pt}}{\pgfqpoint{.41781pt}{.51585pt}} + \pgfpathcurveto{\pgfqpoint{.41781pt}{.48318pt}}{\pgfqpoint{.3918pt}{.45669pt}}{\pgfqpoint{.35973pt}{.45669pt}} + \pgfpathcurveto{\pgfqpoint{.32769pt}{.45669pt}}{\pgfqpoint{.30168pt}{.48318pt}}{\pgfqpoint{.30168pt}{.51585pt}} + \pgfpathcurveto{\pgfqpoint{.30168pt}{.54852pt}}{\pgfqpoint{.32769pt}{.57501pt}}{\pgfqpoint{.35973pt}{.57501pt}} + \pgfpathclose +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.fractals.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.fractals.code.tex new file mode 100644 index 0000000000..8355460b54 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.fractals.code.tex @@ -0,0 +1,65 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + + +\pgfdeclaredecoration{Koch curve type 1}{init} +{% + \state{init}[width=\pgfdecoratedinputsegmentremainingdistance] + { + \pgfpathlineto{\pgfpoint{.33333\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{.33333\pgfdecoratedinputsegmentremainingdistance}{.33333\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.66666\pgfdecoratedinputsegmentremainingdistance}{.33333\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.66666\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + }% +}% + +\pgfdeclaredecoration{Koch curve type 2}{init} +{% + \state{init}[width=\pgfdecoratedinputsegmentremainingdistance] + { + \pgfpathlineto{\pgfpoint{.25\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{.25\pgfdecoratedinputsegmentremainingdistance}{.25\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.5\pgfdecoratedinputsegmentremainingdistance}{.25\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.5\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{.5\pgfdecoratedinputsegmentremainingdistance}{-.25\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.75\pgfdecoratedinputsegmentremainingdistance}{-.25\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.75\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + }% +}% + +\pgfdeclaredecoration{Koch snowflake}{init} +{% + \state{init}[width=\pgfdecoratedinputsegmentremainingdistance] + { + \pgfpathlineto{\pgfpoint{.3333\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{.5\pgfdecoratedinputsegmentremainingdistance}{0.2886751347\pgfdecoratedinputsegmentremainingdistance}} + \pgfpathlineto{\pgfpoint{.6666\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + }% +}% + + +\pgfdeclaredecoration{Cantor set}{init} +{% + \state{init}[width=\pgfdecoratedinputsegmentremainingdistance] + { + \pgfpathlineto{\pgfpoint{.3333\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathmoveto{\pgfpoint{.6666\pgfdecoratedinputsegmentremainingdistance}{0pt}} + \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + }% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.markings.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.markings.code.tex new file mode 100644 index 0000000000..23b7ff672e --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.markings.code.tex @@ -0,0 +1,179 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% A marking decoration is used to add markings (which are just pgf +% scopes, essentially) at certain positions of a path. + +\pgfkeys{ + /pgf/decoration/reset marks/.code=\let\pgf@lib@dec@mark@marks\pgfutil@empty, + /pgf/decoration/mark/.code=\pgf@lib@dec@parsemark#1\pgf@lib@dec@stop, +}% + +\let\pgf@lib@dec@mark@marks=\pgfutil@empty + +\def\pgf@lib@dec@parsemark{\pgfutil@ifnextchar b{\pgf@lib@dec@parsebetween}{\pgf@lib@dec@parseat}}% +\def\pgf@lib@dec@parseat at position#1with#2\pgf@lib@dec@stop{% + \expandafter\def\expandafter\pgf@lib@dec@mark@marks\expandafter{\pgf@lib@dec@mark@marks% + \pgf@lib@dec@domark{#1}{#2}% + }% +}% +\def\pgf@lib@dec@parsebetween between positions#1and#2step#3with#4\pgf@lib@dec@stop{% + \expandafter\def\expandafter\pgf@lib@dec@mark@marks\expandafter{\pgf@lib@dec@mark@marks% + \pgf@lib@dec@dobetweenmark{#1}{#2}{#3}{#4}% + }% +}% + +\def\pgf@lib@dec@arrowhead#1#2{% + \pgftransformxscale{#1} + \pgfarrowdraw{#2}% +}% + +\def\pgf@lib@dec@doarrowhead#1{% + \pgf@lib@dec@arrowhead{1}{#1}% +}% +\def\pgf@lib@dec@doarrowheadrev#1{% + \pgf@lib@dec@arrowhead{-1}{#1}% +}% + + +\pgfdeclaredecoration{markings}{init} +{% + \state{init} + [ + width=0pt, + persistent precomputation={% + \pgfkeys{/pgf/decoration/mark info/sequence number/.initial=0}% + \pgfkeys{/pgf/decoration/mark info/distance from start/.initial=}% + }, + next state=pre + ] + {}% + + \state{pre} + [ + width=0pt, + persistent precomputation={% + \def\pgf@lib@dec@computed@width{0pt}% + \pgf@lib@dec@mark@marks\pgf@lib@dec@mark@last% + \let\arrow=\pgf@lib@dec@doarrowhead% + \let\arrowreversed=\pgf@lib@dec@doarrowheadrev% + }, + next state=skipper + ] + {}% + + \state{skipper}[width=\pgf@lib@dec@computed@width-\pgfdecoratedcompleteddistance-1sp, + next state=\pgf@lib@dec@next@state]{}% + + \state{main} + [ + width=1sp, + next state=pre, + persistent precomputation={% + \pgfutil@tempcnta=\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}\relax% + \advance\pgfutil@tempcnta by1\relax% + \pgfkeys{/pgf/decoration/mark info/sequence number/.expanded=\the\pgfutil@tempcnta}% + \pgfkeys{/pgf/decoration/mark info/distance from start/.expanded=\pgf@lib@dec@computed@width}% + }% + ] + {% + \pgfinterruptpath% + \pgfscope% + \let\pgf@lib@dec@mark@marks=\pgfutil@empty% + \pgfslopedattimefalse + \pgf@lib@dec@computed@action% + \endpgfscope% + \endpgfinterruptpath% + \ifx\pgf@lib@mark@node\pgfutil@empty% + \else% + \pgf@lib@mark@connect@node% + \fi% + }% + + \state{final}[width=\pgfdecoratedremainingdistance]{ + \ifx\pgf@lib@mark@node\pgfutil@empty% + \pgfpathmoveto{\pgfpointdecoratedpathlast} + \else% + \pgfpathlineto{\pgfpointdecoratedpathlast} + \fi% + }% +}% + +\def\pgf@lib@dec@domark#1#2#3\pgf@lib@dec@mark@last{% + \def\pgf@lib@dec@mark@marks{#3}% + \pgf@lib@dec@parsenum{#1}% + \def\pgf@lib@dec@computed@action{#2}% + \def\pgf@lib@dec@next@state{main}% +}% + + +\def\pgf@lib@dec@dobetweenmark#1#2#3#4#5\pgf@lib@dec@mark@last{% + \pgf@lib@dec@parsenum{#1}% + \let\pgf@lib@dec@mark@start=\pgf@lib@dec@computed@width% + \pgf@lib@dec@parsenum{#2}% + \let\pgf@lib@dec@mark@end=\pgf@lib@dec@computed@width% + \ifdim\pgf@lib@dec@mark@end<\pgf@lib@dec@mark@start\relax% + % Skip! + #5\pgf@lib@dec@mark@last% + \else% + % + \pgf@lib@dec@parsenum{#3}% + \pgfmathparse{\pgf@lib@dec@mark@start+\pgf@lib@dec@computed@width}% + % Update entry in mark list + \edef\pgf@temp{\noexpand\pgf@lib@dec@dobetweenmark{\pgfmathresult pt}{\pgf@lib@dec@mark@end}{\pgf@lib@dec@computed@width}}% + \expandafter\def\expandafter\pgf@lib@dec@mark@marks\expandafter{\pgf@temp{#4}#5}% + \let\pgf@lib@dec@computed@width\pgf@lib@dec@mark@start% + \def\pgf@lib@dec@computed@action{#4}% + \def\pgf@lib@dec@next@state{main}% + \fi% +}% + + +\def\pgf@lib@dec@parsenum#1{% + \pgfmathparse{#1}% + \ifpgfmathunitsdeclared% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathparse{\pgfdecoratedpathlength\pgfmathresult pt}% + \else% + \pgfmathparse{\pgfmathresult pt}% + \fi% + \else% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathparse{\pgfdecoratedpathlength\pgfmathresult*\pgfdecoratedpathlength}% + \else% + \pgfmathparse{\pgfmathresult*\pgfdecoratedpathlength}% + \fi% + \fi% + \edef\pgf@lib@dec@computed@width{\pgfmathresult pt}% +}% + +\def\pgf@lib@dec@mark@last{% + \def\pgf@lib@dec@next@state{final}% +}% + + +% +% If you set the mark connection node inside a mark picture, the +% output path will contain a line to this node +% + +\pgfkeys{/pgf/decoration/mark connection node/.store in=\pgf@lib@mark@node, + /pgf/decoration/mark connection node=}% +\def\pgf@lib@mark@connect@node{% + % Line to "left" end of the node + \pgfpathlineto{\pgfpointshapeborder{\pgf@lib@mark@node}{\pgfqpoint{-1pt}{0pt}}} + % Move to "right" end of the node + \pgfpathmoveto{\pgfpointshapeborder{\pgf@lib@mark@node}{\pgfqpoint{1pt}{0pt}}} +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathmorphing.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathmorphing.code.tex new file mode 100644 index 0000000000..bdc2752cb8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathmorphing.code.tex @@ -0,0 +1,294 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% +% These decorations "morph" paths. That means that the +% original characteristic of the path is kept and the number of +% subpaths remains the same -- only, the lines are slightly offset or +% changed by the decoration. For instance a line might be turned into +% a squiggly line or a snaking line or a bumping line. +% + + +% +% +% Kind 1: Path morphing straight line decorations +% +% + + +% zigzag decoration. +% +\pgfdeclaredecoration{zigzag}{up from center}{% + \state{up from center}[width=+.5\pgfdecorationsegmentlength, next state=big down] + { + \pgfpathlineto{\pgfqpoint{.25\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + }% + \state{big down}[switch if less than=+.5\pgfdecorationsegmentlength to center finish, + width=+.5\pgfdecorationsegmentlength, + next state=big up] + { + \pgfpathlineto{\pgfqpoint{.25\pgfdecorationsegmentlength}{-\pgfdecorationsegmentamplitude}} + }% + \state{big up}[switch if less than=+.5\pgfdecorationsegmentlength to center finish, + width=+.5\pgfdecorationsegmentlength, + next state=big down] + { + \pgfpathlineto{\pgfqpoint{.25\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + }% + \state{center finish}[width=0pt, next state=final]{ + \pgfpathlineto{\pgfpointorigin} + }% + \state{final} + { + \pgfpathlineto{\pgfpointdecoratedpathlast} + }% +}% + + + + +% saw decoration +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength + +\pgfdeclaredecoration{saw}{initial} +{% + \state{initial}[auto end on length=+\pgfdecorationsegmentlength, + auto corner on length=+\pgfdecorationsegmentlength, + width=+\pgfdecorationsegmentlength] + { + \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{0pt}} + }% + \state{final} + {}% +}% + + + + +% random steps decoration +% +% A decoration that consists of random steps heading towards the target +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength + +\pgfdeclaredecoration{random steps}{start} +{% + \state{start}[width=+0pt,next state=step,persistent precomputation=\pgfdecoratepathhascornerstrue]{}% + \state{step}[auto end on length=1.5\pgfdecorationsegmentlength, + auto corner on length=1.5\pgfdecorationsegmentlength, + width=+\pgfdecorationsegmentlength] + { + \pgfpathlineto{ + \pgfpointadd + {\pgfpoint{\pgfdecorationsegmentlength}{0pt}} + {\pgfpoint{rand*\pgfdecorationsegmentamplitude}{rand*\pgfdecorationsegmentamplitude}} + } + }% + \state{final} + {}% +}% + + + +% Meta-decoration line zigzag + +\pgfdeclaremetadecoration{straight zigzag}{line to}{% + \state{line to}[width=\pgfmetadecorationsegmentlength, next state=zigzag] + { + \decoration{curveto} + }% + \state{zigzag}[width=\pgfmetadecorationsegmentlength, next state=line to] + { + \decoration{zigzag} + }% + \state{final} + { + \decoration{curveto} + }% +}% + + + + + +% +% +% Kind 2: Path morphing curved decorations +% +% + + + +% bent decoration +% +% A decoration that looks like someone bent the line a bit. +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentaspect + +\pgfdeclaredecoration{bent}{bent} +{% + \state{bent}[width=+\pgfdecoratedinputsegmentremainingdistance] + { + \pgfpathcurveto + {\pgfqpoint{\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}{\pgfdecorationsegmentamplitude}} + {\pgfpointadd{\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + {\pgfqpoint{-\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}{\pgfdecorationsegmentamplitude}}} + {\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}} + }% + \state{final} + {}% +}% + + + +% decoration snake +% +% This decoration produces a hopefully optically pleasing squiggly snake. +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength + +\pgfdeclaredecoration{snake}{initial} +{% + \state{initial}[switch if less than=+.625\pgfdecorationsegmentlength to final, + width=+.3125\pgfdecorationsegmentlength, + next state=down] + { + \pgfpathcurveto + {\pgfqpoint{.125\pgfdecorationsegmentlength}{0pt}} + {\pgfqpoint{.1875\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.3125\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + }% + \state{down}[switch if less than=+.8125\pgfdecorationsegmentlength to end down, + width=+.5\pgfdecorationsegmentlength, + next state=up] + { + \pgfpathcosine{\pgfqpoint{.25\pgfdecorationsegmentlength}{-1\pgfdecorationsegmentamplitude}} + \pgfpathsine{\pgfqpoint{.25\pgfdecorationsegmentlength}{-1\pgfdecorationsegmentamplitude}} + }% + \state{up}[switch if less than=+.8125\pgfdecorationsegmentlength to end up, + width=+.5\pgfdecorationsegmentlength, + next state=down] + { + \pgfpathcosine{\pgfqpoint{.25\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + \pgfpathsine{\pgfqpoint{.25\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + }% + \state{end down}[width=+.3125\pgfdecorationsegmentlength, + next state=final] + { + \pgfpathcurveto + {\pgfqpoint{.125\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.1875\pgfdecorationsegmentlength}{0pt}} + {\pgfqpoint{.3125\pgfdecorationsegmentlength}{0pt}} + }% + \state{end up}[width=+.3125\pgfdecorationsegmentlength, + next state=final] + { + \pgfpathcurveto + {\pgfqpoint{.125\pgfdecorationsegmentlength}{-\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.1875\pgfdecorationsegmentlength}{0pt}} + {\pgfqpoint{.3125\pgfdecorationsegmentlength}{0pt}} + }% + \state{final} + { + \pgfpathlineto{\pgfpointdecoratedpathlast} + }% +}% + + +% coil decoration +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength, + +\pgfdeclaredecoration{coil}{coil} +{% + \state{coil}[switch if less than=% + 1.5\pgfdecorationsegmentlength+% + \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude+% + \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude to last, + width=+\pgfdecorationsegmentlength] + { + \pgfpathcurveto + {\pgfpoint@oncoil{0 }{ 0.555}{1}} + {\pgfpoint@oncoil{0.445}{ 1 }{2}} + {\pgfpoint@oncoil{1 }{ 1 }{3}} + \pgfpathcurveto + {\pgfpoint@oncoil{1.555}{ 1 }{4}} + {\pgfpoint@oncoil{2 }{ 0.555}{5}} + {\pgfpoint@oncoil{2 }{ 0 }{6}} + \pgfpathcurveto + {\pgfpoint@oncoil{2 }{-0.555}{7}} + {\pgfpoint@oncoil{1.555}{-1 }{8}} + {\pgfpoint@oncoil{1 }{-1 }{9}} + \pgfpathcurveto + {\pgfpoint@oncoil{0.445}{-1 }{10}} + {\pgfpoint@oncoil{0 }{-0.555}{11}} + {\pgfpoint@oncoil{0 }{ 0 }{12}} + }% + \state{last}[width=.5\pgfdecorationsegmentlength+% + \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude+% + \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude,next state=final] + { + \pgfpathcurveto + {\pgfpoint@oncoil{0 }{ 0.555}{1}} + {\pgfpoint@oncoil{0.445}{ 1 }{2}} + {\pgfpoint@oncoil{1 }{ 1 }{3}} + \pgfpathcurveto + {\pgfpoint@oncoil{1.555}{ 1 }{4}} + {\pgfpoint@oncoil{2 }{ 0.555}{5}} + {\pgfpoint@oncoil{2 }{ 0 }{6}} + }% + \state{final} + { + \pgfpathlineto{\pgfpointdecoratedpathlast} + }% +}% + +\def\pgfpoint@oncoil#1#2#3{% + \pgf@x=#1\pgfdecorationsegmentamplitude% + \pgf@x=\pgfdecorationsegmentaspect\pgf@x% + \pgf@y=#2\pgfdecorationsegmentamplitude% + \pgf@xa=0.083333333333\pgfdecorationsegmentlength% + \advance\pgf@x by#3\pgf@xa% +}% + + +% bumps decoration +% +% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength + +\pgfdeclaredecoration{bumps}{initial} +{% + \state{initial}[auto end on length=+.51\pgfdecorationsegmentlength, + auto corner on length=+.51\pgfdecorationsegmentlength, + width=+.5\pgfdecorationsegmentlength] + { + \pgfpathcurveto + {\pgfqpoint{0pt}{.555\pgfdecorationsegmentamplitude}} + {\pgfqpoint{0.11125\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.25\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + \pgfpathcurveto + {\pgfqpoint{.38875\pgfdecorationsegmentlength}{\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.5\pgfdecorationsegmentlength}{.5\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.5\pgfdecorationsegmentlength}{0\pgfdecorationsegmentamplitude}} + }% + \state{final} + { + \pgfpathlineto{\pgfpointdecoratedpathlast} + }% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex new file mode 100644 index 0000000000..f028ec6c37 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex @@ -0,0 +1,240 @@ +% Copyright 2018 by Mark Wibrow and Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% +% Path replacing decorations +% +% These decorations change the path by replacing it by another path. +% For instance, a line in the path might be replaced by small +% ticks or unconnected curves or crosses. Applying a chopping +% decoration to a path means that the path can no longer be used for +% filling in the original manner. +% + + + +% +% +% Kind 1: Path chopping with open subpaths +% +% + + +% ticks decoration +% +% Parameters: \pgfdecorationsegmentlength, \pgfdecorationsegmentamplitude + +\pgfdeclaredecoration{ticks}{ticks} +{% + \state{ticks}[width=+\pgfdecorationsegmentlength] + { + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfdecorationsegmentamplitude}} + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfdecorationsegmentamplitude}} + }% + \state{final} + { + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfdecorationsegmentamplitude}} + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfdecorationsegmentamplitude}} + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + +% expanding waves decoration +% +% Parameters: \pgfdecorationsegmentangle, \pgfdecorationsegmentlength + +\pgfdeclaredecoration{expanding waves}{initial} +{% + \state{initial}[width=+\pgfdecorationsegmentlength,next state=wave] + {}% + + \state{wave}[switch if less than=+\pgfdecorationsegmentlength to last, + width=+\pgfdecorationsegmentlength] + { + \pgfpathmoveto{ + \pgfpointadd + {\pgfqpoint{-\pgfdecoratedcompleteddistance}{0pt}}% + {\pgfpointpolar{\pgfdecorationsegmentangle}{+\pgfdecoratedcompleteddistance}}}% + \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{+\pgfdecoratedcompleteddistance}% + }% + \state{last}[width=+0pt,next state=final] + { + \pgfpathmoveto{ + \pgfpointadd + {\pgfqpoint{-\pgfdecoratedcompleteddistance}{0pt}}% + {\pgfpointpolar{\pgfdecorationsegmentangle}{+\pgfdecoratedcompleteddistance}}}% + \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{+\pgfdecoratedcompleteddistance}% + }% + \state{final} + { + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + +% waves decoration + +\pgfdeclaredecoration{waves}{wave} +{% + \state{wave}[width=\pgfdecorationsegmentlength] + { + \pgftransformxshift{+\pgfdecorationsegmentlength} + \pgfpathmoveto{ + \pgfpointadd + {\pgfqpoint{-\pgfkeysvalueof{/pgf/decoration/start radius}}{0pt}}% + {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}}% + \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}% + }% + \state{final} + { + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + +% border decoration +% +% Parameters: \pgfdecorationsegmentlength, \pgfdecorationsegmentamplitude, \pgfdecorationsegmentangle + +\pgfdeclaredecoration{border}{tick} +{% + \state{tick}[switch if less than=+\pgfdecorationsegmentlength to last, + width=+\pgfdecorationsegmentlength] + { + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpointpolar{\pgfdecorationsegmentangle}{+\pgfdecorationsegmentamplitude}} + }% + \state{last}[width=+\pgfdecorationsegmentamplitude,next state=final] + { + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpointpolar{\pgfdecorationsegmentangle}{+\pgfdecorationsegmentamplitude}} + }% + \state{final} + { + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + + + + +% brace decorations +% +% Parameters: \pgfdecorationsegmentamplitude + +\pgfdeclaredecoration{brace}{brace} +{% + \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final] + { + \pgf@yc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance + \ifdim2\pgfdecorationsegmentamplitude>\pgf@yc + \pgf@yc=0.5\pgf@yc + \else + \pgf@yc=\pgfdecorationsegmentamplitude + \fi + \pgf@xc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance + \advance\pgf@xc-\pgfdecoratedremainingdistance + \ifdim-2\pgfdecorationsegmentamplitude<\pgf@xc + \pgf@xc=-0.5\pgf@xc + \else + \pgf@xc=\pgfdecorationsegmentamplitude + \fi + \pgfpathmoveto{\pgfpointorigin} + \pgfpathcurveto + {\pgfqpoint{.15\pgf@yc}{.3\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}} + {\pgfqpoint{\pgf@yc}{.5\pgfdecorationsegmentamplitude}} + { + \pgftransformxshift{+\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance} + \pgfpathlineto{\pgfqpoint{-\pgf@yc}{.5\pgfdecorationsegmentamplitude}} + \pgfpathcurveto + {\pgfqpoint{-.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}} + {\pgfqpoint{-.15\pgf@yc}{.7\pgfdecorationsegmentamplitude}} + {\pgfqpoint{0\pgf@yc}{1\pgfdecorationsegmentamplitude}} + \pgfpathcurveto + {\pgfqpoint{.15\pgf@xc}{.7\pgfdecorationsegmentamplitude}} + {\pgfqpoint{.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}} + {\pgfqpoint{\pgf@xc}{.5\pgfdecorationsegmentamplitude}} + } + { + \pgftransformxshift{+\pgfdecoratedremainingdistance} + \pgfpathlineto{\pgfqpoint{-\pgf@xc}{.5\pgfdecorationsegmentamplitude}} + \pgfpathcurveto + {\pgfqpoint{-.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}} + {\pgfqpoint{-.15\pgf@xc}{.3\pgfdecorationsegmentamplitude}} + {\pgfqpoint{0pt}{0pt}} + } + }% + \state{final} + {}% +}% + + + + +% show path construction decoration +% +\pgfdeclaredecoration{show path construction}{check for moveto}{% + \state{check for moveto}[width=0pt, next state=segment, + persistent precomputation={% + \begingroup% + \pgf@lib@decoraions@installinputsegmentpoints% + \ifx\pgfdecorationpreviousinputsegment\pgfdecorationinputsegmentmoveto% + \pgfdecoratedinputsegmentmovetocode% + \fi% + \endgroup% + }]{}% + \state{segment}[width=\pgfdecoratedinputsegmentremainingdistance, next state=check for moveto, + persistent precomputation={% + \begingroup% + \pgf@lib@decoraions@installinputsegmentpoints% + \csname pgfdecoratedinputsegment\pgfdecorationcurrentinputsegment code\endcsname% + \endgroup% + }]{}% + \state{final}{% + \egroup% + \begingroup% + \pgf@lib@decoraions@installinputsegmentpoints% + \csname pgfdecoratedinputsegment\pgfdecorationcurrentinputsegment code\endcsname% + \endgroup% + \bgroup% + }% +}% + +\pgfkeys{ + /pgf/decoration/.cd, + moveto code/.code=\def\pgfdecoratedinputsegmentmovetocode{#1}, + lineto code/.code=\def\pgfdecoratedinputsegmentlinetocode{#1}, + curveto code/.code=\def\pgfdecoratedinputsegmentcurvetocode{#1}, + closepath code/.code=\def\pgfdecoratedinputsegmentclosepathcode{#1} +}% + +\let\pgfdecoratedinputsegmentmovetocode\pgfutil@empty% +\let\pgfdecoratedinputsegmentlinetocode\pgfutil@empty% +\let\pgfdecoratedinputsegmentcurvetocode\pgfutil@empty% +\let\pgfdecoratedinputsegmentclosepathcode\pgfutil@empty% + +\def\pgf@lib@decoraions@installinputsegmentpoints{% + \let\pgfpointdecoratedinputsegmentfirst\pgf@decorate@inputsegment@first% + \let\pgfpointdecoratedinputsegmentlast\pgf@decorate@inputsegment@last% + \let\pgfpointdecoratedinputsegmentsupporta\pgf@decorate@inputsegment@supporta% + \let\pgfpointdecoratedinputsegmentsupportb\pgf@decorate@inputsegment@supportb% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.shapes.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.shapes.code.tex new file mode 100644 index 0000000000..77c366ca0c --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.shapes.code.tex @@ -0,0 +1,468 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% Options for shape decorations + +\pgfkeys{ + /pgf/decoration/.cd, + shape/.initial=circle, + anchor/.initial=center, + shape start width/.initial=2.5pt, + shape start height/.initial=2.5pt, + shape end width/.initial=2.5pt, + shape end height/.initial=2.5pt, + shape sep/.store in=\pgf@lib@shapedecoration@sep, + shape sloped/.is if=pgfshapedecorationsloped, + shape scaled/.is if=pgfshapedecorationscaled, + shape evenly spread/.store in=\pgf@lib@shapedecoration@spread, + shape start size/.style={% + shape start width={#1}, + shape start height={#1}% + },% + shape end size/.style={% + shape end width={#1}, + shape end height={#1}% + },% + shape size/.style={% + shape start size={#1}, + shape end size={#1}% + },% + shape width/.style={% + shape start width={#1}, + shape end width={#1} + }, + shape height/.style={% + shape start height={#1}, + shape end height={#1} + } +}% + +\def\pgf@lib@shapedecoration@sep{.25cm, between centers}% +\newif\ifpgfshapedecorationsloped +\pgfshapedecorationslopedtrue +\newif\ifpgfshapedecorationscaled +\let\pgf@lib@shapedecoration@spread\pgfutil@empty% + + + +% triangle decoration + +\pgfdeclaredecoration{triangles}{init} +{% + \state{init}[width=+0pt,next state=triangle,persistent precomputation={ + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start width}} + \edef\pgf@lib@dec@ssw{\pgfmathresult pt} + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start height}/2} + \edef\pgf@lib@dec@ssh{\pgfmathresult pt} + }]{}% + \state{triangle}[switch if less than=+\pgfdecorationsegmentlength to last, + width=+\pgfdecorationsegmentlength] + { + \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{0pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-\pgf@lib@dec@ssh}} + \pgfpathclose + }% + \state{last}[switch if less than=\pgf@lib@dec@ssw to skip, + width=\pgfdecoratedremainingdistance,next state=final] + { + \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{0pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-\pgf@lib@dec@ssh}} + \pgfpathclose + }% + \state{skip}[width=\pgfdecoratedremainingdistance] + {}% + \state{final} + { + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + + +% crosses decoration + +\pgfdeclaredecoration{crosses}{init} +{% + \state{init}[width=+0pt,next state=crosses,persistent precomputation={ + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start width}/2} + \edef\pgf@lib@dec@ssw{\pgfmathresult pt} + \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start height}/2} + \edef\pgf@lib@dec@ssh{\pgfmathresult pt} + }]{}% + \state{crosses}[switch if less than=+\pgfdecorationsegmentlength to last, + width=+\pgfdecorationsegmentlength] + { + \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}} + \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}} + }% + \state{last}[width=+\pgfdecoratedremainingdistance] + { + \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}} + \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}} + \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}} + }% + \state{final}{ + \pgfpathmoveto{\pgfpointdecoratedpathlast} + }% +}% + + + + + + +% The shape background decoration +% +% The shape background decoration adds repeated instances of +% the background path of a specified shape along the path. The shape +% must have been declared by \pgfdeclareshape. If a shape has +% specialized keys (e.g. the number of points on a star, or the apex +% angle the isosceles triangle), these can be specified in the usual manner. +% +% The separation between shapes in the path can be specified and can +% be between the center of the shape or the border of the shape. +% +% The height and width of the shape can be independently or +% simultaneously scaled (linearly) along the path. It is also +% possible to prevent the shapes being sloped parallel to the +% path. + +% internal if +\newif\ifpgf@lib@shapedecoration@betweenborders + +\edef\pgf@lib@shapedecoration@initialise{0pt}% + +\pgfdeclaredecoration{shape backgrounds}{initialise} +{% + \state{initialise} + [ + width=+\pgf@lib@shapedecoration@initialise, + next state=shape, + persistent precomputation= + { + % + % \egroup ends the group started by the automaton before executing + % a decoration state. This prevents the need for (most) \global variables. + % + % + % Check the shape exists. + % + \pgfutil@ifundefined{pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}}{% + \pgferror{I do not know the shape `\pgfkeysvalueof{/pgf/decoration/shape}', + so I cannot use it in a decoration. Check if its library been loaded or if you + simply mistyped the name}}{}% + % + % Calculate a `default' path size. + % + \pgfinterruptpath% + \pgfinterruptboundingbox% + \pgftransformreset% + \pgf@relevantforpicturesizetrue% + % + % This size of this shape is unimportant, but it should + % be just large/small enough to avoid huge errors when + % calculating the scaling factors later on. + % + \pgfkeys{/pgf/inner sep=50pt, /pgf/minimum size=1pt}% Arbitrary lengths. + \setbox\pgfnodeparttextbox\hbox{}% Assume shape does nothing special if box is empty. + \let\pgf@sh@savedmacros\pgfutil@empty% + \let\pgf@sh@savedpoints\pgfutil@empty% + \csname pgf@sh@s@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname% + \pgf@sh@savedpoints% + \pgf@sh@savedmacros% + % + % Save the macros and points. + % + \expandafter\gdef\expandafter\pgf@lib@shapedecoration@points\expandafter{\pgf@sh@savedpoints}% + \expandafter\gdef\expandafter\pgf@lib@shapedecoration@macros\expandafter{\pgf@sh@savedmacros}% + \csname pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname% + % + % Save the dimensions of the shape path. + % + \pgf@x\pgf@picmaxx% + \pgf@y\pgf@picmaxy% + \advance\pgf@x-\pgf@picminx% + \advance\pgf@y-\pgf@picminy% + \xdef\pgf@lib@shapedecoration@shapepathsize{% + \noexpand\pgf@x\the\pgf@x% + \noexpand\pgf@y\the\pgf@y% + }% + \endpgfinterruptboundingbox% + \endpgfinterruptpath% + % + \edef\pgf@lib@shapedecoration@beforeshape{0pt}% + \edef\pgf@lib@shapedecoration@aftershape{0pt}% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape start width}}% + \edef\pgf@lib@shapedecoration@startwidth{\the\pgf@x}% + \edef\pgf@lib@shapedecoration@width{\the\pgf@x}% + \pgf@x-\pgf@x% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape end width}}% + \edef\pgf@lib@shapedecoration@widthchange{\the\pgf@x}% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/decoration/shape start height}}% + \edef\pgf@lib@shapedecoration@initialheight{\the\pgf@y}% + \edef\pgf@lib@shapedecoration@height{\the\pgf@y}% + \pgf@y-\pgf@y% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/decoration/shape end height}}% + \edef\pgf@lib@shapedecoration@heightchange{\the\pgf@y}% + % + % Calculate the sep. + % + \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty% + % + % Not spreading, so easy: + % + \def\pgf@lib@shapedecoration@borderstext{between borders}% + \afterassignment\pgf@lib@shapedecoration@setkeyword% + \expandafter\pgf@x\pgf@lib@shapedecoration@sep,\pgf@stop% + \edef\pgf@lib@shapedecoration@sep{\the\pgf@x}% + \else% + % + % Spreading (a bit of a nuiscence actually). + % + \def\pgf@lib@shapedecoration@borderstext{by borders}% + \afterassignment\pgf@lib@shapedecoration@setkeyword% + \expandafter\c@pgf@counta\pgf@lib@shapedecoration@spread,\pgf@stop% + \ifpgf@lib@shapedecoration@betweenborders% + % + % Ok. The required sep between borders is: + % + % (r -(n-1)((a+b)/2))/(n-1) + % + % r = decoration length (here, the remaining distance) + % a = initial width + % b = end width + % n = the number of shapes + % + \ifnum\c@pgf@counta>1\relax% + \advance\c@pgf@counta-1\relax% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape start width}}% + \ifpgfshapedecorationscaled% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape end width}}% + \else% + \advance\pgf@x\pgf@x% + \fi% + \pgf@x.5\pgf@x% (a+b)/2 + \multiply\pgf@x-\c@pgf@counta% -(n-1)((a+b)/2) + \advance\pgf@x\pgfdecoratedremainingdistance% + \divide\pgf@x\c@pgf@counta% + \pgf@x.9999\pgf@x% Hackery to control some native TeX inaccuracies. + % + % Unfortunately if the shape is scaled, and evenly spread by borders, + % it is necessary to do something a bit different to control for + % (most) inaccuracies. + % + \ifpgfshapedecorationscaled% + \pgf@xa\pgf@lib@shapedecoration@widthchange\relax% + \divide\pgf@xa\c@pgf@counta% + \edef\pgf@lib@shapedecoration@specialwidth{\the\pgf@xa}% + \fi% + \else% + \pgf@lib@shapedecoration@betweenbordersfalse% + \pgf@x\pgfdecoratedremainingdistance% + \ifnum\c@pgf@counta=1\relax% + \pgf@y.5\pgf@x% + \edef\pgf@lib@shapedecoration@initialise{\the\pgf@y}% + \else% + \advance\pgf@x5pt\relax% An arbitrary value >0pt. + \edef\pgf@lib@shapedecoration@initialise{\the\pgf@x}% + \fi% + \fi% + \else% + % + % Between centers. + % + \pgf@x\pgfdecoratedremainingdistance% + \ifnum\c@pgf@counta>1\relax% + \advance\c@pgf@counta-1\relax% + \divide\pgf@x\c@pgf@counta\relax% + \else% + \ifnum\c@pgf@counta=1\relax% + \pgf@y.5\pgf@x% + \edef\pgf@lib@shapedecoration@initialise{\the\pgf@y}% + \else% + \advance\pgf@x5pt\relax% An arbitrary value >0pt. + \edef\pgf@lib@shapedecoration@initialise{\the\pgf@x}% + \fi% + \fi% + \fi% + \edef\pgf@lib@shapedecoration@sep{\the\pgf@x}% + \fi% + }] + {}% + \state{before shape} + [ + width=\pgf@lib@shapedecoration@beforeshape-1sp, + next state=shape, + persistent precomputation= + { + \ifpgfshapedecorationscaled% + \ifpgf@lib@shapedecoration@betweenborders% + \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty% + % + % Not so straightforward. The required ratio is given by + % + % R = (c+W/2)/(c+r-.5*w) + % + % c = completed distance + % r = remaining distance + % W = initial width + % w = the change in width (i.e., end - start) + % + \pgf@x\pgfdecoratedcompleteddistance% + \advance\pgf@x\pgfdecoratedremainingdistance% + \pgf@xa\pgf@lib@shapedecoration@startwidth\relax% + \pgf@xa.5\pgf@xa% + \advance\pgf@xa\pgfdecoratedcompleteddistance% c+W/2 + % + \pgf@xb\pgf@lib@shapedecoration@widthchange\relax% + \pgf@xb-.5\pgf@xb% + \advance\pgf@xb\pgf@x% c+r-.5*w + % + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}% + \fi% + \else% + % + % Easy peasy. The required ratio is + % + % R = c / (c+r) + % + \pgf@y\pgfdecoratedcompleteddistance% + \advance\pgf@y\pgfdecoratedremainingdistance% + \pgfmathdivide@{\pgfmath@tonumber{\pgfdecoratedcompleteddistance}}{\pgfmath@tonumber{\pgf@y}}% + \fi% + % + % Get the new width. + % + \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty% + \pgf@x\pgf@lib@shapedecoration@widthchange\relax% + \pgf@x\pgfmathresult\pgf@x% + \advance\pgf@x\pgf@lib@shapedecoration@startwidth\relax% + \else% + \ifpgf@lib@shapedecoration@betweenborders% + % + % Special case when decoration is scaled, and evenly spread by borders. + % + \pgf@x\pgf@lib@shapedecoration@width\relax% + \advance\pgf@x\pgf@lib@shapedecoration@specialwidth\relax% + \pgf@xa\pgf@x% + \advance\pgf@xa-\pgf@lib@shapedecoration@startwidth\relax% + \pgf@xb\pgf@lib@shapedecoration@widthchange\relax% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}% + \else% + \pgf@x\pgf@lib@shapedecoration@widthchange\relax% + \pgf@x\pgfmathresult\pgf@x% + \advance\pgf@x\pgf@lib@shapedecoration@startwidth\relax% + \fi% + \fi% + \edef\pgf@lib@shapedecoration@width{\the\pgf@x}% + % + % New height = R*h + H + % + \pgf@y\pgf@lib@shapedecoration@heightchange\relax% + \pgf@y\pgfmathresult\pgf@y% + \advance\pgf@y\pgf@lib@shapedecoration@initialheight\relax% + \edef\pgf@lib@shapedecoration@height{\the\pgf@y}% + \fi% + % + \ifpgf@lib@shapedecoration@betweenborders% + \pgf@x\pgf@lib@shapedecoration@width\relax% + \pgf@x.5\pgf@x% + \edef\pgf@lib@shapedecoration@beforeshape{\the\pgf@x}% + \else% + \def\pgf@lib@shapedecoration@beforeshape{0pt}% + \fi% + }] + {}% + \state{shape}[width=+0sp,next state=after shape] + { + \ifpgfshapedecorationsloped% + \else% + \pgftransformrotate{-\pgfdecoratedangle}% + \fi% + % + % Scale the path when it is actually drawn. + % + \pgf@lib@shapedecoration@shapepathsize% + \pgfutil@tempdima\pgf@x% + \pgfutil@tempdimb\pgf@y% + \pgf@xa\pgf@lib@shapedecoration@width\relax% + \pgf@xb\pgfutil@tempdima% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}% + \expandafter\pgftransformxscale\expandafter{\pgfmathresult}% + % + \pgf@ya\pgf@lib@shapedecoration@height\relax% + \pgf@yb\pgfutil@tempdimb% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@ya}}{\pgfmath@tonumber{\pgf@yb}}% + \expandafter\pgftransformyscale\expandafter{\pgfmathresult}% + % + % Move to the center anchor. + % + \pgf@lib@shapedecoration@points% + \pgf@lib@shapedecoration@macros% + \pgftransformshift{% + \pgf@sh@reanchor{\pgfkeysvalueof{/pgf/decoration/shape}}{\pgfkeysvalueof{/pgf/decoration/anchor}}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }% + % + % And draw the shape path. + % + \csname pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname% + }% + \state{after shape} + [ + width=\pgf@lib@shapedecoration@aftershape-1sp, + next state=sep, + persistent precomputation= + { + \ifpgf@lib@shapedecoration@betweenborders% + \pgf@x\pgf@lib@shapedecoration@width\relax% + \pgf@x.5\pgf@x% + \edef\pgf@lib@shapedecoration@aftershape{\the\pgf@x}% + \else% + \edef\pgf@lib@shapedecoration@aftershape{0pt}% + \fi% + } + ] + {}% + \state{sep}[width=\pgf@lib@shapedecoration@sep,next state=before shape, + persistent precomputation=\def\pgf@lib@shapedecoration@beforeshape{0pt}] + {}% + \state{final} + { + \pgfpathmoveto{\pgfpointdecoratedpathlast}% + }% +}% + +\def\pgf@lib@shapedecoration@setkeyword,{% + \pgfutil@ifnextchar\pgf@stop{\def\pgf@temp{}\pgf@lib@@@shapedecoration@setkeyword}{\pgf@lib@@shapedecoration@setkeyword}% +}% +\def\pgf@lib@@shapedecoration@setkeyword#1,{\def\pgf@temp{#1}\pgf@lib@@@shapedecoration@setkeyword}% +\def\pgf@lib@@@shapedecoration@setkeyword\pgf@stop{% + \ifx\pgf@temp\pgf@lib@shapedecoration@borderstext% + \pgf@lib@shapedecoration@betweenborderstrue% + \else% + \pgf@lib@shapedecoration@betweenbordersfalse% + \fi% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.text.code.tex b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.text.code.tex new file mode 100644 index 0000000000..301fa24784 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/decorations/pgflibrarydecorations.text.code.tex @@ -0,0 +1,357 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgfmodule{decorations}% + + +% Options for text decorations + +\pgfkeys{ + /pgf/decoration/.cd, + text/.store in=\pgfdecorationtext,% + text color/.store in=\pgf@lib@decorationtextcolor,% + text format delimiters/.code={\expandafter\pgfsetdecoratetextformatdelimiters#1}, + text align/.code={\pgfkeys{/pgf/decoration/text align/.cd,#1}}, + text align/.cd, + align/.initial=left, + left/.style={/pgf/decoration/text align/align=left}, + right/.style={/pgf/decoration/text align/align=right}, + center/.style={/pgf/decoration/text align/align=center}, + left indent/.initial=0pt, + right indent/.initial=0pt, + fit to path/.is if=pgf@lib@dec@text@fit, + fit to path stretching spaces/.default=true, + fit to path stretching spaces/.code={% + \csname pgf@lib@dec@text@fit#1\endcsname% + \csname pgf@lib@dec@text@stretch@spaces#1\endcsname% + }% +}% + +\newif\ifpgf@lib@dec@text@scan@space +\newif\ifpgf@lib@dec@text@stretch@spaces +\newif\ifpgf@lib@dec@text@fit + +\def\pgf@lib@decorationtextcolor{black}% + +\def\pgf@lib@dec@text@left@text{left}% +\def\pgf@lib@dec@text@right@text{right}% +\def\pgf@lib@dec@text@right@center{center}% + +% Decorates a path with a text. The path is removed during this +% process + +\pgfdeclaredecoration{text along path}{initial}{% + \state{initial}[ + width=+0pt, next state=left indent, + persistent precomputation={% + \edef\pgf@lib@dec@text@indent@left{\pgfkeysvalueof{/pgf/decoration/text align/left indent}}% + \edef\pgf@lib@dec@text@indent@right{\pgfkeysvalueof{/pgf/decoration/text align/right indent}}% + \edef\pgf@lib@dec@text@align{\pgfkeysvalueof{/pgf/decoration/text align/align}}% + \pgfdecoratedremainingdistance=\pgfdecoratedpathlength% + \advance\pgfdecoratedremainingdistance by-\pgf@lib@dec@text@indent@right\relax% + \edef\pgfdecoratedpathlength{\the\pgfdecoratedremainingdistance}% + \pgf@lib@dec@text@getwidth% + \pgf@x=\pgf@lib@dec@text@width\relax% + \pgf@y=\pgfdecoratedremainingdistance% + \ifpgf@lib@dec@text@fit% + \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax% + \advance\pgf@y by-\pgf@x% + \ifpgf@lib@dec@text@stretch@spaces% + \def\pgf@lib@dec@text@character@shift{0pt}% + \divide\pgf@y by\pgf@lib@dec@space@count\relax% + \edef\pgf@lib@dec@text@space@shift{\the\pgf@y}% + \else% + \c@pgf@counta=\pgf@lib@dec@character@count\relax% + \advance\c@pgf@counta by-1\relax% + \divide\pgf@y by\c@pgf@counta\relax% + \edef\pgf@lib@dec@text@character@shift{\the\pgf@y}% + \def\pgf@lib@dec@text@space@shift{0pt}% + \fi% + \ifdim\pgf@y<0pt\relax% + \pgf@lib@dec@text@fitfalse% + \pgf@lib@dec@text@stretch@spacesfalse% + \def\pgf@lib@dec@text@character@shift{0pt}% + \def\pgf@lib@dec@text@space@shift{0pt}% + \fi% + \else% + \def\pgf@lib@dec@text@character@shift{0pt}% + \def\pgf@lib@dec@text@space@shift{0pt}% + \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@left@text% + \else% + \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@right@text% + \advance\pgf@y by-\pgf@x% + \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}% + \else% + \advance\pgf@y by-\pgf@x% + \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax% + \pgf@y=0.5\pgf@y% + \advance\pgf@y by\pgf@lib@dec@text@indent@left\relax% + \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}% + \fi% + \fi% + \fi% + \let\pgfdecorationrestoftext=\pgfdecorationtext% + }]{}% +\state{left indent}[width=+\pgf@lib@dec@text@indent@left, next state=scan]{}% +% +\state{scan}[ + width=+0pt, + next state=before typeset, + persistent precomputation={ + \pgf@lib@dec@text@scanchar% + \ifvoid\pgf@lib@dec@text@box% + \setbox\pgf@lib@dec@text@box\hbox{}% + \wd\pgf@lib@dec@text@box16383pt\relax% + \fi% +}]{}% +% +\state{before typeset}[width=+.5\wd\pgf@lib@dec@text@box, next state=typeset]{}% +% +\state{typeset}[width=+0pt, next state=after typeset] +{% + \pgftransformxshift{+-.5\wd\pgf@lib@dec@text@box}% + \setbox\pgf@hbox\hbox{\copy\pgf@lib@dec@text@box}% + \pgfqboxsynced\pgf@hbox% +}% +\state{after typeset}[width=+.5\wd\pgf@lib@dec@text@box, next state=shift, + persistent precomputation={% + \ifpgf@lib@dec@text@fit% + \ifpgf@lib@dec@text@stretch@spaces% + \ifpgf@lib@dec@text@scan@space% + \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@space@shift% + \else% + \def\pgf@lib@dec@text@shift{0pt}% + \fi% + \else% + \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@character@shift% + \fi% + \else% + \def\pgf@lib@dec@text@shift{0pt}% + \fi% + }]{}% +\state{shift}[width=+\pgf@lib@dec@text@shift, next state=scan]{}% +\state{final}{}% +}% + + +% \pgfsetdecoratetextformatdelimiters +% +% Set the delimiters for formatting in the text decoration. +% NB: Catcodes for delimiters should be 11 or 12. +% +% Examples: +% +% \pgfsetdecoratetextformatdelimiters{|}{}% 2nd argument can be empty. +% +% \def\pgfdecoratetext{A big |\color{red}|red|| apple.} +% +% \pgfsetdecoratetextformatdelimiters{[}{]} +% +% \def\pgfdecoratetext{The [\it]very[+\color{green}]green[] sprouts.} +% +\def\pgfsetdecoratetextformatdelimiters#1#2{% + \def\pgf@lib@dec@text@formatchar{#1}% + \def\pgf@test{#2}% + \ifx\pgf@test\pgfutil@empty% + \def\pgf@lib@dec@text@collectformat##1#1{% + \pgf@lib@dec@text@@collectformat##1\pgf@stop}% + \else% + \def\pgf@lib@dec@text@collectformat##1#2{% + \pgf@lib@dec@text@@collectformat##1\pgf@stop}% + \fi% +}% + +\pgfsetdecoratetextformatdelimiters{|}{}% + +\newbox\pgf@lib@dec@text@box +\newif\ifpgf@lib@decorate@textmathmode + +\let\pgfdecorationtext=\pgfutil@empty +\let\pgfdecorationrestoftext=\pgfutil@empty% +\let\pgf@lib@dec@text@format=\pgfutil@empty + +\def\pgf@lib@dec@text@scanchar{% + \pgf@lib@dec@text@scan@spacefalse% + \ifx\pgfdecorationrestoftext\pgfutil@empty% + \let\pgf@lib@dec@text@char\pgfutil@empty% + \setbox\pgf@lib@dec@text@box\box\pgfutil@voidb@x% + \let\pgf@next\relax% + \else\ifx\pgfdecorationrestoftext\pgf@lib@dec@mathshift% + \ifpgf@lib@decorate@textmathmode% + \pgf@lib@decorate@textmathmodefalse% + \fi% + \let\pgf@lib@dec@text@char\pgfutil@empty% + \setbox\pgf@lib@dec@text@box\box\pgfutil@voidb@x% + \let\pgf@next\relax% + \else + \let\pgf@next\pgf@lib@dec@text@@scanchar% + \fi\fi% + \pgf@next}% + +\def\pgf@lib@dec@text@@scanchar{% + \expandafter\pgf@lib@dec@text@@@scanchar\pgfdecorationrestoftext\pgf@stop}% + +\def\pgf@lib@dec@text@@@scanchar{% + \futurelet\pgf@lib@dec@lettoken% + \pgf@lib@dec@text@@@@scanchar}% + +\def\pgf@lib@dec@text@@@@scanchar{% + \ifx\pgf@lib@dec@lettoken\pgfutil@sptoken% + \let\pgf@next\pgf@lib@dec@text@insertspace% + \else% + \let\pgf@next\pgf@lib@dec@text@@@@@scanchar% + \fi% + \pgf@next}% + +\def\pgf@lib@dec@text@@@@@scanchar{% + \pgfutil@ifnextchar\bgroup{\pgf@lib@dec@text@collectgroup}% + {\pgf@lib@dec@text@@@@@@scanchar}}% + +\def\pgf@lib@dec@text@collectgroup#1{% + \def\pgf@lib@dec@text@char{#1}% + \pgf@lib@dec@text@collectrestoftext}% + +\def\pgf@lib@dec@text@@@@@@scanchar#1{% + \ifx#1\pgf@stop% + \pgf@lib@dec@text@box\box\pgfutil@voidb@x% + \let\pgf@next\pgf@lib@dec@text@endoftext% + \else% + \def\pgf@lib@dec@text@char{#1}% + \ifx#1\space% + \let\pgf@next\pgf@lib@dec@text@collectrestoftext% + \else% + \ifx#1\ % + \let\pgf@next\pgf@lib@dec@text@collectrestoftext% + \else% + \ifx\pgf@lib@dec@text@char\pgf@lib@dec@text@formatchar% + \let\pgf@next\pgf@lib@dec@text@collectformat% + \else% + \expandafter\ifcat\noexpand#1\relax% + \let\pgf@next\pgf@lib@dec@text@expandcs% + \else% + \ifnum\catcode`#1=3\relax% + \ifpgf@lib@decorate@textmathmode% + \pgf@lib@decorate@textmathmodefalse% + \else% + \pgf@lib@decorate@textmathmodetrue% + \fi% + \let\pgf@next\pgf@lib@dec@text@@@scanchar% + \else% + \let\pgf@next\pgf@lib@dec@text@collectrestoftext% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgf@next% +}% + +\def\pgf@lib@dec@text@@collectformat{% + \pgfutil@ifnextchar+{\pgf@lib@dec@text@addtoformat}{\pgf@lib@dec@text@setformat}}% + +\def\pgf@lib@dec@text@setformat#1\pgf@stop{% + \def\pgf@lib@dec@text@format{#1}% + \pgf@lib@dec@text@@@scanchar% +}% + +\def\pgf@lib@dec@text@addtoformat+#1\pgf@stop{% + \expandafter\def\expandafter\pgf@lib@dec@text@format\expandafter{\pgf@lib@dec@text@format#1}% + \pgf@lib@dec@text@@@scanchar% +}% + +\def\pgf@lib@dec@text@insertspace{% + \pgf@lib@dec@text@scan@spacetrue% + \pgfutil@ifnextchar\bgroup{\pgf@lib@dec@text@@insertspacegrp}% + {\pgf@lib@dec@text@@insertspace}}% + +\def\pgf@lib@dec@text@@insertspacegrp#1{% + \pgf@lib@dec@text@@@@@@scanchar\space{#1}}% + +\def\pgf@lib@dec@text@@insertspace#1{% + \pgf@lib@dec@text@@@@@@scanchar\space#1}% + +\def\pgf@lib@dec@text@expandcs{% + \expandafter\expandafter\expandafter\pgf@lib@dec@text@@@@@scanchar% + \pgf@lib@dec@text@char}% + +\def\pgf@lib@dec@text@endoftext{% + \let\pgfdecorationrestoftext\pgfutil@empty% + \let\pgf@lib@dec@text@char\pgfutil@empty% +}% +\def\pgf@lib@dec@text@collectrestoftext{% + \pgf@lib@dec@text@dobox% + \futurelet\pgf@lib@dec@text@lettoken% + \pgf@lib@dec@text@@collectrestoftext}% + +\def\pgf@lib@dec@text@@collectrestoftext{% + \ifx\bgroup\pgf@lib@dec@text@lettoken% + \let\pgf@next\pgf@lib@dec@text@@@collectrestoftextgrp% + \else% + \let\pgf@next\pgf@lib@dec@text@@@collectrestoftext% + \fi% + \pgf@next}% + +\def\pgf@lib@dec@text@@@collectrestoftextgrp#1#2\pgf@stop{\def\pgfdecorationrestoftext{{#1}#2}% +}% + +\def\pgf@lib@dec@text@@@collectrestoftext#1\pgf@stop{\def\pgfdecorationrestoftext{#1}}% + +{% + \catcode`\$3 % + \gdef\pgf@lib@dec@mathshift{$}% + \catcode`\$9 $% For editors with annoying syntax highlighting. +}% + +\def\pgf@lib@dec@text@dobox{% + \setbox\pgf@lib@dec@text@box\hbox{% + \pgfinterruptpicture% + \begingroup% + \pgfsetcolor{\pgf@lib@decorationtextcolor}% + \ifpgf@lib@decorate@textmathmode\pgf@lib@dec@mathshift\fi% + \pgf@lib@dec@text@format\relax% + \pgf@lib@dec@text@char% + \ifpgf@lib@decorate@textmathmode\pgf@lib@dec@mathshift\fi% + \endgroup% + \endpgfinterruptpicture% + }% +}% + +\def\pgf@lib@dec@text@getwidth{% + \begingroup% + \let\c@pgf@lib@dec@characters=\c@pgf@counta% + \let\c@pgf@lib@dec@spaces=\c@pgf@countb% + \let\pgfdecorationrestoftext=\pgfdecorationtext% + \c@pgf@lib@dec@spaces=0\relax% + \c@pgf@lib@dec@characters=0\relax% + \pgfmathloop% + \pgf@lib@dec@text@scanchar% + \ifvoid\pgf@lib@dec@text@box% + \else% + \setbox\pgf@hbox=\hbox{{% + \unhbox\pgf@hbox% + \unhbox\pgf@lib@dec@text@box% + }}% + \advance\c@pgf@lib@dec@characters by1\relax% + \ifpgf@lib@dec@text@scan@space% + \advance\c@pgf@lib@dec@spaces by1\relax% + \fi% + \repeatpgfmathloop% + \global\pgf@x=\the\wd\pgf@hbox% + \xdef\pgf@lib@dec@temp{\the\c@pgf@lib@dec@characters}% + \xdef\pgf@lib@dec@@temp{\the\c@pgf@lib@dec@spaces}% + \endgroup% + \edef\pgf@lib@dec@text@width{\the\pgf@x}% + \let\pgf@lib@dec@character@count=\pgf@lib@dec@temp% + \let\pgf@lib@dec@space@count=\pgf@lib@dec@@temp% +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/functions.lua b/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/functions.lua new file mode 100644 index 0000000000..367d6ae298 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/functions.lua @@ -0,0 +1,626 @@ +-- Copyright 2011 by Christophe Jorssen +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License. +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more details. +-- +-- $Id$ +-- + +local pgfluamathfunctions = pgfluamathfunctions or {} + +-- Maps function names to their function. +-- +-- Note that this allows to register functions which are not in pgfluamathfunctions. +-- +-- Note that the string keys are not necessarily the same as the function +-- names. In particular, the math expression "not(1,1)" will execute notPGF(1,1) +-- +-- Note that each function which is added to pgfluamathfunctions will _automatically_ be inserted into this map, see __newindex. +-- (I fear it will not be erased directly...) +pgfluamathfunctions.stringToFunctionMap = {} + +local newFunctionAllocatedCallback = function(table,key,value) + local keyName = tostring(key):gsub("PGF","") + if not value then + stringToFunctionMap[keyName] = nil + elseif type(value) == 'function' then + -- remember it, and strip PGF suffix (i.e. remember 'not' instead of 'notPGF') + pgfluamathfunctions.stringToFunctionMap[keyName] = value + end + rawset(table,key,value) +end + +setmetatable(pgfluamathfunctions, { __newindex = newFunctionAllocatedCallback }) + +local mathabs, mathacos, mathasin = math.abs, math.acos, math.asin +local mathatan, mathceil = math.atan, math.ceil +local mathcos, mathdeg = math.cos, math.deg +local mathexp, mathfloor, mathfmod = math.exp, math.floor, math.fmod +local mathlog, mathmax = math.log, math.max +local mathmin, mathpi = math.min, math.pi +local mathrad, mathrandom = math.rad, math.random +local mathrandomseed, mathsin = math.randomseed, math.sin +local mathsqrt = math.sqrt +local mathtan = math.tan + +local trigFormatToRadians = mathrad + +local radiansToTrigFormat = mathdeg + +pgfluamathfunctions.TrigFormat = { 'deg', 'rad' } +pgfluamathfunctions.stringToFunctionMap["TrigFormat"] = nil + +-- choice is one of the valid choices in TrigFormat. +function pgfluamathfunctions.setTrigFormat(choice) + if choice == 'deg' then + trigFormatToRadians = mathrad + radiansToTrigFormat = mathdeg + elseif choice == 'rad' then + local identity = function(x) return x end + trigFormatToRadians = identity + radiansToTrigFormat = identity + else + error("The argument '" .. tostring(choice) .. "' is no valid choice for setTrigFormat.") + end +end +pgfluamathfunctions.stringToFunctionMap["setTrigFormat"] = nil + +pgfluamathfunctions.setRandomSeed = mathrandomseed +pgfluamathfunctions.stringToFunctionMap["setRandomSeed"] = nil + +------------------------------------------- + +function pgfluamathfunctions.add(x,y) + return x+y +end + +function pgfluamathfunctions.subtract(x,y) + return x-y +end + +function pgfluamathfunctions.neg(x) + return -x +end + +function pgfluamathfunctions.multiply(x,y) + return x*y +end + +function pgfluamathfunctions.veclen(x,y) + return mathsqrt(x*x+y*y) +end + +function pgfluamathfunctions.divide(x,y) + return x/y +end + +function pgfluamathfunctions.div(x,y) + return mathfloor(x/y) +end + +function pgfluamathfunctions.pow(x,y) + -- do not use math.pow -- it is deprecated as of LUA 5.3 + return x^y +end + +function pgfluamathfunctions.factorial(x) +-- TODO: x must be an integer + if x == 0 then + return 1 + else + return x * pgfluamathfunctions.factorial(x-1) + end +end + +function pgfluamathfunctions.ifthenelse(x,y,z) + if x~= 0 then + return y + else + return z + end +end + +function pgfluamathfunctions.equal(x,y) + if x == y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.greater(x,y) + if x > y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.less(x,y) + if x < y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.min(x,y) + return mathmin(x,y) +end + +function pgfluamathfunctions.max(x,y) + return mathmax(x,y) +end + +function pgfluamathfunctions.notequal(x,y) + if x ~= y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.notless(x,y) + if x >= y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.notgreater(x,y) + if x <= y then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.andPGF(x,y) + if (x ~= 0) and (y ~= 0) then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.orPGF(x,y) + if (x ~= 0) or (y ~= 0) then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.notPGF(x) + if x == 0 then + return 1 + else + return 0 + end +end + +function pgfluamathfunctions.pi() + return mathpi +end + +function pgfluamathfunctions.e() + return mathexp(1) +end + +function pgfluamathfunctions.abs(x) + return mathabs(x) +end + +function pgfluamathfunctions.floor(x) + return mathfloor(x) +end + +function pgfluamathfunctions.ceil(x) + return mathceil(x) +end + +function pgfluamathfunctions.exp(x) + return mathexp(x) +end + +function pgfluamathfunctions.ln(x) + return mathlog(x) +end + +local logOf10 = mathlog(10) +function pgfluamathfunctions.log10(x) + return mathlog(x) / logOf10 +end + +local logOf2 = mathlog(2) +function pgfluamathfunctions.log2(x) + return mathlog(x) / logOf2 +end + +function pgfluamathfunctions.sqrt(x) + return mathsqrt(x) +end + +function pgfluamathfunctions.sign(x) + if x < 0 then + return -1.0 + elseif x == 0 then + return 0.0 + else + return 1.0 + end +end +function pgfluamathfunctions.real(x) + -- "ensure that x contains a decimal point" is kind of a no-op here, isn't it!? + return x +end + +function pgfluamathfunctions.rnd() + return mathrandom() +end + +function pgfluamathfunctions.rand() + return -1 + mathrandom() *2 +end + +function pgfluamathfunctions.random(x,y) + if x == nil and y == nil then + return mathrandom() + elseif y == nil then + return mathrandom(x) + else + return mathrandom(x,y) + end +end + +function pgfluamathfunctions.deg(x) + return mathdeg(x) +end + +function pgfluamathfunctions.rad(x) + return mathrad(x) +end + +function pgfluamathfunctions.round(x) + if x<0 then + return -mathfloor(mathabs(x)+0.5) + else + return mathfloor(x + 0.5) + end +end + +function pgfluamathfunctions.gcd(a, b) + if b == 0 then + return a + else + return pgfluamathfunctions.gcd(b, a%b) + end +end + +function pgfluamathfunctions.isprime(a) + local ifisprime = true + if a == 1 then + ifisprime = false + elseif a == 2 then + ifisprime = true +-- if a > 2 then + else + local i, imax = 2, mathceil(mathsqrt(a)) + 1 + while ifisprime and (i < imax) do + if pgfluamathfunctions.gcd(a,i) ~= 1 then + ifisprime = false + end + i = i + 1 + end + end + if ifisprime then + return 1 + else + return 0 + end +end + + +function pgfluamathfunctions.split_braces_to_explist(s) + -- (Thanks to mpg and zappathustra from fctt) + -- Make unpack available whatever lua version is used + -- (unpack in lua 5.1 table.unpack in lua 5.2) + local unpack = table.unpack or unpack + local t = {} + for i in s:gmatch('%b{}') do + table.insert(t, tonumber(i:sub(2, -2))) + end + return unpack(t) +end + +function pgfluamathfunctions.split_braces_to_table(s) + local t = {} + for i in s:gmatch('%b{}') do + table.insert(t, tonumber(i:sub(2, -2))) + end + return t +end + +function pgfluamathfunctions.mathtrue() + return 1.0 +end +pgfluamathfunctions.stringToFunctionMap["true"] = pgfluamathfunctions.mathtrue + +function pgfluamathfunctions.mathfalse() + return 0.0 +end +pgfluamathfunctions.stringToFunctionMap["false"] = pgfluamathfunctions.mathfalse + +function pgfluamathfunctions.frac(a) + -- should be positive, apparently + return mathabs(a - pgfluamathfunctions.int(a)) +end + +function pgfluamathfunctions.int(a) + if a < 0 then + return -mathfloor(mathabs(a)) + else + return mathfloor(a) + end +end + +function pgfluamathfunctions.iseven(a) + if (a % 2) == 0 then + return 1.0 + else + return 0.0 + end +end + +function pgfluamathfunctions.isodd(a) + if (a % 2) == 0 then + return 0.0 + else + return 1.0 + end +end + +function pgfluamathfunctions.mod(x,y) + if x/y < 0 then + return -(mathabs(x)%mathabs(y)) + else + return mathabs(x)%mathabs(y) + end +end + +function pgfluamathfunctions.Mod(x,y) + local tmp = pgfluamathfunctions.mod(x,y) + if tmp < 0 then + tmp = tmp + y + end + return tmp +end + +function pgfluamathfunctions.Sin(x) + return mathsin(trigFormatToRadians(x)) +end +pgfluamathfunctions.sin=pgfluamathfunctions.Sin + + +function pgfluamathfunctions.cosh(x) + -- math.cosh is deprecated as of LUA 5.3 . reimplement it: + return 0.5* (mathexp(x) + mathexp(-x)) +end +function pgfluamathfunctions.sinh(x) + -- math.sinh is deprecated as of LUA 5.3 . reimplement it: + return 0.5* (mathexp(x) - mathexp(-x)) +end + +local sinh = pgfluamathfunctions.sinh +local cosh = pgfluamathfunctions.cosh +function pgfluamathfunctions.tanh(x) + -- math.tanh is deprecated as of LUA 5.3 . reimplement it: + return sinh(x)/cosh(x) +end + +function pgfluamathfunctions.Cos(x) + return mathcos(trigFormatToRadians(x)) +end +pgfluamathfunctions.cos=pgfluamathfunctions.Cos + +function pgfluamathfunctions.Tan(x) + return mathtan(trigFormatToRadians(x)) +end +pgfluamathfunctions.tan=pgfluamathfunctions.Tan + +function pgfluamathfunctions.aSin(x) + return radiansToTrigFormat(mathasin(x)) +end +pgfluamathfunctions.asin=pgfluamathfunctions.aSin + +function pgfluamathfunctions.aCos(x) + return radiansToTrigFormat(mathacos(x)) +end +pgfluamathfunctions.acos=pgfluamathfunctions.aCos + +function pgfluamathfunctions.aTan(x) + return radiansToTrigFormat(mathatan(x)) +end +pgfluamathfunctions.atan=pgfluamathfunctions.aTan + +local mathatan2 +if math.atan2 == nil then + -- math.atan2 has been deprecated since LUA 5.3 + mathatan2 = function (y,x) return mathatan(y,x) end +else + mathatan2 = math.atan2 +end + +function pgfluamathfunctions.aTan2(y,x) + return radiansToTrigFormat(mathatan2(y,x)) +end +pgfluamathfunctions.atan2=pgfluamathfunctions.aTan2 +pgfluamathfunctions.atantwo=pgfluamathfunctions.aTan2 + +function pgfluamathfunctions.cot(x) + return pgfluamathfunctions.cos(x) / pgfluamathfunctions.sin(x) +end +function pgfluamathfunctions.sec(x) + return 1 / pgfluamathfunctions.cos(x) +end +function pgfluamathfunctions.cosec(x) + return 1 / pgfluamathfunctions.sin(x) +end + +function pgfluamathfunctions.pointnormalised (pgfx, pgfy) + local pgfx_normalised, pgfy_normalised + if pgfx == 0. and pgfy == 0. then + -- Original pgf macro gives this result + tex.dimen['pgf@x'] = "0pt" + tex.dimen['pgf@y'] = "1pt" + else + pgfx_normalised = pgfx/math.sqrt(pgfx^2 + pgfy^2) + pgfx_normalised = pgfx_normalised - pgfx_normalised%0.00001 + pgfy_normalised = pgfy/math.sqrt(pgfx^2 + pgfy^2) + pgfy_normalised = pgfy_normalised - pgfy_normalised%0.00001 + tex.dimen['pgf@x'] = tostring(pgfx_normalised) .. "pt" + tex.dimen['pgf@y'] = tostring(pgfy_normalised) .. "pt" + end + return nil +end + +local isnan = function(x) + return x ~= x +end + +pgfluamathfunctions.isnan = isnan + +local infty = 1/0 +pgfluamathfunctions.infty = infty + +local nan = math.sqrt(-1) +pgfluamathfunctions.nan = nan + +local stringlen = string.len +local globaltonumber = tonumber +local stringsub=string.sub +local stringformat = string.format +local stringsub = string.sub + +-- like tonumber(x), but it also accepts nan, inf, infty, and the TeX FPU format +function pgfluamathfunctions.tonumber(x) + if type(x) == 'number' then return x end + if not x then return x end + + local len = stringlen(x) + local result = globaltonumber(x) + if not result then + if len >2 and stringsub(x,2,2) == 'Y' and stringsub(x,len,len) == ']' then + -- Ah - some TeX FPU input of the form 1Y1.0e3] . OK. transform it + local flag = stringsub(x,1,1) + if flag == '0' then + -- ah, 0.0 + result = 0.0 + elseif flag == '1' then + result = globaltonumber(stringsub(x,3, len-1)) + elseif flag == '2' then + result = globaltonumber("-" .. stringsub(x,3, len-1)) + elseif flag == '3' then + result = nan + elseif flag == '4' then + result = infty + elseif flag == '5' then + result = -infty + end + else + local lower = x:lower() + if lower == 'nan' then + result = nan + elseif lower == "-nan" then + result = nan + elseif lower == 'inf' or lower == 'infty' then + result = infty + elseif lower == '-inf' or lower == '-infty' then + result = -infty + end + end + end + + return result +end + +local stringlen = string.len +local globaltonumber = tonumber +local stringformat = string.format +local stringsub = string.sub +local stringfind = string.find +local stringbyte = string.byte +local NULL_CHAR = string.byte("0",1) + +local function discardTrailingZeros(x) + local result = x + -- printf is too stupid: I would like to have + -- 1. a fast method + -- 2. a reliable method + -- 3. full precision of x + -- 4. a fixed point representation + -- the 'f' modifier has trailing zeros (stupid!) + -- the 'g' modified can switch to scientific notation (no-go!) + local periodOff = stringfind(result, '.',1,true) + if periodOff ~= nil then + -- strip trailing zeros + local chars = { stringbyte(result,1,#result) }; + local lastNonZero = #chars + for i = #chars, periodOff, -1 do + if chars[i] ~= NULL_CHAR then lastNonZero=i; break; end + end + if lastNonZero ~= #chars then + -- Ah: we had at least one trailing zero. + -- discard all but the last. + lastNonZero = mathmax(periodOff+1,lastNonZero) + end + result = stringsub(result, 1, lastNonZero) + end + return result; +end + +local function discardTrailingZerosFromMantissa(x) + local mantissaStart = stringfind(x, "e") + + local mantissa = stringsub(x,1,mantissaStart-1) + local exponent = stringsub(x,mantissaStart) + + return discardTrailingZeros(mantissa) .. exponent +end + + +-- a helper function which has no catcode issues when communicating with TeX: +function pgfluamathfunctions.tostringfixed(x) + if x == nil then + return "" + end + + return discardTrailingZeros(stringformat("%f", x)) +end + +-- converts an input number to a string which is accepted by the TeX FPU +function pgfluamathfunctions.toTeXstring(x) + local result = "" + if x ~= nil then + if x == infty then result = "4Y0.0e0]" + elseif x == -infty then result = "5Y0.0e0]" + elseif isnan(x) then result = "3Y0.0e0]" + elseif x == 0 then result = "0Y0.0e0]" + else + result = discardTrailingZerosFromMantissa(stringformat("%.10e", x)) + if x > 0 then + result = "1Y" .. result .. "]" + else + result = "2Y" .. stringsub(result,2) .. "]" + end + end + end + return result +end + +return pgfluamathfunctions diff --git a/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/parser.lua b/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/parser.lua new file mode 100644 index 0000000000..42b690e6cf --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/luamath/pgf/luamath/parser.lua @@ -0,0 +1,481 @@ +-- Copyright 2011 by Christophe Jorssen and Mark Wibrow +-- Copyright 2014 by Christian Feuersaenger +-- +-- This file may be distributed and/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License. +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more details. +-- +-- $Id$ +-- +-- usage: +-- +-- pgfluamathparser = require("pgf.luamath.parser") +-- +-- local result = pgfluamathparser.pgfmathparse("1+ 2*4^2") +-- +-- This LUA class has a direct backend in \pgfuselibrary{luamath}, see the documentation of that TeX package. + +local pgfluamathparser = pgfluamathparser or {} + +pgfluamathfunctions = require("pgf.luamath.functions") + +-- lpeg is always present in luatex +local lpeg = require("lpeg") + +local S, P, R = lpeg.S, lpeg.P, lpeg.R +local C, Cc, Ct = lpeg.C, lpeg.Cc, lpeg.Ct +local Cf, Cg, Cs = lpeg.Cf, lpeg.Cg, lpeg.Cs +local V = lpeg.V +local match = lpeg.match + +local space_pattern = S(" \n\r\t")^0 +local tex_unit = + P('pt') + P('mm') + P('cm') + P('in') + + -- while valid units, the font-depending ones need special attention... move them to the TeX side. For now. + -- P('ex') + P('em') + + P('bp') + P('pc') + + P('dd') + P('cc') + P('sp'); + +local one_digit_pattern = R("09") +local positive_integer_pattern = one_digit_pattern^1 +-- FIXME : it might be a better idea to remove '-' from all number_patterns! Instead, rely on the prefix operator 'neg' to implement negative numbers. +-- Is that wise? It is certainly less efficient... +local integer_pattern = S("+-")^-1 * positive_integer_pattern +-- Valid positive decimals are |xxx.xxx|, |.xxx| and |xxx.| +local positive_integer_or_decimal_pattern = positive_integer_pattern * ( P(".") * one_digit_pattern^0)^-1 + + (P(".") * one_digit_pattern^1) +local integer_or_decimal_pattern = S("+-")^-1 * positive_integer_or_decimal_pattern +local fpu_pattern = R"05" * P"Y" * positive_integer_or_decimal_pattern * P"e" * S("+-")^-1 * R("09")^1 * P"]" +local unbounded_pattern = P"inf" + P"INF" + P"nan" + P"NaN" + P"Inf" +local number_pattern = C(unbounded_pattern + fpu_pattern + integer_or_decimal_pattern * (S"eE" * integer_pattern + C(tex_unit))^-1) + +local underscore_pattern = P("_") + +local letter_pattern = R("az","AZ") +local alphanum__pattern = letter_pattern + one_digit_pattern + underscore_pattern + +local identifier_pattern = letter_pattern^1 * alphanum__pattern^0 + +local openparen_pattern = P("(") * space_pattern +local closeparen_pattern = P(")") +local opencurlybrace_pattern = P("{") +local closecurlybrace_pattern = P("}") +local openbrace_pattern = P("[") +local closebrace_pattern = P("]") + +-- hm. what about '\\' or '\%' ? +-- accept \pgf@x, \count0, \dimen42, \c@pgf@counta, \wd0, \ht0, \dp 0 +local controlsequence_pattern = P"\\" * C( (R("az","AZ") + P"@")^1) * space_pattern* C( R"09"^0 ) + +-- local string = P('"') * C((1 - P('"'))^0) * P('"') + +local comma_pattern = P(",") * space_pattern + + +---------------- +local TermOp = C(S("+-")) * space_pattern +local EqualityOp = C( P"==" + P"!=" ) * space_pattern +local RelationalOp = C( P"<=" + P">=" + P"<" + P">" ) * space_pattern +local FactorOp = C(S("*/")) * space_pattern + +-- Grammar +local Exp, Term, Factor = V"Exp", V"Term", V"Factor" +local Prefix = V"Prefix" +local Postfix = V"Postfix" + + + +local function eval (v1, op, v2) + if (op == "+") then return v1 + v2 + elseif (op == "-") then return v1 - v2 + elseif (op == "*") then return v1 * v2 + elseif (op == "/") then return v1 / v2 + else + error("This function must not be invoked for operator "..op) + end +end + +local pgfStringToFunctionMap = pgfluamathfunctions.stringToFunctionMap +local function function_eval(name, ... ) + local f = pgfStringToFunctionMap[name] + if not f then + error("Function '" .. name .. "' is undefined (did not find pgfluamathfunctions."..name .." (looked into pgfluamathfunctions.stringToFunctionMap))") + end + -- FIXME: validate signature + return f(...) +end + + +local func = + (C(identifier_pattern) * space_pattern * openparen_pattern * Exp * (comma_pattern * Exp)^0 * closeparen_pattern) / function_eval; + +local functionWithoutArg = identifier_pattern / function_eval + +-- this is what can occur as exponent after '^'. +-- I have the impression that the priorities could be implemented in a better way than this... but it seems to work. +local pow_exponent = + -- allows 2^-4, 2^1e4, 2^2 + -- FIXME : why not 2^1e2 ? + Cg(C(integer_or_decimal_pattern) + -- 2^pi, 2^multiply(2,2) + + Cg(func+functionWithoutArg) + -- 2^(2+2) + + openparen_pattern * Exp * closeparen_pattern ) + +local function prefix_eval(op, x) + if op == "-" then + return pgfluamathfunctions.neg(x) + elseif op == "!" then + return pgfluamathfunctions.notPGF(x) + else + error("This function must not be invoked for operator "..op) + end +end + + +local prefix_operator = C( S"-!" ) +local prefix_operator_pattern = (prefix_operator * space_pattern * Cg(Prefix) ) / prefix_eval + +-- apparently, we need to distinguish between ! and != : +local postfix_operator = C( S"r!" - P"!=" ) + C(P"^") * space_pattern * pow_exponent + +pgfluamathfunctions.functionMustBeEvaluatedInTeX = function() + error("The function in this context cannot be evaluated by LUA because it depends on TeX macros.") +end + +local ternary_eval = pgfluamathfunctions.ifthenelse + +local factorial_eval = pgfluamathfunctions.factorial +local deg = pgfluamathfunctions.deg +local pow_eval = pgfluamathfunctions.pow + +-- @param prefix the argument before the postfix operator. +-- @param op either nil or the postfix operator +-- @param arg either nil or the (mandatory) argument for 'op' +local function postfix_eval(prefix, op, arg) + local result + if op == nil then + result = prefix + elseif op == "r" then + if arg then error("parser setup error: expected nil argument") end + result = deg(prefix) + elseif op == "!" then + if arg then error("parser setup error: expected nil argument") end + result = factorial_eval(prefix) + elseif op == "^" then + if not arg then error("parser setup error: ^ with its argument") end + result = pow_eval(prefix, arg) + else + error("Parser setup error: " .. tostring(op) .. " unexpected in this context") + end + return result +end + +local function equality_eval(v1, op, v2) + local fct + if (op == "==") then fct = pgfluamathfunctions.equal + elseif (op == "!=") then fct = pgfluamathfunctions.notequal + else + error("This function must not be invoked for operator "..op) + end + return fct(v1,v2) +end +local function relational_eval(v1, op, v2) + local fct + if (op == "<") then fct = pgfluamathfunctions.less + elseif (op == ">") then fct = pgfluamathfunctions.greater + elseif (op == ">=") then fct = pgfluamathfunctions.notless + elseif (op == "<=") then fct = pgfluamathfunctions.notgreater + else + error("This function must not be invoked for operator "..op) + end + return fct(v1,v2) +end + +-- @return either the box property or nil +-- @param cs "wd", "ht", or "dp" +-- @param intSuffix some integer +local function get_tex_box(cs, intSuffix) + -- assume get_tex_box is only called when a dimension is required. + local result + pgfluamathparser.units_declared = true + local box =tex.box[tonumber(intSuffix)] + if not box then error("There is no box " .. intSuffix) end + if cs == "wd" then + result = box.width / 65536 + elseif cs == "ht" then + result = box.height / 65536 + elseif cs == "dp" then + result = box.depth / 65536 + else + result = nil + end + return result +end + + +local function controlsequence_eval(cs, intSuffix) + local result + if intSuffix and #intSuffix >0 then + if cs == "count" then + result= pgfluamathparser.get_tex_count(intSuffix) + elseif cs == "dimen" then + result= pgfluamathparser.get_tex_dimen(intSuffix) + else + result = get_tex_box(cs,intSuffix) + if not result then + -- this can happen - we cannot expand \chardef'ed boxes here. + -- this will be done by the TeX part + error('I do not know/support the TeX register "\\' .. cs .. '"') + end + end + else + result = pgfluamathparser.get_tex_register(cs) + end + return result +end + +pgfluamathparser.units_declared = false +function pgfluamathparser.get_tex_register(register) + -- register is a string which could be a count or a dimen. + if pcall(tex.getcount, register) then + return tex.count[register] + elseif pcall(tex.getdimen, register) then + pgfluamathparser.units_declared = true + return tex.dimen[register] / 65536 -- return in points. + else + error('I do not know the TeX register "' .. register .. '"') + return nil + end +end + +function pgfluamathparser.get_tex_count(count) + -- count is expected to be a number + return tex.count[tonumber(count)] +end + +function pgfluamathparser.get_tex_dimen(dimen) + -- dimen is expected to be a number + pgfluamathparser.units_declared = true + return tex.dimen[tonumber(dimen)] / 65536 +end + +function pgfluamathparser.get_tex_sp(dimension) + -- dimension should be a string + pgfluamathparser.units_declared = true + return tex.sp(dimension) / 65536 +end + + +local initialRule = V"initial" + +local Summand = V"Summand" +local Relational = V"Relational" +local Equality = V"Equality" +local LogicalOr = V"LogicalOr" +local LogicalAnd = V"LogicalAnd" + +local pgftonumber = pgfluamathfunctions.tonumber +local tonumber_withunit = pgfluamathparser.get_tex_sp +local function number_optional_units_eval(x, unit) + if not unit then + return pgftonumber(x) + else + return tonumber_withunit(x) + end +end + +-- @param scale the number. +-- @param controlsequence either nil in which case just the number must be returned or a control sequence +-- @see controlsequence_eval +local function scaled_controlsequence_eval(scale, controlsequence, intSuffix) + if controlsequence==nil then + return scale + else + return scale * controlsequence_eval(controlsequence, intSuffix) + end +end + +-- Grammar +-- +-- for me: +-- - use '/' to evaluate all expressions which contain a _constant_ number of captures. +-- - use Cf to evaluate expressions which contain a _dynamic_ number of captures +-- +-- see unittest_luamathparser.tex for tons of examples +local G = P{ "initialRule", + initialRule = space_pattern* Exp * -1; + -- ternary operator (or chained ternary operators): + -- FIXME : is this chaining a good idea!? + Exp = Cf( LogicalOr * Cg(P"?" * space_pattern * LogicalOr * P":" *space_pattern * LogicalOr )^0, ternary_eval) ; + LogicalOr = Cf(LogicalAnd * (P"||" * space_pattern * LogicalAnd)^0, pgfluamathfunctions.orPGF); + LogicalAnd = Cf(Equality * (P"&&" * space_pattern * Equality)^0, pgfluamathfunctions.andPGF); + Equality = Cf(Relational * Cg(EqualityOp * Relational)^0, equality_eval); + Relational = Cf(Summand * Cg(RelationalOp * Summand)^0, relational_eval); + Summand = Cf(Term * Cg(TermOp * Term)^0, eval) ; + Term = Cf(Prefix * Cg(FactorOp * Prefix)^0, eval); + Prefix = prefix_operator_pattern + Postfix; + -- this calls 'postfix_eval' with nil arguments if it is no postfix operation.. but that does not hurt (right?) + Postfix = Factor * (postfix_operator * space_pattern)^-1 / postfix_eval; + Factor = + ( + number_pattern / number_optional_units_eval * + -- this construction will evaluate number_pattern with 'number_optional_units_eval' FIRST. + -- also accept '0.5 \pgf@x' here: + space_pattern *controlsequence_pattern^-1 / scaled_controlsequence_eval + + func + + functionWithoutArg + + openparen_pattern * Exp * closeparen_pattern + + controlsequence_pattern / controlsequence_eval + ) *space_pattern + ; +} + +-- does not reset units_declared. +local function pgfmathparseinternal(str) + local result = match(G,str) + if result == nil then + error("The string '" .. str .. "' is no valid PGF math expression. Please check for syntax errors.") + end + return result +end + + +-- This is the math parser function in this module. +-- +-- @param str a string like "1+1" which is accepted by the PGF math language +-- @return the result of the expression. +-- +-- Throws an error if the string is no valid expression. +function pgfluamathparser.pgfmathparse(str) + pgfluamathparser.units_declared = false + + return pgfmathparseinternal(str) +end + +local pgfmathparse = pgfluamathparser.pgfmathparse +local tostringfixed = pgfluamathfunctions.tostringfixed +local tostringfpu = pgfluamathfunctions.toTeXstring + +local tmpFunctionArgumentPrefix = "tmpVar" +local stackOfLocalFunctions = {} + +-- This is a backend for PGF's 'declare function'. +-- \tikzset{declare function={mu(\x,\i)=\x^\i;}} +-- will boil down to +-- pgfluamathparser.declareExpressionFunction("mu", 2, "#1^#2") +-- +-- The local function will be pushed on a stack of known local functions and is +-- available until popLocalExpressionFunction() is called. TeX will call this using +-- \aftergroup. +-- +-- @param name the name of the new function +-- @param numArgs the number of arguments +-- @param expression an expression containing #1, ... #n where n is numArgs +-- +-- ATTENTION: local functions behave DIFFERENTLY in LUA! +-- In LUA, local variables are not expanded whereas TeX expands them. +-- The difference is +-- +-- declare function={mu1(\x,\i)=\x^\i;} +-- \pgfmathparse{mu1(-5,2)} --> -25 +-- \pgfluamathparse{mu1(-5,2)} --> 25 +-- +-- x = -5 +-- \pgfmathparse{mu1(x,2)} --> 25 +-- \pgfluamathparse{mu1(x,2)} --> 25 +-- +-- In an early prototype, I simulated TeX's expansion to fix the first case (successfully). +-- BUT: that "simulated expansion" broke the second case because LUA will evaluate "x" and hand -5 to the local function. +-- I decided to keep it as is. Perhaps we should fix PGF's expansion approach in TeX (which is ugly anyway) +function pgfluamathparser.pushLocalExpressionFunction(name, numArgs, expression) + -- now we have "tmpVar1^tmpVar2" instead of "#1^#2" + local normalizedExpr = expression:gsub("#", tmpFunctionArgumentPrefix) + local restores = {} + local tmpVars = {} + for i=1,numArgs do + local tmpVar = tmpFunctionArgumentPrefix .. tostring(i) + tmpVars[i] = tmpVar + end + + local newFunction = function(...) + local args = table.pack(...) + + -- define "tmpVar1" ... "tmpVarN" to return args[i]. + -- Of course, we need to restore "tmpVar" after we return! + for i=1,numArgs do + local tmpVar = tmpVars[i] + local value = args[i] + restores[i] = pgfStringToFunctionMap[tmpVar] + pgfStringToFunctionMap[tmpVar] = function () return value end + end + + -- parse our expression. + + -- FIXME : this here is an attempt to mess around with "units_declared". + -- It would be better to call pgfmathparse and introduce some + -- semaphore to check if pgfmathparse is a nested call-- in this case, it should + -- not reset units_declared. But there is no "finally" block and pcall is crap (looses stack trace). + local success,result = pcall(pgfmathparseinternal, normalizedExpr) + + -- remove 'tmpVar1', ... from the function table: + for i=1,numArgs do + local tmpVar = tmpVars[i] + pgfStringToFunctionMap[tmpVar] = restores[i] + end + + if success==false then error(result) end + return result + end + table.insert(stackOfLocalFunctions, name) + pgfStringToFunctionMap[name] = newFunction +end + +function pgfluamathparser.popLocalExpressionFunction() + local name = stackOfLocalFunctions[#stackOfLocalFunctions] + pgfStringToFunctionMap[name] = nil + -- this removes the last element: + table.remove(stackOfLocalFunctions) +end + + +-- A Utility function which simplifies the interaction with the TeX code +-- @param expression the input expression (string) +-- @param outputFormatChoice 0 if the result should be a fixed point number, 1 if it should be in FPU format +-- @param showErrorMessage (boolean) true if any error should be displayed, false if errors should simply result in an invocation of TeX's parser (the default) +-- +-- it defines \pgfmathresult and \ifpgfmathunitsdeclared +function pgfluamathparser.texCallParser(expression, outputFormatChoice, showErrorMessage) + local success, result + if showErrorMessage then + result = pgfmathparse(expression) + success = true + else + success, result = pcall(pgfmathparse, expression) + end + + if success and result then + local result_str + if outputFormatChoice == 0 then + -- luamath/output format=fixed + result_str = tostringfixed(result) + else + -- luamath/output format=fixed + result_str = tostringfpu(result) + end + tex.sprint("\\def\\pgfmathresult{" .. result_str .. "}") + if pgfluamathparser.units_declared then + tex.sprint("\\pgfmathunitsdeclaredtrue") + else + tex.sprint("\\pgfmathunitsdeclaredfalse") + end + else + tex.sprint("\\def\\pgfmathresult{}") + tex.sprint("\\pgfmathunitsdeclaredfalse") + end +end + +return pgfluamathparser diff --git a/graphics/pgf/base/tex/generic/libraries/luamath/pgflibraryluamath.code.tex b/graphics/pgf/base/tex/generic/libraries/luamath/pgflibraryluamath.code.tex new file mode 100644 index 0000000000..cd991dab4c --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/luamath/pgflibraryluamath.code.tex @@ -0,0 +1,558 @@ +% Copyright 2019 by Christophe Jorssen and Mark Wibrow +% Copyright 2019 by Christian Feuersänger +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. +% +% $Id$ +% +% +% This is a library for a LUA math parser and LUA math operations. +% Advantage compared to its TeX pendant: it is FASTER and has HIGHER +% ACCURACY. +% Disadvantage: any function declared by means of +% \pgfmathdeclarefunction is NOT automatically transported to the LUA +% side (at the time of this writing). +% LUA functions need to be defined by means of LUA code +% +% function pgfluamathfunctions.myoperation(a,b) +% return a*2*b +% end +% +% this will automatically set up 'myoperation' for use in +% \pgfluamathparse{myoperation(4,2)} +% +% The library has TWO use-cases which are more or less distinct: one +% is to use LUA for all math function, but not for math expression +% parsing -- this was still under control of the TeX math parser. +% This approach works like the 'fpu' library. +% +% The second approach is to use LUA to parse all math expressions - +% but if someone calls \pgfmathadd@{1}{2}, it would use the TeX +% command. This approach is relatively lightweight because it does not +% need to substitute all \pgfmath* macros. +% +% One can mix both modes. + +% ******************************************************************* +% Some luatex stuff. Should be put elsewhere (e.g. in +% pgfutil-luatex-engine). + +\edef\pgfliblua@oldcatcodedoublequote{\the\catcode`\"}% +\catcode`\"=12 + +% We assume luatex version > 0.39: +% - \directlua will work +% - \directlua is the only luatex primitive that we can assume +% accessible without being prefixed by the format via +% tex.enableprimitives. +% Ideas taken from the ifluatex package (Heiko Oberdiek) +\let\pgfutil@ifluatex\iffalse +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname directlua\endcsname\relax +\else + \expandafter\let\csname pgfutil@ifluatex\expandafter\endcsname + \csname iftrue\endcsname +\fi + +\pgfutil@ifluatex + \let\pgfutil@directlua\directlua + \pgfutil@directlua{% + tex.enableprimitives('pgfutil@',{'luaescapestring'})}% +\else + \def\pgfutil@directlua#1{}% + \def\pgfutil@luaescapestring#1{}% +\fi + +\pgfutil@directlua{% + pgfluamathfunctions = require("pgf.luamath.functions") + pgfluamathparser = require("pgf.luamath.parser")}% + + +% Patch some configuration macros such that the modifications are +% available in LUA as well: +\pgfkeys{ + /pgf/trig format/deg/.add code={}{\directlua{pgfluamathfunctions.setTrigFormat("deg")}\aftergroup\pgfmath@settrigformat}, + /pgf/trig format/rad/.add code={}{\directlua{pgfluamathfunctions.setTrigFormat("rad")}\aftergroup\pgfmath@settrigformat}, +}% +% ... and reactivate the key: +\pgfmathiftrigonometricusesdeg{% + \pgfkeys{/pgf/trig format/deg}% +}{% + \pgfkeys{/pgf/trig format/rad}% +}% + +% re-activates the current trig format. This is important after a TeX +% group has been closed. +\def\pgfmath@settrigformat{% + \pgfmathiftrigonometricusesdeg{% + \directlua{pgfluamathfunctions.setTrigFormat("deg")}% + }{% + \directlua{pgfluamathfunctions.setTrigFormat("rad")}% + }% +}% + +\let\pgfmathsetseed@pgfbasic = \pgfmathsetseed +\def\pgfmathsetseed#1{% + \pgfmathsetseed@pgfbasic{#1}% + \directlua{pgfluamathfunctions.setRandomSeed(pgfluamathfunctions.tonumber("\pgfmathresult"))}% +}% + +% Patch 'declare function' such that it communicates the function +% directly to LUA. +\let\pgfmathnotifynewdeclarefunction@orig=\pgfmathnotifynewdeclarefunction +\def\pgfmathnotifynewdeclarefunction#1#2#3{% + \pgfmathnotifynewdeclarefunction@orig{#1}{#2}{#3}% + % + % we have to check if '#3' contains control sequences. + % this is highly tricky as it may contain '#1'... + \begingroup + \toks0={#3}% + \xdef\pgf@marshal@glob{\the\toks0 }% + \endgroup + \pgfutil@command@to@string\pgf@marshal@glob\pgf@marshal + \expandafter\pgfutilifcontainsmacro\expandafter{\pgf@marshal}{% + \def\pgf@temp{1}% + }{% + \def\pgf@temp{0}% + }% + \if1\pgf@temp + % let lua produce an error when evaluating this function -- we cannot possibly expand the macro to its current state: + \directlua{pgfluamathparser.pushLocalExpressionFunction(% + "\pgfutil@luaescapestring{#1}",% + #2,% + "functionMustBeEvaluatedInTeX")}% + \else + \directlua{pgfluamathparser.pushLocalExpressionFunction(% + "\pgfutil@luaescapestring{#1}",% + #2,% + "\pgfutil@luaescapestring{#3}")}% + \fi + % + % ensure that the local function is removed at the end of the + % scope. To this end, we maintain a stack on the LUA side. + \aftergroup\pgfluamathparse@pop@local@function +}% + +\def\pgfluamathparse@pop@local@function{% + \directlua{pgfluamathparser.popLocalExpressionFunction()}% +}% + +% End of luatex stuff +% ******************************************************************* + +% Loading part: based on fpu library + + +% if LUA failed to evaluate the expression, it will be evaluated in +% TeX as fallback. This boolean defines if the error message shall be +% shown or suppressed. The default is to suppress it and show any +% resulting TeX errors. +% +% If LUA fails \pgfmathresult will be empty. +% +% This is actually only for debugging; it will be set implicitly when +% activating/deactivating TeX fallback. +\newif\ifpgfluamathshowerrormessage + +% Defines what happens if LUA failed to evaluate the expression: if +% this is true, the TeX parser will be invoked as fallback. +% +% This happens +% - for \chardef'ed boxes for which LUA lacks evaluation capabilities +% - if the expression includes some function which is unavailable in +% LUA (defined only in TeX) +% - some special cases which simply haven't been added to the LUA +% parser (yet). +% At the time of this writing, this includes +% -- arrays created via '{}' and indexed with '[]' +% -- strings with "" +% -- 'scalar' function +% -- hex/octal/binary input +\newif\ifpgfluamathenableTeXfallback + +\newif\ifpgfluamathcomputationactive +\newif\ifpgfluamathparseractive + +\def\pgfluamath@makecomputationactive{% + \ifpgfluamathcomputationactive + \else + \pgfluamath@checkuninstallcmd% + \pgfluamath@install% + \pgfluamathcomputationactivetrue + \fi}% + +\def\pgfluamath@makecomputationinactive{% + \ifpgfluamathcomputationactive + \pgfluamath@uninstall% + \pgfluamathcomputationactivefalse + \fi}% + +\let\pgfluamath@pgfmathparse\pgfmathparse +\def\pgfluamath@makeparseractive{% + \ifpgfluamathparseractive + \else + \let\pgfluamath@pgfmathparse\pgfmathparse + \let\pgfmathparse\pgfluamathparse + \let\pgfmath@iftrue=\pgfmathluamath@iftrue + \pgfluamathparseractivetrue + \fi}% + +\let\pgfmath@iftrue@basic=\pgfmath@iftrue + +\def\pgfluamath@makeparserinactive{% + \ifpgfluamathparseractive + \let\pgfmathparse\pgfluamath@pgfmathparse + \let\pgfmath@iftrue=\pgfmath@iftrue@basic + \pgfluamathparseractivefalse + \fi}% + +\pgfqkeys{/pgf}{% + % Enable lua-side computation of \pgfmathresult + % (will be deactivated after the current TeX group) + luamath/.is choice, + luamath/only computation/.code={% + \pgfutil@ifluatex + \pgfluamath@makecomputationactive + \pgfluamath@makeparserinactive + \else + \pgfmath@error{Sorry, you need the luaTeX engine to use the + luamath library}{}% + \fi}, + luamath/parser and computation/.code={% + \pgfutil@ifluatex + \pgfluamath@makecomputationactive + \pgfluamath@makeparseractive + \else + \pgfmath@error{Sorry, you need the luaTeX engine to use the + luamath library}{}% + \fi}, + luamath/off/.code={% + \pgfluamath@makecomputationinactive + \pgfluamath@makeparserinactive}, + luamath/.default=only computation, + % + % activates ONLY the parser. This is fast and does not replace the + % \pgfmath* functions. + % @see |parser and computation| which also allows to write + % \pgfmathadd{1}{2} to call LUA + luamath/parser/.code={% + \pgfutil@ifluatex + \pgfluamath@makeparseractive + \else + \pgfmath@error{Sorry, you need the luaTeX engine to use the + luamath library}{}% + \fi + }, + luamath/output format/.is choice, + luamath/output format/fixed/.code= {\def\pgfluamath@outputformat@choice{0}}, + % returns results for use in the FPU + luamath/output format/float/.code= {\def\pgfluamath@outputformat@choice{1}}, + luamath/output format/fixed, + % this is merely useful for debugging purposes, I guess. + luamath/show error message/.is if=pgfluamathshowerrormessage, + luamath/enable TeX fallback/.is choice, + luamath/enable TeX fallback/true/.code={\pgfluamathenableTeXfallbacktrue\pgfluamathshowerrormessagefalse}, + luamath/enable TeX fallback/false/.code={\pgfluamathenableTeXfallbackfalse\pgfluamathshowerrormessagetrue}, + luamath/enable TeX fallback/.default=true, + luamath/enable TeX fallback=true, +}% + +\def\pgfluamath@uninstall@appendcmd#1{% + \expandafter\gdef\expandafter\pgfluamath@uninstall\expandafter{% + \pgfluamath@uninstall #1}}% + +% If the uninstall command is already assembled, it will skip the +% uninstall assemblation. +\def\pgfluamath@checkuninstallcmd{% + \pgfutil@ifundefined{pgfluamath@uninstall}{% + \global\let\pgfluamath@uninstall=\pgfutil@empty + }{% + % We already HAVE an uninstall command (prepared globally). + % So: don't waste time assembling one! + \def\pgfluamath@uninstall@appendcmd##1{}% + \def\pgfluamath@prepareuninstallcmd##1{}% + }% +}% + +% This assembles an uninstall command globally ON FIRST USAGE. +% See \pgfmathfloat@plots@checkuninstallcmd +\def\pgfluamath@prepareuninstallcmd#1{% + \expandafter\global\expandafter\let + \csname pgfluamath@backup@\string#1\endcsname=#1% + \expandafter\gdef\expandafter\pgfluamath@uninstall\expandafter{% + \pgfluamath@uninstall + \expandafter\let\expandafter#1\csname pgfluamath@backup@\string#1\endcsname}% +}% + +\def\pgfluamath@install@function#1=#2{% + \pgfluamath@prepareuninstallcmd{#1}% + \let#1=#2% +}% + +\def\pgfluamath@install{% + \pgfluamath@install@function\pgfmathadd@=\pgfluamathadd@% + \pgfluamath@install@function\pgfmathsubtract@=\pgfluamathsubtract@% + \pgfluamath@install@function\pgfmathneg@=\pgfluamathneg@% + \pgfluamath@install@function\pgfmathmultiply@=\pgfluamathmultiply@% + \pgfluamath@install@function\pgfmath@iftrue=\pgfmathluamath@iftrue% + \pgfluamath@install@function\pgfmathdivide@=\pgfluamathdivide@% + % \pgfluamath@install@function\pgfmathdiv@=\pgfluamathdiv@% + \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@% + \pgfluamath@install@function\pgfmathsqrt@=\pgfluamathsqrt@% + % \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@% + \pgfluamath@install@function\pgfmathe@=\pgfluamathe@% + \pgfluamath@install@function\pgfmathexp@=\pgfluamathexp@% + \pgfluamath@install@function\pgfmathln@=\pgfluamathln@% + \pgfluamath@install@function\pgfmathlogten@=\pgfluamathlogten@% + % \pgfluamath@install@function\pgfmathlogtwo@=\pgfluamathlogtwo@% + \pgfluamath@install@function\pgfmathabs@=\pgfluamathabs@% + \pgfluamath@install@function\pgfmathmod@=\pgfluamathmod@% + \pgfluamath@install@function\pgfmathMod@=\pgfluamathMod@% + \pgfluamath@install@function\pgfmathround@=\pgfluamathround@% + \pgfluamath@install@function\pgfmathfloor@=\pgfluamathfloor@% + \pgfluamath@install@function\pgfmathceil@=\pgfluamathceil@% + % \pgfluamath@install@function\pgfmathint@=\pgfluamathint@% + % \pgfluamath@install@function\pgfmathfrac@=\pgfluamathfrac@% + % \pgfluamath@install@function\pgfmathreal@=\pgfluamathreal@% + \pgfluamath@install@function\pgfmathgcd@=\pgfluamathgcd@% + \pgfluamath@install@function\pgfmathisprime@=\pgfluamathisprime@% + \pgfluamath@install@function\pgfmathpi@=\pgfluamathpi@% + \pgfluamath@install@function\pgfmathrad@=\pgfluamathrad@% + \pgfluamath@install@function\pgfmathdeg@=\pgfluamathdeg@% + \pgfluamath@install@function\pgfmathsin@=\pgfluamathsin@% + \pgfluamath@install@function\pgfmathcos@=\pgfluamathcos@% + \pgfluamath@install@function\pgfmathtan@=\pgfluamathtan@% + \pgfluamath@install@function\pgfmathsec@=\pgfluamathsec@% + \pgfluamath@install@function\pgfmathcosec@=\pgfluamathcosec@% + \pgfluamath@install@function\pgfmathcot@=\pgfluamathcot@% + \pgfluamath@install@function\pgfmathasin@=\pgfluamathasin@% + \pgfluamath@install@function\pgfmathacos@=\pgfluamathacos@% + \pgfluamath@install@function\pgfmathatan@=\pgfluamathatan@% + \pgfluamath@install@function\pgfmathatantwo@=\pgfluamathatantwo@% + \pgfluamath@install@function\pgfmathmax@=\pgfluamathmax@% + \pgfluamath@install@function\pgfmathmin@=\pgfluamathmin@% + % \pgfluamath@install@function\pgfmath@pi=\pgfluamathpi@% + % \pgfluamath@install@function\pgfmathpi=\pgfluamathpi@% + % \pgfluamath@install@function\pgfmathe@=\pgfluamathe@% + % \pgfluamath@install@function\pgfmathe=\pgfluamathe@% + % \pgfluamath@install@function\pgfmathlessthan@=\pgfluamathlessthan@% + % \pgfluamath@install@function\pgfmathless@=\pgfluamathlessthan@% + % \pgfluamath@install@function\pgfmathgreaterthan@=\pgfluamathgreaterthan@% + % \pgfluamath@install@function\pgfmathgreater@=\pgfluamathgreaterthan@% + % \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@ + \pgfluamath@install@function\pgfmathrand@=\pgfluamathrand@ + \pgfluamath@install@function\pgfmathrand=\pgfluamathrand@ + \pgfluamath@install@function\pgfmathrnd@=\pgfluamathrnd@ + \pgfluamath@install@function\pgfmathrnd=\pgfluamathrnd@ + % \pgfluamath@install@function\pgfmathtrue@=\pgfluamathtrue@ + % \pgfluamath@install@function\pgfmathfalse@=\pgfluamathfalse@ + % \pgfluamath@install@function\pgfmathnot@=\pgfluamathnot@ + % \pgfluamath@install@function\pgfmathhex@=\pgfluamathhex@ + % \pgfluamath@install@function\pgfmathHex@=\pgfluamathHex@ + % \pgfluamath@install@function\pgfmathoct@=\pgfluamathoct@ + % \pgfluamath@install@function\pgfmathbin@=\pgfluamathbin@ + % \pgfluamath@install@function\pgfmathand@=\pgfluamathand@ + % \pgfluamath@install@function\pgfmathor@=\pgfluamathor@ + % \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@ + % \pgfluamath@install@function\pgfmathveclen@=\pgfluamathveclen@ + % \pgfluamath@install@function\pgfmathcosh@=\pgfluamathcosh@ + % \pgfluamath@install@function\pgfmathsinh@=\pgfluamathsinh@ + % \pgfluamath@install@function\pgfmathtanh@=\pgfluamathtanh@ + % \pgfluamath@install@function@unimplemented{ceil}% + % \pgfluamath@install@function@unimplemented{frac}% + % \pgfluamath@install@function@unimplemented{log2}% + % \pgfluamath@install@function@unimplemented{log10}% + % \pgfluamath@install@function@unimplemented{equalto}% + % \pgfluamath@install@function@unimplemented{random}% + % \pgfluamath@install@function@unimplemented{setseed}% + % \pgfluamath@install@function@unimplemented{Mod}% + % \pgfluamath@install@function@unimplemented{real}% + % \pgfluamath@install@function@unimplemented{notequal}% + \pgfluamath@install@function\pgfmathreciprocal=\pgfluamathreciprocal% + \pgfluamath@install@function\pgfpointnormalised=\pgfluamathpointnormalised +}% + +\def\pgfluamathgetresult#1{% + \edef\pgfmathresult{\pgfutil@directlua{tex.print(-1,#1)}}}% + +\def\pgfmathluamath@iftrue{% + \if 0\pgfluamath@outputformat@choice + \let\pgfmathluamath@@iftrue@v=\pgfluamathone + \else + \let\pgfmathluamath@@iftrue@v=\pgfluamathfloatone + \fi + \pgfmathluamath@iftrue@ +}% +\def\pgfluamathone{1.0}% +\def\pgfluamathfloatone{1Y1.0e+00]}% +\def\pgfmathluamath@iftrue@#1#2{% + \ifx\pgfmathresult\pgfmathluamath@@iftrue@v + \def\pgfmath@next{#1}% + \else + \def\pgfmath@next{#2}% + \fi + \pgfmath@next +}% + +\def\pgfluamathpi@{% + \pgfluamathgetresult{pgfluamathfunctions.pi()}}% +\def\pgfluamathe@{% + \pgfluamathgetresult{pgfluamathfunctions.e()}}% +\def\pgfluamathadd@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.add(#1,#2)}}% +\def\pgfluamathsubtract@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.subtract(#1,#2)}}% +\def\pgfluamathneg@#1{% + \pgfluamathgetresult{pgfluamathfunctions.neg(#1)}}% +\def\pgfluamathmultiply@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.multiply(#1,#2)}}% +\def\pgfluamathdivide@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.divide(#1,#2)}}% +\def\pgfluamathabs@#1{% + \pgfluamathgetresult{pgfluamathfunctions.abs(#1)}}% +\def\pgfluamathround@#1{% + \pgfluamathgetresult{pgfluamathfunctions.round(#1)}}% +\def\pgfluamathfloor@#1{% + \pgfluamathgetresult{pgfluamathfunctions.floor(#1)}}% +\def\pgfluamathceil@#1{% + \pgfluamathgetresult{pgfluamathfunctions.ceil(#1)}}% +\def\pgfluamathgcd@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.gcd(#1,#2)}}% +\def\pgfluamathisprime@#1{% + \pgfluamathgetresult{pgfluamathfunctions.isprime(#1)}}% +\def\pgfluamathmax@#1{% + \pgfluamathgetresult{% + math.max(pgfluamathfunctions.split_braces_to_explist("#1"))}}% +\def\pgfluamathmin@#1{% + \pgfluamathgetresult{% + math.min(pgfluamathfunctions.split_braces_to_explist("#1"))}}% +\def\pgfluamathsin@#1{% + \pgfluamathgetresult{pgfluamathfunctions.Sin(#1)}}% +\def\pgfluamathcos@#1{% + \pgfluamathgetresult{pgfluamathfunctions.Cos(#1)}}% +\def\pgfluamathtan@#1{% + \pgfluamathgetresult{pgfluamathfunctions.Tan(#1)}}% +\def\pgfluamathmod@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.mod(#1,#2)}}% +\def\pgfluamathMod@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.Mod(#1,#2)}}% +\def\pgfluamathrad@#1{% + \pgfluamathgetresult{pgfluamathfunctions.rad(#1)}}% +\def\pgfluamathdeg@#1{% + \pgfluamathgetresult{pgfluamathfunctions.deg(#1)}}% +\def\pgfluamathatan@#1{% + \pgfluamathgetresult{pgfluamathfunctions.aTan(#1)}}% +\def\pgfluamathatantwo@#1#2{% + \pgfluamathgetresult{pgfluamathfunctions.aTan2(#1,#2)}}% +\def\pgfluamathasin@#1{% + \pgfluamathgetresult{pgfluamathfunctions.aSin(#1)}}% +\def\pgfluamathacos@#1{% + \pgfluamathgetresult{pgfluamathfunctions.aCos(#1)}}% +\def\pgfluamathcot@#1{% + \pgfluamathgetresult{1/pgfluamathfunctions.Tan(#1)}}% +\def\pgfluamathsec@#1{% + \pgfluamathgetresult{1/pgfluamathfunctions.Cos(#1)}}% +\def\pgfluamathcosec@#1{% + \pgfluamathgetresult{1/pgfluamathfunctions.Sin(#1)}}% +\def\pgfluamathexp@#1{% + \pgfluamathgetresult{pgfluamathfunctions.exp(#1)}}% +\def\pgfluamathln@#1{% + \pgfluamathgetresult{pgfluamathfunctions.log(#1)}}% +\def\pgfluamathlogten@#1{% + \pgfluamathgetresult{pgfluamathfunctions.log10(#1)}}% +\def\pgfluamathsqrt@#1{% + \pgfluamathgetresult{pgfluamathfunctions.sqrt(#1)}}% +\def\pgfluamathrnd@{% + \pgfluamathgetresult{pgfluamathfunctions.rnd()}}% +\def\pgfluamathrand@{% + \pgfluamathgetresult{pgfluamathfunctions.rand(-1,1)}}% +\def\pgfluamathfactorial@#1{% + \pgfluamathgetresult{pgfluamathfunctions.factorial(#1)}}% +\def\pgfluamathreciprocal#1{% + \pgfluamathgetresult{1/#1}}% +% \pgfluamath@install@function\pgfmath@pi=\pgfluamathpi@% +% \pgfluamath@install@function\pgfmathpi=\pgfluamathpi@% +% \pgfluamath@install@function\pgfmathe@=\pgfluamathe@% +% \pgfluamath@install@function\pgfmathe=\pgfluamathe@% +% \pgfluamath@install@function\pgfmathlessthan@=\pgfluamathlessthan@% +% \pgfluamath@install@function\pgfmathless@=\pgfluamathlessthan@% +% \pgfluamath@install@function\pgfmathgreaterthan@=\pgfluamathgreaterthan@% +% \pgfluamath@install@function\pgfmathgreater@=\pgfluamathgreaterthan@% +% \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@ +% \pgfluamath@install@function\pgfmathrand@=\pgfluamathrand@ +% \pgfluamath@install@function\pgfmathrand=\pgfluamathrand@ +% \pgfluamath@install@function\pgfmathrnd@=\pgfluamathrnd@ +% \pgfluamath@install@function\pgfmathrnd=\pgfluamathrnd@ +% \pgfluamath@install@function\pgfmathtrue@=\pgfluamathtrue@ +% \pgfluamath@install@function\pgfmathfalse@=\pgfluamathfalse@ +% \pgfluamath@install@function\pgfmathnot@=\pgfluamathnot@ +% \pgfluamath@install@function\pgfmathhex@=\pgfluamathhex@ +% \pgfluamath@install@function\pgfmathHex@=\pgfluamathHex@ +% \pgfluamath@install@function\pgfmathoct@=\pgfluamathoct@ +% \pgfluamath@install@function\pgfmathbin@=\pgfluamathbin@ +% \pgfluamath@install@function\pgfmathand@=\pgfluamathand@ +% \pgfluamath@install@function\pgfmathor@=\pgfluamathor@ +% \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@ +% \pgfluamath@install@function\pgfmathveclen@=\pgfluamathveclen@ +% \pgfluamath@install@function\pgfmathcosh@=\pgfluamathcosh@ +% \pgfluamath@install@function\pgfmathsinh@=\pgfluamathsinh@ +% \pgfluamath@install@function\pgfmathtanh@=\pgfluamathtanh@ + +\def\pgfluamathpointnormalised#1{% + \pgf@process{#1}% + \pgfutil@directlua{% + pgfluamathfunctions.pointnormalised(% + \pgf@sys@tonumber{\pgf@x},\pgf@sys@tonumber{\pgf@y})}% + \ignorespaces}% + +% Parser + +\newif\ifpgfluamathunitsdeclared + +% true if and only if LUA failed to evaluate the expression and the +% expression was evaluated by means of the TeX parser as fallback. +% +% This happens +% - for \chardef'ed boxes for which LUA lacks evaluation capabilities +% - if the expression includes some function which is unavailable in +% LUA (defined only in TeX) +% - some special cases which simply haven't been added to the LUA +% parser (yet). +% At the time of this writing, this includes +% -- arrays created via '{}' and indexed with '[]' +% -- strings with "" +% -- 'scalar' function +% -- hex/octal/binary input +\newif\ifpgfluamathusedTeXfallback + +% Parses the math expression and defines \pgfmathresult and +% \ifpgfmathunitsdeclared to contain the result. +% +% If \ifpgfluamathparseractive then the result is also assigned to +% \pgfmathresult. Furthermore, if the expression cannot be evaluated (because LUA does not support +% it), it will be evaluated by mean of TeX as fallback. +% +% @see \ifpgfluamathusedTeXfallback +% @see \ifpgfluamathshowerrormessage +\def\pgfluamathparse#1{% + \pgfluamathusedTeXfallbackfalse + \pgfutil@directlua{pgfluamathparser.texCallParser( + "\pgfutil@luaescapestring{#1}", + \pgfluamath@outputformat@choice, + \ifpgfluamathshowerrormessage true\else false\fi)% + }% + \ifx\pgfmathresult\pgfutil@empty + \ifpgfluamathenableTeXfallback + \pgfluamathusedTeXfallbacktrue + \pgfluamath@pgfmathparse{#1}% + \fi + \fi +}% + +\catcode`\"=\pgfliblua@oldcatcodedoublequote +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.code.tex new file mode 100644 index 0000000000..96216c5f24 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.code.tex @@ -0,0 +1,936 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryarrows.code.tex} + + +% A square bracket shaped arrow + +\pgfarrowsdeclare{square bracket}{square bracket} +{ + \pgfutil@tempdima=1pt% + \advance\pgfutil@tempdima by1.25\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdima} + \pgfarrowsrightextend{+.5\pgflinewidth} +} +{ + \pgfutil@tempdima=2pt% + \advance\pgfutil@tempdima by1.5\pgflinewidth% + \pgfutil@tempdimb=\pgfutil@tempdima% + \advance\pgfutil@tempdimb by\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfsetbuttcap + \pgfpathmoveto{\pgfqpoint{-.5\pgfutil@tempdimb}{-1\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0pt}{-1\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0pt}{\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-.5\pgfutil@tempdimb}{\pgfutil@tempdima}} + \pgfusepathqstroke +}% +\pgfdeclarearrow{name=[-], means=square bracket}% + +\pgfarrowsdeclarereversed{]}{[}{[}{]}% + + +% A round bracket shaped arrow + +\pgfarrowsdeclare{(}{)} +{ + \pgfutil@tempdima=2pt% + \advance\pgfutil@tempdima by1.5\pgflinewidth% + \pgfutil@tempdimb=0.0625\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} + \pgfutil@tempdimb=0.5\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=2pt% + \advance\pgfutil@tempdima by1.5\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfpathmoveto{\pgfqpoint{-.5\pgfutil@tempdima}{-1\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{.25\pgfutil@tempdima}{-.5\pgfutil@tempdima}} + {\pgfqpoint{.25\pgfutil@tempdima}{.5\pgfutil@tempdima}} + {\pgfqpoint{-.5\pgfutil@tempdima}{\pgfutil@tempdima}} + \pgfusepathqstroke +}% + +\pgfarrowsdeclarereversed{)}{(}{(}{)}% + + + + +% A pointed bracket shaped arrow + +\pgfarrowsdeclare{angle 90}{angle 90} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=5.5\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by0.707\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpoint{-5.5\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-5.5\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfusepathqstroke +}% + +\pgfarrowsdeclarereversed{angle 90 reversed}{angle 90 reversed}{angle 90}{angle 90}% + + +\pgfarrowsdeclare{angle 60}{angle 60} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=7.29\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{150}{9\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-150}{9\pgfutil@tempdima}}} + \pgfusepathqstroke +}% + +\pgfarrowsdeclarereversed{angle 60 reversed}{angle 60 reversed}{angle 60}{angle 60}% + + + +\pgfarrowsdeclare{angle 45}{angle 45} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=8.705\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by1.28\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.3pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{157}{10\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-157}{10\pgfutil@tempdima}}} + \pgfusepathqstroke +}% + +\pgfarrowsdeclarereversed{angle 45 reversed}{angle 45 reversed}{angle 45}{angle 45}% + + + +% A dot shaped arrow + +\pgfarrowsdeclare{*}{*} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfutil@tempdimb=7.5\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=1.5\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfpathcircle{\pgfqpoint{-3\pgfutil@tempdima}{0pt}}{+4.5\pgfutil@tempdima} + \pgfusepathqfillstroke +}% + + +% An open dot shaped arrow + +\pgfarrowsdeclare{o}{o} +{ + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfutil@tempdimb=9\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfpathcircle{\pgfqpoint{4.5\pgfutil@tempdima}{0bp}}{4.5\pgfutil@tempdima} + \pgfusepathqstroke +}% + + + +% A diamond shaped arrow + +\pgfarrowsdeclare{diamond}{diamond} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.275\pgflinewidth% + \pgfutil@tempdimb=13\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=1\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.275\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{1\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-6\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-13\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-6\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfarrowsdeclare{open diamond}{open diamond}%{{-.5bp}{14.5bp}} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.275\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=14\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.275\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{14\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{7\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{7\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqstroke +}% + + +% A square shaped arrow +\newdimen\arrowsize +\pgfarrowsdeclare{square}{square} +{ + \arrowsize=0.4pt + \advance\arrowsize by.275\pgflinewidth% + \pgfarrowsleftextend{-7\arrowsize-.5\pgflinewidth} + \advance\arrowsize by.5\pgflinewidth + \pgfarrowsrightextend{+\arrowsize} +} +{ + \arrowsize=0.4pt + \advance\arrowsize by.275\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{1\arrowsize}{4\arrowsize}} + \pgfpathlineto{\pgfqpoint{-7\arrowsize}{4\arrowsize}} + \pgfpathlineto{\pgfqpoint{-7\arrowsize}{-4\arrowsize}} + \pgfpathlineto{\pgfqpoint{1\arrowsize}{-4\arrowsize}} + \pgfpathclose + \pgfusepathqfillstroke +}% +% A open square shaped arrow + +\pgfarrowsdeclare{open square}{open square}%{{-.5bp}{8.5bp}} +{ + \arrowsize=0.4pt + \advance\arrowsize by.275\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \advance\arrowsize by7\arrowsize + \advance\arrowsize by.5\pgflinewidth + \pgfarrowsrightextend{+\arrowsize} +} +{ + \arrowsize=0.4pt + \advance\arrowsize by.275\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{8\arrowsize}{4\arrowsize}} + \pgfpathlineto{\pgfqpoint{0\arrowsize}{4\arrowsize}} + \pgfpathlineto{\pgfqpoint{0\arrowsize}{-4\arrowsize}} + \pgfpathlineto{\pgfqpoint{8\arrowsize}{-4\arrowsize}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +% A triangle shaped arrow + +\pgfarrowsdeclare{triangle 90}{triangle 90} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=5.5\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by0.707\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpoint{-5.5\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-5.5\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfarrowsdeclarereversed{triangle 90 reversed}{triangle 90 reversed}{triangle 90}{triangle 90}% + + +\pgfarrowsdeclare{triangle 60}{triangle 60} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=7.29\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{150}{9\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-150}{9\pgfutil@tempdima}}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfarrowsdeclarereversed{triangle 60 reversed}{triangle 60 reversed}{triangle 60}{triangle 60}% + + + + +\pgfarrowsdeclare{triangle 45}{triangle 45} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfutil@tempdimb=8.705\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=.5\pgfutil@tempdima\advance\pgfutil@tempdimb by1.28\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{157}{10\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{0.5\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-157}{10\pgfutil@tempdima}}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfarrowsdeclarereversed{triangle 45 reversed}{triangle 45 reversed}{triangle 45}{triangle 45}% + + + + +\pgfarrowsdeclare{open triangle 90}{open triangle 90} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=6\pgfutil@tempdima\advance\pgfutil@tempdimb by0.707\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{6\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqstroke +}% + +\pgfarrowsdeclare{open triangle 90 reversed}{open triangle 90 reversed}% +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-.707\pgflinewidth} + \pgfutil@tempdimb=6\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpoint{6\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{6\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +\pgfarrowsdeclare{open triangle 60}{open triangle 60} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=7.794\pgfutil@tempdima\advance\pgfutil@tempdimb by\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{7.794\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{150}{9\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{7.794\pgfutil@tempdima}{0pt}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{7.794\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-150}{9\pgfutil@tempdima}}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +\pgfarrowsdeclare{open triangle 60 reversed}{open triangle 60 reversed} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-\pgflinewidth} + \pgfutil@tempdimb=7.794\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpointpolar{30}{9\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointorigin} + \pgfpathlineto{\pgfqpointpolar{-30}{9\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +\pgfarrowsdeclare{open triangle 45}{open triangle 45} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=9.205\pgfutil@tempdima\advance\pgfutil@tempdimb by1.28\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{9.205\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{157}{10\pgfutil@tempdima}}} + \pgfpathlineto{\pgfqpoint{9.205\pgfutil@tempdima}{0pt}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{9.205\pgfutil@tempdima}{0pt}}{\pgfqpointpolar{-157}{10\pgfutil@tempdima}}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +\pgfarrowsdeclare{open triangle 45 reversed}{open triangle 45 reversed} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfarrowsleftextend{+-1.28\pgflinewidth} + \pgfutil@tempdimb=9.205\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.5pt% + \advance\pgfutil@tempdima by.25\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetmiterjoin + \pgfpathmoveto{\pgfqpointpolar{23}{10\pgfutil@tempdima}} + \pgfpathlineto{\pgfpointorigin} + \pgfpathlineto{\pgfqpointpolar{-23}{10\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqstroke +}% + + + +% A less fleshy variant of LaTeX's ordinal arrow type + +\pgfarrowsdeclare{latex'}{latex'} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfarrowsleftextend{+-4\pgfutil@tempdima} + \pgfarrowsrightextend{+6\pgfutil@tempdima} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfpathmoveto{\pgfqpoint{6\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{3.5\pgfutil@tempdima}{.5\pgfutil@tempdima}} + {\pgfqpoint{-1\pgfutil@tempdima}{1.5\pgfutil@tempdima}} + {\pgfqpoint{-4\pgfutil@tempdima}{3.75\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-1.5\pgfutil@tempdima}{1\pgfutil@tempdima}} + {\pgfqpoint{-1.5\pgfutil@tempdima}{-1\pgfutil@tempdima}} + {\pgfqpoint{-4\pgfutil@tempdima}{-3.75\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-1\pgfutil@tempdima}{-1.5\pgfutil@tempdima}} + {\pgfqpoint{3.5\pgfutil@tempdima}{-.5\pgfutil@tempdima}} + {\pgfqpoint{6\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfill +}% + +\pgfarrowsdeclarereversed{latex' reversed}{latex' reversed}{latex'}{latex'}% + + +% A rounded variant of the stealth arrow + +\pgfarrowsdeclare{stealth'}{stealth'} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfutil@tempdimb=6\pgfutil@tempdima\advance\pgfutil@tempdimb by.5\pgflinewidth% + \pgfarrowsleftextend{+-\pgfutil@tempdimb} + \pgfutil@tempdimb=2\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{2\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-.5\pgfutil@tempdima}{.5\pgfutil@tempdima}} + {\pgfqpoint{-3\pgfutil@tempdima}{1.5\pgfutil@tempdima}} + {\pgfqpoint{-6\pgfutil@tempdima}{3.25\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-3\pgfutil@tempdima}{1\pgfutil@tempdima}} + {\pgfqpoint{-3\pgfutil@tempdima}{-1\pgfutil@tempdima}} + {\pgfqpoint{-6\pgfutil@tempdima}{-3.25\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-3\pgfutil@tempdima}{-1.5\pgfutil@tempdima}} + {\pgfqpoint{-.5\pgfutil@tempdima}{-.5\pgfutil@tempdima}} + {\pgfqpoint{2\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfarrowsdeclarereversed{stealth' reversed}{stealth' reversed}{stealth'}{stealth'}% + + + +% The two half of the $\to$ arrow + +\pgfarrowsdeclare{left to}{left to} +{ + \pgfutil@tempdima=-0.84pt% + \advance\pgfutil@tempdima by-1.3\pgflinewidth% + \pgfutil@tempdimb=0.21pt% + \advance\pgfutil@tempdimb by.625\pgflinewidth% + \pgfarrowsleftextend{+\pgfutil@tempdima} + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetlinewidth{0.8\pgflinewidth} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{-3\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-2.75\pgfutil@tempdima}{2.5\pgfutil@tempdima}} + {\pgfqpoint{0pt}{0.25\pgfutil@tempdima}} + {\pgfqpoint{0.75\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{0.55\pgfutil@tempdima}{-0.125\pgflinewidth}} + {\pgfqpoint{0.5\pgfutil@tempdima}{-0.125\pgflinewidth}} + {\pgfqpoint{0.5\pgfutil@tempdima}{-0.125\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{0pt}{-0.125\pgflinewidth}} + \pgfusepathqstroke +}% + + +\pgfarrowsdeclare{right to}{right to} +{ + \pgfutil@tempdima=-0.84pt% + \advance\pgfutil@tempdima by-1.3\pgflinewidth% + \pgfutil@tempdimb=0.21pt% + \advance\pgfutil@tempdimb by.625\pgflinewidth% + \pgfarrowsleftextend{+\pgfutil@tempdima} + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetlinewidth{0.8\pgflinewidth} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{-3\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-2.75\pgfutil@tempdima}{-2.5\pgfutil@tempdima}} + {\pgfqpoint{0pt}{-0.25\pgfutil@tempdima}} + {\pgfqpoint{0.75\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{0.55\pgfutil@tempdima}{0.125\pgflinewidth}} + {\pgfqpoint{0.5\pgfutil@tempdima}{0.125\pgflinewidth}} + {\pgfqpoint{0.5\pgfutil@tempdima}{0.125\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{0pt}{0.125\pgflinewidth}} + \pgfusepathqstroke +}% + + + +% The halfs of the $\to$ arrow reversed + +\pgfarrowsdeclare{left to reversed}{left to reversed} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfarrowsleftextend{+-.1\pgflinewidth} + \pgfutil@tempdimb=3.75\pgfutil@tempdima\advance\pgfutil@tempdimb by0.9\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfsetbuttcap + \pgfpathmoveto{\pgfqpoint{0.5\pgflinewidth}{0pt}} + \pgfpathlineto{\pgfqpoint{-0.1\pgflinewidth}{0pt}} + \pgfusepathqstroke + \pgfsetroundcap + \pgfsetlinewidth{.8\pgflinewidth} + {\pgftransformxshift{0.625\pgflinewidth} + \pgfpathmoveto{\pgfqpoint{3.75\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.5\pgfutil@tempdima}{2.5\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{0.25\pgfutil@tempdima}}{\pgfqpoint{0pt}{0.125\pgflinewidth}} + \pgfpathmoveto{\pgfqpoint{3.75\pgfutil@tempdima}{4\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.5\pgfutil@tempdima}{2.5\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{0.25\pgfutil@tempdima}}{\pgfqpoint{0pt}{-0.125\pgflinewidth}} + } + \pgfusepathqstroke% +}% + +\pgfarrowsdeclare{right to reversed}{right to reversed} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfarrowsleftextend{+-.1\pgflinewidth} + \pgfutil@tempdimb=3.75\pgfutil@tempdima\advance\pgfutil@tempdimb by0.9\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.28pt% + \advance\pgfutil@tempdima by.3\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfsetbuttcap + \pgfpathmoveto{\pgfqpoint{0.5\pgflinewidth}{0pt}} + \pgfpathlineto{\pgfqpoint{-0.1\pgflinewidth}{0pt}} + \pgfusepathqstroke + \pgfsetroundcap + \pgfsetlinewidth{.8\pgflinewidth} + {\pgftransformxshift{0.625\pgflinewidth} + \pgfpathmoveto{\pgfqpoint{3.75\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.5\pgfutil@tempdima}{-2.5\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{-0.25\pgfutil@tempdima}}{\pgfqpoint{0pt}{-0.125\pgflinewidth}} + \pgfpathmoveto{\pgfqpoint{3.75\pgfutil@tempdima}{-4\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.5\pgfutil@tempdima}{-2.5\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{-0.25\pgfutil@tempdima}}{\pgfqpoint{0pt}{0.125\pgflinewidth}} + } + \pgfusepathqstroke% +}% + + + +% A left hook + +\pgfarrowsdeclare{left hook}{left hook} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=3.75\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.75\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{2.415\pgfutil@tempdima}{0\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{1.665\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{3\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.75\pgfutil@tempdima}{4.665\pgfutil@tempdima}}{\pgfqpoint{2.415\pgfutil@tempdima}{6\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfusepathqstroke% +}% + +\pgfarrowsdeclarereversed{left hook reversed}{left hook reversed}{left hook}{left hook}% + + + +% A right hook + +\pgfarrowsdeclare{right hook}{right hook} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=3.75\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.75\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{2.415\pgfutil@tempdima}{0\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{-1.665\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{-3\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.75\pgfutil@tempdima}{-4.665\pgfutil@tempdima}}{\pgfqpoint{2.415\pgfutil@tempdima}{-6\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfusepathqstroke% +}% + +\pgfarrowsdeclarereversed{right hook reversed}{right hook reversed}{right hook}{right hook}% + + +% Hooks in both directions + +\pgfarrowsdeclare{hooks}{hooks} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfarrowsleftextend{+-.5\pgflinewidth} + \pgfutil@tempdimb=3.75\pgfutil@tempdima\advance\pgfutil@tempdimb by0.5\pgflinewidth% + \pgfarrowsrightextend{+\pgfutil@tempdimb} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.2\pgflinewidth% + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.75\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{2.415\pgfutil@tempdima}{0\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{1.665\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{3\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.75\pgfutil@tempdima}{4.665\pgfutil@tempdima}}{\pgfqpoint{2.415\pgfutil@tempdima}{6\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{6\pgfutil@tempdima}} + \pgfpathmoveto{\pgfqpoint{0.75\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{2.415\pgfutil@tempdima}{0\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{-1.665\pgfutil@tempdima}}{\pgfqpoint{3.75\pgfutil@tempdima}{-3\pgfutil@tempdima}} + \pgfpathcurveto{\pgfqpoint{3.75\pgfutil@tempdima}{-4.665\pgfutil@tempdima}}{\pgfqpoint{2.415\pgfutil@tempdima}{-6\pgfutil@tempdima}}{\pgfqpoint{0.75\pgfutil@tempdima}{-6\pgfutil@tempdima}} + \pgfusepathqstroke% +}% + +\pgfarrowsdeclarereversed{hooks reversed}{hooks reversed}{hooks}{hooks}% + + +% An arrow that looks like a serif of the computer modern font + +\pgfarrowsdeclare{serif cm}{serif cm} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.45\pgflinewidth% + \pgfarrowsleftextend{+-.75\pgfutil@tempdima} + \pgfarrowsrightextend{+.04\pgflinewidth} +} +{ + \pgfutil@tempdima=0.4pt% + \advance\pgfutil@tempdima by.45\pgflinewidth% + \pgftransformxshift{.04\pgflinewidth} + \pgfpathmoveto{\pgfqpoint{-.75\pgfutil@tempdima}{.5\pgflinewidth}} + \pgfpathcurveto + {\pgfqpoint{-.375\pgfutil@tempdima}{.5\pgflinewidth}} + {\pgfqpoint{-.375\pgfutil@tempdima}{.7\pgflinewidth}} + {\pgfqpoint{-.375\pgfutil@tempdima}{1.95\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0pt}{1.95\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-.04\pgflinewidth}{.5\pgfutil@tempdima}} + {\pgfqpoint{-.04\pgflinewidth}{-.5\pgfutil@tempdima}} + {\pgfqpoint{0pt}{-1.95\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-.375\pgfutil@tempdima}{-1.95\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfqpoint{-.375\pgfutil@tempdima}{-.7\pgflinewidth}} + {\pgfqpoint{-.375\pgfutil@tempdima}{-.5\pgflinewidth}} + {\pgfqpoint{-.75\pgfutil@tempdima}{-.5\pgflinewidth}} + \pgfpathclose + \pgfusepathqfill +}% + + + +% Round cap + +\pgfarrowsdeclare{round cap}{round cap} +{\pgfarrowsleftextend{+0pt}\pgfarrowsrightextend{+\pgflinewidth}} +{ + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfqpoint{0.5\pgflinewidth}{0pt}} + \pgfusepathqstroke +}% + + +% Butt cap + +\pgfarrowsdeclare{butt cap}{butt cap} +{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+.5\pgflinewidth}} +{ + \pgfsetdash{}{+0pt} + \pgfsetbuttcap + \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0pt}} + \pgfpathlineto{\pgfqpoint{0.5\pgflinewidth}{0pt}} + \pgfusepathqstroke +}% + + + +% 90 degrees cap + +\pgfarrowsdeclare{triangle 90 cap}{triangle 90 cap} +{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}} +{ + \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{\pgflinewidth}{0pt}} + \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-0.5\pgflinewidth}} + \pgfpathclose + \pgfusepathqfill +}% + + +% reversed 90 degrees cap + +\pgfarrowsdeclare{triangle 90 cap reversed}{triangle 90 cap reversed} +{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}} +{ + \pgfpathmoveto{\pgfqpoint{1\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{0.5\pgflinewidth}{0\pgflinewidth}} + \pgfpathclose + \pgfusepathqfill +}% + + + +% fast + +\pgfarrowsdeclare{fast cap}{fast cap} +{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+2\pgflinewidth}} +{ + \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{0\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-0.5\pgflinewidth}} + \pgfpathclose + \pgfpathmoveto{\pgfqpoint{1\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1.5\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{2\pgflinewidth}{0\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1.5\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{-0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1.5\pgflinewidth}{0\pgflinewidth}} + \pgfpathclose + \pgfusepathqfill +}% + + +\pgfarrowsdeclare{fast cap reversed}{fast cap reversed} +{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+2\pgflinewidth}} +{ + \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{0\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-0.5\pgflinewidth}} + \pgfpathclose + \pgfpathmoveto{\pgfqpoint{1.5\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{2\pgflinewidth}{0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1.5\pgflinewidth}{0\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{2\pgflinewidth}{-.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1.5\pgflinewidth}{-0.5\pgflinewidth}} + \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{0\pgflinewidth}} + \pgfpathclose + \pgfusepathqfill +}% + + + + + +% Mathematical arrows + + +% The arrow tip of an \implies arrow, to be used with an inner line. +% +% Example: +% +% \pgfsetarrow{-implies} +% \pgfsetlinewidth{1.8pt} +% \pgfsetinnerlinewidth{1pt} + +\pgfarrowsdeclare{implies}{implies} +{ + \pgfmathsetlength{\pgfutil@tempdima}{.25\pgflinewidth+.25*\pgfinnerlinewidth}% + \pgfmathsetlength{\pgfutil@tempdimb}{.5\pgflinewidth-.5*\pgfinnerlinewidth}% + \pgfarrowsrightextend{2.06\pgfutil@tempdima+.5\pgfutil@tempdimb} + \pgfarrowsleftextend{-1.36\pgfutil@tempdima-.5\pgfutil@tempdimb} +} +{ + \pgfmathsetlength{\pgfutil@tempdima}{.25\pgflinewidth+.25*\pgfinnerlinewidth}% + \pgfmathsetlength{\pgfutil@tempdimb}{.5\pgflinewidth-.5*\pgfinnerlinewidth}% + \pgftransformxshift{.06\pgfutil@tempdima} + \pgfsetlinewidth{\pgfutil@tempdimb} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfpoint{-1.4\pgfutil@tempdima}{2.65\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfpoint{-0.75\pgfutil@tempdima}{1.25\pgfutil@tempdima}} + {\pgfpoint{1\pgfutil@tempdima}{0.05\pgfutil@tempdima}} + {\pgfpoint{2\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfpoint{1\pgfutil@tempdima}{-0.05\pgfutil@tempdima}} + {\pgfpoint{-.75\pgfutil@tempdima}{-1.25\pgfutil@tempdima}} + {\pgfpoint{-1.4\pgfutil@tempdima}{-2.65\pgfutil@tempdima}} + \pgfusepathqstroke +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.meta.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.meta.code.tex new file mode 100644 index 0000000000..dbe2fb77d4 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.meta.code.tex @@ -0,0 +1,1607 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryarrows.meta.code.tex} + + + +% +% +% Meta keys +% +% + + +\newdimen\pgfarrowinset +\newdimen\pgfarrowlength +\newdimen\pgfarrowwidth +\newdimen\pgfarrowlinewidth +\newif\ifpgfarrowroundcap +\newif\ifpgfarrowroundjoin + +\pgfarrowsaddtolengthscalelist\pgfarrowlength +\pgfarrowsaddtolengthscalelist\pgfarrowinset +\pgfarrowsaddtowidthscalelist\pgfarrowwidth + + +\pgfkeys{ + /pgf/arrow keys/.cd, + length/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters\pgfarrowlength\pgf@x}% + }, + inset/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters\pgfarrowinset\pgf@x}% + }, + inset'/.code={ + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslengthdependent\pgfarrowstheparameters\pgfarrowinset}% + }, + line width/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters\pgfarrowlinewidth\pgf@x}% + }, + line width'/.code={ + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslengthdependent\pgfarrowstheparameters\pgfarrowlinewidth}% + }, + width/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters\pgfarrowwidth\pgf@x}% + }, + width'/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{\expandafter\pgfarrowslengthdependent\pgfarrowstheparameters\pgfarrowwidth}% + }, + angle/.code={% + \pgfarrowsfourparameters{#1}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\pgfarrows@angle@setup\pgfarrowstheparameters}% + }, + angle'/.code={ + \pgfarrowsaddtolateoptions{\pgfarrows@angle@setup@prime{#1}}% + }, + % + line cap/.is choice, + line cap/butt/.code=\pgfarrowsaddtooptions{\pgfarrowroundcapfalse}, + line cap/round/.code=\pgfarrowsaddtooptions{\pgfarrowroundcaptrue}, + line join/.is choice, + line join/miter/.code=\pgfarrowsaddtooptions{\pgfarrowroundjoinfalse}, + line join/round/.code=\pgfarrowsaddtooptions{\pgfarrowroundjointrue}, + round/.style={line cap=round,line join=round}, + sharp/.style={line cap=butt,line join=miter}, +}% +% +% +% Classification of arrow tips: +% +% +% Barbs +% ----- +% +% These arrow tips consisting of stroked lines starting at the tip, +% typically going backward. They cannot be filled, only stroked +% +% A special case are the arrows mimicking the tip at the end of a +% \rightarrow command. +% +% +% Geometric +% --------- +% +% The arrow tips have a geometric form like a triangle or a +% "stealth" fighter or a kite. They can be filled and/or stroked. +% +% +% Caps +% ---- +% +% These arrow tips have their width fixed to the line width and +% provide different ways of adding a "cap" to the end of a line. This +% allows one to use more than just the standard "round cap", "butt +% cap" and "rect cap" and, additionally, one can one kind of cap at +% one end and another at the other end. +% +% +% Other +% ----- +% +% Special purpose arrow tips. +% + + + +% +% +% Barbs arrow tips +% +% + + +% An Straight Barb yields a simple angle + +\pgfdeclarearrow{ + name = Straight Barb, + defaults = { + length = +1.5pt 2, + width' = +0pt 2, + line width = +0pt 1 1, + }, + setup code = { + % Compute front miter length: + \pgfmathdivide@{\pgf@sys@tonumber\pgfarrowlength}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x4\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% xc is front miter + \pgf@xc.5\pgf@xc + \pgf@xa\pgf@temp@quot\pgfarrowlinewidth% xa is extra harpoon miter + % Set ends + \ifpgfarrowroundjoin + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by\pgf@xc\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi} + \fi + \pgfarrowssetvisualbackend{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth} + \pgfarrowssetbackend{-.5\pgfarrowlinewidth} + % harpoon miter correction + \ifpgfarrowreversed + \pgfarrowssetlineend{\pgfarrowlength\ifpgfarrowharpoon\advance\pgf@x by.5\pgfarrowlinewidth\fi} + \else + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth} + \fi + % The hull: + \ifpgfarrowroundjoin + \pgfarrowshullpoint{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else0pt\fi}% + \else% + \ifpgfarrowharpoon + \pgfarrowshullpoint{\pgfarrowlength\advance\pgf@x by\pgf@xc\advance\pgf@x by\pgf@xa}{-.5\pgfarrowlinewidth}% + \else + \pgfarrowshullpoint{\pgfarrowlength\advance\pgf@x by\pgf@xc\advance\pgf@x by\pgf@xa}{0pt}% + \fi% + \fi + \pgfarrowsupperhullpoint{.5\pgfarrowlinewidth}{.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}% + \pgfarrowsupperhullpoint{-.5\pgfarrowlinewidth}{.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}% + \ifpgfarrowharpoon + \pgfarrowshullpoint{-.5\pgfarrowlinewidth}{-.5\pgfarrowlinewidth}% + \fi + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \pgfpathmoveto{\pgfqpoint{0pt}{.5\pgfarrowwidth}} + \pgfpathlineto{\pgfqpoint{\pgfarrowlength}{0pt}} + \ifpgfarrowharpoon + \pgfpathlineto{\pgfqpoint{\pgfarrowlength\advance\pgf@x by\ifpgfarrowreversed\else-\fi\pgfarrowlinewidth}{0pt}} + \else + \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgfarrowwidth}} + \fi + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundjoin j\fi% + \ifpgfarrowroundcap c\fi% + }, +}% +% +% +% Hooks are barbs that consist of an arc going forward from the line +% end and curving back by a given angle specified using the |arc| +% key. + +\pgfkeys{ + /pgf/arrow keys/.cd, + arc/.code={% + \pgfmathparse{#1}% + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\def\expandafter\pgfarrowarc\expandafter{\pgfmathresult}} + } +}% + +\def\pgfarrowarc{180}% + +\pgfdeclarearrow{ + name = Hooks, + defaults = { + length = +0.75pt 1.25, + width' = +0pt 4 -1, + line width = +0pt 1 1, + }, + setup code = { + \ifpgfarrowharpoon + \pgfarrowshullpoint{.5\pgfarrowlength}{-.5\pgfarrowlinewidth} + \pgfarrowshullpoint{\pgfarrowlength}{-.5\pgfarrowlinewidth\advance\pgf@y by.125\pgfarrowwidth} + \fi + \ifdim\pgfarrowarc pt<90.1pt + \pgfarrowsupperhullpoint{0pt}{.25\pgfarrowwidth\ifpgfarrowroundcap\else\advance\pgf@y by-.25\pgfarrowlinewidth\fi} + \pgfarrowsupperhullpoint{\pgfarrowlength}{.25\pgfarrowwidth\ifpgfarrowroundcap\else\advance\pgf@y by-.25\pgfarrowlinewidth\fi} + \else% + \pgfarrowsupperhullpoint{\pgfarrowlength}{.375\pgfarrowwidth} + \pgfarrowsupperhullpoint{.5\pgfarrowlength}{.5\pgfarrowwidth} + \ifdim\pgfarrowarc pt>180pt + \pgfarrowsupperhullpoint{-.5\pgfarrowlength}{.5\pgfarrowwidth} + \pgfarrowsupperhullpoint{-\pgfarrowlength}{.375\pgfarrowwidth} + \pgfarrowsupperhullpoint{-\pgfarrowlength}{.25\pgfarrowwidth} + \else + \pgfarrowsupperhullpoint{\ifpgfarrowroundcap-.5\pgfarrowlinewidth\else0pt\fi}{.25\pgfarrowwidth} + \pgfarrowsupperhullpoint{\ifpgfarrowroundcap-.5\pgfarrowlinewidth\else0pt\fi}{.5\pgfarrowwidth} + \fi + \fi + % Adjust width and length: Take line thickness into account: + \advance\pgfarrowlength by-.5\pgfarrowlinewidth + \advance\pgfarrowwidth by-\pgfarrowlinewidth + \ifpgfarrowreversed + \ifpgfarrowroundjoin + \pgfarrowssetbackend{-.5\pgfarrowlinewidth} + \fi + \fi + % There are four different intervals for the values of + % \pgfarrowsarc that give rise to four different settings of tip + % ends and so on: + % + % Case 1: 0 <= Angle < 90 + % + \ifdim\pgfarrowarc pt<90pt% + % Tip end is given by sin(pgfarrowarc)*length + \pgfmathsin@{\pgfarrowarc} + \pgfarrowssettipend{\pgfmathresult\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth}% + \else\ifdim\pgfarrowarc pt<180pt% + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth}% + \ifpgfarrowroundcap\pgfarrowssetbackend{-.5\pgfarrowlinewidth}\fi% + \else\ifdim\pgfarrowarc pt<270pt% + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth}% + \ifdim\pgfarrowarc pt>180pt + % Back end is given by sin(pgfarrowarc)*length + \pgfmathsin@{\pgfarrowarc} + \pgfarrowssetbackend{\pgfmathresult\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth}% + \else + \ifpgfarrowroundcap\pgfarrowssetbackend{-.5\pgfarrowlinewidth}\fi% + \fi% + \else% + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by.5\pgfarrowlinewidth}% + \pgfarrowssetbackend{-\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth}% + \fi\fi\fi% + \ifpgfarrowreversed + \pgfarrowssetlineend{.5\pgfarrowlinewidth} + \else% + \ifpgfarrowharpoon + \pgfarrowssetlineend{0pt} + \else + \pgfarrowssetlineend{.25\pgfarrowlinewidth} + \fi + \fi + % Adjust arc: + \pgf@x\pgfarrowarc pt% + \advance\pgf@x by-90pt% + \edef\pgfarrowarc{\pgf@sys@tonumber\pgf@x}% + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + \pgfarrowssave\pgfarrowarc + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + {% + \pgftransformxscale{+\pgfarrowlength} + \pgftransformyscale{+.25\pgfarrowwidth} + \pgfpathmoveto{\pgfpointpolar{+\pgfarrowarc}{+1pt}\advance\pgf@y by1pt} + \pgfpatharc{\pgfarrowarc}{+-90}{+1pt} + \ifpgfarrowharpoon + \else + \pgfpatharc{+90}{+-\pgfarrowarc}{+1pt} + \fi + } + \ifpgfarrowharpoon\ifpgfarrowreversed + \pgfpathlineto{\pgfqpoint{\pgflinewidth}{0pt}} + \fi\fi + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \pgfarrowarc,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundjoin j\fi% + \ifpgfarrowroundcap c\fi% + }, +}% + + +\pgfdeclarearrow{ + name = Arc Barb, + defaults = { + length = +1.5pt 2, + width' = +0pt 2, + line width = +0pt 1 1, + }, + setup code = { + % Adjust arc: + \pgf@x\pgfarrowarc pt% + \pgf@x.5\pgf@x% + \edef\pgfarrowarc{\pgf@sys@tonumber\pgf@x}% + % The tips: + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetvisualbackend{\pgfarrowlength} + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth} + % The hull: + \pgfarrowsupperhullpoint{\pgfarrowlength}{.25\pgfarrowwidth} + \ifpgfarrowharpoon\pgfarrowshullpoint{\pgfarrowlength}{-.5\pgflinewidth}\fi + \pgfmathsincos@{\pgfarrowarc}% + \pgf@xa.5\pgfarrowwidth% + \pgfarrowsupperhullpoint{\pgfmathresultx\pgfarrowlength}{\pgfmathresulty\pgf@xa} + \ifdim\pgfarrowarc pt>60pt + \pgfarrowsupperhullpoint{.5\pgfarrowlength}{\ifdim\pgfarrowarc pt<90pt\pgfmathresulty\pgf@xa\else.5\pgfarrowwidth\fi} + \fi + \ifdim\pgfarrowarc pt>90pt + \ifdim\pgfarrowarc pt<120pt + \pgfarrowsupperhullpoint{\pgfmathresultx\pgfarrowlength}{.5\pgfarrowwidth} + \else + \pgfarrowsupperhullpoint{-.5\pgfarrowlength}{.5\pgfarrowwidth} + \ifdim\pgfarrowarc pt>150pt + \pgfarrowsupperhullpoint{-\pgfarrowlength}{.25\pgfarrowwidth} + \fi + \fi + \fi + \pgfutil@tempswafalse + \ifdim\pgfarrowarc pt<90pt + \pgfutil@tempswatrue + \fi + \ifpgfarrowharpoon + \pgfutil@tempswatrue + \fi + \ifpgfutil@tempswa + \pgf@xa.5\pgfarrowwidth\advance\pgf@xa by-\pgfarrowlinewidth% + \pgf@ya\pgfarrowlength\advance\pgf@ya by-\pgfarrowlinewidth% + \pgfarrowsupperhullpoint{\pgfmathresultx\pgf@ya}{\pgfmathresulty\pgf@xa} + \fi + % Compute back end + \ifpgfarrowroundcap + \pgf@y\pgfarrowlength + \advance\pgf@y by-.5\pgfarrowlinewidth + \pgf@x\pgfmathresultx\pgf@y% + \else + \ifdim\pgfarrowarc pt<90pt + \pgf@y\pgfarrowlength + \advance\pgf@y by-\pgfarrowlinewidth + \pgf@x\pgfmathresultx\pgf@y% + \else + \pgf@x\pgfmathresultx\pgfarrowlength% + \fi + \fi + \pgfarrowssetbackend{\pgf@x\ifpgfarrowroundcap\advance\pgf@x by-.5\pgfarrowlinewidth\fi} + % Adjust width and length: Take line thickness into account: + \advance\pgfarrowlength by-.5\pgfarrowlinewidth + \advance\pgfarrowwidth by-\pgfarrowlinewidth + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + \pgfarrowssave\pgfarrowarc + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + {% + \pgftransformxscale{+\pgfarrowlength} + \pgftransformyscale{+.5\pgfarrowwidth} + \pgfpathmoveto{\pgfpointpolar{+\pgfarrowarc}{+1pt}} + \ifpgfarrowharpoon + \pgfpatharc{+\pgfarrowarc}{0pt}{+1pt} + \else + \pgfpatharc{+\pgfarrowarc}{+-\pgfarrowarc}{+1pt} + \fi + } + \ifpgfarrowharpoon + \pgfpathlineto{\pgfqpoint{\pgfarrowlength\advance\pgf@x by\ifpgfarrowreversed\else-\fi.5\pgflinewidth}{0pt}} + \fi + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \pgfarrowarc,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundcap c\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + + + +% Tee Barb are barb arrows heads that look like a T + +\pgfdeclarearrow{ + name = Tee Barb, + defaults = { + length = +1.5pt 2, + width = +3pt 4, + inset' = +0pt .5, + line width = +0pt 1 1, + }, + bending mode=polar, + setup code = { + % Two useful numbers... + \pgfutil@tempswafalse% + \pgfutil@tempswbfalse% + \pgfutil@tempdima\pgfarrowlength\advance\pgfutil@tempdima by-\pgfarrowinset\ifdim\pgfutil@tempdima<.5\pgfarrowlinewidth\pgfutil@tempdima.5\pgfarrowlinewidth\pgfutil@tempswatrue\fi% + \pgfutil@tempdimb-\pgfarrowinset\ifdim\pgfutil@tempdimb>-.5\pgfarrowlinewidth\pgfutil@tempdimb-.5\pgfarrowlinewidth\pgfutil@tempswbtrue\fi + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowwidth + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + % Infos: + \pgfarrowssettipend{\pgfutil@tempdima\ifpgfarrowroundcap\ifpgfutil@tempswa\else\advance\pgf@x by.5\pgfarrowlinewidth\fi\fi} + \pgfarrowssetvisualbackend{.5\pgfarrowlinewidth} + \pgfarrowssetbackend{\pgfutil@tempdimb\ifpgfarrowroundcap\ifpgfutil@tempswb\else\advance\pgf@x by-.5\pgfarrowlinewidth\fi\fi} + \pgfarrowssetlineend{\ifpgfarrowreversed\else-\fi.25\pgfarrowlinewidth}% + % The hull: + \pgfarrowsupperhullpoint{\pgfutil@tempdima\ifpgfarrowroundcap\ifpgfutil@tempswa\else\advance\pgf@x by.5\pgfarrowlinewidth\fi\fi}{.5\pgfarrowwidth}% + \pgfarrowsupperhullpoint{\pgfutil@tempdimb\ifpgfarrowroundcap\ifpgfutil@tempswb\else\advance\pgf@x by-.5\pgfarrowlinewidth\fi\fi}{.5\pgfarrowwidth}% + \ifpgfarrowharpoon + \pgfarrowshullpoint{.5\pgfarrowlinewidth}{-.5\pgfarrowlinewidth}% + \fi + }, + drawing code = { + \pgfsetdash{}{+0pt} + \pgf@yc\pgflinewidth% save... + \ifdim\pgflinewidth=\pgfarrowlinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \pgf@x\pgfutil@tempdima\advance\pgf@x by-.5\pgfarrowlinewidth% + \pgf@y\pgfutil@tempdimb\advance\pgf@y by.5\pgfarrowlinewidth% + % Case 1: No bar atop the I: + \ifdim\pgf@x=\pgf@y% + \pgfpathmoveto{\pgfqpoint{0pt}{.5\pgfarrowwidth}} + \pgfpathlineto{\pgfqpoint{0pt}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else-.5\pgfarrowwidth\fi}} + \else + % Case 2: Bar, but only in one direction: + \ifdim\pgfutil@tempdima=.5\pgfarrowlinewidth% + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdimb}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{0pt}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \ifpgfarrowharpoon% + \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgf@yc}}% + \else% + \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{\pgfutil@tempdimb}{-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}} + \fi + \else% Case 3: Complete I: + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdimb}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{\pgfutil@tempdima}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \pgfpathmoveto{\pgfqpoint{0pt}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \ifpgfarrowharpoon% + \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgf@yc}}% + \else% + \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}} + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdimb}{-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{\pgfutil@tempdima}{-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth}} + \fi + \fi + \fi + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowwidth,% + \the\pgfarrowlength,% + \the\pgfarrowinset,% + \the\pgfarrowlinewidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundjoin j\fi% + \ifpgfarrowroundcap c\fi% + }, +}% + + +% Math barbs that resemble \rightarrow in different fonts: + + + +% The original default arrow head used in TikZ. It is modeled on an +% old version of the \rightarrow head of the *old* Computer Modern +% fonts. + +\pgfdeclarearrow{ + name = Classical TikZ Rightarrow, + defaults = { + length = +1.05pt 1.925, + width' = +0pt 1.9237, + line width = 0pt 0.8 1, + round + }, + setup code = + { + \ifpgfarrowharpoon\pgfarrowroundjointrue\fi + % inner length: + \pgfutil@tempdima\pgfarrowlength + \advance\pgfutil@tempdima by-\pgfarrowlinewidth + \pgfutil@tempdimb\pgfarrowwidth + \advance\pgfutil@tempdimb by-\pgfarrowlinewidth + \ifpgfarrowroundjoin% + \else% + \pgfmathdivide@{\pgf@sys@tonumber\pgfutil@tempdima}{\pgf@sys@tonumber\pgfutil@tempdimb}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x40.96\pgf@x% + \advance\pgf@x by1pt% \pgflinewidth^2 + (6.4 \pgftempdim@a / \pgfutil@tempdimb) \pgflinewidth^2 + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% xc is front miter + \pgf@xc.5\pgf@xc + \fi% + % The following are needed in the code: + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + % The extend: + \pgfarrowssettipend{\pgfutil@tempdima\ifpgfarrowroundjoin\advance\pgf@x by.5\pgfarrowlinewidth\else\advance\pgf@x by\pgf@xc\fi}% + \pgfarrowssetvisualbackend{\pgfutil@tempdima\advance\pgf@x by.5\pgfarrowlinewidth}% + \ifpgfarrowreversed% + \ifpgfarrowharpoon% + % A reversed arrow needs a slightly different line end: + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by.5\pgflinewidth}% + \else% + % A reversed arrow needs a slightly different line end: + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by-.25\pgflinewidth}% + \fi% + \else% + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by-.6\pgflinewidth}% + \fi% + \pgfarrowssetbackend{-.5\pgfarrowlinewidth}% + % The hull: + % Tip: + \pgfarrowshullpoint{\pgfutil@tempdima\ifpgfarrowroundjoin\advance\pgf@x by.5\pgfarrowlinewidth\else\advance\pgf@x by\pgf@xc\fi}{.5\pgfarrowlinewidth}% + \pgfarrowshullpoint{\pgfutil@tempdima\ifpgfarrowroundjoin\advance\pgf@x by.5\pgfarrowlinewidth\else\advance\pgf@x by\pgf@xc\fi}{-.5\pgfarrowlinewidth}% + % Upper end: + \pgfarrowsupperhullpoint{.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by.5\pgfarrowlinewidth}% + \pgfarrowsupperhullpoint{-.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by.5\pgfarrowlinewidth}% + % Lower end: + \ifpgfarrowharpoon + \pgfarrowshullpoint{\pgfutil@tempdima\advance\pgf@x by-\pgflinewidth}{-.5\pgflinewidth}% + \pgfarrowshullpoint{-.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by-.5\pgflinewidth}% + \fi + }, + drawing code = + { + \pgfsetdash{}{+0pt} + \edef\pgf@orig@linewidth{\the\pgflinewidth} + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \ifpgfarrowharpoon\pgfarrowroundjointrue\fi + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \pgfpathmoveto + {\pgfqpoint{0pt}{.5\pgfutil@tempdimb}} + \ifpgfarrowharpoon + \pgf@arrows@old@tikz@harpoon + \else + \pgfpathcurveto + {\pgfqpoint{0.066666\pgfutil@tempdima}{0.3125\pgfutil@tempdimb}} + {\pgfqpoint{.8\pgfutil@tempdima}{0.03125\pgfutil@tempdimb}} + {\pgfqpoint{\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{.8\pgfutil@tempdima}{-.03125\pgfutil@tempdimb}} + {\pgfqpoint{0.066666\pgfutil@tempdima}{-.3125\pgfutil@tempdimb}} + {\pgfqpoint{0pt}{-.5\pgfutil@tempdimb}} + \pgfsetlinewidth{+\pgfarrowlinewidth} + \pgfusepathqstroke + \fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundjoin j\fi% + \ifpgfarrowroundcap c\fi% + }, +}% + +\def\pgf@arrows@old@tikz@harpoon{ + \ifpgfarrowreversed + \pgf@arrows@old@tikz@harpoon@reversed + \else + \pgfpathcurveto + {\pgfqpoint{0.066666\pgfutil@tempdima}{0.3125\pgfutil@tempdimb}} + {\pgfqpoint{.8\pgfutil@tempdima}{0.03125\pgfutil@tempdimb}} + {\pgfqpoint{\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfqpoint{0.95\pgfutil@tempdima}{-0.125\pgflinewidth}} + {\pgfqpoint{0.933333\pgfutil@tempdima}{-0.125\pgflinewidth}} + {\pgfqpoint{0.933333\pgfutil@tempdima}{-0.125\pgflinewidth}} + \pgfpathlineto + {\pgfqpoint{0.8\pgfutil@tempdima\advance\pgf@x by-.5\pgflinewidth}{-0.125\pgflinewidth}} + \pgfusepathqstroke + \fi +}% +\def\pgf@arrows@old@tikz@harpoon@reversed{ + \pgfpathcurveto + {\pgfqpoint{0.066666\pgfutil@tempdima}{0.3125\pgfutil@tempdimb}} + {\pgfqpoint{.8\pgfutil@tempdima}{0.03125\pgfutil@tempdimb}} + {\pgfqpoint{\pgfutil@tempdima}{0.125\pgflinewidth}} + \pgfpathmoveto + {\pgfqpoint{0pt}{.5\pgfutil@tempdimb}} + \pgfpathcurveto + {\pgfqpoint{0.066666\pgfutil@tempdima}{0.3125\pgfutil@tempdimb}} + {\pgfqpoint{.8\pgfutil@tempdima}{0.03125\pgfutil@tempdimb}} + {\pgfqpoint{\pgfutil@tempdima}{-0.125\pgflinewidth}} + \pgfusepathqstroke + \pgfsetlinewidth{+\pgf@orig@linewidth} + \pgfsetroundcap + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdima\advance\pgf@x by0.6\pgflinewidth}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgfutil@tempdima}{0pt}} + \pgfusepathqstroke +}% + + +% An approximation to the new (past 1992) Computer Modern math arrow +% heads. This would be a better version of "to", so consider saying +% to/.tips=Computer Modern Rightarrow + +\pgfdeclarearrow{ + name = Computer Modern Rightarrow, + defaults = { + length = +1.6pt 2.2, % 0pt 5.2 + width' = +0pt 2.096774, + line width = 0pt 1 1, + round + }, + setup code = + { + % inner length: + \pgfutil@tempdima\pgfarrowlength + \advance\pgfutil@tempdima by-\pgfarrowlinewidth + \pgfutil@tempdimb\pgfarrowwidth + \advance\pgfutil@tempdimb by-\pgfarrowlinewidth + % The following are needed in the code: + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + % Front miter: + \ifpgfarrowroundjoin% + \else% + \pgfmathdivide@{\pgf@sys@tonumber\pgfutil@tempdima}{\pgf@sys@tonumber\pgfutil@tempdimb}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x49.44662\pgf@x% + \advance\pgf@x by1pt% \pgfarrowlinewidth^2 + (0.41019/0.0583333 \pgftempdim@a / \pgfutil@tempdimb) \pgfarrowlinewidth^2 + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% xc is front miter + \pgf@xc.5\pgf@xc + \pgf@xa\pgf@temp@quot\pgfarrowlinewidth% xa is extra harpoon miter + \pgf@xa3.51591\pgf@xa% xa is extra harpoon miter + \fi% + % The extend: + \pgfarrowssettipend{\ifpgfarrowroundjoin.5\pgfarrowlinewidth\else\pgf@xc\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi\fi}% + \pgfarrowssetvisualbackend{.5\pgfarrowlinewidth}% + \ifpgfarrowreversed% + \ifpgfarrowharpoon% + \pgfarrowssetlineend{.5\pgfarrowlinewidth}% + \else% + \pgfarrowssetlineend{-.5\pgfarrowlinewidth}% + \fi% + \else% + \pgfarrowssetlineend{-.5\pgfarrowlinewidth}% + \fi% + \pgfarrowssetbackend{-\pgfutil@tempdima\advance\pgf@x by-.5\pgfarrowlinewidth}% + % The hull: + % Tip: + \pgfarrowshullpoint{\ifpgfarrowroundjoin.5\pgfarrowlinewidth\else\pgf@xc\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi\fi}{.5\pgfarrowlinewidth}% + \pgfarrowshullpoint{\ifpgfarrowroundjoin.5\pgfarrowlinewidth\else\pgf@xc\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi\fi}{-.5\pgfarrowlinewidth}% + % Upper end: + \pgfarrowsupperhullpoint{-\pgfutil@tempdima\advance\pgf@x by.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by.5\pgfarrowlinewidth}% + \pgfarrowsupperhullpoint{-\pgfutil@tempdima\advance\pgf@x by-.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by.5\pgfarrowlinewidth}% + % Lower end: + \ifpgfarrowharpoon + \pgfarrowshullpoint{-\pgfarrowlinewidth}{-.5\pgfarrowlinewidth}% + \pgfarrowshullpoint{-\pgfutil@tempdima\advance\pgf@x by-.5\pgfarrowlinewidth}{.5\pgfutil@tempdimb\advance\pgf@y by-.5\pgfarrowlinewidth}% + \fi + }, + drawing code = + { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \pgfpathmoveto + {\pgfqpoint{-\pgfutil@tempdima}{.5\pgfutil@tempdimb}} + \pgfpathcurveto + {\pgfqpoint{-0.81731\pgfutil@tempdima}{.2\pgfutil@tempdimb}} + {\pgfqpoint{-0.41019\pgfutil@tempdima}{0.05833333\pgfutil@tempdimb}} + {\pgfpointorigin} + \ifpgfarrowharpoon + \pgfpathlineto + {\pgfqpoint{\ifpgfarrowreversed.5\else-\fi\pgfarrowlinewidth}{0pt}} + \else + \pgfpathcurveto + {\pgfqpoint{-0.41019\pgfutil@tempdima}{-0.05833333\pgfutil@tempdimb}} + {\pgfqpoint{-0.81731\pgfutil@tempdima}{-.2\pgfutil@tempdimb}} + {\pgfqpoint{-\pgfutil@tempdima}{-.5\pgfutil@tempdimb}} + \fi + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi + \ifpgfarrowharpoon r\fi + \ifpgfarrowroundjoin j\fi% + \ifpgfarrowroundcap c\fi% + }, +}% + + + +% The arrow tip of an \implies arrow, to be used with an inner +% line. Cannot be configured otherwise. + +\pgfdeclarearrow{ + name = Implies, + setup code = { + \pgf@xa\pgfinnerlinewidth + \pgfutil@tempdima.25\pgflinewidth + \advance\pgfutil@tempdima by.25\pgf@xa% + \pgfutil@tempdimb.5\pgflinewidth + \advance\pgfutil@tempdimb by-.5\pgf@xa% + \pgfarrowssettipend{2.06\pgfutil@tempdima\advance\pgf@x by.5\pgfutil@tempdimb} + \pgfarrowssetbackend{-1.36\pgfutil@tempdima\advance\pgf@x by.5\pgfutil@tempdimb} + \pgfarrowsupperhullpoint{-1.4\pgfutil@tempdima}{2.8\pgfutil@tempdima} + \pgfarrowsupperhullpoint{2\pgfutil@tempdima}{.5\pgfutil@tempdimb} + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + }, + drawing code = { + \pgftransformxshift{.06\pgfutil@tempdima} + \pgfsetlinewidth{\pgfutil@tempdimb} + \pgfsetdash{}{+0pt} + \pgfsetroundcap + \pgfsetroundjoin + \pgfpathmoveto{\pgfpoint{-1.4\pgfutil@tempdima}{2.65\pgfutil@tempdima}} + \pgfpathcurveto + {\pgfpoint{-0.75\pgfutil@tempdima}{1.25\pgfutil@tempdima}} + {\pgfpoint{1\pgfutil@tempdima}{0.05\pgfutil@tempdima}} + {\pgfpoint{2\pgfutil@tempdima}{0pt}} + \pgfpathcurveto + {\pgfpoint{1\pgfutil@tempdima}{-0.05\pgfutil@tempdima}} + {\pgfpoint{-.75\pgfutil@tempdima}{-1.25\pgfutil@tempdima}} + {\pgfpoint{-1.4\pgfutil@tempdima}{-2.65\pgfutil@tempdima}} + \pgfusepathqstroke + }, + parameters = {\the\pgfarrowlength} +}% + + + + +% +% +% Geometric arrow tips +% +% + + +% Generic "latex-like" arrow tip. This is the basic arrow tip used in +% latex's picture environment. You can configure its length and width. + +\pgfdeclarearrow{ + name = Latex, + defaults = { + length = +3pt 4.5 .8,% +2.8pt 3 0.8, + width' = +0pt .75, + line width = +0pt 1 1, + }, + setup code = { + % Cap the line width at 1/4th distance from inset to tip + \pgf@x.2\pgfarrowlength + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + \pgfarrowssavethe\pgfarrowlinewidth% + % Compute front miter length: + \pgfmathdivide@{\pgf@sys@tonumber\pgfarrowlength}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x9\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% + \pgf@xa\pgf@temp@quot\pgfarrowlinewidth + % Inner length (pgfutil@tempdima) is now arrowlength - front miter + % - 0.5 linewidth (back thickness) + \pgfutil@tempdima\pgfarrowlength% + \advance\pgfutil@tempdima by-.5\pgf@xc% + \advance\pgfutil@tempdima by-.5\pgfarrowlinewidth% + % harpoon miter correction + \pgfarrowssetbackend{-.5\pgfarrowlinewidth} + \ifpgfarrowreversed + \ifdim\pgfinnerlinewidth>0pt + \pgfarrowssetlineend{0pt} + \else + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by-.5\pgflinewidth} + \fi + \else + \pgfarrowssetlineend{0pt} + \fi + \ifpgfarrowroundjoin + \pgfarrowssettipend{\pgfutil@tempdima\advance\pgf@x by.5\pgfarrowlinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth\ifpgfarrowharpoon\advance\pgf@x by1.5\pgf@xa\fi} + \fi + % The following are needed in the code: + \pgfarrowssavethe\pgfutil@tempdima + % Now, compute back tip miter limit: + \pgf@process{\pgfpointnormalised{\pgfqpoint{.3\pgfarrowlength}{.2333333\pgfarrowwidth}}}% + \advance\pgf@y by1pt% + \pgf@yc\pgf@y\pgf@xc\pgf@x% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@yc}{\pgf@sys@tonumber\pgf@xc}% + \pgfutil@tempdimb\pgfmathresult\pgfarrowlinewidth% + \pgfutil@tempdimb-.5\pgfutil@tempdimb% + \advance\pgfutil@tempdimb by.5\pgfarrowwidth% + \pgfarrowssavethe\pgfutil@tempdimb% + % The hull: + \pgfarrowshullpoint{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth\ifpgfarrowroundjoin\else\ifpgfarrowharpoon\advance\pgf@x by1.5\pgf@xa\fi\fi}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else0pt\fi}% + \pgfarrowshullpoint{-.5\pgfarrowlinewidth}{.5\pgfarrowwidth\ifpgfarrowharpoon\advance\pgf@y by-.5\pgfarrowlinewidth\fi}% + \pgfarrowshullpoint{-.5\pgfarrowlinewidth}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else-.5\pgfarrowwidth\fi}% + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \pgfpathmoveto {\pgfqpoint{\pgfutil@tempdima}{0pt}} + \pgfpathcurveto {\pgfqpoint{.877192\pgfutil@tempdima}{.077922\pgfutil@tempdimb}} + {\pgfqpoint{.337381\pgfutil@tempdima}{.519480\pgfutil@tempdimb}} + {\pgfqpoint{0pt}{\pgfutil@tempdimb}} + \ifpgfarrowharpoon + \pgfpathlineto {\pgfpointorigin} + \else + \pgfpathlineto {\pgfqpoint{0pt}{-\pgfutil@tempdimb}} + \pgfpathcurveto {\pgfqpoint{.337381\pgfutil@tempdima}{-.519480\pgfutil@tempdimb}} + {\pgfqpoint{.877192\pgfutil@tempdima}{-.077922\pgfutil@tempdimb}} + {\pgfqpoint{\pgfutil@tempdima}{0pt}} + \fi + \pgfpathclose + \ifpgfarrowopen\pgfusepathqstroke\else\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi\fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowopen o\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + + + +% A basic stealth-fighter-like pointed arrow + +\pgfdeclarearrow{ + name = Stealth, + defaults = { + length = +3pt 4.5 .8, + width' = +0pt .75, + inset' = +0pt 0.325, + line width = +0pt 1 1, + }, + setup code = { + % Cap the line width at 1/4th distance from inset to tip + \pgf@x\pgfarrowlength + \advance\pgf@x by-\pgfarrowinset + \pgf@x.25\pgf@x + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + % Compute front miter length: + \pgfmathdivide@{\pgf@sys@tonumber\pgfarrowlength}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x4\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% xc is front miter + \pgf@xc.5\pgf@xc + \pgf@xa\pgf@temp@quot\pgfarrowlinewidth% xa is extra harpoon miter + % Compute back miter length: + \pgf@ya.5\pgfarrowwidth% + \csname pgfmathatan2@\endcsname{\pgfmath@tonumber\pgfarrowlength}{\pgfmath@tonumber\pgf@ya}% + \pgf@yb\pgfmathresult pt% + \csname pgfmathatan2@\endcsname{\pgfmath@tonumber\pgfarrowinset}{\pgfmath@tonumber\pgf@ya}% + \pgf@ya\pgfmathresult pt% + \advance\pgf@yb by-\pgf@ya% + \pgf@yb.5\pgf@yb% half angle in yb + \pgfmathtan@{\pgf@sys@tonumber\pgf@yb}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@yc\pgfmathresult\pgfarrowlinewidth% + \pgf@yc.5\pgf@yc% + \advance\pgf@ya by\pgf@yb% + \pgfmathsincos@{\pgf@sys@tonumber\pgf@ya}% + \pgf@ya\pgfmathresulty\pgf@yc% ya is the back miter + \pgf@yb\pgfmathresultx\pgf@yc% yb is the top miter + \ifdim\pgfarrowinset=0pt% + \pgf@ya.5\pgfarrowlinewidth% easy: back miter is half linewidth + \fi + % Compute inset miter length: + \pgfmathdivide@{\pgf@sys@tonumber\pgfarrowinset}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x4\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@yc\pgfmathresult\pgfarrowlinewidth% yc is inset miter + \pgf@yc.5\pgf@yc% + % Inner length (pgfutil@tempdima) is now arrowlength - front miter - back miter + \pgfutil@tempdima\pgfarrowlength% + \advance\pgfutil@tempdima by-\pgf@xc% + \advance\pgfutil@tempdima by-\pgf@ya% + \pgfutil@tempdimb.5\pgfarrowwidth% + \advance\pgfutil@tempdimb by-\pgf@yb% + % harpoon miter correction + \ifpgfarrowroundjoin + \pgfarrowssetbackend{\pgf@ya\advance\pgf@x by-.5\pgfarrowlinewidth} + \else + \pgfarrowssetbackend{0pt} + \fi + \ifpgfarrowharpoon + \pgfarrowssetlineend{\pgfarrowinset\advance\pgf@x + by\pgf@yc\advance\pgf@x by.5\pgfarrowlinewidth} + \else + \pgfarrowssetlineend{\pgfarrowinset\advance\pgf@x by\pgf@yc\advance\pgf@x by-.25\pgfarrowlinewidth} + \ifpgfarrowreversed + \ifdim\pgfinnerlinewidth>0pt + \pgfarrowssetlineend{\pgfarrowinset} + \else + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by\pgf@ya\advance\pgf@x by-.25\pgfarrowlinewidth} + \fi + \fi + \fi + \ifpgfarrowroundjoin + \pgfarrowssettipend{\pgfutil@tempdima\advance\pgf@x by\pgf@ya\advance\pgf@x by.5\pgfarrowlinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi} + \fi + % The hull: + \pgfarrowshullpoint{\pgfarrowlength\ifpgfarrowroundjoin\else\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi\fi}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else0pt\fi}% + \pgfarrowsupperhullpoint{0pt}{.5\pgfarrowwidth}% + \pgfarrowshullpoint{\pgfarrowinset}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else 0pt\fi}% + % Adjust inset + \pgfarrowssetvisualbackend{\pgfarrowinset} + \advance\pgfarrowinset by\pgf@yc% + % The following are needed in the code: + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgf@ya + \pgfarrowssavethe\pgfarrowinset + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdima\advance\pgf@x by\pgf@ya}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgf@ya}{\pgfutil@tempdimb}} + \pgfpathlineto{\pgfqpoint{\pgfarrowinset}{0pt}} + \ifpgfarrowharpoon \else + \pgfpathlineto{\pgfqpoint{\pgf@ya}{-\pgfutil@tempdimb}} + \fi + \pgfpathclose + \ifpgfarrowopen\pgfusepathqstroke\else\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi\fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \the\pgfarrowinset,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowopen o\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + + + +% A Kite is like a Stealth, only the inset counts in the other direction + +\pgfdeclarearrow{ + name = Kite, + defaults = { + length = +3.6pt +5.4, + width' = +0pt +0.5, + inset' = +0pt 0.25, + line width = +0pt 1 1, + }, + setup code = { + % Cap the line width at 1/4th of the length + \pgf@x.4\pgfarrowlength + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + \pgf@x.4\pgfarrowwidth + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + % Compute front miter length: + \pgf@xa\pgfarrowlength% + \advance\pgf@xa by-\pgfarrowinset% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@xa}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x4\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@xc\pgfmathresult\pgfarrowlinewidth% xc is front miter + \pgf@xc.5\pgf@xc + \pgf@xa\pgf@temp@quot\pgfarrowlinewidth% xa is extra harpoon miter + % Compute back miter length: + \pgfmathdivide@{\pgf@sys@tonumber\pgfarrowinset}{\pgf@sys@tonumber\pgfarrowwidth}% + \let\pgf@temp@quot\pgfmathresult% + \pgf@x\pgfmathresult pt% + \pgf@x\pgfmathresult\pgf@x% + \pgf@x4\pgf@x% + \advance\pgf@x by1pt% + \pgfmathsqrt@{\pgf@sys@tonumber\pgf@x}% + \pgf@yc\pgfmathresult\pgfarrowlinewidth% yc is back miter + \pgf@yc.5\pgf@yc + \pgf@ya\pgf@temp@quot\pgfarrowlinewidth% ya is extra harpoon miter + % Compute top miter length: + {% + \pgfutil@tempdimb.5\pgfarrowwidth% + \pgfutil@tempdima\pgfarrowlength\advance\pgfutil@tempdima by-\pgfarrowinset% + \csname pgfmathatan2@\endcsname{\pgfmath@tonumber\pgfutil@tempdima}{\pgfmath@tonumber\pgfutil@tempdimb}% + \pgf@yb\pgfmathresult pt% + \csname pgfmathatan2@\endcsname{\pgfmath@tonumber\pgfarrowinset}{\pgfmath@tonumber\pgfutil@tempdimb}% + \pgf@ya\pgfmathresult pt% + \advance\pgf@yb by\pgf@ya% + \pgf@yb.5\pgf@yb% half angle in yb + \ifdim\pgf@yb=45pt% + \def\pgfmathresult{1.414213}% + \else% + \pgfmathsin@{\pgf@sys@tonumber\pgf@yb}% + \pgfmathreciprocal@{\pgfmathresult}% + \fi% + \pgf@yc\pgfmathresult\pgfarrowlinewidth% + \pgf@yc.5\pgf@yc% + \pgf@ya-\pgf@ya% + \advance\pgf@ya by-90pt% + \advance\pgf@ya by\pgf@yb% + \pgfmathsincos@{\pgf@sys@tonumber\pgf@ya}% + \pgf@xb\pgfmathresultx\pgf@yc% ya is the back miter + \pgf@yb\pgfmathresulty\pgf@yc% yb is the top miter + \expandafter\expandafter\expandafter% + }\expandafter\expandafter\expandafter\pgf@xb\expandafter\the\expandafter\pgf@xb\expandafter\pgf@yb\the\pgf@yb% + % Inner length (pgfutil@tempdima) is now arrowlength - front miter - back miter + \pgfutil@tempdima\pgfarrowlength% + \advance\pgfutil@tempdima by-\pgf@xc% + \pgfutil@tempdimb.5\pgfarrowwidth% + \advance\pgfutil@tempdimb by\pgf@yb% + % Set back end + \ifpgfarrowroundjoin + \pgfarrowssetbackend{\pgf@ya\advance\pgf@x by-.5\pgfarrowlinewidth} + \else + \pgfarrowssetbackend{0pt} + \fi + % harpoon miter correction + \ifpgfarrowreversed + \pgfarrowssetlineend{\pgfutil@tempdima\advance\pgf@x by-\pgflinewidth\advance\pgf@x by\pgfarrowlinewidth} + \else + \pgfarrowssetlineend{\pgf@yc\advance\pgf@x by\pgflinewidth\advance\pgf@x by-\pgfarrowlinewidth} + \fi + \ifpgfarrowroundjoin + \pgfarrowssettipend{\pgfutil@tempdima\advance\pgf@x by.5\pgfarrowlinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi} + \fi + % The hull: + \pgfarrowshullpoint{\pgfarrowlength\ifpgfarrowroundjoin\else\ifpgfarrowharpoon\advance\pgf@x by\pgf@xa\fi\fi}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else0pt\fi}% + \pgfarrowsupperhullpoint{\pgfarrowinset}{.5\pgfarrowwidth}% + \pgfarrowshullpoint{0pt}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else0pt\fi}% + % Adjust the inset: + \advance\pgfarrowinset by\pgf@xb% + % The following are needed in the code: + \pgfarrowssavethe\pgfutil@tempdima + \pgfarrowssavethe\pgfutil@tempdimb + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgf@yc + \pgfarrowssavethe\pgfarrowinset + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{\pgfarrowlinewidth}\fi + \pgfpathmoveto{\pgfqpoint{\pgfutil@tempdima}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgfarrowinset}{\pgfutil@tempdimb}} + \pgfpathlineto{\pgfqpoint{\pgf@yc}{0pt}} + \ifpgfarrowharpoon \else + \pgfpathlineto{\pgfqpoint{\pgfarrowinset}{-\pgfutil@tempdimb}} + \fi + \pgfpathclose + \ifpgfarrowopen\pgfusepathqstroke\else\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi\fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \the\pgfarrowinset,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowopen o\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + + + + +% A simple rectangle shape + +\pgfdeclarearrow{ + name = Square, + defaults = { + length = +2.12132pt +2.828427, + width' = +0pt +1, + line width = +0pt +1 +1, + }, + setup code = { + % Cap the line width at 1/2th of the length + \pgf@x.5\pgfarrowlength + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + \ifpgfarrowreversed + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth} + \else + \pgfarrowssetlineend{.5\pgfarrowlinewidth} + \fi + \pgfarrowssettipend{\pgfarrowlength} + % The hull: + \pgfarrowshullpoint{\pgfarrowlength}{.5\pgfarrowwidth} + \pgfarrowshullpoint{0pt}{.5\pgfarrowwidth} + \pgfarrowshullpoint{\pgfarrowlength}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else-.5\pgfarrowwidth\fi} + \pgfarrowshullpoint{0pt}{\ifpgfarrowharpoon-.5\pgfarrowlinewidth\else-.5\pgfarrowwidth\fi} + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \pgfpathmoveto{\pgfqpoint{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgfarrowlinewidth}{.5\pgfarrowwidth\advance\pgf@y by-.5\pgfarrowlinewidth}} + \pgfpathlineto{\pgfqpoint{.5\pgfarrowlinewidth}{\ifpgfarrowharpoon0pt\else-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth\fi}} + \pgfpathlineto{\pgfqpoint{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth}{\ifpgfarrowharpoon0pt\else-.5\pgfarrowwidth\advance\pgf@y by.5\pgfarrowlinewidth\fi}} + \pgfpathclose + \ifpgfarrowopen\pgfusepathqstroke\else\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi\fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowopen o\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + + +% A simple rectangle shape + +\pgfdeclarearrow{ + name = Circle, + defaults = { + length = +2.39365pt +3.191538, + width' = +0pt 1, + line width = +0pt 1 1, + }, + setup code = { + % Cap the line width at 1/2th of the length + \pgf@x.5\pgfarrowlength + \ifdim\pgf@x<\pgfarrowlinewidth + \pgfarrowlinewidth\pgf@x + \fi + \ifpgfarrowreversed + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by-.5\pgfarrowlinewidth} + \else + \pgfarrowssetlineend{.5\pgfarrowlinewidth} + \fi + \pgfarrowssettipend{\pgfarrowlength} + % The hull: + \pgfarrowsupperhullpoint{\pgfarrowlength}{.25\pgfarrowwidth} + \pgfarrowsupperhullpoint{.75\pgfarrowlength}{.5\pgfarrowwidth} + \pgfarrowsupperhullpoint{.25\pgfarrowlength}{.5\pgfarrowwidth} + \pgfarrowsupperhullpoint{0pt}{.25\pgfarrowwidth} + \ifpgfarrowharpoon% + \pgfarrowshullpoint{0pt}{-.5\pgfarrowlinewidth} + \pgfarrowshullpoint{\pgfarrowlength}{-.5\pgfarrowlinewidth} + \fi% + % The following are needed in the code: + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + \ifpgfarrowharpoon + \pgfpathmoveto{\pgfqpoint{\pgfarrowlength\advance\pgf@x + by-.5\pgfarrowlinewidth}{0pt}} + {% + \pgf@xa.5\pgfarrowlength + \advance\pgf@xa by-.5\pgfarrowlinewidth + \pgftransformxscale{+\the\pgf@xa} + \pgf@xa.5\pgfarrowwidth + \advance\pgf@xa by-.5\pgfarrowlinewidth + \pgftransformyscale{+\the\pgf@xa} + \pgfpatharc{0}{180}{1pt} + } + \pgfpathclose + \else% + \pgfpathellipse{\pgfqpoint{.5\pgfarrowlength}{0pt}}{\pgfqpoint{.5\pgfarrowlength\advance\pgf@x + by-.5\pgfarrowlinewidth}{0pt}}{\pgfqpoint{0pt}{.5\pgfarrowwidth\advance\pgf@y + by-.5\pgfarrowlinewidth}} + \fi + \ifpgfarrowopen\pgfusepathqstroke\else\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi\fi + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowopen o\fi% + \ifpgfarrowroundjoin j\fi% + }, +}% + +% Round cap + +\pgfdeclarearrow{ + name = Round Cap, + defaults = { + length = +0pt .5 + }, + setup code = { + \ifpgfarrowreversed + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by.5\pgflinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetlineend{-.5\pgflinewidth} + \fi + \pgfarrowssavethe\pgfarrowlength + \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth} + \pgfarrowsupperhullpoint{\pgfarrowlength}{.5\pgflinewidth} + }, + drawing code = { + \ifpgfarrowreversed + \pgftransformxscale{-1} + \pgftransformxshift{-\pgfarrowlength} + \fi + \pgfutil@tempdima.5\pgflinewidth + \pgfpathmoveto {\pgfqpoint{-0.75\pgflinewidth}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \ifpgfarrowreversed + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{\pgfutil@tempdima}} + \begingroup + \pgftransformxshift{\pgfarrowlength} + \pgftransformxscale{-1} + \fi + \pgfpathcurveto {\pgfqpoint{0.55228475\pgfarrowlength}{\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{0.55228475\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{0pt}} + \pgfpathcurveto {\pgfqpoint{\pgfarrowlength}{-0.55228475\pgfutil@tempdima}} + {\pgfqpoint{0.55228475\pgfarrowlength}{-\pgfutil@tempdima}} + {\pgfqpoint{0pt}{-\pgfutil@tempdima}} + \ifpgfarrowreversed + \endgroup + \fi + \pgfpathlineto {\pgfqpoint{-.75\pgflinewidth}{-\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfill + }, + parameters = {\the\pgfarrowlength} +}% + + + +\pgfdeclarearrow{ + name = Butt Cap, + defaults = { + length = +0pt .5 + }, + setup code = { + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetlineend{-.5\pgflinewidth} + \pgfarrowssavethe\pgfarrowlength + \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth} + \pgfarrowsupperhullpoint{\pgfarrowlength}{.5\pgflinewidth} + }, + drawing code = { + \pgfutil@tempdima.5\pgflinewidth + \pgfpathmoveto {\pgfqpoint{-0.75\pgflinewidth}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{-\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{-.75\pgflinewidth}{-\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfill + }, + parameters = {\the\pgfarrowlength} +}% + + + +\pgfkeys{ + /pgf/arrow keys/.cd, + cap angle/.code={% + \pgfmathsetlength\pgf@x{#1}% + \pgf@x.5\pgf@x + \pgfmathtan@{\pgf@sys@tonumber\pgf@x}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@x\pgfmathresult pt% + \pgf@x.5\pgf@x% + \edef\pgf@marshal{\noexpand\pgfarrowsaddtooptions{\noexpand\pgfarrowslinewidthdependent{+0pt}{\pgf@sys@tonumber\pgf@x}{0}\pgfarrowlength\pgf@x}} + \pgf@marshal + } +}% + + +\pgfdeclarearrow{ + name = Triangle Cap, + defaults = { + length = +0pt .5 + }, + setup code = { + \ifpgfarrowreversed + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by.5\pgflinewidth} + \else + \pgfarrowssettipend{\pgfarrowlength} + \pgfarrowssetlineend{-.5\pgflinewidth} + \fi + \pgfarrowssavethe\pgfarrowlength + \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth} + \pgfarrowshullpoint{\pgfarrowlength}{0pt} + }, + drawing code = { + \ifpgfarrowreversed + \pgftransformxscale{-1} + \pgftransformxshift{-\pgfarrowlength} + \fi + \pgfutil@tempdima.5\pgflinewidth + \pgfpathmoveto {\pgfqpoint{-0.75\pgflinewidth}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \ifpgfarrowreversed + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{\pgfutil@tempdima}} + \begingroup + \pgftransformxshift{\pgfarrowlength} + \pgftransformxscale{-1} + \fi + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{0pt}} + \ifpgfarrowreversed + \endgroup + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{-\pgfutil@tempdima}} + \fi + \pgfpathlineto {\pgfqpoint{0pt}{-\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{-.75\pgflinewidth}{-\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfill + }, + parameters = {\the\pgfarrowlength} +}% + + + +\pgfdeclarearrow{ + name = Fast Triangle, + defaults = { + length = +0pt .5, + inset = +0pt .5, + }, + setup code = { + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by\pgfarrowinset} + \ifpgfarrowreversed\pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by\pgfarrowinset}\fi + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowinset + \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth} + \pgfarrowsupperhullpoint{\pgfarrowinset}{.5\pgflinewidth} + \pgfarrowshullpoint{\pgfarrowlength\advance\pgf@x by\pgfarrowinset}{0pt} + }, + drawing code = { + \pgfutil@tempdima.5\pgflinewidth + \pgfpathmoveto {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowinset}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowinset\advance\pgf@x by\pgfarrowlength}{0pt}} + \pgfpathlineto {\pgfqpoint{\pgfarrowinset}{-\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{0pt}{-\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowlength}{0pt}} + \pgfpathclose + \pgfusepathqfill + }, + parameters = {\the\pgfarrowlength,\the\pgfarrowinset} +}% + + +\pgfdeclarearrow{ + name = Fast Round, + defaults = { + length = +0pt .5, + inset = +0pt .5, + }, + setup code = { + \pgfarrowssettipend{\pgfarrowlength\advance\pgf@x by\pgfarrowinset} + \ifpgfarrowreversed\pgfarrowssetlineend{\pgfarrowlength\advance\pgf@x by\pgfarrowinset}\fi + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowinset + \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth} + \pgfarrowsupperhullpoint{\pgfarrowlength\advance\pgf@x by\pgfarrowinset}{.5\pgflinewidth} + }, + drawing code = { + \pgfutil@tempdima.5\pgflinewidth + \pgfpathmoveto {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \pgfpathlineto {\pgfqpoint{\pgfarrowinset}{\pgfutil@tempdima}} + { + \pgftransformxshift{\pgfarrowinset} + \pgfpathcurveto{\pgfqpoint{0.55228475\pgfarrowlength}{\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{0.55228475\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{0pt}} + \pgfpathcurveto{\pgfqpoint{\pgfarrowlength}{-0.55228475\pgfutil@tempdima}} + {\pgfqpoint{0.55228475\pgfarrowlength}{-\pgfutil@tempdima}} + {\pgfqpoint{0pt}{-\pgfutil@tempdima}} + } + \pgfpathlineto {\pgfqpoint{0pt}{-\pgfutil@tempdima}} + \pgfpathcurveto {\pgfqpoint{0.55228475\pgfarrowlength}{-\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{-0.55228475\pgfutil@tempdima}} + {\pgfqpoint{\pgfarrowlength}{0pt}} + \pgfpathcurveto {\pgfqpoint{\pgfarrowlength}{0.55228475\pgfutil@tempdima}} + {\pgfqpoint{0.55228475\pgfarrowlength}{\pgfutil@tempdima}} + {\pgfqpoint{0pt}{\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfill + }, + parameters = {\the\pgfarrowlength,\the\pgfarrowinset} +}% + + + + +% +% +% Other arrow tips. +% +% + + +\pgfkeys{ + /pgf/arrow keys/.cd, + n/.code={% + \pgfmathparse{#1}% + \expandafter\pgf@lib@meta@strip@dot\pgfmathresult.\relax% + } +}% +\def\pgf@lib@meta@strip@dot#1.#2\relax{% + \pgfarrowsaddtooptions{\def\pgfarrown{#1}}% +}% + +\def\pgfarrown{4}% + +\pgfdeclarearrow{ + name = Rays, + defaults = { + length = +3pt 4, + width' = +0pt 1, + line width = +0pt 1 1, + }, + setup code = { + \pgfmathdivide@{360}{\pgfarrown}% + \let\pgfarrow@inc\pgfmathresult% + % Compute tips: + \pgf@xa\pgfarrow@inc pt% + \ifodd\pgfarrown\pgf@ya.25\pgf@xa\else\pgf@ya.5\pgf@xa\fi% + \pgfmathsincos@{\pgf@sys@tonumber\pgf@ya}% + \pgf@x.5\pgfarrowlength% + \pgf@xa\pgfmathresultx\pgf@x% + \ifpgfarrowroundcap + \advance\pgf@xa by.5\pgfarrowlinewidth + \else + \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgfmathresultx\pgfarrowlength}{\pgfmathresulty\pgfarrowwidth}}}% + \pgf@x.5\pgfarrowlinewidth% + \advance\pgf@xa by\pgf@sys@tonumber{\pgf@y}\pgf@x% + \fi% + \pgfarrowssettipend{\pgf@xa} + \pgfarrowssetbackend{-\pgf@xa} + % Hull is always 8-point hull, except for tip + % The following are needed in the code: + \pgfarrowsupperhullpoint{\pgf@xa}{.25\pgfarrowwidth} + \pgfarrowsupperhullpoint{.25\pgfarrowlength}{.5\pgfarrowwidth\ifpgfarrowroundcap\advance\pgf@y by.5\pgfarrowlinewidth\fi} + \pgfarrowsupperhullpoint{-.25\pgfarrowlength}{.5\pgfarrowwidth\ifpgfarrowroundcap\advance\pgf@y by.5\pgfarrowlinewidth\fi} + \pgfarrowsupperhullpoint{-\pgf@xa}{.25\pgfarrowwidth} + \ifpgfarrowharpoon + \pgfarrowshullpoint{-.5\pgfarrowlength\ifpgfarrowroundcap\advance\pgf@x by-.5\pgfarrowlinewidth\fi}{-.5\pgfarrowlinewidth} + \pgfarrowshullpoint{.5\pgfarrowlength\ifpgfarrowroundcap\advance\pgf@x by.5\pgfarrowlinewidth\fi}{-.5\pgfarrowlinewidth} + \fi + \pgfarrowssavethe\pgfarrowlinewidth + \pgfarrowssavethe\pgfarrowlength + \pgfarrowssavethe\pgfarrowwidth + \pgfarrowssave\pgfarrow@inc + \pgfarrowssave\pgfarrown + }, + drawing code = { + \pgfsetdash{}{+0pt} + \ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi + \ifdim\pgfarrowlinewidth=\pgflinewidth\else\pgfsetlinewidth{+\pgfarrowlinewidth}\fi + {% + \pgfgettransform\pgf@temp@trans + \pgftransformxscale{+.5\pgfarrowlength} + \pgftransformyscale{+.5\pgfarrowwidth} + \pgf@xa\pgfarrow@inc pt% + \ifodd\pgfarrown\pgf@ya.25\pgf@xa\else\pgf@ya.5\pgf@xa\fi% + \ifpgfarrowharpoon\pgf@yb180pt\else\pgf@yb360pt\fi + \pgfutil@loop% + \ifdim\pgf@ya<\pgf@yb% + \pgfpathmoveto{\pgfpointpolar{+\pgf@ya}{+1pt}} + \pgfpathlineto{\pgfpointorigin} + \ifpgfarrowharpoon\ifdim\pgf@ya>\pgf@xa\else{\pgfsettransform\pgf@temp@trans\pgfpathlineto{\pgfqpoint{-.5\pgflinewidth}{0pt}}}\fi\fi + \advance\pgf@ya by\pgf@xa\relax% + \pgfutil@repeat% + } + \pgfusepathqstroke + }, + parameters = { + \the\pgfarrowlinewidth,% + \the\pgfarrowlength,% + \the\pgfarrowwidth,% + \pgfarrown,% + \ifpgfarrowharpoon h\fi% + \ifpgfarrowroundcap c\fi% + } +}% + + + +% Shorthands and Aliases: + +\pgfkeys{ + LaTeX /.tip = {Latex}, + Triangle /.tip = {Stealth[inset=+0pt, angle=+60:+2.7pt +3.6]}, + Rectangle /.tip = {Square[length=+3pt +4.5,width'=+0pt +.5]}, + Ellipse /.tip = {Circle[length=+3.3pt +4.95, width'=+0pt +0.5]}, + Diamond /.tip = {Kite[inset'=+0pt .5]}, + Turned Square /.tip = {Kite[length=+3pt 4,width'= +0pt 1,inset'= +0pt 0.5]}, + To /.tip = {Computer Modern Rightarrow}, + Bar /.tip = {Tee Barb[length=+0pt]}, + Bracket /.tip = {Tee Barb[inset'=+0pt +1,length=+0.75pt +1]}, + Parenthesis /.tip = {Arc Barb[arc=+120,length=+1.725pt +2.3]} +}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.spaced.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.spaced.code.tex new file mode 100644 index 0000000000..f125afddca --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryarrows.spaced.code.tex @@ -0,0 +1,92 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryarrows.spaced.code.tex} + + +\usepgflibrary{arrows}% + + +% This library offers "spaced" versions of existing arrows, where a +% bit of additional space is inserted at the tip. This often looks +% better than the normal arrow. +% +% These arrows are called "spaced whatever" where "whatever" is the +% original name of the arrow. + + +\pgfarrowsdeclarecombine*{spaced to}{spaced to}{to}{to}{space}{space}% +\pgfarrowsdeclarecombine*{spaced to reversed}{spaced to reversed}{to reversed}{to reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced implies}{spaced implies}{implies}{implies}{space}{space}% +\pgfarrowsdeclarecombine*{spaced latex}{spaced latex}{latex}{latex}{space}{space}% +\pgfarrowsdeclarecombine*{spaced latex reversed}{spaced latex reversed}{latex reversed}{latex reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced latex'}{spaced latex'}{latex'}{latex'}{space}{space}% +\pgfarrowsdeclarecombine*{spaced latex' reversed}{spaced latex' reversed}{latex' reversed}{latex' reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced stealth}{spaced stealth}{stealth}{stealth}{space}{space}% +\pgfarrowsdeclarecombine*{spaced stealth reversed}{spaced stealth reversed}{stealth reversed}{stealth reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced stealth'}{spaced stealth'}{stealth'}{stealth'}{space}{space}% +\pgfarrowsdeclarecombine*{spaced stealth' reversed}{spaced stealth' reversed}{stealth' reversed}{stealth' reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 90}{spaced triangle 90}{triangle 90}{triangle 90}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 90 reversed}{spaced triangle 90 reversed}{triangle 90 reversed}{triangle 90 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 60}{spaced triangle 60}{triangle 60}{triangle 60}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 60 reversed}{spaced triangle 60 reversed}{triangle 60 reversed}{triangle 60 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 45}{spaced triangle 45}{triangle 45}{triangle 45}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 45 reversed}{spaced triangle 45 reversed}{triangle 45 reversed}{triangle 45 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 90}{spaced open triangle 90}{open triangle 90}{open triangle 90}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 90 reversed}{spaced open triangle 90 reversed}{open triangle 90 reversed}{open triangle 90 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 60}{spaced open triangle 60}{open triangle 60}{open triangle 60}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 60 reversed}{spaced open triangle 60 reversed}{open triangle 60 reversed}{open triangle 60 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 45}{spaced open triangle 45}{open triangle 45}{open triangle 45}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open triangle 45 reversed}{spaced open triangle 45 reversed}{open triangle 45 reversed}{open triangle 45 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 90}{spaced angle 90}{angle 90}{angle 90}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 90 reversed}{spaced angle 90 reversed}{angle 90 reversed}{angle 90 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 60}{spaced angle 60}{angle 60}{angle 60}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 60 reversed}{spaced angle 60 reversed}{angle 60 reversed}{angle 60 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 45}{spaced angle 45}{angle 45}{angle 45}{space}{space}% +\pgfarrowsdeclarecombine*{spaced angle 45 reversed}{spaced angle 45 reversed}{angle 45 reversed}{angle 45 reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced hooks}{spaced hooks}{hooks}{hooks}{space}{space}% +\pgfarrowsdeclarecombine*{spaced hooks reversed}{spaced hooks reversed}{hooks reversed}{hooks reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced o}{spaced o}{o}{o}{space}{space}% +\pgfarrowsdeclarecombine*{spaced *}{spaced *}{*}{*}{space}{space}% +\pgfarrowsdeclarecombine*{spaced diamond}{spaced diamond}{diamond}{diamond}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open diamond}{spaced open diamond}{open diamond}{open diamond}{space}{space}% +\pgfarrowsdeclarecombine*{spaced square}{spaced square}{square}{square}{space}{space}% +\pgfarrowsdeclarecombine*{spaced open square}{spaced open square}{open square}{open square}{space}{space}% +\pgfarrowsdeclarecombine*{spaced serif cm}{spaced serif cm}{serif cm}{serif cm}{space}{space}% +\pgfarrowsdeclarecombine*{spaced left to}{spaced left to}{left to}{left to}{space}{space}% +\pgfarrowsdeclarecombine*{spaced left to reversed}{spaced left to reversed}{left to reversed}{left to reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced right to}{spaced right to}{right to}{right to}{space}{space}% +\pgfarrowsdeclarecombine*{spaced right to reversed}{spaced right to reversed}{right to reversed}{right to reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced left hook}{spaced left hook}{left hook}{left hook}{space}{space}% +\pgfarrowsdeclarecombine*{spaced left hook reversed}{spaced left hook reversed}{left hook reversed}{left hook reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced right hook}{spaced right hook}{right hook}{right hook}{space}{space}% +\pgfarrowsdeclarecombine*{spaced right hook reversed}{spaced right hook reversed}{right hook reversed}{right hook reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced round cap}{spaced round cap}{round cap}{round cap}{space}{space}% +\pgfarrowsdeclarecombine*{spaced butt cap}{spaced butt cap}{butt cap}{butt cap}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 90 cap}{spaced triangle 90 cap}{triangle 90 cap}{triangle 90 cap}{space}{space}% +\pgfarrowsdeclarecombine*{spaced triangle 90 cap reversed}{spaced triangle 90 cap reversed}{triangle 90 cap reversed}{triangle 90 cap reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced fast cap}{spaced fast cap}{fast cap}{fast cap}{space}{space}% +\pgfarrowsdeclarecombine*{spaced fast cap reversed}{spaced fast cap reversed}{fast cap reversed}{fast cap reversed}{space}{space}% +\pgfarrowsdeclarecombine*{spaced (}{spaced )}{(}{)}{space}{space}% +\pgfarrowsdeclarecombine*{spaced )}{spaced (}{)}{(}{space}{space}% +\pgfarrowsdeclarecombine*{spaced |}{spaced |}{|}{|}{space}{space}% + +\pgfdeclarearrow{ + name = spaced [-spaced ], + means = square bracket[].space +}% + +\pgfdeclarearrow{ + name = spaced ]-spaced [, + means = square bracket[reversed].space +}% + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarycurvilinear.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarycurvilinear.code.tex new file mode 100644 index 0000000000..12f26ccbdf --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarycurvilinear.code.tex @@ -0,0 +1,379 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarycurvilinear.code.tex} + +% +% This file defines commands for computing points in curvilinear +% coordinate systems. +% + + +% +% Curvilinear coordinate systems defined in terms of a Bezier curve. +% +% For the following coordinate systems, you must first provide a +% Bezier curve (using, as always, four points), which will be set for +% the current scope. When the curve is "installed" some expensive +% precomputations are done; subsequent calls to +% \pgfpointcurvilinearxxx based on this Bezier curve will be +% relatively quick. +% + + + +% Install a Bezier curve +% +% #1 = start point +% #2 = first control point +% #3 = second control point +% #4 = end point +% +% Description: +% +% Subsequent calls to functions like +% \pgfpointcurvilinearbezierorthogonal will be relative to the curve +% installed using this command. The main job of this macro is a +% precomputation for computing length along the curve. +% All lengths along the Bezier curve are approximated using a lookup table +% of four time/length points. For this, an approximate time for length +% 1pt is computed first, and then the length for twice this time, four +% times this time, and eight times this time are approximated. A +% distance-to-time conversion is then done by a linear interpolation +% of distance-to-time for these four points. Note that all of these +% computations are not particularly precise, but a compromise trading +% speed against precision. Also note that the results will only be +% best near the start of the curve and may be far off near the end if +% that end is degenerate (second control point very near to end +% point). +% +% Example: +% +% \pgfsetcurvilinearbeziercurve +% {\pgfpoint{0mm}{10mm}} +% {\pgfpoint{5.5mm}{10mm}} +% {\pgfpoint{10mm}{5.5mm}} +% {\pgfpoint{10mm}{0mm}} % nearly a quarter circle +% \pgfpointcurvilinearbezierorthogonal{5mm}{5mm} +% % should be 5mm along the circle, put at +% % distance 15mm from the origin (5mm from the circle line). + +\def\pgfsetcurvilinearbeziercurve#1#2#3#4{% + \pgf@process{#1}% + \edef\pgf@curvilinear@line@a{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgf@xa=-\pgf@x% + \pgf@ya=-\pgf@y% + \pgf@process{#2}% + \edef\pgf@curvilinear@line@b{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgf@xb=-\pgf@x% + \pgf@yb=-\pgf@y% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@lenab\pgfmathresult% + \pgf@process{#3}% + \edef\pgf@curvilinear@line@c{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgf@xc=-\pgf@x% + \pgf@yc=-\pgf@y% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@lenbc\pgfmathresult% + \pgf@process{#4}% + \edef\pgf@curvilinear@line@d{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@lencd\pgfmathresult + % + \pgf@x=\pgf@curvilinear@lenab pt% + \advance\pgf@x by\pgf@curvilinear@lenbc pt% + \advance\pgf@x by\pgf@curvilinear@lencd pt% + \pgfmathreciprocal@{\pgf@sys@tonumber\pgf@x}% + \pgf@curvilinear@time@a\pgfmathresult pt% + \pgf@process{\pgfpointcurveattime{\pgf@curvilinear@time@a}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}}% + \pgf@xb=-\pgf@x% + \pgf@yb=-\pgf@y% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgf@curvilinear@length@a\pgfmathresult pt% + \ifdim\pgf@curvilinear@length@a>1pt\relax% + % Ok, too large, let us make this smaller + \pgfmathdivide@{\pgf@sys@tonumber\pgf@curvilinear@time@a}{\pgf@sys@tonumber\pgf@curvilinear@length@a}% + \pgf@curvilinear@time@a\pgfmathresult pt% + \pgf@process{\pgfpointcurveattime{\pgf@curvilinear@time@a}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}} + \pgf@xb=-\pgf@x% + \pgf@yb=-\pgf@y% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgf@curvilinear@length@a\pgfmathresult pt% + \fi% + % Compute three positions: + \pgf@process{\pgfpointcurveattime{2\pgf@curvilinear@time@a}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}} + \pgf@xa=-\pgf@x% + \pgf@ya=-\pgf@y% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgf@curvilinear@length@b\pgfmathresult pt% + \advance\pgf@curvilinear@length@b by\pgf@curvilinear@length@a% + \pgf@process{\pgfpointcurveattime{4\pgf@curvilinear@time@a}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}} + \pgf@xb=-\pgf@x% + \pgf@yb=-\pgf@y% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgf@curvilinear@length@c\pgfmathresult pt% + \advance\pgf@curvilinear@length@c by\pgf@curvilinear@length@b% + \pgf@process{\pgfpointcurveattime{8\pgf@curvilinear@time@a}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}} + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + \pgf@curvilinear@length@d\pgfmathresult pt% + \advance\pgf@curvilinear@length@d by\pgf@curvilinear@length@c% + \let\pgf@curvilinear@comp@a\pgf@curvilinear@comp@a@initial% + \let\pgf@curvilinear@comp@b\pgf@curvilinear@comp@b@initial% + \let\pgf@curvilinear@comp@c\pgf@curvilinear@comp@c@initial% + \let\pgf@curvilinear@comp@d\pgf@curvilinear@comp@d@initial% + \let\pgf@curvilinear@comp@e\pgf@curvilinear@comp@e@initial% + \let\pgf@curvilinear@point\pgf@curvilinear@curve@point% +}% +\newdimen\pgf@curvilinear@time@a +\newdimen\pgf@curvilinear@length@a +\newdimen\pgf@curvilinear@length@b +\newdimen\pgf@curvilinear@length@c +\newdimen\pgf@curvilinear@length@d + + +\def\pgf@curvilinear@comp@a@initial{% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@curvilinear@time@a}{\pgf@sys@tonumber\pgf@curvilinear@length@a}% + \let\pgf@curvilinear@quot@a\pgfmathresult% + \let\pgf@curvilinear@comp@a\pgf@curvilinear@comp@a@cont% + \pgf@curvilinear@comp@a@cont% +}% +\def\pgf@curvilinear@comp@a@cont{% + \pgf@x\pgf@curvilinear@quot@a\pgf@x% +}% + +\def\pgf@curvilinear@comp@b@initial{% + \pgf@y=\pgf@curvilinear@length@b% + \advance\pgf@y by-\pgf@curvilinear@length@a% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@curvilinear@time@a}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@quot@b\pgfmathresult% + \pgf@y\pgfmathresult\pgf@curvilinear@length@a% + \pgf@y-\pgf@y% + \advance\pgf@y by\pgf@curvilinear@time@a% + \edef\pgf@curvilinear@correct@b{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@comp@b\pgf@curvilinear@comp@b@cont% + \pgf@curvilinear@comp@b@cont% +}% +\def\pgf@curvilinear@comp@b@cont{% + \pgf@x\pgf@curvilinear@quot@b\pgf@x% + \advance\pgf@x by\pgf@curvilinear@correct@b pt% +}% + +\def\pgf@curvilinear@comp@c@initial{% + \pgf@y=\pgf@curvilinear@length@c% + \advance\pgf@y by-\pgf@curvilinear@length@b% + \pgf@y.5\pgf@y% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@curvilinear@time@a}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@quot@c\pgfmathresult% + \pgf@y\pgf@curvilinear@quot@c\pgf@curvilinear@length@b% + \pgf@y-\pgf@y% + \advance\pgf@y by2\pgf@curvilinear@time@a% + \edef\pgf@curvilinear@correct@c{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@comp@c\pgf@curvilinear@comp@c@cont% + \pgf@curvilinear@comp@c@cont% +}% +\def\pgf@curvilinear@comp@c@cont{% + \pgf@x\pgf@curvilinear@quot@c\pgf@x% + \advance\pgf@x by\pgf@curvilinear@correct@c pt% +}% + +\def\pgf@curvilinear@comp@d@initial{% + \pgf@y=\pgf@curvilinear@length@d% + \advance\pgf@y by-\pgf@curvilinear@length@c% + \pgf@y.25\pgf@y% + \pgfmathdivide@{\pgf@sys@tonumber\pgf@curvilinear@time@a}{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@quot@d\pgfmathresult% + \pgf@y\pgf@curvilinear@quot@d\pgf@curvilinear@length@c% + \pgf@y-\pgf@y% + \advance\pgf@y by4\pgf@curvilinear@time@a% + \edef\pgf@curvilinear@correct@d{\pgf@sys@tonumber\pgf@y}% + \let\pgf@curvilinear@comp@d\pgf@curvilinear@comp@d@cont% + \pgf@curvilinear@comp@d@cont% +}% +\def\pgf@curvilinear@comp@d@cont{% + \pgf@x\pgf@curvilinear@quot@d\pgf@x% + \advance\pgf@x by\pgf@curvilinear@correct@d pt% +}% + +\def\pgf@curvilinear@comp@e@initial{% + \pgfmathmultiply@{8}{\pgf@sys@tonumber\pgf@curvilinear@time@a}% + \expandafter\pgfmathdivide@\expandafter{\pgfmathresult}{\pgf@sys@tonumber\pgf@curvilinear@length@d}% + \let\pgf@curvilinear@quot@e\pgfmathresult% + \let\pgf@curvilinear@comp@e\pgf@curvilinear@comp@e@cont% + \pgf@curvilinear@comp@e@cont% +}% +\def\pgf@curvilinear@comp@e@cont{% + \pgf@x\pgf@curvilinear@quot@e\pgf@x% +}% + + +% Convert a distance into a time +% +% #1 = a distance +% +% Description: +% +% After having called \pgfsetcurvilinearbeziercurve, you can use this +% macro to convert a distance into a time along the curve set in that +% command. The result will be stored in \pgf@x. It will only be +% reasonably precise for small nonnegative #1 (in particular, #1 +% should not be more than about half the length of the curve). + +\def\pgfcurvilineardistancetotime#1{% + \pgfmathsetlength{\pgf@x}{#1}% + \ifdim\pgf@x<\pgf@curvilinear@length@c\relax% + \ifdim\pgf@x<\pgf@curvilinear@length@a\relax% + \pgf@curvilinear@comp@a% + \else\ifdim\pgf@x<\pgf@curvilinear@length@b\relax% + \pgf@curvilinear@comp@b% + \else% + \pgf@curvilinear@comp@c% + \fi\fi% + \else\ifdim\pgf@x<\pgf@curvilinear@length@d\relax% + \pgf@curvilinear@comp@d% + \else% + \pgf@curvilinear@comp@e% + \fi\fi% +}% + + + +% Compute a "Bezier-orthogonal" point for use in a nonlinear transformation. +% +% #1 = x +% #2 = y +% +% Description: +% +% In this coordinate system, the x-axis "goes along" the Bezier curve +% installed using \pgfsetcurvilinearbeziercurve +% and the y-axis is always perpendicular to the (Bezier) curve at the +% given x-coordinate. Formally, given a pair (x,y), let B(x) be the point on +% the Bezier curve B at distance x from the start of the curve. Let +% T(x) be the tangent of B at B(x) and let P(x) be the (normalized) +% vector perpendicular to T(x). Then (x,y) would be mapped to B(x) + +% y*P(x). As an example, if B is a circle, then the corresponding +% curvilinear coordinate system is (essentially, except for an offset in +% the y value) the polar coordinate system. +% +% In addition to setting \pgf@x and \pgf@y, \pgf@xa/ya will be set to +% a tangent along the curve at the given point and \pgf@xb/yb to a +% tangent orthogonal to the curve. + +\def\pgfpointcurvilinearbezierorthogonal#1#2{% + \pgfmathsetmacro\pgf@curvilinear@yfactor{#2}% + \pgfcurvilineardistancetotime{#1}% + \pgfpointcurveattime{\pgf@x}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d} + \pgf@xc\pgf@x% save + \pgf@yc\pgf@y% save + % compute normal: + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \ifdim\pgf@xb<0.0001pt\ifdim\pgf@xb>-0.0001pt\ifdim\pgf@yb<0.0001pt\ifdim\pgf@yb>-0.0001pt\pgf@diff@curvi@ac\fi\fi\fi\fi + \pgf@process{\pgfpointnormalised{\pgf@x=\pgf@yb\pgf@y=-\pgf@xb}} + \pgf@x\pgf@curvilinear@yfactor\pgf@x% + \pgf@y\pgf@curvilinear@yfactor\pgf@y% + \advance\pgf@x by\pgf@xc% + \advance\pgf@y by\pgf@yc% +}% + +\def\pgf@diff@curvi@ac{% + \pgf@curvilinear@line@a% + \pgf@xa\pgf@x\pgf@ya\pgf@y% + \pgf@curvilinear@line@c% + \pgf@xb\pgf@x\pgf@yb\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \ifdim\pgf@xb<0.0001pt\ifdim\pgf@xb>-0.0001pt\ifdim\pgf@yb<0.0001pt\ifdim\pgf@yb>-0.0001pt% still degenerate! + \pgf@curvilinear@line@d% + \pgf@xb\pgf@x\pgf@yb\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \fi\fi\fi\fi% + \pgf@xb-\pgf@xb% + \pgf@yb-\pgf@yb% +}% + + + +% Compute a "Bezier-polar" point. +% +% #1 = x +% #2 = y +% +% Description: +% +% Let (r:d) be the point (x,y) in polar coordinates, that is, r is the +% angle and d the distance of (x,y) to the origin. The point returned +% by \pgfpointcurvilinearbezierpolar is now defined as follows: First, +% we compute that point at distance d along the Bezier curve B. Let +% B(d) be this point. Then, we rotate this point around the start of +% the curve (B(0)) by r degrees. +% +% As an example, consider a triangle with one tip at the origin and +% the other tips as (4cm,3cm) and (4cm,-3cm). Then this triangle would be +% transformed as follows: We take the first 5cm of the Bezier curve +% and rotate it by roughly 37 degrees to the left and by 37 degrees to +% the right. +% +% Note that this command is pretty expensive. + +\def\pgfpointcurvilinearbezierpolar#1#2{% + \pgfmathsetlength\pgfutil@tempdima{#1}% + \pgfmathsetlength\pgfutil@tempdimb{#2}% + % Compute angle: + \pgfpointnormalised{\pgfqpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}% + \ifdim\pgfutil@tempdimb=0pt\relax\ifdim\pgfutil@tempdima=0pt\pgf@x1pt\pgf@y0pt\fi\fi% + \ifdim\pgfutil@tempdima<0pt% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + \fi% + \pgf@ya=-\pgf@y% + \pgfsettransformentries% + {\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% + {\pgf@sys@tonumber\pgf@ya}{\pgf@sys@tonumber\pgf@x}{0pt}{0pt}% + \pgftransformshift{\pgfpointscale{-1}{\pgf@curvilinear@line@a}}% + \pgfmathveclen@{\pgf@sys@tonumber\pgfutil@tempdima}{\pgf@sys@tonumber\pgfutil@tempdimb}% + \ifdim\pgfutil@tempdima<0pt% + \edef\pgfmathresult{-\pgfmathresult}% + \fi% + \pgfcurvilineardistancetotime{\pgfmathresult}% + % Now, transform: + \pgf@process{% + \pgfpointadd{% + \pgfpointtransformed{% + \pgfpointcurveattime% + {\pgf@x}% + {\pgf@curvilinear@line@a}% + {\pgf@curvilinear@line@b}% + {\pgf@curvilinear@line@c}% + {\pgf@curvilinear@line@d}% + }% + }% + \pgf@curvilinear@line@a% + }% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryfadings.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryfadings.code.tex new file mode 100644 index 0000000000..c8ce556b40 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryfadings.code.tex @@ -0,0 +1,57 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryfadings.code.tex} + + +% Axial fadings + +\pgfdeclarehorizontalshading{pgf@lib@fade@east}{100bp} +{color(0bp)=(pgftransparent!0); color(25bp)=(pgftransparent!0); + color(75bp)=(pgftransparent!100); color(100bp)=(pgftransparent!100)}% + +\pgfdeclarehorizontalshading{pgf@lib@fade@west}{100bp} +{color(0bp)=(pgftransparent!100); color(25bp)=(pgftransparent!100); + color(75bp)=(pgftransparent!0); color(100bp)=(pgftransparent!0)}% + +\pgfdeclareverticalshading{pgf@lib@fade@north}{100bp} +{color(0bp)=(pgftransparent!0); color(25bp)=(pgftransparent!0); + color(75bp)=(pgftransparent!100); color(100bp)=(pgftransparent!100)}% + +\pgfdeclareverticalshading{pgf@lib@fade@south}{100bp} +{color(0bp)=(pgftransparent!100); color(25bp)=(pgftransparent!100); + color(75bp)=(pgftransparent!0); color(100bp)=(pgftransparent!0)}% + +\pgfdeclarefading{east}{\pgfuseshading{pgf@lib@fade@east}}% +\pgfdeclarefading{west}{\pgfuseshading{pgf@lib@fade@west}}% +\pgfdeclarefading{north}{\pgfuseshading{pgf@lib@fade@north}}% +\pgfdeclarefading{south}{\pgfuseshading{pgf@lib@fade@south}}% + + +% Circular fadings + +\pgfdeclareradialshading{tikz@lib@fade@circle@10}{\pgfpointorigin}{ + color(0pt)=(pgftransparent!0); color(22.5bp)=(pgftransparent!0); + color(25bp)=(pgftransparent!100); color(50bp)=(pgftransparent!100)}% +\pgfdeclarefading{circle with fuzzy edge 10 percent}{\pgfuseshading{tikz@lib@fade@circle@10}}% + +\pgfdeclareradialshading{tikz@lib@fade@circle@15}{\pgfpointorigin}{ + color(0pt)=(pgftransparent!0); color(21.25bp)=(pgftransparent!0); + color(25bp)=(pgftransparent!100); color(50bp)=(pgftransparent!100)}% +\pgfdeclarefading{circle with fuzzy edge 15 percent}{\pgfuseshading{tikz@lib@fade@circle@15}}% + +\pgfdeclareradialshading{tikz@lib@fade@circle@20}{\pgfpointorigin}{ + color(0pt)=(pgftransparent!0); color(20bp)=(pgftransparent!0); + color(25bp)=(pgftransparent!100); color(50bp)=(pgftransparent!100)}% +\pgfdeclarefading{circle with fuzzy edge 20 percent}{\pgfuseshading{tikz@lib@fade@circle@20}}% + +\pgfdeclareradialshading{tikz@lib@fade@fuzzy@15}{\pgfpointorigin}{ + color(0pt)=(pgftransparent!100); color(21.25bp)=(pgftransparent!100); color(23.125bp)=(pgftransparent!0); + color(25bp)=(pgftransparent!100); color(50bp)=(pgftransparent!100)}% +\pgfdeclarefading{fuzzy ring 15 percent}{\pgfuseshading{tikz@lib@fade@fuzzy@15}}% diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryfixedpointarithmetic.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryfixedpointarithmetic.code.tex new file mode 100644 index 0000000000..b10c7b795c --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryfixedpointarithmetic.code.tex @@ -0,0 +1,656 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Free Documentation License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + +\pgfkeys{/pgf/.cd, + fixed point arithmetic/.code={% + \pgfmathfp@plots@install% + \pgfmathfp@parser@install% + \let\pgfmathparse=\pgfmathfpparse% + \pgfkeys{/pgf/fixed point/.cd, #1}% + },% + fixed point/.cd, + scale results/.code={% + \pgfmathfpparse{#1}% + \let\pgfmathfpscale=\pgfmathresult% + }% +}% + +\def\pgfmathfpscale{1}% + +\def\pgfmathfpparse{% + \begingroup% + \let\pgfmathpostparse=\relax% + \pgfmath@catcodes% + \pgfmath@quickparsefalse% + \pgfmathfpparse@}% + +\def\pgfmathfpparse@#1{% + \edef\pgfmathfp@expression{#1}% + \expandafter\pgfmathfpparse@@\pgfmathfp@expression\pgfmathfp@}% + +\def\pgfmathfp@char@asterisk{*}% +\def\pgfmathfpparse@@#1#2\pgfmathfp@{% + \def\pgfmathfp@test{#1}% + \ifx\pgfmathfp@test\pgfmathfp@char@asterisk% + \edef\pgfmathfp@expression{\pgfmathfpscale#1#2}% + \else% + \edef\pgfmathfp@expression{#1#2}% + \fi% + \expandafter\pgfmathparse@\expandafter{\pgfmathfp@expression}% + % \endgroup provided by \pgfpathmarse@end +}% + +% Crude handling of file plots +% +\pgfkeys{/pgf/fixed point/.cd, + scale file plot x/.code=\pgfmathfpparse{#1}\edef\pgfmathfpplotscalex{\pgfmathresult*}, + scale file plot y/.code=\pgfmathfpparse{#1}\edef\pgfmathfpplotscaley{\pgfmathresult*}, + scale file plot z/.code=\pgfmathfpparse{#1}\edef\pgfmathfpplotscalez{\pgfmathresult*}, +}% + +\def\pgfmathfp@plots@install{% + \let\pgfmathfpplotscalex=\pgfutil@empty + \let\pgfmathfpplotscaley=\pgfutil@empty + \let\pgfmathfpplotscalez=\pgfutil@empty + \let\pgf@parsexyline=\pgfmathfp@parsexyline% + \let\pgf@parsexyzline=\pgfmathfp@parsexyzline% +}% + +\def\pgfmathfp@parsexyline#1 #2 #3\pgf@stop{% + \edef\pgfmathfp@marshal{% + \noexpand\pgfplotstreampoint{\noexpand\pgfpointxy{\pgfmathfpplotscalex#1}{\pgfmathfpplotscaley#2}}% + }% + \pgfmathfp@marshal% +}% + +\def\pgfmathfp@parsexyzline#1 #2 #3 #4\pgf@stop{% + \edef\pgfmathfp@marshal{% + \noexpand\pgfplotstreampoint{% + \noexpand\pgfpointxyz{\pgfmathfpplotscalex#1}{\pgfmathfpplotscaley#2}{\pgfmathfpplotscalez#3}% + }% + }% + \pgfmathfp@marshal% +}% + +% +\def\pgfmathfp@parser@install{% + % + \expandafter\ifx\csname FP@version\endcsname\relax% + \pgferror{You need to say `\string\usepackage{fp}' to use % + fixed point arithmetic}% + \else% + % + % Don't want messages. + % + \FPmessagesfalse% + \FPdebugfalse% + % + % Install float commands... + % + \let\pgfmathadd@=\pgfmathfpadd@% + \let\pgfmathsubtract@=\pgfmathfpsubtract@% + \let\pgfmathmultiply@=\pgfmathfpmultiply@% + \let\pgfmathdivide@=\pgfmathfpdivide@% + \let\pgfmathabs@=\pgfmathfpabs@% + \let\pgfmathneg@=\pgfmathfpneg@% + \let\pgfmathround@=\pgfmathfpround@% + \let\pgfmathfloor@=\pgfmathfpfloor@% + \let\pgfmathceil@=\pgfmathfpceil@% + \let\pgfmathmod@=\pgfmathfpmod@% + \let\pgfmathmax@=\pgfmathfpmax@% + \let\pgfmathmin@=\pgfmathfpmin@% + \let\pgfmathsin@=\pgfmathfpsin@% + \let\pgfmathcos@=\pgfmathfpcos@% + \let\pgfmathtan@=\pgfmathfptan@% + \let\pgfmathdeg@=\pgfmathfpdeg@% + \let\pgfmathrad@=\pgfmathfprad@% + \let\pgfmathatan@=\pgfmathfpatan@% + \let\pgfmathasin@=\pgfmathfpasin@% + \let\pgfmathacos@=\pgfmathfpacos@% + \let\pgfmathcot@=\pgfmathfpcot@% + \let\pgfmathsec@=\pgfmathfpsec@% + \let\pgfmathcosec@=\pgfmathfpcosec@% + \let\pgfmathpow@=\pgfmathfppow@% + \let\pgfmathexp@=\pgfmathfpexp@% + \let\pgfmathln@=\pgfmathfpln@% + \let\pgfmathsqrt@=\pgfmathfpsqrt@% + \let\pgfmath@pi=\pgfmathfppi@% + \let\pgfmathveclen@=\pgfmathfpveclen@% + \let\pgfmathe@=\pgfmathfpe@% + % + \let\pgfmathlessthan@=\pgfmathfplessthan@% + \let\pgfmathgreaterthan@=\pgfmathfpgreaterthan@% + \let\pgfmathequalto@=\pgfmathfpequalto@% + % + \let\pgfmathrnd=\pgfmathfprnd% + \let\pgfmathrand=\pgfmathfprand% + \let\pgfmathsetseed=\pgfmathfpsetseed% + % + \let\pgfmathscientific=\pgfmathfpscientific% + \fi% +}% + +\def\pgfmathfpe@{let\pgfmathresult=\FPe}% +\def\pgfmathfppi@{let\pgfmathresult=\FPpi}% + + +% Scientific notation. + +\def\pgfmathfpscientific#1#2{% + \begingroup% + \FPpow\pgfmathresult{10}{#2}\unskip% Needed. + \FPmul\pgfmathresult{#1}{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% Comparison stuff... + +% lessthan +% +\def\pgfmathfplessthan#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfplessthan@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfplessthan@#1#2{% + \begingroup% + \FPiflt{#1}{#2}% + \def\pgfmathresult{1.0}% + \else% + \def\pgfmathresult{0.0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% greaterthan +% +\def\pgfmathfpgreaterthan#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpgreaterthan@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpgreaterthan@#1#2{% + \begingroup% + \FPifgt{#1}{#2}% + \def\pgfmathresult{1.0}% + \else% + \def\pgfmathresult{0.0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% equalto +% +\def\pgfmathfpequalto#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpequalto@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpequalto@#1#2{% + \begingroup% + \FPifeq{#1}{#2}% + \def\pgfmathresult{1.0}% + \else% + \def\pgfmathresult{0.0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + + +% Basic arithmetic stuff... + +% add +% +\def\pgfmathfpadd#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpadd@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpadd@#1#2{% + \begingroup% + \FPadd\pgfmathresult{#1}{#2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% subtract +% +\def\pgfmathfpsubtract#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpsubtract@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpsubtract@#1#2{% + \begingroup% + \FPsub\pgfmathresult{#1}{#2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% multiply +% +\def\pgfmathfpmultiply#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpmultiply@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpmultiply@#1#2{% + \begingroup% + \FPmul\pgfmathresult{#1}{#2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% divide +% +\def\pgfmathfpdivide#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpdivide@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpdivide@#1#2{% + \begingroup% + \FPdiv\pgfmathresult{#1}{#2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% abs +% +\def\pgfmathfpabs#1{% + \pgfmathfpparse{#1}% + \pgfmathfpabs@{\pgfmathresult}% +}% +\def\pgfmathfpabs@#1{% + \begingroup% + \FPabs\pgfmathresult{#1}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% neg +% +\def\pgfmathfpneg#1{% + \pgfmathfpparse{#1}% + \pgfmathfpneg@{\pgfmathresult}% +}% +\def\pgfmathfpneg@#1{% + \begingroup% + \FPneg\pgfmathresult{#1}% + \pgfmath@smuggleone\pgfmathresult + \endgroup% +}% + +% round +% +\def\pgfmathfpround#1{% + \pgfmathfpparse{#1}% + \pgfmathfpround@{\pgfmathresult}% +}% +\def\pgfmathfpround@#1{% + \begingroup% + \FPround\pgfmathresult{#1}{0}% + \edef\pgfmathresult{\pgfmathresult.0}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% floor +% +\def\pgfmathfpfloor#1{% + \pgfmathfpparse{#1}% + \pgfmathfpfloor@{\pgfmathresult}% +}% +\def\pgfmathfpfloor@#1{% + \begingroup% + \FPtrunc\pgfmathresult{#1}{0}% + \FPifneg{#1}% + \FPsub\pgfmathresult{\pgfmathresult}{1}% + \fi% + \edef\pgfmathresult{\pgfmathresult.0}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% ceil +% +\def\pgfmathfpceil#1{% + \pgfmathfpparse{#1}% + \pgfmathfpceil@{\pgfmathresult}% +}% +\def\pgfmathfpceil@#1{% + \begingroup% + \FPtrunc\pgfmathresult{#1}{0}% + \FPifpos{#1}% + \FPadd\pgfmathresult{\pgfmathresult}{1}% + \fi% + \edef\pgfmathresult{\pgfmathresult.0}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% mod +% +\def\pgfmathfpmod#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpmod@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpmod@#1#2{% + \begingroup% + \FPdiv\pgfmathresult{#1}{#2}% + \FPtrunc\pgfmathresult{\pgfmathresult}{0}% + \FPmul\pgfmathresult{\pgfmathresult}{#2}% + \FPsub\pgfmathresult{#1}{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% max +% +\def\pgfmathfpmax#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpmax@@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpmax@#1{% + \pgfmathfpmax@@#1% +}% +\def\pgfmathfpmax@@#1#2{% + \begingroup% + \FPifgt{#1}{#2}% + \def\pgfmathresult{#1}% + \else% + \def\pgfmathresult{#2}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% min +% +\def\pgfmathfpmin#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpmin@@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpmin@#1{% + \pgfmathfpmin@@#1% +}% +\def\pgfmathfpmin@@#1#2{% + \begingroup% + \FPiflt{#1}{#2}% + \def\pgfmathresult{#1}% + \else% + \def\pgfmathresult{#2}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% Functions... + +% pow +% +\def\pgfmathfppow#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfppow@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfppow@#1#2{% + \begingroup% + \FPpow\pgfmathresult{#1}{#2}\unskip% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% exp +% +\def\pgfmathfpexp#1{% + \pgfmathfpparse{#1}% + \pgfmathfpexp@{\pgfmathresult}% +}% +\def\pgfmathfpexp@#1{% + \begingroup% + \FPexp\pgfmathresult{#1}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% ln +% +\def\pgfmathfpln#1{% + \pgfmathfpparse{#1}% + \pgfmathfpln@{\pgfmathresult}% +}% +\def\pgfmathfpln@#1{% + \begingroup% + \FPln\pgfmathresult{#1}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% sqrt +% +\def\pgfmathfpsqrt#1{% + \pgfmathfpparse{#1}% + \pgfmathfpsqrt@{\pgfmathresult}% +}% +\def\pgfmathfpsqrt@#1{% + \begingroup% + \FProot\pgfmathresult{#1}{2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% veclen +% +\def\pgfmathfpveclen#1#2{% + \pgfmathfpparse{#2}\let\pgfmath@result=\pgfmathresult% + \pgfmathfpparse{#1}% + \pgfmathfpveclen@{\pgfmathresult}{\pgfmath@result}% +}% +\def\pgfmathfpveclen@#1#2{% + \begingroup% + \FPmul\pgfmath@result{#1}{#1}% + \FPmul\pgfmath@@result{#2}{#2}% + \FPadd\pgfmathresult{\pgfmath@result}{\pgfmath@@result}% + \FProot\pgfmathresult{\pgfmathresult}{2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% Trigonometric stuff... + +% sin +% +\def\pgfmathfpsin#1{% + \pgfmathfpparse{#1}% + \pgfmathfpsin@{\pgfmathresult}% +}% +\def\pgfmathfpsin@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPsin\pgfmathresult{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% cos +% +\def\pgfmathfpcos#1{% + \pgfmathfpparse{#1}% + \pgfmathfpcos@{\pgfmathresult}% +}% +\def\pgfmathfpcos@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPcos\pgfmathresult{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% tan +% +\def\pgfmathfptan#1{% + \pgfmathfpparse{#1}% + \pgfmathfptan@{\pgfmathresult}% +}% +\def\pgfmathfptan@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPtan\pgfmathresult{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% acos +% +\def\pgfmathfpacos#1{% + \pgfmathfpparse{#1}% + \pgfmathfpacos@{\pgfmathresult}% +}% +\def\pgfmathfpacos@#1{% + \begingroup% + \FParccos\pgfmathresult{#1}% + \FPmul\pgfmathresult{\pgfmathresult}{57.295779513082320885}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% asin +% +\def\pgfmathfpasin#1{% + \pgfmathfpparse{#1}% + \pgfmathfpasin@{\pgfmathresult}% +}% +\def\pgfmathfpasin@#1{% + \begingroup% + \FParcsin\pgfmathresult{#1}% + \FPmul\pgfmathresult{\pgfmathresult}{57.295779513082320885}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% atan +% +\def\pgfmathfpatan#1{% + \pgfmathfpparse{#1}% + \pgfmathfpatan@{\pgfmathresult}% +}% +\def\pgfmathfpatan@#1{% + \begingroup% + \FParctan\pgfmathresult{#1}% + \FPmul\pgfmathresult{\pgfmathresult}{57.295779513082320885}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% cot +% +\def\pgfmathfpcot#1{% + \pgfmathfpparse{#1}% + \pgfmathfpcot@{\pgfmathresult}% +}% +\def\pgfmathfpcot@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPcot\pgfmathresult{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% sec +% +\def\pgfmathfpsec#1{% + \pgfmathfpparse{#1}% + \pgfmathfpsec@{\pgfmathresult}% +}% +\def\pgfmathfpsec@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPcos\pgfmathresult{\pgfmathresult}% + \FPdiv\pgfmathresult{1}{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% cosec +% +\def\pgfmathfpcosec#1{% + \pgfmathfpparse{#1}% + \pgfmathfpcosec@{\pgfmathresult}% +}% +\def\pgfmathfpcosec@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.017453292519943295}% + \FPsin\pgfmathresult{\pgfmathresult}% + \FPdiv\pgfmathresult{1}{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% deg +% +\def\pgfmathfpdeg#1{% + \pgfmathfpparse{#1}% + \pgfmathfpdeg@{\pgfmathresult}% +}% +\def\pgfmathfpdeg@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{57.295779513082320885}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% rad +% +\def\pgfmathfprad#1{% + \pgfmathfpparse{#1}% + \pgfmathfprad@{\pgfmathresult}% +}% +\def\pgfmathfprad@#1{% + \begingroup% + \FPmul\pgfmathresult{#1}{0.01745329251994325}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% Random stuff... + +\def\pgfmathfpsetseed#1{% + \pgfmathfpparse{#1}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \FPseed\pgfmathresult\relax\pgfmath@% +}% + +% rnd +% +\def\pgfmathfprnd{% + \begingroup% + \FPrandom\pgfmathresult% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% + +% rand +% +\def\pgfmathfprand{% + \begingroup% + \FPrandom\pgfmathresult% + \FPmul\pgfmathresult{2}{\pgfmathresult}% + \FPsub\pgfmathresult{\pgfmathresult}{1}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryfpu.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryfpu.code.tex new file mode 100644 index 0000000000..a93fa7f90a --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryfpu.code.tex @@ -0,0 +1,2392 @@ +% Copyright 2008/2019 by Christian Feuersaenger +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU General Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\newif\ifpgfmathfloatparseactive +\newif\ifpgfmathfloat@scaleactive + +% public macro which invokes '#1' if the fpu is installed and ready and '#2' +% otherwise. +\def\pgflibraryfpuifactive#1#2{% + \ifpgfmathfloatparseactive + #1% + \else + #2% + \fi +}% + +\pgfqkeys{/pgf}{ + % enable the FPU parser if it is not yet active + % + % It will be deactivated after the current TeX group + fpu/.is choice, + fpu/true/.code={% + \ifpgfmathfloatparseactive + \else + \pgfutil@ifundefined{pgfmathdeclarefunction}{% + % Ohoh - we are running on a TeX distribution with + % PGF 2.00 which doesn't have the new math engine. + % I can provide special treatment here, provided that + % all float commands are still able to run (that means + % more information needs to be copied from the pgf cvs + % to pgf 2.00 - for example pgfmathfloat.code.tex). + % + % I employ this to work with pgfplots and pgf 2.00 + % using all new features. + \pgfmathfloat@parser@install@pgf@two@null@null% + }{% + \pgfmathfloat@parser@install% + }% + \pgfmathfloatparseactivetrue + % improve compatibility with Marks FP library: + \pgfkeysalso{/pgf/fixed point arithmetic/.prefix style={/pgf/fpu=false}}% + \fi + },% + fpu/false/.code={% + \ifpgfmathfloatparseactive + \pgfmathfloat@uninstall% + \pgfmathfloatparseactivefalse + \fi + },% + fpu/.default=true, + % Use this to introduce a result scaling. + % Every expression in which the prefix '*' occurs + % will be multiplied with the result and converted to fixed point + % representation. + fpu/scale results/.code={% + \ifpgfmathfloatparseactive + \pgfmathparse{#1}% + \else + \pgfmathfloatparsenumber{#1}% + \fi + \let\pgfmathfloatscale=\pgfmathresult% + },% + % determines the output format of each complete expression parsing + % process. If 'scale results' is active, 'fixed' is assumed + % automatically. + fpu/output format/.is choice, + fpu/output format/float/.code= {% + \def\pgfmathfloatparse@output@choice{Y}% + \let\pgfmathfloatparse@output=\relax + }, + fpu/output format/sci/.code= {% + \def\pgfmathfloatparse@output@choice{S}% + \def\pgfmathfloatparse@output{\pgfmathfloattosci@{\pgfmathresult}}% + }, + fpu/output format/fixed/.code= {% + \def\pgfmathfloatparse@output@choice{F}% + \def\pgfmathfloatparse@output{\pgfmathfloattofixed@{\pgfmathresult}}% + }, + fpu/output format/float, + fpu/rel thresh/.code={% + \pgfmathfloatparsenumber{#1}% + \let\pgfmathfloat@relthresh=\pgfmathresult + }, + fpu/rel thresh=1e-4, + fpu/install only/.code={ + \edef\pgf@list{#1}% + \pgfutil@for\pgf@temp:=\pgf@list\do{% + \expandafter\pgfmath@float@install@singlefunction\expandafter{% + \romannumeral-`0\expandafter\pgfutil@trimspaces\expandafter{\pgf@temp}}% + }% + }, +}% + +\pgfmathfloatcreate{1}{1.0}{0}\let\pgfmathfloatscale=\pgfmathresult + +\let\pgfmathfloatone=\pgfmathresult + +% This is the replacement parser invocation. +% It does two things which are different to \pgfmathparse: +% 1. it disables any dimension dependent scalings, +% 2. it implements the 'scale results' feature. +\def\pgfmathfloatparse{% + \begingroup% + % disable any dimension-dependant scalings: + \let\pgfmathpostparse=\relax% + \pgfmath@catcodes% + \pgfmath@quickparsefalse% + \ifpgfmathfloatparseactive\else + \pgfmathfloat@parser@install + \fi + \pgfmathfloatparse@}% + +% for pgf 2.00 : +\def\pgfmathfloatparse@pgf@two@null@null{% + \pgfmath@quickparsefalse% + \pgfmathfloatparse@}% + +\def\pgfmathfloatparse@#1{% + \edef\pgfmathfloat@expression{#1}% + \expandafter\pgfmathfloatparse@@\pgfmathfloat@expression\pgfmathfloat@ + \ifpgfmathfloat@scaleactive + \expandafter\pgfmathfloatmultiply@\expandafter{\pgfmathresult}{\pgfmathfloatscale}% + \pgfmathfloattofixed{\pgfmathresult}% + \else + \pgfmathfloatparse@output + \fi + \ignorespaces +}% + +\def\pgfmathfloat@char@asterisk{*}% +\def\pgfmathfloatparse@@#1#2\pgfmathfloat@{% + \def\pgfmathfloat@test{#1}% + \ifx\pgfmathfloat@test\pgfmathfloat@char@asterisk% + \def\pgfmathfloat@expression{#2}% + \pgfmathfloat@scaleactivetrue + \fi% + \expandafter\pgfmathparse@\expandafter{\pgfmathfloat@expression}% + % \endgroup provided by \pgfpathmarse@end +}% + +% Crude handling of file plots +% +\pgfkeys{/pgf/fpu/.cd, + scale file plot x/.code=\pgfmathfloatparse{#1}\edef\pgfmathfloatplotscalex{\pgfmathresult*}, + scale file plot y/.code=\pgfmathfloatparse{#1}\edef\pgfmathfloatplotscaley{\pgfmathresult*}, + scale file plot z/.code=\pgfmathfloatparse{#1}\edef\pgfmathfloatplotscalez{\pgfmathresult*} +}% + +\def\pgfmathfloat@uninstall@appendcmd#1{% + \expandafter\gdef\expandafter\pgfmathfloat@uninstall\expandafter{\pgfmathfloat@uninstall #1}% +}% + +% If the uninstall command is already assembled, it will skip the +% uninstall assemblation. +\def\pgfmathfloat@plots@checkuninstallcmd{% + \pgfutil@ifundefined{pgfmathfloat@uninstall}{% + \global\let\pgfmathfloat@uninstall=\pgfutil@empty + }{% + % We already HAVE an uninstall command (prepared globally). + % So: don't waste time assembling one! + \def\pgfmathfloat@uninstall@appendcmd##1{}% + \def\pgfmathfloat@prepareuninstallcmd##1{}% + }% +}% + +% This assembles an uninstall command globally ON FIRST USAGE. +% See \pgfmathfloat@plots@checkuninstallcmd +\def\pgfmathfloat@prepareuninstallcmd#1{% + % and store backup information (globally - I don't want to do that + % all the time when the FPU is used!): + \expandafter\global\expandafter\let\csname pgfmathfloat@backup@\string#1\endcsname=#1% + \expandafter\gdef\expandafter\pgfmathfloat@uninstall\expandafter{\pgfmathfloat@uninstall + \expandafter\let\expandafter#1\csname pgfmathfloat@backup@\string#1\endcsname% + }% +}% + +\def\pgfmathfloat@install#1=#2{% + \pgfmathfloat@prepareuninstallcmd{#1}% + \let#1=#2% +}% +\def\pgfmathfloat@install@csname#1#2{% + \expandafter\pgfmathfloat@prepareuninstallcmd\csname #1\endcsname% + \pgfutil@namelet{#1}{#2}% +}% +\def\pgfmathfloat@install@unimplemented#1{% + \expandafter\pgfmathfloat@prepareuninstallcmd\csname pgfmath#1@\endcsname% + \expandafter\def\csname pgfmath#1@\endcsname##1{\pgfmathfloat@notimplemented{#1}}% +}% +\def\pgfmathfloat@plots@install{% + \let\pgfmathfloatplotscalex=\pgfutil@empty + \let\pgfmathfloatplotscaley=\pgfutil@empty + \let\pgfmathfloatplotscalez=\pgfutil@empty + \pgfmathfloat@install\pgf@parsexyline=\pgfmathfloat@parsexyline% + \pgfmathfloat@install\pgf@parsexyzline=\pgfmathfloat@parsexyzline% +}% +\def\pgfmathfloat@parsexyline#1 #2 #3\pgf@stop{% + \edef\pgfmathfloat@marshal{% + \noexpand\pgfplotstreampoint{\noexpand\pgfpointxy{\pgfmathfloatplotscalex#1}{\pgfmathfloatplotscaley#2}}% + }% + \pgfmathfloat@marshal% +}% +\def\pgfmathfloat@parsexyzline#1 #2 #3 #4\pgf@stop{% + \edef\pgfmathfloat@marshal{% + \noexpand\pgfplotstreampoint{% + \noexpand\pgfpointxyz{\pgfmathfloatplotscalex#1}{\pgfmathfloatplotscaley#2}{\pgfmathfloatplotscalez#3}% + }% + }% + \pgfmathfloat@marshal% +}% + +% +\def\pgfmathfloat@parser@install@functions{% + % Install float commands... + % + \pgfmathfloat@install\pgfmathadd@=\pgfmathfloatadd@% + \pgfmathfloat@install\pgfmathsubtract@=\pgfmathfloatsubtract@% + \pgfmathfloat@install\pgfmathneg@=\pgfmathfloatneg@% + \pgfmathfloat@install\pgfmathmultiply@=\pgfmathfloatmultiply@% + \pgfmathfloat@install\pgfmathdivide@=\pgfmathfloatdivide@% + \pgfmathfloat@install\pgfmathabs@=\pgfmathfloatabs@% + \pgfmathfloat@install\pgfmathsign@=\pgfmathfloatsign@% + \pgfmathfloat@install\pgfmathround@=\pgfmathfloatround@% + \pgfmathfloat@install\pgfmathfloor@=\pgfmathfloatfloor@% + \pgfmathfloat@install\pgfmathceil@=\pgfmathfloatceil@ + \pgfmathfloat@install\pgfmathint@=\pgfmathfloatint@ + \pgfmathfloat@install\pgfmathmod@=\pgfmathfloatmod@% + \pgfmathfloat@install\pgfmathmax@=\pgfmathfloatmax@% + \pgfmathfloat@install\pgfmathmin@=\pgfmathfloatmin@% + \pgfmathfloat@install\pgfmathsin@=\pgfmathfloatsin@% + \pgfmathfloat@install\pgfmathcos@=\pgfmathfloatcos@% + \pgfmathfloat@install\pgfmathtan@=\pgfmathfloattan@% + \pgfmathfloat@install\pgfmathdeg@=\pgfmathfloatdeg@% + \pgfmathfloat@install\pgfmathrad@=\pgfmathfloatrad@% + \pgfmathfloat@install\pgfmathatan@=\pgfmathfloatatan@% + \pgfmathfloat@install\pgfmathasin@=\pgfmathfloatasin@% + \pgfmathfloat@install\pgfmathacos@=\pgfmathfloatacos@% + \pgfmathfloat@install\pgfmathcot@=\pgfmathfloatcot@% + \pgfmathfloat@install\pgfmathsec@=\pgfmathfloatsec@% + \pgfmathfloat@install\pgfmathcosec@=\pgfmathfloatcosec@% + \pgfmathfloat@install\pgfmathexp@=\pgfmathfloatexp@% + \pgfmathfloat@install\pgfmathln@=\pgfmathfloatln@% + \pgfmathfloat@install@csname{pgfmathlog10@}{pgfmathfloatlog10@}% + \pgfmathfloat@install@csname{pgfmathlog2@}{pgfmathfloatlog2@}% + \pgfmathfloat@install\pgfmathsqrt@=\pgfmathfloatsqrt@% + \pgfmathfloat@install\pgfmath@pi=\pgfmathfloatpi@% + \pgfmathfloat@install\pgfmathpi=\pgfmathfloatpi@% + \pgfmathfloat@install\pgfmathe@=\pgfmathfloate@% + \pgfmathfloat@install\pgfmathe=\pgfmathfloate@% + \pgfmathfloat@install\pgfmathlessthan@=\pgfmathfloatlessthan@% + \pgfmathfloat@install\pgfmathnotless@=\pgfmathfloatnotless@% + \pgfmathfloat@install\pgfmathnotgreater@=\pgfmathfloatnotgreater@% + \pgfmathfloat@install\pgfmathless@=\pgfmathfloatlessthan@% + \pgfmathfloat@install\pgfmathgreaterthan@=\pgfmathfloatgreaterthan@% + \pgfmathfloat@install\pgfmathgreater@=\pgfmathfloatgreaterthan@% + \pgfmathfloat@install\pgfmathifthenelse@=\pgfmathfloatifthenelse@% + \pgfmathfloat@install\pgfmathequal@=\pgfmathfloatequal@% + \pgfmathfloat@install\pgfmathequalto@=\pgfmathfloatequal@% + \pgfmathfloat@install\pgfmathnotequal@=\pgfmathfloatnotequal@% + \pgfmathfloat@install\pgfmathnotequalto@=\pgfmathfloatnotequal@% + \pgfmathfloat@install\pgfmathpow@=\pgfmathfloatpow@ + \pgfmathfloat@install\pgfmathrand@=\pgfmathfloatrand@ + \pgfmathfloat@install\pgfmathrand=\pgfmathfloatrand@ + \pgfmathfloat@install\pgfmathrnd@=\pgfmathfloatrnd@ + \pgfmathfloat@install\pgfmathrnd=\pgfmathfloatrnd@ + \pgfmathfloat@install\pgfmathtrue@=\pgfmathfloattrue@ + \pgfmathfloat@install\pgfmathfalse@=\pgfmathfloatfalse@ + \pgfmathfloat@install\pgfmathnot@=\pgfmathfloatnot@ + \pgfmathfloat@install\pgfmathhex@=\pgfmathfloathex@ + \pgfmathfloat@install\pgfmathHex@=\pgfmathfloatHex@ + \pgfmathfloat@install\pgfmathoct@=\pgfmathfloatoct@ + \pgfmathfloat@install\pgfmathbin@=\pgfmathfloatbin@ + \pgfmathfloat@install\pgfmathand@=\pgfmathfloatand@ + \pgfmathfloat@install\pgfmathor@=\pgfmathfloator@ + \pgfmathfloat@install\pgfmathfactorial@=\pgfmathfloatfactorial@ + \pgfmathfloat@install\pgfmathveclen@=\pgfmathfloatveclen@ + \pgfmathfloat@install\pgfmathcosh@=\pgfmathfloatcosh@ + \pgfmathfloat@install\pgfmathsinh@=\pgfmathfloatsinh@ + \pgfmathfloat@install\pgfmathtanh@=\pgfmathfloattanh@ + \pgfmathfloat@install\pgfmath@iftrue=\pgfmathfloat@iftrue% + \expandafter\pgfmathfloat@install\csname pgfmathatan2@\endcsname=\pgfmathfloatatantwo@ + \pgfmathfloat@install@unimplemented{isprime}% + \pgfmathfloat@install@unimplemented{iseven}% + \pgfmathfloat@install@unimplemented{isodd}% + \pgfmathfloat@install@unimplemented{gcd}% + \pgfmathfloat@install@unimplemented{frac}% + \pgfmathfloat@install@unimplemented{random}% + \pgfmathfloat@install@unimplemented{setseed}% + \pgfmathfloat@install@unimplemented{Mod}% + \pgfmathfloat@install@unimplemented{div}% + \pgfmathfloat@install@unimplemented{real}% +% \pgfmathfloat@install@unimplemented{height}% + % + % + \pgfmathfloat@install\pgfmathscientific=\pgfmathfloatscientific% +}% + +\def\pgfmath@float@install@singlefunction#1{% + \ifcsname pgfmath@function@#1\endcsname\else + \pgfmath@error{The function `#1' does not exist}{}% + \fi + \pgfmath@toks={}% + \pgfmathloop + \ifnum\pgfmathcounter>\csname pgfmath@operation@#1@arity\endcsname\relax% + \else + \expandafter\pgfmath@addto@toks\expandafter{\pgfmath@char@hash}% + \expandafter\pgfmath@addto@toks\expandafter{\pgfmathcounter}% + \repeatpgfmathloop + \edef\pgfmath@head{\noexpand\def\expandafter\noexpand\csname pgfmath#1@\endcsname\the\pgfmath@toks}% + \pgfmath@toks={}% + \def\pgfmath@arguments{}% + \pgfmathloop + \ifnum\pgfmathcounter>\csname pgfmath@operation@#1@arity\endcsname\relax% + \else + \pgfmath@addto@toks{\pgfmathfloatparsenumber}% + \expandafter\expandafter\expandafter\pgfmath@addto@toks + \expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter + {\expandafter\pgfmath@char@hash\pgfmathcounter}}% + \pgfmath@addto@toks{\let}% + \expandafter\pgfmath@addto@toks\expandafter{% + \csname pgfmath@argument@\pgfmathcounter\endcsname=\pgfmathresult}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter + \pgfmath@arguments\expandafter\expandafter\expandafter{\expandafter + \pgfmath@arguments\expandafter{\csname pgfmath@argument@\pgfmathcounter\endcsname}}% + \repeatpgfmathloop + \expandafter\pgfmath@addto@toks\expandafter{\csname pgfmathfloat#1@\expandafter\endcsname\pgfmath@arguments}% + \pgfmath@addto@toks{\pgfmathfloattofixed{\pgfmathresult}}% + \edef\pgfmath@body{{\the\pgfmath@toks}}% + \expandafter\pgfmath@head\pgfmath@body +} + +\def\pgfmathfloat@iftrue{% + \if Y\pgfmathfloatparse@output@choice + \let\pgfmathfloat@@iftrue@v=\pgfmathfloatone + \let\pgfmathfloat@@iftrue@next=\pgfmathfloat@iftrue@ + \else + \if S\pgfmathfloatparse@output@choice + \def\pgfmathfloat@@iftrue@v{1.0e0}% + \let\pgfmathfloat@@iftrue@next=\pgfmathfloat@iftrue@ + \else + \def\pgfmath@next{\pgfutilifstartswith{1.0}}% + \expandafter\pgfmath@next\expandafter{\pgfmathresult}{% + \ifdim\pgfmathresult pt=1.0pt % + \let\pgfmathfloat@@iftrue@next=\pgfutil@firstoftwo + \else + \let\pgfmathfloat@@iftrue@next=\pgfutil@secondoftwo + \fi + }{% + \let\pgfmathfloat@@iftrue@next=\pgfutil@secondoftwo + }% + \fi + \fi + \pgfmathfloat@@iftrue@next% +}% +\def\pgfmathfloat@iftrue@{% + \ifx\pgfmathresult\pgfmathfloat@@iftrue@v + \let\pgfmath@next=\pgfutil@firstoftwo + \else + \let\pgfmath@next=\pgfutil@secondoftwo + \fi + \pgfmath@next% +}% + +\def\pgfmathfloat@parser@install{% + \pgfmathfloat@plots@checkuninstallcmd + \pgfmathfloat@plots@install% + \pgfmathfloat@parser@install@functions + % + % + % + % The following methods actually enable the parser to work with + % the internal floating point number representation. + % + % The idea is as follows: + % 1. Every operand must be given in internal float representation. + % 2. The internal float repr can be distinguished by a normal + % number. This is accomplished by introducing a new "exponent" + % token. + % 3. The stack-push-operation checks whether the argument is a + % float. If not, it is parsed properly before pushing it. + \pgfmath@tokens@make{exponent}{\pgfmathfloat@POSTFLAGSCHAR}% + \pgfmathfloat@uninstall@appendcmd{% + \expandafter\let\csname pgfmath@token@exponent@\pgfmathfloat@POSTFLAGSCHAR\endcsname=\relax + }% + \let\pgfmath@basic@parse@exponent=\pgfmath@parse@exponent% + \let\pgfmath@basic@stack@push@operand=\pgfmath@stack@push@operand + \pgfmathfloat@install\pgfmath@stack@push@operand=\pgfmathfloat@stack@push@operand + \pgfmathfloat@install\pgfmath@parse@operand@quote=\pgfmathfloat@parse@operand@quote + \pgfmathfloat@install\pgfmath@parse@exponent=\pgfmathfloat@parse@float@or@exponent + % + \pgfmathfloat@install\pgfmathparse=\pgfmathfloatparse% + %\pgfmathfloat@install\pgfmathparse@trynumber@token=\pgfmathfloat@parse@trynumber@token + \pgfmathfloat@install\pgfmathparse@expression@is@number=\pgfmathfloat@parse@expression@is@number +}% + +% This here might bring speed improvements... if implemented +% correctly. +% However, this heuristics might fail in cases like "1+1" vs "1e+1" ... +%\def\pgfmathfloat@parse@trynumber@token{numericfpu} +%\pgfmath@tokens@make{numericfpu}{eE+-Y.0123456789} + +\def\pgfmathfloat@parse@expression@is@number{% + \pgfmathfloatparsenumber{\pgfmath@expression}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup + \ignorespaces +}% + +\def\pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG#1{% + \edef\pgfmathfloat@loc@TMPa{% + \noexpand\def\expandafter\noexpand\csname pgfmath@parsefunction@#1\endcsname{% + \noexpand\let\noexpand\pgfmath@parsepostgroup\expandafter\noexpand\csname pgfmath@parsefunction@#1@\endcsname% + \noexpand\expandafter\noexpand\pgfmath@parse@}% + \noexpand\def\expandafter\noexpand\csname pgfmath@parsefunction@#1@\endcsname{% + \noexpand\expandafter\expandafter\noexpand\csname pgfmath#1@\endcsname\noexpand\expandafter{\noexpand\pgfmathresult}% + \noexpand\pgfmath@postfunction% + }% + }% + \pgfmathfloat@loc@TMPa +}% +\def\pgfmathfloat@parser@install@pgf@two@null@null{% + \pgfmathfloat@plots@checkuninstallcmd + \pgfmathfloat@plots@install% + \pgfmathfloat@parser@install@functions + \let\pgfmathrand@=\pgfmath@basic@rand@ + \let\pgfmathrnd@=\pgfmath@basic@rnd@ + \pgfmathfloat@install\pgfmathmax@=\pgfmathfloatmaxtwo% + \pgfmathfloat@install\pgfmathmin@=\pgfmathfloatmintwo% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{factorial}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{hex}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{bin}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{oct}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{tanh}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{sinh}% + \pgfmathfloat@defineadapter@for@pgf@two@null@null@ONEARG{cosh}% + % + % The following methods actually enable the parser to work with + % the internal floating point number representation. + % + % The idea is as follows: + % 1. Every operand must be given in internal float representation. + % 2. The internal float repr can be distinguished by a normal + % number. This is accomplished by introducing a new "exponent" + % token. + % 3. The stack-push-operation checks whether the argument is a + % float. If not, it is parsed properly before pushing it. + \let\pgfmath@basic@parsedecimalpoint=\pgfmath@parsedecimalpoint% + \let\pgfmath@basic@stack@push@operand=\pgfmath@stackpushoperand + \pgfmathfloat@install\pgfmath@stackpushoperand=\pgfmathfloat@stack@push@operand + \pgfmathfloat@install\pgfmath@parsedecimalpoint=\pgfmathfloat@parsedecimalpoint@pgf@two@null@null + \pgfmathfloat@install\pgfmath@endparse=\pgfmathfloat@endparse@pgf@two@null@null + \pgfmathfloat@install\pgfmath@endparsegroup=\pgfmathfloat@endparsegroup@pgf@two@null@null + \pgfmathfloat@install\pgfmath@postfunction=\pgfmathfloat@postfunction@pgf@two@null@null + \pgfmathfloat@install\pgfmath@@parseoperandgroup=\pgfmathfloat@@parseoperandgroup + % + \pgfmathfloat@install\pgfmathparse=\pgfmathfloatparse@pgf@two@null@null% +}% + +\pgfutil@ifundefined{pgfmathdeclarefunction}{% + % BACKWARDS COMPATIBILITY: We have PGF 2.00 : + \def\pgfmathdeclarepseudoconstant#1#2{% + \begingroup + \toks0=\expandafter{\csname pgfmath#1@\endcsname}% + \toks1={\pgfmath@postfunction}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 }% + \xdef\pgfmathfloat@glob@TMPb{\the\toks0 }% + \endgroup + \expandafter\let\csname pgfmath@parsefunction@#1\endcsname=\pgfmathfloat@glob@TMP + \expandafter\let\csname pgfmath#1\endcsname=\pgfmathfloat@glob@TMPb + \expandafter\def\csname pgfmath#1@\endcsname{#2}% + }% + \let\pgfmathredeclarepseudoconstant=\pgfmathdeclarepseudoconstant +}{% + \pgfutil@ifundefined{pgfmathdeclarepseudoconstant}{% + \def\pgfmathdeclarepseudoconstant#1#2{\pgfmathdeclarefunction*{#1}{0}{#2}} + }{}% +}% + +\pgfmathdeclarepseudoconstant{inf}{\def\pgfmathresult{inf}}% +\pgfmathdeclarepseudoconstant{INF}{\def\pgfmathresult{inf}}% +\pgfmathdeclarepseudoconstant{Inf}{\def\pgfmathresult{inf}}% +\pgfmathdeclarepseudoconstant{infty}{\def\pgfmathresult{inf}}% +\pgfmathdeclarepseudoconstant{nan}{\def\pgfmathresult{nan}}% +\pgfmathdeclarepseudoconstant{NaN}{\def\pgfmathresult{nan}}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Hacks to the basic level pgf math engine: +% +% WARNING: These methods rely heavily on the internal float representation! +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% for pgf2.00 : +\def\pgfmathfloat@parsedecimalpoint@pgf@two@null@null#1{% + \expandafter\ifx\pgfmathfloat@POSTFLAGSCHAR#1% check whether it is a float + \let\pgfmath@next=\pgfmathfloat@return@float@pgf@two@null@null% + \else + \def\pgfmath@next{\pgfmath@basic@parsedecimalpoint#1}% + \fi + \pgfmath@next +}% +% for pgf2.00: +\def\pgfmathfloat@return@float@pgf@two@null@null#1]{% + \edef\pgfmathresult{\the\c@pgfmath@parsecounta\pgfmathfloat@POSTFLAGSCHAR#1]}% + \let\pgfmath@resulttemp=\pgfmathresult + \pgfmath@parseoperator% +}% +% for pgf2.00: +\def\pgfmathfloat@endparse@pgf@two@null@null#1\pgfmath@empty{% + \pgfmath@processalloperations% + \pgfmath@stackpop{\pgfmathresult}% + % delete the final unit scalings + \pgfmath@smuggleone{\pgfmathresult}% + \endgroup% + \ignorespaces% +}% +% for pgf2.00: +\def\pgfmathfloat@endparsegroup@pgf@two@null@null{% + \pgfmath@processalloperations% + \pgfmath@stackpop{\pgfmathresult}% + % eliminated register usage here... + \pgfmath@smuggleone{\pgfmathresult}% + \endgroup% + \pgfmath@parsepostgroup% +}% +% for pgf2.00: +\def\pgfmathfloat@postfunction@pgf@two@null@null{% + \let\pgfmath@parsepostgroup\pgfmath@parseoperator% + \ifnum\pgfmath@sign1<0 + \pgfmathfloatneg@{\pgfmathresult}% + \let\pgfmath@sign\pgfutil@empty + \fi + \pgfmath@parseoperator}% +% for pgf2.00: +\def\pgfmathfloat@@parseoperandgroup{% + \let\pgfmath@postparsegroup\pgfmath@parseoperator% + \ifnum\pgfmath@sign1<0 + \pgfmathfloatneg@{\pgfmathresult}% + \let\pgfmath@sign\pgfutil@empty + \fi + \pgfmath@parseoperator% +}% + + + + + + +% PRECONDITION: +% either +% e +% ^ +% -> read the exponent. +% or +% \pgfmathfloat@POSTFLAGSCHAR +% ^ +% -> we have a parsed floating point number -> read it. +\def\pgfmathfloat@parse@float@or@exponent{% + \if\pgfmath@token \pgfmathfloat@POSTFLAGSCHAR% + % Ok, we actually HAVE a pre-parsed floating point number! + % Return it. + \expandafter\pgfmathfloat@return@float\expandafter\pgfmath@token@next + \else + % We have a standard number in scientific format. Parse it. + \expandafter\pgfmath@basic@parse@exponent + \fi +}% +\def\pgfmathfloat@return@float#1]{% + \edef\pgfmathresult{\pgfmath@number \pgfmathfloat@POSTFLAGSCHAR#1]}% + \expandafter\pgfmath@basic@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +}% + +\def\pgfmathfloat@parse@operand@quote#1"{% + \edef\pgfmathresult{\pgfmath@fpu@stringmarker #1}% + \expandafter\pgfmath@basic@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + +\def\pgfmath@fpu@stringmarker{@@str@@:}% + +% This extends the functionality of the basic level operand stack: it +% assures every element on the stack is a float. +\def\pgfmathfloat@stack@push@operand#1{% + \pgfutil@ifnextchar\bgroup{% + \let\pgfmathfloat@stack@push@operand@list@=\pgfutil@empty + \pgfmathfloat@stack@push@operand@list + }{% + \pgfmathfloat@stack@push@operand@single + }% + #1\relax +}% + +\def\pgfmathfloat@stack@push@operand@single#1\relax{% + \expandafter\pgfutil@in@\pgfmathfloat@POSTFLAGSCHAR{#1}% + \ifpgfutil@in@ + \pgfmath@basic@stack@push@operand{#1}% + \else + \expandafter\pgfutil@in@\expandafter{\pgfmath@fpu@stringmarker}{#1}% + \ifpgfutil@in@ + \pgfmathfloat@stack@push@operand@single@str#1\relax + \else + \pgfmathfloatparsenumber{#1}% + \expandafter\pgfmath@basic@stack@push@operand\expandafter{\pgfmathresult}% + \fi + \fi +}% + +\expandafter\def\expandafter\pgfmathfloat@stack@push@operand@single@str\pgfmath@fpu@stringmarker #1\relax{% + \pgfmath@basic@stack@push@operand{#1}% +}% + +\def\pgfmathfloat@stack@push@operand@GOBBLE#1\relax{}% +\def\pgfmathfloat@stack@push@operand@list#1{% + \expandafter\pgfutil@in@ \pgfmathfloat@POSTFLAGSCHAR{#1}% + \ifpgfutil@in@ + \expandafter\def\expandafter\pgfmathfloat@stack@push@operand@list@\expandafter{% + \pgfmathfloat@stack@push@operand@list@{#1}% + }% + \else + \pgfmathfloatparsenumber{#1}% + \begingroup + \toks0=\expandafter{\pgfmathfloat@stack@push@operand@list@}% + \toks1=\expandafter{\pgfmathresult}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 {\the\toks1}}% + \endgroup + \let\pgfmathfloat@stack@push@operand@list@=\pgfmathfloat@glob@TMP + \fi + \pgfutil@ifnextchar\relax{% + \expandafter\pgfmath@basic@stack@push@operand\expandafter{\pgfmathfloat@stack@push@operand@list@}% + \pgfmathfloat@stack@push@operand@GOBBLE + }{% + \pgfmathfloat@stack@push@operand@list + }% +}% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% --- END --- Hacks to the basic level pgf math engine +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Here starts the implementation of the floating point +% routines. +% +% They can be used even if the FPU parser is not active. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Remember the basic math commands. They will be invoked as subroutines in floating point routines. +\let\pgfmath@basic@add@=\pgfmathadd@ +\let\pgfmath@basic@subtract@=\pgfmathsubtract@ +\let\pgfmath@basic@multiply@=\pgfmathmultiply@ +\let\pgfmath@basic@divide@=\pgfmathdivide@ +\let\pgfmath@basic@reciprocal@=\pgfmathreciprocal@ +\let\pgfmath@basic@abs@=\pgfmathabs@ +\let\pgfmath@basic@round@=\pgfmathround@ +\let\pgfmath@basic@rand@=\pgfmathrand@ +\let\pgfmath@basic@rnd@=\pgfmathrnd@ +\let\pgfmath@basic@setseed@=\pgfmathsetseed@ +\let\pgfmath@basic@random@=\pgfmathrandom@ +\let\pgfmath@basic@floor@=\pgfmathfloor@ +\let\pgfmath@basic@ceil@=\pgfmathceil@ +\let\pgfmath@basic@mod@=\pgfmathmod@ +\let\pgfmath@basic@max@=\pgfmathmax@ +\let\pgfmath@basic@min@=\pgfmathmin@ +\let\pgfmath@basic@sin@=\pgfmathsin@ +\let\pgfmath@basic@cos@=\pgfmathcos@ +\let\pgfmath@basic@tan@=\pgfmathtan@ +\let\pgfmath@basic@deg@=\pgfmathdeg@ +\let\pgfmath@basic@rad@=\pgfmathrad@ +\let\pgfmath@basic@atan@=\pgfmathatan@ +\let\pgfmath@basic@asin@=\pgfmathasin@ +\let\pgfmath@basic@acos@=\pgfmathacos@ +\let\pgfmath@basic@cot@=\pgfmathcot@ +\let\pgfmath@basic@sec@=\pgfmathsec@ +\let\pgfmath@basic@cosec@=\pgfmathcosec@ +\let\pgfmath@basic@pow@=\pgfmathpow@ +\let\pgfmath@basic@exp@=\pgfmathexp@ +\let\pgfmath@basic@ln@=\pgfmathln@ +\let\pgfmath@basic@sqrt@=\pgfmathsqrt@ +\let\pgfmath@basic@@pi=\pgfmath@pi +\let\pgfmath@basic@veclen@=\pgfmathveclen@ +\let\pgfmath@basic@e@=\pgfmathe@ +\let\pgfmath@basic@lessthan@=\pgfmathlessthan@ +\let\pgfmath@basic@greaterthan@=\pgfmathgreaterthan@ +\let\pgfmath@basic@equalto@=\pgfmathequalto@ +\let\pgfmath@basic@equal@=\pgfmathequal@ +\let\pgfmath@basic@true@=\pgfmathtrue@ +\let\pgfmath@basic@false@=\pgfmathfalse@ + +\def\pgfmathfloatscientific#1#2{% + \edef\pgfmathresult{#1e#2}% + \expandafter\pgfmathfloatparsenumber\expandafter{\pgfmathresult}% +}% +% Compares #1 with #2 and sets \pgfmathresult either to 1.0 or 0.0. +% +% It also sets the boolean \ifpgfmathfloatcomparison (globally). +\def\pgfmathfloatlessthan@#1#2{% +%\def\pgfmathfloatlessthan#1#2#3\and#4#5#6{% + \global\pgfmathfloatcomparisonfalse + \begingroup + \edef\pgfmathfloat@loc@TMPa{#1}% + \edef\pgfmathfloat@loc@TMPb{#2}% + \expandafter\pgfmathfloat@decompose\pgfmathfloat@loc@TMPa\relax\pgfmathfloat@a@S\pgfmathfloat@a@M\pgfmathfloat@a@E + \expandafter\pgfmathfloat@decompose\pgfmathfloat@loc@TMPb\relax\pgfmathfloat@b@S\pgfmathfloat@b@M\pgfmathfloat@b@E + \ifcase\pgfmathfloat@a@S + % x = 0 -> (x y >0) + \ifcase\pgfmathfloat@b@S + % y = 0 + \or% y > 0 + \global\pgfmathfloatcomparisontrue + \or% y < 0 + \or% y = nan + \or% y = + infty + \global\pgfmathfloatcomparisontrue + \or% y = -infty + \fi + \or + % x > 0 -> (x ( y > 0 && |x| < |y|) ) + \ifcase\pgfmathfloat@b@S + % y = 0 + \or% y>0: + \pgfmathfloatlessthan@positive + \or% y < 0 + \or% y = nan + \or% y = + infty + \global\pgfmathfloatcomparisontrue + \or% y = -infty + \fi + \or + % x < 0 -> (x (y >= 0 || |x| > |y|) ) + \ifcase\pgfmathfloat@b@S + % y = 0 + \global\pgfmathfloatcomparisontrue + \or%y > 0 + \global\pgfmathfloatcomparisontrue + \or% 'y<0': + \pgfmathfloatgreaterthan@positive + \or% y = nan + \or% y = + infty + \global\pgfmathfloatcomparisontrue + \or% y = -infty + \fi + \or + % x = nan. + \or + % x = +infty + \or + % x = -infty + \ifnum\pgfmathfloat@b@S=3 + \else + \global\pgfmathfloatcomparisontrue + \fi + \fi + \endgroup + \ifpgfmathfloatcomparison + \def\pgfmathresult{1.0}% + \else + \def\pgfmathresult{0.0}% + \fi +}% +\let\pgfmathfloatlessthan=\pgfmathfloatlessthan@ +\let\pgfmathfloatless@=\pgfmathfloatlessthan@ + +% ! (#1 < #2) <=> (#1 >= #2) +\def\pgfmathfloatnotless@#1#2{% + \pgfmathfloatless@{#1}{#2}% + \ifpgfmathfloatcomparison + \def\pgfmathresult{0.0}% + \else + \def\pgfmathresult{1.0}% + \fi +}% +% ! (#1 > #2) <=> (#1 <= #2) +\def\pgfmathfloatnotgreater@#1#2{% + \pgfmathfloatless@{#2}{#1}% + \ifpgfmathfloatcomparison + \def\pgfmathresult{0.0}% + \else + \def\pgfmathresult{1.0}% + \fi +}% + +% compares \pgfmathfloat@a@[SME] < \pgfmathfloat@b@[SME] +\def\pgfmathfloatlessthan@positive{% + \ifnum\pgfmathfloat@a@E<\pgfmathfloat@b@E + \global\pgfmathfloatcomparisontrue + \else + \ifnum\pgfmathfloat@a@E=\pgfmathfloat@b@E + \ifdim\pgfmathfloat@a@M<\pgfmathfloat@b@M + \global\pgfmathfloatcomparisontrue + \fi + \fi + \fi +}% + +% compares \pgfmathfloat@a@[SME] > \pgfmathfloat@b@[SME] +\def\pgfmathfloatgreaterthan@positive{% + \ifnum\pgfmathfloat@a@E>\pgfmathfloat@b@E + \global\pgfmathfloatcomparisontrue + \else + \ifnum\pgfmathfloat@a@E=\pgfmathfloat@b@E + \ifdim\pgfmathfloat@a@M>\pgfmathfloat@b@M + \global\pgfmathfloatcomparisontrue + \fi + \fi + \fi +}% + + +\def\pgfmathfloatgreaterthan@#1#2{\pgfmathfloatlessthan@{#2}{#1}}% +\let\pgfmathfloatgreaterthan=\pgfmathfloatgreaterthan@ +\let\pgfmathfloatgreater@=\pgfmathfloatgreaterthan@ + +\def\pgfmathfloatmax@#1{% + \begingroup + \pgfmathfloatcreate{2}{1.0}{2147483644}% + \let\pgfmathmaxsofar=\pgfmathresult + \pgfmathfloatmax@@#1{}% +}% +\def\pgfmathfloatmax@@#1{% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \expandafter\pgfmathfloatmax@@@% + \else% + \pgfmathfloatlessthan{\pgfmathmaxsofar}{#1}% + \ifpgfmathfloatcomparison + \edef\pgfmathmaxsofar{#1}% + \fi + \expandafter\pgfmathfloatmax@@% + \fi% +}% +\def\pgfmathfloatmax@@@{% + \let\pgfmathresult=\pgfmathmaxsofar + \pgfmath@smuggleone{\pgfmathresult}% + \endgroup +}% +\def\pgfmathfloatmin@#1{% + \begingroup + \pgfmathfloatcreate{1}{1.0}{2147483644}% + \let\pgfmathminsofar=\pgfmathresult + \pgfmathfloatmin@@#1{}% +}% +\def\pgfmathfloatmin@@#1{% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \expandafter\pgfmathfloatmin@@@% + \else% + \pgfmathfloatlessthan{#1}{\pgfmathminsofar}% + \ifpgfmathfloatcomparison + \edef\pgfmathminsofar{#1}% + \fi + \expandafter\pgfmathfloatmin@@% + \fi% +}% +\def\pgfmathfloatmin@@@{% + \let\pgfmathresult=\pgfmathminsofar + \pgfmath@smuggleone{\pgfmathresult}% + \endgroup +}% + +\def\pgfmathfloatmaxtwo#1#2{% + \pgfmathfloatlessthan{#1}{#2}% + \ifpgfmathfloatcomparison + \edef\pgfmathresult{#2}% + \else + \edef\pgfmathresult{#1}% + \fi +}% +\let\pgfmathfloatmax=\pgfmathfloatmaxtwo + +\def\pgfmathfloatmintwo#1#2{% + \pgfmathfloatlessthan{#1}{#2}% + \ifpgfmathfloatcomparison + \edef\pgfmathresult{#1}% + \else + \edef\pgfmathresult{#2}% + \fi +}% +\let\pgfmathfloatmin=\pgfmathfloatmintwo + +% Renormalizes #1 to extended precision mantissa, meaning +% 100 <= m < 1000 +% instead of 1 <= m < 10. +% +% The 'extended precision' means we have higher accuracy when we apply pgfmath operations to mantissas. +% +% The input argument is expected to be a normalized floating point number; the output argument is a non-normalized floating point number (well, normalized to extended precision). +% +% The operation is supposed to be very fast. +% +% @see \pgfmathfloatsetextprecision +% +% There is a routine for internal usage, +% \pgfmathfloattoextentedprecision@a. It also provides exponent and +% sign of #1 in output arguments and may be used to increase speed. +\def\pgfmathfloattoextentedprecision#1{% + \begingroup + \pgfmathfloattoextentedprecision@a{#1}% + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\pgfmathresult}{\the\pgfmathfloat@a@E}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +\def\pgfmathfloattoextentedprecision@@zero#1\pgfmathfloat@EOI{% + \edef\pgfmathresult{#1}% +}% +\def\pgfmathfloattoextentedprecision@@one#1.#2#3\pgfmathfloat@EOI{% + \edef\pgfmathresult{#1#2.#3}% +}% +\def\pgfmathfloattoextentedprecision@@two#1.#2#3#4\pgfmathfloat@EOI{% + \edef\pgfmathresult{#1#2#3.#4}% +}% +\def\pgfmathfloattoextentedprecision@@three#1.#2#3#4#5\pgfmathfloat@EOI{% + \edef\pgfmathresult{#1#2#3#4.#5}% +}% + +% Sets extended precision to 10^#1. +% +% The different choices are +% +% - 0: normalization 0 <= m < 1 (disable extended precision) +% - 1: normalization 10 <= m < 100 +% - 2: normalization 100 <= m < 1000 (default) +% - 3: normalization 1000 <= m < 10000 +% +% #1 is the exponent, #1 = 0,1,2 or 3. +% +% This setting applies to \pgfmathfloattoextentedprecision and friends. +\def\pgfmathfloatsetextprecision#1{% + \ifcase#1\relax + \let\pgfmathfloattoextentedprecision@@=\pgfmathfloattoextentedprecision@@zero + \def\pgfmathfloatextprec@shift{0}% + \or + \let\pgfmathfloattoextentedprecision@@=\pgfmathfloattoextentedprecision@@one + \def\pgfmathfloatextprec@shift{1}% + \or + \let\pgfmathfloattoextentedprecision@@=\pgfmathfloattoextentedprecision@@two + \def\pgfmathfloatextprec@shift{2}% + \else + \let\pgfmathfloattoextentedprecision@@=\pgfmathfloattoextentedprecision@@three + \def\pgfmathfloatextprec@shift{3}% + \fi +}% +\pgfmathfloatsetextprecision{2}% + +% Does the "hard" work for \pgfmathfloattoextentedprecision. It +% provides additional outputs. +% +% INPUT: +% #1 normalized floating point number. Maybe a macro (it will be expanded ONCE) +% +% OUTPUT: +% - \pgfmathresult : the mantissa in extended precision +% - \pgfmathfloat@a@S : the sign of #1 +% - \pgfmathfloat@a@E : the exponent of #1, adjusted for extended precision +% - \pgfmathfloat@a@Mtok : undefined (its contents will be destroyed. +% +\def\pgfmathfloattoextentedprecision@a#1{% + \edef\pgfmathresult{#1}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifnum\pgfmathfloat@a@S<3 + \advance\pgfmathfloat@a@E by-\pgfmathfloatextprec@shift\relax% compensate for shift + \expandafter\pgfmathfloattoextentedprecision@@\the\pgfmathfloat@a@Mtok 000\pgfmathfloat@EOI + \fi +}% + + +% Similar to \pgfmathfloattoextentedprecision@a, this one here fills the '@b' registers. +\def\pgfmathfloattoextentedprecision@b#1{% + \edef\pgfmathresult{#1}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@b@S\pgfmathfloat@a@Mtok\pgfmathfloat@b@E + \ifnum\pgfmathfloat@b@S<3 + \advance\pgfmathfloat@b@E by-\pgfmathfloatextprec@shift\relax + \expandafter\pgfmathfloattoextentedprecision@@\the\pgfmathfloat@a@Mtok 00\pgfmathfloat@EOI + \fi +}% + +% Addition of two floating point numbers using 8 significant digits. +\def\pgfmathfloatadd@#1#2{% + \begingroup + % + % renormalize argument to 100 <= m < 1000 for extended accuracy: + \pgfmathfloattoextentedprecision@a{#1}% + \let\pgfmathfloat@arga=\pgfmathresult + % + \pgfmathfloattoextentedprecision@b{#2}% + \let\pgfmathfloat@argb=\pgfmathresult + % + \pgfmathfloatcomparisontrue% re-use this boolean here to handle special cases. + \ifcase\pgfmathfloat@a@S + \edef\pgfmathresult{#2}% + \pgfmathfloatcomparisonfalse + \or + \or + \edef\pgfmathfloat@arga{-\pgfmathfloat@arga}% + \else + \pgfmathfloatcomparisonfalse + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{0.0}{0}% + \fi + \ifcase\pgfmathfloat@b@S + \edef\pgfmathresult{#1}% + \pgfmathfloatcomparisonfalse + \or + \or + \edef\pgfmathfloat@argb{-\pgfmathfloat@argb}% + \else + \pgfmathfloatcomparisonfalse + \pgfmathfloatcreate{\the\pgfmathfloat@b@S}{0.0}{0}% + \fi + \ifpgfmathfloatcomparison + % Shift lesser mantisse to fit the larger one: + \ifnum\pgfmathfloat@a@E<\pgfmathfloat@b@E + \pgfmathfloatadd@shift{\pgfmathfloat@arga}{\pgfmathfloat@a@E}{\pgfmathfloat@b@E}% + \else + \pgfmathfloatadd@shift{\pgfmathfloat@argb}{\pgfmathfloat@b@E}{\pgfmathfloat@a@E}% + \fi + % add them! + \pgfmath@basic@add@{\pgfmathfloat@arga}{\pgfmathfloat@argb}% + % renormalize sum. This is the only part were an expensive routine comes into play: + \edef\pgfmathresult{\pgfmathresult e\the\pgfmathfloat@a@E}% + \expandafter\pgfmathfloatqparsenumber\expandafter{\pgfmathresult}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +% #1= floating point number +% #2= TeX code to execute if #1 == 0 +% #3= TeX code to execute if #1 != 0 +\def\pgfmathfloatifzero#1#2#3{% + \pgfmathfloatgetflagstomacro{#1}\pgfmathfloat@loc@TMPa + \if\pgfmathfloat@loc@TMPa0 #2\else#3\fi +}% + +\def\pgfmathfloatiffinite#1#2#3{% + \pgfmathfloatgetflagstomacro{#1}\pgfmathfloatiffinite@ + \ifnum\pgfmathfloatiffinite@>2 #3\else #2\fi +}% + +\def\pgfmathfloatifthenelse@#1#2#3{% + \pgfmathfloatifflags{#1}{0}{% + \edef\pgfmathresult{#3}%% + }{% + \edef\pgfmathresult{#2}% + }% +}% +\def\pgfmathfloatequal@#1#2{% + \pgfmathfloatifapproxequalrel{#1}{#2}{% + \def\pgfmathresult{1}% + \pgfmathfloatcomparisontrue + }{% + \def\pgfmathresult{0}% + \pgfmathfloatcomparisonfalse + }% +}% +\let\pgfmathfloatequalto@=\pgfmathfloatequal@ + +\def\pgfmathfloatnotequal@#1#2{% + \pgfmathfloatifapproxequalrel{#1}{#2}{% + \def\pgfmathresult{0}% + \pgfmathfloatcomparisonfalse + }{% + \def\pgfmathresult{1}% + \pgfmathfloatcomparisontrue + }% +}% +\let\pgfmathfloatnotequalto@=\pgfmathfloatnotequal@ + +% Computes the relative error between #1 and #2 (assuming #2 != 0) and +% invokes #3 if the relative error is below `/pgf/fpu/rel thresh' and +% #4 if that is not the case. +\long\def\pgfmathfloatifapproxequalrel#1#2#3#4{% + \begingroup + \pgfmathfloatparsenumber{#1}% + \let\pgfmathfloatarga=\pgfmathresult + \pgfmathfloatparsenumber{#2}% + \let\pgfmathfloatargb=\pgfmathresult + \pgfmathfloatrelerror@\pgfmathfloatarga\pgfmathfloatargb + \let\pgfmathfloatarga=\pgfmathresult + \pgfmathfloatlessthan@\pgfmathfloatarga\pgfmathfloat@relthresh + \ifpgfmathfloatcomparison + \def\pgfmathfloat@loc@TMPa{#3}% + \else + \def\pgfmathfloat@loc@TMPa{#4}% + \fi + \expandafter\endgroup + \pgfmathfloat@loc@TMPa +}% + +% Invokes code '#3' if the flags of the floating point number '#1' +% match the flag provided in '#2'. +% +% \pgfmathfloatcreate{1}{1.0}{2} +% \pgfmathfloatifflags{\pgfmathresult}{0}{It's zero!}{It's not zero!}% +% \pgfmathfloatifflags{\pgfmathresult}{1}{It's positive!}{It's not positive!}% +% \pgfmathfloatifflags{\pgfmathresult}{2}{It's negative!}{It's not negative!}% +% or, equivalently +% \pgfmathfloatifflags{\pgfmathresult}{+}{It's positive!}{It's not positive!}% +% \pgfmathfloatifflags{\pgfmathresult}{-}{It's negative!}{It's not negative!}% +% it also supports #2=u which means 'unbounded' +\def\pgfmathfloatifflags#1#2#3#4{% + \if#2-% + \pgfmathfloatifflags{#1}{2}{#3}{#4}% + \else + \if#2+% + \pgfmathfloatifflags{#1}{1}{#3}{#4}% + \else + \pgfmathfloatgetflagstomacro{#1}\pgfmathfloat@loc@TMPa + \if#2u% + \ifnum\pgfmathfloat@loc@TMPa>2 + #3\relax + \else + #4\relax + \fi + \else + \if\pgfmathfloat@loc@TMPa#2% + #3\relax + \else + #4\relax + \fi + \fi + \fi + \fi +}% + +% #1=mantissa which needs to be shifted (with smaller exponent) +% #2=smaller exponent +% #3=larger exponent +% +% ATTENTION: this helper method DESTROYS contents of \pgfmathfloat@a@S. +\def\pgfmathfloatadd@shift#1#2#3{% + \pgf@xa=#1 pt% + \pgfmathfloat@a@S=#3\relax + \advance\pgfmathfloat@a@S by-#2\relax + \ifcase\pgfmathfloat@a@S + \or + \divide\pgf@xa by10\relax + \or + \divide\pgf@xa by100\relax + \or + \divide\pgf@xa by1000\relax + \or + \divide\pgf@xa by10000\relax + \or + \divide\pgf@xa by10000\relax + \divide\pgf@xa by10\relax + \or + \divide\pgf@xa by10000\relax + \divide\pgf@xa by100\relax + \or + \divide\pgf@xa by10000\relax + \divide\pgf@xa by1000\relax + \or + \divide\pgf@xa by10000\relax + \divide\pgf@xa by10000\relax + \else + \pgf@xa=0pt% + \fi + #2=#3\relax + \edef#1{\pgf@sys@tonumber\pgf@xa}% +}% + +\let\pgfmathfloatadd=\pgfmathfloatadd@ + + +% Subtracts two floating point numbers. +\def\pgfmathfloatsubtract@#1#2{% + \begingroup + \edef\pgfmathresult{#2}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@b@S\pgfmathfloat@a@Mtok\pgfmathfloat@b@E + \ifcase\pgfmathfloat@b@S + \edef\pgfmathresult{#1}% + \or + \pgfmathfloatcreate{2}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@b@E}% + \let\pgfmathfloatsub@arg=\pgfmathresult + \pgfmathfloatadd@{#1}{\pgfmathfloatsub@arg}% + \or + \pgfmathfloatcreate{1}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@b@E}% + \let\pgfmathfloatsub@arg=\pgfmathresult + \pgfmathfloatadd@{#1}{\pgfmathfloatsub@arg}% + \else + \pgfmathfloatcreate{\the\pgfmathfloat@b@S}{0.0}{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +\let\pgfmathfloatsubtract=\pgfmathfloatsubtract@ + +% Scales a floating point number #1 with a fixed point number #2 using pgfmathmultiply. +% +% Use this method if #2 is small number. +\def\pgfmathfloatmultiplyfixed@#1#2{% + \begingroup + % + % renormalize argument to 100 <= m < 1000 for extended accuracy: + \pgfmathfloattoextentedprecision@a{#1}% + \let\pgfmathfloat@arga=\pgfmathresult + % + \pgfmathfloatcomparisontrue% re-use this boolean here to handle special cases. + \ifcase\pgfmathfloat@a@S + \edef\pgfmathresult{#1}% + \pgfmathfloatcomparisonfalse + \or + \or + \edef\pgfmathfloat@arga{-\pgfmathfloat@arga}% + \else + \pgfmathfloatcomparisonfalse + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{0.0}{0}% + \fi + \ifpgfmathfloatcomparison + \pgfmath@basic@multiply@{\pgfmathfloat@arga}{#2}% + % renormalize product. This is the only part were an expensive routine comes into play: + \edef\pgfmathresult{\pgfmathresult e\the\pgfmathfloat@a@E}% + \expandafter\pgfmathfloatqparsenumber\expandafter{\pgfmathresult}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +\let\pgfmathfloatmultiplyfixed=\pgfmathfloatmultiplyfixed@ + + +\def\pgfmathfloatmultiply@#1#2{% + \begingroup + \pgfmathfloatsetextprecision{1}% + \pgfmathfloattoextentedprecision@a{#1}% + \let\pgfmathfloat@arga=\pgfmathresult + % + \pgfmathfloattoextentedprecision@b{#2}% + \let\pgfmathfloat@argb=\pgfmathresult + % + \pgfmathfloatcomparisontrue% re-use this boolean here to handle special cases. + \ifcase\pgfmathfloat@a@S + % 0 + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or% + + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \def\pgfmathresult@S{1}% + \or + \def\pgfmathresult@S{2}% + \else + \expandafter\pgfmathfloatcreate\the\pgfmathfloat@b@S{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \or% - + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \def\pgfmathresult@S{2}% + \or + \def\pgfmathresult@S{1}% + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \or% nan + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or% +infty + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \or% -infty + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \fi + \ifpgfmathfloatcomparison + \pgfmath@basic@multiply@{\pgfmathfloat@arga}{\pgfmathfloat@argb}% + \advance\pgfmathfloat@a@E by\pgfmathfloat@b@E + % renormalize sum. This is the only part were an expensive routine comes into play: + \edef\pgfmathresult{\pgfmathresult e\the\pgfmathfloat@a@E}% + \expandafter\pgfmathfloatqparsenumber\expandafter{\pgfmathresult}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \pgfmathfloatcreate{\pgfmathresult@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatmultiply=\pgfmathfloatmultiply@ + +% Defines \pgfmathresult to be #1 / #2 for two floating point numbers. +% +% It employs the basic math engine internally to divide mantissas. +\def\pgfmathfloatdivide@#1#2{% + \begingroup + \pgfmathfloatsetextprecision{1}% is not too important, I think. After all, 0.1 <= #1/#2 < 10 or so due to normalization (no matter, which) + \edef\pgfmathfloat@arga{#1}% + \pgfmathfloattoextentedprecision@a{\pgfmathfloat@arga}% + \let\pgfmathfloat@arga=\pgfmathresult + % + \edef\pgfmathfloat@argb{#2}% + \pgfmathfloattoextentedprecision@b{\pgfmathfloat@argb}% + \let\pgfmathfloat@argb=\pgfmathresult + % + \pgfmathfloatcomparisontrue% re-use this boolean here to handle special cases. + \ifcase\pgfmathfloat@a@S + % 0 + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or% + + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \def\pgfmathresult@S{1}% + \or + \def\pgfmathresult@S{2}% + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \else + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \or% - + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \def\pgfmathresult@S{2}% + \or + \def\pgfmathresult@S{1}% + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \else + \pgfmathfloatcreate{0}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \or% nan + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or% +infty + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% what is inf/inf ? + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% or inf/-inf ? + \pgfmathfloatcomparisonfalse + \fi + \or% -infty + \ifcase\pgfmathfloat@b@S + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{3}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{5}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \or + \pgfmathfloatcreate{4}{0.0}{0}% + \pgfmathfloatcomparisonfalse + \fi + \fi + \ifpgfmathfloatcomparison + \pgfmath@basic@divide@{\pgfmathfloat@arga}{\pgfmathfloat@argb}% + \advance\pgfmathfloat@a@E by-\pgfmathfloat@b@E + % renormalize. This is the only part were an expensive float routine comes into play: + \edef\pgfmathresult{\pgfmathresult e\the\pgfmathfloat@a@E}% + \expandafter\pgfmathfloatqparsenumber\expandafter{\pgfmathresult}% + % And re-insert the proper sign: + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \pgfmathfloatcreate{\pgfmathresult@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatdivide=\pgfmathfloatdivide@ + +\def\pgfmathfloatreciprocal@#1{% + \begingroup + % FIXME optimize + \edef\pgfmathfloat@loc@TMPa{#1}% + \pgfmathfloatcreate{1}{1.0}{0}% + \pgfmathfloatdivide@{\pgfmathresult}{\pgfmathfloat@loc@TMPa}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +% Computes sqrt(#1) in floating point arithmetics. +% +% It employs sqrt( m * 10^e ) = sqrt(m) * sqrt(10^e). +\def\pgfmathfloatsqrt@#1{% + \begingroup + \pgfmathfloatsetextprecision{3}% + \edef\pgfmathfloat@arga{#1}% + \pgfmathfloattoextentedprecision@a{\pgfmathfloat@arga}% + \let\pgfmathfloat@arga=\pgfmathresult + % + \ifcase\pgfmathfloat@a@S + % 0 + \pgfmathfloatcreate{0}{0.0}{0}% + \or% + + \pgfmath@basic@sqrt@{\pgfmathfloat@arga}% + \ifodd\pgfmathfloat@a@E + \ifnum\pgfmathfloat@a@E>0 + \expandafter\pgfmath@basic@multiply@\expandafter{\pgfmathresult}{3.16227766}% * sqrt(10) + \else + \expandafter\pgfmath@basic@multiply@\expandafter{\pgfmathresult}{0.316227766}% * sqrt(0.1) + \fi + \fi + \divide\pgfmathfloat@a@E by2 % sqrt(10^e) = 10^{e/2} (see above for odd e) + % renormalize sum. This is the only part were an expensive routine comes into play: + \edef\pgfmathfloat@arga{\pgfmathresult e\the\pgfmathfloat@a@E}% + \pgfmathfloatqparsenumber{\pgfmathfloat@arga}% + \or% - + \pgfmathfloatcreate{3}{0.0}{0}% + \or% nan + \pgfmathfloatcreate{3}{0.0}{0}% + \or% +infty + \pgfmathfloatcreate{4}{0.0}{0}% + \or% -infty + \pgfmathfloatcreate{3}{0.0}{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatsqrt=\pgfmathfloatsqrt@ + +% Returns the integer part of the floating point number #1. +% +% The result is returned as floating point as well. +% +% This operation is not limited to TeX's range of count registers (it +% works symbolly) +% +% @see \pgfmathfloattoint +% POSTCONDITION: \pgfmathresult contains the result and +% \pgfmathfloatintwasnoop=1 if there was nothing to do +% \pgfmathfloatintwasnoop=0 if there where non-zero digits after the period +% \pgfmathfloatintwasnoop=2 if there where digits after the period. The digits will be stored in \pgfmathfloatintremainder in this case. +\def\pgfmathfloatint@#1{% + \begingroup + \edef\pgfmathfloatint@input{#1}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathfloatint@input\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \gdef\pgfmathfloatintwasnoop{1}% + \gdef\pgfmathfloatintremainder{}% + \ifcase\pgfmathfloat@a@S + % 0: nothing to do. + \or% + + \expandafter\pgfmathfloatint@@\the\pgfmathfloat@a@Mtok\pgfmathfloat@EOI + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \or% - + \expandafter\pgfmathfloatint@@\the\pgfmathfloat@a@Mtok\pgfmathfloat@EOI + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \else + % nothing to do + \fi + %\message{ XXXXX int(\pgfmathfloatint@input) = \pgfmathresult -> was no op = \pgfmathfloatintwasnoop\space (remainder \pgfmathfloatintremainder)^^J}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\def\pgfmathfloatint@@#1.{% + \ifnum\pgfmathfloat@a@E<0 + \pgfmathfloat@a@S=0 + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0 + \gdef\pgfmathfloatintwasnoop{0}% + \expandafter\pgfmathfloatint@@loop@gobble + \else + \pgfmathfloat@a@Mtok={#1.}% + \pgfmathfloat@b@E=\pgfmathfloat@a@E + \expandafter\pgfmathfloatint@@loop + \fi +}% +\def\pgfmathfloatint@@loop#1{% + \def\pgfmathfloatint@@loop@{#1}% + \ifx\pgfmathfloatint@@loop@\pgfmathfloat@EOI + \gdef\pgfmathfloatintwasnoop{1}% + \let\pgfmathfloatint@@loop@next=\relax + \else + \ifnum\pgfmathfloat@b@E=0 + \def\pgfmathfloatint@@loop@next{\pgfmathfloatint@@loop@gobble#1}% + \else + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok#1}% + \advance\pgfmathfloat@b@E by-1 + \let\pgfmathfloatint@@loop@next=\pgfmathfloatint@@loop + \fi + \fi + \pgfmathfloatint@@loop@next +}% +\def\pgfmathfloatint@@loop@gobble#1\pgfmathfloat@EOI{% + \if0\pgfmathfloatintwasnoop + \else + \gdef\pgfmathfloatintwasnoop{2}% + \gdef\pgfmathfloatintremainder{#1}% + \fi +}% +\let\pgfmathfloatint=\pgfmathfloatint@ + +\def\pgfmathfloatfloor#1{% + \edef\pgfmath@orig{#1}% + \pgfmathfloatint@{#1}% + \pgfmathfloatifflags{\pgfmath@orig}{2}{% + \let\pgfmath@trunc=\pgfmathresult + \ifcase\pgfmathfloatintwasnoop\relax + % ah - we stripped something! Round DOWN + \pgfmathfloatcreate{2}{1.0}{0}% -1 + \expandafter\pgfmathfloatadd@\expandafter{\pgfmathresult}{\pgfmath@trunc}% + \or + % was no-op + \let\pgfmathresult=\pgfmath@trunc + \else + % ok, we have to inspect the remainder: + \pgfmathfloatparsenumber{0.\pgfmathfloatintremainder}% + \pgfmathfloatifflags{\pgfmathresult}{1}{% + % ah - we stripped a non-zero remainder! Round DOWN + \pgfmathfloatcreate{2}{1.0}{0}% -1 + \expandafter\pgfmathfloatadd@\expandafter{\pgfmathresult}{\pgfmath@trunc}% + }{% + % was no-op + \let\pgfmathresult=\pgfmath@trunc + }% + \fi + }{}% +}% +\let\pgfmathfloatfloor@=\pgfmathfloatfloor + +\def\pgfmathfloatceil#1{% + \edef\pgfmath@orig{#1}% + \pgfmathfloatint@{#1}% + \pgfmathfloatifflags{\pgfmath@orig}{1}{% + \let\pgfmath@trunc=\pgfmathresult + \ifcase\pgfmathfloatintwasnoop\relax + % ah - we stripped something! Round UP + \pgfmathfloatcreate{1}{1.0}{0}% +1 + \expandafter\pgfmathfloatadd@\expandafter{\pgfmathresult}{\pgfmath@trunc}% + \or + % was no-op + \let\pgfmathresult=\pgfmath@trunc + \else + % ok, we have to inspect the remainder: + \pgfmathfloatparsenumber{0.\pgfmathfloatintremainder}% + \pgfmathfloatifflags{\pgfmathresult}{1}{% + % ah - we stripped a non-zero remainder! Round UP + \pgfmathfloatcreate{1}{1.0}{0}% +1 + \expandafter\pgfmathfloatadd@\expandafter{\pgfmathresult}{\pgfmath@trunc}% + }{% + % was no-op + \let\pgfmathresult=\pgfmath@trunc + }% + \fi + }{}% +}% +\let\pgfmathfloatceil@=\pgfmathfloatceil + +\def\pgfmathfloat@notimplemented#1{% + \pgfmath@error{Sorry, the operation '#1' has not yet been implemented in the floating point unit}{}% + \pgfmathfloatcreate{0}{0.0}{0}% +}% + +% Divides or multiplies the input number by 10^#4 using an arithmetic +% left/right shift. +% +% Input: +% #1 a normalised floating point number. +% #2 a positive or negative integer number denoting the shift. +% +% Example: +% \pgfmathfloatshift{11e3}{4}% +% -> pgfmathresult = 11e7 +\def\pgfmathfloatshift@#1#2{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \advance\pgfmathfloat@a@E by#2\relax + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatshift=\pgfmathfloatshift@ + +% Defines \pgfmathresult to be |#1|, the absolute value of the +% normalized floating point number #1. +\def\pgfmathfloatabs@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S + % 0: do nothing. + \or + % +: ok, is positive. + \or + % -: multiply with -1: + \pgfmathfloat@a@S=1 + \or + % nan: do nothing. + \or + % +infty: ok. + \or + % -infty: multiply with -1: + \pgfmathfloat@a@S=4 + \fi + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +% +% Defines \pgfmathresult to be sign(#1) +\def\pgfmathfloatsign@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S + % 0: + \pgfmathfloatcreate{0}{0.0}{0}% + \or + % +: ok, is positive. + \pgfmathfloatcreate{1}{1.0}{0}% + \or + % -: + \pgfmathfloatcreate{2}{1.0}{0}% + \or + % nan: do nothing. + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \or + % +infty:. + \pgfmathfloatcreate{1}{1.0}{0}% + \or + % -infty: + \pgfmathfloatcreate{2}{1.0}{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatsign=\pgfmathfloatsign@ + +% Computes the absolute error |#1 - #2| into \pgfmathresult. +\def\pgfmathfloatabserror@#1#2{% + \pgfmathfloatsubtract@{#1}{#2}% + \pgfmathfloatabs@{\pgfmathresult}% +}% +\let\pgfmathfloatabserror=\pgfmathfloatabserror@ + +% Computes the relative error |#1 - #2|/|#2| into \pgfmathresult, +% assuming #2 != 0. +\def\pgfmathfloatrelerror@#1#2{% + \pgfmathfloatsubtract@{#1}{#2}% + \let\pgfmathfloat@subtract=\pgfmathresult + \pgfmathfloatifflags{#2}{0}{% + \let\pgfmathresult=\pgfmathfloat@subtract + }{% + \pgfmathfloatdivide@{\pgfmathfloat@subtract}{#2}% + }% + \pgfmathfloatabs@{\pgfmathresult}% +}% +\let\pgfmathfloatrelerror=\pgfmathfloatrelerror@ + +% Computes \pgfmathresult = #1 mod #2 using truncated division. +% +\def\pgfmathfloatmod@#1#2{% + \begingroup + \pgfmathfloattoint{#1}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloattoint{#2}% + \let\pgfmathfloat@loc@TMPb=\pgfmathresult + \c@pgfmath@counta=\pgfmathfloat@loc@TMPa\relax + \divide\c@pgfmath@counta by\pgfmathfloat@loc@TMPb\relax + \expandafter\pgfmathfloatparsenumber\expandafter{\the\c@pgfmath@counta}% + % + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatmultiply@{\pgfmathfloat@loc@TMPa}{#2}% + \let\pgfmathfloat@loc@TMPb=\pgfmathresult + \pgfmathfloatsubtract@{#1}{\pgfmathfloat@loc@TMPb}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatmod=\pgfmathfloatmod@ + + +% A modification of \pgfmathfloatmod@ where #3 = 1/#2 is already +% known. This may be faster. +\def\pgfmathfloatmodknowsinverse@#1#2#3{% + \pgfmathfloatmod@{#1}{#2}% + %-------------------------------------------------- + % \begingroup + % % FIXME : is this function correct? \pgfmathfloatmod had a + % % rounding flaw... + % \pgfmathfloatmultiply@{#1}{#3}% + % \pgfmathfloatint@{\pgfmathresult}% + % \let\pgfmathfloat@loc@TMPa=\pgfmathresult + % \pgfmathfloatmultiply@{\pgfmathfloat@loc@TMPa}{#2}% + % \let\pgfmathfloat@loc@TMPb=\pgfmathresult + % \pgfmathfloatsubtract@{#1}{\pgfmathfloat@loc@TMPb}% + % \pgfmath@smuggleone\pgfmathresult + % \endgroup + %-------------------------------------------------- +}% +\let\pgfmathfloatmodknowsinverse=\pgfmathfloatmodknowsinverse@ + +\def\pgfmathfloatpi@{% + \pgfmathfloatcreate{1}{3.14159265358979}{0}% +}% +\let\pgfmathfloatpi=\pgfmathfloatpi@ + +\def\pgfmathfloate@{% + \pgfmathfloatcreate{1}{2.71828182845905}{0}% +}% +\let\pgfmathfloate=\pgfmathfloate@ + +% Converts #1 from radians to degrees. +\def\pgfmathfloatdeg@#1{% + \expandafter\ifx\csname pgfmfltdeg@factor\endcsname\relax + % Lazy evaluation: + \pgfmathfloatcreate{1}{5.72957795130823}{1}% + \global\let\pgfmfltdeg@factor=\pgfmathresult + \fi + \pgfmathfloatmultiply@{#1}\pgfmfltdeg@factor% +}% +\let\pgfmathfloatdeg=\pgfmathfloatdeg@ + +% Converts #1 from degree to radians. +\def\pgfmathfloatrad@#1{% + \expandafter\ifx\csname pgfmfltrad@factor\endcsname\relax + % Lazy evaluation: + \pgfmathfloatcreate{1}{1.74532925199433}{-2}% + \global\let\pgfmfltrad@factor=\pgfmathresult + \fi + \pgfmathfloatmultiply@{#1}\pgfmfltrad@factor% +}% +\let\pgfmathfloatrad=\pgfmathfloatrad@ + +% Computes #1(#2) where #1 is a trigonometric function, i.e. +% #1(#2) = #1( #2 + r*360 ) +% +% #1 is a one-argument macro which assigns \pgfmathresult. +\def\pgfmathfloatTRIG@#1#2{% + \if0\pgfmath@trig@format@choice + % trig format=deg + \expandafter\ifx\csname pgfmathfloatTRIG@NUM\endcsname\relax% + % Lazy evaluation: + \pgfmathfloatcreate{1}{3.6}{2}% + \global\let\pgfmathfloatTRIG@NUM=\pgfmathresult + \pgfmathfloatcreate{1}{2.77777777777778}{-3}% + \global\let\pgfmathfloatTRIG@NUM@INV=\pgfmathresult + \fi + \pgfmathfloatmodknowsinverse@{#2}{\pgfmathfloatTRIG@NUM}{\pgfmathfloatTRIG@NUM@INV}% + \else + % trig format=rad + \expandafter\ifx\csname pgfmathfloatTRIG@rad@NUM\endcsname\relax% + % Lazy evaluation: + \pgfmathfloatcreate{1}{6.28318530717959}{0}% + \global\let\pgfmathfloatTRIG@rad@NUM=\pgfmathresult + \pgfmathfloatcreate{1}{1.59154943091895}{-1}% + \global\let\pgfmathfloatTRIG@rad@NUM@INV=\pgfmathresult + \fi + \pgfmathfloatmodknowsinverse@{#2}{\pgfmathfloatTRIG@rad@NUM}{\pgfmathfloatTRIG@rad@NUM@INV}% + \fi + \pgfmathfloattofixed@{\pgfmathresult}% + \expandafter#1\expandafter{\pgfmathresult}% + \pgfmathfloatparsenumber{\pgfmathresult}% +}% + +\def\pgfmathfloatsin@#1{\pgfmathfloatTRIG@\pgfmath@basic@sin@{#1}}% +\let\pgfmathfloatsin=\pgfmathfloatsin@ +\def\pgfmathfloatcos@#1{\pgfmathfloatTRIG@\pgfmath@basic@cos@{#1}}% +\let\pgfmathfloatcos=\pgfmathfloatcos@ +\def\pgfmathfloattan@#1{% + % compute sin(#1) / cos(#1) + \begingroup + \pgfmathfloatcos@{#1}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatsin@{#1}% + \expandafter\pgfmathfloatdivide@\expandafter{\pgfmathresult}{\pgfmathfloat@loc@TMPa}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloattan=\pgfmathfloattan@ + +\def\pgfmathfloatcot@#1{% + % compute cos(#1) / sin(#1) + \begingroup + \pgfmathfloatsin@{#1}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatcos@{#1}% + \expandafter\pgfmathfloatdivide@\expandafter{\pgfmathresult}{\pgfmathfloat@loc@TMPa}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatcot=\pgfmathfloatcot@ + +\def\pgfmathfloatatan@#1{% + \begingroup + \expandafter\ifx\csname pgfmathfloatatan@TMP\endcsname\relax% + \pgfmathfloatcreate{1}{1.6}{4}% + \global\let\pgfmathfloatatan@TMP=\pgfmathresult + \pgfmathfloatcreate{2}{1.6}{4}% + \global\let\pgfmathfloatatan@TMPB=\pgfmathresult + \fi + \pgfmathfloatgreaterthan@{#1}{\pgfmathfloatatan@TMP}% + \ifpgfmathfloatcomparison + \pgfmathiftrigonometricusesdeg{% + \pgfmathfloatcreate{1}{9.0}{1}% + }{% + \pgfmathfloatcreate{1}{1.570796326794}{0}% + }% + \else + \pgfmathfloatlessthan{#1}{\pgfmathfloatatan@TMPB}% + \ifpgfmathfloatcomparison + \pgfmathiftrigonometricusesdeg{% + \pgfmathfloatcreate{2}{9.0}{1}% + }{% + \pgfmathfloatcreate{2}{1.570796326794}{0}% + }% + \else + \pgfmathfloattofixed@{#1}% + \expandafter\pgfmath@basic@atan@\expandafter{\pgfmathresult}% + \pgfmathfloatparsenumber{\pgfmathresult}% + \fi + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloatatan=\pgfmathfloatatan@ + +\def\pgfmathfloatatantwo#1#2{% + % Note: first parameter is y (!), second is x (!) + \begingroup% + \let\pgfmath@trig@format@choice@@=\pgfmath@trig@format@choice + \def\pgfmath@trig@format@choice{0}% + % + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \expandafter\pgfmathfloat@decompose#2\relax\pgfmathfloat@b@S\pgfmathfloat@b@M\pgfmathfloat@b@E + \ifnum\pgfmathfloat@a@S=0 + % ok, #1 = 0. Substitute by 1e-16 such that the next \ifnum catches it: + \pgfmathfloat@a@E=-16 % + \fi + % + \ifnum\pgfmathfloat@a@E<-3 % + \ifnum\pgfmathfloat@b@S=2 % + % #2 < 0 + \pgfmathfloatcreate{1}{1.8}{2}% +180 + \else + \ifnum\pgfmathfloat@b@S=1 % + % #2 >0 + \pgfmathfloatcreate{0}{0.0}{0}% + \else + % + or - 90, just use the sign of #1: + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{9.0}{1}% + \fi + \fi + \else% + \pgfmathfloatabs@{#1}\let\pgfmath@tempa\pgfmathresult% + \pgfmathfloatabs@{#2}\let\pgfmath@tempb\pgfmathresult% + \pgfmathfloatgreaterthan@{\pgfmath@tempa}{\pgfmath@tempb}% + \ifpgfmathfloatcomparison + \pgfmathfloatdivide@{#2}{\pgfmath@tempa}% + \expandafter\pgfmathfloatatan@\expandafter{\pgfmathresult}% + \let\pgfmath@tempa=\pgfmathresult + \pgfmathfloatcreate{1}{9.0}{1}% + \let\pgfmath@tempb=\pgfmathresult + \pgfmathfloatsubtract@{\pgfmath@tempb}{\pgfmath@tempa}% + \else% + \pgfmathfloatdivide@{\pgfmath@tempa}{#2}% + \expandafter\pgfmathfloatatan@\expandafter{\pgfmathresult}% + \expandafter\pgfmathfloatifflags\expandafter{\pgfmathresult}{2}{% + \let\pgfmath@tempa=\pgfmathresult + \pgfmathfloatcreate{1}{1.8}{2}% + \let\pgfmath@tempb=\pgfmathresult + \pgfmathfloatadd@{\pgfmath@tempa}{\pgfmath@tempb}% + }{}% + \fi% + % + \pgfmathfloatifflags{#1}{-}{% + % #1 < 0: + \pgfmathfloatmultiplyfixed@{\pgfmathresult}{-1}% + }{}% + \fi% + \if1\pgfmath@trig@format@choice@@ + % trig format=rad + \pgfmathfloat@scale@deg@to@rad\pgfmathresult + \fi + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +}% +\let\pgfmathfloatatantwo@=\pgfmathfloatatantwo +\expandafter\let\csname pgfmathfloatatan2\endcsname=\pgfmathfloatatantwo +\expandafter\let\csname pgfmathfloatatan2@\endcsname=\pgfmathfloatatantwo@ + +\def\pgfmathfloat@scale@deg@to@rad#1{% + \edef\pgfmathfloat@loc@TMPb{#1}% + \pgfmathfloatcreate{1}{1.74532925199433}{-2}% = pi / 180 + \pgfmathfloatmultiply@{\pgfmathresult}{\pgfmathfloat@loc@TMPb}% +}% + +\def\pgfmathfloatsec@#1{\pgfmathfloatTRIG@\pgfmath@basic@cos@{#1}\pgfmathfloatreciprocal@{\pgfmathresult}}% +\let\pgfmathfloatsec=\pgfmathfloatsec@ +\def\pgfmathfloatcosec@#1{\pgfmathfloatTRIG@\pgfmath@basic@sin@{#1}\pgfmathfloatreciprocal@{\pgfmathresult}}% +\let\pgfmathfloatcosec=\pgfmathfloatcosec@ + +% Expands #2 using \edef and invokes #1 with the resulting string. +% +% DEPRECATED +% Example: +% \pgfmath@y=7.9pt +% \pgfmathlog@invoke@expanded\pgfmathexp@{{\pgf@sys@tonumber{\pgfmath@y}}}% +% will invoke +% \pgfmathexp@{7.9} +\def\pgfmathlog@invoke@expanded#1#2{% + \edef\pgfmath@resulttemp{#2}% + \expandafter#1\pgfmath@resulttemp +}% + +\def\pgfmathfloatln@#1{% + \pgfmathlog@float{#1}% + \ifx\pgfmathresult\pgfutil@empty + \pgfmathfloatcreate{3}{0.0}{0}% + \else + \pgfmathfloatparsenumber{\pgfmathresult}% + \fi +}% +\let\pgfmathfloatln=\pgfmathfloatln@ + +\expandafter\def\csname pgfmathfloatlog10@\endcsname#1{% + \pgfmathfloatln@{#1}% + \let\pgfmathfloat@log@e=\pgfmathresult + \pgfmathfloatcreate{1}{4.34294481903252}{-1}% 1/ln(10) + \pgfmathfloatmultiply@{\pgfmathresult}{\pgfmathfloat@log@e}% +}% +\pgfutil@namelet{pgfmathfloatlog10}{pgfmathfloatlog10@}% + +\expandafter\def\csname pgfmathfloatlog2@\endcsname#1{% + \pgfmathfloatln@{#1}% + \let\pgfmathfloat@log@e=\pgfmathresult + \pgfmathfloatcreate{1}{1.44269504088896}{0}% 1/ln(2) + \pgfmathfloatmultiply@{\pgfmathresult}{\pgfmathfloat@log@e}% +}% +\pgfutil@namelet{pgfmathfloatlog2}{pgfmathfloatlog2@}% + +\expandafter\let\expandafter\pgfmathfloatlogtwo\csname pgfmathfloatlog2\endcsname +\expandafter\let\expandafter\pgfmathfloatlogtwo@\csname pgfmathfloatlog2@\endcsname +\expandafter\let\expandafter\pgfmathfloatlogten\csname pgfmathfloatlog10\endcsname +\expandafter\let\expandafter\pgfmathfloatlogten@\csname pgfmathfloatlog10@\endcsname + +% Computes log(x) into \pgfmathresult. +% +% This allows numbers such at 10000000 or 5.23e-10 to be represented +% properly, although TeX-registers would produce overflow/underflow +% errors in these cases. +% +% The natural logarithm is computed using log(X*10^Y) = log(X) + log(10)*Y +% +% FIXME This routine is only kept for backwards compatibility! +% It does not work as expected because +% 1. it calls \pgfmathfloatparsenumber +% 2. it returns the result as fixed point number +% Use \pgfmathln@ instead! +\def\pgfmathlog@#1{% + \pgfmathfloatparsenumber{#1}% + \pgfmathlog@float{\pgfmathresult}% +}% +\let\pgfmathlog=\pgfmathlog@ +\def\pgfmathlog@float#1{% + \begingroup% + % compute #1 = M*10^E with normalised mantissa M = [+-]*[1-9].XXXXX + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifnum\pgfmathfloat@a@S=1 + % Now, compute log(#1) = log(M) + E*log(10) + \expandafter\pgfmath@basic@ln@\expandafter{\the\pgfmathfloat@a@Mtok}% + \pgfmathfloat@b@M=\pgfmathresult pt% + \pgfmathfloat@a@M=2.302585pt% = log(10) + \multiply\pgfmathfloat@a@M by\pgfmathfloat@a@E\relax + \advance\pgfmathfloat@b@M by\pgfmathfloat@a@M + \edef\pgfmathresult{\pgf@sys@tonumber{\pgfmathfloat@b@M}}% + \else + \let\pgfmathresult=\pgfutil@empty% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup% +}% + + +% Computes exp(#1) in floating point. +% +% The algorithm employs the identity +% exp(x) = exp(x - log(10^k) + log(10^k) +% = 10^k exp( x - k*log 10 ) +% with k chosen such that exp( x - k*log10) can be computed with the +% basic level math engine. +% +% The precision (relative error) is between 10^{-4} and 10^{-6}. For +% #1 = 700, it is even 10^{-3}. I will need to improve that someday. +\def\pgfmathfloatexp@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S + % #1 = 0: + \pgfmathfloatcreate{1}{1.0}{0}% + \or% #1 > 0 + \pgfmathfloatexp@@{#1}% + \or% #1 < 0 + \pgfmathfloatexp@@{#1}% + \else + \edef\pgfmathresult{#1}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\def\pgfmathfloatexp@@#1{% + % Employ the identity + % exp(x) = exp(x - log(10^k) + log(10^k)) = 10^k exp( x - k *log(10)) + % + % I'd like to have x - k*log(10) <= 1 + % => compute k := int( (x - 1) * 1/log(10) ) + % that should suffice since \pgfmathexp@ should be + % accurate enough for those numbers. + % + % please note that we can do all this in TeX registers. + % exp(700) is almost the maximum of double precision + % anyway, and exp(16000) is certainly the largest we will + % ever need. + \pgfmathfloattofixed@{#1}% + \pgf@xa=\pgfmathresult pt + \pgf@xa=0.434294481\pgf@xa\relax + \edef\pgfmathfloat@loc@TMPa{\pgf@sys@tonumber{\pgf@xa}}% + \expandafter\pgfmathfloatexp@@toint\pgfmathfloat@loc@TMPa\relax + \pgf@xa=2.302585092pt + \multiply\pgf@xa by-\pgfmathfloat@k\relax + \advance\pgf@xa by\pgfmathresult pt + \edef\pgfmathfloat@loc@TMPa{\pgf@sys@tonumber{\pgf@xa}}% +%\message{computing exp(\pgfmathresult) = 10^\pgfmathfloat@k * exp(\pgfmathfloat@loc@TMPa)...}% + \pgfmath@basic@exp@{\pgfmathfloat@loc@TMPa}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatparsenumber{\pgfmathfloat@loc@TMPa}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatshift@{\pgfmathfloat@loc@TMPa}{\pgfmathfloat@k}% +}% +% determine 'k'. This is a heuristics. The exponential series +% converges best for |x| <= 1. However, the fixed point arithmetics +% for tex results in best results for large |x|. Well, I'll need to +% tune this here. +\def\pgfmathfloatexp@@toint#1.#2\relax{% + \c@pgf@counta=#1\relax + \ifnum\c@pgf@counta<0 +\advance\c@pgf@counta by-1 % FIXME . this is a test for optimizations. + \c@pgf@countb=#2\relax + \ifnum\c@pgf@countb>0 + \advance\c@pgf@counta by-1 + \fi + \fi + \edef\pgfmathfloat@k{\the\c@pgf@counta}% +}% +\let\pgfmathfloatexp=\pgfmathfloatexp@ + +\def\pgfmathfloatround@#1{% + \begingroup + \pgfkeysvalueof{/pgf/number format/precision/.@cmd}0\pgfeov + \pgfmathfloattofixed{#1}% + \pgfmathroundto{\pgfmathresult}% + \pgfmathfloatparsenumber{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + + +\def\pgfmathfloatneg@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S\relax + % 0: + \edef\pgfmathresult{#1}% + \or + % +: + \pgfmathfloatcreate{2}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \or + % -: + \pgfmathfloatcreate{1}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \or + % nan: + \edef\pgfmathresult{#1}% + \or + % +infty: + \pgfmathfloatcreate{5}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \or + % -infty: + \pgfmathfloatcreate{4}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + + +\def\pgfmathfloatpow@#1#2{% + \begingroup% + \expandafter\pgfmathfloat@decompose@tok#2\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S\relax + % #1 ^ 0 = 1 + \pgfmathfloatcreate{1}{1.0}{0}% + \or + % #2 > 0 + \pgfmathfloatpow@@{#1}{#2}% + \or + % #2 < 0 + \pgfmathfloatpow@@{#1}{#2}% + \or + % #2 = nan + \edef\pgfmathresult{#2}% + \or + % #2 = inf + \edef\pgfmathresult{#2}% + \or + % #2 = -inf + \pgfmathfloatcreate{0}{0.0}{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +% computes #1^#2 +% PRECONDITIONS +% - #2 is positive. +\def\pgfmathfloatpow@@#1#2{% + \pgfmathfloattofixed@{#2}% + \afterassignment\pgfmath@x% + \expandafter\c@pgfmath@counta\pgfmathresult pt\relax% + \ifdim\pgfmath@x=0pt % + % loop "manually"; we have an integer exponent! + \ifnum\c@pgfmath@counta<0 + \pgfmathfloatreciprocal@{#1}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \c@pgfmath@counta=-\c@pgfmath@counta + \else + \edef\pgfmathfloat@loc@TMPa{#1}% + \fi + \pgfmathfloatcreate{1}{1.0}{0}% + \let\pgfmathfloat@loc@TMPb=\pgfmathresult + \pgfmathloop + \ifnum\c@pgfmath@counta>0\relax% + \ifodd\c@pgfmath@counta% + \pgfmathfloatmultiply@{\pgfmathfloat@loc@TMPb}{\pgfmathfloat@loc@TMPa}% + \let\pgfmathfloat@loc@TMPb=\pgfmathresult + \fi + \ifnum\c@pgfmath@counta>1\relax% + \pgfmathfloatmultiply@{\pgfmathfloat@loc@TMPa}{\pgfmathfloat@loc@TMPa}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \fi% + \divide\c@pgfmath@counta by2\relax% + \repeatpgfmathloop% + \else + \pgfmathfloatgetflags{#1}\c@pgfmath@counta + \ifnum0=\c@pgfmath@counta + % ah: 0^x + \pgfmathfloatgetflags{#2}\c@pgfmath@counta + \ifnum0=\c@pgfmath@counta + % ah: 0^0 + \pgfmathfloatcreate{1}{1.0}{0}% + \else + % ah: 0^x with x!=0: + \pgfmathfloatcreate{0}{0.0}{0}% + \fi + \else + % employ #1^#2 = exp( #2 * ln(#1) ) + \pgfmathfloatln@{#1}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \edef\pgfmathfloat@loc@TMPb{#2}% + \pgfmathfloatmultiply@{\pgfmathfloat@loc@TMPa}{\pgfmathfloat@loc@TMPb}% + \pgfmathfloatexp@{\pgfmathresult}% + \fi + \fi +}% + +\def\pgfmathfloat@definemethodfrombasic@NOARG#1{% + \pgfutil@ifundefined{pgfmath@basic@#1@}{% + \pgfutil@namelet{pgfmath@basic@#1@}{pgfmath#1@}% + }{}% + \edef\pgfmathfloat@glob@TMP{% + \expandafter\noexpand\csname pgfmath@basic@#1@\endcsname + \noexpand\pgfmathfloatparsenumber{\noexpand\pgfmathresult}% + }% + \expandafter\let\csname pgfmathfloat#1@\endcsname=\pgfmathfloat@glob@TMP% + \expandafter\let\csname pgfmathfloat#1\endcsname=\pgfmathfloat@glob@TMP% +}% +\def\pgfmathfloat@definemethodfrombasic@ONEARG#1{% + \pgfutil@ifundefined{pgfmath@basic@#1@}{% + \pgfutil@namelet{pgfmath@basic@#1@}{pgfmath#1@}% + }{}% + \edef\pgfmathfloat@glob@TMP##1{% + \noexpand\pgfmathfloattofixed{##1}% + \noexpand\expandafter + \expandafter\noexpand\csname pgfmath@basic@#1@\endcsname\noexpand\expandafter% + {\noexpand\pgfmathresult}% + \noexpand\pgfmathfloatparsenumber{\noexpand\pgfmathresult}% + }% + \expandafter\let\csname pgfmathfloat#1@\endcsname=\pgfmathfloat@glob@TMP% + \expandafter\let\csname pgfmathfloat#1\endcsname=\pgfmathfloat@glob@TMP% +}% +\def\pgfmathfloat@definemethodfrombasic@TWOARGS#1{% + \pgfutil@ifundefined{pgfmath@basic@#1@}{% + \pgfutil@namelet{pgfmath@basic@#1@}{pgfmath#1@}% + }{}% + \edef\pgfmathfloat@glob@TMP##1##2{% + \noexpand\pgfmathfloattofixed{##2}% + \noexpand\let\noexpand\pgfmathfloat@loc@TMPa=\noexpand\pgfmathresult + \noexpand\pgfmathfloattofixed{##1}% + \noexpand\expandafter + \expandafter\noexpand\csname pgfmath@basic@#1@\endcsname\noexpand\expandafter% + {\noexpand\pgfmathresult}{\noexpand\pgfmathfloat@loc@TMPa}% + \noexpand\pgfmathfloatparsenumber{\noexpand\pgfmathresult}% + }% + \expandafter\let\csname pgfmathfloat#1@\endcsname=\pgfmathfloat@glob@TMP% + \expandafter\let\csname pgfmathfloat#1\endcsname=\pgfmathfloat@glob@TMP% +}% +\pgfmathfloat@definemethodfrombasic@NOARG{rand}% +\pgfmathfloat@definemethodfrombasic@NOARG{rnd}% +\pgfmathfloat@definemethodfrombasic@NOARG{false}% +\pgfmathfloat@definemethodfrombasic@NOARG{true}% +% arcsin, arccos +\pgfmathfloat@definemethodfrombasic@ONEARG{asin}% +\pgfmathfloat@definemethodfrombasic@ONEARG{acos}% +\pgfmathfloat@definemethodfrombasic@ONEARG{not}% +\pgfmathfloat@definemethodfrombasic@ONEARG{hex}% +\pgfmathfloat@definemethodfrombasic@ONEARG{Hex}% +\pgfmathfloat@definemethodfrombasic@ONEARG{oct}% +\pgfmathfloat@definemethodfrombasic@ONEARG{bin}% +\pgfmathfloat@definemethodfrombasic@TWOARGS{and}% +\pgfmathfloat@definemethodfrombasic@TWOARGS{or}% + +\pgfutil@ifundefined{pgfmathdeclarefunction}{% + % special treatment: \pgfmathrand@ was not properly defined for pgf 2.00: + \let\pgfmath@basic@rand=\pgfmathrand + \let\pgfmath@basic@rand@=\pgfmathrand@ + \def\pgfmathfloatrand@{% + \pgfmath@basic@rand + \pgfmathfloatparsenumber{\pgfmathresult}% + }% + \let\pgfmathfloatrand=\pgfmathfloatrand@% + % + % special treatment: \pgfmathrnd@ was not properly defined for pgf 2.00: + \let\pgfmath@basic@rnd=\pgfmathrnd + \let\pgfmath@basic@rnd@=\pgfmathrnd@ + \def\pgfmathfloatrnd@{% + \pgfmath@basic@rnd + \pgfmathfloatparsenumber{\pgfmathresult}% + }% + \let\pgfmathfloatrnd=\pgfmathfloatrnd@% +}{}% + +% Implements the factorial of '#1'. +% This does only work if '#1 < 2^32'. +\def\pgfmathfloatfactorial@#1{% + \begingroup + \pgfmathfloattofixed{#1}% + % collect integer part into a 32 bit register: + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgfmath@counta\pgfmathresult\relax\pgfmath@% + \pgfmathfloatcreate{1}{1.0}{0}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathloop + \ifnum\c@pgfmath@counta<2 % + \else + \expandafter\pgfmathfloatparsenumber\expandafter{\the\c@pgfmath@counta}% + \expandafter\pgfmathfloatmultiply@\expandafter{\pgfmathresult}{\pgfmathfloat@loc@TMPa}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \advance\c@pgfmath@counta by-1\relax% + \repeatpgfmathloop + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +% Implements the vector length of a 2D vector. +% +% ATTENTION: this does NOT use the improved code of the basic layer! +% It simply computed sqrt( #1^2 + #2^2 )! +\def\pgfmathfloatveclen@#1#2{% + \begingroup + \edef\pgfmathfloat@@a{#1}% + \pgfmathfloatmultiply@{\pgfmathfloat@@a}{\pgfmathfloat@@a}% + \let\pgfmathfloat@@a=\pgfmathresult + % + \edef\pgfmathfloat@@b{#2}% + \pgfmathfloatmultiply@{\pgfmathfloat@@b}{\pgfmathfloat@@b}% + \let\pgfmathfloat@@b=\pgfmathresult + % + \pgfmathfloatadd@{\pgfmathfloat@@a}{\pgfmathfloat@@b}% + \pgfmathfloatsqrt@{\pgfmathresult}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +\def\pgfmathfloatcosh@#1{% + \begingroup + \pgfmathfloatexp@{#1}% + \let\pgfmathfloat@@a=\pgfmathresult + % + \pgfmathfloatneg@{#1}% + \pgfmathfloatexp@{\pgfmathresult}% + % + \pgfmathfloatadd@{\pgfmathresult}{\pgfmathfloat@@a}% + \expandafter\pgfmathfloatmultiplyfixed@\expandafter{\pgfmathresult}{0.5}% + % + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\def\pgfmathfloatsinh@#1{% + \begingroup + \pgfmathfloatexp@{#1}% + \let\pgfmathfloat@@a=\pgfmathresult + % + \pgfmathfloatneg@{#1}% + \pgfmathfloatexp@{\pgfmathresult}% + % + \pgfmathfloatsubtract@{\pgfmathfloat@@a}{\pgfmathresult}% + \expandafter\pgfmathfloatmultiplyfixed@\expandafter{\pgfmathresult}{0.5}% + % + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\def\pgfmathfloattanh@#1{% + \begingroup + \pgfmathfloatsinh@{#1}% + \let\pgfmathfloat@@a=\pgfmathresult + % + \pgfmathfloatcosh@{#1}% + \let\pgfmathfloat@@b=\pgfmathresult + % + \pgfmathfloatdivide@{\pgfmathfloat@@a}{\pgfmathfloat@@b}% + % + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryintersections.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryintersections.code.tex new file mode 100644 index 0000000000..2457157690 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryintersections.code.tex @@ -0,0 +1,1172 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Free Documentation License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% Note: at the time of this writing, the library has quadratic runtime. +% Experimentally, it performed well while computing ~12 intersections of two +% plots, each with 600 samples. It failed when the number of samples exceeded 700. + +\usepgflibrary{fpu}% + +\newcount\pgf@intersect@solutions + +\newif\ifpgf@intersect@sort +\newif\ifpgf@intersect@sort@by@second@path + +\def\pgfintersectionsortbyfirstpath{% + \pgf@intersect@sorttrue% + \pgf@intersect@sort@by@second@pathfalse% +}% + +\def\pgfintersectionsortbysecondpath{% + \pgf@intersect@sorttrue% + \pgf@intersect@sort@by@second@pathtrue% +}% + +% #1: the index. It starts at 1 and ends with \pgfintersectionsolutions (inclusive). +% Invalid values will implicitly result in the origin. +\def\pgfpointintersectionsolution#1{% + \ifnum#1<1\relax% + \pgfpoint@intersect@solution@orgin% + \else% + \ifnum#1>\pgfintersectionsolutions\relax% + \pgfpoint@intersect@solution@orgin% + \else% + \csname pgfpoint@intersect@solution@#1\endcsname% + \fi% + \fi% +}% + +% Gets the segment indices of solution #1. +% +% #1: the solution index (i.e. the same argument as in \pgfpointintersectionsolution) +% #2: [output] a macro name which will contain the segment index of the first path which contains the solution +% #3: [output] a macro name which will contain the segment index of the second path which contains the solution +% +% Example: \pgfintersectiongetsolutionsegmentindices{0}{\first}{\second}% +% +% -> \first may be 0 if point #0 is in the 0'th segment +% -> \second may be 42 if point #0 is in the 42'th segment +% +% The "segment index" is actually close to the "time" of the solution. +% If a solution is at "time" 42.2, it will have segment index 42. +\def\pgfintersectiongetsolutionsegmentindices#1#2#3{% + \ifnum#1<1\relax% + \let#2=\pgfutil@empty + \let#3=\pgfutil@empty + \else% + \ifnum#1>\pgfintersectionsolutions\relax% + \let#2=\pgfutil@empty + \let#3=\pgfutil@empty + \else% + \def\pgf@temp##1##2##3##4{% + \edef#2{##1}% + \edef#3{##2}% + }% + \expandafter\let\expandafter\pgf@tempb\csname pgf@intersect@solution@props@#1\endcsname + \expandafter\pgf@temp\pgf@tempb + \fi% + \fi% +}% + +% Gets the time indices of solution #1. +% +% #1: the solution index (i.e. the same argument as in \pgfpointintersectionsolution) +% #2: [output] a macro name which will contain the time of the first path which contains the solution +% It will never be empty. +% #3: [output] a macro name which will contain the time of the second path which contains the solution +% It will never be empty. +% +% Example: \pgfintersectiongetsolutiontimes{0}{\first}{\second}% +% +% -> \first may be 0.5 if point #0 is in just in the middle of the path +% -> \second may be 42.8 if point #0 is in the 42'th segment (compare +% \pgfintersectiongetsolutionsegmentindices) and is at 80% of the +% 42'th segment +% +% Note that the precise time inside of a segment may be unavailable +% (currently, it is only computed for curveto paths and not +% necessarily for lineto). If the precise time is unavailable, this +% call will return the value of +% \pgfintersectiongetsolutionsegmentindices (which is a +% "coarse-grained" time). +\def\pgfintersectiongetsolutiontimes#1#2#3{% + \ifnum#1<1\relax% + \let#2=\pgfutil@empty + \let#3=\pgfutil@empty + \else% + \ifnum#1>\pgfintersectionsolutions\relax% + \let#2=\pgfutil@empty + \let#3=\pgfutil@empty + \else% + \def\pgf@temp##1##2##3##4{% + \edef#2{##3}% + \edef#3{##4}% + % + % check for fallback to segment indices: + \ifx#2\pgfutil@empty \edef#2{##1}\fi + \ifx#3\pgfutil@empty \edef#3{##2}\fi + }% + \expandafter\let\expandafter\pgf@tempb\csname pgf@intersect@solution@props@#1\endcsname + \expandafter\pgf@temp\pgf@tempb + \fi% + \fi% +}% + +\def\pgfpoint@intersect@solution@orgin{% + \begingroup% + \pgftransforminvert% + \pgfpointorigin% + \pgf@pos@transform@glob + \global\pgf@x=\pgf@x% + \global\pgf@y=\pgf@y% + \endgroup% +}% + +% #1 code which assigns the first path using \pgfsetpath. +% #2 code which assigns the second path using \pgfsetpath. +% +% On output, the points, their properties, and the number of points are set. +% Use \pgfintersectionsolutions which expands to the number of intersections +\long\def\pgfintersectionofpaths#1#2{% + \begingroup% + \pgfinterruptpath% + #1% + \pgfgetpath\pgf@intersect@path@a% + \global\let\pgf@intersect@path@temp=\pgf@intersect@path@a% + \endpgfinterruptpath% + \endgroup% + \let\pgf@intersect@path@a=\pgf@intersect@path@temp% + % + \begingroup% + \pgfinterruptpath% + #2% + \pgfgetpath\pgf@intersect@path@b% + \global\let\pgf@intersect@path@temp=\pgf@intersect@path@b% + \endpgfinterruptpath% + \endgroup% + \let\pgf@intersect@path@b=\pgf@intersect@path@temp% + % + \pgf@intersect@solutions=0\relax% + \pgf@intersect@path@reset@a + % + \ifpgf@intersect@sort@by@second@path% + \let\pgf@intersect@temp=\pgf@intersect@path@a% + \let\pgf@intersect@path@a=\pgf@intersect@path@b% + \let\pgf@intersect@path@b=\pgf@intersect@temp% + \fi% + % + \pgfprocessround\pgf@intersect@path@a\pgf@intersect@path@a% + \pgfprocessround\pgf@intersect@path@b\pgf@intersect@path@b% + % + \let\pgf@intersect@token@after=\pgf@intersect@path@process@a% + \expandafter\pgf@intersectionofpaths\pgf@intersect@path@a\pgf@stop% + \edef\pgfintersectionsolutions{\the\pgf@intersect@solutions}% + \pgfmathloop% + \ifnum\pgfmathcounter>\pgfintersectionsolutions\relax% + \else% + \pgfutil@namelet{pgfpoint@intersect@solution@\pgfmathcounter}% + {pgfpoint@g@intersect@solution@\pgfmathcounter}% + \edef\pgf@marshal{\noexpand\pgf@intersection@set@properties{\csname pgfpoint@g@intersect@solution@\pgfmathcounter @props\endcsname}}% + \pgf@marshal + \ifpgf@intersect@sort% + \pgfutil@namelet{pgf@intersect@solution@\pgfmathcounter @time@a}% + {pgf@g@intersect@solution@\pgfmathcounter @time@a}% + \fi% + \repeatpgfmathloop% + \ifpgf@intersect@sort% + \pgfintersectionsolutionsortbytime% + \fi% +}% + +\def\pgf@intersection@set@properties#1{% + \pgfutil@namedef{pgf@intersect@solution@props@\pgfmathcounter}{#1}% +}% + +% #1 a global name prefix to store properties. +\def\pgf@intersection@store@properties#1{% + % we store the time offsets as well and make them available programmatically: + % note that \pgf@intersect@time@a and \pgf@intersect@time@b may be empty. + % + % However, \pgf@intersect@time@offset and + % \pgf@intersect@time@offset@b are *always* valid. In fact,they + % resemble a part of the time: it holds + % 0 <= \pgf@intersect@time@a < 1 + % and \pgf@intersect@time@offset > 0. + % + % If we have an intersection in segment 42 of path A, + % \pgf@intersect@time@offset will be 42. The time inside of that + % segment is given as number in the interval [0,1]. If it is 0.3, + % the total time will be 42.3 and that number will be stored as + % \pgf@intersect@time@a. + % + \expandafter\xdef\csname #1@props\endcsname{{\pgf@intersect@time@offset}{\pgf@intersect@time@offset@b}{\pgf@intersect@time@a}{\pgf@intersect@time@b}}% +}% + +\def\pgf@intersectionofpaths#1{% + \ifx#1\pgf@stop% + \let\pgf@intersect@next=\relax% + \else% + \ifx#1\pgfsyssoftpath@movetotoken% + \let\pgf@intersect@next=\pgf@intersect@token@moveto% + \else% + \ifx#1\pgfsyssoftpath@linetotoken% + \let\pgf@intersect@next=\pgf@intersect@token@lineto% + \else% + \ifx#1\pgfsyssoftpath@closepathtoken% + \let\pgf@intersect@next=\pgf@intersect@token@lineto% + \else% + \ifx#1\pgfsyssoftpath@curvetosupportatoken% + \let\pgf@intersect@next=\pgf@intersect@token@curveto% + \else% + \ifx#1\pgfsyssoftpath@rectcornertoken% + \let\pgf@intersect@next=\pgf@intersect@token@rect% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgf@intersect@next}% + +\def\pgf@intersect@token@moveto#1#2{% + \def\pgfpoint@intersect@start{\pgfqpoint{#1}{#2}}% + \pgf@intersectionofpaths% +}% + +\def\pgf@intersect@token@lineto#1#2{% + \def\pgfpoint@intersect@end{\pgfqpoint{#1}{#2}}% + \def\pgf@intersect@type{line}% + \pgf@intersect@token@after% +}% +\def\pgf@intersect@token@curveto#1#2\pgfsyssoftpath@curvetosupportbtoken#3#4\pgfsyssoftpath@curvetotoken#5#6{% + \def\pgfpoint@intersect@firstsupport{\pgfqpoint{#1}{#2}}% + \def\pgfpoint@intersect@secondsupport{\pgfqpoint{#3}{#4}}% + \def\pgfpoint@intersect@end{\pgfqpoint{#5}{#6}}% + \def\pgf@intersect@type{curve}% + \pgf@intersect@token@after% +}% + +\def\pgf@intersect@token@rect#1#2\pgfsyssoftpath@rectsizetoken#3#4{% + \pgf@xa=#1\relax% + \advance\pgf@xa by#3\relax% + \pgf@ya=#2\relax% + \advance\pgf@ya by#4\relax% + \edef\pgf@marshal{% + \noexpand\pgfsyssoftpath@movetotoken{#1}{#2}% + \noexpand\pgfsyssoftpath@linetotoken{#1}{\the\pgf@ya}% + \noexpand\pgfsyssoftpath@linetotoken{\the\pgf@xa}{\the\pgf@ya}% + \noexpand\pgfsyssoftpath@linetotoken{\the\pgf@xa}{#2}% + \noexpand\pgfsyssoftpath@closepathtoken{#1}{#2}% + }% + \expandafter\pgf@intersectionofpaths\pgf@marshal% +}% + +\def\pgf@intersect@path@process@a{% + \pgf@intersect@path@getpoints@a% + \let\pgf@intersect@token@after=\pgf@intersect@path@process@b% + \pgf@intersect@path@reset@b + \expandafter\pgf@intersectionofpaths\pgf@intersect@path@b\pgf@stop% + \let\pgfpoint@intersect@start=\pgfpoint@intersect@end@a% + \let\pgf@intersect@token@after=\pgf@intersect@path@process@a% + \c@pgf@counta=\pgf@intersect@time@offset\relax% + \advance\c@pgf@counta by1\relax% + \edef\pgf@intersect@time@offset{\the\c@pgf@counta}% + \pgf@intersectionofpaths% +}% + +\def\pgf@intersect@path@reset@a{% + \def\pgf@intersect@time@offset{0}% + \def\pgf@intersect@time@a{}% +}% + +\def\pgf@intersect@path@reset@b{% + \def\pgf@intersect@time@offset@b{0}% + \def\pgf@intersect@time@b{}% +}% + +\def\pgf@intersect@path@getpoints@a{% + \let\pgfpoint@intersect@start@a=\pgfpoint@intersect@start% + \let\pgfpoint@intersect@end@a=\pgfpoint@intersect@end% + \let\pgfpoint@intersect@firstsupport@a=\pgfpoint@intersect@firstsupport% + \let\pgfpoint@intersect@secondsupport@a=\pgfpoint@intersect@secondsupport% + \let\pgf@intersect@type@a=\pgf@intersect@type% +}% + +\def\pgf@intersect@path@process@b{% + \pgf@intersect@path@getpoints@b% + \csname pgf@intersect@\pgf@intersect@type@a @and@\pgf@intersect@type@b\endcsname% + \let\pgfpoint@intersect@start=\pgfpoint@intersect@end@b% + \c@pgf@counta=\pgf@intersect@time@offset@b\relax% + \advance\c@pgf@counta by1\relax% + \edef\pgf@intersect@time@offset@b{\the\c@pgf@counta}% + \pgf@intersectionofpaths}% + +\def\pgf@intersect@path@getpoints@b{% + \let\pgfpoint@intersect@start@b=\pgfpoint@intersect@start% + \let\pgfpoint@intersect@end@b=\pgfpoint@intersect@end% + \let\pgfpoint@intersect@firstsupport@b=\pgfpoint@intersect@firstsupport% + \let\pgfpoint@intersect@secondsupport@b=\pgfpoint@intersect@secondsupport% + \let\pgf@intersect@type@b=\pgf@intersect@type% +}% + +\def\pgf@intersect@line@and@line{% + \pgf@intersectionoflines{\pgfpoint@intersect@start@a}{\pgfpoint@intersect@end@a}% + {\pgfpoint@intersect@start@b}{\pgfpoint@intersect@end@b}% +}% + +\def\pgf@intersect@line@and@curve{% + \pgf@intersectionoflineandcurve% + {\pgf@process{\pgfpoint@intersect@start@a}}{\pgf@process{\pgfpoint@intersect@end@a}}% + {\pgf@process{\pgfpoint@intersect@start@b}}{\pgf@process{\pgfpoint@intersect@firstsupport@b}}% + {\pgf@process{\pgfpoint@intersect@secondsupport@b}}{\pgf@process{\pgfpoint@intersect@end@b}}% +}% + +\def\pgf@intersect@curve@and@line{% + \pgf@intersectionofcurveandline% + {\pgf@process{\pgfpoint@intersect@start@a}}{\pgf@process{\pgfpoint@intersect@firstsupport@a}}% + {\pgf@process{\pgfpoint@intersect@secondsupport@a}}{\pgf@process{\pgfpoint@intersect@end@a}}% + {\pgf@process{\pgfpoint@intersect@start@b}}{\pgf@process{\pgfpoint@intersect@end@b}}% +}% + +\def\pgf@intersect@curve@and@curve{% + \pgf@intersectionofcurves% + {\pgf@process{\pgfpoint@intersect@start@a}}{\pgf@process{\pgfpoint@intersect@firstsupport@a}}% + {\pgf@process{\pgfpoint@intersect@secondsupport@a}}{\pgf@process{\pgfpoint@intersect@end@a}}% + {\pgf@process{\pgfpoint@intersect@start@b}}{\pgf@process{\pgfpoint@intersect@firstsupport@b}}% + {\pgf@process{\pgfpoint@intersect@secondsupport@b}}{\pgf@process{\pgfpoint@intersect@end@b}}% +}% + + +\def\pgfintersectionoflines#1#2#3#4{% + \pgf@intersect@solutions=0\relax% + \pgf@intersectionoflines{#1}{#2}{#3}{#4}% +}% + +\def\pgf@intersectionoflines#1#2#3#4{% + \pgf@iflinesintersect{#1}{#2}{#3}{#4}% + {% + \pgfextract@process\pgf@intersect@solution@candidate{% + % pgf@x and pgf@y are already assigned by \pgf@iflinesintersect + }% + \pgf@ifsolution@duplicate{\pgf@intersect@solution@candidate}{% + % ah - we a duplicate. Apparently, we have a hit on an + % endpoint. + }{% + \global\advance\pgf@intersect@solutions by1\relax% + \expandafter\global\expandafter\let\csname pgfpoint@g@intersect@solution@\the\pgf@intersect@solutions\endcsname=\pgf@intersect@solution@candidate + \ifpgf@intersect@sort% + % save coordinates of the intersection + \pgf@process{\pgf@intersect@solution@candidate}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % determine length of path + \pgf@process{\pgfpointdiff{\pgfpoint@intersect@start@a}{\pgfpoint@intersect@end@a}}% + \edef\pgf@marshal{% + \noexpand\pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + }% + \pgf@marshal% + \let\pgf@intersect@length@a=\pgfmathresult% + % determine distance of intersection from start + \pgf@process{\pgfpointdiff{\pgfpoint@intersect@start@a}{\pgfqpoint{\pgf@xc}{\pgf@yc}}}% + \edef\pgf@marshal{% + \noexpand\pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + }% + \pgf@marshal% + % scale the distance to the path length (path time) + \pgfmathdivide@{\pgfmathresult}{\pgf@intersect@length@a}% + \pgf@x=\pgfmathresult pt\relax% + % advance by the path segment (see definition of \pgf@intersection@store@properties) + \advance\pgf@x by\pgf@intersect@time@offset pt\relax% + \edef\pgf@intersect@time@a{\pgfmath@tonumber{\pgf@x}}% + % save numbered + \expandafter\global\expandafter\let\csname pgf@g@intersect@solution@\the\pgf@intersect@solutions @time@a\endcsname= + \pgf@intersect@time@a + \else + \let\pgf@intersect@time@a=\pgfutil@empty + \fi% + \let\pgf@intersect@time@b=\pgfutil@empty + \pgf@intersection@store@properties{pgfpoint@g@intersect@solution@\the\pgf@intersect@solutions}% + }% + % + }{% + }% +}% + +% Test if two lines L1 and L2 intersect. +% +% #1 - first point P1 on L1. +% #2 - second point P2 on L1. +% #3 - first point P3 on L2. +% #2 - second point P4 on L2. +% #5 - code executed if intersection occurs. +% #6 - code executed if intersection does no occur. +% +% Let L1 be represented by P1+(P2-P1)s where 0<=s<=1 +% Let L2 be represented by P3+(P4-P3)t where 0<=t<=1 +% +% Then L1 and L2 intersect at +% +% s = |x2-x1 x3-x1| / |x4-x3 x2-x1| +% |y2-y1 y3-y1| |y4-y3 y2-y1| +% +% t = |x4-x3 x3-x1| / |x4-x3 x2-x1| +% |y4-y3 y3-y1| |y4-y3 y2-y1| +% +% with 0<=s,t<=1 +% +% s and t do not need to be calculated: +% +% Let s = A / C and t = B / C +% +% Then 0<=s<=1 if !(C=0) && ((A=0) || ((A>0) && !(CA))) +% 0<=t<=1 if !(C=0) && ((B=0) || ((B>0) && !(CB))) +% +\newif\ifpgf@s +\newif\ifpgf@t +\def\pgfiflinesintersect#1#2#3#4{% + \begingroup% + \pgf@iflinesintersect{\pgf@process{#1}}{\pgf@process{#2}}{\pgf@process{#3}}{\pgf@process{#4}}% + {\aftergroup\pgfutil@firstoftwo}{\aftergroup\pgfutil@secondoftwo}% + \endgroup% +}% + +% queried by pgfplots. Do not delete, only increase. +\def\pgf@intersections@version{2}% + +% #1,#2: line 1 +% #3,#4: line 2 +\def\pgf@iflinesintersect#1#2#3#4{% + % first: check bounding boxes -- but somewhat increased such that we do not + % exclude "visible" hits due to rounding issues (i.e. use an upper bound): + \pgf@intersect@boundingbox@reset% + \pgf@intersect@boundingbox@update{#1}% + \pgf@intersect@boundingbox@update{#2}% + \pgf@intersect@boundingbox@assign@b% + % + \pgf@intersect@boundingbox@reset% + \pgf@intersect@boundingbox@update{#3}% + \pgf@intersect@boundingbox@update{#4}% + \pgf@intersect@boundingbox@assign@a% + % + \pgf@intersect@boundingbox@a% + \pgf@intersect@boundingbox@b% + % + \pgf@intersect@boundingbox@ifoverlap@upperbound{% + \pgf@iflinesintersect@{#1}{#2}{#3}{#4}% + }{% + \let\pgf@intersect@next=\pgfutil@secondoftwo% + }% + \pgf@intersect@next% +}% + +% a helper routine which simply defines \pgf@intersect@next. +% +% In principle, this routine is capable of computing the entire intersection... but we only invoke it after checking for bounding box overlaps. This has two reasons: +% 1. robustness. almost-parallel lines could cause "dimension too large" when solving the linear equation system +% XXX : I still needed to replace the linear solver by one using the FPU. Perhaps I do not need the BB check anymore? +% 2. performance. I hope it is faster to first check for BB (but this is not sure in TeX) +% +% #1,#2: line 1 +% #3,#4: line 2 +\def\pgf@iflinesintersect@#1#2#3#4{% + % we have two lines of sorts + % l_1(s) := #1 + s * (#2 - #1), 0<= s <= 1 + % and + % l_2(t) := #3 + t * (#4 - #3), 0<= t <= 1 + % -> + % set up LGS + % ( #2 - #1 ) *s + (#3-#4) * t = #3-#1 + % we have a hit if 0<= s,t <= 1 . + #1\relax% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + #2\relax% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + #3\relax% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + #4\relax% + % + % will be overwritten, remember it: + \edef\pgf@intersect@A{% + \pgf@xa=\the\pgf@xa\space + \pgf@ya=\the\pgf@ya\space + }% + % + % B := (2-1) + \advance\pgf@xb by-\pgf@xa + \advance\pgf@yb by-\pgf@ya + % + % A := (3-1) + \advance\pgf@xa by-\pgf@xc + \advance\pgf@ya by-\pgf@yc + \pgf@xa=-\pgf@xa + \pgf@ya=-\pgf@ya + % + % C := (3-4) + \advance\pgf@xc by-\pgf@x + \advance\pgf@yc by-\pgf@y + % + \begingroup + % compute the |.|_1 norm of each of lines. We need to compute + % tolerance factors in order to decide if we have an intersection. + % line 1: compute |#2 - #1|_1 : + \ifdim\pgf@xb<0sp \pgf@xb=-\pgf@xb\fi + \ifdim\pgf@yb<0sp \pgf@yb=-\pgf@yb\fi + \advance\pgf@xb by\pgf@yb + \xdef\pgf@intersect@len@a{\pgf@sys@tonumber\pgf@xb}% + % + % line 2: compute |#3 - #4|_1 : + \ifdim\pgf@xc<0sp \pgf@xc=-\pgf@xc\fi + \ifdim\pgf@yc<0sp \pgf@yc=-\pgf@yc\fi + \advance\pgf@xc by\pgf@yc + \xdef\pgf@intersect@len@b{\pgf@sys@tonumber\pgf@xc}% + \endgroup + % + \edef\pgf@marshal{% + \noexpand\pgfutilsolvetwotwoleqfloat{% + {\pgf@sys@tonumber\pgf@xb}{\pgf@sys@tonumber\pgf@xc}% + {\pgf@sys@tonumber\pgf@yb}{\pgf@sys@tonumber\pgf@yc}% + }{% + {\pgf@sys@tonumber\pgf@xa}% + {\pgf@sys@tonumber\pgf@ya}% + }% + }% + \pgf@marshal + % + \let\pgf@intersect@next=\pgfutil@secondoftwo% + \ifx\pgfmathresult\pgfutil@empty + % matrix was singular. + \else + \def\pgf@marshal##1##2{% + \global\pgf@x=##1pt % + \global\pgf@y=##2pt % + }% + \expandafter\pgf@marshal\pgfmathresult + % + \def\pgf@marshal{XXXX}% this should never be read + % FIRST: check line 1: + \ifdim\pgf@x<0sp + % let it count as hit if + % || l_1(s) - l_1(0) || < eps + % <=> |s| * ||#2 - #1|| < eps + % and, since s< 0 here: + % <=> -s * ||#2 - #1|| < eps + \pgf@xa=-\pgf@intersect@len@a\pgf@x + \ifdim\pgf@xa<\pgfintersectiontolerance\relax + % close enough to first endpoint of line 1: + \def\pgf@marshal{1}% + \else + \def\pgf@marshal{0}% + \fi + \else + \ifdim\pgf@x>1pt + % let it count as hit if + % || l_1(s) - l_1(1) || < eps + % <=> |s-1| * ||#2 - #1|| < eps + % and, since s > 1 here: + % <=> s * ||#2 - #1|| - ||#2 - #1|| < eps + \pgf@xa=\pgf@intersect@len@a\pgf@x + \advance\pgf@xa by-\pgf@intersect@len@a pt % + \ifdim\pgf@xa<\pgfintersectiontolerance\relax + % close enough to second endpoint of line 1: + \def\pgf@marshal{1}% + \else + \def\pgf@marshal{0}% + \fi + \else + % 0<= s <= 1: we have an intersection within line 1. + \def\pgf@marshal{1}% + \fi + \fi + % + % SECOND: check line 2: + \if1\pgf@marshal + \ifdim\pgf@y<0sp + % see remarks for line 1. same applies here. + \pgf@xa=-\pgf@intersect@len@b\pgf@y + \ifdim\pgf@xa<\pgfintersectiontolerance\relax + % close enough to first endpoint of line 2: + \def\pgf@marshal{1}% + \else + \def\pgf@marshal{0}% + \fi + \else + \ifdim\pgf@y>1pt + % see remarks for line 1. same applies here. + \pgf@xa=\pgf@intersect@len@b\pgf@y + \advance\pgf@xa by-\pgf@intersect@len@b pt % + \ifdim\pgf@xa<\pgfintersectiontolerance\relax + % close enough to second endpoint of line 2: + \def\pgf@marshal{1}% + \else + \def\pgf@marshal{0}% + \fi + \else + % 0<= t <= 1: we have an intersection within line 2. + \def\pgf@marshal{1}% + \fi + \fi + \fi + % + \if1\pgf@marshal + % Ok, compute the intersection point and return it: + % we use (x,y) = A + s * (B-A) + % keep in mind that (s,t) == (\pgf@x,\pgf@y) + \pgf@intersect@A + \pgf@yc=\pgf@x + \global\pgf@x=\pgf@sys@tonumber\pgf@xb\pgf@yc + \global\pgf@y=\pgf@sys@tonumber\pgf@yb\pgf@yc + \global\advance\pgf@x by \pgf@xa + \global\advance\pgf@y by \pgf@ya + \let\pgf@intersect@next=\pgfutil@firstoftwo% + \fi + \fi +}% + + + + +\def\pgfintersectionoflineandcurve#1#2#3#4#5#6{% + \pgf@intersect@solutions=0\relax% + \pgf@intersectionoflineandcurve{#1}{#2}{#3}{#4}{#5}{#6}% +}% + +\def\pgf@intersectionoflineandcurve#1#2#3#4#5#6{% + \pgf@intersectionofcurves% + {\pgf@process{#1}}% + {% + \pgf@process{% + \pgfpointadd{#1\relax\pgf@x=0.666666\pgf@x\pgf@y=0.666666\pgf@y}% + {#2\relax\pgf@x=0.333333\pgf@x\pgf@y=0.333333\pgf@y}% + }% + }% + {% + \pgf@process{% + \pgfpointadd{#1\relax\pgf@x=0.333333\pgf@x\pgf@y=0.333333\pgf@y}% + {#2\relax\pgf@x=0.666666\pgf@x\pgf@y=0.666666\pgf@y}% + }% + }% + {\pgf@process{#2}}% + {\pgf@process{#3}}% + {\pgf@process{#4}}% + {\pgf@process{#5}}% + {\pgf@process{#6}}% +}% + +\def\pgf@intersectionofcurveandline#1#2#3#4#5#6{% + \pgf@intersectionofcurves% + {\pgf@process{#1}}% + {\pgf@process{#2}}% + {\pgf@process{#3}}% + {\pgf@process{#4}}% + {\pgf@process{#5}}% + {% + \pgf@process{% + \pgfpointadd{#5\relax\pgf@x=0.666666\pgf@x\pgf@y=0.666666\pgf@y}% + {#6\relax\pgf@x=0.333333\pgf@x\pgf@y=0.333333\pgf@y}% + }% + }% + {% + \pgf@process{% + \pgfpointadd{#5\relax\pgf@x=0.333333\pgf@x\pgf@y=0.333333\pgf@y}% + {#6\relax\pgf@x=0.666666\pgf@x\pgf@y=0.666666\pgf@y}% + }% + }% + {\pgf@process{#6}}% +}% + + + + +\def\pgfintersectiontolerance{0.1pt}% +\def\pgfintersectiontoleranceupperbound{1pt}% +\def\pgfintersectiontolerancefactor{0.1}% + + + +% Find the intersections of two bezier curves. +% +% #1 - #4 = curve 1. +% #5 - #8 = curve 2. +% #9 = the solution number. +% +% There is no guarantee of ordering of solutions. If there are +% no solutions, the origin is returned. +% +\def\pgfpointintersectionofcurves#1#2#3#4#5#6#7#8#9{% + \pgf@intersect@solutions=0\relax% + \pgf@intersectionofcurves% + {\pgf@process{#1}}{\pgf@process{#2}}{\pgf@process{#3}}{\pgf@process{#4}}% + {\pgf@process{#5}}{\pgf@process{#6}}{\pgf@process{#7}}{\pgf@process{#8}}% + \pgfpointintersectionsolution{#9}% +}% + +% Return any intersection points of two curves C1 and C2. +% No order can be guaranteed for the solutions. +% +% #1, #2, #3, #4 - the points on C1 +% #5, #6, #7, #8 - the points on C2 +% +% Returns: +% +% \pgf@intersect@solutions - the number of solutions. +% \pgfpointintersectionsolution{} - the point for solution S. +% +% (Sort of) use: +% +% intersection(C1,C2) +% S = {}; +% intersection'(C1,C2); +% return S; +% +% intersection'(C1,C2) +% B1 = boundingbox(C1); +% B2 = boundingbox(C2); +% if intersect(B1,B2) +% if (B1.width < q) and (B1.height < q) and +% (B2.width < q) and (B2.height < q) +% S = S + {average_of_all_points(B1,B2)}; \\ is there a better choice? +% else +% Q = subdivideLeft(C1); +% R = subdivideRight(C1); +% intersection'(C2,Q); +% intersection'(C2,R); +% +% where q is a small value (tolerance). +% +\def\pgfintersectionofcurves#1#2#3#4#5#6#7#8{% + \pgf@intersect@solutions=0\relax% + \pgf@intersectionofcurves% + {\pgf@process{#1}}{\pgf@process{#2}}{\pgf@process{#3}}{\pgf@process{#4}}% + {\pgf@process{#5}}{\pgf@process{#6}}{\pgf@process{#7}}{\pgf@process{#8}}% +}% +\def\pgf@intersectionofcurves#1#2#3#4#5#6#7#8{% + \begingroup% + \dimendef\pgf@time@a=2\relax% + \dimendef\pgf@time@aa=4\relax% + \dimendef\pgf@time@b=6\relax% + \dimendef\pgf@time@bb=8\relax% + \pgf@time@a=0pt\relax% + \pgf@time@aa=1pt\relax% + \pgf@time@b=0pt\relax% + \pgf@time@bb=1pt\relax% + \let\pgf@intersect@subdivide@curve=\pgf@intersect@subdivide@curve@b% + \let\pgf@curve@subdivde@after=\pgf@@intersectionofcurves% + \pgf@@intersectionofcurves{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% + \endgroup% +}% + +\def\pgf@intersect@boundingbox@assign@a{% + \edef\pgf@intersect@boundingbox@a{% + % lower left: + \noexpand\pgf@xb=\the\pgf@xa\space% + \noexpand\pgf@yb=\the\pgf@ya\space% + % upper right: + \noexpand\pgf@xc=\the\pgf@xb\space% + \noexpand\pgf@yc=\the\pgf@yb\space% + }% +}% +\def\pgf@intersect@boundingbox@assign@b{% + \edef\pgf@intersect@boundingbox@b{% + % lower left: + \noexpand\global\noexpand\pgf@x=\the\pgf@xa\space% + \noexpand\global\noexpand\pgf@y=\the\pgf@ya\space% + % upper right: + \noexpand\pgf@xa=\the\pgf@xb\space% + \noexpand\pgf@ya=\the\pgf@yb\space% + }% +}% + +% see \pgf@intersect@boundingbox@assign@a and \pgf@intersect@boundingbox@assign@b for the naming conventions +\def\pgf@intersect@boundingbox@ifoverlap{% + \def\pgf@intersect@next{\pgfutil@secondoftwo}% + % + \ifdim\pgf@xa<\pgf@xb% + \else% + \ifdim\pgf@x>\pgf@xc% + \else% + \ifdim\pgf@ya<\pgf@yb% + \else% + \ifdim\pgf@y>\pgf@yc% + \else% + \def\pgf@intersect@next{\pgfutil@firstoftwo}% + \fi + \fi + \fi + \fi + \pgf@intersect@next +}% +\def\pgf@intersect@boundingbox@ifoverlap@upperbound{% + \begingroup + \def\pgf@intersect@next{\pgfutil@secondoftwo}% + % + \advance\pgf@xa by+\pgfintersectiontolerance\relax + \ifdim\pgf@xa<\pgf@xb% + \else% + \global\advance\pgf@x by-\pgfintersectiontolerance\relax + \ifdim\pgf@x>\pgf@xc% + \else% + \advance\pgf@ya by\pgfintersectiontolerance\relax + \ifdim\pgf@ya<\pgf@yb% + \else% + \global\advance\pgf@y by-\pgfintersectiontolerance\relax + \ifdim\pgf@y>\pgf@yc% + \else% + \def\pgf@intersect@next{\pgfutil@firstoftwo}% + \fi + \fi + \fi + \fi + \expandafter + \endgroup + \pgf@intersect@next +}% +\def\pgf@intersect@boundingbox@ifoverlap@UNUSED{% + \let\pgf@intersect@next=\pgfutil@secondoftwo% + \ifdim\pgf@xa<\pgf@xb% + \else% + \ifdim\pgf@x>\pgf@xc% + \else% + \ifdim\pgf@ya<\pgf@yb% + \else% + \ifdim\pgf@y>\pgf@yc% + \else% + \let\pgf@intersect@next=\pgfutil@firstoftwo% + \fi + \fi + \fi + \fi + \pgf@intersect@next +}% +\def\pgf@@intersectionofcurves#1#2#3#4#5#6#7#8{% + \pgf@intersect@boundingbox@reset% + \pgf@intersect@boundingbox@update{#1}% + \pgf@intersect@boundingbox@update{#2}% + \pgf@intersect@boundingbox@update{#3}% + \pgf@intersect@boundingbox@update{#4}% + \pgf@intersect@boundingbox@assign@b% + % + \pgf@intersect@boundingbox@reset% + \pgf@intersect@boundingbox@update{#5}% + \pgf@intersect@boundingbox@update{#6}% + \pgf@intersect@boundingbox@update{#7}% + \pgf@intersect@boundingbox@update{#8}% + \pgf@intersect@boundingbox@assign@a% + % + \pgf@intersect@boundingbox@a% + \pgf@intersect@boundingbox@b% + % + \pgf@intersect@boundingbox@ifoverlap{% + \pgf@@@intersectionofcurves{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% + }{% + % no overlap -- no intersection. + }% +}% + +\def\pgf@@@intersectionofcurves#1#2#3#4#5#6#7#8{% + % compute DIFFERENCE vectors: + \advance\pgf@xc by-\pgf@xb% + \advance\pgf@yc by-\pgf@yb% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \let\pgf@intersect@subdivde=\relax% + % check if both difference vectors are point wise + % less than tolerance (i.e. |v|_infty < eps ). + % That means that both bounding boxes are "small enough" + \ifdim\pgf@xc<\pgfintersectiontolerance\relax% + \ifdim\pgf@xa<\pgfintersectiontolerance\relax% + \ifdim\pgf@yc<\pgfintersectiontolerance\relax% + \ifdim\pgf@ya<\pgfintersectiontolerance\relax% + \pgfextract@process\pgf@intersect@solution@candidate{% + % set (x,y) = mean(the 4 points of the two bounding boxes): + \pgf@intersect@boundingbox@a% + \pgf@intersect@boundingbox@b% + \pgf@x=0.25\pgf@x% + \advance\pgf@x by0.25\pgf@xa% + \advance\pgf@x by0.25\pgf@xb% + \advance\pgf@x by0.25\pgf@xc% + \pgf@y=0.25\pgf@y% + \advance\pgf@y by0.25\pgf@ya% + \advance\pgf@y by0.25\pgf@yb% + \advance\pgf@y by0.25\pgf@yc% + }% + % We must avoid duplicate solutions. + \let\pgf@intersect@subdivde=\pgf@stop% + \pgf@ifsolution@duplicate\pgf@intersect@solution@candidate{}% + {% + \global\advance\pgf@intersect@solutions by1\relax% + \begingroup + \advance\pgf@time@a by\pgf@time@aa% + \divide\pgf@time@a by2\relax% + \advance\pgf@time@a by\pgf@intersect@time@offset pt\relax% + \edef\pgf@intersect@time@a{\pgfmath@tonumber{\pgf@time@a}}% + % + \advance\pgf@time@b by\pgf@time@bb% + \divide\pgf@time@b by2\relax% + \advance\pgf@time@b by\pgf@intersect@time@offset@b pt\relax% + \edef\pgf@intersect@time@b{\pgfmath@tonumber{\pgf@time@b}}% + % + \pgf@intersection@store@properties{pgfpoint@g@intersect@solution@\the\pgf@intersect@solutions}% + \expandafter\global\expandafter\let% + \csname pgfpoint@g@intersect@solution@\the\pgf@intersect@solutions\endcsname=% + \pgf@intersect@solution@candidate% + \ifpgf@intersect@sort% + \expandafter\xdef% + \csname pgf@g@intersect@solution@\the\pgf@intersect@solutions @time@a\endcsname% + {\pgf@intersect@time@a}% + \fi% + \endgroup + }% + \fi% + \fi% + \fi% + \fi% + \ifx\pgf@intersect@subdivde\pgf@stop% + \else% + \pgf@intersect@subdivide@curve{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% + \fi% +}% + +\def\pgf@intersect@subdivide@curve@b#1#2#3#4#5#6#7#8{% + \begingroup% + \advance\pgf@time@bb by\pgf@time@b\relax% + \divide\pgf@time@bb by2\relax% + \let\pgf@intersect@subdivide@curve=\pgf@intersect@subdivide@curve@a% + \pgf@curve@subdivide@left{#5}{#6}{#7}{#8}{#1}{#2}{#3}{#4}% + \endgroup% + \begingroup% + \advance\pgf@time@b by\pgf@time@bb\relax% + \divide\pgf@time@b by2\relax% + \let\pgf@intersect@subdivide@curve=\pgf@intersect@subdivide@curve@a% + \pgf@curve@subdivide@right{#5}{#6}{#7}{#8}{#1}{#2}{#3}{#4}% + \endgroup% +}% + +\def\pgf@intersect@subdivide@curve@a#1#2#3#4#5#6#7#8{% + \begingroup% + \advance\pgf@time@aa by\pgf@time@a\relax% + \divide\pgf@time@aa by2\relax% + \let\pgf@intersect@subdivide@curve=\pgf@intersect@subdivide@curve@b% + \pgf@curve@subdivide@left{#5}{#6}{#7}{#8}{#1}{#2}{#3}{#4}% + \endgroup% + \begingroup% + \advance\pgf@time@a by\pgf@time@aa\relax% + \divide\pgf@time@a by2\relax% + \let\pgf@intersect@subdivide@curve=\pgf@intersect@subdivide@curve@b% + \pgf@curve@subdivide@right{#5}{#6}{#7}{#8}{#1}{#2}{#3}{#4}% + \endgroup% +}% + +\def\pgf@intersect@boundingbox@reset{% + \pgf@xa=16000pt\relax% + \pgf@ya=16000pt\relax% + \pgf@xb=-16000pt\relax% + \pgf@yb=-16000pt\relax% +}% + +\def\pgf@intersect@boundingbox@update#1{% + #1\relax% + \ifdim\pgf@x<\pgf@xa\pgf@xa=\pgf@x\fi% + \ifdim\pgf@y<\pgf@ya\pgf@ya=\pgf@y\fi% + \ifdim\pgf@x>\pgf@xb\pgf@xb=\pgf@x\fi% + \ifdim\pgf@y>\pgf@yb\pgf@yb=\pgf@y\fi% +}% + +% The following subroutines are part of a conversion from pgfbasic +% math to FPU. This transition is necessary due to the restricted +% accuracy of pgfbasic. In order to limit the error rate of the +% transition pgfbasic -> FPU, I chose to +% keep the old "pattern" of sorts \advance\pgf@xa by0.5\pgf@y etc and +% simply adapt to some FPU call. +% +% The following routines constitute the "adapter": + +\def\pgf@float@adapter@setxy{% + \pgfmathfloatparsenumber{\pgf@sys@tonumber\pgf@x}\let\pgf@fpu@x=\pgfmathresult + \pgfmathfloatparsenumber{\pgf@sys@tonumber\pgf@y}\let\pgf@fpu@y=\pgfmathresult +}% +\def\pgf@float@adapter@mult#1=#2*#3{% + \pgfmathfloatmultiplyfixed@{#3}{#2}% + \let#1=\pgfmathresult +}% +\def\pgf@float@adapter@advance#1by#2*#3{% + \pgfmathfloatmultiplyfixed@{#3}{#2}% + \let\pgfutil@temp=\pgfmathresult + \pgfmathfloatadd@{#1}{\pgfutil@temp}% + \let#1=\pgfmathresult +}% + +\def\pgf@float@adapter@tostring#1{% + \pgfmathfloattofixed{#1}\edef#1{\pgfmathresult pt }% +}% + +\def\pgf@curve@subdivide@left#1#2#3#4{% + % + % The left curve (from t=0 to t=.5) + % + \begingroup + #1\relax% + \pgfutil@tempdima=\pgf@x% + \pgfutil@tempdimb=\pgf@y% + \pgf@float@adapter@setxy + \pgf@float@adapter@mult\pgf@fpu@xa=.5*\pgf@fpu@x \pgf@float@adapter@mult\pgf@fpu@ya=.5*\pgf@fpu@y% + \pgf@float@adapter@mult\pgf@fpu@xb=.25*\pgf@fpu@x \pgf@float@adapter@mult\pgf@fpu@yb=.25*\pgf@fpu@y% + \pgf@float@adapter@mult\pgf@fpu@xc=.125*\pgf@fpu@x\pgf@float@adapter@mult\pgf@fpu@yc=.125*\pgf@fpu@y% + #2\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@fpu@xa by.5*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@ya by.5*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xb by.5*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yb by.5*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xc by.375*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yc by.375*\pgf@fpu@y% + #3\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@fpu@xb by.25*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yb by.25*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xc by.375*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yc by.375*\pgf@fpu@y% + #4\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@fpu@xc by.125*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yc by.125*\pgf@fpu@y% + % + \pgf@float@adapter@tostring\pgf@fpu@xa + \pgf@float@adapter@tostring\pgf@fpu@ya + \pgf@float@adapter@tostring\pgf@fpu@xb + \pgf@float@adapter@tostring\pgf@fpu@yb + \pgf@float@adapter@tostring\pgf@fpu@xc + \pgf@float@adapter@tostring\pgf@fpu@yc + \edef\pgf@marshal{% + \noexpand\pgf@curve@subdivde@after% + {\noexpand\pgf@x=\the\pgfutil@tempdima\noexpand\pgf@y=\the\pgfutil@tempdimb}% + {\noexpand\pgf@x=\pgf@fpu@xa\noexpand\pgf@y=\pgf@fpu@ya}% + {\noexpand\pgf@x=\pgf@fpu@xb\noexpand\pgf@y=\pgf@fpu@yb}% + {\noexpand\pgf@x=\pgf@fpu@xc\noexpand\pgf@y=\pgf@fpu@yc}% + }% + \expandafter + \endgroup + \pgf@marshal% +}% + +\def\pgf@curve@subdivide@right#1#2#3#4{% + % + % The right curve (from t=0.5 to t=1) + % + \begingroup + #1\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@mult\pgf@float@tmpa=.125*\pgf@fpu@x\pgf@float@adapter@mult\pgf@float@tmpb=.125*\pgf@fpu@y% + #2\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@float@tmpa by.375*\pgf@fpu@x\pgf@float@adapter@advance\pgf@float@tmpb by.375*\pgf@fpu@y% + \pgf@float@adapter@mult\pgf@fpu@xa=.25*\pgf@fpu@x\pgf@float@adapter@mult\pgf@fpu@ya=.25*\pgf@fpu@y% + #3\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@float@tmpa by.375*\pgf@fpu@x\pgf@float@adapter@advance\pgf@float@tmpb by.375*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xa by.5*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@ya by.5*\pgf@fpu@y% + \pgf@float@adapter@mult\pgf@fpu@xb=.5*\pgf@fpu@x\pgf@float@adapter@mult\pgf@fpu@yb=.5*\pgf@fpu@y% + #4\relax% + \pgf@float@adapter@setxy + \pgf@float@adapter@advance\pgf@float@tmpa by.125*\pgf@fpu@x\pgf@float@adapter@advance\pgf@float@tmpb by.125*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xa by.25*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@ya by.25*\pgf@fpu@y% + \pgf@float@adapter@advance\pgf@fpu@xb by.5*\pgf@fpu@x\pgf@float@adapter@advance\pgf@fpu@yb by.5*\pgf@fpu@y% + \let\pgf@fpu@xc=\pgf@fpu@x\let\pgf@fpu@yc=\pgf@fpu@y% + % + \pgf@float@adapter@tostring\pgf@float@tmpa + \pgf@float@adapter@tostring\pgf@float@tmpb + \pgf@float@adapter@tostring\pgf@fpu@xa + \pgf@float@adapter@tostring\pgf@fpu@ya + \pgf@float@adapter@tostring\pgf@fpu@xb + \pgf@float@adapter@tostring\pgf@fpu@yb + \pgf@float@adapter@tostring\pgf@fpu@xc + \pgf@float@adapter@tostring\pgf@fpu@yc + \edef\pgf@marshal{% + \noexpand\pgf@curve@subdivde@after% + {\noexpand\pgf@x=\pgf@float@tmpa\noexpand\pgf@y=\pgf@float@tmpb}% + {\noexpand\pgf@x=\pgf@fpu@xa\noexpand\pgf@y=\pgf@fpu@ya}% + {\noexpand\pgf@x=\pgf@fpu@xb\noexpand\pgf@y=\pgf@fpu@yb}% + {\noexpand\pgf@x=\pgf@fpu@xc\noexpand\pgf@y=\pgf@fpu@yc}% + }% + \expandafter + \endgroup + \pgf@marshal% +}% + + +% A solution S1 is considered a duplicate of S2, if +% +% |x1 - x2|f < q and |y1 - y2|f < q +% +% where q is a small value (tolerance). +% +% #1 - the solution. +% +\def\pgf@ifsolution@duplicate#1{% + #1% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \let\pgf@intersect@next=\pgfutil@secondoftwo% + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@intersect@solutions\relax% + \else% + \pgf@ifsolution@duplicate@{\pgfmathcounter}% + \repeatpgfmathloop% + \pgf@intersect@next% +}% + +\def\pgf@ifsolution@duplicate@#1{% + \pgf@process{\csname pgfpoint@g@intersect@solution@#1\endcsname}% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@y by-\pgf@ya% + \ifdim\pgf@x<0pt\relax\pgf@x=-\pgf@x\fi% + \ifdim\pgf@y<0pt\relax\pgf@y=-\pgf@y\fi% + % + \pgf@x=\pgfintersectiontolerancefactor\pgf@x% + \pgf@y=\pgfintersectiontolerancefactor\pgf@y% + \ifdim\pgf@x<\pgfintersectiontolerance\relax% + \ifdim\pgf@y<\pgfintersectiontolerance\relax% + \let\pgf@intersect@next=\pgfutil@firstoftwo% + \fi% + \fi% +}% + +\newif\ifpgf@intersect@solutions@sortfinish + +% Sort solutions according to their time index. +% +\def\pgfintersectionsolutionsortbytime{% + \pgf@intersect@solutions@sortfinishtrue% + \pgfmathloop% + \ifnum\pgfmathcounter<\pgfintersectionsolutions\relax% + \pgfutil@tempcnta=\pgfmathcounter% + \advance\pgfutil@tempcnta by1\relax% + \ifdim\csname pgf@intersect@solution@\pgfmathcounter @time@a\endcsname pt>% + \csname pgf@intersect@solution@\the\pgfutil@tempcnta @time@a\endcsname pt\relax% + \pgf@intersect@solutions@sortfinishfalse% + % + \pgfintersectionsolutionsortbytime@swap{pgfpoint@intersect@solution@\pgfmathcounter}% + {pgfpoint@intersect@solution@\the\pgfutil@tempcnta}% + % + \pgfintersectionsolutionsortbytime@swap{pgf@intersect@solution@\pgfmathcounter @time@a}% + {pgf@intersect@solution@\the\pgfutil@tempcnta @time@a}% + % + \pgfintersectionsolutionsortbytime@swap{pgf@intersect@solution@props@\pgfmathcounter}% + {pgf@intersect@solution@props@\the\pgfutil@tempcnta}% + \fi% + \repeatpgfmathloop% + \ifpgf@intersect@solutions@sortfinish% + \else% + \expandafter\pgfintersectionsolutionsortbytime% + \fi% +}% + +\def\pgfintersectionsolutionsortbytime@swap#1#2{% + \pgfutil@namelet{pgf@intersect@temp}{#1}% + \pgfutil@namelet{#1}{#2}% + \pgfutil@namelet{#2}{pgf@intersect@temp}% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarylindenmayersystems.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarylindenmayersystems.code.tex new file mode 100644 index 0000000000..6fbdd86664 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarylindenmayersystems.code.tex @@ -0,0 +1,229 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\newdimen\pgflsystemstep +\newcount\c@pgf@lsystem@iteration + +\newif\ifpgf@lsystem@randomize@step +\newif\ifpgf@lsystem@randomize@angle + +\pgfkeys{/pgf/lindenmayer system/.cd,% + step/.code={\pgfmathsetlength\pgflsystemstep{#1}},% + randomize step percent/.code={% + \pgfmathparse{#1}% + \let\pgflsystemrandomizesteppercent=\pgfmathresult% + \ifdim\pgfmathresult pt=0pt\relax% + \pgf@lsystem@randomize@stepfalse% + \else% + \pgf@lsystem@randomize@steptrue% + \fi% + },% + left angle/.code={\pgfmathparse{#1}\let\pgflsystemleftangle=\pgfmathresult},% + right angle/.code={\pgfmathparse{#1}\let\pgflsystemrightangle=\pgfmathresult},% + angle/.style={/pgf/lindenmayer system/left angle={#1}, /pgf/lindenmayer system/right angle={#1}},% + randomize angle percent/.code={% + \pgfmathparse{#1}% + \let\pgflsystemrandomizeanglepercent=\pgfmathresult% + \ifdim\pgfmathresult pt=0pt\relax% + \pgf@lsystem@randomize@anglefalse% + \else% + \pgf@lsystem@randomize@angletrue% + \fi% + }% +}% + +\pgfkeys{/pgf/lindenmayer system/.cd, + step=5pt,% + randomize step percent=0,% + angle=90,% + randomize angle percent=0% +}% + +\long\def\pgfdeclarelindenmayersystem#1#2{% + \pgfutil@ifundefined{pgf@lsystem@#1}% + {% + \begingroup% + \edef\pgf@lsystem@name{#1}% + \expandafter\global\expandafter\let\csname pgf@lsystem@#1\endcsname=\pgf@lsystem@name% + \let\symbol=\pgf@lsystem@symbol% + \let\rule=\pgf@lsystem@rule% + #2% + \endgroup% + }% + {\pgferror{Lindenmayer system `#1' is already defined}}% +}% + +\def\pgf@lsystem@symbol#1#2{% + \expandafter\gdef\csname pgf@lsystem@\pgf@lsystem@name @symbol@#1\endcsname{#2}% +}% + +\def\pgf@lsystem@rule#1{\expandafter\pgf@lsystem@rule@#1\pgf@stop}% +\def\pgf@lsystem@rule@#1{\def\pgf@lsystem@rule@head{#1}\pgf@lsystem@rule@@}% +\def\pgf@lsystem@rule@@#1->{% Now some `fooling around' to deal with unwanted spaces. + \let\pgf@lsystem@rule@body=\pgfutil@empty% + \pgfutil@ifnextchar x{\pgf@lsystem@rule@@@}{\pgf@lsystem@rule@@@}}% +\def\pgf@lsystem@rule@@@#1{% + \ifx#1\pgf@stop% + \expandafter\global\expandafter\let% + \csname pgf@lsystem@\pgf@lsystem@name @rule@\pgf@lsystem@rule@head\endcsname=\pgf@lsystem@rule@body% + \else% + \edef\pgf@lsystem@rule@body{\pgf@lsystem@rule@body#1}% + \expandafter\pgf@lsystem@rule@@@% + \fi% +}% + +\def\pgflindenmayersystem#1#2#3{% + \begingroup% + \edef\pgf@lsystem@name{#1}% + \edef\pgf@lsystem@axiom{#2}% + \pgfmathtruncatemacro\pgf@lsystem@order{#3}% + % + \let\pgf@lsystem@current@symbol=\relax% + % + \c@pgf@lsystem@iteration=0\relax% + % + \ifnum\pgf@lsystem@order=0\relax% + \expandafter\pgf@lsystem@draw\pgf@lsystem@axiom\pgf@stop + \let\pgf@lsystem@next=\pgf@lsystem@end% + \else% + \let\pgf@lsystem@next=\pgf@lsystem@run% + \fi% + \expandafter\pgf@lsystem@next\pgf@lsystem@axiom\pgf@lsystem@stop% +}% + +\def\pgf@lsystem@run#1{% + \ifx#1\pgf@lsystem@stop% + \def\pgf@lsystem@token{\pgf@lsystem@stop}% + \let\pgf@lsystem@next=\pgf@lsystem@end% + \else% + \ifx#1\pgf@stop% + \advance\c@pgf@lsystem@iteration by-1\relax% + \let\pgf@system@token=\pgfutil@empty% + \let\pgf@lsystem@next=\pgf@lsystem@run% + \else% + % Does #1 appear on the RHS of a rule...? + \expandafter\let\expandafter\pgf@lsystem@token\expandafter=% + \csname pgf@lsystem@\pgf@lsystem@name @rule@#1\endcsname% + \ifx\pgf@lsystem@token\relax% + % ...nope. So draw it straight away. + \pgf@lsystem@draw#1\pgf@stop% + \let\pgf@lsystem@token=\pgfutil@empty% + \else% + % ...yep. So, if the order has been reached draw the LHS + % immediately. Otherwise add the LHS to the token stream + % and continue. + \advance\c@pgf@lsystem@iteration by1\relax% + \ifnum\c@pgf@lsystem@iteration=\pgf@lsystem@order% + \expandafter\pgf@lsystem@draw\pgf@lsystem@token \pgf@stop% + \advance\c@pgf@lsystem@iteration by-1\relax% + \let\pgf@lsystem@token=\pgfutil@empty% + \else% + \expandafter\def\expandafter\pgf@lsystem@token\expandafter{\pgf@lsystem@token \pgf@stop}% + \fi% + \fi% + \let\pgf@lsystem@next=\pgf@lsystem@run% + \fi% + \fi% + \expandafter\pgf@lsystem@next\pgf@lsystem@token}% + +\def\pgf@lsystem@end#1\pgf@lsystem@stop{\endgroup}% + +\def\pgf@lsystem@draw#1{% + \ifx#1\pgf@stop% + \let\pgf@lsystem@next=\relax% + \else% + \expandafter\let\expandafter\pgf@lsystem@current@symbol\expandafter=% + \csname pgf@lsystem@\pgf@lsystem@name @symbol@#1\endcsname% + \ifx\pgf@lsystem@current@symbol\relax% Try a default symbol. + \expandafter\let\expandafter\pgf@lsystem@current@symbol\expandafter=% + \csname pgf@lsystem@symbol@default@#1\endcsname% + \fi% + \let\pgf@lsystem@next=\pgf@lsystem@@draw% + \fi% + \pgf@lsystem@next}% + +\def\pgf@lsystem@@draw{% + \edef\pgflsystemcurrentstep{\the\pgflsystemstep}% + \let\pgflsystemcurrentrightangle=\pgflsystemrightangle% + \let\pgflsystemcurrentrightangle=\pgflsystemleftangle% + \pgf@lsystem@current@symbol% + \pgf@lsystem@draw}% + +\expandafter\def\csname +pgf@lsystem@symbol@default@F\endcsname{\pgflsystemdrawforward}% +\expandafter\def\csname +pgf@lsystem@symbol@default@f\endcsname{\pgflsystemmoveforward}% +\expandafter\def\csname +pgf@lsystem@symbol@default@+\endcsname{\pgflsystemturnleft}% +\expandafter\def\csname +pgf@lsystem@symbol@default@-\endcsname{\pgflsystemturnright}% +\expandafter\def\csname +pgf@lsystem@symbol@default@[\endcsname{\pgflsystemsavestate}% +\expandafter\def\csname +pgf@lsystem@symbol@default@]\endcsname{\pgflsystemrestorestate}% + +\def\pgflsystemradonmizestep{% + \ifpgf@lsystem@randomize@step% + \pgfmathrand% + \pgf@x=\pgflsystemrandomizesteppercent pt\relax% + \pgf@x=\pgfmathresult\pgf@x% + \divide\pgf@x by20\relax% + \advance\pgf@x by\pgflsystemstep\relax% + \edef\pgflsystemcurrentstep{\the\pgf@x}% + \else% + \edef\pgflsystemcurrentstep{\the\pgflsystemstep}% + \fi% +}% + +\def\pgflsystemdrawforward{% + \pgflsystemradonmizestep + \pgftransformxshift{+\pgflsystemcurrentstep}% + \pgfpathlineto{\pgfpointorigin}}% + +\def\pgflsystemmoveforward{% + \pgflsystemradonmizestep + \pgftransformxshift{+\pgflsystemcurrentstep}% + \pgfpathmoveto{\pgfpointorigin}}% + +\def\pgflsystemranomizerightangle{% + \ifpgf@lsystem@randomize@angle% + \pgf@x=\pgflsystemrandomizeanglepercent pt\relax% + \divide\pgf@x by20\relax% + \pgfmathrand% + \pgf@x=\pgfmathresult\pgf@x% + \advance\pgf@x by\pgflsystemrightangle pt\relax% + \edef\pgflsystemcurrentrightangle{\pgfmath@tonumber{\pgf@x}}% + \else% + \let\pgflsystemcurrentrightangle=\pgflsystemrightangle% + \fi% +}% + +\def\pgflsystemranomizeleftangle{% + \ifpgf@lsystem@randomize@angle% + \pgf@x=\pgflsystemrandomizeanglepercent pt\relax% + \divide\pgf@x by20\relax% + \pgfmathrand% + \pgf@x=\pgfmathresult\pgf@x% + \advance\pgf@x by\pgflsystemleftangle pt\relax% + \edef\pgflsystemcurrentleftangle{\pgfmath@tonumber{\pgf@x}}% + \else% + \let\pgflsystemcurrentleftangle=\pgflsystemleftangle% + \fi% +}% + +\def\pgflsystemturnright{% + \pgflsystemranomizerightangle + \pgftransformrotate{-\pgflsystemcurrentrightangle}}% + +\def\pgflsystemturnleft{% + \pgflsystemranomizeleftangle + \pgftransformrotate{\pgflsystemcurrentleftangle}}% + +\def\pgflsystemsavestate{\begingroup}% +\def\pgflsystemrestorestate{\endgroup\pgfpathmoveto{\pgfpointorigin}}% diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.code.tex new file mode 100644 index 0000000000..a2dba8e076 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.code.tex @@ -0,0 +1,264 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarypatterns.code.tex} + + +% Lines in different directions + +\pgfdeclarepatternformonly{horizontal lines}{\pgfpointorigin}{\pgfqpoint{100pt}{1pt}}{\pgfqpoint{100pt}{3pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{0pt}{0.5pt}}% + \pgfpathlineto{\pgfqpoint{100pt}{0.5pt}}% + \pgfusepath{stroke}% +}% + +\pgfdeclarepatternformonly{vertical lines}{\pgfpointorigin}{\pgfqpoint{1pt}{100pt}}{\pgfqpoint{3pt}{100pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{0.5pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{0.5pt}{100pt}}% + \pgfusepath{stroke}% +}% + +\pgfdeclarepatternformonly{north east lines}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{4pt}{4pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{3.1pt}{3.1pt}}% + \pgfusepath{stroke}% +}% + +\pgfdeclarepatternformonly{north west lines}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{4pt}{4pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{0pt}{3pt}}% + \pgfpathlineto{\pgfqpoint{3.1pt}{-0.1pt}}% + \pgfusepath{stroke}% +}% + +% Crossed lines in different directions + +\pgfdeclarepatternformonly{grid}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{4pt}{4pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{3.1pt}}% + \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{3.1pt}{0pt}}% + \pgfusepath{stroke}% +}% + +\pgfdeclarepatternformonly{crosshatch}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{4pt}{4pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfsetlinewidth{0.4pt}% + \pgfpathmoveto{\pgfqpoint{3.1pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{3.1pt}}% + \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}% + \pgfpathlineto{\pgfqpoint{3.1pt}{3.1pt}}% + \pgfusepath{stroke}% +}% + + +% Dotted regions + +\pgfdeclarepatternformonly{dots}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{1pt}{1pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfpathcircle{\pgfqpoint{0pt}{0pt}}{.5pt}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatternformonly{crosshatch dots}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{2.5pt}{2.5pt}}{\pgfqpoint{3pt}{3pt}}% +{% + \pgfpathcircle{\pgfqpoint{0pt}{0pt}}{.5pt}% + \pgfpathcircle{\pgfqpoint{1.5pt}{1.5pt}}{.5pt}% + \pgfusepath{fill}% +}% + + + + +% Star shaped patterns + +\pgfdeclarepatternformonly{fivepointed stars}{\pgfpointorigin}{\pgfqpoint{3mm}{3mm}}{\pgfqpoint{3mm}{3mm}}% +{% + \pgftransformshift{\pgfqpoint{1mm}{1mm}}% + \pgfpathmoveto{\pgfqpointpolar{18}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{162}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{306}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{90}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{234}{1mm}}% + \pgfpathclose%% + \pgfusepath{fill}% +}% + +\pgfdeclarepatternformonly{sixpointed stars}{\pgfpointorigin}{\pgfqpoint{3mm}{3mm}}{\pgfqpoint{3mm}{3mm}}% +{% + \pgftransformshift{\pgfqpoint{1mm}{1mm}}% + \pgfpathmoveto{\pgfqpointpolar{30}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{150}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{270}{1mm}}% + \pgfpathclose% + \pgfpathmoveto{\pgfqpointpolar{-30}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{-270}{1mm}}% + \pgfpathlineto{\pgfqpointpolar{-150}{1mm}}% + \pgfpathclose% + \pgfsetnonzerorule% + \pgfusepath{fill}% +}% + + + +% Bricks + +\pgfdeclarepatternformonly{bricks}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{5mm}{5mm}}{\pgfqpoint{4mm}{4mm}}% +{% + \pgfsetlinewidth{0.8pt}% + \pgfpathmoveto{\pgfqpoint{0mm}{1mm}}% + \pgfpathlineto{\pgfqpoint{4mm}{1mm}}% + \pgfpathmoveto{\pgfqpoint{0mm}{3mm}}% + \pgfpathlineto{\pgfqpoint{4mm}{3mm}}% + \pgfpathmoveto{\pgfqpoint{1mm}{0mm}}% + \pgfpathlineto{\pgfqpoint{1mm}{1mm}}% + \pgfpathmoveto{\pgfqpoint{3mm}{1mm}}% + \pgfpathlineto{\pgfqpoint{3mm}{3mm}}% + \pgfpathmoveto{\pgfqpoint{1mm}{3mm}}% + \pgfpathlineto{\pgfqpoint{1mm}{4mm}}% + \pgfusepath{stroke}% +}% + + +% Checkerboards + +\pgfdeclarepatternformonly{checkerboard}{\pgfpointorigin}{\pgfqpoint{4mm}{4mm}}{\pgfqpoint{4mm}{4mm}}% +{% + \pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{2mm}{2mm}}% + \pgfpathrectangle{\pgfqpoint{2mm}{2mm}}{\pgfqpoint{2mm}{2mm}}% + \pgfusepath{fill}% +}% + + + +% Backgrounds + +\pgfdeclarepatterninherentlycolored{checkerboard light gray} +{\pgfpointorigin}{\pgfqpoint{4mm}{4mm}}{\pgfqpoint{4mm}{4mm}}% +{% +% \pgfsetfillcolor{black!10} + \pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{4.1mm}{4.1mm}}% make + % slightly larger to ensure that tiles + % are really solid + \pgfusepath{fill}% + \pgfsetfillcolor{black!20}% + \pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{2mm}{2mm}}% + \pgfpathrectangle{\pgfqpoint{2mm}{2mm}}{\pgfqpoint{2mm}{2mm}}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatterninherentlycolored{horizontal lines light gray} +{\pgfpointorigin}{\pgfpoint{100pt}{4pt}} +{\pgfpoint{100pt}{4pt}} +{% + \pgfsetfillcolor{black!10}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{black!15}% + \pgfpathrectangle{\pgfpoint{0pt}{2pt}}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatterninherentlycolored{horizontal lines gray} +{\pgfpointorigin}{\pgfpoint{100pt}{4pt}} +{\pgfpoint{100pt}{4pt}} +{% + \pgfsetfillcolor{black!30}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{black!35}% + \pgfpathrectangle{\pgfpoint{0pt}{2pt}}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatterninherentlycolored{horizontal lines dark gray} +{\pgfpointorigin}{\pgfpoint{100pt}{4pt}} +{\pgfpoint{100pt}{4pt}} +{% + \pgfsetfillcolor{black!90}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{black!85}% + \pgfpathrectangle{\pgfpoint{0pt}{2pt}}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatterninherentlycolored{horizontal lines light blue} +{\pgfpointorigin}{\pgfpoint{100pt}{4pt}} +{\pgfpoint{100pt}{4pt}} +{% + \pgfsetfillcolor{blue!10}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{blue!15}% + \pgfpathrectangle{\pgfpoint{0pt}{2pt}}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% +}% + +\pgfdeclarepatterninherentlycolored{horizontal lines dark blue} +{\pgfpointorigin}{\pgfpoint{100pt}{4pt}} +{\pgfpoint{100pt}{4pt}} +{% + \pgfsetfillcolor{blue!90}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{blue!85}% + \pgfpathrectangle{\pgfpoint{0pt}{2pt}}{\pgfpoint{100pt}{2.5pt}}% + \pgfusepath{fill}% +}% + + +\pgfdeclarepatterninherentlycolored{crosshatch dots gray} +{\pgfpointorigin}{\pgfpoint{8pt}{8pt}} +{\pgfpoint{8pt}{8pt}} +{% + \pgfsetfillcolor{black!20}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{8pt}{8pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{black!10}% + \pgfpathcircle{\pgfpoint{2pt}{1.75pt}}{1pt}% + \pgfpathcircle{\pgfpoint{6pt}{5.75pt}}{1pt}% + \pgfusepath{fill}% + \pgfsetfillcolor{black!70}% + \pgfpathcircle{\pgfpoint{2pt}{2.25pt}}{1pt}% + \pgfpathcircle{\pgfpoint{6pt}{6.25pt}}{1pt}% + \pgfusepath{fill}% +}% + +\pgfutil@definecolor{pgf@lightsteelblue}{rgb}{0.6875,0.765625,0.8671875}% +\pgfutil@colorlet{pgf@darklightsteelblue}{black!50!pgf@lightsteelblue}% + +\pgfdeclarepatterninherentlycolored{crosshatch dots light steel blue} +{\pgfpointorigin}{\pgfpoint{8pt}{8pt}} +{\pgfpoint{8pt}{8pt}} +{% + \pgfsetfillcolor{pgf@lightsteelblue}% + \pgfpathrectangle{\pgfpointorigin}{\pgfpoint{8pt}{8pt}}% + \pgfusepath{fill}% + \pgfsetfillcolor{pgf@darklightsteelblue!10}% + \pgfpathcircle{\pgfpoint{2pt}{1.75pt}}{1pt}% + \pgfpathcircle{\pgfpoint{6pt}{5.75pt}}{1pt}% + \pgfusepath{fill}% + \pgfsetfillcolor{pgf@darklightsteelblue!70}% + \pgfpathcircle{\pgfpoint{2pt}{2.25pt}}{1pt}% + \pgfpathcircle{\pgfpoint{6pt}{6.25pt}}{1pt}% + \pgfusepath{fill}% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.meta.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.meta.code.tex new file mode 100644 index 0000000000..00de962abe --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarypatterns.meta.code.tex @@ -0,0 +1,458 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\def\pgf@pat@type@uncolored{0}% +\def\pgf@pat@type@colored{1}% +\newif\ifpgf@pat@makepatternimmutable + +\pgfkeys{/pgf/patterns/.cd, + name/.store in=\pgf@pat@name, + number ../.store in=\pgf@pat@number, + type/.is choice, + type/uncolored/.code={\let\pgf@pat@type=\pgf@pat@type@uncolored}, + type/colored/.code={\let\pgf@pat@type=\pgf@pat@type@colored}, + type/form only/.style={/pgf/patterns/type=uncolored}, + type/inherently colored/.style={/pgf/patterns/type=colored}, + x/.store in=\pgf@pat@xvec, + y/.store in=\pgf@pat@yvec, + parameters/.store in=\pgf@pat@parameters, + defaults/.store in=\pgf@pat@defaults, + append to defaults/.code={% + \pgf@pat@addto@macro\pgf@pat@defaults{,#1}% + }, + bottom left/.store in=\pgf@pat@bottomleft, + top right/.store in=\pgf@pat@topright, + tile size/.store in=\pgf@pat@tilesize, + tile transformation/.store in=\pgf@pat@transformation, + code/.store in=\pgf@pat@code, + set up code/.store in=\pgf@pat@declarebefore, + % + name=, + number ..=, + type=uncolored, + x=1cm, y=1cm, + parameters=, + defaults=, + bottom left=, + top right=, + tile size=, + tile transformation=, + code=, + set up code=, +}% + +\def\pgf@pat@name@prefix{pgf@pattern@name@meta@}% + +\def\pgfifpatternundefined#1{% + \pgfutil@ifundefined{\pgf@pat@name@prefix#1}% +}% + +\def\pgf@pat@adddef@to@macro#1#2{% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter{\expandafter#1\expandafter% + \def\expandafter#2\expandafter{#2}}% +}% + +\def\pgf@pat@addto@macro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}}% + +\def\pgf@pat@process#1{% + \pgf@process{#1}% +}% + +\def\pgf@pat@doifnotempty#1{% + \ifx#1\pgfutil@empty% + \let\pgf@pat@next=\relax% + \else% + \let\pgf@pat@next=#1% + \fi% + \pgf@pat@next% +}% + +\def\pgf@pat@processtransformations#1{#1}% +\def\pgf@pat@processpoint#1{% + \pgf@process{#1}% +}% + + +\def\pgfdeclarepattern#1{% + \begingroup% + \nullfont% + \def\pgf@pat@options{,#1}% + \pgfkeys{/pgf/patterns/.cd,#1}% + \ifx\pgf@pat@name\pgfutil@empty + \pgferror{Declaring unnamed pattern}% + \fi + \ifx\pgf@pat@bottomleft\pgfutil@empty + \pgferror{Bottom left corner of the bounding box unset}% + \fi + \ifx\pgf@pat@topright\pgfutil@empty + \pgferror{Top right corner of the bounding box unset}% + \fi + \ifx\pgf@pat@tilesize\pgfutil@empty + \pgferror{Tile size unset}% + \fi + \ifx\pgf@pat@code\pgfutil@empty + \pgferror{Pattern code is empty}% + \fi + \pgf@declarepattern@meta% + \endgroup% +}% +\def\pgf@declarepattern@meta{% + \pgfifpatternundefined{\pgf@pat@name}{% + \ifx\pgf@pat@parameters\pgfutil@empty% + % No parameters, so pattern is declared now. + \pgf@pat@declare% + \edef\pgf@marshal{% + \noexpand\pgf@pat@addto@macro\noexpand\pgf@pat@options{,number ..=\pgf@pattern@number}}% + \pgf@marshal% + \fi% + % It is a bit inefficient that all the options for + % immutable patterns are saved when only the type + % and number are needed. + \expandafter\global\expandafter\let\csname\pgf@pat@name@prefix\pgf@pat@name\endcsname=\pgf@pat@options% + }{% + \pgferror{Pattern `\pgf@pat@name' already defined}% + }% +}% +\let\pgf@pat@declarebefore=\pgfutil@empty +\let\pgf@pat@declareafter=\pgfutil@empty +\let\pgf@pat@codebefore=\pgfutil@empty +\let\pgf@pat@codeafter=\pgfutil@empty + +\def\pgf@pat@declare{% + \pgfsysprotocol@getcurrentprotocol\pgf@pattern@temp% + {% + % Set up x and y vectors. Should use a scope rather than TeX group? + % Vectors may be needed when the tile bounding box is + % calculated. + \pgfsetxvec{\pgfpoint{\pgf@pat@xvec}{+0pt}}% + \pgfsetyvec{\pgfpoint{+0pt}{\pgf@pat@yvec}}% + \pgf@pat@doifnotempty\pgf@pat@declarebefore% + \pgfinterruptpath% + \pgfpicturetrue% + \pgf@relevantforpicturesizetrue% + \pgftransformreset% + \pgfsysprotocol@setcurrentprotocol\pgfutil@empty% + \pgfsysprotocol@bufferedtrue% + \pgfsys@beginscope% + \pgfinterruptboundingbox% + \pgfsetarrows{-}% + \pgf@pat@doifnotempty\pgf@pat@codebefore + \pgf@pat@code% + \pgf@pat@doifnotempty\pgf@pat@codeafter% + \endpgfinterruptboundingbox% + \pgfsys@endscope% + \pgfsysprotocol@getcurrentprotocol\pgf@pattern@code% + \global\let\pgf@pattern@code=\pgf@pattern@code% + \endpgfinterruptpath% + \pgf@pat@doifnotempty\pgf@pat@declareafter% + \pgf@pat@processpoint{\pgf@pat@bottomleft}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@pat@processpoint{\pgf@pat@topright}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@pat@processpoint{\pgf@pat@tilesize}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \begingroup% + \pgftransformreset% + \pgf@pat@processtransformations\pgf@pat@transformation% + \pgfgettransformentries\aa\ab\ba\bb\shiftx\shifty% + \global\edef\pgf@pattern@matrix{{\aa}{\ab}{\ba}{\bb}{\shiftx}{\shifty}}% + \endgroup% + % Now, build a name for the pattern + \pgfutil@tempcnta=\pgf@pattern@number\relax% + \advance\pgfutil@tempcnta by1\relax% + \xdef\pgf@pattern@number{\the\pgfutil@tempcnta}% + \xdef\pgf@marshal{\noexpand\pgfsys@declarepattern% + {\pgf@pattern@number}% + {\the\pgf@xa}{\the\pgf@ya}{\the\pgf@xb}{\the\pgf@yb}{\the\pgf@xc}{\the\pgf@yc}\pgf@pattern@matrix{\pgf@pattern@code}{\pgf@pat@type}}% + }% + \pgf@marshal% + \pgfsysprotocol@setcurrentprotocol\pgf@pattern@temp% +}% + +\def\pgf@pat@checkname#1{% + \pgf@pat@@checkname#1[]\pgf@patstop}% + +\def\pgf@pat@@checkname#1[#2]#3\pgf@patstop{% + \expandafter\def\expandafter\pgf@pat@onlinename\expandafter{\romannumeral-`0\pgfutil@trimspaces{#1}}% + \def\pgf@pat@onlineoptions{#2}% +}% + + +\def\pgf@pat@unravel#1/{% + \pgfutil@ifnextchar\pgf@stop{\def\pgf@pat@unravelled{#1}}{\pgf@pat@unravel}}% + +\pgfkeys{/handlers/.pattern/.code={% + \expandafter\expandafter\expandafter\pgf@pat@unravel\pgfkeyscurrentpath/\pgf@stop% + \pgfpatternalias{#1}{\pgf@pat@unravelled}% +}}% + +\def\pgfpatternalias#1#2{% + \begingroup% + \pgf@pat@checkname{#1}% + \expandafter\let\expandafter\pgf@pat@options\expandafter=% + \csname\pgf@pat@name@prefix\pgf@pat@onlinename\endcsname% + \pgf@pat@macroaskeys{/pgf/patterns/.cd}{\pgf@pat@options}% + \pgfutil@toks@\expandafter{\pgf@pat@onlineoptions}% + \edef\pgf@pat@tmp{append to defaults={\the\pgfutil@toks@}}% + \expandafter\pgf@pat@addto@macro\expandafter\pgf@pat@options\expandafter{\expandafter,\pgf@pat@tmp}% + \pgf@pat@addto@macro\pgf@pat@options{,name=#2}% + \expandafter\global\expandafter\let\csname\pgf@pat@name@prefix#2\endcsname=\pgf@pat@options% + \endgroup% +}% + + +\let\pgfsetfillpattern@old=\pgfsetfillpattern + +\def\pgf@pat@macroaskeys#1#2{% + \pgfutil@toks@\expandafter{#2}% + \edef\pgf@marshal{\noexpand\pgfkeys{,#1,\the\pgfutil@toks@}}% + \pgf@marshal% +}% +\def\pgfsetfillpattern#1#2{% + \pgf@pat@checkname{#1}% + \pgfutil@ifundefined{\pgf@pat@name@prefix\pgf@pat@onlinename}{% + \pgfsetfillpattern@old{\pgf@pat@onlinename}{#2}% + }{% + \let\pgf@pat@parameters=\pgfutil@empty% + % Get pattern parameters, type, and number + \expandafter\let\expandafter\pgf@pat@options\expandafter=% + \csname\pgf@pat@name@prefix\pgf@pat@onlinename\endcsname% + \pgf@pat@macroaskeys{/pgf/patterns/.cd}{\pgf@pat@options}% + \ifx\pgf@pat@parameters\pgfutil@empty% + % Immutable pattern. Do nothing. + \else% + % Mutable. Do a *lot*. + \begingroup% + \pgf@pat@macroaskeys{/pgf/pattern keys/.cd}{\pgf@pat@defaults}% + \pgf@pat@macroaskeys{/pgf/pattern keys/.cd}{\pgf@pat@onlineoptions}% + % ...to get the values of the current parameters... + \edef\pgf@pat@current@parameters{\pgf@pat@parameters}% + % ...and the internal pattern name. + \edef\pgf@pat@onlinename{\pgf@pat@onlinename\pgf@pat@current@parameters}% + \let\pgf@pat@name=\pgf@pat@onlinename% + \pgfutil@ifundefined{\pgf@pat@name@prefix\pgf@pat@onlinename}{% + %\ifpgf@pat@makepatternimmutable% + \let\pgf@pat@parameters=\pgfutil@empty% + %\fi% + \pgf@declarepattern@meta% + }{}% + \expandafter% + \endgroup% + \expandafter\def\expandafter\pgf@pat@onlinename\expandafter{\pgf@pat@onlinename}% + \expandafter\let\expandafter\pgf@pat@options\expandafter=% + \csname\pgf@pat@name@prefix\pgf@pat@onlinename\endcsname% + \pgf@pat@macroaskeys{/pgf/patterns/.cd}{\pgf@pat@options}% + \fi% + \ifx\pgf@pat@type\pgf@pat@type@uncolored% + \pgf@pat@setpatternuncolored{\pgf@pat@number}{#2}% + \else% + \pgfsys@setpatterncolored{\pgf@pat@number}% + \fi% + }% +}% + +\def\pgf@pat@setpatternuncolored#1#2{% + \pgfutil@colorlet{pgf@tempcolor}{#2}% + \pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgf@tempcolor}}% + \pgfutil@extractcolorspec{pgf@tempcolor}{\pgf@tempcolor}% + \expandafter\pgfutil@convertcolorspec\pgf@tempcolor{rgb}{\pgf@rgbcolor}% + \expandafter\pgf@pat@set@fill@patternuncolored\pgf@rgbcolor\relax{#1}% +}% +\def\pgf@pat@set@fill@patternuncolored#1,#2,#3\relax#4{% + \pgfsys@setpatternuncolored{#4}{#1}{#2}{#3}% +}% + +% Predefined patterns + +\pgfdeclarepattern{ + name=Lines, + parameters={ + \pgfkeysvalueof{/pgf/pattern keys/distance}, + \pgfkeysvalueof{/pgf/pattern keys/angle}, + \pgfkeysvalueof{/pgf/pattern keys/xshift}, + \pgfkeysvalueof{/pgf/pattern keys/yshift}, + \pgfkeysvalueof{/pgf/pattern keys/line width}, + }, + bottom left={% + \pgfpoint + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + top right={% + \pgfpoint + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + tile size={% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/distance}}% + {\pgfkeysvalueof{/pgf/pattern keys/distance}}}, + tile transformation={% + \pgftransformshift{% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/xshift}}% + {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}% + \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}}, + defaults={ + distance/.initial=3pt, + angle/.initial=0, + xshift/.initial=0pt, + yshift/.initial=0pt, + line width/.initial=\the\pgflinewidth, + }, + code={% + \pgfsetlinewidth{\pgfkeysvalueof{/pgf/pattern keys/line width}}% + \pgfpathmoveto{\pgfpoint{-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}% + \pgfpathlineto{\pgfpoint{.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}% + \pgfusepath{stroke}% + }, +} + +\pgfdeclarepattern{ + name=Hatch, + parameters={ + \pgfkeysvalueof{/pgf/pattern keys/distance}, + \pgfkeysvalueof{/pgf/pattern keys/angle}, + \pgfkeysvalueof{/pgf/pattern keys/xshift}, + \pgfkeysvalueof{/pgf/pattern keys/yshift}, + \pgfkeysvalueof{/pgf/pattern keys/line width}, + }, + bottom left={% + \pgfpoint + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + top right={% + \pgfpoint + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + tile size={% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/distance}}% + {\pgfkeysvalueof{/pgf/pattern keys/distance}}}, + tile transformation={% + \pgftransformshift{% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/xshift}}% + {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}% + \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}}, + defaults={ + distance/.initial=3pt, + angle/.initial=0, + xshift/.initial=0pt, + yshift/.initial=0pt, + line width/.initial=\the\pgflinewidth, + }, + code={% + \pgfsetlinewidth{\pgfkeysvalueof{/pgf/pattern keys/line width}}% + \pgfpathmoveto{\pgfpoint{-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}% + \pgfpathlineto{\pgfpoint{.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}% + \pgfpathmoveto{\pgfpoint{0pt}{-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}% + \pgfpathlineto{\pgfpoint{0pt}{.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}% + \pgfusepath{stroke}% + }, +} + +\pgfdeclarepattern{ + name=Dots, + parameters={ + \pgfkeysvalueof{/pgf/pattern keys/distance}, + \pgfkeysvalueof{/pgf/pattern keys/angle}, + \pgfkeysvalueof{/pgf/pattern keys/xshift}, + \pgfkeysvalueof{/pgf/pattern keys/yshift}, + \pgfkeysvalueof{/pgf/pattern keys/radius}, + }, + bottom left={% + \pgfpoint + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + top right={% + \pgfpoint + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + tile size={% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/distance}}% + {\pgfkeysvalueof{/pgf/pattern keys/distance}}}, + tile transformation={% + \pgftransformshift{% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/xshift}}% + {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}% + \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}}, + defaults={ + distance/.initial=3pt, + angle/.initial=0, + xshift/.initial=0pt, + yshift/.initial=0pt, + radius/.initial=.5pt, + }, + code={% + \pgfpathcircle% + {\pgfpointorigin}% + {\pgfkeysvalueof{/pgf/pattern keys/radius}} + \pgfusepath{fill}% + }, +} + +\pgfdeclarepattern{ + name=Stars, + parameters={ + \pgfkeysvalueof{/pgf/pattern keys/distance}, + \pgfkeysvalueof{/pgf/pattern keys/angle}, + \pgfkeysvalueof{/pgf/pattern keys/xshift}, + \pgfkeysvalueof{/pgf/pattern keys/yshift}, + \pgfkeysvalueof{/pgf/pattern keys/radius}, + \pgfkeysvalueof{/pgf/pattern keys/points}, + }, + bottom left={% + \pgfpoint + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + top right={% + \pgfpoint + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}% + {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}}, + tile size={% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/distance}}% + {\pgfkeysvalueof{/pgf/pattern keys/distance}}}, + tile transformation={% + \pgftransformshift{% + \pgfpoint + {\pgfkeysvalueof{/pgf/pattern keys/xshift}}% + {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}% + \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}}, + defaults={ + distance/.initial=3mm, + angle/.initial=0, + xshift/.initial=0pt, + yshift/.initial=0pt, + radius/.initial=1mm, + points/.initial=5, + }, + code={% + \pgfmathsetmacro\a{180/(\pgfkeysvalueof{/pgf/pattern keys/points})}% + \pgfpathmoveto{\pgfpointpolar{90}{\pgfkeysvalueof{/pgf/pattern keys/radius}}}% + \foreach \i in {1,...,\pgfkeysvalueof{/pgf/pattern keys/points}}{% + \pgfpathlineto{\pgfpointpolar{90+2*\i*\a-\a}{.5*(\pgfkeysvalueof{/pgf/pattern keys/radius})}}% + \pgfpathlineto{\pgfpointpolar{90+2*\i*\a}{\pgfkeysvalueof{/pgf/pattern keys/radius}}}% + }% + \pgfpathclose% + \pgfusepath{fill}% + }, +} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryplothandlers.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryplothandlers.code.tex new file mode 100644 index 0000000000..d0b9a388eb --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryplothandlers.code.tex @@ -0,0 +1,1114 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryplothandlers.code.tex} + + +% This handler converts each plot stream command into a curveto +% command, except for the first, which is converted to the previously +% specified action. +% +% Example: +% +% \pgfpathmoveto{\pgfpointorigin} +% \pgfsetlinetofirstplotpoint +% \pgfplothandlercurveto +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlercurveto}{}{% + point macro=\pgf@plot@curveto@handler@initial, + jump macro=\pgf@plot@smooth@next@moveto, + end macro=\pgf@plot@curveto@handler@finish +}% + +\def\pgf@plot@smooth@next@moveto{% + \pgf@plot@curveto@handler@finish% + \global\pgf@plot@startedfalse% + \global\let\pgf@plotstreampoint\pgf@plot@curveto@handler@initial% +}% + +\def\pgf@plot@curveto@handler@initial#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@plot@first@action{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@curveto@first{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \global\let\pgf@plot@curveto@first@support=\pgf@plot@curveto@first% + \global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@second% +}% + +\def\pgf@plot@curveto@handler@second#1{% + \pgf@process{#1}% + \xdef\pgf@plot@curveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@third% + \global\pgf@plot@startedtrue% +}% + +\def\pgf@plot@curveto@handler@third#1{% + \pgf@process{#1}% + \xdef\pgf@plot@curveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % compute difference vector: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgf@plot@curveto@first} + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % compute support directions: + \pgf@xa=\pgf@plottension\pgf@xa% + \pgf@ya=\pgf@plottension\pgf@ya% + % first marshal: + \pgf@process{\pgf@plot@curveto@second}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by\pgf@xa% + \advance\pgf@yc by\pgf@ya% + \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@curveto@first@support}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@curveto@second}}% + {\pgf@marshal}% + % Prepare next: + \global\let\pgf@plot@curveto@first=\pgf@plot@curveto@second% + \global\let\pgf@plot@curveto@second=\pgf@plot@curveto@current% + \xdef\pgf@plot@curveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% +}% + +\def\pgf@plot@curveto@handler@finish{% + \ifpgf@plot@started% + \pgfpathcurveto{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}% + \fi% +}% + + +% This commands sets the tension for smoothing of plots. +% +% #1 = tension of curves. A value of 1 will yield a circle when the +% control points are at quarters of a circle. A smaller value +% will result in a tighter curve. Default is 0.5. +% +% Example: +% +% \pgfsetplottension{0.2} + +\def\pgfsetplottension#1{% + \pgf@x=#1pt\relax% + \pgf@x=0.2775\pgf@x\relax% + \edef\pgf@plottension{\pgf@sys@tonumber\pgf@x}}% +\pgfsetplottension{0.5}% + + +% This handler converts the plot stream command into a curveto +% command that is closed using a closepath. +% +% Example: +% +% \pgfpathmoveto{\pgfpointorigin} +% \pgfplothandlerclosedcurve +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerclosedcurve}{}{% + point macro=\pgf@plot@closedcurve@handler@initial, + end macro=\pgf@plot@closedcurve@handler@finish, + jump macro=\pgf@plot@closedsmooth@next@moveto +}% + +\def\pgf@plot@closedsmooth@next@moveto{% + \pgf@plot@closedcurve@handler@finish% + \global\pgf@plot@startedfalse% + \global\let\pgf@plotstreampoint\pgf@plot@closedcurve@handler@initial% +}% + +\def\pgf@plot@closedcurve@handler@initial#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \xdef\pgf@plot@closedcurve@initial{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \global\let\pgf@plotstreampoint=\pgf@plot@closedcurve@handler@second% + \global\pgf@plot@startedfalse% +}% + +\def\pgf@plot@closedcurve@handler@second#1{% + \pgf@process{#1}% + \xdef\pgf@plot@closedcurve@after@initial{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + {\pgfpathmoveto{}}% + \global\let\pgf@plotstreampoint=\pgf@plot@closedcurve@handler@third% +}% + +\def\pgf@plot@closedcurve@handler@third#1{% + \global\pgf@plot@startedtrue% + \pgf@process{#1}% + \xdef\pgf@plot@closedcurve@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % compute difference vector: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgf@plot@closedcurve@initial} + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % compute support directions: + \pgf@xa=\pgf@plottension\pgf@xa% + \pgf@ya=\pgf@plottension\pgf@ya% + % first marshal: + \pgf@process{\pgf@plot@closedcurve@after@initial}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by\pgf@xa% + \advance\pgf@yc by\pgf@ya% + \global\let\pgf@plot@closedcurve@first=\pgf@plot@closedcurve@after@initial% + \global\let\pgf@plot@closedcurve@second=\pgf@plot@closedcurve@current% + \xdef\pgf@plot@closedcurve@after@initial@presupport{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}% + \xdef\pgf@plot@closedcurve@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + \global\let\pgf@plotstreampoint=\pgf@plot@closedcurve@handler@fourth% +}% + +\def\pgf@plot@closedcurve@handler@fourth#1{% + \pgf@process{#1}% + \xdef\pgf@plot@closedcurve@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % compute difference vector: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgf@plot@closedcurve@first} + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % compute support directions: + \pgf@xa=\pgf@plottension\pgf@xa% + \pgf@ya=\pgf@plottension\pgf@ya% + % first marshal: + \pgf@process{\pgf@plot@closedcurve@second}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by\pgf@xa% + \advance\pgf@yc by\pgf@ya% + \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@closedcurve@first@support}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@closedcurve@second}}% + {\pgf@marshal}% + % Prepare next: + \global\let\pgf@plot@closedcurve@first=\pgf@plot@closedcurve@second% + \global\let\pgf@plot@closedcurve@second=\pgf@plot@closedcurve@current% + \xdef\pgf@plot@closedcurve@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% +}% + +\def\pgf@plot@closedcurve@handler@finish{% + \ifpgf@plot@started + % + % first, draw line from 2nd last to last: + % + \pgf@process{\pgf@plot@closedcurve@initial}% + % compute difference vector: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgf@plot@closedcurve@first}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % compute support directions: + \pgf@xa=\pgf@plottension\pgf@xa% + \pgf@ya=\pgf@plottension\pgf@ya% + % first marshal: + \pgf@process{\pgf@plot@closedcurve@second}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by\pgf@xa% + \advance\pgf@yc by\pgf@ya% + \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@closedcurve@first@support}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@closedcurve@second}}% + {\pgf@marshal}% + \xdef\pgf@plot@closedcurve@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + % + % second, draw line from last point to start: + % + \pgf@process{\pgf@plot@closedcurve@after@initial}% + % compute difference vector: + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgf@plot@closedcurve@second}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % compute support directions: + \pgf@xa=\pgf@plottension\pgf@xa% + \pgf@ya=\pgf@plottension\pgf@ya% + % first marshal: + \pgf@process{\pgf@plot@closedcurve@initial}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \advance\pgf@xb by-\pgf@xa% + \advance\pgf@yb by-\pgf@ya% + \advance\pgf@xc by\pgf@xa% + \advance\pgf@yc by\pgf@ya% + \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@closedcurve@first@support}% + {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@closedcurve@initial}}% + {\pgf@marshal}% + % + % third, draw line from first to second point: + % + \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% + {\noexpand\pgf@plot@closedcurve@after@initial@presupport}{\noexpand\pgf@plot@closedcurve@after@initial}}% + {\pgf@marshal}% + \pgfpathclose% + \fi% +}% + + + + + +% This handler converts each point in a stream into a line from the +% $y$-axis to the given points coordinate, resulting in a +% ``comb.'' +% +% Example: +% +% \pgfplothandlerxcomb +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerxcomb}{}{% + start macro=\pgfplotxzerolevelstreamstart, + point macro=\pgf@plot@xcomb@handler, + end macro=\pgfplotxzerolevelstreamend, +}% + +\def\pgf@plot@xcomb@handler#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \begingroup + \pgfplotxzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \pgfpathmoveto{\pgfqpoint{\pgf@yb}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% +}% + + +% This handler converts each point in a stream into a line from the +% $x$-axis straight up to the given points coordinate, resulting in a +% ``comb.'' +% +% Example: +% +% \pgfplothandlerycomb +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerycomb}{}{% + start macro=\pgfplotyzerolevelstreamstart, + point macro=\pgf@plot@ycomb@handler, + end macro=\pgfplotyzerolevelstreamend +}% + +\def\pgf@plot@ycomb@handler#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \begingroup + \pgfplotyzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% +}% + +% PGF Bar or comb plots usually draw something from zero to the current plot's coordinate. +% +% The 'zero' offset can be changed using an input stream. +% +% There are two such streams which can be configured independently. +% The first one returns "zeros" for coordinate x, the second one +% returns "zeros" for coordinate y. +% +% \pgfplotxzerolevelstreamstart +% \pgfplotxzerolevelstreamnext % assigns \pgf@x globally +% \pgfplotxzerolevelstreamnext +% \pgfplotxzerolevelstreamnext +% \pgfplotxzerolevelstreamend +% +% and +% \pgfplotyzerolevelstreamstart +% \pgfplotyzerolevelstreamnext % assigns \pgf@x globally +% \pgfplotyzerolevelstreamend +% +\def\pgfplotxzerolevelstreamstart{\pgf@plotxzerolevelstreamstart}% +\def\pgfplotxzerolevelstreamend{\pgf@plotxzerolevelstreamend}% +\def\pgfplotxzerolevelstreamnext{\pgf@plotxzerolevelstreamnext} +\def\pgfplotyzerolevelstreamstart{\pgf@plotyzerolevelstreamstart}% +\def\pgfplotyzerolevelstreamend{\pgf@plotyzerolevelstreamend}% +\def\pgfplotyzerolevelstreamnext{\pgf@plotyzerolevelstreamnext}% + +% This zero level stream always returns '#1' (a dimension). +\def\pgfplotxzerolevelstreamconstant#1{% + \edef\pgfplotxzerolevelstreamconstant@val{#1}% + \def\pgf@plotxzerolevelstreamstart{% + \global\let\pgf@plotxzerolevelstreamend=\relax + \gdef\pgf@plotxzerolevelstreamnext{\global\pgf@x=\pgfplotxzerolevelstreamconstant@val\relax}% + }% +}% +\pgfplotxzerolevelstreamconstant{0pt}% + +% This zero level stream always returns '#1'. +\def\pgfplotyzerolevelstreamconstant#1{% + \edef\pgfplotyzerolevelstreamconstant@val{#1}% + \def\pgf@plotyzerolevelstreamstart{% + \global\let\pgf@plotyzerolevelstreamend=\relax + \gdef\pgf@plotyzerolevelstreamnext{\global\pgf@x=\pgfplotyzerolevelstreamconstant@val\relax}% + }% +}% +\pgfplotyzerolevelstreamconstant{0pt}% + +\def\pgfplotbarwidth{\pgfkeysvalueof{/pgf/bar width}}% +\def\pgfplotbarshift{\pgfkeysvalueof{/pgf/bar shift}}% + +\pgfqkeys{/pgf}{% + bar width/.initial=10pt, + bar shift/.initial=0pt, + bar interval width/.initial=1, + bar interval shift/.initial=0.5, + % + % hook which is executed right before a new bar is begun. + at begin bar/.initial=, + % hook which is executed right after a bar path has been finished. + % In this context, the bar's path has not been used. + at end bar/.initial=, +}% + +% This handler places a rectangle at each point in the plot stream, a +% rectangle which touches the x-axis at one end and the current point +% at the other end: +% --(X)-- +% | | +% | | +% | | +% --(0)-- +% Example: +% +% \pgfplothandlerybar +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerybar}{}{% + start={ + \pgfmathparse{\pgfplotbarwidth}% + \xdef\pgfplotbarwidth@{\pgfmathresult pt}% + \pgfmathparse{\pgfplotbarshift}% + \xdef\pgfplotbarshift@{\pgfmathresult pt}% + \pgfplotyzerolevelstreamstart + }, + end macro=\pgfplotyzerolevelstreamend, + point macro=\pgf@plot@ybar@handler +}% + +\def\pgf@plot@ybar@handler#1{% + \pgfkeysvalueof{/pgf/at begin bar}% + \pgf@process{#1}% + \pgf@ya=\pgf@y + \expandafter\pgf@xb\pgfplotbarwidth@\relax + \pgf@xc=\pgf@x + \advance\pgf@xc by-.5\pgf@xb + \advance\pgf@xc by\pgfplotbarshift@\relax + \begingroup + \pgfplotyzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \advance\pgf@ya by-\pgf@yb + \pgfpathrectangle + {\pgfqpoint{\pgf@xc}{\pgf@yb}}% + {\pgfqpoint{\pgf@xb}{\pgf@ya}}% + \pgfkeysvalueof{/pgf/at end bar}% +}% + +% This handler places a rectangle at each point in the plot stream, a +% rectangle which touches the y-axis at one end and the current point +% at the other end: +% --------- +% | | +% (0) (X) +% | | +% --------- +% Example: +% +% \pgfplothandlerxbar +% \pgfplotxyfile{mytable} +\pgfdeclareplothandler{\pgfplothandlerxbar}{}{% + start={ + \pgfmathparse{\pgfplotbarwidth}% + \xdef\pgfplotbarwidth@{\pgfmathresult pt}% + \pgfmathparse{\pgfplotbarshift}% + \xdef\pgfplotbarshift@{\pgfmathresult pt}% + \pgfplotxzerolevelstreamstart + }, + end macro=\pgfplotxzerolevelstreamend, + point macro=\pgf@plot@xbar@handler +}% + +\def\pgf@plot@xbar@handler#1{% + \pgfkeysvalueof{/pgf/at begin bar}% + \pgf@process{#1}% + \pgf@ya=\pgf@x + \expandafter\pgf@xb\pgfplotbarwidth@\relax + \pgf@xc=\pgf@y + \advance\pgf@xc by-.5\pgf@xb + \advance\pgf@xc by\pgfplotbarshift@\relax + \begingroup + \pgfplotxzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \advance\pgf@ya by-\pgf@yb + \pgfpathrectangle + {\pgfqpoint{\pgf@yb}{\pgf@xc}}% + {\pgfqpoint{\pgf@ya}{\pgf@xb}}% + \pgfkeysvalueof{/pgf/at end bar}% +}% + +% This handler is a variant of \pgfplothandlerybar which works with +% intervals instead of points. +% +% Bars are drawn between successive input coordinates and the width is +% determined relatively to the interval length. +% +% It looks like this: +% +% |---| |-----| +% | | | | +% | | | | +% | | | | +% (X)------(X)-----------(X) +% +% where (X) denotes the x-axis offsets of input coordinates. +% +% In more detail, if (x_i,y_i) and (x_{i+1},y_{i+1}) denote successive +% input coordinates, the bar will be placed above the +% interval [x_i,x_{i+1}], centered at +% +% x_i + \pgfkeysvalueof{/pgf/bar interval shift} * (x_{i+1} - x_i) +% +% with width +% +% \pgfkeysvalueof{/pgf/bar interval width} * (x_{i+1} - x_i). +% +% If you have N+1 input points, you will get N bars (one for each +% interval). The y_i value of the last bar will be ignored. +% +% Example: +% +% \pgfplothandlerybarinterval +% \pgfplotxyfile{mytable} +\pgfdeclareplothandler{\pgfplothandlerybarinterval}{}{% + start={ + \pgfmathparse{\pgfkeysvalueof{/pgf/bar interval width}}% + \xdef\pgfplotbarintervalwidth@{\pgfmathresult}% + \pgfmathparse{\pgfkeysvalueof{/pgf/bar interval shift}}% + \xdef\pgfplotbarintervalshift@{\pgfmathresult}% + \pgfplotyzerolevelstreamstart + }, + end macro=\pgfplotyzerolevelstreamend, + point macro=\pgf@plot@ybarinterval@handler@first +}% + +\def\pgf@plot@ybarinterval@handler@first#1{% + \pgf@process{#1}% + \xdef\pgf@plot@barinterval@intervalstart{\the\pgf@x}% + \xdef\pgf@plot@barinterval@bar{\the\pgf@y}% + \global\let\pgf@plotstreampoint=\pgf@plot@ybarinterval@handler% +}% +\def\pgf@plot@ybarinterval@handler#1{% + \pgfkeysvalueof{/pgf/at begin bar}% + \pgf@process{#1}% + \pgf@ya=\pgf@plot@barinterval@bar + \xdef\pgf@plot@barinterval@bar{\the\pgf@y}% + \pgf@xc=\pgf@plot@barinterval@intervalstart\relax + \xdef\pgf@plot@barinterval@intervalstart{\the\pgf@x}% + \pgf@xb=\pgf@x + \advance\pgf@xb by-\pgf@xc + \advance\pgf@xc by\pgfplotbarintervalshift@\pgf@xb + \pgf@xb=\pgfplotbarintervalwidth@\pgf@xb + \advance\pgf@xc by-.5\pgf@xb% center + \begingroup + \pgfplotyzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \advance\pgf@ya by-\pgf@yb + \pgfpathrectangle + {\pgfqpoint{\pgf@xc}{\pgf@yb}}% + {\pgfqpoint{\pgf@xb}{\pgf@ya}}% + \pgfkeysvalueof{/pgf/at end bar}% +}% + +% Like \pgfplothandlerybarinterval but for xbar. +\pgfdeclareplothandler{\pgfplothandlerxbarinterval}{}{% + start={ + \pgfmathparse{\pgfkeysvalueof{/pgf/bar interval width}}% + \xdef\pgfplotbarintervalwidth@{\pgfmathresult}% + \pgfmathparse{\pgfkeysvalueof{/pgf/bar interval shift}}% + \xdef\pgfplotbarintervalshift@{\pgfmathresult}% + \pgfplotxzerolevelstreamstart + }, + end macro=\pgfplotxzerolevelstreamend, + point macro=\pgf@plot@xbarinterval@handler@first +}% + +\def\pgf@plot@xbarinterval@handler@first#1{% + \pgf@process{#1}% + \xdef\pgf@plot@barinterval@intervalstart{\the\pgf@y}% + \xdef\pgf@plot@barinterval@bar{\the\pgf@x}% + \global\let\pgf@plotstreampoint=\pgf@plot@xbarinterval@handler% +}% +\def\pgf@plot@xbarinterval@handler#1{% + \pgfkeysvalueof{/pgf/at begin bar}% + \pgf@process{#1}% + \pgf@ya=\pgf@plot@barinterval@bar + \xdef\pgf@plot@barinterval@bar{\the\pgf@x}% + \pgf@xc=\pgf@plot@barinterval@intervalstart\relax + \xdef\pgf@plot@barinterval@intervalstart{\the\pgf@y}% + \pgf@xb=\pgf@y + \advance\pgf@xb by-\pgf@xc + \advance\pgf@xc by\pgfplotbarintervalshift@\pgf@xb + \pgf@xb=\pgfplotbarintervalwidth@\pgf@xb + \advance\pgf@xc by-.5\pgf@xb% center + \begingroup + \pgfplotxzerolevelstreamnext + \endgroup + \pgf@yb=\pgf@x + \advance\pgf@ya by-\pgf@yb + \pgfpathrectangle + {\pgfqpoint{\pgf@yb}{\pgf@xc}}% + {\pgfqpoint{\pgf@ya}{\pgf@xb}}% + \pgfkeysvalueof{/pgf/at end bar}% +}% + + +% This handler is very similar to \pgfplothandlerlineto, but it +% produces CONSTANT connected pieces of the form +% +% x +% | +% x--- | +% | x---- +% x-| +% +% Example: +% +% \pgfplothandlerconstantlineto +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerconstantlineto}{}{% + point macro=\pgf@plot@const@line@handler +}% + +\def\pgf@plot@const@line@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@y}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@const@line@handler@@% +}% +\def\pgf@plot@const@line@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@yb\pgf@plot@const@line@handler@last\relax + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@ya}% +}% + +% A variant of \pgfplothandlerconstantlineto which places its mark on +% the right line ends. +% +% |---x +% ---x | +% |--x +% x +% +% Example: +% +% \pgfplothandlerconstantlinetomarkright +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerconstantlinetomarkright}{}{% + point macro=\pgf@plot@const@line@mark@right@handler +}% + +\def\pgf@plot@const@line@mark@right@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@x}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@const@line@mark@right@handler@@% +}% +\def\pgf@plot@const@line@mark@right@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@yb\pgf@plot@const@line@handler@last\relax + \pgfpathlineto{\pgfqpoint{\pgf@yb}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@xa}% +}% + +% A variant of \pgfplothandlerconstantlineto which places its mark on +% the middle of the line segment. +% +% ----x +% | +% --x--- | +% | |--x---- +% x-- +% +% Example: +% +% \pgfplothandlerconstantlinetomarkmid +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerconstantlinetomarkmid}{}{% + point macro=\pgf@plot@const@line@mark@mid@handler +}% + +\def\pgf@plot@const@line@mark@mid@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\global\pgf@x=\the\pgf@x\space\global\pgf@y=\the\pgf@y\space}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@const@line@mark@mid@handler@@% +}% +\def\pgf@plot@const@line@mark@mid@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@plot@const@line@handler@last + \pgf@xc=.5\pgf@xa + \advance\pgf@xc by.5\pgf@x + \pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@y}}% + \pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\global\pgf@x=\the\pgf@x\space\global\pgf@y=\the\pgf@y\space}% +}% + +% This handler is in fact a variant of \pgfplothandlerconstantlineto, +% but it does not draw vertical lines. It produces a sequence of +% line-to and move-to operations such that plot marks are placed at +% each right end: +% +% ---x +% ---x +% ---x +% --x +% +% Example: +% +% \pgfplothandlerjumpmarkright +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerjumpmarkright}{}{% + point macro=\pgf@plot@jumpmarkright@handler +}% + +\def\pgf@plot@jumpmarkright@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@x}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@jumpmarkright@handler@@% +}% +\def\pgf@plot@jumpmarkright@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@yb\pgf@plot@const@line@handler@last\relax + \pgfpathmoveto{\pgfqpoint{\pgf@yb}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@xa}% +}% + +% This handler is in fact a variant of \pgfplothandlerconstantlineto, +% but it does not draw vertical lines. It produces a sequence of +% line-to and move-to operations such that plot marks are placed at +% each left end: +% +% x--- +% x--- +% x--- +% x-- +% +% Example: +% +% \pgfplothandlerjumpmarkleft +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerjumpmarkleft}{}{% + point macro=\pgf@plot@jumpmarkleft@handler +}% +\def\pgf@plot@jumpmarkleft@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@y}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@jumpmarkleft@handler@@% +}% +\def\pgf@plot@jumpmarkleft@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@yb\pgf@plot@const@line@handler@last\relax + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}% + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\the\pgf@ya}% +}% + +% This handler is in fact a variant of +% \pgfplothandlerconstantlinetomarkmid, +% but it does not draw vertical lines. It produces a sequence of +% line-to and move-to operations such that plot marks are placed like +% +% ----x +% +% --x-- +% --x---- +% x-- +% +% Example: +% +% \pgfplothandlerjumpmarkmid +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerjumpmarkmid}{}{% + point macro=\pgf@plot@jump@mark@mid@handler +}% + +\def\pgf@plot@jump@mark@mid@handler#1{% + \pgf@process{#1}% + \xdef\pgf@plot@const@line@handler@last{\global\pgf@x=\the\pgf@x\space\global\pgf@y=\the\pgf@y\space}% + \pgf@plot@first@action{}% + \global\let\pgf@plotstreampoint=\pgf@plot@jump@mark@mid@handler@@% +}% +\def\pgf@plot@jump@mark@mid@handler@@#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@plot@const@line@handler@last + \pgf@xc=.5\pgf@xa + \advance\pgf@xc by.5\pgf@x + \pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@y}}% + \pgfpathmoveto{\pgfqpoint{\pgf@xc}{\pgf@ya}}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \xdef\pgf@plot@const@line@handler@last{\global\pgf@x=\the\pgf@x\space\global\pgf@y=\the\pgf@y\space}% +}% + + +% This handler converts each point in a stream into a line from the +% origin to the point's coordinate, resulting in a ``star''. +% +% Example: +% +% \pgfplothandlerpolarcomb +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlerpolarcomb}{}{% + point macro=\pgf@plot@polarcomb@handler +}% + +\def\pgf@plot@polarcomb@handler#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgfpathmoveto{\pgfpointorigin}% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% +}% + + + + +% This handler draws a given mark at each point. +% +% #1 = some code to be executed at each point (with the coordinate +% system translated to that point). +% Typically, this code will be \pgfuseplotmark{whatever}. +% +% Example: +% +% \pgfplothandlermark{\pgfuseplotmark{*}} +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlermark}{#1}{% + start={ + \def\pgf@plot@mark{% + \ifnum\pgf@plot@mark@count<\pgf@plot@mark@repeat\relax% + \else% + \global\pgf@plot@mark@count=0\relax% + #1% + \fi% + }% + \global\pgf@plot@mark@count=\pgf@plot@mark@repeat\relax% + \global\advance\pgf@plot@mark@count by-\pgf@plot@mark@phase\relax% + }, + point macro=\pgf@plot@mark@handler +}% + +\newcount\pgf@plot@mark@count +\def\pgf@plot@mark@phase{0}% + +\def\pgf@plot@mark@handler#1{% + \global\advance\pgf@plot@mark@count by1\relax% + {\pgftransformshift{#1}\pgf@plot@mark}% +}% + + +% Set the repeat count for marks. For example, if 3 is given as a +% value, only every third point will get a mark. +% +% #1 = repeat count +% +% Example: +% +% \pgfsetplotmarkrepeat{2} + +\def\pgfsetplotmarkrepeat#1{\def\pgf@plot@mark@repeat{#1}}% +\pgfsetplotmarkrepeat{1}% + + +% Set the phase for marks. For example, if 3 is the repeat and 3 is +% the phase, already the first point will be marked. +% +% #1 = the index of the first point that should be marked. +% +% Example: +% +% \pgfsetplotmarkphase{3} + +\def\pgfsetplotmarkphase#1{\def\pgf@plot@mark@phase{#1}}% +\pgfsetplotmarkphase{1}% + + + +% This handler draws a given mark at those points whose number is +% given in the (pgffor-like) list. +% +% #1 = some code to be executed at each point (with the coordinate +% system translated to that point). +% Typically, this code will be \pgfuseplotmark{whatever}. +% #2 = list of positions like "1,2,4,...,9,10" +% +% Example: +% +% \pgfplothandlermarklisted{\pgfuseplotmark{*}}{1,2,4,...,9} +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlermarklisted}{#1#2}{% + start={ + \let\pgf@plot@mark@list=\pgfutil@empty% + \edef\pgf@marshal{\noexpand\foreach\noexpand\pgf@temp in{#2}} + \pgf@marshal{\xdef\pgf@plot@mark@list{\pgf@plot@mark@list(\pgf@temp)}}% + \def\pgf@plot@mark{% + \edef\pgf@marshal{\noexpand\pgfutil@in@{(\the\pgf@plot@mark@count)}{\pgf@plot@mark@list}}% + \pgf@marshal% + \ifpgfutil@in@#1\fi% + }% + \global\pgf@plot@mark@count=\pgf@plot@mark@repeat\relax% + \global\advance\pgf@plot@mark@count by-\pgf@plot@mark@phase\relax% + }, + point macro=\pgf@plot@mark@handler +}% + +% \def\pgfplothandlermarklisted#1#2{% +% \let\pgf@plot@mark@list=\pgfutil@empty% +% \edef\pgf@marshal{\noexpand\foreach\noexpand\pgf@temp in{#2}} +% \pgf@marshal{\xdef\pgf@plot@mark@list{\pgf@plot@mark@list(\pgf@temp)}}% +% \pgf@plothandlermark{% +% \edef\pgf@marshal{\noexpand\pgfutil@in@{(\the\pgf@plot@mark@count)}{\pgf@plot@mark@list}}% +% \pgf@marshal% +% \ifpgfutil@in@#1\fi}% +% }% + + +% Define a new plot mark for use with \pgfplotmark. +% +% #1 = a plot mark mnemonic +% #2 = code for drawing the mark +% +% Example: +% +% \pgfdeclareplotmark{*}{\pgfpathcircle{\pgfpointorigin}{2pt}\pgfusepathqfill} + +\def\pgfdeclareplotmark#1#2{\expandafter\def\csname pgf@plot@mark@#1\endcsname{#2}}% + + +% Set the size of plot marks. For circles, this will be the radius, +% for other shapes it should be about half the width/height. +% +% Example: +% +% \pgfsetplotmarksize{1pt} + +\def\pgfsetplotmarksize#1{\pgfmathsetlength\pgfplotmarksize{#1}}% + +\newdimen\pgfplotmarksize +\pgfplotmarksize=2pt + + +% Insert a plot mark's code at the origin. +% +% #1 = plot mark mnemonic +% +% Example: +% +% \pgfuseplotmark{*} + +\def\pgfuseplotmark#1{\csname pgf@plot@mark@#1\endcsname}% + + +% A stroke-filled circle mark + +\pgfdeclareplotmark{*} +{% + \pgfpathellipse{\pgfpointorigin}{\pgfqpoint{\pgfplotmarksize}{0sp}}{\pgfqpoint{0sp}{\pgfplotmarksize}}% + \pgfusepathqfillstroke +}% + + +% A plus-sign like mark + +\pgfdeclareplotmark{+} +{% + \pgfpathmoveto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + +% An x-shaped mark + +\pgfdeclareplotmark{x} +{% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfusepathqstroke +}% + +% See pgflibraryplotmarks for more plot marks + + + + +% This handler turns creates a series of straight line segments +% between consecutive points, but leaving /pgf/gap around stream point +% space. +% +% Example: +% +% \pgfplothandlergaplineto +% \pgfplotxyfile{mytable} + +\pgfkeys{/pgf/gap around stream point/.initial=1.5pt}% + +\pgfdeclareplothandler{\pgfplothandlergaplineto}{}{% + point macro=\pgf@plot@gap@lineto@handler@initial, + jump macro=\pgf@plot@gap@next@moveto +}% + +\def\pgf@plot@gap@next@moveto{% + \global\let\pgf@plotstreampoint=\pgf@plot@gap@lineto@handler@initial% +}% + +\def\pgf@plot@gap@lineto@handler@initial#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \xdef\pgf@plot@gap@lineto@last{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \global\let\pgf@plotstreampoint=\pgf@plot@gap@lineto@handler% +}% + +\def\pgf@plot@gap@lineto@handler#1{% + % Ok, compute normalized line vector + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \xdef\pgf@plot@gap@lineto@next{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\pgf@plot@gap@lineto@last}{\pgf@plot@gap@lineto@next}}}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfpathmoveto{\pgfpointadd{\pgfpointscale{\pgfkeysvalueof{/pgf/gap + around stream point}}{\pgfqpoint{\pgf@xc}{\pgf@yc}}}{\pgf@plot@gap@lineto@last}}% + \pgfpathlineto{\pgfpointadd{\pgfpointscale{\pgfkeysvalueof{/pgf/gap + around stream point}}{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}}{\pgf@plot@gap@lineto@next}}% + \global\let\pgf@plot@gap@lineto@last=\pgf@plot@gap@lineto@next% +}% + + + + +% This handler works like \pgfplothandlergaplineto, only the last +% point is connected to the first point, creating a closed curve +% space. +% +% Example: +% +% \pgfplothandlergapcycle +% \pgfplotxyfile{mytable} + +\pgfdeclareplothandler{\pgfplothandlergapcycle}{}{% + point macro=\pgf@plot@gap@cycle@handler@initial, + jump macro=\pgf@plot@gapcycle@next@moveto, + end macro=\pgf@plot@gap@cycle@handler@finish, + start={\global\let\pgf@plot@gap@cycle@first\relax} +}% + +\def\pgf@plot@gapcycle@next@moveto{% + \pgf@plot@gap@cycle@handler@finish% + \global\let\pgf@plot@gap@cycle@first=\relax% + \global\let\pgf@plotstreampoint=\pgf@plot@gap@cycle@handler@initial% +}% + +\def\pgf@plot@gap@cycle@handler@initial#1{% + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \xdef\pgf@plot@gap@cycle@last{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \global\let\pgf@plot@gap@cycle@first=\pgf@plot@gap@cycle@last% + \global\let\pgf@plotstreampoint=\pgf@plot@gap@cycle@handler% +}% + +\def\pgf@plot@gap@cycle@handler#1{% + % Ok, compute normalized line vector + \pgf@process{#1}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \xdef\pgf@plot@gap@cycle@next{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\pgf@plot@gap@cycle@last}{\pgf@plot@gap@cycle@next}}}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfpathmoveto{\pgfpointadd{\pgfpointscale{\pgfkeysvalueof{/pgf/gap + around stream point}}{\pgfqpoint{\pgf@xc}{\pgf@yc}}}{\pgf@plot@gap@cycle@last}}% + \pgfpathlineto{\pgfpointadd{\pgfpointscale{\pgfkeysvalueof{/pgf/gap + around stream point}}{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}}{\pgf@plot@gap@cycle@next}}% + \global\let\pgf@plot@gap@cycle@last=\pgf@plot@gap@cycle@next% +}% + +\def\pgf@plot@gap@cycle@handler@finish{% + \ifx\pgf@plot@gap@cycle@first\relax% + \else + \pgf@plot@gap@cycle@handler{\pgf@plot@gap@cycle@first}% + \fi +}% + + + +\endinput + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryplotmarks.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryplotmarks.code.tex new file mode 100644 index 0000000000..0beb873c07 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryplotmarks.code.tex @@ -0,0 +1,453 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryplotmarks.code.tex} + + +% A stroked circle mark + +\pgfdeclareplotmark{o} +{% + \pgfpathellipse{\pgfpointorigin}{\pgfqpoint{\pgfplotmarksize}{0sp}}{\pgfqpoint{0sp}{\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + +% A Mercedes-line star + +\pgfdeclareplotmark{Mercedes star} +{% + \pgfpathmoveto{\pgfqpointpolar{90}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfpathmoveto{\pgfqpointpolar{-30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfpathmoveto{\pgfqpointpolar{-150}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfusepathqstroke +}% + +\pgfdeclareplotmark{Mercedes star flipped} +{% + \pgfpathmoveto{\pgfqpointpolar{-90}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfpathmoveto{\pgfqpointpolar{30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfpathmoveto{\pgfqpointpolar{150}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfpointorigin}% + \pgfusepathqstroke +}% + + + + +% A six-pointed star mark + +\pgfdeclareplotmark{asterisk} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{210}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{-30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-210}{\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + +% A five-pointed star mark + +\pgfdeclareplotmark{star} +{% + \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfqpointpolar{18}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfqpointpolar{-54}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfqpointpolar{234}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfqpointpolar{162}{\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + +% An 10-pointed star mark + +\pgfdeclareplotmark{10-pointed star} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}\pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{18}{-\pgfplotmarksize}}\pgfpathlineto{\pgfqpointpolar{18}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{-54}{-\pgfplotmarksize}}\pgfpathlineto{\pgfqpointpolar{-54}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{234}{-\pgfplotmarksize}}\pgfpathlineto{\pgfqpointpolar{234}{\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpointpolar{162}{-\pgfplotmarksize}}\pgfpathlineto{\pgfqpointpolar{162}{\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + +% An \oplus mark + +\pgfdeclareplotmark{oplus} +{% + \pgfpathcircle{\pgfpointorigin}{\pgfplotmarksize}% + \pgfpathmoveto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfusepathqstroke +}% + +\pgfdeclareplotmark{oplus*} +{% + \pgfpathcircle{\pgfpointorigin}{\pgfplotmarksize}% + \pgfpathmoveto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfusepathqfillstroke +}% + + +% An \otimes mark + +\pgfdeclareplotmark{otimes} +{% + \pgfpathcircle{\pgfpointorigin}{\pgfplotmarksize}% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfusepathqstroke +}% + +\pgfdeclareplotmark{otimes*} +{% + \pgfpathcircle{\pgfpointorigin}{\pgfplotmarksize}% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathmoveto{\pgfqpoint{-.70710678\pgfplotmarksize}{.70710678\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.70710678\pgfplotmarksize}{-.70710678\pgfplotmarksize}}% + \pgfusepathqfillstroke +}% + + +% A vertical bar mark + +\pgfdeclareplotmark{|} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfusepathqstroke +}% + + + +% A horizontal bar mark + +\pgfdeclareplotmark{-} +{% + \pgfpathmoveto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfusepathqstroke +}% + + +% A square stroked mark + +\pgfdeclareplotmark{square} +{% + \pgfpathrectangle{\pgfqpoint{-\pgfplotmarksize}{-\pgfplotmarksize}}{\pgfqpoint{2\pgfplotmarksize}{2\pgfplotmarksize}}% + \pgfusepathqstroke +}% + +% A square stroked-filled mark + +\pgfdeclareplotmark{square*} +{% + \pgfpathrectangle{\pgfqpoint{-\pgfplotmarksize}{-\pgfplotmarksize}}{\pgfqpoint{2\pgfplotmarksize}{2\pgfplotmarksize}}% + \pgfusepathqfillstroke +}% + + +% A triangle mark + +\pgfdeclareplotmark{triangle} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-150}{\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + + +% A stroke-filled triangle mark + +\pgfdeclareplotmark{triangle*} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-30}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-150}{\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqfillstroke +}% + + + +% A diamond-shaped mark + +\pgfdeclareplotmark{diamond} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-.75\pgfplotmarksize}{0pt}}% + \pgfpathclose + \pgfusepathqstroke +}% + + +% A stroke-filled diamond-shaped mark + +\pgfdeclareplotmark{diamond*} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-.75\pgfplotmarksize}{0pt}}% + \pgfpathclose + \pgfusepathqfillstroke +}% + + + +% A pentagon-shaped mark + +\pgfdeclareplotmark{pentagon} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{18}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-54}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{234}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{162}{\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + +% A stroke-filled pentagon-shaped mark + +\pgfdeclareplotmark{pentagon*} +{% + \pgfpathmoveto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{18}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{-54}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{234}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpointpolar{162}{\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqfillstroke +}% + +\newif\ifpgfmarktext@usetikznode +\pgfkeys{ + /pgf/text mark/.initial=p, + /pgf/text mark style/.initial=, + /pgf/text mark as node/.is if=pgfmarktext@usetikznode, + /pgf/text mark as node/.default=true, + % + % backw. compat: the extra search path confuses the '.unknown' + % handlers, so this here is deprecated: + /pgf/text mark/style/.style={/pgf/text mark style={#1}},% + /pgf/text mark/as node/.style={/pgf/text mark as node={#1}},% +}% + +\pgfdeclareplotmark{text} +{ + \pgfkeysgetvalue{/pgf/text mark style}\pgfmarktext@style + \pgfkeysgetvalue{/pgf/text mark}\pgfmarktext@ + \ifpgfmarktext@usetikznode + \expandafter\node\expandafter[\pgfmarktext@style]{\pgfmarktext@}; + \else + \expandafter\pgftext\expandafter[\pgfmarktext@style]{\pgfmarktext@}% + \fi +}% + +\pgfkeysdef{/pgf/mark color}{\def\pgf@mark@color{#1}}% +\let\pgf@mark@color\pgfutil@empty + +\def\pgf@set@mark@color{% + \ifx\pgf@mark@color\pgfutil@empty + \pgfsys@color@rgb@fill{1}{1}{1}% + \else + \pgfsetfillcolor{\pgf@mark@color}% + \fi +}% +\def\pgf@mark@color@none{none}% + +% A half-down-filled and half-up-filled-white diamond-shaped mark +% (the shape can be rotated by "mark options = {rotate = 90}") +% created by Tomek + +\pgfdeclareplotmark{halfcircle}{% + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto + {\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpatharc{180}{360}{\pgfplotmarksize}% + \pgfusepathqfill + \endpgfscope% + \fi + \pgfpathmoveto + {\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto + {\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathcircle{\pgfpointorigin}% + {\pgfplotmarksize}% + \pgfusepathqstroke +}% +\pgfdeclareplotmark{halfcircle*}{% + \pgfpathmoveto + {\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpatharc{0}{180}{\pgfplotmarksize}% + \pgfpathclose + \pgfusepathqfill + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto + {\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpatharc{180}{360}{\pgfplotmarksize}% + \pgfusepathqfill + \endpgfscope% + \fi + \pgfpathcircle{\pgfpointorigin}% + {\pgfplotmarksize}% + \pgfusepathqstroke +}% + +% A half-down-filled and half-up-filled-white diamond-shaped mark +% created by Magnus Tewes + +\pgfdeclareplotmark{halfdiamond*}{% + \pgfpathmoveto{\pgfqpoint{-.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{.75\pgfplotmarksize}{0pt}}% + \pgfusepathqfill + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto{\pgfqpoint{.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-.75\pgfplotmarksize}{0pt}}% + \pgfusepathqfill + \endpgfscope + \fi + \pgfpathmoveto{\pgfqpoint{.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-.75\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + +% A half-down-filled and half-up-filled-white tilted-squared-shaped mark +% created by Magnus Tewes + +\pgfdeclareplotmark{halfsquare*}{% + \pgfpathmoveto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfusepathqfill + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfusepathqfill + \endpgfscope + \fi + \pgfpathmoveto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + +% A half-right-filled and half-up-filled-white tilted-squared-shaped mark +% created by Magnus Tewes + +\pgfdeclareplotmark{halfsquare right*}{% + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfusepathqfill + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfusepathqfill + \endpgfscope + \fi + \pgfpathmoveto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + +% A half-left-filled and half-up-filled-white tilted-squared-shaped mark +% created by Magnus Tewes + +\pgfdeclareplotmark{halfsquare left*}{% + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfusepathqfill + \ifx\pgf@mark@color@none\pgf@mark@color + \else + \pgfscope + \pgf@set@mark@color + \pgfpathmoveto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfusepathqfill + \endpgfscope + \fi + \pgfpathmoveto{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgfplotmarksize}}% + \pgfpathlineto{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqstroke +}% + + +% A stroke-filled heart-shaped mark +% created by Magnus Tewes +\pgfdeclareplotmark{heart}{% + \pgfpathmoveto{\pgfqpoint{0pt}{-1.75\pgfplotmarksize}}% + \pgfpathcurveto{\pgfqpoint{0pt}{-1.75\pgfplotmarksize}}{\pgfqpoint{0pt}{-1.66\pgfplotmarksize}}{\pgfqpoint{-.5\pgfplotmarksize}{-1.165\pgfplotmarksize}}% + \pgfpathcurveto{\pgfqpoint{-.5\pgfplotmarksize}{-1.165\pgfplotmarksize}}{\pgfqpoint{-\pgfplotmarksize}{-.75\pgfplotmarksize}}{\pgfqpoint{-\pgfplotmarksize}{0pt}}% + \pgfpathcurveto{\pgfqpoint{-\pgfplotmarksize}{0pt}}{\pgfqpoint{-\pgfplotmarksize}{.5825\pgfplotmarksize}}{\pgfqpoint{-.5825\pgfplotmarksize}{.5825\pgfplotmarksize}}% + \pgfpathcurveto{\pgfqpoint{-.5825\pgfplotmarksize}{.5825\pgfplotmarksize}}{\pgfqpoint{0pt}{.5825\pgfplotmarksize}}{\pgfqpoint{0pt}{0pt}}% + \pgfpathcurveto{\pgfqpoint{0pt}{0pt}}{\pgfqpoint{0pt}{.5825\pgfplotmarksize}}{\pgfqpoint{.5825\pgfplotmarksize}{.5825\pgfplotmarksize}}% + \pgfpathcurveto{\pgfqpoint{.5825\pgfplotmarksize}{.5825\pgfplotmarksize}}{\pgfqpoint{\pgfplotmarksize}{.5825\pgfplotmarksize}}{\pgfqpoint{\pgfplotmarksize}{0pt}}% + \pgfpathcurveto{\pgfqpoint{\pgfplotmarksize}{0pt}}{\pgfqpoint{\pgfplotmarksize}{-.75\pgfplotmarksize}}{\pgfqpoint{.5\pgfplotmarksize}{-1.165\pgfplotmarksize}}% + \pgfpathcurveto{\pgfqpoint{.5\pgfplotmarksize}{-1.165\pgfplotmarksize}}{\pgfqpoint{0pt}{-1.66\pgfplotmarksize}}{\pgfqpoint{0pt}{-1.75\pgfplotmarksize}}% + \pgfpathclose + \pgfusepathqfillstroke +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryprofiler.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryprofiler.code.tex new file mode 100644 index 0000000000..d6327db062 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryprofiler.code.tex @@ -0,0 +1,530 @@ +%-------------------------------------------- +% +% TeX profiling library +% +% Copyright 2018 by Christian Feuersänger. +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . +% +%-------------------------------------------- + +\pgfutil@ifundefined{pdfelapsedtime}{% + % Ok, \pdfelapsedtime is not defined. + % Maybe we run luatex? + \pgfutil@ifluatex + % Yes. So we emulate the primitive by a macro. + % (see http://tex.stackexchange.com/q/32507/8425) + \def\pgfutil@pdfelapsedtime{% + \numexpr\pgfutil@directlua{% + tex.print(math.floor((os.clock())*65536+0.5))}\relax} + \else + % Raise an error + \pgferror{% + Library 'profiler' can only be used with pdftex Rev. >= 1.671 + because it needs the \string\pdfelapsedtime\space command or + with luatex}% + \global\let\pgfutil@pdfelapsedtime=\c@pgf@counta + \fi}{% + % We run pdftex. That's ok. + \let\pgfutil@pdfelapsedtime\pdfelapsedtime}% + + +% Defines a new profiler entry named `#1'. +% +% This allocates a set of counters. +\def\pgfprofilenew#1{% + \pgfutil@ifundefined{c@pgfprofile@elapsedtotal@#1}{% + \expandafter\gdef\csname c@pgfprofile@elapsedtotal@#1\endcsname{0}% + \expandafter\gdef\csname c@pgfprofile@elapsedself@#1\endcsname{0}% + \expandafter\gdef\csname c@pgfprofile@numinvocations@#1\endcsname{0}% + \expandafter\gdef\csname c@pgfprofile@subtractforself@#1\endcsname{0}% + \expandafter\gdef\csname c@pgfprofile@semaphor@#1\endcsname{0}% + \expandafter\gdef\csname c@pgfprofile@elapsed@at@start@#1\endcsname{0}% + \pgfprofile@all@registered@list@add{#1}% + }{% + % it is already defined and registered. Shouldn't hurt, might + % even be a good feature. + }% +}% + +\def\pgfprofile@TeX@DIALECT@toenvironment@begin#1{\csname #1\endcsname}% +\def\pgfprofile@TeX@DIALECT@toenvironment@end#1{\csname end#1\endcsname}% + +\def\pgfprofile@@to@pgfretval#1{% + \expandafter\let\expandafter\pgfretval#1% +}% + +% Defines a new profiler entry for the environment `#1'. +% +% This calls \pgfprofilenew and handles the begin/end of the +% environment automatically. +% +% #1 the environment name (a string) +% +% Optionally in square brackets: the profiler entry name +% \pgfprofilenewforenvironment{} +% \pgfprofilenewforenvironment[]{} +\def\pgfprofilenewforenvironment{\pgfutil@ifnextchar[{\pgfprofilenewforenvironment@}{\pgfprofilenewforenvironment@[]}}% +\def\pgfprofilenewforenvironment@[#1]#2{% + \expandafter\pgfprofile@@to@pgfretval\pgfprofile@TeX@DIALECT@toenvironment@begin{#2}% + \ifx\pgfretval\relax + \pgferror{\string\pgfprofilenewforenvironment{#2} doesn't work: the environment `#2' is (not yet?) known or not known in this context}{}% + \else + \expandafter\global\expandafter\let\csname pgfprofile@orig@begin@#2\endcsname=\pgfretval + \expandafter\pgfprofile@@to@pgfretval\pgfprofile@TeX@DIALECT@toenvironment@end{#2}% + \expandafter\global\expandafter\let\csname pgfprofile@orig@end@#2\endcsname=\pgfretval + % + \def\pgfprofile@temp{#1}% + \ifx\pgfprofile@temp\pgfutil@empty + \pgfprofilenewforenvironment@@{\pgfprofileenv #2}{#2}% + \else + \pgfprofilenewforenvironment@@{#1}{#2}% + \fi + \fi +}% +\def\pgfprofilenewforenvironment@@#1#2{% + \pgfprofilenew{#1}% + \expandafter\expandafter\expandafter\gdef\pgfprofile@TeX@DIALECT@toenvironment@begin{#2}{% + \pgfprofilestart{#1}% + \csname pgfprofile@orig@begin@#2\endcsname + }% + \expandafter\expandafter\expandafter\gdef\pgfprofile@TeX@DIALECT@toenvironment@end{#2}{% + \csname pgfprofile@orig@end@#2\endcsname + \pgfprofileend{#1}% + }% +}% + + +\def\pgfprofilecs{}% +\def\pgfprofileenv{}% + +% Defines a new profiler entry for the control sequence '#1'. +% +% This calls \pgfprofilenew and enhances the control sequence with +% support for timings. +% +% #1: the control sequence (with backslash!) +% #2: the number of arguments (see below). +% +% The following commands are supported: +% - commands which take one (optional) argument in square brackets, +% - commands which take one (optional) argument in square brackets +% followed by one optional argument which has to be delimited with +% curly braces (use an empty argument for '#2' in this case), +% - commands which take one (optional) argument in square brackets +% and *exactly* #2 arguments afterwards. +\def\pgfprofilenewforcommand{\pgfutil@ifnextchar[{\pgfprofilenewforcommand@}{\pgfprofilenewforcommand@[]}}% +\def\pgfprofilenewforcommand@[#1]#2#3{% + \def\pgfprofile@temp{#3}% + \ifx\pgfprofile@temp\pgfutil@empty + \pgfprofilenewforcommandpattern[#1]{#2}{}{}% + \else + \ifcase#3\relax + \pgfprofilenewforcommandpattern[#1]{#2}{}{}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1}{{##1}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2}{{##1}{##2}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2##3}{{##1}{##2}{##3}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2##3##4}{{##1}{##2}{##3}{##4}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2##3##4##5}{{##1}{##2}{##3}{##4}{##5}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2##3##4##5##6}{{##1}{##2}{##3}{##4}{##5}{##6}}% + \or + \pgfprofilenewforcommandpattern[#1]{#2}{##1##2##3##4##5##6##7}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}}% + \else + \pgferror{library 'profiler' can't replace control sequences with '#3' arguments automatically, sorry.}{}% + \fi + \fi +}% + +% \pgfprofilenewforcommandpattern[]{<\CS>}{}{} +% +% example: +% \pgfprofilenewforcommandpattern{\pgfqkeys}{##1##2}{{##1}{##2}} +% +% \def\mymacro##1\to##2\in##3{ .... } +% \pgfprofilenewforcommandpattern{\mymacro}{##1\to##2\in##3}{{##1}\to{##2}\in{##3}} +\def\pgfprofilenewforcommandpattern{\pgfutil@ifnextchar[{\pgfprofilenewforcommandpattern@}{\pgfprofilenewforcommandpattern@[]}}% +\def\pgfprofilenewforcommandpattern@[#1]#2#3#4{% + \def\pgfprofile@known{1}% + \ifx#2\undefined + \def\pgfprofile@known{0}% + \else + \ifx#2\relax + \def\pgfprofile@known{0}% + \fi + \fi + \if\pgfprofile@known0% + \pgferror{\string\pgfprofilenewforcommandpattern{\string#2} doesn't work: the command `\string#2' is (not yet?) known or not known in this context}% + \else + \begingroup + \pgfprofile@cs@to@name{#2}% + \let\pgfprofilenew@cmdname=\pgfretval + % + \def\pgfprofile@temp{#1}% + \ifx\pgfprofile@temp\pgfutil@empty + \edef\pgfprofilenew@profilerentryname{\pgfprofilecs\pgfprofilenew@cmdname}% + \else + \edef\pgfprofilenew@profilerentryname{#1}% + \fi + \expandafter\global\expandafter\let\csname pgfprofile@name@for@\pgfprofilenew@cmdname\endcsname=\pgfprofilenew@profilerentryname + \pgfprofilenew{\pgfprofilenew@profilerentryname}% + \expandafter\gdef\csname b@pgfprofile@show@\pgfprofilenew@profilerentryname\endcsname{0}% + % + \expandafter\global\expandafter\let\csname pgfprofile@orig@\pgfprofilenew@cmdname\endcsname=#2% + \toks0={#3}% + \edef\pgfprofile@temp{\the\toks0}%% + \def\pgfprofile@tempb{}% + \ifx\pgfprofile@temp\pgfprofile@tempb + \expandafter\global\expandafter\let\csname pgfprofile@repl@\pgfprofilenew@cmdname\endcsname=\pgfprofileinvokecommand@uptoonearg + \else + \expandafter\gdef\csname pgfprofile@repl@\pgfprofilenew@cmdname\endcsname#3{% + \pgfprofile@invokeorig{#4}% + }% + \fi + \xdef#2{\noexpand\pgfprofileinvokecommand{\pgfprofilenew@cmdname}}% + \endgroup + \fi +}% + +\def\pgfprofileshowinvocationsfor#1{% + \pgfutil@ifundefined{b@pgfprofile@show@#1}{% + \pgferror{\string\pgfprofileshowinvocationsfor{#1} doesn't work: the argument is no profiler entry}% + }{% + \expandafter\gdef\csname b@pgfprofile@show@#1\endcsname{1}% + \expandafter\gdef\csname b@pgfprofile@show@edef@#1\endcsname{0}% + }% +}% +\def\pgfprofileshowinvocationsexpandedfor#1{% + \pgfutil@ifundefined{b@pgfprofile@show@#1}{% + \pgferror{\string\pgfprofileshowinvocationsfor{#1} doesn't work: the argument is no profiler entry}% + }{% + \expandafter\gdef\csname b@pgfprofile@show@#1\endcsname{1}% + \expandafter\gdef\csname b@pgfprofile@show@edef@#1\endcsname{1}% + }% +}% + +\def\pgfprofile@no@optional@arg@text{}% +\def\pgfprofileinvokecommand#1{% + \pgfutil@ifnextchar[{\pgfprofileinvokecommand@{#1}}{\pgfprofileinvokecommand@{#1}[]}% +}% +\def\pgfprofileinvokecommand@#1[#2]{% + \def\pgfprofileinvokecommand@cs{#1}% + \def\pgfprofileinvokecommand@optarg{#2}% + \edef\pgfprofileinvokecommand@profilerentryname{\csname pgfprofile@name@for@#1\endcsname}% + \csname pgfprofile@repl@#1\endcsname% +}% + +% #1 contains ALL arguments, including any braces. +\def\pgfprofile@invokeorig#1{% + % re-insert the control sequence name and the optional argument: + % this wasn't possible directly. + \begingroup + \toks1=\expandafter{\pgfprofileinvokecommand@optarg}% + \toks2={#1}% + \toks3=\expandafter{\csname pgfprofile@orig@\pgfprofileinvokecommand@cs\endcsname}% + % + \ifx\pgfprofileinvokecommand@optarg\pgfprofile@no@optional@arg@text + % no [] argument after original command: + \xdef\pgfprofile@invokeorig@doitfinally{\the\toks3 \the\toks2 }%% + \else + \xdef\pgfprofile@invokeorig@doitfinally{\the\toks3[\the\toks1]\the\toks2 }% + \fi + \if1\csname b@pgfprofile@show@\pgfprofileinvokecommand@profilerentryname\endcsname + \pgfprofile@orig@show + \fi + \endgroup + \edef\pgfprofile@temp{{\pgfprofileinvokecommand@cs}{\pgfprofileinvokecommand@profilerentryname}}% + \expandafter\pgfprofile@invokeorig@\pgfprofile@temp% +}% +\def\pgfprofile@orig@show{% + \toks4=\expandafter{\csname\pgfprofileinvokecommand@cs\endcsname}% + \ifx\pgfprofileinvokecommand@optarg\pgfprofile@no@optional@arg@text + \def\pgfprofile@orig@show@args{\the\toks2 }% + \else + \def\pgfprofile@orig@show@args{[\the\toks1] \the\toks2 }% + \fi + \if1\csname b@pgfprofile@show@edef@\pgfprofileinvokecommand@profilerentryname\endcsname + \edef\pgfprofile@orig@show@args{\pgfprofile@orig@show@args}% + \edef\pgfprofile@orig@show@args{\pgfprofile@orig@show@args}% + \fi + \pgf@typeout{pgflibraryprofiler: calling + \#\csname c@pgfprofile@numinvocations@\pgfprofileinvokecommand@profilerentryname\endcsname\space + (\the\toks4 \pgfprofile@orig@show@args)}% +}% + +% #1: control sequence name (without backslash) +% #2: profiler entry name +\def\pgfprofile@invokeorig@#1#2{% + % this check should avoid save stack impact + \pgfprofileifisrunning{#2}{% + \pgfprofile@invokeorig@doitfinally% + }{% + \pgfprofilestart{#2}% + \pgfprofile@invokeorig@doitfinally% + \pgfprofileend{#2}% + }% +}% + + +\def\pgfprofileinvokecommand@uptoonearg{% + \pgfutil@ifnextchar\bgroup{\pgfprofileinvokecommand@onearg}{\pgfprofileinvokecommand@noarg}% +}% +\def\pgfprofileinvokecommand@onearg#1{% + \pgfprofile@invokeorig{{#1}}% +}% +\def\pgfprofileinvokecommand@noarg{% + \pgfprofile@invokeorig{}% +}% + + + +% Starts / Resumes timing of the profiler entry named `#1'. +% +% The timing will continue until \pgfprofileend{#1} is called. +% +% Nested calls of \pgfprofilestart{#1} (with the same argument) will +% result in the same result as if just one \pgfprofilestart command +% has been issued. +\def\pgfprofilestart#1{% + \pgfprofileifisrunning{#1}{% + \relax + }{% + \expandafter\xdef\csname c@pgfprofile@elapsed@at@start@#1\endcsname{\the\pgfutil@pdfelapsedtime}% + \expandafter\gdef\csname c@pgfprofile@subtractforself@#1\endcsname{0}% + \pgfprofile@advance{c@pgfprofile@numinvocations@#1}{1}% + \pgfprofilestackpush{#1}% + }% + \pgfprofile@advance{c@pgfprofile@semaphor@#1}{1}% +}% + +% Stops / Interrupts timing of the profiler entry named `#1'. +\def\pgfprofileend#1{% + \pgfprofile@advance{c@pgfprofile@semaphor@#1}{-1}% + \pgfprofileifisrunning{#1}{% + \relax + }{% + \begingroup + \c@pgf@countb=\pgfutil@pdfelapsedtime\relax + \advance\c@pgf@countb by-\csname c@pgfprofile@elapsed@at@start@#1\endcsname\relax + % + \pgfprofilestackpop\pgfretval + \edef\pgfprofile@temp{#1}% + \ifx\pgfprofile@temp\pgfretval + \else + \pgf@typeout{pgflibraryprofiler WARNING: possible error in self time computation...}% + \fi + \pgfprofilestackifempty{% + \relax + }{% + \pgfprofilestacktop\pgfretval + \pgfprofile@advance{c@pgfprofile@subtractforself@\pgfretval}{\c@pgf@countb}% + }% + % + \pgfprofile@advance{c@pgfprofile@elapsedtotal@#1}{\c@pgf@countb}% + \advance\c@pgf@countb by-\csname c@pgfprofile@subtractforself@#1\endcsname\relax + \pgfprofile@advance{c@pgfprofile@elapsedself@#1}{\c@pgf@countb}% + \endgroup + }% +}% + +% invokes '#2' if '#1' is currently running and '#3' if not. +\def\pgfprofileifisrunning#1#2#3{% + \ifnum\csname c@pgfprofile@semaphor@#1\endcsname=0 \def\pgfprofileifisrunning@next{#3}\else \def\pgfprofileifisrunning@next{#2}\fi + \pgfprofileifisrunning@next +}% + +% Sets the profiler entry whose total time is used to compute all +% other relative times. +\def\pgfprofilesetrel#1{\edef\pgfprofile@rel{#1}}% + +% Stops all running timings and postprocesses them. +\def\pgfprofilepostprocess{% + \begingroup + % + % prepare files. + \c@pgf@countb=\time + \divide\c@pgf@countb by60 + \c@pgf@countd=\c@pgf@countb + \multiply\c@pgf@countd by60 + \c@pgf@countc=\time + \advance\c@pgf@countc by-\c@pgf@countd + \immediate\openout\w@pgf@writea=\jobname.profiler.\the\year-\pgfprofiletotwodigitstr\month-\pgfprofiletotwodigitstr\day_\pgfprofiletotwodigitstr\c@pgf@countb h_\pgfprofiletotwodigitstr\c@pgf@countc m.dat + \immediate\write\w@pgf@writea{% + \pgfprofile@percent relative values are measured against the totaltime of `\pgfprofile@rel'.% + }% + \pgf@typeout{pgflibraryprofiler: relative values are measured against the totaltime of `\pgfprofile@rel'.}% + \immediate\write\w@pgf@writea{% + profilerentry\pgfprofile@TAB + totaltime[s]\pgfprofile@TAB + totaltime[percent]\pgfprofile@TAB + selftime[s]\pgfprofile@TAB + selftime[percent]\pgfprofile@TAB + numinvocations\pgfprofile@TAB}% + % + % + % compute main time and prepare computation of relative times: + \pgfprofileifisrunning{\pgfprofile@rel}{% + \pgfprofileend{\pgfprofile@rel}% + }{}% + \pgf@xa=\csname c@pgfprofile@elapsedtotal@\pgfprofile@rel\endcsname sp + \edef\pgfprofiletotaltime{\pgf@sys@tonumber\pgf@xa}% + \pgfmathreciprocal@{\pgfprofiletotaltime}% + \let\pgfprofiletotaltime@inv=\pgfmathresult + % + % postprocess each of them: + \pgfprofile@all@registered@list@foreach{% + \pgfprofileifisrunning{##1}{% + \pgfprofileend{##1}% + }{}% + \pgfprofilepostprocess@single{##1}% + }% + \immediate\write\w@pgf@writea{% + \pgfprofile@percent\space vim: ts=40 nowrap nostartofline + }% + \immediate\closeout\w@pgf@writea + \endgroup +}% + +{% +\catcode`\[=1 % +\catcode`\]=2 % +\catcode`\{=12 % +\catcode`\}=12 % +\catcode`\^^I=12 +\gdef\pgfprofile@lbrace[{]% +\gdef\pgfprofile@rbrace[}]% +\gdef\pgfprofile@TAB[^^I]% +] +{ +\catcode`\%=12 \gdef\pgfprofile@percent{%}} + +\def\pgfprofilepostprocess@single#1{% + \begingroup + \pgf@xa=\csname c@pgfprofile@elapsedtotal@#1\endcsname sp + \pgf@xb=\csname c@pgfprofile@elapsedself@#1\endcsname sp + \pgf@ya=\pgfprofiletotaltime@inv\pgf@xa + \pgf@yb=\pgfprofiletotaltime@inv\pgf@xb + \multiply\pgf@ya by100 + \multiply\pgf@yb by100 + \edef\pgfprofilecur@total{\pgf@sys@tonumber\pgf@xa}% + \edef\pgfprofilecur@self{\pgf@sys@tonumber\pgf@xb}% + \edef\pgfprofilecur@total@rel{\pgf@sys@tonumber\pgf@ya}% + \edef\pgfprofilecur@self@rel{\pgf@sys@tonumber\pgf@yb}% + \pgf@typeout{ + pgflibraryprofiler(#1) + \pgfprofile@lbrace + total time=\pgfprofilecur@total sec; (\pgfprofilecur@total@rel\pgfprofile@percent) + self time=\pgfprofilecur@self sec; (\pgfprofilecur@self@rel\pgfprofile@percent) + invocations=\csname c@pgfprofile@numinvocations@#1\endcsname; + \pgfprofile@rbrace + }% + \immediate\write\w@pgf@writea{% + #1\pgfprofile@TAB + \pgfprofilecur@total\pgfprofile@TAB + \pgfprofilecur@total@rel\pgfprofile@TAB + \pgfprofilecur@self\pgfprofile@TAB + \pgfprofilecur@self@rel\pgfprofile@TAB + \csname c@pgfprofile@numinvocations@#1\endcsname\pgfprofile@TAB + }% + \endgroup +}% +% Invokes '#2' for each element of the command separated list '#1'. +% the current list element is available as '#1' inside of '#2'. +\long\def\pgfprofileforeachentryinCSV#1#2{% + \long\def\pgfprofileinvokeforeach@@##1{#2}% + \pgfprofileforeachentryinCSVisterminated@loop#1,\pgfeov +}% +\long\def\pgfprofileforeachentryinCSVisterminated@loop{% + \pgfutil@ifnextchar\pgfeov{\pgfutil@gobble}{\pgfprofileforeachentryinCSV@next}% +}% +\long\def\pgfprofileforeachentryinCSV@next#1,{% + \pgfprofileinvokeforeach@@{#1}% + \pgfprofileforeachentryinCSVisterminated@loop% +}% + +\xdef\pgfprofile@all@registered@list{}% +\xdef\pgfprofile@currently@running@list{}% + +\def\pgfprofile@all@registered@list@add#1{% + \ifx\pgfprofile@all@registered@list\pgfutil@empty + \xdef\pgfprofile@all@registered@list{#1}% + \else + \xdef\pgfprofile@all@registered@list{\pgfprofile@all@registered@list,#1}% + \fi +}% + +\def\pgfprofile@all@registered@list@foreach#1{% + \expandafter\pgfprofileforeachentryinCSV\expandafter{\pgfprofile@all@registered@list}{#1}% +}% + +\def\pgfprofile@advance#1#2{% + \begingroup + \c@pgf@counta=\csname #1\endcsname\relax + \advance\c@pgf@counta by#2\relax + \expandafter\xdef\csname #1\endcsname{\the\c@pgf@counta}% + \endgroup +}% + +\def\pgfprofile@cs@to@name@#1#2\relax{\def\pgfretval{#2}} + +% defines '\pgfretval' to be the control sequences name of '#1' *without* the backslash. +\def\pgfprofile@cs@to@name#1{% + \expandafter\pgfprofile@cs@to@name@\string#1\relax +}% + +\newcount\c@pgfprofile@stacktop + +\c@pgfprofile@stacktop=-1 +\def\pgfprofilestackpush#1{% + \global\advance\c@pgfprofile@stacktop by1 + \expandafter\xdef\csname pgfprofile@stack@\the\c@pgfprofile@stacktop\endcsname{#1}% +}% +% pops the current stack top to macro #1 +\def\pgfprofilestackpop#1{% + \pgfprofilestacktop#1% + \global\advance\c@pgfprofile@stacktop by-1 +}% +% returns the stack's top to macro #1 +\def\pgfprofilestacktop#1{% + \expandafter\let\expandafter#1\csname pgfprofile@stack@\the\c@pgfprofile@stacktop\endcsname +}% +\def\pgfprofilestackifempty#1#2{% + \ifnum\c@pgfprofile@stacktop<0 #1\else #2\fi +}% + + +\def\pgfprofiletotwodigitstr#1{\ifnum#1<10 0\the#1\else\the#1\fi}% + +\pgfprofilenew{main job}% +\pgfprofilestart{main job}% +\expandafter\xdef\csname c@pgfprofile@elapsed@at@start@main job\endcsname{0}% +\pgfprofilesetrel{main job}% + +\pgfutil@ifundefined{AtEndDocument}{% + % no latex. ok. +}{% + % do latex specific stuff: + \pgfprofilenew{preamble} + \pgfprofilestart{preamble} + \expandafter\xdef\csname c@pgfprofile@elapsed@at@start@preamble\endcsname{0}% + \AtBeginDocument{\pgfprofileend{preamble}}% + % + \AtEndDocument{\pgfprofilepostprocess}% +}% +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibraryshadings.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibraryshadings.code.tex new file mode 100644 index 0000000000..81e0386a60 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibraryshadings.code.tex @@ -0,0 +1,444 @@ +% Copyright 2019 by Till Tantau and others +% CMYK and grayscale shadings adaptation copyright 2019 by David Purton +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshadings.code.tex} + + +% +% An hsv color wheel. Initial code graciously donated by Ken Starks. +% + +\pgfdeclarefunctionalshading[black]{color wheel white center} +{\pgfpoint{-50bp}{-50bp}} +{\pgfpoint{50bp}{50bp}} +{} +{ % x y + 2 copy % ... x y x y + 2 copy abs exch abs add 0.0001 ge + {atan 360.0 div} % ... x y heading; heading being in + %the interval [0, 1.0] + { pop } % silently deal with error: return + % arbitrary heading of zero for origin + ifelse % because we will use it for 'Hue' + 3 1 roll % ... heading x y + dup mul % ... heading x y*y + exch dup mul % ... heading y*y x*x + add sqrt % ... heading ra_pt (distance from origin in points) + 25.0 div % scale it means a ra of 25bp + dup 1.0 ge % BOOLEAN. ready to clamp to interval [0, 1.0] + { pop 1.0 }{} ifelse % We shall use the scaled ra as 'Saturation' + %2.5 mul 0.25 sub % now, Ra in [0.1, 0.5] --> Saturation + % in [0.0, 1.0]. Saturation varies between the two radii + 1.0 % ... H S V ( with 'Value' set to literal constant of 1.0 ) + % C version to use as model: + % H' = H * 6 + % i = floor(H') + % f = H' - i + % P = V * (1.0 - S) + % Q = V * (1.0 - (S*f)) + % T = V * (1.0 - (S * (1.0 - f))) + 3 2 roll 6.0 mul dup 4 1 roll % H' S V H' + floor cvr % H' S V i + dup 5 1 roll % i H' S V i + 3 index sub neg % i H' S V f + 1.0 3 index sub % i H' S V f (1.0 - S ) + 2 index mul % i H' S V f P + 6 1 roll % P i H' S V f + dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S)) + 2 index mul % P i H' S V f Q + 7 1 roll % Q P i H' S V f + neg 1.0 add % Q P i H' S V (1.0 - f) + 2 index mul neg 1.0 add % Q P i H' S V (1.0 - S * (1.0 - f)) + 1 index mul % Q P i H' S V T + 7 2 roll % V T Q P i H' S + pop pop % V T Q P i + %%% + % end of BLOCK B. The rest is just stack manipulation + dup 0.5 le % TEST II [ i == 0 ] + { % BLOCK C [ take stack to V T P ] + pop exch pop + } + { dup 1.5 le % TEST III [ i == 1 ] + { % BLOCK D [ take stack to Q V P ] + pop exch 4 1 roll exch pop + } + { dup 2.5 le % TEST IV [ i == 2 ] + { % BLOCK E [ take stack to P V T ] + pop 4 1 roll pop + } + { dup 3.5 le % TEST V [ i == 3 ] + { % BLOCK F [ take stack to P Q V ] + pop exch 4 2 roll pop + } + { dup 4.5 le % TEST VI [ i == 4 ] + { % BLOCK G [ take stack to T P V ] + pop exch pop 3 -1 roll + } + { % BLOCK H [ take stack to V P Q ] + pop 3 1 roll exch pop + } + ifelse + } + ifelse % for V + } + ifelse % for IV + } + ifelse % for III + } + ifelse % for II + \ifpgfshadingmodelcmyk + \pgffuncshadingrgbtocmyk + \fi + \ifpgfshadingmodelgray + \pgffuncshadingrgbtogray + \fi +}% + +\pgfdeclarefunctionalshading[black]{color wheel black center} +{\pgfpoint{-50bp}{-50bp}} +{\pgfpoint{50bp}{50bp}} +{} +{ % x y + 2 copy % ... x y x y + 2 copy abs exch abs add 0.0001 ge + {atan 360.0 div} % ... x y heading; heading being in + %the interval [0, 1.0] + { pop } % silently deal with error: return + % arbitrary heading of zero for origin + ifelse % because we will use it for 'Hue' + 3 1 roll % ... heading x y + dup mul % ... heading x y*y + exch dup mul % ... heading y*y x*x + add sqrt % ... heading ra_pt (distance from origin in points) + 25.0 div % scale it means a ra of 25bp + dup 1.0 ge % BOOLEAN. ready to clamp to interval [0, 1.0] + { pop 1.0 }{} ifelse % We shall use the scaled ra as 'Saturation' + %2.5 mul 0.25 sub % now, Ra in [0.1, 0.5] --> Saturation + % in [0.0, 1.0]. Saturation varies between the two radii + 1.0 exch % ... H S V ( with 'Value' set to literal constant of 1.0 ) + % C version to use as model: + % H' = H * 6 + % i = floor(H') + % f = H' - i + % P = V * (1.0 - S) + % Q = V * (1.0 - (S*f)) + % T = V * (1.0 - (S * (1.0 - f))) + 3 2 roll 6.0 mul dup 4 1 roll % H' S V H' + floor cvr % H' S V i + dup 5 1 roll % i H' S V i + 3 index sub neg % i H' S V f + 1.0 3 index sub % i H' S V f (1.0 - S ) + 2 index mul % i H' S V f P + 6 1 roll % P i H' S V f + dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S)) + 2 index mul % P i H' S V f Q + 7 1 roll % Q P i H' S V f + neg 1.0 add % Q P i H' S V (1.0 - f) + 2 index mul neg 1.0 add % Q P i H' S V (1.0 - S * (1.0 - f)) + 1 index mul % Q P i H' S V T + 7 2 roll % V T Q P i H' S + pop pop % V T Q P i + %%% + % end of BLOCK B. The rest is just stack manipulation + dup 0.5 le % TEST II [ i == 0 ] + { % BLOCK C [ take stack to V T P ] + pop exch pop + } + { dup 1.5 le % TEST III [ i == 1 ] + { % BLOCK D [ take stack to Q V P ] + pop exch 4 1 roll exch pop + } + { dup 2.5 le % TEST IV [ i == 2 ] + { % BLOCK E [ take stack to P V T ] + pop 4 1 roll pop + } + { dup 3.5 le % TEST V [ i == 3 ] + { % BLOCK F [ take stack to P Q V ] + pop exch 4 2 roll pop + } + { dup 4.5 le % TEST VI [ i == 4 ] + { % BLOCK G [ take stack to T P V ] + pop exch pop 3 -1 roll + } + { % BLOCK H [ take stack to V P Q ] + pop 3 1 roll exch pop + } + ifelse + } + ifelse % for V + } + ifelse % for IV + } + ifelse % for III + } + ifelse % for II + \ifpgfshadingmodelcmyk + \pgffuncshadingrgbtocmyk + \fi + \ifpgfshadingmodelgray + \pgffuncshadingrgbtogray + \fi +}% + +\pgfdeclarefunctionalshading[black]{color wheel} +{\pgfpoint{-50bp}{-50bp}} +{\pgfpoint{50bp}{50bp}} +{} +{ % x y + 2 copy abs exch abs add 0.0001 ge + {atan 360.0 div} % ... x y heading; heading being in + %the interval [0, 1.0] + { pop } % silently deal with error: return + % arbitrary heading of zero for origin + ifelse % because we will use it for 'Hue' + 1.0 1.0 % ... H S V + % C version to use as model: + % H' = H * 6 + % i = floor(H') + % f = H' - i + % P = V * (1.0 - S) + % Q = V * (1.0 - (S*f)) + % T = V * (1.0 - (S * (1.0 - f))) + 3 2 roll 6.0 mul dup 4 1 roll % H' S V H' + floor cvr % H' S V i + dup 5 1 roll % i H' S V i + 3 index sub neg % i H' S V f + 1.0 3 index sub % i H' S V f (1.0 - S ) + 2 index mul % i H' S V f P + 6 1 roll % P i H' S V f + dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S)) + 2 index mul % P i H' S V f Q + 7 1 roll % Q P i H' S V f + neg 1.0 add % Q P i H' S V (1.0 - f) + 2 index mul neg 1.0 add % Q P i H' S V (1.0 - S * (1.0 - f)) + 1 index mul % Q P i H' S V T + 7 2 roll % V T Q P i H' S + pop pop % V T Q P i + %%% + % end of BLOCK B. The rest is just stack manipulation + dup 0.5 le % TEST II [ i == 0 ] + { % BLOCK C [ take stack to V T P ] + pop exch pop + } + { dup 1.5 le % TEST III [ i == 1 ] + { % BLOCK D [ take stack to Q V P ] + pop exch 4 1 roll exch pop + } + { dup 2.5 le % TEST IV [ i == 2 ] + { % BLOCK E [ take stack to P V T ] + pop 4 1 roll pop + } + { dup 3.5 le % TEST V [ i == 3 ] + { % BLOCK F [ take stack to P Q V ] + pop exch 4 2 roll pop + } + { dup 4.5 le % TEST VI [ i == 4 ] + { % BLOCK G [ take stack to T P V ] + pop exch pop 3 -1 roll + } + { % BLOCK H [ take stack to V P Q ] + pop 3 1 roll exch pop + } + ifelse + } + ifelse % for V + } + ifelse % for IV + } + ifelse % for III + } + ifelse % for II + \ifpgfshadingmodelcmyk + \pgffuncshadingrgbtocmyk + \fi + \ifpgfshadingmodelgray + \pgffuncshadingrgbtogray + \fi +}% + + +% +% A bilinear interpolation. +% + +\colorlet{lower left}{white}% +\colorlet{lower right}{white}% +\colorlet{upper left}{white}% +\colorlet{upper right}{white}% + +\pgfdeclarefunctionalshading[lower left,lower right,upper left,upper right]{bilinear interpolation} +{\pgfpointorigin} +{\pgfpoint{100bp}{100bp}} +{ + \pgfshadecolortorgb{lower left}{\pgf@lib@shadings@ll}\pgfshadecolortorgb{lower right}{\pgf@lib@shadings@lr} + \pgfshadecolortorgb{upper right}{\pgf@lib@shadings@ur}\pgfshadecolortorgb{upper left}{\pgf@lib@shadings@ul} +}{ + 25 sub 50 div exch 25 sub 50 div 2 copy % Calculate y/100 x/100. +% 100 div exch 100 div 2 copy % Calculate y/100 x/100. + neg 1 add exch neg 1 add % Calculate 1-y/100 1-x/100. + 3 1 roll 2 copy exch 5 2 roll 6 copy 6 copy % Set up stack. + \pgf@lib@shadings@llred mul exch \pgf@lib@shadings@lrred mul add mul % Process red component. + 4 1 roll + \pgf@lib@shadings@urred mul exch \pgf@lib@shadings@ulred mul add mul + add + 13 1 roll + \pgf@lib@shadings@llgreen mul exch \pgf@lib@shadings@lrgreen mul add mul % Process green component. + 4 1 roll + \pgf@lib@shadings@urgreen mul exch \pgf@lib@shadings@ulgreen mul add mul + add + 7 1 roll + \pgf@lib@shadings@llblue mul exch \pgf@lib@shadings@lrblue mul add mul % Process blue component. + 4 1 roll + \pgf@lib@shadings@urblue mul exch \pgf@lib@shadings@ulblue mul add mul + add + \ifpgfshadingmodelcmyk + \pgffuncshadingrgbtocmyk + \fi + \ifpgfshadingmodelgray + \pgffuncshadingrgbtogray + \fi +}% + + +% +% A Mandelbrot set shading. Just for fun... +% + +\pgfdeclarefunctionalshading[black]{Mandelbrot set} +{\pgfpoint{-50bp}{-50bp}} +{\pgfpoint{50bp}{50bp}}{} +{ + 12.5 div exch 12.5 div exch + 1 index 1 index + % Stack: c_r c_i z_r z_i + % Formula: z' = z^2 + c = (z_r + i z_i)^2 + c_r + i c_i + % = (z_r^2 - z_i^2 + c_r) + i (2 z_r z_i + c_i) + % + % First iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Second iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Third iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Fourth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Check for break (to avoid too large numbers) + 1 index dup mul 1 index dup mul add + 4 lt { + % Fifth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Sixth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Seventh iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Check for break (to avoid too large numbers) + 1 index dup mul 1 index dup mul add + 4 lt { + % Eighth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Ninth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + % Tenth iteration + % 1. Compute z_r^2 -z_i^2 + c_r + 1 index dup mul % z_r^2 + 1 index dup mul % z_i^2 + sub % z_r^2 - z_i^2 + 4 index add % z_r^2 -z_i^2 + c_r + % 2. Compute 2 z_r z_i + c_i + 3 1 roll + mul 2 mul % 2 z_r z_i + 2 index add % 2 z_r z_i + c_i + } { pop pop 1000.0 1000.0 } ifelse + } { pop pop 1000.0 1000.0 } ifelse + % Compute distance + dup mul exch + dup mul + add sqrt + dup 4 1 roll + 2 gt { pop pop 2.0 exch div 1.0 exch sub dup dup} {pop pop pop 0.0 0.0 0.0} ifelse + \ifpgfshadingmodelcmyk + \pgffuncshadingrgbtocmyk + \fi + \ifpgfshadingmodelgray + \pgffuncshadingrgbtogray + \fi +}% diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarysnakes.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarysnakes.code.tex new file mode 100644 index 0000000000..c45140535e --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarysnakes.code.tex @@ -0,0 +1,16 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarysnakes.code.tex} + +\pgfwarning{Snakes have been superseded by decorations. Use the decoration libraries instead of the snakes library}% + +\usepgflibrary{decorations.pathmorphing,decorations.pathreplacing,decorations.shapes}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarysvg.path.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarysvg.path.code.tex new file mode 100644 index 0000000000..e802ca778e --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarysvg.path.code.tex @@ -0,0 +1,829 @@ +% Copyright 2019 by Till Tantau +% Copyright 2019 by Jonathan P. Spratte +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarysvg.path.code.tex} + + +\usepgfmodule{parser}% + + +% Scan an SVG-Path +% +% #1 = the path +% +% Description: +% +% This command takes a path in the compressed SVG-syntax. It then +% issues a sequences of appropriate \pgfpath commands for this +% path. For a description of the compressed svg path syntax, see a +% book on svg. +% +% The notion of a pixel used by svg makes no sense in pgf (actually +% it does not really make sense in svg either, but never mind), and +% instead of pixels "pt" is used as the basic unit. Use coordinate +% transformation to change this. +% +% Example: +% +% \pgfpathsvg{M10 20 L 30-20 0 1} +% +% % this has the same effect as +% +% \pgfpathmoveto{\pgfpoint{10pt}{20pt}} +% \pgfpathlineto{\pgfpint{30pt}{-20pt}} +% \pgfpathlineto{\pgfpint{0pt}{1pt}} +% + +\def\pgfpathsvg#1{% + \let\pgf@lib@svg@finish@prev\relax% + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@path@lastx}{\pgf@path@lasty}}}% + }% + \pgf@lib@svg@last@x\pgf@x% + \pgf@lib@svg@last@y\pgf@y% + \let\pgf@lib@svg@num=\pgfutil@empty% + \let\pgf@lib@svg@exp=\pgfutil@empty% + \pgfparserparse{svgpath}#1"% +}% + + + +\newdimen\pgf@lib@svg@last@x +\newdimen\pgf@lib@svg@last@y +\newdimen\pgf@lib@svg@last@c@x +\newdimen\pgf@lib@svg@last@c@y + +\newcount\pgf@lib@svg@count +\newcount\pgf@lib@svg@max@num + +\newif\pgf@lib@svg@relative + + + +% For the smooth commands (S, s, T, t) we need to keep track of the +% previous control points. This is done in the following two +% variables. If they are empty, there was no previous control point of +% the desired kind, in which case the specification prescribes that +% the start point is used. + +\def\pgf@lib@svg@clear@bezier@quad{% + \let\pgf@lib@svg@bezier@last=\pgfutil@empty + \let\pgf@lib@svg@quad@last=\pgfutil@empty +}% +\pgf@lib@svg@clear@bezier@quad + +% +% Here comes the DFA: +% + +% Handle a moveto: + +\pgfparserdef{svgpath}{all}{the letter M} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@moveto}% +}% + +\def\pgf@lib@svg@moveto{% + \pgf@lib@svg@clear@bezier@quad% + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{0}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{1}pt% + \pgfpathmoveto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto}% +}% + + +% Handle a relative moveto: + +\pgfparserdef{svgpath}{all}{the letter m} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@moveto@rel}% +}% + +\def\pgf@lib@svg@moveto@rel{% + \pgf@lib@svg@clear@bezier@quad% + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{0}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{1}pt% + \pgfpathmoveto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto@rel}% +}% + + +% Handle a lineto: + +\pgfparserdef{svgpath}{all}{the letter L} +{% + \pgf@lib@svg@finish@prev% + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto}% +}% + +\def\pgf@lib@svg@lineto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{0}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{1}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto}% + \fi +}% + + +% Handle a relative lineto: + +\pgfparserdef{svgpath}{all}{the letter l} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto@rel}% +}% + +\def\pgf@lib@svg@lineto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{0}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{1}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@lineto@rel}% + \fi +}% + + +% Handle a closepath: + +\pgfparserdef{svgpath}{all}{the letter Z} +{% + \pgf@lib@svg@closepath +}% + +\pgfparserdef{svgpath}{all}{the letter z} +{% + \pgf@lib@svg@closepath +}% + +\def\pgf@lib@svg@closepath{% + \pgf@lib@svg@finish@prev + \pgfpathclose + \let\pgf@lib@svg@finish@prev=\relax + \pgf@lib@svg@clear@bezier@quad% + \pgfparserswitch{initial}% +}% + + +% Ignore spaces if no other rules says differently: + +\pgfparserdef{svgpath}{all}{blank space \space}{}% + + + + +% Handle a horizontal lineto: + +\pgfparserdef{svgpath}{all}{the letter H} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@hlineto}% +}% + +\def\pgf@lib@svg@hlineto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{0}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@hlineto}% + \fi +}% + +\pgfparserdef{svgpath}{all}{the letter h} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@hlineto@rel}% +}% + +\def\pgf@lib@svg@hlineto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{0}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@hlineto@rel}% + \fi +}% + + +% Handle a horizontal lineto: + +\pgfparserdef{svgpath}{all}{the letter V} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@vlineto}% +}% + +\def\pgf@lib@svg@vlineto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{0}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@vlineto}% + \fi +}% + +\pgfparserdef{svgpath}{all}{the letter v} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@vlineto@rel}% +}% + +\def\pgf@lib@svg@vlineto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + \pgf@lib@svg@clear@bezier@quad% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{0}pt% + \pgfpathlineto{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \pgf@lib@svg@read@nums{1}{\pgf@lib@svg@vlineto@rel}% + \fi +}% + + + + +% Handle a Bezier curve: + +\pgfparserdef{svgpath}{all}{the letter C} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{6}{\pgf@lib@svg@curveto}% +}% + +\def\pgf@lib@svg@curveto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@quad@last=\pgfutil@empty% + \edef\pgf@lib@svg@bezier@last{% + \noexpand\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}% + % Draw curve + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{4}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{5}pt% + \pgfpathcurveto + {\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + {\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + % Go on + \pgf@lib@svg@read@nums{6}{\pgf@lib@svg@curveto}% + \fi +}% + + +\pgfparserdef{svgpath}{all}{the letter c} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{6}{\pgf@lib@svg@curveto@rel}% +}% + +\def\pgf@lib@svg@curveto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@quad@last=\pgfutil@empty% + \pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}% + \edef\pgf@lib@svg@bezier@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % Draw curve + \pgfpathcurveto + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{4}pt}{\pgf@lib@svg@get@num{5}pt}}}% + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{4}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{5}pt% + \pgf@lib@svg@read@nums{6}{\pgf@lib@svg@curveto@rel}% + \fi +}% + + + + + +\pgfparserdef{svgpath}{all}{the letter S} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@smooth}% +}% + +\def\pgf@lib@svg@curveto@smooth{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Draw curve + % Compute first control point + \ifx\pgf@lib@svg@bezier@last\pgfutil@empty% + \def\pgf@lib@svg@first@cp{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \else + \def\pgf@lib@svg@first@cp{% + \pgfpointadd + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + {\pgfpointdiff + {\pgf@lib@svg@bezier@last}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + }% + }% + \fi + \pgfpathcurveto + {\pgf@lib@svg@first@cp}% + {\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + {\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@quad@last=\pgfutil@empty% + \edef\pgf@lib@svg@bezier@last{% + \noexpand\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + % Update + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{2}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{3}pt% + % Go on + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@smooth}% + \fi +}% + + +\pgfparserdef{svgpath}{all}{the letter s} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@rel@smooth}% +}% + +\def\pgf@lib@svg@curveto@rel@smooth{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Draw curve + % Compute first control point + \ifx\pgf@lib@svg@bezier@last\pgfutil@empty% + \def\pgf@lib@svg@first@cp{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + \else + \def\pgf@lib@svg@first@cp{% + \pgfpointadd + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + {\pgfpointdiff + {\pgf@lib@svg@bezier@last}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + }% + }% + \fi + \pgfpathcurveto + {\pgf@lib@svg@first@cp}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@quad@last=\pgfutil@empty% + \pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + \edef\pgf@lib@svg@bezier@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % update + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{2}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{3}pt% + % Go on + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@rel@smooth}% + \fi +}% + + + + +% Handle a quadratic curve: + +\pgfparserdef{svgpath}{all}{the letter Q} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@quad@curveto}% +}% + +\def\pgf@lib@svg@quad@curveto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear bezier last point and save new last control point: + \let\pgf@lib@svg@bezier@last=\pgfutil@empty% + \edef\pgf@lib@svg@quad@last{% + \noexpand\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + % Draw curve + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{2}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{3}pt% + \pgfpathquadraticcurveto + {\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + % Go on + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@quad@curveto}% + \fi +}% + + +\pgfparserdef{svgpath}{all}{the letter q} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@quad@curveto@rel}% +}% + +\def\pgf@lib@svg@quad@curveto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@bezier@last=\pgfutil@empty% + \pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + \edef\pgf@lib@svg@quad@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % Draw curve + \pgfpathquadraticcurveto + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}% + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{2}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{3}pt% + \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@quad@curveto@rel}% + \fi +}% + + + + +\pgfparserdef{svgpath}{all}{the letter T} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@quad@curveto@smooth}% +}% + +\def\pgf@lib@svg@quad@curveto@smooth{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Draw curve + % Compute first control point + \pgf@process{% + \ifx\pgf@lib@svg@quad@last\pgfutil@empty% + \pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}% + \else + \pgfpointadd + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + {\pgfpointdiff + {\pgf@lib@svg@quad@last}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + }% + \fi + }% + \edef\pgf@lib@svg@first@cp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfpathquadraticcurveto + {\pgf@lib@svg@first@cp}% + {\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@bezier@last=\pgfutil@empty% + \let\pgf@lib@svg@quad@last=\pgf@lib@svg@first@cp% + % Update + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{0}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{1}pt% + % Go on + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@quad@curveto@smooth}% + \fi +}% + + +\pgfparserdef{svgpath}{all}{the letter t} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@quad@curveto@rel@smooth}% +}% + +\def\pgf@lib@svg@quad@curveto@rel@smooth{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Draw curve + % Compute first control point + \pgf@process{% + \ifx\pgf@lib@svg@quad@last\pgfutil@empty% + \pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}% + \else + \pgfpointadd + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + {\pgfpointdiff + {\pgf@lib@svg@quad@last}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + }% + \fi + }% + \edef\pgf@lib@svg@first@cp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + \pgfpathquadraticcurveto + {\pgf@lib@svg@first@cp}% + {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% + % Clear quadratic last point and save new last control point: + \let\pgf@lib@svg@bezier@last=\pgfutil@empty% + \let\pgf@lib@svg@quad@last=\pgf@lib@svg@first@cp% + % update + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{0}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{1}pt% + % Go on + \pgf@lib@svg@read@nums{2}{\pgf@lib@svg@quad@curveto@rel@smooth}% + \fi +}% + + + +% Handle an arcto: + +\pgfparserdef{svgpath}{all}{the letter A} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{7}{\pgf@lib@svg@arcto}% +}% + +\def\pgf@lib@svg@arcto{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear bezier last point and save new last control point: + \pgf@lib@svg@clear@bezier@quad% + % Draw curve + \pgf@lib@svg@last@x=\pgf@lib@svg@get@num{5}pt% + \pgf@lib@svg@last@y=\pgf@lib@svg@get@num{6}pt% + \pgfpatharcto + {\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}% + {\pgf@lib@svg@get@num{2}}% + {\pgf@lib@svg@get@num{3}}% + {\pgf@lib@svg@get@num{4}}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + % Go on + \pgf@lib@svg@read@nums{7}{\pgf@lib@svg@arcto}% + \fi +}% + +\pgfparserdef{svgpath}{all}{the letter a} +{% + \pgf@lib@svg@finish@prev + \pgf@lib@svg@read@nums{7}{\pgf@lib@svg@arcto@rel}% +}% + +\def\pgf@lib@svg@arcto@rel{% + \ifnum\pgf@lib@svg@count=0\relax% nothing read + \else% + % Clear bezier last point and save new last control point: + \pgf@lib@svg@clear@bezier@quad% + % Draw curve + \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{5}pt% + \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{6}pt% + \pgfpatharcto + {\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}% + {\pgf@lib@svg@get@num{2}}% + {\pgf@lib@svg@get@num{3}}% + {\pgf@lib@svg@get@num{4}}% + {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}% + % Go on + \pgf@lib@svg@read@nums{7}{\pgf@lib@svg@arcto@rel}% + \fi +}% + + + + + +% Handle to end of the world + +\pgfparserdef{svgpath}{all}{the character "} +{% + \pgf@lib@svg@finish@prev + \pgfparserswitch{final}% +}% + + + + +% Handle spacers for numbers + +\def\pgf@lib@svg@read@nums#1#2{% get #1 number symbols, then do #2 + \pgf@lib@svg@count=0\relax + \pgf@lib@svg@max@num=#1\relax + \pgfparserswitch{num}% + \def\pgf@lib@svg@finish@prev{% + \ifx\pgf@lib@svg@num\pgfutil@empty% + \else% + \ifx\pgf@lib@svg@exp\pgfutil@empty + \else + \pgfmathfloatparsenumber{\pgf@lib@svg@num e\pgf@lib@svg@exp}% + \pgfmathfloattofixed{\pgfmathresult}% + \let\pgf@lib@svg@num=\pgfmathresult + \fi + \expandafter\let\csname pgf@lib@svg@num@\the\pgf@lib@svg@count\endcsname=\pgf@lib@svg@num + \advance\pgf@lib@svg@count by1\relax% + \let\pgf@lib@svg@num=\pgfutil@empty% + \let\pgf@lib@svg@exp=\pgfutil@empty% + \fi + #2% + }% +}% + +\def\pgf@lib@svg@get@num#1{\csname pgf@lib@svg@num@#1\endcsname}% + + +\pgfparserdef{svgpath}{num}{the character ,} +{% + \pgf@lib@svg@handle@spacer +}% +\pgfparserlet{svgpath}{after.}{the character ,}[num]{the character ,} +\pgfparserlet{svgpath}{exp},[num], +\pgfparserlet{svgpath}{exp sign},[num], + +\pgfparserdef{svgpath}{num}{\meaning\pgfutil@sptoken} +{% + \pgf@lib@svg@handle@spacer +}% +\pgfparserlet{svgpath}{after.}{blank space}[num]{blank space} +\pgfparserlet{svgpath}{exp}{blank space}, +\pgfparserlet{svgpath}{exp sign}{blank space}, + +\pgfparserdef{svgpath}{num}{the character -} +{% + \pgf@lib@svg@handle@spacer + \def\pgf@lib@svg@num{-}% +}% +\pgfparserlet{svgpath}{after.}{the character -}[num]{the character -} +\pgfparserlet{svgpath}{exp}-[num]- +\pgfparserdef{svgpath}{num}{the character +} +{% + \pgf@lib@svg@handle@spacer + \def\pgf@lib@svg@num{+}% +} +\pgfparserlet{svgpath}{after.}{the character +}[num]{the character +} +\pgfparserlet{svgpath}{exp}+[num]+ + +\def\pgf@lib@svg@handle@spacer{% + \ifx\pgf@lib@svg@num\pgfutil@empty% + % ignore + \else + \ifx\pgf@lib@svg@exp\pgfutil@empty + \else + \pgfmathfloatparsenumber{\pgf@lib@svg@num e\pgf@lib@svg@exp}% + \pgfmathfloattofixed{\pgfmathresult}% + \let\pgf@lib@svg@num=\pgfmathresult + \fi + \expandafter\let\csname pgf@lib@svg@num@\the\pgf@lib@svg@count\endcsname=\pgf@lib@svg@num + \advance\pgf@lib@svg@count by1\relax% + \ifnum\pgf@lib@svg@count=\pgf@lib@svg@max@num\relax% + \pgf@lib@svg@finish@prev% + \fi + \let\pgf@lib@svg@num=\pgfutil@empty% + \let\pgf@lib@svg@exp=\pgfutil@empty% + \pgfparserswitch{num}% + \fi +}% + + +% Handle digits + +\pgfparserdef{svgpath}{num}e + {% + \pgfparserswitch{exp sign}% + \let\pgf@lib@svg@exp=\pgfutil@empty + } +\pgfparserlet{svgpath}{after.}e[num]e +\pgfparserdef{svgpath}{exp sign}- + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp-}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}+ + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp+}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}0 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp0}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}1 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp1}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}2 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp2}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}3 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp3}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}4 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp4}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}5 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp5}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}6 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp6}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}7 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp7}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}8 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp8}% + \pgfparserswitch{exp}% + } +\pgfparserdef{svgpath}{exp sign}9 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp9}% + \pgfparserswitch{exp}% + } + +\pgfparserdef{svgpath}{exp}0 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp0}% + } +\pgfparserdef{svgpath}{exp}1 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp1}% + } +\pgfparserdef{svgpath}{exp}2 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp2}% + } +\pgfparserdef{svgpath}{exp}3 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp3}% + } +\pgfparserdef{svgpath}{exp}4 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp4}% + } +\pgfparserdef{svgpath}{exp}5 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp5}% + } +\pgfparserdef{svgpath}{exp}6 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp6}% + } +\pgfparserdef{svgpath}{exp}7 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp7}% + } +\pgfparserdef{svgpath}{exp}8 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp8}% + } +\pgfparserdef{svgpath}{exp}9 + {% + \expandafter\def\expandafter\pgf@lib@svg@exp\expandafter{\pgf@lib@svg@exp9}% + } + +\pgfparserdef{svgpath}{num}{the character .} + {% + \expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num.}% + \pgfparserswitch{after.}% + }% +\pgfparserdef{svgpath}{after.}{the character .} + {% + \pgf@lib@svg@handle@spacer + \def\pgf@lib@svg@num{.}% + \pgfparserswitch{after.}% + }% +\pgfparserlet{svgpath}{exp}{the character .}[after.]{the character .} + +\pgfparserdef{svgpath}{all}{the character 0} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num0}}% + +\pgfparserdef{svgpath}{all}{the character 1} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num1}}% + +\pgfparserdef{svgpath}{all}{the character 2} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num2}}% + +\pgfparserdef{svgpath}{all}{the character 3} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num3}}% + +\pgfparserdef{svgpath}{all}{the character 4} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num4}}% + +\pgfparserdef{svgpath}{all}{the character 5} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num5}}% + +\pgfparserdef{svgpath}{all}{the character 6} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num6}}% + +\pgfparserdef{svgpath}{all}{the character 7} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num7}}% + +\pgfparserdef{svgpath}{all}{the character 8} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num8}}% + +\pgfparserdef{svgpath}{all}{the character 9} +{\expandafter\def\expandafter\pgf@lib@svg@num\expandafter{\pgf@lib@svg@num9}}% diff --git a/graphics/pgf/base/tex/generic/libraries/pgflibrarytimelines.code.tex b/graphics/pgf/base/tex/generic/libraries/pgflibrarytimelines.code.tex new file mode 100644 index 0000000000..0e9afce0f2 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/pgflibrarytimelines.code.tex @@ -0,0 +1,197 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarytimelines.code.tex} + + +% We need the animation module: + +\usepgfmodule{animations}% + + +% Starts a fixed timeline +% +% Description: +% +% A (fixed) timeline defines for a specific number of seconds how a +% different objects are animated. In contrast to a dynamic timeline, +% the animation must be fixed beforehand, that is, in a fixed timeline +% you can specify things like "be there after 2s and there after 4s +% and be red after 5s" but not "be there after that other animation +% has finished and then stay there until another animation has +% finished or something has been clicked". Note that while a fixed +% timeline describes a fixed sequence of animations, the starting +% point of the timeline may depend for instance on when some button is +% clicked; only when the timeline's animation gets started there is +% nothing dynamic about it till its end (a timeline may be ended +% prematurely, however). +% +% This command allows you to start a timeline. Once the timeline has +% been started, you can call the following macro repeatedly: +% +% \pgftimelineentry{time}{object}{attribute}{value} +% +% The time is some time when the given attribute should have the given +% value. The important thing is that the entries need not come in any +% specific order; it is the job of the timeline library to sort them +% into a sensible order. +% +% At the end of the timeline, you will have specified for a whole +% bunch of objects and attributes their values at certain time +% points. The macro \pgftimelineend will now call \pgfanimateattribute +% for all attributes and objects mentioned in the timeline. +% +% +% Internally, pgf keeps track of all objects in a timeline and all +% attributes and sorts the times using a simple insertion sort (which +% will be fastest when the times are given in increasing order as +% happens most of the time). + +\def\pgftimelinebegin{% + \pgf@timeline@todo@saved=\pgf@timeline@todo% + \begingroup% + \advance\pgf@timeline@depth by1\relax% + \pgf@timeline@todo{}% +}% + +\newcount\pgf@timeline@depth +\newtoks\pgf@timeline@todo +\newtoks\pgf@timeline@todo@saved + + +% Ends a timeline +% +% Description: +% +% This command will scan \pgfanimateattribute for the objects and +% attributes mentioned in the timeline. + +\def\pgftimelineend{% + \the\pgf@timeline@todo% + \endgroup% + \global\pgf@timeline@todo=\pgf@timeline@todo@saved% +}% + + +% Adds an entry to a timeline +% +% #1 = a time (evaluated using \pgfparsetime) +% #2 = an object (a "whom" in the sense of pgfmoduleanimations, will +% be expanded) +% #3 = an attribute (in the sense of pgfmoduleanimations, will be expanded) +% #4 = a value +% +% Description: +% +% Adds a new entry to the timeline. For a fixed #1, several calls to +% this macro allow you to specify a key frame by specifying the +% different values of the different attributes of the different +% objects in the key frame. + +\def\pgftimelineentry#1#2#3#4{% + \begingroup% + \pgfparsetime{#1}% + \edef\pgf@timeline@whom{#2}% + \edef\pgf@timeline@attr{#3}% + \expandafter\let\expandafter\pgf@timeline@entry\csname pgf@tl@\pgf@timeline@whom @\pgf@timeline@attr @\the\pgf@timeline@depth\endcsname% + \ifx\pgf@timeline@entry\relax% + \edef\pgf@timeline@entry{\noexpand\pgf@timeline@setup{\pgf@timeline@whom}{\pgf@timeline@attr}}% + \fi% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@timeline@entry\expandafter\expandafter\expandafter% + {\expandafter\pgf@timeline@entry\expandafter\pgf@timeline@doentry\expandafter{\pgftimeresult}{#4}}% + \expandafter\global\expandafter\let\csname pgf@tl@\pgf@timeline@whom @\pgf@timeline@attr @\the\pgf@timeline@depth\endcsname\pgf@timeline@entry% + \global\pgf@timeline@todo\expandafter\expandafter\expandafter{\expandafter\the\expandafter\pgf@timeline@todo\expandafter\pgf@timeline@handle\csname pgf@tl@\pgf@timeline@whom @\pgf@timeline@attr @\the\pgf@timeline@depth\endcsname}% + \endgroup% +}% + + +\newtoks\pgf@timeline@sort@toks +\countdef\pgf@timeline@sort@count=0\relax% +\countdef\pgf@timeline@count@down=1\relax% +\countdef\pgf@timeline@count@down@next=2\relax% + +% Handles one entry in a timeline + +\def\pgf@timeline@handle#1{% + \ifx#1\relax% + \else% + % Do an inserting sort. The time is kept in the dimension registers + % 1 to n, the value in the token registers 1 to n. + {% + \pgf@timeline@sort@count=1\relax% + #1% will start a group + % Now we collect the toks: + \pgf@timeline@count@down=1\relax% + \pgf@timeline@sort@toks{}% + \pgfutil@loop% + \ifnum\pgf@timeline@count@down<\pgf@timeline@sort@count\relax% + \edef\pgf@temp{\the\pgf@timeline@sort@toks\noexpand\pgf@timeline@donow{\the\dimen\pgf@timeline@count@down}{\the\toks\pgf@timeline@count@down}}% + \pgf@timeline@sort@toks\expandafter{\pgf@temp}% + \advance\pgf@timeline@count@down by1\relax% + \pgfutil@repeat% + % Do computations now + \pgf@timeline@compute@duration% + % + \edef\pgf@temp{\noexpand\pgf@timeline@call@attribute{\pgf@timeline@whom}{\pgf@timeline@attr}{\the\pgf@timeline@sort@toks}} + \expandafter% + \endgroup% + \pgf@temp% + }% + \global\let#1\relax% cleanup + \fi% +}% + +\def\pgf@timeline@compute@duration{% + \advance\pgf@timeline@sort@count by-1\relax% + \pgfmathparse{\the\dimen\pgf@timeline@sort@count}% + \global\let\pgf@timeline@duration\pgfmathresult% +}% + + +\def\pgf@timeline@setup#1#2{% + \def\pgf@timeline@whom{#1}% + \def\pgf@timeline@attr{#2}% + \begingroup% +}% + +\def\pgf@timeline@doentry#1#2{% + \dimen\pgf@timeline@sort@count=#1pt\relax% + \toks\pgf@timeline@sort@count{#2}% + \pgf@timeline@count@down\pgf@timeline@sort@count\relax% + \pgfutil@loop% + \ifnum\pgf@timeline@count@down>1\relax% + \pgf@timeline@count@down@next\pgf@timeline@count@down% + \advance\pgf@timeline@count@down@next by-1\relax% + \ifdim\dimen\pgf@timeline@count@down<\dimen\pgf@timeline@count@down@next\relax% + % Swap: + \toks0=\toks\pgf@timeline@count@down% + \dimen0=\dimen\pgf@timeline@count@down% + \toks\pgf@timeline@count@down=\toks\pgf@timeline@count@down@next% + \dimen\pgf@timeline@count@down=\dimen\pgf@timeline@count@down@next% + \toks\pgf@timeline@count@down@next=\toks0\relax% + \dimen\pgf@timeline@count@down@next=\dimen0\relax% + \pgf@timeline@count@down\pgf@timeline@count@down@next\relax% + \else% + \pgf@timeline@count@down1\relax% + \fi% + \pgfutil@repeat% + \advance\pgf@timeline@sort@count by1\relax% +}% + + +\def\pgf@timeline@call@attribute#1#2#3{% + \pgfanimateattributecode{#2}{\pgfkeys{/pgf/animation/whom={#1},/pgf/animation/duration=\pgf@timeline@duration}#3}% +}% + +\def\pgf@timeline@donow#1#2{% + \pgfkeys{/pgf/animation/key time={#1/\pgf@timeline@duration}}% + \pgfkeys{/pgf/animation/value={#2}}% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.IEC.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.IEC.code.tex new file mode 100644 index 0000000000..0d25e307e4 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.IEC.code.tex @@ -0,0 +1,679 @@ +% Copyright 2018 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + +% +% Resistor shape based on a zig-zag-line +% + +\pgfdeclareshape{var resistor IEC} +{% + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % Middle line + \pgf@yc=.5\pgf@ya + \advance\pgf@yc by.5\pgf@yb + % Height + \pgf@xc=-.5\pgf@ya + \advance\pgf@xc by.5\pgf@yb + % Start point + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yc}} + % Lines + \advance\pgf@xb by.1pt% + \pgfutil@loop% + \advance\pgf@xa by4\pgf@xc\relax% + \ifdim\pgf@xa<\pgf@xb% + \advance\pgf@xa by-3\pgf@xc% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}% + \advance\pgf@xa by2\pgf@xc% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}% + \advance\pgf@xa by\pgf@xc% + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yc}}% + \pgfutil@repeat% + \advance\pgf@xb by-.1pt% + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yc}}% + }% +}% + + + +% +% Inductor shape based on a bumpy line +% + +\pgfdeclareshape{inductor IEC} +{% + \savedanchor\northeast{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=\pgf@xa% + \advance\pgf@x by .5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@yb% + }% + \savedanchor\southwest{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=-\pgf@xa% + \advance\pgf@x by -.5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgf@y=-\pgf@ya% + }% + + \anchor{center}{\pgfpointorigin}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + + \anchorborder{% + \ifdim\pgf@y<0pt% + % tricky... simpilfy to the origin... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\southwest}% + \advance\pgf@y by-0.5pt% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\pgfqpoint{-\pgf@xa}{-\pgf@ya}}}% + \else% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\northeast}}% + \fi% + }% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xa=-\pgf@x \pgf@ya=0pt + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % Height + \pgf@xc=\pgf@yb% + % Start point + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}} + % Lines + \advance\pgf@xb by.1pt% + \pgfutil@loop% + \advance\pgf@xa by2\pgf@xc\relax% + \ifdim\pgf@xa<\pgf@xb% + \pgfpatharc{180}{0}{\pgf@xc}% + \pgfutil@repeat% + \advance\pgf@xb by-.1pt% + \pgfpathlineto{\pgfqpoint{\pgf@xb}{0pt}}% + }% +}% + + + + +% +% Simple capacitor, consisting of two parallel lines +% + +\pgfdeclareshape{capacitor IEC} +{% + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + + + +% +% Simple ground, consisting of three lines, getting smaller +% + +\pgfdeclareshape{ground IEC} +{% + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % First line, simple + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + % Advance to middle + \pgfmathsetlength\pgf@xa{.5\pgf@xa+.5\pgf@xb} + % Make smaller + \pgfmathsetlength\pgf@yc{.16666\pgf@yb-.16666\pgf@ya} + \advance\pgf@ya by\pgf@yc + \advance\pgf@yb by-\pgf@yc + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + % Make even smaller + \advance\pgf@ya by\pgf@yc + \advance\pgf@yb by-\pgf@yc + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + + +% +% Battery, consisting of two parallel lines, one smaller than +% the other +% + +\pgfdeclareshape{battery IEC} +{% + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % First line, simple + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + % Make smaller + \pgfmathsetlength\pgf@yc{.25\pgf@yb-.25\pgf@ya} + \advance\pgf@ya by\pgf@yc + \advance\pgf@yb by-\pgf@yc + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + +% +% Special diodes +% + + +\pgfdeclareshape{breakdown diode IEC} +{% + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgf@xc=.5\pgf@xa \advance\pgf@xc by.5\pgf@xb + \pgf@yc=.5\pgf@ya + \advance\pgf@yc by .5\pgf@yb + % Triangles: + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@yc}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + \pgfpathclose + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@yc}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + \pgfpathclose + }% + + + \beforebackgroundpath{ + { + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgf@yc=.5\pgf@ya + \advance\pgf@yc by.5\pgf@yb + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yc}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yc}} + \pgfusepathqstroke + \pgf@xc=.5\pgf@xa + \advance\pgf@xc by.5\pgf@xb + \pgftransformshift{\pgfqpoint{\pgf@xc}{\pgf@yc}} + \pgf@yc=.5\pgf@yb + \advance\pgf@yc by-.5\pgf@ya + \pgftransformscale{\pgf@sys@tonumber{\pgf@yc}} + \pgfpathmoveto{\pgfqpoint{-.5pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{-1pt}} + \pgfpathlineto{\pgfqpoint{0pt}{1pt}} + \pgfpathlineto{\pgfqpoint{.5pt}{1pt}} + \pgfusepathqstroke + } + }% +}% + + + + + + +% Generic shapes +% +% When these shapes are used, you can set a key derived form the +% shapes name to some code that will be executed as the before +% background path. This means that the basic shape is fixed, but +% things like a special line inside the shape or at the border can be +% added without having to define a whole new shape. + + +\pgfdeclareshape{generic circle IEC} +{% + % This shape is a generic circle, to which you can add something to + % the before background path using the key + % /pgf/generic circle IEC/before background + % When this key is invoked, the transformation matrix will have been + % setup such that the circle's center is at the origin and that the + % position \pgfpoint{1pt}{0pt} lies exactly on the top of the circle + % (and, there, on the middle of the line). + + \inheritsavedanchors[from=circle ee]% + \inheritanchorborder[from=circle ee]% + \inheritanchor[from=circle ee]{north}% + \inheritanchor[from=circle ee]{north west}% + \inheritanchor[from=circle ee]{north east}% + \inheritanchor[from=circle ee]{center}% + \inheritanchor[from=circle ee]{west}% + \inheritanchor[from=circle ee]{east}% + \inheritanchor[from=circle ee]{south}% + \inheritanchor[from=circle ee]{south west}% + \inheritanchor[from=circle ee]{south east}% + \inheritanchor[from=circle ee]{input}% + \inheritanchor[from=circle ee]{output}% + \inheritbackgroundpath[from=circle ee]% + + \beforebackgroundpath{ + { + \centerpoint% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgftransformshift{} + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgfutil@tempdima by-\pgf@yb% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \pgftransformscale{\pgf@sys@tonumber{\pgfutil@tempdima}} + \pgfkeysvalueof{/pgf/generic circle IEC/before background} + } + }% +}% + + + +% +% Generic diode, based on a rectangle +% + +\pgfdeclareshape{generic diode IEC} +{% + % This shape is a generic diode, to which you can add something to + % the before background path using the key + % /pgf/generic diode IEC/before background + % When this key is invoked, the transformation matrix will have been + % setup such that the center is at the tip of the diode. The + % position \pgfpoint{1pt}{0pt} lies exactly on the top of the + % (suggested) line before the diode. + + \inheritsavedanchors[from=rectangle ee]% + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % Move tip back a little bit + \advance\pgf@xb by-.5\pgflinewidth + % Triangle triangle: + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + \pgf@yc=.5\pgf@ya + \advance\pgf@yc by .5\pgf@yb + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yc}} + \pgfpathclose + }% + + + \beforebackgroundpath{ + { + \pgf@process{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}} + \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgf@yc=.5\pgf@ya + \advance\pgf@yc by.5\pgf@yb + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yc}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yc}} + \pgfusepathqstroke + \pgftransformshift{\pgfqpoint{\pgf@xb}{\pgf@yc}} + \pgf@yc=.5\pgf@yb + \advance\pgf@yc by-.5\pgf@ya + \pgftransformscale{\pgf@sys@tonumber{\pgf@yc}} + \pgfkeysvalueof{/pgf/generic diode IEC/before background} + } + }% +}% + + +\pgfkeys{ + /pgf/generic circle IEC/before background/.initial=, + /pgf/generic diode IEC/before background/.initial=, +}% + + + + + +% +% Contacts +% + +\pgfdeclareshape{make contact IEC} +{% + \savedanchor\northeast{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=\pgf@xa% + \advance\pgf@x by .5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@yb% + }% + \savedanchor\southwest{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=-.5\pgf@xa% + \advance\pgf@x by -.5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgf@y=-\pgf@ya% + }% + + \anchor{center}{\pgfpointorigin}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + + \anchorborder{% + \ifdim\pgf@y<0pt% + % tricky... simplify to the origin... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\southwest}% + \advance\pgf@y by-0.5pt% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\pgfqpoint{-\pgf@xa}{-\pgf@ya}}}% + \else% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\northeast}}% + \fi% + }% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xa=-\pgf@x \pgf@ya=0pt + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % Start point + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + + +% +% Contacts +% + +\pgfdeclareshape{var make contact IEC} +{% + \savedanchor\northeast{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=\pgf@xa% + \advance\pgf@x by .5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@yb% + }% + \savedanchor\southwest{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=-.5\pgf@xa% + \advance\pgf@x by -.5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgf@y=-\pgf@ya% + \pgf@xc=0.083333\pgf@x% + \advance\pgf@y by\pgf@xc% + }% + + \anchor{center}{\pgfpointorigin}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + + \anchorborder{% + \ifdim\pgf@y<0pt% + % tricky... simplify to the origin... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\southwest}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\pgfqpoint{-\pgf@xa}{-\pgf@ya}}}% + \else% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\northeast}}% + \fi% + }% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\northeast}{ + \pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xa=-\pgf@x \pgf@ya=0pt + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgf@xc=\pgf@xa + \pgfutil@tempdima=2\pgf@xb% + \pgfutil@tempdima=0.083333\pgfutil@tempdima% + \advance\pgf@xa by \pgfutil@tempdima + % Circle + {\pgfpathcircle{\pgfqpoint{\pgf@xa}{0pt}}{\pgfutil@tempdima}} + % Height + % Start point + \pgf@process{\pgfpointnormalised{\pgfpointdiff{\pgfqpoint{\pgf@xa}{0pt}}{\pgfqpoint{\pgf@xb}{\pgf@yb}}}} + \pgf@xc=\pgf@x + \pgf@yc=\pgf@y + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{\pgf@xa}{0pt}}{% + \pgfpointscale{\pgfutil@tempdima}{\pgfqpoint{\pgf@xc}{\pgf@yc}}}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + + +\pgfdeclareshape{break contact IEC} +{% + \savedanchor\northeast{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=\pgf@xa% + \advance\pgf@x by .5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=\pgf@ya% + \advance\pgf@y by\pgf@yb% + }% + \savedanchor\southwest{% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x=-.5\pgf@xa% + \advance\pgf@x by -.5\pgf@xb% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgf@y=-\pgf@ya% + }% + + \anchor{center}{\pgfpointorigin}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + + \anchorborder{% + \ifdim\pgf@y<0pt% + % tricky... simplify to the origin... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\southwest}% + \advance\pgf@y by-0.5pt% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\pgfqpoint{-\pgf@xa}{-\pgf@ya}}}% + \else% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{\pgfpointborderrectangle{\pgfqpoint{\pgf@xc}{\the\pgf@yc}}{\northeast}}% + \fi% + }% + + \backgroundpath{ + \pgf@process{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}} + \pgf@xa=-\pgf@x \pgf@ya=0pt + \pgf@xb=\pgf@x \pgf@yb=\pgf@y + % Start point + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + % Break point + \pgf@xc=.2\pgf@xb + \advance\pgf@xc by-.2\pgf@xa + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{0pt}} + \advance\pgf@xb by-\pgf@xc + \pgfpathlineto{\pgfqpoint{\pgf@xb}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + }% +}% + + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.code.tex new file mode 100644 index 0000000000..c8f95ff4bf --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.ee.code.tex @@ -0,0 +1,170 @@ +% Copyright 2018 by Till Tantau and others Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + + +% +% Base shapes +% +% These shapes are identical to the shapes without "ee", only an "input" +% and an "output" anchor have been added at the left and right end. + +\pgfdeclareshape{rectangle ee} +{% + \inheritsavedanchors[from=rectangle]% + \inheritanchorborder[from=rectangle]% + \inheritanchor[from=rectangle]{north}% + \inheritanchor[from=rectangle]{north west}% + \inheritanchor[from=rectangle]{north east}% + \inheritanchor[from=rectangle]{center}% + \inheritanchor[from=rectangle]{west}% + \inheritanchor[from=rectangle]{east}% + \inheritanchor[from=rectangle]{mid}% + \inheritanchor[from=rectangle]{mid west}% + \inheritanchor[from=rectangle]{mid east}% + \inheritanchor[from=rectangle]{base}% + \inheritanchor[from=rectangle]{base west}% + \inheritanchor[from=rectangle]{base east}% + \inheritanchor[from=rectangle]{south}% + \inheritanchor[from=rectangle]{south west}% + \inheritanchor[from=rectangle]{south east}% + \inheritbackgroundpath[from=rectangle]% + % New: + \anchor{input}{ + \pgf@process{\northeast}% + \pgf@ya=.5\pgf@y% + \pgf@process{\southwest}% + \pgf@y=.5\pgf@y% + \advance\pgf@y by \pgf@ya% + }% + \anchor{output}{% + \pgf@process{\southwest}% + \pgf@ya=.5\pgf@y% + \pgf@process{\northeast}% + \pgf@y=.5\pgf@y% + \advance\pgf@y by \pgf@ya% + }% +}% + +\pgfdeclareshape{circle ee} +{% + \inheritsavedanchors[from=circle]% + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \inheritbackgroundpath[from=circle]% + % New: + \anchor{input}{\centerpoint\advance\pgf@x by-\radius}% + \anchor{output}{\centerpoint\advance\pgf@x by\radius}% +}% + + + +% +% Current direction indicator. This shape uses the current setting of +% the current direction arrow tip for the arrow. The shape is a +% rectangle around the arrow tip. +% + +\pgfdeclareshape{direction ee} +{% + \savedanchor\northeast{ + \pgf@x=0pt% + % Height is given by minimum height/2 + \pgfmathsetlength{\pgf@y}{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=.5\pgf@y + }% + \savedanchor\southwest{ + % Left border is given by left extend + \pgfarrowtotallength{\pgfkeysvalueof{/pgf/direction ee arrow}}% + \pgf@x=-\pgf@x% + % Height is given by minimum height/2 + \pgfmathsetlength{\pgf@y}{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y=-.5\pgf@y + }% + + \inheritanchor[from=rectangle ee]{center}% + \inheritanchor[from=rectangle ee]{north}% + \inheritanchor[from=rectangle ee]{south}% + \inheritanchor[from=rectangle ee]{east}% + \inheritanchor[from=rectangle ee]{west}% + \inheritanchor[from=rectangle ee]{north east}% + \inheritanchor[from=rectangle ee]{north west}% + \inheritanchor[from=rectangle ee]{south east}% + \inheritanchor[from=rectangle ee]{south west}% + \inheritanchor[from=rectangle ee]{input}% + \inheritanchor[from=rectangle ee]{output}% + \inheritanchorborder[from=rectangle ee]% + \nodeparts{}% no text + + \behindbackgroundpath{ + \pgf@process{\southwest} + \pgf@xa=\pgf@x + \pgf@process{\northeast} + \pgf@xb=\pgf@x + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{0pt}} + \pgfusepathqstroke + }% + + \beforebackgroundpath{ + { + \pgfsys@beginscope + \pgfarrowdraw{\pgfkeysvalueof{/pgf/direction ee arrow}}% + \pgfsys@endscope + } + }% +}% + +\pgfkeys{ + /pgf/direction ee arrow/.initial=direction ee, +}% + + + +% Special arrow for ee directions: + +\pgfarrowsdeclare{direction ee}{direction ee} +{% + \pgfmathsetlength\pgfutil@tempdima{\pgfgetarrowoptions{direction ee}}% + \pgfutil@tempdima=.5\pgfutil@tempdima + \pgfarrowsleftextend{+-\pgfutil@tempdima} + \pgfarrowsrightextend{+\pgfutil@tempdima} +} +{ + \pgfmathsetlength\pgfutil@tempdima{\pgfgetarrowoptions{direction ee}}% + \pgfsetdash{}{+0pt} + \pgfsetroundjoin + \pgfpathmoveto{\pgfqpoint{-0.5\pgfutil@tempdima}{0.38268343237\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{0.5\pgfutil@tempdima}{0\pgfutil@tempdima}} + \pgfpathlineto{\pgfqpoint{-0.5\pgfutil@tempdima}{-0.38268343237\pgfutil@tempdima}} + \pgfpathclose + \pgfusepathqfillstroke +}% + +\pgfsetarrowoptions{direction ee}{4pt}% + + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.IEC.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.IEC.code.tex new file mode 100644 index 0000000000..4022cd605d --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.IEC.code.tex @@ -0,0 +1,739 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{shapes.gates.logic}% + +\pgfkeys{/pgf/.cd, + and gate IEC symbol/.initial=$\char`\&$, + nand gate IEC symbol/.initial=$\char`\&$, + or gate IEC symbol/.initial=$\geq1$, + nor gate IEC symbol/.initial=$\geq1$, + xor gate IEC symbol/.initial={$=1$}, + xnor gate IEC symbol/.initial={$=1$}, + not gate IEC symbol/.initial=1, + buffer gate IEC symbol/.initial=1, + logic gate IEC symbol align/.initial=top, + logic gate IEC symbol color/.initial=% no value +}% + +\pgfkeys{/pgf/logic gate IEC symbol align/.cd, + top/.code=\pgftransformyshift{\innerhalfheight}, + bottom/.code=\pgftransformyshift{-\innerhalfheight}, + left/.code=\pgftransformxshift{-\innerhalfwidth}, + right/.code=\pgftransformxshift{\innerhalfwidth}, +}% + +\def\pgf@lib@sh@logicgates@IEC@foregroundpath#1{% + \dimensions% + {% + \pgftransformshift{\centerpoint}% + \edef\pgf@lib@sh@temp{\pgfkeysvalueof{/pgf/logic gate IEC symbol align}}% + \edef\pgf@lib@sh@@temp{/pgf/logic gate IEC symbol align/.cd, \pgf@lib@sh@temp}% + \expandafter\pgfkeys\expandafter{\pgf@lib@sh@@temp}% + \expandafter\pgftext\expandafter[\pgf@lib@sh@temp]{% + \pgfkeysgetvalue{/pgf/logic gate IEC symbol color}{\pgf@lib@sh@temp}% + \ifx\pgf@lib@sh@temp\pgfutil@empty% + \else% + \expandafter\color\expandafter{\pgf@lib@sh@temp}% + \fi% + \pgfkeysvalueof{/pgf/#1 gate IEC symbol}% + }% + }% +}% + + +\def\pgf@lib@sh@logicgates@dimensions@IEC#1{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + % Adjust for the width of the gate symbol. + % + \setbox\pgf@hbox\hbox{% + % wrap in `\pgfinterruptpicture' to restore font, like how `\pgfnode` sets + % `\pgfnodeparttextbox` + \pgfinterruptpicture + {\pgfkeysvalueof{/pgf/#1 gate IEC symbol}}% add braces as color-aftergroup-fix TT + \endpgfinterruptpicture + }% + \pgf@xa.5\wd\pgf@hbox% + \pgf@ya.5\ht\pgf@hbox% + \advance\pgf@ya.5\dp\pgf@hbox% + \ifdim\pgf@x<\pgf@xa% + \pgf@x\pgf@xa% + \fi% + \ifdim\pgf@y<\pgf@ya% + \pgf@y\pgf@ya% + \fi% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + % + % Adjust for minimum height and width. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + % + % Adjust the height for the number of inputs. + % + \c@pgf@counta\pgf@lib@sh@logicgate@numinputs% + \advance\c@pgf@counta1\relax% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \pgf@yb2.0\pgf@yb% + \advance\pgf@yb\pgflinewidth% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/logic gate input sep}}% + \edef\inputsep{\the\pgf@yc}% + \addtosavedmacro\inputsep% + \ifdim\pgf@yb<\pgf@yc% + \pgf@yb\pgf@yc% + \fi% + \multiply\pgf@yb\c@pgf@counta% + \ifdim\pgf@y<.5\pgf@yb% + \pgf@y.5\pgf@yb% + \fi% + % + \pgf@xa\pgf@x% + \pgfmathaddtolength\pgf@xa{-\pgfkeysvalueof{/pgf/inner xsep}}% + \edef\innerhalfwidth{\the\pgf@xa}% + \addtosavedmacro\innerhalfwidth% + % + \pgf@ya\pgf@y% + \pgfmathaddtolength\pgf@ya{-\pgfkeysvalueof{/pgf/inner ysep}}% + \edef\innerhalfheight{\the\pgf@ya}% + \addtosavedmacro\innerhalfheight% + % + % Take into account the outer sep. + % + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + % + \edef\halfwidth{\the\pgf@x}% + \edef\halfheight{\the\pgf@y}% + \addtosavedmacro\halfwidth% + \addtosavedmacro\halfheight% +}% + +\def\pgf@lib@sh@logicgate@IEC@inputanchor#1{% + \dimensions% + \centerpoint% + \advance\pgf@x-\halfwidth% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-#1\endcsname% + \advance\pgf@x-\invertedradius% + \advance\pgf@x-\outerinvertedradius% + \fi% + % + \pgfutil@tempdima\halfheight% + \multiply\pgfutil@tempdima2\relax% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \multiply\pgfutil@tempdima#1\relax% + \advance\pgf@y\halfheight% + \advance\pgf@y-\pgfutil@tempdima% +}% + + + +% Shape and gate IEC +% +\pgfdeclareshape{and gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@and gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@and gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@and gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An and gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{and}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \dimensions% + \midpoint% + \advance\pgf@x-\halfwidth}% + \anchor{mid east}{% + \dimensions% + \midpoint% + \advance\pgf@x\halfwidth}% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \dimensions% + \basepoint% + \advance\pgf@x-\halfwidth}% + \anchor{base east}{% + \dimensions% + \basepoint% + \advance\pgf@x\halfwidth}% + \anchor{north}{\dimensions\centerpoint\advance\pgf@y\halfheight}% + \anchor{south}{\dimensions\centerpoint\advance\pgf@y-\halfheight}% + \anchor{east}{\dimensions\centerpoint\advance\pgf@x\halfwidth}% + \anchor{west}{\dimensions\centerpoint\advance\pgf@x-\halfwidth}% + \anchor{north east}{\dimensions\centerpoint\advance\pgf@x\halfwidth\advance\pgf@y\halfheight}% + \anchor{north west}{\dimensions\centerpoint\advance\pgf@x-\halfwidth\advance\pgf@y\halfheight}% + \anchor{south east}{\dimensions\centerpoint\advance\pgf@x\halfwidth\advance\pgf@y-\halfheight}% + \anchor{south west}{\dimensions\centerpoint\advance\pgf@x-\halfwidth\advance\pgf@y-\halfheight}% + \anchor{output}{\dimensions\centerpoint\advance\pgf@x\halfwidth}% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \pgfmathaddtolength\pgf@xc{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@yc{-\pgfkeysvalueof{/pgf/outer xsep}}% + {% + \pgftransformshift{\centerpoint}% + \pgfpathrectangle{\pgfqpoint{-\pgf@xc}{-\pgf@yc}}% + {% + \pgf@xc2.0\pgf@xc% + \pgf@yc2.0\pgf@yc% + \pgfqpoint{\pgf@xc}{\pgf@yc}% + }% + \pgfpathclose% + % + % Draw inputs. + % + \pgf@xc-\halfwidth% + \advance\pgf@xc-\invertedradius% + \pgf@yc\halfheight% + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{and}}% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \dimensions% + \pgfpointadd{\centerpoint}{\pgfpointborderrectangle{\externalpoint}{\pgfqpoint{\halfwidth}{\halfheight}}}% + }% +}% + + + + + +% Shape nand gate IEC +% +\pgfdeclareshape{nand gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@nand gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@nand gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@nand gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A nand gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{nand}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \anchor{output}{% + \csname pgf@anchor@and gate IEC@east\endcsname% + \advance\pgf@x\invertedradius% + \advance\pgf@x\outerinvertedradius% + }% + \backgroundpath{% + \csname pgf@sh@bg@and gate IEC\endcsname% + \pgfpathcircle{% + \centerpoint% + \advance\pgf@x\halfwidth% + \advance\pgf@x\invertedradius% + }{+\invertedradius}% + }% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{nand}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + + +% Shape or gate IEC +% +\pgfdeclareshape{or gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@or gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@or gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@or gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An or gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{or}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=and gate IEC]{output}% + \inheritbackgroundpath[from=and gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{or}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + + +% Shape nor gate IEC +% +\pgfdeclareshape{nor gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@nor gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@nor gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@nor gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A nor gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{nor}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=nand gate IEC]{output}%% + \inheritbackgroundpath[from=nand gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{nor}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + + +% Shape xor gate IEC +% +\pgfdeclareshape{xor gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@xor gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{2}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@xor gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@xor gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An xor gate must have two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{xor}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=and gate IEC]{output}% + \inheritbackgroundpath[from=and gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{xor}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + +% Shape xnor gate IEC +% + +\pgfdeclareshape{xnor gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@xnor gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@xnor gate IEC@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@xnor gate IEC@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@IEC@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A xnor gate must have two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{xnor}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=nand gate IEC]{output}% + \inheritbackgroundpath[from=nand gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{xnor}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + +% Shape buffer gate IEC +% +\pgfdeclareshape{buffer gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@buffer gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1}% Maximum 1 input. + % + \expandafter\gdef\csname pgf@anchor@buffer gate IEC@input\endcsname{% + \pgf@lib@sh@logicgate@IEC@inputanchor{1}% + }% + \ifnum\pgf@lib@sh@logicgate@numinputs=0\relax% + \pgferror{A buffer gate must have one inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{xor}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=and gate IEC]{output}% + \inheritbackgroundpath[from=and gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{buffer}}% + \inheritanchorborder[from=and gate IEC]% +}% + + + + + +% Shape not gate IEC +% +\pgfdeclareshape{not gate IEC}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@not gate IEC\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1}% + % + \pgfutil@ifundefined{pgf@anchor@not gate IEC@input}{% + \expandafter\gdef\csname pgf@anchor@not gate IEC@input\endcsname{% + \pgf@lib@sh@logicgate@IEC@inputanchor{1}% + }}{}% + \ifnum\pgf@lib@sh@logicgate@numinputs=0\relax% + \pgferror{A not gate must have one input}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{% + \pgf@lib@sh@logicgates@dimensions@IEC{not}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=and gate IEC]{center}% + \inheritanchor[from=and gate IEC]{mid}% + \inheritanchor[from=and gate IEC]{mid west}% + \inheritanchor[from=and gate IEC]{mid east}% + \inheritanchor[from=and gate IEC]{base}% + \inheritanchor[from=and gate IEC]{base west}% + \inheritanchor[from=and gate IEC]{base east}% + \inheritanchor[from=and gate IEC]{north}% + \inheritanchor[from=and gate IEC]{south}% + \inheritanchor[from=and gate IEC]{east}% + \inheritanchor[from=and gate IEC]{west}% + \inheritanchor[from=and gate IEC]{north east}% + \inheritanchor[from=and gate IEC]{north west}% + \inheritanchor[from=and gate IEC]{south east}% + \inheritanchor[from=and gate IEC]{south west}% + \inheritanchor[from=nand gate IEC]{output}% + \inheritbackgroundpath[from=nand gate IEC]% + \foregroundpath{\pgf@lib@sh@logicgates@IEC@foregroundpath{not}}% + \inheritanchorborder[from=and gate IEC]% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.US.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.US.code.tex new file mode 100644 index 0000000000..3f0d668ca0 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.US.code.tex @@ -0,0 +1,2525 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{shapes.gates.logic}% + + +\newif\ifpgfgateanchorsuseboundingrectangle% + + +% Keys for US/CDH logic gates. +% +\pgfkeys{ + /pgf/logic gate anchors use bounding box/.is if=pgfgateanchorsuseboundingrectangle,% +}% + +% An internal macro for calculating internal dimensions of +% the US + CDH gates (excluding and gate US and nand gate US). +% +\def\pgf@lib@sh@logicgates@dimensions@orUS{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + % Adjust the height for the number of inputs. + % + \c@pgf@counta\pgf@lib@sh@logicgate@numinputs% + \advance\c@pgf@counta1\relax% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@ya\pgflinewidth% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/logic gate input sep}}% + \pgf@yb.5\pgf@yb% + \ifdim\pgf@ya<\pgf@yb% + \pgf@ya\pgf@yb% + \fi% + \multiply\pgf@ya\c@pgf@counta% + \ifdim\pgf@y<\pgf@ya% + \pgf@y\pgf@ya% + \fi% + % + \ifdim\pgf@x>\pgf@y% + \pgf@y\pgf@x% + \else% + \pgf@x\pgf@y% + \fi% + % + % Adjust for minimum height and width. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \pgf@xb\pgf@x% + \advance\pgf@xb1.732051\pgf@y% 2y*cos(30) + \ifdim\pgf@xb<\pgf@xa% + \pgf@xb\pgf@xa% + \pgf@x0.366025\pgf@xb% xb / (1 + 2*cos(30)) + \fi% + % + \ifdim\pgf@x>\pgf@y% + \pgf@y\pgf@x% + \else% + \pgf@x\pgf@y% + \fi% + \edef\halfside{\the\pgf@x}% + \addtosavedmacro\halfside% + % + % Take into account the outer sep. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\outerxsep{\the\pgf@xa}% + \edef\outerysep{\the\pgf@ya}% + \addtosavedmacro\outerxsep% + \addtosavedmacro\outerysep% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + % + \edef\halfwidth{\the\pgf@x}% + \edef\halfheight{\the\pgf@y}% + \addtosavedmacro\halfwidth% + \addtosavedmacro\halfheight% + % + \pgfextract@process\tipanchor{% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y-\pgf@ya% + \pgf@x-.16666\pgf@x% + \pgf@yb2.0\pgf@y% + \advance\pgf@x.866025\pgf@yb% + \advance\pgf@x1.154701\pgf@xa% + \pgf@y0pt% + }% + \addtosavedmacro\tipanchor% +}% + + +% An internal macro for calculating internal dimensions of +% the and gate US and nand gate US. +% +\def\pgf@lib@sh@logicgates@dimensions@andUS{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + % Adjust the height for the number of inputs. + % + \c@pgf@counta\pgf@lib@sh@logicgate@numinputs% + \advance\c@pgf@counta1\relax% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@ya\pgflinewidth% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/logic gate input sep}}% + \pgf@yb.5\pgf@yb% + \ifdim\pgf@ya<\pgf@yb% + \pgf@ya\pgf@yb% + \fi% + \multiply\pgf@ya\c@pgf@counta% + \ifdim\pgf@y<\pgf@ya% + \pgf@y\pgf@ya% + \fi% + % + \ifdim\pgf@x>\pgf@y% + \pgf@y\pgf@x% + \else% + \pgf@x\pgf@y% + \fi% + % + % Adjust for minimum height and width. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \pgf@xb2.5\pgf@x% + \ifdim\pgf@xb<\pgf@xa% + \pgf@xb\pgf@xa% + \pgf@x0.4\pgf@xb% + \fi% + % + \ifdim\pgf@x>\pgf@y% + \pgf@y\pgf@x% + \else% + \pgf@x\pgf@y% + \fi% + \edef\halfside{\the\pgf@x}% + \addtosavedmacro\halfside% + % + % Take into account the outer sep. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\outerxsep{\the\pgf@xa}% + \edef\outerysep{\the\pgf@ya}% + \addtosavedmacro\outerxsep% + \addtosavedmacro\outerysep% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + % + \edef\halfwidth{\the\pgf@x}% + \edef\halfheight{\the\pgf@y}% + \addtosavedmacro\halfwidth% + \addtosavedmacro\halfheight% + % +}% + + +% Internal macro for calculation input anchors. Used by +% both and gates and nand gates, and also the not gate and buffer. +% +\def\pgf@lib@sh@logicgate@AND@inputanchor#1{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-.166666\pgf@xa% + \advance\pgf@x-\halfwidth% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-#1\endcsname% + \advance\pgf@x-\invertedradius% + \advance\pgf@x-\outerinvertedradius% + \fi% + % + \pgfutil@tempdima\halfside% + \multiply\pgfutil@tempdima2\relax% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \multiply\pgfutil@tempdima#1\relax% + \advance\pgf@y\halfside% + \advance\pgf@y-\pgfutil@tempdima% +}% + + + + +% Shape and gate US +% +\pgfdeclareshape{and gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@and gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@and gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@and gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@AND@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An and gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@andUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \csname pgf@anchor@and gate US@east\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{mid west}{% + \csname pgf@anchor@and gate US@west\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \csname pgf@anchor@and gate US@east\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{base west}{% + \csname pgf@anchor@and gate US@west\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{east}{% + \dimensions% + \pgf@xa\halfwidth% + \pgf@xb\pgf@xa% + \advance\pgf@xb-\outerxsep% + \centerpoint% + \advance\pgf@x.333333\pgf@xb% + \advance\pgf@x\pgf@xa% + }% + \anchor{output}{\csname pgf@anchor@and gate US@east\endcsname}% + \anchor{north east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@nand gate US@east\endcsname% + \advance\pgf@y\halfheight% + \else + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\pgf@xa% + \advance\pgf@xb-\outerxsep% + \centerpoint% + \advance\pgf@x.333333\pgf@xb% + \advance\pgf@x.707106\pgf@xa% + \advance\pgf@y.707106\pgf@ya% + \fi% + }% + \anchor{south east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@nand gate US@east\endcsname% + \advance\pgf@y-\halfheight% + \else + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\pgf@xa% + \advance\pgf@xb-\outerxsep% + \centerpoint% + \advance\pgf@x.333333\pgf@xb% + \advance\pgf@x.707106\pgf@xa% + \advance\pgf@y-.707106\pgf@ya% + \fi% + }% + \anchor{north}{% + \dimensions% + \centerpoint% + \advance\pgf@y\halfheight% + }% + \anchor{south}{% + \dimensions% + \centerpoint% + \advance\pgf@y-\halfheight% + }% + \anchor{south west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@y-\halfheight% + }% + \anchor{north west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@y\halfheight% + }% + \anchor{west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + \pgf@xb.333333\pgf@xc% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yc}}% + {% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{\pgf@yc}}% + \pgfpathclose% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-1.16666\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \pgfextract@process\externalpoint{\pgfpointadd{\centerpoint}{\externalpoint}}% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \dimensions% + \pgf@xb\halfside% + \pgf@xc1.66666\pgf@xb% + \advance\pgf@xc\outerxsep% + \pgf@yc\halfheight% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@and gate US@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\centerpoint}{\centerpoint\advance\pgf@x.333333\pgf@xb\advance\pgf@y\pgf@yc}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@x.333333\pgf@xb% + }% + {0}{90}{+\halfwidth and +\halfheight}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\centerpoint\advance\pgf@x.333333\pgf@xb\advance\pgf@y\pgf@yc}% + {\centerpoint\advance\pgf@x-\pgf@xc\advance\pgf@y\pgf@yc}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\centerpoint\advance\pgf@x.333333\pgf@xb\advance\pgf@y-\pgf@yc}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@x.333333\pgf@xb% + }% + {270}{360}{+\halfwidth and +\halfheight}% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@and gate US@south west\endcsname}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\centerpoint\advance\pgf@x.333333\pgf@xb\advance\pgf@y-\pgf@yc}% + {\csname pgf@anchor@and gate US@south west\endcsname}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@and gate US@north west\endcsname}% + {\csname pgf@anchor@and gate US@south west\endcsname}% + \fi% + \fi% + \fi% + }% +}% + + + + + +% Shape nand gate US +% +\pgfdeclareshape{nand gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@nand gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@nand gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@nand gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@AND@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A nand gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@andUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \inheritanchor[from=and gate US]{mid}% + \inheritanchor[from=and gate US]{mid east}% + \inheritanchor[from=and gate US]{mid west}% + \inheritanchor[from=and gate US]{base}% + \inheritanchor[from=and gate US]{base east}% + \inheritanchor[from=and gate US]{base west}% + \anchor{output}{% + \dimensions + \pgfpointadd{\centerpoint}{% + \pgf@xa\halfside% + \pgf@x1.33333\pgf@xa% + \advance\pgf@x\invertedradius% + \advance\pgf@x\outerinvertedradius% + \advance\pgf@x\outerxsep% + \pgf@y0pt% + }% + }% + \inheritanchor[from=and gate US]{east}% + \inheritanchor[from=and gate US]{north east}% + \inheritanchor[from=and gate US]{south east}% + \inheritanchor[from=and gate US]{north}% + \inheritanchor[from=and gate US]{south}% + \inheritanchor[from=and gate US]{south west}% + \inheritanchor[from=and gate US]{north west}% + \inheritanchor[from=and gate US]{west}% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + \pgf@xb.333333\pgf@xc% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yc}}% + {% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{\pgf@yc}}% + \pgfpathclose% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-1.166666\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + % + % Draw the output inverter. + % + {% + \pgfpathcircle{% + \pgf@x1.33333\pgf@xc% + \advance\pgf@x\outerinvertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + }% + }% + \inheritanchorborder[from=and gate US]% +}% + + +% Internal macro for calculation input anchors. Used by +% or, nor xnor gates (US). +% +\def\pgf@lib@sh@logicgate@OR@inputanchor#1{% + \dimensions% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + % + \pgfutil@tempdima\halfside% + \multiply\pgfutil@tempdima2\relax% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \multiply\pgfutil@tempdima#1\relax% + \pgf@yc\pgf@ya% + \advance\pgf@yc-\pgfutil@tempdima% + % + \pgf@xb\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@xc-1.166666\pgf@ya% + \advance\pgf@xc-.866025\pgf@xb% + \advance\pgf@xc\pgfmathresult\pgf@yb% + \advance\pgf@xc\halflinewidth% + \advance\pgf@xc-\outerxsep% + % + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-#1\endcsname% + \advance\pgf@xc-\invertedradius% + \advance\pgf@xc-\outerinvertedradius% + \fi% + % + \centerpoint% + \advance\pgf@x\pgf@xc% + \advance\pgf@y\pgf@yc% +}% + + +% Shape or gate US +% +\pgfdeclareshape{or gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@or gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@or gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@or gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@OR@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An or gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \csname pgf@anchor@or gate US@east\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{mid west}{% + \csname pgf@anchor@or gate US@north west\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \csname pgf@anchor@or gate US@east\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{base west}{% + \csname pgf@anchor@or gate US@north west\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{east}{% + \dimensions% + \pgfpointadd{\centerpoint}{\tipanchor}% + }% + \anchor{output}{\csname pgf@anchor@or gate US@east\endcsname}% + \anchor{north east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\halfheight% + \else% + \centerpoint% + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\halfside% + \advance\pgf@x-.166666\pgf@xb% + \advance\pgf@xa\pgf@xb% + \advance\pgf@x.5\pgf@xa% + \advance\pgf@y-\pgf@xb% + \advance\pgf@ya\pgf@xb% + \advance\pgf@y.866025\pgf@ya% + \fi% + }% + \anchor{south east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y-\halfheight% + \else + \centerpoint% + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\halfside% + \advance\pgf@x-.166666\pgf@xb% + \advance\pgf@xa\pgf@xb% + \advance\pgf@x.5\pgf@xa% + \advance\pgf@y\pgf@xb% + \advance\pgf@ya\pgf@xb% + \advance\pgf@y-.866025\pgf@ya% + \fi% + }% + \anchor{north}{% + \dimensions% + \centerpoint% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y\halfheight% + \else% + \pgf@ya\halfheight% + \advance\pgf@y.993043\pgf@ya% + \fi% + }% + \anchor{south}{% + \dimensions% + \centerpoint% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y-\halfheight% + \else% + \pgf@ya\halfheight% + \advance\pgf@y-.993043\pgf@ya% + \fi% + }% + \anchor{south west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \pgf@xa\outerxsep% + \advance\pgf@x-1.732050\pgf@xa% + \advance\pgf@y-\halfheight% + }% + \anchor{north west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \pgf@xa\outerxsep% + \advance\pgf@x-1.732050\pgf@xa% + \advance\pgf@y\halfheight% + }% + \anchor{west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \else% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@x0.267949\pgf@xa% + \fi% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \pgfpatharc{-30}{0}{+\pgf@yc}% + } + {% + \pgf@yc2.0\pgf@yc% + \pgfpatharc{0}{30}{+\pgf@yc}% + }% + \pgfpathclose% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + \pgf@xa\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \let\sineangle\pgfmathresult% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@x-1.166666\pgf@ya% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x\pgfmathresult\pgf@yb% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \pgfextract@process\externalpoint{\pgfpointadd{\centerpoint}{\externalpoint}}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \dimensions% + \pgf@xc\halfside% + % + \pgf@xc-.166666\pgf@xc% + \ifdim\pgf@xa<\pgf@xc% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@or gate US@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@or gate US@north\endcsname% + }% + {\csname pgf@anchor@or gate US@north west\endcsname}% + \else% + \pgfmathsubtract@{360}{\pgfmathresult}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@or gate US@south\endcsname% + }% + {\csname pgf@anchor@or gate US@south west\endcsname}% + \else% + \ifdim\pgf@ya>\pgf@yb% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \advance\pgf@yc-\outerxsep% + \pgfextract@process\point{% + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.166666\pgf@xa% + \pgf@xa2.0\pgf@xa% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x-\outerxsep% + }% + {0}{90}{+\pgf@yc}% + }% + \else% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \advance\pgf@yc-\outerxsep% + \pgfextract@process\point{% + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.166666\pgf@xa% + \pgf@xa2.0\pgf@xa% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x-\outerxsep% + }% + {270}{360}{+\pgf@yc}% + }% + \fi% + \fi% + \fi% + \else% + \ifdim\pgf@y=0pt\relax% + \csname pgf@anchor@and gate US@east\endcsname% + \else% + \pgf@xc\halfwidth% + \advance\pgf@xc\halfside% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \pgf@xb\halfside% + \pgf@xb-.166666\pgf@xb% + \ifdim\pgf@ya<0pt% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y\halfside% + \advance\pgf@x\pgf@xb% + }% + {270}{330}{+\pgf@yc}% + \else% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y-\halfside% + \advance\pgf@x\pgf@xb% + }% + {30}{90}{+\pgf@xc and +\pgf@yc}% + \fi% + \fi% + \fi% + }% +}% + + + + +% Shape nor gate US +% +\pgfdeclareshape{nor gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@nor gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@nor gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@nor gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@OR@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A nor gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \inheritanchor[from=or gate US]{center}% + \inheritanchor[from=or gate US]{mid}% + \inheritanchor[from=or gate US]{mid east}% + \inheritanchor[from=or gate US]{mid west}% + \inheritanchor[from=or gate US]{base}% + \inheritanchor[from=or gate US]{base east}% + \inheritanchor[from=or gate US]{base west}% + \inheritanchor[from=or gate US]{east}% + \inheritanchor[from=or gate US]{north east}% + \inheritanchor[from=or gate US]{south east}% + \inheritanchor[from=or gate US]{north}% + \inheritanchor[from=or gate US]{south}% + \inheritanchor[from=or gate US]{south west}% + \inheritanchor[from=or gate US]{north west}% + \inheritanchor[from=or gate US]{west}% + \anchor{output}{% + \dimensions% + \centerpoint% + \pgf@xc\halfside% + \pgf@yc\pgf@xc% + \advance\pgf@x-.166666\pgf@xc% + \pgf@yc2.0\pgf@yc% + \advance\pgf@x.866025\pgf@yc% + \advance\pgf@x\outerinvertedradius% + \advance\pgf@x\invertedradius% + \advance\pgf@x\outerxsep% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \pgfpatharc{-30}{0}{+\pgf@yc}% + } + {% + \pgf@yc2.0\pgf@yc% + \pgfpatharc{0}{30}{+\pgf@yc}% + }% + \pgfpathclose% + % Draw the output inverter. + % + {% + \pgfpathcircle{% + \pgf@x-.166666\pgf@xc% + \pgf@yc2.0\pgf@yc% + \advance\pgf@x.866025\pgf@yc% + \advance\pgf@x\outerinvertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + \pgf@xa\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \let\sineangle\pgfmathresult% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@x-1.166666\pgf@ya% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x\pgfmathresult\pgf@yb% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \inheritanchorborder[from=or gate US]% +}% + + + +% Internal macro for calculation input anchors. Used by +% xor and xnor gates (US). +% +\def\pgf@lib@sh@logicgate@XOR@inputanchor#1{% + \dimensions% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + % + \pgfutil@tempdima\halfside% + \multiply\pgfutil@tempdima2\relax% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \multiply\pgfutil@tempdima#1\relax% + \pgf@yc\pgf@ya% + \advance\pgf@yc-\pgfutil@tempdima% + % + \pgf@xb\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@xc-1.166666\pgf@ya% + \advance\pgf@xc-.866025\pgf@xb% + \advance\pgf@xc\pgfmathresult\pgf@yb% + \advance\pgf@xc\halflinewidth% + \advance\pgf@xc-\outerxsep% + % + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-#1\endcsname% + \advance\pgf@xc-\invertedradius% + \advance\pgf@xc-\outerinvertedradius% + \fi% + % + \centerpoint% + \advance\pgf@x\pgf@xc% + \advance\pgf@y\pgf@yc% + \pgf@xa\halfside% + \advance\pgf@x-.333333\pgf@xa% +}% + + + + + +% Shape xor gate US +% +\pgfdeclareshape{xor gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@xor gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{2}% + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@xor gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@xor gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@XOR@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An xor gate must have at two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \inheritanchor[from=or gate US]{mid east}% + \anchor{mid west}{% + \csname pgf@anchor@xor gate US@north west\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{base}{\basepoint}% + \inheritanchor[from=or gate US]{base east}% + \anchor{base west}{% + \csname pgf@anchor@xor gate US@north west\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \inheritanchor[from=or gate US]{base}% + \inheritanchor[from=or gate US]{output}% + \inheritanchor[from=or gate US]{east}% + \inheritanchor[from=or gate US]{north east}% + \inheritanchor[from=or gate US]{south east}% + \inheritanchor[from=or gate US]{north}% + \inheritanchor[from=or gate US]{south}% + \anchor{south west}{% + \dimensions% + \pgf@xa\halfside% + \pgf@xa-3.232051\pgf@xa% (7/6 + 2*cos(30) + 1/3) * x + \pgf@xb\halfside% + \pgf@xb2.0\pgf@xb% + \advance\pgf@xb-\halflinewidth% + \advance\pgf@xa.866025\pgf@xb% + \pgf@ya.5\pgf@xb% + \centerpoint% + \advance\pgf@x\pgf@xa% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y-\halfheight% + \else% + \advance\pgf@y-\pgf@ya% + \fi% + }% + \anchor{north west}{% + \dimensions% + \pgf@xa\halfside% + \pgf@xa-3.232051\pgf@xa% (7/6 + 2*cos(30) + 1/3) * x + \pgf@xb\halfside% + \pgf@xb2.0\pgf@xb% + \advance\pgf@xb-\halflinewidth% + \advance\pgf@xa.866025\pgf@xb% + \pgf@ya.5\pgf@xb% + \centerpoint% + \advance\pgf@x\pgf@xa% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y\halfheight% + \else% + \advance\pgf@y\pgf@ya% + \fi% + }% + \anchor{west}{% + \dimensions% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + % + \pgf@xb\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{0}{\pgfmath@tonumber{\pgf@yb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@xc-1.166666\pgf@ya% + \advance\pgf@xc-.866025\pgf@xb% + \advance\pgf@xc\pgfmathresult\pgf@yb% + \advance\pgf@xc\halflinewidth% + \advance\pgf@xc-\outerxsep% + % + \centerpoint% + \advance\pgf@x\pgf@xc% + \pgf@xa\halfside% + \advance\pgf@x-.333333\pgf@xa% + \ifpgfgateanchorsuseboundingrectangle% + \pgf@xa2.0\pgf@xa% + \advance\pgf@x-0.133974\pgf@xa% + \fi% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + {% + \pgf@yc2.66666\pgf@yc% + \pgfpatharc{-22}{0}{+1.166666\pgf@yc and +\pgf@yc}% + } + {% + \pgf@yc2.66666\pgf@yc% + \pgfpatharc{0}{22}{+1.166666\pgf@yc and +\pgf@yc}% + }% + \pgfpathclose% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + \pgf@xa\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@x-1.5\pgf@ya% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x\pgfmathresult\pgf@yb% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + % + % Now, some fooling around to stop the `tail' being filled. + % Technically it still is, but it isn't visible. + % + \pgf@xc\halfside% + \pgf@yc\halfside% + \pgfpathmoveto{\pgfqpoint{-1.5\pgf@xc}{-\pgf@yc}}% + \pgf@yc2.0\pgf@yc% + \pgfmathloop% + \ifnum\pgfmathcounter<61\relax% + {% + \pgfextract@process\point{% + \pgfpointadd{% + \pgf@x\halfside% + \pgf@x-3.232051\pgf@x% (7/6 + 2*cos(30) + 1/3) * x + \pgf@y0pt% + }{% + \pgfpointpolar{\pgfmathcounter-30}{+\pgf@yc}% + }% + }% + \pgfpathlineto{\point}% + \pgfpathmoveto{\point}% + } + \repeatpgfmathloop% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \pgfextract@process\externalpoint{\pgfpointadd{\centerpoint}{\externalpoint}}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \dimensions% + \pgf@xc\halfside% + % + \pgf@xc-.166666\pgf@xc% + \ifdim\pgf@xa<\pgf@xc% + \pgfmathanglebetweenpoints{\centerpoint}% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@xor gate US@north west\endcsname% + }% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@xor gate US@north\endcsname% + }% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@xor gate US@north west\endcsname% + }% + \else% + \pgfmathsubtract@{360}{\pgfmathresult}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@xor gate US@south\endcsname% + }% + {% + \pgfgateanchorsuseboundingrectangletrue% + \csname pgf@anchor@xor gate US@south west\endcsname% + }% + \else% + \ifdim\pgf@ya>\pgf@yb% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \advance\pgf@yc-\outerxsep% + \pgf@process{% + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.166666\pgf@xa% + \pgf@xa2.0\pgf@xa% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@x-.166666\pgf@xa% + }% + {0}{90}{+\pgf@yc}% + }% + \else% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \advance\pgf@yc-\outerxsep% + \pgf@process{% + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.166666\pgf@xa% + \pgf@xa2.0\pgf@xa% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@x-.166666\pgf@xa% + }% + {270}{360}{+\pgf@yc}% + }% + \fi% + \fi% + \fi% + \else% + \ifdim\pgf@y=0pt\relax% + \csname pgf@anchor@and gate US@east\endcsname% + \else% + \pgf@xc\halfwidth% + \advance\pgf@xc\halfside% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \pgf@xb\halfside% + \pgf@xb-.166666\pgf@xb% + \ifdim\pgf@ya<0pt% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y\halfside% + \advance\pgf@x\pgf@xb% + }% + {270}{330}{+\pgf@yc}% + \else% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y-\halfside% + \advance\pgf@x\pgf@xb% + }% + {30}{90}{+\pgf@xc and +\pgf@yc}% + \fi% + \fi% + \fi% + }% +}% + + + + +% Shape xnor gate US +% +\pgfdeclareshape{xnor gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@xnor gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{2}% + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@xnor gate US@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@xnor gate US@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@XOR@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An xnor gate must have two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \inheritanchor[from=xor gate US]{mid east}% + \inheritanchor[from=xor gate US]{mid west}% + \anchor{base}{\basepoint}%% + \inheritanchor[from=xor gate US]{base east}% + \inheritanchor[from=xor gate US]{base west}% + \inheritanchor[from=xor gate US]{base}% + \inheritanchor[from=nor gate US]{output}% + \inheritanchor[from=xor gate US]{east}% + \inheritanchor[from=xor gate US]{north east}% + \inheritanchor[from=xor gate US]{south east}% + \inheritanchor[from=xor gate US]{north}% + \inheritanchor[from=xor gate US]{south}% + \inheritanchor[from=xor gate US]{south west}% + \inheritanchor[from=xor gate US]{north west}% + \inheritanchor[from=xor gate US]{west}% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + {% + \pgf@yc2.66666\pgf@yc% + \pgfpatharc{-22}{0}{+1.166666\pgf@yc and +\pgf@yc}% + } + {% + \pgf@yc2.66666\pgf@yc% + \pgfpatharc{0}{22}{+1.166666\pgf@yc and +\pgf@yc}% + }% + \pgfpathclose% + % + % Draw the output inverter. + % + {% + \pgfpathcircle{% + \pgf@x-.166666\pgf@xc% + \pgf@yc2.0\pgf@yc% + \advance\pgf@x.866025\pgf@yc% + \advance\pgf@x\outerinvertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@ya\halfside% + \pgf@yb2.0\pgf@ya% + \pgf@xa\pgf@yb% + \advance\pgf@yb-\halflinewidth% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@yb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + % + \pgf@x-1.5\pgf@ya% + \advance\pgf@x-.866025\pgf@xa% + \advance\pgf@x\pgfmathresult\pgf@yb% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + % + % Now, some fooling around to stop the `tail' being filled. + % + \pgf@xc\halfside% + \pgf@yc\halfside% + \pgfpathmoveto{\pgfqpoint{-1.5\pgf@xc}{-\pgf@yc}}% + \pgf@yc2.0\pgf@yc% + \pgfmathloop% + \ifnum\pgfmathcounter<61\relax% + {% + \pgfextract@process\point{% + \pgfpointadd{% + \pgf@x\halfside% + \pgf@x-3.232051\pgf@x% (7/6 + 2*cos(30) + 1/3) * x + \pgf@y0pt% + }{% + \pgfpointpolar{\pgfmathcounter-30}{+\pgf@yc}% + }% + }% + \pgfpathlineto{\point}% + \pgfpathmoveto{\point}% + } + \repeatpgfmathloop% + }% + }% + \inheritanchorborder[from=xor gate US]% +}% + + + + + + +% Shape not gate US +% +\pgfdeclareshape{not gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@not gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1}% + \ifnum\pgf@lib@sh@logicgate@numinputs=0\relax% + \pgferror{A not gate must have one input}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \midpoint% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@not gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + }% + \anchor{mid west}{% + \dimensions% + \pgf@xc\halfside% + \pgf@xc-.833333\pgf@xc% + \advance\pgf@xc-\outerxsep% + \midpoint% + \advance\pgf@x\pgf@xc% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \basepoint% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@not gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + }% + \anchor{base west}{% + \dimensions% + \pgf@xc\halfside% + \pgf@xc-.833333\pgf@xc% + \advance\pgf@xc-\outerxsep% + \basepoint% + \advance\pgf@x\pgf@xc% + }% + \inheritanchor[from=and gate US]{base}% + \anchor{output}{% + \dimensions% + \pgf@xc\halfside% + \centerpoint% + \advance\pgf@x-.166666\pgf@xc% + \pgf@xc2.0\pgf@xc% + \advance\pgf@x.866025\pgf@xc% + \advance\pgf@x\invertedradius% + \advance\pgf@x\outerinvertedradius% + \advance\pgf@x\outerxsep% + }% + \anchor{east}{% + \dimensions% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + }% + \anchor{north}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@north west\endcsname% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@y1pt}% + {\csname pgf@anchor@not gate US@north west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{south}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@south west\endcsname% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@y-1pt}% + {\csname pgf@anchor@not gate US@south west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{south east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@south west\endcsname% + \pgf@ya\pgf@y% + \pgf@process{% + \dimensions% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + }% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@x1pt\advance\pgf@y-1pt}% + {\csname pgf@anchor@not gate US@south west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{north east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@north west\endcsname% + \pgf@ya\pgf@y% + \pgf@process{% + \dimensions% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + }% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@x1pt\advance\pgf@y1pt}% + {\csname pgf@anchor@not gate US@north west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{south west}{% + \dimensions% + \pgf@xa\halfside% + \centerpoint% + \advance\pgf@x-.833333\pgf@xa + \advance\pgf@x-\outerxsep% + \advance\pgf@y-1.166666\pgf@xa% + \pgf@ya\outerysep% + \advance\pgf@y-1.565\pgf@ya% Selected by trial and error. + }% + \anchor{north west}{% + \dimensions% + \pgf@xa\halfside% + \centerpoint% + \advance\pgf@x-.833333\pgf@xa + \advance\pgf@x-\outerxsep% + \advance\pgf@y1.166666\pgf@xa% + \pgf@ya\outerysep% + \advance\pgf@y1.565\pgf@ya% Selected by trial and error. + }% + \anchor{input}{% + \dimensions% + \pgf@lib@sh@logicgate@AND@inputanchor{1}% + \pgf@xc\halfside% + \advance\pgf@x.333333\pgf@xc% + }% + \anchor{west}{% + \dimensions% + \pgf@xc\halfside% + \pgf@xc-.833333\pgf@xc% + \advance\pgf@xc-\outerxsep% + \centerpoint% + \advance\pgf@x\pgf@xc% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\tipanchor}% + \pgfpathlineto{\pgfqpoint{-.833333\pgf@xc}{1.166666\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-.833333\pgf@xc}{-1.166666\pgf@yc}}% + \pgfpathlineto{\tipanchor}% + % + % Draw the output inverter. + % + {% + \pgfpathcircle{% + \pgf@x-.166666\pgf@xc% + \pgf@yc2.0\pgf@yc% + \advance\pgf@x.866025\pgf@yc% + \advance\pgf@x\outerinvertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + % + % Draw the input. + % + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-1\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-.833333\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + \fi% + }% + }% + \anchorborder{% + \pgf@lib@gates@not@buffer@border{not gate US} + }% +}% + +\def\pgf@lib@gates@not@buffer@border#1{ + \pgfextract@process\externalpoint{}% + \pgfextract@process\externalpoint{\pgfpointadd{\centerpoint}{\externalpoint}}% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \ifx\pgfmathresult\pgf@lib@zero@text% + \csname pgf@anchor@#1@output\endcsname% + \else% + \ifx\pgfmathresult\pgf@lib@onehundredeighty@text% + \csname pgf@anchor@#1@input\endcsname% + \else% + \let\externalangle\pgfmathresult% + \dimensions% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@not gate US@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\csname pgf@anchor@not gate US@north west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@not gate US@south west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@not gate US@north west\endcsname}% + {\csname pgf@anchor@not gate US@south west\endcsname}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\csname pgf@anchor@not gate US@south west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + \fi% + \fi% + \fi% +}% + + +\def\pgf@lib@zero@text{0.0}% +\def\pgf@lib@onehundredeighty@text{180.0}% + + + + +% Shape buffer gate US. +% +\pgfdeclareshape{buffer gate US}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@buffer gate US\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1}% + \ifnum\pgf@lib@sh@logicgate@numinputs=0\relax% + \pgferror{A buffer gate must have one input}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\halflinewidth{% + \pgf@x.5\pgflinewidth% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \midpoint% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@buffer gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + }% + \anchor{mid west}{% + \dimensions% + \pgf@xc\halfside% + \pgf@xc-.833333\pgf@xc% + \advance\pgf@xc-\outerxsep% + \midpoint% + \advance\pgf@x\pgf@xc% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \basepoint% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@buffer gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + }% + \inheritanchor[from=not gate US]{base west}% + \inheritanchor[from=and gate US]{base}% + \anchor{output}{\csname pgf@anchor@buffer gate US@east\endcsname}% + \anchor{east}{% + \dimensions% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \anchor{north}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@north west\endcsname% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@y1pt}% + {\csname pgf@anchor@buffer gate US@north west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{south}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@south west\endcsname% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@y-1pt}% + {\csname pgf@anchor@not gate US@south west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \anchor{south east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@south west\endcsname% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@buffer gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@x1pt\advance\pgf@y-1pt}% + {\csname pgf@anchor@buffer gate US@south west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xc\outerxsep% + \advance\pgf@x2.350943\pgf@xc% + }% + }% + \fi% + }% + \anchor{north east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \csname pgf@anchor@not gate US@north west\endcsname% + \pgfutil@tempdima\pgf@y% + \csname pgf@anchor@buffer gate US@east\endcsname% + \pgf@y\pgfutil@tempdima% + \else% + \pgfpointintersectionoflines{\centerpoint}{\centerpoint\advance\pgf@x1pt\advance\pgf@y1pt}% + {\csname pgf@anchor@buffer gate US@north west\endcsname}% + {% + \pgfpointadd{\centerpoint}{% + \tipanchor% + \pgf@xa\outerxsep% + \advance\pgf@x2.350943\pgf@xa% + }% + }% + \fi% + }% + \inheritanchor[from=not gate US]{south west}% + \inheritanchor[from=not gate US]{north west}% + \inheritanchor[from=not gate US]{input}% + \inheritanchor[from=not gate US]{west}% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\tipanchor}% + \pgfpathlineto{\pgfqpoint{-.833333\pgf@xc}{1.166666\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-.833333\pgf@xc}{-1.166666\pgf@yc}}% + \pgfpathclose% + % + % Draw the input. + % + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-1\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-.833333\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + \fi% + }% + }% + \anchorborder{% + \pgf@lib@gates@not@buffer@border{buffer gate US} + }% +}% + + + + + +\pgfdeclareshape{and gate CDH}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@and gate CDH\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@and gate CDH@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@and gate CDH@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@AND@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{An and gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \csname pgf@anchor@and gate CDH@east\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{mid west}{% + \csname pgf@anchor@and gate CDH@west\endcsname% + \pgf@xa\pgf@x% + \midpoint% + \pgf@x\pgf@xa}% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \csname pgf@anchor@and gate CDH@east\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{base west}{% + \csname pgf@anchor@and gate CDH@west\endcsname% + \pgf@xa\pgf@x% + \basepoint% + \pgf@x\pgf@xa}% + \anchor{east}{% + \dimensions% + \pgfpointadd{\centerpoint}{\tipanchor}% + }% + \anchor{output}{\csname pgf@anchor@and gate CDH@east\endcsname}% + \anchor{north east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\halfheight% + \else% + \centerpoint% + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\halfside% + \advance\pgf@x-.166666\pgf@xb% + \advance\pgf@xa\pgf@xb% + \advance\pgf@x.5\pgf@xa% + \advance\pgf@y-\pgf@xb% + \advance\pgf@ya\pgf@xb% + \advance\pgf@y.866025\pgf@ya% + \fi% + }% + \anchor{south east}{% + \dimensions% + \ifpgfgateanchorsuseboundingrectangle% + \tipanchor% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y-\halfheight% + \else + \centerpoint% + \pgf@xa\halfwidth% + \pgf@ya\halfheight% + \pgf@xb\halfside% + \advance\pgf@x-.166666\pgf@xb% + \advance\pgf@xa\pgf@xb% + \advance\pgf@x.5\pgf@xa% + \advance\pgf@y\pgf@xb% + \advance\pgf@ya\pgf@xb% + \advance\pgf@y-.866025\pgf@ya% + \fi% + }% + \anchor{north}{% + \dimensions% + \centerpoint% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y\halfheight% + \else% + \pgf@ya\halfheight% + \advance\pgf@y.993043\pgf@ya% + \fi% + }% + \anchor{south}{% + \dimensions% + \centerpoint% + \ifpgfgateanchorsuseboundingrectangle% + \advance\pgf@y-\halfheight% + \else% + \pgf@ya\halfheight% + \advance\pgf@y-.993043\pgf@ya% + \fi% + }% + \anchor{south west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@y-\halfheight% + }% + \anchor{north west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + \advance\pgf@y\halfheight% + }% + \anchor{west}{% + \dimensions% + \centerpoint% + \pgf@xa\halfside% + \advance\pgf@x-1.16666\pgf@xa% + \advance\pgf@x-\outerxsep% + }% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{\pgf@yc}}% + \pgfpathclose% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-1.16666\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \dimensions% + \pgf@xb\halfside% + % + \pgf@xb-.166666\pgf@xb% + \ifdim\pgf@xa<\pgf@xb% + \pgfpointadd{\centerpoint}{% + \pgfpointborderrectangle{\externalpoint}{% + \pgf@xc\halfside% + \pgf@xc.166666\pgf@xc% + \advance\pgf@xc\halfwidth% + \pgfqpoint{\pgf@xc}{\halfheight}% + }% + }% + \else% + \ifdim\pgf@y=0pt\relax% + \csname pgf@anchor@and gate CDH@east\endcsname% + \else% + \pgfextract@process\externalpoint{\pgfpointadd{\centerpoint}{\externalpoint}}% + \pgf@xc\halfwidth% + \advance\pgf@xc\halfside% + \pgf@yc\halfheight% + \advance\pgf@yc\halfside% + \ifdim\pgf@ya<0pt% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y\halfside% + \advance\pgf@x\pgf@xb% + }% + {270}{330}{+\pgf@yc}% + \else% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \advance\pgf@y-\halfside% + \advance\pgf@x\pgf@xb% + }% + {30}{90}{+\pgf@xc and +\pgf@yc}% + \fi% + \fi% + \fi% + }% +}% + + +\pgfdeclareshape{nand gate CDH}{% + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@nand gate CDH\endcsname{% + \pgf@lib@sh@logicgate@parseinputs{1024}% Maximum 1024 (!) inputs. + % + \pgfmathloop% + \ifnum\pgfmathcounter>\pgf@lib@sh@logicgate@numinputs% + \else% + \pgfutil@ifundefined{pgf@anchor@nand gate CDH@input \pgfmathcounter}{% + \expandafter\xdef\csname pgf@anchor@nand gate CDH@input \pgfmathcounter\endcsname{% + \noexpand\pgf@lib@sh@logicgate@AND@inputanchor{\pgfmathcounter}% + }% + }{}% + \repeatpgfmathloop% + \ifnum\pgf@lib@sh@logicgate@numinputs<2\relax% + \pgferror{A nand gate must have at least two inputs}% + \fi% + }% + \savedmacro\numinputs{\let\numinputs\pgf@lib@sh@logicgate@numinputs}% + \saveddimen\invertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + }% + \saveddimen\outerinvertedradius{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/logic gate inverted radius}}% + \advance\pgf@x.5\pgflinewidth% + }% + \savedmacro\dimensions{\pgf@lib@sh@logicgates@dimensions@orUS}% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \inheritanchor[from=and gate CDH]{mid east}% + \inheritanchor[from=and gate CDH]{mid west}% + \anchor{base}{\basepoint}%% + \inheritanchor[from=and gate CDH]{base east}% + \inheritanchor[from=and gate CDH]{base west}% + \anchor{output}{% + \dimensions + \pgfpointadd{\centerpoint}{% + \pgf@xa\halfside% + \pgf@x-.166666\pgf@xa% + \pgf@xb2.0\pgf@xa% + \advance\pgf@x.866025\pgf@xb% + \advance\pgf@x\invertedradius% + \advance\pgf@x\outerinvertedradius% + \advance\pgf@x\outerxsep% + \pgf@y0pt% + }% + }% + \inheritanchor[from=and gate CDH]{east}% + \inheritanchor[from=and gate CDH]{north east}% + \inheritanchor[from=and gate CDH]{south east}% + \inheritanchor[from=and gate CDH]{north}% + \inheritanchor[from=and gate CDH]{south}% + \inheritanchor[from=and gate CDH]{south west}% + \inheritanchor[from=and gate CDH]{north west}% + \inheritanchor[from=and gate CDH]{west}% + \backgroundpath{% + \dimensions% + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + \advance\pgf@xc-\outerxsep% + \advance\pgf@yc-\outerysep% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-.16666\pgf@xc}{\pgf@yc}}% + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{90}{30}{\the\pgf@yc}% + }% + \pgf@marshal% + } + {% + \pgf@yc2.0\pgf@yc% + \edef\pgf@marshal{% + \noexpand\pgfpatharc{-30}{-90}{\the\pgf@yc}% + }% + \pgf@marshal% + } + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{-\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-1.16666\pgf@xc}{\pgf@yc}}% + \pgfpathclose% + % + % Draw the output inverter. + % + {% + \pgfpathcircle{% + \pgf@x-.166666\pgf@xc% + \pgf@yc2.0\pgf@yc% + \advance\pgf@x.866025\pgf@yc% + \advance\pgf@x\outerinvertedradius% + \pgf@y0pt% + }{+\invertedradius}% + }% + % + % Draw the inputs. + % + \pgfutil@tempdima2.0\pgf@yc% + \c@pgf@counta\numinputs% + \advance\c@pgf@counta1\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + \pgfmathloop% + \ifnum\pgfmathcounter>\numinputs% + \else% + \advance\pgf@yc-\pgfutil@tempdima% + \expandafter\ifx\expandafter\pgf@lib@sh@itext\csname input-\pgfmathcounter\endcsname% + {% + \pgfpathcircle{% + \pgf@xa\halfside% + \pgf@x-1.16666\pgf@xa% + \advance\pgf@x-.5\pgflinewidth% + \advance\pgf@x-\invertedradius% + \pgf@y\pgf@yc% + }{+\invertedradius}% + }% + \fi% + \repeatpgfmathloop% + }% + }% + \inheritanchorborder[from=and gate CDH]% +}% diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.code.tex new file mode 100644 index 0000000000..474a183d6f --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/circuits/pgflibraryshapes.gates.logic.code.tex @@ -0,0 +1,103 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + +% Common keys for all logic gates. +% +\pgfkeys{/pgf/.cd,% + logic gate input sep/.initial=0.125cm, + logic gate inputs/.initial={normal,normal},% + logic gate inverted radius/.initial=2pt, +}% + + +% Internal macro for parsing inputs. +% +\expandafter\ifx\csname pgf@lib@sh@logicgate@parseinputs\endcsname\relax% +\def\pgf@lib@sh@logicgate@parseinputs#1{% + \edef\pgf@lib@sh@temp{\pgfkeysvalueof{/pgf/logic gate inputs}}% + \c@pgf@counta#1\relax% + \c@pgf@countb0\relax% + \expandafter\pgfutil@in@\expandafter,\expandafter{\pgf@lib@sh@temp}% + \ifpgfutil@in@% + \let\pgf@lib@sh@next\pgf@lib@sh@logicgate@parseinputs@long% + \else% + \let\pgf@lib@sh@next\pgf@lib@sh@logicgate@parseinputs@short% + \fi% + \pgf@lib@sh@next% +}% +\def\pgf@lib@sh@itext{i}% +\def\pgf@lib@sh@invertedtext{inverted}% +\def\pgf@lib@sh@atchar{@}% +\def\pgf@lib@sh@gobbletilat#1@{}% +\def\pgf@lib@sh@gobbletilatcomma#1@,{}% +% +% The `short' version for input specification is an extension of +% ideas due to Juergen Werber and Christoph Bartoschek. +% +\def\pgf@lib@sh@logicgate@parseinputs@short{% + \expandafter\pgf@lib@sh@logicgate@parseinputs@@short\pgf@lib@sh@temp @% +}% +\def\pgf@lib@sh@logicgate@parseinputs@@short#1{% + \def\pgf@lib@sh@tmp{#1}% + \ifx\pgf@lib@sh@tmp\pgf@lib@sh@atchar% + \edef\pgf@lib@sh@logicgate@numinputs{\the\c@pgf@countb}% + \let\pgf@lib@sh@next=\relax% + \else% + \ifnum\c@pgf@countb=\c@pgf@counta% + \edef\pgf@lib@sh@logicgate@numinputs{\the\c@pgf@countb}% + \let\pgf@lib@sh@next=\pgf@lib@sh@gobbletilat% + \else% + \advance\c@pgf@countb by1\relax% + \expandafter\ifx\pgf@lib@sh@itext#1% + \expandafter\pgf@sh@resavedmacro\expandafter{\csname input-\the\c@pgf@countb\endcsname}{% + \expandafter\def\csname input-\the\c@pgf@countb\endcsname{i}}% + \else% + \expandafter\pgf@sh@resavedmacro\expandafter{\csname input-\the\c@pgf@countb\endcsname}{% + \expandafter\def\csname input-\the\c@pgf@countb\endcsname{n}}% + \fi% + \let\pgf@lib@sh@next=\pgf@lib@sh@logicgate@parseinputs@@short% + \fi% + \fi% + \pgf@lib@sh@next% +}% + + +\def\pgf@lib@sh@logicgate@parseinputs@long{% + \expandafter\pgf@lib@sh@logicgate@parseinputs@@long\pgf@lib@sh@temp,@,% +}% +\def\pgf@lib@sh@logicgate@parseinputs@@long#1,{% + \def\pgf@lib@sh@tmp{#1}% + \ifx\pgf@lib@sh@tmp\pgf@lib@sh@atchar% + \edef\pgf@lib@sh@logicgate@numinputs{\the\c@pgf@countb}% + \let\pgf@lib@sh@next=\relax% + \else% + \ifnum\c@pgf@countb=\c@pgf@counta% + \edef\pgf@lib@sh@logicgate@numinputs{\the\c@pgf@countb}% + \let\pgf@lib@sh@next=\pgf@lib@sh@gobbletilatcomma% + \else% + \advance\c@pgf@countb by1\relax% + \def\pgf@lib@sh@temp{#1}% + \ifx\pgf@lib@sh@invertedtext\pgf@lib@sh@temp% + \expandafter\pgf@sh@resavedmacro\expandafter{\csname input-\the\c@pgf@countb\endcsname}{% + \expandafter\def\csname input-\the\c@pgf@countb\endcsname{i}}% + \else% + \expandafter\pgf@sh@resavedmacro\expandafter{\csname input-\the\c@pgf@countb\endcsname}{% + \expandafter\def\csname input-\the\c@pgf@countb\endcsname{n}}% + \fi% + \let\pgf@lib@sh@next=\pgf@lib@sh@logicgate@parseinputs@@@long% + \fi% + \fi% + \pgf@lib@sh@next% +}% +\def\pgf@lib@sh@logicgate@parseinputs@@@long{% + \pgfutil@ifnextchar x{\pgf@lib@sh@logicgate@parseinputs@@long}% + {\pgf@lib@sh@logicgate@parseinputs@@long}% +}% +\fi% diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.arrows.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.arrows.code.tex new file mode 100644 index 0000000000..be8cb3740c --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.arrows.code.tex @@ -0,0 +1,2361 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.arrows.code.tex} + + +% keys for shape single arrow +% +% /pgf/single arrow tip angle +% /pgf/single arrow head extend +% /pgf/single arrow head indent + +\pgfkeys{/pgf/.cd, + single arrow tip angle/.initial=90, + single arrow head extend/.initial=.25cm, + single arrow head indent/.initial=0cm, +}% + +% Shape single arrow +% +% +\pgfdeclareshape{single arrow}{% + \savedmacro\getsinglearrowpoints{% + % + % Get the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \edef\xoutersep{\the\pgf@x}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\youtersep{\the\pgf@y}% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa.5\wd\pgfnodeparttextbox% + \advance\pgf@xa.5\pgflinewidth% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya.5\ht\pgfnodeparttextbox% + \advance\pgf@ya.5\dp\pgfnodeparttextbox% + \advance\pgf@ya.5\pgflinewidth% + \ifpgfshapeborderusesincircle% + \ifdim\pgf@xa<\pgf@ya% + \pgf@xa\pgf@ya% + \fi% + \pgf@xa1.41421\pgf@xa% + \pgf@ya\pgf@xa% + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \ifdim\xoutersep>\youtersep\relax% + \let\youtersep\xoutersep% + \else% + \let\xoutersep\youtersep% + \fi% + \else% + % + % Round the rotation. + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \pgfmathmod@{\rotate}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@x\pgf@xa% + \pgf@xa\pgf@ya% + \pgf@ya\pgf@x% + \let\pgfmathresult\xoutersep% + \let\xoutersep\youtersep% + \let\youtersep\pgfmathresult% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@x\pgf@xa% + \pgf@xa\pgf@ya% + \pgf@ya\pgf@x% + \let\pgfmathresult\xoutersep% + \let\xoutersep\youtersep% + \let\youtersep\pgfmathresult% + \fi% + \fi% + \fi% + \addtosavedmacro\rotate% + % + % Get some useful trig stuff. + % + \pgfmathdivide{\pgfkeysvalueof{/pgf/single arrow tip angle}}{2}% + \let\halftipangle\pgfmathresult% + \pgfmathcosec@{\halftipangle}% + \let\cosechalftipangle\pgfmathresult% + \pgfmathcos@{\halftipangle}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima\cosechalftipangle\pgfutil@tempdima% + \edef\cothalftipangle{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfmathreciprocal@{\pgfmathresult}% + \let\sechalftipangle\pgfmathresult% + \pgfmathsin@{\halftipangle}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima\sechalftipangle\pgfutil@tempdima% + \edef\tanhalftipangle{\pgfmath@tonumber{\pgfutil@tempdima}}% + % + % Get the single arrow head extend, and adjust for minimum width. + % + \pgf@xb\pgf@ya% + \pgf@xb\cothalftipangle\pgf@xb% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/single arrow head extend}}% + \pgf@yc\pgf@xc% + \advance\pgf@xc\pgf@ya% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@xc<.5\pgfutil@tempdimb% + \pgfutil@tempdimb.5\pgfutil@tempdimb% + \pgfmathdivide@{\pgfmath@tonumber{\pgfutil@tempdimb}}{\pgfmath@tonumber{\pgf@xc}}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgf@xc\pgfmathresult\pgf@xc% + \pgf@yc\pgfmathresult\pgf@yc% + \pgf@xb\pgfmathresult\pgf@xb% + \fi% + % + % Now calculate the height of the arrow and adjust for minimum height. + % + \advance\pgf@xc-\pgf@ya% + \pgf@xc\cothalftipangle\pgf@xc% + \pgf@xa2.0\pgf@xa% + \advance\pgf@xa\pgf@xb% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@xa<\pgfutil@tempdimb% + \pgf@xa\pgfutil@tempdimb% + \fi% + \advance\pgf@xa-\pgf@xb% + \pgf@xa.5\pgf@xa% + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/single arrow head indent}}% + % + % Now: + % + % xa - .5 * width of the node minus xb. + % ya - .5 * height of the node contents. + % xb - distance from the end of the node contents to the arrow tip. + % xc - distance from the end of the node contents to the back end of the arrow head. + % yc - distance from the top of the node contents to the top end of the arrow head. + % + \pgfsavepgf@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \pgfsavepgf@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \pgfsavepgf@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % As the arrow is symmetrical it can be described by only four points: + % + \pgfsavepgf@process\arrowtip{% + \pgf@x\pgf@xa% + \advance\pgf@x\pgf@xb% + \pgf@y0pt\relax% + }% + \pgfsavepgf@process\beforearrowtip{% + \pgf@x\pgf@xa% + \advance\pgf@x-\pgf@xc% + \pgf@y\pgf@ya% + \advance\pgf@y\pgf@yc% + }% + \pgfsavepgf@process\beforearrowhead{% + \pgf@x\pgf@xa% + \advance\pgf@x-\pgf@xc% + \advance\pgf@x\pgfutil@tempdima% + \pgf@y\pgf@ya% + }% + \pgfsavepgf@process\afterarrowtail{% + \pgf@x-\pgf@xa% + \pgf@y\pgf@ya% + }% + % + % Calculate the anchor point at the arrow tip... + % + \pgfsavepgf@process\arrowtipanchor{% + \pgfpointadd{\centerpoint}{\arrowtip}% + \pgf@xa\xoutersep\relax% + \advance\pgf@x\cosechalftipangle\pgf@xa% + }% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \edef\externalradius{\the\pgf@x}% + \addtosavedmacro\externalradius% + % + % ...and the rest of the points. + % + \pgfmathanglebetweenlines{\beforearrowtip}{\beforearrowhead}{\beforearrowtip}{\arrowtip}% + \pgf@xa\xoutersep\relax% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \advance\pgfutil@tempdima-\halftipangle pt\relax% + % + \pgfsavepgf@process\beforearrowtipanchor{% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgf@xa}% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgf@process{\pgfpointadd{\centerpoint}{\beforearrowtip}}% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + }% + \pgfmathanglebetweenpoints{\beforearrowhead}{\beforearrowtip}% + \pgfutil@tempdima-\pgfmathresult pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgf@xa\xoutersep\relax% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \pgfsavepgf@process\beforearrowheadanchor{% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgf@xa}% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgf@process{\pgfpointadd{\centerpoint}{\beforearrowhead}}% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + }% + \pgfsavepgf@process\afterarrowtailanchor{% + \pgfpointadd{\centerpoint}{\afterarrowtail}% + \advance\pgf@x-\xoutersep\relax% + \advance\pgf@y\youtersep\relax% + }% + % + \pgfmathanglebetweenpoints{\centerpoint}{\beforearrowtipanchor}% + \let\center@angle@beforearrowtip\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\beforearrowheadanchor}% + \let\center@angle@beforearrowhead\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\afterarrowtailanchor}% + \let\center@angle@afterarrowtail\pgfmathresult% + \addtosavedmacro\center@angle@beforearrowtip% + \addtosavedmacro\center@angle@beforearrowhead% + \addtosavedmacro\center@angle@afterarrowtail% + % + \pgfmathanglebetweenpoints{\midpoint}{\beforearrowtipanchor}% + \let\mid@angle@beforearrowtip\pgfmathresult% + \pgfmathanglebetweenpoints{\midpoint}{\beforearrowheadanchor}% + \let\mid@angle@beforearrowhead\pgfmathresult% + \pgfmathanglebetweenpoints{\midpoint}{\afterarrowtailanchor}% + \let\mid@angle@afterarrowtail\pgfmathresult% + \addtosavedmacro\mid@angle@beforearrowtip% + \addtosavedmacro\mid@angle@beforearrowhead% + \addtosavedmacro\mid@angle@afterarrowtail% + % + \pgfmathanglebetweenpoints{\basepoint}{\beforearrowtipanchor}% + \let\base@angle@beforearrowtip\pgfmathresult% + \pgfmathanglebetweenpoints{\basepoint}{\beforearrowheadanchor}% + \let\base@angle@beforearrowhead\pgfmathresult% + \pgfmathanglebetweenpoints{\basepoint}{\afterarrowtailanchor}% + \let\base@angle@afterarrowtail\pgfmathresult% + \addtosavedmacro\base@angle@beforearrowtip% + \addtosavedmacro\base@angle@beforearrowhead% + \addtosavedmacro\base@angle@afterarrowtail% + % + \addtosavedmacro\arrowtipanchor% + \addtosavedmacro\beforearrowtipanchor% + \addtosavedmacro\beforearrowheadanchor% + \addtosavedmacro\afterarrowtailanchor% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \getsinglearrowpoints% + \let\pgf@singlearrow@referencepoint\midpoint% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid west}{% + \getsinglearrowpoints% + \let\pgf@singlearrow@referencepoint\midpoint% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \getsinglearrowpoints% + \let\pgf@singlearrow@referencepoint\basepoint% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{base west}{% + \getsinglearrowpoints% + \let\pgf@singlearrow@referencepoint\basepoint% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south east}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{south west}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \getsinglearrowpoints% + \csname pgf@anchor@single arrow@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{before head}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{\beforearrowheadanchor}{\centerpoint}{\rotate}% + }% + \anchor{before tip}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{\beforearrowtipanchor}{\centerpoint}{\rotate}% + }% + \anchor{tip}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{\arrowtipanchor}{\centerpoint}{\rotate}% + }% + \anchor{after tip}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{after head}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{before tail}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\afterarrowtailanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{after tail}{% + \getsinglearrowpoints% + \pgfmathrotatepointaround{\afterarrowtailanchor}{\centerpoint}{\rotate}% + }% + \anchor{tail}{% + \getsinglearrowpoints% + \pgfpointlineattime{0.5}{% + \pgfmathrotatepointaround{\afterarrowtailanchor}{\centerpoint}{\rotate}% + }% + {% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\afterarrowtailanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + }% + \backgroundpath{% + {% + \pgftransformshift{\centerpoint}% + \pgftransformrotate{\rotate}% + \pgfpathmoveto{\arrowtip}% + \pgfpathlineto{\beforearrowtip}% + \pgfpathlineto{\beforearrowhead}% + \pgfpathlineto{\afterarrowtail}% + \pgfpathlineto{\afterarrowtail\pgf@y-\pgf@y}% + \pgfpathlineto{\beforearrowhead\pgf@y-\pgf@y}% + \pgfpathlineto{\beforearrowtip\pgf@y-\pgf@y}% + }% + \pgfpathclose% + }% + \anchorborder{% + \pgfsavepgf@process\externalpoint{}% + \getsinglearrowpoints% + \pgfutil@ifundefined{pgf@singlearrow@referencepoint}{\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@singlearrow@referencepoint}% + \pgfsavepgf@process\externalpoint{% + \externalpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \referencepoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya}% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + \pgf@x\externalangle pt\relax% + \ifx\referencepoint\midpoint% + \pgf@xa\mid@angle@beforearrowtip pt\relax% + \pgf@xb\mid@angle@beforearrowhead pt\relax% + \pgf@xc\mid@angle@afterarrowtail pt\relax% + \else% + \ifx\referencepoint\basepoint% + \pgf@xa\base@angle@beforearrowtip pt\relax% + \pgf@xb\base@angle@beforearrowhead pt\relax% + \pgf@xc\base@angle@afterarrowtail pt\relax% + \else% + \pgf@xa\center@angle@beforearrowtip pt\relax% + \pgf@xb\center@angle@beforearrowhead pt\relax% + \pgf@xc\center@angle@afterarrowtail pt\relax% + \fi% + \fi% + \ifdim\pgf@x<\pgf@xa% + \let\firstpoint\arrowtipanchor% + \let\secondpoint\beforearrowtipanchor% + \else% + \ifdim\pgf@x<\pgf@xb% + \ifdim\pgf@xb<\pgf@xa% + \let\firstpoint\arrowtipanchor% + \let\secondpoint\beforearrowtipanchor% + \else% + \let\firstpoint\beforearrowheadanchor% + \let\secondpoint\beforearrowtipanchor% + \fi% + \else% + \ifdim\pgf@x<\pgf@xc% + \let\firstpoint\beforearrowheadanchor% + \let\secondpoint\afterarrowtailanchor% + \else% + \pgf@xc-\pgf@xc% + \advance\pgf@xc360pt\relax% + \ifdim\pgf@x<\pgf@xc% + \let\firstpoint\afterarrowtailanchor% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\afterarrowtailanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \else% + \pgf@xa-\pgf@xa% + \advance\pgf@xa360pt\relax% + \pgf@xb-\pgf@xb% + \advance\pgf@xb360pt\relax% + \ifdim\pgf@x<\pgf@xa% + \ifdim\pgf@x<\pgf@xb% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\afterarrowtailanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \else% + \ifdim\pgf@xb<\pgf@xa% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \else% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\arrowtipanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \fi% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \fi% + \else% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}% + }% + \let\secondpoint\arrowtipanchor% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgfsavepgf@process\firstpoint{% + \pgfmathrotatepointaround{\firstpoint}{\centerpoint}{\rotate}% + }% + \pgfsavepgf@process\secondpoint{% + \pgfmathrotatepointaround{\secondpoint}{\centerpoint}{\rotate}% + }% + \pgfpointintersectionoflines{\referencepoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% +}% + + + + + + + +% keys for shape double arrow +% +% /pgf/double arrow tip angle +% /pgf/double arrow head sep + +\pgfkeys{/pgf/.cd, + double arrow tip angle/.initial=90, + double arrow head extend/.initial=.25cm, + double arrow head indent/.initial=0cm, +}% + +% Shape double arrow +% +% +\pgfdeclareshape{double arrow}{% + \savedmacro\getdoublearrowpoints{% + % + % Get the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \edef\xoutersep{\the\pgf@x}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\youtersep{\the\pgf@y}% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa.5\wd\pgfnodeparttextbox% + \advance\pgf@xa.5\pgflinewidth% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya.5\ht\pgfnodeparttextbox% + \advance\pgf@ya.5\dp\pgfnodeparttextbox% + \advance\pgf@ya.5\pgflinewidth% + \ifpgfshapeborderusesincircle% + \ifdim\pgf@xa<\pgf@ya% + \pgf@xa\pgf@ya% + \fi% + \pgf@xa1.41421\pgf@xa% + \pgf@ya\pgf@xa% + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \ifdim\xoutersep>\youtersep\relax% + \let\youtersep\xoutersep% + \else% + \let\xoutersep\youtersep% + \fi% + \else% + % + % Round the rotation. + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}} + \pgfmathmod@{\rotate}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@x\pgf@xa% + \pgf@xa\pgf@ya% + \pgf@ya\pgf@x% + \let\pgfmathresult\xoutersep% + \let\xoutersep\youtersep% + \let\youtersep\pgfmathresult% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@x\pgf@xa% + \pgf@xa\pgf@ya% + \pgf@ya\pgf@x% + \let\pgfmathresult\xoutersep% + \let\xoutersep\youtersep% + \let\youtersep\pgfmathresult% + \fi% + \fi% + \fi% + \addtosavedmacro\rotate% + % + % Get some useful trig stuff. + % + \pgfmathdivide{\pgfkeysvalueof{/pgf/double arrow tip angle}}{2}% + \let\halftipangle\pgfmathresult% + \pgfmathcosec@{\halftipangle}% + \let\cosechalftipangle\pgfmathresult% + \pgfmathcos@{\halftipangle}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima\cosechalftipangle\pgfutil@tempdima% + \edef\cothalftipangle{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfmathreciprocal@{\pgfmathresult}% + \let\sechalftipangle\pgfmathresult% + \pgfmathsin@{\halftipangle}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima\sechalftipangle\pgfutil@tempdima% + \edef\tanhalftipangle{\pgfmath@tonumber{\pgfutil@tempdima}}% + % + % Get the double arrow head extend, and adjust for minimum width. + % + \pgf@xb\pgf@ya% + \pgf@xb\cothalftipangle\pgf@xb% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/double arrow head extend}}% + \pgf@yc\pgf@xc% + \advance\pgf@xc\pgf@ya% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@xc<.5\pgfutil@tempdimb% + \pgfutil@tempdimb.5\pgfutil@tempdimb% + \pgfmathdivide@{\pgfmath@tonumber{\pgfutil@tempdimb}}{\pgfmath@tonumber{\pgf@xc}}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgf@xc\pgfmathresult\pgf@xc% + \pgf@yc\pgfmathresult\pgf@yc% + \pgf@xb\pgfmathresult\pgf@xb% + \fi% + % + % Now calculate the height of the arrow and adjust for minimum height. + % + \advance\pgf@xc-\pgf@ya% + \pgf@xc\cothalftipangle\pgf@xc% + \advance\pgf@xa\pgf@xb% + \pgf@xa2.0\pgf@xa% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@xa<\pgfutil@tempdimb% + \pgf@xa\pgfutil@tempdimb% + \fi% + \pgf@xa.5\pgf@xa% + \advance\pgf@xa-\pgf@xb% + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/double arrow head indent}}% + % + % Now: + % + % xa - .5 * width of the node minus xb. + % ya - .5 * height of the node contents. + % xb - distance from the end of the node contents to the arrow tip. + % xc - distance from the end of the node contents to the back end of the arrow head. + % yc - distance from the top of the node contents to the top end of the arrow head. + % + \pgfsavepgf@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \pgfsavepgf@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \pgfsavepgf@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % As the arrow is symmetrical it can be described by only 3 points: + % + \pgfsavepgf@process\arrowtip{% + \pgf@x\pgf@xa% + \advance\pgf@x\pgf@xb% + \pgf@y0pt\relax% + }% + \pgfsavepgf@process\beforearrowtip{% + \pgf@x\pgf@xa% + \advance\pgf@x-\pgf@xc% + \pgf@y\pgf@ya% + \advance\pgf@y\pgf@yc% + }% + \pgfsavepgf@process\beforearrowhead{% + \pgf@x\pgf@xa% + \advance\pgf@x-\pgf@xc% + \advance\pgf@x\pgfutil@tempdima% + \pgf@y\pgf@ya% + }% + % + % Calculate the anchor point at the arrow tip. + % + \pgfsavepgf@process\arrowtipanchor{% + \pgfpointadd{\centerpoint}{\arrowtip}% + \pgf@xa\xoutersep\relax% + \advance\pgf@x\cosechalftipangle\pgf@xa% + }% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \edef\externalradius{\the\pgf@x}% + \addtosavedmacro\externalradius% + % + % + \pgfmathanglebetweenlines{\beforearrowtip}{\beforearrowhead}{\beforearrowtip}{\arrowtip}% + \pgf@xa\xoutersep\relax% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \advance\pgfutil@tempdima-\halftipangle pt\relax% + \pgfsavepgf@process\beforearrowtipanchor{% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgf@xa}% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgf@process{\pgfpointadd{\centerpoint}{\beforearrowtip}}% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + }% + \pgfmathanglebetweenpoints{\beforearrowhead}{\beforearrowtip}% + \pgfutil@tempdima-\pgfmathresult pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgf@xa\xoutersep\relax% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \pgfsavepgf@process\beforearrowheadanchor{% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgf@xa}% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgf@process{\pgfpointadd{\centerpoint}{\beforearrowhead}}% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + }% + % + \pgfmathanglebetweenpoints{\centerpoint}{\beforearrowtipanchor}% + \let\center@angle@beforearrowtip\pgfmathresult% + \addtosavedmacro\center@angle@beforearrowtip% + % + \pgfmathanglebetweenpoints{\midpoint}{\beforearrowtipanchor}% + \let\mid@angle@beforearrowtip\pgfmathresult% + \addtosavedmacro\mid@angle@beforearrowtip% + % + \pgfmathanglebetweenpoints{\basepoint}{\beforearrowtipanchor}% + \let\base@angle@beforearrowtip\pgfmathresult% + \addtosavedmacro\base@angle@beforearrowtip% + % + \addtosavedmacro\arrowtipanchor% + \addtosavedmacro\beforearrowtipanchor% + \addtosavedmacro\beforearrowheadanchor% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \getdoublearrowpoints% + \let\pgf@singlearrow@referencepoint\midpoint% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid west}{% + \getdoublearrowpoints% + \let\pgf@singlearrow@referencepoint\midpoint% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \getdoublearrowpoints% + \let\pgf@singlearrow@referencepoint\basepoint% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{base west}{% + \getdoublearrowpoints% + \let\pgf@singlearrow@referencepoint\basepoint% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south east}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{south west}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \getdoublearrowpoints% + \csname pgf@anchor@double arrow@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{before head 1}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{\beforearrowheadanchor}{\centerpoint}{\rotate}% + }% + \anchor{before tip 1}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{\beforearrowtipanchor}{\centerpoint}{\rotate}% + }% + \anchor{tip 1}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{\arrowtipanchor}{\centerpoint}{\rotate}% + }% + \anchor{after tip 1}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{after head 1}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{before head 2}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{before tip 2}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{tip 2}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\arrowtipanchor}% + \pgf@x-\pgf@x% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{after tip 2}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@x-\pgf@x% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{after head 2}{% + \getdoublearrowpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@x-\pgf@x% + }{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \backgroundpath{% + {% + \pgftransformshift{\centerpoint}% + \pgftransformrotate{\rotate}% + \pgfpathmoveto{\arrowtip}% + \pgfpathlineto{\beforearrowtip}% + \pgfpathlineto{\beforearrowhead}% + \pgfpathlineto{\beforearrowhead\pgf@x-\pgf@x}% + \pgfpathlineto{\beforearrowtip\pgf@x-\pgf@x}% + \pgfpathlineto{\arrowtip\pgf@x-\pgf@x}% + \pgfpathlineto{\beforearrowtip\pgf@x-\pgf@x\pgf@y-\pgf@y}% + \pgfpathlineto{\beforearrowhead\pgf@x-\pgf@x\pgf@y-\pgf@y}% + \pgfpathlineto{\beforearrowhead\pgf@y-\pgf@y}% + \pgfpathlineto{\beforearrowtip\pgf@y-\pgf@y}% + }% + \pgfpathclose% + }% + \anchorborder{% + \pgfsavepgf@process\externalpoint{}% + \getdoublearrowpoints% + \pgfutil@ifundefined{pgf@singlearrow@referencepoint}{\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@singlearrow@referencepoint}% + \pgfsavepgf@process\externalpoint{% + \externalpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \referencepoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya}% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + \pgf@x\externalangle pt\relax% + \ifx\referencepoint\midpoint% + \pgf@xa\mid@angle@beforearrowtip pt\relax% + \else% + \ifx\referencepoint\basepoint% + \pgf@xa\base@angle@beforearrowtip pt\relax% + \else% + \pgf@xa\center@angle@beforearrowtip pt\relax% + \fi% + \fi% + \ifdim\pgf@x<180pt\relax% + \ifdim\pgf@x<\pgf@xa% + \let\firstpoint\arrowtipanchor% + \let\secondpoint\beforearrowtipanchor% + \else% + \pgf@xa-\pgf@xa% + \advance\pgf@xa180pt\relax% + \ifdim\pgf@x<\pgf@xa% + \let\firstpoint\beforearrowheadanchor% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@x-\pgf@x + }{\centerpoint}}% + \else% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@x-\pgf@x + }{\centerpoint}}% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\arrowtipanchor}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }{\centerpoint}}% + \fi% + \fi% + \else% + \pgf@xa-\pgf@xa% + \advance\pgf@xa360pt\relax% + \ifdim\pgf@x<\pgf@xa% + \pgf@xa-\pgf@xa% + \advance\pgf@xa540pt\relax% + \ifdim\pgf@x<\pgf@xa% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\arrowtipanchor}% + \pgf@x-\pgf@x% + }{\centerpoint}}% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowtipanchor}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }{\centerpoint}}% + \else% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }{\centerpoint}}% + \pgfsavepgf@process\secondpoint{% + \pgfpointadd{% + \pgfpointdiff{\centerpoint}{\beforearrowheadanchor}% + \pgf@y-\pgf@y% + }{\centerpoint}}% + \fi% + \else% + \pgfsavepgf@process\firstpoint{% + \pgfpointadd{% + \pgfpointdiff{\beforearrowtipanchor}{\centerpoint}% + \pgf@x-\pgf@x% + }{\centerpoint}}% + \let\secondpoint\arrowtipanchor% + \fi% + \fi% + \pgfsavepgf@process\firstpoint{% + \pgfmathrotatepointaround{\firstpoint}{\centerpoint}{\rotate}% + }% + \pgfsavepgf@process\secondpoint{% + \pgfmathrotatepointaround{\secondpoint}{\centerpoint}{\rotate}% + }% + \pgfpointintersectionoflines{\referencepoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% +}% + + + + +% +% Internal macros for the arrow box/shape. +% +\def\pgf@lib@arrowbox@parsearrowlength#1#2#3{% + \edef\pgf@lib@temp{#3}% + \edef\pgf@lib@marshal{% + \noexpand\pgfutil@in@{none}{\pgf@lib@temp}% + }% + \pgf@lib@marshal% + \ifpgfutil@in@% + #10pt\relax% + \else% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter#1\pgf@lib@temp\relax\pgfmath@% + % + \edef\pgf@lib@marshal{% + \noexpand\pgfutil@in@{from center}{\pgf@lib@temp}% + }% + \pgf@lib@marshal% + \ifpgfutil@in@% + \else% + \ifdim#1>0pt\relax% + \advance#1#2\relax% + \fi% + \fi% + \fi}% + +\def\pgf@lib@arrowbox@parsearrows#1{% + \pgfkeys{/pgf/.cd,% + arrow box west arrow=0pt, + arrow box east arrow=0pt, + arrow box south arrow=0pt, + arrow box north arrow=0pt + }% + \def\pgf@lib@arrowbox@extend{0pt}% + \edef\pgf@lib@temp{#1}% + \expandafter\pgf@lib@arrowbox@@parsearrows\pgf@lib@temp,\pgf@lib@arrowbox@parsearrows, +}% + + +\def\pgf@lib@arrowbox@@parsearrows#1,{% + \ifx\pgf@lib@arrowbox@parsearrows#1% + \let\pgflib@next\relax% + \else% + \pgfutil@in@:{#1}% + \ifpgfutil@in@% + \pgf@lib@arrowbox@getextend#1\pgf@lib% + \else% + \def\pgf@lib@arrowbox@direction{#1}% + \fi% + \edef\pgf@marshal{% + \noexpand\pgfkeys{/pgf/arrow box \pgf@lib@arrowbox@direction\space arrow=\pgf@lib@arrowbox@extend}% + }% + \pgf@marshal% + \let\pgflib@next\pgf@lib@arrowbox@@@parsearrows% + \fi% + \pgflib@next% +}% +\def\pgf@lib@arrowbox@@@parsearrows{% + \pgfutil@ifnextchar x{\relax\pgf@lib@arrowbox@@parsearrows}{\relax\pgf@lib@arrowbox@@parsearrows}% +}% + +\def\pgf@lib@arrowbox@getextend#1:#2\pgf@lib{% + \def\pgf@lib@arrowbox@direction{#1}% + \def\pgf@lib@arrowbox@extend{#2}% +}% + +% +% /pgf/arrow box north arrow +% /pgf/arrow box south arrow +% /pgf/arrow box west arrow +% /pgf/arrow box east arrow +% /pgf/arrow box arrows +% /pgf/arrow box shaft width +% /pgf/arrow box head extend +% /pgf/arrow box head indent +% /pgf/arrow box tip angle +% +\pgfkeys{/pgf/.cd, + arrow box west arrow/.initial=.5cm, + arrow box east arrow/.initial=.5cm, + arrow box south arrow/.initial=.5cm, + arrow box north arrow/.initial=.5cm, + arrow box shaft width/.initial=.125cm, + arrow box head extend/.initial=.125cm, + arrow box head indent/.initial=0cm, + arrow box tip angle/.initial=90, +}% + +% +% arrow box/Shape. +% +\pgfdeclareshape{arrow box}{% + \saveddimen\shaftwidth{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/arrow box shaft width}}% + }% + % + % Calculate far the arrows extend from the center of the node. + % + \savedmacro\arrowboxpoints{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + % + \edef\halfboxwidth{\the\pgf@x}% + \edef\halfboxheight{\the\pgf@y}% + \pgfextract@process\arrowboxcorner{}% + \addtosavedmacro\arrowboxcorner% + % + \pgf@lib@arrowbox@parsearrowlength\pgf@x{\halfboxwidth}% + {\pgfkeysvalueof{/pgf/arrow box west arrow}}% + \edef\westextend{\the\pgf@x}% + \addtosavedmacro\westextend% + % + \pgf@lib@arrowbox@parsearrowlength\pgf@x{\halfboxwidth}% + {\pgfkeysvalueof{/pgf/arrow box east arrow}}% + \edef\eastextend{\the\pgf@x}% + \addtosavedmacro\eastextend% + % + \pgf@lib@arrowbox@parsearrowlength\pgf@x{\halfboxheight}% + {\pgfkeysvalueof{/pgf/arrow box north arrow}}% + \edef\northextend{\the\pgf@x}% + \addtosavedmacro\northextend% + % + \pgf@lib@arrowbox@parsearrowlength\pgf@x{\halfboxheight}% + {\pgfkeysvalueof{/pgf/arrow box south arrow}}% + \edef\southextend{\the\pgf@x}% + \addtosavedmacro\southextend% + }% + \saveddimen\arrowheadextend{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/arrow box head extend}}% + }% + \saveddimen\arrowheadindent{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/arrow box head indent}}% + }% + % + % Calculate the `miter' angle for the outer sep at the arrow tip. + % + \savedmacro\arrowtipmiterangle{% + \pgfmathparse{\pgfkeysvalueof{/pgf/arrow box tip angle}}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\arrowtipmiterangle\pgfmathresult% + }% + % + % Calculate the `miter' angle for the outer sep at the point just + % before the arrow tip. + % + \savedmacro\arrowheadangles{% + % + % Calculate the `miter' angle and its cosecant at the arrow tip... + % + \pgfmathparse{\pgfkeysvalueof{/pgf/arrow box tip angle}}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\arrowtipmiterangle\pgfmathresult% + \addtosavedmacro\arrowtipmiterangle% + \pgfmathcosec@{\arrowtipmiterangle}% + \let\cosecarrowtipmiterangle\pgfmathresult% + \addtosavedmacro\cosecarrowtipmiterangle% + % + % ...before the arrow head... + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/arrow box head extend}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/arrow box head indent}}% + \ifdim\pgf@y=0pt\relax% + \def\pgfmathresult{90}% + \else% + \ifdim\pgf@y<0pt\relax% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \pgfmathatan@{\pgfmathresult}% + \pgfmathadd@{\pgfmathresult}{180}% + \else% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \pgfmathatan@{\pgfmathresult}% + \fi% + \fi% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\beforearrowheadmiterangle\pgfmathresult% + \addtosavedmacro\beforearrowheadmiterangle% + \pgfmathcosec@{\beforearrowheadmiterangle}% + \let\cosecbeforearrowheadmiterangle\pgfmathresult% + \addtosavedmacro\cosecbeforearrowheadmiterangle% + % + % ...and before the arrow tip. + % + \pgfutil@tempdima-\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima90pt\relax% + \pgfutil@tempdimb\beforearrowheadmiterangle pt\relax% + \pgfutil@tempdimb2.0\pgfutil@tempdimb% + \advance\pgfutil@tempdimb-90pt\relax% + \advance\pgfutil@tempdima\pgfutil@tempdimb% + \divide\pgfutil@tempdima2\relax% + \edef\beforearrowtipmiterangle{\pgfmath@tonumber{\pgfutil@tempdima}}% + \addtosavedmacro\beforearrowtipmiterangle% + \pgfmathcosec@{\beforearrowtipmiterangle}% + \let\cosecbeforearrowtipmiterangle\pgfmathresult% + \addtosavedmacro\cosecbeforearrowtipmiterangle% + }% + \saveddimen\outerxsep{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + }% + \saveddimen\outerysep{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer ysep}}% + }% + % + % Calculate the (path) point immediately prior to an arrow tip. + % + \savedanchor\beforearrowtip{% + \pgfmathparse{\pgfkeysvalueof{/pgf/arrow box tip angle}}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfmathcot@{\pgfmathresult}% + \let\cothalfangle\pgfmathresult% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/arrow box shaft width}}% + \pgf@y.5\pgf@y% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/arrow box head extend}}% + \pgf@y\pgf@y% + \pgf@x\cothalfangle\pgf@y% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \let\pgf@lib@shapes@arrowbox@referencepoint\midpoint% + \csname pgf@anchor@arrow box@border\endcsname{\pgfqpoint{\eastextend}{0pt}}% + \else% + \arrowboxcorner% + \pgf@xa\pgf@x% + \midpoint% + \advance\pgf@x\pgf@xa% + \fi% + }% + \anchor{mid west}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \let\pgf@lib@shapes@arrowbox@referencepoint\midpoint% + \csname pgf@anchor@arrow box@border\endcsname{\pgfqpoint{-\westextend}{0pt}}% + \else% + \arrowboxcorner% + \pgf@xa\pgf@x% + \midpoint% + \advance\pgf@x-\pgf@xa% + \fi% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \let\pgf@lib@shapes@arrowbox@referencepoint\basepoint% + \csname pgf@anchor@arrow box@border\endcsname{\pgfqpoint{\eastextend}{0pt}}% + \else% + \arrowboxcorner% + \pgf@xa\pgf@x% + \basepoint% + \advance\pgf@x\pgf@xa% + \fi% + }% + \anchor{base west}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \let\pgf@lib@shapes@arrowbox@referencepoint\basepoint% + \csname pgf@anchor@arrow box@border\endcsname{\pgfqpoint{-\westextend}{0pt}}% + \else% + \arrowboxcorner% + \pgf@xa\pgf@x% + \basepoint% + \advance\pgf@x-\pgf@xa% + \fi% + }% + \anchor{north}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \csname pgf@anchor@arrow box@north arrow tip\endcsname% + \else% + \pgfpointadd{\centerpoint}{\arrowboxcorner}% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \fi% + }% + \anchor{south}{% + \arrowboxpoints% + \ifdim\southextend>0pt\relax% + \csname pgf@anchor@arrow box@south arrow tip\endcsname% + \else% + \pgfpointadd{\centerpoint}{\arrowboxcorner\pgf@y-\pgf@y}% + \pgf@ya\pgf@y% + \centerpoint% + \pgf@y\pgf@ya% + \fi% + }% + \anchor{east}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \csname pgf@anchor@arrow box@east arrow tip\endcsname% + \else% + \pgfpointadd{\centerpoint}{\arrowboxcorner}% + \pgf@xa\pgf@x% + \centerpoint% + \pgf@x\pgf@xa% + \fi% + }% + \anchor{west}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \csname pgf@anchor@arrow box@west arrow tip\endcsname% + \else% + \pgfpointadd{\centerpoint}{\arrowboxcorner\pgf@x-\pgf@x}% + \pgf@xa\pgf@x% + \centerpoint% + \pgf@x\pgf@xa% + \fi% + }% + \anchor{north east}{% + \arrowboxpoints% + \pgfpointadd{\centerpoint}{\arrowboxcorner}% + }% + \anchor{north west}{% + \arrowboxpoints% + \pgfpointadd{\centerpoint}{\arrowboxcorner\pgf@x-\pgf@x}% + }% + \anchor{south west}{% + \arrowboxpoints% + \pgfpointadd{\centerpoint}{\arrowboxcorner\pgf@x-\pgf@x\pgf@y-\pgf@y}% + }% + \anchor{south east}{% + \arrowboxpoints% + \pgfpointadd{\centerpoint}{\arrowboxcorner\pgf@y-\pgf@y}% + }% + \anchor{before east arrow}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + \advance\pgf@y\outerysep\relax% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{before east arrow head}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{before east arrow tip}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + }% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{east arrow tip}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \centerpoint% + \advance\pgf@x\eastextend\relax% + \pgf@xa\outerxsep\relax% + \pgfmathcosec@{\arrowtipmiterangle}% + \advance\pgf@x\pgfmathresult\pgf@xa% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{after east arrow tip}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + }% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{after east arrow head}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{after east arrow}{% + \arrowboxpoints% + \ifdim\eastextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + \advance\pgf@y\outerysep\relax% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + % + \anchor{before west arrow}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@x-\pgf@x% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + \advance\pgf@y\outerysep\relax% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{before west arrow head}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\westextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{before west arrow tip}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\westextend\relax% + }% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{west arrow tip}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \centerpoint% + \advance\pgf@x-\westextend\relax% + \pgf@xa\outerxsep\relax% + \pgfmathcosec@{\arrowtipmiterangle}% + \advance\pgf@x-\pgfmathresult\pgf@xa% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{after west arrow tip}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\westextend\relax% + }% + \pgf@x-\pgf@x% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{after west arrow head}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\westextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgf@x-\pgf@x% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + \anchor{after west arrow}{% + \arrowboxpoints% + \ifdim\westextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + \advance\pgf@y\outerysep\relax% + \pgf@x-\pgf@x% + }% + \else% + \csname pgf@anchor@arrow box@west\endcsname% + \fi% + }% + % + \anchor{before north arrow}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + \advance\pgf@x-\outerxsep\relax% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{before north arrow head}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima270pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{before north arrow tip}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-90pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y-\pgf@xa% + \advance\pgf@y\northextend\relax% + }% + \pgf@x-\pgf@x% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{north arrow tip}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \centerpoint% + \advance\pgf@y\northextend\relax% + \pgf@ya\outerysep\relax% + \pgfmathcosec@{\arrowtipmiterangle}% + \advance\pgf@y\pgfmathresult\pgf@ya% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{after north arrow tip}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-90pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y-\pgf@xa% + \advance\pgf@y\northextend\relax% + }% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{after north arrow head}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima270pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \pgf@x-\pgf@x% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + \anchor{after north arrow}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + \advance\pgf@x\outerxsep\relax% + }% + \else% + \csname pgf@anchor@arrow box@north\endcsname% + \fi% + }% + % + \anchor{before south arrow}{% + \arrowboxpoints% + \ifdim\southextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + \advance\pgf@x\outerxsep\relax% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + \anchor{before south arrow head}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima270pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + \anchor{before south arrow tip}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-90pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y-\pgf@xa% + \advance\pgf@y\northextend\relax% + }% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + \anchor{south arrow tip}{% + \arrowboxpoints% + \ifdim\southextend>0pt\relax% + \centerpoint% + \advance\pgf@y-\southextend\relax% + \pgf@ya\outerysep\relax% + \pgfmathcosec@{\arrowtipmiterangle}% + \advance\pgf@y-\pgfmathresult\pgf@ya% + \else% + \csname pgf@anchor@arrow box@east\endcsname% + \fi% + }% + \anchor{after south arrow tip}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima\arrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima\beforearrowtipmiterangle pt\relax% + \advance\pgfutil@tempdima-90pt\relax% + \pgfutil@tempdimb\outerxsep\relax% + \pgfutil@tempdimb\cosecbeforearrowtipmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y-\pgf@xa% + \advance\pgf@y\northextend\relax% + }% + \pgf@x-\pgf@x% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + \anchor{after south arrow head}{% + \arrowboxpoints% + \ifdim\northextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointadd{% + \arrowheadangles% + \pgfutil@tempdima-\beforearrowheadmiterangle pt\relax% + \advance\pgfutil@tempdima270pt\relax% + \pgfutil@tempdimb\outerysep\relax% + \pgfutil@tempdimb\cosecbeforearrowheadmiterangle\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }% + {% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + \anchor{after south arrow}{% + \arrowboxpoints% + \ifdim\southextend>0pt\relax% + \pgfpointadd{\centerpoint}{% + \arrowboxcorner% + \pgf@x-\shaftwidth\relax% + \pgf@x.5\pgf@x% + \advance\pgf@x-\outerxsep\relax% + \pgf@y-\pgf@y% + }% + \else% + \csname pgf@anchor@arrow box@south\endcsname% + \fi% + }% + % + \backgroundpath{% + \arrowboxpoints% + \pgfextract@process\arrowboxcorner{% + \arrowboxcorner% + \pgfmathaddtolength\pgf@x{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{-\pgfkeysvalueof{/pgf/outer ysep}}% + }% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\arrowboxcorner}% + \ifdim\eastextend>0pt\relax% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + }% + \pgfpathlineto{% + \pgf@x\eastextend\relax% + \pgf@y0pt\relax% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + \pgf@y-\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@x-\pgf@x% + \advance\pgf@x\eastextend\relax% + \advance\pgf@x\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y-.5\pgf@y% + }% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@y\shaftwidth\relax% + \pgf@y-.5\pgf@y% + }% + \fi% + \pgfpathlineto{\arrowboxcorner\pgf@y-\pgf@y}% + \ifdim\southextend>0pt\relax% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + \pgf@y-\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@y\pgf@x% + \advance\pgf@y-\southextend\relax% + \advance\pgf@y-\arrowheadindent\relax% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@xa\pgf@y% + \pgf@y\pgf@x% + \advance\pgf@y-\southextend\relax% + \pgf@x\pgf@xa% + }% + \pgfpathlineto{% + \pgf@x0pt\relax% + \pgf@y-\southextend\relax% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@xa\pgf@y% + \pgf@y\pgf@x% + \advance\pgf@y-\southextend\relax% + \pgf@x-\pgf@xa% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@y\pgf@x% + \advance\pgf@y-\southextend\relax% + \advance\pgf@y-\arrowheadindent\relax% + \pgf@x\shaftwidth\relax% + \pgf@x-.5\pgf@x% + }% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x-.5\pgf@x% + \pgf@y-\pgf@y% + }% + \fi% + \pgfpathlineto{\arrowboxcorner\pgf@x-\pgf@x\pgf@y-\pgf@y}% + \ifdim\westextend>0pt\relax% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x-\pgf@x + \pgf@y\shaftwidth\relax% + \pgf@y-.5\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \advance\pgf@x-\westextend\relax% + \advance\pgf@x-\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y-.5\pgf@y% + }% + \pgfpathlineto{% + \beforearrowtip% + \advance\pgf@x-\westextend\relax% + \pgf@y-\pgf@y% + }% + \pgfpathlineto{% + \pgf@x-\westextend\relax% + \pgf@y0pt\relax% + }% + \pgfpathlineto{% + \beforearrowtip% + \advance\pgf@x-\westextend\relax% + }% + \pgfpathlineto{% + \beforearrowtip% + \advance\pgf@x-\westextend\relax% + \advance\pgf@x-\arrowheadindent\relax% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x-\pgf@x% + \pgf@y\shaftwidth\relax% + \pgf@y.5\pgf@y% + }% + \fi% + \pgfpathlineto{\arrowboxcorner\pgf@x-\pgf@x}% + \ifdim\northextend>0pt\relax% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x-.5\pgf@x% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x\shaftwidth\relax% + \pgf@x-.5\pgf@x% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@xa\pgf@y% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \pgf@x-\pgf@xa% + }% + \pgfpathlineto{% + \pgf@x0pt\relax% + \pgf@y\northextend\relax% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@xa\pgf@y% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \pgf@x\pgf@xa% + }% + \pgfpathlineto{% + \beforearrowtip% + \pgf@y-\pgf@x% + \advance\pgf@y\northextend\relax% + \advance\pgf@y\arrowheadindent\relax% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \pgfpathlineto{% + \arrowboxcorner% + \pgf@x\shaftwidth\relax% + \pgf@x.5\pgf@x% + }% + \fi% + \pgfpathclose% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \pgfutil@ifundefined{pgf@lib@shapes@arrowbox@referencepoint}% + {\let\referencepoint\centerpoint}{\let\referencepoint\pgf@lib@shapes@arrowbox@referencepoint}% + \pgfextract@process\externalpoint{% + \pgfpointadd{\referencepoint}{\externalpoint}% + }% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@north\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@north east\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before east arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{east arrow tip}% + \def\secondpoint{before east arrow tip}% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before east arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{before east arrow head}% + \def\secondpoint{before east arrow}% + \else% + \def\firstpoint{before east arrow}% + \def\secondpoint{north east}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after north arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after north arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{north east}% + \def\secondpoint{after north arrow}% + \else% + \def\firstpoint{after north arrow}% + \def\secondpoint{after north arrow head}% + \fi% + \else% + \def\firstpoint{after north arrow tip}% + \def\secondpoint{north arrow tip}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before north arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{north arrow tip}% + \def\secondpoint{before north arrow tip}% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before north arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{before north head}% + \def\secondpoint{before north arrow}% + \else% + \def\firstpoint{before north arrow}% + \def\secondpoint{north west}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after west arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after west arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{north west}% + \def\secondpoint{after west arrow}% + \else% + \def\firstpoint{after west arrow}% + \def\secondpoint{after west arrow head}% + \fi% + \else% + \def\firstpoint{after west arrow tip}% + \def\secondpoint{west arrow tip}% + \fi% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@south arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@south west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before west arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{west arrow tip}% + \def\secondpoint{before west arrow tip}% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before west arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{before west arrow head}% + \def\secondpoint{before west arrow}% + \else% + \def\firstpoint{before west arrow}% + \def\secondpoint{south west}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after south arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after south arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{south west}% + \def\secondpoint{after south arrow}% + \else% + \def\firstpoint{after south arrow}% + \def\secondpoint{after south arrow head}% + \fi% + \else% + \def\firstpoint{after south arrow tip}% + \def\secondpoint{south arrow tip}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@south east\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before south arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{south arrow tip}% + \def\secondpoint{before south arrow tip}% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@before south arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{before south arrow head}% + \def\secondpoint{before south arrow}% + \else% + \def\firstpoint{before south arrow}% + \def\secondpoint{south east}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after east arrow tip\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}% + {\csname pgf@anchor@arrow box@after east arrow\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \def\firstpoint{south east}% + \def\secondpoint{after east arrow}% + \else% + \def\firstpoint{after east arrow}% + \def\secondpoint{after east arrow head}% + \fi% + \else% + \def\firstpoint{after east arrow tip}% + \def\secondpoint{east arrow tip}% + \fi% + \fi% + \fi% + \fi% + \pgfpointintersectionoflines{\referencepoint}{\externalpoint}% + {\csname pgf@anchor@arrow box@\firstpoint\endcsname}% + {\csname pgf@anchor@arrow box@\secondpoint\endcsname}% + }% +}% + + + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.callouts.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.callouts.code.tex new file mode 100644 index 0000000000..72d9761a19 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.callouts.code.tex @@ -0,0 +1,951 @@ +% Copyright 2018 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\usepgflibrary{shapes.symbols}% + +% Keys for callouts +% +% Common to all callouts: +% /pgf/callout absolute pointer +% /pgf/callout relative pointer +% +% ellipse callout only: +% /pgf/callout pointer arc +% +% rectangle callout only: +% /pgf/callout pointer width +% +% cloud callout only: +% /pgf/callout pointer start size +% /pgf/callout pointer end size +% /pgf/callout pointer segments +% +\newif\ifpgf@lib@callout@absolutepointer +\pgfkeys{/pgf/.cd, + callout pointer arc/.initial=15, + callout pointer width/.initial=.25cm, + callout pointer start size/.initial=.2 of callout, + callout pointer end size/.initial=.1 of callout, + callout pointer segments/.initial=2, + callout absolute pointer/.code={\pgf@lib@callout@makeabsolutepointer{#1}}, + callout relative pointer/.code={\pgf@lib@callout@makerelativepointer{#1}}, + callout pointer shorten/.initial=0cm, +}% + + + +\def\pgf@lib@callout@makeabsolutepointer#1{% + \pgf@lib@callout@absolutepointertrue% + {% + \pgftransformshift{#1}% + \pgfmultipartnode{coordinate}{center}{pgf@lib@callout@pointer}{}% + }% +}% + +\def\pgf@lib@callout@makerelativepointer#1{% + \pgf@lib@callout@absolutepointerfalse% + \def\pgf@lib@callout@relativepointer{#1}% +}% +\pgfkeys{/pgf/callout relative pointer=\pgfpointpolar{300}{.5cm}}% + + +% Shape ellipse callout +% +% +\pgfdeclareshape{ellipse callout}{% + \savedmacro\ellipsecalloutpoints{% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x>\pgf@y% + \edef\outersep{\the\pgf@x}% + \else% + \edef\outersep{\the\pgf@y}% + \fi% + \addtosavedmacro\outersep% + % + % Calculate the node dimensions... + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgf@x1.4142136\pgf@x% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \pgf@y1.4142136\pgf@y% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + % + % ...without outer sep... + % + \edef\xpathradius{\the\pgf@x}% + \edef\ypathradius{\the\pgf@y}% + % + % ...and width outer sep. + % + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \edef\xradius{\the\pgf@x}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\yradius{\the\pgf@y}% + % + \addtosavedmacro\xradius% + \addtosavedmacro\xpathradius% + \addtosavedmacro\yradius% + \addtosavedmacro\ypathradius% + % + \pgfmathsetmacro\pointerarc{\pgfkeysvalueof{/pgf/callout pointer arc}}% + \addtosavedmacro\pointerarc% + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + % + % Get the relative pointer. + % + \ifpgf@lib@callout@absolutepointer% + \else% + \pgfextract@process\calloutpointer{% + \pgfextract@process\borderpoint{% + \expandafter\pgfpointborderellipse\expandafter{\pgf@lib@callout@relativepointer}{\pgfqpoint{\xpathradius}{\ypathradius}}% + }% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\borderpoint}% + \let\pointerangle\pgfmathresult% + \expandafter\pgf@process\expandafter{\pgf@lib@callout@relativepointer}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \edef\pointerradius{\pgfmathresult pt}% + \pgfpointadd{\borderpoint}{\pgfqpointpolar{\pointerangle}{\pointerradius}}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + \addtosavedmacro\calloutpointer% + \pgf@lib@callouts@shortenpointer% + \pgf@lib@ellipsecallout@getpoints% + \addtosavedmacro\calloutpointeranchor% + \addtosavedmacro\beforecalloutangle% + \addtosavedmacro\aftercalloutangle% + \fi% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \ellipsecalloutpoints% + \pgfmathpointintersectionoflineandarc{\midpoint\advance\pgf@x\xradius}{\midpoint}% + {\centerpoint}{270}{450}{\xradius and \yradius}% + }% + \anchor{mid west}{% + \ellipsecalloutpoints% + \pgfmathpointintersectionoflineandarc{\midpoint\advance\pgf@x-\xradius}{\midpoint}% + {\centerpoint}{90}{270}{\xradius and \yradius}% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \ellipsecalloutpoints% + \pgfmathpointintersectionoflineandarc{\basepoint\advance\pgf@x\xradius}{\basepoint}% + {\centerpoint}{270}{450}{\xradius and \yradius}% + }% + \anchor{base west}{% + \ellipsecalloutpoints% + \pgfmathpointintersectionoflineandarc{\basepoint\advance\pgf@x-\xradius}{\basepoint}% + {\centerpoint}{90}{270}{\xradius and \yradius}% + }% + \anchor{north}{% + \ellipsecalloutpoints% + \centerpoint% + \advance\pgf@y\yradius\relax% + }% + \anchor{south}{% + \ellipsecalloutpoints% + \centerpoint% + \advance\pgf@y-\yradius\relax% + }% + \anchor{east}{% + \ellipsecalloutpoints% + \centerpoint% + \advance\pgf@x\xradius\relax% + }% + \anchor{west}{% + \ellipsecalloutpoints% + \centerpoint% + \advance\pgf@x-\xradius\relax% + }% + \anchor{north west}{% + \ellipsecalloutpoints% + \pgf@xa\xradius\relax% + \pgf@ya\yradius\relax% + \centerpoint% + \advance\pgf@y0.7071067\pgf@ya% + \advance\pgf@x-0.7071067\pgf@xa% + }% + \anchor{north east}{% + \ellipsecalloutpoints% + \pgf@xa\xradius\relax% + \pgf@ya\yradius\relax% + \centerpoint% + \advance\pgf@y0.7071067\pgf@ya% + \advance\pgf@x0.7071067\pgf@xa% + }% + \anchor{south west}{% + \ellipsecalloutpoints% + \pgf@xa\xradius\relax% + \pgf@ya\yradius\relax% + \centerpoint% + \advance\pgf@y-0.7071067\pgf@ya% + \advance\pgf@x-0.7071067\pgf@xa% + }% + \anchor{south east}{% + \ellipsecalloutpoints% + \pgf@xa\xradius\relax% + \pgf@ya\yradius\relax% + \centerpoint% + \advance\pgf@y-0.7071067\pgf@ya% + \advance\pgf@x0.7071067\pgf@xa% + }% + \anchor{pointer}{% + \ellipsecalloutpoints% + \calloutpointeranchor% + }% + \backgroundpath{% + \ellipsecalloutpoints% + \ifpgf@lib@callout@absolutepointer% + \pgfextract@process\calloutpointer{% + \pgfpointanchor{pgf@lib@callout@pointer}{center}% + }% + \pgf@lib@callouts@shortenpointer% + \pgf@lib@ellipsecallout@getpoints% + \calloutpointeranchor% + \ifx\pgf@node@name\pgfutil@empty% + \else% + \edef\pgf@sh@@temp{\noexpand\expandafter\noexpand\pgfutil@g@addto@macro\noexpand\csname pgf@sh@np@\pgf@node@name\noexpand\endcsname}% + \edef\pgf@sh@@@temp{% + \noexpand\def\noexpand\calloutpointeranchor{% + \noexpand\pgf@x\the\pgf@x% + \noexpand\pgf@y\the\pgf@y% + }% + }% + \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@@@temp} + \fi% + \fi% + \pgfpathmoveto{\calloutpointer}% + \pgfpathlineto{\aftercalloutpointer}% + \ifdim\aftercalloutangle pt<\beforecalloutangle pt\relax% + \pgfpatharc{\aftercalloutangle}{\beforecalloutangle}{\xpathradius and \ypathradius}% + \else% + \pgfpatharc{\aftercalloutangle}{360}{\xpathradius and \ypathradius}% + \pgfpatharc{0}{\beforecalloutangle}{\xpathradius and \ypathradius}% + \fi% + \pgfpathclose% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \ellipsecalloutpoints% + \pgfpointadd{\pgfpointborderellipse{\externalpoint}{\pgfpoint{\xradius}{\yradius}}% + }{\centerpoint}% + }% +}% + +% Internal macro for calculating the points for the +% ellipse callout pointer. +% +% The following must be set up: +% +% \centerpoint - the center of the ellipse. +% \calloutpointer - the location of the callout point. +% \pointerarc - the width of the pointer. +% \xpathradius - the x radius of the ellipse. +% \ypathradius - the y radius of the ellipse. +% +\def\pgf@lib@ellipsecallout@getpoints{% + \pgfextract@process\borderpoint{% + \pgfpointborderellipse{% + \centerpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \calloutpointer% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y-\pgf@ya% + }{\pgfqpoint{\xpathradius}{\ypathradius}}% + }% + \pgfmathangleonellipse{\borderpoint}{\xpathradius and \ypathradius}% + \pgfutil@tempdima\pointerarc pt\relax% + \pgfutil@tempdimb\pgfmathresult pt\relax% + \advance\pgfutil@tempdimb-.5\pgfutil@tempdima% + \ifdim\pgfutil@tempdimb<0pt\relax% + \advance\pgfutil@tempdimb360pt\relax% + \fi% + \edef\beforecalloutangle{\pgfmath@tonumber{\pgfutil@tempdimb}}% + \advance\pgfutil@tempdimb\pgfutil@tempdima% + \ifdim\pgfutil@tempdimb<360pt\relax% + \else% + \advance\pgfutil@tempdimb-360pt\relax% + \fi% + \edef\aftercalloutangle{\pgfmath@tonumber{\pgfutil@tempdimb}}% + % + \pgfextract@process\beforecalloutpointer{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{\beforecalloutangle}{\xpathradius and \ypathradius}% + }% + }% + \pgfextract@process\aftercalloutpointer{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{\aftercalloutangle}{\xpathradius and \ypathradius}% + }% + }% + % + % Calculate the pointer anchor. + % + \pgf@lib@callouts@pointeranchor% +}% + + +% If the callout pointer is very pointed and stroked, the anchor will be +% miles away from the end of the pointer which will (typically) be +% bevelled. +% Using outer sep=0pt is one solution, however, another is provided +% using this special key: +% +% /pgf/callout pointer anchor aspect +% +% which takes a value from 0 (ignore any outer sep) to 1 (use +% the full outer sep). + +\pgfkeys{/pgf/callout pointer anchor aspect/.initial=1}% + +% Internal macro for calculating the anchor for the callout pointer. +% +% Requires the following to be set up (points are anti-clockwise) +% +% \beforecalloutpointer - point on the border before the callout pointer +% \calloutpointer +% \aftercalloutpointer - point on the border after the callout pointer +% \outersep - the largest of the outer xsep or ysep. +% +\def\pgf@lib@callouts@pointeranchor{% + \pgfutil@tempdimb\outersep\relax% + % + \pgfmathanglebetweenlines{\calloutpointer}{\aftercalloutpointer}{\calloutpointer}{\beforecalloutpointer}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \pgfmathcosec@{\pgfmathresult}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \pgfmathanglebetweenpoints{\calloutpointer}{\aftercalloutpointer}% + \advance\pgfutil@tempdima\pgfmathresult pt\relax% + \advance\pgfutil@tempdima180pt\relax% + % + \pgfextract@process\calloutpointeranchor{% + \pgfpointadd{% + \pgfmathparse{\pgfkeysvalueof{/pgf/callout pointer anchor aspect}}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + }{% + \calloutpointer% + }% + }% +}% + +\def\pgf@lib@callouts@shortenpointer{% + \pgfextract@process\calloutpointer{% + \pgfmathanglebetweenpoints{\calloutpointer}{\centerpoint}% + \let\angle\pgfmathresult% + \pgfmathsin@{\angle}% + \let\sinpointerangle\pgfmathresult% + \pgfmathcos@{\angle}% + \let\cospointerangle\pgfmathresult% + \pgfpointadd{\calloutpointer}{% + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/callout pointer shorten}}% + \pgf@x\cospointerangle\pgfutil@tempdima% + \pgf@y\sinpointerangle\pgfutil@tempdima% + }% + }% +}% + + +\pgfdeclareshape{rectangle callout}{% + \savedmacro\rectanglecalloutpoints{% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \edef\xtemp{\the\pgf@x}% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \edef\ytemp{\the\pgf@y}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + % + \edef\xlength{\the\pgf@x}% + \edef\ylength{\the\pgf@y}% + \addtosavedmacro\xlength% + \addtosavedmacro\ylength% + % + \pgfmathsetlengthmacro\pointerwidth{\pgfkeysvalueof{/pgf/callout pointer width}}% + \addtosavedmacro\pointerwidth% + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + % + % Process the relative callout pointer. + % + \ifpgf@lib@callout@absolutepointer% + \else% + \pgfextract@process\calloutpointer{% + \pgfextract@process\borderpoint{% + \expandafter\pgfpointborderrectangle\expandafter{\pgf@lib@callout@relativepointer}% + {\pgfqpoint{\xtemp}{\ytemp}}% + }% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\borderpoint}% + \let\pointerangle\pgfmathresult% + \expandafter\pgf@process\expandafter{\pgf@lib@callout@relativepointer}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \edef\pointerradius{\pgfmathresult pt}% + \pgfpointadd{\borderpoint}{\pgfqpointpolar{\pointerangle}{\pointerradius}}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgf@lib@callouts@shortenpointer% + \addtosavedmacro\calloutpointer% + \pgf@lib@rectanglecallout@pointer% + \addtosavedmacro\calloutpointeranchor% + \addtosavedmacro\beforecalloutpointer% + \addtosavedmacro\aftercalloutpointer% + \addtosavedmacro\firstpoint% + \addtosavedmacro\secondpoint% + \addtosavedmacro\thirdpoint% + \addtosavedmacro\fourthpoint% + \fi% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5em}% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \rectanglecalloutpoints% + \midpoint% + \advance\pgf@x\xlength\relax% + }% + \anchor{mid west}{% + \rectanglecalloutpoints% + \midpoint% + \advance\pgf@x-\xlength\relax% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \rectanglecalloutpoints% + \basepoint% + \advance\pgf@x\xlength\relax% + }% + \anchor{base west}{% + \rectanglecalloutpoints% + \basepoint% + \advance\pgf@x-\xlength\relax% + }% + \anchor{north}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@y\ylength\relax% + }% + \anchor{south}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@y-\ylength\relax% + }% + \anchor{east}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x\xlength\relax% + }% + \anchor{west}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x-\xlength\relax% + }% + \anchor{north east}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x\xlength\relax% + \advance\pgf@y\ylength\relax% + }% + \anchor{south west}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x-\xlength\relax% + \advance\pgf@y-\ylength\relax% + }% + \anchor{south east}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x\xlength\relax% + \advance\pgf@y-\ylength\relax% + }% + \anchor{north west}{% + \rectanglecalloutpoints% + \centerpoint% + \advance\pgf@x-\xlength\relax% + \advance\pgf@y\ylength\relax% + }% + \anchor{pointer}{% + \rectanglecalloutpoints% + \calloutpointeranchor% + }% + \backgroundpath{% + \rectanglecalloutpoints% + \pgf@x\xlength\relax% + \pgf@y\ylength\relax% + \pgfmathaddtolength\pgf@x{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{-\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\xtemp{\the\pgf@x}% + \edef\ytemp{\the\pgf@y}% + % + % The absolute pointer must be calculated here because the + % anchor of the shape (which is calculated after the saved + % macros and points) affects how the pointer joins the + % main rectangle. + % + \ifpgf@lib@callout@absolutepointer% + \pgfextract@process\calloutpointer{% + \pgfpointanchor{pgf@lib@callout@pointer}{center}% + }% + \pgf@lib@callouts@shortenpointer% + \pgfmathsetlengthmacro\pointerwidth{\pgfkeysvalueof{/pgf/callout pointer width}}% + \pgf@lib@rectanglecallout@pointer% + % + % \pgf@node@name = the shape name (from \pgfmultipartnode) + % + \ifx\pgf@node@name\pgfutil@empty% + \else% + % + % Now hack an extra saved anchor \calloutpointeranchor, + % with the new anchor for the callout pointer. + % + \edef\pgf@sh@@temp{\noexpand\expandafter\noexpand\pgfutil@g@addto@macro\noexpand\csname pgf@sh@np@\pgf@node@name\noexpand\endcsname}% + \edef\pgf@sh@@@temp{% + \noexpand\def\noexpand\calloutpointeranchor{% + \noexpand\pgf@x\the\pgf@x% + \noexpand\pgf@y\the\pgf@y% + }% + }% + \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@@@temp}% + \fi% + \fi% + {% + \pgfsetcornersarced{\pgfqpoint{0pt}{0pt}}% + \pgfpathmoveto{\beforecalloutpointer}% + }% + \pgfpathlineto{\calloutpointer}% + {% + \pgfsetcornersarced{\pgfqpoint{0pt}{0pt}}% + \pgfpathlineto{\aftercalloutpointer}% + }% + {% + \pgftransformshift{\centerpoint}% + \pgfpathlineto{\firstpoint}% + \pgfpathlineto{\secondpoint}% + \pgfpathlineto{\thirdpoint}% + \pgfpathlineto{\fourthpoint}% + {% + \pgfsetcornersarced{\pgfqpoint{0pt}{0pt}}% + \pgfpathclose% + }% + } + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \rectanglecalloutpoints% + \pgfpointadd{\centerpoint}% + {% + \pgfpointborderrectangle{\pgfpointadd{\centerpoint}{\externalpoint}}% + {\pgfqpoint{\xlength}{\ylength}}% + }% + }% +}% + + + +% \pgf@lib@rectanglecallout@pointer +% +% Internal macro for calculations relating to the rectangle callout. +% +% Requires the following to be set up: +% +% \calloutpointer - the location of the callout point. +% \xtemp - the half width of the rectangle +% \ytemp - the half height of the rectangle +% \pointerwidth - the width of the pointer. +% +\def\pgf@lib@rectanglecallout@pointer{% + % + % Ensure that the pointer never connects to the main shape + % too near to a corner. This is done for two reasons: + % 1. It can look ugly. + % 2. If the corners are rounded, a mess can result. + % + \pgfextract@process\borderpoint{% + \pgfpointborderrectangle{% + \centerpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \calloutpointer% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y-\pgf@ya% + }{\pgfqpoint{\xtemp}{\ytemp}}% + }% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\borderpoint}% + \let\borderangle\pgfmathresult% + % + \pgfutil@tempdima\pointerwidth\relax% + \pgf@xa\xtemp\relax% + \advance\pgf@xa-\pgfutil@tempdima% + \pgf@ya\ytemp\relax% + \advance\pgf@ya-\pgfutil@tempdima% + % + \pgf@process{% + \pgfutil@ifundefined{pgf@corner@arc}{\pgfpointorigin}{% + \expandafter\pgfqpoint\pgf@corner@arc}% + }% + \advance\pgf@xa-\pgf@x% + \advance\pgf@ya-\pgf@y% + % + \borderpoint% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + % + \pgf@xc0pt\relax% + \pgf@yc0pt\relax% + % + \pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfqpoint{\xtemp}{\ytemp}}% + \ifdim\borderangle pt<\pgfmathresult pt\relax% + \pgf@yc.5\pgfutil@tempdima% + \ifdim\pgf@yb>\pgf@ya% + \pgf@yb\pgf@ya% + \fi% + % + % Establish the order for drawing the rectangle corners. + % + \edef\firstpoint{\noexpand\pgfqpoint{\xtemp}{\ytemp}}% + \edef\secondpoint{\noexpand\pgfqpoint{-\xtemp}{\ytemp}}% + \edef\thirdpoint{\noexpand\pgfqpoint{-\xtemp}{-\ytemp}}% + \edef\fourthpoint{\noexpand\pgfqpoint{\xtemp}{-\ytemp}}% + \else% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfqpoint{-\xtemp}{\ytemp}}% + \ifdim\borderangle pt<\pgfmathresult pt\relax% + \pgf@xc-.5\pgfutil@tempdima% + \ifdim\pgf@xb>\pgf@xa% + \pgf@xb\pgf@xa% + \else% + \ifdim\pgf@xb<-\pgf@xa% + \pgf@xb-\pgf@xa% + \fi% + \fi% + \edef\firstpoint{\noexpand\pgfqpoint{-\xtemp}{\ytemp}}% + \edef\secondpoint{\noexpand\pgfqpoint{-\xtemp}{-\ytemp}}% + \edef\thirdpoint{\noexpand\pgfqpoint{\xtemp}{-\ytemp}}% + \edef\fourthpoint{\noexpand\pgfqpoint{\xtemp}{\ytemp}}% + \else% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfqpoint{-\xtemp}{-\ytemp}}% + \ifdim\borderangle pt<\pgfmathresult pt\relax% + \pgf@yc-.5\pgfutil@tempdima% + \ifdim\pgf@yb>\pgf@ya% + \pgf@yb\pgf@ya% + \else% + \ifdim\pgf@yb<-\pgf@ya% + \pgf@yb-\pgf@ya% + \fi% + \fi% + \edef\firstpoint{\noexpand\pgfqpoint{-\xtemp}{-\ytemp}}% + \edef\secondpoint{\noexpand\pgfqpoint{\xtemp}{-\ytemp}}% + \edef\thirdpoint{\noexpand\pgfqpoint{\xtemp}{\ytemp}}% + \edef\fourthpoint{\noexpand\pgfqpoint{-\xtemp}{\ytemp}}% + \else% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\pgfqpoint{\xtemp}{-\ytemp}}% + \ifdim\borderangle pt<\pgfmathresult pt\relax% + \pgf@xc.5\pgfutil@tempdima% + \ifdim\pgf@xb>\pgf@xa% + \pgf@xb\pgf@xa% + \else% + \ifdim\pgf@xb<-\pgf@xa% + \pgf@xb-\pgf@xa% + \fi% + \fi% + \edef\firstpoint{\noexpand\pgfqpoint{\xtemp}{-\ytemp}}% + \edef\secondpoint{\noexpand\pgfqpoint{\xtemp}{\ytemp}}% + \edef\thirdpoint{\noexpand\pgfqpoint{-\xtemp}{\ytemp}}% + \edef\fourthpoint{\noexpand\pgfqpoint{-\xtemp}{-\ytemp}}% + \else% + \pgf@yc.5\pgfutil@tempdima% + \ifdim\pgf@yb<-\pgf@ya% + \pgf@yb-\pgf@ya% + \fi% + \edef\firstpoint{\noexpand\pgfqpoint{\xtemp}{\ytemp}}% + \edef\secondpoint{\noexpand\pgfqpoint{-\xtemp}{\ytemp}}% + \edef\thirdpoint{\noexpand\pgfqpoint{-\xtemp}{-\ytemp}}% + \edef\fourthpoint{\noexpand\pgfqpoint{\xtemp}{-\ytemp}}% + \fi% + \fi% + \fi% + \fi% + \pgfextract@process\beforecalloutpointer{% + \centerpoint% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + \advance\pgf@x-\pgf@xc% + \advance\pgf@y-\pgf@yc% + }% + \pgfextract@process\aftercalloutpointer{% + \centerpoint% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + \advance\pgf@x\pgf@xc% + \advance\pgf@y\pgf@yc% + }% + % + % Now calculate the pointer anchor. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x>\pgf@y% + \edef\outersep{\the\pgf@x}% + \else% + \edef\outersep{\the\pgf@y}% + \fi% + \pgf@lib@callouts@pointeranchor% +}% + + +% Internal macro for parsing the size of +% the cloud callout pointer. +% +% \pgf@x and \pgf@y should be set up as the +% width and height of the main shape. +% +% \pgf@xa and \pgf@ya are returned appropriately. +% +\def\pgf@lib@callout@setpointersize#1{% + \edef\pgf@lib@callout@temp{#1}% + \edef\pgf@marshall{\noexpand\pgfutil@in@{of callout}{\pgf@lib@callout@temp}}% + \pgf@marshall% + \ifpgfutil@in@% + \expandafter\pgf@xa\expandafter\pgf@lib@callout@setpointerrelativesize% + \pgf@lib@callout@temp\pgf@lib@stop\pgf@x% + \expandafter\pgf@ya\expandafter\pgf@lib@callout@setpointerrelativesize% + \pgf@lib@callout@temp\pgf@lib@stop\pgf@y% + \else% + \edef\pgf@marshall{\noexpand\pgfutil@in@{and}{\pgf@lib@callout@temp}}% + \pgf@marshall% + \ifpgfutil@in@% + \expandafter\pgf@lib@callout@setpointerbothsizes\pgf@lib@callout@temp\pgf@lib@stop% + \else% + \pgfmathsetlength\pgf@xa{#1}% + \pgfmathsetlength\pgf@ya{#1}% + \fi% + \fi% +}% +\def\pgf@lib@callout@setpointerrelativesize#1of callout#2\pgf@lib@stop{#1}% +\def\pgf@lib@callout@setpointerbothsizes#1and#2\pgf@lib@stop{% + \pgfmathsetlength\pgf@xa{#2}% + \pgfmathsetlength\pgf@ya{#2}% +}% + +% Shape: cloud callout. +% +\pgfdeclareshape{cloud callout}{% + \savedanchor\calloutpointer{% + \pgfutil@ifundefined{pgf@sh@s@cloud}{% + \pgferror{I cannot find the cloud shape. Please load the `symbol shapes' library}}{}% + \pgf@sh@s@cloud% + \pgf@sh@savedmacros% + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \ifpgf@lib@callout@absolutepointer% + \else% + \pgfextract@process\calloutpointer{% + \pgfextract@process\borderpoint{% + \expandafter\pgfpointborderellipse\expandafter{\pgf@lib@callout@relativepointer}% + {\pgfqpoint{\xouterradius}{\youterradius}}% + }% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\borderpoint}% + \let\pointerangle\pgfmathresult% + \expandafter\pgf@process\expandafter{\pgf@lib@callout@relativepointer}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \edef\pointerradius{\pgfmathresult pt}% + \pgfpointadd{\borderpoint}{\pgfqpointpolar{\pointerangle}{\pointerradius}}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgf@lib@callouts@shortenpointer% + \fi% + }% + \anchor{pointer}{% + \calloutpointer% + }% + \inheritsavedanchors[from=cloud]% + \inheritanchor[from=cloud]{center}% + \inheritanchor[from=cloud]{base}% + \inheritanchor[from=cloud]{mid}% + \inheritanchor[from=cloud]{north}% + \inheritanchor[from=cloud]{south}% + \inheritanchor[from=cloud]{east}% + \inheritanchor[from=cloud]{west}% + \inheritanchor[from=cloud]{north east}% + \inheritanchor[from=cloud]{south west}% + \inheritanchor[from=cloud]{south east}% + \inheritanchor[from=cloud]{north west}% + \inheritanchorborder[from=cloud]% + \backgroundpath{% + \pgf@sh@bg@cloud% + \ifpgf@lib@callout@absolutepointer% + \pgfextract@process\calloutpointer{% + \pgfpointanchor{pgf@lib@callout@pointer}{center}% + }% + \ifx\pgf@node@name\pgfutil@empty% + \else% + \edef\pgf@sh@@temp{\noexpand\expandafter\noexpand\pgfutil@g@addto@macro\noexpand\csname pgf@sh@np@\pgf@node@name\noexpand\endcsname}% + \edef\pgf@sh@@@temp{% + \noexpand\def\noexpand\calloutpointeranchor{% + \noexpand\pgf@x\the\pgf@x% + \noexpand\pgf@y\the\pgf@y% + }% + }% + \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@@@temp} + \fi% + \fi% + % + \pgfextract@process\borderpoint{% + \pgfpointadd{% + \pgfpointborderellipse{\pgfpointdiff{\centerpoint}{\calloutpointer}}% + {\pgfqpoint{\xouterradius}{\youterradius}}% + }{\centerpoint}% + }% + \pgf@lib@callouts@shortenpointer% + \pgfmathanglebetweenpoints{\calloutpointer}{\centerpoint}% + \let\angle\pgfmathresult% + \pgfmathsin@{\angle}% + \let\sinpointerangle\pgfmathresult% + \pgfmathcos@{\angle}% + \let\cospointerangle\pgfmathresult% + % + \pgf@x\xouterradius\relax% + \pgf@x2.0\pgf@x% + \pgf@y\yinnerradius\relax% + \pgf@y2.0\pgf@y% + \pgf@lib@callout@setpointersize{\pgfkeysvalueof{/pgf/callout pointer start size}}% + \pgf@xb\pgf@xa% + \pgf@yb\pgf@ya% + \pgf@lib@callout@setpointersize{\pgfkeysvalueof{/pgf/callout pointer end size}}% + \advance\pgf@xb-\pgf@xa% + \advance\pgf@yb-\pgf@ya% + % + \pgfmathsetcount\c@pgf@counta{\pgfkeysvalueof{/pgf/callout pointer segments}}% + \divide\pgf@xb\c@pgf@counta% + \divide\pgf@yb\c@pgf@counta% + % + \pgf@process{\pgfpointdiff{\borderpoint}{\calloutpointer}}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \divide\pgfutil@tempdima\c@pgf@counta% + % + \pgfutil@tempdimb0pt\relax% + \pgfmathloop% + \ifnum\pgfmathcounter>\c@pgf@counta% + \else% + {% + \pgf@xa.5\pgf@xa% + \pgf@ya.5\pgf@ya% + \edef\tempxradius{\the\pgf@xa}% + \edef\tempyradius{\the\pgf@ya}% + \pgfpathellipse% + {% + \calloutpointer% + \advance\pgf@x\cospointerangle\pgfutil@tempdimb% + \advance\pgf@y\sinpointerangle\pgfutil@tempdimb% + }% + {\pgfqpoint{\tempxradius}{0pt}}{\pgfqpoint{0pt}{\tempyradius}}% + }% + \advance\pgf@xa\pgf@xb% + \advance\pgf@ya\pgf@yb% + \advance\pgfutil@tempdimb\pgfutil@tempdima% + \repeatpgfmathloop% + }% + % + % Hack the puff anchors for the callout. + % + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@cloud callout\endcsname{% + \c@pgf@counta\puffs\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \pgfutil@ifundefined{pgf@anchor@cloud callout@puff\space\the\c@pgf@counta}{% + \expandafter\xdef\csname pgf@anchor@cloud callout@puff\space\the\c@pgf@counta\endcsname{% + \noexpand\pgf@sh@@cloudpuffanchor{\the\c@pgf@counta}% + }% + }{\c@pgf@counta0\relax}% + \advance\c@pgf@counta-1\relax% + \repeatpgfmathloop% + }% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.code.tex new file mode 100644 index 0000000000..dace51bf0b --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.code.tex @@ -0,0 +1,21 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.code.tex} + +% Only the following are loaded by default and only for historical +% reasons. + +\usepgflibrary{shapes.geometric}% +\usepgflibrary{shapes.misc}% +\usepgflibrary{shapes.symbols}% + +% Further libraries should be included directly + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.geometric.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.geometric.code.tex new file mode 100644 index 0000000000..71d03f9535 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.geometric.code.tex @@ -0,0 +1,4417 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.geometric.code.tex} + +\pgfdeclareshape{ellipse} +% +% Draws a circle around the text +% +{% + \savedanchor\centerpoint{% + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgf@y=.5\ht\pgfnodeparttextbox% + \advance\pgf@y by-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\radius{% + % + % Calculate ``height radius'' + % + \pgf@y=.5\ht\pgfnodeparttextbox% + \advance\pgf@y by.5\dp\pgfnodeparttextbox% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y by\pgf@yb% + % + % Calculate ``width radius'' + % + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x by\pgf@xb% + % + % Adjust + % + \pgf@x=1.4142136\pgf@x% + \pgf@y=1.4142136\pgf@y% + % + % Adjust height, if necessary + % + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@yc% + \pgf@y=.5\pgf@yc% + \fi% + % + % Adjust width, if necessary + % + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<.5\pgf@xc% + \pgf@x=.5\pgf@xc% + \fi% + % + % Add outer sep + % + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \advance\pgf@x by\pgf@xb% + \advance\pgf@y by\pgf@yb% + }% + + % + % Anchors + % + \anchor{center}{\centerpoint}% + \anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}% + \anchor{base}{\centerpoint\pgf@y=0pt}% + \anchor{north} + { + \pgf@process{\radius} + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@y by\pgf@ya + }% + \anchor{south} + { + \pgf@process{\radius} + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@y by-\pgf@ya + }% + \anchor{west} + { + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by-\pgf@xa + }% + \anchor{mid west} + {% + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by-\pgf@xa% + \pgfmathsetlength\pgf@y{.5ex} + }% + \anchor{base west} + {% + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by-\pgf@xa% + \pgf@y=0pt + }% + \anchor{north west} + { + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@x by-0.707107\pgf@xa + \advance\pgf@y by0.707107\pgf@ya + }% + \anchor{south west} + { + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@x by-0.707107\pgf@xa + \advance\pgf@y by-0.707107\pgf@ya + }% + \anchor{east} + {% + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by\pgf@xa + }% + \anchor{mid east} + {% + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by\pgf@xa% + \pgfmathsetlength\pgf@y{.5ex} + }% + \anchor{base east} + {% + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@process{\centerpoint} + \advance\pgf@x by\pgf@xa% + \pgf@y=0pt + }% + \anchor{north east} + { + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@x by0.707107\pgf@xa + \advance\pgf@y by0.707107\pgf@ya + }% + \anchor{south east} + { + \pgf@process{\radius} + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\centerpoint} + \advance\pgf@x by0.707107\pgf@xa + \advance\pgf@y by-0.707107\pgf@ya + }% + \anchorborder{% + \edef\pgf@marshal{% + \noexpand\pgfpointborderellipse + {\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + {\noexpand\radius}% + }% + \pgf@marshal% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \centerpoint% + \advance\pgf@x by\pgf@xa% + \advance\pgf@y by\pgf@ya% + }% + + % + % Background path + % + \backgroundpath + { + \pgf@process{\radius}% + \pgfutil@tempdima=\pgf@x% + \pgfutil@tempdimb=\pgf@y% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \advance\pgfutil@tempdima by-\pgf@xb% + \advance\pgfutil@tempdimb by-\pgf@yb% + \pgfpathellipse{\centerpoint}{\pgfqpoint{\pgfutil@tempdima}{0pt}}{\pgfqpoint{0pt}{\pgfutil@tempdimb}}% + }% +}% + + + + +% Set the recommended shape aspect ratio +% +% #1 = aspect ratio +% +% Example: +% +% \pgfsetshapeaspect{1.5} + +% Keys for shape aspect ratio. +% +% /pgf/aspect : recommended width/height quotient. +% +\pgfkeys{/pgf/.cd, + aspect/.code={\pgfsetshapeaspect{#1}},% this for tikz... + shape aspect/.initial=1,% but this is consistent with other pgfset stuff. + shape aspect/.code={% + \pgfkeys{/pgf/aspect={#1}}% + \pgfkeyssetvalue{/pgf/shape aspect}{#1} + }% +}% + + +\def\pgfsetshapeaspect#1{% + \def\pgfshapeaspect{#1}% + % Invert + \pgfutil@tempdima=#1pt% + \pgfutil@tempdima=.125\pgfutil@tempdima% + \c@pgf@counta=\pgfutil@tempdima\relax% 8192*determinant + \pgfutil@tempdima=8192pt% + \divide\pgfutil@tempdima by\c@pgf@counta% + \edef\pgfshapeaspectinverse{\pgf@sys@tonumber{\pgfutil@tempdima}}% +}% + +\pgfsetshapeaspect{1}% + +\pgfdeclareshape{diamond} +{% + \savedanchor\outernortheast{% + % + % Calculate width and height of the inner rectangle + % + \pgf@xa=.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa by\pgf@xc% + \pgf@ya=.5\ht\pgfnodeparttextbox% + \advance\pgf@ya by.5\dp\pgfnodeparttextbox% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya by\pgf@yc% + % + % Calculate width and height of diamond + % + \pgf@x=\pgf@xa% + \advance\pgf@x by\pgfshapeaspect\pgf@ya% + \pgf@y=\pgfshapeaspectinverse\pgf@xa% + \advance\pgf@y by\pgf@ya% + % + % Check against minimum height/width + % + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@xb=.5\pgf@xb% + \ifdim\pgf@x<\pgf@xb% + % yes, too small. Enlarge... + \pgf@x=\pgf@xb% + \fi% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@yb=.5\pgf@yb% + \ifdim\pgf@y<\pgf@yb% + % yes, too small. Enlarge... + \pgf@y=\pgf@yb% + \fi% + % + % Add outer border + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \advance\pgf@x by\pgf@xa% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \advance\pgf@y by\pgf@ya% + }% + \savedanchor\text{% + \pgf@x=-.5\wd\pgfnodeparttextbox% + \pgf@y=-.5\ht\pgfnodeparttextbox% + \advance\pgf@y by.5\dp\pgfnodeparttextbox% + }% + + % + % Anchors + % + \anchor{text}{\text}% + \anchor{center}{\pgfpointorigin}% + \anchor{mid}{% + \pgf@process{\text}% + \pgf@x=0pt% + \pgfmathsetlength\pgf@ya{.5ex}% + \advance\pgf@y by\pgf@ya% + }% + \anchor{base}{\pgf@process{\text}\pgf@x=0pt}% + \anchor{north}{\pgf@process{\outernortheast}\pgf@x=0pt}% + \anchor{south}{\pgf@process{\outernortheast}\pgf@x=0pt\pgf@y=-\pgf@y}% + \anchor{west}{\pgf@process{\outernortheast}\pgf@x=-\pgf@x\pgf@y=0pt}% + \anchor{north west}{\pgf@process{\outernortheast}\pgf@x=-.5\pgf@x\pgf@y=.5\pgf@y}% + \anchor{south west}{\pgf@process{\outernortheast}\pgf@x=-.5\pgf@x\pgf@y=-.5\pgf@y}% + \anchor{east}{\pgf@process{\outernortheast}\pgf@y=0pt}% + \anchor{north east}{\pgf@process{\outernortheast}\pgf@x=.5\pgf@x\pgf@y=.5\pgf@y}% + \anchor{south east}{\pgf@process{\outernortheast}\pgf@x=.5\pgf@x\pgf@y=-.5\pgf@y}% + \anchorborder{% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\outernortheast}% + \ifdim\pgf@xa>0pt% + \else% + \pgf@x=-\pgf@x% + \fi% + \ifdim\pgf@ya>0pt% + \else% + \pgf@y=-\pgf@y% + \fi% + \edef\pgf@marshal{% + \noexpand\pgfpointintersectionoflines + {\noexpand\pgfpointorigin} + {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}} + {\noexpand\pgfqpoint{\the\pgf@x}{0pt}} + {\noexpand\pgfqpoint{0pt}{\the\pgf@y}}% + }% + \pgf@process{\pgf@marshal}% + }% + + % + % Background path + % + \backgroundpath{ + \pgf@process{\outernortheast}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/outer ysep}}% + \advance\pgf@xc by-1.414213\pgf@xa% + \advance\pgf@yc by-1.414213\pgf@ya% + \pgfpathmoveto{\pgfqpoint{\pgf@xc}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{\pgf@yc}}% + \pgfpathlineto{\pgfqpoint{-\pgf@xc}{0pt}}% + \pgfpathlineto{\pgfqpoint{0pt}{-\pgf@yc}}% + \pgfpathclose% + }% +}% + + + + + + +\newif\ifpgf@lib@shapes@starouterradiususesratio +\pgf@lib@shapes@starouterradiususesratiotrue + +% Keys for star shape +% +% /pgf/star points : Number of points on the star. +% /pgf/star point height : The height of the outer star points. +% /pgf/star point ratio : The ratio of the outer point and inner point radii. + +\pgfkeys{/pgf/.cd, + star points/.initial=5, + star point height/.initial=.5cm, + star point height/.code={% + \def\pgf@lib@temp{#1}% + \pgfkeyslet{/pgf/star point height}{\pgf@lib@temp}% + \pgf@lib@shapes@starouterradiususesratiofalse% + }, + star point ratio/.initial=1.5, + star point ratio/.code={% + \def\pgf@lib@temp{#1}% + \pgfkeyslet{/pgf/star point ratio}{\pgf@lib@temp}% + \pgf@lib@shapes@starouterradiususesratiotrue% + },% + star rotate/.style={/pgf/shape border rotate={#1}},% For compatibility with 1.18 +}% + + +% Shape star. +% +\pgfdeclareshape{star}{% + \savedmacro\totalstarpoints{% + \pgfmathsetcounter{pgf@counta}{\pgfkeysvalueof{/pgf/star points}}% + \multiply\c@pgf@counta2\relax% + \edef\totalstarpoints{\the\c@pgf@counta}% + }% + \savedmacro\anglestep{% + \pgfmathdivide{180}{\pgfkeysvalueof{/pgf/star points}}% + \let\anglestep\pgfmathresult% + }% + \savedmacro\calculateradii{% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \ifdim\pgf@y>\pgf@x% + \pgf@x\pgf@y% + \fi% + % + % Calculate the incircle radius. + % + \pgf@x1.41421\pgf@x% + \edef\innerradius{\the\pgf@x}% + % + % Calculate the circumcircle radius. + % + % Use the star point height or the star point ratio? + % + \ifpgf@lib@shapes@starouterradiususesratio% + \pgfmathparse{\pgfkeysvalueof{/pgf/star point ratio}}% + \expandafter\pgf@x\pgfmathresult\pgf@x% + \else% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/star point height}}% + \fi% + \pgf@xc\pgf@x% + % + % Accommodate the larger of the minimum height/width. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@ya>\pgf@xa% + \pgf@xa\pgf@ya% + \fi% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \edef\outerradius{\the\pgf@x}% + % + % If the outer radius has been enlarged, adjust the inner radius... + % + \ifdim\pgf@x>\pgf@xc% + % + % ...using the star point ratio, or... + % + \ifpgf@lib@shapes@starouterradiususesratio% + \pgfmathreciprocal{\pgfkeysvalueof{/pgf/star point ratio}}% + \pgf@xa\pgfmathresult\pgf@x\relax% + \edef\innerradius{\the\pgf@xa}% + \else% + % + % The star point height. + % + \pgf@xa\pgf@x\relax% + \pgfmathaddtolength\pgf@xa{-\pgfkeysvalueof{/pgf/star point height}}% + \edef\innerradius{\the\pgf@xa}% + \fi% + \fi% + \edef\outerradius{\the\pgf@x}% + % + % Now calculate the anchor radii from the outer sep. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@ya>\pgf@xa% + \pgf@xa\pgf@ya% + \fi + % + % Take into account the miter length... + % + \pgfmathdivide{180}{\pgfkeysvalueof{/pgf/star points}}% + \let\angletofirstpoint\pgfmathresult% + \pgfmathmultiply@{\angletofirstpoint}{2}% + \let\angletosecondpoint\pgfmathresult% + % + % ...for the outer radius... + % + \pgfmathanglebetweenlines% + {\pgfqpointpolar{\angletofirstpoint}{\outerradius}}% + {\pgfqpointpolar{\angletosecondpoint}{\innerradius}}% + {\pgfqpointpolar{\angletofirstpoint}{\outerradius}}% + {\pgfqpointpolar{0}{\innerradius}}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfmathcosec@{\pgfmathresult}% + \pgf@x\outerradius\relax% + \advance\pgf@x\pgfmathresult\pgf@xa% + \edef\anchorouterradius{\the\pgf@x}% + % + % ...and for the inner radius. + % + \pgfmathanglebetweenlines% + {\pgfqpointpolar{\angletofirstpoint}{\innerradius}}% + {\pgfqpointpolar{0}{\outerradius}}% + {\pgfqpointpolar{\angletofirstpoint}{\innerradius}}% + {\pgfqpointpolar{\angletosecondpoint}{\outerradius}}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfmathcosec@{\pgfmathresult}% + \pgf@x\innerradius\relax% + \advance\pgf@x\pgfmathresult\pgf@xa% + \edef\anchorinnerradius{\the\pgf@x}% + % + % Save all radii. + % + \addtosavedmacro{\innerradius}% + \addtosavedmacro{\outerradius}% + \addtosavedmacro{\anchorinnerradius}% + \addtosavedmacro{\anchorouterradius}% + }% + \savedmacro\startangle{% + \pgfmathadd{90}{\pgfkeysvalueof{/pgf/shape border rotate}}% + \let\startangle\pgfmathresult% + }% + % + % Saved anchors. + % + \savedanchor{\centerpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor{\midpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % + % Other anchors. + % + \anchor{center}{\centerpoint}% + \anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}% + \anchor{base}{\centerpoint\pgf@y=0pt}% + \anchor{north}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{0pt}{\anchorouterradius}}}% + \anchor{south}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{0pt}{-\anchorouterradius}}}% + \anchor{east}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{\anchorouterradius}{0pt}}}% + \anchor{west}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{-\anchorouterradius}{0pt}}}% + \anchor{north east}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{\anchorouterradius}{\anchorouterradius}}}% + \anchor{north west}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{-\anchorouterradius}{\anchorouterradius}}}% + \anchor{south east}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{\anchorouterradius}{-\anchorouterradius}}}% + \anchor{south west}{% + \calculateradii% + \csname pgf@anchor@star@border\endcsname{\pgfqpoint{-\anchorouterradius}{-\anchorouterradius}}}% + % + % Background path. + % + \backgroundpath{% + \calculateradii% + \let\angle\startangle% + \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{\startangle}{\outerradius}}}% + \pgfmathloop% + \pgfmathadd@{\angle}{\anglestep}% + \let\angle\pgfmathresult% + \ifnum\pgfmathcounter=\totalstarpoints% + \pgfpathclose% + \else% + \ifodd\pgfmathcounter + \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{\angle}{\innerradius}}}% + \else% + \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpointpolar{\angle}{\outerradius}}}% + \fi% + \repeatpgfmathloop% + }% + % + % Define points on the anchor border. + % + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Adjust the location of the external + % point relative to \centerpoint. + % + \centerpoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Get the angle of the external point to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + % + % Locate the appropriate sides on the star border... + % + \pgfmathsubtract@{\pgfmathresult}{\startangle}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \pgfmathdivide@{\pgfmathresult}{\anglestep}% + \pgfmathfloor@{\pgfmathresult}% + \afterassignment\pgfmath@gobbletilpgfmath@ + \c@pgf@counta\pgfmathresult\relax\pgfmath@ + \pgfmathmultiply@{\pgfmathresult}{\anglestep}% + \pgfmathadd@{\pgfmathresult}{\startangle}% + \let\firstangle\pgfmathresult% + \pgfmathadd@{\pgfmathresult}{\anglestep}% + \let\secondangle\pgfmathresult% + \calculateradii% + % + % ...and thus, the point on the star border. + % + \ifodd\c@pgf@counta + \pgfpointintersectionoflines{\centerpoint}{\pgfpoint{+\externalx}{+\externaly}}% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\firstangle}{+\anchorinnerradius}}% + }% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\secondangle}{+\anchorouterradius}}% + }% + \else% + \pgfpointintersectionoflines{\centerpoint}{\pgfpoint{+\externalx}{+\externaly}}% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\firstangle}{+\anchorouterradius}}% + }% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\secondangle}{+\anchorinnerradius}}% + }% + \fi% + }% + % + % Some hackery. This is needed if a star is positioned using + % a `...point ' anchor, where n is the maximum number of + % points of any previously drawn star. + % + \pgfutil@g@addto@macro\pgf@sh@s@star{% + \c@pgf@counta\totalstarpoints\relax% + \divide\c@pgf@counta2\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \c@pgf@countb\c@pgf@counta\relax% + \advance\c@pgf@countb-1\relax% + \pgfutil@ifundefined{pgf@anchor@star@inner point\space\the\c@pgf@counta}{% + \expandafter\xdef\csname pgf@anchor@star@inner point\space\the\c@pgf@counta\endcsname{% + \noexpand\calculateradii% + \noexpand\pgfmathmultiply@{\the\c@pgf@countb}{\noexpand\anglestep}% + \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{2}% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\anglestep}% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}% + \noexpand\let\noexpand\angle\noexpand\pgfmathresult% + \noexpand\pgfpointadd{\noexpand\centerpoint}% + {\noexpand\pgfqpointpolar{\noexpand\angle}{\noexpand\anchorinnerradius}}% + }% + \expandafter\xdef\csname pgf@anchor@star@outer point\space\the\c@pgf@counta\endcsname{% + \noexpand\calculateradii% + \noexpand\pgfmathmultiply@{\the\c@pgf@countb}{\noexpand\anglestep}% + \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{2}% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}% + \noexpand\let\noexpand\angle\noexpand\pgfmathresult% + \noexpand\pgfpointadd{\noexpand\centerpoint}% + {\noexpand\pgfqpointpolar{\noexpand\angle}{\noexpand\anchorouterradius}}% + }% + }{\c@pgf@counta0\relax}% + \advance\c@pgf@counta-1\relax% + \repeatpgfmathloop% + }% +}% + + + + +% Keys for shape regular polygon +% +% /pgf/regular polygon sides +% +\pgfkeys{/pgf/.cd, + regular polygon sides/.initial=5, + regular polygon rotate/.style={/pgf/shape border rotate={#1}}% For compatibility with 1.18 +}% + + +% Shape Regular Polygon. +% +\pgfdeclareshape{regular polygon}{% + \savedmacro\sides{% + \pgfmathtruncatemacro\sides{\pgfkeysvalueof{/pgf/regular polygon sides}}% + }% + \savedmacro\anglestep{% + \pgfmathdivide{360}{\pgfkeysvalueof{/pgf/regular polygon sides}}% + \let\anglestep\pgfmathresult% + }% + \savedmacro\calculateradii{% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \ifdim\pgf@y>\pgf@x% + \pgf@x\pgf@y% + \fi% + % + % Calculate i, the incircle radius + % + \pgf@x1.41421\pgf@x% + % + % Calculate r, the polygon radius + % + % r = i / cos(360 / s / 2) + % + % (s = polygon sides) + % + \pgfmathdivide{180}{\pgfkeysvalueof{/pgf/regular polygon sides}}% + \pgfmathsec@{\pgfmathresult}% + \pgf@x\pgfmathresult\pgf@x% + % + % Accommodate the minimum width/height. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@ya>\pgf@xa% + \pgf@xa\pgf@ya% + \fi% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \edef\radius{\the\pgf@x}% + % + % Now calculate the anchor radius from the outer sep. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@ya>\pgf@xa% + \pgf@xa\pgf@ya% + \fi + % + % Take into account the miter length. + % + % m = o / sin (90 - (360 / s / 2)) + % + % (o = outer sep, s = sides) + % + \pgfmathdivide{180}{\pgfkeysvalueof{/pgf/regular polygon sides}}% + \pgfmathsubtract@{90}{\pgfmathresult}% + \pgfmathcosec@{\pgfmathresult}% + \advance\pgf@x\pgfmathresult\pgf@xa% + \edef\anchorradius{\the\pgf@x}% + % + % Save both radii. + % + \addtosavedmacro{\radius}% + \addtosavedmacro{\anchorradius}% + }% + \savedmacro\startangle{% + \pgfmathdivide{360}{\pgfkeysvalueof{/pgf/regular polygon sides}}% + \let\anglestep\pgfmathresult% + \pgfmathtruncatemacro\sides{\pgfkeysvalueof{/pgf/regular polygon sides}}% + \expandafter\ifodd\sides\relax% + \edef\pgfmathresult{90}% + \else% + \pgfmathdivide@{\anglestep}{2}% + \pgfmathsubtract@{90}{\pgfmathresult}% + \fi% + \pgfmathadd{\pgfmathresult}{\pgfkeysvalueof{/pgf/shape border rotate}}% + \let\startangle\pgfmathresult% + }% + % + % Saved anchors. + % + \savedanchor{\centerpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor{\midpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % Other anchors. + % + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{base}{\centerpoint\pgf@y=0pt}% + \anchor{north}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{0pt}{\anchorradius}}}% + \anchor{south}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{0pt}{-\anchorradius}}}% + \anchor{east}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{\anchorradius}{0pt}}}% + \anchor{west}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{-\anchorradius}{0pt}}}% + \anchor{north east}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{\anchorradius}{\anchorradius}}}% + \anchor{north west}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{-\anchorradius}{\anchorradius}}}% + \anchor{south east}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{\anchorradius}{-\anchorradius}}}% + \anchor{south west}{% + \calculateradii% + \csname pgf@anchor@regular polygon@border\endcsname{\pgfqpoint{-\anchorradius}{-\anchorradius}}}% + % + % Background path. + % + \backgroundpath{% + \calculateradii% + \pgfpathmoveto{% + \pgfpointadd{\centerpoint}{\pgfqpointpolar{\startangle}{\radius}}% + }% + \let\angle\startangle% + \pgfmathloop% + \ifnum\pgfmathcounter=\sides\relax% + \pgfpathclose% + \else% + \pgfmathadd@{\angle}{\anglestep}% + \let\angle\pgfmathresult% + \pgfpathlineto{% + \pgfpointadd{\centerpoint}{\pgfqpointpolar{\angle}{\radius}}% + }% + \repeatpgfmathloop% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Adjust the location of the external + % point relative to \centerpoint. + % + \centerpoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Get the angle of the external point to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + % + % Locate the appropriate sides on the polygon border... + % + \pgfmathsubtract@{\pgfmathresult}{\startangle}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \pgfmathdivide@{\pgfmathresult}{\anglestep}% + \pgfmathfloor@{\pgfmathresult}% + \pgfmathmultiply@{\pgfmathresult}{\anglestep}% + \pgfmathadd@{\pgfmathresult}{\startangle}% + \let\firstangle\pgfmathresult% + \pgfmathadd@{\pgfmathresult}{\anglestep}% + \let\secondangle\pgfmathresult% + \calculateradii% + % + % ...and thus, the point on the polygon border. + % + \pgfpointintersectionoflines{\centerpoint}{\pgfpoint{+\externalx}{+\externaly}}% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\firstangle}{+\anchorradius}}% + }% + {% + \pgfpointadd{\centerpoint}% + {\pgfqpointpolar{+\secondangle}{+\anchorradius}}% + }% + }% + % + % More hackery for when the rectangular polygon is positioned using + % a `corner ' or `side ' anchor, where n is the maximum + % number of sides of any previously drawn regular polygon. + % + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@regular polygon\endcsname{% + \c@pgf@counta\sides\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \pgfutil@ifundefined{pgf@anchor@regular polygon@corner\space\the\c@pgf@counta}{% + % + % ...(manually \xdef as \gdef is normally used by \anchor)... + % + \expandafter\xdef\csname pgf@anchor@regular polygon@corner\space\the\c@pgf@counta\endcsname{% + \noexpand\calculateradii% + \noexpand\pgfmathsubtract@{\the\c@pgf@counta}{1}% + \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{\noexpand\anglestep}% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}% + \noexpand\let\noexpand\angle\noexpand\pgfmathresult% + \noexpand\pgfpointadd{\noexpand\centerpoint}% + {\noexpand\pgfqpointpolar{\noexpand\angle}{\noexpand\anchorradius}}% + }% + \expandafter\xdef\csname pgf@anchor@regular polygon@side\space\the\c@pgf@counta\endcsname{% + \noexpand\calculateradii% + \noexpand\pgfmathsubtract@{\the\c@pgf@counta}{1}% + \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{\noexpand\anglestep}% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}% + \noexpand\let\noexpand\firstangle\noexpand\pgfmathresult% + \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\anglestep}% + \noexpand\let\noexpand\secondangle\noexpand\pgfmathresult% + \noexpand\pgfpointlineattime{0.5}% + {\noexpand\pgfpointadd{\noexpand\centerpoint}% + {\noexpand\pgfqpointpolar{\noexpand\firstangle}{\noexpand\anchorradius}}}% + {\noexpand\pgfpointadd{\noexpand\centerpoint}% + {\noexpand\pgfqpointpolar{\noexpand\secondangle}{\noexpand\anchorradius}}}% + }% + }{\c@pgf@counta0\relax}% + \advance\c@pgf@counta-1\relax% + \repeatpgfmathloop% + }% +}% + + + +% Keys for shape trapezium +% +% /pgf/trapezium left angle : angle of the left side. +% /pgf/trapezium right angle : angle of the right side. + +\pgfkeys{/pgf/.cd, + trapezium left angle/.initial=60, + trapezium right angle/.initial=60, + trapezium angle/.style={ + /pgf/trapezium left angle={#1}, + /pgf/trapezium right angle={#1} + },% + trapezium stretches/.is if=pgf@lib@sh@trapeziumstretches,% + trapezium stretches body/.is if=pgf@lib@sh@trapeziumstretchesbody,% +}% + +\newif\ifpgf@lib@sh@trapeziumstretchesbody +\newif\ifpgf@lib@sh@trapeziumstretches + + +% Shape trapezium. +% +\pgfdeclareshape{trapezium}{% + \savedmacro\installtrapeziumparameters{% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \ifpgfshapeborderusesincircle% + % + % Get the rotation (no rounding). + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + % + % Use the radius of the incircle if required... + % + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + \pgf@y\pgf@x% + \else% + % + % Get the rotation (with rounding). + % + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + \fi% + \pgfmathmod{\pgfkeysvalueof{/pgf/trapezium left angle}}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\leftangle\pgfmathresult% + \ifdim\leftangle pt=0pt\relax% + \def\pgfmathresult{0}% + \else% + \pgfmathcot@{\leftangle}% + \fi% + \pgf@xa2\pgf@y% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfmathmod{\pgfkeysvalueof{/pgf/trapezium right angle}}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\rightangle\pgfmathresult% + \ifdim\rightangle pt=0pt\relax% + \def\pgfmathresult{0}% + \else% + \pgfmathcot@{\rightangle}% + \fi% + \pgf@xb2\pgf@y% + \pgf@xb\pgfmathresult\pgf@xb% + % + % Take into account minimum height and width. + % + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@ya% + \ifpgf@lib@sh@trapeziumstretches% + \pgf@y.5\pgf@ya% + \else% + \ifpgf@lib@sh@trapeziumstretchesbody% + \pgf@y.5\pgf@ya% + \else% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@y}}% + \pgf@yb.5\pgf@ya% + \pgf@yb\pgfmathresult\pgf@yb% + \pgf@y.5\pgf@ya% + \pgf@x\pgfmath@tonumber{\pgf@yb}\pgf@x% + \pgf@xa\pgfmath@tonumber{\pgf@yb}\pgf@xa% + \pgf@xb\pgfmath@tonumber{\pgf@yb}\pgf@xb% + \fi% + \fi% + \fi% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@xc2\pgf@x% + \ifdim\pgf@xa<0pt\relax% + \advance\pgf@xc-\pgf@xa% + \else% + \advance\pgf@xc\pgf@xa% + \fi% + \ifdim\pgf@xb<0pt\relax% + \advance\pgf@xc-\pgf@xb% + \else% + \advance\pgf@xc\pgf@xb% + \fi% + \ifdim\pgf@xc<\pgf@ya% + \ifpgf@lib@sh@trapeziumstretchesbody% + \pgf@xc-\pgf@xc% + \advance\pgf@xc\pgf@ya% + \advance\pgf@x.5\pgf@xc% + \else% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@xc}}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgf@x\pgfmath@tonumber{\pgf@ya}\pgf@x% + \pgf@xa\pgfmath@tonumber{\pgf@ya}\pgf@xa% + \pgf@xb\pgfmath@tonumber{\pgf@ya}\pgf@xb% + \ifpgf@lib@sh@trapeziumstretches% + \else% + \pgf@y\pgfmath@tonumber{\pgf@ya}\pgf@y% + \fi% + \fi% + \fi% + \edef\halfheight{\the\pgf@y}% + \edef\halfwidth{\the\pgf@x}% + \edef\leftextension{\the\pgf@xa}% + \edef\rightextension{\the\pgf@xb}% + \pgf@xc2\pgf@x% + % + % Take the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@y>\pgf@x% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % The \externalradius is a length that is + % guarenteed to produce a point outside the trapezium. + % + \advance\pgf@xc2.0\pgf@x% + \pgf@yc\halfheight\relax% + \multiply\pgf@yc2\relax% + \advance\pgf@yc2.0\pgf@x% + \ifdim\pgf@xc<\pgf@yc% + \edef\externalradius{\the\pgf@yc}% + \else% + \edef\externalradius{\the\pgf@xc}% + \fi% + % + % Calculate the centre base and mid poins of the node. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \pgfextract@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \pgfextract@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % Calculate each point on the trapezium (without rotation). + % + \pgfextract@process\lowerleftpoint{% + \centerpoint% + \advance\pgf@x-\halfwidth\relax% + \ifdim\leftextension>0pt\relax% + \advance\pgf@x-\leftextension\relax% + \fi% + \advance\pgf@y-\halfheight\relax% + }% + \pgfextract@process\upperleftpoint{% + \centerpoint% + \advance\pgf@x-\halfwidth\relax% + \ifdim\leftextension<0pt\relax% + \advance\pgf@x\leftextension\relax% + \fi% + \advance\pgf@y\halfheight\relax% + }% + \pgfextract@process\upperrightpoint{% + \centerpoint% + \advance\pgf@x\halfwidth\relax% + \ifdim\rightextension<0pt\relax% + \advance\pgf@x-\rightextension\relax% + \fi% + \advance\pgf@y\halfheight\relax% + }% + \pgfextract@process\lowerrightpoint{% + \centerpoint% + \advance\pgf@x\halfwidth\relax% + \ifdim\rightextension>0pt\relax% + \advance\pgf@x\rightextension\relax% + \fi% + \advance\pgf@y-\halfheight\relax% + }% + % + % Now calculate the adjustment for the miter length at each corner + % of the trapezium. This ensures more accurate anchor positioning + % when the line width is particularly thick. + % + \pgfextract@process\lowerleftmiter{% + \pgfmathanglebetweenlines{\lowerleftpoint}{\lowerrightpoint}{\lowerleftpoint}{\upperleftpoint}% + \pgfmathmultiply@{\pgfmathresult}{.5}% + \pgfmathtan@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@x-\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y-\outersep\relax% + }% + \pgfextract@process\upperleftmiter{% + \pgfmathanglebetweenlines{\upperleftpoint}{\lowerleftpoint}{\upperleftpoint}{\upperrightpoint}% + \pgfmathmultiply@{\pgfmathresult}{.5}% + \pgfmathtan@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@x-\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y\outersep\relax% + }% + \pgfextract@process\upperrightmiter{% + \pgfmathanglebetweenlines{\upperrightpoint}{\upperleftpoint}{\upperrightpoint}{\lowerrightpoint}% + \pgfmathmultiply@{\pgfmathresult}{.5}% + \pgfmathtan@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y\outersep\relax% + }% + \pgfextract@process\lowerrightmiter{% + \pgfmathanglebetweenlines{\lowerrightpoint}{\upperrightpoint}{\lowerrightpoint}{\lowerleftpoint}% + \pgfmathmultiply@{\pgfmathresult}{.5}% + \pgfmathtan@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y-\outersep\relax% + }% + % + % Now calculate the corners for determining anchor border + % points, by adding the adjustment for the miter length. + % + \pgfextract@process\lowerleftborderpoint{% + \pgfpointadd{\lowerleftpoint}{\lowerleftmiter}% + }% + \pgfextract@process\upperleftborderpoint{% + \pgfpointadd{\upperleftpoint}{\upperleftmiter}% + }% + \pgfextract@process\upperrightborderpoint{% + \pgfpointadd{\upperrightpoint}{\upperrightmiter}% + }% + \pgfextract@process\lowerrightborderpoint{% + \pgfpointadd{\lowerrightpoint}{\lowerrightmiter}% + }% + % + % Calculate the angle from the centerpoint to each corner. + % Rotation is not important here (see \anchorborder code). + % + \pgfmathanglebetweenpoints{\centerpoint}{\lowerleftborderpoint}% + \let\angletolowerleft\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\upperleftborderpoint}% + \let\angletoupperleft\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\upperrightborderpoint}% + \let\angletoupperright\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\lowerrightborderpoint}% + \let\angletolowerright\pgfmathresult% + % + % Do the same for the *inversely rotated* base point... + % + \pgfextract@process\rotatedbasepoint{% + \pgfmathrotatepointaround{\basepoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\lowerleftborderpoint}% + \let\baseangletolowerleft\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\upperleftborderpoint}% + \let\baseangletoupperleft\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\upperrightborderpoint}% + \let\baseangletoupperright\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\lowerrightborderpoint}% + \let\baseangletolowerright\pgfmathresult% + % + % And the *inversely rotated* mid point... + % + \pgfextract@process\rotatedmidpoint{% + \pgfmathrotatepointaround{\midpoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\lowerleftborderpoint}% + \let\midangletolowerleft\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\upperleftborderpoint}% + \let\midangletoupperleft\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\upperrightborderpoint}% + \let\midangletoupperright\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\lowerrightborderpoint}% + \let\midangletolowerright\pgfmathresult% + % + % Now rotate the border points around the centerpoint... + % + \pgfextract@process\lowerleftborderpoint{% + \pgfmathrotatepointaround% + {\lowerleftborderpoint}% + {\centerpoint}% + {\rotate}% + }% + \pgfextract@process\upperleftborderpoint{% + \pgfmathrotatepointaround% + {\upperleftborderpoint}% + {\centerpoint}% + {\rotate}% + }% + \pgfextract@process\upperrightborderpoint{% + \pgfmathrotatepointaround% + {\upperrightborderpoint}% + {\centerpoint}% + {\rotate}% + }% + \pgfextract@process\lowerrightborderpoint{% + \pgfmathrotatepointaround% + {\lowerrightborderpoint}% + {\centerpoint}% + {\rotate}% + }% + % + % ...and the points for drawing the border (i.e. no outer sep). + % + \pgfextract@process\lowerleftpoint{% + \pgfmathrotatepointaround{\lowerleftpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\upperleftpoint{% + \pgfmathrotatepointaround{\upperleftpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\upperrightpoint{% + \pgfmathrotatepointaround{\upperrightpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\lowerrightpoint{% + \pgfmathrotatepointaround{\lowerrightpoint}{\centerpoint}{\rotate}% + }% + % + % And finally, save all the relevant stuff. + % + \addtosavedmacro{\lowerleftpoint}% + \addtosavedmacro{\upperleftpoint}% + \addtosavedmacro{\upperrightpoint}% + \addtosavedmacro{\lowerrightpoint}% + % + \addtosavedmacro{\lowerleftborderpoint}% + \addtosavedmacro{\upperleftborderpoint}% + \addtosavedmacro{\upperrightborderpoint}% + \addtosavedmacro{\lowerrightborderpoint}% + % + \addtosavedmacro{\angletolowerleft}% + \addtosavedmacro{\angletoupperleft}% + \addtosavedmacro{\angletoupperright}% + \addtosavedmacro{\angletolowerright}% + % + \addtosavedmacro{\baseangletolowerleft}% + \addtosavedmacro{\baseangletoupperleft}% + \addtosavedmacro{\baseangletoupperright}% + \addtosavedmacro{\baseangletolowerright}% + % + \addtosavedmacro{\midangletolowerleft}% + \addtosavedmacro{\midangletoupperleft}% + \addtosavedmacro{\midangletoupperright}% + \addtosavedmacro{\midangletolowerright}% + % + \addtosavedmacro{\rotate}% + \addtosavedmacro{\externalradius}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \installtrapeziumparameters% + \let\pgf@trapeziumanchorborderreferencepoint\basepoint% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{base west}{% + \installtrapeziumparameters% + \let\pgf@trapeziumanchorborderreferencepoint\basepoint% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \installtrapeziumparameters% + \let\pgf@trapeziumanchorborderreferencepoint\midpoint% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid west}{% + \installtrapeziumparameters% + \let\pgf@trapeziumanchorborderreferencepoint\midpoint% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south west}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{south east}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \installtrapeziumparameters% + \csname pgf@anchor@trapezium@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{bottom left corner}{% + \installtrapeziumparameters% + \lowerleftborderpoint% + }% + \anchor{top left corner}{% + \installtrapeziumparameters% + \upperleftborderpoint% + }% + \anchor{top right corner}{% + \installtrapeziumparameters% + \upperrightborderpoint% + }% + \anchor{bottom right corner}{% + \installtrapeziumparameters% + \lowerrightborderpoint% + }% + \anchor{left side}{% + \installtrapeziumparameters% + \pgfpointlineattime{0.5}{\lowerleftborderpoint}{\upperleftborderpoint}% + }% + \anchor{right side}{% + \installtrapeziumparameters% + \pgfpointlineattime{0.5}{\lowerrightborderpoint}{\upperrightborderpoint}% + }% + \anchor{top side}{% + \installtrapeziumparameters% + \pgfpointlineattime{0.5}{\upperleftborderpoint}{\upperrightborderpoint}% + }% + \anchor{bottom side}{% + \installtrapeziumparameters% + \pgfpointlineattime{0.5}{\lowerleftborderpoint}{\lowerrightborderpoint}% + }% + \backgroundpath{% + \installtrapeziumparameters% + \pgfpathmoveto{\lowerleftpoint}% + \pgfpathlineto{\upperleftpoint}% + \pgfpathlineto{\upperrightpoint}% + \pgfpathlineto{\lowerrightpoint}% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % This allows anchors base east, base west, mid east and mid west, + % to redefine the `center' of the node to correctly calculate the + % border points. + % + \pgfutil@ifundefined{pgf@trapeziumanchorborderreferencepoint}% + {\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@trapeziumanchorborderreferencepoint}% + % + % Adjust the location of the external + % point relative to the reference point. + % + \referencepoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Install the required points and angles. + % + \installtrapeziumparameters% + % + % Get the angle of the external point to the \referencepoint. + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + % + % *Subtract* the rotation from the external angle. This is + % why the border point angles do not neeed to be rotated. + % + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + % + % Get the relevant angles for the reference point. + % + \let\externalangle\pgfmathresult% + \ifx\referencepoint\basepoint% + \let\angletoupperright\baseangletoupperright% + \let\angletoupperleft\baseangletoupperleft% + \let\angletolowerright\baseangletolowerright% + \let\angletolowerleft\baseangletolowerleft% + \else% + \ifx\referencepoint\midpoint% + \let\angletoupperright\midangletoupperright% + \let\angletoupperleft\midangletoupperleft% + \let\angletolowerright\midangletolowerright% + \let\angletolowerleft\midangletolowerleft% + \fi\fi% + % + % Find the line on the border... + % + \ifdim\externalangle pt<\angletoupperright pt\relax% + \let\firstpoint\upperrightborderpoint% + \let\secondpoint\lowerrightborderpoint% + \else% + \ifdim\externalangle pt<\angletoupperleft pt\relax% + \let\firstpoint\upperleftborderpoint% + \let\secondpoint\upperrightborderpoint% + \else% + \ifdim\externalangle pt<\angletolowerleft pt\relax% + \let\firstpoint\upperleftborderpoint% + \let\secondpoint\lowerleftborderpoint% + \else% + \ifdim\externalangle pt<\angletolowerright pt\relax% + \let\firstpoint\lowerleftborderpoint% + \let\secondpoint\lowerrightborderpoint% + \else% + \let\firstpoint\upperrightborderpoint% + \let\secondpoint\lowerrightborderpoint% + \fi% + \fi% + \fi% + \fi% + % + % ...and thus the point on the border. + % + \pgfpointintersectionoflines{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + }% +}% + + + + +% Shape semicircle. +% +\pgfdeclareshape{semicircle}{% + \savedmacro\installsemicircleparameters{% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x+.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y+.5\ht\pgfnodeparttextbox% + \advance\pgf@y+.5\dp\pgfnodeparttextbox% + % + % Use the radius of the incircle if required... + % + \ifpgfshapeborderusesincircle% + % + % Get the rotation (no rounding). + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + \edef\halfheight{\the\pgf@x}% + \advance\pgf@x\pgf@x% + \else% + % + % Get the rotation (with rounding). + % + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + \advance\pgf@y\pgf@y% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \pgf@x\pgfmathresult pt\relax% + \pgf@y.5\pgf@y% + \edef\halfheight{\the\pgf@y}% + \fi% + \edef\defaultradius{\the\pgf@x}% + % + % Take into account minimum height and width. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<\pgf@ya% + \pgf@x\pgf@ya% + \fi% + \edef\semicircleradius{\the\pgf@x}% + % + % Find the center/base/mid of the semi circle node. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y+-.5\dp\pgfnodeparttextbox% + }% + \pgfextract@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \pgfextract@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \pgfextract@process\semicirclecenterpoint{% + \centerpoint% + \pgf@ya\semicircleradius\relax% + \advance\pgf@ya-\defaultradius\relax% + % + % The point is adjusted to make the node contents + % appear more centered if the node is enlarged to + % some minimum size. The factor .4 just seems OK. + % + \pgf@ya.4\pgf@ya% + \advance\pgf@y-\pgf@ya% + \pgf@ya\halfheight\relax% + \advance\pgf@y-\pgf@ya% + }% + % + % Add the outer sep to the radius here. + % + \pgf@x\semicircleradius\relax% + \advance\pgf@x\outersep\relax% + \edef\semicircleradius{\the\pgf@x}% + \pgfpointdiff{\centerpoint}{\semicirclecenterpoint}% + \ifdim\pgf@y<0pt\pgf@y-\pgf@y\fi% + \edef\centerpointdiff{\the\pgf@y}% + % + % Calculate the start and end points on the border. + % + \pgfextract@process\arcstartborder{% + \semicirclecenterpoint% + \advance\pgf@x\semicircleradius\relax% + }% + \pgfextract@process\arcendborder{% + \semicirclecenterpoint% + \advance\pgf@x-\semicircleradius\relax% + }% + % + % Calculate the start and end *corner* points on the border. + % This is needed to accommodate the outer sep. + % + \pgfextract@process\arcstartcorner{% + \arcstartborder% + \advance\pgf@y-\outersep\relax% + }% + \pgfextract@process\arcendcorner{% + \arcendborder% + \advance\pgf@y-\outersep\relax% + } + % + % Now calculate all the relevant angles. + % + % For the center point. + % + \pgfmathanglebetweenpoints{\centerpoint}{\arcstartborder}% + \let\angletoarcstartborder\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcendborder}% + \let\angletoarcendborder\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcstartcorner}% + \let\angletoarcstartcorner\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcendcorner}% + \let\angletoarcendcorner\pgfmathresult% + % + % For the basepoint (rotated about the center point). + % + \pgfextract@process\rotatedbasepoint{% + \pgfmathrotatepointaround{\basepoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\arcstartborder}% + \let\baseangletoarcstartborder\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\arcendborder}% + \let\baseangletoarcendborder\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\arcstartcorner}% + \let\baseangletoarcstartcorner\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\arcendcorner}% + \let\baseangletoarcendcorner\pgfmathresult% + % + % For the midpoint (rotated about the center point). + % + \pgfextract@process\rotatedmidpoint{% + \pgfmathrotatepointaround{\midpoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\arcstartborder}% + \let\midangletoarcstartborder\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\arcendborder}% + \let\midangletoarcendborder\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\arcstartcorner}% + \let\midangletoarcstartcorner\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\arcendcorner}% + \let\midangletoarcendcorner\pgfmathresult% + % + % Now, rotate the semicircle points around the centerpoint. + % + \pgfextract@process\semicirclecenterpoint{% + \pgfmathrotatepointaround{\semicirclecenterpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcstartborder{% + \pgfmathrotatepointaround{\arcstartborder}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcendborder{% + \pgfmathrotatepointaround{\arcendborder}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcstartcorner{% + \pgfmathrotatepointaround{\arcstartcorner}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcendcorner{% + \pgfmathrotatepointaround{\arcendcorner}{\centerpoint}{\rotate}% + }% + % + % Calculate the distance between the base point and the (rotated) semicircle center. + % + \pgfpointdiff{\basepoint}{\semicirclecenterpoint}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \edef\basesemicirclecenterdiff{\pgfmathresult pt}% + % + % Calculate the distance between the base point and the (rotated) semicircle center. + % + \pgfpointdiff{\midpoint}{\semicirclecenterpoint}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}% + \edef\midsemicirclecenterdiff{\pgfmathresult pt}% + % + % And save all the stuff. + % + \addtosavedmacro{\rotate}% + \addtosavedmacro{\outersep}% + \addtosavedmacro{\semicircleradius}% + % + \addtosavedmacro{\arcstartborder}% + \addtosavedmacro{\arcendborder}% + \addtosavedmacro{\arcstartcorner}% + \addtosavedmacro{\arcendcorner}% + \addtosavedmacro{\semicirclecenterpoint}% + % + \addtosavedmacro{\angletoarcstartborder}% + \addtosavedmacro{\angletoarcendborder}% + \addtosavedmacro{\angletoarcstartcorner}% + \addtosavedmacro{\angletoarcendcorner}% + % + \addtosavedmacro{\centerpointdiff}% + \addtosavedmacro{\basesemicirclecenterdiff}% + \addtosavedmacro{\midsemicirclecenterdiff}% + % + \addtosavedmacro{\baseangletoarcstartborder}% + \addtosavedmacro{\baseangletoarcendborder}% + \addtosavedmacro{\baseangletoarcstartcorner}% + \addtosavedmacro{\baseangletoarcendcorner}% + % + \addtosavedmacro{\midangletoarcstartborder}% + \addtosavedmacro{\midangletoarcendborder}% + \addtosavedmacro{\midangletoarcstartcorner}% + \addtosavedmacro{\midangletoarcendcorner}% + }% + \savedanchor{\centerpoint}{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5\ht\pgfnodeparttextbox}% + \pgfmathaddtolength\pgf@y{-.5\dp\pgfnodeparttextbox}% + }% + \savedanchor{\basepoint}{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgf@y0pt\relax% + }% + \savedanchor{\midpoint}{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \installsemicircleparameters% + \let\pgf@semicirclereferencepoint\basepoint% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpoint{-\semicircleradius}{0pt}}% + }% + \anchor{base east}{% + \installsemicircleparameters% + \let\pgf@semicirclereferencepoint\basepoint% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpoint{\semicircleradius}{0pt}}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \installsemicircleparameters% + \let\pgf@semicirclereferencepoint\midpoint% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpoint{-\semicircleradius}{0pt}}% + }% + \anchor{mid east}{% + \installsemicircleparameters% + \let\pgf@semicirclereferencepoint\midpoint% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpoint{\semicircleradius}{0pt}}% + }% + \anchor{apex}{% + \installsemicircleparameters% + \pgfmathadd@{\rotate}{90}% + \let\angle\pgfmathresult% + \pgfpointadd{\semicirclecenterpoint}{\pgfqpointpolar{\angle}{\semicircleradius}}% + }% + \anchor{arc start}{% + \installsemicircleparameters% + \arcstartcorner% + }% + \anchor{arc end}{% + \installsemicircleparameters% + \arcendcorner% + }% + \anchor{chord center}{% + \installsemicircleparameters% + \pgfpointlineattime{0.5}{\arcstartcorner}{\arcendcorner}% + }% + \anchor{north}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{90}{\semicircleradius}}% + }% + \anchor{south}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{270}{\semicircleradius}}% + }% + \anchor{east}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{0}{\semicircleradius}}% + }% + \anchor{west}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{180}{\semicircleradius}}% + }% + \anchor{north west}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{135}{\semicircleradius}}% + }% + \anchor{south west}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{225}{\semicircleradius}}% + }% + \anchor{north east}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{45}{\semicircleradius}}% + }% + \anchor{south east}{% + \installsemicircleparameters% + \csname pgf@anchor@semicircle@border\endcsname{\pgfqpointpolar{315}{\semicircleradius}}% + }% + \backgroundpath{% + \installsemicircleparameters% + \pgf@x\semicircleradius\relax% + \advance\pgf@x-\outersep\relax% + \edef\semicircleradius{\the\pgf@x}% + \pgfpathmoveto{\pgfpointadd{\semicirclecenterpoint}{\pgfqpointpolar{\rotate}{\semicircleradius}}}% + {% + \pgftransformrotate{\rotate}% + \pgfpatharc{0}{180}{\semicircleradius}% + \pgfpathclose% + }% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Check if a reference point has been defined (i.e. \midpoint or \basepoint). + % + \pgfutil@ifundefined{pgf@semicirclereferencepoint}% + {\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@semicirclereferencepoint}% + % + % Adjust the location of the external point relative to the reference point. + % + \referencepoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Install the required points and angles. + % + \installsemicircleparameters% + % + % Get the angle of the external point to the \referencepoint. + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + \let\externalangle\pgfmathresult% + % + % *Subtract* the rotation from the external angle. + % + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\angle\pgfmathresult% + \ifx\referencepoint\basepoint% + \let\angletoarcstartborder\baseangletoarcstartborder% + \let\angletoarcendborder\baseangletoarcendborder% + \let\angletoarcstartcorner\baseangletoarcstartcorner% + \let\angletoarcendcorner\baseangletoarcendcorner% + \let\centerpointdiff\basesemicirclecenterdiff% + \else% + \ifx\referencepoint\midpoint% + \let\angletoarcstartborder\midangletoarcstartborder% + \let\angletoarcendborder\midangletoarcendborder% + \let\angletoarcstartcorner\midangletoarcstartcorner% + \let\angletoarcendcorner\midangletoarcendcorner% + \let\centerpointdiff\midsemicirclecenterdiff% + \fi\fi% + % + % Determine if the line will cross the semicircle arc, or the chord. + % + \ifdim\angle pt>\angletoarcstartborder pt\relax% + \let\firstpoint\pgfutil@empty% + \let\secondpoint\pgfutil@empty% + \else% + \ifdim\angle pt>\angletoarcstartcorner pt\relax% + \let\firstpoint\arcstartcorner% + \let\secondpoint\arcstartborder% + \else% + \ifdim\angle pt>\angletoarcendcorner pt\relax% + \let\firstpoint\arcendcorner% + \let\secondpoint\arcstartcorner% + \else% + \ifdim\angle pt>\angletoarcendborder pt\relax% + \let\firstpoint\arcendborder% + \let\secondpoint\arcendcorner% + \else% + \let\firstpoint\pgfutil@empty% + \let\secondpoint\pgfutil@empty% + \fi% + \fi% + \fi% + \fi% + \ifx\firstpoint\pgfutil@empty + % + % Calculate the angle from the centre of the semicircle to the + % point on the semicircle arc which intersects the line from + % the external point to the reference point... + % + \pgfmathanglebetweenlines{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + {\semicirclecenterpoint}{\referencepoint}% + \pgfmathsin@{\pgfmathresult}% + \let\sineangle\pgfmathresult% + \pgf@x\semicircleradius\relax% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@x}}% + \let\reciprocalradius\pgfmathresult% + \pgf@x\centerpointdiff\relax% + \pgf@x\sineangle\pgf@x% + \pgf@x\reciprocalradius\pgf@x% + \pgfmathasin@{\pgfmath@tonumber{\pgf@x}}% + \pgf@x\pgfmathresult pt\relax% + \advance\pgf@x\externalangle pt\relax% + \edef\angle{\pgfmath@tonumber{\pgf@x}}% + % + % ...and thus the point on the border. + % + \pgfpointadd{\semicirclecenterpoint}{\pgfqpointpolar{\angle}{\semicircleradius}}% + \else% + % + % Calculate the the point where the semicircle chord intersects + % the line from the external point to the reference point. + % + \pgfpointintersectionoflines{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + \fi% + }% +}% + + +% Keys for shape isosceles triangle +% +% /pgf/isosceles triangle apex angle : angle at the apex of the triangle. +\pgfkeys{/pgf/.cd, + isosceles triangle apex angle/.initial=45, + isosceles triangle stretches/.is if=pgf@lib@sh@isosceslestrianglestretches +}% +\newif\ifpgf@lib@sh@isosceslestrianglestretches + +\pgfdeclareshape{isosceles triangle}{% + \savedmacro\trianglepoints{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/isosceles triangle apex angle}}% + \divide\pgf@x2\relax% + \edef\halfapexangle{\pgfmath@tonumber{\pgf@x}}% + \addtosavedmacro\halfapexangle% + % + \pgfmathtan@{\halfapexangle}% + \let\tanhalfapexangle\pgfmathresult% + % + \pgfmathcot@{\halfapexangle}% + \let\cothalfapexangle\pgfmathresult% + % + \pgfmathsin@{\halfapexangle}% + \let\sinhalfapexangle\pgfmathresult% + % + \pgfmathreciprocal@{\pgfmathresult}% + \let\cosechalfapexangle\pgfmathresult% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + \ifpgfshapeborderusesincircle% + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \else% + \pgf@y\pgf@x% + \fi% + \pgf@x1.414213\pgf@x% + \pgf@y1.414213\pgf@y% + % + \pgf@xa\pgf@x% + \advance\pgf@xa\cosechalfapexangle\pgf@x% + \pgf@ya\tanhalfapexangle\pgf@xa% + \else% + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \pgfmathsetcount\c@pgf@counta{+\pgfmathresult}% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \edef\rotate{\the\c@pgf@counta}% + \ifnum\c@pgf@counta=90\relax% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xa% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xa% + \fi% + \fi% + % + \pgf@xa2.0\pgf@x% + \pgf@ya\tanhalfapexangle\pgf@xa% + \advance\pgf@xa\cothalfapexangle\pgf@y% + \advance\pgf@ya\pgf@y% + \fi% + \addtosavedmacro\rotate% + \ifdim\pgf@xa=0pt\relax% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum height}}% + \fi% + % Adjust for minimum height and width. + % + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@ya<.5\pgf@yb% + \ifpgf@lib@sh@isosceslestrianglestretches% + \pgf@ya.5\pgf@yb% + % + \pgfmathdivide@{\pgfmath@tonumber{\pgf@ya}}{\pgfmath@tonumber{\pgf@xa}}% + \pgfmathatan@{\pgfmathresult}% + \let\halfapexangle\pgfmathresult% + % + \else% + \pgf@ya.5\pgf@yb% + \pgf@xa\cothalfapexangle\pgf@ya% + \fi% + \fi% + % + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@xa<\pgf@xb% + \ifpgf@lib@sh@isosceslestrianglestretches% + \pgf@xa\pgf@xb% + % + \pgfmathdivide@{\pgfmath@tonumber{\pgf@ya}}{\pgfmath@tonumber{\pgf@xa}}% + \pgfmathatan@{\pgfmathresult}% + \let\halfapexangle\pgfmathresult% + % + \else% + \pgf@xa\pgf@xb% + \pgf@ya\tanhalfapexangle\pgf@xa% + \fi% + \fi% + % + % + % Now find the ``offset height'' (h'). This is the distance from the + % center of the node contents to the base of the triangle. + % + \ifpgfshapeborderusesincircle% + % + % h' = H*sin(a/2) / (1+sin(a/2)) + % + % where: + % H = the height of the triangle. + % a = the apex angle. + % + \pgf@xc\pgf@xa% + \pgfmathsin@{\halfapexangle}% + \pgf@xc\pgfmathresult\pgf@xc% + \pgf@yc1pt\relax% + \advance\pgf@yc\pgfmathresult pt\relax% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xc}}{\pgfmath@tonumber{\pgf@yc}} + \pgfutil@tempdima\pgfmathresult pt\relax% + \else% + % + % h' = 0.5*h + (0.5*(W-w)*cos(a/2) - h*sin(a/2))/(1+sin(a/2)) + % + % where: + % h = the height of the node contents. + % w = the width of the node contents. + % W = the width of the triangle. + % a = the apex angle. + % + \pgf@xc\pgf@ya% + \advance\pgf@xc-\pgf@y% + \pgfmathcos@{\halfapexangle}% + \pgf@xc\pgfmathresult\pgf@xc% + \pgfmathsin@{\halfapexangle}% + \advance\pgf@xc-\pgfmathresult\pgf@x% + \advance\pgf@xc-\pgfmathresult\pgf@x% + \pgf@yc\pgfmathresult pt\relax% + \advance\pgf@yc1pt\relax% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xc}}{\pgfmath@tonumber{\pgf@yc}}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \advance\pgfutil@tempdima\pgf@x% + \fi% + \pgfextract@process\apex{% + \pgf@y0pt% + \pgf@x\pgf@xa% + \advance\pgf@x-\pgfutil@tempdima% + }% + \addtosavedmacro\apex% + % + \pgfextract@process\lowerleft{% + \pgf@y\pgf@ya% + \pgf@x-\pgfutil@tempdima% + }% + \addtosavedmacro\lowerleft% + % + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \pgf@xb\pgf@yb% + \fi% + \pgfextract@process\apexanchor{% + \apex% + \advance\pgf@x\cosechalfapexangle\pgf@xb% + }% + \addtosavedmacro\apexanchor% + % + \pgf@yc-\halfapexangle pt\relax% + \advance\pgf@yc90pt\relax% + \divide\pgf@yc2\relax% + \pgfmathcot@{\pgfmath@tonumber{\pgf@yc}}% + \pgfextract@process\lowerleftanchor{% + \lowerleft% + \advance\pgf@y\pgfmathresult\pgf@xb% + \advance\pgf@x-\pgf@xb% + }% + \addtosavedmacro\lowerleftanchor% + % + \pgfextract@process\lowerrightanchor{% + \lowerleftanchor% + \pgf@y-\pgf@y% + }% + \addtosavedmacro\lowerrightanchor% + }% + \anchor{apex}{% + \trianglepoints% + \pgfpointadd{\centerpoint}{% + \pgfmathrotatepointaround{\apexanchor}{\pgfpointorigin}{\rotate}% + }% + }% + \anchor{left corner}{% + \trianglepoints% + \pgfpointadd{\centerpoint}{% + \pgfmathrotatepointaround{\lowerleftanchor}{\pgfpointorigin}{\rotate}% + }% + }% + \anchor{right corner}{% + \trianglepoints% + \pgfpointadd{\centerpoint}{% + \pgfmathrotatepointaround{\lowerrightanchor}{\pgfpointorigin}{\rotate}% + }% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \trianglepoints% + \let\pgf@isoscelestriangle@referencepoint\midpoint% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{-1pt}{0pt}}% + }% + \anchor{mid east}{% + \trianglepoints% + \let\pgf@isoscelestriangle@referencepoint\midpoint% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{1pt}{0pt}}% + }% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \trianglepoints% + \let\pgf@isoscelestriangle@referencepoint\basepoint% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{-1pt}{0pt}}% + }% + \anchor{base east}{% + \trianglepoints% + \let\pgf@isoscelestriangle@referencepoint\basepoint% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{1pt}{0pt}}% + }% + \anchor{north}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{0pt}{1pt}}% + }% + \anchor{south}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{0pt}{-1pt}}% + }% + \anchor{east}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{1pt}{0pt}}% + }% + \anchor{west}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{-1pt}{0pt}}% + }% + \anchor{north east}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{1pt}{1pt}}% + }% + \anchor{south west}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{-1pt}{-1pt}}% + }% + \anchor{south east}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{1pt}{-1pt}}% + }% + \anchor{north west}{% + \trianglepoints% + \csname pgf@anchor@isosceles triangle@border\endcsname{\pgfqpoint{-1pt}{1pt}}% + }% + \anchor{left side}{% + \trianglepoints% + \pgfmathrotatepointaround{% + \pgfpointadd{\pgfpointlineattime{0.5}{\lowerleftanchor}{\apexanchor}}{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{right side}{% + \trianglepoints% + \pgfmathrotatepointaround{% + \pgfpointadd{\pgfpointlineattime{0.5}{\lowerrightanchor}{\apexanchor}}{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{lower side}{% + \trianglepoints% + \pgfmathrotatepointaround{% + \pgfpointadd{\pgfpointlineattime{0.5}{\lowerleftanchor}{\lowerrightanchor}}{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \backgroundpath{% + \trianglepoints% + {% + \pgftransformshift{\centerpoint}% + \pgftransformrotate{\rotate}% + \pgfpathmoveto{\apex}% + \pgfpathlineto{\lowerleft}% + \pgfpathlineto{\lowerleft\pgf@y-\pgf@y}% + \pgfpathclose% + }% + }% + \anchorborder{% + \pgfutil@ifundefined{pgf@isoscelestriangle@referencepoint}{\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@isoscelestriangle@referencepoint}% + \pgfextract@process\externalpoint{% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \referencepoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \trianglepoints% + \pgfmathanglebetweenpoints{\referencepoint}{\externalpoint}% + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \pgfmathmod@{\pgfmathresult}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\centerpoint}{\lowerrightanchor}}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\centerpoint}{\lowerleftanchor}}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\centerpoint}{\apexanchor}}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \let\firstpoint\apexanchor% + \let\secondpoint\lowerleftanchor% + \else% + \let\firstpoint\apexanchor% + \let\secondpoint\lowerrightanchor% + \fi% + \else% + \let\firstpoint\lowerleftanchor% + \let\secondpoint\lowerrightanchor% + \fi% + \else% + \let\firstpoint\lowerrightanchor% + \let\secondpoint\apexanchor% + \fi% + \pgfpointintersectionoflines{\referencepoint}{\externalpoint}% + {\pgfmathrotatepointaround{\pgfpointadd{\centerpoint}{\firstpoint}}{\centerpoint}{\rotate}}% + {\pgfmathrotatepointaround{\pgfpointadd{\centerpoint}{\secondpoint}}{\centerpoint}{\rotate}}% + }% +}% + + + + +% Keys for shape kite +% +% +\pgfkeys{/pgf/.cd, + kite upper vertex angle/.initial=120, + kite lower vertex angle/.initial=60, + kite vertex angles/.code={% + \pgfutil@in@{and}{#1}% + \ifpgfutil@in@% + \def\pgf@marshal##1and##2\@@{% + \pgfkeys{/pgf/kite upper vertex angle={##1}}% + \pgfkeys{/pgf/kite lower vertex angle={##2}}% + }% + \expandafter\pgf@marshal#1\@@% + \else% + \pgfkeys{/pgf/kite upper vertex angle={#1}}% + \pgfkeys{/pgf/kite lower vertex angle={#1}}% + \fi% + }% +}% + +% Shape kite. +% +\pgfdeclareshape{kite}{% + \savedmacro\installkiteparameters{% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % Calculate the centre, base and mid points of the node. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \pgfextract@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \pgfextract@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % Halve the vertex angles. + % + \pgfmathdivide{\pgfkeysvalueof{/pgf/kite upper vertex angle}}{2}% + \let\halfuppervertexangle\pgfmathresult% + \pgfmathdivide{\pgfkeysvalueof{/pgf/kite lower vertex angle}}{2}% + \let\halflowervertexangle\pgfmathresult% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \ifpgfshapeborderusesincircle% + % + % Get the rotation. + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + % + % Get the radius of the incircle. + % + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + % + % Get the distances from the upper and lower vertices + % to the center of the incircle. + % + \pgfmathsin@{\halfuppervertexangle}% + \let\sinehalfuppervertexangle\pgfmathresult% + \pgfmathreciprocal@{\pgfmathresult}% + \let\cosechalfuppervertexangle\pgfmathresult% + \pgf@ya\pgfmathresult\pgf@x% + \pgfmathsin@{\halflowervertexangle}% + \let\sinehalflowervertexangle\pgfmathresult% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@yb\pgfmathresult\pgf@x% + % + % Now calculate vertical offset (yc) between the center of + % the incircle, and the intersection of the kite diagonals. + % + % yc = x * cosec(a/2) - x * cot(a/2) * (sin(a/2) + sin(b/2)) * cosec(a/2 + b/2) + % + % where: + % x = the incircle radius. + % a = the upper vertex angle. + % b = the lower vertex angle. + % + \pgf@yc\pgf@x% + \pgfmathadd@{\halfuppervertexangle}{\halflowervertexangle}% + \pgfmathcosec@{\pgfmathresult}% + \pgf@yc\pgfmathresult\pgf@yc% + \pgfmathadd@{\sinehalfuppervertexangle}{\sinehalflowervertexangle}% + \pgf@yc\pgfmathresult\pgf@yc% + \pgfmathcos@{\halfuppervertexangle}% + \pgf@yc\pgfmathresult\pgf@yc% + \pgf@yc-\cosechalfuppervertexangle\pgf@yc% + \advance\pgf@yc\cosechalfuppervertexangle\pgf@x% + \edef\deltay{\the\pgf@yc}% + % + % Now calculate the height of the kite... + % + \advance\pgf@ya-\pgf@yc% + % + % ...and the depth. + % + \advance\pgf@yb\pgf@yc% + % + % Get the half width of the widest part of the kite. + % + \pgfmathtan@{\halfuppervertexangle}% + \pgf@xa\pgfmathresult\pgf@ya% + \else% + \multiply\pgf@x2\relax% + \multiply\pgf@y2\relax% + % + % Get the rotation (with rounding). + % + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + % + % The node contents (total height y) extends a distance ya into the + % upper isosceles triangle of the kite and a distance yb into the + % lower isosceles triangle. Thus, the following relationships hold: + % + % ya/yb = tan(b/2)/tan(a/2) + % + % and y = ya + yb + % + % so ya = y * sin(a/2 + b/2) / (cos(a/2) * sin(b/2)) + % + % where: + % a = upper vertex angle. + % b = lower vertex angle. + % + \pgfmathadd@{\halfuppervertexangle}{\halflowervertexangle}% + \pgfmathsin@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@ya\pgfmathresult\pgf@y% + \pgfmathcos@{\halfuppervertexangle}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgfmathsin@{\halflowervertexangle}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgf@yb\pgf@y% + \advance\pgf@yb-\pgf@ya% + % + % The vertical offset between the center of the node, and + % the intersection of the kite diagonals is given by: + % + % yc = y/2 - ya + % + \pgf@yc.5\pgf@y% + \advance\pgf@yc-\pgf@ya% + \edef\deltay{\the\pgf@yc}% + % + % Get the half width of the widest part of the kite. + % + \pgfmathtan@{\halfuppervertexangle}% + \pgf@xa.5\pgf@x% + \advance\pgf@xa\pgfmathresult\pgf@ya% + % + % Now calculate the height of the kite... + % + \pgf@xb.5\pgf@x% + \pgfmathreciprocal@{\pgfmathresult}% + \advance\pgf@ya\pgfmathresult\pgf@xb% + % + % ...and the depth. + % + \pgfmathtan@{\halflowervertexangle}% + \pgfmathreciprocal@{\pgfmathresult}% + \advance\pgf@yb\pgfmathresult\pgf@xb% + \fi% + % + % Take into account minimum height and width. + % + % ya is the kite height. + % yb is the kite depth. + % xa is the kite (half) width. + % + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}% + \pgf@y\pgf@ya% + \advance\pgf@y\pgf@yb% + \ifdim\pgf@y<\pgf@yc% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@y}}% + \pgf@yc\pgfmathresult\pgf@yc% + \pgf@xa\pgfmath@tonumber{\pgf@yc}\pgf@xa% + \pgf@ya\pgfmath@tonumber{\pgf@yc}\pgf@ya% + \pgf@yb\pgfmath@tonumber{\pgf@yc}\pgf@yb% + \fi% + \pgf@x2.0\pgf@xa% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@x<\pgf@xc% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@x}}% + \pgf@xc\pgfmathresult\pgf@xc% + \pgf@xa\pgfmath@tonumber{\pgf@xc}\pgf@xa% + \pgf@ya\pgfmath@tonumber{\pgf@xc}\pgf@ya% + \pgf@yb\pgfmath@tonumber{\pgf@xc}\pgf@yb% + \fi% + \edef\kitehalfwidth{\the\pgf@xa}% + \edef\kiteheight{\the\pgf@ya}% + \edef\kitedepth{\the\pgf@yb}% + % + % Calculate the basic points on the kite (for the background path). + % + \pgfextract@process\toppoint{% + \centerpoint% + \advance\pgf@y\deltay\relax% + \advance\pgf@y\kiteheight% + }% + \pgfextract@process\bottompoint{% + \centerpoint% + \advance\pgf@y\deltay\relax% + \advance\pgf@y-\kitedepth% + }% + \pgfextract@process\leftpoint{% + \centerpoint% + \advance\pgf@y\deltay\relax% + \advance\pgf@x-\kitehalfwidth% + }% + \pgfextract@process\rightpoint{% + \centerpoint% + \advance\pgf@y\deltay\relax% + \advance\pgf@x\kitehalfwidth% + }% + % + % Now calculate the miter length. At the top... + % + \pgfmathsin@{\halfuppervertexangle}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@y\outersep\relax% + \pgf@y\pgfmathresult\pgf@y% + \edef\topmiter{\the\pgf@y}% + % + % ...at the bottom... + % + \pgfmathsin@{\halflowervertexangle}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@y\outersep\relax% + \pgf@y\pgfmathresult\pgf@y% + \edef\bottommiter{\the\pgf@y}% + % + % ...to the right... + % + \pgfmathsubtract@{180}{\halflowervertexangle}% + \pgfmathsubtract@{\pgfmathresult}{\halfuppervertexangle}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfmathsin@{\pgfmathresult}% + \pgfmathreciprocal@{\pgfmathresult}% + \pgf@xa\outersep\relax% + \pgf@xa\pgfmathresult\pgf@xa% + \pgfmathsubtract@{\halfuppervertexangle}{\halflowervertexangle}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\angle\pgfmathresult% + \pgfextract@process\rightmiter{% + \pgfqpointpolar{\angle}{\the\pgf@xa}% + }% + % + % ...and to the left. + % + \pgfmathsubtract@{180}{\angle}% + \let\angle\pgfmathresult% + \pgfextract@process\leftmiter{% + \pgfqpointpolar{\angle}{\the\pgf@xa}% + }% + % + % Create the border points. + % + \pgfextract@process\topborderpoint{% + \toppoint% + \advance\pgf@y\topmiter\relax% + }% + \pgfextract@process\bottomborderpoint{% + \bottompoint% + \advance\pgf@y-\bottommiter\relax% + }% + \pgfextract@process\leftborderpoint{% + \leftpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \leftmiter% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfextract@process\rightborderpoint{% + \rightpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \rightmiter% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Get the angle from the \centerpoint to the *unrotated points*. + % + \pgfmathanglebetweenpoints{\centerpoint}{\topborderpoint}% + \let\angletotoppoint\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\leftborderpoint}% + \let\angletoleftpoint\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\bottomborderpoint}% + \let\angletobottompoint\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\rightborderpoint}% + \let\angletorightpoint\pgfmathresult% + % + % ...from the *inversely rotated* \basepoint... + % + \pgfextract@process\rotatedbasepoint{% + \pgfmathrotatepointaround{\basepoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\topborderpoint}% + \let\baseangletotoppoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\leftborderpoint}% + \let\baseangletoleftpoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\bottomborderpoint}% + \let\baseangletobottompoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\rightborderpoint}% + \let\baseangletorightpoint\pgfmathresult% + % + % ...and from the *inversely rotated* \midpoint. + % + \pgfextract@process\rotatedmidpoint{% + \pgfmathrotatepointaround{\midpoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\topborderpoint}% + \let\midangletotoppoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\leftborderpoint}% + \let\midangletoleftpoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\bottomborderpoint}% + \let\midangletobottompoint\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\rightborderpoint}% + \let\midangletorightpoint\pgfmathresult% + % + % Calculate a radius guaranteed to be outside the kite. + % + \pgfextractx\pgf@xa{\pgfpointdiff{\leftborderpoint}{\rightborderpoint}}% + \ifdim\pgf@xa<0pt\relax% + \pgf@xa-\pgf@xa% + \fi% + \pgfextracty\pgf@ya{\pgfpointdiff{\topborderpoint}{\bottomborderpoint}}% + \ifdim\pgf@ya<0pt\relax% + \pgf@ya-\pgf@ya% + \fi% + \ifdim\pgf@ya>\pgf@xa% + \edef\externalradius{\the\pgf@ya}% + \else% + \edef\externalradius{\the\pgf@xa}% + \fi% + % + % Now rotate the points... + % + \pgfextract@process\toppoint{% + \pgfmathrotatepointaround{\toppoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\bottompoint{% + \pgfmathrotatepointaround{\bottompoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\leftpoint{% + \pgfmathrotatepointaround{\leftpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\rightpoint{% + \pgfmathrotatepointaround{\rightpoint}{\centerpoint}{\rotate}% + }% + % + % ...and the border points. + % + \pgfextract@process\topborderpoint{% + \pgfmathrotatepointaround{\topborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\bottomborderpoint{% + \pgfmathrotatepointaround{\bottomborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\leftborderpoint{% + \pgfmathrotatepointaround{\leftborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\rightborderpoint{% + \pgfmathrotatepointaround{\rightborderpoint}{\centerpoint}{\rotate}% + }% + % + % Now save it all. + % + \addtosavedmacro{\rotate}% + \addtosavedmacro{\externalradius}% + % + \addtosavedmacro\toppoint% + \addtosavedmacro\bottompoint% + \addtosavedmacro\leftpoint% + \addtosavedmacro\rightpoint% + % + \addtosavedmacro\topborderpoint% + \addtosavedmacro\bottomborderpoint% + \addtosavedmacro\leftborderpoint% + \addtosavedmacro\rightborderpoint% + % + \addtosavedmacro\angletotoppoint% + \addtosavedmacro\angletobottompoint% + \addtosavedmacro\angletoleftpoint% + \addtosavedmacro\angletorightpoint% + % + \addtosavedmacro\baseangletotoppoint% + \addtosavedmacro\baseangletobottompoint% + \addtosavedmacro\baseangletoleftpoint% + \addtosavedmacro\baseangletorightpoint% + % + \addtosavedmacro\midangletotoppoint% + \addtosavedmacro\midangletobottompoint% + \addtosavedmacro\midangletoleftpoint% + \addtosavedmacro\midangletorightpoint% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \installkiteparameters% + \let\pgf@kiteanchorborderreferencepoint\basepoint% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{base east}{% + \installkiteparameters% + \let\pgf@kiteanchorborderreferencepoint\basepoint% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \installkiteparameters% + \let\pgf@kiteanchorborderreferencepoint\midpoint% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{mid east}{% + \installkiteparameters% + \let\pgf@kiteanchorborderreferencepoint\midpoint% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{north}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south west}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{south east}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \installkiteparameters% + \csname pgf@anchor@kite@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{upper vertex}{% + \installkiteparameters% + \topborderpoint}% + \anchor{lower vertex}{% + \installkiteparameters% + \bottomborderpoint}% + \anchor{left vertex}{% + \installkiteparameters% + \leftborderpoint}% + \anchor{right vertex}{% + \installkiteparameters% + \rightborderpoint}% + \anchor{upper left side}{% + \installkiteparameters% + \pgfpointlineattime{0.5}{\topborderpoint}{\leftborderpoint}}% + \anchor{lower left side}{% + \installkiteparameters% + \pgfpointlineattime{0.5}{\bottomborderpoint}{\leftborderpoint}}% + \anchor{upper right side}{% + \installkiteparameters% + \pgfpointlineattime{0.5}{\topborderpoint}{\rightborderpoint}}% + \anchor{lower right side}{% + \installkiteparameters% + \pgfpointlineattime{0.5}{\bottomborderpoint}{\rightborderpoint}}% + \backgroundpath{% + \installkiteparameters% + \pgfpathmoveto{\toppoint}% + \pgfpathlineto{\leftpoint}% + \pgfpathlineto{\bottompoint}% + \pgfpathlineto{\rightpoint}% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % This allows anchors base east, base west, mid east and mid west, + % to redefine the `center' of the node to correctly calculate the + % border points. + % + \pgfutil@ifundefined{pgf@kiteanchorborderreferencepoint}% + {\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@kiteanchorborderreferencepoint}% + % + % Adjust the location of the external + % point relative to the reference point. + % + \referencepoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Install the required points and angles. + % + \installkiteparameters% + % + % Get the angle of the external point relative to \referencepoint. + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + % + % *Subtract* the rotation from the external angle. + % + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + \ifx\referencepoint\basepoint% + \let\angletotoppoint\baseangletotoppoint% + \let\angletobottompoint\baseangletobottompoint% + \let\angletoleftpoint\baseangletoleftpoint% + \let\angletorightpoint\baseangletorightpoint% + \else% + \ifx\referencepoint\midpoint% + \let\angletotoppoint\midangletotoppoint% + \let\angletobottompoint\midangletobottompoint% + \let\angletoleftpoint\midangletoleftpoint% + \let\angletorightpoint\midangletorightpoint% + \fi\fi% + % + % Depending on the rotation, the angle to \rightborderpoint + % may be smaller than the angle to \topborderpoint. + % + \ifdim\angletorightpoint pt<\angletotoppoint pt\relax% + \ifdim\externalangle pt<\angletorightpoint pt\relax% + \let\firstpoint\rightborderpoint% + \let\secondpoint\bottomborderpoint% + \else% + \ifdim\externalangle pt<\angletotoppoint pt\relax% + \let\firstpoint\rightborderpoint% + \let\secondpoint\topborderpoint% + \else% + \ifdim\externalangle pt<\angletoleftpoint pt\relax% + \let\firstpoint\topborderpoint% + \let\secondpoint\leftborderpoint% + \else% + \ifdim\externalangle pt<\angletobottompoint pt\relax% + \let\firstpoint\leftborderpoint% + \let\secondpoint\bottomborderpoint% + \else% + \let\firstpoint\rightborderpoint% + \let\secondpoint\bottomborderpoint% + \fi% + \fi% + \fi% + \fi% + \else% + \ifdim\externalangle pt<\angletotoppoint pt\relax% + \let\firstpoint\rightborderpoint% + \let\secondpoint\topborderpoint% + \else% + \ifdim\externalangle pt<\angletoleftpoint pt\relax% + \let\firstpoint\leftborderpoint% + \let\secondpoint\topborderpoint% + \else% + \ifdim\externalangle pt<\angletobottompoint pt\relax% + \let\firstpoint\bottomborderpoint% + \let\secondpoint\leftborderpoint% + \else% + \ifdim\externalangle pt<\angletorightpoint pt\relax% + \let\firstpoint\rightborderpoint% + \let\secondpoint\bottomborderpoint% + \else% + \let\firstpoint\rightborderpoint% + \let\secondpoint\topborderpoint% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgfpointintersectionoflines{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + }% +}% + + + + +% Keys for shape dart. +% +% + +\pgfkeys{/pgf/.cd, + dart tip angle/.initial=45, + dart tail angle/.initial=135, +}% + +% Shape dart. +% +\pgfdeclareshape{dart}{% + \savedmacro\installdartparameters{% + % + % Get the halved angles (more useful). + % + \pgfmathdivide{\pgfkeysvalueof{/pgf/dart tip angle}}{2}% + \let\halftipangle\pgfmathresult% + \pgfmathdivide{\pgfkeysvalueof{/pgf/dart tail angle}}{2}% + \let\halftailangle\pgfmathresult% + % + % Calculate some common results. + % + \pgfmathcot@{\halftipangle}% + \let\cothalftipangle\pgfmathresult% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % Calculate the centre, base and mid points of the node. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \pgfextract@process\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \pgfextract@process\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + % + % Get the (halved) dimension of the node. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + % Get the length of the dart tip. + % + \ifpgfshapeborderusesincircle% + % + % Get the (unrounded) rotation. + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + % + % Get the radius of the incircle. + % + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + % + % Calculate the length of the dart tip. + % + \pgf@xa\cothalftipangle\pgf@x% + \advance\pgf@xa\pgf@x% + \else% + % + % Get the rotation (with rounding). + % + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Flip the width and height of the node contents, + % according to the appropriate border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + % + % Calculate the length of the dart tip. + % + \pgf@xa\cothalftipangle\pgf@y% + \advance\pgf@xa2.0\pgf@x% + \fi% + % + % Get the (half) separation of the dart tails. + % + \pgfmathsubtract@{\halftailangle}{\halftipangle}% + \pgfmathcosec@{\pgfmathresult}% + \pgf@ya\pgfmathresult\pgf@xa% + \pgfmathsin@{\halftipangle}% + \pgf@ya\pgfmathresult\pgf@ya% + \pgfmathcos@{\halftipangle}% + \pgf@ya\pgfmathresult\pgf@ya% + % + % Get the total length of the dart... + % + \pgf@xb\cothalftipangle\pgf@ya% + % + % and hence the length of the tails. + % + \pgf@xc-\pgf@xa% + \advance\pgf@xc\pgf@xb% + % + % Adjust for minimum height (length of the dart). + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@xb<\pgf@y% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@xb}}% + \pgf@y\pgfmathresult\pgf@y% + \pgf@xa\pgfmath@tonumber{\pgf@y}\pgf@xa% + \pgf@xc\pgfmath@tonumber{\pgf@y}\pgf@xc% + \pgf@ya\pgfmath@tonumber{\pgf@y}\pgf@ya% + \pgf@x\pgfmath@tonumber{\pgf@y}\pgf@x% + \fi% + % + % Adjust for minimum width (tail separation length). + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@y.5\pgf@y% + \ifdim\pgf@ya<\pgf@y% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@ya}}% + \pgf@ya\pgf@y% + \pgf@y\pgfmathresult\pgf@y% + \pgf@xa\pgfmath@tonumber{\pgf@y}\pgf@xa% + \pgf@xc\pgfmath@tonumber{\pgf@y}\pgf@xc% + \pgf@x\pgfmath@tonumber{\pgf@y}\pgf@x% + \fi% + \edef\dartlength{\the\pgf@xa}% + \edef\deltax{\the\pgf@x}% + \edef\taillength{\the\pgf@xc}% + \edef\halftailseparation{\the\pgf@ya} + % + % Create the basic points on the dart (for the background path). + % + \pgfextract@process\tippoint{% + \centerpoint% + \advance\pgf@x\dartlength\relax% + \advance\pgf@x-\deltax\relax% + }% + \pgfextract@process\tailcenterpoint{% + \centerpoint% + \advance\pgf@x-\deltax\relax% + }% + \pgfextract@process\lefttailpoint{% + \centerpoint% + \advance\pgf@x-\deltax\relax% + \advance\pgf@x-\taillength\relax% + \advance\pgf@y\halftailseparation\relax% + }% + \pgfextract@process\righttailpoint{% + \centerpoint% + \advance\pgf@x-\deltax\relax% + \advance\pgf@x-\taillength\relax% + \advance\pgf@y-\halftailseparation\relax% + }% + % + % Calculate the miter vectors. At the dart tip... + % + \pgfextract@process\tipmiter{% + \pgfmathcosec@{\halftipangle}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y0pt\relax% + }% + % + % ...at the tail center... + % + \pgfextract@process\tailcentermiter{% + \pgfmathcosec@{\halftailangle}% + \pgf@x-\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y0pt\relax% + }% + % + % ...at the left tail... + % + \pgfmathsubtract@{\halftailangle}{\halftipangle}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\angle\pgfmathresult% + \pgfmathcosec@{\pgfmathresult}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \pgfmathadd@{\angle}{90}% + \pgfmathsubtract{\pgfmathresult}{\halftailangle}% + \pgfmathsincos@{\pgfmathresult}% + \pgf@ya\pgfmathresultx\pgf@x% + \pgf@xa\pgfmathresulty\pgf@x% + \pgfextract@process\lefttailmiter{% + \pgf@x-\pgf@xa% + \pgf@y\pgf@ya% + }% + % + % ...and the right tail. + % + \pgfextract@process\righttailmiter{% + \pgf@x-\pgf@xa% + \pgf@y-\pgf@ya% + }% + % + % Create the border points. + % + \pgfextract@process\tipborderpoint{% + \pgfpointadd{\tippoint}{\tipmiter} + }% + \pgfextract@process\tailcenterborderpoint{% + \pgfpointadd{\tailcenterpoint}{\tailcentermiter}% + }% + \pgfextract@process\lefttailborderpoint{% + \pgfpointadd{\lefttailpoint}{\lefttailmiter}% + }% + \pgfextract@process\righttailborderpoint{% + \pgfpointadd{\righttailpoint}{\righttailmiter}% + }% + % + % Calculate the angles between the centerpoint + % and the *unrotated* borderpoints. + % + \pgfmathanglebetweenpoints{\centerpoint}{\tipborderpoint}% + \let\angletotip\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\tailcenterborderpoint}% + \let\angletotailcenter\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\lefttailborderpoint}% + \let\angletolefttail\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\righttailborderpoint}% + \let\angletorighttail\pgfmathresult% + % + % Calculate the angles between the *inversely rotated* + % basepoint and the *unrotated* borderpoints. + % + \pgfextract@process\rotatedbasepoint{% + \pgfmathrotatepointaround{\basepoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\tipborderpoint}% + \let\baseangletotip\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\tailcenterborderpoint}% + \let\baseangletotailcenter\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\lefttailborderpoint}% + \let\baseangletolefttail\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedbasepoint}{\righttailborderpoint}% + \let\baseangletorighttail\pgfmathresult% + % + % Calculate the angles between the *inversely rotated* + % midpoint and the *unrotated* borderpoints. + % + \pgfextract@process\rotatedmidpoint{% + \pgfmathrotatepointaround{\midpoint}{\centerpoint}{-\rotate}% + }% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\tipborderpoint}% + \let\midangletotip\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\tailcenterborderpoint}% + \let\midangletotailcenter\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\lefttailborderpoint}% + \let\midangletolefttail\pgfmathresult% + \pgfmathanglebetweenpoints{\rotatedmidpoint}{\righttailborderpoint}% + \let\midangletorighttail\pgfmathresult% + % + % Rotate the background path points. + % + \pgfextract@process\tippoint{% + \pgfmathrotatepointaround{\tippoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\tailcenterpoint{% + \pgfmathrotatepointaround{\tailcenterpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\lefttailpoint{% + \pgfmathrotatepointaround{\lefttailpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\righttailpoint{% + \pgfmathrotatepointaround{\righttailpoint}{\centerpoint}{\rotate}% + }% + % + % Calculate a radius guaranteed to be outside the dart. + % + \pgfextractx\pgf@xa{\pgfpointdiff{\lefttailborderpoint}{\tipborderpoint}}% + \pgfextracty\pgf@ya{\pgfpointdiff{\lefttailborderpoint}{\righttailborderpoint}}% + \ifdim\pgf@xa<0pt\relax% + \pgf@xa-\pgf@xa% + \fi% + \ifdim\pgf@ya<0pt\relax% + \pgf@ya-\pgf@ya% + \fi% + \ifdim\pgf@xa>\pgf@ya% + \edef\externalradius{\the\pgf@xa}% + \else% + \edef\externalradius{\the\pgf@ya}% + \fi% + % + % Rotate the border anchor points. + % + \pgfextract@process\tipborderpoint{% + \pgfmathrotatepointaround{\tipborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\tailcenterborderpoint{% + \pgfmathrotatepointaround{\tailcenterborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\lefttailborderpoint{% + \pgfmathrotatepointaround{\lefttailborderpoint}{\centerpoint}{\rotate}% + }% + \pgfextract@process\righttailborderpoint{% + \pgfmathrotatepointaround{\righttailborderpoint}{\centerpoint}{\rotate}% + }% + % + % Save everything. + % + \addtosavedmacro{\rotate}% + \addtosavedmacro{\externalradius}% + % + \addtosavedmacro{\tippoint}% + \addtosavedmacro{\tailcenterpoint}% + \addtosavedmacro{\lefttailpoint}% + \addtosavedmacro{\righttailpoint}% + % + \addtosavedmacro{\tipborderpoint}% + \addtosavedmacro{\tailcenterborderpoint}% + \addtosavedmacro{\lefttailborderpoint}% + \addtosavedmacro{\righttailborderpoint}% + % + \addtosavedmacro{\angletotip}% + \addtosavedmacro{\angletotailcenter}% + \addtosavedmacro{\angletolefttail}% + \addtosavedmacro{\angletorighttail}% + % + \addtosavedmacro{\baseangletotip}% + \addtosavedmacro{\baseangletotailcenter}% + \addtosavedmacro{\baseangletolefttail}% + \addtosavedmacro{\baseangletorighttail}% + % + \addtosavedmacro{\midangletotip}% + \addtosavedmacro{\midangletotailcenter}% + \addtosavedmacro{\midangletolefttail}% + \addtosavedmacro{\midangletorighttail}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \installdartparameters% + \let\pgf@dartanchorborderreferencepoint\basepoint% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{base east}{% + \installdartparameters% + \let\pgf@dartanchorborderreferencepoint\basepoint% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \installdartparameters% + \let\pgf@dartanchorborderreferencepoint\midpoint% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{mid east}{% + \installdartparameters% + \let\pgf@dartanchorborderreferencepoint\midpoint% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{north}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south west}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{south east}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \installdartparameters% + \csname pgf@anchor@dart@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{tip}{% + \installdartparameters% + \tipborderpoint}% + \anchor{left tail}{% + \installdartparameters% + \lefttailborderpoint}% + \anchor{right tail}{% + \installdartparameters% + \righttailborderpoint}% + \anchor{tail center}{% + \installdartparameters% + \tailcenterborderpoint}% + \anchor{left side}{% + \installdartparameters% + \pgfpointlineattime{0.5}{\tipborderpoint}{\lefttailborderpoint}}% + \anchor{right side}{% + \installdartparameters% + \pgfpointlineattime{0.5}{\tipborderpoint}{\righttailborderpoint}}% + \backgroundpath{% + \installdartparameters% + \pgfpathmoveto{\tippoint}% + \pgfpathlineto{\lefttailpoint}% + \pgfpathlineto{\tailcenterpoint}% + \pgfpathlineto{\righttailpoint}% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % This allows anchors base east, base west, mid east and mid west, + % to redefine the `center' of the node to correctly calculate the + % border points. + % + \pgfutil@ifundefined{pgf@dartanchorborderreferencepoint}% + {\let\referencepoint\centerpoint}% + {\let\referencepoint\pgf@dartanchorborderreferencepoint}% + % + % Adjust the location of the external + % point relative to the reference point. + % + \referencepoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Install the required points and angles. + % + \installdartparameters% + % + % Get the angle of the external point relative to \referencepoint. + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + % + % *Subtract* the rotation from the external angle. + % + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + % + % Get the set of angles for the appropriate border point. + % + \ifx\referencepoint\basepoint% + \let\angletotip\baseangletotip% + \let\angletotailcenter\baseangletotailcenter% + \let\angletolefttail\baseangletolefttail% + \let\angletorighttail\baseangletorighttail% + \else% + \ifx\referencepoint\midpoint% + \let\angletotip\midangletotip% + \let\angletotailcenter\midangletotailcenter% + \let\angletolefttail\midangletolefttail% + \let\angletorighttail\midangletorighttail% + \fi\fi% + % + % Locate the appropriate line on the border... + % + \ifdim\externalangle pt<\angletotip pt\relax% + \let\firstpoint\tipborderpoint% + \let\secondpoint\righttailborderpoint% + \else% + \ifdim\externalangle pt<\angletolefttail pt\relax% + \let\firstpoint\lefttailborderpoint% + \let\secondpoint\tipborderpoint% + \else% + \ifdim\externalangle pt<\angletotailcenter pt\relax% + \let\firstpoint\lefttailborderpoint% + \let\secondpoint\tailcenterborderpoint% + \else% + \ifdim\externalangle pt<\angletorighttail pt\relax% + \let\firstpoint\righttailborderpoint% + \let\secondpoint\tailcenterborderpoint% + \else% + \let\firstpoint\tipborderpoint% + \let\secondpoint\righttailborderpoint% + \fi% + \fi% + \fi% + \fi% + % + % ...and thus the point on the border. + % + \pgfpointintersectionoflines{\referencepoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + }% +}% + + + +% Keys for shape circular sector: +% +% /pgf/circular sector angle : the angle at the center of the sector. +% +\pgfkeys{/pgf/circular sector angle/.initial=60}% + +% Shape circular sector +% +\pgfdeclareshape{circular sector}{% + \savedmacro\installcircularsectorparameters{% + % + % Define a \centerpoint, \basepoint and \midpoint. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % Half of the sector angle is more useful. + % + \pgfmathmod{\pgfkeysvalueof{/pgf/circular sector angle}}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\angle\pgfmathresult% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\halfangle\pgfmathresult% + % + % Get some useful trigonometric stuff. + % + \pgfmathsin@{\halfangle}% + \let\sinehalfangle\pgfmathresult% + \pgfmathreciprocal@{\pgfmathresult}% + \let\cosechalfangle\pgfmathresult% + \pgfmathabs@{\halfangle}% + \pgfmathcos@{\pgfmathresult}% + \let\coshalfangle\pgfmathresult% + \pgf@x\pgfmathresult pt\relax% + \pgf@x\cosechalfangle\pgf@x% + \edef\cothalfangle{\pgfmath@tonumber{\pgf@x}}% + % + % Calculate the miter length at the center, + % according to the outer sep. + % + \pgf@x\outersep\relax% + \pgf@x\cosechalfangle\pgf@x% + \edef\centermiter{\the\pgf@x}% + % + % Get the start and end angles of the arc. + % + \pgfmathsubtract@{180}{\halfangle}% + \let\startangle\pgfmathresult% + \pgfmathadd@{180}{\halfangle}% + \let\endangle\pgfmathresult% + % + % Get (half) the node dimensions. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + % Calculate the radius of the sector and the `center offset', + % which is the distance between the center of the node and the + % center of the sector. + % + \ifpgfshapeborderusesincircle% + % + % Get the rotation. + % + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + % + % Calculate the incircle radius. + % + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + \pgf@xa\cosechalfangle\pgf@x% + % + % xa is the radius, xb the offset. + % + \pgf@xb\pgf@xa% + \advance\pgf@xa\pgf@x% + \else% + % + % Get the rotation (with rounding). + % + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % Swap the height and width for relevant angles. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + % + % xa is the radius, xb the offset. + % + \pgf@xa\cosechalfangle\pgf@y% + \pgf@xa\coshalfangle\pgf@xa% + \advance\pgf@xa\pgf@x% + \pgf@xb\pgf@xa% + \advance\pgf@xa\pgf@x% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@y}}% + \pgf@xa\pgfmathresult pt\relax% + \fi% + % + % Adjust for minimum height and width. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/minimum width}}% + \pgf@x.5\pgf@x% + \pgfmathsec@{\halfangle}% + \pgf@xc\pgfmathresult\pgf@xb% + \ifdim\pgf@xc<0pt\relax% + \pgf@xc-\pgf@xc% + \fi% + \ifdim\pgf@xc<\pgf@x% + \pgfmathreciprocal{\pgfmath@tonumber{\pgf@xc}}% + \pgf@xc\pgfmathresult\pgf@x% Increase by ratio. + \pgf@xa\pgfmath@tonumber{\pgf@xc}\pgf@xa% + \pgf@xb\pgfmath@tonumber{\pgf@xc}\pgf@xb% + \fi% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@xa<\pgf@y% + \pgfmathreciprocal{\pgfmath@tonumber{\pgf@xa}}% + \pgf@xc\pgfmathresult\pgf@y% Increase by ratio. + \pgf@xa\pgf@y% + \pgf@xb\pgfmath@tonumber{\pgf@xc}\pgf@xb% + \fi% + \edef\centeroffset{\the\pgf@xb}% + \edef\radius{\the\pgf@xa}% + % + % Calculate the radius at sector border and the arc corners. + % + \advance\pgf@xa\outersep\relax% + \edef\borderradius{\the\pgf@xa}% + \pgf@x\outersep\relax% + \pgf@x\cosechalfangle\pgf@x% + \pgf@x\coshalfangle\pgf@x% + \advance\pgf@xa\pgf@x% + \edef\cornerradius{\the\pgf@xa}% + % + % Calculate the *unrotated* points for the background path. + % + \pgfextract@process\sectorcenter{% + \centerpoint% + \advance\pgf@x\centeroffset% + }% + \pgfextract@process\arcstart{% + \pgfqpointpolar{\startangle}{\radius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \sectorcenter% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Calculate the *unrotated* points for the anchor border. + % + \pgfextract@process\sectorcenterborder{% + \sectorcenter% + \advance\pgf@x\centermiter\relax% + }% + \pgfextract@process\arcstartborder{% + \pgfqpointpolar{\startangle}{\borderradius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \sectorcenter% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfextract@process\arcendborder{% + \pgfqpointpolar{\endangle}{\borderradius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \sectorcenter% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfextract@process\arcstartcorner{% + \pgfqpointpolar{\startangle}{\cornerradius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \sectorcenterborder% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfextract@process\arcendcorner{% + \pgfqpointpolar{\endangle}{\cornerradius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \sectorcenterborder% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Calculate the *unrotated* corner angles to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\sectorcenterborder}% + \let\angletosectorcenterborder\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcstartborder}% + \let\angletoarcstartborder\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcendborder}% + \let\angletoarcendborder\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcstartcorner}% + \let\angletoarcstartcorner\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\arcendcorner}% + \let\angletoarcendcorner\pgfmathresult% + % + % Rotate the background path points around the note center. + % + \pgfextract@process\sectorcenter{% + \pgfmathrotatepointaround{\sectorcenter}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcstart{% + \pgfmathrotatepointaround{\arcstart}{\centerpoint}{\rotate}% + }% + % + % Rotate the border points around the note center. + % + \pgfextract@process\sectorcenterborder{% + \pgfmathrotatepointaround{\sectorcenterborder}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcstartborder{% + \pgfmathrotatepointaround{\arcstartborder}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcendborder{% + \pgfmathrotatepointaround{\arcendborder}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcstartcorner{% + \pgfmathrotatepointaround{\arcstartcorner}{\centerpoint}{\rotate}% + }% + \pgfextract@process\arcendcorner{% + \pgfmathrotatepointaround{\arcendcorner}{\centerpoint}{\rotate}% + }% + % + % Add the rotation to the start and end angles. + % + \pgfmathadd@{\startangle}{\rotate}% + \let\startangle\pgfmathresult% + \pgfmathadd@{\endangle}{\rotate}% + \let\endangle\pgfmathresult% + % + % Save everything. + % + % NB \addtosavedmacro is currently experimental. May get changed. + % + \addtosavedmacro{\rotate}% + \addtosavedmacro{\centeroffset}% + % + \addtosavedmacro{\radius}% + \addtosavedmacro{\borderradius}% + \addtosavedmacro{\cornerradius}% + % + \addtosavedmacro{\endangle}% + \addtosavedmacro{\startangle}% + % + \addtosavedmacro{\sectorcenter}% + \addtosavedmacro{\arcstart}% + % + \addtosavedmacro{\sectorcenterborder}% + \addtosavedmacro{\arcstartborder}% + \addtosavedmacro{\arcendborder}% + \addtosavedmacro{\arcstartcorner}% + \addtosavedmacro{\arcendcorner}% + % + \addtosavedmacro{\angletosectorcenterborder}% + \addtosavedmacro{\angletoarcstartborder}% + \addtosavedmacro{\angletoarcendborder}% + \addtosavedmacro{\angletoarcstartcorner}% + \addtosavedmacro{\angletoarcendcorner}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{mid}{\midpoint}% + \anchor{arc start}{% + \installcircularsectorparameters% + \arcstartcorner% + }% + \anchor{arc end}{% + \installcircularsectorparameters% + \arcendcorner% + }% + \anchor{sector center}{% + \installcircularsectorparameters% + \sectorcenterborder% + }% + \anchor{arc center}{% + \installcircularsectorparameters% + \pgfmathadd@{\rotate}{180}% + \let\angle\pgfmathresult% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpointpolar{\angle}{\cornerradius}}% + }% + \anchor{north}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{0pt}{\cornerradius}}% + }% + \anchor{south}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{0pt}{-\cornerradius}}% + }% + \anchor{east}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{\cornerradius}{0pt}}% + }% + \anchor{west}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{-\cornerradius}{0pt}}% + }% + \anchor{north west}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{-\cornerradius}{\cornerradius}}% + }% + \anchor{south west}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{-\cornerradius}{-\cornerradius}}% + }% + \anchor{north east}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{\cornerradius}{\cornerradius}}% + }% + \anchor{south east}{% + \installcircularsectorparameters% + \csname pgf@anchor@circular sector@border\endcsname{\pgfqpoint{\cornerradius}{-\cornerradius}}% + }% + \backgroundpath{% + \installcircularsectorparameters% + \pgfpathmoveto{\sectorcenter}% + \pgfpathlineto{\arcstart}% + \ifdim\endangle pt>360pt\relax% + \ifdim\startangle pt>360pt\relax% + \pgfpatharc{\startangle}{\endangle}{\radius}% + \else% + \pgfpatharc{\startangle}{360}{\radius}% + \pgfpatharc{0}{\endangle}{\radius}% + \fi% + \else% + \pgfpatharc{\startangle}{\endangle}{\radius}% + \fi% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Adjust the location of the external point relative to \centerpoint. + % + \centerpoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Install the required points and angles. + % + \installcircularsectorparameters% + % + % Get the angle of the external point to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + \let\externalangle\pgfmathresult% + % + % *Subtract* the rotation from the external angle. + % + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\angle\pgfmathresult% + % + % Determine if the line will cross the sector arc. + % + \ifdim\angle pt>\angletoarcendcorner pt\relax% + \let\firstpoint\arcendcorner% + \let\secondpoint\sectorcenterborder% + \else% + \ifdim\angle pt>\angletoarcendborder pt\relax% + \let\firstpoint\arcendborder% + \let\secondpoint\arcendcorner% + \else% + \ifdim\angle pt>\angletoarcstartborder pt\relax% + \let\firstpoint\pgfutil@empty% + \let\secondpoint\pgfutil@empty% + \else% + \ifdim\angle pt>\angletoarcstartcorner pt\relax% + \let\firstpoint\arcstartborder + \let\secondpoint\arcstartcorner + \else% + \let\firstpoint\sectorcenterborder% + \let\secondpoint\arcstartcorner% + \fi% + \fi% + \fi% + \fi% + \ifx\firstpoint\pgfutil@empty + % + % Calculate the angle from the centre of the semicircle to the + % point on the semicircle arc which intersects the line from + % the external point to the reference point... + % + \pgfmathanglebetweenlines{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + {\sectorcenter}{\centerpoint}% + \pgfmathsin@{\pgfmathresult}% + \let\sineangle\pgfmathresult% + \pgf@x\borderradius\relax% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@x}}% + \let\reciprocalradius\pgfmathresult% + \pgf@x\centeroffset\relax% + \pgf@x\sineangle\pgf@x% + \pgf@x\reciprocalradius\pgf@x% + \pgfmathasin@{\pgfmath@tonumber{\pgf@x}}% + \pgf@x\pgfmathresult pt\relax% + \advance\pgf@x\externalangle pt\relax% + \edef\angle{\pgfmath@tonumber{\pgf@x}}% + % + % ...and thus the point on the border. + % + \pgfpointadd{\sectorcenter}{\pgfqpointpolar{\angle}{\borderradius}}% + \else% + % + % Calculate the the point where the semicircle chord intersects + % the line from the external point to the reference point. + % + \pgfpointintersectionoflines{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + \fi% + }% +}% + + + +% Keys for shape cylinder +% +% /pgf/shape aspect : Ratio between the x and y radii of the cylinder end. +% /pgf/cylinder uses custom fill : Use a custom fill for the cylinder. +% /pgf/cylinder end fill : Custom color for the cylinder end. +% /pgf/cylinder body fill : Custom color for the cylinder body. +% + +\newif\ifpgfcylinderusescustomfill +\pgfkeys{/pgf/.cd, + cylinder uses custom fill/.is if=pgfcylinderusescustomfill, + cylinder end fill/.initial=white, + cylinder body fill/.initial=white, +}% + + +\pgfdeclareshape{cylinder}{% + \savedmacro\getcylinderpoints{% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}% + \pgf@x\pgf@xc% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgf@y\pgf@yc% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \ifpgfshapeborderusesincircle% + \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \else% + \pgf@y\pgf@x% + \fi% + \pgf@x1.414213\pgf@x% + \pgf@y1.414213\pgf@y% + \else% + \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \pgfmathsetcount\c@pgf@counta{+\pgfmathresult}% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \edef\rotate{\the\c@pgf@counta}% + \ifnum\c@pgf@counta=90\relax% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xa% + \pgf@yc\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xa\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xa% + \pgf@yc\pgf@xc% + \fi% + \fi% + \fi% + \addtosavedmacro\rotate% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfutil@tempdima\pgfshapeaspect\pgf@ya% + \pgfutil@tempdimb\pgf@ya% + % + % Adjust for minimum height. + % + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgfutil@tempdimb<.5\pgf@xc\relax% + \pgfutil@tempdimb.5\pgf@xc% + \pgf@ya\pgfutil@tempdimb% + \fi% + % + % Calculate how far the node contents can extend into the cylinder bottom. + % + \pgf@yb\pgfutil@tempdimb% + \advance\pgf@yb-\pgf@yc% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yb}}{\pgfmath@tonumber{\pgfutil@tempdimb}}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + \let\angle\pgfmathresult% + \pgf@xb\pgfmathresult\pgfutil@tempdima% + % + % Adjust for minimum width. + % + \pgf@x.5\pgflinewidth% + \advance\pgf@x2.0\pgf@xa% + \advance\pgf@x3.0\pgfutil@tempdima% + \advance\pgf@x-\pgf@xb% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<\pgf@xc% + \advance\pgf@xc-\pgf@x% + \advance\pgf@xa.5\pgf@xc% + \fi% + % + % Add the larger of the outer sep to the radii. + % + \pgf@x\pgfutil@tempdima\relax% + \pgf@y\pgfutil@tempdimb\relax% + \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xc>\pgf@yc% + \advance\pgf@x\pgf@xc% + \advance\pgf@y\pgf@xc% + \edef\outersep{\the\pgf@xc}% + \else% + \advance\pgf@x\pgf@yc% + \advance\pgf@y\pgf@yc% + \edef\outersep{\the\pgf@yc}% + \fi% + \edef\xradius{\the\pgf@x}% + \edef\yradius{\the\pgf@y}% + \addtosavedmacro\xradius% + \addtosavedmacro\yradius% + \addtosavedmacro\outersep% + % + \pgfextract@process\cylindercenter{% + \pgf@x\pgfutil@tempdima% + \advance\pgf@x.5\pgflinewidth% + \advance\pgf@x\pgf@xb% + \pgf@x.5\pgf@x% + \pgf@y0pt% + }% + \addtosavedmacro\cylindercenter% + % + \pgfextract@process\beforetop{% + \pgf@x\pgf@xa% + \advance\pgf@x\pgfutil@tempdima% + \advance\pgf@x.5\pgflinewidth% + \pgf@y\pgf@ya% + }% + \pgfextract@process\afterbottom{% + \pgf@x-\pgf@xa% + \advance\pgf@x\pgf@xb% + \pgf@y\pgf@ya% + }% + \addtosavedmacro\beforetop% + \addtosavedmacro\afterbottom% + \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfextract@process\beforetopanchor{% + \beforetop% + \advance\pgf@y\pgf@yc% + }% + \pgfextract@process\afterbottomanchor{% + \afterbottom% + \advance\pgf@y\pgf@yc% + }% + \addtosavedmacro\beforetopanchor% + \addtosavedmacro\afterbottomanchor% + % + \beforetopanchor% + \advance\pgf@x\xradius\relax% + \ifdim\pgf@x>\pgf@y% + \edef\externalradius{\the\pgf@x}% + \else% + \edef\externalradius{\the\pgf@y}% + \fi% + \addtosavedmacro\externalradius% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{shape center}{% + \getcylinderpoints% + \pgfmathrotatepointaround{\pgfpointadd{\cylindercenter}{\centerpoint}}% + {\centerpoint}{\rotate}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \getcylinderpoints% + \let\pgf@cylinder@referencepoint\midpoint% + \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{mid west}{% + \getcylinderpoints% + \let\pgf@cylinder@referencepoint\midpoint% + \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \getcylinderpoints% + \let\pgf@cylinder@referencepoint\basepoint% + \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{base west}{% + \getcylinderpoints% + \let\pgf@cylinder@referencepoint\basepoint% + \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north east}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south west}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{south east}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \anchor{north west}{% + \getcylinderpoints% + \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{before top}{% + \getcylinderpoints% + \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor}{\centerpoint}}{\centerpoint}{\rotate}% + }% + \anchor{top}{% + \getcylinderpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \beforetop% + \pgf@y0pt\relax% + \advance\pgf@x\xradius\relax% + }{\centerpoint}}{\centerpoint}{\rotate}% + }% + \anchor{after top}{% + \getcylinderpoints% + \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}{\centerpoint}{\rotate}% + }% + \anchor{before bottom}{% + \getcylinderpoints% + \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}{\centerpoint}{\rotate}% + }% + \anchor{bottom}{% + \getcylinderpoints% + \pgfmathrotatepointaround{% + \pgfpointadd{% + \afterbottom% + \pgf@y0pt\relax% + \advance\pgf@x-\xradius\relax% + }{\centerpoint}}{\centerpoint}{\rotate}% + }% + \anchor{after bottom}{% + \getcylinderpoints% + \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor}{\centerpoint}}{\centerpoint}{\rotate}% + }% + \backgroundpath{% + \getcylinderpoints% + {% + \pgf@x\xradius\relax% + \advance\pgf@x-\outersep\relax% + \edef\xradius{\the\pgf@x}% + \pgf@y\yradius\relax% + \advance\pgf@y-\outersep\relax% + \edef\yradius{\the\pgf@y}% + \pgftransformshift{\centerpoint}% + \pgftransformrotate{\rotate}% + \pgfpathmoveto{\afterbottom}% + \pgfpatharc{90}{270}{\xradius and \yradius}% + \pgfpathlineto{\beforetop\pgf@y-\pgf@y}% + \pgfpatharc{-90}{90}{\xradius and \yradius}% + \pgfpathclose% + \pgfpathmoveto{\beforetop}% + \pgfpatharc{90}{270}{\xradius and \yradius}% + }% + }% + \behindbackgroundpath{% + \ifpgfcylinderusescustomfill% + \getcylinderpoints% + \pgf@x\xradius\relax% + \advance\pgf@x-\outersep\relax% + \edef\xradius{\the\pgf@x}% + \pgf@y\yradius\relax% + \advance\pgf@y-\outersep\relax% + \edef\yradius{\the\pgf@y}% + {% + \pgftransformshift{\centerpoint}% + \pgftransformrotate{\rotate}% + \pgfpathmoveto{\afterbottom}% + \pgfpatharc{90}{270}{\xradius and \yradius}% + \pgfpathlineto{\beforetop\pgf@y-\pgf@y}% + \pgfpatharc{270}{90}{\xradius and \yradius}% + \pgfpathclose% + \expandafter\pgfsetfillcolor\expandafter{\pgfkeysvalueof{/pgf/cylinder body fill}}% + \pgfusepath{fill}% + % + \pgfpathmoveto{\beforetop}% + \pgfpatharc{90}{-270}{\xradius and \yradius}% + \pgfpathclose + \expandafter\pgfsetfillcolor\expandafter{\pgfkeysvalueof{/pgf/cylinder end fill}}% + \pgfusepath{fill}% + }% + \fi% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \getcylinderpoints% + \pgfutil@ifundefined{pgf@cylinder@referencepoint}{\let\referencepoint\centerpoint}{% + \let\referencepoint\pgf@cylinder@referencepoint}% + \pgfextract@process\externalpoint{% + \externalpoint% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \referencepoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + % + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\afterbottomanchor}{\centerpoint}}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\beforetopanchor}{\centerpoint}}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathrotatepointaround{% + \pgfmathpointintersectionoflineandarc% + {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}% + {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}% + {% + \beforetop% + \pgf@xa\pgf@x% + \centerpoint% + \advance\pgf@x\pgf@xa% + }% + {0}{90}{\xradius and \yradius}% + }{\centerpoint}{\rotate}% + \else% + \pgfpointintersectionoflines{% + \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor}{\centerpoint}}% + {\centerpoint}{\rotate}}{% + \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor}{\centerpoint}}% + {\centerpoint}{\rotate}}% + {\referencepoint}{\externalpoint}% + \fi% + \else% + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}% + \ifdim\externalangle pt>\pgfmathresult pt\relax% + \pgfmathrotatepointaround{% + \pgfmathpointintersectionoflineandarc% + {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}% + {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}% + {% + \beforetop% + \pgf@xa\pgf@x% + \centerpoint + \advance\pgf@x\pgf@xa% + }% + {270}{360}{\xradius and \yradius}% + }{\centerpoint}{\rotate}% + \else% + \pgfpointintersectionoflines{% + \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}% + {\centerpoint}{\rotate}}{% + \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}% + {\centerpoint}{\rotate}}% + {\referencepoint}{\externalpoint}% + \fi% + \else% + \pgfmathrotatepointaround{% + \pgfmathpointintersectionoflineandarc% + {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}% + {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}% + {% + \afterbottom% + \pgf@xa\pgf@x% + \centerpoint + \advance\pgf@x\pgf@xa% + }% + {90}{270}{\xradius and \yradius}% + }{\centerpoint}{\rotate}% + \fi% + \fi% + }% +}% diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.misc.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.misc.code.tex new file mode 100644 index 0000000000..477a7b7caf --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.misc.code.tex @@ -0,0 +1,1127 @@ +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.misc.code.tex} + + +\pgfdeclareshape{cross out} +{% + \inheritsavedanchors[from=rectangle]% % this is nearly a rectangle + \inheritanchorborder[from=rectangle]% + \inheritanchor[from=rectangle]{north}% + \inheritanchor[from=rectangle]{north west}% + \inheritanchor[from=rectangle]{north east}% + \inheritanchor[from=rectangle]{center}% + \inheritanchor[from=rectangle]{west}% + \inheritanchor[from=rectangle]{east}% + \inheritanchor[from=rectangle]{mid}% + \inheritanchor[from=rectangle]{mid west}% + \inheritanchor[from=rectangle]{mid east}% + \inheritanchor[from=rectangle]{base}% + \inheritanchor[from=rectangle]{base west}% + \inheritanchor[from=rectangle]{base east}% + \inheritanchor[from=rectangle]{south}% + \inheritanchor[from=rectangle]{south west}% + \inheritanchor[from=rectangle]{south east}% + \foregroundpath{ + % store lower right in xa/ya and upper right in xb/yb + \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y + \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}} + \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}} + \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}} + \pgfsetarrowsstart{} + \pgfsetarrowsend{} + }% +}% + + +\pgfdeclareshape{strike out} +{% + \inheritsavedanchors[from=rectangle]% % this is nearly a rectangle + \inheritanchorborder[from=rectangle]% + \inheritanchor[from=rectangle]{north}% + \inheritanchor[from=rectangle]{north west}% + \inheritanchor[from=rectangle]{north east}% + \inheritanchor[from=rectangle]{center}% + \inheritanchor[from=rectangle]{west}% + \inheritanchor[from=rectangle]{east}% + \inheritanchor[from=rectangle]{mid}% + \inheritanchor[from=rectangle]{mid west}% + \inheritanchor[from=rectangle]{mid east}% + \inheritanchor[from=rectangle]{base}% + \inheritanchor[from=rectangle]{base west}% + \inheritanchor[from=rectangle]{base east}% + \inheritanchor[from=rectangle]{south}% + \inheritanchor[from=rectangle]{south west}% + \inheritanchor[from=rectangle]{south east}% + \foregroundpath{ + \pgfpathmoveto{\southwest} + \pgfpathlineto{\northeast} + \pgfsetarrowsstart{} + \pgfsetarrowsend{} + }% +}% + + +% Rounded rectangle + + +\pgfkeys{/pgf/.cd, + rounded rectangle west arc/.initial=convex, + rounded rectangle east arc/.initial=convex, + rounded rectangle left arc/.style={/pgf/rounded rectangle west arc={#1}},% + rounded rectangle right arc/.style={/pgf/rounded rectangle east arc={#1}},% + rounded rectangle arc length/.initial=180% +}% + +\def\pgf@lib@sh@misc@rr@text@concave{concave}% +\def\pgf@lib@sh@misc@rr@text@convex{convex}% + +\pgfdeclareshape{rounded rectangle}{% + \savedmacro\westarc{% + \edef\westarc{\pgfkeysvalueof{/pgf/rounded rectangle west arc}}% + }% + \savedmacro\eastarc{% + \edef\eastarc{\pgfkeysvalueof{/pgf/rounded rectangle east arc}}% + }% + \savedmacro\roundedrectanglepoints{% + % + % Get half the arc angle, a. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/rounded rectangle arc length}}% + \pgf@x=.5\pgf@x% + \edef\halfarcangle{\pgfmath@tonumber{\pgf@x}}% + \addtosavedmacro\halfarcangle% + % + % Get the (half) node dimensions x & y. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \edef\innerxsep{\the\pgf@x}% + \pgf@xa=0.5\wd\pgfnodeparttextbox% + \edef\halftextwidth{\the\pgf@xa}% + \addtosavedmacro\halftextwidth% + \advance\pgf@x by\pgf@xa% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \edef\innerysep{\the\pgf@y}% + \pgf@ya=.5\ht\pgfnodeparttextbox% + \advance\pgf@ya by.5\dp\pgfnodeparttextbox% + \edef\halftextheight{\the\pgf@ya}% + \addtosavedmacro\halftextheight% + \advance\pgf@y by\pgf@ya% + % + % Adjust for minimum height + % + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@y<.5\pgf@yb% + \pgf@y=.5\pgf@yb% + \fi% + \edef\halfheight{\the\pgf@y}% + \addtosavedmacro\halfheight% + % + % Calculate the radius of the arc ends. + % + \pgfmathcosec@{\halfarcangle}% + \pgf@ya=\pgfmathresult\pgf@y% + \edef\radius{\the\pgf@ya}% + \addtosavedmacro\radius% + % + % Arc width = r - r*cos(a/2). + % + \pgfmathcos@{\halfarcangle}% + \pgf@xa=\pgf@ya% + \advance\pgf@xa by-\pgfmathresult\pgf@ya% + % + % When the node contents are pushed inside a convex arc, + % the resulting chord has a height r - r*cos(asin(0.5*h/r)). + % + \pgfmathdivide{\halftextheight}{\radius}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathcos@{\pgfmathresult}% + \pgf@xb=\pgf@ya% + \advance\pgf@xb by-\pgfmathresult\pgf@ya% + % + % Adjust for minimum width. + % + \edef\westarc{\pgfkeysvalueof{/pgf/rounded rectangle west arc}}% + \edef\eastarc{\pgfkeysvalueof{/pgf/rounded rectangle east arc}}% + % + \pgfutil@tempdima=2.0\pgf@x% x still holds the half width. + \ifx\westarc\pgf@lib@sh@misc@rr@text@concave% + \advance\pgfutil@tempdima by\pgf@xa% + \else% + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \advance\pgfutil@tempdima by\pgf@xb% + \fi% + \fi% + % + \ifx\eastarc\pgf@lib@sh@misc@rr@text@concave% + \advance\pgfutil@tempdima by\pgf@xa% + \else% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \advance\pgfutil@tempdima by\pgf@xb% + \fi% + \fi% + % + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgfutil@tempdima<\pgfutil@tempdimb% + \advance\pgfutil@tempdimb by-\pgfutil@tempdima% + \divide\pgfutil@tempdimb by2\relax% + \edef\xoffset{\the\pgfutil@tempdimb}% + \else% + \let\xoffset=\innerxsep% + \fi% + % + % The node is made wider if convex arcs overlap. + % + \pgf@x=\halftextwidth\relax% + \advance\pgf@x by\xoffset\relax% + \pgf@xc=\pgf@ya% + \advance\pgf@xc by-\pgf@xb% + \ifdim\pgf@xc>\pgf@x\relax% + \advance\pgf@xc by-\pgf@x% + \advance\pgf@xc by\xoffset\relax% + \edef\xoffset{\the\pgf@xc}% + \fi% + \addtosavedmacro\xoffset% + % + \pgf@x=\halftextwidth\relax% + \advance\pgf@x by\xoffset\relax% + \edef\halfwidth{\the\pgf@x}% + \addtosavedmacro\halfwidth% + % + \edef\arcwidth{\the\pgf@xa}% + \addtosavedmacro\arcwidth% + % + \edef\chordwidth{\the\pgf@xb}% + \addtosavedmacro\chordwidth% + % + \pgfmathsetlengthmacro\outerxsep{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlengthmacro\outerysep{\pgfkeysvalueof{/pgf/outer ysep}}% + \addtosavedmacro\outerxsep% + \addtosavedmacro\outerysep% + % + % calculate some horizontal adjustments made for the default miter + % drawn when an arc meets the north or south side of the node path. + % + \ifdim\halfarcangle pt=90pt\relax% Avoid division by zero. + \def\concavexshift{0pt}% + \else% + % For a concave arc: outer xsep * cosec((90-a/2)/2)*cos((90-a/2)/2). + \pgfmathsubtract@{90}{\halfarcangle}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\angletemp=\pgfmathresult% + \pgf@x=\outerxsep\relax% + \pgfmathcosec@{\angletemp}% + \pgf@x=\pgfmathresult\pgf@x% + \pgfmathcos@{\angletemp}% + \pgf@x=\pgfmathresult\pgf@x% + \edef\concavexshift{\the\pgf@x}% + \fi% + \addtosavedmacro\concavexshift% + % + \ifdim\halfarcangle pt=90pt\relax% Avoid division by zero. + \def\convexxshift{0pt}% + \else% + % For a convex arc: outer xsep * cosec((90+a/2)/2)*cos((90+a/2)/2). + \pgfmathadd@{90}{\halfarcangle}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\angletemp=\pgfmathresult% + \pgf@x=\outerxsep\relax% + \pgfmathcosec@{\angletemp}% + \pgf@x=\pgfmathresult\pgf@x% + \pgfmathcos@{\angletemp}% + \pgf@x=\pgfmathresult\pgf@x% + \edef\convexxshift{\the\pgf@x}% + \fi% + \addtosavedmacro\convexxshift% + }% + \saveddimen\halflinewidth{\pgf@x.5\pgflinewidth}% + \savedanchor\centerpoint{% + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgf@y=.5\ht\pgfnodeparttextbox% + \advance\pgf@y by-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgf@y=0pt\relax% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid west}{% + \csname pgf@anchor@rounded rectangle@west\endcsname% + \pgf@xc=\pgf@x% + \midpoint% + \pgf@x=\pgf@xc% + }% + \anchor{mid east}{% + \csname pgf@anchor@rounded rectangle@east\endcsname% + \pgf@xc=\pgf@x% + \midpoint% + \pgf@x=\pgf@xc% + }% + \anchor{base}{\basepoint}% + \anchor{base west}{% + \csname pgf@anchor@rounded rectangle@west\endcsname% + \pgf@xc=\pgf@x% + \basepoint% + \pgf@x=\pgf@xc% + }% + \anchor{base east}{% + \csname pgf@anchor@rounded rectangle@east\endcsname% + \pgf@xc=\pgf@x% + \basepoint% + \pgf@x=\pgf@xc% + }% + \anchor{north}{% + \roundedrectanglepoints% + \pgfpointadd{\centerpoint}{\pgfpoint{+0pt}{\halfheight+\outerysep}}% + }% + \anchor{south}{% + \roundedrectanglepoints% + \pgfpointadd{\centerpoint}{\pgfpoint{+0pt}{-\halfheight-\outerysep}}% + }% + \anchor{west}{% + \roundedrectanglepoints% + \pgfpointadd{\centerpoint}{% + \ifx\westarc\pgf@lib@sh@misc@rr@text@concave% + \pgfpoint{-\halfwidth-\arcwidth-\concavexshift}{+0pt}% + \else% + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpoint{-\halfwidth-\chordwidth-\outerxsep}{+0pt}% + \else% + \pgfpoint{-\halfwidth-\outerxsep}{+0pt}% + \fi% + \fi% + }% + }% + \anchor{north west}{% + \roundedrectanglepoints% + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpointadd{\centerpoint}{\pgfpoint{-\halfwidth-\chordwidth+\arcwidth-\convexxshift}{+0pt}}% + \else% + \csname pgf@anchor@rounded rectangle@west\endcsname% + \fi% + \pgf@xc=\pgf@x% + \csname pgf@anchor@rounded rectangle@north\endcsname% + \pgf@x=\pgf@xc% + }% + \anchor{south west}{% + \roundedrectanglepoints% + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpointadd{\centerpoint}{\pgfpoint{-\halfwidth-\chordwidth+\arcwidth-\convexxshift}{+0pt}}% + \else% + \csname pgf@anchor@rounded rectangle@west\endcsname% + \fi% + \pgf@xc=\pgf@x% + \csname pgf@anchor@rounded rectangle@south\endcsname% + \pgf@x=\pgf@xc% + }% + \anchor{east}{% + \roundedrectanglepoints% + \pgfpointadd{\centerpoint}{% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@concave% + \pgfpoint{\halfwidth+\arcwidth+\concavexshift}{+0pt}% + \else% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpoint{\halfwidth+\chordwidth+\outerxsep}{+0pt}% + \else% + \pgfpoint{\halfwidth+\outerxsep}{+0pt}% + \fi% + \fi% + }% + }% + \anchor{north east}{% + \roundedrectanglepoints% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpointadd{\centerpoint}{\pgfpoint{\halfwidth+\chordwidth-\arcwidth+\convexxshift}{+0pt}}% + \else% + \csname pgf@anchor@rounded rectangle@east\endcsname% + \fi% + \pgf@xc=\pgf@x% + \csname pgf@anchor@rounded rectangle@north\endcsname% + \pgf@x=\pgf@xc% + }% + \anchor{south east}{% + \roundedrectanglepoints% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpointadd{\centerpoint}{\pgfpoint{\halfwidth+\chordwidth-\arcwidth+\convexxshift}{+0pt}}% + \else% + \csname pgf@anchor@rounded rectangle@east\endcsname% + \fi% + \pgf@xc=\pgf@x% + \csname pgf@anchor@rounded rectangle@south\endcsname% + \pgf@x=\pgf@xc% + }% + \backgroundpath{% + {% + \roundedrectanglepoints% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfpoint{0pt}{\halfheight}}% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@concave% + \pgfpathlineto{\pgfpoint{\halfwidth+\arcwidth}{+\halfheight}}% + \pgfpatharc{180-\halfarcangle}{180+\halfarcangle}{+\radius}% + \else% + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpathlineto{\pgfpoint{\halfwidth+\chordwidth-\arcwidth}{+\halfheight}}% + \pgfpatharc{+\halfarcangle}{+-\halfarcangle}{+\radius}% + \else% + \pgfpathlineto{\pgfqpoint{\halfwidth}{\halfheight}}% + \pgfpathlineto{\pgfqpoint{\halfwidth}{-\halfheight}}% + \fi% + \fi% + \ifx\westarc\pgf@lib@sh@misc@rr@text@concave% + \pgfpathlineto{\pgfpoint{-\halfwidth-\arcwidth}{+-\halfheight}}% + \pgfpatharc{+-\halfarcangle}{+\halfarcangle}{+\radius}% + \else% + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \pgfpathlineto{\pgfpoint{-\halfwidth-\chordwidth+\arcwidth}{+-\halfheight}}% + \pgfpatharc{180+\halfarcangle}{180-\halfarcangle}{+\radius}% + \else% + \pgfpathlineto{\pgfqpoint{-\halfwidth}{-\halfheight}}% + \pgfpathlineto{\pgfqpoint{-\halfwidth}{\halfheight}}% + \fi% + \fi% + \pgfpathclose% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{% + \pgfextract@process\externalpoint{}% + \pgfpointadd{\centerpoint}{\externalpoint}% + }% + \roundedrectanglepoints% + % + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle=\pgfmathresult% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@rounded rectangle@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@rounded rectangle@north east\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + % Between north east and east. + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfextract@process\arccenter{% + \pgfpointadd{\centerpoint}{\pgfpoint{\halfwidth+\chordwidth-\radius}{+0pt}}% + }% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {\arccenter}{0}{\halfarcangle}{\radius+\outerxsep and \radius+\outerysep}% + \else% + \pgfpointintersectionoflines% + {\csname pgf@anchor@rounded rectangle@north east\endcsname}% + {\csname pgf@anchor@rounded rectangle@south east\endcsname}% + {\externalpoint}{\centerpoint}% + \fi% + \else% + % Between north west and north east. + \pgfpointintersectionoflines% + {\csname pgf@anchor@rounded rectangle@north east\endcsname}% + {\csname pgf@anchor@rounded rectangle@north west\endcsname}% + {\externalpoint}{\centerpoint}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@rounded rectangle@south west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + % Between south west and north west. + \ifx\westarc\pgf@lib@sh@misc@rr@text@convex% + \pgfextract@process\arccenter{% + \pgfpointadd{\centerpoint}{\pgfpoint{-\halfwidth-\chordwidth+\radius}{+0pt}}% + }% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {\arccenter}{180-\halfarcangle}{180+\halfarcangle}{\radius+\outerxsep and \radius+\outerysep}% + \else% + \pgfpointintersectionoflines% + {\csname pgf@anchor@rounded rectangle@north west\endcsname}% + {\csname pgf@anchor@rounded rectangle@south west\endcsname}% + {\externalpoint}{\centerpoint}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@rounded rectangle@south east\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + % Between south east and south west. + \pgfpointintersectionoflines% + {\csname pgf@anchor@rounded rectangle@south east\endcsname}% + {\csname pgf@anchor@rounded rectangle@south west\endcsname}% + {\externalpoint}{\centerpoint}% + \else% + % Between east and south east. + \ifx\eastarc\pgf@lib@sh@misc@rr@text@convex% + \pgfextract@process\arccenter{% + \pgfpointadd{\centerpoint}{\pgfpoint{\halfwidth+\chordwidth-\radius}{+0pt}}% + }% + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {\arccenter}{360-\halfarcangle}{360}{\radius+\outerxsep and \radius+\outerysep}% + \else% + \pgfpointintersectionoflines% + {\csname pgf@anchor@rounded rectangle@north east\endcsname}% + {\csname pgf@anchor@rounded rectangle@south east\endcsname}% + {\externalpoint}{\centerpoint}% + \fi% + \fi% + \fi% + \fi% + }% +}% + + + +% Keys for chamfered rectangle +% +% /pgf/chamfered rectangle corners : specify the corners to chamfer. +% /pgf/chamfered rectangle angle : set the angle of the chamfer. +% /pgf/chamfered rectangle xsep : set the extent of the x chamferling. +% /pgf/chamfered rectangle ysep : set the extent of the y chamferling. + +\pgfkeys{/pgf/chamfered rectangle corners/.store in=\pgf@lib@sh@misc@cr@corners}% +\pgfkeys{/tikz/chamfered rectangle corners/.store in=\pgf@lib@sh@misc@cr@corners}% + +\def\pgf@lib@sh@misc@cr@chamferall{chamfer all}% +\def\pgf@lib@sh@misc@cr@chamfer{chamfer}% +\let\pgf@lib@sh@misc@cr@corners\pgf@lib@sh@misc@cr@chamferall + + +\def\pgf@lib@sh@misc@cr@getcorners{% + \let\northeastcorner\pgfutil@empty% + \let\southeastcorner\pgfutil@empty% + \let\southwestcorner\pgfutil@empty% + \let\northwestcorner\pgfutil@empty% + \expandafter\pgfutil@in@\expandafter{\pgf@lib@sh@misc@cr@corners}{chamfer all}% + \ifpgfutil@in@% + \let\northeastcorner\pgf@lib@sh@misc@cr@round% + \let\southeastcorner\pgf@lib@sh@misc@cr@round% + \let\southwestcorner\pgf@lib@sh@misc@cr@round% + \let\northwestcorner\pgf@lib@sh@misc@cr@round% + \let\pgf@next\relax% + \else% + \let\pgf@next\pgf@lib@sh@misc@cr@parsecorners% + \fi% + \pgf@next}% + +\def\pgf@lib@sh@misc@cr@parsecorners{% + \expandafter\pgf@@chamferedrectangle@parsecorners\pgf@lib@sh@misc@cr@corners,\pgf@stop,% +}% + +\def\pgf@@chamferedrectangle@parsecorners#1,{% + \ifx#1\pgf@stop% + \let\pgf@next\relax% + \else% + \pgfutil@in@{@#1@}{@north east@@top left@}% + \ifpgfutil@in@% + \let\northeastcorner\pgf@lib@sh@misc@cr@chamfer% + \else% + \pgfutil@in@{@#1@}{@south east@@bottom right@}% + \ifpgfutil@in@% + \let\southeastcorner\pgf@lib@sh@misc@cr@chamfer% + \else% + \pgfutil@in@{@#1@}{@south west@@bottom left@}% + \ifpgfutil@in@% + \let\southwestcorner\pgf@lib@sh@misc@cr@chamfer% + \else% + \pgfutil@in@{@#1@}{@north west@@top right@}% + \ifpgfutil@in@% + \let\northwestcorner\pgf@lib@sh@misc@cr@round% + \fi% + \fi% + \fi% + \fi% + \let\pgf@next\pgf@@@chamferedrectangle@parsecorners% + \fi% + \pgf@next% +}% +\def\pgf@@@chamferedrectangle@parsecorners{% + \pgfutil@ifnextchar x{\pgf@@chamferedrectangle@parsecorners}{\pgf@@chamferedrectangle@parsecorners}% +}% + +\pgfkeys{/pgf/.cd, + chamfered rectangle angle/.initial=45,% + chamfered rectangle xsep/.initial=.666ex,% + chamfered rectangle ysep/.initial=.666ex% +}% + \pgfkeys{/pgf/chamfered rectangle sep/.style={% + /pgf/chamfered rectangle xsep={#1},/pgf/chamfered rectangle ysep={#1}}% +}% + + + + +% Shape chamfered rectangle. +% +% +\pgfdeclareshape{chamfered rectangle}{% + \savedmacro\getchamferedrectanglepoints{% + \pgf@lib@sh@misc@cr@getcorners% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya.5\ht\pgfnodeparttextbox% + \advance\pgf@ya.5\dp\pgfnodeparttextbox% + % + % Get chamfer stuff. + % + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/chamfered rectangle angle}}% + \ifdim\pgfutil@tempdima<89pt\relax% + \ifdim\pgfutil@tempdima<1pt\relax% + \pgfutil@tempdima1pt\relax% + \fi% + \else% + \pgfutil@tempdima89pt\relax% + \fi% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima90pt\relax% + \pgfmathtan@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \let\tanangle\pgfmathresult% + \pgfmathcot@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \let\cotangle\pgfmathresult% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/chamfered rectangle xsep}}% + \pgf@yc\tanangle\pgf@xb% + \ifdim\pgf@yc>\pgf@ya% + \pgf@yc\pgf@ya% + \pgf@xb\cotangle\pgf@yc% + \fi% + \pgfmathcot@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/chamfered rectangle ysep}}% + \pgf@xc\cotangle\pgf@yb% + \ifdim\pgf@xc>\pgf@xa% + \pgf@xc\pgf@xa% + \pgf@yb\tanangle\pgf@xc% + \fi% + % + % Check for minimum width and height% + % + \pgfutil@tempdima\pgf@xa% + \advance\pgfutil@tempdima\pgf@xb% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgfutil@tempdima<.5\pgfutil@tempdimb% + \pgf@xa.5\pgfutil@tempdimb% + \advance\pgf@xa-\pgf@xb% + \fi% + \pgfutil@tempdima\pgf@ya% + \advance\pgfutil@tempdima\pgf@yb% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgfutil@tempdima<.5\pgfutil@tempdimb% + \pgf@ya.5\pgfutil@tempdimb% + \advance\pgf@ya-\pgf@yb% + \fi% + % + % Define the background path points. + % + \pgfextract@process\centerpoint{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5\ht\pgfnodeparttextbox}% + \pgfmathaddtolength\pgf@y{+-.5\dp\pgfnodeparttextbox}% + }% + \pgfextract@process\beforenortheast{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@ya% + \advance\pgf@y-\pgf@yc% + }% + \pgfextract@process\northeast{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + \ifx\northeastcorner\pgfutil@empty% + \advance\pgf@x\pgf@xb% + \advance\pgf@y\pgf@yb% + \fi% + }% + \pgfextract@process\afternortheast{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@x-\pgf@xc% + \advance\pgf@y\pgf@ya% + \advance\pgf@y\pgf@yb% + }% + \pgfextract@process\northwest{% + \centerpoint% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y\pgf@ya% + \ifx\northwestcorner\pgfutil@empty% + \advance\pgf@x-\pgf@xb% + \advance\pgf@y\pgf@yb% + \fi% + }% + \pgfextract@process\beforesouthwest{% + \centerpoint% + \advance\pgf@x-\pgf@xa% + \advance\pgf@x-\pgf@xb% + \advance\pgf@y-\pgf@ya% + \advance\pgf@y\pgf@yc% + }% + \pgfextract@process\southwest{% + \centerpoint% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y-\pgf@ya% + \ifx\southwestcorner\pgfutil@empty% + \advance\pgf@x-\pgf@xb% + \advance\pgf@y-\pgf@yb% + \fi% + }% + \pgfextract@process\aftersouthwest{% + \centerpoint% + \advance\pgf@x-\pgf@xa% + \advance\pgf@x\pgf@xc% + \advance\pgf@y-\pgf@ya% + \advance\pgf@y-\pgf@yb% + }% + \pgfextract@process\southeast{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y-\pgf@ya% + \ifx\southeastcorner\pgfutil@empty% + \advance\pgf@x\pgf@xb% + \advance\pgf@y-\pgf@yb% + \fi% + }% + % + % Calculate the `miter' vectors. + % + \pgfmathanglebetweenlines{\beforenortheast}{\afternortheast}{\beforenortheast}% + {\beforesouthwest\pgf@ya\pgf@y\beforenortheast\pgf@y\pgf@ya}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \ifdim\pgfutil@tempdima>180pt\relax% + \advance\pgfutil@tempdima-180pt\relax% + \fi% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/outer xsep}}% + \ifdim\pgfutil@tempdima<90pt\relax% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \pgfutil@tempdima0pt\relax% + \else% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima90pt\relax% + \fi% + \pgfextract@process\before@ne@anchor{% + \beforenortheast% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \pgfextract@process\before@sw@anchor{% + \beforesouthwest% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfqpointpolar{-\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + \pgfmathanglebetweenlines{\afternortheast}{\aftersouthwest\pgf@xa\pgf@x\afternortheast\pgf@x\pgf@xa}% + {\afternortheast}{\beforenortheast}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \ifdim\pgfutil@tempdima>270pt\relax% + \advance\pgfutil@tempdima-270pt\relax% + \fi% + \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgfutil@tempdima<90pt\relax% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \pgfutil@tempdima90pt\relax% + \else% + \pgfutil@tempdima.5\pgfutil@tempdima% + \pgfmathcosec@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdimb\pgfmathresult\pgfutil@tempdimb% + \fi% + % + \pgfextract@process\after@ne@anchor{% + \afternortheast% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfqpointpolar{\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfutil@tempdima-\pgfutil@tempdima% + \advance\pgfutil@tempdima180pt\relax% + \pgfextract@process\after@sw@anchor{% + \aftersouthwest + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfqpointpolar{-\pgfmath@tonumber{\pgfutil@tempdima}}{\the\pgfutil@tempdimb}% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \addtosavedmacro\before@ne@anchor% + \addtosavedmacro\after@ne@anchor% + \addtosavedmacro\before@sw@anchor% + \addtosavedmacro\after@sw@anchor% + \pgfextract@process\ne@anchor{% + \ifx\northeastcorner\pgfutil@empty% + \northeast% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \else% + \pgfpointlineattime{0.5}{\before@ne@anchor}{\after@ne@anchor}% + \fi% + }% + \pgfextract@process\nw@anchor{% + \ifx\northwestcorner\pgfutil@empty% + \northwest% + \pgfmathaddtolength\pgf@x{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \else% + \pgfpointlineattime{0.5}{% + \before@ne@anchor% + \pgf@ya\pgf@y + \before@sw@anchor% + \pgf@y\pgf@ya% + }{% + \after@ne@anchor% + \pgf@ya\pgf@y + \after@sw@anchor% + \pgf@y\pgf@ya% + }% + \fi% + }% + \pgfextract@process\sw@anchor{% + \ifx\southwestcorner\pgfutil@empty% + \southwest% + \pgfmathaddtolength\pgf@x{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{-\pgfkeysvalueof{/pgf/outer ysep}}% + \else% + \pgfpointlineattime{0.5}{\before@sw@anchor}{\after@sw@anchor}% + \fi% + }% + \pgfextract@process\se@anchor{% + \ifx\southeastcorner\pgfutil@empty% + \southeast% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{-\pgfkeysvalueof{/pgf/outer ysep}}% + \else% + \pgfpointlineattime{0.5}{% + \before@ne@anchor% + \pgf@xa\pgf@x + \before@sw@anchor% + \pgf@x\pgf@xa% + }{% + \after@ne@anchor% + \pgf@xa\pgf@x + \after@sw@anchor% + \pgf@x\pgf@xa% + }% + \fi% + }% + \addtosavedmacro\ne@anchor% + \addtosavedmacro\nw@anchor% + \addtosavedmacro\sw@anchor% + \addtosavedmacro\se@anchor% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \getchamferedrectanglepoints% + \midpoint% + \pgf@ya\pgf@y% + \pgf@process{% + \before@sw@anchor% + \pgf@ya\pgf@y% + \before@ne@anchor% + \pgf@y\pgf@ya% + }% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\after@sw@anchor\pgf@ya\pgf@y\after@ne@anchor\pgf@y\pgf@ya}% + \else% + \pgf@process{\before@ne@anchor}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor}% + \else% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor}% + {\after@ne@anchor}% + \fi% + \fi% + }% + \anchor{mid west}{% + \getchamferedrectanglepoints% + \midpoint% + \pgf@ya\pgf@y% + \pgf@process{\before@sw@anchor}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor}{\after@sw@anchor}% + \else% + \pgf@process{\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor}% + \else% + \pgfpointintersectionoflines{\midpoint}{\midpoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\after@ne@anchor\pgf@ya\pgf@y\after@sw@anchor\pgf@y\pgf@ya}% + \fi% + \fi% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \getchamferedrectanglepoints% + \basepoint% + \pgf@ya\pgf@y% + \pgf@process{% + \before@sw@anchor% + \pgf@ya\pgf@y% + \before@ne@anchor% + \pgf@y\pgf@ya% + }% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\after@sw@anchor\pgf@ya\pgf@y\after@ne@anchor\pgf@y\pgf@ya}% + \else% + \pgf@process{\before@ne@anchor}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor}% + \else% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor}% + {\after@ne@anchor}% + \fi% + \fi% + }% + \anchor{base west}{% + \getchamferedrectanglepoints% + \basepoint% + \pgf@ya\pgf@y% + \pgf@process{\before@sw@anchor}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor}{\after@sw@anchor}% + \else% + \pgf@process{\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + \ifdim\pgf@ya<\pgf@y% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@sw@anchor}% + \else% + \pgfpointintersectionoflines{\basepoint}{\basepoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\before@ne@anchor\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + {\after@ne@anchor\pgf@ya\pgf@y\after@sw@anchor\pgf@y\pgf@ya}% + \fi% + \fi% + }% + \anchor{before north east}{\getchamferedrectanglepoints\before@ne@anchor}% + \anchor{north east}{\getchamferedrectanglepoints\ne@anchor}% + \anchor{after north east}{\getchamferedrectanglepoints\after@ne@anchor}% + \anchor{north}{% + \getchamferedrectanglepoints% + \centerpoint% + \pgf@xa\pgf@x% + \after@ne@anchor% + \pgf@x\pgf@xa}% + \anchor{before north west}{% + \getchamferedrectanglepoints% + \after@sw@anchor% + \pgf@xa\pgf@x% + \after@ne@anchor% + \pgf@x\pgf@xa}% + \anchor{north west}{\getchamferedrectanglepoints\nw@anchor}% + \anchor{after north west}{% + \getchamferedrectanglepoints% + \before@sw@anchor% + \pgf@xa\pgf@x% + \before@ne@anchor% + \pgf@x\pgf@xa}% + \anchor{west}{% + \getchamferedrectanglepoints% + \centerpoint% + \pgf@ya\pgf@y% + \before@sw@anchor% + \pgf@y\pgf@ya}% + \anchor{before south west}{\getchamferedrectanglepoints\before@sw@anchor}% + \anchor{south west}{\getchamferedrectanglepoints\sw@anchor}% + \anchor{after south west}{\getchamferedrectanglepoints\after@sw@anchor}% + \anchor{south}{% + \getchamferedrectanglepoints% + \centerpoint% + \pgf@xa\pgf@x% + \after@sw@anchor% + \pgf@x\pgf@xa}% + \anchor{before south east}{% + \getchamferedrectanglepoints% + \after@sw@anchor% + \pgf@ya\pgf@y% + \after@ne@anchor% + \pgf@y\pgf@ya}% + \anchor{south east}{\getchamferedrectanglepoints\se@anchor}% + \anchor{after south east}{% + \getchamferedrectanglepoints% + \before@sw@anchor% + \pgf@ya\pgf@y% + \before@ne@anchor% + \pgf@y\pgf@ya}% + \anchor{east}{% + \getchamferedrectanglepoints% + \centerpoint% + \pgf@ya\pgf@y% + \before@ne@anchor% + \pgf@y\pgf@ya}% + \backgroundpath{% + \pgfpathmoveto{\beforenortheast}% + \pgfpathlineto{\northeast}% + \pgfpathlineto{\afternortheast}% + \pgfpathlineto{\aftersouthwest\pgf@xa\pgf@x\afternortheast\pgf@x\pgf@xa}% + \pgfpathlineto{\northwest}% + \pgfpathlineto{\beforesouthwest\pgf@xa\pgf@x\beforenortheast\pgf@x\pgf@xa}% + \pgfpathlineto{\beforesouthwest}% + \pgfpathlineto{\southwest}% + \pgfpathlineto{\aftersouthwest}% + \pgfpathlineto{\aftersouthwest\pgf@ya\pgf@y\afternortheast\pgf@y\pgf@ya}% + \pgfpathlineto{\southeast}% + \pgfpathlineto{\beforesouthwest\pgf@ya\pgf@y\beforenortheast\pgf@y\pgf@ya}% + \pgfpathclose% + }% + \anchorborder{% + \pgfextract@process\externalpoint{% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \getchamferedrectanglepoints% + \pgfmathanglebetweenpoints{\centerpoint}{\centerpoint\pgf@ya\pgf@y\before@sw@anchor\pgf@y\pgf@ya}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% west. + \pgfmathanglebetweenpoints{\centerpoint}{\centerpoint\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% north. + \pgfmathanglebetweenpoints{\centerpoint}{\ne@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% north east. + \pgfmathanglebetweenpoints{\centerpoint}{\before@ne@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% before north east. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\centerpoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}{\before@ne@anchor}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\before@ne@anchor}{\ne@anchor}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\after@ne@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% after north east. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\ne@anchor}{\after@ne@anchor}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\after@ne@anchor}{\centerpoint\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\nw@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% north west. + \pgfmathanglebetweenpoints{\centerpoint}{\after@sw@anchor\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% before north west. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\centerpoint\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + {\after@sw@anchor\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\after@sw@anchor\pgf@xa\pgf@x\after@ne@anchor\pgf@x\pgf@xa}% + {\nw@anchor}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\before@sw@anchor\pgf@xa\pgf@x\before@ne@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% after north west. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\nw@anchor}{\before@sw@anchor\pgf@xa\pgf@x\before@ne@anchor\pgf@x\pgf@xa}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\before@sw@anchor\pgf@xa\pgf@x\before@ne@anchor\pgf@x\pgf@xa}% + {\before@sw@anchor\pgf@xa\pgf@x\centerpoint\pgf@x\pgf@xa}% + \fi% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\centerpoint\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% south. + \pgfmathanglebetweenpoints{\centerpoint}{\sw@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% south west. + \pgfmathanglebetweenpoints{\centerpoint}{\before@sw@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% before south west. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\before@sw@anchor\pgf@xa\pgf@x\centerpoint\pgf@x\pgf@xa}% + {\before@sw@anchor}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\before@sw@anchor}{\sw@anchor}% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\after@sw@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% after south west. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\sw@anchor}{\after@sw@anchor}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\after@sw@anchor}{\centerpoint\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\se@anchor}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% south east. + \pgfmathanglebetweenpoints{\centerpoint}{\after@ne@anchor\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% before south east. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\after@ne@anchor\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}% + {\centerpoint\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\after@ne@anchor\pgf@xa\pgf@x\after@sw@anchor\pgf@x\pgf@xa}{\se@anchor} + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\before@ne@anchor\pgf@xa\pgf@x\before@sw@anchor\pgf@x\pgf@xa}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% after south east. + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\se@anchor}{\before@ne@anchor\pgf@xa\pgf@x\before@sw@anchor\pgf@x\pgf@xa}% + \else% + \pgfpointintersectionoflines{\centerpoint}{\externalpoint}% + {\before@ne@anchor\pgf@xa\pgf@x\before@sw@anchor\pgf@x\pgf@xa}% + {\centerpoint\pgf@ya\pgf@y\before@ne@anchor\pgf@y\pgf@ya}% + \fi% + \fi% + \fi% + \fi% + }% +}% + + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.multipart.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.multipart.code.tex new file mode 100644 index 0000000000..481e65094f --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.multipart.code.tex @@ -0,0 +1,1356 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.multipart.code.tex} + +\newbox\pgfnodepartlowerbox + +% +% A circle that is split in the middle into an upper and a lower part. +% +% This node consists of two parts: The upper (main) part is shown in +% the upper half of the circle. The second part is the (optional) +% lower part. +% +% Parts: text, lower + +\pgfdeclareshape{circle split} +{% + % + % Node parts + % + \nodeparts{text,lower}% + + % + % Anchors + % + \savedanchor\centerpoint{% + \pgf@x=.5\wd\pgfnodeparttextbox% + \pgfmathsetlength{\pgf@y}{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgf@y=-\pgf@y% + \advance\pgf@y by-\dp\pgfnodeparttextbox% + \advance\pgf@y by-.5\pgflinewidth% + }% + \savedanchor\loweranchor{% + \pgf@x=-.5\wd\pgfnodepartlowerbox% + \advance\pgf@x by.5\wd\pgfnodeparttextbox% + \pgfmathsetlength{\pgf@y}{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgf@y=-2\pgf@y% + \advance\pgf@y by-\ht\pgfnodepartlowerbox% + \advance\pgf@y by-.5\pgflinewidth% + \advance\pgf@y by-\dp\pgfnodeparttextbox% + \advance\pgf@y by-.5\pgflinewidth% + }% + + \saveddimen\radius{% + % + % Calculate ``height radius'' + % + %\pgf@ya=.5\ht\pgfnodeparttextbox% +% \advance\pgf@ya by.5\dp\pgfnodeparttextbox% +% \advance\pgf@ya by.5\ht\pgfnodepartlowerbox% +% \advance\pgf@ya by.5\dp\pgfnodepartlowerbox% +% \advance\pgf@ya by.5\pgflinewidth% + % + % MW: Suggested correction for above calculation: Use the tallest box * 2. + % + \pgf@ya=.5\ht\pgfnodeparttextbox% + \advance\pgf@ya by.5\dp\pgfnodeparttextbox% + \pgf@yb=.5\ht\pgfnodepartlowerbox% + \advance\pgf@yb by.5\dp\pgfnodepartlowerbox% + \ifdim\pgf@ya>\pgf@yb\relax% + \pgf@ya2.0\pgf@ya\relax% + \else% + \pgf@ya2.0\pgf@yb\relax% + \fi% + \advance\pgf@ya by.5\pgflinewidth% + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya by2\pgf@yb% + % + % Calculate ``width radius'' + % + \pgf@xa=.5\wd\pgfnodeparttextbox% + \ifdim\pgf@xa<.5\wd\pgfnodepartlowerbox% + \pgf@xa=.5\wd\pgfnodepartlowerbox% + \fi% + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa by\pgf@xb% + % + % Calculate length of radius vector: + % + \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + \ifdim\pgf@x>\pgf@y% + \c@pgf@counta=\pgf@x% + \ifnum\c@pgf@counta=0\relax% + \else% + \divide\c@pgf@counta by 255\relax% + \pgf@xa=16\pgf@xa\relax% + \divide\pgf@xa by\c@pgf@counta% + \pgf@xa=16\pgf@xa\relax% + \fi% + \else% + \c@pgf@counta=\pgf@y% + \ifnum\c@pgf@counta=0\relax% + \else% + \divide\c@pgf@counta by 255\relax% + \pgf@ya=16\pgf@ya\relax% + \divide\pgf@ya by\c@pgf@counta% + \pgf@xa=16\pgf@ya\relax% + \fi% + \fi% + \pgf@x=\pgf@xa% + % + % If necessary, adjust radius so that the size requirements are + % met: + % + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<.5\pgf@xb% + \pgf@x=.5\pgf@xb% + \fi% + \ifdim\pgf@x<.5\pgf@yb% + \pgf@x=.5\pgf@yb% + \fi% + % + % Now, add larger of outer separations. + % + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgf@x by\pgf@yb% + \else% + \advance\pgf@x by\pgf@xb% + \fi% + }% + + % + % Anchors + % + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \anchor{lower}{\loweranchor}% + + % + % Background path + % + \inheritbackgroundpath[from=circle]% + \beforebackgroundpath{ + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgfutil@tempdima by-\pgf@yb% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \advance\pgfutil@tempdima by-.5\pgflinewidth% + \pgfsetshortenstart{0pt}% + \pgfsetshortenend{0pt}% + \pgfsetarrows{-}% + \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpoint{-1\pgfutil@tempdima}{0pt}}}% + \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpoint{\pgfutil@tempdima}{0pt}}}% + \pgfusepath{stroke}% + }% +}% + + +% +% A circle that is split diagonally into an upper and a lower part. +% +% Parts: text, lower + +\pgfdeclareshape{circle solidus}{% + % Node parts + \nodeparts{text,lower}% + % Anchors + % solidus slants at 45 degrees + % text placement minimizes the required radius, + % this is achieved placing the "outer" corner + % of each box in the line orthogonal to the + % solidus which passes through circle center + \savedanchor\centerpoint{% + \pgf@x=0.5\wd\pgfnodeparttextbox% + \advance\pgf@x by0.5\dp\pgfnodeparttextbox% + \advance\pgf@x by0.5\ht\pgfnodeparttextbox% + \pgf@y=-\pgf@x% + \advance\pgf@y by\ht\pgfnodeparttextbox% + \advance\pgf@x by0.3536\pgflinewidth% + \advance\pgf@y by-0.3536\pgflinewidth% + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x by\pgf@xa% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y by-\pgf@ya% + }% + \savedanchor\loweranchor{% + \pgf@x=0.5\wd\pgfnodeparttextbox% + \advance\pgf@x by0.5\dp\pgfnodeparttextbox% + \advance\pgf@x by0.5\ht\pgfnodeparttextbox% + \pgf@y=-\pgf@x% + \advance\pgf@y by\ht\pgfnodeparttextbox% + \advance\pgf@x by0.5\ht\pgfnodepartlowerbox% + \advance\pgf@x by0.5\dp\pgfnodepartlowerbox% + \advance\pgf@x by-0.5\wd\pgfnodepartlowerbox% + \advance\pgf@y by-0.5\ht\pgfnodepartlowerbox% + \advance\pgf@y by0.5\dp\pgfnodepartlowerbox% + \advance\pgf@y by-0.5\wd\pgfnodepartlowerbox% + \advance\pgf@x by0.7071\pgflinewidth% + \advance\pgf@y by-0.7071\pgflinewidth% + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x by2\pgf@xa% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y by-2\pgf@ya% + }% + \saveddimen\radius{% + % "top" radius + \pgf@x=\ht\pgfnodeparttextbox% + \advance\pgf@x by\dp\pgfnodeparttextbox% + \advance\pgf@x by\wd\pgfnodeparttextbox% + % "bottom" radius + \pgf@y=\ht\pgfnodepartlowerbox% + \advance\pgf@y by\dp\pgfnodepartlowerbox% + \advance\pgf@y by\wd\pgfnodepartlowerbox% + % use the larger + \ifdim\pgf@x<\pgf@y% + \pgf@x=\pgf@y% + \fi% + \pgf@x=0.7071\pgf@x% + % add spacings + \advance\pgf@x by0.5\pgflinewidth% + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/inner xsep}}% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgfmathaddtolength{\pgf@x}{veclen(2\pgf@xa,2\pgf@ya)}% + % If necessary, adjust radius so that the size requirements are + % met: + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x=.5\pgf@xa% + \fi% + \ifdim\pgf@x<.5\pgf@ya% + \pgf@x=.5\pgf@ya% + \fi% + % Now, add larger of outer separations. + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xa<\pgf@ya% + \advance\pgf@x by\pgf@ya% + \else% + \advance\pgf@x by\pgf@xa% + \fi% + }% + % Anchors + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \anchor{lower}{\loweranchor}% + % Background path + \inheritbackgroundpath[from=circle]% + \beforebackgroundpath{% + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xa}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@ya}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xa<\pgf@ya% + \advance\pgfutil@tempdima by-\pgf@ya% + \else% + \advance\pgfutil@tempdima by-\pgf@xa% + \fi% + \advance\pgfutil@tempdima by-.5\pgflinewidth% + \pgfsetshortenstart{0pt}% + \pgfsetshortenend{0pt}% + \pgfsetarrows{-}% + % solidus slants at 45 degrees and its length is + % the golden section of the diameter + \pgfpathmoveto{\pgfpointadd{\centerpoint}{\pgfqpoint{-0.437\pgfutil@tempdima}{-0.437\pgfutil@tempdima}}}% + \pgfpathlineto{\pgfpointadd{\centerpoint}{\pgfqpoint{0.437\pgfutil@tempdima}{0.437\pgfutil@tempdima}}}% + \pgfusepath{stroke}% + }% +}% + + +\def\pgf@lib@sh@newbox{\csname newbox\endcsname}% Get round outer. + +\def\pgf@lib@sh@toalpha#1{% + \ifcase#1\relax% + \or one\or two\or three\or four\or five\or six\or seven\or eight\or nine\or ten% + \or eleven\or twelve\or thirteen\or fourteen\or fifteen% + \or sixteen\or seventeen\or eighteen\or nineteen\or twenty% + \else% + twenty% + \fi% +}% + + +\def\pgf@lib@sh@getalpha#1#2{\expandafter\edef\expandafter#1\expandafter{\pgf@lib@sh@toalpha{#2}}}% + +\newbox\pgfnodeparttwobox +\newbox\pgfnodepartthreebox +\newbox\pgfnodepartfourbox + +\let\pgfnodepartonebox=\pgfnodeparttextbox +\let\pgfnodepartsecondbox=\pgfnodeparttwobox +\let\pgfnodepartthirdbox=\pgfnodepartthreebox +\let\pgfnodepartfourthbox=\pgfnodepartfourbox + +\def\pgf@lib@sh@allocateboxes#1{% + \c@pgf@counta=#1\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>4\relax% + \pgfutil@ifundefined{pgfnodepart\pgf@lib@sh@toalpha{\c@pgf@counta}box}% + {% + \expandafter\pgf@lib@sh@newbox\csname pgfnodepart\pgf@lib@sh@toalpha{\c@pgf@counta}box\endcsname% + }% + {}% + \advance\c@pgf@counta by-1\relax% + \repeatpgfmathloop% +}% + +\def\pgf@lib@sh@rs@lefttext{left}% +\def\pgf@lib@sh@rs@righttext{right}% +\def\pgf@lib@sh@rs@centertext{center}% +\def\pgf@lib@sh@rs@bottomtext{bottom}% +\def\pgf@lib@sh@rs@toptext{top}% +\def\pgf@lib@sh@rs@basetext{base}% +\def\pgf@lib@sh@rs@nonetext{none}% + + +\newif\ifpgfrectanglesplithorizontal +\newif\ifpgfrectanglesplitdrawsplits\pgfrectanglesplitdrawsplitstrue +\newif\ifpgfrectanglesplitignoreemptyparts +\newif\ifpgfrectanglesplitusecustomfill + +\let\pgf@lib@sh@rs@every@emptypart=\pgfutil@empty +\let\pgf@lib@sh@rs@every@part=\pgfutil@empty +\def\pgf@lib@sh@rs@list@fill{none}% + +\pgfkeys{/pgf/.cd, + rectangle split parts/.initial=4, + rectangle split part align/.initial=center, + rectangle split horizontal/.is if=pgfrectanglesplithorizontal, + rectangle split ignore empty parts/.is if=pgfrectanglesplitignoreemptyparts, + rectangle split empty part width/.code={% + \pgfmathsetlength\pgf@x{#1} + \edef\pgf@lib@sh@rs@temp{\noexpand\vrule width\the\pgf@x height0ptdepth0pt\relax}% + \def\pgf@lib@sh@rs@@temp{\def\pgf@lib@sh@rs@every@emptypart}% + \expandafter\expandafter\expandafter\pgf@lib@sh@rs@@temp\expandafter\expandafter\expandafter{% + \expandafter\pgf@lib@sh@rs@every@emptypart\pgf@lib@sh@rs@temp}% + },% + rectangle split empty part width=1ex, + rectangle split empty part height/.code={% + \pgfmathsetlength\pgf@x{#1} + \edef\pgf@lib@sh@rs@temp{\noexpand\vrule width0ptheight\the\pgf@x depth0pt\relax}% + \def\pgf@lib@sh@rs@@temp{\def\pgf@lib@sh@rs@every@emptypart}% + \expandafter\expandafter\expandafter\pgf@lib@sh@rs@@temp\expandafter\expandafter\expandafter{% + \expandafter\pgf@lib@sh@rs@every@emptypart\pgf@lib@sh@rs@temp}% + },% + rectangle split empty part height=1ex, + rectangle split empty part depth/.code={% + \pgfmathsetlength\pgf@x{#1} + \edef\pgf@lib@sh@rs@temp{\noexpand\vrule width0ptheight0ptdepth\the\pgf@x\relax}% + \def\pgf@lib@sh@rs@@temp{\def\pgf@lib@sh@rs@every@emptypart}% + \expandafter\expandafter\expandafter\pgf@lib@sh@rs@@temp\expandafter\expandafter\expandafter{% + \expandafter\pgf@lib@sh@rs@every@emptypart\pgf@lib@sh@rs@temp}% + },% + rectangle split empty part depth=0ex, + rectangle split every empty part/.store in=\pgf@lib@sh@rs@every@emptypart, + rectangle split part fill/.code=\def\pgf@lib@sh@rs@list@fill{#1}\pgfrectanglesplitusecustomfilltrue, + rectangle split uses custom fill/.is if=pgfrectanglesplitusecustomfill, + rectangle split draw splits/.is if=pgfrectanglesplitdrawsplits, + rectangle split allocate boxes/.code=\pgf@lib@sh@allocateboxes{#1}, +}% + + +\def\pgf@lib@sh@rs@process@list#1#2{% + \c@pgf@counta=1\relax% + \c@pgf@countb=#2\relax% + \edef\pgf@lib@sh@rs@temp{#1}% + \expandafter\pgf@lib@sh@rs@@process@list\pgf@lib@sh@rs@temp,\pgf@stop, +}% + +\def\pgf@lib@sh@rs@@process@list{% + \pgfutil@ifnextchar x{\pgf@lib@sh@rs@@@process@list}% + {\pgf@lib@sh@rs@@@process@list} +}% + +\def\pgf@lib@sh@rs@@@process@list#1,{% + \ifx#1\pgf@stop% + \let\pgf@next\pgf@lib@sh@rs@@@@process@list% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\c@pgf@counta}% + \def\pgf@lib@sh@rs@lastalign{#1}% + \pgfutil@namedef{pgf@lib@sh@rs@\pgf@lib@sh@toalpha{\c@pgf@counta}@item}{#1}% + \let\pgf@next\pgf@lib@sh@rs@@process@list% + \advance\c@pgf@counta by1\relax% + \fi% + \pgf@next}% + +\def\pgf@lib@sh@rs@@@@process@list{% + \pgfmathloop% + \ifnum\c@pgf@counta>\c@pgf@countb% + \else% + \expandafter\edef\csname pgf@lib@sh@rs@\pgf@lib@sh@toalpha{\c@pgf@counta}@item\endcsname% + {\pgf@lib@sh@rs@lastalign}% + \advance\c@pgf@counta by1\relax% + \repeatpgfmathloop% +}% + +\pgf@lib@sh@allocateboxes{20}% + +\pgfdeclareshape{rectangle split}{% + \savedmacro\rectanglesplitparameters{% + \pgfmathsetcount\c@pgf@counta{\pgfkeysvalueof{/pgf/rectangle split parts}}% + \edef\parts{\the\c@pgf@counta}% + \addtosavedmacro\parts% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \edef\innerxsep{\the\pgf@x}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \edef\innerysep{\the\pgf@y}% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \edef\outerxsep{\the\pgf@x}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \edef\outerysep{\the\pgf@y}% + \addtosavedmacro\outerxsep% + \addtosavedmacro\outerysep% + % + \pgf@x=0pt\relax% Widest box. + \pgf@y=0pt\relax% Tallest box. + % + \pgfutil@tempdima=0pt\relax% Maximum box height. + \pgfutil@tempdimb=0pt\relax% Maximum box depth. + % + % Get the dimensions of the boxes... + % + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\let\expandafter\pgf@lib@sh@box\expandafter=% + \csname pgfnodepart\pgf@lib@sh@rs@number box\endcsname% + \pgf@xa=\wd\pgf@lib@sh@box% + \pgf@ya=\ht\pgf@lib@sh@box% + \pgf@yb=\dp\pgf@lib@sh@box% + % + % Test to see if the box is empty... + % + \expandafter\def\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname{\relax}% + \ifdim\pgf@xa=0pt\relax% + \ifdim\pgf@ya=0pt\relax% + \ifdim\pgf@yb=0pt\relax% + % + % ...It is. So... + % + \ifpgfrectanglesplitignoreemptyparts% + % + % ...flag this if we are ignoring parts... + % + \expandafter\let\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname=\pgfutil@empty% + \else% + % + % ...otherwise insert the code for every empty part. + % + \setbox\pgf@lib@sh@box=\hbox{{\pgf@lib@sh@rs@every@emptypart}}% + \pgf@xa=\wd\pgf@lib@sh@box% + \pgf@ya=\ht\pgf@lib@sh@box% + \pgf@yb=\dp\pgf@lib@sh@box% + \fi% + \fi% + \fi% + \fi% + \expandafter\edef\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@number\endcsname{\the\pgf@xa}% + \expandafter\edef\csname pgf@lib@sh@rs@height@\pgf@lib@sh@rs@number\endcsname{\the\pgf@ya}% + \expandafter\edef\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@number\endcsname{\the\pgf@yb}% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname% + % + % ...saving the widest box... + % + \ifdim\pgf@xa>\pgf@x% + \pgf@x=\pgf@xa% + \fi% + % + % ...the maximum height and depth... + % + \ifdim\pgf@ya>\pgfutil@tempdima% + \pgfutil@tempdima=\pgf@ya% + \fi% + \ifdim\pgf@yb>\pgfutil@tempdimb% + \pgfutil@tempdimb=\pgf@yb% + \fi% + % + % ...and the tallest box. + % + \pgf@yc=\pgfutil@tempdima% + \advance\pgf@yc by\pgfutil@tempdimb% + \ifdim\pgf@yc>\pgf@y% + \pgf@y=\pgf@yc% + \fi% + \repeatpgfmathloop% + % + \edef\pgf@lib@sh@rs@max@width{\the\pgf@x}% + \edef\pgf@lib@sh@rs@max@totalheight{\the\pgf@y}% + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/minimum width}}% + \advance\pgf@x by-\innerxsep\relax% + \advance\pgf@x by-\innerxsep\relax% + \pgf@xa=\pgf@x% + \advance\pgf@xa by-\pgf@lib@sh@rs@max@width\relax% + \ifdim\pgf@xa>0pt\relax% + \edef\pgf@lib@sh@rs@max@width{\the\pgf@x}% + \fi% + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/minimum height}}% + \advance\pgf@y by-\innerysep\relax% + \advance\pgf@y by-\innerysep\relax% + \pgf@ya=\pgf@y% + \advance\pgf@ya by-\pgf@lib@sh@rs@max@totalheight\relax% + \ifdim\pgf@ya>0pt\relax% + \edef\pgf@lib@sh@rs@max@totalheight{\the\pgf@y}% + \fi% + % + % Get the alignment of each node part box. + % + \pgf@lib@sh@rs@process@list{\pgfkeysvalueof{/pgf/rectangle split part align}}{\parts}% + % + % Are we splitting horizontally or vertically? + % + \ifpgfrectanglesplithorizontal% + % + % Calculate the origins of each node part box. + % + \pgf@x=0pt\relax% + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\let\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname=\pgfutil@empty% + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \ifpgfrectanglesplitignoreemptyparts% + \expandafter\let\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname=% + \pgf@lib@sh@rs@lastanchor% + \fi% + \fi% + % + % Adjust for alignment. + % + \expandafter\ifx\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname% + \pgf@lib@sh@rs@bottomtext% + \pgf@y=\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@number\endcsname\relax% + \else% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname% + \pgf@lib@sh@rs@toptext% + \pgf@y=-\csname pgf@lib@sh@rs@height@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@y by\pgf@lib@sh@rs@max@totalheight\relax% + \else% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname% + \pgf@lib@sh@rs@basetext% + \pgf@y=\pgf@lib@sh@rs@max@totalheight\relax% + \advance\pgf@y by-\pgfutil@tempdima% + \advance\pgf@y by\pgfutil@tempdimb% + \divide\pgf@y by2\relax% + \else% + \pgf@y=\pgf@lib@sh@rs@max@totalheight\relax% + \advance\pgf@y by-\csname pgf@lib@sh@rs@height@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@y by\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@number\endcsname\relax% + \divide\pgf@y by2\relax% + \fi% + \fi% + \fi% + % + % Re-adjust as the first box is at the origin. + % + \ifnum\pgfmathcounter=1\relax% + \edef\pgf@lib@sh@rs@yoffset{\the\pgf@y}% + \pgf@y=0pt\relax% + \pgfextract@process\pgf@lib@sh@rs@anchor@one{}% + \addtosavedmacro\pgf@lib@sh@rs@anchor@one% + \let\pgf@lib@sh@rs@lastanchor=\pgf@lib@sh@rs@anchor@one% + \let\pgf@lib@sh@rs@lastnumber=\pgf@lib@sh@rs@number% + \else + \advance\pgf@y by-\pgf@lib@sh@rs@yoffset\relax% + \advance\pgf@x by\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@lastnumber\endcsname\relax% + \advance\pgf@x by\innerxsep\relax% + \advance\pgf@x by\pgflinewidth% + \advance\pgf@x by\innerxsep\relax% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname{}% + \expandafter\let\expandafter\pgf@lib@sh@rs@lastanchor\expandafter=% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \let\pgf@lib@sh@rs@lastnumber=\pgf@lib@sh@rs@number% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \fi% + \fi% + \repeatpgfmathloop% + % + % Calculate some anchors. + % + \pgfextract@process\northeast{% + \pgf@lib@sh@rs@lastanchor% + \advance\pgf@x by\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@lastnumber\endcsname\relax% + \advance\pgf@x by\innerxsep\relax% + \advance\pgf@x by\outerxsep\relax% + \pgf@y=\pgf@lib@sh@rs@max@totalheight\relax% + \advance\pgf@y by-\pgf@lib@sh@rs@yoffset\relax% + \advance\pgf@y by\innerysep\relax% + \advance\pgf@y by\outerysep\relax% + }% + \addtosavedmacro\northeast% + \pgfextract@process\southwest{% + \pgf@lib@sh@rs@anchor@one% + \advance\pgf@x by-\innerxsep\relax% + \advance\pgf@x by-\outerxsep\relax% + \pgf@y=-\pgf@lib@sh@rs@yoffset\relax% + \advance\pgf@y by-\innerysep\relax% + \advance\pgf@y by-\outerysep\relax% + }% + \addtosavedmacro\southwest% + % + \pgfextract@process\centerpoint{% + \pgfpointadd{\southwest}{\northeast}% + \divide\pgf@x by2\relax% + \divide\pgf@y by2\relax% + }% + \addtosavedmacro\centerpoint% + % + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \else% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \pgf@xa=\pgf@x% + \pgf@xb=\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@xa by0.5\pgf@xb% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @south\endcsname{% + \southwest% + \pgf@x=\pgf@xa% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @north\endcsname{% + \northeast% + \pgf@x=\pgf@xa% + }% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @north\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @south\endcsname% + \ifnum\pgfmathcounter=\parts% + \else% + \advance\pgf@xa by0.5\pgf@xb% + \advance\pgf@xa by\innerxsep\relax% + \advance\pgf@xa by.5\pgflinewidth% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@south\endcsname{% + \southwest% + \pgf@x=\pgf@xa% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@north\endcsname{% + \northeast% + \pgf@x=\pgf@xa% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split\endcsname{% + \centerpoint% + \pgf@x=\pgf@xa% + }% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@north\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@south\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split\endcsname% + \fi% + \fi% + \repeatpgfmathloop% + \else% + % + % Calculate the origins of each node part box. + % + \pgf@y=0pt\relax% + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\let\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname=\pgfutil@empty% + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \ifpgfrectanglesplitignoreemptyparts% + \expandafter\let\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname=% + \pgf@lib@sh@rs@lastanchor% + \fi% + \fi% + % + % Adjust for alignment. + % + \expandafter\ifx\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname% + \pgf@lib@sh@rs@lefttext% + \pgf@x=0pt\relax% + \else% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname% + \pgf@lib@sh@rs@righttext% + \pgf@x=-\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@x by\pgf@lib@sh@rs@max@width\relax% + \else% + \pgf@x=-\csname pgf@lib@sh@rs@width@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@x by\pgf@lib@sh@rs@max@width\relax% + \divide\pgf@x by2\relax% + \fi% + \fi% + % + % Re-adjust as the first box is at the origin. + % + \ifnum\pgfmathcounter=1\relax% + \edef\pgf@lib@sh@rs@xoffset{\the\pgf@x}% + \pgf@x=0pt\relax% + \pgfextract@process\pgf@lib@sh@rs@anchor@one{}% + \addtosavedmacro\pgf@lib@sh@rs@anchor@one% + \let\pgf@lib@sh@rs@lastanchor=\pgf@lib@sh@rs@anchor@one% + \let\pgf@lib@sh@rs@lastnumber=\pgf@lib@sh@rs@number% + \else + \advance\pgf@x by-\pgf@lib@sh@rs@xoffset\relax% + \advance\pgf@y by-\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@lastnumber\endcsname\relax% + \advance\pgf@y by-\innerysep\relax% + \advance\pgf@y by-\pgflinewidth% + \advance\pgf@y by-\innerysep\relax% + \advance\pgf@y by-\csname pgf@lib@sh@rs@height@\pgf@lib@sh@rs@number\endcsname\relax% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname{}% + \expandafter\let\expandafter\pgf@lib@sh@rs@lastanchor\expandafter=% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \let\pgf@lib@sh@rs@lastnumber=\pgf@lib@sh@rs@number% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \fi% + \fi% + \repeatpgfmathloop% + % + % Calculate some anchors. + % + \pgfextract@process\northeast{% + \pgf@x=\pgf@lib@sh@rs@max@width\relax% + \advance\pgf@x by-\pgf@lib@sh@rs@xoffset\relax% + \advance\pgf@x by\innerxsep\relax% + \advance\pgf@x by\outerxsep\relax% + \pgf@y=\pgf@lib@sh@rs@height@one\relax% + \advance\pgf@y by\innerysep\relax% + \advance\pgf@y by\outerysep\relax% + \advance\pgf@y by.5\pgflinewidth% + }% + \addtosavedmacro\northeast% + \pgfextract@process\southwest{% + \pgf@lib@sh@rs@lastanchor% + \pgf@x=-\pgf@lib@sh@rs@xoffset\relax% + \advance\pgf@x by-\innerxsep\relax% + \advance\pgf@x by-\outerxsep\relax% + \advance\pgf@y by-\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@lastnumber\endcsname\relax% + \advance\pgf@y by-\innerysep\relax% + \advance\pgf@y by-\outerysep\relax% + \advance\pgf@y by-.5\pgflinewidth% + }% + \addtosavedmacro\southwest% + % + \pgfextract@process\centerpoint{% + \pgfpointadd{\southwest}{\northeast}% + \divide\pgf@x by2\relax% + \divide\pgf@y by2\relax% + }% + \addtosavedmacro\centerpoint% + % + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \else% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \pgf@ya=\csname pgf@lib@sh@rs@height@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@y by0.5\pgf@ya% + \pgf@ya=\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@y by-0.5\pgf@ya% + \pgf@ya=\pgf@y% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @west\endcsname{% + \southwest% + \pgf@y=\pgf@ya% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @east\endcsname{% + \northeast% + \pgf@y=\pgf@ya% + }% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @east\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @west\endcsname% + \ifnum\pgfmathcounter=\parts% + \else% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number\endcsname% + \pgf@ya=\pgf@y% + \advance\pgf@ya by-\csname pgf@lib@sh@rs@depth@\pgf@lib@sh@rs@number\endcsname\relax% + \advance\pgf@ya by-\innerysep\relax% + \advance\pgf@ya by-.5\pgflinewidth% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@west\endcsname{% + \southwest% + \pgf@y=\pgf@ya% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@east\endcsname{% + \northeast% + \pgf@y=\pgf@ya% + }% + \expandafter\pgfextract@process\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split\endcsname{% + \centerpoint% + \pgf@y=\pgf@ya% + }% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@east\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@west\endcsname% + \expandafter\addtosavedmacro\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split\endcsname% + \fi% + \fi% + \repeatpgfmathloop% + \fi% + }% + \savedanchor\basepoint{% + \pgf@x=0.5\wd\pgfnodeparttextbox% + \pgf@y=0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x=0.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \anchor{center}{% + \rectanglesplitparameters% + \centerpoint% + }% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \rectanglesplitparameters% + \northeast% + \pgf@y=0pt\relax% + }% + \anchor{base west}{% + \rectanglesplitparameters% + \southwest% + \pgf@y=0pt\relax% + }% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \rectanglesplitparameters% + \northeast% + \pgf@xa=\pgf@x% + \midpoint% + \pgf@x=\pgf@xa% + }% + \anchor{mid west}{% + \rectanglesplitparameters% + \southwest% + \pgf@xa=\pgf@x% + \midpoint% + \pgf@x=\pgf@xa% + }% + \anchor{north}{% + \rectanglesplitparameters% + \centerpoint% + \pgf@xa=\pgf@x% + \northeast% + \pgf@x=\pgf@xa% + }% + \anchor{south}{% + \rectanglesplitparameters% + \centerpoint% + \pgf@xa=\pgf@x% + \southwest% + \pgf@x=\pgf@xa% + }% + \anchor{east}{% + \rectanglesplitparameters% + \centerpoint% + \pgf@ya=\pgf@y% + \northeast% + \pgf@y=\pgf@ya% + }% + \anchor{west}{% + \rectanglesplitparameters% + \centerpoint% + \pgf@ya=\pgf@y% + \southwest% + \pgf@y=\pgf@ya% + }% + \anchor{north east}{% + \rectanglesplitparameters% + \northeast% + }% + \anchor{north west}{% + \rectanglesplitparameters% + \northeast% + \pgf@ya=\pgf@y% + \southwest% + \pgf@y=\pgf@ya% + }% + \anchor{south west}{% + \rectanglesplitparameters% + \southwest% + }% + \anchor{south east}{% + \rectanglesplitparameters% + \southwest% + \pgf@ya=\pgf@y% + \northeast% + \pgf@y=\pgf@ya% + }% + \behindbackgroundpath{% + \ifpgfrectanglesplitusecustomfill% + \pgf@lib@sh@rs@process@list{\pgf@lib@sh@rs@list@fill}{\parts}% + {% + \ifpgfrectanglesplithorizontal% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@bottomleft\expandafter=% + \csname pgf@anchor@rectangle split@south west\endcsname% + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + \ifnum\pgfmathcounter=\parts% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@topright\expandafter=% + \csname pgf@anchor@rectangle split@north east\endcsname% + \else% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@topright\expandafter=% + \csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@number\space split north\endcsname% + \fi% + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \else% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname\pgf@lib@sh@rs@nonetext% + \else% + \pgfextract@process\pgf@lib@sh@rs@fill@bottomleft{% + \pgf@lib@sh@rs@fill@bottomleft% + \advance\pgf@y by\outerysep\relax% + \ifnum\pgfmathcounter=1\relax% + \advance\pgf@x by\outerxsep\relax% + \fi% + }% + \pgfextract@process\pgf@lib@sh@rs@fill@topright{% + \pgf@lib@sh@rs@fill@topright% + \advance\pgf@y by-\outerysep\relax% + \ifnum\pgfmathcounter=\parts\relax% + \advance\pgf@x by-\outerxsep\relax% + \fi% + }% + \ifnum\pgfmathcounter>1\relax% + \begingroup\pgfsetcornersarced{\pgfpointorigin}% + \fi% + \pgfpathmoveto{% + \pgf@lib@sh@rs@fill@topright% + \pgf@xa=\pgf@x% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@x=\pgf@xa% + }% + \pgfpathlineto{\pgf@lib@sh@rs@fill@bottomleft}% + \pgfpathlineto{% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@xa=\pgf@x% + \pgf@lib@sh@rs@fill@topright% + \pgf@x=\pgf@xa% + }% + \ifnum\pgfmathcounter>1\relax% + \endgroup% + \fi% + \ifnum\pgfmathcounter<\parts% + \begingroup\pgfsetcornersarced{\pgfpointorigin}% + \fi% + \pgfpathlineto{\pgf@lib@sh@rs@fill@topright}% + \pgfpathclose% + \ifnum\pgfmathcounter<\parts% + \endgroup% + \fi% + \pgfsetfillcolor{\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname}% + \pgfusepath{fill}% + \fi% + \fi% + \pgfextract@process\pgf@lib@sh@rs@fill@bottomleft{% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@ya=\pgf@y% + \pgf@lib@sh@rs@fill@topright% + \pgf@y=\pgf@ya% + \advance\pgf@y by-\outerysep% + }% + \repeatpgfmathloop% + \else% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@topright\expandafter=% + \csname pgf@anchor@rectangle split@north east\endcsname% + \pgfmathloop% + \ifnum\pgfmathcounter>\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + \ifnum\pgfmathcounter=\parts% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@bottomleft\expandafter=% + \csname pgf@anchor@rectangle split@south west\endcsname% + \else% + \expandafter\let\expandafter\pgf@lib@sh@rs@fill@bottomleft\expandafter=% + \csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@number\space split west\endcsname% + \fi% + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \else% + \expandafter\ifx\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname\pgf@lib@sh@rs@nonetext% + \else% + \pgfextract@process\pgf@lib@sh@rs@fill@bottomleft{% + \pgf@lib@sh@rs@fill@bottomleft% + \advance\pgf@x by\outerxsep\relax% + \ifnum\parts=1\relax% + \advance\pgf@y by\outerysep\relax% + \else% + \ifnum\pgfmathcounter=\parts + \advance\pgf@y by\outerysep\relax% + \fi% + \fi% + }% + \pgfextract@process\pgf@lib@sh@rs@fill@topright{% + \pgf@lib@sh@rs@fill@topright% + \advance\pgf@x by-\outerxsep\relax% + \ifnum\parts=1\relax% + \advance\pgf@y by-\outerysep\relax% + \else% + \ifnum\pgfmathcounter=1\relax% + \advance\pgf@y by-\outerysep\relax% + \fi% + \fi% + }% + \pgfpathmoveto{\pgf@lib@sh@rs@fill@bottomleft}% + \ifnum\pgfmathcounter>1\relax% + \begingroup\pgfsetcornersarced{\pgfpointorigin}% + \fi% + \pgfpathlineto{% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@xa=\pgf@x% + \pgf@lib@sh@rs@fill@topright% + \pgf@x=\pgf@xa% + }% + \pgfpathlineto{\pgf@lib@sh@rs@fill@topright}% + \ifnum\pgfmathcounter>1\relax% + \endgroup%% + \fi% + \ifnum\pgfmathcounter<\parts% + \begingroup\pgfsetcornersarced{\pgfpointorigin}% + \fi% + \pgfpathlineto{% + \pgf@lib@sh@rs@fill@topright% + \pgf@xa=\pgf@x% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@x=\pgf@xa% + }% + \pgfpathclose% + \ifnum\pgfmathcounter<\parts% + \endgroup% + \fi% + \pgfsetfillcolor{\csname pgf@lib@sh@rs@\pgf@lib@sh@rs@number @item\endcsname}% + \pgfusepath{fill}% + \fi% + \fi% + \pgfextract@process\pgf@lib@sh@rs@fill@topright{% + \pgf@lib@sh@rs@fill@topright% + \pgf@xa=\pgf@x% + \pgf@lib@sh@rs@fill@bottomleft% + \pgf@x=\pgf@xa% + \advance\pgf@x by\outerxsep\relax% + }% + \repeatpgfmathloop% + \fi% + }% + \fi% + }% + \backgroundpath{% + \begingroup% + \pgfextract@process\southwest{% + \southwest% + \advance\pgf@x by\outerxsep\relax% + \advance\pgf@y by\outerysep\relax% + }% + \pgfextract@process\northeast{% + \northeast% + \advance\pgf@x by-\outerxsep\relax% + \advance\pgf@y by-\outerysep\relax% + }% + \pgfpathrectangle{\southwest}{\pgfpointdiff{\southwest}{\northeast}}% + \endgroup% + \ifpgfrectanglesplitdrawsplits% + \pgfmathloop% + \ifnum\pgfmathcounter=\parts% + \else% + \pgf@lib@sh@getalpha\pgf@lib@sh@rs@number{\pgfmathcounter}% + % + \expandafter\ifx\csname pgf@lib@sh@rs@empty@\pgf@lib@sh@rs@number\endcsname\pgfutil@empty% + \else% + \pgfpathmoveto{% + \ifpgfrectanglesplithorizontal% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@north\endcsname% + \advance\pgf@y by-\outerysep\relax% + \else% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@east\endcsname% + \advance\pgf@x by-\outerxsep\relax% + \fi% + }% + \pgfpathlineto{% + \ifpgfrectanglesplithorizontal% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@south\endcsname% + \advance\pgf@y by\outerysep\relax% + \else% + \csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@number @split@west\endcsname% + \advance\pgf@x by\outerxsep\relax% + \fi% + }% + \fi% + \repeatpgfmathloop% + \fi% + }% + \anchorborder{% + \pgfutil@tempdima\pgf@x% + \pgfutil@tempdimb\pgf@y% + \rectanglesplitparameters% + \pgfpointdiff{\southwest}{\northeast}% + \pgf@x.5\pgf@x% + \pgf@y.5\pgf@y% + \edef\pgf@marshall{% + \noexpand\pgfpointborderrectangle{% + \noexpand\pgfqpoint{\the\pgfutil@tempdima}{\the\pgfutil@tempdimb}% + }% + {% + \noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}% + }% + }% + \pgf@marshall% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Hackery to install the correct number of node parts. + % + \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@rectangle split\endcsname{% + \let\pgf@lib@sh@rs@temp=\pgfutil@empty% + \pgfmathloop% + \ifnum\pgfmathcounter=\parts% + \expandafter\edef\csname pgf@sh@boxes@rectangle split\endcsname% + {\pgf@lib@sh@rs@temp\pgf@lib@sh@toalpha{\pgfmathcounter}}% + \else% + \edef\pgf@lib@sh@rs@temp{\pgf@lib@sh@rs@temp\pgf@lib@sh@toalpha{\pgfmathcounter},}% + \repeatpgfmathloop% + }% +}% + +\pgfutil@for\pgf@lib@sh@rs@temp:={one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen,twenty}\do{% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp}{\noexpand\pgf@lib@sh@rs@anchor@one}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space split\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split}% + {\noexpand\centerpoint}% + {\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space split north\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@north}% + {\noexpand\csname pgf@anchor@rectangle split@north\noexpand\endcsname}% + {\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@north\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space split south\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@south}% + {\noexpand\csname pgf@anchor@rectangle split@south\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@south\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space north\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @north}% + {\noexpand\csname pgf@anchor@rectangle split@north\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @north\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space south\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @south}% + {\noexpand\csname pgf@anchor@rectangle split@south\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @south\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space split east\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@east}% + {\noexpand\csname pgf@anchor@rectangle split@east\noexpand\endcsname}% + {\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@east\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space split west\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@west}% + {\noexpand\csname pgf@anchor@rectangle split@west\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @split@west\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space east\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @east}% + {\noexpand\csname pgf@anchor@rectangle split@east\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @east\noexpand\endcsname}% + }% + \expandafter\xdef\csname pgf@anchor@rectangle split@\pgf@lib@sh@rs@temp\space west\endcsname{% + \noexpand\rectanglesplitparameters% + \noexpand\pgfutil@ifundefined{pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @west}% + {\noexpand\csname pgf@anchor@rectangle split@west\noexpand\endcsname}% + {\noexpand\csname pgf@lib@sh@rs@anchor@\pgf@lib@sh@rs@temp @west\noexpand\endcsname}% + }% +}% + + +\pgfutil@namelet{pgf@anchor@rectangle split@text east}{pgf@anchor@rectangle split@one east}% +\pgfutil@namelet{pgf@anchor@rectangle split@text west}{pgf@anchor@rectangle split@one west}% +\pgfutil@namelet{pgf@anchor@rectangle split@text split}{pgf@anchor@rectangle split@one split}% +\pgfutil@namelet{pgf@anchor@rectangle split@text split east}{pgf@anchor@rectangle split@one split east}% +\pgfutil@namelet{pgf@anchor@rectangle split@text split west}{pgf@anchor@rectangle split@one split west}% + +\pgfutil@namelet{pgf@anchor@rectangle split@second}{pgf@anchor@rectangle split@two}% +\pgfutil@namelet{pgf@anchor@rectangle split@second east}{pgf@anchor@rectangle split@two east}% +\pgfutil@namelet{pgf@anchor@rectangle split@second west}{pgf@anchor@rectangle split@two west}% +\pgfutil@namelet{pgf@anchor@rectangle split@second split}{pgf@anchor@rectangle split@two split}% +\pgfutil@namelet{pgf@anchor@rectangle split@second split east}{pgf@anchor@rectangle split@two split east}% +\pgfutil@namelet{pgf@anchor@rectangle split@second split west}{pgf@anchor@rectangle split@two split west}% + +\pgfutil@namelet{pgf@anchor@rectangle split@third}{pgf@anchor@rectangle split@three}% +\pgfutil@namelet{pgf@anchor@rectangle split@third east}{pgf@anchor@rectangle split@three east}% +\pgfutil@namelet{pgf@anchor@rectangle split@third west}{pgf@anchor@rectangle split@three west}% +\pgfutil@namelet{pgf@anchor@rectangle split@third split}{pgf@anchor@rectangle split@three split}% +\pgfutil@namelet{pgf@anchor@rectangle split@third split east}{pgf@anchor@rectangle split@three split east}% +\pgfutil@namelet{pgf@anchor@rectangle split@third split west}{pgf@anchor@rectangle split@three split west}% + +\pgfutil@namelet{pgf@anchor@rectangle split@fourth}{pgf@anchor@rectangle split@four}% +\pgfutil@namelet{pgf@anchor@rectangle split@fourth east}{pgf@anchor@rectangle split@four east}% +\pgfutil@namelet{pgf@anchor@rectangle split@fourth west}{pgf@anchor@rectangle split@four west}% +\pgfutil@namelet{pgf@anchor@rectangle split@fourth split}{pgf@anchor@rectangle split@four split}% +\pgfutil@namelet{pgf@anchor@rectangle split@fourth split east}{pgf@anchor@rectangle split@four split east}% +\pgfutil@namelet{pgf@anchor@rectangle split@fourth split west}{pgf@anchor@rectangle split@four split west}% + + + + +% Shape: ellipse split. +% +\pgfdeclareshape{ellipse split}{% + \nodeparts{text,lower}% + \savedanchor\radii{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgf@y2.0\pgf@y% + \advance\pgf@y.5\pgflinewidth% + \pgf@xa.5\wd\pgfnodeparttextbox% + \pgf@xb.5\wd\pgfnodepartlowerbox% + \advance\pgf@xa\pgf@x% + \advance\pgf@xb\pgf@x% + \pgf@ya\ht\pgfnodeparttextbox% + \advance\pgf@ya\dp\pgfnodeparttextbox% + \pgf@yb\ht\pgfnodepartlowerbox% + \advance\pgf@yb\dp\pgfnodepartlowerbox% + \advance\pgf@ya\pgf@y% + \advance\pgf@yb\pgf@y% + \ifdim\pgf@xa>\pgf@xb% + \pgf@x1.414213\pgf@xa% + \else% + \pgf@x1.414213\pgf@xb% + \fi% + \ifdim\pgf@ya>\pgf@yb% + \pgf@y1.414213\pgf@ya% + \else% + \pgf@y1.414213\pgf@yb% + \fi% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + }% + \savedanchor\lower{% + \pgf@x-.5\wd\pgfnodepartlowerbox% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \pgf@y-2.0\pgf@y% + \advance\pgf@y-\pgflinewidth% + \advance\pgf@y-\dp\pgfnodeparttextbox% + \advance\pgf@y-\ht\pgfnodepartlowerbox% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{-\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y-\dp\pgfnodeparttextbox% + \advance\pgf@y-.5\pgflinewidth% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt\relax% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{lower}{\lower}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{\radii\pgf@xa\pgf@x\midpoint\advance\pgf@x\pgf@xa}% + \anchor{mid west}{\radii\pgf@xa\pgf@x\midpoint\advance\pgf@x-\pgf@xa}% + \anchor{base}{\basepoint}% + \anchor{base east}{\radii\pgf@xa\pgf@x\basepoint\advance\pgf@x\pgf@xa}% + \anchor{base west}{\radii\pgf@xa\pgf@x\basepoint\advance\pgf@x-\pgf@xa}% + \anchor{north}{\pgfpointadd{\centerpoint}{\radii\pgf@x0pt}}% + \anchor{south}{\pgfpointadd{\centerpoint}{\radii\pgf@x0pt\pgf@y-\pgf@y}}% + \anchor{east}{\pgfpointadd{\centerpoint}{\radii\pgf@y0pt}}% + \anchor{west}{\pgfpointadd{\centerpoint}{\radii\pgf@x-\pgf@x\pgf@y0pt}}% + \anchor{north west}{\pgfpointadd{\centerpoint}{\radii\pgf@x-0.707106\pgf@x\pgf@y0.707106\pgf@y}}% + \anchor{south west}{\pgfpointadd{\centerpoint}{\radii\pgf@x-0.707106\pgf@x\pgf@y-0.707106\pgf@y}}% + \anchor{north east}{\pgfpointadd{\centerpoint}{\radii\pgf@x0.707106\pgf@x\pgf@y0.707106\pgf@y}}% + \anchor{south east}{\pgfpointadd{\centerpoint}{\radii\pgf@x0.707106\pgf@x\pgf@y-0.707106\pgf@y}}% + \backgroundpath{% + \radii% + \pgfmathaddtolength\pgf@x{-\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathaddtolength\pgf@y{-\pgfkeysvalueof{/pgf/outer ysep}}% + \pgfutil@tempdima\pgf@x% + \pgfutil@tempdimb\pgf@y% + \pgfpathellipse{\centerpoint}{\pgfqpoint{\the\pgfutil@tempdima}{0pt}}{\pgfqpoint{0pt}{\the\pgfutil@tempdimb}}% + \pgfpathmoveto{\centerpoint\advance\pgf@x-\pgfutil@tempdima}% + \pgfpathlineto{\centerpoint\advance\pgf@x\pgfutil@tempdima}% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \radii% + \edef\pgf@marshal{% + \noexpand\pgfpointadd{\noexpand\pgfpointborderellipse{\noexpand\externalpoint}% + {\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}}{\noexpand\centerpoint}% + }% + \pgf@marshal% + }% +}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.symbols.code.tex b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.symbols.code.tex new file mode 100644 index 0000000000..b876db6fd1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/libraries/shapes/pgflibraryshapes.symbols.code.tex @@ -0,0 +1,2775 @@ +% Copyright 2018 by Till Tantau and Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibraryshapes.symbols.code.tex} + +\pgfdeclareshape{forbidden sign} +{% + \inheritsavedanchors[from=circle]% this is nearly a circle + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \inheritbackgroundpath[from=circle]% + \foregroundpath{ + \centerpoint% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgfutil@tempdima by-\pgf@yb% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{-0.707107\pgfutil@tempdima}{-0.707107\pgfutil@tempdima}}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{0.707107\pgfutil@tempdima}{0.707107\pgfutil@tempdima}}} + \pgfsetarrowsstart{} + \pgfsetarrowsend{} + }% +}% + + +\pgfdeclareshape{correct forbidden sign} +{% + \inheritsavedanchors[from=circle]% this is nearly a circle + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \inheritbackgroundpath[from=circle]% + \foregroundpath{ + \centerpoint% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgfutil@tempdima by-\pgf@yb% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{0.707107\pgfutil@tempdima}{-0.707107\pgfutil@tempdima}}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{-0.707107\pgfutil@tempdima}{0.707107\pgfutil@tempdima}}} + \pgfsetarrowsstart{} + \pgfsetarrowsend{} + }% +}% + + + + + +% Keys for starburst shape +% +% /pgf/starburst point height : The maximum height of the outer points. +% /pgf/starburst points : The number of points. +% /pgf/random starburst : The seed for the random number generator. +% +\pgfkeys{/pgf/random starburst/% + .code={% + \ifx\pgfkeysnovalue#1% + \pgfmathgeneratepseudorandomnumber% + \else% + \pgfmathtruncatemacro\pgfmathresult{#1}% + \fi% + \pgfkeyslet{/pgf/random starburst}{\pgfmathresult}% + }% +}% +\pgfkeys{/pgf/random starburst=100}% + +\pgfkeys{/pgf/starburst point height/.value required}% +\pgfkeys{/pgf/starburst point height/.code={% + \pgfmathparse{#1}% + \edef\pgfmathresult{\pgfmathresult pt}% + \pgfkeyslet{/pgf/starburst point height}{\pgfmathresult}% + }% +}% +\pgfkeys{/pgf/starburst point height=.5cm}% + +\pgfkeys{/pgf/starburst points/.value required}% +\pgfkeys{/pgf/starburst points/.code={% + \pgfmathtruncatemacro\pgfmathresult{#1}% + \pgfkeyslet{/pgf/starburst points}{\pgfmathresult}% + }% +}% +\pgfkeys{/pgf/starburst points=17}% + +\pgfdeclareshape{starburst}{% + \savedmacro\anglestep{% + \pgfmathdivide@{180}{\pgfkeysvalueof{/pgf/starburst points}}% + \let\anglestep\pgfmathresult% + }% + \savedmacro\calculatestarburstpoints{% + % + % Get the angle step. + % + \pgfmathdivide@{180}{\pgfkeysvalueof{/pgf/starburst points}}% + \let\anglestep\pgfmathresult% + % + % Get the total number of points. + % + \pgfmathsetcounter{pgf@counta}{\pgfkeysvalueof{/pgf/starburst points}}% + \multiply\c@pgf@counta2\relax% + \edef\totalpoints{\the\c@pgf@counta}% + \addtosavedmacro{\totalpoints}% + % + % Calculate the centerpoint. + % + \pgfextract@process\centerpoint{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5\ht\pgfnodeparttextbox}% + \pgfmathaddtolength\pgf@y{+-.5\dp\pgfnodeparttextbox}% + }% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{+\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{+\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + % + % Get the node dimensions. + % + \pgfmathsetlength\pgf@x{+\pgfkeysvalueof{/pgf/inner xsep}}% + \pgfmathaddtolength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+\pgfkeysvalueof{/pgf/inner ysep}}% + \pgfmathaddtolength\pgf@y{+.5\ht\pgfnodeparttextbox}% + \pgfmathaddtolength\pgf@y{+.5\dp\pgfnodeparttextbox}% + % + % Calculate the inner radii. + % + \ifpgfshapeborderusesincircle% + \pgfkeysgetvalue{/pgf/shape border rotate}{\rotate}% + % + % Use the incircle... + % + \ifdim\pgf@y>\pgf@x% + \pgf@x\pgf@y% + \fi% + \pgf@x1.41421\pgf@x% + \pgf@y\pgf@x% + \else% + % + % Get the rotation (with rounding). + % + \pgfkeysgetvalue{/pgf/shape border rotate}{\rotate}% + \pgfmathmod@{\rotate}{360}% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgf@counta\pgfmathresult\relax\pgfmath@% + \advance\c@pgf@counta45\relax% + \divide\c@pgf@counta90\relax% + \multiply\c@pgf@counta90\relax% + \ifnum\c@pgf@counta<0\relax% + \advance\c@pgf@counta360\relax% + \fi% + % + % Calculate the width and height of the node + % contents, according to any border rotation. + % + \ifnum\c@pgf@counta=90\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \else% + \ifnum\c@pgf@counta=270\relax% + \pgf@xc\pgf@x% + \pgf@x\pgf@y% + \pgf@y\pgf@xc% + \fi% + \fi% + \edef\rotate{\the\c@pgf@counta}% + % + % ...or not. + % + \pgf@x=1.41421\pgf@x% + \pgf@y=1.41421\pgf@y% + \fi% + \addtosavedmacro{\rotate}% + % + % Adjust innerradius for minimum width and height. + % + \pgf@xa\pgf@x% + \pgfmathsetlength\pgf@xb{+\pgfkeysvalueof{/pgf/starburst point height}}% + \advance\pgf@xa\pgf@xb% + \pgfmathsetlength\pgf@xc{+\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@xa<.5\pgf@xc% + \pgf@x.5\pgf@xc% + \advance\pgf@x-\pgf@xb% + \fi% + \pgf@ya\pgf@y% + \pgfmathsetlength\pgf@yb{+\pgfkeysvalueof{/pgf/starburst point height}}% + \advance\pgf@ya\pgf@yb% + \pgfmathsetlength\pgf@yc{+\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@ya<.5\pgf@yc% + \pgf@y.5\pgf@yc% + \advance\pgf@y-\pgf@yb% + \fi% + \edef\xinnerradius{\the\pgf@x}% + \edef\yinnerradius{\the\pgf@y}% + \addtosavedmacro{\xinnerradius}% + \addtosavedmacro{\yinnerradius}% + % + % Calculate a radius outside the starburst. + % + \ifdim\pgf@y>\pgf@x% + \pgf@x\pgf@y% + \fi% + \pgfmathaddtolength\pgf@x{+\pgfkeysvalueof{/pgf/starburst point height}}% + \edef\externalradius{\the\pgf@x}% + \addtosavedmacro{\externalradius}% + % + % Set the seed for the random number generator. + % + \pgfmathsetseed{\pgfkeysvalueof{/pgf/random starburst}}% + % + % Now create the points on the shape and also + % the miter length and angle for each point. + % + \def\angle{90}% Start at the top. + % + % At point a, the miter length and angle are calculated for point b = a - 1. + % + \c@pgf@counta1\relax% + \c@pgf@countb0\relax% + % + % As 3 consecutive points are required to be defined for miter + % calculations, it is necessary to go over the first two points + % again. + % + \c@pgf@countc\totalpoints\relax% + \advance\c@pgf@countc2\relax% + \edef\looppoints{\the\c@pgf@countc}% + \let\secondpoint\pgfutil@empty% + \let\thirdpoint\pgfutil@empty% + \pgfmathloop% + % + % Cycle the point definitions. + % + \let\firstpoint\secondpoint% + \let\secondpoint\thirdpoint% + \ifnum\pgfmathcounter>\looppoints% + \else% + \ifnum\pgfmathcounter>\totalpoints% + \expandafter\let\expandafter\thirdpoint\csname point@\the\c@pgf@counta @\endcsname% + \else% + \ifodd\pgfmathcounter% + % + % An outer point. + % + \ifnum\pgfkeysvalueof{/pgf/random starburst}=0\relax% + \pgf@xa\pgfkeysvalueof{/pgf/starburst point height}\relax% + \else% + \pgf@x\pgfkeysvalueof{/pgf/starburst point height}\relax% + \pgf@xa.75\pgf@x% + \pgf@xb.25\pgf@x% + \pgfmathrnd% + \pgf@xa\pgfmathresult\pgf@xa% + \advance\pgf@xa\pgf@xb% + \fi% + \pgf@x\xinnerradius\relax% + \advance\pgf@x\pgf@xa% + \pgf@y\yinnerradius\relax% + \advance\pgf@y\pgf@xa% + \expandafter\pgfextract@process\csname point@\the\c@pgf@counta @\endcsname{% + \pgfpointpolar{\angle}{\the\pgf@x and \the\pgf@y}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \else% + % + % An inner point. + % + \expandafter\pgfextract@process\csname point@\the\c@pgf@counta @\endcsname{% + \pgfpointpolar{\angle}{\xinnerradius and \yinnerradius}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \fi% + % + % Add the points to the saved macro. + % + \expandafter\let\expandafter\thirdpoint\csname point@\the\c@pgf@counta @\endcsname% + \expandafter\addtosavedmacro\expandafter{\csname point@\the\c@pgf@counta @\endcsname}% + \fi% + % + % It is only possible to do the miter calculations if three points are defined. + % + \ifx\firstpoint\pgfutil@empty% + \else% + % + % Calculate the miter length... + % + \pgfmathanglebetweenlines{\secondpoint}{\thirdpoint}{\secondpoint}{\firstpoint}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\defaultmiterangle\pgfmathresult% + \pgfmathcosec@{\pgfmathresult}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \edef\miterlength{\the\pgf@x}% + % + % ...the miter angle... + % + \pgfmathanglebetweenlines{\firstpoint}{\secondpoint}{\firstpoint}{\thirdpoint}% + \pgfmathadd@{\pgfmathresult}{\defaultmiterangle}% + \pgfmathsubtract@{180}{\pgfmathresult}% + \let\angletemp\pgfmathresult% + \pgfmathanglebetweenpoints{\firstpoint}{\thirdpoint}% + \pgfmathsubtract@{180}{\pgfmathresult}% + \pgfmathsubtract@{\angletemp}{\pgfmathresult}% + \edef\miterangle{\pgfmathresult}% + % + % ...and thus the border point. + % + \pgfextract@process\borderpoint{% + \secondpoint% + \pgf@xa\pgf@x + \pgf@ya\pgf@y% + \pgfpointpolar{\miterangle}{\miterlength}% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Get the angle from the centerpoint to the *unrotated* border points. + % + \pgfmathanglebetweenpoints{\centerpoint}{\borderpoint}% + \expandafter\edef\csname angletoborderpoint@\the\c@pgf@countb @\endcsname{\pgfmathresult}% + \expandafter\addtosavedmacro\expandafter{\csname angletoborderpoint@\the\c@pgf@countb @\endcsname}% + % + % Rotate the border points and save. + % + \expandafter\pgfextract@process\csname borderpoint@\the\c@pgf@countb @\endcsname{% + \pgfmathrotatepointaround{\borderpoint}{\centerpoint}{\rotate}% + }% + \expandafter\addtosavedmacro\expandafter{\csname borderpoint@\the\c@pgf@countb @\endcsname}% + % + % Now create the anchors. + % + \c@pgf@countc\c@pgf@countb% + \advance\c@pgf@countc1\relax% + \divide\c@pgf@countc2\relax% + \ifodd\c@pgf@countb\relax% + \pgfutil@ifundefined{pgf@anchor@starburst@outer point\space\the\c@pgf@countc}{% + \expandafter\xdef\csname pgf@anchor@starburst@outer point\space\the\c@pgf@countc\endcsname{% + \noexpand\calculatestarburstpoints% + \noexpand\csname borderpoint@\the\c@pgf@countb @\noexpand\endcsname% + }% + }{}% + \else% + \pgfutil@ifundefined{pgf@anchor@starburst@inner point\space\the\c@pgf@countc}{% + \expandafter\xdef\csname pgf@anchor@starburst@inner point\space\the\c@pgf@countc\endcsname{% + \noexpand\calculatestarburstpoints% + \noexpand\csname borderpoint@\the\c@pgf@countb @\noexpand\endcsname% + }% + }{}% + \fi% + \fi% + \pgfmathadd@{\angle}{\anglestep}% + \pgfmathmod@{\pgfmathresult}{360}% + \let\angle\pgfmathresult% + \advance\c@pgf@counta1\relax% + \ifnum\c@pgf@counta>\totalpoints% + \c@pgf@counta1\relax% + \fi% + \advance\c@pgf@countb1\relax% + \ifnum\c@pgf@countb>\totalpoints% + \c@pgf@countb1\relax% + \fi% + \repeatpgfmathloop% + }% + \savedanchor\centerpoint{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5\ht\pgfnodeparttextbox}% + \pgfmathaddtolength\pgf@y{+-.5\dp\pgfnodeparttextbox}% + }% + \savedanchor\midpoint{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \savedanchor\basepoint{% + \pgfmathsetlength\pgf@x{+.5\wd\pgfnodeparttextbox}% + \pgf@y0pt\relax% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{mid}{\midpoint}% + \anchor{north}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{0pt}{\externalradius}}% + }% + \anchor{south}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{0pt}{-\externalradius}}% + }% + \anchor{east}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{\externalradius}{0pt}}% + }% + \anchor{west}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{-\externalradius}{0pt}}% + }% + \anchor{north west}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{-\externalradius}{\externalradius}}% + }% + \anchor{south west}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{-\externalradius}{-\externalradius}}% + }% + \anchor{north east}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{\externalradius}{\externalradius}}% + }% + \anchor{south east}{% + \calculatestarburstpoints% + \csname pgf@anchor@starburst@border\endcsname{\pgfqpoint{\externalradius}{-\externalradius}}% + }% + \backgroundpath{% + \calculatestarburstpoints% + \pgfmathloop% + \ifnum\pgfmathcounter>\totalpoints% + \else% + \ifnum\pgfmathcounter=1\relax% + \let\starburstaction\pgfpathmoveto% + \else% + \let\starburstaction\pgfpathlineto% + \fi% + \starburstaction{% + %\pgfmathrotatepointaround{\csname point@\pgfmathcounter @\endcsname}{\centerpoint}{\rotate}}% + \csname point@\pgfmathcounter @\endcsname} + \repeatpgfmathloop% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Adjust the location of the external + % point relative to \centerpoint. + % + \centerpoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Get the starburst points. + % + \calculatestarburstpoints% + % + % Get the angle of the external point to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + \pgfmathsubtract@{\pgfmathresult}{\rotate}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\externalangle\pgfmathresult% + % + % Locate the appropriate sides on the starburst border... + % + \ifdim\externalangle pt<90pt\relax% + \c@pgf@counta0\relax% + \c@pgf@countb\totalpoints\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \else% + \ifdim\csname angletoborderpoint@\the\c@pgf@countb @\endcsname pt>90pt\relax% + \c@pgf@counta\c@pgf@countb% + \else% + \ifdim\externalangle pt>\csname angletoborderpoint@\the\c@pgf@countb @\endcsname pt\relax% + \c@pgf@counta\c@pgf@countb% + \fi% + \fi% + \advance\c@pgf@countb-1\relax% + \repeatpgfmathloop% + \edef\first{\the\c@pgf@counta}% + \advance\c@pgf@counta1\relax% + \ifnum\c@pgf@counta>\totalpoints\relax% + \c@pgf@counta1\relax% + \fi% + \edef\second{\the\c@pgf@counta}% + \else% + \c@pgf@counta0\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \else% + \ifdim\csname angletoborderpoint@\pgfmathcounter @\endcsname pt<90pt\relax% + \c@pgf@counta\pgfmathcounter% + \else% + \ifdim\externalangle pt<\csname angletoborderpoint@\pgfmathcounter @\endcsname pt\relax% + \c@pgf@counta\pgfmathcounter% + \fi% + \fi% + \repeatpgfmathloop% + \edef\first{\the\c@pgf@counta}% + \advance\c@pgf@counta-1\relax% + \ifnum\c@pgf@counta=0\relax% + \c@pgf@counta\totalpoints\relax% + \fi% + \edef\second{\the\c@pgf@counta}% + \fi% + % + % ...and thus, the point on the star border. + % + \pgfpointintersectionoflines{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + {\csname borderpoint@\first @\endcsname}{\csname borderpoint@\second @\endcsname}% + }% +}% + + + + +% Keys for shape cloud. +% +% /pgf/cloud puffs : the number of cloud puffs. +% /pgf/cloud puff arc : the length of the cloud puff arc. + +\newif\ifpgfcloudanchorsuseellipse% +\newif\ifpgfcloudignoresaspect% +\pgfcloudignoresaspectfalse% +\pgfkeys{/pgf/.cd, + cloud puffs/.initial=10, + cloud puff arc/.initial=150, + cloud ignores aspect/.is if=pgfcloudignoresaspect, + cloud anchors use ellipse/.is if=pgfcloudanchorsuseellipse, +}% + + +% If symbol library is loaded separately these need to be defined. +% +\pgfkeys{/pgf/.cd, + aspect/.code={\pgfsetshapeaspect{#1}},% this for tikz... + shape aspect/.initial=1,% but this is consistent with other pgfset stuff. + shape aspect/.code={% + \pgfkeys{/pgf/aspect={#1}}% + \pgfkeyssetvalue{/pgf/shape aspect}{#1} + }% +}% + +\def\pgfsetshapeaspect#1{% + \def\pgfshapeaspect{#1}% + % Invert + \pgfutil@tempdima=#1pt% + \pgfutil@tempdima=.125\pgfutil@tempdima% + \c@pgf@counta=\pgfutil@tempdima\relax% 8192*determinant + \pgfutil@tempdima=8192pt% + \divide\pgfutil@tempdima by\c@pgf@counta% + \edef\pgfshapeaspectinverse{\pgf@sys@tonumber{\pgfutil@tempdima}}% +}% + +\pgfsetshapeaspect{1}% + + +% Shape cloud. +% +\pgfdeclareshape{cloud}{% + \savedmacro\getradii{% + \pgfmathtruncatemacro\puffs{\pgfkeysvalueof{/pgf/cloud puffs}}% + \addtosavedmacro\puffs% + \pgfmathdivide{360}{\pgfkeysvalueof{/pgf/cloud puffs}}% + \let\anglestep\pgfmathresult% + \addtosavedmacro\anglestep% + \pgfmathsetmacro\arc{\pgfkeysvalueof{/pgf/cloud puff arc}}% + \addtosavedmacro\arc% + % + % x radius. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgf@x1.4142135\pgf@x% + % + % y radius. + % + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + \pgf@y1.4142135\pgf@y% + % + % Adjust for shape aspect. + % + \ifpgfcloudignoresaspect% + \pgf@xc\pgf@x% + \pgf@yc\pgf@y% + \else% + \pgf@xc\pgfshapeaspect\pgf@y% + \ifdim\pgf@xc<\pgf@x% + \pgf@xc\pgf@x% + \fi% + \pgf@yc\pgfshapeaspectinverse\pgf@xc% + \ifdim\pgf@yc<\pgf@y% + \pgf@yc\pgf@y% + \pgf@xc\pgfshapeaspect\pgf@y% + \fi% + \fi% + % + \edef\xinnerradius{\the\pgf@xc}% + \edef\yinnerradius{\the\pgf@yc}% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x<\pgf@y% + \pgf@x\pgf@y% + \fi% + \edef\outersep{\the\pgf@x}% + \addtosavedmacro\outersep% + % + % For a given cloud, with puff arc length a, the quotient of the + % distance between the start and end point of a puffs circular arc + % and the radius of that arc, is constant: + % + % g = .5 * sec((180-a)/2) + % + \pgfmathsubtract{180}{\arc}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\tempangle\pgfmathresult% + \pgfmathsec@{\pgfmathresult}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\arcradiusquotient\pgfmathresult% + \addtosavedmacro\arcradiusquotient% + % + % In addition, the quotient of the distance between the start and + % end point of a puffs circular arc and the height of that arc + % (ignoring rotation), is also constant: + % + % h = .5 * (1-sin((180-a)/2))/cos((180-a)/2) + % = g * (1 - sin((180-a)/2)) + \pgfmathsin@{\tempangle}% + \pgfmathsubtract@{1}{\pgfmathresult}% + \pgfmathmultiply@{\pgfmathresult}{\arcradiusquotient}% + \let\archeightquotient\pgfmathresult% + \addtosavedmacro\archeightquotient% + % + % Minimum size is applied to the circum-ellipse (i.e. the ellipse + % that passes through the extremities of each puff). Thus, the + % relationship between the radii of the elliptical incircle ("inellipse"?) + % of the cloud (x and y) and the radii of the circum-ellipse (X and Y), + % is given by + % + % X = 2(x*cos(p/2) + ky) + % Y = 2(y*cos(p/2) + kx) + % + % where: + % k = sin(p/2)*((1-cos(a/2))/sin(a/2)) + % p = the angle between each puff (i.e. 360/) + % a = the length of arc of the puff. + % + \pgfmathdivide{\arc}{2}% + \let\halfarcangle\pgfmathresult% + \pgfmathcos@{\pgfmathresult}% + \pgfmathsubtract@{1}{\pgfmathresult}% + \let\pgf@temp\pgfmathresult% + \pgfmathsin@{\halfarcangle}% + \pgfmathdivide@{\pgf@temp}{\pgfmathresult}% + \let\pgf@temp\pgfmathresult% + \pgfmathdivide@{\anglestep}{2}% + \pgfmathsin@{\pgfmathresult}% + \pgfmathmultiply@{\pgfmathresult}{\pgf@temp}% + \let\k\pgfmathresult% + % + \pgfmathdivide@{\anglestep}{2}% + \pgfmathcos@{\pgfmathresult}% + \let\coshalfanglestep\pgfmathresult% + % + % Calculate the actual radii of the circum-ellipse. + % + \pgf@x\xinnerradius\relax% + \pgf@y\yinnerradius\relax% + \pgf@xa\coshalfanglestep\pgf@x% + \advance\pgf@xa\k\pgf@y% + \pgf@ya\coshalfanglestep\pgf@y% + \advance\pgf@ya\k\pgf@x% + % + % Adjust for minimum height (Y'). + % + \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@ya<.5\pgf@yb% + \pgf@ya.5\pgf@yb% + \fi% + % + % Adjust for minimum width (X'). + % + \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgf@xa<.5\pgf@xb% + \pgf@xa.5\pgf@xb% + \fi% + % + \edef\xouterradius{\the\pgf@xa}% + \addtosavedmacro\xouterradius% + \edef\youterradius{\the\pgf@ya}% + \addtosavedmacro\youterradius% + % + % Now recalculate `in-ellipse' radii: + % + % x = (X'cos(p/2)-kY')/cos^2(p/2)-k^2, + % y = (Y'cos(p/2)-kX')/cos^2(p/2)-k^2, + % + \pgf@xc\k pt\relax% + \pgf@xc-\k\pgf@xc% + \pgf@yc\coshalfanglestep pt\relax% + \pgf@yc\coshalfanglestep\pgf@yc% + \advance\pgf@xc\pgf@yc\relax% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@xc}}% cos^2(p/2)-k^2 + % + \pgf@x\coshalfanglestep\pgf@xa% + \advance\pgf@x-\k\pgf@ya% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y\coshalfanglestep\pgf@ya% + \advance\pgf@y-\k\pgf@xa% + \pgf@y\pgfmathresult\pgf@y% + % + \edef\xinnerradius{\the\pgf@x}% + \edef\yinnerradius{\the\pgf@y}% + \addtosavedmacro\xinnerradius% + \addtosavedmacro\yinnerradius% + % + % Get some useful trig. constants. + % + \pgfmathdivide@{\arc}{4}% + \let\quarterarc\pgfmathresult% + \pgfmathsubtract@{180}{\arc}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\halfcomplementarc\pgfmathresult% + % + \addtosavedmacro\arc% + \addtosavedmacro\quarterarc% + \addtosavedmacro\halfcomplementarc% + % + \pgfmathsec@{\halfcomplementarc}% 1/cos((180-a)/2) + \let\sechalfcomplementarc\pgfmathresult% + \pgfmathsin@{\halfcomplementarc}% sin((180-a)/2) + \let\sinhalfcomplementarc\pgfmathresult% + % + \addtosavedmacro\sechalfcomplementarc% + \addtosavedmacro\sinhalfcomplementarc% + % + \pgfmathsin@{\quarterarc}% sin(a/4) + \let\sinquarterarc\pgfmathresult% + \pgfmathcos@{\quarterarc}% cos(a/4) + \let\cosquarterarc\pgfmathresult% + \pgfmathreciprocal@{\cosquarterarc}% + \pgfmathmultiply@{\pgfmathresult}{\sinquarterarc}% tan(a/4) + \let\tanquarterarc\pgfmathresult% + % + \addtosavedmacro\sinquarterarc% + \addtosavedmacro\cosquarterarc% + \addtosavedmacro\tanquarterarc% + % + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{base}{\basepoint}% + \anchor{north}{% + \getradii% + \csname pgf@anchor@cloud@border\endcsname{\pgfqpoint{0pt}{\youterradius}}% + }% + \anchor{south}{% + \getradii% + \csname pgf@anchor@cloud@border\endcsname{\pgfqpoint{0pt}{-\youterradius}}% + }% + \anchor{east}{% + \getradii% + \csname pgf@anchor@cloud@border\endcsname{\pgfqpoint{\xouterradius}{0pt}}% + }% + \anchor{west}{% + \getradii% + \csname pgf@anchor@cloud@border\endcsname{\pgfqpoint{-\xouterradius}{0pt}}% + }% + \anchor{north west}{% + \getradii% + \pgfextract@process\pgf@sh{% + \pgf@x\xouterradius\relax% + \pgf@x-0.707106\pgf@x% + \pgf@y\youterradius\relax% + \pgf@y0.707106\pgf@y% + }% + \csname pgf@anchor@cloud@border\endcsname{\pgf@sh}% + }% + \anchor{north east}{% + \getradii% + \pgfextract@process\pgf@sh{% + \pgf@x\xouterradius\relax% + \pgf@x0.707106\pgf@x% + \pgf@y\youterradius\relax% + \pgf@y0.707106\pgf@y% + }% + \csname pgf@anchor@cloud@border\endcsname{\pgf@sh}% + }% + \anchor{south west}{% + \getradii% + \pgfextract@process\pgf@sh{% + \pgf@x\xouterradius\relax% + \pgf@x-0.707106\pgf@x% + \pgf@y\youterradius\relax% + \pgf@y-0.707106\pgf@y% + }% + \csname pgf@anchor@cloud@border\endcsname{\pgf@sh}% + }% + \anchor{south east}{% + \getradii% + \pgfextract@process\pgf@sh{% + \pgf@x\xouterradius\relax% + \pgf@x0.707106\pgf@x% + \pgf@y\youterradius\relax% + \pgf@y-0.707106\pgf@y% + }% + \csname pgf@anchor@cloud@border\endcsname{\pgf@sh}% + }% + % + % Each `puff' is a circular arc of length a, drawn using two a/2 + % arcs (a < 180), approximated by Bezier curves. + % Due to TeX rounding errors, it is sometimes necessary to `force' + % the arc to end at a specific point. So... + % + % @article{riskus2006, + % author = {Aleskus Ri\v{s}kus}, + % title = {Approximation of a cubic Bezier curve by circular arcs and vice versa}, + % journal = {Information Technology and Control}, + % year = {2006}, + % volume = {35}, + % number = {4} + % } + % + \backgroundpath{% + {% + \getradii% + % + % Get the start angle. + % + \pgfmathdivide@{\anglestep}{2}% + \pgfmathsubtract@{90}{\pgfmathresult}% + \let\angle\pgfmathresult% + % + % Calculate the first arc point. + % + \pgfextract@process\arcfirstpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\angle}{+\xinnerradius and +\yinnerradius}% + }% + }% + \pgfpathmoveto{\arcfirstpoint}% + \let\arcendpoint\arcfirstpoint% + % + \pgfmathloop% + \ifnum\pgfmathcounter>\puffs\relax% + \else + \let\arcstartpoint\arcendpoint% + % + % Make sure beginning and end of path are exactly the same. + % + \ifnum\pgfmathcounter=\puffs\relax% + \let\arcendpoint\arcfirstpoint% + \else% + \pgfmathadd@{\angle}{\anglestep}% + \let\angle\pgfmathresult% + \pgfextract@process\arcendpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\angle}{+\xinnerradius and +\yinnerradius}% + }% + }% + \fi% + % + % Get some useful cloud parameters from \arcstartpoint and \arcendpoint. + % + \pgf@sh@getcloudpuffparameters% + % + % Get the rotation for the Bezier curve. + % + \pgfmathsubtract@{90}{\quarterarc}% + \pgfmathadd@{\pgfmathresult}{\arcslope}% + \let\arcrotate\pgfmathresult% + \pgfmathsin@{\arcrotate}% + \let\sinarcrotate\pgfmathresult% + \pgfmathcos@{\arcrotate}% + \let\cosarcrotate\pgfmathresult% + % + % Calculate the amount by which to scale the control + % points, in order to approximate an a/2 arc with radius x. + % + \pgf@x\arcradius\relax% + \pgf@x\tanquarterarc\pgf@x% tan(a/4) + \edef\controlscale{\pgfmath@tonumber{\pgf@x}}% + % + % Get the first control point for the first arc (length a/2)... + % + \pgfextract@process\controlone{% + % + % k = 0.552284745 (a `magic' number)... + % + \pgf@x0.55228475pt\relax% + \pgf@x\sinquarterarc\pgf@x% k * sin(a/2) + \pgf@y0.55228475pt\relax% + \pgf@y\cosquarterarc\pgf@y% k * cos(a/2) + % + % ...scale the control points up... + % + \pgf@x\controlscale\pgf@x% + \pgf@y\controlscale\pgf@y% + % + % ...rotate... + % + \pgf@xa\cosarcrotate\pgf@x% + \advance\pgf@xa-\sinarcrotate\pgf@y% + \pgf@ya\cosarcrotate\pgf@y% + \advance\pgf@ya\sinarcrotate\pgf@x% + % + % ...and shift. + % + \arcstartpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Get the midpoint of the 150� arc. + % + \pgfextract@process\arcmidpoint{% + \pgfextract@process\arcmidpoint{% + \pgf@x-\halfchordlength\relax% + \pgf@y\segmentheight\relax% + }% + \pgfpointadd{\arcstartpoint}{% + \pgfmathrotatepointaround{\arcmidpoint}{\pgfpointorigin}{\arcslope}% + }% + }% + % + % Get the second control point for the first arc (length a/2)... + % + \pgfextract@process\controltwo{% + \pgf@x0.55228475pt\relax% + \pgf@x\sinquarterarc\pgf@x% k * sin(a/2) + \pgf@y-0.55228475pt\relax% + \pgf@y\cosquarterarc\pgf@y% -k * cos(a/2) + % + % ...scale, rotate and shift. + % + \pgf@x\controlscale\pgf@x% + \pgf@y\controlscale\pgf@y% + % + \pgf@xa\cosarcrotate\pgf@x% + \advance\pgf@xa-\sinarcrotate\pgf@y% + \pgf@ya\cosarcrotate\pgf@y% + \advance\pgf@ya\sinarcrotate\pgf@x% + % + \arcmidpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + {% + \pgfsetcornersarced{\pgfpointorigin}% + \pgfpathcurveto{\controlone}{\controltwo}{\arcmidpoint}% + }% + % + % Do the same for the second arc... + % + \pgfmathadd@{\quarterarc}{90}% + \pgfmathadd@{\pgfmathresult}{\arcslope}% + \let\arcrotate\pgfmathresult% + \pgfmathsin@{\arcrotate}% + \let\sinarcrotate\pgfmathresult% + \pgfmathcos@{\arcrotate}% + \let\cosarcrotate\pgfmathresult% + % + % First control point for the second arc... + % + \pgfextract@process\controlone{% + \pgf@x0.55228475pt\relax% + \pgf@x\sinquarterarc\pgf@x% k * sin(a/2) + \pgf@y0.55228475pt\relax% + \pgf@y\cosquarterarc\pgf@y% k * cos(a/2) + % + % ...scale, rotate and shift. + % + \pgf@x\controlscale\pgf@x% + \pgf@y\controlscale\pgf@y% + % + \pgf@xa\cosarcrotate\pgf@x% + \advance\pgf@xa-\sinarcrotate\pgf@y% + \pgf@ya\cosarcrotate\pgf@y% + \advance\pgf@ya\sinarcrotate\pgf@x% + % + \arcmidpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + % + % Second control point for the second arc. + % + \pgfextract@process\controltwo{% + \pgf@x0.55228475pt\relax% + \pgf@x\sinquarterarc\pgf@x% k * sin(a/2) + \pgf@y-0.55228475pt\relax% + \pgf@y\cosquarterarc\pgf@y% -k * cos(a/2) + % + % ...scale, rotate and shift. + % + \pgf@x\controlscale\pgf@x% + \pgf@y\controlscale\pgf@y% + % + \pgf@xa\cosarcrotate\pgf@x% + \advance\pgf@xa-\sinarcrotate\pgf@y% + \pgf@ya\cosarcrotate\pgf@y% + \advance\pgf@ya\sinarcrotate\pgf@x% + % + \arcendpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfpathcurveto{\controlone}{\controltwo}{\arcendpoint}% + \repeatpgfmathloop% + \pgfpathclose% Phew! + }% + }% + % + % Calculate a point on the border of the cloud. This is a two-stage process: + % + % 1. Locate the correct puff. + % 2. Locate the angle on the circular arc which forms the puff. + % + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Get the inner radii and trig. constants. + % + \getradii% + % + % + % + \ifpgfcloudanchorsuseellipse% + \pgfpointadd{\centerpoint}{% + \pgfpointborderellipse{% + \pgfpoint{\externalx}{\externaly} + }{% + \pgfpoint{\xouterradius}{\youterradius} + }% + }% + \else% + \pgfextract@process\externalpoint{% + \centerpoint% + \advance\pgf@x\externalx\relax% + \advance\pgf@y\externaly\relax% + }% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + % + % 1. Locate the correct puff: + % + % Get end angle of the relevant puff arc. + % + \pgfmathdivide@{\anglestep}{2}% + \let\halfanglestep\pgfmathresult% + \pgfmathsubtract@{90}{\halfanglestep}% + \let\endangle\pgfmathresult% + \pgfmathloop% + \pgfmathsubtract@{\endangle}{\anglestep}% + \ifdim\pgfmathresult pt<-\anglestep pt\relax% + \else% + \let\endangle\pgfmathresult% + \repeatpgfmathloop% + \def\angle{0}% + \let\lastangle\angle% + \pgfmathloop% + \pgfmathadd@{\endangle}{\anglestep}% + \let\endangle\pgfmathresult% + % + % Calculate the `miter point'. This is the point between + % each puff, and takes into account the outer sep. + % + \pgfextract@process\miterpoint{% + % + \pgfextract@process\secondpoint{% + \pgfpointpolar{+\endangle}{+\xinnerradius and +\yinnerradius}% + }% + % + \pgfmathadd@{\endangle}{\anglestep}% + \let\angletemp\pgfmathresult% + \pgfextract@process\thirdpoint{% + \pgfpointpolar{+\angletemp}{+\xinnerradius and +\yinnerradius}% + }% + % + \pgfmathsubtract@{\endangle}{\anglestep}% + \let\angletemp\pgfmathresult% + \pgfextract@process\firstpoint{% + \pgfpointpolar{+\angletemp}{+\xinnerradius and +\yinnerradius}% + }% + % + \pgfmathanglebetweenpoints{\firstpoint}{\secondpoint}% + \let\anglealpha\pgfmathresult% + \pgfmathanglebetweenpoints{\secondpoint}{\thirdpoint}% + \let\anglebeta\pgfmathresult% + % + \pgfmathsubtract@{\anglebeta}{\anglealpha}% + \pgfmathdivide@{\pgfmathresult}{2}% + \pgfmathadd@{\pgfmathresult}{\halfcomplementarc}% + \pgfmathcosec@{\pgfmathresult}% + \pgf@x\outersep\relax% + \pgf@x\pgfmathresult\pgf@x% + \edef\miterradius{\the\pgf@x}% + % + \pgfmathadd@{\anglealpha}{\anglebeta}% + \pgfmathsubtract@{\pgfmathresult}{180}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\miterangle\pgfmathresult% + \pgfpointadd{\secondpoint}{% + \pgfqpointpolar{\miterangle}{\miterradius}% + }% + }% + % + % Get the angle of the miter point... + % + \pgfmathanglebetweenpoints{\pgfpointorigin}{\miterpoint}% + \let\angle\pgfmathresult% + \ifdim\angle pt<\lastangle pt\relax% Guard against 360� = 0� + \pgfmathadd@{\angle}{360}% + \let\angle\pgfmathresult% + \fi% + \let\lastangle\angle% + % + % ...and see if it is greater than the external point. + % + \ifdim\externalangle pt>\angle pt\relax% + \repeatpgfmathloop% + % + % Get the start angle of the relevant arc and ensure angles are in the range. + % + \pgfmathmod@{\endangle}{360}% + \let\endangle\pgfmathresult% + \pgfmathsubtract@{\endangle}{\anglestep}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\startangle\pgfmathresult% + % + % Now, get the start and end points of the arc. + % + \pgfextract@process\arcstartpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\startangle}{+\xinnerradius and +\yinnerradius}% + }% + }% + \pgfextract@process\arcendpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\endangle}{+\xinnerradius and +\yinnerradius}% + }% + }% + % + % Get some useful cloud parameters from \arcstartpoint and \arcendpoint. + % + \pgf@sh@getcloudpuffparameters% + % + % Hackery, for when an arc straddles 0�. + % + \ifdim\endangle pt<\startangle pt\relax% + \pgfmathadd@{\externalangle}{180}% + \pgfmathmod@{\pgfmathresult}{360}% + \let\x\pgfmathresult% + \else% + \let\x\externalangle% + \fi% + % + % 2. Locate the angle on the circular arc which forms the puff. + % + % Essentially a binary search to find the angle on the circular + % arc, which provides the nearest estimate to the border point. + % + \let\s\halfcomplementarc% The start of the arc. + \pgfmathadd@{\s}{\arc}% + \let\e\pgfmathresult% The end of the arc. + \pgfmathadd@{\e}{\s}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\n\pgfmathresult% The nearest estimate (default to middle of arc). + \def\m{360}% Measure of `nearness'. + \pgfmathloop% + \pgfmathadd@{\e}{\s}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\p\pgfmathresult% The point halfway between \s and \e. + \ifdim\p pt=\s pt\relax% + \else% + % + % Get the point on the circular arc. + % + \pgfmathadd@{\p}{\arcslope}% + \let\a\pgfmathresult% + \pgfextract@process\arcpoint{% + \pgfpointadd{\circlecenterpoint}{% + \pgfqpointpolar{\a}{\outerarcradius}% + }% + }% + % + % Find the angle between the node centre and the point on the arc. + % + \pgfmathanglebetweenpoints{\centerpoint}{\arcpoint}% + % + % Hackery, for when an arc straddles 0�. + % + \ifdim\endangle pt<\startangle pt\relax% + \pgfmathadd@{\pgfmathresult}{180}% + \pgfmathmod@{\pgfmathresult}{360}% + \fi% + \let\q\pgfmathresult% + \ifdim\x pt=\q pt% Found it! + \pgfmathbreakloop% Breaks after current iteration is complete. + \else + \ifdim\x pt<\q pt\relax% + \let\e\p% + \else% + \let\s\p% + \fi% + \fi% + \pgfmathsubtract@{\x}{\q}% + \pgfmathabs@{\pgfmathresult}% + % + % Save the estimate if it is better than any previous estimate. + % + \ifdim\pgfmathresult pt<\m pt\relax% + \let\m\pgfmathresult% + \let\n\p% + \fi% + \repeatpgfmathloop% + % + % Use the nearest estimate as the anchor angle. + % + \pgfmathadd@{\n}{\arcslope}% + \let\anchorangle\pgfmathresult% + % + % Finally, the required point. + % + \pgfpointadd{\circlecenterpoint}{% + \pgfqpointpolar{\anchorangle}{\outerarcradius}% + }% + \fi% + }% Again, Phew! + % + % Now, a sneaky hack. This means an arbitrary `puff' anchors + % can be used for positioning the cloud shape. This is needed + % if a cloud is positioned using the `puff ' anchor, where + % n is the number of puffs of any previously drawn cloud. + % + \pgfutil@g@addto@macro\pgf@sh@s@cloud{% + \c@pgf@counta\puffs\relax% + \pgfmathloop% + \ifnum\c@pgf@counta>0\relax% + \pgfutil@ifundefined{pgf@anchor@cloud@puff\space\the\c@pgf@counta}{% + \expandafter\xdef\csname pgf@anchor@cloud@puff\space\the\c@pgf@counta\endcsname{% + \noexpand\pgf@sh@@cloudpuffanchor{\the\c@pgf@counta}% + }% + }{\c@pgf@counta0\relax}% + \advance\c@pgf@counta-1\relax% + \repeatpgfmathloop% + }% +}% + +% \pgf@sh@@cloudpuffanchor +% +% Internal macro for calculating the anchors puff 1, puff 2, ... etc. +% +\def\pgf@sh@@cloudpuffanchor#1{% + \getradii% + \pgfmathdivide@{\anglestep}{2}% + \let\halfanglestep\pgfmathresult% + \c@pgf@counta#1\relax% + \advance\c@pgf@counta-1\relax% + \pgfmathmultiply@{\anglestep}{\the\c@pgf@counta}% + \pgfmathadd@{\pgfmathresult}{90}% + \pgfmathsubtract@{\pgfmathresult}{\halfanglestep}% + \let\angle\pgfmathresult% + % + % Calculate the first arc point. + % + \pgfextract@process\arcstartpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\angle}{+\xinnerradius and +\yinnerradius}% + }% + }% + % + \pgfmathadd@{\angle}{\anglestep}% + \let\angle\pgfmathresult% + \pgfextract@process\arcendpoint{% + \pgfpointadd{\centerpoint}{% + \pgfpointpolar{+\angle}{+\xinnerradius and +\yinnerradius}% + }% + }% + % + % Get some useful cloud parameters from \arcstartpoint and \arcendpoint. + % + \pgf@sh@getcloudpuffparameters% + % + % Calculate the point. + % + \pgfmathadd@{\arcslope}{90}% + \let\anchorangle\pgfmathresult% + \pgfpointadd{\circlecenterpoint}{% + \pgfqpointpolar{\anchorangle}{\outerarcradius}% + }% +}% + +% \pgf@sh@cloudpuffparameters +% +% Internal macro to calculate some common arc parameters which +% are required when calculating radii, drawing the background +% path and calculating border anchors. +% +\def\pgf@sh@getcloudpuffparameters{% + % + % Calculate the angle to which the entire arc is sloped. + % + \pgfmathanglebetweenpoints{\arcendpoint}{\arcstartpoint}% + \let\arcslope\pgfmathresult% + % + % Calculate the chord length and arc radius. + % + \pgfpointdiff{\arcendpoint}{\arcstartpoint}% + \pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}} + \pgf@x\pgfmathresult pt\relax% + \pgf@xa.5\pgf@x% + \edef\halfchordlength{\the\pgf@xa}% + \pgf@x\arcradiusquotient\pgf@x% + \edef\arcradius{\the\pgf@x}% + \pgf@xa\outersep\relax% + \advance\pgf@xa\pgf@x% + \edef\outerarcradius{\the\pgf@xa}% + % + % Calculate the height of the resulting segment. + % + \pgf@y-\sinhalfcomplementarc\pgf@x% sin((180-a)/2) + \advance\pgf@y\pgf@x% + \edef\segmentheight{\the\pgf@y}% + % + % Calculate the center of the circle of which the arc is a part. + % + \pgfextract@process\circlecenterpoint{% + \pgfextract@process\circlecenterpoint{% + \pgf@x-\halfchordlength\relax% + \pgf@y\segmentheight\relax% + \advance\pgf@y-\arcradius + }% + \pgfpointadd{\arcstartpoint}{% + \pgfmathrotatepointaround{\circlecenterpoint}{\pgfpointorigin}{\arcslope}% + }% + }% +}% + + + + + +% Internal macros for signal shape. +% +\def\pgf@lib@sh@signal@nowhere{nowhere}% +\def\pgf@lib@sh@signal@from{from}% +\def\pgf@lib@sh@signal@to{to}% + +\def\pgf@lib@sh@signal@parsedirection#1#2{% + % + \let\pgf@lib@sh@signal@direction=#2% + \edef\pgf@lib@sh@temp{#1}% + \expandafter\pgf@lib@sh@signal@@parsedirection\pgf@lib@sh@temp\pgf@stop}% + +\def\pgf@lib@sh@signal@@parsedirection#1\pgf@stop{% + \pgfutil@in@{and}{#1}% + \ifpgfutil@in@% + \pgf@lib@sh@signal@@@parsedirection#1\pgf@lib% + \else% + \pgf@lib@sh@signal@@@parsedirection#1 and #1\pgf@lib% + \fi +}% +\def\pgf@lib@sh@signal@@@parsedirection#1 and #2\pgf@lib{% + \pgfutil@in@{nowhere}{#1}% + \ifpgfutil@in@ + \else% + \pgf@lib@sh@signal@@@@parsedirection{#1}% + \pgf@lib@sh@signal@@@@parsedirection{#2}% + \fi% +}% +\def\pgf@lib@sh@signal@@@@parsedirection#1{% + \pgfutil@in@{ #1 }{ east right }% + \ifpgfutil@in@% + \let\pgf@lib@sh@signal@east=\pgf@lib@sh@signal@direction% + \let\pgf@lib@sh@signal@north=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@south=\pgf@lib@sh@signal@nowhere% + \fi% + \pgfutil@in@{ #1 }{ left west }% + \ifpgfutil@in@% + \let\pgf@lib@sh@signal@west=\pgf@lib@sh@signal@direction% + \let\pgf@lib@sh@signal@north=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@south=\pgf@lib@sh@signal@nowhere% + \fi% + \pgfutil@in@{ #1 }{ above up north }% + \ifpgfutil@in@% + \let\pgf@lib@sh@signal@north=\pgf@lib@sh@signal@direction% + \let\pgf@lib@sh@signal@east=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@west=\pgf@lib@sh@signal@nowhere% + \fi% + \pgfutil@in@{ #1 }{ below down south }% + \ifpgfutil@in@% + \let\pgf@lib@sh@signal@south=\pgf@lib@sh@signal@direction% + \let\pgf@lib@sh@signal@east=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@west=\pgf@lib@sh@signal@nowhere% + \fi% +}% + + +% Keys for signal shape: +% +\pgfkeys{/pgf/.cd, + signal pointer angle/.initial=90, + signal to/.initial=east, + signal from/.initial=nowhere, +}% + +\pgfdeclareshape{signal}{% + \savedmacro\installsignalparameters{% + % + \let\pgf@lib@sh@signal@north=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@south=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@east=\pgf@lib@sh@signal@nowhere% + \let\pgf@lib@sh@signal@west=\pgf@lib@sh@signal@nowhere% + % + \pgf@lib@sh@signal@parsedirection{\pgfkeysvalueof{/pgf/signal from}}{\pgf@lib@sh@signal@from}% + \pgf@lib@sh@signal@parsedirection{\pgfkeysvalueof{/pgf/signal to}}{\pgf@lib@sh@signal@to}% + % + % Define a centerpoint. + % + \pgfextract@process\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + % + % Get some useful trig. stuff + % + \pgfmathsetmacro\pointerangle{\pgfkeysvalueof{/pgf/signal pointer angle}}% + % + \pgfmathdivide@{\pointerangle}{2}% + \let\halfpointerangle=\pgfmathresult% + % + \pgfmathcosec@{\halfpointerangle}% + \let\cosechalfpointerangle=\pgfmathresult% + % + \pgfmathdivide@{\halfpointerangle}{2}% + \let\quarterpointerangle=\pgfmathresult% + % + \pgfmathcosec@{\quarterpointerangle}% + \let\cosecquarterpointerangle=\pgfmathresult% + % + \pgfmathsec@{\quarterpointerangle}% + \let\secquarterpointerangle=\pgfmathresult% + % + \pgfmathsubtract@{90}{\quarterpointerangle}% + \let\complementquarterpointerangle\pgfmathresult% + % + % Get the larger of the outer sep. + % + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@x>\pgf@y% + \pgf@y\pgf@x% + \fi% + \pgf@yc=\pgf@y% + % + % Calculate the miter due to the line width, at the pointer apex... + % + \pgf@x=\cosechalfpointerangle\pgf@y% + \edef\pointerapexmiter{\the\pgf@x}% + % + % ...at a corner by a `to' pointer (i.e. sticks out)... + % + \pgf@x=\secquarterpointerangle\pgf@y% + \edef\tocornermiter{\the\pgf@x}% + % + % ...at a corner by a `from' pointer (i.e. sticks in). + % + \pgf@x=\cosecquarterpointerangle\pgf@y + \edef\fromcornermiter{\the\pgf@x}% + % + % Get the (half) dimensions of the node. + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@xa.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@ya.5\ht\pgfnodeparttextbox% + \advance\pgf@ya.5\dp\pgfnodeparttextbox% + % + % Get the distance a pointer sticks out to the side... + % + \pgfmathsubtract@{90}{\halfpointerangle}% + \pgfmathtan@{\pgfmathresult}% + \pgf@xb=\pgfmathresult\pgf@ya% + % + % ...and up. + % + \pgf@yb=\pgfmathresult\pgf@xa% + % + % Adjust for minimum height. + % + \pgfutil@tempdima=2.0\pgf@ya% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by\pgf@yb% + \fi% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgfutil@tempdima<\pgf@y% + \pgfutil@tempdima=\pgf@y% + % + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by-\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by-\pgf@yb% + \fi% + \pgf@ya=0.5\pgfutil@tempdima% + \pgfmathsubtract@{90}{\halfpointerangle}% + \pgfmathtan@{\pgfmathresult}% + \pgf@xb=\pgfmathresult\pgf@ya% + \fi% + % + % Adjust for minimum width. + % + \pgfutil@tempdima=2.0\pgf@xa% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by\pgf@xb% + \fi% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by\pgf@xb% + \fi% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/minimum width}}% + \ifdim\pgfutil@tempdima<\pgf@x% + \pgfutil@tempdima=\pgf@x% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@nowhere% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \pgf@xa=0.5\pgfutil@tempdima% + \pgfmathsubtract@{90}{\halfpointerangle}% + \pgfmathtan@{\pgfmathresult}% + \pgf@yb=\pgfmathresult\pgf@xa% + \fi% + % + % So, define the points for the background path. + % + \pgfextract@process\north{% + \centerpoint% + \advance\pgf@y\pgf@ya% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@to% + \advance\pgf@y\pgf@yb% + \fi% + }% + \pgfextract@process\south{% + \centerpoint% + \advance\pgf@y-\pgf@ya% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@to% + \advance\pgf@y-\pgf@yb% + \fi% + }% + \pgfextract@process\east{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@to% + \advance\pgf@x\pgf@xb% + \fi% + }% + \pgfextract@process\west{% + \centerpoint% + \advance\pgf@x-\pgf@xa% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@to% + \advance\pgf@x-\pgf@xb% + \fi% + }% + \pgfextract@process\northeast{% + \centerpoint% + \advance\pgf@y\pgf@ya% + \advance\pgf@x\pgf@xa% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@from% + \advance\pgf@y\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@from% + \advance\pgf@x\pgf@xb% + \fi% + }% + \pgfextract@process\southeast{% + \centerpoint% + \advance\pgf@y-\pgf@ya% + \advance\pgf@x\pgf@xa% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@from% + \advance\pgf@y-\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@from% + \advance\pgf@x\pgf@xb% + \fi% + }% + \pgfextract@process\southwest{% + \centerpoint% + \advance\pgf@y-\pgf@ya% + \advance\pgf@x-\pgf@xa% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@from% + \advance\pgf@y-\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@from% + \advance\pgf@x-\pgf@xb% + \fi% + }% + \pgfextract@process\northwest{% + \centerpoint% + \advance\pgf@y\pgf@ya% + \advance\pgf@x-\pgf@xa% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@from% + \advance\pgf@y\pgf@yb% + \fi% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@from% + \advance\pgf@x-\pgf@xb% + \fi% + }% + \addtosavedmacro{\north}% + \addtosavedmacro{\south}% + \addtosavedmacro{\east}% + \addtosavedmacro{\west}% + \addtosavedmacro{\northeast}% + \addtosavedmacro{\southwest}% + \addtosavedmacro{\southeast}% + \addtosavedmacro{\northwest}% + % + % Calculate the `miter vectors' (i.e. +outer sep). + % + \pgfextract@process\northmiter{% + \pgf@x0pt% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@nowhere% + \pgf@y\pgf@yc% + \else% + \pgf@y\pointerapexmiter\relax% + \fi% + }% + \pgfextract@process\southmiter{% + \pgf@x0pt% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@nowhere% + \pgf@y-\pgf@yc% + \else% + \pgf@y-\pointerapexmiter\relax% + \fi% + }% + \pgfextract@process\eastmiter{% + \pgf@y0pt% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@nowhere% + \pgf@x\pgf@yc% + \else% + \pgf@x\pointerapexmiter\relax% + \fi% + }% + \pgfextract@process\westmiter{% + \pgf@y0pt% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@nowhere% + \pgf@x-\pgf@yc% + \else% + \pgf@x-\pointerapexmiter\relax% + \fi% + }% + \pgfextract@process\northeastmiter{% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@nowhere% + \pgf@x\pgf@yc + \pgf@y\pgf@yc% + \else + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@from% + \pgfqpointpolar{\quarterpointerangle}{\fromcornermiter} + \else% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@to% + \pgfqpointpolar{\complementquarterpointerangle}{\tocornermiter}% + \fi% + \fi% + \fi% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@from% + \pgfqpointpolar{\complementquarterpointerangle}{\fromcornermiter}% + \else% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@to% + \pgfqpointpolar{\quarterpointerangle}{\tocornermiter}% + \fi% + \fi% + }% + \pgfextract@process\southeastmiter{% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@nowhere% + \pgf@x\pgf@yc% + \pgf@y\pgf@yc% + \else + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@from% + \pgfqpointpolar{-\quarterpointerangle}{\fromcornermiter} + \else% + \ifx\pgf@lib@sh@signal@east\pgf@lib@sh@signal@to% + \pgfqpointpolar{-\complementquarterpointerangle}{\tocornermiter}% + \fi% + \fi% + \fi% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@from% + \pgfqpointpolar{-\complementquarterpointerangle}{\fromcornermiter} + \else% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@to% + \pgfqpointpolar{-\quarterpointerangle}{\tocornermiter}% + \fi% + \fi% + }% + \pgfextract@process\southwestmiter{% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@nowhere% + \pgf@x-\pgf@yc + \pgf@y-\pgf@yc% + \else + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@from% + \pgfmathadd@{\quarterpointerangle}{180}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\fromcornermiter} + \else% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@to% + \pgfmathadd@{\complementquarterpointerangle}{180}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\tocornermiter}% + \fi% + \fi% + \fi% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@from% + \pgfmathadd@{\complementquarterpointerangle}{180}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\fromcornermiter}% + \else% + \ifx\pgf@lib@sh@signal@south\pgf@lib@sh@signal@to% + \pgfmathadd@{\quarterpointerangle}{180}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\tocornermiter}% + \fi% + \fi% + }% + \pgfextract@process\northwestmiter{% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@nowhere% + \pgf@x-\pgf@yc% + \pgf@y\pgf@yc% + \else + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@from% + \pgfmathsubtract@{180}{\quarterpointerangle}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\fromcornermiter} + \else% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@to% + \pgfmathsubtract@{180}{\complementquarterpointerangle}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\tocornermiter}% + \fi% + \fi% + \fi% + \ifx\pgf@lib@sh@signal@north\pgf@lib@sh@signal@from% + \pgfmathsubtract@{180}{\complementquarterpointerangle}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\fromcornermiter}% + \else% + \ifx\pgf@lib@sh@signal@west\pgf@lib@sh@signal@to% + \pgfmathsubtract@{180}{\quarterpointerangle}% + \expandafter\pgfqpointpolar\expandafter{\pgfmathresult}{\tocornermiter}% + \fi% + \fi% + }% + \addtosavedmacro{\northmiter}% + \addtosavedmacro{\southmiter}% + \addtosavedmacro{\eastmiter}% + \addtosavedmacro{\westmiter}% + \addtosavedmacro{\northeastmiter}% + \addtosavedmacro{\southeastmiter}% + \addtosavedmacro{\southwestmiter}% + \addtosavedmacro{\northwestmiter}% + % + % Now calculate the anchor points + % + \pgfextract@process\anchornorth{% + \pgfpointadd{\north}{\northmiter}% + }% + \pgfextract@process\anchorsouth{% + \pgfpointadd{\south}{\southmiter}% + }% + \pgfextract@process\anchoreast{% + \pgfpointadd{\east}{\eastmiter}% + }% + \pgfextract@process\anchorwest{% + \pgfpointadd{\west}{\westmiter}% + }% + \pgfextract@process\anchornortheast{% + \pgfpointadd{\northeast}{\northeastmiter}% + }% + \pgfextract@process\anchorsoutheast{% + \pgfpointadd{\southeast}{\southeastmiter}% + }% + \pgfextract@process\anchorsouthwest{% + \pgfpointadd{\southwest}{\southwestmiter}% + }% + \pgfextract@process\anchornorthwest{% + \pgfpointadd{\northwest}{\northwestmiter}% + }% + \addtosavedmacro{\anchornorth}% + \addtosavedmacro{\anchorsouth}% + \addtosavedmacro{\anchoreast}% + \addtosavedmacro{\anchorwest}% + \addtosavedmacro{\anchornortheast}% + \addtosavedmacro{\anchorsouthwest}% + \addtosavedmacro{\anchorsoutheast}% + \addtosavedmacro{\anchornorthwest}% + }% + \savedanchor\centerpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor\basepoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \savedanchor\midpoint{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+.5ex}% + }% + \anchor{center}{\centerpoint}% + \anchor{base}{\basepoint}% + \anchor{base east}{% + \installsignalparameters% + \anchoreast% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \anchorsoutheast% + \ifdim\pgf@xa>\pgf@x% + \pgfutil@tempdima\pgf@xa% + \else% + \pgfutil@tempdima\pgf@x% + \fi% + \pgfextract@process\externalpoint{% + \basepoint% + \pgf@x\pgfutil@tempdima% + } + \basepoint% + \let\firstpoint\anchoreast% + \ifdim\pgf@y<\pgf@ya% + \let\secondpoint\anchorsoutheast% + \else% + \let\secondpoint\anchornortheast% + \fi% + \pgfpointintersectionoflines{\basepoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% + \anchor{base west}{% + \installsignalparameters% + \anchorwest% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \anchorsouthwest% + \ifdim\pgf@xa<\pgf@x% + \pgfutil@tempdima\pgf@xa% + \else% + \pgfutil@tempdima\pgf@x% + \fi% + \pgfextract@process\externalpoint{% + \basepoint% + \pgf@x\pgfutil@tempdima% + } + \basepoint% + \let\firstpoint\anchorwest% + \ifdim\pgf@y<\pgf@ya% + \let\secondpoint\anchorsouthwest% + \else% + \let\secondpoint\anchornorthwest% + \fi% + \pgfpointintersectionoflines{\basepoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% + \anchor{mid}{\midpoint}% + \anchor{mid east}{% + \installsignalparameters% + \anchoreast% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \anchorsoutheast% + \ifdim\pgf@xa>\pgf@x% + \pgfutil@tempdima\pgf@xa% + \else% + \pgfutil@tempdima\pgf@x% + \fi% + \pgfextract@process\externalpoint{% + \midpoint% + \pgf@x\pgfutil@tempdima% + } + \midpoint% + \let\firstpoint\anchoreast% + \ifdim\pgf@y<\pgf@ya% + \let\secondpoint\anchorsoutheast% + \else% + \let\secondpoint\anchornortheast% + \fi% + \pgfpointintersectionoflines{\midpoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% + \anchor{mid west}{% + \installsignalparameters% + \anchorwest% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \anchorsouthwest% + \ifdim\pgf@xa<\pgf@x% + \pgfutil@tempdima\pgf@xa% + \else% + \pgfutil@tempdima\pgf@x% + \fi% + \pgfextract@process\externalpoint{% + \midpoint% + \pgf@x\pgfutil@tempdima% + } + \midpoint% + \let\firstpoint\anchorwest% + \ifdim\pgf@y<\pgf@ya% + \let\secondpoint\anchorsouthwest% + \else% + \let\secondpoint\anchornorthwest% + \fi% + \pgfpointintersectionoflines{\midpoint}{\externalpoint}% + {\firstpoint}{\secondpoint}% + }% + \anchor{north}{\installsignalparameters\anchornorth}% + \anchor{south}{\installsignalparameters\anchorsouth}% + \anchor{east}{\installsignalparameters\anchoreast}% + \anchor{west}{\installsignalparameters\anchorwest}% + \anchor{north east}{\installsignalparameters\anchornortheast}% + \anchor{south east}{\installsignalparameters\anchorsoutheast}% + \anchor{south west}{\installsignalparameters\anchorsouthwest}% + \anchor{north west}{\installsignalparameters\anchornorthwest}% + \backgroundpath{% + \installsignalparameters% + \pgfpathmoveto{\north}% + \pgfpathlineto{\northeast}% + \pgfpathlineto{\east}% + \pgfpathlineto{\southeast}% + \pgfpathlineto{\south}% + \pgfpathlineto{\southwest}% + \pgfpathlineto{\west}% + \pgfpathlineto{\northwest}% + \pgfpathclose% + }% + \anchorborder{% + % + % Save x and y. + % + \edef\externalx{\the\pgf@x}% + \edef\externaly{\the\pgf@y}% + % + % Adjust the location of the external + % point relative to \centerpoint. + % + \centerpoint% + \pgf@xa\externalx\relax% + \pgf@ya\externaly\relax% + \advance\pgf@xa\pgf@x% + \advance\pgf@ya\pgf@y% + \edef\externalx{\the\pgf@xa}% + \edef\externaly{\the\pgf@ya}% + % + % Get the shape parameters. + % + \installsignalparameters% + % + % Get the angle of the external point to the \centerpoint. + % + \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + \let\externalangle\pgfmathresult% + % + % + % + \pgfmathanglebetweenpoints{\centerpoint}{\anchorwest}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\centerpoint}{\anchornorth}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\centerpoint}{\anchornortheast}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \let\firstpoint\anchoreast% + \let\secondpoint\anchornortheast% + \else% + \let\secondpoint\anchornortheast% + \let\firstpoint\anchornorth% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\anchornorthwest}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \let\firstpoint\anchornorth% + \let\secondpoint\anchornorthwest% + \else% + \let\secondpoint\anchornorthwest% + \let\firstpoint\anchorwest% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\anchorsouth}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \pgfmathanglebetweenpoints{\centerpoint}{\anchorsouthwest}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \let\firstpoint\anchorwest% + \let\secondpoint\anchorsouthwest% + \else% + \let\secondpoint\anchorsouthwest% + \let\firstpoint\anchorsouth% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\anchorsoutheast}% + \ifdim\externalangle pt<\pgfmathresult pt\relax% + \let\firstpoint\anchorsouth% + \let\secondpoint\anchorsoutheast% + \else% + \let\secondpoint\anchorsoutheast% + \let\firstpoint\anchoreast% + \fi% + \fi% + \fi% + % + % Now locate the point. + % + \pgfpointintersectionoflines{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}% + {\firstpoint}{\secondpoint}% + }% +}% + + + + + + +% Keys for shape tape +% +% /pgf/tape bend top : Type of bend for north side. +% /pgf/tape bend bottom : Type of bend for south side. +% /pgf/tape bend height : The height of the bends. +\pgfkeys{/pgf/.cd, + tape bend top/.initial=in and out, + tape bend bottom/.initial=in and out, + tape bend/.style={/pgf/tape bend top={#1}, /pgf/tape bend bottom={#1}}, + tape bend height/.initial=5pt, +}% + +\def\pgf@lib@sh@inandouttext{in and out}% +\def\pgf@lib@sh@outandintext{out and in}% +\def\pgf@lib@sh@nonetext{none}% + +\pgfdeclareshape{tape}{% + \savedmacro\tapedimensions{% + \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}% + \advance\pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y.5\dp\pgfnodeparttextbox% + % + \pgfmathsetlengthmacro\outerxsep{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlengthmacro\outerysep{\pgfkeysvalueof{/pgf/outer ysep}}% + \addtosavedmacro\outerxsep% + \addtosavedmacro\outerysep% + % + \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/tape bend height}}% + \pgfutil@tempdima.5\pgfutil@tempdima% + \edef\halfbendheight{\the\pgfutil@tempdima}% + \addtosavedmacro\halfbendheight% + % + \pgfkeysgetvalue{/pgf/tape bend top}{\topbendstyle}% + \pgfkeysgetvalue{/pgf/tape bend bottom}{\bottombendstyle}% + \addtosavedmacro\topbendstyle% + \addtosavedmacro\bottombendstyle% + % + \ifx\topbendstyle\pgf@lib@sh@nonetext% + \else% + \advance\pgf@y\pgfutil@tempdima% + \fi% + \ifx\bottombendstyle\pgf@lib@sh@none% + \else% + \advance\pgf@y\pgfutil@tempdima% + \fi% + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<.5\pgf@xa% + \pgf@x.5\pgf@xa% + \fi% + \ifdim\pgf@y<.5\pgf@ya% + \pgf@y.5\pgf@ya% + \fi% + \ifx\topbendstyle\pgf@lib@sh@nonetext% + \else% + \advance\pgf@y-\pgfutil@tempdima% + \fi% + \ifx\bottombendstyle\pgf@lib@sh@nonetext% + \else% + \advance\pgf@y-\pgfutil@tempdima% + \fi% + % + \pgfutil@tempdima3.414213\pgfutil@tempdima% 1 / (1-sin(45)) + \edef\bendyradius{\the\pgfutil@tempdima}% + \addtosavedmacro\bendyradius% + \advance\pgfutil@tempdima\outerysep% + \edef\outerbendyradius{\the\pgfutil@tempdima}% + \addtosavedmacro\outerbendyradius% + \advance\pgfutil@tempdima-\outerysep% + \advance\pgfutil@tempdima-\outerysep% + \edef\innerbendyradius{\the\pgfutil@tempdima}% + \addtosavedmacro\innerbendyradius% + % + \pgfutil@tempdima0.707106\pgf@x% cos(45) + \edef\bendxradius{\the\pgfutil@tempdima}% + \addtosavedmacro\bendxradius% + \advance\pgfutil@tempdima\outerxsep% + \edef\outerbendxradius{\the\pgfutil@tempdima}% + \addtosavedmacro\outerbendxradius% + \advance\pgfutil@tempdima-\outerxsep% + \advance\pgfutil@tempdima-\outerxsep% + \edef\innerbendxradius{\the\pgfutil@tempdima}% + \addtosavedmacro\innerbendxradius% + % + \edef\halfwidth{\the\pgf@x}% + \edef\halfheight{\the\pgf@y}% + \addtosavedmacro\halfwidth% + \addtosavedmacro\halfheight% + % + \advance\pgf@x\outerxsep% + \edef\outerhalfwidth{\the\pgf@x}% + \addtosavedmacro\outerhalfwidth% + % + \pgf@xc\bendxradius% + \pgf@yc\bendyradius% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@yc}}{\pgfmath@tonumber{\pgf@xc}}% + \pgfmathatan{\pgfmathresult}% + \pgf@xc\pgfmathresult pt\relax% + \pgf@xc.5\pgf@xc% + \edef\halfangle{\pgfmath@tonumber{\pgf@xc}}% + \addtosavedmacro\halfangle% + % + \pgf@xc45pt\relax% + \advance\pgf@xc-\halfangle pt% + \pgfmathcot@{\pgfmath@tonumber{\pgf@xc}}% + \let\cothalfanglein\pgfmathresult% + \addtosavedmacro\cothalfanglein% + % + \pgf@xc90pt\relax% + \advance\pgf@xc-\halfangle pt% + \pgfmathcot@{\pgfmath@tonumber{\pgf@xc}}% + \let\cothalfangleout\pgfmathresult% + \addtosavedmacro\cothalfangleout% + % + }% + \savedanchor{\centerpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y.5\ht\pgfnodeparttextbox% + \advance\pgf@y-.5\dp\pgfnodeparttextbox% + }% + \savedanchor{\midpoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgfmathsetlength\pgf@y{+0.5ex}% + }% + \savedanchor{\basepoint}{% + \pgf@x.5\wd\pgfnodeparttextbox% + \pgf@y0pt% + }% + \anchor{center}{\centerpoint}% + \anchor{mid}{\midpoint}% + \anchor{mid east}{\tapedimensions\midpoint\advance\pgf@x\outerhalfwidth}% + \anchor{mid west}{\tapedimensions\midpoint\advance\pgf@x-\outerhalfwidth}% + \anchor{base}{\basepoint}% + \anchor{base east}{\tapedimensions\basepoint\advance\pgf@x\outerhalfwidth}% + \anchor{base west}{\tapedimensions\basepoint\advance\pgf@x-\outerhalfwidth}% + \anchor{north}{% + \csname pgf@anchor@tape@north east\endcsname% + \pgf@ya\pgf@y% + \csname pgf@anchor@tape@north west\endcsname% + \advance\pgf@ya\pgf@y% + \centerpoint% + \pgf@y.5\pgf@ya% + }% + \anchor{south}{% + \csname pgf@anchor@tape@south east\endcsname% + \pgf@ya\pgf@y% + \csname pgf@anchor@tape@south west\endcsname% + \advance\pgf@ya\pgf@y% + \centerpoint% + \pgf@y.5\pgf@ya% + }% + \anchor{east}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x\outerhalfwidth% + }% + \anchor{west}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x-\outerhalfwidth% + }% + \anchor{north east}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x\outerhalfwidth% + \advance\pgf@y\halfheight% + \pgf@yc\outerysep% + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + \advance\pgf@y\halfbendheight% + \advance\pgf@y\cothalfangleout\pgf@yc% + \else% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + \advance\pgf@y\halfbendheight% + \advance\pgf@y\cothalfanglein\pgf@yc% + \else% + \advance\pgf@y\pgf@yc% + \fi% + \fi% + }% + \anchor{north west}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x-\outerhalfwidth% + \advance\pgf@y\halfheight% + \pgf@yc\outerysep% + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + \advance\pgf@y\halfbendheight% + \advance\pgf@y\cothalfanglein\pgf@yc% + \else% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + \advance\pgf@y\halfbendheight% + \advance\pgf@y\cothalfangleout\pgf@yc% + \else% + \advance\pgf@y\pgf@yc% + \fi% + \fi% + }% + \anchor{south east}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x\outerhalfwidth% + \advance\pgf@y-\halfheight% + \pgf@yc\outerysep% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + \advance\pgf@y-\halfbendheight% + \advance\pgf@y-\cothalfangleout\pgf@yc% + \else% + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + \advance\pgf@y-\halfbendheight% + \advance\pgf@y-\cothalfanglein\pgf@yc% + \else% + \advance\pgf@y-\pgf@yc% + \fi% + \fi% + }% + \anchor{south west}{% + \tapedimensions% + \centerpoint% + \advance\pgf@x-\outerhalfwidth% + \advance\pgf@y-\halfheight% + \pgf@yc\outerysep% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + \advance\pgf@y-\halfbendheight% + \advance\pgf@y-\cothalfanglein\pgf@yc% + \else% + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + \advance\pgf@y-\halfbendheight% + \advance\pgf@y-\cothalfangleout\pgf@yc% + \else% + \advance\pgf@y-\pgf@yc% + \fi% + \fi% + }% + \backgroundpath{% + \tapedimensions% + % + \pgf@xc\halfwidth% + \pgf@yc\halfheight% + % + \pgf@xc\bendxradius% + \pgf@yc\bendyradius% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfqpoint{-\halfwidth}{0pt}}% + \pgfpathlineto{\pgfqpoint{-\halfwidth}{\halfheight}}% + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + \pgfpathlineto{\pgf@x-\halfwidth\pgf@y\halfheight\advance\pgf@y\halfbendheight}% + \pgfpatharc{225}{315}{\bendxradius and \bendyradius}% + \pgfpatharc{135}{45}{\bendxradius and \bendyradius}% + \else% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + \pgfpathlineto{\pgf@x-\halfwidth\pgf@y\halfheight\advance\pgf@y\halfbendheight}% + \pgfpatharc{135}{45}{\bendxradius and \bendyradius}% + \pgfpatharc{225}{315}{\bendxradius and \bendyradius}% + \else% + \pgfpathlineto{\pgfqpoint{\halfwidth}{\halfheight}}% + \fi% + \fi% + \pgfpathlineto{\pgfqpoint{\halfwidth}{-\halfheight}}% + \ifx\bottombendstyle\pgf@lib@sh@inandouttext% + \pgfpathlineto{\pgf@x\halfwidth\pgf@y-\halfheight\advance\pgf@y-\halfbendheight}% + \pgfpatharc{45}{135}{\bendxradius and \bendyradius}% + \pgfpatharc{315}{225}{\bendxradius and \bendyradius}% + \else% + \ifx\bottombendstyle\pgf@lib@sh@outandintext% + \pgfpathlineto{\pgf@x\halfwidth\pgf@y-\halfheight\advance\pgf@y-\halfbendheight}% + \pgfpatharc{315}{225}{\bendxradius and \bendyradius}% + \pgfpatharc{45}{135}{\bendxradius and \bendyradius}% + \else% + \pgfpathlineto{\pgfqpoint{-\halfwidth}{-\halfheight}}% + \fi% + \fi% + \pgfpathclose% + }% + }% + \anchorborder{% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfextract@process\externalpoint{% + \centerpoint% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% + \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}% + \let\externalangle\pgfmathresult% + \tapedimensions% + % + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@tape@north west\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt% + \ifdim\externalangle pt<90pt% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@tape@north east\endcsname}% + \ifdim\externalangle pt<\pgfmathresult pt% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@north east\endcsname}% + {\csname pgf@anchor@tape@south east\endcsname}% + \else% + % Between north and north east. + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + % in and out. + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x.5\pgf@xc% + \advance\pgf@y\halfheight% + \advance\pgf@y\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y-.707106\pgf@yc% + }% + {5}{175}{\outerbendxradius and \outerbendyradius}% + \else% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + % out and in. + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x.5\pgf@xc% + \advance\pgf@y\halfheight% + \advance\pgf@y\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y.707106\pgf@yc% + }% + {185}{355}{\innerbendxradius and \innerbendyradius}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@north east\endcsname}% + {\csname pgf@anchor@tape@north west\endcsname}% + \fi% + \fi% + \fi% + \else% + % Between north and north west. + \ifx\topbendstyle\pgf@lib@sh@inandouttext% + % in and out. + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x-.5\pgf@xc% + \advance\pgf@y\halfheight% + \advance\pgf@y\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y.707106\pgf@yc% + }% + {185}{355}{\innerbendxradius and \innerbendyradius}% + \else% + \ifx\topbendstyle\pgf@lib@sh@outandintext% + % out and in. + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x-.5\pgf@xc% + \advance\pgf@y\halfheight% + \advance\pgf@y\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y-.707106\pgf@yc% + }% + {5}{175}{\outerbendxradius and \outerbendyradius}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@north east\endcsname}% + {\csname pgf@anchor@tape@north west\endcsname}% + \fi% + \fi% + \fi% + \else% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@tape@south west\endcsname}% + \ifdim\externalangle pt>\pgfmathresult pt% + \ifdim\externalangle pt>270pt% + \pgfmathanglebetweenpoints{\centerpoint}{\csname pgf@anchor@tape@south east\endcsname}% + \ifdim\externalangle pt>\pgfmathresult pt% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@north east\endcsname}% + {\csname pgf@anchor@tape@south east\endcsname}% + \else% + % Between south and south east. + \ifx\bottombendstyle\pgf@lib@sh@inandouttext% + % in and out. + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x.5\pgf@xc% + \advance\pgf@y-\halfheight% + \advance\pgf@y-\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y-.707106\pgf@yc% + }% + {5}{175}{\innerbendxradius and \innerbendyradius}% + \else% + \ifx\bottombendstyle\pgf@lib@sh@outandintext% + % out and in. + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x.5\pgf@xc% + \advance\pgf@y-\halfheight% + \advance\pgf@y-\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y.707106\pgf@yc% + }% + {185}{355}{\outerbendxradius and \outerbendyradius}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@south east\endcsname}% + {\csname pgf@anchor@tape@south west\endcsname}% + \fi% + \fi% + \fi% + \else% + % Between south and south west. + \ifx\bottombendstyle\pgf@lib@sh@inandouttext% + % in and out. + \pgfmathpointintersectionoflineandarc{\externalpoint}{\centerpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x-.5\pgf@xc% + \advance\pgf@y-\halfheight% + \advance\pgf@y-\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y.707106\pgf@yc% + }% + {185}{355}{\outerbendxradius and \outerbendyradius}% + \else% + \ifx\bottombendstyle\pgf@lib@sh@outandintext% + % out and in. + \pgfmathpointintersectionoflineandarc{\centerpoint}{\externalpoint}% + {% + \centerpoint% + \pgf@xc\halfwidth% + \advance\pgf@x-.5\pgf@xc% + \advance\pgf@y-\halfheight% + \advance\pgf@y-\halfbendheight% + \pgf@yc\bendyradius% + \advance\pgf@y-.707106\pgf@yc% + }% + {5}{175}{\innerbendxradius and \innerbendyradius}% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@south east\endcsname}% + {\csname pgf@anchor@tape@south west\endcsname}% + \fi% + \fi% + \fi% + \else% + \pgfpointintersectionoflines{\externalpoint}{\centerpoint}% + {\csname pgf@anchor@tape@north west\endcsname}% + {\csname pgf@anchor@tape@south west\endcsname}% + \fi% + \fi% + }% +}% + + + + +% Keys for magnifying glass shape +% +% /pgf/magnifying glass handle angle : The angle of handle +% /pgf/magnifying glass handle aspect : The length of the handle as a multiple +% of the radius of the circle +% + +\pgfkeys{/pgf/.cd, + magnifying glass handle angle/.initial=-45, + magnifying glass handle aspect/.initial=1.5, +}% + +\pgfdeclareshape{magnifying glass} +{% + \inheritsavedanchors[from=circle]% this is nearly a circle + \inheritanchorborder[from=circle]% + \inheritanchor[from=circle]{north}% + \inheritanchor[from=circle]{north west}% + \inheritanchor[from=circle]{north east}% + \inheritanchor[from=circle]{center}% + \inheritanchor[from=circle]{west}% + \inheritanchor[from=circle]{east}% + \inheritanchor[from=circle]{mid}% + \inheritanchor[from=circle]{mid west}% + \inheritanchor[from=circle]{mid east}% + \inheritanchor[from=circle]{base}% + \inheritanchor[from=circle]{base west}% + \inheritanchor[from=circle]{base east}% + \inheritanchor[from=circle]{south}% + \inheritanchor[from=circle]{south west}% + \inheritanchor[from=circle]{south east}% + \inheritbackgroundpath[from=circle]% + \foregroundpath{ + \centerpoint% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgfutil@tempdima=\radius% + \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xb<\pgf@yb% + \advance\pgfutil@tempdima by-\pgf@yb% + \else% + \advance\pgfutil@tempdima by-\pgf@xb% + \fi% + \pgfpathmoveto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}} + {\pgfpointpolar{\pgfkeysvalueof{/pgf/magnifying glass handle angle}}{\pgfutil@tempdima}}} + \pgfpathlineto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}} + {\pgfpointpolar{\pgfkeysvalueof{/pgf/magnifying glass handle angle}}{\pgfutil@tempdima+\pgfutil@tempdima*(\pgfkeysvalueof{/pgf/magnifying glass handle aspect})}}} + \pgfsetarrowsstart{} + \pgfsetarrowsend{} + }% +}% + + +\pgfkeys{% + /pgf/magnetic tape tail/.initial=0.15, + /pgf/magnetic tape tail extend/.initial=0cm, +}% +\pgfdeclareshape{magnetic tape}{% + \nodeparts{text}% + \savedmacro\installparameters{% + % + \pgf@x=0.5\wd\pgfnodeparttextbox% + \pgf@y=0.5\ht\pgfnodeparttextbox% + \advance\pgf@y by-0.5\dp\pgfnodeparttextbox% + \edef\centerpoint{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + % + \pgf@x=\wd\pgfnodeparttextbox% + \pgf@y=\ht\pgfnodeparttextbox% + \advance\pgf@y by\dp\pgfnodeparttextbox% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/inner xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/inner ysep}}% + \advance\pgf@x by2.0\pgf@xa% + \advance\pgf@y by2.0\pgf@ya% + \ifdim\pgf@y>\pgf@x% + \pgf@x=\pgf@y% + \fi% + \pgf@x=1.414213\pgf@x% + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}% + \ifdim\pgf@x<\pgf@xa% + \pgf@x=\pgf@xa% + \fi% + \ifdim\pgf@x<\pgf@ya% + \pgf@x=\pgf@ya% + \fi% + \pgf@x=0.5\pgf@x% + \edef\radius{\the\pgf@x}% + % + \pgfmathparse{max(\pgfkeysvalueof{/pgf/magnetic tape tail extend},0)}% + \edef\tailextend{\pgfmathresult pt}% + % + \pgfmathparse{min(max(\pgfkeysvalueof{/pgf/magnetic tape tail},0),1)}% + \pgf@xa=\pgfmathresult\pgf@x% + \edef\tailheight{\the\pgf@xa}% + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + \ifdim\pgf@xa<\pgf@ya% + \pgf@xa=\pgf@ya% + \fi% + \edef\outersep{\the\pgf@xa}% + % + \pgfmathparse{\outersep+\radius}% + \edef\outerradius{\pgfmathresult pt}% + % + \pgfmathparse{(\radius-\tailheight)/\radius}% + \pgfmathasin@{\pgfmathresult}% + \pgfmathadd@{-\pgfmathresult}{360}% + \let\tailangle=\pgfmathresult% + % + \pgfmathparse{\outerradius/(\outerradius+\tailextend)}% + \pgfmathatan@{\pgfmathresult}% + \pgfmathadd@{-\pgfmathresult}{360}% + \let\tailbottomangle=\pgfmathresult% + % + \pgfmathparse{(\outerradius-\outersep-\tailheight-\outersep)/(\outerradius+\tailextend)}% + \pgfmathatan@{\pgfmathresult}% + \pgfmathadd@{-\pgfmathresult}{360}% + \let\tailtopangle=\pgfmathresult% + % + \addtosavedmacro\radius% + \addtosavedmacro\outerradius% + \addtosavedmacro\outersep% + \addtosavedmacro\tailheight% + \addtosavedmacro\tailextend + \addtosavedmacro\tailangle% + \addtosavedmacro\tailtopangle% + \addtosavedmacro\tailbottomangle% + \addtosavedmacro\centerpoint% + }% + \savedanchor{\base}{\pgfqpoint{0.5\wd\pgfnodeparttextbox}{0pt}}% + \savedanchor{\mid}{\pgfqpoint{0.5\wd\pgfnodeparttextbox}{0pt}\pgfmathsetlength\pgf@y{.5ex}}% + \anchor{center}{\installparameters\centerpoint}% \addtosavedmacro\outerradius% + \anchor{base}{\base}% + \anchor{mid}{\mid}% + \anchor{base west}{\installparameters\pgfpointadd{\base}{\pgfqpoint{-\outerradius}{0pt}}}% + \anchor{base east}{\installparameters\pgfpointadd{\base}{\pgfqpoint{\outerradius}{0pt}}}% + \anchor{mid west}{\installparameters\pgfpointadd{\mid}{\pgfqpoint{-\outerradius}{0pt}}}% + \anchor{mid east}{\installparameters\pgfpointadd{\mid}{\pgfqpoint{\outerradius}{0pt}}}% + \anchor{north}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpoint{0pt}{\outerradius}}}% + \anchor{north east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpointpolar{45}{\outerradius}}}% + \anchor{south}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpoint{0pt}{-\outerradius}}}% + \anchor{south east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpoint{\outerradius}{-\outerradius}}}% + \anchor{east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpoint{\outerradius}{0pt}}}% + \anchor{south west}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpointpolar{225}{\outerradius}}}% + \anchor{west}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpoint{-\outerradius}{0pt}}}% + \anchor{north west}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfqpointpolar{135}{\outerradius}}}% + \anchor{tail east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfpoint{\radius+\tailextend+\outersep}{-\outerradius+\outersep+\tailheight/2}}}% + \anchor{tail south east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfpoint{\radius+\tailextend+\outersep}{-\outerradius}}}% + \anchor{tail north east}{\installparameters% + \pgfpointadd{\centerpoint}{\pgfpoint{\radius+\tailextend+\outersep}{-\outerradius+\outersep+\tailheight+\outersep}}}% + \backgroundpath{ + % + \installparameters% + {% + \pgftransformshift{\centerpoint}% + \pgfpathmoveto{\pgfpointpolar{\tailangle}{\radius}}% + \pgfpatharc{\tailangle}{360}{\radius}% + \pgfpatharc{0}{270}{\radius}% + \pgfpathlineto{\pgfpoint{\radius+\tailextend}{-\radius}}% + \pgfpathlineto{\pgfpoint{\radius+\tailextend}{-\radius+\tailheight}}% + \pgfpathclose% + }% + }% + \anchorborder{% + \pgfextract@process\externalpoint{}% + \installparameters% + \pgfmathanglebetweenpoints{\pgfpointorigin}{\externalpoint} + \ifdim\pgfmathresult pt<270pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointborderellipse% + {\externalpoint}% + {\pgfqpoint{\outerradius}{\outerradius}}% + }% + \else% + \ifdim\pgfmathresult pt<\tailbottomangle pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointintersectionoflines% + {\externalpoint}{\pgfpointorigin}% + {\pgfqpoint{0pt}{-\outerradius}}{\pgfqpoint{\outerradius}{-\outerradius}}% + }% + \else% + \ifdim\pgfmathresult pt<\tailtopangle pt\relax% + \pgfpointadd{\centerpoint}{% + \pgfpointintersectionoflines% + {\externalpoint}{\pgfpointorigin}% + {\pgfqpoint{\outerradius}{\outerradius}}{\pgfqpoint{\outerradius}{-\outerradius}}% + }% + \else% + \pgfpointadd{\centerpoint}{% + \pgfpointborderellipse% + {\externalpoint}% + {\pgfqpoint{\outerradius}{\outerradius}}% + }% + \fi% + \fi% + \fi% + }% +}% + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/lua/pgf/manual.lua b/graphics/pgf/base/tex/generic/lua/pgf/manual.lua new file mode 100644 index 0000000000..7142eea3ec --- /dev/null +++ b/graphics/pgf/base/tex/generic/lua/pgf/manual.lua @@ -0,0 +1,18 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +local manual = {} + +require 'pgf'.manual = manual + +return manual diff --git a/graphics/pgf/base/tex/generic/lua/pgf/manual/DocumentParser.lua b/graphics/pgf/base/tex/generic/lua/pgf/manual/DocumentParser.lua new file mode 100644 index 0000000000..bd2a7026a4 --- /dev/null +++ b/graphics/pgf/base/tex/generic/lua/pgf/manual/DocumentParser.lua @@ -0,0 +1,613 @@ +-- Copyright 2013 by Till Tantau +-- +-- This file may be distributed an/or modified +-- +-- 1. under the LaTeX Project Public License and/or +-- 2. under the GNU Public License +-- +-- See the file doc/generic/pgf/licenses/LICENSE for more information + +-- @release $Header$ + + + +--- +-- This class offers functions for converting the documentation of Lua +-- and other code into \TeX. +-- +-- @field renderers This array must consist of tables having two +-- fields: |test| and |renderer|. The first must be set to a function +-- that is called with an information table as parameter and must +-- return |true| if the function stored in the |renderer| should be +-- called. (Typically, the |test| will test whether the ``head line'' +-- following a documentation block has a special form.) + +local DocumentParser = { + renderers = {} +} + +-- Namespace: +require 'pgf.manual'.DocumentParser = DocumentParser + +-- Imports +local keys = require 'pgf.gd.interface.InterfaceCore'.keys + +-- Forwards: + +local collect_infos, render_infos + + +--- +-- Includes the documentation stored in some file in the manual. +-- +-- @param filename The file from which the documentation is to be read +-- @param type The type of the file. + +function DocumentParser.include(filename, typ) + + local fullname = assert(kpse.find_file(filename:gsub("%.", "/"), typ or "lua") + or kpse.find_file(filename:gsub("%.", "\\"), typ or "lua"), + "file " .. filename .. " not found") + + local file, error = io.open(fullname) + + -- First, let us read the file into a table to make handling easier: + local lines = {} + + for line in file:lines() do + lines [#lines + 1] = line + end + + -- A table storing the current output. The array part contains TeX + -- lines, the table part contains information about special table.s + local output = {} + + -- Now, start the main parser loop. + local i = 1 + while i <= #lines do + + if lines[i]:match("^%-%-%-") then + local infos = collect_infos (lines, i) + + infos.filename = filename + + render_infos(infos, output) + + i = infos.last_line + end + + i = i + 1 + end + + -- Render output: + for _,l in ipairs(output) do + if type(l) == "string" then + tex.print(l) + else + l() + end + end + +end + + + +--- +-- Add a test and a renderer to the array of renderers. +-- +-- @param test A test function (see |DocumentParser.renderers|). +-- @param renderer A rendering function. + +function DocumentParser.addRenderer (test, renderer) + DocumentParser.renderers [#DocumentParser.renderers + 1] = + { test = test, renderer = renderer } +end + + +-- Forwards: +local print_on_output, print_on_output_escape, print_docline_on_output, open_mode, close_mode, print_lines_on_output + + + +local function strip_quotes(s) + if s then return string.gsub(s, '^"(.*)"$', "%1") end +end + +local function split(s) + local t = {} + for line in string.gmatch(s, ".-\n") do + t[#t+1] = line + end + for i=#t,1,-1 do + if t[i]:match("^%s*$") then + t[i] = nil + else + return t + end + end + return t +end + + +local function process_string(s) + if s then + local t = split(s.."\n") + -- Compute min spaces + local min = math.huge + for _,l in ipairs(t) do + min = math.min(min, string.find(l, "%S") or math.huge) + end + if min < math.huge then + -- Now, trim 'em all! + for i=1,#t do + t[i] = string.sub(t[i],min,-2) + end + end + return t + end +end + + +local function process_examples(t) + if not t then + return nil + end + + if type(t) == "string" then + t = {t} + end + + local n = {} + for i=1,#t do + local code, options + if type(t[i]) == "table" then + code = assert(t[i].code) + options = t[i].options + else + code = t[i] + end + n[i] = { + options = process_string(strip_quotes(options)), + code = process_string(strip_quotes(code)) + } + end + return n +end + + + +-- The standard renderers: + + +-- The function renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return + infos.keywords["function"] or + infos.head_line:match("^%s*function%s+") or + infos.head_line:match("^%s*local%s+function%s+") + end, + function (infos, output) + -- The renderer + + if infos.keywords["function"] then + local k = infos.keywords["function"][1] + infos.head_line = k:match("^%s*@(.*)") + end + + local rest = infos.head_line:match("function%s+(.*)") + local tab = rest:match("([^(]*[%.%:]).*") + local fun = rest:match("[^(]*[%.%:](.-)%s*%(") or rest:match("(.-)%s*%(") + local pars = rest:match(".-%((.*)%)") + + -- Render the head + print_on_output_escape(output, [[\begin{luacommand}]]) + output[#output+1] = "{" .. (tab or "") .. fun .. "}" + print_on_output_escape(output, + "{", tab or "", "}", + "{", fun, "}", + "{", pars, "}") + + if tab then + local table_name = tab:sub(1,-2) + local t = output[table_name] or {} + t[#t+1] = { + link = "pgf/lua/" .. tab .. fun, + text = "function " .. tab .. "\\declare{" .. fun .. "} (" .. pars .. ")" + } + output[table_name] = t + end + + local mode = "text" + for _,l in ipairs(infos.doc_lines) do + if mode ~= "done" then + mode = print_docline_on_output(output, l, mode) + end + end + close_mode(output, mode) + + print_on_output(output, [[\end{luacommand}]]) + + end +) + + +-- The table renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return + infos.keywords["table"] or + infos.head_line:match("=%s*{") + end, + function (infos, output) + -- The renderer + + if infos.keywords["table"] then + local k = infos.keywords["table"][1] + infos.head_line = k:match("^%s*@table(.*)") .. "=" + end + + local name = + infos.head_line:match("^%s*local%s+(.-)%s*=") or + infos.head_line:match("^%s*(.*)%s*=") + + -- Render the head + print_on_output_escape(output, + [[\begin{luatable}]], + "{", name:match("(.*[%.%:]).*") or "", "}", + "{", name:match(".*[%.%:](*-)") or name,"}", + "{", infos.filename, "}") + + local mode = "text" + for _,l in ipairs(infos.doc_lines) do + mode = print_docline_on_output(output, l, mode) + end + close_mode(output, mode) + + output[#output+1] = + function () + if output[name] then + tex.print("\\par\\emph{Alphabetical method summary:}\\par{\\small") + table.sort(output[name], function (a,b) return a.text < b.text end) + for _,l in ipairs(output[name]) do + tex.print("\\texttt{\\hyperlink{" .. l.link .. "}{" .. l.text:gsub("_", "\\_") .. "}}\\par") + end + tex.print("}") + end + end + + print_on_output(output, [[\end{luatable}]]) + + end +) + + + +-- The library renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return infos.keywords["library"] + end, + function (infos, output) + -- The renderer + + local name = infos.filename:gsub("%.library$",""):gsub("^pgf%.gd%.","") + + -- Render the head + print_on_output_escape(output, "\\begin{lualibrary}{", name, "}") + + local mode = "text" + for _,l in ipairs(infos.doc_lines) do + mode = print_docline_on_output(output, l, mode) + end + close_mode(output, mode) + + print_on_output(output, "\\end{lualibrary}") + + end +) + + +-- The section renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return infos.keywords["section"] + end, + function (infos, output) + -- The renderer + local mode = "text" + for _,l in ipairs(infos.doc_lines) do + mode = print_docline_on_output(output, l, mode) + end + close_mode(output, mode) + end +) + + +-- The documentation (plain text) renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return infos.keywords["documentation"] + end, + function (infos, output) + -- The renderer + local mode = "text" + for _,l in ipairs(infos.doc_lines) do + mode = print_docline_on_output(output, l, mode) + end + close_mode(output, mode) + end +) + + +-- The declare renderer +DocumentParser.addRenderer ( + function (infos) + -- The test + return + infos.keywords["declare"] or + infos.head_line:match("declare%s*{") or + infos.head_line:match("^%s*key%s*") + end, + function (infos, output) + -- The renderer + + local key_name + + if infos.keywords["declare"] then + local k = infos.keywords["declare"][1] + key_name = k:match("^%s*@declare%s*(.*)") + elseif infos.head_line:match("^%s*key%s*") then + key_name = infos.head_line:match('^%s*key%s*"(.*)"') or + infos.head_line:match("^%s*key%s*'(.*)'") + else + local l = infos.lines [infos.last_line + 1] + key_name = l:match('key%s*=%s*"(.*)"') or l:match("key%s*=%s*'(.*)'") + end + + assert (key_name, "could not determine key") + local key = assert (keys[key_name], "unknown key '" .. key_name .. "'") + + -- Render the head + if key.type then + print_on_output_escape(output, + "\\begin{luadeclare}", + "{", key.key, "}", + "{\\meta{", key.type, "}}", + "{", key.default or "", "}", + "{", key.initial or "", "}") + else + print_on_output_escape(output, + "\\begin{luadeclarestyle}", + "{", key.key, "}", + "{}", + "{", key.default or "", "}", + "{", key.initial or "", "}") + end + + + local mode = "text" + + print_lines_on_output(output, process_string(strip_quotes(key.summary))) + print_lines_on_output(output, process_string(strip_quotes(key.documentation))) + + if key.examples then + local e = process_examples(key.examples) + print_on_output(output, + "\\par\\smallskip\\emph{Example" .. (((#e>1) and "s") or "") .. "}\\par") + for _,example in ipairs(e) do + local opts = table.concat(example.options or {}, "") + print_on_output(output, "\\begin{codeexample}[" .. opts .. "]") + print_lines_on_output(output, example.code) + print_on_output(output, "\\end{codeexample}") + end + end + + print_on_output(output, key.type and "\\end{luadeclare}" or "\\end{luadeclarestyle}") + end +) + + + +-- The empty line +DocumentParser.addRenderer ( + function (infos) + -- The test + return + #infos.doc_lines == 1 and + infos.doc_lines[1]:match("^%-*%s*$") + end, + function (infos, output) + end +) + + +function print_lines_on_output(output, lines) + for n,l in ipairs(lines or {}) do + if (n == 1 or n == #lines) and l == "" then + -- skip leading and trailing blank lines + else + output[#output+1] = l + end + end +end + +function print_on_output(output, ...) + local args = {...} + if #args > 0 then + for i = 1, #args do + args[i] = tostring(args[i]) + end + output[#output+1] = table.concat(args) + end +end + +function print_on_output_escape(output, ...) + local args = {...} + if #args > 0 then + for i = 1, #args do + args[i] = tostring(args[i]):gsub("_", "\\_") + end + output[#output+1] = table.concat(args) + end +end + + +function print_docline_on_output(output, l, mode) + + if l:match("^%s*@section") then + print_on_output(output, "\\", l:match("%s*@section%s*(.*)")) + elseif l:match("^%s*@param%s+") then + if mode ~= "param" then + close_mode (output, mode) + mode = open_mode (output, "param") + end + print_on_output(output, "\\item[\\texttt{", + l:match("%s@param%s+(.-)%s"):gsub("_", "\\_"), + "}] ", + l:match("%s@param%s+.-%s+(.*)")) + elseif l:match("^%s*@return%s+") then + if mode ~= "return" then + close_mode (output, mode) + mode = open_mode (output, "returns") + end + print_on_output(output, "\\item[]", l:match("%s@return%s+(.*)")) + elseif l:match("^%s*@see%s+") then + if mode ~= "text" then + close_mode (output, mode) + mode = open_mode (output, "text") + end + print_on_output(output, "\\par\\emph{See also:} \\texttt{", + l:match("%s@see%s+(.*)"):gsub("_", "\\_"), + "}") + elseif l:match("^%s*@usage%s+") then + if mode ~= "text" then + close_mode (output, mode) + mode = open_mode (output, "text") + end + print_on_output(output, "\\par\\emph{Usage:} ", + l:match("%s@usage%s+(.*)")) + elseif l:match("^%s*@field+") then + close_mode (output, mode) + mode = open_mode (output, "field") + print_on_output(output, "{", + (l:match("%s@field%s+(.-)%s") or l:match("%s@field%s+(.*)")):gsub("_", "\\_"), + "}", + l:match("%s@field%s+.-%s+(.*)")) + elseif l:match("^%s*@done") or l:match("^%s*@text") then + close_mode(output, mode) + print_on_output(output, l) + + mode = "text" + elseif l:match("^%s*@library") then + -- do nothing + elseif l:match("^%s*@function") then + -- do nothing + elseif l:match("^%s*@end") then + close_mode(output, mode) + mode = "done" + elseif l:match("^%s*@") then + error("Unknown mark " .. l) + else + print_on_output(output, l) + end + + return mode +end + +function open_mode (output, mode) + if mode == "param" then + print_on_output(output, "\\begin{luaparameters}") + elseif mode == "field" then + print_on_output(output, "\\begin{luafield}") + elseif mode == "returns" then + print_on_output(output, "\\begin{luareturns}") + end + return mode +end + +function close_mode (output, mode) + if mode == "param" then + print_on_output(output, "\\end{luaparameters}") + elseif mode == "field" then + print_on_output(output, "\\end{luafield}") + elseif mode == "returns" then + print_on_output(output, "\\end{luareturns}") + end + return mode +end + + +function collect_infos (lines, i, state) + + local doc_lines = {} + + local keywords = {} + + local function find_keywords(line) + local keyword = line:match("^%s*@([^%s]*)") + if keyword then + local t = keywords[keyword] or {} + t[#t+1] = line + keywords[keyword] = t + end + return line + end + + -- Copy triple matches: + while lines[i] and lines[i]:match("^%-%-%-") do + doc_lines [#doc_lines + 1] = find_keywords(lines[i]:sub(4)) + i = i + 1 + end + + -- Continue with double matches: + while lines[i] and lines[i]:match("^%-%-") do + doc_lines [#doc_lines + 1] = find_keywords(lines[i]:sub(3)) + i = i + 1 + end + + local head_line = "" + + if not keywords["end"] then + -- Skip empty lines + while lines[i] and lines[i]:match("^%s*$") do + i = i + 1 + end + head_line = lines[i] or "" + if lines[i] and lines[i]:match("^%-%-%-") then + i = i - 1 + end + end + + return { + lines = lines, + last_line = i, + doc_lines = doc_lines, + keywords = keywords, + head_line = head_line + } + +end + + + +function render_infos(infos, state) + + for _,renderer in ipairs(DocumentParser.renderers) do + if renderer.test (infos, state) then + renderer.renderer (infos, state) + return + end + end + + pgf.debug(infos) + error("Unknown documentation type") +end + + +return DocumentParser diff --git a/graphics/pgf/base/tex/generic/math/pgfint.code.tex b/graphics/pgf/base/tex/generic/math/pgfint.code.tex new file mode 100644 index 0000000000..8921ee5fbd --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfint.code.tex @@ -0,0 +1,126 @@ +% Copyright 2019 by Henri Menke +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + +% Guard against reading twice +\ifx\pgfintloaded\pgfutil@undefined + \let\pgfintloaded=\relax +\else + \expandafter\endinput +\fi + +% This module is pretty much a rip-off of the LaTeX3 l3int module for integer +% calculations. Since PGF supports e-TeX now, we can make use of those +% extended facilities. + +% In contrast to l3int we will just admit that integers are regular TeX \count +% register and will not implement an extra "integer datatype". + +% Evaluate an integer expression using \numexpr +\def\pgfinteval#1{\number\numexpr#1\relax} + +% Get the absolute value of an integer by stripping off a leading minus sign +\def\pgfintabs#1{\number\expandafter\pgfint@abs\number\numexpr#1\relax} +\def\pgfint@abs#1{\ifx-#1\else\expandafter#1\fi} + +% Minimum and maximum +\def\pgfintmax#1#2{% + \number\expandafter\pgfint@minmax + \number\numexpr#1\expandafter;% + \number\numexpr#2;% + > +} +\def\pgfintmin#1#2{% + \number\expandafter\pgfint@minmax + \number\numexpr#1\expandafter;% + \number\numexpr#2;% + < +} +\def\pgfint@minmax#1;#2;#3{% + \ifnum#1#3#2 + #1% + \else + #2% + \fi +} + +% \numexpr has the annoying property to round divisions rather than truncating +% (as you would expect for integer arithmetic). Therefore we need a truncating +% division function. +\def\pgfintdivtruncate#1#2{% + \number\numexpr\expandafter\pgfint@divtruncate + \number\numexpr#1\expandafter;% + \number\numexpr#2;% + \relax +} +\def\pgfint@divtruncate#1#2;#3#4;{% + \ifx0#1 + 0% + \else + (#1#2% + \ifx-#1 +\else-\fi + (\ifx-#3 -\fi#3#4-1)/2% + )% + \fi + /#3#4% +} + +% \pgfintdivtruncate always truncates the result which leads to a rounding +% towards zero. Donald Knuth defines in TAoCP, Vol 1, 3rd Ed, Section 1.2.4 +% that the modulo operation is +% +% x mod y = x - y * floor(x/y) +% +% In contrast to truncated division, floored division always rounds towards +% -inf, i.e. floor(1/2) = 0 and floor(-1/2) = -1. This is also how integer +% division is done in Lua. +\def\pgfintdivfloor#1#2{% + \number\numexpr\expandafter\pgfint@divfloor + \number\numexpr#1\expandafter;% + \number\numexpr#2;% + \relax +} +\def\pgfint@divfloor#1#2;#3#4;{% + \ifx0#1 + 0% + \else + \ifnum + 0\ifx-#1\ifx#3-\else1\fi\fi + 0\ifx-#3\ifx#1-\else1\fi\fi + >0 + \pgfint@@divfloor#1#2;#3#4;-+% + \else + \pgfint@@divfloor#1#2;#3#4;+-% + \fi + \fi + /#3#4% +} +\def\pgfint@@divfloor#1#2;#3#4;#5#6{% + (#1#2% + \ifx-#1 #5\else#6\fi + (\ifx-#3 -\fi#3#4#61)/2% + )% +} + +% Round +\def\pgfintdivround#1#2{\number\numexpr(#1)/(#2)\relax} + +% Modulo +\def\pgfintmod#1#2{% + \number\numexpr\expandafter\pgfint@mod% + \number\numexpr#1\expandafter;% + \number\numexpr#2;% + \relax +} +\def\pgfint@mod#1;#2;{#1-(\pgfint@divfloor#1;#2;)*#2} + +% Setter function so we don't always have to write \pgfinteval +\def\pgfintset#1#2{#1 \numexpr#2\relax} + +\endinput diff --git a/graphics/pgf/base/tex/generic/math/pgfmath.code.tex b/graphics/pgf/base/tex/generic/math/pgfmath.code.tex new file mode 100644 index 0000000000..fd40a36d59 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmath.code.tex @@ -0,0 +1,37 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + + +% Guard against reading twice +\ifx\pgfmathloaded\pgfutil@undefined + \let\pgfmathloaded=\relax +\else + \expandafter\endinput +\fi + +% We need keys: +\ifx\pgfkeysloaded\pgfutil@undefined + \input pgfkeys.code.tex +\fi + +\input pgfmathutil.code.tex +\input pgfmathparser.code.tex +\input pgfmathfunctions.code.tex +\input pgfmathfunctions.basic.code.tex +\input pgfmathfunctions.trigonometric.code.tex +\input pgfmathfunctions.random.code.tex +\input pgfmathfunctions.comparison.code.tex +\input pgfmathfunctions.base.code.tex +\input pgfmathfunctions.round.code.tex +\input pgfmathfunctions.misc.code.tex +\input pgfmathfunctions.integerarithmetics.code.tex +\input pgfmathcalc.code.tex +\input pgfmathfloat.code.tex + +\endinput diff --git a/graphics/pgf/base/tex/generic/math/pgfmathcalc.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathcalc.code.tex new file mode 100644 index 0000000000..1e854864d8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathcalc.code.tex @@ -0,0 +1,537 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file loads all the parsing, functions and operator stuff +% +% Version 1.414213 29/9/2007 + +% \pgfmathsetlength, \pgfmathaddtolength +% +% #1 = dimension register +% #2 = expression +% +% Description: +% +% These functions work similar to \setlength and \addtolength. Only, +% they allow #2 to contain an expression, which is evaluated before +% assignment. Furthermore, the font is setup before the assignment is +% done, so that dimensions like 1em are evaluated correctly. +% +% If #2 starts with "+", then a simple assignment is done (but the +% font is still setup). This is orders of magnitude faster than a +% parsed assignment. + +\def\pgfmathsetlength#1#2{% + \expandafter\pgfmath@onquick#2\pgfmath@% + {% + % Ok, quick version: + \begingroup% + \pgfmath@selectfont% + #1#2\unskip% + \expandafter\endgroup% + \expandafter#1\the#1\relax% + }% + {% + \pgfmathparse{#2}% + \ifpgfmathmathunitsdeclared% + #1\pgfmathresult mu\relax% + \else% + #1\pgfmathresult pt\relax% + \fi% + }% + \ignorespaces% +} + +% \pgfmathaddtolength +% +% Add to #1 the result of evaluating #2. +% +% #1 - a dimension register +% #2 - an expression +% +\def\pgfmathaddtolength#1#2{% + \expandafter\pgfmath@onquick#2\pgfmath@% + {% + \begingroup% + \pgfmath@selectfont% + \advance#1#2\unskip% + \expandafter% + \endgroup% + \expandafter#1\the#1\relax% + }% + {% + \pgfmathparse{#2}% + \ifpgfmathmathunitsdeclared% + \advance#1\pgfmathresult mu\relax% + \else% + \advance#1\pgfmathresult pt\relax% + \fi% + }% + \ignorespaces% +} + +% \pgfmathsetcount +% +% Assign #1 the truncated evaluation of #2. +% +% #1 - a count register +% #2 - an expression +% +\def\pgfmathsetcount#1#2{% + \expandafter\pgfmath@onquick#2\pgfmath@% + {% + \afterassignment\pgfmath@gobbletilpgfmath@% + #1#2\relax\pgfmath@% + }% + {% + \pgfmathparse{#2}% + \afterassignment\pgfmath@gobbletilpgfmath@% + #1\pgfmathresult\relax\pgfmath@% + }% + \ignorespaces% +} + +% \pgfmathaddtocount +% +% Add to #1 the truncated evaluation of #2. +% +% #1 - a count register +% #2 - an expression +% +\def\pgfmathaddtocount#1#2{% + \expandafter\pgfmath@onquick#2\pgfmath@% + {% + \edef\pgfmath@addtocounttemp{\the#1}% + \afterassignment\pgfmath@gobbletilpgfmath@% + #1#2\relax\pgfmath@% + \advance#1\pgfmath@addtocounttemp\relax% + }% + {% + \edef\pgfmath@addtocounttemp{\the#1}% + \pgfmathparse{#2}% + \afterassignment\pgfmath@gobbletilpgfmath@% + #1\pgfmathresult\relax\pgfmath@% + \advance#1\pgfmath@addtocounttemp\relax% + }% + \ignorespaces% +} + +% \pgfmathnewcounter +% +% LaTeX style counter which also works in plain TeX. Defines +% \c@ as a count register and also defines \the. +% +% #1 the name of the counter. +% +% Example: +% +% \pgfmathnewcounter{counter} +% \pgfmathsetcounter{counter}{12} +% \thecounter (same as \the\c@counter) +% +\def\pgfmathnewcounter#1{% + \expandafter\ifx\csname c@#1\endcsname\relax% + \def\pgfmath@marshal{\csname newcount\endcsname}% Ha! Who cares about \outer? + \expandafter\pgfmath@marshal\csname c@#1\endcsname% + \expandafter\def\csname the#1\endcsname{\expandafter\the\csname c@#1\endcsname}% + \fi% +} + +% \pgfmathsetcounter +% +% Set the counter #1 to the evaluation of #2. +% +% #1 - a counter name +% #2 - an expression +% +\def\pgfmathsetcounter#1#2{% + \expandafter\pgfmathsetcount\csname c@#1\endcsname{#2}% +} + +% \pgfmathaddtocounter +% +% Add the counter #1 to the evaluation of #2. +% +% #1 - a counter name +% #2 - an expression +% +\def\pgfmathaddtocounter#1#2{% + \expandafter\pgfmathaddtocount\csname c@#1\endcsname{#2}% +} + +% \pgfmathmakecounterglobal +% +% Make the current value of a counter globally defined. +% +% #1 - a (valid) counter name. +% +\def\pgfmath@pgftext{pgf} +\def\pgfmath@tikztext{tikz} +\def\pgfmathmakecounterglobal#1{% + \pgfmath@ifundefined{c@#1}{}{% + \expandafter\pgfmath@in@\expandafter{\pgfmath@pgftext}{#1}% + \ifpgfmath@in@% + \else% + \expandafter\pgfmath@in@\expandafter{\pgfmath@tikztext}{#1}% + \ifpgfmath@in@% + \else% + \expandafter\global\csname c@#1\endcsname\csname c@#1\endcsname\relax% + \fi% + \fi% + }% +} + +% \pgfmathsetmacro +% +% \edef#1 as the result of evaluating #2. +% +% #1 - a macro +% #2 - an expression +% +\def\pgfmathsetmacro#1#2{% + \begingroup% + \pgfmathparse{#2}% + \let#1=\pgfmathresult + \pgfmath@smuggleone{#1}% + \endgroup% +} + +% \pgfmathsetlengthmacro +% +% \edef#1 as the result of evaluating #2 with pt. +% +% #1 - a macro +% #2 - an expression +% +\def\pgfmathsetlengthmacro#1#2{% + \begingroup% + \pgfmathsetlength\pgfmath@x{#2}% + \edef#1{\the\pgfmath@x}% + \pgfmath@smuggleone{#1}% + \endgroup% +} + +% \pgfmathtruncatemacro +% +% \edef#1 as the truncated result of evaluating #2. +% +% #1 - a macro +% #2 - an expression +% +\def\pgfmathtruncatemacro#1#2{% + \begingroup% + \pgfmathsetcount\c@pgfmath@counta{#2}% + \edef#1{\the\c@pgfmath@counta}% + \pgfmath@smuggleone{#1}% + \endgroup% +} + +% Check whether a given parameter starts with quick. +% +% The command should be followed by nonempty text, ending with +% \pgfmath@ as a stop-token. Then should follow +% +% #1 - code to execute if text starts with + +% #2 - code to execute if text does not +% +% Example: +% +% \pgfmath@onquick+0pt\pgfmath@{is quick}{is slow} + +\def\pgfmath@onquick{% + \futurelet\pgfmath@next% + \pgfmath@@onquick} +\def\pgfmath@@onquick#1\pgfmath@{% + \ifx\pgfmath@next+% + \let\pgfmath@next=\pgfmath@firstoftwo% + \else% + \let\pgfmath@next=\pgfmath@secondoftwo% + \fi% + \pgfmath@next% +} + +% *** The following commands DO NOT WORK without the rest of PGF *** +% +% (a dumping ground for stuff that doesn't really belong anywhere else) + +% \pgfmathanglebetweenpoints +% +% Define \pgfmathresult as the angle between points #1 and #2 +% Should get the quadrants right as well. +% +\def\pgfmathanglebetweenpoints#1#2{% + \begingroup% + \pgf@process{\pgfpointdiff{#1}{#2}}% + \edef\pgf@marshall{\expandafter\noexpand\csname pgfmathatan2@\endcsname{\expandafter\Pgf@geT\the\pgf@y}{\expandafter\Pgf@geT\the\pgf@x}}% + \pgf@marshall% + \ifdim\pgfmathresult pt<0pt% + \pgfmathparse{\pgfmathresult+360}% + \fi% + \expandafter% + \endgroup\expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult}% +} + +% +% \pgfmathrotatepointaround +% +% Rotate point #1 about point #2 by #3 degrees. +% +\def\pgfmathrotatepointaround#1#2#3{% + \pgf@process{% + \pgf@process{#1}% + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgf@process{#2}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgf@xb\pgf@x% + \pgf@yb\pgf@y% + \pgf@x=\pgf@xc% + \pgf@y=\pgf@yc% + \advance\pgf@x-\pgf@xa% + \advance\pgf@y-\pgf@ya% + \pgfmathsetmacro\angle{#3}% + \pgfmathsin@{\angle}% + \let\sineangle\pgfmathresult% + \pgfmathcos@{\angle}% + \let\cosineangle\pgfmathresult% + \pgf@xa\cosineangle\pgf@x% + \advance\pgf@xa-\sineangle\pgf@y% + \pgf@ya\sineangle\pgf@x% + \advance\pgf@ya\cosineangle\pgf@y% + \pgf@x\pgf@xb% + \pgf@y\pgf@yb% + \advance\pgf@x\pgf@xa% + \advance\pgf@y\pgf@ya% + }% +} + +% \pgfmathanglebetweenlines +% +% Calculate the clockwise angle between a line from point #1 +% to point #2 and a line from #3 to point #4. +% +\def\pgfmathanglebetweenlines#1#2#3#4{% + \begingroup% + \pgfmathanglebetweenpoints{#1}{#2}% + \let\firstangle\pgfmathresult% + \pgfmathanglebetweenpoints{#3}{#4}% + \let\secondangle\pgfmathresult% + \ifdim\firstangle pt>\secondangle pt\relax% + \pgfmathadd@{\secondangle}{360}% + \let\secondangle\pgfmathresult% + \fi% + \pgfmathsubtract@{\secondangle}{\firstangle}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% \pgfmathpointreflectalongaxis +% +% Reflects point #1 around an axis centered on #2 at an angle #3. +% +\def\pgfmathreflectpointalongaxis#1#2#3{% + \pgf@process{% + \pgfmathanglebetweenpoints{#2}{#1}% + \pgfmath@tempdima\pgfmathresult pt\relax% + \pgfmathparse{#3}% + \advance\pgfmath@tempdima-\pgfmathresult pt\relax% + \pgfmath@tempdima-2.0\pgfmath@tempdima% + \pgfmathrotatepointaround{#1}{#2}{\pgfmath@tonumber{\pgfmath@tempdima}}% + }% +} + + + +% \pgfmathpointintersectionoflineandarc +% +% A bit experimental at the moment: +% +% Locates the point where a line crosses an eliptical arc. If the line +% does not cross the arc, a meaningless point will result. +% +% #1 the point of the line on the "convex" side of the arc. +% #2 the point of the line on the "concave" side of the arc. +% #3 the center of the eliptical arc. +% #4 start angle of the arc. +% #5 end angle of the arc. +% #6 radii of the arc. +% +\def\pgfmathpointintersectionoflineandarc#1#2#3#4#5#6{% + \pgf@process{% + % + % Get the required angle. + % + \pgfmathanglebetweenpoints{#2}{#1}% + \let\x\pgfmathresult% + % + % Get the radii of the arc. + % + \pgfmath@in@{and }{#6}% + \ifpgfmath@in@% + \pgf@polar@#6\@@% + \else% + \pgf@polar@#6 and #6\@@% + \fi% + \edef\xarcradius{\the\pgf@x}% + \edef\yarcradius{\the\pgf@y}% + % + % Get the start and end angles of the arc... + % + \pgfmathsetmacro\s{#4}% + \pgfmathsetmacro\e{#5}% + % + % ...and also with rounding. + % + \pgfmathmod@{\s}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\ss\pgfmathresult% + \pgfmathmod@{\e}{360}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathadd@{\pgfmathresult}{360}% + \fi% + \let\ee\pgfmathresult% + % + % Hackery for when arc straddles zero. + % + \ifdim\ee pt<\ss pt\relax% + \pgfmathadd@{\x}{180}% + \pgfmathmod@{\pgfmathresult}{360}% + \let\x\pgfmathresult% + \fi% + \def\m{360}% Measure of nearness. + \pgfmathadd@{\s}{\e}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\n\pgfmathresult% The best estimate (default to middle of arc). + \pgfmathloop% + \pgfmathadd@{\s}{\e}% + \pgfmathdivide@{\pgfmathresult}{2}% + \let\p\pgfmathresult% + \ifdim\p pt=\s pt\relax% + \else% + \pgfmathanglebetweenpoints{#2}{% + \pgfpointadd{#3}{% + \pgf@x\xarcradius\relax% + \pgfmathcos@{\p}% + \pgf@x\pgfmathresult\pgf@x% + \pgf@y\yarcradius\relax% + \pgfmathsin@{\p}% + \pgf@y\pgfmathresult\pgf@y% + }% + }% + % + % Hackery for when arc straddles zero. + % + \ifdim\ee pt<\ss pt\relax% + \pgfmathadd@{\pgfmathresult}{180}% + \pgfmathmod@{\pgfmathresult}{360}% + \fi% + \let\q\pgfmathresult% + % + % More hackery... + % + \ifdim\x pt>335pt\relax% + \ifdim\q pt<45pt\relax% + \pgfmathadd@{\q}{360}% + \let\q\pgfmathresult% + \fi% + \fi% + \ifdim\x pt=\q pt% Found it! + \pgfmathbreakloop% Breaks after current iteration is complete. + \else + \ifdim\x pt<\q pt\relax% + \let\e\p% + \else% + \let\s\p% + \fi% + \fi% + \pgfmathsubtract@{\x}{\q}% + \pgfmathabs@{\pgfmathresult}% + % + % Save the estimate if it is better than any previous estimate. + % + \ifdim\pgfmathresult pt<\m pt\relax% + \let\m\pgfmathresult% + \let\n\p% + \fi% + \repeatpgfmathloop% + \pgfpointadd{#3}{\pgfpointpolar{\n}{\xarcradius and \yarcradius}}% + }% +} + +% \pgfmathangleonellipse +% +% Find the angle corresponding to a point on the border of an ellispe. +% +% #1 - the point on the border. +% #2 - the radii of the ellipse. +% +\def\pgfmathangleonellipse#1#2{% + \begingroup% + \pgfmath@in@{and }{#2}% + \ifpgfmath@in@% + \pgf@polar@#2\@@% + \else% + \pgf@polar@#2 and #2\@@% + \fi% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgf@process{#1}% + \ifdim\pgf@x=0pt\relax% + \pgfutil@tempdima1pt\relax% + \else% + \pgfutil@tempdima\pgf@x% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgfutil@tempdima}}% + \pgfutil@tempdima\pgfmathresult pt\relax% + \fi% + \ifdim\pgf@y=0pt\relax% + \pgfutil@tempdima1pt\relax% + \else% + \pgfmathdivide@{\pgfmath@tonumber{\pgf@y}}{\pgfmath@tonumber{\pgf@ya}}% + \pgfutil@tempdima\pgfmathresult\pgfutil@tempdima% + \pgfmathatan@{\pgfmath@tonumber{\pgfutil@tempdima}}% + \fi% + % + \pgfutil@tempdima\pgfmathresult pt\relax% + \ifdim\pgfutil@tempdima<0pt\relax% + \advance\pgfutil@tempdima360pt\relax% + \fi% + \ifdim\pgf@x<0pt\relax% + \ifdim\pgf@y=0pt\relax% + \pgfutil@tempdima180pt\relax% + \else% + \ifdim\pgf@y<0pt\relax% + \advance\pgfutil@tempdima180pt\relax% + \else% + \advance\pgfutil@tempdima-180pt\relax% + \fi% + \fi% + \else% + \ifdim\pgf@x=0pt\relax% + \ifdim\pgf@y<0pt\relax% + \pgfutil@tempdima270pt\relax% + \else% + \pgfutil@tempdima90pt\relax% + \fi% + \else% + \ifdim\pgf@y=0pt\relax% + \pgfutil@tempdima0pt\relax% + \fi% + \fi% + \fi% + \pgfmath@returnone\pgfutil@tempdima% + \endgroup% +} + + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfloat.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfloat.code.tex new file mode 100644 index 0000000000..f133c6d495 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfloat.code.tex @@ -0,0 +1,2669 @@ +% Copyright 2019 by Christian Feuersaenger +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. +% +% This file contains methods for basic floating point arithmetics, rounding +% to arbitrary precision and number pretty printing. +% + + +\pgfkeys{ + % The bug 3430171 (wrong minus sign spacing in pgfmathprintnumber) + % has been fixed in 2.10 CVS. Since it changes the spacing, its + % effects can be undone with this compatibility switch. + /pgf/compat/number printer/.is choice, + /pgf/compat/number printer/2.10/.code={% + \def\pgfmathprintnumber@begingroup{\bgroup}% + \def\pgfmathprintnumber@endgroup{\egroup}% + }, + % I do not know the version number of the next release at this + % time. Please be so kind and KEEP THIS NAME INTACT. Add an alias + % if needed. + /pgf/compat/number printer/next after 2.10/.code={% + \def\pgfmathprintnumber@begingroup{\begingroup}% + \def\pgfmathprintnumber@endgroup{\endgroup}% + }, + % activate the fix by default. + /pgf/compat/number printer/next after 2.10,% +} + + +\newif\ifpgfmathfloatcomparison +\newif\ifpgfmathfloatroundhasperiod +\newif\ifpgfmathprintnumberskipzeroperiod + + +% used internally in grouped macros: +\toksdef\pgfmathfloat@tmptoks=1 +\newif\ifpgfmathfloat@fixed@digits@after@period +\newif\ifpgfmathfloatroundmayneedrenormalize +\toksdef\pgfmathfloat@a@Mtok=0 + +%% WARNING: avoid conflicting register names! +\let\pgfmathfloat@a@S=\c@pgf@counta +\let\pgfmathfloat@a@M=\pgf@xa +\let\pgfmathfloat@a@E=\c@pgf@countb +\let\pgfmathfloat@b@S=\c@pgf@countc +\let\pgfmathfloat@b@M=\pgf@xb +\let\pgfmathfloat@b@E=\c@pgf@countd + +% can be changed with options. +\def\pgfmathfloat@round@precision{2} + +% I introduced this to access the "original" precision in case a +% formatted changes it locally... in this case, the formatter may +% overwrite \pgfmathfloat@round@precision@orig to provide the original +% one. +% The default implementation here does nothing: +\def\pgfmathfloat@round@precision@orig{\pgfmathfloat@round@precision}% + +\gdef\pgfmathfloat@glob@TMP{} + + +% Computes a normalised floating point representation for #1 of the +% form +% [FLAGS] MANTISSE EXPONENT +% meaning +% [+-]X.XXXXXXX*10^C +% where +% X.XXXXXX is a mantissa with first number != 0, C is an integer and +% FLAGS contains the sign and some other special cases. +% +% This method does NOT use TeX Registers to represent the numbers! The +% computation is COMPLETELY STRING BASED. +% This allows numbers such at 10000000 or 5.23e-10 to be represented +% properly, although TeX-registers would produce overflow/underflow +% errors in these cases. +% +% It is to be used to compute logs, because log(X*10^Y) = log(X) + log(10)*Y +% +% Arguments: +% #1: an arbitrary number which shall be parsed. Maybe a macro. +% Examples: +% [+-]XXXXX.XXXXXX +% [+-]XXXXX.XXXXXXeXXXX +% [+-]0.0000XXXXXX +% [+-]0.0000XXXXXXeXXXX +% [+-]inf +% nan +% Maybe a macro containing such a number. +% +% Return value: +% \pgfmathresult will be \def'ed to +% FLAGS MANTISSE 'e' EXPONENT +% where +% FLAGS is a number in [0-5] where +% 0 == '0' (the number is +- 0.0), +% 1 == '+', +% 2 == '-', +% 3 == 'not a number' +% 4 == '+ infinity' +% 5 == '- infinity' +% +% MANTISSE is a normalised number 1 <= M < 10. It always contains a +% period and at least one digit after the period. +% +% EXPONENT is an integer value. +% +% Example: +% \pgfmathfloatparsenumber{1} +% -> \pgfmathresult = 11.0e0 +% \pgfmathfloatparsenumber{141.212} +% -> \pgfmathresult = 11.41212e2 +\def\pgfmathfloatparsenumber#1{% + \begingroup + \edef\pgfmathresult{#1}% + \expandafter\pgfflt@impl\pgfmathresult\pgfflt@EOI + \ifpgfmathfloatparsenumberpendingperiod + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok.0}% + \fi + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +% The same as \pgfmathfloatparsenumber, but does not perform sanity checking. +% FIXME: there is no longer any difference here. +\let\pgfmathfloatqparsenumber=\pgfmathfloatparsenumber + +% Takes a floating point number #1 as input and writes flags to count +% register #2, mantissa to dimen register #3 and exponent to count +% register #4. +\def\pgfmathfloattoregisters#1#2#3#4{% + \expandafter\pgfmathfloat@decompose#1\relax{#2}{#3}{#4}% +} + +% the same, but writes the mantissa into a token register. +\def\pgfmathfloattoregisterstok#1#2#3#4{% + \expandafter\pgfmathfloat@decompose@tok#1\relax{#2}{#3}{#4}% +} + +% Extracts the flags of #1 into the count register #2. +\def\pgfmathfloatgetflags#1#2{% + \expandafter\pgfmathfloat@decompose@F#1\relax{#2}% +} +% Extracts the flags of #1 into the macro #2. +\def\pgfmathfloatgetflagstomacro#1#2{% + \expandafter\pgfmathfloat@decompose@Fmacro#1\relax{#2}% +}% + +% Extracts the mantissa of #1 into the dimen register #2. +\def\pgfmathfloatgetmantissa#1#2{% + \expandafter\pgfmathfloat@decompose@M#1\relax{#2}% +} +\let\pgfmathfloatgetmantisse=\pgfmathfloatgetmantissa +% Extracts the mantissa of #1 into the token register #2. +\def\pgfmathfloatgetmantissatok#1#2{% + \expandafter\pgfmathfloat@decompose@Mtok#1\relax{#2}% +} +\let\pgfmathfloatgetmantissetok=\pgfmathfloatgetmantissatok +% Extracts the exponent of #1 into the count register #2. +\def\pgfmathfloatgetexponent#1#2{% + \expandafter\pgfmathfloat@decompose@E#1\relax{#2}% +} + + +% Assigns \pgfmathresult to be a float encoded as +% e +% +% example: +% \pgfmathfloatcreate{1}{2.0}{10} +% \pgfmathfloat@to@FMeE@style\pgfmathresult +% -> +% \pgfmathresult is now '12.0e10' regardless of the internal float +% format. +\def\pgfmathfloat@to@FMeE@style#1{\expandafter\pgfmathfloat@to@FMeE@style@#1\relax\relax}% +\def\pgfmathfloat@to@FMeE@style@#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@to@FMeE@style@@% + \else + \expandafter\pgfmathfloat@to@FMeE@style@error% + \fi + #1#2% +}% +\def\pgfmathfloat@to@FMeE@style@@#1Y#2e#3]\relax\relax{\def\pgfmathresult{#1#2e#3}}% +\def\pgfmathfloat@to@FMeE@style@error#1\relax\relax{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{% + \noexpand\pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + }% + \endgroup + \pgfmathfloat@decompose@TMP +}% + + +% decomposes a lowlevel floating point representation into flags, +% mantissa and exponent. +% +% #4: integer register for the flags. +% #5: dimen registers for the mantissa. +% #6: integer register for the exponent. +% +% \expandafter\pgfmathfloat@decompose\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@M\pgfmathfloat@a@E +% -> the three temp registers contain flags, mantissa and exponent +\def\pgfmathfloat@decompose#1#2{% sanitize! + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@% + \else + \expandafter\pgfmathfloat@decompose@error% + \fi + #1#2% +} +\def\pgfmathfloat@decompose@#1Y#2e#3]\relax#4#5#6{% + #4=#1\relax + #5=#2pt % keep space here. + #6=#3\relax% +} + +% overloaded, #5 needs to be a token register for the mantissa. +% @see also \pgfmathfloatvalueof which does also employ the load +% level repr. +% \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E +% -> the three temp registers contain flags, mantissa and exponent +\def\pgfmathfloat@decompose@tok#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@tok@% + \else + \expandafter\pgfmathfloat@decompose@tok@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@tok@#1Y#2e#3]\relax#4#5#6{% + #4=#1\relax + #5={#2}% + #6=#3\relax% +} +% overloaded, returns only ONE of the three components into #4: +% \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S +% -> \pgfmathfloat@a@S contains the flags field. +\def\pgfmathfloat@decompose@F#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@F@% + \else + \expandafter\pgfmathfloat@decompose@F@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@Fmacro#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@Fmacro@% + \else + \expandafter\pgfmathfloat@decompose@F@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@M#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@M@% + \else + \expandafter\pgfmathfloat@decompose@M@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@E#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@E@% + \else + \expandafter\pgfmathfloat@decompose@E@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@Mtok#1#2{% + \ifx#2Y% + \expandafter\pgfmathfloat@decompose@Mtok@% + \else + \expandafter\pgfmathfloat@decompose@Mtok@error% + \fi + #1#2% +}% +\def\pgfmathfloat@decompose@F@#1Y#2e#3]\relax#4{#4=#1\relax}% +\def\pgfmathfloat@decompose@Fmacro@#1Y#2e#3]\relax#4{\def#4{#1}}% +\def\pgfmathfloat@decompose@M@#1Y#2e#3]\relax#4{#4=#2pt}% +\def\pgfmathfloat@decompose@Mtok@#1Y#2e#3]\relax#4{#4={#2}}% +\def\pgfmathfloat@decompose@E@#1Y#2e#3]\relax#4{#4=#3\relax}% + +\def\pgfmathfloat@decompose@error#1\relax#2#3#4{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{% + \noexpand#2=\the\pgfmathfloat@a@S\space + \noexpand#3=\the\pgfmathfloat@a@Mtok pt + \noexpand#4=\the\pgfmathfloat@a@E\space + }% + \endgroup + \pgfmathfloat@decompose@TMP +}% +\def\pgfmathfloat@decompose@tok@error#1\relax#2#3#4{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{% + \noexpand#2=\the\pgfmathfloat@a@S\space + \noexpand#3={\the\pgfmathfloat@a@Mtok}% + \noexpand#4=\the\pgfmathfloat@a@E\space + }% + \endgroup + \pgfmathfloat@decompose@TMP +}% +\def\pgfmathfloat@decompose@F@error#1\relax#2{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{\noexpand#2=\the\pgfmathfloat@a@S\space}% + \endgroup + \pgfmathfloat@decompose@TMP +}% +\def\pgfmathfloat@decompose@M@error#1\relax#2{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{\noexpand#2=\the\pgfmathfloat@a@Mtok pt }% + \endgroup + \pgfmathfloat@decompose@TMP +}% +\def\pgfmathfloat@decompose@Mtok@error#1\relax#2{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{\noexpand#2={\the\pgfmathfloat@a@Mtok}}% + \endgroup + \pgfmathfloat@decompose@TMP +}% +\def\pgfmathfloat@decompose@E@error#1\relax#2{% + \begingroup + \pgfmathfloatparsenumber@handleerror{wrong lowlevel format}{#1}{#1}% + \xdef\pgfmathfloat@decompose@TMP{\noexpand#2=\the\pgfmathfloat@a@E\space}% + \endgroup + \pgfmathfloat@decompose@TMP +}% +% Takes a floating point number #1 as input and writes flags to macro +% #2, mantissa to macro #3 and exponent to macro #4. +\def\pgfmathfloattomacro#1#2#3#4{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \xdef\pgfmathfloat@glob@TMP{% + \noexpand\def\noexpand#2{\the\pgfmathfloat@a@S}% + \noexpand\def\noexpand#3{\the\pgfmathfloat@a@Mtok}% + \noexpand\def\noexpand#4{\the\pgfmathfloat@a@E}% + }% + \endgroup + \pgfmathfloat@glob@TMP +} + + +% Defines \pgfmathresult as the floating point number encoded by +% the flags #1, mantissa #2 and exponent #3. +% +% All arguments are characters and will be expanded using '\edef'. +\def\pgfmathfloatcreate#1#2#3{% + \edef\pgfmathresult{#1Y#2e#3]}% +}% +% This is the character present in any low-level floating point +% number. It is assumed to be the SECOND character of a float (after +% the flags integer). +\def\pgfmathfloat@POSTFLAGSCHAR{Y} + + + +% Converts a composed floating point representation to fixed point. +% +% Example: +% \pgfmathfloattofixed{142e1} +% -> \pgfmathresult = 42.0 +\def\pgfmathfloattofixed@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S + \def\pgfmathresult{0.0}% + \or + \expandafter\pgfmathfloattofixed@impl\the\pgfmathfloat@a@Mtok\relax + \or + \expandafter\pgfmathfloattofixed@impl\the\pgfmathfloat@a@Mtok\relax + \pgfmathfloat@a@Mtok=\expandafter{\pgfmathresult}% + \edef\pgfmathresult{-\the\pgfmathfloat@a@Mtok}% + \or\def\pgfmathresult{nan}% + \or\def\pgfmathresult{inf}% + \or\def\pgfmathresult{-inf}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} +\let\pgfmathfloattofixed=\pgfmathfloattofixed@ + +% Converts a float to an integer (in integer format). +% +% @see \pgfmathfloatint +\def\pgfmathfloattoint#1{% + \pgfmathfloattofixed{#1}% + \expandafter\pgfmathfloattoint@@\pgfmathresult\relax +}% +\def\pgfmathfloattoint@@#1.#2\relax{% + \def\pgfmathresult{#1}% +}% + +% Converts a floating point number to scientific format 1.234e5. +% +% This operation is very fast. +\def\pgfmathfloattosci@#1{% + \begingroup + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifcase\pgfmathfloat@a@S + \def\pgfmathresult{0.0e0}% + \or + \edef\pgfmathresult{\the\pgfmathfloat@a@Mtok e\the\pgfmathfloat@a@E}% + \or + \edef\pgfmathresult{-\the\pgfmathfloat@a@Mtok e\the\pgfmathfloat@a@E}% + \or\def\pgfmathresult{nan}% + \or\def\pgfmathresult{inf}% + \or\def\pgfmathresult{-inf}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\let\pgfmathfloattosci=\pgfmathfloattosci@ + +% Expands a floating point number to scientific format 1.234e5. +% +% This operation is very fast. +\def\pgfmathfloatvalueof#1{\expandafter\pgfmathfloatvalueof@@#1@@}% + +% Make it fool proof such that the following arguments work: +% \pgfmathfloatvalueof{1Y1.0e1} -> 1.0e1 +% \pgfmathfloatvalueof{2Y1.0e1} -> -1.0e1 +% and wrong arguments as well: +% \pgfmathfloatvalueof{1} -> 1 +% \pgfmathfloatvalueof{1e2} -> 1e2 +\def\pgfmathfloatvalueof@@#1#2{% + \if#2Y% + % keep in mind that \pgfmathfloatvalueof should be expandable! + % We must not use \let here. Let's hope that #1 and #2 are + % single tokens (not something which was enclosed by curly + % braces...) + \expandafter\pgfmathfloatvalueof@@@\expandafter#1\expandafter#2% + \else + % Oh - no float!? Ok, we cannot report errors in this context. + % So: make it a feature and return the input argument as-is. + % Might be useful, in fact... + \expandafter\pgfmathfloatvalueof@abort\expandafter#1\expandafter#2% + \fi +} +\def\pgfmathfloatvalueof@@@#1Y#2e#3]@@{% + \ifcase#1 % + 0.0e0% + \or + #2e#3% + \or + -#2e#3% + \or nan% + \or inf% + \or -inf% + \fi +}% +\def\pgfmathfloatvalueof@abort#1@@{#1}% + + + +% Rounds a fixed point number #1 to \pgfmathfloat@round@precision digits precision and returns +% the result into \pgfmathresult. +% +% Any trailing zeros after the period are discarded. +% See \pgfmathroundtozerofill if you want trailing zeros and fixed +% width. +% +% This method is PURELY text based and can work with arbitrary +% precision (well, limited to TeX's stack size and integer size). +% +% Examples: +% \pgfmathroundto{1} +% -> \pgfmathresult = '1' +% +% \pgfmathroundto{19999.9996} +% -> \pgfmathresult = '20000' +% +% Arguments: +% #1 may be either a number or a macro (\pgfmathresult is allowed) expanding to a number. +% +% SIDE EFFECT: the global variable \ifpgfmathfloatroundhasperiod will be set. +\def\pgfmathroundto#1{% + \pgfmathfloatroundhasperiodtrue + \begingroup + \pgfmathfloat@fixed@digits@after@periodfalse + \pgfmathroundto@impl{#1}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + + +% Overloaded method. +% +% This variant always uses a FIXED number behind the period and fills +% in zeros if necessary. +% Examples: +% \pgfmathroundtozerofill{1} +% -> \pgfmathresult = '1.00' +% +% \pgfmathroundtozerofill{19999.9996} +% -> \pgfmathresult = '20000.00' +% +% SIDE EFFECT: the global variable \ifpgfmathfloatroundhasperiod will be set. +\def\pgfmathroundtozerofill#1{% + \pgfmathfloatroundhasperiodtrue + \begingroup + \pgfmathfloat@fixed@digits@after@periodtrue + \pgfmathroundto@impl{#1}% + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +% see \pgfmathprintnumber@fixed@style for docs +\def\pgfmathprintnumber@fixed@styleDEFAULT#1#2#3e#4\relax{% + \begingroup + \pgfkeysgetvalue{/pgf/number format/set decimal separator}\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP + \pgfkeysgetvalue{/pgf/number format/@dec sep mark}\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP@MARK + \pgfkeysgetvalue{/pgf/number format/set thousands separator}\pgfmathprintnumber@fixed@styleDEFAULT@THOUSAND@SEP + \c@pgf@counta=#4\relax % it is the exponent here. + \ifnum#2=0 + \c@pgf@counta=0 + \fi + \def\pgfmathresult{}% + \ifpgfmathfloatroundhasperiod + \expandafter\pgfmathprintnumber@fixed@styleDEFAULT@impl@period#1\pgfmathfloat@EOI + \else + \expandafter\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod#1\pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI% + \begingroup + \toks0=\expandafter{\pgfmathresult}% + \toks1=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP@MARK}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 }% + \endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@period#1.#2\pgfmathfloat@EOI{% + \ifpgfmathprintnumberskipzeroperiod + \def\pgfmathfloat@loc@TMPb{#1}% + \ifx\pgfmathfloatparsenumber@tok@ZERO\pgfmathfloat@loc@TMPb + \else + \def\pgfmathfloat@loc@TMPc{-0}% + \ifx\pgfmathfloat@loc@TMPc\pgfmathfloat@loc@TMPb + \def\pgfmathresult{-}% + \else + \def\pgfmathfloat@loc@TMPc{+0}% + \ifx\pgfmathfloat@loc@TMPc\pgfmathfloat@loc@TMPb + \def\pgfmathresult{+}% + \else + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod#1\pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI + \fi + \fi + \fi + \else + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod#1\pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI + \fi + \ifpgfmathprintnumber@thousand@sep@in@fractional + \let\pgfmathresultfractional\pgfutil@empty% + \pgfmathprintnumber@thousand@sep@in@fractional#2MMMM\@@ + \else + \def\pgfmathresultfractional{#2}% + \fi + \begingroup + \toks0=\expandafter{\pgfmathresult}% + \toks1=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP@MARK}% + \toks2=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP}% + \toks3=\expandafter{\pgfmathresultfractional}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 \the\toks2 \the\toks3 }% + \endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP +}% + +% assigns \pgfmathresult such that it contains the formatted result. +% It assumes that none of the following tokens contains a period. +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod{% + \ifx\pgfmathprintnumber@fixed@styleDEFAULT@THOUSAND@SEP\pgfutil@empty + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall}% + \else + \ifnum\c@pgf@counta<0\relax % exponent of the number in this context + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall}% + \else + \ifnum\c@pgf@counta<\pgfkeysvalueof{/pgf/number format/min exponent for 1000 sep}\relax + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall}% + \else + \advance\c@pgf@counta by1 % counta:= total number of digits, N. + \c@pgf@countb=\c@pgf@counta + \divide\c@pgf@countb by3 % countb := N DIV 3 + \c@pgf@countc=\c@pgf@countb + \multiply\c@pgf@countc by3 + \advance\c@pgf@counta by-\c@pgf@countc% now counta := N MOD 3 + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printsign + }% + \fi + \fi + \fi + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT +} +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printsign#1{% + \def\pgfmathfloat@loc@TMPb{#1}% + \ifx\pgfmathfloat@loc@TMPb\pgfmathfloatparsenumber@tok@MINUS + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1}% + \let\pgfmathfloat@loc@TMPb=\pgfutil@empty + \else + \ifx\pgfmathfloat@loc@TMPb\pgfmathfloatparsenumber@tok@PLUS + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1}% + \let\pgfmathfloat@loc@TMPb=\pgfutil@empty + \else + \ifpgfmathprintnumber@showpositive + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult +}% + \fi + \fi + \fi + \ifnum\c@pgf@counta>0 % \c@pgf@counta = N MOD 3 in this context + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \expandafter\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printtrailingdigits\pgfmathfloat@loc@TMPb + }% + \else + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \expandafter\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@counteverythird\pgfmathfloat@loc@TMPb + }% + \fi + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT +} +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printtrailingdigits#1#2{% + \ifcase\c@pgf@counta % = N MOD 3 in this context + % does not happen per construction + \or + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1}% + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@counteverythird#2% + }% + \or + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1#2}% + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@counteverythird% + }% + \fi + \ifnum\c@pgf@countb>0\relax % \c@pgf@countb = N DIV 3 in this context + \begingroup + \toks0=\expandafter{\pgfmathresult}% + \toks1=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@THOUSAND@SEP}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 }% + \endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP + \fi + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT +} +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@counteverythird#1#2#3{% + \ifnum\c@pgf@countb>0\relax + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1#2#3}% + \advance\c@pgf@countb by-1 + \ifnum\c@pgf@countb>0\relax + \begingroup + \toks0=\expandafter{\pgfmathresult}% + \toks1=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@THOUSAND@SEP}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 }% + \endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP + \fi + \def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT{% + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@counteverythird% + }% + \else + % in this case, #1#2#3 are expected to be + % \pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI + %-------------------------------------------------- + % \def\pgfmathfloat@loc@TMPb{\pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI}% + % \def\pgfmathfloat@loc@TMPc{#1#2#3}% + % \ifx\pgfmathfloat@loc@TMPc\pgfmathfloat@loc@TMPb + % \else + % \pgfmath@error{INTERNAL ERROR in fixed style - The input sequence did not terminate as expected; which indicates a wrong exponent argument provided to \string\pgfmathprintnumber@fixed@style}{}% + % \fi + %-------------------------------------------------- + \let\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT=\relax + \fi + \pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@NEXT +} + +% \pgfmathprintnumber@thousand@sep@in@fractional 01234525MMMM\@@ +% -> +% 01234525 +\def\pgfmathprintnumber@thousand@sep@in@fractional#1#2#3#4{% + \if#4M% + % Ok, no further separator + \def\pgfmathprint@next{\pgfmathprintnumber@thousand@sep@in@fractional@finish#1#2#3#4}% + \else + \begingroup + \toks0=\expandafter{\pgfmathresultfractional}% + \toks1={#1#2#3}% + \toks2=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@THOUSAND@SEP}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 \the\toks2 }% + \endgroup + \let\pgfmathresultfractional=\pgfmathfloat@glob@TMP + \def\pgfmathprint@next{\pgfmathprintnumber@thousand@sep@in@fractional#4}% + \fi + \pgfmathprint@next +}% +\def\pgfmathprintnumber@thousand@sep@in@fractional@finish#1M{% + \expandafter\def\expandafter\pgfmathresultfractional\expandafter{\pgfmathresultfractional #1}% + \pgfmathprintnumber@thousand@sep@in@fractional@finish@ +}% +\def\pgfmathprintnumber@thousand@sep@in@fractional@finish@#1\@@{}% + +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall#1{% + \def\pgfmathfloat@loc@TMPb{#1}% + \let\pgfmathfloat@loc@TMPc=\pgfutil@empty + \ifx\pgfmathfloat@loc@TMPb\pgfmathfloatparsenumber@tok@MINUS + \else + \ifx\pgfmathfloat@loc@TMPb\pgfmathfloatparsenumber@tok@PLUS + \else + \ifpgfmathprintnumber@showpositive + \def\pgfmathfloat@loc@TMPc{+}% + \fi + \fi + \fi + \expandafter\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall@\pgfmathfloat@loc@TMPc#1% +} +\def\pgfmathprintnumber@fixed@styleDEFAULT@impl@noperiod@printall@#1\pgfmathfloat@EOI\pgfmathfloat@EOI\pgfmathfloat@EOI{% + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult #1}% +}% + +% @deprecated. It has been replaced by \pgfmathprintnumber@fixed@styleDEFAULT +% #1 maybe a macro +\def\pgfmathprintnumber@fixed@stylePERIOD#1#2#3e#4\relax{% + \def\pgfmathresult{#1}% +} + +% @deprecated. It has been replaced by \pgfmathprintnumber@fixed@styleDEFAULT +% #1 maybe a macro +\def\pgfmathprintnumber@fixed@styleCOMMA#1#2#3e#4\relax{% + \ifpgfmathfloatroundhasperiod + \expandafter\pgfmathprintnumber@fixed@styleCOMMA@impl#1\pgfmathfloat@EOI + \else + \def\pgfmathresult{#1}% + \fi +} +\def\pgfmathprintnumber@fixed@styleCOMMA@impl#1.#2\pgfmathfloat@EOI{\def\pgfmathresult{#1{,}#2}} + +% The default style to display fixed point numbers. +% +% It does not apply numerics, but it is responsible for typesetting the +% rounded number. +% It can access the \ifpgfmathfloatroundhasperiod boolean. +% +% Arguments: +% #1#2#3e#4\relax + +% Input: +% #1 the fixed point number to be displayed (maybe a macro). +% #2#3e#4: the (possibly unformatted) floating point representation +% which belongs to #1. This format is returned (only!) by +% \pgfmathfloat@to@FMeE@style. +% It is used to determine sign and exponent. +\let\pgfmathprintnumber@fixed@style=\pgfmathprintnumber@fixed@styleDEFAULT + + +% Rounds a normalized floating point number to \pgfmathfloat@round@precision +% digits precision and writes the result to \pgfmathresult. +% +% This method uses \pgfmathroundto for the mantissa. +% +% @see pgfmathfloatroundzerofill +% +% SIDE EFFECT: the global variable \ifpgfmathfloatroundhasperiod will be set to +% whether the final mantissa #5 has a period or not. +\def\pgfmathfloatround#1{% + \pgfmathfloatroundhasperiodtrue + \begingroup + \pgfmathfloat@fixed@digits@after@periodfalse + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \pgfmathfloatround@impl + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +% Overload. +% +% This method uses a fixed width for the mantissa and fills in zeros +% if necessary. +% +% This method uses \pgfmathroundtozerofill for the mantissa. +% +% SIDE EFFECT: the global variable \ifpgfmathfloatroundhasperiod will be set to +% whether the final mantissa #5 has a period or not. +\def\pgfmathfloatroundzerofill#1{% + \pgfmathfloatroundhasperiodtrue + \begingroup + \pgfmathfloat@fixed@digits@after@periodtrue + \expandafter\pgfmathfloat@decompose@tok#1\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \pgfmathfloatround@impl + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +\newif\ifpgfmathfloatround@allow@empty@mantissa +\def\pgfmathfloatround@mantissa@ONE{1pt }% + +% #1: sign +% #2: mantissa +% #3: exponent +% #4: CODE to display if the mantissa is drawn. +% This code will be shown just before the exponent. +% Example: #4=\cdot +% #5: CODE to display if the mantissa is NOT draw. (unused currently) +% Might be used to display '10^1' instead of '1*10^1'. +% #6: CODE to display the exponent. +\def\pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax#4#5#6{% + \pgfkeysgetvalue{/pgf/number format/@sci exponent mark}\pgfmathfloatrounddisplaystyle@e@mark + \ifcase#1\relax + \pgfmathprintnumber@fixed@style{#2}#1#2e0\relax% + \expandafter\pgfmathfloatrounddisplaystyle@shared@impl@\expandafter{\pgfmathresult}{#4#6}% + \or + \def\pgfmathfloat@loc@TMPa{1}% "should draw mantissa=1" + \ifpgfmathfloatround@allow@empty@mantissa + \else + \ifdim#2pt=\pgfmathfloatround@mantissa@ONE + \def\pgfmathfloat@loc@TMPa{0}% do not draw it. + \fi + \fi + % + \if1\pgfmathfloat@loc@TMPa + \pgfmathprintnumber@fixed@style{#2}#1#2e0\relax% + \expandafter\pgfmathfloatrounddisplaystyle@shared@impl@\expandafter{\pgfmathresult}{#4#6}% + \else + \def\pgfmathfloat@loc@TMPa{0}% + \pgfmathfloatrounddisplaystyle@shared@impl@{#5}{#6}% + \fi + \or + \def\pgfmathfloat@loc@TMPa{1}% "should draw mantissa=1" + \ifpgfmathfloatround@allow@empty@mantissa + \else + \ifdim#2pt=\pgfmathfloatround@mantissa@ONE + \def\pgfmathfloat@loc@TMPa{0}% do not draw it. + \fi + \fi + % + \if1\pgfmathfloat@loc@TMPa + \pgfmathprintnumber@fixed@style{-#2}#1#2e0\relax% + \expandafter\pgfmathfloatrounddisplaystyle@shared@impl@\expandafter{\pgfmathresult}{#4#6}% + \else + \def\pgfmathfloat@loc@TMPa{0}% + \pgfmathfloatrounddisplaystyle@shared@impl@{-#5}{#6}% + \fi + \or + \pgfmathfloatrounddisplaystyle@shared@impl@@{\hbox{NaN}}{}% + \or + \ifpgfmathprintnumber@showpositive + \pgfmathfloatrounddisplaystyle@shared@impl@@{+\infty}{}% + \else + \pgfmathfloatrounddisplaystyle@shared@impl@@{\infty}{}% + \fi + \or + \pgfmathfloatrounddisplaystyle@shared@impl@@{-\infty}{}% + \fi +} + +% #1: the part before the exponent code +% #2: the part for the exponent code. +\def\pgfmathfloatrounddisplaystyle@shared@impl@#1#2{% + \pgfmathprintnumber@begingroup + \toks0={#1}% + \toks1=\expandafter{\pgfmathfloatrounddisplaystyle@e@mark #2}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 }% + \pgfmathprintnumber@endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP +}% +% Same as \pgfmathfloatrounddisplaystyle@shared@impl@, but it also +% inserts the '@dec sep mark' at the end. +\def\pgfmathfloatrounddisplaystyle@shared@impl@@#1#2{% + \pgfmathprintnumber@begingroup + \toks0={#1}% + \toks1=\expandafter{\pgfmathfloatrounddisplaystyle@e@mark #2}% + \pgfkeysgetvalue{/pgf/number format/@dec sep mark}\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP@MARK + \toks2=\expandafter{\pgfmathprintnumber@fixed@styleDEFAULT@DEC@SEP@MARK}% + \xdef\pgfmathfloat@glob@TMP{\the\toks0 \the\toks1 \the\toks2 }% + \pgfmathprintnumber@endgroup + \let\pgfmathresult=\pgfmathfloat@glob@TMP +} + +\def\pgfmathfloatrounddisplaystyle@std#1#2e#3\relax{% + \pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax{\cdot}{}{10^{#3}}% +} +\def\pgfmathfloatrounddisplaystyle@subscript#1#2e#3\relax{% + \pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax{}{1}{_{#3}}% +} +\def\pgfmathfloatrounddisplaystyle@superscript#1#2e#3\relax{% + \pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax{}{1}{^{#3}}% +} +\def\pgfmathfloatrounddisplaystyle@e#1#2e#3\relax{% + \ifnum#3<0\relax + \pgfmathprintnumber@begingroup + \count0=#3\relax + \multiply\count0 by-1 + \xdef\pgfmathfloat@glob@TMP{e{-}\the\count0}% + \pgfmathprintnumber@endgroup% + \let\pgfmathresult=\pgfmathfloat@glob@TMP + \else + \def\pgfmathresult{e{+}#3}% + \fi + \def\pgfmathfloat@loc@TMPb{\pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax{}{1}}% + \expandafter\pgfmathfloat@loc@TMPb\expandafter{\pgfmathresult}% +} +\def\pgfmathfloatrounddisplaystyle@E#1#2e#3\relax{% + \ifnum#3<0\relax + \pgfmathprintnumber@begingroup + \count0=#3\relax + \multiply\count0 by-1 + \xdef\pgfmathfloat@glob@TMP{E{-}\the\count0}% + \pgfmathprintnumber@endgroup% + \let\pgfmathresult=\pgfmathfloat@glob@TMP + \else + \def\pgfmathresult{E{+}#3}% + \fi + \def\pgfmathfloat@loc@TMPb{\pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\relax{}{1}}% + \expandafter\pgfmathfloat@loc@TMPb\expandafter{\pgfmathresult}% +} + +\def\pgfmathfloatrounddisplaystyle@generic#1#2e#3\relax{% + \begingroup + \pgfkeysvalueof {/pgf/number format/sci generic/@/.@cmd}{#3}{#1}{#2}\pgfeov + \pgfkeysgetvalue{/pgf/number format/sci generic/mantissa sep}\pgfmathdisplay@aftermantissa + \pgfkeysgetvalue{/pgf/number format/sci generic/empty mantissa sep}\pgfmathdisplay@nomantissa + \pgfkeysgetvalue{/pgf/number format/sci generic/exponent}\pgfmathdisplay@e + \toks0=\expandafter{\pgfmathdisplay@aftermantissa}% + \toks1=\expandafter{\pgfmathdisplay@nomantissa}% + \toks2=\expandafter{\pgfmathdisplay@e}% + \xdef\pgfmathfloat@glob@TMP{\noexpand\pgfmathfloatrounddisplaystyle@shared@impl#1#2e#3\noexpand\relax{\the\toks0}{\the\toks1}{\the\toks2}}% + \endgroup + \pgfmathfloat@glob@TMP +} + +% A macro which takes the argument 'e' and +% expands to the final TeX-representation for that floating point +% number. +% +% PRECONDITION: +% the floating point number has already been rounded properly and +% the mantissa has been rounded correctly. +% +% The argument needs to be in the format returned by +% \pgfmathfloat@to@FMeE@style and terminated by '\relax'. +\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@std +\newif\ifpgfmathfloat@usezerofill@sci +\newif\ifpgfmathfloat@usezerofill@fixed +\newif\ifpgfmathprintnumber@assumemathmode +\newif\ifpgfmathprintnumber@showpositive +\newif\ifpgfmathprintnumber@frac@warn +\newif\ifpgfmathprintnumber@frac@whole +\newif\ifpgfmathparsenumber@comma@as@period + +\long\def\pgfmathfloatfrac@verbatim#1#2{#1/#2}% + +\let\pgfmathround@@orig=\pgfmathround@ + +% 2 = compatible +% 0 = no +% 1 = yes +\def\pgfmathprintnumber@RELATIVE@choice@roundtofixed{2}% + +\newif\ifpgfmathprintnumber@thousand@sep@in@fractional +\pgfkeys{% + /pgf/number format/.is family, + /pgf/number format, + fixed/.code= \pgfmath@set@number@printer{pgfmathprintnumber@FIXED}, + sci/.code= \pgfmath@set@number@printer{pgfmathprintnumber@SCI}, + std/.code= {\pgfmath@set@number@printer{pgfmathprintnumber@STD}\pgfmathprintnumber@STD@setparam{#1}}, + std/.default=,% + relative round mode/.is choice, + relative round mode/fixed/.code={\def\pgfmathprintnumber@RELATIVE@choice@roundtofixed{1}}, + relative round mode/mantissa/.code={\def\pgfmathprintnumber@RELATIVE@choice@roundtofixed{0}}, + relative round mode/compatible/.code={\def\pgfmathprintnumber@RELATIVE@choice@roundtofixed{2}}, + % relative={} + relative/.code={% + \pgfmath@set@number@printer{pgfmathprintnumber@RELATIVE}% + \pgfmathround@@orig{#1}% + \expandafter\pgfmathfloattoint@@\pgfmathresult\relax + \let\pgfmathprintnumber@RELATIVE@param=\pgfmathresult + },% + relative/.value required, + relative*/.style={/pgf/number format/relative={#1},/pgf/number format/relative round mode=fixed}, + every relative/.style=std, + relative style/.style={/pgf/number format/every relative/.append style={#1}}, + fixed relative/.code= \pgfmath@set@number@printer{pgfmathprintnumber@FIXED@RELATIVE}, + int detect/.code= \pgfmath@set@number@printer{pgfmathprintnumber@INT@DETECT}, + int trunc/.code= \pgfmath@set@number@printer{pgfmathprintnumber@INT@TRUNC}, + frac/.code= \pgfmath@set@number@printer{pgfmathprintnumber@frac},% + frac TeX/.initial=\frac, + frac whole format/.code={\def\pgfmathresult{#1}}, + frac denom/.initial=, + frac whole/.is if=pgfmathprintnumber@frac@whole, + frac whole=true, + frac shift/.initial=4, + frac warning/.is if=pgfmathprintnumber@frac@warn, + frac warning=true, + assume math mode/.is if=pgfmathprintnumber@assumemathmode, + assume math mode/.default=true, + fixed zerofill/.is if= pgfmathfloat@usezerofill@fixed, + fixed zerofill/.default=true, + sci zerofill/.is if= pgfmathfloat@usezerofill@sci, + sci zerofill/.default=true, + zerofill/.style= {/pgf/number format/fixed zerofill={#1},/pgf/number format/sci zerofill={#1}}, + zerofill/.default= true, + precision/.store in= \pgfmathfloat@round@precision, + sci precision/.code={% + \edef\pgfmathfloat@loc@TMPa{#1}% + \ifx\pgfmathfloat@loc@TMPa\pgfutil@empty + \def\pgfmathprintnumber@sci@precision{\pgfmathfloat@round@precision}% + \else + \let\pgfmathprintnumber@sci@precision=\pgfmathfloat@loc@TMPa + \fi + },% + sci precision/.default=, + sci precision=, + fixed default/.code= {\let\pgfmathprintnumber@fixed@style=\pgfmathprintnumber@fixed@styleDEFAULT}, + set decimal separator/.initial=, + dec sep/.style={/pgf/number format/set decimal separator={#1}}, + @dec sep mark/.initial=, + @sci exponent mark/.initial=, + set thousands separator/.initial=, + 1000 sep in fractionals/.is if=pgfmathprintnumber@thousand@sep@in@fractional, + 1000 sep in fractionals/.default=true, + 1000 sep/.style={/pgf/number format/set thousands separator={#1}}, + min exponent for 1000 sep/.initial=0, + use period/.style= {/pgf/number format/set decimal separator={.},/pgf/number format/set thousands separator={{{,}}}}, + use comma/.style= {/pgf/number format/set decimal separator={{{,}}},/pgf/number format/set thousands separator={.}}, + showpos/.is if=pgfmathprintnumber@showpositive, + showpos/.default=true, + print sign/.is if=pgfmathprintnumber@showpositive, + print sign/.default=true, + read comma as period/.is if=pgfmathparsenumber@comma@as@period, + read comma as period/.default=true, + skip 0./.is if=pgfmathprintnumberskipzeroperiod, + skip 0./.default=true, + skip 0.= false, + use period, + sci 10^e/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@std}, + sci 10e/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@std}, + sci e/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@e}, + sci E/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@E}, + sci subscript/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@subscript}, + sci superscript/.code= {\let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@superscript}, + sci generic/.code= {% + \let\pgfmathfloatrounddisplaystyle=\pgfmathfloatrounddisplaystyle@generic + \pgfkeysdefargs{/pgf/number format/sci generic/@}% + {##1##2##3}% + {\pgfqkeys{/pgf/number format/sci generic}{#1}}% + }, + sci generic/mantissa sep/.initial=,% + sci generic/empty mantissa sep/.initial=,% + sci generic/mantisse sep/.style={/pgf/number format/sci generic/mantissa sep={#1}},% + sci generic/empty mantisse sep/.style={/pgf/number format/sci generic/empty mantissa sep={#1}},% + sci generic/exponent/.initial=,% + sci generic/.value required, + verbatim/.code={% + \pgfqkeys{/pgf/number format}{% + sci generic={mantissa sep=,exponent={e##1}}, + 1000 sep=, + skip 0.=false, + print sign=false, + dec sep=., + assume math mode, + frac TeX=\pgfmathfloatfrac@verbatim, + frac whole format/.code={\def\pgfmathresult{##1 }}, + @dec sep mark=, + @sci exponent mark=, + }% + }, + retain unit mantissa/.is if=pgfmathfloatround@allow@empty@mantissa, + retain unit mantissa/.default=true, + retain unit mantissa=true, + % + % allows to replace the implementation, for example + % 'implementation=\num'. This is experimental -- it is unclear + % if all consumers work well since they rely on the keys in + % /pgf/number format. + implementation/.code={\def\pgfmathprintnumber@protected{#1}}, +} + + + +\def\pgfmathprintnumber@STD#1{% + % parse the input: + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@STD@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@STD@setparam#1{% + \edef\pgfmathfloat@loc@TMPb{#1}% + \ifx\pgfmathfloat@loc@TMPb\pgfutil@empty + % DEFAULT for lower and upper bound. + \def\pgfmathprintnumber@STD@getlowerbound{% + \c@pgf@counta=\pgfmathfloat@round@precision@orig\relax + \divide\c@pgf@counta by-2\relax + }% + \def\pgfmathprintnumber@STD@upperbound{4}% + \else + \expandafter\pgfutil@in@\expandafter:\expandafter{\pgfmathfloat@loc@TMPb}% + \ifpgfutil@in@ + % we have -4:5 or something like that. + % parse both values: + \def\pgfmathfloat@loc@TMPa##1:##2\relax{% + \edef\pgfmathprintnumber@STD@getlowerbound{% + \noexpand\c@pgf@counta=##1\space + }% + \edef\pgfmathprintnumber@STD@upperbound{##2}% + }% + \expandafter\pgfmathfloat@loc@TMPa\pgfmathfloat@loc@TMPb\relax + \else + % we have just the lower bound: + \def\pgfmathprintnumber@STD@upperbound{4}% + \edef\pgfmathprintnumber@STD@getlowerbound{% + \noexpand\c@pgf@counta=\pgfmathfloat@loc@TMPb\space + }% + \fi + \fi +}% + +\def\pgfmathprintnumber@STD@issci#1#2e#3\relax{% + \expandafter\ifnum#1<3 + \expandafter\ifnum#3>\pgfmathprintnumber@STD@upperbound\relax + \pgfmathprintnumber@SCI@issci#1#2e#3\relax% + \else + \begingroup + \pgfmathprintnumber@STD@getlowerbound + \ifnum#3<\c@pgf@counta + \pgfmathprintnumber@SCI@issci#1#2e#3\relax% + \else + \pgfmathprintnumber@FIXED@issci#1#2e#3\relax% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup + \fi + \else% nan or inf: + \pgfmathfloatrounddisplaystyle#1#2e#3\relax% + \fi +} + +\def\pgfmathprintnumber@RELATIVE#1{% + % parse the input: + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@RELATIVE@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@RELATIVE@choice@roundtofixed@warn{% + \pgf@typeout{! Package pgf warning: the use of /pgf/number format/relative is discouraged (buggy). Please use 'relative*' instead or type \string\pgfkeys{/pgf/number format/relative round mode=fixed} into your preamble.}% + \global\let\pgfmathprintnumber@RELATIVE@choice@roundtofixed@warn=\relax +} + +\def\pgfmathprintnumber@RELATIVE@issci#1#2e#3\relax{% + \begingroup + % format X / 10^{relative}: + \c@pgf@counta=#3\relax + \advance\c@pgf@counta by-\pgfmathprintnumber@RELATIVE@param\relax + \pgfmathfloatcreate{#1}{#2}{\the\c@pgf@counta}% + % OK, round it to the desired precision: + \if0\pgfmathprintnumber@RELATIVE@choice@roundtofixed + % relative round mode=mantissa + \def\b@round@fixed{0}% + \else + \if1\pgfmathprintnumber@RELATIVE@choice@roundtofixed + % relative round mode=fixed + \def\b@round@fixed{1}% + \else + \pgfmathprintnumber@RELATIVE@choice@roundtofixed@warn + % relative round mode=compatible + \ifnum\c@pgf@counta>0 + % hm. for positive exponents, we should round the + % mantissa rather than only the fractional part. + \def\b@round@fixed{0}% + \else + % negative exponent -> round fixed representation: + \def\b@round@fixed{1}% + \fi + \fi + \fi + \if1\b@round@fixed + % round fixed representation: + \pgfmathfloattofixed\pgfmathresult + \expandafter\pgfmathroundto\expandafter{\pgfmathresult}% + \pgfmathfloatparsenumber{\pgfmathresult}% + \pgfmathfloatroundhasperiodtrue% make sure the code below works: + \else + % round the mantissa: + \expandafter\pgfmathfloatround\expandafter{\pgfmathresult}% + \fi + % Now, compute result * 10^{relative} and format the result: + \pgfmathfloattoregisterstok\pgfmathresult\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifnum\pgfmathfloat@a@S=0 + \pgfmathfloat@a@E=\pgfmathfloat@a@S % avoid 0 * 10^8 + \else + \advance\pgfmathfloat@a@E by+\pgfmathprintnumber@RELATIVE@param\relax + \fi + \edef\pgfmathresultX{% + \the\pgfmathfloat@a@S + \the\pgfmathfloat@a@Mtok + \ifpgfmathfloatroundhasperiod\else.0\fi + e\the\pgfmathfloat@a@E}% + % call another formatter for the result (but avoid rounding inside of it): + \pgfqkeys{/pgf/number format}{/pgf/number format/every relative, + fixed zerofill=false,% useless here! + sci zerofill=false}% + \ifx\pgfmathprintnumber@issci\pgfmathprintnumber@RELATIVE@issci + \pgfmath@error{The '/pgf/number format/every relative' style should set a valid display style}{}% + \fi + \let\pgfmathfloat@round@precision@orig=\pgfmathfloat@round@precision + \def\pgfmathfloat@round@precision{9999}% + \expandafter\pgfmathprintnumber@issci\pgfmathresultX\relax% + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +\def\pgfmathprintnumber@FIXED@RELATIVE#1{% + % parse the input: + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@FIXED@RELATIVE@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@FIXED@RELATIVE@issci#1#2e#3\relax{% + \begingroup + \pgfmathfloatcreate{#1}{#2}{#3}% + % we want the first digits - not the first + % +1 digits: + \c@pgf@counta=\pgfmathfloat@round@precision\relax + \advance\c@pgf@counta by-1 + \edef\pgfmathfloat@round@precision{\the\c@pgf@counta}% + \pgfmathfloatround{\pgfmathresult}% + \pgfmathfloattoregisterstok\pgfmathresult\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \ifnum\pgfmathfloat@a@S=0 + \pgfmathfloat@a@E=\pgfmathfloat@a@S % avoid 0 * 10^8 + \fi + \edef\pgfmathresultX{% + \the\pgfmathfloat@a@S + \the\pgfmathfloat@a@Mtok + \ifpgfmathfloatroundhasperiod\else.0\fi + e\the\pgfmathfloat@a@E}% + \let\pgfmathfloat@round@precision@orig=\pgfmathfloat@round@precision + \pgfmathfloat@usezerofill@fixedfalse + \def\pgfmathfloat@round@precision{9999}% typeset all remaining digits! + \expandafter\pgfmathprintnumber@FIXED@issci\pgfmathresultX\relax% + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +\def\pgfmathprintnumber@frac#1{% + % parse the input: + \pgfmathfloatparsenumber{#1}% + \pgfmathfloatgetfrac{\pgfmathresult}% + \expandafter\pgfmathprintnumber@frac@formatresult\pgfmathresult +} +\def\pgfmathprintnumber@frac@issci#1#2e#3\relax{% + \pgfmathfloatcreate{#1}{#2}{#3}% + \pgfmathfloatgetfrac{\pgfmathresult}% + \expandafter\pgfmathprintnumber@frac@formatresult\pgfmathresult +} +\def\pgfmathprintnumber@frac@formatresult#1#2#3{% + \begingroup + \pgfkeysgetvalue{/pgf/number format/frac TeX}\pgfmathresult + \toks0=\expandafter{\pgfmathresult}% + \def\pgfmathfloat@loc@TMPa{#1}% + \ifx\pgfmathfloat@loc@TMPa\pgfutil@empty + \ifpgfmathprintnumber@showpositive + \def\pgfmathfloat@loc@TMPa{+}% + \fi + \else + \ifx\pgfmathfloat@loc@TMPa-% + \else + \ifx\pgfmathfloat@loc@TMPa+% + \else + \ifpgfmathprintnumber@showpositive + \edef\pgfmathfloat@loc@TMPa{+\pgfmathfloat@loc@TMPa}% + \fi + \def\pgfmathfloat@loc@TMPb{\pgfkeysvalueof{/pgf/number format/frac whole format/.@cmd}}% + \expandafter\pgfmathfloat@loc@TMPb\pgfmathfloat@loc@TMPa\pgfeov + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \fi + \fi + \fi + \toks1=\expandafter{\pgfmathfloat@loc@TMPa}% + \edef\pgfmathresult{% + \the\toks1 \ifnum#2=0 \else\the\toks0 {#2}{#3}\fi% + }% + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% + +% Defines \pgfmathresult to contain three sets of braces containing +% the sign (optionally containing any components >1), the numerator and the denominator for #1. +% +% \pgfmathfloatgetfrac{0.5} -> \pgfmathresult contains {}{1}{2} +% \pgfmathfloatgetfrac{-0.5} -> \pgfmathresult contains {-}{1}{2} +% \pgfmathfloatgetfrac{1.5} -> \pgfmathresult contains {1}{1}{2} +% +% special cases: +% \pgfmathfloatgetfrac{0} -> \pgfmathresult contains {0}{0}{1} +% \pgfmathfloatgetfrac{1} -> \pgfmathresult contains {1}{0}{1} +% +% The numerator and denominator is always a number (not empty) +\def\pgfmathfloatgetfrac#1{% + \pgfutil@ifundefined{pgfmathfloatmultiply@}{% + \pgfmath@error{Sorry, the number format 'frac' requires '\string\usetikzlibrary{fpu}' (and, optionally, \string\usepackage{fp}) in order to work correctly}{}% + \edef\pgfmathresult{{#1}{0}{1}}% + }{% + \pgfmathfloatgetfrac@{#1}% + }% +}% +\def\pgfmathfloatgetfrac@#1{% + \begingroup + \edef\pgfmathfloat@arg{#1}% + \expandafter\pgfmathfloat@decompose@tok\pgfmathfloat@arg\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \def\pgfmathfloat@loc@TMPa{0}% + \ifcase\pgfmathfloat@a@S + % #1 = 0: + \def\pgfmathresult{{0}{0}{1}}% + \or% #1 > 0 + \pgfmathfloat@a@S=1 + \def\pgfmathfloat@loc@TMPa{1}% + \or% #1 < 0 + \pgfmathfloat@a@S=-1 + \def\pgfmathfloat@loc@TMPa{1}% + \or + \edef\pgfmathresult{{}{NaN}{1}}% + \or + \edef\pgfmathresult{{}{\infty}{1}}% + \or + \edef\pgfmathresult{{-}{\infty}{1}}% + \fi + \if1\pgfmathfloat@loc@TMPa + \ifnum\pgfmathfloat@a@E<0 + \def\pgfmathfloat@wholenumber{}% + \else + \pgfmathfloatcreate{1}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \pgfmathfloattofixed\pgfmathresult% + \def\pgfmathfloat@loc@TMPa##1.##2\relax{% + \def\pgfmathfloat@wholenumber{##1}% + \pgfmathfloatparsenumber{0.##2}% + }% + \expandafter\pgfmathfloat@loc@TMPa\pgfmathresult\relax + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@b@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \fi + % + \def\pgfmathfloat@loc@TMPa##1.##2\relax{% + \def\pgfmathfloat@mantissa@first{##1}% + \def\pgfmathfloat@mantissa@ltone{0.##2}% + }% + \expandafter\pgfmathfloat@loc@TMPa\the\pgfmathfloat@a@Mtok\relax + % + \def\pgfmathfloat@loc@@to@int##1.##2\relax##3{% + ##3=##1 + \ifdim0.##2pt>0.5pt + \advance##3 by1 + \fi + }% + % + % alias registers names: + \let\pgfmathresultnumerator=\pgfmathfloat@b@S + \let\pgfmathresultdenom=\pgfmathfloat@b@E + % + \pgfkeysgetvalue{/pgf/number format/frac denom}\pgfmath@target@denominator + \ifx\pgfmath@target@denominator\pgfutil@empty + % + \pgfmathfloat@a@E=-\pgfmathfloat@a@E + \ifdim\pgfmathfloat@mantissa@ltone pt=0pt + \def\pgfmathfloat@factor{1}% + \edef\pgfmathfloat@scaled@numerator{\the\pgfmathfloat@a@Mtok}% + \else + % FIXME : this here is numerically instable. + % + % The errors of 1/r are magnified by 10^k which + % doesn't work. + \pgfutil@ifundefined{FPdiv}{% + \pgfmathfloatparsenumber{\pgfmathfloat@mantissa@ltone}% + \pgfmathfloatreciprocal@{\pgfmathresult}% + }{% + % \usepackage{fp}. + % yields higher absolute precision. + \FPmessagesfalse% + \FPdebugfalse% + \FPdiv\pgfmathresult{1}{\pgfmathfloat@mantissa@ltone}% + \pgfmathfloatparsenumber{\pgfmathresult}% + }% + \let\pgfmathfloat@inv=\pgfmathresult + \pgfmathfloatcreate{1}{1.0}{\pgfkeysvalueof{/pgf/number format/frac shift}}% + \let\pgfmathfloat@scalebaseten=\pgfmathresult + \pgfmathfloatmultiply@{\pgfmathfloat@inv}{\pgfmathfloat@scalebaseten}% + \let\pgfmathfloat@factor=\pgfmathresult + % + \expandafter\pgfmathfloatparsenumber\expandafter{\the\pgfmathfloat@a@Mtok}% + \let\pgfmathfloat@loc@TMPa=\pgfmathresult + \pgfmathfloatmultiply@{\pgfmathfloat@factor}{\pgfmathfloat@loc@TMPa}% + \pgfmathfloattofixed\pgfmathresult + \let\pgfmathfloat@scaled@numerator=\pgfmathresult + % + \pgfmathfloattofixed\pgfmathfloat@factor + \expandafter\pgfmathfloat@loc@@to@int\pgfmathresult\relax{\pgfmathfloat@b@S}% + \edef\pgfmathfloat@factor{\the\pgfmathfloat@b@S}% + \fi + % + % + \pgfmathresultdenom=\pgfmathfloat@factor\relax + \pgfmathfloat@multiply@ten@to@the@E\pgfmathresultdenom + % + \expandafter\pgfmathfloat@loc@@to@int\pgfmathfloat@scaled@numerator\relax{\pgfmathresultnumerator}% + %\message{scale = \pgfmathfloat@factor; Z = \the\pgfmathresultnumerator\space ( von \pgfmathfloat@scaled@numerator), N = \the\pgfmathresultdenom.}% + % + \pgfmathgreatestcommondivisor{\pgfmathresultnumerator}{\pgfmathresultdenom}% + \divide\pgfmathresultnumerator by\pgfmathresult\relax + \divide\pgfmathresultdenom by\pgfmathresult\relax + \ifpgfmathprintnumber@frac@warn + \ifnum\pgfmathresultdenom>1000 + \pgfutil@ifundefined{FPdiv}{% + \pgfmathfloattosci@\pgfmathfloat@arg + \pgf@typeout{! Package pgf /pgf/number format/frac warning=true: /pgf/number format/frac of `\pgfmathresult' = \the\pgfmathresultnumerator\space / \the\pgfmathresultdenom\space might be large due to instabilities. Try \string\usepackage{fp} to improve accuracy.}% + }{}% + \fi + \fi + \else + % use target denominator: + \pgfmathresultdenom=\pgfmath@target@denominator\relax + \pgfmathfloatcreate{1}{\the\pgfmathfloat@a@Mtok}{\the\pgfmathfloat@a@E}% + \pgfmathfloattofixed\pgfmathresult + \pgf@xa=\pgfmathresult pt + \multiply\pgf@xa by\pgfmathresultdenom + \edef\pgfmathfloat@scaled@numerator{\pgfmath@tonumber\pgf@xa}% + \expandafter\pgfmathfloat@loc@@to@int\pgfmathfloat@scaled@numerator\relax{\pgfmathresultnumerator}% + \fi + \ifpgfmathprintnumber@frac@whole + \else + \ifx\pgfmathfloat@wholenumber\pgfutil@empty + \else + \count0=\pgfmathfloat@wholenumber\relax + \multiply\count0 by\pgfmathresultdenom + \advance\pgfmathresultnumerator by\count0 + \def\pgfmathfloat@wholenumber{}% + \fi + \fi + \ifnum\pgfmathfloat@a@S<0 + \edef\pgfmathresult{{-\pgfmathfloat@wholenumber}{\the\pgfmathresultnumerator}{\the\pgfmathresultdenom}}% + \else + \edef\pgfmathresult{{\pgfmathfloat@wholenumber}{\the\pgfmathresultnumerator}{\the\pgfmathresultdenom}}% + \fi + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +}% +\def\pgfmathfloat@gobble@until@relax#1\relax{} + +% computes the greatest common divisor of two integer numbers (in +% integer arithmetics). +\def\pgfmathgreatestcommondivisor#1#2{% + \begingroup + \count0=#1\relax + \count1=#2\relax + \ifnum\count0=0 + \edef\pgfmathresult{\the\count1}% + \else + \pgfmathgreatestcommondivisor@loop + \edef\pgfmathresult{\the\count0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} +\def\pgfmathgreatestcommondivisor@loop{% + \ifnum\count1=0 + \else + \ifnum\count0>\count1 + \advance\count0 by-\count1 + \else + \advance\count1 by-\count0 + \fi + \expandafter\pgfmathgreatestcommondivisor@loop + \fi +}% + +% multiplies a TeX register by 10^E where E is stored in the register +% \pgfmathfloat@a@E (and it should be positive!)% +% +% #1 a TeX register +\def\pgfmathfloat@multiply@ten@to@the@E#1{% + \ifnum\pgfmathfloat@a@E>0 + \multiply#1 by10 + \advance\pgfmathfloat@a@E by-1 + \def\pgfmathfloat@multiply@ten@to@the@E@next{\pgfmathfloat@multiply@ten@to@the@E{#1}}% + \else + \let\pgfmathfloat@multiply@ten@to@the@E@next=\relax% + \fi + \pgfmathfloat@multiply@ten@to@the@E@next +}% + +\def\pgfmathprintnumber@INT@TRUNC#1{% + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@INT@TRUNC@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@INT@TRUNC@impl#1.#2\relax#3#4e#5\relax{% + \pgfmathfloatroundhasperiodfalse + \pgfmathprintnumber@fixed@style{#1}#3#4e#5\relax% +} +\def\pgfmathprintnumber@INT@TRUNC@issci#1#2e#3\relax{% + \ifnum#1<3\relax + \pgfmathfloatcreate{#1}{#2}{#3}% + \pgfmathfloattofixed{\pgfmathresult}% + \expandafter\pgfmathprintnumber@INT@TRUNC@impl\pgfmathresult\relax#1#2e#3\relax + \else + \pgfmathfloatrounddisplaystyle#1#2e#3\relax% + \fi +} + +% Invokes '#2' if '#1' is actually an integer or '#3' if not. +% +% As a side-effect, \pgfretval will be set to the integer value if it +% actually *is* an integer. Otherwise, \pgfretval will contain the +% parsed floating point number. +% +% #1 a number constant (not necessarily a parsed float). +\def\pgfmathifisint#1#2#3{% + \gdef\pgfmathfloatisint@@{0}% + \begingroup + \pgfmathfloatparsenumber{#1}% + \let\pgfretval\pgfmathresult + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathfloatisint@\pgfmathresult\relax + \pgfmath@smuggleone\pgfretval + \endgroup + \if1\pgfmathfloatisint@@ #2\else #3\fi +}% +\def\pgfmathfloatisint@#1#2e#3\relax{% + \ifnum#1<3\relax + \pgfmathfloatcreate{#1}{#2}{#3}% + \pgfmathfloattofixed{\pgfmathresult}% + \def\pgfmathfloat@round@precision{6}% + \expandafter\pgfmathroundto\expandafter{\pgfmathresult}% + \ifpgfmathfloatroundhasperiod + \else + \let\pgfretval\pgfmathresult% + \gdef\pgfmathfloatisint@@{1}% + \fi + \fi +} + +\def\pgfmathprintnumber@INT@DETECT#1{% + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@INT@DETECT@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@INT@DETECT@issci#1#2e#3\relax{% + \begingroup + \ifnum#1<3\relax + \pgfmathfloatcreate{#1}{#2}{#3}% + \pgfmathfloattofixed{\pgfmathresult}% + \let\pgfmathfloat@round@precision@=\pgfmathfloat@round@precision + \def\pgfmathfloat@round@precision{6}% + \expandafter\pgfmathroundto\expandafter{\pgfmathresult}% + \let\pgfmathfloat@round@precision=\pgfmathfloat@round@precision@ + \ifpgfmathfloatroundhasperiod + \pgfmathprintnumber@SCI@issci#1#2e#3\relax + \else + \expandafter\pgfmathprintnumber@fixed@style\expandafter{\pgfmathresult}#1#2e#3\relax + \fi + \else + \pgfmathfloatrounddisplaystyle#1#2e#3\relax% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +\def\pgfmathprintnumber@FIXED#1{% + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@FIXED@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@FIXED@issci#1#2e#3\relax{% + \begingroup + \ifnum#1<3 + \pgfmathfloatcreate{#1}{#2}{#3}% + \pgfmathfloattofixed{\pgfmathresult}% + \ifpgfmathfloat@usezerofill@fixed + \expandafter\pgfmathroundtozerofill\expandafter{\pgfmathresult}% + \else + \expandafter\pgfmathroundto\expandafter{\pgfmathresult}% + \fi + \ifpgfmathfloatroundmayneedrenormalize + \pgfmathfloat@a@E=#3\relax + \advance\pgfmathfloat@a@E by1 + \edef\pgfmathfloat@loc@TMPb{\noexpand\pgfmathprintnumber@fixed@style{\pgfmathresult}#1#2e\the\pgfmathfloat@a@E}% + \pgfmathfloat@loc@TMPb\relax% + \else + \expandafter\pgfmathprintnumber@fixed@style\expandafter{\pgfmathresult}#1#2e#3\relax% + \fi + \else% nan or inf: + \pgfmathfloatrounddisplaystyle#1#2e#3\relax% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + + +\def\pgfmathprintnumber@SCI#1{% + \pgfmathfloatparsenumber{#1}% + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathprintnumber@SCI@issci\pgfmathresult\relax +} + +\def\pgfmathprintnumber@SCI@issci#1#2e#3\relax{% + \begingroup + \pgfmathfloatcreate{#1}{#2}{#3}% + \edef\pgfmathfloat@round@precision{\pgfmathprintnumber@sci@precision}% + \ifpgfmathfloat@usezerofill@sci + \pgfmathfloatroundzerofill{\pgfmathresult}% + \else + \pgfmathfloatround{\pgfmathresult}% + \fi + \pgfmathfloat@to@FMeE@style\pgfmathresult + \expandafter\pgfmathfloatrounddisplaystyle\pgfmathresult\relax + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +% Prints argument #1 using the current pretty printer environment (all +% variables in /pgf/number format). +% +% You may specify optional arguments with \pgfmathprintnumber[...]. +\pgfutil@protected\def\pgfmathprintnumber{% + \pgfutil@ifnextchar[% + {\pgfmathprintnumber@OPT}% + {\pgfmathprintnumber@noopt}% +} + +\def\pgfmathprintnumber@noopt#1{% + \pgfmathprintnumber@{#1}% + \ifpgfmathprintnumber@assumemathmode + \pgfmathresult + \else + \pgfutilensuremath{\pgfmathresult}% + \fi +}% +\def\pgfmathprintnumber@OPT[#1]#2{% + \begingroup + \pgfqkeys{/pgf/number format}{#1}% + \pgfmathprintnumber@{#2}% + \ifpgfmathprintnumber@assumemathmode + \pgfmathresult + \else + \pgfutilensuremath{\pgfmathresult}% + \fi + \endgroup +}% + +% As \pgfmathprintnumber, but it produces its output into the second +% argument. +\def\pgfmathprintnumberto{% + \pgfutil@ifnextchar[% + {\pgfmathprintnumberto@OPT}% + {\pgfmathprintnumberto@noopt}% +} + +\def\pgfmathprintnumberto@noopt#1#2{% + \begingroup + \pgfmathprintnumber@{#1}% + \ifpgfmathprintnumber@assumemathmode + \global\let\pgfmathfloat@glob@TMP=\pgfmathresult + \else + \toks0=\expandafter{\pgfmathresult}% + \xdef\pgfmathfloat@glob@TMP{\noexpand\pgfutilensuremath{\the\toks0 }}% + \fi + \endgroup + \let#2=\pgfmathfloat@glob@TMP +}% +\def\pgfmathprintnumberto@OPT[#1]#2#3{% + \begingroup + \pgfqkeys{/pgf/number format}{#1}% + \pgfmathprintnumber@{#2}% + \ifpgfmathprintnumber@assumemathmode + \global\let\pgfmathfloat@glob@TMP=\pgfmathresult + \else + \toks0=\expandafter{\pgfmathresult}% + \xdef\pgfmathfloat@glob@TMP{\noexpand\pgfutilensuremath{\the\toks0 }}% + \fi + \endgroup + \let#3=\pgfmathfloat@glob@TMP +}% + + +% Changes the current number pretty printer to #1. +% +% #1 is the macro base name for the pretty print routine, without the +% leading '\'. +\def\pgfmath@set@number@printer#1{% + \expandafter\let\expandafter\pgfmathprintnumber@\csname #1\endcsname + \expandafter\let\expandafter\pgfmathprintnumber@issci\csname #1@issci\endcsname +} + +\pgfkeys{/pgf/number format/std} + +%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% IMPL +% +%%%%%%%%%%%%%%%%%%%%%%%%%% + +% equals only itself when compared with \ifx: +\def\pgfmathfloat@EOI{\pgfmathfloat@EOI}% + +% Re-use counters internally. +% +% They are always grouped and only used inside of the rounding +% routines. +\let\c@pgfmathroundto@prec=\pgfmathfloat@b@S% ATTENTION: DOUBLE-USED REGISTERS! +\let\c@pgfmathroundto@offsetbehindperiod=\pgfmathfloat@b@E +\newcount\c@pgfmathroundto@lastzeros + +\newif\ifpgfmathround@impl@PREPERIOD@is@negative@zero + +% PRECONDITION: +% \ifpgfmathfloatroundhasperiod=\iftrue holds outside of the current TeX group. +% +% POSTCONDITION: +% \ifpgfmathfloatroundhasperiod will be set correctly AFTER the +% current TeX group. +% \ifpgfmathfloatroundmayneedrenormalize will be set globally +\def\pgfmathroundto@impl#1{% + \edef\pgfmathround@input{#1}% + \global\pgfmathfloatroundmayneedrenormalizefalse + \pgfmathfloat@tmptoks={}% + \let\pgfmathround@next=\pgfutil@empty + \let\pgfmathround@cur=\pgfutil@empty + \let\pgfmathresult=\pgfutil@empty + \expandafter\c@pgfmathroundto@prec\pgfmathfloat@round@precision\relax + \c@pgfmathroundto@lastzeros=0 + \c@pgfmathroundto@offsetbehindperiod=-1 % means: no period found so far + \pgfmathround@impl@PREPERIOD@is@negative@zerotrue + \expandafter\pgfmathroundto@impl@ITERATE@NODOT@firstcall\pgfmathround@input\pgfmathfloat@EOI +} + +% \pgfmathroundto implementation in WORDS: +% +% coarse idea: +% 1. collect all digits/sign BEFORE the first period in REVERSE order +% 2. then, collect UP TO \prec digits after the period in REVERSE order +% Steps 1. and 2. lead to the digit [sign] sequence +% "x_{-p} x_{-p+1} ... x_{-2} x_{-1} '.' x_0 ... x_r" +% where 'r' is the total number of digits. The integer 'p' denotes the +% ACTUALLY collected number of digits behind the period. +% +% Let 'k' be the desired precision. +% +% Please note that pgfmathroundto rounds the mantissa, that means |abs(x)|. +% +% There are exactly TWO cases: +% 1. The case with p<=k and x_{-p-1} = end of input. +% 2. The case with p=k and x_{-p-1} is a further, next character. +% +% Then, for case 1.): +% discard any unused zeros at the tail of our number (possibly +% including the period) +% +% and in case 2.) +% if NEXT DIGIT < 5: +% do exactly the same as in case 1.) above and discard any +% following digits. +% else +% let q := -p +% while(x_q = 9 and q<=r ) +% if q>=0 +% set x_q = '0' +% else +% discard digit x_q='9' +% fi +% ++q +% if q=0 +% discard the period +% fi +% end while +% if q = r+1 +% insert a '1' +% else +% set x_q = x_q + 1 +% fi +% fi +% +% All these loops have been implemented in spaghetti-code below. +% Sorry, I fear its hard to understand. In principle, everything is +% realised using more or less finite state machines (with some number +% counting logic). +% +% Some comments: +% - The token register \pgfmathfloat@tmptoks is used to accumulate the REVERSED input number. +% - \pgfmathfloat@EOI always denotes 'END OF INPUT'. +% - in the second stage, we need to reverse \pgfmathfloat@tmptoks. +% This is -- again -- done with \pgfmathfloat@tmptoks. + +\def\pgfmathroundto@impl@discard@period#1.#2\pgfmathfloat@EOI{% + \pgfmathfloatroundhasperiodfalse + \aftergroup\pgfmathfloatroundhasperiodfalse + \def\pgfmathresult{#1}% +} + +\def\pgfmathroundto@impl@gobble@rest@and@start#1\pgfmathfloat@EOI{% + \pgfmathroundto@impl@start +} +\def\pgfmathroundto@impl@gobble@and@start\pgfmathfloat@EOI{% + \pgfmathroundto@impl@start +} +\def\pgfmathroundto@impl@gobble\pgfmathfloat@EOI{}% +\def\pgfmathroundto@impl@gobble@rest#1\pgfmathfloat@EOI{}% + +% This method will be invoked as soon as the first step, the reverse +% collection of up to PREC digits after the period, has finished. +\def\pgfmathroundto@impl@start{% + \ifx\pgfmathround@next\pgfutil@empty + \ifnum\c@pgfmathroundto@offsetbehindperiod<0 + % no period found. + \ifpgfmathfloat@fixed@digits@after@period + \ifnum\c@pgfmathroundto@prec=0\relax + \pgfmathfloatroundhasperiodfalse + \aftergroup\pgfmathfloatroundhasperiodfalse + \edef\pgfmathresult{\pgfmathround@input}% + \else + \pgfmathfloat@tmptoks=\expandafter{\pgfmathround@input.}% + \c@pgfmathroundto@offsetbehindperiod=\c@pgfmathroundto@prec + \pgfmathroundto@impl@append@zeros + \edef\pgfmathresult{\the\pgfmathfloat@tmptoks}% + \fi + \else + \pgfmathfloatroundhasperiodfalse + \aftergroup\pgfmathfloatroundhasperiodfalse + \edef\pgfmathresult{\pgfmathround@input}% + \fi + \else + %\ifnum\c@pgfmathroundto@offsetbehindperiod>\c@pgfmathroundto@prec + % \pgfmath@error{Internal logic error in pgfmathroundto at [I] - should not have happened!?}{}% + %\fi + \pgfmathroundto@impl@finish@with@truncation + \fi + \else + %\ifnum\c@pgfmathroundto@offsetbehindperiod=\c@pgfmathroundto@prec + %\else + % \pgfmath@error{Internal logic error in pgfmathroundto at [II] - should not have happened!? I have offsetbehindperiod=\the\c@pgfmathroundto@offsetbehindperiod and prec = \the\c@pgfmathroundto@prec}{}% + %\fi + \expandafter\ifnum\pgfmathround@next<5\relax + \pgfmathroundto@impl@finish@with@truncation + \else + \multiply\c@pgfmathroundto@offsetbehindperiod by-1 + \expandafter\pgfmathroundto@impl@ADD@ONE\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \fi + \fi +} + +% takes the current input and decides whether trailing zeros shall be +% discarded or more zeros need to be filled in. +\def\pgfmathroundto@impl@finish@with@truncation{% + \ifpgfmathfloat@fixed@digits@after@period + \expandafter\pgfmathroundto@impl@REVERSE\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \ifnum\c@pgfmathroundto@lastzeros=\c@pgfmathroundto@offsetbehindperiod + \ifpgfmathround@impl@PREPERIOD@is@negative@zero + % write '0.0000' instead of '-0.0000': + \expandafter\pgfmathroundto@impl@discard@minus\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \fi + \fi + \ifnum\c@pgfmathroundto@prec=0\relax + \expandafter\pgfmathroundto@impl@discard@period\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \else + \advance\c@pgfmathroundto@prec by-\c@pgfmathroundto@offsetbehindperiod + \c@pgfmathroundto@offsetbehindperiod=\c@pgfmathroundto@prec + \pgfmathroundto@impl@append@zeros + \edef\pgfmathresult{\the\pgfmathfloat@tmptoks}% + \fi + \else + \pgfmathroundto@impl@discard@suffix@zeros + \fi +} + +\def\pgfmathroundto@impl@discard@minus-#1\pgfmathfloat@EOI{\pgfmathfloat@tmptoks={#1}}% + +% appends \c@pgfmathroundto@offsetbehindperiod zeros at the end of \pgfmathfloat@tmptoks. +\def\pgfmathroundto@impl@append@zeros{% + \ifnum\c@pgfmathroundto@offsetbehindperiod>0 + \pgfmathfloat@tmptoks=\expandafter{\the\pgfmathfloat@tmptoks0}% + \advance\c@pgfmathroundto@offsetbehindperiod by-1 + \pgfmathroundto@impl@append@zeros + \fi +} + +\def\pgfmathroundto@impl@ADD@ONE{% + \pgfmathfloat@tmptoks={}% no longer needed because its old value will be read from input + \pgfmathroundto@impl@ADD@ONE@ITERATE +} +\def\pgfmathroundto@impl@ADD@ONE@ITERATE{% + \pgfutil@ifnextchar\pgfmathfloat@EOI{% + \global\pgfmathfloatroundmayneedrenormalizetrue + \edef\pgfmathresult{1\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@gobble + }{% + \pgfutil@ifnextchar.{% + \ifnum\c@pgfmathroundto@prec=0 + % silently discard period in special case precision=0 + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ADD@ONE@ITERATE@gobble@dot}% + \else + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ADD@ONE@NEXT@COLLECT}% + \fi + \pgfmathround@nextcmd + }{% + \pgfutil@ifnextchar+{% + \global\pgfmathfloatroundmayneedrenormalizetrue + \edef\pgfmathresult{1\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@gobble@rest + }{% + \pgfutil@ifnextchar-{% + \global\pgfmathfloatroundmayneedrenormalizetrue + \edef\pgfmathresult{-1\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@gobble@rest + }{% + \pgfmathroundto@impl@ADD@ONE@NEXT + }% + }% + }% + }% +} + +\def\pgfmathroundto@impl@ADD@ONE@ITERATE@gobble@dot.{% + \pgfmathfloatroundhasperiodfalse + \aftergroup\pgfmathfloatroundhasperiodfalse + \pgfmathroundto@impl@ADD@ONE@ITERATE +} + +\def\pgfmathroundto@impl@ADD@ONE@NEXT@COLLECT#1{% + \pgfmathfloat@tmptoks=\expandafter{\expandafter#1\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@ADD@ONE@ITERATE +} +\def\pgfmathroundto@impl@ADD@ONE@NEXT#1{% + \ifnum#1=9 + \ifnum\c@pgfmathroundto@offsetbehindperiod<0 + \ifpgfmathfloat@fixed@digits@after@period + \pgfmathfloat@tmptoks=\expandafter{\expandafter0\the\pgfmathfloat@tmptoks}% + \else + % silently DROP digit + \fi + \else + \pgfmathfloat@tmptoks=\expandafter{\expandafter0\the\pgfmathfloat@tmptoks}% + \fi + \advance\c@pgfmathroundto@offsetbehindperiod by1 + \ifnum\c@pgfmathroundto@offsetbehindperiod=0 + \ifpgfmathfloat@fixed@digits@after@period + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ADD@ONE@ITERATE}% + \else + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ADD@ONE@ITERATE@gobble@dot}% + \fi + \else + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ADD@ONE@ITERATE}% + \fi + \else + % re-use this counter: + \c@pgfmathroundto@lastzeros=#1 + \advance\c@pgfmathroundto@lastzeros by1 + \edef\pgfmathresult{\the\c@pgfmathroundto@lastzeros\the\pgfmathfloat@tmptoks}% + \pgfmathfloat@tmptoks=\expandafter{\pgfmathresult}% + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@REVERSE@ITERATE}% + \fi + \pgfmathround@nextcmd +} + + +\def\pgfmathroundto@impl@discard@suffix@zeros{% + \ifnum\c@pgfmathroundto@lastzeros=\c@pgfmathroundto@offsetbehindperiod + \ifpgfmathround@impl@PREPERIOD@is@negative@zero + \pgfmathfloatroundhasperiodfalse + \aftergroup\pgfmathfloatroundhasperiodfalse + \def\pgfmathresult{0}% write '0' instead of '-0' + \else + \expandafter\pgfmathroundto@impl@discard@period\pgfmathround@input\pgfmathfloat@EOI + \fi + \else + \ifnum\c@pgfmathroundto@lastzeros=0 + \expandafter\pgfmathroundto@impl@REVERSE\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \else + \expandafter\pgfmathroundto@impl@discard@suffix@zeros@ITERATE\the\pgfmathfloat@tmptoks\pgfmathfloat@EOI + \fi + \fi +} + +% PRECONDITION: +% \c@pgfmathroundto@lastzeros > 0 +\def\pgfmathroundto@impl@discard@suffix@zeros@ITERATE#1{% + \advance\c@pgfmathroundto@lastzeros by-1 + \ifnum\c@pgfmathroundto@lastzeros=0 + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@REVERSE}% + \else + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@discard@suffix@zeros@ITERATE}% + \fi + \pgfmathround@nextcmd +} + +% Usage: +% \pgfmathroundto@impl@REVERSE#1\pgfmathfloat@EOI +% -> writes #1 reversed into \pgfmathfloat@tmptoks +\def\pgfmathroundto@impl@REVERSE{% + \pgfmathfloat@tmptoks={}% + \pgfmathroundto@impl@REVERSE@ITERATE +} + +\def\pgfmathroundto@impl@REVERSE@ITERATE{% + \pgfutil@ifnextchar\pgfmathfloat@EOI{% + \edef\pgfmathresult{\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@gobble + }{% + \pgfmathroundto@impl@REVERSE@NEXT + }% +} + +\def\pgfmathroundto@impl@REVERSE@NEXT#1{% + \pgfmathfloat@tmptoks=\expandafter{\expandafter#1\the\pgfmathfloat@tmptoks}% + \pgfmathroundto@impl@REVERSE@ITERATE +} + +\def\pgfmathroundto@impl@BEGIN@DOT.{% + \pgfmathfloat@tmptoks=\expandafter{\expandafter.\the\pgfmathfloat@tmptoks}% + \c@pgfmathroundto@offsetbehindperiod=0 + \pgfmathroundto@impl@ITERATE@DOT +} +\def\pgfmathroundto@impl@ITERATE@DOT{% + \pgfutil@ifnextchar\pgfmathfloat@EOI{% + % finished. + \pgfmathroundto@impl@gobble@and@start + }{% + \pgfmathroundto@impl@NEXT@DOT + }% +} +\def\pgfmathroundto@impl@NEXT@DOT#1{% + \ifnum\c@pgfmathroundto@offsetbehindperiod=\c@pgfmathroundto@prec + \def\pgfmathround@next{#1}% + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@gobble@rest@and@start}% + \else + \advance\c@pgfmathroundto@offsetbehindperiod by1 + \ifnum#1=0 + \advance\c@pgfmathroundto@lastzeros by1 + \else + \c@pgfmathroundto@lastzeros=0 + \fi + \pgfmathfloat@tmptoks=\expandafter{\expandafter#1\the\pgfmathfloat@tmptoks}% + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ITERATE@DOT}% + \fi + \pgfmathround@nextcmd +}% + +% in contrast to pgfmathroundto@impl@ITERATE@NODOT, this method here +% checks also for signs +\def\pgfmathroundto@impl@ITERATE@NODOT@firstcall#1{% + \def\pgfmathround@cur{#1}% + \ifx\pgfmathround@cur\pgfmathfloat@EOI + \pgfmathround@impl@PREPERIOD@is@negative@zerofalse + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@start}% + \else + \ifx\pgfmathround@cur\pgfmathfloatparsenumber@tok@PERIOD + \pgfmathround@impl@PREPERIOD@is@negative@zerofalse + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@BEGIN@DOT.}% + \else + \ifx\pgfmathround@cur\pgfmathfloatparsenumber@tok@MINUS + \else + \pgfmathround@impl@PREPERIOD@is@negative@zerofalse + \fi + \pgfmathfloat@tmptoks=\expandafter{\expandafter#1\the\pgfmathfloat@tmptoks}% + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ITERATE@NODOT}% + \fi + \fi + \pgfmathround@nextcmd +} + +\def\pgfmathroundto@impl@ITERATE@NODOT#1{% + \def\pgfmathround@cur{#1}% + \ifx\pgfmathround@cur\pgfmathfloat@EOI + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@start}% + \else + \ifx\pgfmathround@cur\pgfmathfloatparsenumber@tok@PERIOD + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@BEGIN@DOT.}% + \else + \ifx\pgfmathround@cur\pgfmathfloatparsenumber@tok@ZERO + \else + \pgfmathround@impl@PREPERIOD@is@negative@zerofalse + \fi + \pgfmathfloat@tmptoks=\expandafter{\expandafter#1\the\pgfmathfloat@tmptoks}% + \def\pgfmathround@nextcmd{\pgfmathroundto@impl@ITERATE@NODOT}% + \fi + \fi + \pgfmathround@nextcmd +} + +%-------------------------------------------- +% END of pgfmathroundto implementation. +%-------------------------------------------- + + +% flags, mantissa and exponent has already been stored into +% \pgfmathfloat@a@* [using ...@Mtok] +% +% PRECONDITION: +% \ifpgfmathfloatroundhasperiod = \iftrue outside of the current +% group +% +% POSTCONDITION: +% \ifpgfmathfloatroundhasperiod will be set after the current TeX +% group. +\def\pgfmathfloatround@impl{% + \expandafter\pgfmathroundto@impl\expandafter{\the\pgfmathfloat@a@Mtok}% + \ifpgfmathfloatroundmayneedrenormalize + \ifpgfmathfloatroundhasperiod + \expandafter\pgfmathfloatround@impl@renormalize\pgfmathresult\pgfmathfloat@EOI% + \else + \expandafter\pgfmathfloatround@impl@renormalize\pgfmathresult.\pgfmathfloat@EOI% + \fi + \advance\pgfmathfloat@a@E by1 + \fi + \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\pgfmathresult}{\the\pgfmathfloat@a@E}% +} + +\def\pgfmathfloatround@impl@renormalize#1#2.#3\pgfmathfloat@EOI{% + \pgfmathroundto@impl{#1.#2#3}% +} + + + + + +% ATTENTION: this thing REQUIRES a period in the mantissa! +% collects everything into \pgfmathresult +\def\pgfmathfloattofixed@impl#1.#2\relax{% + \ifnum\pgfmathfloat@a@E<0 + \ifcase-\pgfmathfloat@a@E + \or%e-1 + \pgfmathfloat@a@Mtok={0.}% + \or%e-2 + \pgfmathfloat@a@Mtok={0.0}% + \or%e-3 + \pgfmathfloat@a@Mtok={0.00}% + \or%e-4 + \pgfmathfloat@a@Mtok={0.000}% + \or%e-5 + \pgfmathfloat@a@Mtok={0.0000}% + \or%e-6 + \pgfmathfloat@a@Mtok={0.00000}% + \or%e-7 + \pgfmathfloat@a@Mtok={0.000000}% + \or%e-8 + \pgfmathfloat@a@Mtok={0.0000000}% + \or%e-9 + \pgfmathfloat@a@Mtok={0.00000000}% + \or%e-10 + \pgfmathfloat@a@Mtok={0.000000000}% + \else%<= -11 + \pgfmathfloat@a@Mtok={0.0000000000}% + \advance\pgfmathfloat@a@E by10 + \pgfutil@loop + \ifnum\pgfmathfloat@a@E<-1 + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok 0}% + \advance\pgfmathfloat@a@E by1 + \pgfutil@repeat + \fi + \def\pgfmathfloat@loc@TMPb{#2}% + \def\pgfmathfloat@loc@TMPc{0}% + \ifx\pgfmathfloat@loc@TMPb\pgfmathfloat@loc@TMPc + \edef\pgfmathresult{\the\pgfmathfloat@a@Mtok #1}% + \else + \edef\pgfmathresult{\the\pgfmathfloat@a@Mtok #1#2}% + \fi + \else + %-------------------------------------------------- + % \ifnum\pgfmathfloat@a@E=0% + % \edef\pgfmathresult{#1.#2}% + % \else + % \pgfmathfloat@a@Mtok={#1}% + % \pgfmathfloattofixed@impl@collectmantissa#2\count\pgfmathfloat@a@E + % \edef\pgfmathresult{\the\pgfmathfloat@a@Mtok}% + % \fi + %-------------------------------------------------- + \pgfmathfloat@a@Mtok{#1}% + \pgfmathfloattofixed@impl@pos#2000000000\pgfmathfloat@EOI + \edef\pgfmathresult{\the\pgfmathfloat@a@Mtok}% + \fi +} + +% FIXME: this implementation here is very fast, but it introduces trailing zeros. Is that acceptable? +\def\pgfmathfloattofixed@impl@pos#1#2#3#4#5#6#7#8#9\pgfmathfloat@EOI{% + \ifcase\pgfmathfloat@a@E + % e+0 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok .#1#2#3#4#5#6#7#8#9}% + \or%e+1 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1.#2#3#4#5#6#7#8#9}% + \or%e+2 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2.#3#4#5#6#7#8#9}% + \or%e+3 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3.#4#5#6#7#8#9}% + \or%e+4 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4.#5#6#7#8#9}% + \or%e+5 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4#5.#6#7#8#9}% + \or%e+6 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4#5#6.#7#8#9}% + \or%e+7 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4#5#6#7.#8#9}% + \or%e+8 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4#5#6#7#8.#9}% + \else%>=9 + \pgfmathfloat@a@Mtok\expandafter{\the\pgfmathfloat@a@Mtok #1#2#3#4#5#6#7#8}% + \advance\pgfmathfloat@a@E by-8 + \pgfmathfloattofixed@impl@collectmantissa#9\count\pgfmathfloat@a@E + \fi +}% + +\def\pgfmathfloattofixed@impl@collectmantissa#1#2\count#3{% + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok #1}% + \advance\pgfmathfloat@a@E by-1% + \def\pgfmathfloat@loc@TMPb{#2}% + \ifx\pgfmathfloat@loc@TMPb\pgfutil@empty + \pgfutil@loop + \ifnum\pgfmathfloat@a@E>0% + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok 0}% + \advance\pgfmathfloat@a@E by-1% + \pgfutil@repeat + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok .0}% + \else + \ifnum\pgfmathfloat@a@E=0 + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok .#2}% + \else + \pgfmathfloattofixed@impl@collectmantissa#2\count#3% + \fi + \fi +} + + +% ============================================ +% +% +% \pgfmathfloatparsenumber implementation +% +% +% ============================================ + +% accepted parser tokens: +\def\pgfmathfloatparsenumber@tok@ZERO{0} +\def\pgfmathfloatparsenumber@tok@PLUS{+} +\def\pgfmathfloatparsenumber@tok@MINUS{-} +\def\pgfmathfloatparsenumber@tok@PERIOD{.} + +\newif\ifpgfmathfloatparsenumberpendingperiod + +\def\pgfflt@EOI{p@EOI}% +\def\pgfflt@EOI@unexpanded{\pgfflt@EOI}% + +% Starts a finite-start-machine parser to read a number. +% +% The machine's state is represented by the macro which is currently +% processed; state transitions are realised using \csname...#1\endcsname +% constructions. +% +% It assigns \pgfmathfloat@a@S, \pgfmathfloat@a@Mtok, \pgfmathfloat@a@E. +\def\pgfflt@impl#1{% + \pgfmathfloatparsenumberpendingperiodfalse + \pgfmathfloat@tmptoks={}% this register is used to collect PENDING ZEROS + \pgfmathfloat@a@E=0 + % start parsing: check for sign: + \expandafter\ifx\csname pgfflt@#1\endcsname\relax + \pgfmathfloat@a@S=1 + \expandafter\pgfflt@init\expandafter#1% + \else + \expandafter\expandafter\csname pgfflt@#1\endcsname + \fi +} +% State transitions: +\expandafter\def\csname pgfflt@+\endcsname{% + \pgfmathfloat@a@S=1 % + \pgfflt@init}% +\expandafter\def\csname pgfflt@-\endcsname{% + \pgfmathfloat@a@S=2 % + \pgfflt@init}% +\expandafter\def\csname pgfflt@\pgfflt@EOI\endcsname{% + \pgfmathfloatparsenumber@handleerror{empty number}{}{}}% + +\pgfkeys{ + /pgf/fpu/handlers/empty number/.style 2 args={% + /pgf/fpu/handlers/invalid number={#1}{#2}% + }, + /pgf/fpu/empty number is zero/.style={% + /pgf/fpu/handlers/empty number/.code 2 args={% + \pgfmathfloatcreate{0}{0.0}{0}% + }% + },% + /pgf/fpu/handlers/invalid separator/.code 2 args={% + \pgfmath@error{Could not parse input '#1' as a floating point number, sorry. The unreadable part was near the decimal separator '#2'. Do you need the option 'read comma as period'?}{}% + }, + /pgf/fpu/handlers/invalid number/.code 2 args={% + \pgfmath@error{Could not parse input '#1' as a floating point number, sorry. The unreadable part was near '#2'.}{}% + }, + /pgf/fpu/handlers/wrong lowlevel format/.code 2 args={% + \pgfmath@error{Sorry, an internal routine of the floating point unit got an ill-formatted floating point number `#1'. The unreadable part was near '#2'.}{}% + \let\pgfmathresult=\pgfutil@empty + }, +} + +% #1 the error handler +% #2 the number which was invalid. +% #3 the part which produced the error +% +% POSTCONDITION: the three registers +% \pgfmathfloat@a@S +% \pgfmathfloat@a@Mtok +% \pgfmathfloat@a@E +% will contain the number which results from the error handler. +\def\pgfmathfloatparsenumber@handleerror#1#2#3{% + \let\pgfmathresult=\pgfutil@empty + \pgfmathfloatparsenumberpendingperiodfalse + \pgfkeys{/pgf/fpu/handlers/#1={#2}{#3}}% + \ifx\pgfmathresult\pgfutil@empty + \pgfmathfloat@a@S=3 + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0 + \else + \expandafter\pgfmathfloat@decompose@tok\pgfmathresult\relax\pgfmathfloat@a@S\pgfmathfloat@a@Mtok\pgfmathfloat@a@E + \fi +} +\def\pgfflt@error#1\pgfflt@EOI{% + \begingroup + \pgfmathfloat@a@Mtok={#1}% + \xdef\pgfmathfloat@glob@TMP{% + \noexpand\pgfmathfloatparsenumber@handleerror + {invalid number}{\pgfmathresult}{\the\pgfmathfloat@a@Mtok}}% + \endgroup + \pgfmathfloat@glob@TMP +}% + + + +% FROM: checksign. +% +\def\pgfflt@init#1{% + \expandafter\ifx\csname pgffltA@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltA@#1\endcsname + \fi} +% state transitions: +\expandafter\def\csname pgffltA@0\endcsname{\pgfflt@leadingzero}% FIXME: inline optimization! +\expandafter\def\csname pgffltA@1\endcsname{\pgfflt@nonzerodigit1}% +\expandafter\def\csname pgffltA@2\endcsname{\pgfflt@nonzerodigit2}% +\expandafter\def\csname pgffltA@3\endcsname{\pgfflt@nonzerodigit3}% +\expandafter\def\csname pgffltA@4\endcsname{\pgfflt@nonzerodigit4}% +\expandafter\def\csname pgffltA@5\endcsname{\pgfflt@nonzerodigit5}% +\expandafter\def\csname pgffltA@6\endcsname{\pgfflt@nonzerodigit6}% +\expandafter\def\csname pgffltA@7\endcsname{\pgfflt@nonzerodigit7}% +\expandafter\def\csname pgffltA@8\endcsname{\pgfflt@nonzerodigit8}% +\expandafter\def\csname pgffltA@9\endcsname{\pgfflt@nonzerodigit9}% +\def\pgfflt@nonzerodigit#1{% + \pgfmathfloat@a@Mtok={#1}% + \pgfmathfloatparsenumberpendingperiodtrue + \pgfflt@positiveexp}% +\expandafter\def\csname pgffltA@n\endcsname{\pgfflt@readnan}% FIXME: inlining? +\expandafter\def\csname pgffltA@N\endcsname{\pgfflt@readnan}% FIXME: inlining? +\expandafter\def\csname pgffltA@i\endcsname{\pgfflt@readinf}% FIXME: inlining? +\expandafter\def\csname pgffltA@I\endcsname{\pgfflt@readinf}% FIXME: inlining? +\expandafter\def\csname pgffltA@.\endcsname{% read '.9' like '0.9' + \pgfmathfloat@a@E=-1 + \pgfflt@leadingzero@foundperiod}% +\expandafter\def\csname pgffltA@,\endcsname{% read ',9' like '0,9' + \pgfmathfloat@frenchinput{% + \pgfmathfloat@a@E=-1 + \pgfflt@leadingzero@foundperiod + }% +}% + +\def\pgfmathfloat@frenchinput#1{% + \ifpgfmathparsenumber@comma@as@period + \def\pgf@marshal{#1}% + \expandafter\pgf@marshal + \else + \expandafter\pgfflt@error@separator\expandafter,% + \fi +}% +\def\pgfflt@error@separator#1\pgfflt@EOI{% + \begingroup + \pgfmathfloat@a@Mtok={#1}% + \xdef\pgfmathfloat@glob@TMP{% + \noexpand\pgfmathfloatparsenumber@handleerror + {invalid separator}{\pgfmathresult}{\the\pgfmathfloat@a@Mtok}}% + \endgroup + \pgfmathfloat@glob@TMP +}% + +\def\pgfflt@finish#1\pgfflt@EOI{} + +\def\pgfflt@readnan #1#2{% + \def\pgfflt@readnan@ok{1}% + \if#1a\else\if#1A\else\def\pgfflt@readnan@ok{0}\fi\fi + \if#2n\else\if#2N\else\def\pgfflt@readnan@ok{0}\fi\fi + \if\pgfflt@readnan@ok1% + \pgfmathfloat@a@S=3\relax% + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0% + \expandafter\pgfflt@finish + \else + \def\pgfflt@readnan@{\pgfflt@error #1#2}% + \expandafter\pgfflt@readnan@ + \fi +} +\def\pgfflt@readinf #1#2{% + \def\pgfflt@readinf@ok{1}% + \if#1n\else\if#1N\else\def\pgfflt@readinf@ok{0}\fi\fi + \if#2f\else\if#2F\else\def\pgfflt@readinf@ok{0}\fi\fi + \if\pgfflt@readinf@ok1% + \ifnum\pgfmathfloat@a@S=1 % + \pgfmathfloat@a@S=4 % + \pgfmathfloat@a@Mtok={0.0}% + \else + \pgfmathfloat@a@S=5 % + \pgfmathfloat@a@Mtok={0.0}% + \fi + \pgfmathfloat@a@E=0 % + \expandafter\pgfflt@finish + \else + \def\pgfflt@readinf@{\pgfflt@error #1#2}% + \expandafter\pgfflt@readinf@ + \fi +} +\def\pgfflt@leadingzero#1{% + \expandafter\ifx\csname pgffltB@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltB@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltB@0\endcsname{\pgfflt@leadingzero}% +\expandafter\def\csname pgffltB@1\endcsname{\pgfmathfloat@a@Mtok={1}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@2\endcsname{\pgfmathfloat@a@Mtok={2}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@3\endcsname{\pgfmathfloat@a@Mtok={3}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@4\endcsname{\pgfmathfloat@a@Mtok={4}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@5\endcsname{\pgfmathfloat@a@Mtok={5}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@6\endcsname{\pgfmathfloat@a@Mtok={6}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@7\endcsname{\pgfmathfloat@a@Mtok={7}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@8\endcsname{\pgfmathfloat@a@Mtok={8}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@9\endcsname{\pgfmathfloat@a@Mtok={9}\pgfmathfloatparsenumberpendingperiodtrue \pgfflt@positiveexp} +\expandafter\def\csname pgffltB@\pgfmathfloat@POSTFLAGSCHAR\endcsname{\pgfmathfloat@a@Mtok={0}\pgfflt@readlowlevelfloat}% +\expandafter\def\csname pgffltB@.\endcsname{% + \pgfmathfloat@a@E=-1 + \pgfflt@leadingzero@foundperiod}% +\expandafter\def\csname pgffltB@,\endcsname{% + \pgfmathfloat@frenchinput{% + \pgfmathfloat@a@E=-1 + \pgfflt@leadingzero@foundperiod + }% +}% +\expandafter\def\csname pgffltB@e\endcsname{% + \pgfmathfloat@a@S=0\relax% + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0% + \pgfflt@readexponent}% +\let\pgffltB@E=\pgffltB@e +\expandafter\def\csname pgffltB@\pgfflt@EOI\endcsname{% + \pgfmathfloat@a@S=0\relax% + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0}% + +\def\pgfflt@leadingzero@foundperiod#1{% + \expandafter\ifx\csname pgffltC@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltC@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltC@0\endcsname{% + \advance\pgfmathfloat@a@E by-1 + \pgfflt@leadingzero@foundperiod}% +\expandafter\def\csname pgffltC@1\endcsname{\pgfmathfloat@a@Mtok={1}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@2\endcsname{\pgfmathfloat@a@Mtok={2}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@3\endcsname{\pgfmathfloat@a@Mtok={3}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@4\endcsname{\pgfmathfloat@a@Mtok={4}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@5\endcsname{\pgfmathfloat@a@Mtok={5}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@6\endcsname{\pgfmathfloat@a@Mtok={6}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@7\endcsname{\pgfmathfloat@a@Mtok={7}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@8\endcsname{\pgfmathfloat@a@Mtok={8}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@9\endcsname{\pgfmathfloat@a@Mtok={9}\pgfmathfloatparsenumberpendingperiodtrue\pgfflt@finish@number@after@period}% +\expandafter\def\csname pgffltC@e\endcsname{% + \pgfmathfloat@a@S=0\relax% + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0% + \pgfflt@readexponent}% +\let\pgffltC@E=\pgffltC@e +\expandafter\def\csname pgffltC@\pgfflt@EOI\endcsname{% + \pgfmathfloat@a@S=0\relax% + \pgfmathfloat@a@Mtok={0.0}% + \pgfmathfloat@a@E=0}% + + +\def\pgfflt@positiveexp#1{% + \expandafter\ifx\csname pgffltD@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltD@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltD@0\endcsname{% + \advance\pgfmathfloat@a@E by1 + \pgfmathfloat@tmptoks=\expandafter{\the\pgfmathfloat@tmptoks0}% + \pgfflt@pendingzeros@positiveexp}% +\expandafter\def\csname pgffltD@1\endcsname{\pgffltD@nonzerodigit1}% +\expandafter\def\csname pgffltD@2\endcsname{\pgffltD@nonzerodigit2}% +\expandafter\def\csname pgffltD@3\endcsname{\pgffltD@nonzerodigit3}% +\expandafter\def\csname pgffltD@4\endcsname{\pgffltD@nonzerodigit4}% +\expandafter\def\csname pgffltD@5\endcsname{\pgffltD@nonzerodigit5}% +\expandafter\def\csname pgffltD@6\endcsname{\pgffltD@nonzerodigit6}% +\expandafter\def\csname pgffltD@7\endcsname{\pgffltD@nonzerodigit7}% +\expandafter\def\csname pgffltD@8\endcsname{\pgffltD@nonzerodigit8}% +\expandafter\def\csname pgffltD@9\endcsname{\pgffltD@nonzerodigit9}% +\expandafter\def\csname pgffltD@\pgfmathfloat@POSTFLAGSCHAR\endcsname{\pgfflt@readlowlevelfloat}% +\expandafter\def\csname pgffltD@.\endcsname{\pgfflt@finish@number@after@period}% FIXME : inlining? +\expandafter\def\csname pgffltD@,\endcsname{\pgfmathfloat@frenchinput{\pgfflt@finish@number@after@period}}% +\expandafter\def\csname pgffltD@e\endcsname{\pgfflt@readexponent}% FIXME : inlining? +\let\pgffltD@E=\pgffltD@e +\expandafter\def\csname pgffltD@\pgfflt@EOI\endcsname{}% NOP +\def\pgffltD@nonzerodigit#1{% + \advance\pgfmathfloat@a@E by1 + \ifpgfmathfloatparsenumberpendingperiod + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok.}% + \pgfmathfloatparsenumberpendingperiodfalse + \fi + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok#1}% + \pgfflt@positiveexp}% + +% Read a low-level floating point. +% Since we are in the second state, \pgfmathfloat@a@Mtok contains the +% FLAGS. The post-flags-char has also been read. +\def\pgfflt@readlowlevelfloat#1e#2]\pgfflt@EOI{% + \pgfmathfloatparsenumberpendingperiodfalse + \pgfmathfloat@a@S=\the\pgfmathfloat@a@Mtok\relax + \pgfmathfloat@a@Mtok={#1}% + \pgfmathfloat@a@E=#2 +}% + +\def\pgfflt@readexponent#1\pgfflt@EOI{% + \afterassignment\pgfflt@readexponent@ + \pgfmathfloat@b@E=#1 \pgfflt@EOI% the white space is important, otherwise \pgfflt@EOI will be expanded. +} +\def\pgfflt@readexponent@#1{% + \advance\pgfmathfloat@a@E by\pgfmathfloat@b@E\relax + % + % sanity checking: + \def\pgfmathfloat@loc@TMPb{#1}% + \ifx\pgfmathfloat@loc@TMPb\pgfflt@EOI@unexpanded + \else + \def\pgfmathfloat@loc@TMPb{\pgfflt@error#1}% + \expandafter\pgfmathfloat@loc@TMPb + \fi +} + +\def\pgfflt@pendingzeros@positiveexp#1{% + \expandafter\ifx\csname pgffltE@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltE@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltE@0\endcsname{% + \pgfmathfloat@tmptoks=\expandafter{\the\pgfmathfloat@tmptoks0}% + \advance\pgfmathfloat@a@E by1 + \pgfflt@pendingzeros@positiveexp}% +\expandafter\def\csname pgffltE@1\endcsname{\pgffltE@nonzerodigit1}% +\expandafter\def\csname pgffltE@2\endcsname{\pgffltE@nonzerodigit2}% +\expandafter\def\csname pgffltE@3\endcsname{\pgffltE@nonzerodigit3}% +\expandafter\def\csname pgffltE@4\endcsname{\pgffltE@nonzerodigit4}% +\expandafter\def\csname pgffltE@5\endcsname{\pgffltE@nonzerodigit5}% +\expandafter\def\csname pgffltE@6\endcsname{\pgffltE@nonzerodigit6}% +\expandafter\def\csname pgffltE@7\endcsname{\pgffltE@nonzerodigit7}% +\expandafter\def\csname pgffltE@8\endcsname{\pgffltE@nonzerodigit8}% +\expandafter\def\csname pgffltE@9\endcsname{\pgffltE@nonzerodigit9}% +\expandafter\def\csname pgffltE@.\endcsname{\pgfflt@finish@number@after@period}% FIXME : inlining? +\expandafter\def\csname pgffltE@,\endcsname{\pgfmathfloat@frenchinput{\pgfflt@finish@number@after@period}}% FIXME : inlining? +\def\pgffltE@e{\pgfflt@readexponent}% FIXME : inlining? +\let\pgffltE@E=\pgffltE@e +\expandafter\def\csname pgffltE@\pgfflt@EOI\endcsname{}% NOP +\def\pgffltE@nonzerodigit#1{% + \advance\pgfmathfloat@a@E by1 + \ifpgfmathfloatparsenumberpendingperiod + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok.}% + \pgfmathfloatparsenumberpendingperiodfalse + \fi + \pgfmathfloat@a@Mtok=\expandafter\expandafter\expandafter{\expandafter\the\expandafter\pgfmathfloat@a@Mtok\the\pgfmathfloat@tmptoks}% + \pgfmathfloat@tmptoks={}% + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok#1}% + \pgfflt@positiveexp}% + +\def\pgfflt@finish@number@after@period#1{% + \expandafter\ifx\csname pgffltF@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltF@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltF@0\endcsname{% + \pgfmathfloat@tmptoks=\expandafter{\the\pgfmathfloat@tmptoks0}% + \pgfflt@pendingzeros}% +\expandafter\def\csname pgffltF@1\endcsname{\pgffltF@nonzerodigit1}% +\expandafter\def\csname pgffltF@2\endcsname{\pgffltF@nonzerodigit2}% +\expandafter\def\csname pgffltF@3\endcsname{\pgffltF@nonzerodigit3}% +\expandafter\def\csname pgffltF@4\endcsname{\pgffltF@nonzerodigit4}% +\expandafter\def\csname pgffltF@5\endcsname{\pgffltF@nonzerodigit5}% +\expandafter\def\csname pgffltF@6\endcsname{\pgffltF@nonzerodigit6}% +\expandafter\def\csname pgffltF@7\endcsname{\pgffltF@nonzerodigit7}% +\expandafter\def\csname pgffltF@8\endcsname{\pgffltF@nonzerodigit8}% +\expandafter\def\csname pgffltF@9\endcsname{\pgffltF@nonzerodigit9}% +\def\pgffltF@e{\pgfflt@readexponent}% +\let\pgffltF@E=\pgffltF@e +\expandafter\def\csname pgffltF@\pgfflt@EOI\endcsname{}% NOP +\def\pgffltF@nonzerodigit#1{% + \ifpgfmathfloatparsenumberpendingperiod + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok.}% + \pgfmathfloatparsenumberpendingperiodfalse + \fi + \pgfmathfloat@a@Mtok=\expandafter\expandafter\expandafter{\expandafter\the\expandafter\pgfmathfloat@a@Mtok\the\pgfmathfloat@tmptoks}% + \pgfmathfloat@tmptoks={}% + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok#1}% + \pgfflt@finish@number@after@period}% + + +\def\pgfflt@pendingzeros#1{% + \expandafter\ifx\csname pgffltG@#1\endcsname\relax + \expandafter\pgfflt@error\expandafter#1% + \else + \expandafter\expandafter\csname pgffltG@#1\endcsname + \fi} +% State transitions: +\expandafter\def\csname pgffltG@0\endcsname{% + \pgfmathfloat@tmptoks=\expandafter{\the\pgfmathfloat@tmptoks0}% + \pgfflt@pendingzeros}% +\expandafter\def\csname pgffltG@1\endcsname{\pgffltG@nonzerodigit1}% +\expandafter\def\csname pgffltG@2\endcsname{\pgffltG@nonzerodigit2}% +\expandafter\def\csname pgffltG@3\endcsname{\pgffltG@nonzerodigit3}% +\expandafter\def\csname pgffltG@4\endcsname{\pgffltG@nonzerodigit4}% +\expandafter\def\csname pgffltG@5\endcsname{\pgffltG@nonzerodigit5}% +\expandafter\def\csname pgffltG@6\endcsname{\pgffltG@nonzerodigit6}% +\expandafter\def\csname pgffltG@7\endcsname{\pgffltG@nonzerodigit7}% +\expandafter\def\csname pgffltG@8\endcsname{\pgffltG@nonzerodigit8}% +\expandafter\def\csname pgffltG@9\endcsname{\pgffltG@nonzerodigit9}% +\def\pgffltG@e{\pgfflt@readexponent}% FIXME: inlining? +\let\pgffltG@E=\pgffltG@e +\expandafter\def\csname pgffltG@\pgfflt@EOI\endcsname{}% NOP +\def\pgffltG@nonzerodigit#1{% + \ifpgfmathfloatparsenumberpendingperiod + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok.}% + \pgfmathfloatparsenumberpendingperiodfalse + \fi + \pgfmathfloat@a@Mtok=\expandafter\expandafter\expandafter{\expandafter\the\expandafter\pgfmathfloat@a@Mtok\the\pgfmathfloat@tmptoks}% + \pgfmathfloat@tmptoks={}% + \pgfmathfloat@a@Mtok=\expandafter{\the\pgfmathfloat@a@Mtok#1}% + \pgfflt@finish@number@after@period}% + +\endinput diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.base.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.base.code.tex new file mode 100644 index 0000000000..fcf5503b36 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.base.code.tex @@ -0,0 +1,330 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. +% +% This file provides basic macros for converting between bases. +% +% Version 1.4142135 8/11/2008 + +% Base conversion operations for the parser. +% +\pgfmathdeclarefunction{bin}{1}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=#1\relax\pgfmath@% + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\the\c@pgfmath@counta}{10}{2}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} +\pgfmathdeclarefunction{hex}{1}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=#1\relax\pgfmath@% + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\the\c@pgfmath@counta}{10}{16}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +\pgfmathdeclarefunction{Hex}{1}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=#1\relax\pgfmath@% + \expandafter\pgfmathbasetoBase\expandafter\pgfmathresult\expandafter{\the\c@pgfmath@counta}{10}{16}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +\pgfmathdeclarefunction{oct}{1}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=#1\relax\pgfmath@% + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\the\c@pgfmath@counta}{10}{8}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% Additional macros: + +% \pgfmathbasetodec +% +% Convert a representation of an integer from +% the specified base to base 10. +% +% #1 - a macro to store the result. +% #2 - the representation of a number (i.e. not a register) +% #3 - the current base. +% +% e.g. +% +% \pgfmathbasetodec\mynumber{10111}{2} +% +% \mynumber <- 23 +% +\def\pgfmathbasetodec#1#2#3{% + \pgfmath@checknumber{#2}% + \pgfmath@checkbase{#3}% + \def\pgfmath@base{#3}% + \def\pgfmath@base@macro{#1}% + \c@pgfmath@counta=1\relax% + \let\pgfmath@reversed=\pgfmath@empty% + \expandafter\pgfmathbasetodec@#2\pgfmath@base@stop} + +\def\pgfmathbasetodec@#1{% + \ifx#1\pgfmath@base@stop% + \c@pgfmath@countb=0% + \divide\c@pgfmath@counta by\pgfmath@base\relax% + \expandafter\pgfmathbasetodec@@% + \else% + \edef\pgfmath@reversed{\pgfmath@reversed#1}% + \expandafter\multiply\expandafter\c@pgfmath@counta\pgfmath@base\relax% + \expandafter\pgfmathbasetodec@% + \fi} + +\def\pgfmathbasetodec@@{\expandafter\pgfmathbasetodec@@@\pgfmath@reversed\pgfmathbasetodec} + +\def\pgfmathbasetodec@@@#1{% + \ifx\pgfmathbasetodec#1\relax% + \expandafter\edef\pgfmath@base@macro{\the\c@pgfmath@countb}% + \let\pgfmath@next=\pgfmathbasetodec@@@@% + \else% + \chardef\pgfmath@charnum`#1\relax% + \c@pgfmath@countc=\pgfmath@charnum\relax% + \ifnum\c@pgfmath@countc>96\relax% + \advance\c@pgfmath@countc by-87\relax% + \else + \ifnum\c@pgfmath@countc>64\relax% + \advance\c@pgfmath@countc by-55\relax% + \else + \advance\c@pgfmath@countc by-48\relax% + \fi% + \fi% + \ifnum\c@pgfmath@countc<\pgfmath@base\relax% + \multiply\c@pgfmath@countc by\c@pgfmath@counta% + \advance\c@pgfmath@countb by\c@pgfmath@countc% + \divide\c@pgfmath@counta by\pgfmath@base\relax% + \let\pgfmath@next\pgfmathbasetodec@@@% + \else + \pgfmath@error{Digit `#1' invalid for base \pgfmath@base}{}% + \let\pgfmath@next=\relax% + \fi% + \fi% + \pgfmath@next} +\def\pgfmathbasetodec@@@@{% + \expandafter\pgfmath@ensurenumberlength\expandafter{\pgfmath@base@macro}% +} + +% \pgfmathdectobase +% +% Convert a representation of an integer from +% base 10 to the specified base. Letters for bases +% greater than 10 are in lowercase. +% +% #1 - a macro to store the result. +% #2 - a number in base 10 (in a macro, not a register) +% #3 - the required base. +% +% e.g. +% +% \pgfmathdectobase\mynumber{127}{16} +% +% \mynumber <- 7f +% +\def\pgfmathdectobase#1#2#3{% + \pgfmath@checknumber{#2}% + \pgfmath@checkbase{#3}% + \c@pgfmath@counta=#2\relax% + \let#1=\pgfmath@empty% + \pgfmathloop + \ifnum\c@pgfmath@counta>0\relax% + \c@pgfmath@countb=\c@pgfmath@counta% + \divide\c@pgfmath@countb by#3\relax% + \multiply\c@pgfmath@countb by-#3\relax% + \advance\c@pgfmath@countb by\c@pgfmath@counta% + \edef#1{\csname pgfmath@lowercase digit@\the\c@pgfmath@countb\endcsname#1}% + \divide\c@pgfmath@counta by#3\relax% + \repeatpgfmathloop% + \pgfmath@ensurenumberlength{#1}} + +% \pgfmathdectoBase +% +% Convert a representation of an integer from +% base 10 to the specified base. Letters for bases +% greater than 10 are in uppercase. +% +% #1 - a macro to store the result. +% #2 - a number in base 10 (in a macro, not a register) +% #3 - the required base. +% +% e.g. +% +% \pgfmathdectoBase\mynumber{127}{16} +% +% \mynumber <- 7F +% +\def\pgfmathdectoBase#1#2#3{% + \pgfmath@checkbase{#3}% + \pgfmath@checknumber{#2}% + \c@pgfmath@counta=#2\relax% + \let#1=\pgfmath@empty% + \pgfmathloop + \ifnum\c@pgfmath@counta>0\relax% + \c@pgfmath@countb=\c@pgfmath@counta% + \divide\c@pgfmath@countb by#3\relax% + \multiply\c@pgfmath@countb by-#3\relax% + \advance\c@pgfmath@countb by\c@pgfmath@counta% + \edef#1{\csname pgfmath@uppercase digit@\the\c@pgfmath@countb\endcsname#1}% + \divide\c@pgfmath@counta by#3\relax% + \repeatpgfmathloop% + \pgfmath@ensurenumberlength{#1}} + +\def\pgfmath@base@digits@create{% + \def\pgfmath@base@digit@style{lowercase digit}% + \c@pgfmath@counta=0\relax% + \pgfmath@base@digits@create@0123456789abcdefghijklmnopqrstuvwxyz\pgfmath@base@digits@create% + \def\pgfmath@base@digit@style{uppercase digit}% + \c@pgfmath@counta=0\relax% + \pgfmath@base@digits@create@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\pgfmath@base@digits@create} + +\def\pgfmath@base@digits@create@#1{% + \ifx\pgfmath@base@digits@create#1\relax% + \else% + \expandafter\pgfmath@def\expandafter{\pgfmath@base@digit@style}{\the\c@pgfmath@counta}{#1}% + \advance\c@pgfmath@counta by1\relax% + \expandafter\pgfmath@base@digits@create@% + \fi} +\pgfmath@base@digits@create + +% \pgfmathbasetobase +% +% Convert a representation of an integer from +% between the specified bases. Letters for target +% bases greater than 10 are in uppercase. +% +% #1 - a macro to store the result. +% #2 - a number (in a macro, not a register) +% #3 - the source base. +% #4 - the target base. +% +% e.g. +% +% \pgfmathbasetobase\mynumber{4321}{5}{9} +% +% \mynumber <- 721 +% +\def\pgfmathbasetobase#1#2#3#4{% + \pgfmathbasetodec{\pgfmath@base@temp}{#2}{#3}% + \pgfmathdectobase{#1}{\pgfmath@base@temp}{#4}% +} + +% \pgfmathbasetobase +% +% Convert a representation of an integer from +% between the specified bases. Letters for target +% bases greater than 10 are in uppercase. +% +% #1 - a macro to store the result. +% #2 - a number (in a macro, not a register) +% #3 - the source base. +% #4 - the target base. +% +% e.g. +% +% \pgfmathbasetobase\mynumber{1234}{5}{12} +% +% \mynumber <- 142 +% +\def\pgfmathbasetoBase#1#2#3#4{% + \pgfmathbasetodec{\pgfmath@base@temp}{#2}{#3}% + \pgfmathdectoBase{#1}{\pgfmath@base@temp}{#4}% +} + +\def\pgfmath@checkbase#1{% + \ifnum#1<2\relax% + \pgfmath@error{Cannot process numbers in base `#1'.}{}% + \else% + \ifnum#1>36\relax% + \pgfmath@error{Cannot process numbers in base `#1'.}{}% + \fi% + \fi} + +\def\pgfmath@checknumber#1{% + \expandafter\pgfmath@checknumber@#1\pgfmath@} +\def\pgfmath@checknumber@#1#2\pgfmath@{% + \ifx#1-% + \pgfmath@error{Cannot process negative numbers.}{}% + \fi} + +% \pgfmath@ensurenumberlength +% +% Internal macro for making a representation of a number have +% a specific length, byte prefixing zeros to the number. +% +% #1 - a macro containing a representation of an integer. +% #2 - the number of digits to ensure. +% +% e.g. +% +% \foo <- 7FF +% +% \pgfmathsetnumberlength{8}% +% \pgfmath@ensurenumberlength\foo +% +% \foo <- 000007FF +% +\def\pgfmath@ensurenumberlength#1{% + \def\pgfmath@base@tempa{#1}% + \expandafter\c@pgfmath@counta\pgfmath@basenumberlength\relax% + \expandafter\pgfmath@ensurenumberlength@#1\pgfmath@ensurenumberlength} +\def\pgfmath@ensurenumberlength@#1{% + \ifx\pgfmath@ensurenumberlength#1\relax% + \expandafter\pgfmath@ensurenumberlength@@% + \else% + \advance\c@pgfmath@counta by-1\relax% + \expandafter\pgfmath@ensurenumberlength@ + \fi} + +\def\pgfmath@ensurenumberlength@@{% + \edef\pgfmath@base@tempb{\pgfmath@base@tempa}% + \pgfmath@ensurenumberlength@@@} +\def\pgfmath@ensurenumberlength@@@{% + \ifnum\c@pgfmath@counta>0\relax% + \advance\c@pgfmath@counta by-1\relax% + \edef\pgfmath@base@tempb{0\pgfmath@base@tempb}% + \expandafter\pgfmath@ensurenumberlength@@@% + \fi% + \expandafter\edef\pgfmath@base@tempa{\pgfmath@base@tempb}} + +\def\pgfmathsetbasenumberlength#1{\def\pgfmath@basenumberlength{#1}} +\pgfmathsetbasenumberlength{1}% + +% \pgfmathtodigitlist\marg{macro}\marg{number}} +% +% This command converts \meta{number} into a comma-separated +% list of digits and stores the result in \meta{macro}. +% The \marg{number} is \emph{not} parsed before processing. +% +\def\pgfmathtodigitlist#1#2{% + \def\pgfmath@temp{#1}% + \let\pgfmath@digitlist=\pgfutil@empty% + \edef\pgfmath@@tmp{#2}% + \expandafter\pgfmath@todigitlist\pgfmath@@tmp @% +} +\def\pgfmath@base@atchar{@} +\def\pgfmath@todigitlist#1{% + \def\pgfmath@digit{#1}% + \ifx\pgfmath@digit\pgfmath@base@atchar% + \expandafter\let\pgfmath@temp=\pgfmath@digitlist% + \else% + \ifx\pgfmath@digitlist\pgfutil@empty% + \edef\pgfmath@digitlist{#1}% + \else% + \edef\pgfmath@digitlist{\pgfmath@digitlist,#1}% + \fi% + \expandafter\pgfmath@todigitlist% + \fi% +} diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.basic.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.basic.code.tex new file mode 100644 index 0000000000..1607c386e8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.basic.code.tex @@ -0,0 +1,803 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the mathematical functions and operators. +% +% Version 1.4142135 25/8/2008 + +% add function. +% +\pgfmathdeclarefunction{add}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@y=#2pt\relax% + \advance\pgfmath@x by\pgfmath@y% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + + +% subtract function. +% +\pgfmathdeclarefunction{subtract}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@y=#2pt\relax% + \advance\pgfmath@x by-\pgfmath@y% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% neg function. +% +\pgfmathdeclarefunction{neg}{1}{% + \begingroup% + \pgfmath@x=-#1pt\relax% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} +% change the precedence for neg. +% Otherwise, unary minus and exponentiation won't have the correct precedence +% (test '-2^2') +\def\pgfmath@operation@neg@precedence{500} + +% multiply function. +% +\pgfmathdeclarefunction{multiply}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@y=#2pt\relax% + \pgfmath@x=\pgfmath@tonumber{\pgfmath@y}\pgfmath@x% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% divide function. +% +\newif\ifpgfmath@divide@period + +\pgfmathdeclarefunction{divide}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@y=#2pt\relax% + \let\pgfmath@sign=\pgfmath@empty% + \ifdim0pt=\pgfmath@y% + \pgfmath@error{You've asked me to divide `#1' by `#2', % + but I cannot divide any number by `#2'}{}% + \fi% + \afterassignment\pgfmath@xa% + \c@pgfmath@counta\the\pgfmath@y\relax% + \ifdim0pt=\pgfmath@xa% + \divide\pgfmath@x by\c@pgfmath@counta% + \else% + \ifdim0pt>\pgfmath@x% + \def\pgfmath@sign{-}% + \pgfmath@x=-\pgfmath@x% + \fi% + \ifdim0pt>\pgfmath@y% + \expandafter\def\expandafter\pgfmath@sign\expandafter{\pgfmath@sign-}% + \pgfmath@y=-\pgfmath@y% + \fi% + \ifdim1pt>\pgfmath@y% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgfmath@y}}% + \pgfmath@x=\pgfmath@sign\pgfmathresult\pgfmath@x% + \else% + \def\pgfmathresult{0}% + \pgfmath@divide@periodtrue% + \c@pgfmath@counta=0\relax% + \pgfmathdivide@@% + \pgfmath@x=\pgfmath@sign\pgfmathresult pt\relax% + \fi% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +\def\pgfmath@small@number{0.00002} + +\def\pgfmathdivide@@{% + \let\pgfmath@next=\relax% + \ifdim\pgfmath@small@number pt<\pgfmath@x% + \ifdim\pgfmath@small@number pt<\pgfmath@y% + \ifdim\pgfmath@y>\pgfmath@x% + \ifpgfmath@divide@period% + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult.}% + \pgfmath@divide@periodfalse% + \fi% + \pgfmathdivide@dimenbyten\pgfmath@y% + \ifdim\pgfmath@y>\pgfmath@x% + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult0}% + \fi% + \else% + \c@pgfmath@counta=\pgfmath@x% + \c@pgfmath@countb=\pgfmath@y% + \divide\c@pgfmath@counta by\c@pgfmath@countb% + \pgfmath@ya=\c@pgfmath@counta\pgfmath@y% + \advance\pgfmath@x by-\pgfmath@ya% + \def\pgfmath@next{% + \toks0=\expandafter{\pgfmathresult}% + \edef\pgfmathresult{\the\toks0 \the\c@pgfmath@counta}% + }% + \ifpgfmath@divide@period + \else + % we are behind the period. It may happen that the + % result is more than one digit - in that case, + % introduce special handling: + \ifnum\c@pgfmath@counta>9 % + \expandafter\pgfmathdivide@advance@last@digit\pgfmathresult CCCCC\@@ + \advance\c@pgfmath@counta by-10 % + \ifnum\c@pgfmath@counta=0 + \let\pgfmath@next=\relax + \fi + \fi + \fi + \pgfmath@next + \fi% + \let\pgfmath@next=\pgfmathdivide@@% + \fi% + \fi% + \pgfmath@next% +} + +% advances the last digit found in the number. Any missing digits are +% supposed to be filled with 'C'. +\def\pgfmathdivide@advance@last@digit#1.#2#3#4#5#6#7\@@{% + \pgfmath@ya=\pgfmathresult pt % + \if#2C% + \pgfmath@xa=1pt % + \else + \if#3C% + \pgfmath@xa=0.1pt % + \else + \if#4C% + \pgfmath@xa=0.01pt % + \else + \if#5C% + \pgfmath@xa=0.001pt % + \else + \if#6C% + \pgfmath@xa=0.0001pt % + \else + \pgfmath@xa=0.00001pt % + \fi + \fi + \fi + \fi + \fi + \advance\pgfmath@ya by\pgfmath@xa + \edef\pgfmathresult{\pgfmath@tonumber@notrailingzero\pgfmath@ya}% +}% + +{ +\catcode`\p=12 +\catcode`\t=12 +\gdef\Pgf@geT@NO@TRAILING@ZERO#1.#2pt{% + #1.% + \ifnum#2=0 \else #2\fi +} +} +\def\pgfmath@tonumber@notrailingzero#1{\expandafter\Pgf@geT@NO@TRAILING@ZERO\the#1} + + +\def\pgfmathdivide@dimenbyten#1{% + \edef\pgfmath@temp{\pgfmath@tonumber{#1}}% + \expandafter\pgfmathdivide@@dimenbyten\pgfmath@temp\@@#1\@@} +\def\pgfmathdivide@@dimenbyten#1.#2\@@#3\@@{% + \pgfmath@tempcnta=#1\relax% + \divide\pgfmath@tempcnta by10\relax% + \pgfmath@tempcntb=\pgfmath@tempcnta% + \multiply\pgfmath@tempcnta by-10\relax% + \advance\pgfmath@tempcnta by#1\relax% + #3=\the\pgfmath@tempcntb.\the\pgfmath@tempcnta#2pt\relax% +} + + +% reciprocal function. +% +\pgfmathdeclarefunction{reciprocal}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \ifdim\pgfmath@x=0pt\relax% + \pgfmath@error{You asked me to calculate `1/#1', but I cannot divide any number by zero}{}% + \fi% + \edef\pgfmath@reciprocaltemp{\pgfmath@tonumber{\pgfmath@x}}% + \expandafter\pgfmathreciprocal@@\pgfmath@reciprocaltemp0000000\pgfmath@} +\def\pgfmathreciprocal@@#1.#2#3#4#5#6#7\pgfmath@{% + \c@pgfmath@counta#2#3#4#5#6\relax% + % If the number is an integer, use TeX arithmetic. + \ifnum\c@pgfmath@counta=0\relax% + \pgfmath@x1pt\relax% + \divide\pgfmath@x#1\relax% + \else% + \ifnum#1>100\relax% + \c@pgfmath@counta#1#2#3#4\relax% + \c@pgfmath@countb1000000000\relax% + \divide\c@pgfmath@countb\c@pgfmath@counta% + \c@pgfmath@counta\c@pgfmath@countb% + \divide\c@pgfmath@counta10000\relax% + \pgfmath@x\c@pgfmath@counta pt\relax% + \multiply\c@pgfmath@counta-10000\relax% + \advance\c@pgfmath@countb\c@pgfmath@counta% + \pgfmath@y\c@pgfmath@countb pt\relax% + \divide\pgfmath@y1000000\relax% + \advance\pgfmath@x\pgfmath@y% + \else% + \c@pgfmath@counta#1#2#3#4#5#6\relax% + \c@pgfmath@countb1000000000\relax% + \divide\c@pgfmath@countb\c@pgfmath@counta% + \c@pgfmath@counta\c@pgfmath@countb% + \divide\c@pgfmath@counta10000\relax% + \pgfmath@x\c@pgfmath@counta pt\relax% + \multiply\c@pgfmath@counta-10000\relax% + \advance\c@pgfmath@countb\c@pgfmath@counta% + \pgfmath@y\c@pgfmath@countb pt\relax% + \pgfmath@y.1\pgfmath@y% Yes! This way is more accurate. Go figure... + \pgfmath@y.1\pgfmath@y% + \pgfmath@y.1\pgfmath@y% + \pgfmath@y.1\pgfmath@y% + \advance\pgfmath@x\pgfmath@y% + \fi% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% div function. +% +\pgfmathdeclarefunction{div}{2}{% + \begingroup% + \pgfmathdivide@{#1}{#2}% + \ifdim\pgfmathresult pt<0pt\relax% + \pgfmathceil@{\pgfmathresult}% + \else% + \pgfmathfloor@{\pgfmathresult}% + \fi% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=\pgfmathresult\relax\pgfmath@% + \edef\pgfmathresult{\the\c@pgfmath@counta}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% mod function. +% +\pgfmathdeclarefunction{mod}{2}{% + \begingroup% + \pgfmath@xa#1pt% + \pgfmath@xb#2pt% + \pgfmath@x\pgfmath@xa% + \c@pgfmath@counta\pgfmath@xa% + \c@pgfmath@countb\pgfmath@xb% + \divide\c@pgfmath@counta\c@pgfmath@countb% + \multiply\pgfmath@xb\c@pgfmath@counta% + \advance\pgfmath@x-\pgfmath@xb% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% Mod function (never negative). +% +\pgfmathdeclarefunction{Mod}{2}{% + \begingroup% + \pgfmathmod@{#1}{#2}% + \pgfmath@x=\pgfmathresult pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \advance\pgfmath@x by#2pt\relax% + \fi% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% abs function. +% +\pgfmathdeclarefunction{abs}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% sign(x) +\pgfmathdeclarefunction{sign}{1}{% + \begingroup + \ifdim#1pt>0sp % + \def\pgfmathresult{1}% + \else + \ifdim#1pt=0sp % + \def\pgfmathresult{0}% + \else + \def\pgfmathresult{-1}% + \fi + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup +} + +% e constant. +% +\pgfmathdeclarefunction{e}{0}{\def\pgfmathresult{2.718281828}} + +% ln function. +% +% This is based on an algorithm due to Rouben Rostamian and +% uses coefficients contributed by Alain Matthes. +% +\pgfmathdeclarefunction{ln}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \ifdim\pgfmath@x>0pt\else% + \pgfmath@error{I cannot calculate the logarithm of `#1'}{}% + \fi% + \c@pgfmath@counta=0\relax% + \ifdim\pgfmath@x>2pt\relax% + \ifdim\pgfmath@x<128pt\relax% + \ifdim\pgfmath@x<8pt\relax% + \ifdim\pgfmath@x<4pt\relax% + \divide\pgfmath@x by2\relax% + \c@pgfmath@counta=1\relax% + \else% + \divide\pgfmath@x by4\relax% + \c@pgfmath@counta=2\relax% + \fi% + \else% + \ifdim\pgfmath@x<32pt\relax% + \ifdim\pgfmath@x<16pt\relax% + \divide\pgfmath@x by8\relax% + \c@pgfmath@counta=3\relax% + \else% + \divide\pgfmath@x by16\relax% + \c@pgfmath@counta=4\relax% + \fi% + \else% + \ifdim\pgfmath@x<64pt\relax% + \divide\pgfmath@x by32\relax% + \c@pgfmath@counta=5\relax% + \else% + \divide\pgfmath@x by64\relax% + \c@pgfmath@counta=6\relax% + \fi% + \fi% + \fi% + \else% + \ifdim\pgfmath@x<2048pt\relax% + \ifdim\pgfmath@x<512pt\relax% + \ifdim\pgfmath@x<256pt\relax% + \divide\pgfmath@x by128\relax% + \c@pgfmath@counta=7\relax% + \else% + \divide\pgfmath@x by256\relax% + \c@pgfmath@counta=8\relax% + \fi% + \else% + \ifdim\pgfmath@x<1024pt\relax% + \divide\pgfmath@x by512\relax% + \c@pgfmath@counta=9\relax% + \else% + \divide\pgfmath@x by1024\relax% + \c@pgfmath@counta=10\relax% + \fi% + \fi% + \else% + \ifdim\pgfmath@x<8192pt\relax% + \ifdim\pgfmath@x<4096pt\relax% + \divide\pgfmath@x by2048\relax% + \c@pgfmath@counta=11\relax% + \else% + \divide\pgfmath@x by4096\relax% + \c@pgfmath@counta =12\relax% + \fi% + \else% + \divide\pgfmath@x by8192\relax% + \c@pgfmath@counta=13\relax% + \fi% + \fi% + \fi% + \else% + \ifdim\pgfmath@x<1pt\relax% + \ifdim\pgfmath@x>0.0078125pt\relax% 2^-7 + \ifdim\pgfmath@x>0.125pt\relax% 2^-3 + \ifdim\pgfmath@x>0.5pt\relax% 2^-1 + \multiply\pgfmath@x by2\relax% + \c@pgfmath@counta=-1\relax% + \else% + \multiply\pgfmath@x by4\relax% + \c@pgfmath@counta=-2\relax% + \fi% + \else% + \ifdim\pgfmath@x>0.03125pt\relax% 2^-5 + \ifdim\pgfmath@x>0.0625pt\relax% + \multiply\pgfmath@x by8\relax% + \c@pgfmath@counta=-3\relax% + \else% + \multiply\pgfmath@x by16\relax% + \c@pgfmath@counta=-4\relax% + \fi% + \else% + \ifdim\pgfmath@x>0.015625pt\relax% 2^-6 + \multiply\pgfmath@x by32\relax% + \c@pgfmath@counta=-5\relax% + \else% + \multiply\pgfmath@x by64\relax% + \c@pgfmath@counta=-6\relax% + \fi% + \fi% + \fi% + \else% + \ifdim\pgfmath@x>0.00048828125pt\relax% 2^-11 + \ifdim\pgfmath@x>0.001953125pt\relax% 2^-9 + \ifdim\pgfmath@x>0.00390625pt\relax% 2^-8 + \multiply\pgfmath@x by128\relax% + \c@pgfmath@counta=-7\relax% + \else% + \multiply\pgfmath@x by256\relax% + \c@pgfmath@counta=-8\relax% + \fi% + \else% + \ifdim\pgfmath@x>0.0009765625pt\relax% 2^-10 + \multiply\pgfmath@x by512\relax% + \c@pgfmath@counta=-9\relax% + \else% + \multiply\pgfmath@x by1024\relax% + \c@pgfmath@counta=-10\relax% + \fi% + \fi% + \else% + \ifdim\pgfmath@x>0.0001220703125pt\relax% 2^13 + \ifdim\pgfmath@x>0.0002441406256pt\relax% 2^12 + \multiply\pgfmath@x by2048\relax% + \c@pgfmath@counta=-11\relax% + \else% + \multiply\pgfmath@x by4096\relax% + \c@pgfmath@counta=-12\relax% + \fi% + \else% + \multiply\pgfmath@x by8192\relax% + \c@pgfmath@counta=-13\relax% + \fi% + \fi% + \fi% + \fi% + \fi% + % + % Use A+(B+(C+(D+(E+F*x)*x)*x)*x)*x + % + % where: + % A = -2.787927935 + % B = 5.047861502 + % C = -3.489886985 + % D = 1.589480044 + % E = -.4025153233 + % F = 0.04300521312 + % + \edef\pgfmath@temp{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@x=0.04300521312\pgfmath@x% + \advance\pgfmath@x by-.4025153233pt\relax% + \pgfmath@x=\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x by1.589480044pt\relax% + \pgfmath@x=\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x by-3.489886985pt\relax% + \pgfmath@x=\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x by5.047861502pt\relax% + \pgfmath@x=\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x by-2.787927935pt\relax% + \advance\pgfmath@x by\c@pgfmath@counta pt\relax% + \pgfmath@x=0.6931471806\pgfmath@x% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% log2 function. +% +\pgfmathdeclarefunction{log2}{1}{% + \begingroup% + \pgfmathln@{#1}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmath@x=1.442695041\pgfmath@x% 1/ln(2). + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% log10 function +% +\pgfmathdeclarefunction{log10}{1}{% + \begingroup% + \pgfmathln@{#1}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmath@x=0.43429441\pgfmath@x% 1/ln(10). + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% This is needed since \pgfmathlog2 and \pgfmathlog10 are not legal macro names +\expandafter\let\expandafter\pgfmathlogtwo\csname pgfmathlog2\endcsname +\expandafter\let\expandafter\pgfmathlogtwo@\csname pgfmathlog2@\endcsname +\expandafter\let\expandafter\pgfmathlogten\csname pgfmathlog10\endcsname +\expandafter\let\expandafter\pgfmathlogten@\csname pgfmathlog10@\endcsname + +% exp function. +% +\pgfmathdeclarefunction{exp}{1}{% + \begingroup + \pgfmath@xc=#1pt\relax + \pgfmath@yc=#1pt\relax + \ifdim\pgfmath@xc<-9pt + \pgfmath@x=1sp\relax + \else + \ifdim\pgfmath@xc<0pt + \pgfmath@xc=-\pgfmath@xc + \fi + \pgfmath@x=1pt\relax + \pgfmath@xa=1pt\relax + \pgfmath@xb=\pgfmath@x + \pgfmathloop% + \divide\pgfmath@xa by\pgfmathcounter + \pgfmath@xa=\pgfmath@tonumber\pgfmath@xc\pgfmath@xa% + \advance\pgfmath@x by\pgfmath@xa + \ifdim\pgfmath@x=\pgfmath@xb + \else + \pgfmath@xb=\pgfmath@x + \repeatpgfmathloop% + \ifdim\pgfmath@yc<0pt + \pgfmathreciprocal@{\pgfmath@tonumber\pgfmath@x}% + \pgfmath@x=\pgfmathresult pt\relax + \fi + \fi + \pgfmath@returnone\pgfmath@x% + \endgroup +} + +% sqrt function. +% +\pgfmathdeclarefunction{sqrt}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@error{I cannot calculate the square-root of the negative number `#1'}{}% + \else% + \ifdim\pgfmath@x<10pt\relax% + \def\pgfmath@zeros{0}% + \def\pgfmath@targetiterations{1}% + \else% + \ifdim\pgfmath@x<100pt\relax% + \def\pgfmath@zeros{}% + \def\pgfmath@targetiterations{1}% + \else% + \ifdim\pgfmath@x<1000pt\relax% + \def\pgfmath@zeros{0}% + \def\pgfmath@targetiterations{2}% + \else% + \ifdim\pgfmath@x<10000pt\relax% + \def\pgfmath@zeros{}% + \def\pgfmath@targetiterations{2}% + \else% + \def\pgfmath@zeros{0}% + \def\pgfmath@targetiterations{3}% + \fi\fi\fi\fi\fi% + \edef\pgfmath@temp{\pgfmath@zeros\pgfmath@tonumber{\pgfmath@x}}% + \expandafter\pgfmath@sqrt@\pgfmath@temp\pgfmath@% +} +\def\pgfmath@sqrt@#1.#2\pgfmath@{\pgfmath@@sqrt@#1#2\pgfmath@empty\pgfmath@empty\pgfmath@} + +\def\pgfmath@@sqrt@#1#2{% + \c@pgfmath@countb=#1#2\relax% + \ifnum\c@pgfmath@countb>35\relax% + \ifnum\c@pgfmath@countb>63\relax% + \ifnum\c@pgfmath@countb>80\relax% + \c@pgfmath@counta=9\relax% + \else% + \c@pgfmath@counta=8\relax% + \fi% + \else% + \ifnum\c@pgfmath@countb>48\relax% + \c@pgfmath@counta=7\relax% + \else% + \c@pgfmath@counta=6\relax% + \fi% + \fi% + \else% + \ifnum\c@pgfmath@countb>15\relax% + \ifnum\c@pgfmath@countb>24\relax% + \c@pgfmath@counta5\relax% + \else% + \c@pgfmath@counta=4\relax% + \fi% + \else% + \ifnum\c@pgfmath@countb>3\relax% + \ifnum\c@pgfmath@countb>8\relax% + \c@pgfmath@counta=3\relax% + \else% + \c@pgfmath@counta=2\relax% + \fi% + \else% + \ifnum\c@pgfmath@countb>0\relax% + \c@pgfmath@counta=1\relax% + \else% + \c@pgfmath@counta=0\relax% + \fi% + \fi% + \fi% + \fi% + \edef\pgfmath@root{\the\c@pgfmath@counta}% + \edef\pgfmath@rootspecial{\the\c@pgfmath@counta}% + \multiply\c@pgfmath@counta by-\c@pgfmath@counta\relax% + \advance\c@pgfmath@counta by#1#2\relax% + \edef\pgfmath@remainder{\the\c@pgfmath@counta}% + \pgfmath@@@sqrt@% +} + +\def\pgfmath@@@sqrt@#1#2{% + \ifx\pgfmath@empty#1% + \edef\pgfmath@remainder{\pgfmath@remainder00}% + \def\pgfmath@tokens{\pgfmath@empty\pgfmath@empty}% + \else% + \ifx\pgfmath@empty#2% + \edef\pgfmath@remainder{\pgfmath@remainder#10}% + \def\pgfmath@tokens{\pgfmath@empty\pgfmath@empty}% + \else% + \edef\pgfmath@remainder{\pgfmath@remainder#1#2}% + \def\pgfmath@tokens{}% + \fi\fi% + \c@pgfmath@counta=\pgfmath@rootspecial\relax% + \multiply\c@pgfmath@counta by20\relax% + \c@pgfmath@countb=\c@pgfmath@counta% + \multiply\c@pgfmath@countb by6\relax% + \advance\c@pgfmath@countb by36\relax% + \c@pgfmath@countc=\c@pgfmath@counta% + \multiply\c@pgfmath@countc by2\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \advance\c@pgfmath@countb by-\c@pgfmath@countc% + \advance\c@pgfmath@countb by-20\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \advance\c@pgfmath@countb by-\c@pgfmath@countc% + \advance\c@pgfmath@countb by-12\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \advance\c@pgfmath@countb by-\c@pgfmath@counta% + \advance\c@pgfmath@countb by-3\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \def\pgfmath@digit{0}% + \else% + \def\pgfmath@digit{1}% + \fi% + \else% + \advance\c@pgfmath@countb by\c@pgfmath@counta% + \advance\c@pgfmath@countb by5\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \def\pgfmath@digit{2}% + \else% + \def\pgfmath@digit{3}% + \fi% + \fi% + \else% + \advance\c@pgfmath@countb by\c@pgfmath@counta% + \advance\c@pgfmath@countb by9\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \def\pgfmath@digit{4}% + \else% + \def\pgfmath@digit{5}% + \fi% + \fi% + \else% + \advance\c@pgfmath@countb by\c@pgfmath@countc% + \advance\c@pgfmath@countb by28\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \advance\c@pgfmath@countb by-\c@pgfmath@counta% + \advance\c@pgfmath@countb by-15\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \def\pgfmath@digit{6}% + \else% + \def\pgfmath@digit{7}% + \fi% + \else% + \advance\c@pgfmath@countb by\c@pgfmath@counta% + \advance\c@pgfmath@countb by17\relax% + \ifnum\c@pgfmath@countb>\pgfmath@remainder\relax% + \def\pgfmath@digit{8}% + \else% + \def\pgfmath@digit{9}% + \fi% + \fi% + \fi% + \edef\pgfmath@rootspecial{\pgfmath@rootspecial\pgfmath@digit}% + \advance\c@pgfmath@counta by\pgfmath@digit\relax% + \multiply\c@pgfmath@counta by-\pgfmath@digit\relax% + \advance\c@pgfmath@counta by\pgfmath@remainder\relax% + \edef\pgfmath@remainder{\the\c@pgfmath@counta}% + \c@pgfmath@counta=\pgfmath@targetiterations\relax% + \advance\c@pgfmath@counta by-1\relax% + \edef\pgfmath@targetiterations{\the\c@pgfmath@counta}% + \ifnum\c@pgfmath@counta=0\relax% + \edef\pgfmath@root{\pgfmath@root.\pgfmath@digit}% + \else% + \edef\pgfmath@root{\pgfmath@root\pgfmath@digit}% + \fi% + \ifnum\c@pgfmath@counta=-4\relax% -n+1 digits of precision. + \let\pgfmath@next\pgfmath@sqrt@end% + \else% + \let\pgfmath@next\pgfmath@@@sqrt@% + \fi% + \expandafter\pgfmath@next\pgfmath@tokens% +} + +\def\pgfmath@sqrt@end#1\pgfmath@{% + \edef\pgfmathresult{\pgfmath@root}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup} + +% \pgfmathpow +% +% Calculates #1 ^ #2 +% +\pgfmathdeclarefunction{pow}{2}{% + \begingroup% + \pgfmath@xa=#1pt% + \pgfmath@xb=#2pt% + \ifdim\pgfmath@xa=0pt\relax% + \ifdim\pgfmath@xb=0pt\relax% + \pgfmath@x=1pt\relax% + \else% + \pgfmath@x=0pt\relax% + \fi% + \else% + \afterassignment\pgfmath@x% + \expandafter\c@pgfmath@counta\the\pgfmath@xb\relax% + \ifnum\c@pgfmath@counta<0\relax% + \c@pgfmath@counta=-\c@pgfmath@counta% + \pgfmathreciprocal@{#1}% + \pgfmath@xa=\pgfmathresult pt\relax% + \fi + \ifdim\pgfmath@x=0pt\relax% + \pgfmath@x=1pt\relax% + \pgfmathloop% + \ifnum\c@pgfmath@counta>0\relax% + \ifodd\c@pgfmath@counta% + \pgfmath@x=\pgfmath@tonumber{\pgfmath@x}\pgfmath@xa% + \fi + \ifnum\c@pgfmath@counta>1\relax% + \pgfmath@xa=\pgfmath@tonumber{\pgfmath@xa}\pgfmath@xa% + \fi% + \divide\c@pgfmath@counta by2\relax% + \repeatpgfmathloop% + \else% + \pgfmathln@{#1}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmath@x=\pgfmath@tonumber{\pgfmath@xb}\pgfmath@x% + \pgfmathexp@{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@x=\pgfmathresult pt\relax% + \fi% + \fi + \pgfmath@returnone\pgf@x% + \endgroup% +} + +% factorial function. +% +\pgfmathdeclarefunction{factorial}{1}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@% + \c@pgfmath@counta=#1\relax\pgfmath@% + \pgfmath@x=1pt\relax% + \pgfmathloop% + \ifnum\c@pgfmath@counta<2\relax% + \else% + \multiply\pgfmath@x by\c@pgfmath@counta% + \advance\c@pgfmath@counta by-1\relax% + \repeatpgfmathloop% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% Local Variables: +% coding: undecided-unix +% End: diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.code.tex new file mode 100644 index 0000000000..6e5d079c6b --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.code.tex @@ -0,0 +1,267 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% Declare a function for the parser. +% +% #1 - the name of the function. +% #2 - arity (or ... for variable arguments). +% #3 - the code for the function. +% +% Use \pgfmathdeclarefunction* to force a redefinition if the function exists already. +\def\pgfmathdeclarefunction{\pgfmath@ifnextchar*\pgfmathdeclarefunction@force\pgfmathdeclarefunction@check} +\def\pgfmathdeclarefunction@check#1{% + \expandafter\ifx\csname pgfmath@function@#1\endcsname\relax\else% + \pgfmath@error{The function `#1' already exists}{}% + \fi% + \pgfmath@declarefunction{#1}% +} +\def\pgfmathdeclarefunction@force*{\pgfmath@declarefunction}% + +\def\pgfmathredeclarefunction#1#2{% + \expandafter\ifx\csname pgfmath@function@#1\endcsname\relax% + \pgfmath@error{The function `#1' does not exist}{}% + \else% + % was: \pgfmath@namedef{pgfmath#1@}{#2}% TT + \edef\pgf@marshal{\noexpand\pgfmathdeclarefunction*{#1}{\csname pgfmath@operation@#1@arity\endcsname}}% + \pgf@marshal{#2}% + \fi% +} + +\def\pgfmath@declarefunction#1#2{% + \pgfmath@namedef{pgfmath@function@#1}{#1}% + \pgfmath@namedef{pgfmath@operation@#1@type}{function}% + \pgfmath@namedef{pgfmath@operation@#1@arity}{#2}% + \pgfmath@namedef{pgfmath@operation@#1@infix}{#1}% + \pgfmath@namedef{pgfmath@operation@#1@precedence}{1000}% + \expandafter\ifx\csname pgfmath@operation@#1@arity\endcsname\pgfmath@dots% + \pgfmath@namedef{pgfmath@operation@#1@arity}{1}% + \else% + \ifnum\csname pgfmath@operation@#1@arity\endcsname>9\relax% + \pgfmath@namedef{pgfmath@operation@#1@arity}{1}% + \fi% + \fi% + \edef\pgfmath@marshal{% + \noexpand\pgfmath@@declarefunction% + {\expandafter\noexpand\csname pgfmath#1\endcsname}% + {\expandafter\noexpand\csname pgfmath#1@\endcsname}% + {\csname pgfmath@operation@#1@arity\endcsname}% + }% + \pgfkeysvalueof{/pgf/declare function/execute at begin function}% + \pgfmath@marshal% +} + +% #1 - \pgfmath. +% #2 - \pgfmath@. +% #3 - arity. +% #4 - code for function . +% +\def\pgfmath@@declarefunction#1#2#3#4{% Function of arity 0 - 9. + \pgfkeysvalueof{/pgf/declare function/execute at end function}% + \ifcase#3\relax% + \def#1{#2}% + \def\pgfmath@@head{\def#2}% + \or + \def#1##1{\pgfmathparse{##1}\expandafter#2\expandafter{\pgfmathresult}}% + \def\pgfmath@@head{\def#2####1}% + \else% + \pgfmath@toks={}% + \pgfmathloop% + \ifnum\pgfmathcounter>#3\relax% + \else% + \expandafter\pgfmath@addto@toks\expandafter{\pgfmath@char@hash}% + \expandafter\pgfmath@addto@toks\expandafter{\pgfmathcounter}% + \repeatpgfmathloop% + \edef\pgfmath@head{\noexpand\def\noexpand#1\the\pgfmath@toks}% + \edef\pgfmath@@head{\noexpand\def\noexpand#2\the\pgfmath@toks}% + \pgfmath@toks={}% + \def\pgfmath@arguments{}% + \pgfmathloop% + \ifnum\pgfmathcounter>#3\relax% + \else% + \pgfmath@addto@toks{\pgfmathparse}% + \expandafter\expandafter\expandafter\pgfmath@addto@toks% + \expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter% + {\expandafter\pgfmath@char@hash\pgfmathcounter}}% + \pgfmath@addto@toks{\let}% + \expandafter\pgfmath@addto@toks\expandafter{% + \csname pgfmath@argument@\pgfmathcounter\endcsname=\pgfmathresult}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgfmath@arguments\expandafter\expandafter\expandafter{\expandafter% + \pgfmath@arguments\expandafter{\csname pgfmath@argument@\pgfmathcounter\endcsname}}% + \repeatpgfmathloop% + \expandafter\pgfmath@addto@toks\expandafter{\expandafter#2\pgfmath@arguments}% + \edef\pgfmath@body{{\the\pgfmath@toks}}% + \expandafter\pgfmath@head\pgfmath@body% + \fi% + \pgfmath@@head{#4}% +} + +\def\pgfmath@addto@toks#1{% + \edef\pgfmath@toks@expanded{\the\pgfmath@toks}% + \expandafter\pgfmath@toks\expandafter{\pgfmath@toks@expanded#1}} + +% Key for declaring local functions. +% +\pgfkeys{% + /pgf/declare function/.code={% + \pgfmath@local@functions#1@=@;% + }, + /pgf/declare function/execute at begin function/.initial={}, + /pgf/declare function/execute at end function/.initial={}, + /pgf/declare function/ignore spaces/.is choice, + /pgf/declare function/ignore spaces/.default=true, + /pgf/declare function/ignore spaces/true/.style={% + /pgf/declare function/execute at begin function={% + \begingroup + \catcode`\^^I=9\relax + \catcode`\ =9\relax + \catcode`\~=10\relax + \endlinechar=`\ \relax + }, + /pgf/declare function/execute at end function={% + \endgroup + }, + }, + /pgf/declare function/ignore spaces/false/.style={% + /pgf/declare function/execute at begin function={}, + /pgf/declare function/execute at end function={}, + }, +} + +\def\pgfmath@local@gobbleone#1{} +\def\pgfmath@local@at{@}% + +\def\pgfmath@local@functions{% + \pgfutil@ifnextchar x{\pgfmath@local@@functions}{\pgfmath@local@@functions}% +} + +\def\pgfmath@local@@functions#1=#2;{% + \def\pgfmath@local@temp{#1}% + \ifx\pgfmath@local@temp\pgfmath@local@at% + \let\pgfmath@local@next=\relax% + \else% + \pgfmath@local@function#1=#2;% + \let\pgfmath@local@next=\pgfmath@local@functions% + \fi% + \pgfmath@local@next% +} + +\def\pgfmath@local@function{% + \let\pgfmath@local@name=\pgfutil@empty% + \let\pgfmath@local@args=\pgfutil@empty% + \let\pgfmath@local@body=\pgfutil@empty% + \pgfmath@local@@function} + +\def\pgfmath@local@@function#1{% + \if#1=% + \let\pgfmath@local@next=\pgfmath@local@function@body% + \else% + \if#1(% + \let\pgfmath@local@next=\pgfmath@local@function@args% + \else% + \expandafter\def\expandafter\pgfmath@local@name\expandafter{\pgfmath@local@name#1}% + \let\pgfmath@local@next=\pgfmath@local@@function% + \fi% + \fi% + \pgfmath@local@next% +} + +\def\pgfmath@local@function@args#1){% + \def\pgfmath@local@args{#1}% + \pgfmath@local@@function} + +\def\pgfmath@local@function@body#1;{% + \def\pgfmath@local@body{#1}% + \begingroup% + \c@pgf@counta=0\relax% + \ifx\pgfmath@local@args\pgfmath@empty% + \expandafter\pgfmath@toks\expandafter=\expandafter{\pgfmath@local@body}% + \else% + \pgfmath@toks={}% + \expandafter\pgfmath@local@function@@body\pgfmath@local@args,,% + \fi% + \xdef\pgfmath@local@temp{% + \noexpand\pgfmathnotifynewdeclarefunction{\pgfmath@local@name}{\the\c@pgf@counta}% + {\the\pgfmath@toks}% + }% + \endgroup% + \pgfmath@local@temp% +} + +% #1: the name +% #2: the number of arguments +% #3: a math expression containing '#1', '#2', ... ,'#' +% This callback is overwritten by pgflibraryluamath. +\def\pgfmathnotifynewdeclarefunction#1#2#3{% + \pgfmathdeclarefunction{#1}{#2}{\pgfmathparse{#3}}% +}% + +\def\pgfmath@local@function@@body#1,{% + \def\pgfmath@local@test{#1}% + \ifx\pgfmath@local@test\pgfutil@empty% + \let\pgfmath@local@next=\relax% + \else% + \edef\pgfmath@local@var@string{@\expandafter\pgfmath@local@gobbleone\string#1}% + \advance\c@pgf@counta by1\relax% + \expandafter\expandafter\expandafter\pgfmath@toks\expandafter\expandafter\expandafter=% + \expandafter\expandafter\expandafter{\expandafter\pgfmath@char@hash\the\c@pgf@counta}% + \edef#1{\the\pgfmath@toks}% + \pgfmath@toks={}% + \expandafter\pgfmath@local@function@@@body\pgfmath@local@body @% + \edef\pgfmath@local@body{\the\pgfmath@toks}% + \let\pgfmath@local@next=\pgfmath@local@function@@body% + \fi% + \pgfmath@local@next% +} + +\def\pgfmath@local@function@@@body{% + \pgfutil@ifnextchar\bgroup{\pgfmath@local@function@@@body@bgroup}% + {\pgfmath@local@function@@@body@nobgroup}}% + +\def\pgfmath@local@function@@@body@bgroup#1{% + \begingroup% + \pgfmath@toks={}% + \pgfmath@local@function@@@body#1 @% + \xdef\pgfmath@local@temp{{\the\pgfmath@toks}}% + \endgroup% + \expandafter\pgfmath@addto@toks\expandafter{\pgfmath@local@temp}% + \pgfmath@local@function@@@body% +} + +\def\pgfmath@local@function@@@body@nobgroup#1{% + \ifx#1@% + \let\pgfmath@local@next=\relax% + \else% + \let\pgfmath@local@next=\pgfmath@local@function@@@body% + \edef\pgfmath@local@var@@string{@\expandafter\pgfmath@local@gobbleone\string#1}% + \ifx\pgfmath@local@var@@string\pgfmath@local@var@string% + \expandafter\pgfmath@addto@toks\expandafter{#1}% + \else% + \edef\pgfmath@local@temp{\the\pgfmath@toks}% + \pgfmath@toks={#1}% + \edef\pgfmath@local@@temp{\the\pgfmath@toks}% + \expandafter\pgfmath@toks\expandafter=\expandafter{\pgfmath@local@temp}% + \expandafter\pgfmath@addto@toks\expandafter{\pgfmath@local@@temp}% + \fi% + \fi% + \pgfmath@local@next% +} + +% Allows to define 'x' as some \TeX command '#2'. +\def\pgfmathdeclarepseudoconstant#1#2{% + \pgfmathdeclarefunction*{#1}{0}{#2}% +}% +% Redefines a pseudo constant '#1'. +\def\pgfmathredeclarepseudoconstant#1#2{% + \pgfmathredeclarefunction{#1}{#2}% +}% + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.comparison.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.comparison.code.tex new file mode 100644 index 0000000000..a0632670d8 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.comparison.code.tex @@ -0,0 +1,179 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the mathematical functions and operators. +% +% Version 1.4142135 11/8/2008 + +\pgfmathdeclarefunction{greater}{2}{% + \begingroup% + \ifdim#1pt>#2pt\relax% + \def\pgfmathresult{1}% + \else% + \def\pgfmathresult{0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} +\let\pgfmathgreaterthan=\pgfmathgreater + +\pgfmathdeclarefunction{less}{2}{% + \begingroup% + \ifdim#1pt<#2pt\relax% + \def\pgfmathresult{1}% + \else% + \def\pgfmathresult{0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} +\let\pgfmathlessthan=\pgfmathless + +\pgfmathdeclarefunction{equal}{2}{% + \begingroup% + \ifdim#1pt=#2pt\relax% + \def\pgfmathresult{1}% + \else% + \def\pgfmathresult{0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} +\let\pgfmathequalto=\pgfmathequal + + +% approxequalto function from Christian Feuersaenger. +% +\newif\ifpgfmathcomparison +\pgfmathdeclarefunction{approxequalto}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@y=#2pt\relax% + \advance\pgfmath@x by-\pgfmath@y% + \ifdim\pgfmath@x<0pt\relax% + \multiply\pgfmath@x by-1\relax% + \fi + \ifdim\pgfmath@x<0.0001pt\relax% + \def\pgfmathresult{1.0}% + \global\pgfmathcomparisontrue% + \else% + \def\pgfmathresult{0.0}% + \global\pgfmathcomparisonfalse% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + + + +% ifthenelse function. +% +\pgfmathdeclarefunction{ifthenelse}{3}{% + \begingroup% + \ifdim#1pt=0.0pt\relax% + \expandafter\def\expandafter\pgfmathresult\expandafter{#3}% + \else% + \expandafter\def\expandafter\pgfmathresult\expandafter{#2}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% notequal function. +% +\pgfmathdeclarefunction{notequal}{2}{% + \begingroup% + \ifdim#1pt=#2pt\relax% + \def\pgfmathresult{0}% + \else% + \def\pgfmathresult{1}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% notless function. +% +\pgfmathdeclarefunction{notless}{2}{% + \begingroup% + \ifdim#1pt<#2pt\relax% + \def\pgfmathresult{0}% + \else% + \def\pgfmathresult{1}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% notgreater function. +% +\pgfmathdeclarefunction{notgreater}{2}{% + \begingroup% + \ifdim#1pt>#2pt\relax% + \def\pgfmathresult{0}% + \else% + \def\pgfmathresult{1}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% and function. +% +\pgfmathdeclarefunction{and}{2}{% + \begingroup% + \def\pgfmathresult{1}% + \ifdim#1pt=0pt\relax% + \def\pgfmathresult{0}% + \else% + \ifdim#2pt=0pt\relax% + \def\pgfmathresult{0}% + \fi% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% or function. +% +\pgfmathdeclarefunction{or}{2}{% + \begingroup% + \def\pgfmathresult{0}% + \ifdim#1pt=0pt\relax% + \ifdim#2pt=0pt\relax% + \else% + \def\pgfmathresult{1}% + \fi% + \else% + \def\pgfmathresult{1}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% not function. +% +\pgfmathdeclarefunction{not}{1}{% + \begingroup% + \ifdim#1pt=0pt\relax% + \def\pgfmathresult{1}% + \else% + \def\pgfmathresult{0}% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% true function. +% +\pgfmathdeclarefunction{true}{0}{\def\pgfmathresult{1}} + +% false function. +% +\pgfmathdeclarefunction{false}{0}{\def\pgfmathresult{0}} diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.integerarithmetics.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.integerarithmetics.code.tex new file mode 100644 index 0000000000..ab8f4e6d3c --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.integerarithmetics.code.tex @@ -0,0 +1,124 @@ +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% Macros contributed by Alain Matthes and adapted by CJ +\pgfmathdeclarefunction{gcd}{2}{% + \begingroup + \pgfmathcontinuelooptrue + \pgfmath@xa=#1pt + \pgfmath@xb=#2pt + \ifdim\pgfmath@xa=0pt\relax + \pgfmathcontinueloopfalse + \pgfmath@xa=\pgfmath@xb + \fi + \ifdim\pgfmath@xb=0pt\relax + \pgfmathcontinueloopfalse + \pgfmath@xb=\pgfmath@xa + \fi + \ifdim\pgfmath@xa<0pt\relax + \pgfmath@xa=-\pgfmath@xa + \fi + \ifdim\pgfmath@xb<0pt\relax + \pgfmath@xb=-\pgfmath@xb + \fi + \loop + \ifpgfmathcontinueloop + \ifdim\pgfmath@xa=\pgfmath@xb + \pgfmathcontinueloopfalse + \else + \ifdim\pgfmath@xa>\pgfmath@xb + \advance\pgfmath@xa by-\pgfmath@xb + \else + \advance\pgfmath@xb by-\pgfmath@xa + \fi + \fi + \repeat + \pgfmathparse{int(\pgfmath@xa)}% + \pgfmath@smuggleone\pgfmathresult + \endgroup} + +\newif\ifpgfmath@isprime@unknown +\newif\ifpgfmath@isprime + +\pgfmathdeclarefunction{isprime}{1}{% + \begingroup + \pgfmath@isprime@unknowntrue + \pgfmathsetcount\c@pgfmath@counta{abs(int(#1))}% + \ifcase\c@pgfmath@counta\relax + % |#1| = 0 + \pgfmath@isprimefalse + \pgfmath@isprime@unknownfalse + \or + % |#1| = 1 + \pgfmath@isprimefalse + \pgfmath@isprime@unknownfalse + \or + % |#1| = 2 + \pgfmath@isprimetrue + \pgfmath@isprime@unknownfalse + \or + % |#1| = 3 + \pgfmath@isprimetrue + \pgfmath@isprime@unknownfalse + \else + % |#1| > 3 + \ifodd\c@pgfmath@counta\relax + \else + \pgfmath@isprimefalse + \pgfmath@isprime@unknownfalse + \fi + \fi + \ifpgfmath@isprime@unknown + \c@pgfmath@countd=3 + \pgfmath@isprimetrue + \pgfmathloop + \c@pgfmath@countb=\c@pgfmath@counta + \divide\c@pgfmath@countb by\c@pgfmath@countd + \ifnum\c@pgfmath@countb>\c@pgfmath@countd + \pgfmath@isprime@unknowntrue + \else + \pgfmath@isprime@unknownfalse + \fi + \multiply\c@pgfmath@countb by\c@pgfmath@countd + \ifnum\c@pgfmath@countb=\c@pgfmath@counta + \global\pgfmath@isprimefalse + \pgfmath@isprime@unknownfalse + \fi + \ifpgfmath@isprime@unknown\advance\c@pgfmath@countd by 2 + \repeatpgfmathloop + \fi + \ifpgfmath@isprime + \def\pgfmathresult{1}% + \else + \def\pgfmathresult{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup} + +\pgfmathdeclarefunction{isodd}{1}{% + \begingroup + \pgfmathsetcount\c@pgfmath@counta{abs(int(#1))}% + \ifodd\c@pgfmath@counta + \def\pgfmathresult{1}% + \else + \def\pgfmathresult{0}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup} + +\pgfmathdeclarefunction{iseven}{1}{% + \begingroup + \pgfmathsetcount\c@pgfmath@counta{abs(int(#1))}% + \ifodd\c@pgfmath@counta + \def\pgfmathresult{0}% + \else + \def\pgfmathresult{1}% + \fi + \pgfmath@smuggleone\pgfmathresult + \endgroup} + +\endinput diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.misc.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.misc.code.tex new file mode 100644 index 0000000000..859d8266a9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.misc.code.tex @@ -0,0 +1,353 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the mathematical functions and operators. +% +% Version 1.414213 29/9/2007 + +% veclen function adapted from ideas due to Rouben Rostamian. +% +% Calculate the Euclidean length of a 2D vector. +% +% +\pgfmathdeclarefunction{veclen}{2}{% + \begingroup% + \pgfmath@x#1pt\relax% + \pgfmath@y#2pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \ifdim\pgfmath@y<0pt\relax% + \pgfmath@y-\pgfmath@y% + \fi% + \ifdim\pgfmath@x=0pt\relax% + \pgfmath@x\pgfmath@y% + \else% + \ifdim\pgfmath@y=0pt\relax% + \else% + \ifdim\pgfmath@x>\pgfmath@y% + \pgfmath@xa\pgfmath@x% + \pgfmath@x\pgfmath@y% + \pgfmath@y\pgfmath@xa% + \fi% + % We use a scaling factor to reduce errors. + \ifdim\pgfmath@y>10000pt\relax% + \c@pgfmath@counta1500\relax% + \else% + \ifdim\pgfmath@y>1000pt\relax% + \c@pgfmath@counta150\relax% + \else% + \ifdim\pgfmath@y>100pt\relax% + \c@pgfmath@counta50\relax% + \else% + \c@pgfmath@counta1\relax% + \fi% + \fi% + \fi% + \divide\pgfmath@x\c@pgfmath@counta\relax% + \divide\pgfmath@y\c@pgfmath@counta\relax% + \pgfmathreciprocal@{\pgfmath@tonumber{\pgfmath@y}}% + \pgfmath@x\pgfmathresult\pgfmath@x% + \pgfmath@xa\pgfmath@tonumber{\pgfmath@x}\pgfmath@x% + \edef\pgfmath@temp{\pgfmath@tonumber{\pgfmath@xa}}% + % + % Use A+x^2*(B+x^2*(C+x^2*(D+E*x^2))) + % where + % A = +1.000012594 + % B = +0.4993615349 + % C = -0.1195159052 + % D = +0.04453994279 + % E = -0.01019210944 + % + \pgfmath@x-0.01019210944\pgfmath@xa% + \advance\pgfmath@x0.04453994279pt\relax% + \pgfmath@x\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x-0.1195159052pt\relax% + \pgfmath@x\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x0.4993615349pt\relax% + \pgfmath@x\pgfmath@temp\pgfmath@x% + \advance\pgfmath@x1.000012594pt\relax% + \ifdim\pgfmath@y<0pt\relax% + \pgfmath@y-\pgfmath@y% + \fi% + \pgfmath@x\pgfmath@tonumber{\pgfmath@y}\pgfmath@x% + % Invert the scaling factor. + \multiply\pgfmath@x\c@pgfmath@counta\relax% + \fi% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% Hyperbolic functions contributed by Martin Heller. +% +\pgfmathdeclarefunction{cosh}{1}{% + \begingroup + \edef\pgfmath@arg{#1}% + \pgfmathexp@{\pgfmath@arg}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmathexp@{-\pgfmath@arg}% + \advance\pgfmath@x by\pgfmathresult pt\relax% + \divide\pgfmath@x by2\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup} + +\pgfmathdeclarefunction{sinh}{1}{% + \begingroup + \edef\pgfmath@arg{#1}% + \pgfmathexp@{\pgfmath@arg}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmathexp@{-\pgfmath@arg}% + \advance\pgfmath@x by-\pgfmathresult pt\relax% + \divide\pgfmath@x by2\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup +}% + +\pgfmathdeclarefunction{tanh}{1}{% + \begingroup + \edef\pgfmath@arg{#1}% + \pgfmathsinh@{\pgfmath@arg}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmathcosh@{\pgfmath@arg}% + \pgfmath@y=\pgfmathresult pt\relax% + \pgfmathdivide@{\pgfmath@tonumber{\pgfmath@x}}{\pgfmath@tonumber{\pgfmath@y}}% + \pgfmath@x=\pgfmathresult pt\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup +}% + +% \pgfmathscientific +% +% Return the value of #1e#2 +% +% e.g. \pgfmathscientific{1.23456789123}{4} +% +% defines \pgfmathresult as 12345.67891 +% +% NB These arguments *are not parsed*, as the long mantissa would be lost. +% +\def\pgfmathscientific#1#2{% + \begingroup% + \edef\pgfmath@sci@exponent{#2}% + \pgfmath@x#1pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \edef\pgfmath@sci@sign{-}% + \expandafter\edef\expandafter\pgfmath@temp\expandafter{\expandafter\pgfmath@gobbleone#1}% + \else% + \edef\pgfmath@sci@sign{+}% + \edef\pgfmath@temp{#1}% + \fi% + \expandafter\pgfmath@in@\expandafter.\expandafter{#1}% + \ifpgfmath@in@% + \else% + \edef\pgfmath@temp{\pgfmath@temp.0}% + \fi% + \expandafter\pgfmath@scientific@@\pgfmath@temp00000000000\pgfmath@} + +\def\pgfmath@scientific@@#1.#2#3#4#5#6{% + \edef\pgfmath@sci@int{#1}% + \edef\pgfmath@sci@mantissaA{#2#3#4#5#6}% + \pgfmath@scientific@@@} + +\def\pgfmath@scientific@@@#1#2#3#4#5#6\pgfmath@{% + \edef\pgfmath@sci@mantissaB{#1#2#3#4#5}% + \c@pgfmath@counta\pgfmath@sci@exponent\relax% + \ifnum\c@pgfmath@counta<-4\relax% + \pgfmath@x0pt\relax% + \else% + \c@pgfmath@countb\c@pgfmath@counta% + \ifnum\c@pgfmath@counta<0\relax% + \c@pgfmath@counta-\c@pgfmath@counta% + \fi% + \pgfmathpow@{10}{\the\c@pgfmath@counta}% + \afterassignment\pgfmath@gobbletilpgfmath@ + \c@pgfmath@countc\pgfmathresult\relax\pgfmath@ + \edef\pgfmath@sci@factor{\the\c@pgfmath@countc}% + \ifnum\c@pgfmath@countb<0\relax% + % xE-y: easy... + \pgfmath@x\pgfmath@sci@int.\pgfmath@sci@mantissaA pt\relax% + \divide\pgfmath@x\pgfmath@sci@factor\relax% + \else% + % xE+y: + % Must do this way so as not lose digits in a long mantissa. Sigh... + \c@pgfmath@counta\pgfmath@sci@int% + \c@pgfmath@countb\pgfmath@sci@mantissaA% + \multiply\c@pgfmath@counta\pgfmath@sci@factor\relax% + \multiply\c@pgfmath@countb\pgfmath@sci@factor\relax% + \c@pgfmath@countc\c@pgfmath@countb% + \divide\c@pgfmath@countb100000\relax% + \advance\c@pgfmath@counta\c@pgfmath@countb% + \multiply\c@pgfmath@countb100000\relax% + \advance\c@pgfmath@countc-\c@pgfmath@countb% + \c@pgfmath@countb\pgfmath@sci@mantissaB\relax% + \multiply\c@pgfmath@countb\pgfmath@sci@factor\relax% + \divide\c@pgfmath@countb100000\relax% + \advance\c@pgfmath@countc\c@pgfmath@countb% + \advance\c@pgfmath@countc100000\relax% + \edef\pgfmath@sci@result{\pgfmath@sci@sign\the\c@pgfmath@counta.\expandafter\pgfmath@gobbleone\the\c@pgfmath@countc pt}% + \pgfmath@x\pgfmath@sci@result\relax% + \fi\fi% + \pgfmath@returnone\pgfmath@x% + \endgroup} + + + +% width function. +% +\pgfmathdeclarefunction{width}{1}{% + \begingroup% + \setbox\pgfmath@box=\hbox{{\pgfmath@selectfont{#1}}}% + \pgfmath@x=\wd\pgfmath@box% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + + +% height function. +% +\pgfmathdeclarefunction{height}{1}{% + \begingroup% + \setbox\pgfmath@box=\hbox{{\pgfmath@selectfont{#1}}}% + \pgfmath@x=\ht\pgfmath@box% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + +% depth function. +% +\pgfmathdeclarefunction{depth}{1}{% + \begingroup% + \setbox\pgfmath@box=\hbox{{\pgfmath@selectfont{#1}}}% + \pgfmath@x=\dp\pgfmath@box% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} + + +% array function. +% +\pgfmathdeclarefunction{array}{2}{% + \begingroup% + \afterassignment\pgfmath@gobbletilpgfmath@\pgfmath@count=#2\relax\pgfmath@% + \expandafter\pgfmatharray@@#1\pgfmath@stop% +} + +\def\pgfmath@token@stop{\pgfmath@stop}% +\def\pgfmatharray@@#1{% + \def\pgfmath@temp{#1}% + \advance\pgfmath@count by-1\relax% + \ifx\pgfmath@temp\pgfmath@token@stop% + \pgfmath@error{Array index out of bounds.}{}% + \def\pgfmathresult{0}% + \pgfmath@smuggleone\pgfmathresult\endgroup% + \let\pgfmath@next=\relax% + \else% + \ifnum\pgfmath@count=-1\relax% + \def\pgfmathresult{#1}% + \let\pgfmath@next=\pgfmatharray@@@% + \else% + \let\pgfmath@next=\pgfmatharray@@% + \fi% + \fi% + \pgfmath@next} + +\def\pgfmatharray@@@#1\pgfmath@stop{% + \pgfmath@smuggleone\pgfmathresult\endgroup% +} + +% dim function: return dimension of an array +% dim({1,2,3}) return 3 +% dim({{1,2,3},{4,5,6}}) return 2 +\pgfmathdeclarefunction{dim}{1}{% + \begingroup + \pgfmath@count=0\relax + \expandafter\pgfmath@dim@i\pgfutil@firstofone#1{\pgfmath@token@stop}% + \edef\pgfmathresult{\the\pgfmath@count}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup} + +\def\pgfmath@dim@i#1#{% + \pgfutil@ifempty{#1}{}{\advance\pgfmath@count by 1}% + \pgfmath@dim@ii{#1}} + +\def\pgfmath@dim@ii#1#2{% + \ifx\pgfmath@token@stop#2% + \else + \advance\pgfmath@count by 1\relax + \expandafter\pgfmath@dim@i + \fi} + + +% max function. +% +\pgfmathdeclarefunction{max}{...}{% + \begingroup% + \pgfmath@x=-16383pt\relax% + \pgfmathmax@@#1{}} + +\def\pgfmathmax@@#1{% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \let\pgfmath@next=\pgfmathmax@@@% + \else% + \ifdim#1pt>\pgfmath@x% + \pgfmath@x=#1pt\relax% + \fi% + \let\pgfmath@next=\pgfmathmax@@% + \fi% + \pgfmath@next} + +\def\pgfmathmax@@@{\pgfmath@returnone\pgfmath@x\endgroup}% + +% For computability with old code. +\def\pgfmathmax#1#2{% + \pgfmathparse{#1,#2}% + \expandafter\pgfmathmax@\expandafter{\pgfmathresult}% +} + +% min function. +% +\pgfmathdeclarefunction{min}{...}{% + \begingroup% + \pgfmath@x=16383pt\relax% + \pgfmathmin@@#1{}} + +\def\pgfmathmin@@#1{% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \let\pgfmath@next=\pgfmathmin@@@% + \else% + \ifdim#1pt<\pgfmath@x% + \pgfmath@x=#1pt\relax% + \fi% + \let\pgfmath@next=\pgfmathmin@@% + \fi% + \pgfmath@next} + +\def\pgfmathmin@@@{\pgfmath@returnone\pgfmath@x\endgroup}% + +% For computability with old code. +\def\pgfmathmin#1#2{% + \pgfmathparse{#1,#2}% + \expandafter\pgfmathmin@\expandafter{\pgfmathresult}% +} + + + +% scalar function. +% +\pgfmathdeclarefunction{scalar}{1}{% + \def\pgfmathresult{#1}% + \global\pgfmathunitsdeclaredfalse% +} diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.random.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.random.code.tex new file mode 100644 index 0000000000..969762c6c9 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.random.code.tex @@ -0,0 +1,246 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the pseudorandom numbers. +% +% Version 1.414213 29/9/2007 + +% Pseudo-random number generation. +% +% See: +% \book@{pressetal1992, +% author = {William H. Press and Brian P. Flannery and Saul A. +% Teukolsky and William T. Vetterling}, +% title = {Numerical Recipies in C}, +% edition = {Second}, +% publisher = {Cambridge University Press} +% } +% +% See also, the documentation for the lcg package by Erich Janka: +% (http://www.ctan.org/tex-archive/macros/latex/contrib/lcg/lcg.pdf) +% +\def\pgfmath@rnd@m{2147483647}% LaTeX Maximum. + +\begingroup +\c@pgfmath@counta=\time% +\multiply\c@pgfmath@counta by\year% +\ifnum\c@pgfmath@counta=0 + \c@pgfmath@counta=1 +\fi +\xdef\pgfmath@rnd@z{\the\c@pgfmath@counta}% The seed. +\endgroup + +% \pgfmathsetseed +% +% Explicitly set the seed for the generator +% +% #1 -> the new seed. +% +\def\pgfmathsetseed#1{% + % Attention pgflibraryluamath.code.tex relies on the fact that + % this method also modifies \pgfmathresult: + \pgfmathparse{#1}\expandafter\pgfmath@setseed\pgfmathresult.0\pgfmath@stop +}% +\def\pgfmath@setseed#1.#2\pgfmath@stop{\def\pgfmath@rnd@z{#1}}% + +% Alternative parameters - see Press et al (1992) p278-279, +% for discussion. +% +% a=16807 q=127773 r=2836 +% a=48271 q=4488 r=3399 +% +\def\pgfmath@rnd@a{69621} +\def\pgfmath@rnd@r{23902} +\def\pgfmath@rnd@q{30845} + +% \pgfmathgeneratepseudorandomnumber +% +% A linear congruency generator for generating +% pseudo-random numbers. Generates numbers in +% the range 1 - 2^31-1. +% +\def\pgfmathgeneratepseudorandomnumber{% + \begingroup% + \c@pgfmath@counta=\pgfmath@rnd@z% + \c@pgfmath@countb=\pgfmath@rnd@z% + \c@pgfmath@countc=\pgfmath@rnd@q% + \divide\c@pgfmath@counta by\c@pgfmath@countc% + \multiply\c@pgfmath@counta by-\c@pgfmath@countc% + \advance\c@pgfmath@counta by\c@pgfmath@countb + \c@pgfmath@countc=\pgfmath@rnd@a% + \multiply\c@pgfmath@counta by\c@pgfmath@countc% + \c@pgfmath@countc=\pgfmath@rnd@q% + \divide\c@pgfmath@countb by\c@pgfmath@countc% + \c@pgfmath@countc=\pgfmath@rnd@r% + \multiply\c@pgfmath@countb by\c@pgfmath@countc% + \advance\c@pgfmath@counta by-\c@pgfmath@countb% + \ifnum\c@pgfmath@counta<0\relax% + \c@pgfmath@countb=\pgfmath@rnd@m% + \advance\c@pgfmath@counta by\c@pgfmath@countb% + \fi% + \xdef\pgfmath@rnd@z{\the\c@pgfmath@counta}% + \endgroup% + \edef\pgfmathresult{\pgfmath@rnd@z}% +} + +% \pgfmathrnd +% +% Generates a pseudo-random number between 0 and 1. +% +\pgfmathdeclarefunction{rnd}{0}{% + \begingroup% + \pgfmathgeneratepseudorandomnumber% + \c@pgfmath@counta\pgfmathresult% + \c@pgfmath@countb\c@pgfmath@counta% + \divide\c@pgfmath@countb100001\relax% To get one. + \multiply\c@pgfmath@countb-100001\relax% + \advance\c@pgfmath@countb\c@pgfmath@counta% + \advance\c@pgfmath@countb1000000\relax% + \expandafter\pgfmathrnd@@\the\c@pgfmath@countb\pgfmath@% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +\def\pgfmathrnd@@#1#2#3\pgfmath@{% + \edef\pgfmath@temp{#2.#3}% + \pgfmath@x=\pgfmath@temp pt\relax% +}% + +% \pgfmathrand +% +% Generates a pseudo-random number between -1 and 1. +% +\pgfmathdeclarefunction{rand}{0}{% + \begingroup% + \pgfmathgeneratepseudorandomnumber% + \c@pgfmath@counta\pgfmathresult% + \c@pgfmath@countb\c@pgfmath@counta% + \divide\c@pgfmath@countb200001\relax% + \multiply\c@pgfmath@countb-200001\relax% + \advance\c@pgfmath@countb\c@pgfmath@counta% + \advance\c@pgfmath@countb-100000\relax% + \ifnum\c@pgfmath@countb<0\relax% + \advance\c@pgfmath@countb-1000000\relax% + \else% + \advance\c@pgfmath@countb1000000\relax% + \fi% + \expandafter\pgfmathrand@@\the\c@pgfmath@countb\pgfmath@% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +\def\pgfmathrand@@#1#2#3#4\pgfmath@{% + \ifx#1-% + \edef\pgfmath@temp{-#3.#4}% + \else% + \edef\pgfmath@temp{#2.#3#4}% + \fi% + \pgfmath@x=\pgfmath@temp pt\relax% +}% + +\pgfmathdeclarefunction{random}{...}{% + \begingroup% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \pgfmathrnd@% + \else% + \expandafter\pgfmathrandom@@#1\pgfmath@stop% + \fi% + \pgfmath@smuggleone\pgfmathresult% + \endgroup} + +\def\pgfmathrandom@@{\futurelet\pgfmath@token\pgfmathrandom@@@} +\def\pgfmathrandom@@@{% + \ifx\pgfmath@token\bgroup% + \expandafter\pgfmath@random@@@@% + \else% + \expandafter\pgfmath@random@@@@@% + \fi% +} +\def\pgfmath@random@@@@@#1\pgfmath@stop{% + \pgfmathrandominteger\pgfmathresult{1}{#1}% +} +\def\pgfmath@random@@@@#1#2\pgfmath@stop{% + \pgfmathrandominteger\pgfmathresult{#1}{#2}% +} + +% \pgfmathrandominteger +% +% Return a 'randomly' selected integer in the range #2 - #3 (inclusive). +% +% #1 - a macro to store the integer (not a count register). +% #2 - the lower limit of the range. +% #3 - the upper limit of the range. +% +\def\pgfmathrandominteger#1#2#3{% + \begingroup% + \pgfmathsetcount\c@pgfmath@counta{#2}% + \pgfmathsetcount\c@pgfmath@countb{#3}% + \c@pgfmath@countc\c@pgfmath@countb% + % OK. Maybe #2 > #3. + \ifnum\c@pgfmath@counta>\c@pgfmath@countb\relax% + \c@pgfmath@countc\c@pgfmath@counta% + \c@pgfmath@counta\c@pgfmath@countb% + \c@pgfmath@countb\c@pgfmath@countc% + \fi% + \c@pgfmath@countd\c@pgfmath@counta + \advance\c@pgfmath@countc1\relax% + \advance\c@pgfmath@countc-\c@pgfmath@counta% + \pgfmathgeneratepseudorandomnumber% + \c@pgfmath@counta\pgfmathresult\relax% + \c@pgfmath@countb\c@pgfmath@counta% + \divide\c@pgfmath@countb\c@pgfmath@countc% + \multiply\c@pgfmath@countb-\c@pgfmath@countc% + \advance\c@pgfmath@counta\c@pgfmath@countb% + \advance\c@pgfmath@counta\c@pgfmath@countd + \edef\pgfmathresult{\the\c@pgfmath@counta}% + \pgfmath@smuggleone{\pgfmathresult}% + \endgroup% + \edef#1{\pgfmathresult}% +} + +% \pgfmathdeclarerandomlist +% +% Create a list to be used with \pgfmathrandomelement. +% +% #1 - the name of the list +% #2 - a list of elements (e.g., {item-1}{item-2}...{item-n}). +% +\def\pgfmathdeclarerandomlist#1#2{% + \def\pgfmath@randomlistname{#1}% + \begingroup% + \c@pgfmath@counta=1\relax% + % {} is a possible random element so (locally) + % redefine \pgfmath@empty. + \def\pgfmath@empty{pgfmath@empty}% + \expandafter\pgfmath@scanrandomlist#2{pgfmath@empty}} +\def\pgfmath@scanrandomlist#1{% + \def\pgfmath@scanneditem{#1}% + \ifx\pgfmath@scanneditem\pgfmath@empty% + \advance\c@pgfmath@counta-1\relax% + \expandafter\xdef\csname pgfmath@randomlist@\pgfmath@randomlistname\endcsname{\the\c@pgfmath@counta}% + \endgroup% + \else% + \expandafter\gdef\csname pgfmath@randomlist@\pgfmath@randomlistname @\the\c@pgfmath@counta\endcsname{#1}% + \advance\c@pgfmath@counta1\relax% + \expandafter\pgfmath@scanrandomlist% + \fi} + +% \pgfmathrandomitem +% +% Return a 'randomly' selected element from a list. +% +% #1 - a macro to store the item. +% #2 - the name of the list. +% +\def\pgfmathrandomitem#1#2{% + \pgfmath@ifundefined{pgfmath@randomlist@#2}{\pgfmath@error{Unknown random list `#2'}{}}{% + \edef\pgfmath@randomlistlength{\csname pgfmath@randomlist@#2\endcsname}% + \pgfmathrandominteger{\pgfmath@randomtemp}{1}{\pgfmath@randomlistlength}% + \expandafter\def\expandafter#1\expandafter{\csname pgfmath@randomlist@#2@\pgfmath@randomtemp\endcsname}}} diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.round.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.round.code.tex new file mode 100644 index 0000000000..120e971c8c --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.round.code.tex @@ -0,0 +1,123 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the mathematical functions and operators. +% +% Version 1.414213 29/9/2007 + +% round function. Uses asymmetric half-up rounding. +% +\pgfmathdeclarefunction{round}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \afterassignment\pgfmath@xa% + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax% + \pgfmath@xb\pgfmath@x% + \ifdim\pgfmath@xb<0pt\relax% + \ifdim\pgfmath@xa<0.5pt\relax% + \else% + \advance\c@pgfmath@counta-1\relax% + \fi% + \else% + \ifdim\pgfmath@xa<0.5pt\relax% + \else% + \advance\c@pgfmath@counta1\relax% + \fi% + \fi% + \pgfmath@returnone\the\c@pgfmath@counta pt% + \endgroup% +}% + +% floor function. +% +\pgfmathdeclarefunction{floor}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \afterassignment\pgfmathfloor@collect@remainder% + \expandafter\c@pgfmath@counta\the\pgfmath@x\pgfmath@% + \expandafter\pgfmath@x#1pt\relax% + \ifdim\pgfmath@x<0pt\relax% + \ifdim\pgfmathfloor@remainder>0pt + \advance\c@pgfmath@counta by -1\relax% + \else + % ok, we stripped only '0'. + \fi + \fi% + \pgfmath@x\c@pgfmath@counta pt\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +\def\pgfmathfloor@collect@remainder#1\pgfmath@{% + \def\pgfmathfloor@remainder{#1}% + \ifx\pgfmathfloor@remainder\pgfutil@empty + \def\pgfmathfloor@remainder{0}% + \fi +}% + +% ceil function. +% +\pgfmathdeclarefunction{ceil}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax\pgfmath@% + \pgfmath@y\pgfmath@x% + \advance\pgfmath@y-\c@pgfmath@counta pt\relax% + \pgfmath@x\c@pgfmath@counta pt\relax% + \ifdim\pgfmath@y>0pt\relax% + \advance\pgfmath@x1pt\relax% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +% int function +% +\pgfmathdeclarefunction{int}{1}{% + \begingroup% + \expandafter\pgfmathint@@#1.\pgfmath@stop + \pgfmath@smuggleone\pgfmathresult% + \endgroup} + +\def\pgfmathint@@#1.#2\pgfmath@stop{% + \def\pgfmath@temp{#1}% + \ifx\pgfmath@temp\pgfmath@empty% + \def\pgfmathresult{0}% + \else% + \pgfmath@in@{#1}{+-+0-0}% + \ifpgfmath@in@ + \def\pgfmathresult{0}% + \else% + \def\pgfmathresult{#1}% + \fi% + \fi} + +% frac function. +% +\pgfmathdeclarefunction{frac}{1}{% + \begingroup% + \expandafter\pgfmathfrac@@#1.\pgfmath@stop% + \pgfmath@smuggleone\pgfmathresult% + \endgroup} + +\def\pgfmathfrac@@#1.{% + \pgfmath@ifnextchar\pgfmath@stop{\def\pgfmathresult{0.0}\pgfmath@gobbleone}{\pgfmathfrac@@@}% +} +\def\pgfmathfrac@@@#1.\pgfmath@stop{\def\pgfmathresult{0.#1}} + +% real function. +% +\pgfmathdeclarefunction{real}{1}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmath@smuggleone\pgfmathresult% + \endgroup% +} diff --git a/graphics/pgf/base/tex/generic/math/pgfmathfunctions.trigonometric.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.trigonometric.code.tex new file mode 100644 index 0000000000..b76c5b440c --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathfunctions.trigonometric.code.tex @@ -0,0 +1,1571 @@ +% Copyright 2019 by Mark Wibrow +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +% This file defines the trigonometric functions/functions. +% +% Much of this file is based on ideas and code (particularly +% the old \pgfcoremath.code.tex) due to Till Tantau. +% +% Version 1.414213 29/9/2007 + +% \pgfmathpi +% +\pgfmathdeclarefunction{pi}{0}{\def\pgfmathresult{3.141592654}} + +\pgfkeys{ + /pgf/trig format/.is choice, + % attention: the luamath library will hook into these code keys. + /pgf/trig format/deg/.code={\def\pgfmath@trig@format@choice{0}}, + /pgf/trig format/rad/.code={\def\pgfmath@trig@format@choice{1}}, + /pgf/trig format/deg, +} + +% Executes #1 if 'trig format=deg' and #2 otherwise. +\def\pgfmathiftrigonometricusesdeg#1#2{% + \if0\pgfmath@trig@format@choice + #1% + \else + #2% + \fi +}% + +% \pgfmathradians +% (for compatibility with 1.18 beta, will be deprecated) +% +% Convert #1 from radians to degrees (accurate to 1 deg). +% +\pgfmathdeclarefunction{radians}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@x57.29577\pgfmath@x\relax% 57.29577 = 360/(2*pi) + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +% \pgfmathdeg +% +% Convert #1 from radians to degrees. +% +\pgfmathdeclarefunction{deg}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@scale@rad@to@deg\pgfmath@x + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +\def\pgfmath@scale@rad@to@deg#1{% + #1=57.29577#1\relax% 57.29577 = 360/(2*pi) +}% + +% \pgfmathrad +% +% Convert #1 from degrees to radians. +% +\pgfmathdeclarefunction{rad}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@scale@deg@to@rad\pgfmath@x + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + +\def\pgfmath@scale@deg@to@rad#1{% + #1=3.14159#1% + \divide#1180\relax% +}% + +% \pgfmathsin +% +% Calculate the sine of #1 (in degrees). +% +\pgfmathdeclarefunction{sin}{1}{% + % Let #1 = a.b + % Then sin(#1) \approx (1-b)*sin(a) + b*sin(a+1) + % + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \if1\pgfmath@trig@format@choice + % trig format=rad + \pgfmath@scale@rad@to@deg\pgfmath@x + \fi + \advance\pgfmath@x-90pt\relax% + \afterassignment\pgfmath@gobbletilpgfmath@ + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax\pgfmath@ + \divide\c@pgfmath@counta360\relax% + \multiply\c@pgfmath@counta-360\relax% + \advance\pgfmath@x\c@pgfmath@counta pt\relax% + \ifdim\pgfmath@x<0pt\relax\pgfmath@x-\pgfmath@x\fi% + \ifdim\pgfmath@x<180pt\relax% + \else + \pgfmath@x-\pgfmath@x% + \advance\pgfmath@x360pt\relax% + \fi% + % Now 0 <= x < 179. So split x into integer and decimal... + % + \afterassignment\pgfmath@xa% + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax% + % + % ...if #1 is an integer, don't do anything fancy. + \ifdim\pgfmath@xa=0pt% + \expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname pt\relax% + \else% + \pgfmath@x-\pgfmath@xa% + \advance\pgfmath@x1pt\relax% + \expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname\pgfmath@x% + \advance\c@pgfmath@counta1\relax% + \ifnum\c@pgfmath@counta=181\relax\c@pgfmath@counta179\relax\fi% + \expandafter\advance\expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname\pgfmath@xa% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup +} + +% \pgfmathcos +% +% Calculate the cosine of #1 (in degrees). +% +\pgfmathdeclarefunction{cos}{1}{% + % Let x = a.b + % Then cos(x) \approx (1-b)*cos(a) + b*cos(a+1) + % + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \if1\pgfmath@trig@format@choice + % trig format=rad + \pgfmath@scale@rad@to@deg\pgfmath@x + \fi + \afterassignment\pgfmath@gobbletilpgfmath@% + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax\pgfmath@% + \divide\c@pgfmath@counta360\relax% + \multiply\c@pgfmath@counta-360\relax% + \advance\pgfmath@x\c@pgfmath@counta pt\relax% + \ifdim\pgfmath@x<0pt\relax\pgfmath@x-\pgfmath@x\fi% + \ifdim\pgfmath@x<180pt\relax% + \else% + \pgfmath@x-\pgfmath@x% + \advance\pgfmath@x360pt\relax% + \fi% + % Now 0 <= x < 179. So split x into integer and decimal... + % + \afterassignment\pgfmath@xa% + \expandafter\c@pgfmath@counta\the\pgfmath@x\relax% + % + % ...if #1 is an integer, don't do anything fancy. + \ifdim\pgfmath@xa=0pt% + \expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname pt% + \else% + \pgfmath@x-\pgfmath@xa% + \advance\pgfmath@x1pt\relax% + \expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname\pgfmath@x% + \advance\c@pgfmath@counta1\relax% + \ifnum\c@pgfmath@counta=181\relax\c@pgfmath@counta179\relax\fi% + \expandafter\advance\expandafter\pgfmath@x\csname pgfmath@cos@\the\c@pgfmath@counta\endcsname\pgfmath@xa% + \fi% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% \pgfmathsincos +% +% Calculate the sin and cosine of #1 (in degrees). +% +\def\pgfmathsincos#1{% + \pgfmathparse{#1}% + \expandafter\pgfmathsincos@\expandafter{\pgfmathresult}} +\def\pgfmathsincos@#1{% + \edef\pgfmath@temparg{#1}% + \pgfmathsin@{\pgfmath@temparg}\edef\pgfmathresulty{\pgfmathresult}% + \pgfmathcos@{\pgfmath@temparg}\edef\pgfmathresultx{\pgfmathresult}% +} + +% \pgfmathtan +% +% Calculate the tangent of #1 (in degrees). +% +\pgfmathdeclarefunction{tan}{1}{% + \begingroup% + \edef\pgfmath@temparg{#1}% + \pgfmathcos@{\pgfmath@temparg}% + \expandafter\pgfmathreciprocal@\expandafter{\pgfmathresult}% + \edef\pgfmath@tantemp{\pgfmathresult}% + \pgfmathsin@{\pgfmath@temparg}% + \pgfmath@x\pgfmathresult pt\relax% + \pgfmath@x\pgfmath@tantemp\pgfmath@x% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% \pgfmathcosec +% +% Calculate the cosec of #1 (in degrees). +% +\pgfmathdeclarefunction{cosec}{1}{% + \expandafter\pgfmathsin@\expandafter{#1}% + \pgfmathreciprocal@{\pgfmathresult}% +} + +% \pgfmathsec +% +% Calculate the sec of #1 (in degrees). +% +\pgfmathdeclarefunction{sec}{1}{% + \expandafter\pgfmathcos@\expandafter{#1}% + \pgfmathreciprocal@{\pgfmathresult}% +} + +% \pgfmathcot +% +% Calculate the cotangent of #1 (in degrees). +% +\pgfmathdeclarefunction{cot}{1}{% + \begingroup% + \edef\pgfmath@temparg{#1}% + \pgfmathsin@{\pgfmath@temparg}% + \expandafter\pgfmathreciprocal@\expandafter{\pgfmathresult}% + \edef\pgfmath@tantemp{\pgfmathresult}% + \pgfmathcos@{\pgfmath@temparg}% + \pgfmath@x\pgfmathresult pt\relax% + \pgfmath@x\pgfmath@tantemp\pgfmath@x% + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +\def\pgfmath@multiply@thousand#1.#2#3#4#5\relax{% + \edef\pgfmathresult{#1#2#3#4.#5}% +}% + +% \pgfmathasin +% +% The asin of #1 +% +\pgfmathdeclarefunction{asin}{1}{% + \begingroup% + \pgfmath@x=#1pt % + \pgfmath@xa\pgfmath@x% + \edef\pgf@temp{\pgfmath@tonumber\pgfmath@x}% + % compute lossless '*1000' operation: + \expandafter\pgfmath@multiply@thousand\pgf@temp 000\relax + \pgfmath@x=\pgfmathresult pt % + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \pgfmath@table@lookup{\pgfmath@x}{pgfmath@acos@}{1001}% + \pgfmath@x=-\pgfmath@x + \advance\pgfmath@x90pt\relax% + \ifdim\pgfmath@xa<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \if1\pgfmath@trig@format@choice + % trig format=rad + \pgfmath@scale@deg@to@rad\pgfmath@x + \fi + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% Defines \pgfmath@x to be the result of the table lookup for value +% '#1' in table '#2' +% +% #1: a value for which lookup should be performed +% #2: the table's prefix name +% #3: the table's size +\def\pgfmath@table@lookup#1#2#3{% + \pgfmath@x=#1\relax + \expandafter\pgfmath@table@lookup@\the\pgfmath@x\relax{#2}{#3}% +} +\def\pgfmath@table@lookup@#1.#2\relax#3#4{% + \edef\pgf@temp{\Pgf@geT#2}% strip 'pt' suffix. + % + % prepare constant interpolant (i.e. the value at node '#1'): + \pgfmath@x=\csname #3#1\endcsname pt % + % + \c@pgfmath@countc=#1 % + \advance\c@pgfmath@countc by1 % + \ifnum\c@pgfmath@countc<#4 % + % Ah - we have enough elements in the table. + % + % perform linear interpolation: + \pgfmath@ya=\csname #3\the\c@pgfmath@countc\endcsname pt % + \advance\pgfmath@ya by-\pgfmath@x % + \advance\pgfmath@x by0.\pgf@temp\pgfmath@ya + \fi +}% + +% \pgfmathacos +% +% The acos of #1 +% +\pgfmathdeclarefunction{acos}{1}{% + \begingroup% + \pgfmath@x#1pt\relax% + \pgfmath@xa\pgfmath@x% + \edef\pgf@temp{\pgfmath@tonumber\pgfmath@x}% + % compute lossless '*1000' operation: + \expandafter\pgfmath@multiply@thousand\pgf@temp 000\relax + \pgfmath@x=\pgfmathresult pt % + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \pgfmath@table@lookup{\pgfmath@x}{pgfmath@acos@}{1001}% + \ifdim\pgfmath@xa<0pt\relax% + \pgfmath@x-\pgfmath@x% + \advance\pgfmath@x by180pt\relax% + \fi% + \if1\pgfmath@trig@format@choice + % trig format=rad + \pgfmath@scale@deg@to@rad\pgfmath@x + \fi + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +\pgfmathdeclarefunction{atan}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@xa\pgfmath@x% + \ifdim\pgfmath@x<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \pgfmath@xb\pgfmath@x% + \ifdim\pgfmath@x>1pt\relax% + \edef\pgfmath@temp{\pgfmath@tonumber{\pgfmath@x}}% + \pgfmathreciprocal@{\pgfmath@temp}% + \pgfmath@x\pgfmathresult pt\relax% + \fi% + % compute lossless '*1000' operation: + \edef\pgf@temp{\pgfmath@tonumber\pgfmath@x}% + \expandafter\pgfmath@multiply@thousand\pgf@temp 000\relax + \pgfmath@x=\pgfmathresult pt % + \pgfmath@table@lookup{\pgfmath@x}{pgfmath@atan@}{1001}%xxx + \ifdim\pgfmath@xb>1pt\relax% + \pgfmath@x=-\pgfmath@x% + \advance\pgfmath@x90pt% + \fi% + \ifdim\pgfmath@xa<0pt\relax% + \pgfmath@x-\pgfmath@x% + \fi% + \if1\pgfmath@trig@format@choice + % trig format=rad + \pgfmath@scale@deg@to@rad\pgfmath@x + \fi + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +\pgfmathdeclarefunction{atan2}{2}{% + % Note: first parameter is y (!), second is x (!) + \begingroup% + \let\pgfmath@trig@format@choice@@=\pgfmath@trig@format@choice + \def\pgfmath@trig@format@choice{0}% + \pgfmath@y=#1pt\relax% + \ifdim\pgfmath@y<0pt\relax% + \pgfmath@y=-\pgfmath@y% + \fi% + \ifdim\pgfmath@y<0.001pt\relax% + \ifdim#2pt<0pt\relax% + \pgfmath@x=+180pt\relax% + \else% + \ifdim#2pt>0pt\relax% + \pgfmath@x=0pt\relax% + \else% + \ifdim#1pt<0pt% + \pgfmath@x=-90pt\relax% + \else% + \pgfmath@x=90pt\relax% + \fi% + \fi% + \fi% + \else% + \pgfmathabs@{#1}\let\pgfmath@tempa\pgfmathresult% + \pgfmathabs@{#2}\let\pgfmath@tempb\pgfmathresult% + \ifdim\pgfmath@tempa pt>\pgfmath@tempb pt% + \pgfmathdivide@{#2}{\pgfmath@tempa}% + \expandafter\pgfmathatan@\expandafter{\pgfmathresult}% + \pgfmath@x=90pt% + \advance\pgfmath@x by-\pgfmathresult pt\relax% + \else% + \pgfmathdivide@{\pgfmath@tempa}{#2}% + \expandafter\pgfmathatan@\expandafter{\pgfmathresult}% + \pgfmath@x=\pgfmathresult pt\relax% + \ifdim#2pt<0pt% + \advance\pgfmath@x by180pt\relax% + \fi% + \fi% + \ifdim#1pt<0pt\relax% + \pgfmath@x=-\pgfmath@x% + \fi% + \fi% + \if1\pgfmath@trig@format@choice@@ + % trig format=rad + \pgfmath@scale@deg@to@rad\pgfmath@x + \fi + \pgfmath@returnone\pgfmath@x% + \endgroup% +} + +% This is needed since \pgfmathatan2 is not a legal macro name +\expandafter\let\expandafter\pgfmathatantwo\csname pgfmathatan2\endcsname +\expandafter\let\expandafter\pgfmathatantwo@\csname pgfmathatan2@\endcsname + +\def\pgfmath@def#1#2#3{\expandafter\def\csname pgfmath@#1@#2\endcsname{#3}} +\pgfmath@def{cos}{0}{1.00000} \pgfmath@def{cos}{1}{0.99985} +\pgfmath@def{cos}{2}{0.99939} \pgfmath@def{cos}{3}{0.99863} +\pgfmath@def{cos}{4}{0.99756} \pgfmath@def{cos}{5}{0.99619} +\pgfmath@def{cos}{6}{0.99452} \pgfmath@def{cos}{7}{0.99255} +\pgfmath@def{cos}{8}{0.99027} \pgfmath@def{cos}{9}{0.98769} +\pgfmath@def{cos}{10}{0.98481} \pgfmath@def{cos}{11}{0.98163} +\pgfmath@def{cos}{12}{0.97815} \pgfmath@def{cos}{13}{0.97437} +\pgfmath@def{cos}{14}{0.97030} \pgfmath@def{cos}{15}{0.96593} +\pgfmath@def{cos}{16}{0.96126} \pgfmath@def{cos}{17}{0.95630} +\pgfmath@def{cos}{18}{0.95106} \pgfmath@def{cos}{19}{0.94552} +\pgfmath@def{cos}{20}{0.93969} \pgfmath@def{cos}{21}{0.93358} +\pgfmath@def{cos}{22}{0.92718} \pgfmath@def{cos}{23}{0.92050} +\pgfmath@def{cos}{24}{0.91355} \pgfmath@def{cos}{25}{0.90631} +\pgfmath@def{cos}{26}{0.89879} \pgfmath@def{cos}{27}{0.89101} +\pgfmath@def{cos}{28}{0.88295} \pgfmath@def{cos}{29}{0.87462} +\pgfmath@def{cos}{30}{0.86603} \pgfmath@def{cos}{31}{0.85717} +\pgfmath@def{cos}{32}{0.84805} \pgfmath@def{cos}{33}{0.83867} +\pgfmath@def{cos}{34}{0.82904} \pgfmath@def{cos}{35}{0.81915} +\pgfmath@def{cos}{36}{0.80902} \pgfmath@def{cos}{37}{0.79864} +\pgfmath@def{cos}{38}{0.78801} \pgfmath@def{cos}{39}{0.77715} +\pgfmath@def{cos}{40}{0.76604} \pgfmath@def{cos}{41}{0.75471} +\pgfmath@def{cos}{42}{0.74314} \pgfmath@def{cos}{43}{0.73135} +\pgfmath@def{cos}{44}{0.71934} \pgfmath@def{cos}{45}{0.70711} +\pgfmath@def{cos}{46}{0.69466} \pgfmath@def{cos}{47}{0.68200} +\pgfmath@def{cos}{48}{0.66913} \pgfmath@def{cos}{49}{0.65606} +\pgfmath@def{cos}{50}{0.64279} \pgfmath@def{cos}{51}{0.62932} +\pgfmath@def{cos}{52}{0.61566} \pgfmath@def{cos}{53}{0.60182} +\pgfmath@def{cos}{54}{0.58779} \pgfmath@def{cos}{55}{0.57358} +\pgfmath@def{cos}{56}{0.55919} \pgfmath@def{cos}{57}{0.54464} +\pgfmath@def{cos}{58}{0.52992} \pgfmath@def{cos}{59}{0.51504} +\pgfmath@def{cos}{60}{0.50000} \pgfmath@def{cos}{61}{0.48481} +\pgfmath@def{cos}{62}{0.46947} \pgfmath@def{cos}{63}{0.45399} +\pgfmath@def{cos}{64}{0.43837} \pgfmath@def{cos}{65}{0.42262} +\pgfmath@def{cos}{66}{0.40674} \pgfmath@def{cos}{67}{0.39073} +\pgfmath@def{cos}{68}{0.37461} \pgfmath@def{cos}{69}{0.35837} +\pgfmath@def{cos}{70}{0.34202} \pgfmath@def{cos}{71}{0.32557} +\pgfmath@def{cos}{72}{0.30902} \pgfmath@def{cos}{73}{0.29237} +\pgfmath@def{cos}{74}{0.27564} \pgfmath@def{cos}{75}{0.25882} +\pgfmath@def{cos}{76}{0.24192} \pgfmath@def{cos}{77}{0.22495} +\pgfmath@def{cos}{78}{0.20791} \pgfmath@def{cos}{79}{0.19081} +\pgfmath@def{cos}{80}{0.17365} \pgfmath@def{cos}{81}{0.15643} +\pgfmath@def{cos}{82}{0.13917} \pgfmath@def{cos}{83}{0.12187} +\pgfmath@def{cos}{84}{0.10453} \pgfmath@def{cos}{85}{0.08716} +\pgfmath@def{cos}{86}{0.06976} \pgfmath@def{cos}{87}{0.05234} +\pgfmath@def{cos}{88}{0.03490} \pgfmath@def{cos}{89}{0.01745} +\pgfmath@def{cos}{90}{0.00000} \pgfmath@def{cos}{91}{-0.01745} +\pgfmath@def{cos}{92}{-0.03490} \pgfmath@def{cos}{93}{-0.05234} +\pgfmath@def{cos}{94}{-0.06976} \pgfmath@def{cos}{95}{-0.08716} +\pgfmath@def{cos}{96}{-0.10453} \pgfmath@def{cos}{97}{-0.12187} +\pgfmath@def{cos}{98}{-0.13917} \pgfmath@def{cos}{99}{-0.15643} +\pgfmath@def{cos}{100}{-0.17365} \pgfmath@def{cos}{101}{-0.19081} +\pgfmath@def{cos}{102}{-0.20791} \pgfmath@def{cos}{103}{-0.22495} +\pgfmath@def{cos}{104}{-0.24192} \pgfmath@def{cos}{105}{-0.25882} +\pgfmath@def{cos}{106}{-0.27564} \pgfmath@def{cos}{107}{-0.29237} +\pgfmath@def{cos}{108}{-0.30902} \pgfmath@def{cos}{109}{-0.32557} +\pgfmath@def{cos}{110}{-0.34202} \pgfmath@def{cos}{111}{-0.35837} +\pgfmath@def{cos}{112}{-0.37461} \pgfmath@def{cos}{113}{-0.39073} +\pgfmath@def{cos}{114}{-0.40674} \pgfmath@def{cos}{115}{-0.42262} +\pgfmath@def{cos}{116}{-0.43837} \pgfmath@def{cos}{117}{-0.45399} +\pgfmath@def{cos}{118}{-0.46947} \pgfmath@def{cos}{119}{-0.48481} +\pgfmath@def{cos}{120}{-0.50000} \pgfmath@def{cos}{121}{-0.51504} +\pgfmath@def{cos}{122}{-0.52992} \pgfmath@def{cos}{123}{-0.54464} +\pgfmath@def{cos}{124}{-0.55919} \pgfmath@def{cos}{125}{-0.57358} +\pgfmath@def{cos}{126}{-0.58779} \pgfmath@def{cos}{127}{-0.60182} +\pgfmath@def{cos}{128}{-0.61566} \pgfmath@def{cos}{129}{-0.62932} +\pgfmath@def{cos}{130}{-0.64279} \pgfmath@def{cos}{131}{-0.65606} +\pgfmath@def{cos}{132}{-0.66913} \pgfmath@def{cos}{133}{-0.68200} +\pgfmath@def{cos}{134}{-0.69466} \pgfmath@def{cos}{135}{-0.70711} +\pgfmath@def{cos}{136}{-0.71934} \pgfmath@def{cos}{137}{-0.73135} +\pgfmath@def{cos}{138}{-0.74314} \pgfmath@def{cos}{139}{-0.75471} +\pgfmath@def{cos}{140}{-0.76604} \pgfmath@def{cos}{141}{-0.77715} +\pgfmath@def{cos}{142}{-0.78801} \pgfmath@def{cos}{143}{-0.79864} +\pgfmath@def{cos}{144}{-0.80902} \pgfmath@def{cos}{145}{-0.81915} +\pgfmath@def{cos}{146}{-0.82904} \pgfmath@def{cos}{147}{-0.83867} +\pgfmath@def{cos}{148}{-0.84805} \pgfmath@def{cos}{149}{-0.85717} +\pgfmath@def{cos}{150}{-0.86603} \pgfmath@def{cos}{151}{-0.87462} +\pgfmath@def{cos}{152}{-0.88295} \pgfmath@def{cos}{153}{-0.89101} +\pgfmath@def{cos}{154}{-0.89879} \pgfmath@def{cos}{155}{-0.90631} +\pgfmath@def{cos}{156}{-0.91355} \pgfmath@def{cos}{157}{-0.92050} +\pgfmath@def{cos}{158}{-0.92718} \pgfmath@def{cos}{159}{-0.93358} +\pgfmath@def{cos}{160}{-0.93969} \pgfmath@def{cos}{161}{-0.94552} +\pgfmath@def{cos}{162}{-0.95106} \pgfmath@def{cos}{163}{-0.95630} +\pgfmath@def{cos}{164}{-0.96126} \pgfmath@def{cos}{165}{-0.96593} +\pgfmath@def{cos}{166}{-0.97030} \pgfmath@def{cos}{167}{-0.97437} +\pgfmath@def{cos}{168}{-0.97815} \pgfmath@def{cos}{169}{-0.98163} +\pgfmath@def{cos}{170}{-0.98481} \pgfmath@def{cos}{171}{-0.98769} +\pgfmath@def{cos}{172}{-0.99027} \pgfmath@def{cos}{173}{-0.99255} +\pgfmath@def{cos}{174}{-0.99452} \pgfmath@def{cos}{175}{-0.99619} +\pgfmath@def{cos}{176}{-0.99756} \pgfmath@def{cos}{177}{-0.99863} +\pgfmath@def{cos}{178}{-0.99939} \pgfmath@def{cos}{179}{-0.99985} +\pgfmath@def{cos}{180}{-1.00000} \pgfmath@def{cos}{181}{-0.99985} + +\pgfmath@def{cosfrac}{0}{1.00000} \pgfmath@def{cosfrac}{1}{0.99995} +\pgfmath@def{cosfrac}{2}{0.99980} \pgfmath@def{cosfrac}{3}{0.99955} +\pgfmath@def{cosfrac}{4}{0.99920} \pgfmath@def{cosfrac}{5}{0.99875} +\pgfmath@def{cosfrac}{6}{0.99820} \pgfmath@def{cosfrac}{7}{0.99755} +\pgfmath@def{cosfrac}{8}{0.99681} \pgfmath@def{cosfrac}{9}{0.99597} +\pgfmath@def{cosfrac}{10}{0.99503} \pgfmath@def{cosfrac}{11}{0.99400} +\pgfmath@def{cosfrac}{12}{0.99287} \pgfmath@def{cosfrac}{13}{0.99165} +\pgfmath@def{cosfrac}{14}{0.99034} \pgfmath@def{cosfrac}{15}{0.98893} +\pgfmath@def{cosfrac}{16}{0.98744} \pgfmath@def{cosfrac}{17}{0.98585} +\pgfmath@def{cosfrac}{18}{0.98418} \pgfmath@def{cosfrac}{19}{0.98242} +\pgfmath@def{cosfrac}{20}{0.98058} \pgfmath@def{cosfrac}{21}{0.97865} +\pgfmath@def{cosfrac}{22}{0.97664} \pgfmath@def{cosfrac}{23}{0.97455} +\pgfmath@def{cosfrac}{24}{0.97238} \pgfmath@def{cosfrac}{25}{0.97014} +\pgfmath@def{cosfrac}{26}{0.96782} \pgfmath@def{cosfrac}{27}{0.96542} +\pgfmath@def{cosfrac}{28}{0.96296} \pgfmath@def{cosfrac}{29}{0.96042} +\pgfmath@def{cosfrac}{30}{0.95782} \pgfmath@def{cosfrac}{31}{0.95515} +\pgfmath@def{cosfrac}{32}{0.95242} \pgfmath@def{cosfrac}{33}{0.94962} +\pgfmath@def{cosfrac}{34}{0.94677} \pgfmath@def{cosfrac}{35}{0.94385} +\pgfmath@def{cosfrac}{36}{0.94088} \pgfmath@def{cosfrac}{37}{0.93786} +\pgfmath@def{cosfrac}{38}{0.93478} \pgfmath@def{cosfrac}{39}{0.93165} +\pgfmath@def{cosfrac}{40}{0.92847} \pgfmath@def{cosfrac}{41}{0.92525} +\pgfmath@def{cosfrac}{42}{0.92198} \pgfmath@def{cosfrac}{43}{0.91866} +\pgfmath@def{cosfrac}{44}{0.91531} \pgfmath@def{cosfrac}{45}{0.91192} +\pgfmath@def{cosfrac}{46}{0.90849} \pgfmath@def{cosfrac}{47}{0.90502} +\pgfmath@def{cosfrac}{48}{0.90152} \pgfmath@def{cosfrac}{49}{0.89799} +\pgfmath@def{cosfrac}{50}{0.89442} \pgfmath@def{cosfrac}{51}{0.89083} +\pgfmath@def{cosfrac}{52}{0.88721} \pgfmath@def{cosfrac}{53}{0.88357} +\pgfmath@def{cosfrac}{54}{0.87990} \pgfmath@def{cosfrac}{55}{0.87621} +\pgfmath@def{cosfrac}{56}{0.87250} \pgfmath@def{cosfrac}{57}{0.86877} +\pgfmath@def{cosfrac}{58}{0.86503} \pgfmath@def{cosfrac}{59}{0.86126} +\pgfmath@def{cosfrac}{60}{0.85749} \pgfmath@def{cosfrac}{61}{0.85370} +\pgfmath@def{cosfrac}{62}{0.84990} \pgfmath@def{cosfrac}{63}{0.84609} +\pgfmath@def{cosfrac}{64}{0.84227} \pgfmath@def{cosfrac}{65}{0.83844} +\pgfmath@def{cosfrac}{66}{0.83460} \pgfmath@def{cosfrac}{67}{0.83077} +\pgfmath@def{cosfrac}{68}{0.82692} \pgfmath@def{cosfrac}{69}{0.82308} +\pgfmath@def{cosfrac}{70}{0.81923} \pgfmath@def{cosfrac}{71}{0.81538} +\pgfmath@def{cosfrac}{72}{0.81153} \pgfmath@def{cosfrac}{73}{0.80768} +\pgfmath@def{cosfrac}{74}{0.80384} \pgfmath@def{cosfrac}{75}{0.80000} +\pgfmath@def{cosfrac}{76}{0.79616} \pgfmath@def{cosfrac}{77}{0.79232} +\pgfmath@def{cosfrac}{78}{0.78850} \pgfmath@def{cosfrac}{79}{0.78468} +\pgfmath@def{cosfrac}{80}{0.78086} \pgfmath@def{cosfrac}{81}{0.77706} +\pgfmath@def{cosfrac}{82}{0.77326} \pgfmath@def{cosfrac}{83}{0.76948} +\pgfmath@def{cosfrac}{84}{0.76570} \pgfmath@def{cosfrac}{85}{0.76193} +\pgfmath@def{cosfrac}{86}{0.75818} \pgfmath@def{cosfrac}{87}{0.75444} +\pgfmath@def{cosfrac}{88}{0.75071} \pgfmath@def{cosfrac}{89}{0.74699} +\pgfmath@def{cosfrac}{90}{0.74329} \pgfmath@def{cosfrac}{91}{0.73960} +\pgfmath@def{cosfrac}{92}{0.73593} \pgfmath@def{cosfrac}{93}{0.73227} +\pgfmath@def{cosfrac}{94}{0.72862} \pgfmath@def{cosfrac}{95}{0.72499} +\pgfmath@def{cosfrac}{96}{0.72138} \pgfmath@def{cosfrac}{97}{0.71779} +\pgfmath@def{cosfrac}{98}{0.71421} \pgfmath@def{cosfrac}{99}{0.71065} +\pgfmath@def{cosfrac}{100}{0.70710} + +% Oh No! Some really loooooong tables. +\pgfmath@def{atan}{0}{0.00000} \pgfmath@def{atan}{1}{0.05729} +\pgfmath@def{atan}{2}{0.11459} \pgfmath@def{atan}{3}{0.17188} +\pgfmath@def{atan}{4}{0.22918} \pgfmath@def{atan}{5}{0.28647} +\pgfmath@def{atan}{6}{0.34377} \pgfmath@def{atan}{7}{0.40106} +\pgfmath@def{atan}{8}{0.45835} \pgfmath@def{atan}{9}{0.51564} +\pgfmath@def{atan}{10}{0.57293} \pgfmath@def{atan}{11}{0.63022} +\pgfmath@def{atan}{12}{0.68751} \pgfmath@def{atan}{13}{0.74480} +\pgfmath@def{atan}{14}{0.80208} \pgfmath@def{atan}{15}{0.85937} +\pgfmath@def{atan}{16}{0.91665} \pgfmath@def{atan}{17}{0.97393} +\pgfmath@def{atan}{18}{1.03121} \pgfmath@def{atan}{19}{1.08848} +\pgfmath@def{atan}{20}{1.14576} \pgfmath@def{atan}{21}{1.20303} +\pgfmath@def{atan}{22}{1.26030} \pgfmath@def{atan}{23}{1.31757} +\pgfmath@def{atan}{24}{1.37483} \pgfmath@def{atan}{25}{1.43209} +\pgfmath@def{atan}{26}{1.48935} \pgfmath@def{atan}{27}{1.54661} +\pgfmath@def{atan}{28}{1.60386} \pgfmath@def{atan}{29}{1.66111} +\pgfmath@def{atan}{30}{1.71835} \pgfmath@def{atan}{31}{1.77560} +\pgfmath@def{atan}{32}{1.83284} \pgfmath@def{atan}{33}{1.89007} +\pgfmath@def{atan}{34}{1.94730} \pgfmath@def{atan}{35}{2.00453} +\pgfmath@def{atan}{36}{2.06175} \pgfmath@def{atan}{37}{2.11897} +\pgfmath@def{atan}{38}{2.17619} \pgfmath@def{atan}{39}{2.23340} +\pgfmath@def{atan}{40}{2.29061} \pgfmath@def{atan}{41}{2.34781} +\pgfmath@def{atan}{42}{2.40500} \pgfmath@def{atan}{43}{2.46220} +\pgfmath@def{atan}{44}{2.51938} \pgfmath@def{atan}{45}{2.57657} +\pgfmath@def{atan}{46}{2.63374} \pgfmath@def{atan}{47}{2.69092} +\pgfmath@def{atan}{48}{2.74808} \pgfmath@def{atan}{49}{2.80524} +\pgfmath@def{atan}{50}{2.86240} \pgfmath@def{atan}{51}{2.91955} +\pgfmath@def{atan}{52}{2.97669} \pgfmath@def{atan}{53}{3.03383} +\pgfmath@def{atan}{54}{3.09097} \pgfmath@def{atan}{55}{3.14809} +\pgfmath@def{atan}{56}{3.20521} \pgfmath@def{atan}{57}{3.26232} +\pgfmath@def{atan}{58}{3.31943} \pgfmath@def{atan}{59}{3.37653} +\pgfmath@def{atan}{60}{3.43363} \pgfmath@def{atan}{61}{3.49071} +\pgfmath@def{atan}{62}{3.54779} \pgfmath@def{atan}{63}{3.60487} +\pgfmath@def{atan}{64}{3.66193} \pgfmath@def{atan}{65}{3.71899} +\pgfmath@def{atan}{66}{3.77604} \pgfmath@def{atan}{67}{3.83308} +\pgfmath@def{atan}{68}{3.89012} \pgfmath@def{atan}{69}{3.94715} +\pgfmath@def{atan}{70}{4.00417} \pgfmath@def{atan}{71}{4.06118} +\pgfmath@def{atan}{72}{4.11819} \pgfmath@def{atan}{73}{4.17518} +\pgfmath@def{atan}{74}{4.23217} \pgfmath@def{atan}{75}{4.28915} +\pgfmath@def{atan}{76}{4.34612} \pgfmath@def{atan}{77}{4.40308} +\pgfmath@def{atan}{78}{4.46004} \pgfmath@def{atan}{79}{4.51698} +\pgfmath@def{atan}{80}{4.57392} \pgfmath@def{atan}{81}{4.63084} +\pgfmath@def{atan}{82}{4.68776} \pgfmath@def{atan}{83}{4.74467} +\pgfmath@def{atan}{84}{4.80157} \pgfmath@def{atan}{85}{4.85846} +\pgfmath@def{atan}{86}{4.91534} \pgfmath@def{atan}{87}{4.97221} +\pgfmath@def{atan}{88}{5.02907} \pgfmath@def{atan}{89}{5.08592} +\pgfmath@def{atan}{90}{5.14276} \pgfmath@def{atan}{91}{5.19959} +\pgfmath@def{atan}{92}{5.25641} \pgfmath@def{atan}{93}{5.31322} +\pgfmath@def{atan}{94}{5.37002} \pgfmath@def{atan}{95}{5.42681} +\pgfmath@def{atan}{96}{5.48359} \pgfmath@def{atan}{97}{5.54035} +\pgfmath@def{atan}{98}{5.59711} \pgfmath@def{atan}{99}{5.65385} +\pgfmath@def{atan}{100}{5.71059} \pgfmath@def{atan}{101}{5.76731} +\pgfmath@def{atan}{102}{5.82402} \pgfmath@def{atan}{103}{5.88072} +\pgfmath@def{atan}{104}{5.93741} \pgfmath@def{atan}{105}{5.99409} +\pgfmath@def{atan}{106}{6.05075} \pgfmath@def{atan}{107}{6.10741} +\pgfmath@def{atan}{108}{6.16405} \pgfmath@def{atan}{109}{6.22068} +\pgfmath@def{atan}{110}{6.27729} \pgfmath@def{atan}{111}{6.33390} +\pgfmath@def{atan}{112}{6.39049} \pgfmath@def{atan}{113}{6.44707} +\pgfmath@def{atan}{114}{6.50364} \pgfmath@def{atan}{115}{6.56019} +\pgfmath@def{atan}{116}{6.61673} \pgfmath@def{atan}{117}{6.67326} +\pgfmath@def{atan}{118}{6.72978} \pgfmath@def{atan}{119}{6.78628} +\pgfmath@def{atan}{120}{6.84277} \pgfmath@def{atan}{121}{6.89924} +\pgfmath@def{atan}{122}{6.95571} \pgfmath@def{atan}{123}{7.01216} +\pgfmath@def{atan}{124}{7.06859} \pgfmath@def{atan}{125}{7.12501} +\pgfmath@def{atan}{126}{7.18142} \pgfmath@def{atan}{127}{7.23781} +\pgfmath@def{atan}{128}{7.29419} \pgfmath@def{atan}{129}{7.35056} +\pgfmath@def{atan}{130}{7.40691} \pgfmath@def{atan}{131}{7.46324} +\pgfmath@def{atan}{132}{7.51957} \pgfmath@def{atan}{133}{7.57587} +\pgfmath@def{atan}{134}{7.63217} \pgfmath@def{atan}{135}{7.68844} +\pgfmath@def{atan}{136}{7.74471} \pgfmath@def{atan}{137}{7.80095} +\pgfmath@def{atan}{138}{7.85719} \pgfmath@def{atan}{139}{7.91340} +\pgfmath@def{atan}{140}{7.96961} \pgfmath@def{atan}{141}{8.02579} +\pgfmath@def{atan}{142}{8.08196} \pgfmath@def{atan}{143}{8.13812} +\pgfmath@def{atan}{144}{8.19426} \pgfmath@def{atan}{145}{8.25038} +\pgfmath@def{atan}{146}{8.30649} \pgfmath@def{atan}{147}{8.36258} +\pgfmath@def{atan}{148}{8.41866} \pgfmath@def{atan}{149}{8.47472} +\pgfmath@def{atan}{150}{8.53076} \pgfmath@def{atan}{151}{8.58679} +\pgfmath@def{atan}{152}{8.64280} \pgfmath@def{atan}{153}{8.69879} +\pgfmath@def{atan}{154}{8.75477} \pgfmath@def{atan}{155}{8.81073} +\pgfmath@def{atan}{156}{8.86667} \pgfmath@def{atan}{157}{8.92260} +\pgfmath@def{atan}{158}{8.97851} \pgfmath@def{atan}{159}{9.03440} +\pgfmath@def{atan}{160}{9.09027} \pgfmath@def{atan}{161}{9.14613} +\pgfmath@def{atan}{162}{9.20197} \pgfmath@def{atan}{163}{9.25779} +\pgfmath@def{atan}{164}{9.31359} \pgfmath@def{atan}{165}{9.36938} +\pgfmath@def{atan}{166}{9.42515} \pgfmath@def{atan}{167}{9.48090} +\pgfmath@def{atan}{168}{9.53663} \pgfmath@def{atan}{169}{9.59235} +\pgfmath@def{atan}{170}{9.64804} \pgfmath@def{atan}{171}{9.70372} +\pgfmath@def{atan}{172}{9.75938} \pgfmath@def{atan}{173}{9.81502} +\pgfmath@def{atan}{174}{9.87064} \pgfmath@def{atan}{175}{9.92624} +\pgfmath@def{atan}{176}{9.98182} \pgfmath@def{atan}{177}{10.03739} +\pgfmath@def{atan}{178}{10.09294} \pgfmath@def{atan}{179}{10.14846} +\pgfmath@def{atan}{180}{10.20397} \pgfmath@def{atan}{181}{10.25946} +\pgfmath@def{atan}{182}{10.31493} \pgfmath@def{atan}{183}{10.37037} +\pgfmath@def{atan}{184}{10.42580} \pgfmath@def{atan}{185}{10.48121} +\pgfmath@def{atan}{186}{10.53660} \pgfmath@def{atan}{187}{10.59197} +\pgfmath@def{atan}{188}{10.64732} \pgfmath@def{atan}{189}{10.70265} +\pgfmath@def{atan}{190}{10.75796} \pgfmath@def{atan}{191}{10.81325} +\pgfmath@def{atan}{192}{10.86852} \pgfmath@def{atan}{193}{10.92377} +\pgfmath@def{atan}{194}{10.97900} \pgfmath@def{atan}{195}{11.03420} +\pgfmath@def{atan}{196}{11.08939} \pgfmath@def{atan}{197}{11.14456} +\pgfmath@def{atan}{198}{11.19970} \pgfmath@def{atan}{199}{11.25483} +\pgfmath@def{atan}{200}{11.30993} \pgfmath@def{atan}{201}{11.36501} +\pgfmath@def{atan}{202}{11.42007} \pgfmath@def{atan}{203}{11.47511} +\pgfmath@def{atan}{204}{11.53013} \pgfmath@def{atan}{205}{11.58512} +\pgfmath@def{atan}{206}{11.64010} \pgfmath@def{atan}{207}{11.69505} +\pgfmath@def{atan}{208}{11.74998} \pgfmath@def{atan}{209}{11.80489} +\pgfmath@def{atan}{210}{11.85977} \pgfmath@def{atan}{211}{11.91464} +\pgfmath@def{atan}{212}{11.96948} \pgfmath@def{atan}{213}{12.02430} +\pgfmath@def{atan}{214}{12.07910} \pgfmath@def{atan}{215}{12.13388} +\pgfmath@def{atan}{216}{12.18863} \pgfmath@def{atan}{217}{12.24336} +\pgfmath@def{atan}{218}{12.29807} \pgfmath@def{atan}{219}{12.35275} +\pgfmath@def{atan}{220}{12.40741} \pgfmath@def{atan}{221}{12.46205} +\pgfmath@def{atan}{222}{12.51667} \pgfmath@def{atan}{223}{12.57126} +\pgfmath@def{atan}{224}{12.62583} \pgfmath@def{atan}{225}{12.68038} +\pgfmath@def{atan}{226}{12.73490} \pgfmath@def{atan}{227}{12.78940} +\pgfmath@def{atan}{228}{12.84388} \pgfmath@def{atan}{229}{12.89833} +\pgfmath@def{atan}{230}{12.95276} \pgfmath@def{atan}{231}{13.00717} +\pgfmath@def{atan}{232}{13.06155} \pgfmath@def{atan}{233}{13.11590} +\pgfmath@def{atan}{234}{13.17024} \pgfmath@def{atan}{235}{13.22455} +\pgfmath@def{atan}{236}{13.27883} \pgfmath@def{atan}{237}{13.33309} +\pgfmath@def{atan}{238}{13.38733} \pgfmath@def{atan}{239}{13.44154} +\pgfmath@def{atan}{240}{13.49573} \pgfmath@def{atan}{241}{13.54989} +\pgfmath@def{atan}{242}{13.60403} \pgfmath@def{atan}{243}{13.65814} +\pgfmath@def{atan}{244}{13.71223} \pgfmath@def{atan}{245}{13.76630} +\pgfmath@def{atan}{246}{13.82034} \pgfmath@def{atan}{247}{13.87435} +\pgfmath@def{atan}{248}{13.92834} \pgfmath@def{atan}{249}{13.98230} +\pgfmath@def{atan}{250}{14.03624} \pgfmath@def{atan}{251}{14.09015} +\pgfmath@def{atan}{252}{14.14404} \pgfmath@def{atan}{253}{14.19790} +\pgfmath@def{atan}{254}{14.25174} \pgfmath@def{atan}{255}{14.30555} +\pgfmath@def{atan}{256}{14.35933} \pgfmath@def{atan}{257}{14.41309} +\pgfmath@def{atan}{258}{14.46682} \pgfmath@def{atan}{259}{14.52053} +\pgfmath@def{atan}{260}{14.57421} \pgfmath@def{atan}{261}{14.62787} +\pgfmath@def{atan}{262}{14.68149} \pgfmath@def{atan}{263}{14.73510} +\pgfmath@def{atan}{264}{14.78867} \pgfmath@def{atan}{265}{14.84222} +\pgfmath@def{atan}{266}{14.89575} \pgfmath@def{atan}{267}{14.94924} +\pgfmath@def{atan}{268}{15.00271} \pgfmath@def{atan}{269}{15.05615} +\pgfmath@def{atan}{270}{15.10957} \pgfmath@def{atan}{271}{15.16296} +\pgfmath@def{atan}{272}{15.21632} \pgfmath@def{atan}{273}{15.26966} +\pgfmath@def{atan}{274}{15.32297} \pgfmath@def{atan}{275}{15.37625} +\pgfmath@def{atan}{276}{15.42950} \pgfmath@def{atan}{277}{15.48273} +\pgfmath@def{atan}{278}{15.53593} \pgfmath@def{atan}{279}{15.58910} +\pgfmath@def{atan}{280}{15.64224} \pgfmath@def{atan}{281}{15.69536} +\pgfmath@def{atan}{282}{15.74845} \pgfmath@def{atan}{283}{15.80151} +\pgfmath@def{atan}{284}{15.85454} \pgfmath@def{atan}{285}{15.90755} +\pgfmath@def{atan}{286}{15.96052} \pgfmath@def{atan}{287}{16.01347} +\pgfmath@def{atan}{288}{16.06640} \pgfmath@def{atan}{289}{16.11929} +\pgfmath@def{atan}{290}{16.17215} \pgfmath@def{atan}{291}{16.22499} +\pgfmath@def{atan}{292}{16.27780} \pgfmath@def{atan}{293}{16.33058} +\pgfmath@def{atan}{294}{16.38333} \pgfmath@def{atan}{295}{16.43605} +\pgfmath@def{atan}{296}{16.48875} \pgfmath@def{atan}{297}{16.54142} +\pgfmath@def{atan}{298}{16.59405} \pgfmath@def{atan}{299}{16.64666} +\pgfmath@def{atan}{300}{16.69924} \pgfmath@def{atan}{301}{16.75179} +\pgfmath@def{atan}{302}{16.80431} \pgfmath@def{atan}{303}{16.85680} +\pgfmath@def{atan}{304}{16.90927} \pgfmath@def{atan}{305}{16.96170} +\pgfmath@def{atan}{306}{17.01411} \pgfmath@def{atan}{307}{17.06648} +\pgfmath@def{atan}{308}{17.11883} \pgfmath@def{atan}{309}{17.17114} +\pgfmath@def{atan}{310}{17.22343} \pgfmath@def{atan}{311}{17.27569} +\pgfmath@def{atan}{312}{17.32792} \pgfmath@def{atan}{313}{17.38012} +\pgfmath@def{atan}{314}{17.43228} \pgfmath@def{atan}{315}{17.48442} +\pgfmath@def{atan}{316}{17.53653} \pgfmath@def{atan}{317}{17.58861} +\pgfmath@def{atan}{318}{17.64066} \pgfmath@def{atan}{319}{17.69268} +\pgfmath@def{atan}{320}{17.74467} \pgfmath@def{atan}{321}{17.79663} +\pgfmath@def{atan}{322}{17.84855} \pgfmath@def{atan}{323}{17.90045} +\pgfmath@def{atan}{324}{17.95232} \pgfmath@def{atan}{325}{18.00416} +\pgfmath@def{atan}{326}{18.05596} \pgfmath@def{atan}{327}{18.10774} +\pgfmath@def{atan}{328}{18.15949} \pgfmath@def{atan}{329}{18.21120} +\pgfmath@def{atan}{330}{18.26289} \pgfmath@def{atan}{331}{18.31454} +\pgfmath@def{atan}{332}{18.36616} \pgfmath@def{atan}{333}{18.41775} +\pgfmath@def{atan}{334}{18.46931} \pgfmath@def{atan}{335}{18.52084} +\pgfmath@def{atan}{336}{18.57234} \pgfmath@def{atan}{337}{18.62381} +\pgfmath@def{atan}{338}{18.67525} \pgfmath@def{atan}{339}{18.72665} +\pgfmath@def{atan}{340}{18.77803} \pgfmath@def{atan}{341}{18.82937} +\pgfmath@def{atan}{342}{18.88068} \pgfmath@def{atan}{343}{18.93196} +\pgfmath@def{atan}{344}{18.98321} \pgfmath@def{atan}{345}{19.03443} +\pgfmath@def{atan}{346}{19.08562} \pgfmath@def{atan}{347}{19.13677} +\pgfmath@def{atan}{348}{19.18789} \pgfmath@def{atan}{349}{19.23898} +\pgfmath@def{atan}{350}{19.29004} \pgfmath@def{atan}{351}{19.34107} +\pgfmath@def{atan}{352}{19.39206} \pgfmath@def{atan}{353}{19.44303} +\pgfmath@def{atan}{354}{19.49396} \pgfmath@def{atan}{355}{19.54486} +\pgfmath@def{atan}{356}{19.59572} \pgfmath@def{atan}{357}{19.64656} +\pgfmath@def{atan}{358}{19.69736} \pgfmath@def{atan}{359}{19.74813} +\pgfmath@def{atan}{360}{19.79887} \pgfmath@def{atan}{361}{19.84958} +\pgfmath@def{atan}{362}{19.90025} \pgfmath@def{atan}{363}{19.95089} +\pgfmath@def{atan}{364}{20.00150} \pgfmath@def{atan}{365}{20.05208} +\pgfmath@def{atan}{366}{20.10262} \pgfmath@def{atan}{367}{20.15313} +\pgfmath@def{atan}{368}{20.20361} \pgfmath@def{atan}{369}{20.25406} +\pgfmath@def{atan}{370}{20.30447} \pgfmath@def{atan}{371}{20.35485} +\pgfmath@def{atan}{372}{20.40520} \pgfmath@def{atan}{373}{20.45551} +\pgfmath@def{atan}{374}{20.50579} \pgfmath@def{atan}{375}{20.55604} +\pgfmath@def{atan}{376}{20.60626} \pgfmath@def{atan}{377}{20.65644} +\pgfmath@def{atan}{378}{20.70659} \pgfmath@def{atan}{379}{20.75670} +\pgfmath@def{atan}{380}{20.80679} \pgfmath@def{atan}{381}{20.85684} +\pgfmath@def{atan}{382}{20.90685} \pgfmath@def{atan}{383}{20.95684} +\pgfmath@def{atan}{384}{21.00678} \pgfmath@def{atan}{385}{21.05670} +\pgfmath@def{atan}{386}{21.10658} \pgfmath@def{atan}{387}{21.15643} +\pgfmath@def{atan}{388}{21.20625} \pgfmath@def{atan}{389}{21.25603} +\pgfmath@def{atan}{390}{21.30578} \pgfmath@def{atan}{391}{21.35549} +\pgfmath@def{atan}{392}{21.40517} \pgfmath@def{atan}{393}{21.45482} +\pgfmath@def{atan}{394}{21.50444} \pgfmath@def{atan}{395}{21.55402} +\pgfmath@def{atan}{396}{21.60356} \pgfmath@def{atan}{397}{21.65307} +\pgfmath@def{atan}{398}{21.70255} \pgfmath@def{atan}{399}{21.75200} +\pgfmath@def{atan}{400}{21.80140} \pgfmath@def{atan}{401}{21.85078} +\pgfmath@def{atan}{402}{21.90012} \pgfmath@def{atan}{403}{21.94943} +\pgfmath@def{atan}{404}{21.99870} \pgfmath@def{atan}{405}{22.04794} +\pgfmath@def{atan}{406}{22.09715} \pgfmath@def{atan}{407}{22.14632} +\pgfmath@def{atan}{408}{22.19546} \pgfmath@def{atan}{409}{22.24456} +\pgfmath@def{atan}{410}{22.29362} \pgfmath@def{atan}{411}{22.34266} +\pgfmath@def{atan}{412}{22.39166} \pgfmath@def{atan}{413}{22.44062} +\pgfmath@def{atan}{414}{22.48955} \pgfmath@def{atan}{415}{22.53845} +\pgfmath@def{atan}{416}{22.58731} \pgfmath@def{atan}{417}{22.63613} +\pgfmath@def{atan}{418}{22.68492} \pgfmath@def{atan}{419}{22.73368} +\pgfmath@def{atan}{420}{22.78240} \pgfmath@def{atan}{421}{22.83109} +\pgfmath@def{atan}{422}{22.87974} \pgfmath@def{atan}{423}{22.92836} +\pgfmath@def{atan}{424}{22.97694} \pgfmath@def{atan}{425}{23.02549} +\pgfmath@def{atan}{426}{23.07400} \pgfmath@def{atan}{427}{23.12248} +\pgfmath@def{atan}{428}{23.17092} \pgfmath@def{atan}{429}{23.21933} +\pgfmath@def{atan}{430}{23.26770} \pgfmath@def{atan}{431}{23.31604} +\pgfmath@def{atan}{432}{23.36434} \pgfmath@def{atan}{433}{23.41261} +\pgfmath@def{atan}{434}{23.46084} \pgfmath@def{atan}{435}{23.50904} +\pgfmath@def{atan}{436}{23.55720} \pgfmath@def{atan}{437}{23.60532} +\pgfmath@def{atan}{438}{23.65341} \pgfmath@def{atan}{439}{23.70147} +\pgfmath@def{atan}{440}{23.74949} \pgfmath@def{atan}{441}{23.79747} +\pgfmath@def{atan}{442}{23.84542} \pgfmath@def{atan}{443}{23.89334} +\pgfmath@def{atan}{444}{23.94122} \pgfmath@def{atan}{445}{23.98906} +\pgfmath@def{atan}{446}{24.03687} \pgfmath@def{atan}{447}{24.08464} +\pgfmath@def{atan}{448}{24.13238} \pgfmath@def{atan}{449}{24.18008} +\pgfmath@def{atan}{450}{24.22774} \pgfmath@def{atan}{451}{24.27537} +\pgfmath@def{atan}{452}{24.32296} \pgfmath@def{atan}{453}{24.37052} +\pgfmath@def{atan}{454}{24.41804} \pgfmath@def{atan}{455}{24.46553} +\pgfmath@def{atan}{456}{24.51298} \pgfmath@def{atan}{457}{24.56040} +\pgfmath@def{atan}{458}{24.60778} \pgfmath@def{atan}{459}{24.65512} +\pgfmath@def{atan}{460}{24.70243} \pgfmath@def{atan}{461}{24.74970} +\pgfmath@def{atan}{462}{24.79693} \pgfmath@def{atan}{463}{24.84413} +\pgfmath@def{atan}{464}{24.89130} \pgfmath@def{atan}{465}{24.93842} +\pgfmath@def{atan}{466}{24.98551} \pgfmath@def{atan}{467}{25.03257} +\pgfmath@def{atan}{468}{25.07959} \pgfmath@def{atan}{469}{25.12657} +\pgfmath@def{atan}{470}{25.17352} \pgfmath@def{atan}{471}{25.22043} +\pgfmath@def{atan}{472}{25.26731} \pgfmath@def{atan}{473}{25.31414} +\pgfmath@def{atan}{474}{25.36095} \pgfmath@def{atan}{475}{25.40771} +\pgfmath@def{atan}{476}{25.45444} \pgfmath@def{atan}{477}{25.50114} +\pgfmath@def{atan}{478}{25.54780} \pgfmath@def{atan}{479}{25.59442} +\pgfmath@def{atan}{480}{25.64100} \pgfmath@def{atan}{481}{25.68755} +\pgfmath@def{atan}{482}{25.73406} \pgfmath@def{atan}{483}{25.78054} +\pgfmath@def{atan}{484}{25.82698} \pgfmath@def{atan}{485}{25.87338} +\pgfmath@def{atan}{486}{25.91975} \pgfmath@def{atan}{487}{25.96608} +\pgfmath@def{atan}{488}{26.01237} \pgfmath@def{atan}{489}{26.05863} +\pgfmath@def{atan}{490}{26.10485} \pgfmath@def{atan}{491}{26.15103} +\pgfmath@def{atan}{492}{26.19718} \pgfmath@def{atan}{493}{26.24329} +\pgfmath@def{atan}{494}{26.28937} \pgfmath@def{atan}{495}{26.33541} +\pgfmath@def{atan}{496}{26.38141} \pgfmath@def{atan}{497}{26.42737} +\pgfmath@def{atan}{498}{26.47330} \pgfmath@def{atan}{499}{26.51919} +\pgfmath@def{atan}{500}{26.56505} \pgfmath@def{atan}{501}{26.61086} +\pgfmath@def{atan}{502}{26.65665} \pgfmath@def{atan}{503}{26.70239} +\pgfmath@def{atan}{504}{26.74810} \pgfmath@def{atan}{505}{26.79377} +\pgfmath@def{atan}{506}{26.83941} \pgfmath@def{atan}{507}{26.88500} +\pgfmath@def{atan}{508}{26.93057} \pgfmath@def{atan}{509}{26.97609} +\pgfmath@def{atan}{510}{27.02158} \pgfmath@def{atan}{511}{27.06703} +\pgfmath@def{atan}{512}{27.11244} \pgfmath@def{atan}{513}{27.15782} +\pgfmath@def{atan}{514}{27.20316} \pgfmath@def{atan}{515}{27.24846} +\pgfmath@def{atan}{516}{27.29373} \pgfmath@def{atan}{517}{27.33896} +\pgfmath@def{atan}{518}{27.38415} \pgfmath@def{atan}{519}{27.42931} +\pgfmath@def{atan}{520}{27.47443} \pgfmath@def{atan}{521}{27.51951} +\pgfmath@def{atan}{522}{27.56455} \pgfmath@def{atan}{523}{27.60956} +\pgfmath@def{atan}{524}{27.65453} \pgfmath@def{atan}{525}{27.69947} +\pgfmath@def{atan}{526}{27.74437} \pgfmath@def{atan}{527}{27.78923} +\pgfmath@def{atan}{528}{27.83405} \pgfmath@def{atan}{529}{27.87884} +\pgfmath@def{atan}{530}{27.92359} \pgfmath@def{atan}{531}{27.96830} +\pgfmath@def{atan}{532}{28.01297} \pgfmath@def{atan}{533}{28.05761} +\pgfmath@def{atan}{534}{28.10221} \pgfmath@def{atan}{535}{28.14678} +\pgfmath@def{atan}{536}{28.19130} \pgfmath@def{atan}{537}{28.23579} +\pgfmath@def{atan}{538}{28.28025} \pgfmath@def{atan}{539}{28.32466} +\pgfmath@def{atan}{540}{28.36904} \pgfmath@def{atan}{541}{28.41338} +\pgfmath@def{atan}{542}{28.45769} \pgfmath@def{atan}{543}{28.50196} +\pgfmath@def{atan}{544}{28.54619} \pgfmath@def{atan}{545}{28.59038} +\pgfmath@def{atan}{546}{28.63454} \pgfmath@def{atan}{547}{28.67865} +\pgfmath@def{atan}{548}{28.72274} \pgfmath@def{atan}{549}{28.76678} +\pgfmath@def{atan}{550}{28.81079} \pgfmath@def{atan}{551}{28.85476} +\pgfmath@def{atan}{552}{28.89869} \pgfmath@def{atan}{553}{28.94259} +\pgfmath@def{atan}{554}{28.98645} \pgfmath@def{atan}{555}{29.03027} +\pgfmath@def{atan}{556}{29.07405} \pgfmath@def{atan}{557}{29.11780} +\pgfmath@def{atan}{558}{29.16151} \pgfmath@def{atan}{559}{29.20519} +\pgfmath@def{atan}{560}{29.24882} \pgfmath@def{atan}{561}{29.29242} +\pgfmath@def{atan}{562}{29.33598} \pgfmath@def{atan}{563}{29.37951} +\pgfmath@def{atan}{564}{29.42299} \pgfmath@def{atan}{565}{29.46644} +\pgfmath@def{atan}{566}{29.50986} \pgfmath@def{atan}{567}{29.55323} +\pgfmath@def{atan}{568}{29.59657} \pgfmath@def{atan}{569}{29.63987} +\pgfmath@def{atan}{570}{29.68314} \pgfmath@def{atan}{571}{29.72636} +\pgfmath@def{atan}{572}{29.76955} \pgfmath@def{atan}{573}{29.81270} +\pgfmath@def{atan}{574}{29.85582} \pgfmath@def{atan}{575}{29.89890} +\pgfmath@def{atan}{576}{29.94194} \pgfmath@def{atan}{577}{29.98494} +\pgfmath@def{atan}{578}{30.02791} \pgfmath@def{atan}{579}{30.07084} +\pgfmath@def{atan}{580}{30.11373} \pgfmath@def{atan}{581}{30.15658} +\pgfmath@def{atan}{582}{30.19940} \pgfmath@def{atan}{583}{30.24218} +\pgfmath@def{atan}{584}{30.28492} \pgfmath@def{atan}{585}{30.32763} +\pgfmath@def{atan}{586}{30.37030} \pgfmath@def{atan}{587}{30.41293} +\pgfmath@def{atan}{588}{30.45552} \pgfmath@def{atan}{589}{30.49808} +\pgfmath@def{atan}{590}{30.54060} \pgfmath@def{atan}{591}{30.58308} +\pgfmath@def{atan}{592}{30.62553} \pgfmath@def{atan}{593}{30.66794} +\pgfmath@def{atan}{594}{30.71031} \pgfmath@def{atan}{595}{30.75264} +\pgfmath@def{atan}{596}{30.79494} \pgfmath@def{atan}{597}{30.83720} +\pgfmath@def{atan}{598}{30.87942} \pgfmath@def{atan}{599}{30.92160} +\pgfmath@def{atan}{600}{30.96375} \pgfmath@def{atan}{601}{31.00586} +\pgfmath@def{atan}{602}{31.04794} \pgfmath@def{atan}{603}{31.08997} +\pgfmath@def{atan}{604}{31.13197} \pgfmath@def{atan}{605}{31.17393} +\pgfmath@def{atan}{606}{31.21586} \pgfmath@def{atan}{607}{31.25775} +\pgfmath@def{atan}{608}{31.29960} \pgfmath@def{atan}{609}{31.34141} +\pgfmath@def{atan}{610}{31.38319} \pgfmath@def{atan}{611}{31.42493} +\pgfmath@def{atan}{612}{31.46663} \pgfmath@def{atan}{613}{31.50829} +\pgfmath@def{atan}{614}{31.54992} \pgfmath@def{atan}{615}{31.59151} +\pgfmath@def{atan}{616}{31.63306} \pgfmath@def{atan}{617}{31.67458} +\pgfmath@def{atan}{618}{31.71606} \pgfmath@def{atan}{619}{31.75750} +\pgfmath@def{atan}{620}{31.79891} \pgfmath@def{atan}{621}{31.84028} +\pgfmath@def{atan}{622}{31.88161} \pgfmath@def{atan}{623}{31.92290} +\pgfmath@def{atan}{624}{31.96416} \pgfmath@def{atan}{625}{32.00538} +\pgfmath@def{atan}{626}{32.04656} \pgfmath@def{atan}{627}{32.08771} +\pgfmath@def{atan}{628}{32.12882} \pgfmath@def{atan}{629}{32.16989} +\pgfmath@def{atan}{630}{32.21092} \pgfmath@def{atan}{631}{32.25192} +\pgfmath@def{atan}{632}{32.29288} \pgfmath@def{atan}{633}{32.33381} +\pgfmath@def{atan}{634}{32.37469} \pgfmath@def{atan}{635}{32.41554} +\pgfmath@def{atan}{636}{32.45636} \pgfmath@def{atan}{637}{32.49713} +\pgfmath@def{atan}{638}{32.53787} \pgfmath@def{atan}{639}{32.57857} +\pgfmath@def{atan}{640}{32.61924} \pgfmath@def{atan}{641}{32.65987} +\pgfmath@def{atan}{642}{32.70046} \pgfmath@def{atan}{643}{32.74101} +\pgfmath@def{atan}{644}{32.78153} \pgfmath@def{atan}{645}{32.82201} +\pgfmath@def{atan}{646}{32.86246} \pgfmath@def{atan}{647}{32.90286} +\pgfmath@def{atan}{648}{32.94323} \pgfmath@def{atan}{649}{32.98357} +\pgfmath@def{atan}{650}{33.02386} \pgfmath@def{atan}{651}{33.06412} +\pgfmath@def{atan}{652}{33.10435} \pgfmath@def{atan}{653}{33.14453} +\pgfmath@def{atan}{654}{33.18468} \pgfmath@def{atan}{655}{33.22479} +\pgfmath@def{atan}{656}{33.26487} \pgfmath@def{atan}{657}{33.30491} +\pgfmath@def{atan}{658}{33.34491} \pgfmath@def{atan}{659}{33.38488} +\pgfmath@def{atan}{660}{33.42481} \pgfmath@def{atan}{661}{33.46470} +\pgfmath@def{atan}{662}{33.50455} \pgfmath@def{atan}{663}{33.54437} +\pgfmath@def{atan}{664}{33.58416} \pgfmath@def{atan}{665}{33.62390} +\pgfmath@def{atan}{666}{33.66361} \pgfmath@def{atan}{667}{33.70328} +\pgfmath@def{atan}{668}{33.74292} \pgfmath@def{atan}{669}{33.78252} +\pgfmath@def{atan}{670}{33.82208} \pgfmath@def{atan}{671}{33.86161} +\pgfmath@def{atan}{672}{33.90110} \pgfmath@def{atan}{673}{33.94055} +\pgfmath@def{atan}{674}{33.97997} \pgfmath@def{atan}{675}{34.01935} +\pgfmath@def{atan}{676}{34.05869} \pgfmath@def{atan}{677}{34.09800} +\pgfmath@def{atan}{678}{34.13727} \pgfmath@def{atan}{679}{34.17650} +\pgfmath@def{atan}{680}{34.21570} \pgfmath@def{atan}{681}{34.25486} +\pgfmath@def{atan}{682}{34.29398} \pgfmath@def{atan}{683}{34.33307} +\pgfmath@def{atan}{684}{34.37212} \pgfmath@def{atan}{685}{34.41114} +\pgfmath@def{atan}{686}{34.45012} \pgfmath@def{atan}{687}{34.48906} +\pgfmath@def{atan}{688}{34.52797} \pgfmath@def{atan}{689}{34.56684} +\pgfmath@def{atan}{690}{34.60567} \pgfmath@def{atan}{691}{34.64447} +\pgfmath@def{atan}{692}{34.68323} \pgfmath@def{atan}{693}{34.72195} +\pgfmath@def{atan}{694}{34.76064} \pgfmath@def{atan}{695}{34.79930} +\pgfmath@def{atan}{696}{34.83791} \pgfmath@def{atan}{697}{34.87649} +\pgfmath@def{atan}{698}{34.91504} \pgfmath@def{atan}{699}{34.95354} +\pgfmath@def{atan}{700}{34.99202} \pgfmath@def{atan}{701}{35.03045} +\pgfmath@def{atan}{702}{35.06885} \pgfmath@def{atan}{703}{35.10721} +\pgfmath@def{atan}{704}{35.14554} \pgfmath@def{atan}{705}{35.18383} +\pgfmath@def{atan}{706}{35.22209} \pgfmath@def{atan}{707}{35.26031} +\pgfmath@def{atan}{708}{35.29849} \pgfmath@def{atan}{709}{35.33664} +\pgfmath@def{atan}{710}{35.37475} \pgfmath@def{atan}{711}{35.41282} +\pgfmath@def{atan}{712}{35.45086} \pgfmath@def{atan}{713}{35.48886} +\pgfmath@def{atan}{714}{35.52683} \pgfmath@def{atan}{715}{35.56476} +\pgfmath@def{atan}{716}{35.60266} \pgfmath@def{atan}{717}{35.64052} +\pgfmath@def{atan}{718}{35.67834} \pgfmath@def{atan}{719}{35.71613} +\pgfmath@def{atan}{720}{35.75388} \pgfmath@def{atan}{721}{35.79160} +\pgfmath@def{atan}{722}{35.82928} \pgfmath@def{atan}{723}{35.86692} +\pgfmath@def{atan}{724}{35.90453} \pgfmath@def{atan}{725}{35.94211} +\pgfmath@def{atan}{726}{35.97965} \pgfmath@def{atan}{727}{36.01715} +\pgfmath@def{atan}{728}{36.05461} \pgfmath@def{atan}{729}{36.09204} +\pgfmath@def{atan}{730}{36.12944} \pgfmath@def{atan}{731}{36.16680} +\pgfmath@def{atan}{732}{36.20412} \pgfmath@def{atan}{733}{36.24141} +\pgfmath@def{atan}{734}{36.27866} \pgfmath@def{atan}{735}{36.31588} +\pgfmath@def{atan}{736}{36.35306} \pgfmath@def{atan}{737}{36.39021} +\pgfmath@def{atan}{738}{36.42732} \pgfmath@def{atan}{739}{36.46440} +\pgfmath@def{atan}{740}{36.50144} \pgfmath@def{atan}{741}{36.53844} +\pgfmath@def{atan}{742}{36.57541} \pgfmath@def{atan}{743}{36.61234} +\pgfmath@def{atan}{744}{36.64924} \pgfmath@def{atan}{745}{36.68611} +\pgfmath@def{atan}{746}{36.72293} \pgfmath@def{atan}{747}{36.75973} +\pgfmath@def{atan}{748}{36.79648} \pgfmath@def{atan}{749}{36.83321} +\pgfmath@def{atan}{750}{36.86989} \pgfmath@def{atan}{751}{36.90654} +\pgfmath@def{atan}{752}{36.94316} \pgfmath@def{atan}{753}{36.97974} +\pgfmath@def{atan}{754}{37.01629} \pgfmath@def{atan}{755}{37.05280} +\pgfmath@def{atan}{756}{37.08928} \pgfmath@def{atan}{757}{37.12572} +\pgfmath@def{atan}{758}{37.16212} \pgfmath@def{atan}{759}{37.19849} +\pgfmath@def{atan}{760}{37.23483} \pgfmath@def{atan}{761}{37.27113} +\pgfmath@def{atan}{762}{37.30740} \pgfmath@def{atan}{763}{37.34363} +\pgfmath@def{atan}{764}{37.37982} \pgfmath@def{atan}{765}{37.41598} +\pgfmath@def{atan}{766}{37.45211} \pgfmath@def{atan}{767}{37.48820} +\pgfmath@def{atan}{768}{37.52426} \pgfmath@def{atan}{769}{37.56028} +\pgfmath@def{atan}{770}{37.59627} \pgfmath@def{atan}{771}{37.63222} +\pgfmath@def{atan}{772}{37.66814} \pgfmath@def{atan}{773}{37.70402} +\pgfmath@def{atan}{774}{37.73987} \pgfmath@def{atan}{775}{37.77568} +\pgfmath@def{atan}{776}{37.81146} \pgfmath@def{atan}{777}{37.84720} +\pgfmath@def{atan}{778}{37.88291} \pgfmath@def{atan}{779}{37.91859} +\pgfmath@def{atan}{780}{37.95423} \pgfmath@def{atan}{781}{37.98983} +\pgfmath@def{atan}{782}{38.02540} \pgfmath@def{atan}{783}{38.06094} +\pgfmath@def{atan}{784}{38.09644} \pgfmath@def{atan}{785}{38.13191} +\pgfmath@def{atan}{786}{38.16734} \pgfmath@def{atan}{787}{38.20274} +\pgfmath@def{atan}{788}{38.23811} \pgfmath@def{atan}{789}{38.27344} +\pgfmath@def{atan}{790}{38.30873} \pgfmath@def{atan}{791}{38.34399} +\pgfmath@def{atan}{792}{38.37922} \pgfmath@def{atan}{793}{38.41441} +\pgfmath@def{atan}{794}{38.44957} \pgfmath@def{atan}{795}{38.48469} +\pgfmath@def{atan}{796}{38.51979} \pgfmath@def{atan}{797}{38.55484} +\pgfmath@def{atan}{798}{38.58986} \pgfmath@def{atan}{799}{38.62485} +\pgfmath@def{atan}{800}{38.65980} \pgfmath@def{atan}{801}{38.69472} +\pgfmath@def{atan}{802}{38.72961} \pgfmath@def{atan}{803}{38.76446} +\pgfmath@def{atan}{804}{38.79928} \pgfmath@def{atan}{805}{38.83406} +\pgfmath@def{atan}{806}{38.86881} \pgfmath@def{atan}{807}{38.90353} +\pgfmath@def{atan}{808}{38.93821} \pgfmath@def{atan}{809}{38.97285} +\pgfmath@def{atan}{810}{39.00747} \pgfmath@def{atan}{811}{39.04205} +\pgfmath@def{atan}{812}{39.07659} \pgfmath@def{atan}{813}{39.11111} +\pgfmath@def{atan}{814}{39.14558} \pgfmath@def{atan}{815}{39.18003} +\pgfmath@def{atan}{816}{39.21444} \pgfmath@def{atan}{817}{39.24882} +\pgfmath@def{atan}{818}{39.28316} \pgfmath@def{atan}{819}{39.31747} +\pgfmath@def{atan}{820}{39.35175} \pgfmath@def{atan}{821}{39.38599} +\pgfmath@def{atan}{822}{39.42020} \pgfmath@def{atan}{823}{39.45438} +\pgfmath@def{atan}{824}{39.48852} \pgfmath@def{atan}{825}{39.52263} +\pgfmath@def{atan}{826}{39.55670} \pgfmath@def{atan}{827}{39.59074} +\pgfmath@def{atan}{828}{39.62475} \pgfmath@def{atan}{829}{39.65873} +\pgfmath@def{atan}{830}{39.69267} \pgfmath@def{atan}{831}{39.72658} +\pgfmath@def{atan}{832}{39.76045} \pgfmath@def{atan}{833}{39.79429} +\pgfmath@def{atan}{834}{39.82810} \pgfmath@def{atan}{835}{39.86188} +\pgfmath@def{atan}{836}{39.89562} \pgfmath@def{atan}{837}{39.92933} +\pgfmath@def{atan}{838}{39.96300} \pgfmath@def{atan}{839}{39.99665} +\pgfmath@def{atan}{840}{40.03025} \pgfmath@def{atan}{841}{40.06383} +\pgfmath@def{atan}{842}{40.09737} \pgfmath@def{atan}{843}{40.13088} +\pgfmath@def{atan}{844}{40.16436} \pgfmath@def{atan}{845}{40.19781} +\pgfmath@def{atan}{846}{40.23122} \pgfmath@def{atan}{847}{40.26459} +\pgfmath@def{atan}{848}{40.29794} \pgfmath@def{atan}{849}{40.33125} +\pgfmath@def{atan}{850}{40.36453} \pgfmath@def{atan}{851}{40.39778} +\pgfmath@def{atan}{852}{40.43099} \pgfmath@def{atan}{853}{40.46417} +\pgfmath@def{atan}{854}{40.49732} \pgfmath@def{atan}{855}{40.53044} +\pgfmath@def{atan}{856}{40.56352} \pgfmath@def{atan}{857}{40.59657} +\pgfmath@def{atan}{858}{40.62959} \pgfmath@def{atan}{859}{40.66257} +\pgfmath@def{atan}{860}{40.69553} \pgfmath@def{atan}{861}{40.72845} +\pgfmath@def{atan}{862}{40.76133} \pgfmath@def{atan}{863}{40.79419} +\pgfmath@def{atan}{864}{40.82701} \pgfmath@def{atan}{865}{40.85980} +\pgfmath@def{atan}{866}{40.89256} \pgfmath@def{atan}{867}{40.92528} +\pgfmath@def{atan}{868}{40.95798} \pgfmath@def{atan}{869}{40.99064} +\pgfmath@def{atan}{870}{41.02326} \pgfmath@def{atan}{871}{41.05586} +\pgfmath@def{atan}{872}{41.08842} \pgfmath@def{atan}{873}{41.12095} +\pgfmath@def{atan}{874}{41.15345} \pgfmath@def{atan}{875}{41.18592} +\pgfmath@def{atan}{876}{41.21836} \pgfmath@def{atan}{877}{41.25076} +\pgfmath@def{atan}{878}{41.28313} \pgfmath@def{atan}{879}{41.31547} +\pgfmath@def{atan}{880}{41.34777} \pgfmath@def{atan}{881}{41.38005} +\pgfmath@def{atan}{882}{41.41229} \pgfmath@def{atan}{883}{41.44450} +\pgfmath@def{atan}{884}{41.47668} \pgfmath@def{atan}{885}{41.50882} +\pgfmath@def{atan}{886}{41.54094} \pgfmath@def{atan}{887}{41.57302} +\pgfmath@def{atan}{888}{41.60507} \pgfmath@def{atan}{889}{41.63709} +\pgfmath@def{atan}{890}{41.66908} \pgfmath@def{atan}{891}{41.70103} +\pgfmath@def{atan}{892}{41.73296} \pgfmath@def{atan}{893}{41.76485} +\pgfmath@def{atan}{894}{41.79671} \pgfmath@def{atan}{895}{41.82854} +\pgfmath@def{atan}{896}{41.86034} \pgfmath@def{atan}{897}{41.89210} +\pgfmath@def{atan}{898}{41.92383} \pgfmath@def{atan}{899}{41.95554} +\pgfmath@def{atan}{900}{41.98721} \pgfmath@def{atan}{901}{42.01885} +\pgfmath@def{atan}{902}{42.05046} \pgfmath@def{atan}{903}{42.08203} +\pgfmath@def{atan}{904}{42.11358} \pgfmath@def{atan}{905}{42.14509} +\pgfmath@def{atan}{906}{42.17657} \pgfmath@def{atan}{907}{42.20802} +\pgfmath@def{atan}{908}{42.23944} \pgfmath@def{atan}{909}{42.27083} +\pgfmath@def{atan}{910}{42.30219} \pgfmath@def{atan}{911}{42.33352} +\pgfmath@def{atan}{912}{42.36481} \pgfmath@def{atan}{913}{42.39607} +\pgfmath@def{atan}{914}{42.42731} \pgfmath@def{atan}{915}{42.45851} +\pgfmath@def{atan}{916}{42.48968} \pgfmath@def{atan}{917}{42.52082} +\pgfmath@def{atan}{918}{42.55193} \pgfmath@def{atan}{919}{42.58300} +\pgfmath@def{atan}{920}{42.61405} \pgfmath@def{atan}{921}{42.64507} +\pgfmath@def{atan}{922}{42.67605} \pgfmath@def{atan}{923}{42.70701} +\pgfmath@def{atan}{924}{42.73793} \pgfmath@def{atan}{925}{42.76882} +\pgfmath@def{atan}{926}{42.79968} \pgfmath@def{atan}{927}{42.83051} +\pgfmath@def{atan}{928}{42.86131} \pgfmath@def{atan}{929}{42.89208} +\pgfmath@def{atan}{930}{42.92282} \pgfmath@def{atan}{931}{42.95353} +\pgfmath@def{atan}{932}{42.98421} \pgfmath@def{atan}{933}{43.01485} +\pgfmath@def{atan}{934}{43.04547} \pgfmath@def{atan}{935}{43.07605} +\pgfmath@def{atan}{936}{43.10661} \pgfmath@def{atan}{937}{43.13713} +\pgfmath@def{atan}{938}{43.16763} \pgfmath@def{atan}{939}{43.19809} +\pgfmath@def{atan}{940}{43.22853} \pgfmath@def{atan}{941}{43.25893} +\pgfmath@def{atan}{942}{43.28930} \pgfmath@def{atan}{943}{43.31964} +\pgfmath@def{atan}{944}{43.34996} \pgfmath@def{atan}{945}{43.38024} +\pgfmath@def{atan}{946}{43.41049} \pgfmath@def{atan}{947}{43.44071} +\pgfmath@def{atan}{948}{43.47090} \pgfmath@def{atan}{949}{43.50106} +\pgfmath@def{atan}{950}{43.53119} \pgfmath@def{atan}{951}{43.56130} +\pgfmath@def{atan}{952}{43.59137} \pgfmath@def{atan}{953}{43.62141} +\pgfmath@def{atan}{954}{43.65142} \pgfmath@def{atan}{955}{43.68140} +\pgfmath@def{atan}{956}{43.71135} \pgfmath@def{atan}{957}{43.74127} +\pgfmath@def{atan}{958}{43.77116} \pgfmath@def{atan}{959}{43.80102} +\pgfmath@def{atan}{960}{43.83086} \pgfmath@def{atan}{961}{43.86066} +\pgfmath@def{atan}{962}{43.89043} \pgfmath@def{atan}{963}{43.92017} +\pgfmath@def{atan}{964}{43.94988} \pgfmath@def{atan}{965}{43.97957} +\pgfmath@def{atan}{966}{44.00922} \pgfmath@def{atan}{967}{44.03884} +\pgfmath@def{atan}{968}{44.06844} \pgfmath@def{atan}{969}{44.09800} +\pgfmath@def{atan}{970}{44.12754} \pgfmath@def{atan}{971}{44.15704} +\pgfmath@def{atan}{972}{44.18652} \pgfmath@def{atan}{973}{44.21597} +\pgfmath@def{atan}{974}{44.24538} \pgfmath@def{atan}{975}{44.27477} +\pgfmath@def{atan}{976}{44.30413} \pgfmath@def{atan}{977}{44.33346} +\pgfmath@def{atan}{978}{44.36276} \pgfmath@def{atan}{979}{44.39203} +\pgfmath@def{atan}{980}{44.42127} \pgfmath@def{atan}{981}{44.45048} +\pgfmath@def{atan}{982}{44.47966} \pgfmath@def{atan}{983}{44.50882} +\pgfmath@def{atan}{984}{44.53794} \pgfmath@def{atan}{985}{44.56704} +\pgfmath@def{atan}{986}{44.59610} \pgfmath@def{atan}{987}{44.62514} +\pgfmath@def{atan}{988}{44.65415} \pgfmath@def{atan}{989}{44.68313} +\pgfmath@def{atan}{990}{44.71208} \pgfmath@def{atan}{991}{44.74100} +\pgfmath@def{atan}{992}{44.76989} \pgfmath@def{atan}{993}{44.79876} +\pgfmath@def{atan}{994}{44.82759} \pgfmath@def{atan}{995}{44.85640} +\pgfmath@def{atan}{996}{44.88517} \pgfmath@def{atan}{997}{44.91392} +\pgfmath@def{atan}{998}{44.94264} \pgfmath@def{atan}{999}{44.97133} +\pgfmath@def{atan}{1000}{45.00000} + +\pgfmath@def{acos}{0}{90.00000} \pgfmath@def{acos}{1}{89.94270} +\pgfmath@def{acos}{2}{89.88540} \pgfmath@def{acos}{3}{89.82811} +\pgfmath@def{acos}{4}{89.77081} \pgfmath@def{acos}{5}{89.71352} +\pgfmath@def{acos}{6}{89.65622} \pgfmath@def{acos}{7}{89.59892} +\pgfmath@def{acos}{8}{89.54162} \pgfmath@def{acos}{9}{89.48433} +\pgfmath@def{acos}{10}{89.42703} \pgfmath@def{acos}{11}{89.36973} +\pgfmath@def{acos}{12}{89.31243} \pgfmath@def{acos}{13}{89.25513} +\pgfmath@def{acos}{14}{89.19783} \pgfmath@def{acos}{15}{89.14053} +\pgfmath@def{acos}{16}{89.08322} \pgfmath@def{acos}{17}{89.02592} +\pgfmath@def{acos}{18}{88.96862} \pgfmath@def{acos}{19}{88.91131} +\pgfmath@def{acos}{20}{88.85400} \pgfmath@def{acos}{21}{88.79670} +\pgfmath@def{acos}{22}{88.73939} \pgfmath@def{acos}{23}{88.68208} +\pgfmath@def{acos}{24}{88.62476} \pgfmath@def{acos}{25}{88.56745} +\pgfmath@def{acos}{26}{88.51014} \pgfmath@def{acos}{27}{88.45282} +\pgfmath@def{acos}{28}{88.39550} \pgfmath@def{acos}{29}{88.33818} +\pgfmath@def{acos}{30}{88.28086} \pgfmath@def{acos}{31}{88.22354} +\pgfmath@def{acos}{32}{88.16622} \pgfmath@def{acos}{33}{88.10889} +\pgfmath@def{acos}{34}{88.05156} \pgfmath@def{acos}{35}{87.99423} +\pgfmath@def{acos}{36}{87.93690} \pgfmath@def{acos}{37}{87.87957} +\pgfmath@def{acos}{38}{87.82223} \pgfmath@def{acos}{39}{87.76489} +\pgfmath@def{acos}{40}{87.70755} \pgfmath@def{acos}{41}{87.65021} +\pgfmath@def{acos}{42}{87.59286} \pgfmath@def{acos}{43}{87.53552} +\pgfmath@def{acos}{44}{87.47817} \pgfmath@def{acos}{45}{87.42081} +\pgfmath@def{acos}{46}{87.36346} \pgfmath@def{acos}{47}{87.30610} +\pgfmath@def{acos}{48}{87.24874} \pgfmath@def{acos}{49}{87.19138} +\pgfmath@def{acos}{50}{87.13401} \pgfmath@def{acos}{51}{87.07664} +\pgfmath@def{acos}{52}{87.01927} \pgfmath@def{acos}{53}{86.96190} +\pgfmath@def{acos}{54}{86.90452} \pgfmath@def{acos}{55}{86.84714} +\pgfmath@def{acos}{56}{86.78975} \pgfmath@def{acos}{57}{86.73237} +\pgfmath@def{acos}{58}{86.67497} \pgfmath@def{acos}{59}{86.61758} +\pgfmath@def{acos}{60}{86.56018} \pgfmath@def{acos}{61}{86.50278} +\pgfmath@def{acos}{62}{86.44538} \pgfmath@def{acos}{63}{86.38797} +\pgfmath@def{acos}{64}{86.33056} \pgfmath@def{acos}{65}{86.27314} +\pgfmath@def{acos}{66}{86.21572} \pgfmath@def{acos}{67}{86.15830} +\pgfmath@def{acos}{68}{86.10087} \pgfmath@def{acos}{69}{86.04344} +\pgfmath@def{acos}{70}{85.98601} \pgfmath@def{acos}{71}{85.92857} +\pgfmath@def{acos}{72}{85.87113} \pgfmath@def{acos}{73}{85.81368} +\pgfmath@def{acos}{74}{85.75623} \pgfmath@def{acos}{75}{85.69877} +\pgfmath@def{acos}{76}{85.64131} \pgfmath@def{acos}{77}{85.58385} +\pgfmath@def{acos}{78}{85.52638} \pgfmath@def{acos}{79}{85.46891} +\pgfmath@def{acos}{80}{85.41143} \pgfmath@def{acos}{81}{85.35395} +\pgfmath@def{acos}{82}{85.29646} \pgfmath@def{acos}{83}{85.23897} +\pgfmath@def{acos}{84}{85.18147} \pgfmath@def{acos}{85}{85.12397} +\pgfmath@def{acos}{86}{85.06646} \pgfmath@def{acos}{87}{85.00895} +\pgfmath@def{acos}{88}{84.95144} \pgfmath@def{acos}{89}{84.89392} +\pgfmath@def{acos}{90}{84.83639} \pgfmath@def{acos}{91}{84.77886} +\pgfmath@def{acos}{92}{84.72132} \pgfmath@def{acos}{93}{84.66378} +\pgfmath@def{acos}{94}{84.60623} \pgfmath@def{acos}{95}{84.54868} +\pgfmath@def{acos}{96}{84.49112} \pgfmath@def{acos}{97}{84.43355} +\pgfmath@def{acos}{98}{84.37598} \pgfmath@def{acos}{99}{84.31841} +\pgfmath@def{acos}{100}{84.26083} \pgfmath@def{acos}{101}{84.20324} +\pgfmath@def{acos}{102}{84.14564} \pgfmath@def{acos}{103}{84.08805} +\pgfmath@def{acos}{104}{84.03044} \pgfmath@def{acos}{105}{83.97283} +\pgfmath@def{acos}{106}{83.91521} \pgfmath@def{acos}{107}{83.85759} +\pgfmath@def{acos}{108}{83.79996} \pgfmath@def{acos}{109}{83.74232} +\pgfmath@def{acos}{110}{83.68468} \pgfmath@def{acos}{111}{83.62703} +\pgfmath@def{acos}{112}{83.56938} \pgfmath@def{acos}{113}{83.51171} +\pgfmath@def{acos}{114}{83.45405} \pgfmath@def{acos}{115}{83.39637} +\pgfmath@def{acos}{116}{83.33869} \pgfmath@def{acos}{117}{83.28100} +\pgfmath@def{acos}{118}{83.22330} \pgfmath@def{acos}{119}{83.16560} +\pgfmath@def{acos}{120}{83.10789} \pgfmath@def{acos}{121}{83.05018} +\pgfmath@def{acos}{122}{82.99245} \pgfmath@def{acos}{123}{82.93472} +\pgfmath@def{acos}{124}{82.87698} \pgfmath@def{acos}{125}{82.81924} +\pgfmath@def{acos}{126}{82.76149} \pgfmath@def{acos}{127}{82.70373} +\pgfmath@def{acos}{128}{82.64596} \pgfmath@def{acos}{129}{82.58819} +\pgfmath@def{acos}{130}{82.53040} \pgfmath@def{acos}{131}{82.47261} +\pgfmath@def{acos}{132}{82.41482} \pgfmath@def{acos}{133}{82.35701} +\pgfmath@def{acos}{134}{82.29920} \pgfmath@def{acos}{135}{82.24138} +\pgfmath@def{acos}{136}{82.18355} \pgfmath@def{acos}{137}{82.12571} +\pgfmath@def{acos}{138}{82.06786} \pgfmath@def{acos}{139}{82.01001} +\pgfmath@def{acos}{140}{81.95215} \pgfmath@def{acos}{141}{81.89428} +\pgfmath@def{acos}{142}{81.83640} \pgfmath@def{acos}{143}{81.77851} +\pgfmath@def{acos}{144}{81.72062} \pgfmath@def{acos}{145}{81.66272} +\pgfmath@def{acos}{146}{81.60480} \pgfmath@def{acos}{147}{81.54688} +\pgfmath@def{acos}{148}{81.48895} \pgfmath@def{acos}{149}{81.43102} +\pgfmath@def{acos}{150}{81.37307} \pgfmath@def{acos}{151}{81.31511} +\pgfmath@def{acos}{152}{81.25715} \pgfmath@def{acos}{153}{81.19917} +\pgfmath@def{acos}{154}{81.14119} \pgfmath@def{acos}{155}{81.08320} +\pgfmath@def{acos}{156}{81.02520} \pgfmath@def{acos}{157}{80.96719} +\pgfmath@def{acos}{158}{80.90917} \pgfmath@def{acos}{159}{80.85114} +\pgfmath@def{acos}{160}{80.79310} \pgfmath@def{acos}{161}{80.73505} +\pgfmath@def{acos}{162}{80.67699} \pgfmath@def{acos}{163}{80.61893} +\pgfmath@def{acos}{164}{80.56085} \pgfmath@def{acos}{165}{80.50276} +\pgfmath@def{acos}{166}{80.44466} \pgfmath@def{acos}{167}{80.38656} +\pgfmath@def{acos}{168}{80.32844} \pgfmath@def{acos}{169}{80.27031} +\pgfmath@def{acos}{170}{80.21218} \pgfmath@def{acos}{171}{80.15403} +\pgfmath@def{acos}{172}{80.09587} \pgfmath@def{acos}{173}{80.03770} +\pgfmath@def{acos}{174}{79.97953} \pgfmath@def{acos}{175}{79.92134} +\pgfmath@def{acos}{176}{79.86314} \pgfmath@def{acos}{177}{79.80493} +\pgfmath@def{acos}{178}{79.74671} \pgfmath@def{acos}{179}{79.68848} +\pgfmath@def{acos}{180}{79.63024} \pgfmath@def{acos}{181}{79.57198} +\pgfmath@def{acos}{182}{79.51372} \pgfmath@def{acos}{183}{79.45545} +\pgfmath@def{acos}{184}{79.39716} \pgfmath@def{acos}{185}{79.33886} +\pgfmath@def{acos}{186}{79.28056} \pgfmath@def{acos}{187}{79.22224} +\pgfmath@def{acos}{188}{79.16391} \pgfmath@def{acos}{189}{79.10556} +\pgfmath@def{acos}{190}{79.04721} \pgfmath@def{acos}{191}{78.98885} +\pgfmath@def{acos}{192}{78.93047} \pgfmath@def{acos}{193}{78.87208} +\pgfmath@def{acos}{194}{78.81368} \pgfmath@def{acos}{195}{78.75527} +\pgfmath@def{acos}{196}{78.69685} \pgfmath@def{acos}{197}{78.63841} +\pgfmath@def{acos}{198}{78.57997} \pgfmath@def{acos}{199}{78.52151} +\pgfmath@def{acos}{200}{78.46304} \pgfmath@def{acos}{201}{78.40455} +\pgfmath@def{acos}{202}{78.34606} \pgfmath@def{acos}{203}{78.28755} +\pgfmath@def{acos}{204}{78.22903} \pgfmath@def{acos}{205}{78.17050} +\pgfmath@def{acos}{206}{78.11195} \pgfmath@def{acos}{207}{78.05339} +\pgfmath@def{acos}{208}{77.99482} \pgfmath@def{acos}{209}{77.93624} +\pgfmath@def{acos}{210}{77.87764} \pgfmath@def{acos}{211}{77.81903} +\pgfmath@def{acos}{212}{77.76041} \pgfmath@def{acos}{213}{77.70178} +\pgfmath@def{acos}{214}{77.64313} \pgfmath@def{acos}{215}{77.58447} +\pgfmath@def{acos}{216}{77.52579} \pgfmath@def{acos}{217}{77.46711} +\pgfmath@def{acos}{218}{77.40841} \pgfmath@def{acos}{219}{77.34969} +\pgfmath@def{acos}{220}{77.29096} \pgfmath@def{acos}{221}{77.23222} +\pgfmath@def{acos}{222}{77.17347} \pgfmath@def{acos}{223}{77.11470} +\pgfmath@def{acos}{224}{77.05591} \pgfmath@def{acos}{225}{76.99712} +\pgfmath@def{acos}{226}{76.93831} \pgfmath@def{acos}{227}{76.87948} +\pgfmath@def{acos}{228}{76.82064} \pgfmath@def{acos}{229}{76.76179} +\pgfmath@def{acos}{230}{76.70292} \pgfmath@def{acos}{231}{76.64404} +\pgfmath@def{acos}{232}{76.58515} \pgfmath@def{acos}{233}{76.52624} +\pgfmath@def{acos}{234}{76.46731} \pgfmath@def{acos}{235}{76.40837} +\pgfmath@def{acos}{236}{76.34942} \pgfmath@def{acos}{237}{76.29045} +\pgfmath@def{acos}{238}{76.23147} \pgfmath@def{acos}{239}{76.17247} +\pgfmath@def{acos}{240}{76.11346} \pgfmath@def{acos}{241}{76.05443} +\pgfmath@def{acos}{242}{75.99538} \pgfmath@def{acos}{243}{75.93632} +\pgfmath@def{acos}{244}{75.87725} \pgfmath@def{acos}{245}{75.81816} +\pgfmath@def{acos}{246}{75.75906} \pgfmath@def{acos}{247}{75.69994} +\pgfmath@def{acos}{248}{75.64080} \pgfmath@def{acos}{249}{75.58165} +\pgfmath@def{acos}{250}{75.52248} \pgfmath@def{acos}{251}{75.46330} +\pgfmath@def{acos}{252}{75.40410} \pgfmath@def{acos}{253}{75.34489} +\pgfmath@def{acos}{254}{75.28566} \pgfmath@def{acos}{255}{75.22641} +\pgfmath@def{acos}{256}{75.16715} \pgfmath@def{acos}{257}{75.10787} +\pgfmath@def{acos}{258}{75.04857} \pgfmath@def{acos}{259}{74.98926} +\pgfmath@def{acos}{260}{74.92993} \pgfmath@def{acos}{261}{74.87059} +\pgfmath@def{acos}{262}{74.81123} \pgfmath@def{acos}{263}{74.75185} +\pgfmath@def{acos}{264}{74.69245} \pgfmath@def{acos}{265}{74.63304} +\pgfmath@def{acos}{266}{74.57361} \pgfmath@def{acos}{267}{74.51417} +\pgfmath@def{acos}{268}{74.45471} \pgfmath@def{acos}{269}{74.39523} +\pgfmath@def{acos}{270}{74.33573} \pgfmath@def{acos}{271}{74.27621} +\pgfmath@def{acos}{272}{74.21668} \pgfmath@def{acos}{273}{74.15713} +\pgfmath@def{acos}{274}{74.09757} \pgfmath@def{acos}{275}{74.03798} +\pgfmath@def{acos}{276}{73.97838} \pgfmath@def{acos}{277}{73.91876} +\pgfmath@def{acos}{278}{73.85912} \pgfmath@def{acos}{279}{73.79946} +\pgfmath@def{acos}{280}{73.73979} \pgfmath@def{acos}{281}{73.68010} +\pgfmath@def{acos}{282}{73.62039} \pgfmath@def{acos}{283}{73.56066} +\pgfmath@def{acos}{284}{73.50091} \pgfmath@def{acos}{285}{73.44115} +\pgfmath@def{acos}{286}{73.38136} \pgfmath@def{acos}{287}{73.32156} +\pgfmath@def{acos}{288}{73.26174} \pgfmath@def{acos}{289}{73.20190} +\pgfmath@def{acos}{290}{73.14204} \pgfmath@def{acos}{291}{73.08216} +\pgfmath@def{acos}{292}{73.02226} \pgfmath@def{acos}{293}{72.96235} +\pgfmath@def{acos}{294}{72.90241} \pgfmath@def{acos}{295}{72.84246} +\pgfmath@def{acos}{296}{72.78248} \pgfmath@def{acos}{297}{72.72249} +\pgfmath@def{acos}{298}{72.66248} \pgfmath@def{acos}{299}{72.60244} +\pgfmath@def{acos}{300}{72.54239} \pgfmath@def{acos}{301}{72.48232} +\pgfmath@def{acos}{302}{72.42223} \pgfmath@def{acos}{303}{72.36212} +\pgfmath@def{acos}{304}{72.30198} \pgfmath@def{acos}{305}{72.24183} +\pgfmath@def{acos}{306}{72.18166} \pgfmath@def{acos}{307}{72.12147} +\pgfmath@def{acos}{308}{72.06125} \pgfmath@def{acos}{309}{72.00102} +\pgfmath@def{acos}{310}{71.94077} \pgfmath@def{acos}{311}{71.88049} +\pgfmath@def{acos}{312}{71.82019} \pgfmath@def{acos}{313}{71.75988} +\pgfmath@def{acos}{314}{71.69954} \pgfmath@def{acos}{315}{71.63918} +\pgfmath@def{acos}{316}{71.57880} \pgfmath@def{acos}{317}{71.51840} +\pgfmath@def{acos}{318}{71.45798} \pgfmath@def{acos}{319}{71.39754} +\pgfmath@def{acos}{320}{71.33707} \pgfmath@def{acos}{321}{71.27658} +\pgfmath@def{acos}{322}{71.21608} \pgfmath@def{acos}{323}{71.15555} +\pgfmath@def{acos}{324}{71.09499} \pgfmath@def{acos}{325}{71.03442} +\pgfmath@def{acos}{326}{70.97382} \pgfmath@def{acos}{327}{70.91321} +\pgfmath@def{acos}{328}{70.85257} \pgfmath@def{acos}{329}{70.79190} +\pgfmath@def{acos}{330}{70.73122} \pgfmath@def{acos}{331}{70.67051} +\pgfmath@def{acos}{332}{70.60978} \pgfmath@def{acos}{333}{70.54903} +\pgfmath@def{acos}{334}{70.48826} \pgfmath@def{acos}{335}{70.42746} +\pgfmath@def{acos}{336}{70.36664} \pgfmath@def{acos}{337}{70.30579} +\pgfmath@def{acos}{338}{70.24493} \pgfmath@def{acos}{339}{70.18404} +\pgfmath@def{acos}{340}{70.12312} \pgfmath@def{acos}{341}{70.06218} +\pgfmath@def{acos}{342}{70.00122} \pgfmath@def{acos}{343}{69.94024} +\pgfmath@def{acos}{344}{69.87923} \pgfmath@def{acos}{345}{69.81820} +\pgfmath@def{acos}{346}{69.75714} \pgfmath@def{acos}{347}{69.69606} +\pgfmath@def{acos}{348}{69.63496} \pgfmath@def{acos}{349}{69.57383} +\pgfmath@def{acos}{350}{69.51268} \pgfmath@def{acos}{351}{69.45150} +\pgfmath@def{acos}{352}{69.39030} \pgfmath@def{acos}{353}{69.32908} +\pgfmath@def{acos}{354}{69.26783} \pgfmath@def{acos}{355}{69.20655} +\pgfmath@def{acos}{356}{69.14525} \pgfmath@def{acos}{357}{69.08393} +\pgfmath@def{acos}{358}{69.02258} \pgfmath@def{acos}{359}{68.96120} +\pgfmath@def{acos}{360}{68.89980} \pgfmath@def{acos}{361}{68.83837} +\pgfmath@def{acos}{362}{68.77692} \pgfmath@def{acos}{363}{68.71544} +\pgfmath@def{acos}{364}{68.65394} \pgfmath@def{acos}{365}{68.59241} +\pgfmath@def{acos}{366}{68.53086} \pgfmath@def{acos}{367}{68.46928} +\pgfmath@def{acos}{368}{68.40767} \pgfmath@def{acos}{369}{68.34604} +\pgfmath@def{acos}{370}{68.28438} \pgfmath@def{acos}{371}{68.22269} +\pgfmath@def{acos}{372}{68.16098} \pgfmath@def{acos}{373}{68.09924} +\pgfmath@def{acos}{374}{68.03748} \pgfmath@def{acos}{375}{67.97568} +\pgfmath@def{acos}{376}{67.91386} \pgfmath@def{acos}{377}{67.85202} +\pgfmath@def{acos}{378}{67.79014} \pgfmath@def{acos}{379}{67.72824} +\pgfmath@def{acos}{380}{67.66631} \pgfmath@def{acos}{381}{67.60436} +\pgfmath@def{acos}{382}{67.54237} \pgfmath@def{acos}{383}{67.48036} +\pgfmath@def{acos}{384}{67.41832} \pgfmath@def{acos}{385}{67.35626} +\pgfmath@def{acos}{386}{67.29416} \pgfmath@def{acos}{387}{67.23204} +\pgfmath@def{acos}{388}{67.16988} \pgfmath@def{acos}{389}{67.10770} +\pgfmath@def{acos}{390}{67.04550} \pgfmath@def{acos}{391}{66.98326} +\pgfmath@def{acos}{392}{66.92099} \pgfmath@def{acos}{393}{66.85870} +\pgfmath@def{acos}{394}{66.79637} \pgfmath@def{acos}{395}{66.73402} +\pgfmath@def{acos}{396}{66.67164} \pgfmath@def{acos}{397}{66.60923} +\pgfmath@def{acos}{398}{66.54679} \pgfmath@def{acos}{399}{66.48432} +\pgfmath@def{acos}{400}{66.42182} \pgfmath@def{acos}{401}{66.35929} +\pgfmath@def{acos}{402}{66.29673} \pgfmath@def{acos}{403}{66.23414} +\pgfmath@def{acos}{404}{66.17152} \pgfmath@def{acos}{405}{66.10887} +\pgfmath@def{acos}{406}{66.04619} \pgfmath@def{acos}{407}{65.98348} +\pgfmath@def{acos}{408}{65.92074} \pgfmath@def{acos}{409}{65.85796} +\pgfmath@def{acos}{410}{65.79516} \pgfmath@def{acos}{411}{65.73233} +\pgfmath@def{acos}{412}{65.66946} \pgfmath@def{acos}{413}{65.60657} +\pgfmath@def{acos}{414}{65.54364} \pgfmath@def{acos}{415}{65.48068} +\pgfmath@def{acos}{416}{65.41769} \pgfmath@def{acos}{417}{65.35467} +\pgfmath@def{acos}{418}{65.29161} \pgfmath@def{acos}{419}{65.22853} +\pgfmath@def{acos}{420}{65.16541} \pgfmath@def{acos}{421}{65.10226} +\pgfmath@def{acos}{422}{65.03908} \pgfmath@def{acos}{423}{64.97586} +\pgfmath@def{acos}{424}{64.91261} \pgfmath@def{acos}{425}{64.84933} +\pgfmath@def{acos}{426}{64.78602} \pgfmath@def{acos}{427}{64.72267} +\pgfmath@def{acos}{428}{64.65929} \pgfmath@def{acos}{429}{64.59588} +\pgfmath@def{acos}{430}{64.53244} \pgfmath@def{acos}{431}{64.46896} +\pgfmath@def{acos}{432}{64.40544} \pgfmath@def{acos}{433}{64.34190} +\pgfmath@def{acos}{434}{64.27832} \pgfmath@def{acos}{435}{64.21470} +\pgfmath@def{acos}{436}{64.15105} \pgfmath@def{acos}{437}{64.08737} +\pgfmath@def{acos}{438}{64.02365} \pgfmath@def{acos}{439}{63.95990} +\pgfmath@def{acos}{440}{63.89611} \pgfmath@def{acos}{441}{63.83229} +\pgfmath@def{acos}{442}{63.76844} \pgfmath@def{acos}{443}{63.70455} +\pgfmath@def{acos}{444}{63.64062} \pgfmath@def{acos}{445}{63.57666} +\pgfmath@def{acos}{446}{63.51266} \pgfmath@def{acos}{447}{63.44863} +\pgfmath@def{acos}{448}{63.38456} \pgfmath@def{acos}{449}{63.32045} +\pgfmath@def{acos}{450}{63.25631} \pgfmath@def{acos}{451}{63.19213} +\pgfmath@def{acos}{452}{63.12792} \pgfmath@def{acos}{453}{63.06367} +\pgfmath@def{acos}{454}{62.99938} \pgfmath@def{acos}{455}{62.93506} +\pgfmath@def{acos}{456}{62.87070} \pgfmath@def{acos}{457}{62.80630} +\pgfmath@def{acos}{458}{62.74187} \pgfmath@def{acos}{459}{62.67740} +\pgfmath@def{acos}{460}{62.61289} \pgfmath@def{acos}{461}{62.54834} +\pgfmath@def{acos}{462}{62.48376} \pgfmath@def{acos}{463}{62.41913} +\pgfmath@def{acos}{464}{62.35447} \pgfmath@def{acos}{465}{62.28977} +\pgfmath@def{acos}{466}{62.22504} \pgfmath@def{acos}{467}{62.16026} +\pgfmath@def{acos}{468}{62.09545} \pgfmath@def{acos}{469}{62.03059} +\pgfmath@def{acos}{470}{61.96570} \pgfmath@def{acos}{471}{61.90077} +\pgfmath@def{acos}{472}{61.83580} \pgfmath@def{acos}{473}{61.77079} +\pgfmath@def{acos}{474}{61.70574} \pgfmath@def{acos}{475}{61.64065} +\pgfmath@def{acos}{476}{61.57552} \pgfmath@def{acos}{477}{61.51035} +\pgfmath@def{acos}{478}{61.44514} \pgfmath@def{acos}{479}{61.37988} +\pgfmath@def{acos}{480}{61.31459} \pgfmath@def{acos}{481}{61.24926} +\pgfmath@def{acos}{482}{61.18389} \pgfmath@def{acos}{483}{61.11847} +\pgfmath@def{acos}{484}{61.05302} \pgfmath@def{acos}{485}{60.98752} +\pgfmath@def{acos}{486}{60.92199} \pgfmath@def{acos}{487}{60.85641} +\pgfmath@def{acos}{488}{60.79078} \pgfmath@def{acos}{489}{60.72512} +\pgfmath@def{acos}{490}{60.65941} \pgfmath@def{acos}{491}{60.59367} +\pgfmath@def{acos}{492}{60.52787} \pgfmath@def{acos}{493}{60.46204} +\pgfmath@def{acos}{494}{60.39616} \pgfmath@def{acos}{495}{60.33025} +\pgfmath@def{acos}{496}{60.26428} \pgfmath@def{acos}{497}{60.19828} +\pgfmath@def{acos}{498}{60.13223} \pgfmath@def{acos}{499}{60.06613} +\pgfmath@def{acos}{500}{60.00000} \pgfmath@def{acos}{501}{59.93381} +\pgfmath@def{acos}{502}{59.86759} \pgfmath@def{acos}{503}{59.80132} +\pgfmath@def{acos}{504}{59.73500} \pgfmath@def{acos}{505}{59.66864} +\pgfmath@def{acos}{506}{59.60224} \pgfmath@def{acos}{507}{59.53579} +\pgfmath@def{acos}{508}{59.46929} \pgfmath@def{acos}{509}{59.40275} +\pgfmath@def{acos}{510}{59.33617} \pgfmath@def{acos}{511}{59.26953} +\pgfmath@def{acos}{512}{59.20285} \pgfmath@def{acos}{513}{59.13613} +\pgfmath@def{acos}{514}{59.06936} \pgfmath@def{acos}{515}{59.00254} +\pgfmath@def{acos}{516}{58.93568} \pgfmath@def{acos}{517}{58.86876} +\pgfmath@def{acos}{518}{58.80180} \pgfmath@def{acos}{519}{58.73480} +\pgfmath@def{acos}{520}{58.66774} \pgfmath@def{acos}{521}{58.60064} +\pgfmath@def{acos}{522}{58.53349} \pgfmath@def{acos}{523}{58.46629} +\pgfmath@def{acos}{524}{58.39905} \pgfmath@def{acos}{525}{58.33175} +\pgfmath@def{acos}{526}{58.26441} \pgfmath@def{acos}{527}{58.19702} +\pgfmath@def{acos}{528}{58.12957} \pgfmath@def{acos}{529}{58.06208} +\pgfmath@def{acos}{530}{57.99454} \pgfmath@def{acos}{531}{57.92695} +\pgfmath@def{acos}{532}{57.85931} \pgfmath@def{acos}{533}{57.79162} +\pgfmath@def{acos}{534}{57.72388} \pgfmath@def{acos}{535}{57.65608} +\pgfmath@def{acos}{536}{57.58824} \pgfmath@def{acos}{537}{57.52035} +\pgfmath@def{acos}{538}{57.45240} \pgfmath@def{acos}{539}{57.38441} +\pgfmath@def{acos}{540}{57.31636} \pgfmath@def{acos}{541}{57.24826} +\pgfmath@def{acos}{542}{57.18010} \pgfmath@def{acos}{543}{57.11190} +\pgfmath@def{acos}{544}{57.04364} \pgfmath@def{acos}{545}{56.97533} +\pgfmath@def{acos}{546}{56.90697} \pgfmath@def{acos}{547}{56.83855} +\pgfmath@def{acos}{548}{56.77008} \pgfmath@def{acos}{549}{56.70156} +\pgfmath@def{acos}{550}{56.63298} \pgfmath@def{acos}{551}{56.56435} +\pgfmath@def{acos}{552}{56.49567} \pgfmath@def{acos}{553}{56.42693} +\pgfmath@def{acos}{554}{56.35813} \pgfmath@def{acos}{555}{56.28928} +\pgfmath@def{acos}{556}{56.22038} \pgfmath@def{acos}{557}{56.15141} +\pgfmath@def{acos}{558}{56.08240} \pgfmath@def{acos}{559}{56.01333} +\pgfmath@def{acos}{560}{55.94420} \pgfmath@def{acos}{561}{55.87501} +\pgfmath@def{acos}{562}{55.80577} \pgfmath@def{acos}{563}{55.73647} +\pgfmath@def{acos}{564}{55.66712} \pgfmath@def{acos}{565}{55.59770} +\pgfmath@def{acos}{566}{55.52823} \pgfmath@def{acos}{567}{55.45871} +\pgfmath@def{acos}{568}{55.38912} \pgfmath@def{acos}{569}{55.31947} +\pgfmath@def{acos}{570}{55.24977} \pgfmath@def{acos}{571}{55.18001} +\pgfmath@def{acos}{572}{55.11019} \pgfmath@def{acos}{573}{55.04030} +\pgfmath@def{acos}{574}{54.97036} \pgfmath@def{acos}{575}{54.90036} +\pgfmath@def{acos}{576}{54.83030} \pgfmath@def{acos}{577}{54.76018} +\pgfmath@def{acos}{578}{54.69000} \pgfmath@def{acos}{579}{54.61976} +\pgfmath@def{acos}{580}{54.54945} \pgfmath@def{acos}{581}{54.47909} +\pgfmath@def{acos}{582}{54.40866} \pgfmath@def{acos}{583}{54.33817} +\pgfmath@def{acos}{584}{54.26762} \pgfmath@def{acos}{585}{54.19701} +\pgfmath@def{acos}{586}{54.12633} \pgfmath@def{acos}{587}{54.05559} +\pgfmath@def{acos}{588}{53.98479} \pgfmath@def{acos}{589}{53.91392} +\pgfmath@def{acos}{590}{53.84299} \pgfmath@def{acos}{591}{53.77199} +\pgfmath@def{acos}{592}{53.70093} \pgfmath@def{acos}{593}{53.62981} +\pgfmath@def{acos}{594}{53.55862} \pgfmath@def{acos}{595}{53.48736} +\pgfmath@def{acos}{596}{53.41604} \pgfmath@def{acos}{597}{53.34466} +\pgfmath@def{acos}{598}{53.27320} \pgfmath@def{acos}{599}{53.20168} +\pgfmath@def{acos}{600}{53.13010} \pgfmath@def{acos}{601}{53.05844} +\pgfmath@def{acos}{602}{52.98672} \pgfmath@def{acos}{603}{52.91494} +\pgfmath@def{acos}{604}{52.84308} \pgfmath@def{acos}{605}{52.77115} +\pgfmath@def{acos}{606}{52.69916} \pgfmath@def{acos}{607}{52.62710} +\pgfmath@def{acos}{608}{52.55497} \pgfmath@def{acos}{609}{52.48276} +\pgfmath@def{acos}{610}{52.41049} \pgfmath@def{acos}{611}{52.33815} +\pgfmath@def{acos}{612}{52.26574} \pgfmath@def{acos}{613}{52.19326} +\pgfmath@def{acos}{614}{52.12070} \pgfmath@def{acos}{615}{52.04808} +\pgfmath@def{acos}{616}{51.97538} \pgfmath@def{acos}{617}{51.90261} +\pgfmath@def{acos}{618}{51.82976} \pgfmath@def{acos}{619}{51.75685} +\pgfmath@def{acos}{620}{51.68386} \pgfmath@def{acos}{621}{51.61080} +\pgfmath@def{acos}{622}{51.53766} \pgfmath@def{acos}{623}{51.46445} +\pgfmath@def{acos}{624}{51.39117} \pgfmath@def{acos}{625}{51.31781} +\pgfmath@def{acos}{626}{51.24437} \pgfmath@def{acos}{627}{51.17086} +\pgfmath@def{acos}{628}{51.09728} \pgfmath@def{acos}{629}{51.02361} +\pgfmath@def{acos}{630}{50.94987} \pgfmath@def{acos}{631}{50.87606} +\pgfmath@def{acos}{632}{50.80216} \pgfmath@def{acos}{633}{50.72819} +\pgfmath@def{acos}{634}{50.65414} \pgfmath@def{acos}{635}{50.58001} +\pgfmath@def{acos}{636}{50.50580} \pgfmath@def{acos}{637}{50.43152} +\pgfmath@def{acos}{638}{50.35715} \pgfmath@def{acos}{639}{50.28270} +\pgfmath@def{acos}{640}{50.20818} \pgfmath@def{acos}{641}{50.13357} +\pgfmath@def{acos}{642}{50.05888} \pgfmath@def{acos}{643}{49.98411} +\pgfmath@def{acos}{644}{49.90926} \pgfmath@def{acos}{645}{49.83432} +\pgfmath@def{acos}{646}{49.75930} \pgfmath@def{acos}{647}{49.68420} +\pgfmath@def{acos}{648}{49.60902} \pgfmath@def{acos}{649}{49.53375} +\pgfmath@def{acos}{650}{49.45839} \pgfmath@def{acos}{651}{49.38296} +\pgfmath@def{acos}{652}{49.30743} \pgfmath@def{acos}{653}{49.23182} +\pgfmath@def{acos}{654}{49.15613} \pgfmath@def{acos}{655}{49.08035} +\pgfmath@def{acos}{656}{49.00448} \pgfmath@def{acos}{657}{48.92852} +\pgfmath@def{acos}{658}{48.85248} \pgfmath@def{acos}{659}{48.77634} +\pgfmath@def{acos}{660}{48.70012} \pgfmath@def{acos}{661}{48.62381} +\pgfmath@def{acos}{662}{48.54741} \pgfmath@def{acos}{663}{48.47092} +\pgfmath@def{acos}{664}{48.39434} \pgfmath@def{acos}{665}{48.31767} +\pgfmath@def{acos}{666}{48.24091} \pgfmath@def{acos}{667}{48.16405} +\pgfmath@def{acos}{668}{48.08710} \pgfmath@def{acos}{669}{48.01006} +\pgfmath@def{acos}{670}{47.93293} \pgfmath@def{acos}{671}{47.85570} +\pgfmath@def{acos}{672}{47.77838} \pgfmath@def{acos}{673}{47.70096} +\pgfmath@def{acos}{674}{47.62345} \pgfmath@def{acos}{675}{47.54585} +\pgfmath@def{acos}{676}{47.46814} \pgfmath@def{acos}{677}{47.39034} +\pgfmath@def{acos}{678}{47.31244} \pgfmath@def{acos}{679}{47.23445} +\pgfmath@def{acos}{680}{47.15635} \pgfmath@def{acos}{681}{47.07816} +\pgfmath@def{acos}{682}{46.99987} \pgfmath@def{acos}{683}{46.92147} +\pgfmath@def{acos}{684}{46.84298} \pgfmath@def{acos}{685}{46.76439} +\pgfmath@def{acos}{686}{46.68569} \pgfmath@def{acos}{687}{46.60690} +\pgfmath@def{acos}{688}{46.52800} \pgfmath@def{acos}{689}{46.44899} +\pgfmath@def{acos}{690}{46.36989} \pgfmath@def{acos}{691}{46.29068} +\pgfmath@def{acos}{692}{46.21136} \pgfmath@def{acos}{693}{46.13194} +\pgfmath@def{acos}{694}{46.05241} \pgfmath@def{acos}{695}{45.97278} +\pgfmath@def{acos}{696}{45.89304} \pgfmath@def{acos}{697}{45.81319} +\pgfmath@def{acos}{698}{45.73323} \pgfmath@def{acos}{699}{45.65317} +\pgfmath@def{acos}{700}{45.57299} \pgfmath@def{acos}{701}{45.49271} +\pgfmath@def{acos}{702}{45.41231} \pgfmath@def{acos}{703}{45.33180} +\pgfmath@def{acos}{704}{45.25118} \pgfmath@def{acos}{705}{45.17045} +\pgfmath@def{acos}{706}{45.08961} \pgfmath@def{acos}{707}{45.00865} +\pgfmath@def{acos}{708}{44.92757} \pgfmath@def{acos}{709}{44.84638} +\pgfmath@def{acos}{710}{44.76508} \pgfmath@def{acos}{711}{44.68366} +\pgfmath@def{acos}{712}{44.60212} \pgfmath@def{acos}{713}{44.52046} +\pgfmath@def{acos}{714}{44.43869} \pgfmath@def{acos}{715}{44.35680} +\pgfmath@def{acos}{716}{44.27478} \pgfmath@def{acos}{717}{44.19265} +\pgfmath@def{acos}{718}{44.11039} \pgfmath@def{acos}{719}{44.02802} +\pgfmath@def{acos}{720}{43.94552} \pgfmath@def{acos}{721}{43.86289} +\pgfmath@def{acos}{722}{43.78014} \pgfmath@def{acos}{723}{43.69727} +\pgfmath@def{acos}{724}{43.61427} \pgfmath@def{acos}{725}{43.53115} +\pgfmath@def{acos}{726}{43.44790} \pgfmath@def{acos}{727}{43.36452} +\pgfmath@def{acos}{728}{43.28101} \pgfmath@def{acos}{729}{43.19737} +\pgfmath@def{acos}{730}{43.11360} \pgfmath@def{acos}{731}{43.02970} +\pgfmath@def{acos}{732}{42.94567} \pgfmath@def{acos}{733}{42.86151} +\pgfmath@def{acos}{734}{42.77721} \pgfmath@def{acos}{735}{42.69278} +\pgfmath@def{acos}{736}{42.60821} \pgfmath@def{acos}{737}{42.52351} +\pgfmath@def{acos}{738}{42.43867} \pgfmath@def{acos}{739}{42.35370} +\pgfmath@def{acos}{740}{42.26858} \pgfmath@def{acos}{741}{42.18333} +\pgfmath@def{acos}{742}{42.09793} \pgfmath@def{acos}{743}{42.01240} +\pgfmath@def{acos}{744}{41.92672} \pgfmath@def{acos}{745}{41.84090} +\pgfmath@def{acos}{746}{41.75493} \pgfmath@def{acos}{747}{41.66882} +\pgfmath@def{acos}{748}{41.58257} \pgfmath@def{acos}{749}{41.49617} +\pgfmath@def{acos}{750}{41.40962} \pgfmath@def{acos}{751}{41.32292} +\pgfmath@def{acos}{752}{41.23607} \pgfmath@def{acos}{753}{41.14908} +\pgfmath@def{acos}{754}{41.06193} \pgfmath@def{acos}{755}{40.97463} +\pgfmath@def{acos}{756}{40.88717} \pgfmath@def{acos}{757}{40.79956} +\pgfmath@def{acos}{758}{40.71180} \pgfmath@def{acos}{759}{40.62388} +\pgfmath@def{acos}{760}{40.53580} \pgfmath@def{acos}{761}{40.44756} +\pgfmath@def{acos}{762}{40.35916} \pgfmath@def{acos}{763}{40.27061} +\pgfmath@def{acos}{764}{40.18189} \pgfmath@def{acos}{765}{40.09300} +\pgfmath@def{acos}{766}{40.00396} \pgfmath@def{acos}{767}{39.91474} +\pgfmath@def{acos}{768}{39.82537} \pgfmath@def{acos}{769}{39.73582} +\pgfmath@def{acos}{770}{39.64611} \pgfmath@def{acos}{771}{39.55622} +\pgfmath@def{acos}{772}{39.46617} \pgfmath@def{acos}{773}{39.37594} +\pgfmath@def{acos}{774}{39.28554} \pgfmath@def{acos}{775}{39.19496} +\pgfmath@def{acos}{776}{39.10421} \pgfmath@def{acos}{777}{39.01328} +\pgfmath@def{acos}{778}{38.92218} \pgfmath@def{acos}{779}{38.83089} +\pgfmath@def{acos}{780}{38.73942} \pgfmath@def{acos}{781}{38.64777} +\pgfmath@def{acos}{782}{38.55594} \pgfmath@def{acos}{783}{38.46392} +\pgfmath@def{acos}{784}{38.37171} \pgfmath@def{acos}{785}{38.27932} +\pgfmath@def{acos}{786}{38.18673} \pgfmath@def{acos}{787}{38.09396} +\pgfmath@def{acos}{788}{38.00100} \pgfmath@def{acos}{789}{37.90784} +\pgfmath@def{acos}{790}{37.81448} \pgfmath@def{acos}{791}{37.72093} +\pgfmath@def{acos}{792}{37.62719} \pgfmath@def{acos}{793}{37.53324} +\pgfmath@def{acos}{794}{37.43909} \pgfmath@def{acos}{795}{37.34474} +\pgfmath@def{acos}{796}{37.25019} \pgfmath@def{acos}{797}{37.15542} +\pgfmath@def{acos}{798}{37.06046} \pgfmath@def{acos}{799}{36.96528} +\pgfmath@def{acos}{800}{36.86989} \pgfmath@def{acos}{801}{36.77429} +\pgfmath@def{acos}{802}{36.67848} \pgfmath@def{acos}{803}{36.58245} +\pgfmath@def{acos}{804}{36.48621} \pgfmath@def{acos}{805}{36.38974} +\pgfmath@def{acos}{806}{36.29305} \pgfmath@def{acos}{807}{36.19615} +\pgfmath@def{acos}{808}{36.09901} \pgfmath@def{acos}{809}{36.00165} +\pgfmath@def{acos}{810}{35.90406} \pgfmath@def{acos}{811}{35.80625} +\pgfmath@def{acos}{812}{35.70820} \pgfmath@def{acos}{813}{35.60991} +\pgfmath@def{acos}{814}{35.51139} \pgfmath@def{acos}{815}{35.41263} +\pgfmath@def{acos}{816}{35.31364} \pgfmath@def{acos}{817}{35.21440} +\pgfmath@def{acos}{818}{35.11491} \pgfmath@def{acos}{819}{35.01518} +\pgfmath@def{acos}{820}{34.91520} \pgfmath@def{acos}{821}{34.81497} +\pgfmath@def{acos}{822}{34.71449} \pgfmath@def{acos}{823}{34.61375} +\pgfmath@def{acos}{824}{34.51276} \pgfmath@def{acos}{825}{34.41150} +\pgfmath@def{acos}{826}{34.30999} \pgfmath@def{acos}{827}{34.20821} +\pgfmath@def{acos}{828}{34.10616} \pgfmath@def{acos}{829}{34.00385} +\pgfmath@def{acos}{830}{33.90126} \pgfmath@def{acos}{831}{33.79840} +\pgfmath@def{acos}{832}{33.69526} \pgfmath@def{acos}{833}{33.59184} +\pgfmath@def{acos}{834}{33.48814} \pgfmath@def{acos}{835}{33.38416} +\pgfmath@def{acos}{836}{33.27989} \pgfmath@def{acos}{837}{33.17533} +\pgfmath@def{acos}{838}{33.07047} \pgfmath@def{acos}{839}{32.96532} +\pgfmath@def{acos}{840}{32.85988} \pgfmath@def{acos}{841}{32.75413} +\pgfmath@def{acos}{842}{32.64807} \pgfmath@def{acos}{843}{32.54171} +\pgfmath@def{acos}{844}{32.43504} \pgfmath@def{acos}{845}{32.32806} +\pgfmath@def{acos}{846}{32.22076} \pgfmath@def{acos}{847}{32.11314} +\pgfmath@def{acos}{848}{32.00520} \pgfmath@def{acos}{849}{31.89693} +\pgfmath@def{acos}{850}{31.78833} \pgfmath@def{acos}{851}{31.67939} +\pgfmath@def{acos}{852}{31.57012} \pgfmath@def{acos}{853}{31.46051} +\pgfmath@def{acos}{854}{31.35056} \pgfmath@def{acos}{855}{31.24026} +\pgfmath@def{acos}{856}{31.12961} \pgfmath@def{acos}{857}{31.01860} +\pgfmath@def{acos}{858}{30.90724} \pgfmath@def{acos}{859}{30.79551} +\pgfmath@def{acos}{860}{30.68341} \pgfmath@def{acos}{861}{30.57095} +\pgfmath@def{acos}{862}{30.45811} \pgfmath@def{acos}{863}{30.34489} +\pgfmath@def{acos}{864}{30.23128} \pgfmath@def{acos}{865}{30.11729} +\pgfmath@def{acos}{866}{30.00291} \pgfmath@def{acos}{867}{29.88813} +\pgfmath@def{acos}{868}{29.77294} \pgfmath@def{acos}{869}{29.65736} +\pgfmath@def{acos}{870}{29.54136} \pgfmath@def{acos}{871}{29.42494} +\pgfmath@def{acos}{872}{29.30810} \pgfmath@def{acos}{873}{29.19084} +\pgfmath@def{acos}{874}{29.07315} \pgfmath@def{acos}{875}{28.95502} +\pgfmath@def{acos}{876}{28.83645} \pgfmath@def{acos}{877}{28.71743} +\pgfmath@def{acos}{878}{28.59796} \pgfmath@def{acos}{879}{28.47803} +\pgfmath@def{acos}{880}{28.35763} \pgfmath@def{acos}{881}{28.23677} +\pgfmath@def{acos}{882}{28.11542} \pgfmath@def{acos}{883}{27.99360} +\pgfmath@def{acos}{884}{27.87128} \pgfmath@def{acos}{885}{27.74847} +\pgfmath@def{acos}{886}{27.62516} \pgfmath@def{acos}{887}{27.50134} +\pgfmath@def{acos}{888}{27.37700} \pgfmath@def{acos}{889}{27.25214} +\pgfmath@def{acos}{890}{27.12675} \pgfmath@def{acos}{891}{27.00082} +\pgfmath@def{acos}{892}{26.87434} \pgfmath@def{acos}{893}{26.74731} +\pgfmath@def{acos}{894}{26.61973} \pgfmath@def{acos}{895}{26.49157} +\pgfmath@def{acos}{896}{26.36283} \pgfmath@def{acos}{897}{26.23351} +\pgfmath@def{acos}{898}{26.10359} \pgfmath@def{acos}{899}{25.97306} +\pgfmath@def{acos}{900}{25.84193} \pgfmath@def{acos}{901}{25.71017} +\pgfmath@def{acos}{902}{25.57778} \pgfmath@def{acos}{903}{25.44475} +\pgfmath@def{acos}{904}{25.31106} \pgfmath@def{acos}{905}{25.17671} +\pgfmath@def{acos}{906}{25.04169} \pgfmath@def{acos}{907}{24.90598} +\pgfmath@def{acos}{908}{24.76958} \pgfmath@def{acos}{909}{24.63247} +\pgfmath@def{acos}{910}{24.49464} \pgfmath@def{acos}{911}{24.35608} +\pgfmath@def{acos}{912}{24.21678} \pgfmath@def{acos}{913}{24.07672} +\pgfmath@def{acos}{914}{23.93588} \pgfmath@def{acos}{915}{23.79427} +\pgfmath@def{acos}{916}{23.65185} \pgfmath@def{acos}{917}{23.50863} +\pgfmath@def{acos}{918}{23.36457} \pgfmath@def{acos}{919}{23.21967} +\pgfmath@def{acos}{920}{23.07391} \pgfmath@def{acos}{921}{22.92728} +\pgfmath@def{acos}{922}{22.77975} \pgfmath@def{acos}{923}{22.63132} +\pgfmath@def{acos}{924}{22.48195} \pgfmath@def{acos}{925}{22.33164} +\pgfmath@def{acos}{926}{22.18036} \pgfmath@def{acos}{927}{22.02810} +\pgfmath@def{acos}{928}{21.87483} \pgfmath@def{acos}{929}{21.72053} +\pgfmath@def{acos}{930}{21.56518} \pgfmath@def{acos}{931}{21.40876} +\pgfmath@def{acos}{932}{21.25124} \pgfmath@def{acos}{933}{21.09260} +\pgfmath@def{acos}{934}{20.93281} \pgfmath@def{acos}{935}{20.77185} +\pgfmath@def{acos}{936}{20.60969} \pgfmath@def{acos}{937}{20.44630} +\pgfmath@def{acos}{938}{20.28165} \pgfmath@def{acos}{939}{20.11570} +\pgfmath@def{acos}{940}{19.94844} \pgfmath@def{acos}{941}{19.77982} +\pgfmath@def{acos}{942}{19.60981} \pgfmath@def{acos}{943}{19.43837} +\pgfmath@def{acos}{944}{19.26546} \pgfmath@def{acos}{945}{19.09105} +\pgfmath@def{acos}{946}{18.91509} \pgfmath@def{acos}{947}{18.73754} +\pgfmath@def{acos}{948}{18.55835} \pgfmath@def{acos}{949}{18.37748} +\pgfmath@def{acos}{950}{18.19487} \pgfmath@def{acos}{951}{18.01047} +\pgfmath@def{acos}{952}{17.82423} \pgfmath@def{acos}{953}{17.63609} +\pgfmath@def{acos}{954}{17.44598} \pgfmath@def{acos}{955}{17.25385} +\pgfmath@def{acos}{956}{17.05962} \pgfmath@def{acos}{957}{16.86322} +\pgfmath@def{acos}{958}{16.66457} \pgfmath@def{acos}{959}{16.46359} +\pgfmath@def{acos}{960}{16.26020} \pgfmath@def{acos}{961}{16.05430} +\pgfmath@def{acos}{962}{15.84580} \pgfmath@def{acos}{963}{15.63459} +\pgfmath@def{acos}{964}{15.42057} \pgfmath@def{acos}{965}{15.20360} +\pgfmath@def{acos}{966}{14.98357} \pgfmath@def{acos}{967}{14.76033} +\pgfmath@def{acos}{968}{14.53374} \pgfmath@def{acos}{969}{14.30364} +\pgfmath@def{acos}{970}{14.06986} \pgfmath@def{acos}{971}{13.83221} +\pgfmath@def{acos}{972}{13.59049} \pgfmath@def{acos}{973}{13.34447} +\pgfmath@def{acos}{974}{13.09392} \pgfmath@def{acos}{975}{12.83856} +\pgfmath@def{acos}{976}{12.57811} \pgfmath@def{acos}{977}{12.31225} +\pgfmath@def{acos}{978}{12.04060} \pgfmath@def{acos}{979}{11.76278} +\pgfmath@def{acos}{980}{11.47834} \pgfmath@def{acos}{981}{11.18676} +\pgfmath@def{acos}{982}{10.88748} \pgfmath@def{acos}{983}{10.57984} +\pgfmath@def{acos}{984}{10.26309} \pgfmath@def{acos}{985}{9.93636} +\pgfmath@def{acos}{986}{9.59863} \pgfmath@def{acos}{987}{9.24870} +\pgfmath@def{acos}{988}{8.88512} \pgfmath@def{acos}{989}{8.50614} +\pgfmath@def{acos}{990}{8.10961} \pgfmath@def{acos}{991}{7.69281} +\pgfmath@def{acos}{992}{7.25224} \pgfmath@def{acos}{993}{6.78328} +\pgfmath@def{acos}{994}{6.27958} \pgfmath@def{acos}{995}{5.73196} +\pgfmath@def{acos}{996}{5.12640} \pgfmath@def{acos}{997}{4.43922} +\pgfmath@def{acos}{998}{3.62430} \pgfmath@def{acos}{999}{2.56255} +\pgfmath@def{acos}{1000}{0.00000} + + + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/math/pgfmathode.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathode.code.tex new file mode 100644 index 0000000000..f072c2361e --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathode.code.tex @@ -0,0 +1,178 @@ +% Copyright 2019 by Christophe Jorssen +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. +\def\pgfmathode@stopadd{\pgfmathode@stopadd} + +\def\pgfmathode@addindextofunc[#1]#2{% + \begingroup + \gdef\pgfmathode@func{}% + \pgfmathode@addindextofunc@i[#1]#2\pgfmathode@stopadd} + +\def\pgfmathode@addindextofunc@i[#1]#2#3{% + \ifx#1#2 + \expandafter\gdef\expandafter\pgfmathode@func\expandafter{% + \pgfmathode@func #2[\pgfmathode@timeindex]}% + \else + \expandafter\gdef\expandafter\pgfmathode@func\expandafter{% + \pgfmathode@func #2}% + \fi + \ifx#3\pgfmathode@stopadd + \expandafter\gdef\expandafter\pgfmathode@func\expandafter{% + \expandafter{\pgfmathode@func}}% + \let\next\endgroup + \else + \def\next{\pgfmathode@addindextofunc@i[#1]#3}% + \fi + \next} + +%********************************************************************** +% Know limitation: fk cannot be a time function. Should be possible to +% use \Sol[0] as time in the set of equations. +%********************************************************************** + +% Numerically solve a differential system with 1st order Runge-Kutta +% (Euler method) +% dq1/dt = f1(t,q1,q2,...,qN) +% dq2/dt = f2(t,q1,q2,...,qN) +% ... +% dqN/dt = fN(t,q1,q2,...,qN) +% +% #1: A pgf array where the solution will be stored. +% At the end: +% #1 -> {{t(0),q1(t(0)),q2(t(0)),...,qN(t(0))}, +% {t(1),q1(t(1)),q2(t(1)),...,qN(t(1))}, +% ... +% {t(Nstep),q1(t(Nstep)),q2(t(Nstep)),...,qN(t(Nstep))}} +% #2: A pgf array with f1,f2,...,fN +% {f1} +% #3: A pgf array with initial conditions. +% {t(0),q1(t(0)),q2(t(0)),...,qN(t(0))} +% #4: t(Nstep) +% #5: Nstep (number of steps) +% +% * First order example: dq/dt = -q + 5 with IC=(t=0,q(0)=0) +% \pgfmathodeRKI{\Sol}{{-\Sol[1]+5}}{{0,0}}{3.5}{100} +% * Second order example: {dq1/dt=q2, dq2/dt=-q2/2-sin(q1)} (damped +% pendulum) +% \pgfmathodeRKI{\Sol}{{\Sol[2],-\Sol[2]/2-sin(deg(\Sol[1]))}}% +% {{0,-1,5}}{15}{50} + +\def\pgfmathode@generic@init@RK{% + \begingroup + % Sol array (#1) first element is given by the set of initial + % conditions (#3). We need to enclose it in brace so that is a now + % a "matrix" array. + \gdef#1{{#3}}% + % The set of rhs {f1(t,q1,q2,...,qN),...,fN(t,q1,q2,...,qN)} is + % given in terms of #1[0],#1[1],...,#1[N]. We need to transform to + % #1[\pgfmathode@timeindex][0],...,#1[\pgfmathode@timeindex][N], that is + % add [\pgfmathode@timeindex] after every occurrence of #1 in #2. + % No need to brace #2 since it is already surrounded by braces. The + % result is stored in \pgfmathode@func + \pgfmathode@addindextofunc[#1]#2% + % Set time step. Actually the number of time steps is #5-1, so we + % divide by (#5-1)+1 = #5. + \pgfmathsetmacro\pgfmathode@Sol@t{#1[0][0]}% + \pgfmathsetmacro\pgfmathode@Deltat{(#4-\pgfmathode@Sol@t)/#5}% + % Compute the order of the system: it is equal to the number of IC + % minus one (time). + \pgfmathsetmacro\pgfmathode@dimfunc{dim(#3)-1}% + \pgfmathsetmacro\pgfmathode@numstep{#5-1}} + +\def\pgfmathodeRKI#1#2#3#4#5{% + \pgfmathode@generic@init@RK + % Start the time loop for Runge-Kutta 1st order + \foreach \pgfmathode@timeindex in {0,...,\pgfmathode@numstep} {% + \message{Step \pgfmathode@timeindex...}% + % Start the function loop + \foreach \pgfmathode@funcindex in {1,...,\pgfmathode@dimfunc} {% + % The RKI algorithm + % qk[t(i)] = Deltat*fk(t(i-1),q1(t(i-1)),...qN(t(i-1))) + + % qk[t(i-1)] + % Note: this part can be really slow due to array management in + % pgfmath. + % TODO: find a better way (at least inside this loop) + \pgfmathparse{% + \pgfmathode@Deltat*(\pgfmathode@func[\pgfmathode@funcindex-1])+ + #1[\pgfmathode@timeindex][\pgfmathode@funcindex]}% + % Store the result in a helper macro + \expandafter\xdef\csname pgfmathode@Sol@\pgfmathode@funcindex + \endcsname{\pgfmathresult}% + } + % Store step i + \pgfmathparse{\pgfmathode@Sol@t+\pgfmathode@Deltat}% + \xdef\pgfmathode@Sol@t{\pgfmathresult}% + \xdef\pgfmathode@temp{}% + \foreach \pgfmathode@funcindex in {1,...,\pgfmathode@dimfunc} {% + \ifx\pgfmathode@temp\pgfutil@empty + \xdef\pgfmathode@temp{% + \csname pgfmathode@Sol@\pgfmathode@funcindex\endcsname}% + \else + \xdef\pgfmathode@temp{% + \pgfmathode@temp, + \csname pgfmathode@Sol@\pgfmathode@funcindex\endcsname}% + \fi} + \xdef#1{% + {\expandafter\pgfutil@firstofone#1,% + {\pgfmathode@Sol@t,\pgfmathode@temp}}}% + } + \endgroup} + +% RKIV: far from working yet! +\def\pgfmathodeRKIV#1#2#3#4#5{% + \pgfmathode@generic@init@RK + % Start the time loop for Runge-Kutta 4th order + \foreach \pgfmathode@timeindex in {0,...,\pgfmathode@numstep} {% + \message{Step \pgfmathode@timeindex...}% + % Start the function loop + \foreach \pgfmathode@funcindex in {1,...,\pgfmathode@dimfunc} {% + % The RKIV algorithm + % qk[t(i)] = qk[t(i-1)] + + % (1/6) * (j1k + 2j2k + 2j3k + j4k) + % where j1k = fk(t(i-1),q1(t(i-1)),...qN(t(i-1))) * Deltat + % j2k = fk(t(i-1)+.5*Deltat, + % q1(t(i-1))+.5*j11,...qN(t(i-1))+.5*j1N) * Deltat + % j3k = fk(t(i-1)+.5*Deltat, + % q1(t(i-1))+.5*j21,...qN(t(i-1))+.5*j2N) * Deltat + % j4k = fk(t(i-1)+Deltat, + % q1(t(i-1))+j31,...qN(t(i-1))+j3N) * Deltat + % + % Compute j1k + \pgfmathparse{% + \pgfmathode@Deltat*(\pgfmathode@func[\pgfmathode@funcindex-1])+ + #1[\pgfmathode@timeindex][\pgfmathode@funcindex]}% + \expandafter\xdef\csname pgfmathode@RKIV@1@\pgfmathode@funcindex + \endcsname{\pgfmathresult}% + % Compute j2k + \pgfmathparse{% + \pgfmathode@Deltat*(\pgfmathode@func[\pgfmathode@funcindex-1])+ + #1[\pgfmathode@timeindex][\pgfmathode@funcindex]}% + \expandafter\xdef\csname pgfmathode@RKIV@1@\pgfmathode@funcindex + \endcsname{\pgfmathresult}% + } + % Store step i + \pgfmathparse{\pgfmathode@Sol@t+\pgfmathode@Deltat}% + \xdef\pgfmathode@Sol@t{\pgfmathresult}% + \xdef\pgfmathode@temp{}% + \foreach \pgfmathode@funcindex in {1,...,\pgfmathode@dimfunc} {% + \ifx\pgfmathode@temp\pgfutil@empty + \xdef\pgfmathode@temp{% + \csname pgfmathode@Sol@\pgfmathode@funcindex\endcsname}% + \else + \xdef\pgfmathode@temp{% + \pgfmathode@temp, + \csname pgfmathode@Sol@\pgfmathode@funcindex\endcsname}% + \fi} + \xdef#1{% + {\expandafter\pgfutil@firstofone#1,% + {\pgfmathode@Sol@t,\pgfmathode@temp}}}% + } + \endgroup} + + +\endinput diff --git a/graphics/pgf/base/tex/generic/math/pgfmathparser.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathparser.code.tex new file mode 100644 index 0000000000..8a560ff114 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathparser.code.tex @@ -0,0 +1,1017 @@ + +\newdimen\pgfmath@dimen +\newcount\pgfmath@count +\newbox\pgfmath@box +\newtoks\pgfmath@toks + +\newif\ifpgfmath@quickparse +\newif\ifpgfmathfloat +\newif\ifpgfmathunitsdeclared +\newif\ifpgfmathmathunitsdeclared +\newif\ifpgfmathignoreunitscale + +\let\pgfmath@protected@edef=\edef +\ifcsname protected@edef\endcsname + \let\pgfmath@protected@edef=\protected@edef +\fi + +\def\pgfmathprint#1{\pgfmathparse{#1}\pgfmathresult} + +\def\pgfmathparse{% + \begingroup + \pgfmath@catcodes + \pgfmath@quickparsefalse + % Test for the fpu library + \ifpgfmathfloat + \let\pgfmath@parse@next=\pgfmathfloatparsenumber + \else + \let\pgfmath@parse@next=\pgfmathparse@ + \fi + \pgfmath@parse@next} + +\begingroup + \lccode`\~=`\" + \lowercase{\endgroup + \def\pgfmath@catcodes{% + \catcode`\==12 % + \catcode`\,=12 % + \catcode`\|=12 % + \catcode`\&=12 % + \let~\pgfmath@char@quote + }}% + +\def\pgfmathqparse{% + \begingroup + \pgfmath@catcodes + \pgfmath@quickparsetrue + \pgfmathparse@} + +\def\pgfmathparse@#1{% + % No (math) units yet. + \global\pgfmathunitsdeclaredfalse + \global\pgfmathmathunitsdeclaredfalse + % Expand expression so any remaining CSs are registers + % or box dimensions (i.e. |\wd|, |\ht|, |\dp|). + \pgfmath@protected@edef\pgfmath@expression{#1}% + % + \expandafter\pgfmathparse@trynumber@loop\pgfmath@expression\pgfmath@parse@stop + % + % this here is the _real_ parser. it is invoked by + % \pgfmathparse@trynumber@loop if that says "this is no number" + %\pgfmathparse@@\pgfmath@parse@stop% +} + +\def\pgfmath@parse@stop{\pgfmath@parse@stop}% equals only itself + +\def\pgfmathparse@trynumber@token{numeric} +\begingroup +\def\\{\global\let\pgf@let@space@token= } \\ % now, \pgf@let@space@token is a space token +\endgroup + +% This a "fast-lane": if the expressions consist merely of number +% tokens, we can simply return the number as-is. +% +% This is significantly faster and should resemble the 80% use-case. +% +% #1 a single token +\def\pgfmathparse@trynumber@loop{% + \futurelet\pgfmath@token@let\pgfmathparse@trynumber@loop@ +}% +\def\pgfmathparse@trynumber@loop@#1{% + \ifx\pgfmath@token@let\pgf@let@space@token + % Hm. we found a white space... and we have no support for + % trimming. That means we have to assume that the white space + % occurred somewhere in the middle - and fall back to the + % expensive method. + \def\pgfmath@parse@next{\pgfmathparse@@#1}% + \else + \ifx\pgfmath@token@let\bgroup% + % oh! We found '{' #1. + % Well, these braces appear to be special; fall back to + % the complicated routine... + \let\pgfmath@parse@next=\pgfmathparse@@ + \else + \ifx\pgfmath@token@let\pgfmath@parse@stop + % Ah: we have passed the check! The expression consists only + % of 0123456789. , so do not parse anything and return it + % as-is! + \let\pgfmath@parse@next=\pgfmathparse@expression@is@number + \else + \expandafter\ifx\csname pgfmath@token@\pgfmathparse@trynumber@token @\string#1\endcsname\relax% + % hm. It is none of 0123456789. + \let\pgfmath@parse@next=\pgfmathparse@@ + \else + % continue... we only found one of 0123456789. so + % far... + \let\pgfmath@parse@next=\pgfmathparse@trynumber@loop + \fi + \fi + \fi + \fi + \pgfmath@parse@next +}% + +\def\pgfmathparse@expression@is@number{% + \let\pgfmathresult=\pgfmath@expression + \pgfmath@smuggleone\pgfmathresult% + \endgroup + \ignorespaces +}% +\def\pgfmathparse@@#1\pgfmath@parse@stop{% + % We are inside a group (opened in |\pgfmathparse| or + % |\pgfmathqparse|). + % Stuff for calc compatibility. + \let\real=\pgfmath@calc@real + \let\minof=\pgfmath@calc@minof + \let\maxof=\pgfmath@calc@maxof + \let\ratio=\pgfmath@calc@ratio + \let\widthof=\pgfmath@calc@widthof + \let\heightof=\pgfmath@calc@heightof + \let\depthof=\pgfmath@calc@depthof + % Restore font (defined in pgfmathutil.code.tex) + \pgfmath@selectfont + % Set up stack. + \pgfmath@stack@operation={{}{}{}}% + \pgfmath@stack@operand={{}{}{}}% + \let\pgfmath@stack@operation@top=\pgfmath@stack@empty + \let\pgfmath@stack@operand@top=\pgfmath@stack@empty + % An expression always begins with an operand. + \expandafter\pgfmath@bgroup@strip\expandafter{\pgfmath@expression}% + % |\pgfmath@bgroup@stripped| is the result of + % |\pgfmath@bgroup@strip| + \expandafter\pgfmath@parse@@operand\pgfmath@bgroup@stripped @@@@\pgfmath@parse@stop% +} + +\def\pgfmath@parse@end#1\pgfmath@parse@stop{% + \pgfmathpostparse + \pgfmath@smuggleone\pgfmathresult% + \endgroup + \ignorespaces} + +\let\pgfmathpostparse=\relax + +% For compatibility with older version. +% +\def\pgfmathscaleresult{% + \ifpgfmathunitsdeclared + \else + \ifpgfmathignoreunitscale + \else + \afterassignment\pgfmath@gobbletilpgfmath@% + \pgfmath@x\pgfmathresultunitscale pt\relax\pgfmath@% + \expandafter\pgfmath@x\pgfmathresult\pgfmath@x% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@x}}% + \fi + \fi +} + +\def\pgfmathsetresultunitscale#1{\def\pgfmathresultunitscale{#1}} + +\def\pgfmathresultunitscale{1} + + +% A utility function which evaluates expression '#1' and invokes '#2' +% if the expression is true and '#3' if it is false. +\def\pgfmathifexpression#1#2#3{% + \pgfmathparse{#1}% + \pgfmath@iftrue{#2}{#3}% +}% +% Executes '#1' if \pgfmathresult is 'true', '#2' otherwise. +% WARNING : overwritten in fpu lib! +\def\pgfmath@iftrue{% + \ifdim\pgfmathresult pt=1.0pt % + \let\pgfmath@next=\pgfutil@firstoftwo + \else + \let\pgfmath@next=\pgfutil@secondoftwo + \fi + \pgfmath@next% +}% + +% Stuff for computability with the calc package. +% +\def\pgfmath@calc@real#1{#1} +\def\pgfmath@calc@minof#1#2{min(#1,#2)} +\def\pgfmath@calc@maxof#1#2{max(#1,#2)} +\def\pgfmath@calc@ratio#1#2{#1/#2} +\def\pgfmath@calc@widthof#1{width("#1")} +\def\pgfmath@calc@heightof#1{height("#1")} +\def\pgfmath@calc@depthof#1{depth("#1")} + +\def\pgfmath@bgroup{\string\pgfmath@bgroup} +\def\pgfmath@egroup{\string\pgfmath@egroup} +\def\pgfmath@egroup@token{\pgfmath@egroup} + +\def\pgfmath@text@@{@} +\def\pgfmath@text@operator{operator} +\def\pgfmath@text@function{function} +\def\pgfmath@dots{...} +\def\pgfmath@char@zero{0} +\def\pgfmath@char@quote{"} +\def\pgfmath@char@exclamation{!} +\def\pgfmath@char@plus{+} +\def\pgfmath@char@minus{-} +\def\pgfmath@char@period{.} +\def\pgfmath@char@leftangle{<} +\def\pgfmath@char@leftbracket{[} +\pgfmath@toks={#} +\edef\pgfmath@char@hash{\the\pgfmath@toks} + +\def\pgfmath@tokens@make#1#2{% + % Defines for each token or balanced text in |#2| a control sequence + % |\pgfmath@token@<#1>@\string| and stores |#2| + % in it. + \def\pgfmath@prefix{#1}% + % Note the empty group |{}| at the end that ends the loop in + % |\pgfmath@token@@make|. + \expandafter\pgfmath@tokens@@make#2{}} + +\def\pgfmath@tokens@@make#1{% + \def\pgfmath@token{#1}% + \ifx\pgfmath@token\pgfmath@empty + % End of loop: all tokens or balanced texts were parsed. + \else + \pgfmath@namedef{pgfmath@token@\pgfmath@prefix @\string#1}{#1}% + \expandafter\pgfmath@tokens@@make% + \fi} + +\pgfmath@tokens@make{box}{\wd\ht\dp} +\ifx\dimexpr\@undefined\else % needed for classic tex + \pgfmath@tokens@make{dimexpr}{\dimexpr\glueexpr} +\fi +\pgfmath@tokens@make{unit}{{bp}{cc}{cm}{dd}{em}{ex}{in}{mm}{pc}{pt}{sp}} +\ifx\pdftexversion\@undefined\else % for pdfTeX + \pgfmath@tokens@make{unit}{{nc}{nd}{px}} +\fi +\ifx\directlua\@undefined\else % for LuaTeX + \pgfmath@tokens@make{unit}{{nc}{nd}{px}} +\fi +\ifx\kanjiskip\@undefined\else % for pTeX, upTeX + \pgfmath@tokens@make{unit}{{H}{Q}{zh}{zw}} +\fi +% +\pgfmath@tokens@make{mathunit}{{mu}} +\pgfmath@tokens@make{numeric}{.0123456789} +\pgfmath@tokens@make{number}{0123456789} +\pgfmath@tokens@make{functional}{_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ} +\pgfmath@tokens@make{exponent}{eE} +\pgfmath@tokens@make{group}{{()}{[]}{\pgfmath@bgroup\pgfmath@egroup}} +\pgfmath@tokens@make{specials}{@)]\pgfmath@egroup} +\pgfmath@tokens@make{hexadecimal}{0123456789ABCDEFabcdef} +\pgfmath@tokens@make{octal}{01234567} +\pgfmath@tokens@make{binary}{01} + +\pgfmath@namedef{pgfmath@base@0x}{16} +\pgfmath@namedef{pgfmath@base@0X}{16} +\pgfmath@namedef{pgfmath@base@0b}{2} +\pgfmath@namedef{pgfmath@base@0B}{2} + +% Determine if a register is a count or a dimension/skip register. +\newif\ifpgfmath@dimen@ +\def\pgfmath@dimen@#1{% + \begingroup + \afterassignment\pgfmath@dimen@@% + #1=0.0pt\relax\pgfmath@} +\def\pgfmath@dimen@@#1#2\pgfmath@{% + \endgroup + \ifx#1.% + \pgfmath@dimen@false + \else + \pgfmath@dimen@true + \fi} + +\def\pgfmath@parse@ifbgroup#1#2{% + \let\pgfmath@parse@bgroup@after=#1% + \let\pgfmath@parse@nobgroup@after=#2% + \futurelet\pgfmath@token@let% + \pgfmath@parse@@ifbgroup} + +\def\pgfmath@parse@@ifbgroup{% + \ifx\pgfmath@token@let\bgroup + \let\pgfmath@parse@next=\pgfmath@parse@@@ifbgroup + \else + % |\pgfmath@sptoken| defined in \file{pgfmathutil.code.tex}. + \ifx\pgfmath@token@let\pgfmath@sptoken + \let\pgfmath@parse@next=\pgfmath@parse@@@@ifbgroup + \else + \let\pgfmath@parse@next=\pgfmath@parse@nobgroup@after + \fi + \fi + \pgfmath@parse@next} + +% TT: If false, octal parsing is switched off (needed for time parsing) +\newif\ifpgfmath@octalparsing +\pgfmath@octalparsingtrue + +% I (CJ) *think* it replaces |{| and |}| by |\pgfmath@bgroup| and +% |\pgfmath@egroup|? +\def\pgfmath@parse@@@ifbgroup#1{% + \pgfmath@parse@bgroup@after\pgfmath@bgroup#1\pgfmath@egroup} + +{ +\def\:{\pgfmath@parse@@@@ifbgroup} +\expandafter\gdef\: {\futurelet\pgfmath@token@let\pgfmath@parse@@ifbgroup} +} + +% Parse an operand. +\def\pgfmath@parse@operand{% + \expandafter\pgfmath@parse@@operand\pgfmath@token@next} + +% This is the entry point for the parser. It is called at the end of +% |\pgfmathparse@| with the following syntax +% |\expandafter\pgfmath@parse@@operand\pgfmath@bgroup@stripped +% @@@@\pgfmath@parse@stop|. +% Note: we are inside a group. +\def\pgfmath@parse@@operand{% + \pgfmath@parse@ifbgroup{\pgfmath@parse@@operand}{\pgfmath@parse@@operand@}} + +% An operand is +% * |+| (unary plus), +% * |-| (unary minus), +% * a prefix operator +\def\pgfmath@parse@@operand@#1{% + \def\pgfmath@token{#1}% + \ifx\pgfmath@token\pgfmath@char@plus + % Unary (prefix) plus + \let\pgfmath@parse@next=\pgfmath@parse@@operand% + \else + \ifx\pgfmath@token\pgfmath@char@minus + % Unary (prefix) minus + \pgfmath@stack@push@operation{neg}% + \let\pgfmath@parse@next=\pgfmath@parse@@operand + \else + % See |\pgfmathdeclareoperator| (below). Note that |+| and |-| + % that are also declared as operators have been tested before so + % they should never be parsed as binary (infix) operator at this stage. + \expandafter\ifx\csname pgfmath@operation@\expandafter\string\pgfmath@token @prefix\endcsname\pgfmath@token + \let\pgfmath@parse@next=\pgfmath@parse@prefix@operator + \else + \ifpgfmath@quickparse + \let\pgfmath@parse@next=\pgfmath@qparse@operand + \else + \let\pgfmath@number=\pgfmath@empty + \expandafter\ifx\csname pgfmath@token@functional@\string#1\endcsname\relax% + \let\pgfmath@base=\pgfmath@empty% + \let\pgfmath@token@next=\pgfmath@token% + \if#10% Check for octal prefix. + \ifpgfmath@octalparsing% + \def\pgfmath@base{8}% + \fi% + \fi% + \let\pgfmath@parse@next=\pgfmath@parse@number% + \else% + \let\pgfmath@function=\pgfmath@token% + \let\pgfmath@parse@next=\pgfmath@parse@function% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgfmath@parse@next% +} + +% Parse prefix operators. +% +\def\pgfmath@parse@prefix@operator{% + \ifx\pgfmath@token\pgfmath@char@quote% Quote character. + \let\pgfmath@parse@next=\pgfmath@parse@operand@quote% + \else% + \ifx\pgfmath@token\pgfmath@char@exclamation% Prefix !. + \pgfmath@stack@push@operation{not}% + \let\pgfmath@parse@next=\pgfmath@parse@@operand% + \else% Anything else, just push and hope. + \expandafter\pgfmath@stack@push@operation\expandafter{\pgfmath@token}% + \let\pgfmath@parse@next=\pgfmath@parse@@operand% + \fi% + \fi% + \pgfmath@parse@next% +}% + + +% Quote part of an expression. +% +\def\pgfmath@parse@operand@quote#1"{% + \def\pgfmathresult{#1}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + +% Quick operand parsing. Should always have units. +% No functions, base conversion, quoting or scientific notation +% are permitted. +\def\pgfmath@qparse@operand{% + \afterassignment\pgfmath@qparse@@operand% + \pgfmath@dimen\pgfmath@token} +\def\pgfmath@qparse@@operand{% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + +% Parse a number, which can take the form: +% +% 1. An integer, or a decimal, with or without units. +% 2. A dimension/skip or a count register. +% 3. A dimension register preceded by a number or count register. +% 4. A box dimension (e.g., \wd\mybox). +% 5. A box dimension preceded by a number or a count register. +% 6. Scientific notation (e.g., 1.234567e-10). +% 7. A binary, hexadecimal, or octal number. +% +\def\pgfmath@parse@number{\pgfmath@parse@ifbgroup{\pgfmath@parse@number}{\pgfmath@parse@number@}} +\def\pgfmath@parse@number@#1{% + \let\pgfmath@token=\pgfmath@token@next% + \def\pgfmath@token@next{#1}% + \pgfmath@parse@@number} + +\def\pgfmath@parse@@number{% + \ifx\pgfmath@token\pgfmath@egroup@token% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmath@number}% + \let\pgfmath@parse@next=\pgfmath@parse@@@operator% + \else% + \expandafter\ifcat\pgfmath@token\relax% A CS? + \expandafter\ifx\csname pgfmath@token@dimexpr@\expandafter\string\pgfmath@token\endcsname\relax% + \expandafter\ifx\pgfmath@token\numexpr% + \let\pgfmath@parse@next=\pgfmath@parse@numexpr% + \else% + \expandafter\ifx\pgfmath@token\muexpr% + \let\pgfmath@parse@next=\pgfmath@parse@muexpr% + \else% + \expandafter\ifx\csname pgfmath@token@box@\expandafter\string\pgfmath@token\endcsname\relax% + % So, is the CS is a dimension or a count register? + \expandafter\pgfmath@dimen@\pgfmath@token% + \ifpgfmath@dimen@% A dimension register. + \global\pgfmathunitsdeclaredtrue% + \pgfmath@dimen=\pgfmath@number\pgfmath@token% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \else% A count register. + \pgfmath@count=\pgfmath@token% + \expandafter\def\expandafter\pgfmath@number\expandafter{\the\pgfmath@count}% + \expandafter\ifcat\pgfmath@token@next\relax% + % A CS following a count register should be \wd, \ht or \dp. + \let\pgfmath@parse@next=\pgfmath@parse@number% + \else% + \let\pgfmathresult=\pgfmath@number% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \fi% + \fi% + \else% + % This should be a box specification, for example, 0.5\wd\mybox. + \global\pgfmathunitsdeclaredtrue% + \pgfmath@dimen=\pgfmath@number\pgfmath@token\pgfmath@token@next% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@operator% + \fi% + \fi% + \fi% + \else% + \global\pgfmathunitsdeclaredtrue% + \let\pgfmath@parse@next=\pgfmath@parse@dimexpr% + \fi% + \else% + \expandafter\ifx\csname pgfmath@token@numeric@\expandafter\string\pgfmath@token\endcsname\relax% + % It isn't numeric (i.e., 012345679.), so it might be units... + % first double-character units... + \expandafter\ifx\csname pgfmath@token@unit@\pgfmath@token\expandafter\string\pgfmath@token@next\endcsname\relax% + % then single-character units... + \expandafter\ifx\csname pgfmath@token@unit@\pgfmath@token\endcsname\relax% + % ...or the exponent characters... + \expandafter\ifx\csname pgfmath@token@exponent@\pgfmath@token\endcsname\relax% + % ...or a base prefix... + \expandafter\ifx\csname pgfmath@base@\pgfmath@number\pgfmath@token\endcsname\relax% + % ...or a math unit... + \expandafter\ifx\csname pgfmath@token@mathunit@\pgfmath@token\expandafter\string\pgfmath@token@next\endcsname\relax% + % ...none of the above... + \ifx\pgfmath@base\pgfmath@empty% + \let\pgfmathresult=\pgfmath@number% + \else% + \ifx\pgfmath@number\pgfmath@char@zero% + \let\pgfmathresult=\pgfmath@number% + \else% + % Convert from octal. + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\pgfmath@number}{8}{10}% + \fi% + \fi% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@@operator% + \else% + % ...here, it is a math unit (mu). Treat it as a pt. + \global\pgfmathunitsdeclaredtrue% + \global\pgfmathmathunitsdeclaredtrue% + \pgfmath@dimen=\pgfmath@number pt\relax% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@operator% + \fi% + \else% + % ...here, it is a base prefix 0x, 0X, 0b or 0B + \expandafter\let\expandafter\pgfmath@base\expandafter=% + \csname pgfmath@base@\pgfmath@number\pgfmath@token\endcsname% + \let\pgfmath@parse@next=\pgfmath@parse@base% + \fi% + \else% ... and here, it is the exponent characters. + \let\pgfmath@parse@next=\pgfmath@parse@exponent% + \fi% + \else% ...but here it is single-character units. + \global\pgfmathunitsdeclaredtrue% + \pgfmath@dimen=\pgfmath@number\pgfmath@token\relax% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@operator% + \fi% + \else% ...but here it is double-character units. + \global\pgfmathunitsdeclaredtrue% + \pgfmath@dimen=\pgfmath@number\pgfmath@token\pgfmath@token@next\relax% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@operator% + \fi% + \else% It is numeric. + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgfmath@number% + \expandafter\expandafter\expandafter{\expandafter\pgfmath@number\pgfmath@token}% + \ifx\pgfmath@token\pgfmath@char@period% + \let\pgfmath@base=\pgfmath@empty% + \fi% + \let\pgfmath@parse@next=\pgfmath@parse@number% + \fi% + \fi% + \fi% + \pgfmath@parse@next% +} + + +% Parse a \dimexpr +\def\pgfmath@parse@dimexpr{% + \afterassignment\pgfmath@parse@dimexpr@% + \expandafter\expandafter\expandafter\pgfmath@dimen\expandafter\pgfmath@token\pgfmath@token@next% +} +\def\pgfmath@parse@dimexpr@{% + \edef\pgfmathresult{\pgfmath@tonumber{\pgfmath@dimen}}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + + +% Parse a \muexpr +\def\pgfmath@parse@muexpr{% + \begingroup% + \afterassignment\pgfmath@parse@muexpr@% + \expandafter\expandafter\expandafter\muskip\expandafter\expandafter\expandafter0\expandafter\pgfmath@token\expandafter\pgfmath@token@next% +} +\def\pgfmath@parse@muexpr@{% + \expandafter\endgroup% + \expandafter\edef\expandafter\pgfmathresult\expandafter{\expandafter\pgfMATH@STRIPMU\the\muskip0}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + +{ +\catcode`\m=12 +\catcode`\u=12 +\gdef\pgfMATH@STRIPMU#1mu{#1} +} + + +% Parse a \numexpr +\def\pgfmath@parse@numexpr{% + \afterassignment\pgfmath@parse@numexpr@% + \expandafter\expandafter\expandafter\pgfmath@count\expandafter\pgfmath@token\pgfmath@token@next% +} +\def\pgfmath@parse@numexpr@#1{% + \expandafter\def\expandafter\pgfmath@number\expandafter{\the\pgfmath@count}% + \def\pgfmath@token@next{#1}% + \expandafter\ifcat\pgfmath@token@next\relax% + % A CS following a count register should be \wd, \ht or \dp. + \let\pgfmath@parse@next=\pgfmath@parse@number% + \else% + \let\pgfmathresult=\pgfmath@number% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \fi% + \pgfmath@parse@next% +} + + +% Parse the exponent of a number. +% +% REMARK: this method will be overwritten by the FPU library. Please +% keep changes consistent... +\def\pgfmath@parse@exponent{% + \afterassignment\pgfmath@parse@@exponent% + \pgfmath@count\pgfmath@token@next} +\def\pgfmath@parse@@exponent{% + \pgfmathscientific{\pgfmath@number}{\the\pgfmath@count}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \pgfmath@parse@@operator% +} + +% Parse binary or hexadecimal numbers (octal numbers done elsewhere). +% +\def\pgfmath@parse@base{% + \ifnum\pgfmath@base=2\relax% + \let\pgfmath@parse@next=\pgfmath@parse@binary% + \else% + \ifnum\pgfmath@base=16\relax% + \let\pgfmath@parse@next=\pgfmath@parse@hexadecimal% + \else% + \pgfmath@error{Unexpected numerical base `\pgfmath@base'}{}% + \def\pgfmathresult{0}% + \let\pgfmath@parse@next=\pgfmath@parse@end% + \fi% + \fi% + \let\pgfmath@number=\pgfmath@empty% + \expandafter\pgfmath@parse@next\pgfmath@token@next% +} + +\def\pgfmath@parse@binary#1{% + \expandafter\ifx\csname pgfmath@token@binary@#1\endcsname\relax% + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\pgfmath@number}{2}{10}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \def\pgfmath@token@next{#1}% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \else% + \expandafter\def\expandafter\pgfmath@number\expandafter{\pgfmath@number#1}% + \let\pgfmath@parse@next=\pgfmath@parse@binary% + \fi% + \pgfmath@parse@next% +} + +\def\pgfmath@parse@hexadecimal#1{% + \expandafter\ifx\csname pgfmath@token@hexadecimal@#1\endcsname\relax% + \expandafter\pgfmathbasetobase\expandafter\pgfmathresult\expandafter{\pgfmath@number}{16}{10}% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \def\pgfmath@token@next{#1}% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \else% + \expandafter\def\expandafter\pgfmath@number\expandafter{\pgfmath@number#1}% + \let\pgfmath@parse@next=\pgfmath@parse@hexadecimal% + \fi% + \pgfmath@parse@next% +} + +% Parse a function. +% +\def\pgfmath@parse@function{\pgfmath@parse@ifbgroup{\pgfmath@parse@function}{\pgfmath@parse@@function}} +\def\pgfmath@parse@function@{\futurelet\pgfmath@token@let\pgfmath@parse@@function} +\def\pgfmath@parse@@function{% + \ifx\pgfmath@token@let\pgfmath@sptoken% + \let\pgfmath@token=\pgfmath@empty% + \let\pgfmath@parse@next=\pgfmath@parse@@@@function% + \else% + \let\pgfmath@parse@next=\pgfmath@parse@@@function% + \fi% + \pgfmath@parse@next} + +\def\pgfmath@parse@@@function#1{% + \expandafter\ifx\csname pgfmath@token@functional@\expandafter\string#1\endcsname\relax% + \expandafter\ifx\csname pgfmath@token@number@\expandafter\string#1\endcsname\relax% + \def\pgfmath@token{#1}% Not from A-Z, a-z, 0-9, or _. + \let\pgfmath@parse@next=\pgfmath@parse@@@@function% + \else% It is from 0-9. + \expandafter\def\expandafter\pgfmath@function\expandafter{\pgfmath@function#1}% + \let\pgfmath@parse@next=\pgfmath@parse@function@% + \fi% + \else% It is from A-Z, a-z, or _. + \edef\pgfmath@function{\pgfmath@function#1}% + \let\pgfmath@parse@next=\pgfmath@parse@function@% + \fi% + \pgfmath@parse@next} + +\def\pgfmath@parse@@@@function{% + \expandafter\ifx\csname pgfmath@function@\pgfmath@function\endcsname\relax% + \pgfmath@error{Unknown function `\pgfmath@function'}{}% + \def\pgfmathresult{0}% + \let\pgfmath@parse@next=\pgfmath@parse@end% + \else% + \expandafter\ifnum\csname pgfmath@operation@\pgfmath@function @arity\endcsname=0\relax% + % Functions with zero arity are called directly. + \csname pgfmath\pgfmath@function @\endcsname% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \let\pgfmath@parse@next=\pgfmath@parse@@operator% + \else% Otherwise, they are pushed onto the operator stack + \expandafter\pgfmath@stack@push@operation\expandafter{\pgfmath@function}% + \let\pgfmath@parse@next=\pgfmath@parse@@operand% + \fi% + \fi% + \expandafter\pgfmath@parse@next\pgfmath@token} + +% Parse an operator. +% +\def\pgfmath@parse@operator{\pgfmath@parse@ifbgroup{\pgfmath@parse@operator}{\pgfmath@parse@operator@}}% +\def\pgfmath@parse@operator@#1{% Get one token. + \let\pgfmath@token=\pgfmath@token@next% + \def\pgfmath@token@next{#1}% + \pgfmath@parse@@@operator} + +\def\pgfmath@parse@@operator{\pgfmath@parse@ifbgroup{\pgfmath@parse@@operator}{\pgfmath@parse@@operator@}}% +\def\pgfmath@parse@@operator@#1{% Get first token... + \def\pgfmath@token{#1}% + \pgfmath@parse@ifbgroup{\pgfmath@parse@@operator@@}{\pgfmath@parse@@operator@@}}% +\def\pgfmath@parse@@operator@@#1{% ...and second token. + \def\pgfmath@token@next{#1}% + \pgfmath@parse@@@operator} + +\def\pgfmath@parse@@@operator{% + \expandafter\ifx\csname pgfmath@operator@\pgfmath@token\expandafter\string\pgfmath@token@next\endcsname\relax% + % Not a double character operator. + \expandafter\ifx\csname pgfmath@operator@\pgfmath@token\endcsname\relax% + % Not a single character operator. + \pgfmath@error{Unknown operator `\pgfmath@token' or `\pgfmath@token\pgfmath@token@next'}{}% + \def\pgfmathresult{0}% + \let\pgfmath@parse@next=\pgfmath@parse@end% + \else% + \expandafter\pgfmath@operation@process\expandafter{\pgfmath@token}% + \ifx\pgfmath@token\pgfmath@text@@% + \let\pgfmath@parse@next=\pgfmath@parse@end% + \else% + \expandafter\ifx\csname pgfmath@operation@\pgfmath@token @postfix\endcsname\pgfmath@token% + % Postfix operators are followed by an operator. + \ifx\pgfmath@token@next\pgfmath@char@leftbracket% Except [. + \let\pgfmath@parse@next=\pgfmath@parse@operand% + \else% + \let\pgfmath@parse@next=\pgfmath@parse@operator% + \fi% + \else% + % Any other operator is followed by an operand. + \let\pgfmath@parse@next=\pgfmath@parse@operand% + \fi% + \fi% + \fi% + \else% + % A double character operator... + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgfmath@token\expandafter\expandafter\expandafter% + {\expandafter\pgfmath@token\pgfmath@token@next}% + \expandafter\pgfmath@operation@process\expandafter{\pgfmath@token}% + % ...is always followed by an operand. + \let\pgfmath@parse@next=\pgfmath@parse@@operand% + \fi% + \pgfmath@parse@next% +} + + +% Process an operation. +% +\def\pgfmath@operation@process#1{% + \def\pgfmath@operator{#1}% + \ifx\pgfmath@stack@operation@top\pgfmath@stack@empty% + \else% + \pgfmath@operation@@process% + \fi% + \expandafter\ifx\csname pgfmath@token@specials@#1\endcsname\relax% + \pgfmath@stack@push@operation{#1}% + \fi% +} + +% Process the operation stack. +% +\def\pgfmath@operation@@process{% + \ifx\pgfmath@stack@operation@top\pgfmath@stack@empty% + \let\pgfmath@parse@next=\relax% + \else% + \ifnum\csname pgfmath@operation@\pgfmath@operator @precedence\endcsname>% + \csname pgfmath@operation@\pgfmath@stack@operation@top @precedence\endcsname\relax% + % If the precedence of the scanned operator is greater than the + % precedence of the operator at the top of the stack, do nothing. + \let\pgfmath@parse@next=\relax% + \else% + \let\pgfmath@stack@operation@last=\pgfmath@stack@operation@top% + \expandafter\ifx\csname pgfmath@operator@\pgfmath@stack@operation@top\endcsname\relax% + \pgfmath@function@@@process% + \else% + \pgfmath@operator@@@process% + \fi% + \expandafter\pgfmath@stack@push@operand\expandafter{\pgfmathresult}% + \expandafter\ifx\csname pgfmath@token@group@\pgfmath@stack@operation@last\pgfmath@operator\endcsname\relax% + \let\pgfmath@parse@next=\pgfmath@operation@@process% + \else% + \let\pgfmath@parse@next=\relax% + \fi% + \fi% + \fi% + \pgfmath@parse@next% +} + +% Process an operator. +% +\def\pgfmath@operator@@@process{% Process an operator. + \pgfmath@stack@pop@operation\pgfmath@@operator% + \pgfmath@stack@pop@operand\pgfmath@operand@a% + \ifcase\csname pgfmath@operation@\pgfmath@@operator @arity\endcsname\relax% + % Zero arity operators (!). + \or% + \pgfmath@operator@@@@process{\pgfmath@operand@a}% + \or% + \pgfmath@stack@pop@operand\pgfmath@operand@b% + \pgfmath@operator@@@@process{\pgfmath@operand@b}{\pgfmath@operand@a}% + \or% + \pgfmath@stack@pop@operand\pgfmath@operand@b% + \expandafter\pgfmath@operator@@@@process\expandafter% + {\expandafter\pgfmath@operand@b\expandafter}\pgfmath@operand@a% + \else% + % No operators with more than tenary arity. + \fi% +} + +\def\pgfmath@operator@@@@process{% + \csname pgfmath% + \csname pgfmath@operation@\pgfmath@@operator @name\endcsname% + @\endcsname} + +% Process a function. +% +\def\pgfmath@function@@@process{% Process a function. + \ifnum\csname pgfmath@operation@\pgfmath@stack@operation@top @arity\endcsname>0\relax% + \pgfmath@stack@pop@operation\pgfmath@@function% + \pgfmath@stack@pop@operand\pgfmath@@operand% + \ifnum\csname pgfmath@operation@\pgfmath@@function @arity\endcsname>1\relax% + \ifnum\csname pgfmath@operation@\pgfmath@@function @arity\endcsname>9\relax% + \csname pgfmath\pgfmath@@function @\endcsname{\pgfmath@@operand}% + \else% + \expandafter\pgfmath@function@@@@process\pgfmath@@operand% + \fi + \else% + \expandafter\pgfmath@function@@@@process\expandafter{\pgfmath@@operand}% + \fi% + \fi% +} + +\def\pgfmath@function@@@@process{\csname pgfmath\pgfmath@@function @\endcsname} + +% Stack. +% +\newtoks\pgfmath@stack@operand +\newtoks\pgfmath@stack@operation +\let\pgfmath@stack@empty=\pgfmath@empty + +\def\pgfmath@stack@push#1#2{% + \def\pgfmath@stack@top{#2}% + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter% + {\expandafter\pgfmath@stack@top\expandafter}\the#1}}% + +\def\pgfmath@stack@pop#1#2{\expandafter\pgfmath@stack@@pop\the#1\pgfmath@stack@stop{#1}{#2}} +\def\pgfmath@stack@@pop#1#2#3\pgfmath@stack@stop#4#5{\def#5{#1}#4={{#2}#3}\def\pgfmath@stack@top{#2}} + +\def\pgfmath@stack@push@operation#1{% + \pgfmath@stack@push\pgfmath@stack@operation{#1}% + \let\pgfmath@stack@operation@top=\pgfmath@stack@top} + +\def\pgfmath@stack@pop@operation#1{% + \pgfmath@stack@pop\pgfmath@stack@operation{#1}% + \let\pgfmath@stack@operation@top=\pgfmath@stack@top} + +% REMARK: This method will be overwritten by the FPU library. Please +% keep any changes consistent. +\def\pgfmath@stack@push@operand#1{% + \pgfmath@stack@push\pgfmath@stack@operand{#1}% + \let\pgfmath@stack@operand@top=\pgfmath@stack@top} + +\def\pgfmath@stack@pop@operand#1{% + \pgfmath@stack@pop\pgfmath@stack@operand{#1}% + \let\pgfmath@stack@operand@top=\pgfmath@stack@top} + + +% Declare an operator for the parser. +% +% It is not recommended that new operators be created as +% the parser is not fully robust for arbitrary operators. +% +\def\pgfmathdeclareoperator#1#2#3#4#5{% + \ifx\pgfmath@operatorlist\pgfutil@empty + \edef\pgfmath@operatorlist{{\string#1}}% + \else + \edef\pgfmath@operatorlist{\pgfmath@operatorlist,{\string#1}}% + \fi + \pgfmath@namedef{pgfmath@operator@\string#1}{#1}% + \pgfmath@namedef{pgfmath@operation@\string#1@name}{#2}% + \pgfmath@namedef{pgfmath@operation@\string#1@arity}{#3}% + \pgfmath@namedef{pgfmath@operation@\string#1@#4}{#1}% + \pgfmath@namedef{pgfmath@operation@\string#1@precedence}{#5}% +} + +\def\pgfmath@operatorlist{} + +\pgfmathdeclareoperator{+}{add} {2}{infix}{500} +\pgfmathdeclareoperator{-}{subtract}{2}{infix}{500} +\pgfmathdeclareoperator{*}{multiply}{2}{infix}{700} +\pgfmathdeclareoperator{/}{divide} {2}{infix}{700} +\pgfmathdeclareoperator{^}{pow} {2}{infix}{900} + +\pgfmathdeclareoperator{<} {} {1}{prefix} {1} + +\pgfmathdeclareoperator{>} {greater} {2}{infix} {250} +\pgfmathdeclareoperator{<} {less} {2}{infix} {250} +\pgfmathdeclareoperator{==}{equal} {2}{infix} {250} +\pgfmathdeclareoperator{>=}{notless} {2}{infix} {250} +\pgfmathdeclareoperator{<=}{notgreater}{2}{infix} {250} +\pgfmathdeclareoperator{&&}{and} {2}{infix} {200} +\pgfmathdeclareoperator{||}{or} {2}{infix} {200} +\pgfmathdeclareoperator{!=}{notequal} {2}{infix} {250} +\pgfmathdeclareoperator{!} {not} {1}{prefix}{975} +\pgfmathdeclareoperator{?} {ifthenelse}{3}{infix} {100} +\pgfmathdeclareoperator{:} {@@collect} {2}{infix}{101} + +\pgfmathdeclareoperator{!}{factorial}{1}{postfix}{800}% Must be defined after prefix ! operator. +\pgfmathdeclareoperator{r}{deg} {1}{postfix}{600} + +\pgfmathdeclareoperator{,}{@collect} {2}{infix} {10} +\pgfmathdeclareoperator{[}{@startindex}{2}{prefix} {7} +\pgfmathdeclareoperator{]}{@endindex} {0}{postfix}{6} +\pgfmathdeclareoperator{(}{@startgroup}{1}{prefix} {5} +\pgfmathdeclareoperator{)}{@endgroup} {0}{postfix}{4} + +\pgfmathdeclareoperator{\pgfmath@bgroup}{@startarray}{1}{prefix} {3} +\pgfmathdeclareoperator{\pgfmath@egroup}{@endarray} {1}{postfix}{2}% + +% Special operators. +\pgfmathdeclareoperator{"}{}{1}{prefix}{1} +\pgfmathdeclareoperator{@}{}{0}{postfix}{0} + +% Internal functions. + +% Begin and end parenthesis (). +% +\def\pgfmath@startgroup@#1{\pgfmath@protected@edef\pgfmathresult{#1}} +\def\pgfmath@endgroup@{}% Never actually called. + +% Begin and end array access []. +% +\def\pgfmath@startindex@#1#2{% + \expandafter\pgfmatharray@#1{#2}% + \expandafter\pgfmath@bgroup@strip\expandafter{\pgfmathresult}% + \ifx\pgfmath@token@let\bgroup% + \expandafter\def\expandafter\pgfmathresult\expandafter{\expandafter{\pgfmathresult}}% + \fi} +\def\pgfmath@endindex@{}% Never actually called. + +% Begin and end array {}. +% +\def\pgfmath@startarray@#1{\expandafter\def\expandafter\pgfmathresult\expandafter{\expandafter{#1}}} +\def\pgfmath@endarray@#1{\expandafter\def\expandafter\pgfmathresult\expandafter{#1}}% Never actually called. + + +\def\pgfmath@@collect@#1#2{% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgfmathresult\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter% + {\expandafter#1\expandafter}\expandafter{#2}}% +} +% Collect items separated by ,. +% +\def\pgfmath@collect@#1#2{% + \expandafter\def\expandafter\pgfmath@collect@original\expandafter{#1}% + \expandafter\pgfmath@bgroup@strip\expandafter{#1}% + \ifx\pgfmath@token@let\bgroup% + \ifx\pgfmath@collect@original\pgfmath@bgroup@stripped% + \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmath@bgroup@stripped}% + \else% + \expandafter\def\expandafter\pgfmathresult\expandafter{\expandafter{\pgfmath@bgroup@stripped}}% + \fi% + \else% + \expandafter\def\expandafter\pgfmathresult\expandafter{\expandafter{\pgfmath@bgroup@stripped}}% + \fi% + \expandafter\pgfmath@bgroup@strip\expandafter{#2}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgfmathresult\expandafter\expandafter\expandafter% + {\expandafter\pgfmathresult\expandafter{\pgfmath@bgroup@stripped}}% +} + +% Strip braces from a token sequence. +% +\def\pgfmath@bgroup@strip#1{% + \def\pgfmath@bgroup@strip@last{#1}% + \pgfmath@bgroup@@strip{#1}\pgfmath@\pgfmath@@\pgfmath@@@} + +\def\pgfmath@bgroup@strip@#1{% + \def\pgfmath@bgroup@strip@last{#1}% + \pgfmath@bgroup@@strip#1\pgfmath@\pgfmath@@\pgfmath@@@} + +\def\pgfmath@bgroup@pgfmath@{\pgfmath@} + +\def\pgfmath@bgroup@@strip{% + \futurelet\pgfmath@token@let\pgfmath@bgroup@@@strip} + +\def\pgfmath@bgroup@@@strip#1#2#3\pgfmath@@@{% + \ifx\pgfmath@token@let\bgroup + \def\pgfmath@bgroup@test{#2}% + \ifx\pgfmath@bgroup@test\pgfmath@bgroup@pgfmath@ + \def\pgfmath@next{\pgfmath@bgroup@strip@{#1}}% + \else + \let\pgfmath@bgroup@stripped=\pgfmath@bgroup@strip@last + \let\pgfmath@next=\relax + \fi + \else + \pgfmath@bgroup@@@@strip#1#2#3% + \let\pgfmath@next=\relax + \fi + \pgfmath@next} + +\def\pgfmath@bgroup@@@@strip#1\pgfmath@\pgfmath@@{% + \def\pgfmath@bgroup@stripped{#1}} + +% Local Variables: +% tab-width: 2 +% End: diff --git a/graphics/pgf/base/tex/generic/math/pgfmathutil.code.tex b/graphics/pgf/base/tex/generic/math/pgfmathutil.code.tex new file mode 100644 index 0000000000..d8d67dd841 --- /dev/null +++ b/graphics/pgf/base/tex/generic/math/pgfmathutil.code.tex @@ -0,0 +1,298 @@ +% Copyright 2019 Mark Wibrow +% +% but subject to the LaTeX Project Public License +% (http://www.latex-project.org/lppl.txt) +% +% and the GNU Public License +% (http://www.gnu.org/licenses/gpl.txt) +% + +% This file defines utilities common to the \pgfmath files. +% +% Version 1.414213 29/9/2007 + +\def\pgfmathincluded{} + +% Helper macros for \pgfmath@ifregister +% +\def\pgfmath@grabv#1#2#3#4#5#6#7\pgfmath@grabv{#2#3#4#5\ifx#6!!\fi} +\def\pgfmath@ifskip@extract#1{\expandafter\pgfmath@grabv\meaning#1!!!!!!\pgfmath@grabv} +\def\pgfmath@iftoks@extract#1{\expandafter\pgfmath@grabv\meaning#1!!!!!!\pgfmath@grabv} + +\def\pgfmath@grabvi#1#2#3#4#5#6#7#8\pgfmath@grabvi{#2#3#4#5#6\ifx#7!!\fi} +\def\pgfmath@ifdimen@extract#1{\expandafter\pgfmath@grabvi\meaning#1!!!!!!\pgfmath@grabvi} +\def\pgfmath@ifcount@extract#1{\expandafter\pgfmath@grabvi\meaning#1!!!!!!\pgfmath@grabvi} + +\def\pgfmath@grabvii#1#2#3#4#5#6#7#8#9\pgfmath@grabvii{#2#3#4#5#6#7\ifx#8!!\fi} +\def\pgfmath@ifmuskip@extract#1{\expandafter\pgfmath@grabvii\meaning#1!!!!!!\pgfmath@grabvii} + +% \pgfmath@ifdimen@unguarded +% +% Check if #2 is a register of type #1. +% Credits to Frank: https://tex.stackexchange.com/a/56905 +% +% #1 register type (count, dimen, skip, muskip, toks) +% #2 single token +% +\def\pgfmath@ifregister@unguarded#1#2{% + \expandafter\ifx\csname\csname pgfmath@if#1@extract\endcsname{#2}\expandafter\endcsname\csname #1\endcsname + \expandafter\pgfutil@firstoftwo + \else + \expandafter\pgfutil@secondoftwo + \fi} + +% \pgfmath@ifregister +% +% Checks if a token is a a certain type of register +% +% #1 register type (count, dimen, skip, muskip, toks) +% #2 single token +% +\def\pgfmath@ifregister#1#2{% + \pgfutil@IfUndefined{pgfmath@if#1@extract}% + {\errmessage{Package PGF Math Error: Cannot test for #1 register}}% + {\pgfutil@IfUndefined{\csname pgfmath@if#1@extract\endcsname{#2}}% + {\pgfutil@secondoftwo}}% + {\pgfmath@ifregister@unguarded{#1}{#2}}} + +% \pgfmath@ensureregister +% +% Ensure a control sequence exists as a TeX count/dimen register. +% +% #1 - count or dimen. +% #2 - a control sequence. +% +\def\pgfmath@ensureregister#1#2{% + \pgfmath@ifregister{#1}{#2}% + {}% + {\csname new#1\endcsname#2}% +} + +% Check registers exist. If not, create them. +% +\pgfmath@ensureregister{dimen}{\pgf@x} +\pgfmath@ensureregister{dimen}{\pgf@xa} +\pgfmath@ensureregister{dimen}{\pgf@xb} +\pgfmath@ensureregister{dimen}{\pgf@xc} + +\pgfmath@ensureregister{dimen}{\pgf@y} +\pgfmath@ensureregister{dimen}{\pgf@ya} +\pgfmath@ensureregister{dimen}{\pgf@yb} +\pgfmath@ensureregister{dimen}{\pgf@yc} + +\pgfmath@ensureregister{dimen}{\pgfutil@tempdima} +\pgfmath@ensureregister{dimen}{\pgfutil@tempdimb} + +\pgfmath@ensureregister{count}{\c@pgf@counta} +\pgfmath@ensureregister{count}{\c@pgf@countb} +\pgfmath@ensureregister{count}{\c@pgf@countc} +\pgfmath@ensureregister{count}{\c@pgf@countd} + +\pgfmath@ensureregister{count}{\pgfutil@tempcnta} +\pgfmath@ensureregister{count}{\pgfutil@tempcntb} + +% Alias for \pgfmath. +% +\let\pgfmath@x\pgf@x +\let\pgfmath@xa\pgf@xa +\let\pgfmath@xb\pgf@xb +\let\pgfmath@xc\pgf@xc + +\let\pgfmath@y\pgf@y +\let\pgfmath@ya\pgf@ya +\let\pgfmath@yb\pgf@yb +\let\pgfmath@yc\pgf@yc + +\let\pgfmath@tempdima\pgfutil@tempdima +\let\pgfmath@tempdimb\pgfutil@tempdimb + +\let\c@pgfmath@counta\c@pgf@counta +\let\c@pgfmath@countb\c@pgf@countb +\let\c@pgfmath@countc\c@pgf@countc +\let\c@pgfmath@countd\c@pgf@countd + +\let\pgfmath@tempcnta\pgfutil@tempcnta +\let\pgfmath@tempcntb\pgfutil@tempcntb + +% Now check if pgfutil and pgf@sys stuff exists. If it does, fine. +% Just \let pgfmath versions. If not, define pgfmath versions (Arghhh). +% + +% \...ifnextchar +% +\ifx\pgfutil@ifnextchar\pgfmath@undefined% + \long\def\pgfmath@ifnextchar#1#2#3{% + \let\pgfmath@reserved@d#1% + \def\pgfmath@reserved@a{#2}% + \def\pgfmath@reserved@b{#3}% + \futurelet\pgfmath@let@token\pgfmath@ifnch} + \def\pgfmath@ifnch{% + \ifx\pgfmath@let@token\pgfmath@sptoken% + \let\pgfmath@reserved@c\pgfmath@xifnch% + \else% + \ifx\pgfmath@let@token\pgfmath@reserved@d% + \let\pgfmath@reserved@c\pgfmath@reserved@a% + \else% + \let\pgfmath@reserved@c\pgfmath@reserved@b% + \fi% + \fi% + \pgfmath@reserved@c} + {% + \def\:{\global\let\pgfmath@sptoken= } \: + \def\:{\pgfmath@xifnch} \expandafter\gdef\: {\futurelet\pgfmath@let@token\pgfmath@ifnch} + }% +\else% + \let\pgfmath@ifnextchar\pgfutil@ifnextchar% + % Still need to define \pgfmath@sptoken (cannot \let). + {% + \def\:{\global\let\pgfmath@sptoken= } \: + }% +\fi% + +% \...ifundefined +% +\ifx\pgfutil@ifundefined\pgfmath@undefined% + \long\def\pgfmath@ifundefined#1{% + \expandafter\ifx\csname#1\endcsname\relax% + \expandafter\pgfmath@firstoftwo% + \else% + \expandafter\pgfmath@secondoftwo% + \fi}% +\else% + \let\pgfmath@ifundefined\pgfutil@ifundefined% +\fi% + +% \...selectfont +% +\ifx\pgfutil@selectfont\pgfmath@undefined% + \ifx\selectfont\pgfmath@undefined% + \let\pgfmath@selectfont\rm% Plain TeX and ConTeXt. + \else% + \let\pgfmath@selectfont\selectfont% LaTeX. + \fi% +\else% + \let\pgfmath@selectfont\pgfutil@selectfont% +\fi% + +% New definition easier than fussing around with let. +% +\newif\ifpgfmath@in@ +\def\pgfmath@in@#1#2{% + \def\pgfmath@in@@##1#1##2##3\pgfmath@in@@{% + \ifx\pgfmath@in@##2\pgfmath@in@false\else\pgfmath@in@true\fi}% + \pgfmath@in@@#2#1\pgfmath@in@\pgfmath@in@@} + + +% \...tonumber +% +\ifx\pgf@sys@tonumber\pgfmath@undefined% + {\catcode`\p=12\catcode`\t=12\gdef\Pgf@geT#1pt{#1}} + \def\pgfmath@tonumber#1{\expandafter\Pgf@geT\the#1} +\else% + \let\pgfmath@tonumber\pgf@sys@tonumber% +\fi% + + +% \PackageWarning and \PackageError +% +\ifx\PackageWarning\pgfmath@undefined + \def\pgfmath@PackageWarning#1#2{\immediate\write-1{Package #1: Warning! #2.}}% +\else% + \let\pgfmath@PackageWarning\PackageWarning% +\fi% +\ifx\PackageError\pgfmath@undefined + \def\pgfmath@PackageError#1#2#3{\errmessage{Package #1 Error: #2.}}% +\else% + \let\pgfmath@PackageError\PackageError% +\fi% + +\def\pgfmath@error#1#2{% + \pgfmath@PackageError{PGF Math}{% + #1% + \pgfutil@ifundefined{pgfmath@expression}{}{ (in '\pgfmath@expression')}% + }{#2}% +} +\def\pgfmath@warning#1{% + \pgfmath@PackageWarning{PGF Math}{% + #1% + \pgfutil@ifundefined{pgfmath@expression}{}{ (in '\pgfmath@expression')}% + }% +} + +% \pgfmath@pt +% +% Needed to test for 'pt' resulting from expansion using \the. +% +{\catcode`\p=12\catcode`\t=12\gdef\PgfmaTh@PT{pt}} +\edef\pgfmath@pt{\PgfmaTh@PT}% + +% \pgfmath@empty +% +% A handy macro. +% +\def\pgfmath@empty{} + +\def\pgfmath@firstoftwo#1#2{#1} +\def\pgfmath@secondoftwo#1#2{#2} + +% \pgfmath@gobbletilpgfmath@ +% +% Gobble stream until \pgfmath@ {which is undefined}. +% +\def\pgfmath@gobbletilpgfmath@#1\pgfmath@{} +\def\pgfmath@gobbleone#1{}% + + +\def\pgfmath@namedef#1{\expandafter\def\csname#1\endcsname} +\def\pgfmath@nameedef#1{\expandafter\edef\csname#1\endcsname} + +% \pgfmathloop +% +% A version of the standard TeX and LaTeX +% \loop, with an additional macro \pgfmathcounter +% (which is *not* a TeX counter) which keeps +% track of the iterations. +% +\newif\ifpgfmathcontinueloop +\def\pgfmathloop#1\repeatpgfmathloop{% + \def\pgfmathcounter{1}% + \def\pgfmath@iterate{% + #1\relax% + {% Do this inside a group, just in case... + \c@pgfmath@counta\pgfmathcounter% + \advance\c@pgfmath@counta1\relax% + \xdef\pgfmathloop@temp{\the\c@pgfmath@counta}% + }% + \edef\pgfmathcounter{\pgfmathloop@temp}% + \expandafter\pgfmath@iterate\fi}% + \pgfmath@iterate\let\pgfmath@iterate\relax} +\let\repeatpgfmathloop\fi +\def\pgfmathbreakloop{\let\pgfmath@iterate\relax}% + +% \pgfmath@returnone +% +% #1 - a dimension representing a number or dimension. +% +% Changed by TT: made faster and simpler since it is used +% *heavily*. #1 must be something that can be assigned to a +% dimension. +% +\def\pgfmath@returnone#1\endgroup{% + \pgfmath@x#1% + \edef\pgfmath@temp{\pgfmath@tonumber{\pgfmath@x}}% + \expandafter\endgroup\expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmath@temp}% +} + +\let\pgfmathreturn=\pgfmath@returnone + +% \pgfmath@smuggleone +% +% Smuggle a macro outside a group. +% +% Changed by TT: Speedup by insisting, that smuggleone is directly +% followed by \endgroup +% +\def\pgfmath@smuggleone#1\endgroup{% + \expandafter\endgroup\expandafter\def\expandafter#1\expandafter{#1}} + +\let\pgfmathsmuggle=\pgfmath@smuggleone diff --git a/graphics/pgf/base/tex/generic/modules/pgfmoduleanimations.code.tex b/graphics/pgf/base/tex/generic/modules/pgfmoduleanimations.code.tex new file mode 100644 index 0000000000..c0a8346811 --- /dev/null +++ b/graphics/pgf/base/tex/generic/modules/pgfmoduleanimations.code.tex @@ -0,0 +1,1314 @@ +% Copyright 2019 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgfmoduleanimations.code.tex} + + +% We need the animation system abstraction: + +\input pgfsysanimations.code.tex + + +% Animate an attribute over time +% +% #1 = an attribute +% #2 = configuration keys +% +% This command adds animation commands for the attribute given in #1 +% of some future object to the current graphic scope. For instance, +% when #1 is "fill opacity" then the fill opacity of the object will +% change over time. The object to which the command refers is +% specified using a special key in #2. +% +% The keys in #2 specify how the changes occur over time. There are a +% number of keys that have an effect on the animation "as a whole" +% (like "repeats") while the most central key is the entry key. This +% key takes two parameters: a time and a value. It specifies that at +% the given time the attribute should have the specified value. The +% times must be given in ascending order. Between the times given in +% this way, the values of the attribute will be interpolated; you can +% influence the details of how this interpolation is done using +% additional keys. +% +% The keys in #2 are given in key-value syntax and can be given in any +% order, except that the entry keys must be given in order of +% ascending times. +% +% The syntax of the second parameter of the entry key depends on +% #1. Currently, these are: +% +% Attribute Value Type +% --------------------------------------- +% fill opacity scalar +% stroke opacity scalar +% opacity scalar +% visible boolean +% line width dimension +% fill color +% stroke color +% motion motion +% translate point +% scale scaling +% rotate scalar +% xskew scalar +% yskew scalar +% path path +% softpath softpath +% view viewbox +% dash phase dimension +% dash pattern dashpattern +% none any +% +% Example: +% +% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={2s}{0}} + +\def\pgfanimateattribute#1#2{% + \pgfanimateattributecode{#1}{\pgfkeys{/pgf/animation/.cd,#2}}% +}% + + +% Variant of \pgfanimateattribute +% +% #1 = attribute +% #2 = code +% +% Description: +% +% A version of \pgfanimateattribute where instead of keys #2 you +% provide a code #2 that calls the animation keys itself. + +\def\pgfanimateattributecode#1#2{% + {% + \pgfkeys{/pgf/@animation attributes/.cd,#1}% + #2% + \csname pgf@animation@check@\pgf@animation@attribute\endcsname% + \pgfsysanimate{\pgf@animation@attribute}% + }% +}% + + + +% Create a time snapshot +% +% #1 = a time +% +% Description: +% +% This command should be called in a scope prior to all calls of +% animation commands in that scope. When called, all animations will +% be "intercepted" and, instead of creating the animation code, normal +% code will be generated that shows the state of the animation at the +% specified "moment" #1. Since no animation code is involved, this +% works with all drivers. +% +% The command \pgfsnapshotafter works the same way as \pgfsnapshot, +% only the timing is slightly different: Conceptually, #1 is +% interpreted as "#1+epsilon". For instance, if there are two values +% specified for the time #1, then \pgfsnapshot will use the first +% while \pgfsnapshotafter will use the second. Likewise, when an +% animation ends at time #1, \pgfsnapshot will still us the +% animation's value, while \pgfsnapshotafter will not. +% +% Example: +% +% { +% \pgfsnapshot{1.2s} +% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={2s}{0}} +% \fill (0,0) rectangle (1,1); +% } + +\def\pgfsnapshot#1{\pgfparsetime{#1}\expandafter\pgfsysanimsnapshot\expandafter{\pgftimeresult}}% +\def\pgfsnapshotafter#1{\pgfparsetime{#1}\expandafter\pgfsysanimsnapshotafter\expandafter{\pgftimeresult}}% + + +% The animation attributes + +\pgfkeys{/pgf/@animation attributes/.cd, + visible/.code=\pgf@animate@attr{visibility}{mapped}\def\pgf@anim@map@true{visible}\def\pgf@anim@map@false{hidden}, + stage/.code=\pgf@animate@attr{visibility}{mapped}\def\pgf@anim@map@true{visible}\def\pgf@anim@map@false{hidden}\pgfsysanimkeybase\pgfsysanimvaltext{hidden}, + opacity/.code=\pgf@animate@attr{opacity}{scalar}, + fill opacity/.code=\pgf@animate@attr{fillopacity}{scalar}, + draw opacity/.code=\pgf@animate@attr{strokeopacity}{scalar}, + stroke opacity/.style=draw opacity, + line width/.code=\pgf@animate@attr{linewidth}{dimension}, + fill/.code=\pgf@animate@attr{fillcolor}{color}, + draw/.code=\pgf@animate@attr{strokecolor}{color}, + color/.code=\pgf@animate@attr{color}{color}, + stroke/.style=draw, + motion/.code=\pgf@animate@attr{motion}{scalar}, + translate/.code=\pgf@animate@attr{translate}{point}, + scale/.code=\pgf@animate@attr{scale}{scaling}, + rotate/.code=\pgf@animate@attr{rotate}{scalar}, + xskew/.code=\pgf@animate@attr{skewx}{scalar}, + yskew/.code=\pgf@animate@attr{skewy}{scalar}, + skew x/.style=xskew, + skew y/.style=yskew, + path/.code=\pgf@animate@attr{path}{path}, + softpath/.code=\pgf@animate@attr{path}{softpath}, + view/.code=\pgf@animate@attr{viewbox}{viewbox}, + dash/.code=\pgf@animate@attr{dash}{dash}, + none/.code=\pgf@animate@attr{none}{none}, +}% + +\def\pgf@animate@attr#1#2{% + \def\pgf@animation@attribute{#1}% + \expandafter\let\expandafter\pgfanim@type@parser\csname pgfanim@parse@type@#2\endcsname% +}% + + + +% The time parser +% +% #1 = a time +% +% This macro parses the time in #1, but adds some support for times: +% +% 1) The postfix operator "s" is added, which has no effect. +% 2) The postfix operator "ms" is added, which divides a number by +% 1000, so "2ms" equals "0.002". +% 3) The postfix operator "min" is added, which multiplies a number by +% 60. +% 4) The postfix operator "h" is added, which multiplies a number by +% 3600. +% 5) The infix operator ":" is redefined, so that it multiplies its +% first argument by 60 and adds the second. This implies that +% "1:20" equals "80" and "01:00:00" equals "3600". +% 6) The parsing of octal numbers is switched off to allow things like +% "01:08" for 68s. + +\def\pgfparsetime#1{% + \begingroup% + \pgfmathdeclareoperator{s}{@seconds}{1}{postfix}{600}% + \pgfmathdeclareoperator{m}{m@encountered}{1}{postfix}{600}% + \pgfmathdeclareoperator{i}{i@encountered}{1}{postfix}{600}% + \pgfmathdeclareoperator{n}{@minutes}{1}{postfix}{600}% + \pgfmathdeclareoperator{h}{@hours}{1}{postfix}{600}% + \pgfmathdeclareoperator{:}{time@colon}{2}{infix}{50}% + \pgfmath@octalparsingfalse% + \pgfmathparse{#1}% + \expandafter\endgroup% + \expandafter\def\expandafter\pgftimeresult\expandafter{\pgfmathresult}% +}% + +\newif\ifpgfanim@m@encountered +\newif\ifpgfanim@i@encountered +\pgfmathdeclarefunction{@seconds}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \ifpgfanim@m@encountered% + \divide\pgfmath@x by1000\relax% + \fi% + \global\pgfanim@m@encounteredfalse% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% +\pgfmathdeclarefunction{m@encountered}{1}{% + \global\pgfanim@m@encounteredtrue% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% +\pgfmathdeclarefunction{i@encountered}{1}{% + \ifpgfanim@m@encountered% + \global\pgfanim@m@encounteredfalse% + \global\pgfanim@i@encounteredtrue% + \else% + \pgfmath@error{Unexpected i}{}% + \fi% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% +\pgfmathdeclarefunction{@minutes}{1}{% + \ifpgfanim@i@encountered% + \global\pgfanim@i@encounteredfalse% + \else% + \pgfmath@error{Unexpected n}{}% + \fi% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@x60\pgfmath@x\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% +\pgfmathdeclarefunction{@hours}{1}{% + \begingroup% + \expandafter\pgfmath@x#1pt\relax% + \pgfmath@x3600\pgfmath@x\relax% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% +\pgfmathdeclarefunction{time@colon}{2}{% + \begingroup% + \pgfmath@x=#1pt\relax% + \pgfmath@x=60\pgfmath@x\relax% + \pgfmath@y=#2pt\relax% + \advance\pgfmath@x by\pgfmath@y% + \pgfmath@returnone\pgfmath@x% + \endgroup% +}% + + + +% Sets general animation attributes +% +% #1 = key-value pairs that are executed for the path /pgf/animation/ + +\def\pgfanimationset{\pgfqkeys{/pgf/animation}}% + + +% Sets the target animation scope that should be animated. +% +% #1 = A name that will be used with an idscope. +% +% Example: +% +% \pgfanimateattribute{fill opacity}{whom=some scope, entry={0s}{1}, entry={1s}{0}} +% \begin{scope}[name=some scope] +% \draw (0,0) -- (1,1); +% \draw (1,0) -- (2,1); +% \end{scope} + +\pgfanimationset{ + whom/.code={% + \pgf@anim@decomp{#1}% + \pgfidrefnextuse\pgf@anim@id\pgf@anim@id@name% + \expandafter\expandafter\expandafter\pgfsysanimkeywhom\expandafter\expandafter\expandafter{\expandafter\pgf@anim@id\expandafter}\expandafter{\pgf@anim@type}% + \let\pgf@anim@whom@id\pgf@anim@id% + \let\pgf@anim@whom@type\pgf@anim@type% + } +}% + +\def\pgf@anim@decomp#1{% + \edef\pgf@temp{#1}% + \expandafter\pgfutil@in@\expandafter.\expandafter{\pgf@temp}% + \ifpgfutil@in@% + \expandafter\pgf@anim@decomp@\pgf@temp\pgf@stop% + \else% + \expandafter\pgf@anim@decomp@\pgf@temp.\pgf@stop% + \fi% +}% +\def\pgf@anim@decomp@#1.#2\pgf@stop{% + \def\pgf@anim@id@name{#1}% + \def\pgf@anim@type{#2}% +}% + + +% Assigns a name to this animation so that it can be used as an event +% id in another animation +% +% #1 = A name +% +% The name "previous" is special and always refers to the most recent +% animation before the animation currently being constructed. +% +% Example: +% +% \pgfanimateattribute{fill opacity}{name=anim 1, entry={0s}{1}, entry={1s}{0}} +% \pgfanimateattribute{fill opacity}{begin on={end,of=anim 1}, entry={0s}{1}, entry={1s}{0}} + +\pgfanimationset{ + name/.code=\pgfuseid{#1}, +}% + + + + +% Configures whether an animation can be restarted +% +% Some animations can restart when certain events take place. This key +% configures this. Setting it to +% +% "true" allows a restart at any time, +% "false" does not allow a restart, +% "when not active" allows a restart only, when the element is not +% active. +% +% Example: +% +% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={1s}{0}, restart=false} + +\pgfanimationset{ + restart/.is choice, + restart/.default=true, + restart/true/.code=\pgfsysanimkeyrestartalways, + restart/false/.code=\pgfsysanimkeyrestartnever, + restart/never/.code=\pgfsysanimkeyrestartnever, + restart/when not active/.code=\pgfsysanimkeyrestartwhennotactive, +}% + + +% Sets the number times an animation should repeat +% +% #1 = A string of the following form: +% +% [ | | for