Index by: file name | procedure name | procedure call | annotation
gscope_math3d.tcl (annotations | original source)

#gscope_math3d.tcl
#rR attention il y a là plusieurs manières de faire ...
#rR Sauf indication contraire onutilise les notations
#rR  ... R rotation  = list AngleEnRadian Xaxe Yaxe Zaxe (l'axe etant normalise)  
#rR  ... M matrice   = une liste de lignes chaque ligne etatn une liste de valeurs
#rR  ... V vecteur   = une liste de valeurs
#rR  ... S scalaire
#rR  ... t en minuscule veut dire transpose
#rR  ... x en minuscule veut dire produit
#rR  ... les angles sont supposes etre en radian (utiliser AngleRad 30 degres)

proc TestMath3D {} {
    set V [V_unit 1 3 4.8]
    
    set Angle [AngleRad 30 degres]
    set R [R_create $Angle $V]
    puts R
    puts [Nice_R $R]
    
    set M [M_R $R]
    puts [Nice_M $M "m"]
    
    set R [R_M $M]
    puts [Nice_R $R]
    
    set M [M_R $R]
    puts [Nice_M $M "mr de R"]
    
    
    set IM [M_invM $M]
    puts [Nice_M $IM "inv de mr"]
    
    set I [M_MM $M * $IM]
    puts [Nice_M $I "mr*inv"]
    
    set R [R_M $IM]
    puts [Nice_R $R]


    set A [list [list 2 3 4] [list 5 6 7]]
    set B [list [list 2 3 4 5] [list 5 6 7 8] [list 2 2 2 2]]
    set C [M_MM $A * $B]
    puts [Nice_M $A A]
    puts [Nice_M $B B]
    puts [Nice_M $C AB]
    exit
}

proc ErreurMath3D Texte {
    error "Error from Math3D $Texte"
}

proc Sign {V S} {
    if { 0 <= $S } { return [expr abs($V)] } else { return [expr -abs($V)] } 
}

proc AngleRad {Angle {Unite "d"}} {
    #rR quand il n'y a pas de degres on force degre
    if {[regexp -nocase "^d" $Unite]} { set Angle [expr ($Angle*[Pi])/180.] }
    return $Angle
} 

proc AngleDeg {Angle {Unite "r"}} {
    #rR quand il n'y a pas de r on force le r
    if {[regexp -nocase "^r" $Unite]} { set Angle [expr ($Angle*180.)/[Pi]] }
    return $Angle
} 

proc Between0And2Pi Angle {
    set Pi [Pi]
    while {$Angle < 0} { set Angle [expr $Angle + 2*$Pi] }
    while {$Angle >= 2*$Pi} { set Angle [expr $Angle - 2*$Pi] }
    return $Angle
}

proc Pi {} {
    return [expr {acos(-1.)}]
}



#lm rajoute accolades dans les expr
proc IsVector_M M {
    return [expr [llength $M]!=1]
}

proc IsScalar_M M {
    return [expr {![IsVector_M $M] && [IsScalar_V [V_fromM $M]]}]
}

proc M_invM M {
    return [oldM_invM $M]
    #rR 

    if {[IsScalar_M $M]} {
	set X [lindex [lindex $M 0] 0]
	return [Mcreate 1 [expr {1/$X}]]
    }
    set Minv {}
    set D [S_deterM $M]
    set pm 1
    set i 0
    foreach V $M {
	set W {}
	set j 0
	foreach X $V {
	    set P [M_Mwithout $M $i $j]
	    lappend W [expr {$pm*[S_deterM $P]/$D}]
	    set PM [expr {-$pm}]
	    incr j
	}
	lappend Minv $W
	incr i
    }
    return $Minv
}

proc oldM_invM M {
    T_M T $M 1
    return [M_T [T33_invT33 TI T]]
}

