#lang racket
(require "../base/coord.rkt")
(provide point
circle
ellipse
arc
line
closed-line
spline
closed-spline
rectangle
text
save-tikz
display-tikz
transform
end-transform
set-view)
(define tikz-port (open-output-string))
(define (tikz obj)
(display obj tikz-port))
(define (tikzln obj)
(displayln obj tikz-port))
(define (save-tikz pathname)
(with-output-to-file pathname
(lambda ()
(write-bytes (get-output-bytes tikz-port #t)))))
(define (display-tikz)
(display (get-output-string tikz-port)))
(define (tikz-end)
(tikzln ";"))
(define (tikz-e arg)
(tikz arg)
(tikz-end))
(define (tikz-draw [fill? #f])
(tikz (if fill? "\\fill " "\\draw ")))
(define (tikz-number x)
(if (integer? x)
(tikz (if (< (abs x) 1e-4) 0 (inexact->exact x)))
(tikz (/ (round (* x 10000)) 10000))))
(define (tikz-cm x)
(tikz-number x)
(tikz "cm"))
(define (tikz-coord c)
(tikz "(")
(tikz-number (cx c))
(tikz ",")
(tikz-number (cy c))
(unless (= (cz c) 0)
(tikz ",")
(tikz-number (cz c)))
(tikz ")"))
(define (tikz-pgfpoint c)
(unless (= 0 (cz c))
(error "Can't handle 3D coords"))
(tikz "\\pgfpoint{")
(tikz-cm (cx c))
(tikz "}{")
(tikz-cm (cy c))
(tikz "}"))
(define (point c)
(circle c 0.01))
(define (circle c r [fill? #f])
(tikz-draw fill?)
(tikz-coord c)
(tikz "circle(")
(tikz-cm r)
(tikz-e ")"))
(define (ellipse c r0 r1 fi [fill? #f])
(tikz-draw fill?)
(tikz "[shift={")
(tikz-coord c)
(tikz "}]")
(tikz "[rotate=")
(tikz-number (radians->degrees fi))
(tikz "]")
(tikz "(0,0)")
(tikz "ellipse(")
(tikz-cm r0)
(tikz " and ")
(tikz-cm r1)
(tikz-e ")"))
(define (arc c r ai af)
(tikz-draw)
(tikz-coord (+pol c r ai))
(tikz "arc(")
(tikz-number (radians->degrees ai))
(tikz ":")
(tikz-number
(radians->degrees
(if (> ai af)
(+ af (* 2 pi))
af)))
(tikz ":")
(tikz-cm r)
(tikz-e ")"))
(define (line pts)
(tikz-draw)
(tikz-coord (car pts))
(for ([pt (in-list (cdr pts))])
(tikz "--")
(tikz-coord pt))
(tikz-end))
(define (closed-line pts [fill? #f])
(tikz-draw fill?)
(for ([pt (in-list pts)])
(tikz-coord pt)
(tikz "--"))
(tikz-e "cycle"))
(define (spline pts [fill? #f])
(tikz-draw fill?)
(tikz "plot [smooth,tension=1] coordinates {")
(for ([pt (in-list pts)])
(tikz-coord pt))
(tikz-e "}"))
(define (closed-spline pts [fill? #f])
(tikz-draw fill?)
(tikz "plot [smooth cycle,tension=1] coordinates {")
(for ([pt (in-list pts)])
(tikz-coord pt))
(tikz-e "}"))
(define (rectangle p w h [fill? #f])
(tikz-draw fill?)
(tikz-coord p)
(tikz "rectangle")
(tikz-coord (+xy p w h))
(tikz-end))
(define (text txt p0 p1 h rot x-scale incl horiz-just vert-just)
(let ((scale-x (* 3.7 h (if x-scale x-scale 1)))
(scale-y (* 3.7 h)))
(tikz-draw)
(tikz "[anchor=base west]")
(tikz-coord p0)
(tikz "node[font=\\fontfamily{phv}\\selectfont,outer sep=0pt,inner sep=0pt")
(unless (and (= horiz-just 0) (= vert-just 0))
(tikz ",minimum width=")
(tikz-cm (abs (/ (- (cx p1) (cx p0)) scale-x)))
(tikz ",minimum height=")
(tikz-cm (abs (/ (- (cy p1) (cy p0)) scale-y))))
(unless (= rot 0)
(tikz ",rotate=")
(tikz-number (radians->degrees rot)))
(unless (= incl 0)
(tikz ",xslant=")
(tikz-number (sin incl)))
(tikz ",xscale=")
(tikz-number scale-x)
(tikz ",yscale=")
(tikz-number scale-y)
(tikz "]{")
(tikz txt)
(tikz-e "}")))
(define (text txt p h)
(let ((scale-x (* 3.7 h))
(scale-y (* 3.7 h)))
(tikz-draw)
(tikz "[anchor=base west]")
(tikz-coord p)
(tikz "node[font=\\fontfamily{phv}\\selectfont,outer sep=0pt,inner sep=0pt")
(tikz ",xscale=")
(tikz-number scale-x)
(tikz ",yscale=")
(tikz-number scale-y)
(tikz "]{")
(tikz txt)
(tikz-e "}")))
(define (set-view camera target lens)
(let ((v (-c camera target))
(contents (get-output-bytes tikz-port #t)))
(tikz "\\tdplotsetmaincoords{")
(tikz-number (radians->degrees (sph-psi v)))
(tikz "}{")
(tikz-number (+ (radians->degrees (sph-phi v)) 90))
(tikzln "}")
(tikzln "\\begin{tikzpicture}[tdplot_main_coords]")
(write-bytes contents tikz-port)
(tikzln "\\end{tikzpicture}")))