2828
2929import spatialmath .base as smb
3030from spatialmath .base .types import *
31+ from spatialmath .base .vectors import orthogonalize
3132from spatialmath .baseposematrix import BasePoseMatrix
3233from spatialmath .pose2d import SE2
3334
@@ -651,8 +652,10 @@ def TwoVectors(
651652 axes in terms of the old axes. Axes are denoted by strings ``"x"``,
652653 ``"y"``, ``"z"``, ``"-x"``, ``"-y"``, ``"-z"``.
653654
654- The directions can also be specified by 3-element vectors, but these
655- must be orthogonal.
655+ The directions can also be specified by 3-element vectors. If the vectors are not orthogonal,
656+ they will orthogonalized w.r.t. the first available dimension. I.e. if x is available, it will be
657+ normalized and the remaining vector will be orthogonalized w.r.t. x, else, y will be normalized
658+ and z will be orthogonalized w.r.t. y.
656659
657660 To create a rotation where the new frame has its x-axis in -z-direction
658661 of the previous frame, and its z-axis in the x-direction of the previous
@@ -679,25 +682,41 @@ def vval(v):
679682 else :
680683 return smb .unitvec (smb .getvector (v , 3 ))
681684
682- if x is not None and y is not None and z is None :
685+ if x is not None and y is not None and z is not None :
686+ raise ValueError (
687+ "Only two vectors should be provided. Please set one to None."
688+ )
689+
690+ elif x is not None and y is not None and z is None :
683691 # z = x x y
684692 x = vval (x )
685693 y = vval (y )
694+ # Orthogonalizes y w.r.t. x
695+ y = orthogonalize (y , x , normalize = True )
686696 z = np .cross (x , y )
687697
688698 elif x is None and y is not None and z is not None :
689699 # x = y x z
690700 y = vval (y )
691701 z = vval (z )
702+ # Orthogonalizes z w.r.t. y
703+ z = orthogonalize (z , y , normalize = True )
692704 x = np .cross (y , z )
693705
694706 elif x is not None and y is None and z is not None :
695707 # y = z x x
696708 z = vval (z )
697709 x = vval (x )
710+ # Orthogonalizes z w.r.t. x
711+ z = orthogonalize (z , x , normalize = True )
698712 y = np .cross (z , x )
699713
700- return cls (np .c_ [x , y , z ], check = False )
714+ else :
715+ raise ValueError (
716+ "Insufficient number of vectors. Please provide exactly two vectors."
717+ )
718+
719+ return cls (np .c_ [x , y , z ], check = True )
701720
702721 @classmethod
703722 def AngleAxis (cls , theta : float , v : ArrayLike3 , * , unit : str = "rad" ) -> Self :
0 commit comments