if ![winfo exists .mbar.cDomain] {
  _menu(Bar) . mbar {_Domain cDomain {}}
  pack forget .mbar.cDomain
  .mbar.cDomain configure -state disabled
}

PackData Subclass CurveData {
  Var domainType
  ClassVar {default {cdSolid}}
  ClassVar {data {domainType}}
  ClassVar {array _curve}
}

csObject Subclass basicCurve {
  Var F C D
  ClassVar {domain {-1 1 24}}
  ClassVar function {param t} f-setup

  ClassVar {delta .00001}
  ClassVar "save-list {[csObject get save-list] Data}"
  ClassVar "pack-list {[csObject get pack-list] Data}"
  CurveData Instance Data

  Method Select {} {
    .mbar.cDomain configure -state normal
    pack .mbar.cDomain -side left
    .mbar.color.menu entryconfigure "by Parameter" -state normal
  }
  Method Unselect {} {
    pack forget .mbar.cDomain
    .mbar.cDomain configure -state disabled
    .mbar.color.menu entryconfigure "by Parameter" -state disabled
  }

  Method F {t} {
    Vars function f-setup
    upvar [val param] param
    catch {set oldt $param}
    set param [uplevel expr double($t)]
    eval ${f-setup}
    _script(Run) $function
    set P [uplevel [Self Inherit point]]
    catch {set param $oldt}
    return $P
  }

  Method ApplyF {list} {
    Vars function f-setup
    Self InheritVars point
    upvar [val param] param
    catch {set oldt $param}
    eval ${f-setup}
    set results {}
    foreach t $list {
      set param [uplevel expr double($t)]
      _script(Run) $function
      lappend results [uplevel $point]
    }
    catch {set param $oldt}
    return $results
  }

  Method Df {t {d ""}} {
    Vars function f-setup
    Self InheritVars point
    global tcl_precision
    set prec $tcl_precision
    set tcl_precision 17
    upvar [val param] param
    if {$d == ""} {set d [val delta]}

    catch {set oldt $param}
    eval ${f-setup}
    set param [uplevel expr double($t)]
    _script(Run) $function
    set P0 [uplevel $point]
    set param [expr $param + $d]
    _script(Run) $function
    set P1 [uplevel $point]
    set V  [/ [- $P1 $P0] $d]
    set tcl_precision $prec
    set v {}; foreach e $V {lappend v [expr $e]}
    catch {set param $oldt}
    return $v
  }

  Method D2f {t {d ""}} {
    Vars function f-setup
    Self InheritVars point
    global tcl_precision
    set prec $tcl_precision
    set tcl_precision 17
    upvar [val param] param
    if {$d == ""} {set d [val delta]}

    catch {set oldt $param}
    eval ${f-setup}
    set param [uplevel expr double($t)]
    _script(Run) $function
    set P0 [uplevel $point]
    set param [expr $param + $d]
    _script(Run) $function
    set P1 [uplevel $point]
    set param [expr $param - $d - $d]
    _script(Run) $function
    set P2 [uplevel $point]
    set V1 [/ [- $P0 $P2] $d]
    set V2 [/ [- $P1 $P0] $d]
    set V  [/ [- $V2 $V1] $d]
    set tcl_precision $prec
    set v {}; foreach e $V {lappend v [expr $e]}
    catch {set param $oldt}
    return $v
  }

  Method Curvature {t {d ""}} {
    Vars function f-setup
    Self InheritVars point
    global tcl_precision
    set prec $tcl_precision
    set tcl_precision 17
    upvar [val param] param
    if {$d == ""} {set d [val delta]}

    catch {set oldt $param}
    eval ${f-setup}
    set param [uplevel expr double($t)]
    _script(Run) $function
    set P0 [uplevel $point]
    set param [expr $param + $d]
    _script(Run) $function
    set P1 [uplevel $point]
    set param [expr $param - $d - $d]
    _script(Run) $function
    set P2 [uplevel $point]
    set V1 [/ [- $P0 $P2] $d]
    set V2 [/ [- $P1 $P0] $d]
    set dTdt [/ [- [Unit $V2] [Unit $V1]] $d]
    set tcl_precision $prec
    catch {set param $oldt}
    return [expr [Norm $dTdt] / [Norm $V1]]
  }

  Method FFrame {t {d ""}} {
    Vars function f-setup
    Self InheritVars point
    global tcl_precision
    set prec $tcl_precision
    set tcl_precision 17
    upvar [val param] param
    if {$d == ""} {set d [val delta]}

    catch {set oldt $param}
    eval ${f-setup}
    set param [uplevel expr double($t)]
    _script(Run) $function
    set P0 [uplevel $point]
    set param [expr $param + $d]
    _script(Run) $function
    set P1 [uplevel $point]
    set param [expr $param - $d - $d]
    _script(Run) $function
    set P2 [uplevel $point]
    set V1 [/ [- $P0 $P2] $d]
    set V2 [/ [- $P1 $P0] $d]
    set V  [/ [- $V2 $V1] $d]
    set tcl_precision $prec
    set T [Unit $V1]; set B [Unit [>< $T $V]]; set N [>< $B $T]
    catch {set param $oldt}
    return [list $T $N $B]
  }

  Method Tangent {t {d ""}} {return [Unit [uplevel [list Self Df $t $d]]]}
  Method Normal {t {d ""}} {return [lindex [uplevel Self FFrame $t $d] 1]}
  Method Binormal {t {d ""}} {return [lindex [uplevel Self FFrame $t $d] 2]}

  Method Compute {} {
    Vars F C D domain param function f-setup
    Self InheritVars point

    Self Color Init
    upvar $param t
    set F {}; set C {}; set D {}

    foreach T [Self GetDomainList [uplevel [list subst $domain]]] {
      Self GetDomain $T
      lappend D [lreplace $T 0 0 [list $tm $tM $tn]]
      set colorfn [lindex $T 2]
      set _F {}; set _C {}
      eval ${f-setup}
      for {set i 0; set t $tm} {$i <= $tn} {incr i; set t [expr $i*$td+$tm]} {
	_script(Run) $function
	lappend _F [uplevel $point]
	lappend _C [eval [list $ColorFN $colorfn]]
      }
      lappend F $_F
      lappend C $_C
    }
    Self NormalizeColors
  }

  Method Recolor {} {
    Vars F C D param
    Self Color Init
    upvar $param t
    upvar _X _X

    set C {}; set f 0
    set dim [Self getDimension]
    foreach T $D {
      Self GetDomain $T
      set colorfn [lindex $T 2]
      set _C {}; set _F [lindex $F $f]; set k 0
      for {set i 0; set t $tm} {$i <= $tn} {incr i; set t [expr $i*$td+$tm]} {
	set xyz [lindex $_F $k]; incr k
	foreach n [array names _X] {set _X($n) [lindex $xyz $n]}
	lappend _C [eval [list $ColorFN $colorfn]]
      }
      lappend C $_C
    }
    Self NormalizeColors
  }

  Method NormalizeColors {} {
    uplevel {
      set nC {}
      foreach _C $C {lappend nC [Self Color Normalize $_C]}
      set C $nC
    }
  }

  Method WriteOOGL {file} {
    Vars F C D
    set isColored [Self Color isColored]
    set dim [Self getDimension]
    set d [llength $D]
    if {$d > 1} {puts $file "LIST"}
    for {set f 0} {$f < $d} {incr f} {
      Self GetDomain [lindex $D $f]
      if {$tn < 1} {
	puts $file "{ LIST }"
      } else {
	set tn1 [expr $tn+1]
	set _F [lindex $F $f]
	set _C [lindex $C $f]
	set dType "cd[lindex [lindex $D $f] 1]"
	if {$dType == "cd"} {set dType [Self Data get domainType]}
	puts $file "{"; $dType Write $file; puts $file "}"
      }
    }
  }

  Method GetDomainList {D} {
    if {[llength [lindex $D 0]] == 1} {set D [list $D]}
    set list {}
    foreach d $D {
      if {[llength [lindex $d 0]] == 1} {set d [list $d]}
      lappend list $d
    }
    return $list
  }

  Method InheritCurveDomainList {D object} {
    set DD {}
    foreach domain [basicCurve GetDomainList $D] {
      set v [string tolower [lindex $domain 0]]
      if {$v == "inherit" || $v == ""} {
        set D [uplevel 2 [list subst [$object get domain]]]
        foreach domain [$object GetDomainList $D] {lappend DD $domain}
      } else {lappend DD $domain}
    }
    return $DD
  }

  Method GetDomain {D} {
    set Dt [_expr(List) [lindex $D 0] 2]
    if {[llength $Dt] != 3} \
	{Error [join [list "Illegal domain range '$Dt';" \
                           "must be of the form 'min max divs'"]]}
    uplevel [list set Dt $Dt]
    uplevel {
      _expr(Let) {tm tM tn} $Dt
      if {$tn == 0} {set td 0} else {set td [expr ($tM-$tm)/double($tn)]}
    }
  }

  Method AutoDomain {} {
    global _object
    Self Save
    _File Changed 1
    if {$_object(autoUpdate) && [val computed]} {Self HandleOOGL} \
	else {_Object NeedsUpdate [Self]}
  }

  Method HandleColor {} {
    if ![val written] return
    Self Color set uncolored 0
    Parent HandleColor
  }

  Method ColorMenus {} {
    Vars param
    global _color
    .mbar.color.menu.parameter delete 0 end
    _menu(Menu) .mbar.color.menu parameter [list \
      [list Radio $param _color(by) [list set $param] {[_Current] AutoColor}]]
    if {$_color(by-old) == "set $param"} {set _color(by) $_color(by-old)}
  }
}


