program PlotBlg8;
        { Opens .FIT files and plots Hi/Lo transition distances vs force.
          Identifies and removes sport points. Overlays WLC curves for
          best fit. Exports .BMP images with titles.
          Initial offset = 4.1 nm for the folded end-end length
          Writes bitmap to local folder  with heat setting in filename
          Temperature/force normalization is true by default
          }
{$N+}
uses graph, crt, mouse;
const
nMax = 1100;  {max number of data lines}
xScale = 40;
yScale = 15;
var
atTheEnd,menuOn,normTemps:boolean;
ch:char;
i,j,k,h,L,n,column,xMax,yMax,xMid,yMid,CycCntCol,PullCol,loLCol,
loFCol,hiLCol,hiFCol,swCol,noiseCol, driftCol,codeCol,numDots: integer;
loLength,hiLength,loForce,hiForce,ff: array[1..nMax] of single;
{unfForce, refForce: array[1..nMax] of single;}
proFrc,proExt: array[1..305] of real;
color: array[1..nMax] of byte;
palette: array[-1..31] of byte;
cycleCount: array[1..nMax] of longInt;
pullNum,switches,noise,drift,code: array[1..nMax] of integer;
inFile, outFile {is for BMP}, forceFile, tempsFile, report: text;
fileName,dataLine,dataWord,titleLine,S,T,dateStr,dateStr2:string;
CL,Temp,ambient,Offset,m0,m1,m2,fn,avError,skew:real;

{$I Bitmap.pas}

procedure openDataFiles;
begin
assign(forceFile,'c:\pascal\bin\wlcbb25.txt');
reset(forceFile);     {WLC force/extension file}
readln(forceFile); readln(forceFile); readln(forceFile);
i:=0;
while i<304 do
  begin
  inc(i);
  readln(forceFile,dataLine);
  S:= copy (dataLine,1,5);
  val(S,proFrc[i],j);
  S:= copy (dataLine,32,6);
  val(S,proExt[i],j);
  end;
close(forceFile);
assign(tempsFile,'temps.txt');
reset(tempsFile); {heating laser measured close to local folder date}
readln(tempsFile,m0);  {coefficients of polynomial fit }
readln(tempsFile,m1);  {to temperature rise}
readln(tempsFile,m2);  {versus switch position}
readln(tempsFile,dateStr);
readln(tempsFile,dateStr2);
close(tempsFile);
assign(report,'c:\pascal\bin\ripPlots.txt');
{assign(report,'c:\Documents and Settings\Steven B. Smith\Desktop\MJ0366\ripPlots.txt');}
clrscr;
writeln;
writeln('What text file to open?  ".FIT" added automatically');
readln(filename);
assign(infile,filename+'.fit');
reset(infile);
readln(infile,titleLine);
i:=0;
repeat
      inc(i);
      S:=Copy(titleLine,i,8) ;
until (S = 'ambient=') or (i>30);
T:= Copy(titleLine,i+9,5);
for i:=5 downto 1 do if T[i]=' ' then T[i]:='0';
{trailing spaces not allowed by VAL function}
val(T,ambient,j);    {extract ambient temperature}
end;


Procedure detectColumns; {finds needed columns}
begin
repeat readln(infile,dataLine) until length(dataLine) > 40;{skip further intro}
i:=0; column:=1; L:=length(dataLine); dataWord:='';
repeat
      if dataLine[i]=chr(9) then  begin inc(column); dataWord:=''; end;
      repeat inc(i); dataWord:=dataWord + dataLine[i];
      until (i=L) or (dataLine[i+1]=chr(9));
      if dataWord='    CycCnt' then CycCntCol := column;
      if dataWord='pull' then PullCol := column;
      if dataWord='loL' then loLCol := column;
      if dataWord='loF' then loFCol := column;
      if dataWord='hiL' then hiLCol := column;
      if dataWord='hiF' then hiFCol := column;
      if dataWord='sw' then swCol := column;
      if dataWord='noise' then noiseCol := column;
      if dataWord='drift' then driftCol := column;
      if dataWord='code' then codeCol := column;
      inc(i);
