#!/usr/local/bin/wish -f
# ltxCurve2qBezier.tcl
# Approximation of a Curve through \qbezier sections for the
# LaTeX picture environment
#
# Author: M. Bernreuther, Feb 2001
#         Martin.Bernreuther@po.uni-stuttgart.de

# Constants
set Pi2 [expr 8.*atan(1.)]

# Global variables
set XOrigin 0
set YOrigin 0
set Angle 0
set Sections 4
set Type 1
set Parameter [list 1]
set Begend 0
set Mdiameter 0
set XYminmax [list]

# GUI
frame .forigin
frame .fsections
frame .ftype
frame .fparameter
frame .fmarkers
frame .fbuttons
pack .forigin .fsections .ftype .fparameter .fmarkers .fbuttons -fill both

label .labelorigin -text "Origin:"
label .labelxorigin -text "X:"
entry .xorigin -width 6 -relief sunken -textvariable XOrigin
label .labelyorigin -text "Y:"
entry .yorigin -width 6 -relief sunken -textvariable YOrigin
label .labelangle -text "Angle:"
entry .angle -width 6 -relief sunken -textvariable Angle
pack .labelorigin .labelxorigin .xorigin .labelyorigin .yorigin .labelangle .angle  -in .forigin -side left -expand 1 -fill x

label .labelsections -text "Sections:"
entry .sections -width 6 -relief sunken -textvariable Sections
pack .labelsections .sections  -in .fsections -side left -expand 1 -fill x

label .labelparameter -text "Radius:"
entry .radius -width 6 -relief sunken -textvariable Parameter
pack .labelparameter .radius -in .fparameter -side left -expand 1 -fill x

label .labeltype -text "Typ:"
radiobutton .radiobuttont1 -text "Circle" -variable Type -relief flat -value 1
bind .radiobuttont1 <1> {+
	.labelparameter configure -text "Radius:"
	set Parameter [list 1]
}
radiobutton .radiobuttont2 -text "Oval" -variable Type -relief flat -value 2
bind .radiobuttont2 <1> {+
	.labelparameter configure -text "a b:"
	set Parameter [list 1 1]
}
pack .labeltype .radiobuttont1 .radiobuttont2 -in .ftype -side left -expand 1 -fill x


checkbutton .checkbegend -text "begin/end" -variable Begend -relief flat
label .labelmdiameter -text "Markers diameter:"
entry .mdiameter -width 6 -relief sunken -textvariable Mdiameter
pack  .checkbegend .labelmdiameter .mdiameter -in .fmarkers -side left -expand 1 -fill x

button .go -text "Go" -command generatelatex
button .exit -text "Exit" -command exit
pack .go .exit -in .fbuttons -side left -expand 1 -fill x

proc UpdateMinMax {x y} {
	global XYminmax
	if {[llength $XYminmax]==4} {
		set xmin [lindex $XYminmax 0]
		set ymin [lindex $XYminmax 1]
		set xmax [lindex $XYminmax 2]
		set ymax [lindex $XYminmax 3]
		if {$x>$xmax} {
			set xmax $x
		} else { if {$x<$xmin} {
			set xmin $x
		}}
		if {$y>$ymax} {
			set ymax $y
		} else { if {$y<$ymin} {
			set ymin $y
		}}
		set XYminmax [list $xmin $ymin $xmax $ymax]
	} else {
		set XYminmax [list $x $y $x $y]
	}
}

proc Transform {px py dpx dpy} {
	global Pi2 XOrigin YOrigin Angle
	upvar $px x
	upvar $py y
	upvar $dpx dxdt
	upvar $dpy dydt

	if {$Angle!=0} {
		set a [expr $Pi2/360.*$Angle]
		set xn [expr $x*cos($a)+$y*sin($a)]
		set yn [expr -$x*sin($a)+$y*cos($a)]
		set x $xn
		set y $yn
		set dxdtn [expr $dxdt*cos($a)+$dydt*sin($a)]
		set dydtn [expr -$dxdt*sin($a)+$dydt*cos($a)]
		set dxdt $dxdtn
		set dydt $dydtn
	}

	if {$XOrigin!=0} {set x [expr $x+$XOrigin]}
	if {$YOrigin!=0} {set y [expr $y+$YOrigin]}
}