ooRoot Subclass CurveDomain {
  ClassVar names

  Method Instance {name menu {def {}}} {
    Vars names
    Parent Instance $name $def
    lappend names $name
    set underline [_menu(Underline) menu]
    eval [list .mbar.cDomain.menu insert [llength $names] radiobutton \
	      -label $menu -command {[_Current] AutoDomain} \
	      -variable _curve(domainType) -value $name] $underline
  }

  Method Write {file} {puts $file "LIST"}
}


CurveDomain Instance cdSolid "_Solid" {
  Method Write {file} {
    uplevel {
      if {$dim == 3 || $dim == 4} {
	if {$dim == 3} {puts $file "VECT"} else {puts $file "4VECT"}
	if {$isColored} {puts $file "1 $tn1 $tn1\n$tn1 $tn1\n"} \
	    else {puts $file "1 $tn1 0\n$tn1 0\n"}
	puts $file [join $_F \n]
	if {$isColored} {puts $file ""; puts $file [join $_C \n]}
      } else {
	if {$isColored} {
	  puts $file "CnOFF\n$dim"
	  puts $file "$tn1 $tn 0"
	  for {set k 0; set n [llength $_F]} {$k < $n} {incr k} \
	      {puts $file "[lindex $_F $k]  [lindex $_C $k]"}
	} else {
	  puts $file "nOFF\n$dim"
	  puts $file "$tn1 $tn 0"
	  puts $file [join $_F \n]
	}
	for {set k 0} {$k < $tn} {} {puts $file "2  $k [incr k]"}
      }
    }
  }
}

