From 0bc01ed14914d02bef04513b77ad04012a571719 Mon Sep 17 00:00:00 2001 From: Ineiev Date: Sun, 6 Mar 2011 08:52:53 +0000 Subject: [PATCH] (GTK HID) fix annoying decimals When in metric grid mode, the coordinates are displayed with irregular tails of nines, e.g. "116.9998 43.9999" when the grid is set to 1mm. The fix includes using more precise metric-to-imperial and crosshair calculations and fitting crosshair values into metric grids. To address the issue in a really reliable way we need at least one more separate variable, to explicitly mark the grid as metric (as opposed to the displayed units); this flag should also be saved in PCB files. First reported by Kai-Martin Knaak. Closes-bug: lp-699452 (sf-2117383) Closes-bug: lp-699169 (sf-1741659) --- src/action.c | 2 +- src/const.h | 4 +- src/crosshair.c | 32 ++++++++++------- src/gpcb-menu.res | 12 +++--- src/hid/gtk/gui-misc.c | 92 ++++++++++++++++++++++++++++++++++++++---------- src/misc.c | 2 +- src/misc.h | 2 +- src/pcb-menu.res | 12 +++--- src/set.c | 2 +- src/set.h | 2 +- 10 files changed, 111 insertions(+), 51 deletions(-) diff --git a/src/action.c b/src/action.c index de2738e..88027ee 100644 --- a/src/action.c +++ b/src/action.c @@ -2212,7 +2212,7 @@ ActionSetValue (int argc, char **argv, int x, int y) char *val = ARG (1); char *units = ARG (2); bool absolute; /* flag for 'absolute' value */ - float value; + double value; int err = 0; if (function && val) diff --git a/src/const.h b/src/const.h index e4a1d31..3b6cd30 100644 --- a/src/const.h +++ b/src/const.h @@ -66,9 +66,9 @@ #define TAN_30_DEGREE 0.577350269 /* tan(30) */ #define TAN_60_DEGREE 1.732050808 /* tan(60) */ #define MIL_TO_MM 0.025400000 -#define MM_TO_MIL 39.37007874 +#define MM_TO_MIL (1./MIL_TO_MM) #define COOR_TO_MM 0.000254000 -#define MM_TO_COOR 3937.007874 +#define MM_TO_COOR (1./COOR_TO_MM) #define LN_2_OVER_2 0.346573590 /* --------------------------------------------------------------------------- diff --git a/src/crosshair.c b/src/crosshair.c index 4c94889..77b372f 100644 --- a/src/crosshair.c +++ b/src/crosshair.c @@ -766,6 +766,12 @@ RestoreCrosshair (bool BlockToo) } } +static double +square (double x) +{ + return x * x; +} + /* --------------------------------------------------------------------------- * recalculates the passed coordinates to fit the current grid setting */ @@ -774,7 +780,7 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) { LocationType x2, y2, x0, y0; void *ptr1, *ptr2, *ptr3; - float nearest, sq_dist; + double nearest, sq_dist; int ans; x0 = 0; @@ -892,10 +898,10 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) px = (pad->Point1.X + pad->Point2.X) / 2; py = (pad->Point1.Y + pad->Point2.Y) / 2; - sq_dist = SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y); + sq_dist = square (px - Crosshair.X) + square (py - Crosshair.Y); if (!gui->shift_is_pressed() || - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist) { x0 = px; y0 = py; @@ -918,10 +924,10 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) if (ans) { PinTypePtr pin = (PinTypePtr) ptr2; - sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y); + sq_dist = square (pin->X - Crosshair.X) + square (pin->Y - Crosshair.Y); if ((nearest == -1 || sq_dist < nearest) && (!gui->shift_is_pressed() || - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist)) { x0 = pin->X; y0 = pin->Y; @@ -946,10 +952,10 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) if (ans) { PinTypePtr pin = (PinTypePtr) ptr2; - sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y); + sq_dist = square (pin->X - Crosshair.X) + square (pin->Y - Crosshair.Y); if ((nearest == -1 || sq_dist < nearest) && (!gui->shift_is_pressed() || - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist)) { x0 = pin->X; y0 = pin->Y; @@ -966,10 +972,10 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) if (ans) { PointTypePtr pnt = (PointTypePtr) ptr3; - sq_dist = SQUARE (pnt->X - Crosshair.X) + SQUARE (pnt->Y - Crosshair.Y); + sq_dist = square (pnt->X - Crosshair.X) + square (pnt->Y - Crosshair.Y); if ((nearest == -1 || sq_dist < nearest) && (!gui->shift_is_pressed() || - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist)) { x0 = pnt->X; y0 = pnt->Y; @@ -986,10 +992,10 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) if (ans) { PointTypePtr pnt = (PointTypePtr) ptr3; - sq_dist = SQUARE (pnt->X - Crosshair.X) + SQUARE (pnt->Y - Crosshair.Y); + sq_dist = square (pnt->X - Crosshair.X) + square (pnt->Y - Crosshair.Y); if ((nearest == -1 || sq_dist < nearest) && (!gui->shift_is_pressed() || - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist)) { x0 = pnt->X; y0 = pnt->Y; @@ -1007,9 +1013,9 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y) if (ans & ELEMENT_TYPE) { ElementTypePtr el = (ElementTypePtr) ptr1; - sq_dist = SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y); + sq_dist = square (el->MarkX - Crosshair.X) + square (el->MarkY - Crosshair.Y); if ((nearest == -1 || sq_dist < nearest) && - SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist) + square (x0 - Crosshair.X) + square (y0 - Crosshair.Y) > sq_dist) { x0 = el->MarkX; y0 = el->MarkY; diff --git a/src/gpcb-menu.res b/src/gpcb-menu.res index bd9acac..593b737 100644 --- a/src/gpcb-menu.res +++ b/src/gpcb-menu.res @@ -133,12 +133,12 @@ MainMenu = { "50 mil" checked=gridsize,5000 SetUnits(mil) SetValue(Grid,5000)} {"100 mil" checked=gridsize,10000 SetUnits(mil) SetValue(Grid,10000)} - - {"0.01 mm" checked=gridsize,39 SetUnits(mm) SetValue(Grid,39.37007874)} - {"0.05 mm" checked=gridsize,197 SetUnits(mm) SetValue(Grid,196.85039370)} - {"0.1 mm" checked=gridsize,394 SetUnits(mm) SetValue(Grid,393.70078740)} - {"0.25 mm" checked=gridsize,984 SetUnits(mm) SetValue(Grid,984.25197)} - {"0.5 mm" checked=gridsize,1969 SetUnits(mm) SetValue(Grid,1968.503937)} - {"1 mm" checked=gridsize,3937 SetUnits(mm) SetValue(Grid,3937.00787400)} + {"0.01 mm" checked=gridsize,39 SetUnits(mm) SetValue(Grid,0.01mm)} + {"0.05 mm" checked=gridsize,197 SetUnits(mm) SetValue(Grid,0.05mm)} + {"0.1 mm" checked=gridsize,394 SetUnits(mm) SetValue(Grid,0.1mm)} + {"0.25 mm" checked=gridsize,984 SetUnits(mm) SetValue(Grid,0.25mm)} + {"0.5 mm" checked=gridsize,1969 SetUnits(mm) SetValue(Grid,0.5mm)} + {"1 mm" checked=gridsize,3937 SetUnits(mm) SetValue(Grid,1mm)} - {"Grid -5mil" SetValue(Grid,-5,mil) a={"Shift-G" "Shiftg"}} {"Grid +5mil" SetValue(Grid,+5,mil) a={"G" "g"}} diff --git a/src/hid/gtk/gui-misc.c b/src/hid/gtk/gui-misc.c index 1c55a99..a8f4ed5 100644 --- a/src/hid/gtk/gui-misc.c +++ b/src/hid/gtk/gui-misc.c @@ -547,6 +547,65 @@ ghid_set_status_line_label (void) ghid_status_line_set_text (text); } +/* returns an auxiliary value needed to adjust mm grid. + the adjustment is needed to prevent ..99 tails in position labels. + + All these are a workaround to precision lost + because of double->integer transform + while fitting Crosshair to grid in crosshair.c + + There is another workaround: report mm dimensions with %.2f, like + in the Lesstif hid; but this reduces the information */ +static double +ghid_get_grid_factor(void) +{ + /* when grid units are mm, they shall be an integer of + 1 mm / grid_scale */ + const int grid_scale = 10000; /* metric grid step is .1 um */ + double factor, rounded_factor; + + /* adjustment is not needed for inches + probably because x/100 is always 'integer' enough */ + if (!Settings.grid_units_mm) + return -1; + + factor = PCB->Grid * COOR_TO_MM * grid_scale; + rounded_factor = floor (factor + .5); + + /* check whether the grid is actually metric + (as of Feb 2011, Settings.grid_units_mm may indicate just that + the _displayed_ units are mm) */ + if (fabs (factor - rounded_factor) > 1e-3) + return -1; + + return rounded_factor / grid_scale; +} +/* transforms a pcb coordinate to selected units + adjusted to the nearest grid point for mm grid */ +static double +ghid_grid_pcb_to_units (double x, double grid_factor) +{ + double x_scaled = (Settings.grid_units_mm? COOR_TO_MM: 1./100) * x; + double nearest_gridpoint; + + if (grid_factor < 0) + return x_scaled; + + x *= COOR_TO_MM; + + nearest_gridpoint = floor (x / grid_factor + .5); + /* honour snapping to an unaligned object */ + if (fabs (nearest_gridpoint * grid_factor - x) > 0.55 * COOR_TO_MM) + return x_scaled; + /* without mm-adjusted grid_factor + (return floor (x / PCB->Grid + .5) * PCB->Grid * COOR_TO_MM), + the round-off errors redintroduce the bug for 0.1 or 0.05 mm grid + at coordinates more than 1500 mm. + grid_factor makes the stuff work at least up to 254 m, + which is 100 times more than default maximum board size as of Feb 2011. */ + return nearest_gridpoint * grid_factor; +} + /* --------------------------------------------------------------------------- * output of cursor position */ @@ -554,32 +613,27 @@ void ghid_set_cursor_position_labels (void) { gchar text[128]; + int prec = Settings.grid_units_mm ? 4: 2; + double grid_factor = ghid_get_grid_factor(); if (Marked.status) - {double scale, dx, dy, r, a; - scale = Settings.grid_units_mm ? COOR_TO_MM: 1. / 100; - dx = (Crosshair.X - Marked.X) * scale; - dy = (Marked.Y - Crosshair.Y) * scale; - r = sqrt( dx * dx + dy * dy); - a = atan2(dy, dx) * 180 / M_PI; - if (Settings.grid_units_mm) - snprintf (text, sizeof (text), "r %-.4f; phi %-.1f; %-.4f %-.4f", - r, a, dx, dy); - - else - snprintf (text, sizeof (text), "r %-.2f; phi %-.1f; %-.2f %-.2f", - r, a, dx, dy); + { + double dx, dy, r, a; + + dx = ghid_grid_pcb_to_units (Crosshair.X - Marked.X, grid_factor); + dy = ghid_grid_pcb_to_units (Crosshair.Y - Marked.Y, grid_factor); + r = sqrt (dx * dx + dy * dy); + a = atan2 (dy, dx) * RAD_TO_DEG; + snprintf (text, sizeof (text), "r %-.*f; phi %-.1f; %-.*f %-.*f", + prec, r, a, prec, dx, prec, dy); ghid_cursor_position_relative_label_set_text (text); } else ghid_cursor_position_relative_label_set_text ("r __.__; phi __._; __.__ __.__"); - if (Settings.grid_units_mm) - snprintf (text, sizeof (text), "%-.4f %-.4f", - COOR_TO_MM * Crosshair.X, COOR_TO_MM * Crosshair.Y); - else - snprintf (text, sizeof (text), "%-.2f %-.2f", - Crosshair.X / 100., Crosshair.Y / 100.); + snprintf (text, sizeof (text), "%-.*f %-.*f", + prec, ghid_grid_pcb_to_units (Crosshair.X, grid_factor), + prec, ghid_grid_pcb_to_units (Crosshair.Y, grid_factor)); ghid_cursor_position_label_set_text (text); } diff --git a/src/misc.c b/src/misc.c index 13c7398..9874861 100644 --- a/src/misc.c +++ b/src/misc.c @@ -107,7 +107,7 @@ static struct /* Get Value returns a numeric value passed from the string and sets the * bool variable absolute to false if it leads with a +/- character */ -float +double GetValue (const char *val, const char *units, bool * absolute) { double value; diff --git a/src/misc.h b/src/misc.h index 776e309..2f66899 100644 --- a/src/misc.h +++ b/src/misc.h @@ -74,7 +74,7 @@ BoxTypePtr GetArcEnds (ArcTypePtr); void ChangeArcAngles (LayerTypePtr, ArcTypePtr, long int, long int); char *UniqueElementName (DataTypePtr, char *); void AttachForCopy (LocationType, LocationType); -float GetValue (const char *, const char *, bool *); +double GetValue (const char *, const char *, bool *); int FileExists (const char *); char *Concat (const char *, ...); /* end with NULL */ diff --git a/src/pcb-menu.res b/src/pcb-menu.res index dcba346..5e3682c 100644 --- a/src/pcb-menu.res +++ b/src/pcb-menu.res @@ -104,12 +104,12 @@ MainMenu = { "50 mil" checked=gridsize,5000 SetUnits(mil) SetValue(Grid,5000)} {"100 mil" checked=gridsize,10000 SetUnits(mil) SetValue(Grid,10000)} - - {"0.01 mm" checked=gridsize,39 SetUnits(mm) SetValue(Grid,39.37007874)} - {"0.05 mm" checked=gridsize,197 SetUnits(mm) SetValue(Grid,196.85039370)} - {"0.1 mm" checked=gridsize,394 SetUnits(mm) SetValue(Grid,393.70078740)} - {"0.25 mm" checked=gridsize,984 SetUnits(mm) SetValue(Grid,984.25197)} - {"0.5 mm" checked=gridsize,1969 SetUnits(mm) SetValue(Grid,1968.503937)} - {"1 mm" checked=gridsize,3937 SetUnits(mm) SetValue(Grid,3937.00787400)} + {"0.01 mm" checked=gridsize,39 SetUnits(mm) SetValue(Grid,0.01mm)} + {"0.05 mm" checked=gridsize,197 SetUnits(mm) SetValue(Grid,0.05mm)} + {"0.1 mm" checked=gridsize,394 SetUnits(mm) SetValue(Grid,0.1mm)} + {"0.25 mm" checked=gridsize,984 SetUnits(mm) SetValue(Grid,0.25mm)} + {"0.5 mm" checked=gridsize,1969 SetUnits(mm) SetValue(Grid,0.5mm)} + {"1 mm" checked=gridsize,3937 SetUnits(mm) SetValue(Grid,1mm)} - {"Grid -5mil" SetValue(Grid,-5,mil) a={"Shift-G" "Shiftg"}} {"Grid +5mil" SetValue(Grid,+5,mil) a={"G" "g"}} diff --git a/src/set.c b/src/set.c index 25267d8..188203a 100644 --- a/src/set.c +++ b/src/set.c @@ -69,7 +69,7 @@ static int mode_stack[MAX_MODESTACK_DEPTH]; * sets cursor grid with respect to grid offset values */ void -SetGrid (float Grid, bool align) +SetGrid (double Grid, bool align) { if (Grid >= 1 && Grid <= MAX_GRID) { diff --git a/src/set.h b/src/set.h index e139766..f8f6a9a 100644 --- a/src/set.h +++ b/src/set.h @@ -34,7 +34,7 @@ #include "global.h" void SetTextScale (Dimension); -void SetGrid (float, bool); +void SetGrid (double, bool); void SetZoom (float); void SetLineSize (BDimension); void SetViaSize (BDimension, bool); -- 1.6.5.2