GNU Exterior Ballistics Computer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

723 lines
20 KiB

#include "TargetWindow.h"
#define PT_PATH 0
TargetWindow::TargetWindow(int w, int h, GBCSolution* Gsln, GBCSolution* GMEM1, GBCSolution* GMEM2, GBCSolution* GMEM3) : Fl_Window(w,h,"Solution Visualization Tools"){
// Store a pointer to the calling solution.
gsln=Gsln;
mem1=GMEM1;
mem2=GMEM2;
mem3=GMEM3;
x_click=0;
y_click=0;
begin();
this->size_range(0,0,1600,1600);
// Put a simple menu, for saving or closing the window.
menu = new Fl_Menu_Bar(0,0,w,25,"MENU");
Fl_Menu_Item items[]= {
{"&File",0,0,0,FL_SUBMENU},
{"Save as..",0,0,0,FL_SUBMENU | FL_MENU_INACTIVE},
{"PNG (.png)",0,(Fl_Callback*)cb_nothing,this,0},
{"JPEG (.jpg)",0,(Fl_Callback*)cb_nothing,this,0},
{"Bitmap (.bmp)",0,(Fl_Callback*)cb_nothing,this,0},
{"Adobe PDF (.pdf)",0,(Fl_Callback*)cb_nothing,this,0},
{0},
{"&Close",0,(Fl_Callback*)cb_Close,this,0},
{0},
{0}
};
menu->copy(items);
menu->down_box(FL_NO_BOX);
// Put in a range slider for selecting the chart's range.
sl_x = new Fl_Value_Slider(10,30,270,30,"Range (yds)");
sl_x->align(FL_ALIGN_RIGHT);
sl_x->value(200);
sl_x->minimum(30);
sl_x->maximum(gsln->MaxRows());
sl_x->type(FL_HOR_NICE_SLIDER);
sl_x->callback(cb_slUpdate,this);
sl_x->precision(0);
sl_x->step(10);
btPerspective=new Fl_Check_Button(380,35,20,20,"Perspective");
btPerspective->value(1);
btPerspective->callback(cb_Perspective,this);
btPerspective->tooltip("Apply perspective to bullet path");
Fl_Menu_Item guideitems[]={
{"None",0,(Fl_Callback*)cb_Guides, this, 0},
{"1,5 MIL",0,(Fl_Callback*)cb_Guides, this, 0},
{"1-5 MIL",0,(Fl_Callback*)cb_Guides, this, 0},
{"1-10 MIL",0,(Fl_Callback*)cb_Guides, this, 0},
{"1-5,10 MIL",0,(Fl_Callback*)cb_Guides, this, 0},
{"2,10 MOA",0,(Fl_Callback*)cb_Guides, this, 0},
{"2,4,6,8,10 MOA",0,(Fl_Callback*)cb_Guides, this, 0},
{"2-20 MOA",0,(Fl_Callback*)cb_Guides, this, 0},
{"2-10,20 MOA",0,(Fl_Callback*)cb_Guides, this, 0},
{"1-5 Degrees",0,(Fl_Callback*)cb_Guides, this, 0},
{"5,10,15 Degree",0,(Fl_Callback*)cb_Guides, this, 0},
{0}
};
cScopeGuides = new Fl_Choice(330,65,150,30,"Scope Guides");
cScopeGuides->copy(guideitems);
cScopeGuides->value(1);
btMem1 = new Fl_Check_Button(490,30,20,20,"Memory 1");
btMem2 = new Fl_Check_Button(490,50,20,20,"Memory 2");
btMem3 = new Fl_Check_Button(490,70,20,20,"Memory 3");
btMem1->align(FL_ALIGN_RIGHT);
btMem2->align(FL_ALIGN_RIGHT);
btMem3->align(FL_ALIGN_RIGHT);
btMem1->labelcolor(FL_RED);
btMem2->labelcolor(FL_DARK_GREEN);
btMem3->labelcolor(FL_BLACK);
btMem1->callback(cb_Mem1,this);
btMem2->callback(cb_Mem2,this);
btMem3->callback(cb_Mem2,this);
if (mem1==NULL) btMem1->deactivate();
if (mem2==NULL) btMem2->deactivate();
if (mem3==NULL) btMem3->deactivate();
if (mem1!=NULL) btMem1->tooltip(mem1->Name());
if (mem2!=NULL) btMem2->tooltip(mem2->Name());
if (mem3!=NULL) btMem3->tooltip(mem3->Name());
#define TARGET_COUNT 15
Fl_Menu_Item plottypeitems[TARGET_COUNT+1]={
{"1/2\" Rings",0,(Fl_Callback*)cb_TargetType, this, 0},
{"1\" Rings",0,(Fl_Callback*)cb_TargetType, this, 0},
{"2\" Rings",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 10m Air Pistol",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 10m Air Rifle",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 25m Rapid Fire Pistol",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 25m Pistol",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 50m Pistol",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 50m Rifle",0,(Fl_Callback*)cb_TargetType, this, 0},
{"ISSF 300m Rifle",0,(Fl_Callback*)cb_TargetType, this, 0},
{"NRA 200 yard reduced for 100yd",0,(Fl_Callback*)cb_TargetType, this, 0},
{"NRA 200 yard",0,(Fl_Callback*)cb_TargetType, this, 0},
{"NRA 300 yard",0,(Fl_Callback*)cb_TargetType, this, 0},
{"NRA 600 yard",0,(Fl_Callback*)cb_TargetType, this, 0},
{"NRA 800 yard+",0,(Fl_Callback*)cb_TargetType, this, 0},
{0}
};
cTargetType = new Fl_Choice(60,65,160,30,"Target");
cTargetType->copy(plottypeitems);
cTargetType->value(1);
end();
show();
}
TargetWindow::~TargetWindow(void){
delete menu;
delete sl_x;
delete btMem1;
delete btMem2;
delete btMem3;
delete cScopeGuides;
delete cTargetType;
}
void TargetWindow::draw(void){
// Let the window draw itself first.
Fl_Window::draw();
PlotPath(PT_PATH);
}
int TargetWindow::handle(int evt){
if (evt==FL_PUSH && Fl::event_button1()){
x_click=Fl::event_x();
y_click=Fl::event_y();
this->redraw();
}
return Fl_Window::handle(evt);
}
/*
PlotMem()
Plot the requested data from a given GBCSolution (the current solution or a memory)
mode = 0: Path, 1: Energy, 2: Velocity, 3: Wind Drift
*/
void TargetWindow::PlotMem(GBCSolution* mem, int mode){
double x1,x2;
double y1,y2;
int px1, px2, py1,py2;
int range;
double t_range=sl_x->value();
int perspective=btPerspective->value()==1;
int start = perspective ? 20 : 0;
x1=mem->GetWindage(start);
y1=mem->GetPath(start);
// apply perspective
if (perspective) {
y1*=t_range / (double)(start+1);
x1*=t_range / (double)(start+1);
}
int m=this->gsln->MaxRows();
for (int n=start+1;n<=t_range && n<m ;n++){
x2=mem->GetWindage(n);
y2=mem->GetPath(n);
// apply perspective
if (perspective && n<t_range) {
y2*=t_range / (double)(n+1);
x2*=t_range / (double)(n+1);
}
// Translate the x,y values into scaled pixels.
px1=(int)(x0+x_scale*(double)x1);
px2=(int)(x0+x_scale*(double)x2);
py1=(int)((y0)-(double)y_scale*(double)y1);
py2=(int)((y0)-(double)y_scale*(double)y2);
if (n>50) {
if (py2>=ymax) break;
if (px2>=xmax) break;
}
// Plot the points.
if (px1>xmin && px1<xmax && py1<ymax && py1>ymin)
fl_line(px1,py1,px2,py2);
x1=x2;
y1=y2;
}
// draw a "bullet hole" at the impact point
//fl_color(FL_YELLOW);
double r=0.300/2; // should use half caliber here
double r2;
fl_pie(px2 - (r*x_scale), py2-(r*y_scale), r*2*x_scale, r*2*y_scale, 0, 360);
// and a 1-MOA ring (predicted impact variance)
// plus 0.1 MOA for every 100 yds over 100 yds (rough spin drift allowance)
r=(1.0 * t_range / 100.0)/2;
r2=r;
if (t_range > 100) r2 += (t_range - 100)/1000;
fl_color(fl_gray_ramp(FL_NUM_GRAY * 2 / 4));
fl_arc(px2 - (r2*x_scale), py2-(r*y_scale), r2*2*x_scale, r*2*y_scale, 0, 360);
}
/*
SetupPlot()
Calculate some common parameters for the plots
This code was common to all plots (Path, Energy, Velocity) and was consolidated here
Requires x_range and y_range to be set before calling
*/
int get_ticks(int range) {
if (range < 100) return 10;
if (range < 200) return 20;
if (range < 400) return 50;
if (range < 800) return 100;
if (range < 1600) return 200;
if (range < 3200) return 500;
if (range < 6400) return 1000;
if (range < 12800) return 2000;
if (range < 25600) return 4000;
if (range < 51200) return 8000;
if (range < 102400) return 16000;
if (range < 204800) return 32000;
return 64000;
}
void TargetWindow::SetupPlot(void){
int w = this->w();
int h = this->h();
xmin = 5;
xmax = w-5;
ymin = 100;
ymax = h-5;
x_scale = (double)(xmax-xmin) / (double)x_range;
y_scale = (double)(ymax-ymin) / (double)y_range;
x_ticks=get_ticks(x_range);
y_ticks=get_ticks(y_range);
}
/*
DrawPlotBackground()
Draw the graph background, axis, scale etc
Code was common to all plots and has been consolidated here
Requires SetupPlot to have been called and y0 set first
*/
void TargetWindow::DrawPlotBackground(int mode, const char *ylabel){
// Draw the x-axis.
fl_color(FL_BLACK);
fl_line_style(FL_SOLID,2);
fl_line(xmin,y0,xmax,y0);
// Draw the y-axis
fl_line(x0,ymin,x0,ymax);
double px;
fl_color(FL_BLACK);
fl_line_style(FL_SOLID,1);
char txt[64];
int r=0;
double txtw=0;
int tick_top=ymax;
if (mode != PT_PATH) tick_top=y0;
// Draw X gridlines every x_ticks yds and label them.
if (xmin<0) {
for (px=x0;px>=xmin;px-=((double)x_ticks*x_scale)){
//fl_line((int)px,y_bottom,(int)px,y_top);
fl_line_style(FL_DOT,1);
fl_line((int)px,(int)ymin,(int)px,tick_top);
sprintf(txt,"%d",r*x_ticks);
if (r%2==0 && r>0) {
txtw=fl_width(txt);
fl_line_style(FL_SOLID,1);
fl_line((int)px,y0,(int)px,y0+8);
fl_draw(txt,(int)((int)px-(txtw/2)),y0+10+fl_height());
}
r++;
}
}
// Draw X gridlines every x_ticks yds and label them.
for (px=x0;px<=xmax;px+=((double)x_ticks*x_scale)){
//fl_line((int)px,y_bottom,(int)px,y_top);
fl_line_style(FL_DOT,1);
fl_line((int)px,(int)ymin,(int)px,tick_top);
sprintf(txt,"%d",r*x_ticks);
if (r%2==0 && r>0) {
txtw=fl_width(txt);
fl_line_style(FL_SOLID,1);
fl_line((int)px,y0,(int)px,y0+8);
fl_draw(txt,(int)((int)px-(txtw/2)),y0+10+fl_height());
}
r++;
}
// Draw Y hashmarks every 1 y_tick going up.
double py;
r=0;
for (py=y0;py>=ymin;py-=((double)y_ticks*y_scale)){
if (r>0){
fl_line(xmin,(int)py,xmax,(int)py);
sprintf(txt,"+%d%s",r*y_ticks, ylabel);
fl_draw(txt,xmin+10,(int)(py+fl_height()/2));
}
r++;
}
// Draw Y hashmarks every 1 y_tick going down
if (mode==PT_PATH) {
r=0;
for (py=y0;py<=ymax;py+=((double)y_ticks*y_scale)){
if (r>0){
fl_line(xmin,(int)py,xmax,(int)py);
sprintf(txt,"-%d%s",r*y_ticks, ylabel);
if (py+fl_height()/2<ymax) fl_draw(txt,xmin+10,(int)(py+fl_height()/2));
}
r++;
}
}
}
void TargetWindow::DrawPlotData(int mode){
fl_color(FL_BLUE);
fl_line_style(FL_SOLID,1);
PlotMem(this->gsln, mode);
if (btMem1->value()==1){
fl_color(FL_RED);
fl_line_style(FL_SOLID,1);
PlotMem(mem1, mode);
}
if (btMem2->value()==1){
fl_color(FL_GREEN);
fl_line_style(FL_SOLID,1);
PlotMem(mem2, mode);
}
if (btMem3->value()==1){
fl_color(FL_BLACK);
fl_line_style(FL_SOLID,1);
PlotMem(mem3, mode);
}
if (x_click>xmin && x_click<xmax && y_click>ymin && y_click<ymax){
// If the user clicks, show the coordinates they clicked on.
double click_label_x= ((x_click)-x0)/x_scale;
double click_label_y= (y0-y_click)/y_scale;
char lbl_point[20];
sprintf(lbl_point,"(%.2f,%.2f)",click_label_x, click_label_y);
fl_color(FL_RED);
fl_draw(lbl_point,x_click+5, y_click-5);
fl_rectf(x_click-2, y_click-2,4,4);
}
// Draw the frame around it last to make it all pretty.
fl_frame("aaaa",5,100,w()-10,h()-105);
}
void TargetWindow::PlotPath(int ptype){
// We need to find the max and min y-values to determine our y scale and y-ticks
double _miny=0;
double _maxy=0;
double _minx=0;
double _maxx=0;
double minsize=20;
switch (cTargetType->value()) {
case 0: minsize=6;
break;
case 1: minsize=12;
break;
case 2: minsize=12;
break;
case 3: minsize=5;
break;
case 4: minsize=1.5;
break;
case 5:
case 6:
case 7: minsize=10;
break;
case 8: minsize=5;
break;
}
for (int e=0;e<sl_x->value();e++){
double v=gsln->GetPath(e);
if (v > _maxy) _maxy=v;
if (v < _miny) _miny=v;
v=gsln->GetWindage(e);
if (v > _maxx) _maxx=v;
if (v < _minx) _minx=v;
}
if (_minx > -minsize) _minx=-minsize;
else _minx *= 1.05;
if (_maxx < minsize) _maxx=minsize;
else _maxx *= 1.05;
x_range= _maxx - _minx;
_miny*=1.1;
if (_miny > -minsize) _miny=-minsize;
else _miny*=1.05;
if (_maxy < minsize) _maxy=minsize;
else _maxy*=1.05;
if (_maxy < fabs(_miny)/3) _maxy = fabs(_miny)/3;
else if (fabs(_miny) < (_maxy/3)) _miny = -_maxy/3;
y_range = _maxy - _miny;
// keep a fixed aspect ratio, and keep the target roughly central
if (y_range < x_range) y_range=x_range;
if (x_range < y_range) x_range=y_range;
t_range = (int)sl_x->value();
SetupPlot();
y0 = ymax + (_miny * y_scale);
x0 = xmin - (_minx * x_scale);
// Now do our custom drawing.
fl_draw_box(FL_FLAT_BOX,xmin,ymin,w()-10,h()-ymin-5,FL_WHITE);
fl_clip(5,100,w()-10,h()-105);
fl_line_style(FL_SOLID,1);
// Draw the score circles at 1 inch intervals
double r, aimring, *rings;
int i, score, aimring_drawn=0;
char txt[10];
#define mm(x) (x/25.4)
double aimrings[TARGET_COUNT]=
{ 3, 6, 12, // 1/2, 1, 2"
mm(59.5), mm(30.5), mm(500), mm(200), mm(200), // ISSF Pistol
mm(112.4), mm(600), // ISSF Rifle
6.35, 13, 19, 36, 44 // NRA
};
double rings_data[TARGET_COUNT][13] = {
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 }, // 1/2" rings
{ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 0 }, // 1" rings
{ 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 0 }, // 2" rings
// ISSF 10m Air Pistol - 11.5mm 10 ring, increasing by 16mm
{ mm(6.5), mm(11.5), mm(27.5), mm(43.5), mm(59.5), mm(75.5), mm(91.5), mm(107.5), mm(123.5), mm(139.5), mm(155), 0 },
// ISSF 10m Air Rifle
{ -0.01, mm(0.5), mm(5.5), mm(10.5), mm(15.5), mm(20.5), mm(25.5), mm(30.5), mm(35.5), mm(40.5), mm(45.5), 0 },
// ISSF 25m Rapid Pistol - 100mm 10 ring, increasing by 100mm
{ mm(50), mm(100), mm(180), mm(260), mm(340), mm(420), mm(500), 0 },
// ISSF 25m Precision Pistol - 50mm 10 ring, increasing by 50mm
{ mm(25), mm(50), mm(100), mm(150), mm(200), mm(250), mm(300), mm(350), mm(400), mm(450), mm(500), 0 },
// ISSF 50m Precision Pistol - 50mm 10 ring, increasing by 50mm
{ mm(25), mm(50), mm(100), mm(150), mm(200), mm(250), mm(300), mm(350), mm(400), mm(450), mm(500), 0 },
// ISSF 50m Rifle
{ mm(5.2), mm(10.4), mm(26.4), mm(42.4), mm(58.4), mm(74.4), mm(90.4), mm(106.4), mm(122.4), mm(138.4), mm(154.4), 0 },
// ISSF 300m Rifle
{ mm(50), mm(100), mm(200), mm(300), mm(400), mm(500), mm(600), mm(700), mm(800), mm(900), mm(1000), 0 },
{ 1.35, 3.35, 6.35, 9.35, 12.35, 15.35, 18.35, 0 }, // NRA 100 yard reduction of 200 yard
{ 3, 7, 13, 19, 25, 31, 37, 0 }, // NRA 200 yard
{ 3, 7, 13, 19, 25, 31, 37, 0 }, // NRA 300 yard
{ 6, 12, 18, 24, 36, 48, 60, 0 }, // NRA 600 yard
{ 10, 20, 30, 44, 60, 72, 0 }, // NRA 800 yard+
};
aimring = aimrings[cTargetType->value()];
rings = rings_data[cTargetType->value()];
score=11;
i=0;
while (i<=10 && rings[i]!=0) {
i++;
score--;
}
while (i > 0) {
i--;
score++;
if (rings[i] < 0) continue;
r=rings[i]/2;
if (rings[i] <= aimring && !aimring_drawn) {
fl_color(FL_GRAY);
double ar=aimring/2;
fl_pie(x0 - (ar*x_scale), y0-(ar*y_scale), ar*2*x_scale, ar*2*y_scale, 0, 360);
aimring_drawn=1;
}
if (i==0 && 1) {
fl_color(FL_RED);
fl_pie(x0 - (r*x_scale), y0-(r*y_scale), r*2*x_scale, r*2*y_scale, 0, 360);
}
else {
//fl_color(rings[i] > aimring ? FL_BLACK : FL_WHITE);
fl_color(FL_BLACK);
fl_arc(x0 - (r*x_scale), y0-(r*y_scale), r*2*x_scale, r*2*y_scale, 0, 360);
}
//fl_color(rings[i] > aimring ? FL_BLACK : FL_WHITE);
fl_color(FL_BLACK);
// draw the score centred in the ring
if (score>9 && r < 0.9) {
// don't bother to draw score as ring is too small
}
else if (score==11 || i==0) {
fl_draw("X", x0 + 1, y0 - 5);
}
else {
sprintf(txt, "%d", score);
double w = (r - (rings[i-1]/2)) / 2;
fl_draw(txt, x0 + ((r - w)*x_scale) - (fl_width(txt)/2) - 1, y0 - 5);
}
}
fl_pop_clip();
DrawPlotBackground(ptype, "\"");
// draw +/- 1 and 5 MOA or MIL lines
if (cScopeGuides->value() > 0) {
int sgmode=cScopeGuides->value();
double pix_inset=50;
// one MIL - not quite equal to one real milliradian
long double oneunit = 3.1415 / 3200;
if (sgmode >= 5)
oneunit=oneunit / 3.438; // use one moa instead
if (sgmode >= 9)
oneunit=0.0174532925; // use one degree
double range_inset=pix_inset/x_scale;
double radius, dotradius;
int start, stop, step, step2, g, dotwidth, dotheight;
char txt[10];
step2=0;
switch (sgmode) {
case 1: start=1; stop=5; step=4; break; // 1,5 MIL
case 2: start=1; stop=5; step=1; break; // 1-5 MIL
case 3: start=1; stop=10; step=1; break; // 1-10 MIL
case 4: start=1; stop=5; step=1; step2=5; break; // 1-5,10 MIL
case 5: start=2; stop=10; step=8; break; // 2,10 MOA
case 6: start=2; stop=10; step=2; break; // 2,4,6,8,10 MOA
case 7: start=2; stop=20; step=2; break; // 2-20 MOA
case 8: start=2; stop=10; step=2; step2=10; break; // 2,4,6,8,10,20 MOA
case 9: start=1; stop=5; step=1; break; // 1-10 Degrees
case 10: start=5; stop=15; step=5; break; // 5,10,15 Degrees
default: start=1; stop=1; step=1; break;
}
fl_clip(5,100,w()-10,h()-105);
fl_line_style(FL_SOLID,2);
fl_color(FL_BLACK);
dotradius= 0.25/2;
dotwidth = tanf(oneunit * dotradius) * t_range * 36.0 * x_scale;
dotheight= tanf(oneunit * dotradius) * t_range * 36.0 * y_scale;
for (g=start; g<=stop; g+=step) {
radius = tanf(oneunit*g) * t_range * 36.0;
if (radius <= -_miny || radius <= x_range/2) {
//fl_color(radius > aimring ? FL_BLACK : FL_WHITE);
fl_line(x0-(radius*x_scale), y0+dotheight, x0-(radius*x_scale), y0-dotheight);
fl_line(x0+(radius*x_scale), y0+dotheight, x0+(radius*x_scale), y0-dotheight);
fl_line(x0-dotwidth, y0-(radius*y_scale), x0+dotwidth, y0-(radius*y_scale));
fl_line(x0-dotwidth, y0+(radius*y_scale), x0+dotwidth, y0+(radius*y_scale));
if (g==start) {
if (sgmode>=9) sprintf(txt, "-%d Deg", g);
else if (sgmode>=5) sprintf(txt, "-%d MOA", g);
else sprintf(txt, "-%d MIL", g);
}
else sprintf(txt, "-%d", g);
fl_draw(txt, x0+dotwidth+2, y0+(radius*y_scale) + 3);
}
}
if (step2 > 0) {
g+=step2-step;
radius =tanf(oneunit*g) * t_range * 36.0;
if (radius <= -_miny || radius <= x_range/2) {
//fl_color(radius > aimring ? FL_BLACK : FL_WHITE);
fl_line(x0-(radius*x_scale), y0+dotheight, x0-(radius*x_scale), y0-dotheight);
fl_line(x0+(radius*x_scale), y0+dotheight, x0+(radius*x_scale), y0-dotheight);
fl_line(x0-dotheight, y0-(radius*y_scale), x0+dotheight, y0-(radius*y_scale));
fl_line(x0-dotheight, y0+(radius*y_scale), x0+dotheight, y0+(radius*y_scale));
sprintf(txt, "+%d", g);
fl_draw(txt, x0+dotwidth+2, y0+(radius*y_scale)+3);
}
}
fl_pop_clip();
}
DrawPlotData(ptype);
return;
}
void TargetWindow::cb_btPlot(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->damage(255);
T->draw();
}
void TargetWindow::cb_nothing(Fl_Widget* o, void* v){
;
}
void TargetWindow::cb_Close(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->~TargetWindow();
}
void TargetWindow::cb_slUpdate(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->damage(255);
T->draw();
}
void TargetWindow::cb_Mem1(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->damage(255);
T->draw();
}
void TargetWindow::cb_Mem2(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->redraw();
}
void TargetWindow::cb_Guides(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->redraw();
}
void TargetWindow::cb_TargetType(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->redraw();
}
void TargetWindow::cb_Perspective(Fl_Widget* o, void* v){
TargetWindow* T = (TargetWindow*)v;
T->redraw();
}