CurveDomain Instance cdDashes "_Dashes" {
  Method Write {file} {
    uplevel {
      if {$isColored} {
	if {$dim == 3} {puts $file "COFF"} else {puts $file "CnOFF\n$dim"}
	puts $file "$tn1 [expr $tn1/2] 0"
	for {set k 0; set n [llength $_F]} {$k < $n} {incr k} \
	    {puts $file "[lindex $_F $k]  [lindex $_C $k]"}
      } else {
	if {$dim == 3} {puts $file "OFF"} else {puts $file "nOFF\n$dim"}
	puts $file "$tn1 [expr $tn1/2] 0"
	puts $file [join $_F \n]
      }
      for {set k 0} {$k < $tn} {incr k} {puts $file "2  $k [incr k]"}
    }
  }
}

CurveDomain Instance cdDots "_Dots" {
  Method Write {file} {
    uplevel {
      if {$dim == 3} {puts $file "SKEL"} else {puts $file "nSKEL\n$dim"}
      puts $file "$tn1 $tn1"
      puts $file [join $_F \n]
      puts $file ""
      if {$isColored} {
	set i 0; foreach p $_C {puts $file "1  $i  $p"; incr i}
      } else {
	set len [llength $_F]
	for {set i 0} {$i < $len} {incr i} {puts $file "1  $i"}
      }
    }
  }
}
