// zoom.c // // This file allows projections within windows to be controlled. Arrow buttons and cursor // keys can be used to move the lookpoint, while scroll bars are tied to the view angles. // The scroll bars can either be slaved to the view angles, as when tracking a moving object, // or they can be used to set the view direction, as when the user manipulates the controls. // // by John D. de Boer #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" #include "floating.h" #include "frame.h" #include "tapedeck.h" #include "vector.h" #include "view.h" #include "zoom.h" static ControlActionUPP AngleUPP, // control action procedure for scroll bars ZoomUPP, // control action procedure for zoom buttons ShiftUPP; // control action procedure for shift buttons // Standard control action procedures static real pageangle(projection *P, bool Azim) { real cosE,secE,Rads; if (!P) return 10.0 / fiftyseven; if (!Azim) secE=1.0; else { cosE=cos(P->elev); secE= (cosE>0.25) ? 1.0 / cosE : 4.0; } Rads= P->terr ? (P->width / P->mag) : P->rads; return flsr(Rads * secE / 4.0,pi / 4.0); } static pascal void anglescroll(ControlRef C, ControlPartCode PART) { int INCR,OLD,NEW; bool Azim; real R; window *W; projection *P; if (!C) return; W=controlswindow(C); if (!W) return; if (PART==kControlIndicatorPart) { scrolltoproj(W); controlaction(W); return; } Azim=(C==W->hsb); INCR=partincrement(PART,2,10); P=W->proj; if (P && (P->persp || P->terr)) { if (!P->terr) INCR=-INCR; R= (INCR / 10.0) * pageangle(W->proj,Azim); if (Azim) P->azim=modtwopi(P->azim + R); else P->elev=fbetween(P->elev + R,-pibytwo,pibytwo); projtoscroll(W); } else { OLD=GetControlValue(C); NEW= OLD + INCR; if (NEW<0 && Azim) NEW+=360; if (NEW>360) NEW-=360; SetControlValue(C,NEW); NEW=GetControlValue(C); if (NEW==OLD) return; scrolltoproj(W); } controlaction(W); } static pascal void shiftaction(ControlRef C, ControlPartCode PART) { int PIX; window *W; projection *P; if (!C) return; W=controlswindow(C); if (!W) return; P=W->proj; if (!P) return; PIX=10; if (C==P->shlf) shiftproj(W->proj,-PIX, 0, 0); else if (C==P->shrt) shiftproj(W->proj,+PIX, 0, 0); else if (C==P->shup) shiftproj(W->proj, 0,+PIX, 0); else if (C==P->shdn) shiftproj(W->proj, 0,-PIX, 0); else if (C==P->shbk) shiftproj(W->proj, 0, 0,-PIX); else if (C==P->shfw) shiftproj(W->proj, 0, 0,+PIX); controlaction(W); } static pascal void zoomaction(ControlRef C, ControlPartCode PART) { real Zoom; window *W; projection *P; if (!C) return; W=controlswindow(C); if (!W) return; P=W->proj; if (!P) return; if (C==P->zout) Zoom=0.95; else if (C==P->zmin) Zoom=1.05; else return; zoommagnification(W->proj,Zoom); controlaction(W); } // Initialisation static bool ZoomInit=0; // whether initialisation has taken place void initzoom(void) { if (ZoomInit) return; AngleUPP=NewControlActionUPP(&anglescroll); ShiftUPP=NewControlActionUPP(&shiftaction); ZoomUPP =NewControlActionUPP(&zoomaction); ZoomInit=1; } // Controlling projections in windows void giveprojcontrols(window *W, int PLACE, int AZIM, int ELEV, bool DownOnly) { projection *P; if (!W) return; P=W->proj; if (!P) return; inittd(); initzoom(); P->zout=commonbutton(W,PLACE ,projMinus ); SetControlAction(P->zout,ZoomUPP); P->zmin=commonbutton(W,PLACE + 1,projPlus ); SetControlAction(P->zmin,ZoomUPP); P->shlf=commonbutton(W,PLACE + 2,projLeftArrow ); SetControlAction(P->shlf,ShiftUPP); P->shup=commonbutton(W,PLACE + 3,projUpArrow ); SetControlAction(P->shup,ShiftUPP); //P->shbk=commonbutton(W,PLACE + 4,projOutArrow); SetControlAction(P->shbk,ShiftUPP); //P->shfw=commonbutton(W,PLACE + 5,projInArrow ); SetControlAction(P->shfw,ShiftUPP); P->shdn=commonbutton(W,PLACE + 4,projDownArrow ); SetControlAction(P->shdn,ShiftUPP); P->shrt=commonbutton(W,PLACE + 5,projRightArrow); SetControlAction(P->shrt,ShiftUPP); givescrolls(W); resizeproj(P,W->page); if (W->hsb) { setscrollbar(W->hsb,360 - AZIM,0,360); SetControlAction(W->hsb,AngleUPP); } if (W->vsb) { setscrollbar(W->vsb,90 - ELEV,DownOnly ? 90 : 0,180); SetControlAction(W->vsb,AngleUPP); } } /*void give2Dcontrols(window *W, int PLACE, int AZIM) { projection *P; if (!W) return; P=W->proj; if (!P) return; inittd(); initzoom(); P->zout=commonbutton(W,PLACE ,projProc,projMinus); P->zmin=commonbutton(W,PLACE + 1,projProc,projPlus); P->shlf=commonbutton(W,PLACE + 2,projProc,projLeftArrow); P->shup=commonbutton(W,PLACE + 3,projProc,projUpArrow); P->shdn=commonbutton(W,PLACE + 4,projProc,projDownArrow); P->shrt=commonbutton(W,PLACE + 5,projProc,projRightArrow); giveazimscroll(W); resizeproj(P,W->page); if (W->hsb) setscrollbar(W->hsb,360 - AZIM,0,360); P->elev=-pibytwo; }*/ void giveglobecontrols(window *W, int PLACE, int LAT, int LONG) { projection *P; if (!W) return; P=W->proj; if (!P) return; P->terr=1; inittd(); initzoom(); P->zout=commonbutton(W,PLACE ,projMinus); SetControlAction(P->zout,ZoomUPP); P->zmin=commonbutton(W,PLACE + 1,projPlus ); SetControlAction(P->zmin,ZoomUPP); givescrolls(W); resizeproj(P,W->page); if (W->hsb) { setscrollbar(W->hsb,mod(180 + LONG,360),0,360); SetControlAction(W->hsb,AngleUPP); } if (W->vsb) { setscrollbar(W->vsb,90 - LAT,0,180); SetControlAction(W->vsb,AngleUPP); } } void scrolltoproj(window *W) { projection *P; if (!W) return; P=W->proj; if (!P) return; setprojangles(P,W->hsb,W->vsb); } void projtoscroll(window *W) { projection *P; if (!W) return; P=W->proj; if (!P) return; setscrollangles(P,W->hsb,W->vsb); } bool projectionkey(keystroke *K) { window *W; projection *P; int PIX; if (!K) return 0; W=K->wind; if (!W) return 0; P=W->proj; if (!P) return 0; PIX= K->shift ? 150 : 50; switch (K->c) { case 28: shiftproj(P,-PIX, 0, 0); break; case 29: shiftproj(P,+PIX, 0, 0); break; case 30: shiftproj(P, 0,+PIX, 0); break; case 31: shiftproj(P, 0,-PIX, 0); break; case 'b': case 'B': if (!P->persp) return 0; shiftproj(P, 0, 0,-PIX); break; case 'f': case 'F': if (!P->persp) return 0; shiftproj(P, 0, 0,+PIX); break; case 43: zoommagnification(P,K->shift ? 2.00 : 1.25); break; case 45: zoommagnification(P,K->shift ? 0.50 : 0.80); break; default: return 0; } controlaction(W); return 1; } bool projectionwheel(window *W, short DX, short DY) { projection *P; float F; if (!W) return 0; P=W->proj; if (!P) return 0; F= 0.02 * pageangle(P,DX!=0); setazimelev(P,P->azim + (DX * F),P->elev + (DY * F)); setscrollangles(P,W->hsb,W->vsb); controlaction(W); return 1; } /* static bool trackanglethumb(mouseclick *M) { window *W; if (!M) return 0; W=M->wind; if (!W) return 0; //if (!trackthumb(M)) return 0; scrolltoproj(W); controlaction(W); return 1; }*/ /* bool projcontent(mouseclick *E) { //ControlRef C; window *W; projection *P; if (!E) return 0; C=E->cont; if (!C || !E->code) return 0; W=E->wind; if (!W) return 0; P=W->proj; if (!P) return 0; if (C==P->shlf || C==P->shup || C==P->shbk || C==P->shfw || C==P->shdn || C==P->shrt) { trackarrow(E,ShiftUPP); return 1; } if (C==P->zout || C==P->zmin) { trackarrow(E,ZoomUPP); return 1; } if (C==W->hsb || C==W->vsb) { if (E->code==kControlIndicatorPart) trackanglethumb(E); else trackarrow(E,AngleUPP); return 1; } return 0; }*/ /* static void sethighlighting(ControlRef C, int STATE) { if (!C) return; HiliteControl(C,STATE); }*/ /* void adjustprojcontrols(window *W, int STATE) { projection *P; if (!W) return; P=W->proj; if (!P) return; if (STATE==0) { ShowControl(W->hsb); ShowControl(W->vsb); } else { HideControl(W->hsb); HideControl(W->vsb); } sethighlighting(P->zout,STATE); sethighlighting(P->zmin,STATE); sethighlighting(P->shlf,STATE); sethighlighting(P->shup,STATE); sethighlighting(P->shdn,STATE); sethighlighting(P->shrt,STATE); sethighlighting(P->shbk,STATE); sethighlighting(P->shfw,STATE); }*/ // Dragging the view angles static const real Breakaway2 = 10.0; // break-away distance for inital dragging of map void initprojdrag(mouseclick *M, projdragtask *T) { projection *P; if (!M || !M->wind || !T) return; T->wind=M->wind; T->start=T->end=M->point; P=T->wind->proj; if (!P) return; T->azim=P->azim; T->elev=P->elev; T->good=reverseprojection(P,T->end,&(T->where)); T->same=1; T->did=0; } void trackprojdrag(projdragtask *T, point P) { point Rel; projection *Proj; if (!T) return; Rel.x= P.x - T->end.x; Rel.y= P.y - T->end.y; T->same=(Rel.x==0.0 && Rel.y==0.0); if (!T->did && (Rel.x * Rel.x) + (Rel.y * Rel.y) <= Breakaway2) T->same=1; if (T->same) return; T->end=P; Proj=T->wind->proj; solveperspdrag(Proj,&(T->where),P); T->azim=Proj->azim; T->elev=Proj->elev; projtoscroll(T->wind); T->did=1; } void initspheredrag(mouseclick *M, projdragtask *T) { projection *P; if (!M || !M->wind || !T) return; T->wind=M->wind; T->start=T->end=M->point; P=T->wind->proj; if (!P) return; T->azim=P->azim; T->elev=P->elev; T->good=reverseprojontosphere(P,T->end,&(T->where)); T->same=1; T->did=0; } void trackspheredrag(projdragtask *T, point P) { point Rel; projection *Proj; if (!T) return; Rel.x= P.x - T->end.x; Rel.y= P.y - T->end.y; T->same=(Rel.x==0.0 && Rel.y==0.0); if (!T->did && (Rel.x * Rel.x) + (Rel.y * Rel.y) <= Breakaway2) T->same=1; if (T->same) return; T->end=P; Proj=T->wind->proj; solvespheredrag(Proj,&(T->where),P); T->azim=Proj->azim; T->elev=Proj->elev; projtoscroll(T->wind); T->did=1; }