#
# QCad
# (c) Q Solutions 1998
#
#
#
#
#
# Line Processing routines
#
#

#
# lineFindSeg list s - find segment closest to x y
# lineFindPoint list s - find point closest to x y
# lineNORM step list			- scans xy coords  clips and removes redundant segments.
# lineBreak step x1 y1 x2 y2 - breaks line into three segments clipped to step
# lineEndOver $l -		swaps line points end for end
# lineLastSeg $l -		returns index of last segment
# lineLastPoint $l -	returns  index of last point
# lineRSeg	seg list args - replaces seg in list 
# lineRPoint point list args - replace point x in list
# lineEndPoint end coords		- end 0 1 returns index to endpoint 0 or n
# lineEndSeg end coords		- end 0 1 returns index to endseg 0 or n
# lineIntercect hv x y coords  - find closest hv seg or point to x y return x y
# linePointLast coords		- returns last xy in list
# lineSegLast	coords		- returns last x1y1x2y2 in list
# linePointMax  coords		- returns index of last point in list
# lineSegMax	coords		- returns index of last segment in list
# linePointOther pt			- returns index of other point in segment
# linePointEnd end coords		- end 0 1 returns point at end
# lineSegEnd end coords		- end 0 1 returns segment at end
#
proc lineBreak {step args} {

	set list [join $args]
	set x1 [lindex $list 0]
	set y1 [lindex $list 1]
	set x2 [lindex $list 2]
	set y2 [lindex $list 3]

	if { [expr abs( $x2 - $x1) > abs($y2 - $y1)] } {
		#Log "Break H"
		set ny $y2
		set nx $x2
		set hx [geomClip $step [expr $x1 + ($x2 - $x1) / 2]]
		set hy $y1
		set n1 $hx
		set n2 $ny
	} else {
		#Log "Break V"
		set ny $y2
		set nx $x2
		set hy [geomClip $step [expr $y1 + ($y2  - $y1) / 2]]
		set hx $x1
		set n1 $nx
		set n2 $hy
	}
	return [list $x1 $y1 $hx $hy $n1 $n2 $nx $ny]
}



proc lineFindSeg { x0 y0 args} {

	set i 0
	set p -1
	set dxy 1e32
	set list [join $args]

	set sx [lindex $list 0]
	set sy [lindex $list 1]

	foreach {x y} [lrange $list 2 end] {

		set xbet [geomBetween $x0 [expr $sx -4] [expr $x + 4]]
		set ybet [geomBetween $y0 [expr $sy -4] [expr $y + 4]]
		#Log "$sx $x0 $x,   $sy $y0 $y    bet $xbet $ybet"
		if { $xbet && $ybet } {
			return $i
		}
		set sx $x
		set sy $y
		incr i
	}		
	return -1
}

proc lineFindPoint {x0 y0 args} {

	set i 0
	set p -1
	set dxy 1e32
	set list [join $args]

	set mindxy 1e32
	set seg [lineFindSeg $x0 $y0 $list]
	if { $seg == -1 } { return -1 }

	scan [lineGetSeg $seg $list] "%f %f %f %f" x1 y1 x2 y2
	if { [expr abs($x0 - $x1) + abs($y0 - $y1)] <  [expr abs($x0 - $x2) + abs($y0 - $y2)] } {
		return [expr $seg ]
	} else {
		return [expr $seg  + 1]
	}
}

proc lineGetSeg {seg args} {

	set list [join $args]
	set p1 [expr $seg * 2]
	set p2 [expr $p1 + 3]
	return [lrange $list $p1 $p2]
}

proc lineGetPoint {pt args} {

	set list [join $args]
	set p1 [expr $pt * 2]
	set p2 [expr $p1 + 1]
	return [lrange $list $p1 $p2]
}

proc lineRSeg {seg coords args} {

	set list [join $args]
	set p1 [expr $seg * 2]
	set p2 [expr $p1 + 3]
	return [join [lreplace $coords $p1 $p2 $list]]
}

proc lineRPoint {pt coords args} {

	set list [join $args]
	set p1 [expr $pt * 2]
	set p2 [expr $p1 + 1]
	return [join [lreplace $coords $p1 $p2 $list]]
}

proc lineSegLast {list} {

	#set list [join $args]
	set len [expr [llength $list] - 4]
	return [lrange $list $len end]
}

proc linePointLast {list} {

	#set list [join $args]
	set len [expr [llength $list] - 2]
	return [lrange $list $len end]
}

proc linePointOther {pt} {

	set opt [expr int($pt / 2) * 2]
	return [expr $opt + (1 - ($pt - $opt))]
}

proc lineSegMax {list} {

	set list [join $list]
	set len [expr [llength $list] / 2 - 2]
	return $len
}

proc linePointMax {list} {

	set list [join $list]
	set len [expr [llength $list] / 2 - 1]
	return $len
}

proc lineEndPoint {end list} {

	if { $end == 0 } { return 0}
	return [linePointMax $list]
}

proc lineEndSeg {end list} {

	if { $end == 0 } { return 0}
	return [lineSegMax $list]
}

proc linePointEnd {end list} {

	if { $end == 0 } { return [lineGetPoint 0 $list]}
	return [linePointLast $list]
}

proc lineSegEnd {end list} {

	if { $end == 0 } { return [lineGetSeg 0 $list]}
	return [lineSegLast $list]
}



proc lineIntercect {hv ix iy list} {

	#Log "Intcpt $hv $list"
	set x1 [lindex $list 0]
	set y1 [lindex $list 1]
	set p 0
	set i 1
	set dxymin [expr abs($ix - $x1) + abs($iy - $y1)]
	foreach { x2 y2 } [lrange $list 2 end] {
		set sl [lineSlope $x1 $y1 $x2 $y2]
		if {$sl != $hv } {
			#Log "sl $sl in $hv"
			if { $sl == 0 } {
			 	if { [geomBetween $ix $x1 $x2] } {
					#Log "intercept seg H $ix $y2"
					return [list $ix $y2]
				}
			} else {
			 	if { [geomBetween $iy $y1 $y2] } {
					#Log "intercept seg V $x2 $iy"
					return [list $x2 $iy]
				}
			}
		}
		set dxy [expr abs($ix - $x2) + abs($iy - $y2)]
		if { $dxy < $dxymin } {
			set dxymin $dxy
			set p $i
		}
		set x1 $x2
		set y1 $y2
		incr i
	}
	#Log "inetercect point $p"
	return [lineGetPoint $p $list]
}










