texlive[73087] Master: luatikz (9dec24)

commits+karl at tug.org commits+karl at tug.org
Mon Dec 9 22:18:16 CET 2024


Revision: 73087
          https://tug.org/svn/texlive?view=revision&revision=73087
Author:   karl
Date:     2024-12-09 22:18:16 +0100 (Mon, 09 Dec 2024)
Log Message:
-----------
luatikz (9dec24)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/libexec/ctan2tds
    trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/luatikz/
    trunk/Master/texmf-dist/doc/latex/luatikz/README.txt
    trunk/Master/texmf-dist/doc/latex/luatikz/example/
    trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier2.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3a.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3b.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/blinea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/circle.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/curvea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/curveb.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipse.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipseArc.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/immute1.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/immute2.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/intro.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/linea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/lineb.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/linec.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/lined.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/nodea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/nodeb.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/plota.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/polylinea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/radon1.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/recta.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/shadea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/sierpinski.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/spiral.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/stylea.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/example/superEllipse.lua
    trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf
    trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.tex
    trunk/Master/texmf-dist/tex/latex/luatikz/
    trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.lua
    trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.sty
    trunk/Master/tlpkg/tlpsrc/luatikz.tlpsrc

Added: trunk/Master/texmf-dist/doc/latex/luatikz/README.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/README.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/README.txt	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,9 @@
+-----------------
+Luatikz is a graphics library to draw tikz graphics
+using the Lua programming language.
+-----------------
+
+License:
+
+LaTeX Project Public License 1.3c
+MIT License (expat)


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/README.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier2.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier2.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier2.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,11 @@
+tikz.within( '*' )
+
+local bz =
+	bezier2{
+		p1 = p{ 0, 0 },
+		pc = p{ 2, 2 },
+		p2 = p{ 4, 0 },
+	}
+
+draw{ line_width=1, bz }
+bz.drawHelpers( 'p' )


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier2.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3a.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3a.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3a.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,12 @@
+tikz.within( '*' )
+
+local bz =
+	bezier3{
+		p1  = p{ 0, 0 },
+		pc1 = p{ 1, 2 },
+		pc2 = p{ 3, 3 },
+		p2  = p{ 4, 0 },
+	}
+
+draw{ line_width=1, bz }
+bz.drawHelpers( 'p' )


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3a.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3b.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3b.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3b.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,32 @@
+tikz.within( '*' )
+
+local bz =
+	bezier3{
+		p1  = p{ 0, 0 },
+		pc1 = p{ 1, 2 },
+		pc2 = p{ 3, 3 },
+		p2  = p{ 4, 0 },
+	}
+
+draw{ line_width = 1, bz }
+
+for t = 0, 1, 0.1
+do
+	local pt = bz.pt( t )
+	draw{
+		fill = black,
+		circle{
+			at = pt,
+			radius = 0.05,
+		}
+	}
+
+	local phit = bz.phit( t ) + math.pi / 2
+	draw{
+		line{
+			p1 = pt,
+			phi = phit,
+			length = 1,
+		}
+	}
+end


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/bezier3b.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/blinea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/blinea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/blinea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,23 @@
+tikz.within( '*' )
+
+local l1 = bline{ p{ 0, 0 }, p{ 2, 3 }, bend_right = 45 }
+local l2 = bline{ p{ 0, 3 }, p{ 2, 1 }, bend_left  = 30 }
+
+draw{ draw=red,  l1 }
+draw{ draw=blue, l2 }
+put{
+	node{
+		at = l1.pc,
+		anchor = south,
+		rotate = l1.line.phi * 180 / math.pi,
+		text = 'red',
+	}
+}
+put{
+	node{
+		at = l2.pc,
+		anchor = south,
+		rotate = l2.line.phi * 180 / math.pi,
+		text = 'blue',
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/blinea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/circle.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/circle.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/circle.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,12 @@
+tikz.within( '*' )
+
+draw{
+	circle{
+		at = p{ 0, 0 },
+		radius = 2,
+	},
+	circle{
+		at = p{ 2, 1 },
+		radius = 1,
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/circle.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/curvea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/curvea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/curvea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,14 @@
+tikz.within( '*' )
+
+local c =
+	curve{
+		points =
+		{
+			p{ 0, 0 },
+			p{ 2, 2 },
+			p{ 4, 0 },
+		},
+	}
+
+draw{ line_width=1, c }
+c.drawHelpers( 'p' )


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/curvea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/curveb.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/curveb.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/curveb.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,16 @@
+tikz.within( '*' )
+
+local c =
+	curve{
+		points =
+		{
+			p{ 0, 0 },
+			p{ 2, 2 },
+			p{ 4, 0 },
+		},
+		cycle = true,
+		tension = 1.0,
+	}
+
+draw{ line_width=1, c }
+c.drawHelpers( 'p' )


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/curveb.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipse.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipse.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipse.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,14 @@
+tikz.within( '*' )
+
+draw{
+	ellipse{
+		at = p{ 0, 0 },
+		xradius = 3,
+		yradius = 2,
+	},
+	ellipse{
+		at = p{ 2, 1 },
+		xradius = 1.5,
+		yradius = 1,
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipse.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipseArc.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipseArc.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipseArc.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,18 @@
+tikz.within( '*' )
+
+draw{
+	ellipseArc{
+		at = p{ 0, 0 },
+		from = 0,
+		to = 90,
+		xradius = 3,
+		yradius = 2,
+	},
+	ellipseArc{
+		at = p{ 2, 1 },
+		xradius = 1.5,
+		yradius = 1,
+		from = -45,
+		to = 45,
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/ellipseArc.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/immute1.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/immute1.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/immute1.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,4 @@
+tikz.within( '*' )
+
+local p1 = p{ 1, 1 }
+p1.x = p1.x + 2


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/immute1.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/immute2.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/immute2.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/immute2.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,6 @@
+tikz.within( '*' )
+
+local p1 = p{ 1, 1 }
+p1 = p{ p1.x + 2, p1.y }
+-- or
+p1 = p1 + p{ 2, 0 }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/immute2.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/intro.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/intro.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/intro.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,8 @@
+tikz.within( '*' )
+
+local p1 = p{ 1, 1 }
+local p2 = p{ 6, 2 }
+local l1 = line{ p1, p2 }
+
+draw{ l1 }
+draw{ line{ p{ 2, 2 }, p{ 3, 3 } } }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/intro.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/linea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/linea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/linea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,7 @@
+tikz.within( '*' )
+
+local l1 = line{ p{ 0, 0 }, p{ 2, 3 } }
+local l2 = line{ p1 = p{ 0, 3 }, p2 = p{ 2, 1 } }
+
+draw{ l1 }
+draw{ l2 }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/linea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/lineb.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/lineb.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/lineb.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,9 @@
+tikz.within( '*' )
+
+local l1 = line{ p{ 0, 0 }, p{ 2, 3 } }
+local l2 = line{ p1 = p{ 0, 3 }, p2 = p{ 2, 1 } }
+local pi = l1.intersectLine( l2 )
+
+draw{ l1 }
+draw{ l2 }
+draw{ circle{ at = pi, radius = 0.1 } }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/lineb.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/linec.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/linec.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/linec.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,7 @@
+tikz.within( '*' )
+
+draw{ line{
+	p1  = p{ 0, 0 },
+	phi = -math.pi / 4,
+	length = 2,
+} }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/linec.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/lined.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/lined.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/lined.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,15 @@
+tikz.within( '*' )
+
+local l = line{ p{ 0, 0 }, p{ 5, 0 } }
+draw{ l }
+
+for i = 1, 10
+do
+	l =
+		line{
+			p1     = l.p2,
+			phi    = l.phi + math.pi / 5,
+			length = l.length * 2 / 3,
+		}
+	draw{ l }
+end


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/lined.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/nodea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/nodea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/nodea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,12 @@
+tikz.within( '*' )
+
+put{
+	node{
+		at = p{ 0, 0 },
+		text = [[$a^2 + b^2 = c^2$]],
+	},
+	node{
+		at = p{ 2, 1 },
+		text = [[$sin(\phi) = \frac{b}{a}$]],
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/nodea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/nodeb.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/nodeb.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/nodeb.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,18 @@
+tikz.within( '*' )
+
+local r1 =
+	rect{
+		pc   = p{ 0, 0 },
+		size = p{ 3, 3 },
+	}
+
+draw{ r1 }
+
+put{
+	node{
+		at = r1.pc,
+		text = [[this is the center of a rect]],
+		text_width = '2cm',
+		rotate = 45,
+	},
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/nodeb.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/plota.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/plota.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/plota.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,14 @@
+tikz.within( '*' )
+
+draw{
+	plot{
+		at   = p{ 0, 0 },
+		from = 0,
+		to   = 5,
+		step = 0.05,
+		func =
+			function( d )
+				return p{ d, math.pow( d - 2.5, 2 ) / 2 }
+			end
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/plota.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/polylinea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/polylinea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/polylinea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,11 @@
+tikz.within( '*' )
+
+draw{
+	polyline{
+		p{ 0, 0 },
+		p{ 2, 2 },
+		p{ 4, 0 },
+		p{ 3, -1 },
+		'cycle',
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/polylinea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/radon1.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/radon1.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/radon1.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,119 @@
+tikz.within( '*' )
+
+local cos = math.cos
+local sin = math.sin
+local pi  = math.pi
+
+-- granularity of calculation
+local fine = 10
+
+-- factor the projection length is reduced
+local fproj = 0.35
+
+-- strength of the ellipse mediums
+local s1 = 1.00
+local s2 = 1.50
+local s3 = 1.75
+
+local e1 = ellipse{ at=p{ 0.00,  0.00 }, xradius=3.00, yradius=3.00 }
+local e2 = ellipse{ at=p{ 0.40,  1.20 }, xradius=0.85, yradius=0.50 }
+local e3 = ellipse{ at=p{ 0.00, -0.89 }, xradius=1.00, yradius=0.60 }
+
+draw{ fill='black!08!white', line_width=1, e1 }
+draw{ fill='black!16!white', line_width=1, e2 }
+draw{ fill='black!24!white', line_width=1, e3 }
+
+-- list of projection angles
+local listphi =
+{
+	-1/4 * pi,
+	 2/4 * pi,
+	 5/4 * pi,
+}
+
+-- length of projection lines
+local lenmaintop = 5.0
+local lenmainbot = 6.5
+
+for proji, phimain in ipairs( listphi )
+do
+	local lmain =
+		line{
+			p{ cos( phimain ), sin( phimain ) } * -lenmaintop,
+			p{ cos( phimain ), sin( phimain ) } *  lenmainbot,
+		}
+	local phinorm = phimain - pi/2
+
+	-- gets a point on the projection.
+	-- dp: distance from projection center
+	-- dv: projection value
+	function getpproj( dp, dv )
+		return(
+			lmain.p2
+			+ p{ cos( phinorm ) * dp,         sin( phinorm ) * dp         }
+			+ p{ cos( phimain ) * dv * fproj, sin( phimain ) * dv * fproj }
+		)
+	end
+
+	-- distance of projection line
+	local ddis = 1 / fine
+
+	-- list of all projection points
+	local listp = { }
+
+	for i = -3.5 * fine, 3.5 * fine
+	do
+		local p1i =
+			lmain.p1
+			+ p{ cos( phinorm ) * ddis * i, sin( phinorm ) * ddis * i }
+		local li = line{ p1i, p1i + ( lmain.p2 - lmain.p1 ) }
+		local lv = 0
+		local is1 = e1.intersectLine( li )
+
+		if is1 and #is1 > 1
+		then
+			local lis = line{ is1[ 1 ], is1[ 2 ] }
+			lv = lv + lis.length * s1
+		end
+
+		local is2 = e2.intersectLine( li )
+		if is2 and #is2 > 1
+		then
+			local lis = line{ is2[ 1 ], is2[ 2 ] }
+			lv = lv + lis.length * s2
+		end
+
+		local is3 = e3.intersectLine( li )
+		if is3 and #is3 > 1
+		then
+			local lis = line{ is3[ 1 ], is3[ 2 ] }
+			lv = lv + lis.length * s3
+		end
+
+		local pproj = getpproj( ddis * i, lv    )
+		if i % ( 0.7 * fine ) == 0
+		then
+			draw{
+				dotted, arrow, line_width=0.5,
+				line{ li.p1, getpproj( ddis * i, -0.20 ) },
+			}
+			draw{
+				dotted, line_width=0.5,
+				line{ li.p1, pproj },
+			}
+		end
+		table.insert( listp, pproj )
+	end
+
+	-- draws the projection screen
+	local lenlproj = 8
+	draw{
+		line{
+			getpproj(  lenlproj / 2, 0 ),
+			getpproj( -lenlproj / 2, 0 ),
+		}
+	}
+
+	-- draws the projection curve
+	draw{ line_width=1, polyline{ table.unpack( listp ) } }
+end


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/radon1.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/recta.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/recta.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/recta.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,21 @@
+tikz.within( '*' )
+
+local r1 =
+	rect{
+		pnw = p{ 0, 3 },
+		pse = p{ 3, 0 },
+	}
+
+local r2 =
+	rect{
+		psw  = r1.pse,
+		size = p{ 1, 1 },
+	}
+
+local r3 =
+	rect{
+		pc   = r1.pc,
+		size = p{ 1.5, 1.5 },
+	}
+
+draw{ r1, r2, r3 }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/recta.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/shadea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/shadea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/shadea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,9 @@
+tikz.within( '*' )
+
+shade{
+	ball_color = gray,
+	circle{
+		at = p0,
+		radius = 2,
+	},
+}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/shadea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/sierpinski.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/sierpinski.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/sierpinski.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,41 @@
+tikz.within( '*' )
+
+local s60 = math.sin( 60 / 180 * math.pi )
+local c60 = math.cos( 60 / 180 * math.pi )
+
+-- creates a table object having ptop, pleft and pright as points
+-- and a "draw yourself" function
+function equilateralTriangle( ptop, len )
+	return {
+		ptop   = ptop,
+		pleft  = ptop + p{ -len/2, -len*s60 },
+		pright = ptop + p{  len/2, -len*s60 },
+		draw =
+		function( self )
+			draw{
+				fill = black,
+				draw = none,
+				polyline{ self.ptop, self.pleft, self.pright, 'cycle' }
+			}
+		end
+	}
+end
+
+-- one step into the fractal
+-- ptop:  top point of triangle
+-- len:   current length
+-- level: current fractal level
+function drawFractal( ptop, len, level )
+	if level == 1
+	then
+		local t = equilateralTriangle( ptop, len )
+		t:draw( )
+	else
+		local ttop   = equilateralTriangle( ptop, len / 2 )
+		drawFractal( ttop.ptop,   len / 2, level - 1 )
+		drawFractal( ttop.pleft,  len / 2, level - 1 )
+		drawFractal( ttop.pright, len / 2, level - 1 )
+	end
+end
+
+drawFractal( p{ 0, 0 }, 8, 6 )


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/sierpinski.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/spiral.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/spiral.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/spiral.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,16 @@
+tikz.within( '*' )
+
+local pi  = p{ 0,    0    }
+local pdx = p{ 0.25, 0    }
+local pdy = p{ 0,    0.25 }
+
+for k = 1, 20
+do
+	local sign = 1
+	if k % 2 == 0 then sign = -1 end
+	local pn  = pi + sign * k * pdx
+	local pn2 = pn + sign * k * pdy
+	draw{ line{ pi, pn }, line{ pn, pn2 } }
+	pi = pn2
+end
+


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/spiral.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/stylea.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/stylea.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/stylea.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,19 @@
+tikz.within( '*' )
+
+local l1 = line{ p{ 0,  0 }, p{ 3,  1 } }
+local l2 = line{ p{ 0, -1 }, p{ 3,  0 } }
+local l3 = line{ p{ 0, -2 }, p{ 3, -1 } }
+
+draw{ arrow, l1 }
+draw{ double_arrow, dashed, l2 }
+draw{ color = purple, line_width = 2, dotted, l3 }
+
+put{ node{
+	at = l3.pc,
+	anchor = center,
+	align = center,
+	color = purple,
+	rotate = l3.phi * 180 / math.pi,
+	text = 'label for purple line',
+	text_width = '2cm',
+} }


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/stylea.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/example/superEllipse.lua
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/example/superEllipse.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/example/superEllipse.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,22 @@
+tikz.within( '*' )
+
+local list = { 1, 1.5, 2, 4, 999 }
+
+for i, v in ipairs( list )
+do
+	local pi = p{ ( i - 1 ) * 2.5, 0 }
+	draw{
+		superEllipse{
+			at = pi,
+			n = v,
+			xradius = 1,
+			yradius = 1,
+		}
+	}
+	put{
+		node{
+			at = pi,
+			text = 'n = ' .. v,
+		}
+	}
+end


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/example/superEllipse.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf	2024-12-09 21:14:59 UTC (rev 73086)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf	2024-12-09 21:18:16 UTC (rev 73087)

Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.tex	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,204 @@
+\documentclass[a4paper,11pt]{ltxdoc}
+
+\usepackage[utf8]{inputenc}
+\usepackage{makeidx}\makeindex
+\usepackage{luatextra}
+\usepackage[margin=1in]{geometry}
+
+\usepackage{fancyvrb}
+\fvset{frame=single,numbers=left,numbersep=3pt,tabsize=4}
+
+\usepackage{tikz}
+\usetikzlibrary{math,backgrounds,calc,intersections,arrows.meta,external,decorations.pathreplacing,shadings}
+\directlua{dofile('./luatikz.lua')}
+
+\newcommand{\example}[2]
+{
+\par#2
+\VerbatimInput{example/#1.lua}
+{\centering
+\begin{tikzpicture}[framed,scale=1]
+\directlua{dofile('example/#1.lua')tikz.without()}
+\end{tikzpicture}\par}
+}
+
+\newcommand{\examplecode}[2]
+{
+\bigskip\par\noindent #2
+\VerbatimInput{example/#1.lua}
+}
+
+
+\title{luatikz}
+\author{Axel Kittenberger}
+\def\version{2.12.0}
+\date{luatikz version \version}
+
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{1ex}
+
+\begin{document}
+
+\maketitle
+
+\section{Introduction}
+Luatikz is a graphics library to draw tikz graphics using the Lua programming language.
+
+\example{intro}
+{Following code draws two lines by specifying begin and end points. First using intermediatery variables and the second line within a single codeline:}
+
+Following \TeX{} wrapper can be used to compile the luatikz Lua code.
+\VerbatimInput{example/wrapper.tex}
+
+Luatikz obviously needs \LuaLaTeX{} to compile.
+
+Note that 2D graphics is a vast topic, functionality to luatikz has been and will be added on a per need basis.
+
+\section{Pointer math}
+
+Mathematical operations are possible with points, adding them with each other or multiplying them with a scalar.
+\example{spiral}{This example uses pointer math to create a spiral:}
+
+\newpage
+\section{Immutability}
+
+In luatikz pointers like all objects are immutable. That means a object once created in memory can no longer be changed.
+However the variable holding an object can be changed to another object with different attributes.
+
+\examplecode{immute1}{Thus following example is invalid:}
+\examplecode{immute2}{This on the other hand are two valid methods to change the value of p1}
+
+\newpage
+\section{luatikz objects}
+
+\subsection{Bezier (quatratic)}
+\example{bezier2}{A quadratic bezier curve is defined by it begin, end and a control point:}
+
+\newpage
+\subsection{Bezier (cubic)}
+\example{bezier3a}{A cubic bezier curve is defined by it begin, end and two control points:}
+
+\newpage
+A cubic bezier has the functions pt and phit that return the point and angle ranging from 0..1 on the curve.
+\example{bezier3b}{This example draw 10 normal lines onto the bezier curve:}
+
+\newpage
+\subsection{BLine}
+\example{blinea}{A bline is defined by it's begin and it's end. Additionally to the standard line it is bend}
+
+\newpage
+\subsection{Circle}
+\example{circle}{A circle is defined by it's center (``at'') and the circle ``radius'':}
+
+\newpage
+\subsection{Curve}
+\example{curvea}{A curve is defined by a list of points:}
+
+\newpage
+\example{curveb}{A curve can cycle and has a changeable tension:}
+
+\newpage
+\subsection{Ellipse}
+\example{ellipse}{An ellipse is difined by it's center (``at'') and a x- and yradius:}
+
+\newpage
+\subsection{EllipseArc}
+\example{ellipseArc}{An ellipse arc is a an ellipse limited by it's ``from'' and ``to'' angle:}
+
+\newpage
+\subsection{Line}
+\example{linea}{A line is defined by it's begin and it's end. There are two basic variants to define a line:}
+
+\example{lineb}{You can use intersectLine() to find the intersection of a line with another. If there is none ``nil'' will be returned:}
+
+\newpage
+\example{linec}{A line can also be defined by it's starting point, angle and length:}
+
+\example{lined}{``length'' and ``phi'' are attributes of a line:}
+
+\newpage
+\subsection{Plot}
+\example{plota}{A plot uses a function to determine a series of points on a curve. It takes values going ``from''--``to''. The function is to be a lua function that takes the input scalar and returns a point. The whole curve is offset ``at'' a point:}
+
+%\newpage
+%\subsection{SuperEllipse}
+%\example{superEllipse}{A ``super'' ellipse is just as an ellipse, but additionally has a strength factor ``n'' that ranges from diamond, to ellipse to rectangle:}
+
+\newpage
+\subsection{Polyline}
+\example{polylinea}{A polyline is a list of points to be connected via straight lines. If the string ``cycle'' is given at the end, it cycles:}
+
+\newpage
+\subsection{Rect}
+\example{recta}{Rectangles have various creation options. Also they provide a wide range of attributes of their points ``pnw'', ``pne'',  ``psw'', ``pse'', ``pn'', ``pe'', ``ps'', ``pw'', ``pc'', ``height'', and ``width'':
+}
+
+\newpage
+\section{Labels a.k.a Nodes}
+
+Labels are created as nodes. Contrary to all other objects they do not need the ``draw'' command to be printed, but the ``put'' command. This is due any call to ``draw'' is turned into exactly one ``draw'' command to tikz and nodes in tikz are not using the ``draw'' command.
+
+\example{nodea}{In it's simplest form a node is specified by it's position and text. The double square brackets are Lua's way to make string constants that may contain simple blackslashes:}
+
+All constructors options of node are as follows; they correspond to the standard tikz options:
+\begin{itemize}
+	\item above
+	\item anchor
+	\item align
+	\item at
+	\item below
+	\item color
+	\item draw
+	\item left
+	\item minimum\_height
+	\item node\_distance
+	\item name
+	\item right
+	\item rotate
+	\item text
+	\item text\_width
+\end{itemize}
+\newpage
+
+\example{nodeb}{Another node example}
+
+\newpage
+\section{Styling}
+
+Styling is applied to draw commands by specifying style options, luatikz autodetects the difference between objects and styles.
+
+\example{stylea}{An example using arrows and dashes}
+
+\newpage
+\section{Shades}
+
+The ``shade'' command works analogous to classical tikz.
+
+\example{shadea}{For example a ball:}
+
+Recognized shade options are:
+\begin{itemize}
+	\item ball\_color
+	\item left\_color
+	\item lower\_left\_color
+	\item lower\_right\_color
+	\item opacity
+	\item right\_color
+	\item shading
+	\item upper\_left\_color
+	\item upper\_right\_color
+\end{itemize}
+
+\newpage
+\section{Some larger examples}
+
+\subsection{A radon projection}
+\example{radon1}{A radon projection, calculating correct projection curves:}
+
+\newpage
+\subsection{A sierpiński fractal}
+\example{sierpinski}{A sierpiński fractal. This one creates own temporary lua objects:}
+
+\printindex
+
+\end{document}


Property changes on: trunk/Master/texmf-dist/doc/latex/luatikz/luatikz.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.lua
===================================================================
--- trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.lua	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,1999 @@
+local _version = '2.12.0'
+
+if tikz
+then
+	if tikz.version ~= _version
+	then
+		error( 'version chaos' )
+	end
+	return
+end
+
+tikz = { version = _version }
+
+--==========================================================================--
+-- DEFINES
+--==========================================================================--
+
+-- directions
+tikz.north      = 'north'
+tikz.north_east = 'north east'
+tikz.east       = 'east'
+tikz.south_east = 'south east'
+tikz.south      = 'south'
+tikz.south_west = 'south west'
+tikz.west       = 'west'
+tikz.north_west = 'north west'
+
+-- colors
+tikz.black     = 'black'
+tikz.blue      = 'blue'
+tikz.brown     = 'brown'
+tikz.cyan      = 'cyan'
+tikz.darkgray  = 'darkgray'
+tikz.gray      = 'gray'
+tikz.green     = 'green'
+tikz.lightgray = 'lightgray'
+tikz.lime      = 'lime'
+tikz.magenta   = 'magenta'
+tikz.olive     = 'olive'
+tikz.orange    = 'orange'
+tikz.pink      = 'pink'
+tikz.purple    = 'purple'
+tikz.red       = 'red'
+tikz.teal      = 'teal'
+tikz.violet    = 'violet'
+tikz.yellow    = 'yellow'
+tikz.white     = 'white'
+
+-- align
+tikz.center = 'center'
+tikz.left   = 'left'
+tikz.right  = 'right'
+
+tikz.none   = 'none'
+
+-- line caps
+tikz.round = 'round'
+
+--==========================================================================--
+-- HELPERS --
+--==========================================================================--
+
+-- if defined writes output here
+local outfile
+
+--
+-- Prints arguments to tex and to stdout.
+--
+local function tprint( ... )
+	local args = {...}
+	print( table.concat( args ) )
+
+	if tex
+	then
+		tex.print( table.concat( args ) )
+	end
+
+	if outfile
+	then
+		outfile:write( table.concat( args ) )
+		outfile:write( '\n%%% DO NOT EDIT THIS FILE %%%\n' )
+	end
+end
+tikz.tprint = tprint
+
+--
+-- Flattens an object stack.
+--
+-- The content of all numerated unclassed objects
+-- are put into a copy of obj.
+--
+local function flatten( o )
+	local r = { }
+	for _, v in ipairs( o )
+	do
+		if type( v ) == 'table' and getmetatable( v ) == nil
+		then
+			local fv = flatten( v )
+			for _, fvv in ipairs( fv )
+			do
+				table.insert( r, fvv )
+			end
+			for k, vv in pairs( fv )
+			do
+				if type( k ) ~= 'number'
+				then
+					r[ k ] = vv
+				end
+			end
+		else
+			table.insert( r, v )
+		end
+	end
+	-- copies (and overwrites) all named attributes
+	for k, v in pairs( o )
+	do
+		if type( k ) ~= 'number'
+		then
+			r[ k ] = v
+		end
+	end
+	return r
+end
+
+--
+-- A key marking an object having a zString function.
+--
+local _zString = { }
+
+--
+-- Converts everything to a tikz string.
+--
+local function zString( v )
+	if type( v ) == 'table' and v[ _zString ]
+	then
+		return v[ _zString ]( v )
+	end
+	return tostring( v )
+end
+
+--
+-- Creates an immutable class.
+--
+local function immutable( definer )
+	local def = { }
+	local lazy = { }
+	local proto = { }
+	def.lazy = lazy
+	def.proto = proto
+	definer( def ) -- the callee fills in data
+	local k = { } -- key the hidden table
+
+	local mt = { }
+	mt.__index =
+		function( self, key )
+			if key == 'id' then return def.id end
+
+			-- first check if native value
+			local v = self[ k ][ key ]
+			if v then return v end
+
+			-- then if a lazy function
+			local f = lazy[ key ]
+			if f
+			then
+				local v = f( self )
+				self[ k ][ key ] = v -- cache
+				return v
+			end
+
+			-- then if a proto value
+			v = proto[ key ]
+			if v
+			then
+				if type( v ) == 'function'
+				then
+					return(
+						function(...)
+							return v( self, table.unpack( {...} ) )
+						end
+					)
+				else
+					return v
+				end
+			end
+
+			-- otherwise
+			-- error( 'invalid property' )
+		end
+
+	mt.__newindex =
+		function( )
+			error( 'this is an immutable' )
+		end
+
+	if def.add
+	then
+		mt.__add = def.add
+	end
+
+	if def.concat
+	then
+		mt.__concat = def.concat
+	end
+
+	if def.div
+	then
+		mt.__div = def.div
+	end
+
+	if def.mul
+	then
+		mt.__mul = def.mul
+	end
+
+	if def.sub
+	then
+		mt.__sub = def.sub
+	end
+
+	if def.tostring
+	then
+		mt.__tostring = def.tostring
+	end
+
+	return function(...)
+		local args = {...}
+		local nt = def.constructor( table.unpack( args ) )
+		local o = { [ k ] = nt, [ _zString ] = def.zString }
+		setmetatable( o, mt )
+		return o
+	end
+end
+tikz.immutable = immutable
+
+--
+-- writes out direct options
+--
+local function _opts( s, _opts, haveOpts )
+	if not _opts
+	then
+		return haveOpts
+	end
+
+	for k, v in pairs( _opts )
+	do
+		if not haveOpts
+		then
+			table.insert( s, '[' )
+		else
+			table.insert( s, ',' )
+		end
+		haveOpts = true
+		if type( k ) == 'number'
+		then
+			table.insert( s, v )
+		else
+			table.insert( s, k..'='..v )
+		end
+	end
+	return haveOpts
+end
+
+-------------------------------------------------------------------------------
+-- Point.
+-------------------------------------------------------------------------------
+tikz.p =
+immutable( function( def )
+	def.id = 'point'
+
+	def.add =
+	function( left, right )
+		if right.id == 'line'
+		or right.id == 'bezier3'
+		then
+			return right + left
+		end
+
+		return tikz.p{ left.x + right.x, left.y + right.y }
+	end
+
+	def.concat =
+	function( left, right )
+		return zString( left )..zString( right )
+	end
+
+	-- constructor
+	def.constructor =
+	function( args )
+		return { x = args[ 1 ], y = args[ 2 ] }
+	end
+
+	-- divisor
+	def.div =
+	function( left, right )
+		return tikz.p{ left.x / right, left.y / right }
+	end
+
+	def.mul =
+	function( left, right )
+		if type( right ) == 'number'
+		then
+			return tikz.p{ left.x * right, left.y * right }
+		elseif type( left ) == 'number'
+		then
+			return tikz.p{ left * right.x, left * right.y }
+		elseif type( right ) == 'table'
+		then
+			if right.id == 'point'
+			then
+				return tikz.p{ left.x * right.x, left.y * right.y }
+			end
+		end
+		error( 'invalid operation' )
+	end
+
+	def.sub =
+	function( left, right )
+		return tikz.p{ left.x - right.x, left.y - right.y }
+	end
+
+	def.tostring =
+	function( self )
+		return 'p{ '..self.x..', '..self.y..' }'
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		return '('..self.x..','..self.y..')'
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A full circle.
+-------------------------------------------------------------------------------
+tikz.circle =
+immutable( function( def )
+	def.id = 'circle'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		return {
+			at     = args.at,
+			radius = args.radius,
+		}
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		return zString( self.at )..' circle ('.. self.radius .. ')'
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A quadratic bezier curve.
+-------------------------------------------------------------------------------
+tikz.bezier2 =
+immutable( function( def )
+	def.id = 'bezier2'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local p1 = args.p1
+		local pc = args.pc
+		local p2 = args.p2
+
+		return {
+			p1 = p1,
+			pc = pc,
+			p2 = p2,
+		}
+	end
+
+	-- draws helping information
+	def.proto.drawHelpers =
+	function( self, prefix )
+		tikz.draw{ draw = 'red',  tikz.line{ self.p1, self.pc } }
+		tikz.draw{ draw = 'blue', tikz.line{ self.pc, self.p2 } }
+		if prefix ~= nil
+		then
+			tikz.put{ tikz.node{
+				at = self.p1,
+				anchor = 'north west',
+				text = prefix .. '1',
+			} }
+			tikz.put{ tikz.node{
+				at = self.pc,
+				anchor = 'north west',
+				text = prefix .. 'c',
+			} }
+			tikz.put{ tikz.node{
+				at = self.p2,
+				anchor = 'north west',
+				text = prefix .. '2',
+			} }
+		end
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, zString( self.p1 ) )
+		table.insert( s, '.. controls' )
+		table.insert( s, zString( self.pc ) )
+		table.insert( s, '..' )
+		table.insert( s, zString( self.p2 ) )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A cubic bezier curve.
+-------------------------------------------------------------------------------
+tikz.bezier3 =
+immutable( function( def )
+	def.id = 'bezier3'
+
+	def.add =
+	function( left, right )
+		if right.id == 'point'
+		then
+			return tikz.bezier3{
+				p1  = left.p1  + right,
+				pc1 = left.pc1 + right,
+				pc2 = left.pc2 + right,
+				p2  = left.p2  + right,
+			}
+		end
+		error( 'unknown operation' )
+	end
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local p1  = args.p1
+		local pc1 = args.pc1
+		local pc2 = args.pc2
+		local p2  = args.p2
+
+		return {
+			p1  = p1,
+			pc1 = pc1,
+			pc2 = pc2,
+			p2  = p2,
+		}
+	end
+
+	-- draws helping information
+	def.proto.drawHelpers =
+	function( self, prefix )
+		tikz.draw{ draw = 'red',    tikz.line{ self.p1,  self.pc1 } }
+		tikz.draw{ draw = 'yellow', tikz.line{ self.pc1, self.pc2 } }
+		tikz.draw{ draw = 'blue',   tikz.line{ self.pc2, self.p2  } }
+		if prefix ~= nil
+		then
+			tikz.put{ tikz.node{
+				at = self.p1,
+				anchor = 'north west',
+				text = prefix .. '1',
+			} }
+			tikz.put{ tikz.node{
+				at = self.pc1,
+				anchor = 'north west',
+				text = prefix .. 'c1',
+			} }
+			tikz.put{ tikz.node{
+				at = self.pc2,
+				anchor = 'north west',
+				text = prefix .. 'c2',
+			} }
+			tikz.put{ tikz.node{
+				at = self.p2,
+				anchor = 'north west',
+				text = prefix .. '2',
+			} }
+		end
+	end
+
+	def.mul =
+	function( left, right )
+		if type( right ) == 'number'
+		then
+			return tikz.bezier3 {
+				p1  = left.p1  * right,
+				pc1 = left.pc1 * right,
+				pc2 = left.pc2 * right,
+				p2  = left.p2  * right,
+			}
+		elseif type( left ) == 'number'
+		then
+			return tikz.bezier3 {
+				p1  = right.p1  * left,
+				pc1 = right.pc1 * left,
+				pc2 = right.pc2 * left,
+				p2  = right.p2  * left,
+			}
+		else
+			error( 'invalid operation' )
+		end
+	end
+
+	-- point in center
+	def.lazy.pc =
+	function( self )
+		return self.pt( 0.5 )
+	end
+
+	-- gets angle at t (0-1)
+	def.proto.phit =
+	function( self, t )
+		local p1  = self.p1
+		local pc1 = self.pc1
+		local pc2 = self.pc2
+		local p2  = self.p2
+
+		local u   = 1 - t
+		local uu3 = 3 * u * u
+		local ut6 = 6 * u * t
+		local tt3 = 3 * t * t
+
+		return math.atan2(
+			-uu3 * p1.y + uu3 * pc1.y - ut6 * pc1.y + ut6 * pc2.y - tt3 * pc2.y + tt3 * p2.y,
+			-uu3 * p1.x + uu3 * pc1.x - ut6 * pc1.x + ut6 * pc2.x - tt3 * pc2.x + tt3 * p2.x
+		)
+	end
+
+	-- reverts p1 and p2 and pc1 and pc2 respectively
+	def.lazy.revert =
+	function( self )
+		return tikz.bezier3{
+			p1  = self.p2,
+			pc1 = self.pc2,
+			pc2 = self.pc1,
+			p2  = self.p1,
+		}
+	end
+
+	-- gets point at t (0-1)
+	def.proto.pt =
+	function( self, t )
+		if type( t ) ~= 'number' or t < 0 or t > 1
+		then
+			error( 'invalid pt' )
+		end
+
+		local p1 = self.p1
+		local pc1 = self.pc1
+		local pc2 = self.pc2
+		local p2 = self.p2
+		local t1 = 1 - t
+
+		return(
+			tikz.p{
+				t1^3*p1.x + 3*t*t1^2*pc1.x + 3 *t^2*t1*pc2.x + t^3*p2.x,
+				t1^3*p1.y + 3*t*t1^2*pc1.y + 3 *t^2*t1*pc2.y + t^3*p2.y
+			}
+		)
+	end
+
+	def.sub =
+	function( left, right )
+		if right.id == 'point'
+		then
+			return tikz.bezier3{
+				p1  = left.p1  - right,
+				pc1 = left.pc1 - right,
+				pc2 = left.pc2 - right,
+				p2  = left.p2  - right,
+			}
+		end
+		error( 'unknown operation' )
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, zString( self.p1 ) )
+		table.insert( s, '.. controls' )
+		table.insert( s, zString( self.pc1 ) )
+		table.insert( s, 'and' )
+		table.insert( s, zString( self.pc2 ) )
+		table.insert( s, '..' )
+		table.insert( s, zString( self.p2 ) )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A bend line
+-------------------------------------------------------------------------------
+tikz.bline =
+immutable( function( def )
+	def.id = 'bline'
+
+	-- moves the line.
+	def.add =
+	function( left, right )
+		if right.id == 'point'
+		then
+			return tikz.line{ p1 = left.p1 + right, p2 = left.p2 + right }
+		end
+		error( 'unknown operation' )
+	end
+
+	-- constructor
+	--
+	-- either
+	--   { p1, p2 },            (a list )
+	--   { p1 = ..., p2 = ... },
+	--   { pc = ..., phi = ..., length = ... },
+	def.constructor =
+	function( args )
+		local p1
+		local p2
+
+		if #args > 1
+		then
+			-- list
+			p1 = args[ 1 ]
+			p2 = args[ 2 ]
+		elseif type( args.p1 ) ~= 'nil' and type( args.p2 ) ~= 'nil'
+		then
+			p1 = args.p1
+			p2 = args.p2
+		elseif args.phi ~= nil
+		then
+			local phi = args.phi
+			if args.pc ~= nil
+			then
+				if args.p1 ~= nil
+				or args.p2 ~= nil
+				then
+					error( 'invalid line options', 2 )
+				end
+				local pc    = args.pc
+				local len05 = args.length / 2
+				p1 = pc + tikz.p{ math.cos( phi ), math.sin( phi ) } * len05
+				p2 = pc - tikz.p{ math.cos( phi ), math.sin( phi ) } * len05
+			elseif type( args.p1 ) ~= 'nil'
+			then
+				if args.pc ~= nil
+				or args.p2 ~= nil
+				then
+					error( 'invalid line options', 2 )
+				end
+				p1 = args.p1
+				p2 = p1 + tikz.p{ math.cos( phi ), math.sin( phi ) } * args.length
+			else
+				error( 'invalid line options', 2 )
+			end
+		else
+			error( 'invalid line options', 2 )
+		end
+
+		return {
+			bend_left  = args.bend_left,
+			bend_right = args.bend_right,
+			p1         = p1,
+			p2         = p2,
+		}
+	end
+
+	-- converts to a cubic bezier (that should look the same)
+	def.lazy.bezier3 =
+	function( self )
+		local phi
+		if self.bend_right ~= nil then
+			phi = self.bend_right * math.pi / 180
+		else
+			phi = -self.bend_left * math.pi / 180
+		end
+		local line = self.line
+		local phil = line.phi
+		local len = line.length * 0.3915
+		local lt1 =
+			tikz.line{
+				p1  = line.p1,
+				phi = phil-phi,
+				length = len
+			}
+		local lt2 =
+			tikz.line{
+				p1 = line.p2,
+				phi = phil+phi+math.pi,
+				length = len
+			}
+
+		return tikz.bezier3{
+			p1  = line.p1,
+			pc1 = lt1.p2,
+			pc2 = lt2.p2,
+			p2  = line.p2,
+		}
+	end
+
+	-- converts to a straight line.
+	def.lazy.line =
+	function( self )
+		return tikz.line{
+			p1 = self.p1,
+			p2 = self.p2,
+		}
+	end
+
+	-- point in center
+	def.lazy.pc =
+	function( self )
+		return self.bezier3.pc
+	end
+
+	-- gets point at t (0-1).
+	def.proto.pt =
+	function( self, t )
+		return self.bezier3.pt( t )
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, zString( self.p1 ) )
+		table.insert( s, 'to' )
+		if self.bend_left ~= nil
+		then
+			table.insert( s, '[bend left='..self.bend_left..']' )
+		end
+		if self.bend_right ~= nil
+		then
+			table.insert( s, '[bend right='..self.bend_right..']' )
+		end
+		table.insert( s, zString( self.p2 ) )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A curve is defined by a list of points.
+-------------------------------------------------------------------------------
+curve =
+immutable( function( def )
+	def.id = 'curve'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		return {
+			points  = args.points,
+			tension = args.tension,
+			cycle   = args.cycle,
+		}
+	end
+
+	-- draws helping information
+	def.proto.drawHelpers =
+	function( self, prefix )
+		local points = self.points
+		for i, pi in ipairs( points )
+		do
+			tikz.draw{
+				fill = 'black',
+				tikz.circle{
+					at = pi,
+					radius = 0.05,
+				}
+			}
+			if prefix ~= nil
+			then
+				tikz.put{ tikz.node{
+					at = pi,
+					anchor = 'north west',
+					text = prefix .. i,
+				} }
+			end
+		end
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { 'plot' }
+		table.insert( s, '[' )
+		if self.cycle
+		then
+			table.insert( s, 'smooth cycle' )
+		else
+			table.insert( s, 'smooth' )
+		end
+		if self.tension then
+			table.insert( s, ',tension='..self.tension )
+		end
+		table.insert( s, ']' )
+		local points = self.points
+		table.insert( s, 'coordinates' )
+		table.insert( s, '{' )
+		for _, p in ipairs( points )
+		do
+			table.insert( s, zString( p ) )
+		end
+		table.insert( s, '}' )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A full ellipse.
+-------------------------------------------------------------------------------
+tikz.ellipse =
+immutable( function( def )
+	def.id = 'ellipse'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local at = args.at
+		local xradius = args.xradius
+		local yradius = args.yradius
+
+		return {
+			at = at,
+			xradius = xradius,
+			yradius = yradius,
+		}
+	end
+
+	-- intersect with a line.
+	def.proto.intersectLine =
+	function( self, line )
+		local at = self.at
+		local rx = self.xradius
+		local ry = self.yradius
+		local p1 = line.p1
+		local p2 = line.p2
+
+		local x0 = p1.x
+		local y0 = p1.y
+		local x1 = p2.x
+		local y1 = p2.y
+		local cx = at.x
+		local cy = at.y
+
+		x0 = x0 - cx
+		y0 = y0 - cy
+		x1 = x1 - cx
+		y1 = y1 - cy
+
+		local A = ((x1 - x0) * (x1 - x0)) / rx / rx + ((y1 - y0) * (y1 - y0)) / ry / ry
+		local B = (2 * x0 * (x1 - x0)) / rx / rx + (2 * y0 * (y1 - y0)) / ry / ry
+		local C = (x0 * x0) / rx / rx + (y0 * y0) / ry / ry - 1
+		local D = B * B - 4 * A * C
+
+		local tv = { }
+		if D == 0
+		then
+			table.insert( tv, -B / 2 / A )
+		else
+			table.insert( tv, (-B + math.sqrt(D)) / 2 / A )
+			table.insert( tv, (-B - math.sqrt(D)) / 2 / A )
+		end
+
+		local r = { }
+		for _, t in ipairs( tv )
+		do
+			if t >= 0 and t <= 1
+			then
+				table.insert(
+					r,
+					p1 + tikz.p{ t * line.length * math.cos( line.phi ), t * line.length * math.sin( line.phi ) }
+				)
+			end
+		end
+
+		if #r == 0
+		then
+			return
+		elseif #r == 1
+		then
+			return r[ 1 ]
+		else
+			return r
+		end
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		s = { }
+		table.insert( s, zString( self.at ) )
+		table.insert( s, 'ellipse' )
+		table.insert( s, '[' )
+		table.insert( s, 'x radius =' )
+		table.insert( s, zString( self.xradius ) )
+		table.insert( s, ', y radius =' )
+		table.insert( s, zString( self.yradius ) )
+		table.insert( s, ']' )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- An ellipse part.
+-------------------------------------------------------------------------------
+tikz.ellipseArc =
+immutable( function( def )
+	def.id = 'ellipseArc'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		return {
+			at      = args.at,
+			from    = args.from,
+			to      = args.to,
+			xradius = args.xradius,
+			yradius = args.yradius,
+		}
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		s = { }
+		table.insert( s, 'plot' )
+		table.insert( s, '[domain =' )
+		table.insert( s, self.from )
+		table.insert( s, ':' )
+		table.insert( s, self.to )
+		table.insert( s, ',variable = \\phi,smooth]' )
+		table.insert( s,
+			'({ '..zString(self.at.x)..'+'..zString(self.xradius)..'*cos(\\phi)},'
+			..'{ '..zString(self.at.y)..'+'..zString(self.yradius)..'*sin(\\phi)})'
+		)
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- Single line (segment).
+-------------------------------------------------------------------------------
+tikz.line =
+immutable( function( def )
+	def.id = 'line'
+
+	-- moves the line.
+	def.add =
+	function( left, right )
+		if right.id == 'point'
+		then
+			return tikz.line{
+				p1 = left.p1 + right,
+				p2 = left.p2 + right,
+			}
+		end
+		error( 'unknown operation' )
+	end
+
+	-- multiplicator
+	def.mul =
+	function( left, right )
+		if type( left ) == 'number'
+		then
+			return tikz.line{
+				p1 = right.p1 * left,
+				p2 = right.p2 * left,
+			}
+		elseif type( right ) == 'number'
+		then
+			return tikz.line{
+				p1 = left.p1 * right,
+				p2 = left.p2 * right,
+			}
+		end
+		error( 'unknown operation' )
+	end
+
+	-- constructor
+	--
+	-- either
+	--   { p1, p2 },            (a list )
+	--   { p1 = ..., p2 = ... },
+	--   { pc = ..., phi = ..., length = ... },
+	def.constructor =
+	function( args )
+		local p1
+		local p2
+
+		if #args > 1
+		then
+			-- list
+			p1 = args[ 1 ]
+			p2 = args[ 2 ]
+		elseif type( args.p1 ) ~= 'nil' and type( args.p2 ) ~= 'nil'
+		then
+			p1 = args.p1
+			p2 = args.p2
+		elseif args.phi ~= nil
+		then
+			local phi = args.phi
+			if args.pc ~= nil
+			then
+				if args.p1 ~= nil
+				or args.p2 ~= nil
+				then
+					error( 'invalid line options', 2 )
+				end
+				local pc    = args.pc
+				local len05 = args.length / 2
+				p1 = pc + tikz.p{ math.cos( phi ), math.sin( phi ) } * len05
+				p2 = pc - tikz.p{ math.cos( phi ), math.sin( phi ) } * len05
+			elseif type( args.p1 ) ~= 'nil'
+			then
+				if args.pc ~= nil
+				or args.p2 ~= nil
+				then
+					error( 'invalid line options', 2 )
+				end
+				p1 = args.p1
+				p2 = p1 + tikz.p{ math.cos( phi ), math.sin( phi ) } * args.length
+			else
+				error( 'invalid line options', 2 )
+			end
+		else
+			error( 'invalid line options', 2 )
+		end
+
+		return {
+			p1 = p1,
+			p2 = p2,
+		}
+	end
+
+	-- divisor
+	def.div =
+	function( left, right )
+		if type( right ) == 'number'
+		then
+			return tikz.line{
+				p1 = left.p1 / right,
+				p2 = left.p2 / right,
+			}
+		end
+		error( 'unknown operation' )
+	end
+
+	-- length of line.
+	def.lazy.length =
+	function( self )
+		local p1 = self.p1
+		local p2 = self.p2
+		local dx = p2.x - p1.x
+		local dy = p2.y - p1.y
+		local result = math.sqrt( dx*dx + dy*dy )
+		return result
+	end
+
+	-- center of line.
+	def.lazy.pc =
+	function( self )
+		local p1 = self.p1
+		local p2 = self.p2
+		local result = tikz.p{ ( p1.x + p2.x ) / 2, ( p1.y + p2.y ) / 2 }
+		return result
+	end
+
+	-- angle of line.
+	def.lazy.phi =
+	function( self )
+		local p1 = self.p1
+		local p2 = self.p2
+		local result = math.atan2( p2.y - p1.y, p2.x - p1.x )
+		return result
+	end
+
+	-- gets point at t (0-1).
+	def.proto.pt =
+	function( self, t )
+		if type( t ) ~= 'number' or t < 0 or t > 1
+		then
+			error( 'invalid pt' )
+		end
+
+		local p1 = self.p1
+		local p2 = self.p2
+		local phi = self.phi
+		local lt = self.length * t
+
+		return(
+			tikz.p{
+				p1.x + lt * math.cos( phi ),
+				p1.y + lt * math.sin( phi ),
+			}
+		)
+	end
+
+	-- intersects the line with another.
+	def.proto.intersectLine =
+	function( self, line )
+		local p1 = self.p1
+		local p2 = self.p2
+		local p3 = line.p1
+		local p4 = line.p2
+
+		if p1.x == p3.x and p1.y == p3.y then return p1 end
+		if p1.x == p4.x and p1.y == p4.y then return p1 end
+		if p2.x == p3.x and p2.y == p3.y then return p2 end
+		if p2.x == p4.x and p2.y == p4.y then return p2 end
+
+		local den = ( p1.x - p2.x )*( p3.y - p4.y ) - ( p1.y - p2.y )*( p3.x - p4.x );
+		if den == 0
+		then
+			-- doesn't intersect
+			return
+		end
+
+		local a = p1.x*p2.y - p1.y*p2.x;
+		local b = p3.x*p4.y - p3.y*p4.x;
+		local x = ( a*( p3.x - p4.x ) - ( p1.x - p2.x )*b ) / den;
+		local y = ( a*( p3.y - p4.y ) - ( p1.y - p2.y )*b ) / den;
+
+		if
+			(
+				( x >= p1.x and x <= p2.x or x <= p1.x and x >= p2.x )
+				and ( x >= p3.x and x <= p4.x or x <= p3.x and x >= p4.x )
+			)
+			or
+			(
+				( y >= p1.y and y <= p2.y or y <= p1.y and y >= p2.y )
+				and ( y >= p3.y and y <= p4.y or y <= p3.y and y >= p4.y )
+			)
+		then
+			return tikz.p{ x, y }
+		end
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, zString( self.p1 ) )
+		table.insert( s, '--' )
+		table.insert( s, zString( self.p2 ) )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- Function plot.
+-------------------------------------------------------------------------------
+tikz.plot =
+immutable( function( def )
+	def.id = 'plot'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		return {
+			at      = args.at,
+			from    = args.from,
+			to      = args.to,
+			step    = args.step,
+			tension = args.tension,
+			func    = args.func,
+		}
+	end
+
+	def.lazy.points =
+	function( self )
+		local from = self.from
+		local to = self.to
+		local step = self.step
+		if step == nil
+		then
+			step = ( to - from ) / 100
+		end
+		local points = { }
+		local d
+		local at = self.at or tikz.p0
+		for d = from, to, step
+		do
+			table.insert( points, at + self.func( d ) )
+		end
+		return points
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { 'plot' }
+		table.insert( s, '[' )
+		table.insert( s, 'smooth' )
+		if self.tension
+		then
+			table.insert( s, ',tension='..self.tension )
+		end
+		table.insert( s, ']' )
+
+		local points = self.points
+
+		table.insert( s, 'coordinates' )
+		table.insert( s, '{' )
+		for _, p in ipairs( points )
+		do
+			table.insert( s, zString( p ) )
+		end
+		table.insert( s, '}' )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A superEllipse
+-------------------------------------------------------------------------------
+tikz.superEllipse =
+immutable( function( def )
+	def.id = 'superEllipse'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local at = args.at
+		local n = args.n
+		local xradius = args.xradius
+		local yradius = args.yradius
+
+		return {
+			at = at,
+			n = n,
+			xradius = xradius,
+			yradius = yradius,
+		}
+	end
+
+	-- returns p on degree (0-360)
+	def.proto.pdeg =
+	function( self, t )
+		if type( t ) ~= 'number' or t < 0 or t > 360
+		then
+			error( 'invalid pdeg' )
+		end
+
+		local at = self.at
+		local n = self.n
+		local xo = self.xradius * math.abs( math.cos( t * math.pi / 180 ) )^(2/n)
+		local yo = self.yradius * math.abs( math.sin( t * math.pi / 180 ) )^(2/n)
+
+		if t <= 90
+		then
+			return tikz.p{ at.x + xo, at.y + yo }
+		elseif t <= 180
+		then
+			return tikz.p{ at.x - xo, at.y + yo }
+		elseif t <= 270
+		then
+			return tikz.p{ at.x - xo, at.y - yo }
+		else
+			return tikz.p{ at.x + xo, at.y - yo }
+		end
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		local at = self.at
+		local xa = at.x
+		local ya = at.y
+		local n = self.n
+		local xr = self.xradius
+		local yr = self.yradius
+		table.insert( s, 'plot[domain=0:90,variable=\\t,smooth]' )
+		table.insert( s, '({'..xr..'*cos(\\t)^(2/'..n..')+'..xa..'},{'..yr..'*sin(\\t)^(2/'..n..')+'..ya..'})' )
+		table.insert( s, '--' )
+		table.insert( s, 'plot[domain=90:0,variable=\\t,smooth]' )
+		table.insert( s, '({-'..xr..'*cos(\\t)^(2/'..n..')+'..xa..'},{'..yr..'*sin(\\t)^(2/'..n..')+'..ya..'})' )
+		table.insert( s, '--' )
+		table.insert( s, 'plot[domain=0:90,variable=\\t,smooth]' )
+		table.insert( s, '({-'..xr..'*cos(\\t)^(2/'..n..')+'..xa..'},{-'..yr..'*sin(\\t)^(2/'..n..')+'..ya..'})' )
+		table.insert( s, '--' )
+		table.insert( s, 'plot[domain=90:0,variable=\\t,smooth]' )
+		table.insert( s, '({'..xr..'*cos(\\t)^(2/'..n..')+'..xa..'},{-'..yr..'*sin(\\t)^(2/'..n..')+'..ya..'})' )
+		table.insert( s, '-- cycle' )
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A reference to a named node.
+-------------------------------------------------------------------------------
+local optionsNamed =
+{
+	ref = false,
+	xshift = 'xshift',
+	yshift = 'yshift',
+}
+
+tikz.named =
+immutable( function( def )
+	def.id = 'named'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local s = { }
+		_doOptions( s, args, optionsNamed, false, 2 )
+		return {
+			opts = table.concat( s, ' ' ),
+			ref = args.ref,
+		}
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, '(' )
+		if self.opts
+		then
+			table.insert( s, self.opts )
+		end
+		table.insert( s, self.ref )
+		table.insert( s, ')' )
+		return table.concat( s )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- Multiple connected lines.
+-------------------------------------------------------------------------------
+tikz.polyline =
+immutable( function( def )
+	def.id = 'polyline'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local o = { }
+		for _, v in ipairs( args )
+		do
+			table.insert( o, v )
+		end
+		return o
+	end
+
+	-- converts to a tikz string.
+	def.zString =
+	function( self )
+		local s = { '' }
+		for k, v in ipairs( self )
+		do
+			if k > 1 then table.insert( s, '--' ) end
+			table.insert( s, zString( v ) )
+		end
+		return table.concat( s, ' ' )
+	end
+end )
+
+-------------------------------------------------------------------------------
+-- A rectangle
+-------------------------------------------------------------------------------
+tikz.rect =
+immutable( function( def )
+	def.id = 'rect'
+
+	-- constructor
+	def.constructor =
+	function( args )
+		local psw
+		local pne
+
+		if args.pnw ~= nil
+		then
+			if args.pse ~= nil
+			then
+				psw = tikz.p{ args.pnw.x, args.pse.y }
+				pne = tikz.p{ args.pse.x, args.pnw.y }
+			elseif args.size ~= nil
+			then
+				psw = tikz.p{ args.pnw.x, args.pnw.y - args.size.y }
+				pne = tikz.p{ args.pnw.x + args.size.x, args.pnw.y }
+			else
+				error( 'invalid rect options', 2 )
+			end
+		elseif args.psw ~= nil
+		then
+			psw = args.psw
+			if args.pne ~= nil
+			then
+				pne = args.pne
+			elseif args.size ~= nil
+			then
+				pne = psw + args.size
+			else
+				error( 'invalid rect options', 2 )
+			end
+		elseif args.pse ~= nil
+		then
+			if args.size ~= nil
+			then
+				psw = tikz.p{ args.pse.x - args.size.x, args.pse.y }
+				pne = tikz.p{ args.pse.x, args.pse.y + args.size.y }
+			else
+				error( 'invalid rect options', 2 )
+			end
+		elseif args.pc ~= nil
+		then
+			if args.size ~= nil
+			then
+				psw = tikz.p{ args.pc.x - args.size.x / 2, args.pc.y - args.size.y / 2 }
+				pne = tikz.p{ args.pc.x + args.size.x / 2, args.pc.y + args.size.y / 2 }
+			else
+				error( 'invalid rect options', 2 )
+			end
+		else
+			error( 'invalid rect options', 2 )
+		end
+
+		return {
+			psw = psw,
+			pne = pne,
+		}
+	end
+
+	def.zString =
+	function( self )
+		local s = { }
+		table.insert( s, zString( self.psw ) )
+		table.insert( s, 'rectangle' )
+		table.insert( s, zString( self.pne ) )
+		return table.concat( s, ' ' )
+	end
+
+	def.lazy.e =
+	function( self )
+		return self.pne.x
+	end
+
+	def.lazy.height =
+	function( self )
+		return self.pne.y - self.psw.y
+	end
+
+	def.lazy.n =
+	function( self )
+		return self.pne.y
+	end
+
+	def.lazy.pc =
+	function( self )
+		return tikz.p{ self.psw.x + self.width / 2, self.psw.y + self.height / 2 }
+	end
+
+	def.lazy.pe =
+	function( self )
+		return tikz.p{ self.pne.x, self.psw.y + self.height / 2 }
+	end
+
+	def.lazy.pn =
+	function( self )
+		return tikz.p{ self.psw.x + self.width / 2, self.pne.y }
+	end
+
+	def.lazy.pnw =
+	function( self )
+		return tikz.p{ self.psw.x, self.pne.y }
+	end
+
+	def.lazy.ps =
+	function( self )
+		return tikz.p{ self.psw.x + self.width / 2, self.psw.y }
+	end
+
+	def.lazy.pse =
+	function( self )
+		return tikz.p{ self.pne.x, self.psw.y }
+	end
+
+	def.lazy.pw =
+	function( self )
+		return tikz.p{ self.psw.x, self.psw.y + self.height / 2 }
+	end
+
+	def.lazy.s =
+	function( self )
+		return self.psw.y
+	end
+
+	def.lazy.size =
+	function( self )
+		return tikz.p{ self.width, self.height }
+	end
+
+	def.lazy.w =
+	function( self )
+		return self.psw.x
+	end
+
+	def.lazy.width =
+	function( self )
+		return self.pne.x - self.psw.x
+	end
+end )
+
+
+--==========================================================================--
+-- STYLES --
+--==========================================================================--
+tikz.style =
+immutable( function( def )
+	def.id = 'style'
+
+	-- constructor
+	def.constructor =
+	function( name )
+		return { name=name }
+	end
+end )
+
+tikz.above         = tikz.style( 'above' )
+tikz.arrow         = tikz.style( '-{Latex}' )
+tikz.below         = tikz.style( 'below' )
+tikz.dashed        = tikz.style( 'dashed' )
+tikz.dotted        = tikz.style( 'dotted' )
+tikz.double_arrow  = tikz.style( '{Latex}-{Latex}' )
+tikz.even_odd_rule = tikz.style( 'even odd rule' )
+tikz.midway        = tikz.style( 'midway' )
+
+--==========================================================================--
+-- OUTPUT ---
+--==========================================================================--
+
+--
+-- Writes out a named option.
+--
+--  ~s:        string to build
+--  ~args:     arguments
+--  ~name:     name of option
+--  ~haveOpts: true if had options
+--  ~rename:   if defined rename options on output
+--
+local function optionNamed( s, args, name, haveOpts, rename )
+
+	local v = args[ name ]
+
+	if not v
+	then
+		return haveOpts
+	end
+
+	if not rename
+	then
+		return haveOpts
+	end
+
+	if not haveOpts
+	then
+		table.insert( s, '[' )
+	else
+		table.insert( s, ',' )
+	end
+
+	if v == true
+	then
+		table.insert( s, rename )
+	else
+		table.insert( s, rename..'='..v )
+	end
+
+	return true
+end
+
+--
+-- Writes out an unnamed option.
+--
+--  ~s:        string to build
+--  ~name:     name of option
+--  ~haveOpts: true if had options
+--
+local function unnamedOption( s, name, haveOpts )
+	if not haveOpts
+	then
+		table.insert( s, '[' )
+	else
+		table.insert( s, ',' )
+	end
+	table.insert( s, name )
+	return true
+end
+
+--
+-- Custom key compare.
+--
+-- keys to put on top
+local topKeys =
+{
+	node_distance = true,
+}
+
+local function kcompare( ka, kb )
+	local ta = topKeys[ ka ]
+	local tb = topKeys[ kb ]
+	if ta and not tb then return true end
+	if not ta and tb then return false end
+	return ka < kb
+end
+
+--
+-- A helper to parse arguments to pass as drawing options to hand to tikz.
+--
+--  s:        string to build
+--  args:     the arguments to parse.
+--  opts:     named options to pass on
+--  haveOpts: true [ has already been built
+--  level:    call level for error throwing
+--
+local function _doOptions( s, args, opts, haveOpts, level )
+	args = flatten( args )
+
+	for _, v in ipairs( args )
+	do
+		if v.id == 'style'
+		then
+			haveOpts = unnamedOption( s, v.name, haveOpts )
+		end
+	end
+
+	local nkeys = { }
+	for key in pairs( args )
+	do
+		if type( key ) ~= 'number'
+		then
+			table.insert( nkeys, key )
+		end
+	end
+	table.sort( nkeys, kcompare )
+
+	for _, k in ipairs( nkeys )
+	do
+		local ok = opts[ k ]
+		if ok
+		then
+			haveOpts = optionNamed( s, args, k, haveOpts, ok )
+		elseif ok == nil
+		then
+			error( 'unknown option '..k, level + 1 )
+		end
+	end
+
+	haveOpts = _opts( s, args._opts, haveOpts )
+
+	if haveOpts
+	then
+		table.insert( s, ']' )
+	end
+end
+
+-------------------------------------------------------------------------------
+-- Drawing shapes.
+-------------------------------------------------------------------------------
+local optionsDraw =
+{
+	decorate         = 'decorate',
+	decoration       = 'decoration',
+	dash_pattern     = 'dash pattern',
+	color            = 'color',
+	draw             = 'draw',
+	fill             = 'fill',
+	line_cap         = 'line cap',
+	line_width       = 'line width',
+	opacity          = 'opacity',
+	pattern          = 'pattern',
+	rotate           = 'rotate',
+	transform_canvas = 'transform canvas',
+	xshift           = 'xshift',
+	yshift           = 'yshift',
+	_butt_cap        = '-Butt Cap',
+	butt_cap_        = 'Butt Cap-',
+	_round_cap       = '-{Round Cap[]}',
+	round_cap_       = '{Round Cap[]}-',
+	_round_cap_      = '{Round Cap[]}-{Round Cap[]}',
+}
+
+--
+-- Puts out a bounding box command
+--
+tikz.boundingbox =
+function( args )
+	tprint( '\\pgfresetboundingbox' )
+	local s = { '\\path [use as bounding box] ' }
+	for _, v in ipairs( args )
+	do
+		if v.id ~= 'style'
+		then
+			table.insert( s, zString( v ) )
+		end
+	end
+	table.insert( s, ';' )
+	tprint( table.unpack( s ) )
+end
+
+--
+-- Puts out a draw command.
+--
+tikz.draw =
+function( args )
+	local s = { '\\draw ' }
+	_doOptions( s, args, optionsDraw, false, 2 )
+
+	for _, v in ipairs( args )
+	do
+		if v.id ~= 'style'
+		then
+			table.insert( s, zString( v ) )
+		end
+	end
+
+	table.insert( s, ';' )
+	tprint( table.unpack( s ) )
+end
+
+--
+-- Puts out a path command.
+--
+tikz.path =
+function( args )
+	local s = { '\\path' }
+	_doOptions( s, args, optionsDraw, false, 2 )
+
+	for _, v in ipairs( args )
+	do
+		if v.id ~= 'style'
+		then
+			table.insert( s, zString( v ) )
+		end
+	end
+	table.insert( s, ';' )
+	tprint( table.unpack( s ) )
+end
+
+--
+-- Puts out a bounding box.
+--
+tikz.clip =
+function( args )
+	local s = { '\\begin{pgfinterruptboundingbox}', '\\clip' }
+	_doOptions( s, args, optionsDraw, false, 2 )
+
+	for _, v in ipairs( args )
+	do
+		if v.id ~= 'style' then table.insert( s, zString( v ) ) end
+	end
+	table.insert( s, ';' )
+	table.insert( s, '\\end{pgfinterruptboundingbox}' )
+	tprint( table.unpack( s ) )
+end
+
+local shadeOptions =
+{
+	ball_color        = 'ball color',
+	left_color        = 'left color',
+	lower_left_color  = 'lower left',
+	lower_right_color = 'lower right',
+	opacity           = 'opacity',
+	right_color       = 'right color',
+	shading           = 'shading',
+	upper_left_color  = 'upper left',
+	upper_right_color = 'upper right',
+}
+
+--
+-- Puts out a shade command.
+--
+tikz.shade =
+function( args )
+	local s = { '\\shade' }
+	_doOptions( s, args, shadeOptions, false, 2 )
+
+	for _, v in ipairs( args )
+	do
+		if v.id ~= 'style' then table.insert( s, zString( v ) ) end
+	end
+	table.insert( s, ';' )
+	tprint( table.unpack( s ) )
+end
+
+--
+-- Puts out z stuff.
+--
+tikz.put =
+function( args )
+	for _, v in ipairs( args )
+	do
+		local s = { }
+		if v.id == 'node'
+		then
+			table.insert( s, '\\' )
+			table.insert( s, zString( v ) )
+			table.insert( s, ';' )
+		else
+			error( 'unknown: ' .. v.id, 1 )
+		end
+		tprint( table.unpack( s ) )
+	end
+end
+
+tikz.declarehorizonalshading =
+function( args )
+	local steps = args.steps
+	local name = args.name
+	local s = { '\\pgfdeclarehorizontalshading{' .. name .. '}{100bp}{' }
+
+	local keys = { }
+	for k, _ in pairs( steps )
+	do
+		table.insert( keys, k )
+	end
+
+	table.sort( keys )
+	for _, k in ipairs( keys )
+	do
+		if _ > 1 then table.insert( s, ';' ) end
+		table.insert( s, 'color(' .. k .. 'bp)=(' .. steps[ k ] .. ')' )
+	end
+	table.insert( s, '}' )
+
+	tprint( table.unpack( s ) )
+end
+
+-------------------------------------------------------------------------------
+-- A node to be defined to tikZ
+-------------------------------------------------------------------------------
+local optionsNode =
+{
+	above          = 'above',
+	anchor         = 'anchor',
+	align          = 'align',
+	at             = false,
+	below          = 'below',
+	color          = 'color',
+	draw           = 'draw',
+	left           = 'left',
+	minimum_height = 'minimum height',
+	node_distance  = 'node distance',
+	name           = false,
+	right          = 'right',
+	rotate         = 'rotate',
+	text           = false,
+	text_width     = 'text width',
+}
+
+tikz.node =
+immutable( function( def )
+	def.id = 'node';
+
+	def.zString =
+		function( self )
+			local s = { 'node' }
+
+			table.insert( s, self.opts )
+			if self.name
+			then
+				table.insert( s, ' (' )
+				table.insert( s, self.name )
+				table.insert( s, ')' )
+			end
+
+			if self.at
+			then
+				table.insert( s, ' at ' )
+				table.insert( s, zString( self.at ) )
+			end
+
+			if self.text
+			then
+				table.insert( s, ' {' )
+				local text = string.gsub( self.text, '\n', '' )
+				table.insert( s, text )
+				table.insert( s, '}' )
+			end
+
+			return table.concat( s )
+		end
+
+	-- constructor
+	def.constructor =
+		function( args )
+			local s = { }
+			_doOptions( s, args, optionsNode, false, 2 )
+			return {
+				at = args.at,
+				name = args.name,
+				opts = table.concat( s, ' ' ),
+				text = args.text
+			}
+		end
+end )
+
+tikz.outfile =
+function( filename )
+	outfile = io.open( filename, 'w' )
+	outfile:write( '%%% DO NOT EDIT THIS FILE %%%\n' )
+end
+
+--
+-- Hacking help.
+--
+function _direct( args )
+	tprint( table.unpack( args ) )
+end
+
+--
+-- Checks version metch.
+--
+tikz.checkVersion =
+function( v )
+	if v ~= tikz.version
+	then
+		error( 'version mismatch', 1 )
+	end
+end
+
+--
+-- Creates a color.
+--
+tikz.colorRGB =
+function( red, green, blue )
+	return '{rgb,255:red,'..red..'; green,'..green..'; blue,'..blue..'}'
+end
+
+--
+-- Makes a tikz scope.
+-- Argument must be a function to call.
+--
+tikz.scope =
+function( args )
+	args = flatten( args )
+	if #args ~= 1 or type( args[ 1 ] ) ~= 'function'
+	then
+		error( 'scope needs a function parameter' )
+	end
+	_direct{ [[\begin{scope}]] }
+	args[ 1 ]( )
+	_direct{ [[\end{scope}]] }
+end
+
+--==========================================================================--
+-- SHORTCUTS
+--==========================================================================--
+tikz.p0 = tikz.p{ 0, 0 }
+
+
+--==========================================================================--
+-- Running code within tikz environment.
+--==========================================================================--
+
+local env_nesting = 0
+local org_env
+tikz.within =
+function( version )
+	if version ~= '*' and version ~= tikz.version
+	then
+		error( 'version mismatch', 1 )
+	end
+
+	env_nesting = env_nesting + 1
+	if env_nesting > 1
+	then
+		return
+	end
+
+	org_env = _ENV
+	local nenv = { }
+	local mt = { }
+	mt.__index =
+		function( _, key )
+			local zk = tikz[ key ]
+			if zk ~= nil
+			then
+				return zk
+			else
+				return org_env[ key ]
+			end
+		end
+	setmetatable( nenv, mt )
+	local func = debug.getinfo( 2 ).func
+	debug.setupvalue( func, 1, nenv )
+end
+
+tikz.without =
+function( )
+	env_nesting = env_nesting - 1
+	if env_nesting > 0 then return end
+	local func = debug.getinfo( 2 ).func
+	debug.setupvalue( func, 1, org_env )
+end


Property changes on: trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.sty	2024-12-09 21:18:16 UTC (rev 73087)
@@ -0,0 +1,5 @@
+\ProvidesPackage{luatikz}[2024/12/04 2.12.0 Luatikz]
+%This package is just wrapper to load the luatikz code.
+\RequirePackage{luacode}
+\directlua{require('luatikz')}
+\endinput


Property changes on: trunk/Master/texmf-dist/tex/latex/luatikz/luatikz.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2024-12-09 21:14:59 UTC (rev 73086)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2024-12-09 21:18:16 UTC (rev 73087)
@@ -545,7 +545,7 @@
     luamesh luamml luamodulartables luamplib luanumint luaoptions luaotfload
     luapackageloader luaplot luaprogtable luapstricks
     luaquotes luarandom
-    luaset luasseq luatex85 luatexbase luatexja luatexko luatextra
+    luaset luasseq luatex85 luatexbase luatexja luatexko luatextra luatikz
     luatodonotes luatruthtable luavlna luaxml
     lutabulartools luwiantype lwarp lxfonts ly1 lyluatex
   macrolist macros2e macroswap mafr magaz magicnum magicwatermark magra

Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds	2024-12-09 21:14:59 UTC (rev 73086)
+++ trunk/Master/tlpkg/libexec/ctan2tds	2024-12-09 21:18:16 UTC (rev 73087)
@@ -2374,6 +2374,7 @@
  'luaprogtable','\.lua|' . $standardtex,
  'luapstricks',	'\.lua|' . $standardtex,
  'luatexko',    '\.lua|' . $standardtex,
+ 'luatikz',     '\.lua|' . $standardtex,
  'luatodonotes','\.lua|' . $standardtex, 
  'luavlna',	'luavlna.*\.lua|luavlna\.tex|' . $standardtex, 
  'luaxml',      '\.lua|' . $standardtex,

Modified: trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2024-12-09 21:14:59 UTC (rev 73086)
+++ trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2024-12-09 21:18:16 UTC (rev 73087)
@@ -76,6 +76,7 @@
 depend luatexbase
 depend luatexko
 depend luatextra
+depend luatikz
 depend luatruthtable
 depend luavlna
 depend luaxml

Added: trunk/Master/tlpkg/tlpsrc/luatikz.tlpsrc
===================================================================


More information about the tex-live-commits mailing list.