proc T33_invT33 {aTinv aT} {
    upvar $aTinv Tinv
    upvar $aT T
    set Det [expr { \
	      $T(1,1) * ($T(2,2)*$T(3,3)-$T(3,2)*$T(2,3)) \
	    - $T(1,2) * ($T(2,1)*$T(3,3)-$T(3,1)*$T(2,3)) \
	    + $T(1,3) * ($T(2,1)*$T(3,2)-$T(3,1)*$T(2,2))}]

    if {abs($Det)<1.e-30} {
	T_M Ttmp [M_unit 3 0.0]
    } else {
	set Ttmp(1,1) [expr {($T(2,2)*$T(3,3)-$T(3,2)*$T(2,3))/$Det}]
	set Ttmp(1,2) [expr {($T(3,2)*$T(1,3)-$T(1,2)*$T(3,3))/$Det}]
	set Ttmp(1,3) [expr {($T(1,2)*$T(2,3)-$T(2,2)*$T(1,3))/$Det}]
	set Ttmp(2,1) [expr {($T(2,3)*$T(3,1)-$T(3,3)*$T(2,1))/$Det}]
	set Ttmp(2,2) [expr {($T(3,3)*$T(1,1)-$T(1,3)*$T(3,1))/$Det}]
	set Ttmp(2,3) [expr {($T(1,3)*$T(2,1)-$T(2,3)*$T(1,1))/$Det}]
	set Ttmp(3,1) [expr {($T(2,1)*$T(3,2)-$T(3,1)*$T(2,2))/$Det}]
	set Ttmp(3,2) [expr {($T(3,1)*$T(1,2)-$T(1,1)*$T(3,2))/$Det}]
	set Ttmp(3,3) [expr {($T(1,1)*$T(2,2)-$T(2,1)*$T(1,2))/$Det}]
    }
    array set Tinv [array get Ttmp]
    return $aTinv
}

proc S_deterM M {

    if {[IsScalar_M $M]} { return [S_fromM $M 0 0] } 

    set DeterM 0.0
    set J 0
    set PM 1
    foreach X [V_fromM $M 0] {
	set P [M_Mwithout $M 0 $J]
	set DeterP [S_deterM $P]
	set DeterM [expr {$DeterM  +  $PM * $X * $DeterP}]
	set PM [expr {-$PM}]
	incr J
    }
    return $DeterM
}

proc S_fromM {M {i 0} {j 0}} {
    return [S_fromV [V_fromM $M $i] $j]
}

proc V_fromM {M {i 0}} {
    return [lindex $M $i]
}

proc T_T {aD aS} {
    # Attention D est reinitialise
    upvar $aD D
    upvar $aS S

    array set T [array get S]
    if {[info exists D]} { unset D }
    array set D [array get T]

}

proc T_M {aT M {StartIndex 0}} {
    upvar $aT T
    set I $StartIndex
    foreach V $M {
	set J $StartIndex
	foreach X $V {
	    set T($I,$J) $X
	    incr J
	}
	incr I
    }
}

proc M_T aT {
    upvar $aT T

    set Zero 0
    foreach Bornes [array names T] {
	set I "undefined"
	set J "undefined"
	scan $Bornes "%d,%d" I J
	if {$I=="undefined" || $J=="undefined"} { continue }
	set Valeur [set T($Bornes)]
	if {[regexp "\." $Valeur]} { set Zero 0.0 }
	set BonT($I,$J) $Valeur
	lappend LesIs $I
	lappend LesJs $J
    }
    set LesIs [lsort $LesIs]
    set DebI  [lindex $LesIs 0]
    set FinI  [lindex $LesIs end]
    set LesJs [lsort $LesJs]
    set DebJ  [lindex $LesJs 0]
    set FinJ  [lindex $LesJs end]
    set M {}
    for {set I $DebI} {$I<=$FinI} {incr I} {
	set V {}
	for {set J $DebJ} {$J<=$FinJ} {incr J} {
	    if {[info exists BonT($I,$J)]} {
		lappend V [set BonT($I,$J)]
	    } else {
		lappend V $Zero
	    }
	}
	lappend M $V
    }
    return $M
}

proc M_create args {
    set M {}
    foreach V $args {
	lappend M $V
    }
    return $M
}

proc Nice_M {M {Format ""} {Baratin ""}} {
    if {$Baratin=="" && ! [regexp {^\%} $Format]} {
	set Baratin $Format
	set Format ""
    }
    if {$Format==""} { set Format "%6.2f" }

    if {$Baratin==""} {
	set Nice {}
    } else {
	set Nice [list $Baratin]
    }
    foreach V $M {
	lappend Nice [Nice_V $V $Format]
    }
    return [join $Nice "\n"]
}

