#include "polytool.h" extern real MinsInRad; extern polygons **TP; extern polyselect Sel; twang Tw; // Projecting the earth polygon onto a sphere inline void projtoearth(const projection *Proj, long LAT, long LONG, image *D) { vector V; if (!Proj || !D) return; polartocartesian(1.0,(5400 - LAT) / MinsInRad,LONG / MinsInRad,&V); projontosphere(Proj,&V,D); } void projearth(const projection *Proj, const polygon **P, int PT, image *D) { polypoint L; if (!Proj || !P || !*P || !D) return; if (!range(PT,(*P)->num)) return; L=(*P)->pt[PT]; projtoearth(Proj,L.v,L.h,D); } bool clicktoearth(const mouseclick *M, polypoint *L) { window *W; projection *P; vector V; real Theta,Phi,X; if (!M) return 0; W=M->wind; if (!W) return 0; P=W->proj; if (!P) return 0; if (!reverseprojontosphere(P,M->point,&V)) return 0; cartesiantopolar(&V,NULL,&Theta,&Phi); X= Phi * MinsInRad; if (X>0.0) X+=0.5; else X-=0.5; L->h=mod(X,21600); if (L->h>10800) L->h-=21600; X= 5400.0 - (Theta * MinsInRad); if (X>0.0) X+=0.5; else X-=0.5; L->v=between(X,-5400,5400); return 1; } void lookatpoly(projection *Proj, const polygons **Py, int POLY, int PT) { polygon **P; polypoint *L; if (!Py || !*Py || !Proj || !range(POLY,(*Py)->num)) return; P=(*Py)->poly[POLY]; if (!P || !*P || !range(PT,(*P)->num)) return; L= (*P)->pt + PT; setviewangles(Proj,(5400 + L->v) / MinsInRad,(10800 + L->h) / MinsInRad); } // Drawing the background & disk static void DrawDisc(window *W, rect Page) { projection *Proj; float Rad,Diag2; if (!W) return; Proj=W->proj; if (!Proj) return; Diag2= (width(Page) * width(Page)) + (height(Page) * height(Page)); Rad=Proj->mag; if (Rad * Rad > Diag2 / 4.0) { fillindex(W,beige); fillrect(W,Page); return; } fillindex(W,black); fillrect(W,Page); fillindex(W,beige); beginpath(W); addcircle(W,Proj->org.x,Proj->org.y,Rad); fill(W); } // Drawing the coordinate lines & ticks static void SphereToView(const projection *P, const vector *V, image *D) { projontosphere(P,V,D); } static spheretask ST; // static void DrawCoords(window *W) { initspheretask(&ST,W,W->proj,1,5,&SphereToView,0); setcolour(&(ST.c2nd),brown); setcolour(&(ST.c1st),chestnut); drawsphericalcoords(&ST); penindex(W,oxblood); drawequator(&ST); drawprimemeridian(&ST,1); penindex(W,black); } static void DrawTicks(window *W) { projection *Proj; int i; image D; vector U; char *S; bool North; if (!W) return; Proj=W->proj; if (!Proj || Proj->mag<150.0) return; fillindex(W,oxblood); North= Proj->elev < 0.0; for (i= -10800 + ST.longintv;i<=10800;i+=ST.longintv) { coordtick(&ST,ST.ticklat,i,&D,North ? 'n' : 's',&U); if (!D.good) continue; scalevector(&U,12); S=cat(1,fig(abso(i / 60)),"¡"); textcentre(W,D.pt.x + U.x,D.pt.y + U.y + 6,S); old(S); } for (i= -5400 + ST.latintv;i<= 5400 - ST.latintv;i+=ST.latintv) { coordtick(&ST,i,ST.ticklong,&D,'e',&U); if (!D.good) continue; scalevector(&U,15); S=cat(1,fig(abso(i / 60)),"¡"); textcentre(W,D.pt.x + U.x,D.pt.y + U.y + 6,S); old(S); } } // Legends static string GeoRefString(projection *Proj) { real Q; char *S,*Hemi; if (!Proj) return NULL; Q=fabs(Proj->elev); Hemi= (Proj->elev<0.0) ? " N" : (Proj->elev>0.0) ? " S" : NULL; S=cat3(2,"Lat: ",degminstring(Q,1),Hemi); Q=modtwopisym(pi - Proj->azim); Hemi= (Q<0.0) ? " E" : (Q>0.0) ? " W" : NULL; return cat4(5,S," Long: ",degminstring(fabs(Q),1),Hemi); } static string ScaleString(projection *Proj) { long Q; if (!Proj) return NULL; Q= 6378.1 * Proj->width / Proj->mag; if (Q>=1000) { Q/=100; return (cat4(5,fig(Q / 10)," ",fig(Q % 10),"00 km")); } if (Q>=100) { Q/=10; return (cat(1,fig(Q),"0 km")); } return cat(1,fig(Q)," km"); } static void DrawLegend(window *W) { projection *Proj; rect R; char *S; if (!W) return; Proj=W->proj; if (!Proj) return; R=Proj->port; fillindex(W,paleyellow); S=ScaleString(Proj); textleft(W,right(R) - 5,top(R) - 15,S); old(S); S=GeoRefString(Proj); textleft(W,right(R) - 5,bottom(R) + 5,S); old(S); } // Drawing the continent outlines static void DrawPolyName(window *W, const polygon **P, rect R) { char *S; int SIZE; point Q; if (!W || !P || !*P) return; S=(*P)->name; if (!S) return; SIZE=gtr(width(R),height(R)); if (SIZE<50) return; Q=middle(R); textcentre(W,Q.x,Q.y,S); } static void DrawPoly(window *W, const polygon **P, bool Selected) { projection *Proj; int i; image D,Prev; bool BInit,PenDown; rect R,B; if (!W || !P || !*P) return; Proj=W->proj; if (!Proj) return; penindex(W,Selected ? forestgreen : black); fillindex(W,Selected ? forestgreen : black); PenDown=0; BInit=0; beginpath(W); for (i=0;i<(*P)->num;i++) { projearth(Proj,P,i,&D); movetolineto(W,&D,&PenDown); if (D.good) { if (!BInit) { setrect(&B,D.pt.x,D.pt.y,0,0); BInit=1; } else stretchrect(&B,D.pt); } Prev=D; } if (!((*P)->open)) { projearth(Proj,P,0,&D); movetolineto(W,&D,&PenDown); } stroke(W); if (Selected) { for (i=0;i<(*P)->num;i++) { projearth(Proj,P,i,&D); if (D.good) { setrect(&R,D.pt.x - 2.5,D.pt.y - 2.5,5,5); if (i==Sel.pt) framerect(W,R); else fillrect(W,R); } if (D.good && i>0 && Prev.good) { int H,V; H= (D.pt.x + Prev.pt.x) / 2; V= (D.pt.y + Prev.pt.y) / 2; setrect(&R,H - 1.5,V - 1.5,3,3); fillrect(W,R); } Prev=D; } if (!((*P)->open)) { projearth(Proj,P,0,&D); if (D.good && Prev.good) { int H,V; H= (D.pt.x + Prev.pt.x) / 2; V= (D.pt.y + Prev.pt.y) / 2; setrect(&R,H - 1.5,V - 1.5,3,3); fillrect(W,R); } } } if (BInit) { fillindex(W,chestnut); DrawPolyName(W,P,B); } penindex(W,black); fillindex(W,black); } // Dragging vertices static void DrawTwang(window *W) { int WIDTH=1; if (!W || !Tw.good) return; /*PenSize(WIDTH,WIDTH);*/ penindex(W,grey); beginpath(W); movept(W,Tw.end); if (Tw.prev.good) linept(W,Tw.prev.pt); movept(W,Tw.end); if (Tw.next.good) linept(W,Tw.next.pt); penindex(W,black); setpenrect(&(Tw.drew),Tw.end,WIDTH); if (Tw.prev.good) stretchrect(&(Tw.drew),Tw.prev.pt); if (Tw.next.good) stretchrect(&(Tw.drew),Tw.next.pt); Tw.drew=rectintersection(Tw.drew,W->page); stroke(W); } // Drawing void Display(window *W) { projection *Proj; int i; if (!W) return; Proj=W->proj; if (!Proj) return; setlookpoint(Proj,0.0,0.0,0.0); DrawDisc(W,W->page); DrawCoords(W); for (i=0;i<(*TP)->num;i++) DrawPoly(W,(*TP)->poly[i],i==Sel.poly); DrawTicks(W); DrawLegend(W); DrawTwang(W); }