File : lattice.adb
with Messages, Reps.Ops;
use Messages, Reps.Ops;
package body Lattice is
function ToInt(I: Integer) return Int is
--- such sillyness should not be necessary
begin
if I >= 0 then
return Int(I);
else
return Int(I-Integer'First)-(Int(-1-Integer'First)+1);
end if;
end ToInt;
function Pt(I1,I2,I3: Integer) return IPoint is
begin
return (I1,I2,I3);
end Pt;
function Coord(L: IPoint) return RPoint is
E: RPoint;
begin
E(1) := Rep(L(1)+L(2))*Half;
E(2) := Rep(L(1)-L(2))*S3/Six;
E(3) := Rep(L(3))*S6/Three;
return E;
end Coord;
function RDist(L1,L2: IPoint) return Rep is
R: constant RPoint := Coord(L2)-Coord(L1);
begin
return Sqrt(R*R);
end RDist;
function "*"(P,Q: IPoint) return Rep is
begin
return (P(1)*Q(2)+P(2)*Q(1)+2*(P(1)*Q(1)+P(2)*Q(2)+2*P(3)*Q(3)))/Six;
end "*";
procedure Translate(L: in IPoint; K: in out Int) is
begin
K := K+ToInt(L(1))+Fac1*(ToInt(L(2))+Fac1*ToInt(L(3)));
end Translate;
procedure Translate(L: in IPoint; B: in out IntVec) is
D: constant Int := ToInt(L(1))+Fac1*(ToInt(L(2))+Fac1*ToInt(L(3)));
begin
for K in B'Range loop
B(K) := B(K)+D;
end loop;
end Translate;
procedure CountNbors(B: in BallPtr; N,Nfix: out Integer) is
begin
N := 0;
Nfix := 0;
if B=null then return; end if;
for K in 1 .. 12 loop
if B.Nb(K) /= null then
N := N+1;
if B.Nb(K).ID=0 then Nfix := Nfix+1; end if;
end if;
end loop;
end CountNbors;
procedure FreeAll(B: in out PolysPtr) is
begin
if B=null then return; end if;
for K in B'Range loop
if B(K) /= null then Free(B(K)); end if;
end loop;
Free(B);
end FreeAll;
procedure ResetParam(B: in PolyPtr) is
begin
B.L := 0; B.M := 1; B.R := Zero;
end ResetParam;
procedure CopyParam(B: in Poly; C: in out Poly) is
begin
C.L := B.L; C.M := B.M; C.R := B.R;
end CopyParam;
procedure CopyParam(B,C: in PolyPtr) is
begin
C.L := B.L; C.M := B.M; C.R := B.R;
end CopyParam;
function NumMovable(B: PolyPtr) return Natural is
begin
for K in 1 .. B.L loop
if B.V(K) < Fac3 then return K-1; end if;
end loop;
return B.L;
end NumMovable;
function RDist(K: Int; B: PolyPtr) return Rep is
P: constant IPoint := UnPack(K);
D: Rep := Rep'Last;
begin
for N in 1 .. B.L loop
D := Rep'Min(RDist(P,UnPack(B.V(N))),D);
end loop;
return D;
end RDist;
procedure AddSpace(N: in Positive; B: in out PolyPtr) is
begin
if B.L+N <= B.V'Last then return; end if;
declare
C: PolyPtr := new Poly(B.L+N);
begin
CopyParam(B,C);
C.V(1 .. C.L) := B.V(1 .. C.L);
Free(B);
B := C;
end;
end AddSpace;
procedure Translate(L: in IPoint; B: in Poly; C: out Poly) is
D: constant Int := ToInt(L(1))+Fac1*(ToInt(L(2))+Fac1*ToInt(L(3)));
begin
CopyParam(B,C);
for I in 1 .. B.L loop
C.V(I) := B.V(I)+D;
end loop;
end Translate;
function ">"(A,B: PolyPtr) return Boolean is
begin
for N in 1 .. Integer'Min(A.L,B.L) loop
if A.V(N) /= B.V(N) then return A.V(N)>B.V(N); end if;
end loop;
return A.L>B.L;
end ">";
procedure Trim(B: in out PolysPtr; Size: in Natural) is
--- has undesired effects if B contains duplicate elements
C: PolysPtr;
begin
if Size >= B'Last then return; end if;
C := new Polys(1 .. Size);
C.all(1 .. Size) := B.all(1 .. Size);
for K in Size+1 .. B'Last loop
Free(B(K));
end loop;
Free(B);
B := C;
end Trim;
procedure SetDim(N1,N2,N3: in Positive) is
begin
Dim1 := N1; Dim2 := N2; Dim3 := N3;
IZero := Pack((0,0,0));
end SetDim;
function InPatch(L: IPoint) return Boolean is
begin
return (abs(L(1)) <= Dim1) and (abs(L(2)) <= Dim2) and (abs(L(3)) <= Dim3);
end InPatch;
function FitsType(L: IPoint) return Boolean is
Type12: constant Integer := (L(1)-L(2)) mod 3;
Type3: constant Integer := L(3) mod LayerPeriod;
begin
return Type3=Type12;
end FitsType;
function Check(I: Int) return Boolean is
P: constant IPoint := UnPack(I);
begin
return InPatch(P) and then FitsType(P);
end Check;
function Pack(L: IPoint) return Int is
begin
return Int(Dim1+L(1))+Fac1*(Int(Dim2+L(2))+Fac1*Int(Dim3+L(3)));
end Pack;
procedure Pack(L: in IPoint; L4: in Natural; K: out Int) is
begin
K := Int(Dim1+L(1))+Fac1*(Int(Dim2+L(2))+Fac1*Int(Dim3+L(3)));
if L4>0 then K := K+Fac3; end if;
end Pack;
function UnPack(K: Int) return IPoint is
X: constant Integer := Integer( K and Mask1)-Dim1;
Y: constant Integer := Integer((K/Fac1) and Mask1)-Dim2;
Z: constant Integer := Integer((K/Fac2) and Mask1)-Dim3;
begin
return (X,Y,Z);
end UnPack;
procedure UnPack(K: in Int; L: out IPoint; L4: out Natural) is
begin
L(1) := Integer( K and Mask1)-Dim1;
L(2) := Integer((K/Fac1) and Mask1)-Dim2;
L(3) := Integer((K/Fac2) and Mask1)-Dim3;
if K<Fac3 then L4 := 0; else L4 := 1; end if;
end UnPack;
procedure Copy(B: in Blob; P: in out PolyPtr) is
begin
if P=null then
P := new Poly(B.L);
elsif P.V'Last<B.L then
Free(P);
P := new Poly(B.L);
else
ResetParam(P);
end if;
P.L := B.L;
for N in 1 .. P.L loop
Pack(B.V(N).IP,B.V(N).ID,P.V(N));
end loop;
end Copy;
procedure AddBallPlus(A: in Ball; B: in out PolyPtr) is
--- assumes ball has correct ID
K: constant Integer := B.L+1;
begin
AddSpace(13,B);
Pack(A.IP,A.ID,B.V(K));
for N in 1 .. 12 loop
Pack(A.Nb(N).IP,A.Nb(N).ID,B.V(K+N));
end loop;
B.L := K+12;
end AddBallPlus;
procedure FreeAll(E: in out PExpPtr) is
begin
for I in E'Range loop FreeAll(E(I)); end loop;
Free(E);
end FreeAll;
function IDiff(A,B: PolyPtr) return Integer is
begin
for N in 1 .. Integer'Min(A.L,B.L) loop
if A.V(N) /= B.V(N) then
if A.V(N)>B.V(N) then return 1; end if;
return -1;
end if;
end loop;
if A.L>B.L then return 1; end if;
if A.L<B.L then return -1; end if;
return 0;
end IDiff;
procedure Find(P: in PolysPtr; B: in PolyPtr; Pos: out Integer; OK: out Boolean) is
--- assuming P is full and sorted
L: Integer := P'First;
R: Integer := P'Last;
D: Integer;
begin
OK := True;
loop
Pos := (L+R)/2;
D := IDiff(B,P(Pos));
OK := D=0;
if D>0 then
if Pos=L then return; end if;
R := Pos-1;
elsif D<0 then
if Pos=R then return; end if;
L := Pos+1;
else return; end if;
end loop;
end Find;
procedure GetR(B: in PolyPtr; P: in PolysPtr; R: out Rep) is
OK: Boolean;
N: Integer;
begin
Find(P,B,N,OK);
if not OK then Message("Lattice.GetR",Data_Problem); end if;
R := P(N).R;
end GetR;
procedure PutR(B: in PolyPtr; P: in PolysPtr; R: in Rep) is
OK: Boolean;
N: Integer;
begin
Find(P,B,N,OK);
if not OK then Message("Lattice.GetR",Data_Problem); end if;
P(N).R := R;
end PutR;
end Lattice;