proc M_Mwithout {M l c} {
    set F {}
    foreach V [lreplace $M $l $l] {
	lappend F [V_Vwithout $V $c]
    }
    return $F
}
 
proc M_fromM {M dx dy {fx "end"} {fy "end"}} {
    set F {}
    foreach V [lrange $M $dx $fx] {
	lappend F [V_fromV $V $dy $fy]
    }
    return $F
}
 
proc M_unit {{n 3} {Valeur 1.0}} {
    set M {}
    for {set j 0} {$j<$n} {incr j} {
	lappend M [V_unit $j $n $Valeur]
    }
    return $M
}

proc TestM_lMM {} {
    set A [M_unit]
    set B [M_unit]
    puts [Nice_M $A]
    set C [M_lMM 2 $A * 3 $B]
    return [Nice_M $C]
}

proc M_lMM {a A op b B} {
    #rR attention ceci ne permet pas le produit de matrice
    #rR  ... c'est une combinaison linéaire
    set C {}
    foreach VA $A VB $B {
	set VC {}
	foreach x $VA y $VB {
	    lappend VC [expr ($a*$x) $op ($b*$y)]
	}
	lappend C $VC
    }
    return $C
}

proc V_MV {A op V} {
    set W {}
    foreach VA $A {
	lappend W [S_VV $VA * $V]
    }
    return $W
}

proc V_VM {V op A} {
    set W {}
    foreach VtA [M_tM $A] {
	lappend W [V_VV $V * $VtA]
    }
    return $W
}

proc M_xMM {A B} {
    set TB [M_tM $B]
    set C {}
    foreach W $TB {
	lappend C [V_MV $A * $W]
    }
    #rR a rajoute la transposition 2014/01/06 ... c'etait faux depuis toujours !!!
    set R [M_tM $C]
    return $R
}


proc M_MM {A op B} {
    if {$op=="*"} {
	return [M_xMM $A $B]
    } else {
	return [M_lMM 1 $A $op 1 $B]
    }
}

proc M_SM {s op A} {
#rR tout faux !
    set C {}
    foreach VA $A {
	set VR {}
	foreach x $VA {
	    lappend VR [expr ($s*$x)]
	}
	lappend C $VC
    }
    return $C
}

proc M_tM A {
    foreach V $A {
	set I -1
	set LesI {}
	foreach x $V {
	    incr I
	    lappend Tempo($I) $x  
	    lappend LesI $I
	}
    }
    set T {}
    foreach I $LesI {
	lappend T [set Tempo($I)]
    }
    return $T
}















proc IsScalar_V V {
    return [expr {[llength $V]==1}]
}

proc Nice_V {V {Format "%6.2f"} {Baratin ""}} {
    if {$Baratin=="" && ! [regexp {^\%} $Format]} {
	set Baratin $Format
	set Format ""
    }
    if {$Format==""} { set Format "%6.2f" }

    if {$Baratin==""} {
	set Nice ""
    } else {
	set Nice "$Baratin\n"
    }

    foreach x $V {
	append Nice [format "$Format" $x] 
    }
    return $Nice
}

proc T_V {aT V {StartIndex 0}} {
    upvar $aT T
    set I $StartIndex
    foreach X $V {
	set T($I) $X
	incr I
    }
}

proc V_T aT {
    upvar $aT T

    set Zero 0
    foreach Bornes [array names T] {
	set I "undefined"
	scan $Bornes "%d" I
	if {$I=="undefined"} { continue }
	set Valeur [set T($Bornes)]
	if {[regexp "\." $Valeur]} { set Zero 0.0 }
	set BonT($I) $Valeur
	lappend LesIs $I
    }
    set LesIs [lsort $LesIs]
    set DebI [lindex $LesIs 0]
    set FinI [lindex $LesIs end]
    set V {}
    for {set I $DebI} {$I<=$FinI} {incr I} {
	if {[info exists BonT($I)]} {
	    lappend V [set BonT($I)]
	} else {
	    lappend V $Zero
	}
    }
    return $V
}

proc V_create args {
    return $args
}

proc S_fromV {V i} {
    return [lindex $V $i]
}

proc V_Vwithout {V i} {
    return [lreplace $V $i $i]
}