until (i>L) or keypressed;    {done parsing row}
writeln;
if  (CycCntCol*PullCol*loLCol*loFCol*hiLCol
                 *hiFCol*swCol*noiseCol*driftCol*codeCol= 0)
    then begin
    writeln('some columns missing.....press any key to exit');
    repeat until keypressed;
    halt;
    end;
end;

procedure loadData;  {into arrays}
begin
n:=1;
repeat  {for all data rows}
       repeat readln(infile,dataLine)
       until (length(dataLine)>20){skips "Start"} or EOF(infile) or keyPressed;
       atTheEnd := eof(infile);
       i:=0; column:=1; L:=length(dataLine); dataWord:='';
          repeat     {read data columns}
          if dataLine[i]=chr(9) then  begin inc(column); dataWord:=''; end;
             repeat
             inc(i);
             dataWord:=dataWord + dataLine[i];
             until (i=L) or (dataLine[i+1]=chr(9));
          if column = CycCntCol then val(dataword,CycleCount[n],j);
          if column = PullCol then val(dataword,PullNum[n],j);
          if column = loLCol then val(dataword,loLength[n],j);
          if column = loFCol then val(dataword,loForce[n],j);
          if column = hiLCol then val(dataword,hiLength[n],j);
          if column = hiFCol then val(dataword,hiForce[n],j);
          if column = swCol then val(dataword,switches[n],j);
          if column = noiseCol then val(dataword,noise[n],j);
          if column = driftCol then val(dataword,drift[n],j);
          if column = 12 then val(dataword,code[n],j);
          inc(i);
          until (i>L) or keypressed;    {done parsing row}
       if code[n] = 1 then inc(n);  {write over preceding code=0 rows}
until atTheEnd;
if code[n]=0 then dec(n);
for i:=1 to n do ff[i]:= {force factors referenced to 25 deg C}
     sqr(298/(273+ambient+m0+m1*switches[i]+m2*switches[i]*switches[i]));
close(infile);
end;

procedure assignColors;
begin
  for i:= 0 to 31 do palette[i]:=0;
  palette[0]:=10;  {switches=0 gets color=10]}
  j:=10;
  for i:= 1 to n do if palette[switches[i]]=0 then
      begin
      inc(j); if j>15 then j:=2;
      palette[switches[i]]:= j;  {sequencial colors from 10 on up}
      end;
  for i:= 1 to n do color[i] := palette[switches[i]];
end;

procedure showMenu;
var mx,my:integer;
begin
mx:=xMax-200; my:=yMax-10;
if menuOn then setColor(white) else setColor(black);
outTextXY(mx,my,'q - quit program');
outTextXY(mx,my-10,'a - add line to report');
outTextXY(mx,my-20,'b - make bitmap file');
outTextXY(mx,my-30,'d - show current dots');
outTextXY(mx,my-40,'r - restore old dots');
outTextXY(mx,my-50,'m - this menu on/off');
outTextXY(mx,my-60,'L/l- WLC contour length');
outTextXY(mx,my-70,'O/o- change WLC Offset');
outTextXY(mx,my-80,'w - draw WLC curve');
outTextXY(mx,my-90,'h - select heat');
outTextXY(mx,my-100,'n - normalize temp/force');
outTextXY(10,my,'delete bad dots with left mouse button');
end;

function avNoise:integer;
var m,sum:integer;
begin
sum:=0; m:=0;
for i:=1 to n do
    if code[i]=1 then begin sum:=sum+noise[i]; inc(m); end;
if m>0 then avNoise := round(sum/m)
       else avNoise := 999;
end;

