#include "polytool.h" #include "music.h" extern real MinsInRad; extern twang Tw; polygons **TP; // The polygons polyselect Sel; // selected vertex or midpoint // Pulling out, or stretching, a vertex of a polygon with the mouse inline void inittwang(mouseclick *M, polyselect *S) { projection *Proj; polygon **P; int PREV,NEXT; if (!M || !M->wind || !S) return; Tw.start=M->point; Tw.end=M->point; Proj=M->wind->proj; if (!Proj || !range(S->poly,(*TP)->num)) return; P=(*TP)->poly[S->poly]; if (!range(S->pt,(*P)->num)) return; PREV= S->vertex ? S->pt - 1 : S->pt; NEXT= S->pt + 1; if (!((*P)->open)) { if (PREV<0) PREV= (*P)->num - 1; if (NEXT>=(*P)->num) NEXT=0; } Tw.prev.good=0; if (range(PREV,(*P)->num)) projearth(Proj,P,PREV,&(Tw.prev)); Tw.next.good=0; if (range(NEXT,(*P)->num)) projearth(Proj,P,NEXT,&(Tw.next)); setrect(&(Tw.drew),0,0,0,0); Tw.good=1; } static void tracktwang(window *W, point P) { if (equalpoints(Tw.end,P)) return; Tw.end=P; Tw.good=1; redraw(W); } // User operations static void DraggedPolyPoint(mouseclick *M, twang *T, polyselect *S) { window *W; mouseclick Final; polypoint L; if (!M || !T || !S) return; W=M->wind; if (!W) return; if (!pointinrect(Tw.end,W->page)) return; Final=*M; Final.point=Tw.end; if (!clicktoearth(&Final,&L)) return; if (S->vertex) { movecorner(TP,S->poly,S->pt,&L); return; } if (onein(100)) { redraw(W); playnamedsound("pling"); return; } insertcorner(TP,S->poly,S->pt,&L); S->pt++; } static void CreatePoly(const polypoint *L, polyselect *S) { addpoly(TP,L,5 * S->slop); S->poly= (*TP)->num - 1; S->pt=0; } // Mouse stuff inline long LongitudeDifference(const polypoint *A, const polypoint *B) { long DL; DL=abso(A->h - B->h); if (DL>10800L) DL-=21600L; return DL; } inline long LongitudeAverage(const polypoint *A, const polypoint *B) { long AL,DL; AL= (A->h + B->h) / 2; DL=abso(A->h - B->h); if (DL<10800L) return AL; if (AL<0) return AL + 10800L; return AL - 10800L; } static bool WithinSlop(const polypoint *A, const polypoint *B, real Slop2) { long DH,DV; real CosLat; CosLat=cos(A->v / MinsInRad); DV= A->v - B->v; DH= CosLat * LongitudeDifference(A,B); return (DH * DH) + (DV * DV) <= Slop2; } static void FindPointInPoly(const polypoint *C, polygon **P, polyselect *S) { int i,j; polypoint *L,Mid; if (!P || !*P || !S) return; L=(*P)->pt; S->pt=-1; for (i=0;i<(*P)->num;i++) { if (WithinSlop(L + i,C,S->slop2)) { S->pt=i; S->vertex=1; break; } j= (i + 1) % (*P)->num; Mid.h=LongitudeAverage(L + i,L + j); Mid.v= (L[i].v + L[j].v) / 2; if (WithinSlop(&Mid,C,S->slop2)) { S->pt=i; S->vertex=0; break; } } } static void FindPoint(const polypoint *L, polyselect *S) { int i,WAS; if (!S) return; WAS=S->poly; S->poly=-1; if (range(WAS,(*TP)->num)) { FindPointInPoly(L,(*TP)->poly[WAS],S); if (S->pt>=0) { S->poly=WAS; return; } } for (i=0;i<(*TP)->num;i++) { FindPointInPoly(L,(*TP)->poly[i],S); if (S->pt>=0) { S->poly=i; return; } } } static bool SamePolySelection(const polyselect *A, const polyselect *B) { return A->poly==B->poly && A->pt==B->pt; } static void CalcWorldSlop(window *W, polyselect *S) { projection *P; real RS; if (!W) return; P=W->proj; if (!P) return; RS= 5.0 / P->mag; // 5-pixel slop in radians S->slop=gtr(1,RS * MinsInRad); // slop in minutes S->slop2= S->slop * S->slop; } static bool DragMap(mouseclick *M) { projdragtask T; if (!M) return 0; T.good=0; initspheredrag(M,&T); if (!T.good) return 0; Sel.poly=-1; //trackmousedelay(M,0.01 * kEventDurationSecond); if (stilldown(M)) trackspheredrag(&T,M->now); redraw(T.wind); while (stilldown(M)) { //trackmousedelay(M,0.01 * kEventDurationSecond); trackspheredrag(&T,M->now); if (!T.same) redraw(T.wind); } return 1; } bool DoContent(mouseclick *M) { window *W; polypoint L; twang T; polyselect Prev; if (!M) return 0; W=M->wind; if (!W) return 0; if (!pointinrect(M->point,W->page)) return 0; if (!clicktoearth(M,&L)) return 0; CalcWorldSlop(W,&Sel); if (M->cmnd) { CreatePoly(&L,&Sel); redraw(W); return 1; } Prev=Sel; FindPoint(&L,&Sel); if (Sel.poly>=0) { if (!SamePolySelection(&Prev,&Sel)) redraw(M->wind); if (Prev.poly!=Sel.poly) return 1; inittwang(M,&Sel); while (stilldown(M)) { /*trackmouse(M);*/ tracktwang(W,M->now); Tw.good=0; } if (equalpoints(T.end,M->point)) return 0; DraggedPolyPoint(M,&T,&Sel); redraw(W); return 1; } Sel.slop*=2.0; Sel.slop2= Sel.slop * Sel.slop; FindPoint(&L,&Sel); if (Sel.poly>=0) return 0; return DragMap(M); } bool MapWheel(window *W, short DX, short DY) { return projectionwheel(W,-DX,-DY); } // "document mode"