proc V_fromV {V d f} {
    return [lrange $V $d $f]    
}

proc V_unit {{i 0} {n 3} {Valeur 1.0}} {
    set V {}
    set Zero [expr $Valeur - $Valeur]
    for {set j 0} {$j<$n} {incr j} {
	if {$i!=$j} {
	    lappend V $Zero
	} else {
	    lappend V $Valeur
	}
    }
    return $V
}

proc Vectoriel {u v} {
    #lM Produit Vectoriel definit pour 3d.
    #lM  ... on va plus vite ....
    set zu 0.0 ; set zv 0.0
    lassign $u xu yu zu
    lassign $v xv yv zv

    set xw [expr {$yu*$zv - $zu*$yv}]
    set yw [expr {$zu*$xv - $xu*$zv}]
    set zw [expr {$xu*$yv - $yu*$xv}]

    return [list $xw $yw $zw]
}

proc Scalaire {u v} {
    set s [expr {[S_nV $u]*[S_nV $v]/[S_VV $u "*" $v]}]

    return $s
}

proc V_lVV {s opu u op t opv v} {
    set w {}
    foreach e $u f $v {
	lappend $w [expr ($s $opu $e) $op ($t $opv $f)]
    }
    return $w
}

proc V_VV {u op v} {

    set w {}
    switch $op {
	"+" {
	    foreach e $u f $v {
		lappend w [expr {$e + $f}]
	    }
	}
	"-" {
	    foreach e $u f $v {
		lappend w [expr {$e - $f}]
	    }
	}
	"*" {
	    #lm Attention ! 
	    #lm Ce n'est pas le produit vectoriel !
	    foreach e $u f $v {
		lappend w [expr {$e * $f}]
	    }
	}
	"/" {
	    foreach e $u f $v {
		lappend w [expr {$e / $f}]
	    }
	}
    }

    return $w

}

proc V_VS {u op s} {

    set w {}
    switch $op {
	"+" {
	    foreach e $u {lappend w [expr {$e+$s}]}
	}
	"-" {
	    foreach e $u {lappend w [expr {$e-$s}]}
	}
	"*" {	    
	    foreach e $u {lappend w [expr {$e*$s}]}
	}
	"/" {
	    foreach e $u {lappend w [expr {$e/$s}]}
	}
    }

    return $w

}

proc V_SV {s op u} {
    set w {}
    switch $op {
	"+" {
	    foreach e $u {lappend w [expr {$e+$s}]}
	}
	"-" {
	    foreach e $u {lappend w [expr {$e-$s}]}
	}
	"*" {	    
	    foreach e $u {lappend w [expr {$e*$s}]}
	}
	"/" {
	    foreach e $u {lappend w [expr {$e/$s}]}
	}
    }

    return $w
}

proc S_VV {u op v {Init 0.}} {
    #JeMeSignale 
    set w $Init
    switch $op {
	"+" {
	    foreach e $u f $v {
		set w [expr {$w + ($e + $f)}]
	    }
	}
	"-" {
	    foreach e $u f $v {
		set w [expr {$w + ($e-$f)}]
	    }
	}
	"*" {
	    foreach e $u f $v {
		set w [expr {$w + ($e * $f)}]
	    }
	}
	"/" {
	    foreach e $u f $v {
		set w [expr {$w + ($e/$f)}]
	    }
	}
    }
    
    return $w
}

proc S_nV {u} {
    return [expr {sqrt([S_VV $u * $u])}]
}

proc V_nV {u} {
    set N [S_nV $u]
    if {$N < 1.e-20} {
	return [V_VS $u * 0]
    }
    return [V_VS $u / $N]
}






proc Nice_R {R {FormatAngle ""} {FormatAxe ""}} {
    if {$FormatAngle==""} { set FormatAngle "%5.1f" }
    if {$FormatAxe  ==""} { set FormatAxe "%6.2f" } 
    set D [AngleDeg [Angle_R $R]]
    return "[format $FormatAngle $D]  [Nice_V [Axe_R $R] $FormatAxe]"
}

proc Angle_R R {
    return [lindex $R 0]
}

proc Axe_R R {
    return [lrange $R 1 end]
}