procedure showTitles;
begin
setColor(white);
outTextXY(10,10,'fileName = '+ fileName);
outTextXY(10,20,titleLine);
str(avNoise,S);
outTextXY(10,30,'av.noise= '+S);
j:=0;
for i := 0 to 31 do if palette[i]>0 then
    begin
    str(i,S);
    if i=0 then Temp:=ambient else Temp:=ambient+ m0+ m1*i+ m2*i*i;
    str(Temp:1:1,T);
    setColor(palette[i]);
    outTextXY (10, 50+j*10, 'sw='+S+' T='+T);
    inc(j);
    end;
end;

procedure showDots;
begin
clearDevice;
showTitles; showMenu;
numDots:=0;
for i:=1 to n do if code[i]=1 then
    begin
    if normTemps then fn:=ff[i] else fn:=1;
    setColor(color[i]);
    circle (round(loLength[i]*xScale),yMax-round(fn*loForce[i]*yScale),2);
    inc(numDots);
    circle (round(hiLength[i]*xScale),yMax-round(fn*hiForce[i]*yScale),2);
    inc(numDots);
    end;
end;

procedure restoreDots;
begin
for i:=1 to n do code[i]:=1;
showDots;
end;

function closest(x,y:integer):integer;
{gets pull number of dot closest to mouse cursor}
var p,z:integer;  dist, minDist:real;
begin
minDist:=1000;
for i:= 1 to n do
    begin
    if normTemps then fn:=ff[i] else fn:=1;
    dist := sqr(x/xScale-loLength[i]) + sqr((yMax-y)/yScale-fn*loForce[i]);
    if dist<minDist then
       begin minDist:=dist; p:=pullNum[i]; z:=i; end;
    dist := sqr(x/xScale-hiLength[i]) + sqr((yMax-y)/yScale-fn*hiForce[i]);
    if dist<minDist then
       begin minDist:=dist; p:=pullNum[i]; z:=i; end;
    end;
code[z]:= -1;
closest := p;
end;

procedure serviceMouse;
var x,y,pNum:integer;
begin
get_cursor_position(x,y);
if button_pressed(0) then {left mouse button}
   begin
   pNum:= closest(x,y);
   str(pNum,S);
   setColor(white);
   SetTextStyle(2, HorizDir, 2); {small digits}
   outTextXY(x-5,y-10,S);
   SetTextStyle(DefaultFont, HorizDir, 1);
   end;
end;