proc Curve {t} {
	global Pi2 Type Parameter Begend XYminmax

	set x 0
	set y 0
	set dxdt 0
	set dydt 0

	switch $Type {
		2
		{
			set a [lindex $Parameter 0]
			set b [lindex $Parameter 1]
			set x [expr $a*cos($Pi2*$t)]
			set y [expr $b*sin($Pi2*$t)]
			set dxdt [expr -$Pi2*$a*sin($Pi2*$t)]
			set dydt [expr $Pi2*$b*cos($Pi2*$t)]
		}
		1
		-
		default
		{
			set r [lindex $Parameter 0]
			set x [expr $r*cos($Pi2*$t)]
			set y [expr $r*sin($Pi2*$t)]
			set dxdt [expr -$Pi2*$r*sin($Pi2*$t)]
			set dydt [expr $Pi2*$r*cos($Pi2*$t)]
		}
	}

	Transform x y dxdt dydt

	if {$Begend} {UpdateMinMax $x $y}

	return [list $x $y $dxdt $dydt]
}

proc ControlPoint {p1 p2} {

	set x1 [lindex $p1 0]
	set y1 [lindex $p1 1]
	set dxdt1 [lindex $p1 2]
	set dydt1 [lindex $p1 3]
	set x2 [lindex $p2 0]
	set y2 [lindex $p2 1]
	set dxdt2 [lindex $p2 2]
	set dydt2 [lindex $p2 3]

	set hdxy12 [expr $dxdt1*$dydt2]
	set hdxy21 [expr $dxdt2*$dydt1]
	set hn [expr $hdxy12-$hdxy21]

	if {$hn!=0} {
		set xc [expr ($hdxy12*$x2-$hdxy21*$x1+($y1-$y2)*$dxdt1*$dxdt2)/$hn]
		set yc [expr ($hdxy12*$y1-$hdxy21*$y2+($x2-$x1)*$dydt1*$dydt2)/$hn]
	} else {
		set xc [expr .5*($x1+$x2)]
		set yc [expr .5*($y1+$y2)]
	}

	return [list $xc $yc]
}

proc OutputSection {p1 pc p2 pm} {
	global Mdiameter

	clipboard append [format "\\qbezier(%.3f,%.3f)(%.3f,%.3f)(%.3f,%.3f)\n" [lindex $p1 0] [lindex $p1 1] [lindex $pc 0] [lindex $pc 1] [lindex $p2 0] [lindex $p2 1]]
	if {$Mdiameter>0} {
		clipboard append [format "\\put(%.3f,%.3f){\\circle{%d}}\n" [lindex $pm 0] [lindex $pm 1] $Mdiameter]
	}

}

proc OutputLeader {} {
	global XYminmax Mdiameter

	set width 1
	set height 1
	set xoffset 0
	set yoffset 0

	set xmin [lindex $XYminmax 0]
	set ymin [lindex $XYminmax 1]
	set xmax [lindex $XYminmax 2]
	set ymax [lindex $XYminmax 3]

	set width [expr $xmax-$xmin+$Mdiameter]
	set height [expr $ymax-$ymin+$Mdiameter]
	set xoffset [expr $xmin-.5*$Mdiameter]
	set yoffset [expr $ymin-.5*$Mdiameter]

	set outputtext [format "\\begin{picture}(%.3f,%.3f)(%.3f,%.3f)\n" $width $height $xoffset $yoffset ]
	clipboard append $outputtext
}

proc OutputTrailer {} {
	set outputtext [format "\\end{picture}\n"]
	clipboard append $outputtext
}



proc generatelatex {} {
	global Sections XYminmax Begend

	if {$Sections<2} { set Sections 2 }

	clipboard clear
	set XYminmax [list]

	if {$Begend} {
		set t1 0.
		for {set i 1} {$i<=$Sections} {incr i 1} {
			set t2 [expr double($i)/$Sections]
			Curve $t2
			Curve [expr .5*($t1+$t2)]
			set t1 $t2
		}
		OutputLeader
	}

	set t1 0.
	set pos1 [Curve $t1]
	for {set i 1} {$i<=$Sections} {incr i 1} {
		set t2 [expr double($i)/$Sections]
		set pos2 [Curve $t2]
		set posc [ControlPoint $pos1 $pos2]
		set posm [Curve [expr .5*($t1+$t2)]]

		OutputSection $pos1 $posc $pos2 $posm

		set t1 $t2
		set pos1 $pos2
	}

	if {$Begend} OutputTrailer

	tk_dialog .dialog {Finished} {LaTeX commands written to clipboard} {} 0 {Ok}
}