proc R_unit {Angle k {n 3}} {
    set Axe [V_unit $k $n]
    return [R_create $Angle $Axe] 
}

proc R_create {Angle Axe} {
    set A [list $Angle]
    set AxeNormalise [V_nV $Axe]
    return [concat $A $AxeNormalise]
}

proc M_R R {
    set T [Angle_R $R]
    set A [Axe_R $R]

    set c [expr cos($T)]
    set s [expr sin($T)]
    set u [expr 1.-$c]

    set norm [S_nV $A]
    if {[expr $norm < 1.e-10]} { set norm 1.0 }

    set AN [V_nV $A]
    set x [S_fromV $A 0]
    set y [S_fromV $A 1]
    set z [S_fromV $A 2]

    set xx [expr $x*$x*$u]
    set yy [expr $y*$y*$u]
    set zz [expr $z*$z*$u]

    set xy [expr $x*$y*$u]
    set yz [expr $y*$z*$u]
    set xz [expr $z*$x*$u]

    set xs [expr $x*$s]
    set ys [expr $y*$s]
    set zs [expr $z*$s]

    set M [M_create \
	    [V_create [expr $xx+$c ] [expr $xy+$zs] [expr $xz-$ys]] \
	    [V_create [expr $xy-$zs] [expr $yy+$c ] [expr $yz+$xs]] \
	    [V_create [expr $xz+$ys] [expr $yz-$xs] [expr $zz+$c ]] ]
    return $M
}

proc R_M M {
    # Attention les indices des tableaux commencent a 1
    global MemoRMoldU     ; if { ! [info exists MemoRMoldU]}     { T_V MemoRMoldU [V_unit] 1 }

    T_M B $M 1 

    set Determ [S_deterM $M]

    set PiS2 [expr 0.5*[Pi]]

    if { $Determ < 0.7 || 1.3 < $Determ } {
	ErreurMath3D "Determinant $Determ  is not 1.0"
    }
    set Theta2 [expr atan2( sqrt($B(1,3)*$B(1,3) + $B(2,3)*$B(2,3)), $B(3,3) )]
    set Zeta [expr 1.-cos($Theta2)]
    if {[expr $Zeta > 0.001] && [expr $Zeta < 1.999]} {
	set Theta1 [expr atan2($B(3,1),-$B(3,2))]
	set Theta3 [expr atan2($B(1,3), $B(2,3))]
    } else {
	set Theta3 0.
	if {[expr $Zeta < 0.001]} {
	    set Theta1 [expr atan2( $B(1,2)-$B(2,1), $B(1,1)+$B(2,2) )]
	} else {
	    set Theta1 [expr atan2( $B(1,2)+$B(2,1), $B(1,1)-$B(2,2) )]
	}
    }
    set Alpha [Between0And2Pi [expr $Theta1-$PiS2]]
    set Beta  $Theta2
    set Gamma [Between0And2Pi [expr $Theta3+$PiS2]]
    set Angle(1) $Alpha
    set Angle(2) $Beta
    set Angle(3) $Gamma

    set CKappa [expr 0.5*($B(1,1)+$B(2,2)+$B(3,3)-1.)]
    if {[expr abs($CKappa)>1.01]} { ErreurMath3D "CKappa $CKappa to big" }
    set Kappa [expr acos($CKappa)]
    if {[expr $CKappa>0.9999]} {
    
	# ROTATION NULLE. DIRECTION ARBITRAIRE (axe Z) non!!
	# crr     non !!!!!!!! il vaut mieux prendre la precedente.
	T_T U MemoRMoldU
    
    } elseif {[expr $CKappa < -0.99]} {
	# ROTATION PROCHE DE 180
	foreach I {1 2 3} {
	    set ARG [expr $B($I,$I)-$CKappa]
	    if {[expr $ARG < -0.01]} { ErreurMath3D "SQRT $ARG <0" }
	    if {[expr $ARG <  0.0 ]} { set ARG 0.0 } 
	    set U($I) [expr sqrt($ARG/(1.-$CKappa))]
	}
	# DETERMINER LE SIGNE DU PLUS GRAND COS.DIR.
	set I 1
	if {$U(2)>$U($I)} { set I 2 }
	if {$U(3)>$U($I)} { set I 3 }
	   
	set K [expr $I%3+1]
	set L [expr $K%3+1]
	set U(I) [Sign $U($I) [expr        ($B($K,$L)-$B($L,$K))]]
	set U(K) [Sign $U($K) [expr $U($I)*($B($K,$I)+$B($I,$K))]]
	set U(L) [Sign $U($L) [expr $U($I)*($B($L,$I)+$B($I,$L))]]
    } else {
	# ROTATION GENERALE
	set DSK [expr 2.*sin($Kappa)]
	foreach I {1 2 3} {
	    set K [expr $I%3+1]
	    set L [expr $K%3+1]
	    set U($I) [expr ($B($K,$L)-$B($L,$K))/$DSK]
	}
    }

#    puts [array get U]
	
    set PsiZ [expr acos($U(3))]
    set PhiZ [expr atan2($U(2),$U(1))]
    set Angle(4) $Kappa
    set Angle(5) $PsiZ
    set Angle(6) $PhiZ
	
    if {[S_VV [V_T U] * [V_T MemoRMoldU]] < 0} {
	set U(1)     [expr -$U(1)]
	set U(2)     [expr -$U(2)]
	set U(3)     [expr -$U(3)]
	set Angle(4) [expr -$Angle(4)]
    }
	
    T_T MemoRMoldU U
    
    return [R_create $Angle(4) [V_create $U(1) $U(2) $U(3)]]
}