procedure drawWLC(CL,Tmp,Offset:real);
{proFrc and proExt assume P=0.650 nm at T=25}
var sum,sk:real;
begin
{P:= 0.650 * 298/(273+Temp);  {ref Landau and Lifshitz}
{ff:=sqr((273+Temp)/298); {WLC force grows by square of abs. temperature }
sum:=0; sk:=0;
for i:=1 to 300 do
    putPixel(round((CL*proExt[i]-Offset)*xScale),
    yMax-round(proFrc[i]*yScale),white);
k:=0;
for j:= 1 to n do if code[j]=1 then
    begin
    if normTemps then fn:=ff[j] else fn:=1;
    i:=1;
    while fn*loForce[j] > proFrc[i] do inc(i);
    sum := sum + sqr(loLength[j] - (CL*proExt[i]-Offset));
  {  sk  := sk  + fn*loForce[j] * (loLength[j] - (CL*proExt[i]-Offset)); }
    sk  := sk  + (loLength[j] - (CL*proExt[i]-Offset));
    inc(k);
    while fn*hiForce[j] > proFrc[i] do inc(i);
    sum := sum + sqr(hiLength[j] - (CL*proExt[i]-Offset));
  {  sk  := sk  + fn*hiForce[j] * (hiLength[j] - (CL*proExt[i]-Offset));}
    sk  := sk  - (hiLength[j] - (CL*proExt[i]-Offset));
    inc(k);
    end;
if k>0 then
   begin
   avError := sqrt(sum/k);
   skew := sk/k;
   end;
bar(10,120,130,180);
setColor(white);
str(CL:2:2,S);
outTextXY(10,120,'CLength= '+S);
str(Offset:2:1,S);
outTextXY(10,130,'Offset = '+S);
{str(Temp:2:1,S); }
outTextXY(10,140,'WLC temp = 25');
{str(P:2:3,S);}
outTextXY(10,150,'PLength= 0.65');
str(avError:0:3,S);
outTextXY(10,160,'av.error= '+S);
str(skew:0:3,S);
outTextXY(10,170,'skew = '+S);
if normTemps then outTextXY(10,180,'T-norm forces');
end;

procedure selectHeat;
begin
repeat  inc(h) until palette[h]>0;
if h>31 then h:=-1;
if h>= 0 then for i:=1 to n do
    if code[i]>=0 then   {rules out sport points marked as -1}
        if switches[i]=h then code[i]:=1 else code[i]:=0;
if h=-1 then for i:= 1 to n do if code[i]=0 then code[i]:=1;
showDots;
end;

procedure makeBitmap;
begin
{menuOn:=false; showMenu;
drawWLC(CL,Temp,Offset);}
S:='';
if h>=0 then str(h,S);
assign (outFile,filename+' '+S+'.bmp');
rewrite (outFile);
writeBitmap;
close(outFile);
end;

procedure drawScales;
begin
setColor(white);
setTextStyle(0,1,0);
outTextXY(xMax-10,60,'Force (pN)');
setTextStyle(0,0,0);
outTextXY(10,yMax-10,'delta_X (nm)');
for i:= 1 to 3 do
    begin
    line(5*i*xScale,yMax-15,5*i*xScale,yMax-25);
    str(i*5:2,S);
    outTextXY(5*i*xScale-7,yMax-10,S);
    end;
for i:=1 to 3 do
    begin
    line(xMax-30,yMax-10*i*yScale,xMax-20,yMax-10*i*yScale);
    str(i*10,S);
    outTextXY(xMax-15,yMax-10*i*yScale-3,S);
    end;
end;

procedure appendReport;
begin
append(report);
writeln(report,dateStr,filename:8,ambient:8:2,numDots:8,offset:8:1,
                  avError:8:3,skew:8:3,CL:8:2);
close(report);
end;

begin {main}
openDataFiles;
detectColumns;
i:=detect;
initgraph(i,j,'C:\PASCAL\BGI');
setFillStyle(1,black);
xMax:=getMaxX; yMax:= getMaxY;
set_min_max_vert(0,yMax);
set_min_max_horiz(0,xMax);
show_cursor;
loadData;
assignColors;
showDots;
menuOn:= true; showMenu;
CL:=23.66; Temp:=25; Offset:=4.1;
showTitles;
h:=-1;
normTemps := true;
repeat
      repeat serviceMouse until keypressed;
      ch:=readkey;
      case ch of
      'm': begin menuOn:=not menuOn; showMenu; end;
      'd': showDots;
      'r': restoreDots;
      'w': begin showDots; drawWLC(CL,25,Offset); end;
      'O': begin Offset:=Offset-0.1; showDots; drawWLC(CL,Temp,Offset); end;
      'o': begin Offset:=Offset+0.1; showDots; drawWLC(CL,Temp,Offset); end;
      'L': begin CL:=CL+0.1; showDots; drawWLC(CL,Temp,Offset); end;
      'l': begin CL:=CL-0.1; showDots; drawWLC(CL,Temp,Offset); end;
      'b': begin
           menuOn:=false;  showDots;
           drawWLC(CL,Temp,Offset);
           drawScales; hide_cursor;
           makeBitmap;
           show_cursor;  showDots;
           drawWLC(CL,Temp,Offset);
           menuOn:=true;  showMenu;
           end;
      'h': selectHeat;
      'n': begin normTemps:=not normTemps;
           showDots; drawWLC(CL,Temp,Offset);
           end;
      's': drawScales;
      'a': appendReport;
      end;{case}
until ch='q';
closegraph;
if mouse_installed then ; {do nothing but restore default mouse settings}
end.