File : minifuns-ops.adb
with Ints, Messages;
use Ints, Messages;
pragma Elaborate (Ints);
package body MiniFuns.Ops is
T3: constant Integer := 3*Int(M_Trunc);
function Det(B: Mat3) return Scalar is
begin
return B.U.A*B.V.B-B.U.B*B.V.A;
end Det;
procedure Normalize(B: in out Bas3) is
--- want B.U.A=1 and B.V.B=1
begin
B.U.B := B.U.B/B.U.A;
B.U.C := B.U.C/B.U.A;
B.U.A := Scal_One;
B.V.A := B.V.A/B.V.B;
B.V.C := B.V.C/B.V.B;
B.V.B := Scal_One;
end Normalize;
procedure Translate(R0,S0: in Scalar; F: in out Vec3) is
begin
F.C := F.C-R0*F.A-S0*F.B;
end Translate;
procedure Prod(B: in Mat3; W1: in Vec3; W2: out Vec3) is
begin
W2.A := W1.A*B.U.A+W1.B*B.V.A;
W2.B := W1.A*B.U.B+W1.B*B.V.B;
W2.C := W1.A*B.U.C+W1.B*B.V.C+W1.C;
end Prod;
procedure Prod(B1,B2: in Mat3; B3: out Mat3) is
begin
Prod(B1,B2.U,B3.U);
Prod(B1,B2.V,B3.V);
end Prod;
procedure Inv(B: in out Mat3) is
IDet: constant Scalar := Inv(Det(B));
M: constant Mat3 := B;
begin
B.U.A := IDet*M.V.B;
B.U.B := -IDet*M.U.B;
B.V.A := -IDet*M.V.A;
B.V.B := IDet*M.U.A;
B.U.C := -(B.U.A*M.U.C+B.U.B*M.V.C);
B.V.C := -(B.V.A*M.U.C+B.V.B*M.V.C);
end Inv;
procedure Scale(S: in Scalar; B: in out Bas3) is
begin
B.U.A := Sqr(S)*B.U.A;
B.U.B := S*B.U.B;
B.V.A := Sqr(S)*B.V.A;
B.V.B := S*B.V.B;
end Scale;
procedure Center(B: in out Bas3; R0,S0: out Scalar) is
--- eliminate constants
begin
if B.U.C=Scal_Zero and then B.V.C=Scal_Zero then
R0 := Scal_Zero;
S0 := Scal_Zero;
else
S0 := Inv(Det(B));
R0 := (B.U.B*B.V.C-B.V.B*B.U.C)*S0;
S0 := (B.V.A*B.U.C-B.U.A*B.V.C)*S0;
B.U.C := Scal_Zero;
B.V.C := Scal_Zero;
end if;
end Center;
function Dom(U,V: in Vec3; R: in RadPair) return RadPair is
--- functions A*U+B*V+C
UA: constant Scalar := Scal(MaxNorm(U.A));
UB: constant Scalar := Scal(MaxNorm(U.B));
VA: constant Scalar := Scal(MaxNorm(V.A));
VB: constant Scalar := Scal(MaxNorm(V.B));
Det: constant Scalar := UA*VB-UB*VA;
Err: Boolean;
D1,D2: Rep;
N1,N2: Scalar;
begin
D1 := Inf(Scal(R(1))-Norm(U.C));
D2 := Inf(Scal(R(2))-Norm(V.C));
Err := (D1<Zero) or (D2<Zero);
N1 := (D1*VB-D2*UB)/Det;
N2 := (D2*UA-D1*VA)/Det;
D1 := Inf(N1);
D2 := Inf(N2);
Err := Err or (D1<Zero) or (D2<Zero);
if Err then
Error("MiniFuns.Ops.Dom error: domain violation",T3);
if M_Trunc then return R; end if;
end if;
return (D1,D2);
end Dom;
procedure Show1(N: in String; W: in Vec3) is
begin
Show1(N & "A =",W.A);
Show1(N & "B =",W.B);
Show1(N & "C =",W.C);
New_Line;
end Show1;
procedure Show1(N: in String; B: in Mat3) is
begin
Show1(N & "U.",B.U);
Show1(N & "V.",B.V);
end Show1;
----------------------------------------
function InvDet(A: Args) return Scalar is
begin
return Inv(Scal_One-A.A*Scal(A.B));
end InvDet;
procedure Approx(B: in Bas3; A: out Args) is
R0,S0: Scalar;
Bt: Bas3 := B;
begin
Normalize(Bt);
Center(Bt,R0,S0);
A.S0 := Approx(S0);
A.T0 := Approx(Sqrt(R0));
A.B := Approx(Bt.U.B);
A.A := Approx(Bt.V.A);
end Approx;
procedure Convert(A: in Args; B: out Bas3) is
R0: constant Scalar := A.T0*Scal(A.T0);
S0: constant Scalar := Scal(A.S0);
begin
B.U.A := Scal_One;
B.U.B := Scal(A.B);
B.U.C := Scal_Zero;
B.V.A := Scal(A.A);
B.V.B := Scal_One;
B.V.C := Scal_Zero;
Translate(R0,S0,B.U);
Translate(R0,S0,B.V);
end Convert;
procedure Coord(A1,A2: in Args; B: out Mat3) is
--- coordinates of A1 in "basis" A2
B1,B2: Mat3;
begin
Convert(A1,B1);
Convert(A2,B2);
Inv(B2);
Prod(B2,B1,B);
end Coord;
function CoordT2(A: Args) return Vec3 is
W: Vec3;
begin
W.A := InvDet(A);
W.B := (-A.B)*W.A;
W.C := A.T0*Scal(A.T0);
return W;
end CoordT2;
function CoordS1(A: Args) return Vec3 is
W: Vec3;
begin
W.B := InvDet(A);
W.A := (-A.A)*W.B;
W.C := Scal(A.S0);
return W;
end CoordS1;
procedure Scale(S: in Scalar; A1,A2: in Args; B: out Mat3) is
--- coordinates of scaled A1 in basis A2
B1,B2: Mat3;
begin
Convert(A1,B1);
Scale(S,B1);
Convert(A2,B2);
Inv(B2);
Prod(B2,B1,B);
end Scale;
------------------------------------
procedure ValTS(T,S: in Scalar; A: in Args; U,V: out Scalar) is
T0: constant Scalar := Scal(A.T0);
S0: constant Scalar := Scal(A.S0);
begin
V := A.A*(T+T0)*(T-T0)+(S-S0);
U := (T+T0)*(T-T0)+A.B*(S-S0);
end ValTS;
procedure Val(X,Y: in Scalar; A: in Args; U,V: out Scalar) is
begin
ValTS(X+Y,X-Y,A,U,V);
end Val;
function ValTSRadii(T,S: Scalar; A: Args) return RadPair is
U,V: Scalar;
begin
ValTS(T,S,A,U,V);
return (MaxNorm(U),MaxNorm(V));
end ValTSRadii;
function ValRadii(X,Y: Scalar; A: Args) return RadPair is
begin
return ValTSRadii(X+Y,X-Y,A);
end ValRadii;
function ValS1(U,V: Scalar; A: Args) return Scalar is
begin
return Scal(A.S0)+(V-A.A*U)*InvDet(A);
end ValS1;
function ValT2(U,V: Scalar; A: Args) return Scalar is
begin
return A.T0*Scal(A.T0)+(U-A.B*V)*InvDet(A);
end ValT2;
function TNorm(A: Args; R: RadPair) return Scalar is
U: constant Scalar := Scal(R(1));
V: constant Scalar := Scal(R(2));
begin
return Sqrt(A.T0*Scal(A.T0)+(U+abs(A.B)*V)*InvDet(A));
end TNorm;
function TNorm(D: Domain) return Scalar is
begin
return TNorm(D.A,D.R);
end TNorm;
procedure CheckDomainTS(E: in String; D: in Domain; T,S: in Scalar) is
U,V: Scalar;
begin
ValTS(T,S,D.A,U,V);
if MaxNorm(U)>D.R(1) then
Error(E & " error: |U|>Rho1",MaxNorm(U),D.R(1),T3);
end if;
if MaxNorm(V)>D.R(2) then
Error(E & " error: |V|>Rho2",MaxNorm(V),D.R(2),T3);
end if;
end CheckDomainTS;
procedure CheckDomain(E: in String; D: in Domain; X,Y: in Scalar) is
begin
CheckDomainTS(E,D,X+Y,X-Y);
end CheckDomain;
end MiniFuns.Ops;