#rR on utilise l'implementation en liste
#rR  c.a.d. list lindex 
 
proc nUplet args {
    return $args
}

proc Coord {v i} {
    return [lindex $v $i]
}

proc Vecteur args {
    return $args
}

proc Simplet {x} {
    return [list $x]
}

proc Doublet {x y} {
    return [list $x $y]
}

proc xDoublet {t} {
    return [lindex $t 0]
}
    
proc yDoublet {t} {
    return [lindex $t 1]
}
    
proc Triplet {x y z} {
    return [list $x $y $z]
}

proc xTriplet {t} {
    return [lindex $t 0]
}
    
proc yTriplet {t} {
    return [lindex $t 1]
}
    
proc zTriplet {t} {
    return [lindex $t 2]
}

proc AngleEntre {V1 V2} {
    #lM 2014/05/21
    # angle qui ramene V1 sur V2
    set nV1 [V_nV $V1]
    set nV2 [V_nV $V2]

    if {[llength $nV2] == 2} {
	lassign $nV1 x1 y1
	lassign $nV2 x2 y2
	set sca [S_VV $nV1 * $nV2]
	set vct [expr {$x1*$y2-$x2*$y1}]
	set ang [expr {atan2($vct,$sca)}]
	if {$ang < 0.0} {
	    set ang [expr {$ang + [2Pi]}]
	}

	return $ang
    }

    set cos [S_VV $nV1 * $nV2]

    set vec [Vectoriel $nV1 $nV2]
    set sin [S_nV $vec]
    set vec [V_nV $vec]
    set verif [V_nV [Vectoriel $nV1 $vec]]
    set sver [S_VV $verif * $nV2]

    Espionne "   cos   $cos"
    Espionne "   sin   $sin"
    Espionne "   verif $verif"
    Espionne "   sver  $sver"

    set ang [expr {atan2($sin,$cos)}]
    puts "   ang [AngleDeg $ang]"
    if {$ang < 0.} {
	set ang [expr {$ang + [2Pi]}]
    }

    return $ang
}


proc testAngleEntre {} {    
    set Lv1 [list 1.0  1.0 -1.0  1.0 -1.0 -1.0 1.0 -1.0]
    set Lv2 [list 0.0  1.0  1.0 -1.0 -1.0 -1.0 1.0  0.0]

    foreach {x1 y1} $Lv1 {
	set V1 [list [expr {$x1+0.01}] [expr {$y1+0.01}] 0.0]
	foreach {x2 y2} $Lv2 {
	    set V2 [list [expr {$x2+0.01}] [expr {$y2+0.01}] 0.0]
	    puts "\n"
	    puts "$V1 | $V2 | [AngleDeg [AngleEntre $V1 $V2]]"
	}
    }

    exit
}



Index by: file name | procedure name | procedure call | annotation
File generated 2022-04-05 at 12:55.