From ac7b82d7c1fbd8bfd38e117faa581b3a65d98d87 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 23 May 2019 17:19:37 +0000 Subject: [PATCH] Allow configuring the amount of digits displayed after decimal point. This is useful in niche cases, like making angular measurement tools. Also, use simpler and more principled code for numeric precision while editing constraints: don't special-case angles, but use up to 10 digits after the decimal point for everything. --- src/confscreen.cpp | 25 ++++++++++++++++++++++--- src/drawconstraint.cpp | 6 +----- src/mouse.cpp | 42 ++++++++++++++++++------------------------ src/solvespace.cpp | 9 +++++++++ src/solvespace.h | 2 ++ src/ui.h | 18 ++++++++++-------- 6 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/confscreen.cpp b/src/confscreen.cpp index df5a95d20..12b543756 100644 --- a/src/confscreen.cpp +++ b/src/confscreen.cpp @@ -60,10 +60,15 @@ void TextWindow::ScreenChangeGridSpacing(int link, uint32_t v) { } void TextWindow::ScreenChangeDigitsAfterDecimal(int link, uint32_t v) { - SS.TW.ShowEditControl(3, ssprintf("%d", SS.UnitDigitsAfterDecimal())); + SS.TW.ShowEditControl(14, ssprintf("%d", SS.UnitDigitsAfterDecimal())); SS.TW.edit.meaning = Edit::DIGITS_AFTER_DECIMAL; } +void TextWindow::ScreenChangeDigitsAfterDecimalDegree(int link, uint32_t v) { + SS.TW.ShowEditControl(14, ssprintf("%d", SS.afterDecimalDegree)); + SS.TW.edit.meaning = Edit::DIGITS_AFTER_DECIMAL_DEGREE; +} + void TextWindow::ScreenChangeExportScale(int link, uint32_t v) { SS.TW.ShowEditControl(5, ssprintf("%.3f", (double)SS.exportScale)); SS.TW.edit.meaning = Edit::EXPORT_SCALE; @@ -235,10 +240,14 @@ void TextWindow::ShowConfiguration() { SS.MmToString(SS.gridSpacing).c_str(), &ScreenChangeGridSpacing, 0); Printf(false, "%Ft digits after decimal point to show%E"); - Printf(false, "%Ba %d %Fl%Ll%f%D[change]%E (e.g. '%s')", + Printf(false, "%Ba%Ft distances: %Fd%d %Fl%Ll%f%D[change]%E (e.g. '%s')", SS.UnitDigitsAfterDecimal(), &ScreenChangeDigitsAfterDecimal, 0, SS.MmToString(SS.StringToMm("1.23456789")).c_str()); + Printf(false, "%Ba%Ft angles: %Fd%d %Fl%Ll%f%D[change]%E (e.g. '%s')", + SS.afterDecimalDegree, + &ScreenChangeDigitsAfterDecimalDegree, 0, + SS.DegreeToString(1.23456789).c_str()); Printf(false, ""); Printf(false, "%Ft export scale factor (1:1=mm, 1:25.4=inch)"); @@ -400,13 +409,23 @@ bool TextWindow::EditControlDoneForConfiguration(const std::string &s) { case Edit::DIGITS_AFTER_DECIMAL: { int v = atoi(s.c_str()); if(v < 0 || v > 8) { - Error(_("Specify between 0 and 8 digits after the decimal.")); + Error(_("Specify between 0 and %d digits after the decimal."), 8); } else { SS.SetUnitDigitsAfterDecimal(v); SS.GW.Invalidate(); } break; } + case Edit::DIGITS_AFTER_DECIMAL_DEGREE: { + int v = atoi(s.c_str()); + if(v < 0 || v > 4) { + Error(_("Specify between 0 and %d digits after the decimal."), 4); + } else { + SS.afterDecimalDegree = v; + SS.GW.Invalidate(); + } + break; + } case Edit::EXPORT_SCALE: { Expr *e = Expr::From(s, /*popUpError=*/true); if(e) { diff --git a/src/drawconstraint.cpp b/src/drawconstraint.cpp index 5c5836245..02aa6ab20 100644 --- a/src/drawconstraint.cpp +++ b/src/drawconstraint.cpp @@ -11,11 +11,7 @@ std::string Constraint::Label() const { std::string result; if(type == Type::ANGLE) { - if(valA == floor(valA)) { - result = ssprintf("%.0f°", valA); - } else { - result = ssprintf("%.2f°", valA); - } + result = SS.DegreeToString(valA) + "°"; } else if(type == Type::LENGTH_RATIO) { result = ssprintf("%.3f:1", valA); } else if(type == Type::COMMENT) { diff --git a/src/mouse.cpp b/src/mouse.cpp index 685eaeb3f..4e1c3fcd4 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -1361,36 +1361,30 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { editPlaceholder = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; break; - case Constraint::Type::ANGLE: - case Constraint::Type::LENGTH_RATIO: - editValue = ssprintf("%.3f", c->valA); - editPlaceholder = "0.000"; - break; - default: { - double v = fabs(c->valA); + double value = fabs(c->valA); // If displayed as radius, also edit as radius. if(c->type == Constraint::Type::DIAMETER && c->other) - v /= 2; - - std::string def = SS.MmToString(v); - double eps = 1e-12; - if(fabs(SS.StringToMm(def) - v) < eps) { - // Show value with default number of digits after decimal, - // which is at least enough to represent it exactly. - editValue = def; + value /= 2; + + // Try showing value with default number of digits after decimal first. + if(c->type == Constraint::Type::LENGTH_RATIO) { + editValue = ssprintf("%.3f", value); + } else if(c->type == Constraint::Type::ANGLE) { + editValue = SS.DegreeToString(value); } else { - // Show value with as many digits after decimal as - // required to represent it exactly, up to 10. - v /= SS.MmPerUnit(); - int i; - for(i = 0; i <= 10; i++) { - editValue = ssprintf("%.*f", i, v); - if(fabs(std::stod(editValue) - v) < eps) break; - } + editValue = SS.MmToString(value); + value /= SS.MmPerUnit(); + } + // If that's not enough to represent it exactly, show the value with as many + // digits after decimal as required, up to 10. + int digits = 0; + while(fabs(std::stod(editValue) - value) > 1e-10) { + editValue = ssprintf("%.*f", digits, value); + digits++; } - editPlaceholder = "0.00000"; + editPlaceholder = "10.000000"; break; } } diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 409c7eda4..944ac431d 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -56,6 +56,7 @@ void SolveSpaceUI::Init() { // Number of digits after the decimal point afterDecimalMm = settings->ThawInt("AfterDecimalMm", 2); afterDecimalInch = settings->ThawInt("AfterDecimalInch", 3); + afterDecimalDegree = settings->ThawInt("AfterDecimalDegree", 2); // Camera tangent (determines perspective) cameraTangent = settings->ThawFloat("CameraTangent", 0.3f/1e3); // Grid spacing @@ -229,6 +230,7 @@ void SolveSpaceUI::Exit() { // Number of digits after the decimal point settings->FreezeInt("AfterDecimalMm", (uint32_t)afterDecimalMm); settings->FreezeInt("AfterDecimalInch", (uint32_t)afterDecimalInch); + settings->FreezeInt("AfterDecimalDegree", (uint32_t)afterDecimalDegree); // Camera tangent (determines perspective) settings->FreezeFloat("CameraTangent", (float)cameraTangent); // Grid spacing @@ -320,6 +322,13 @@ std::string SolveSpaceUI::MmToString(double v) { } return ""; } +std::string SolveSpaceUI::DegreeToString(double v) { + if(fabs(v - floor(v)) > 1e-10) { + return ssprintf("%.*f", afterDecimalDegree, v); + } else { + return ssprintf("%.0f", v); + } +} double SolveSpaceUI::ExprToMm(Expr *e) { return (e->Eval()) * MmPerUnit(); } diff --git a/src/solvespace.h b/src/solvespace.h index 46d2104c2..f6be2509d 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -621,9 +621,11 @@ class SolveSpaceUI { Unit viewUnits; int afterDecimalMm; int afterDecimalInch; + int afterDecimalDegree; int autosaveInterval; // in minutes std::string MmToString(double v); + std::string DegreeToString(double v); double ExprToMm(Expr *e); double StringToMm(const std::string &s); const char *UnitName(); diff --git a/src/ui.h b/src/ui.h index 0ac02b658..fd033d9df 100644 --- a/src/ui.h +++ b/src/ui.h @@ -300,14 +300,15 @@ class TextWindow { CAMERA_TANGENT = 105, GRID_SPACING = 106, DIGITS_AFTER_DECIMAL = 107, - EXPORT_SCALE = 108, - EXPORT_OFFSET = 109, - CANVAS_SIZE = 110, - G_CODE_DEPTH = 120, - G_CODE_PASSES = 121, - G_CODE_FEED = 122, - G_CODE_PLUNGE_FEED = 123, - AUTOSAVE_INTERVAL = 124, + DIGITS_AFTER_DECIMAL_DEGREE = 108, + EXPORT_SCALE = 109, + EXPORT_OFFSET = 110, + CANVAS_SIZE = 111, + G_CODE_DEPTH = 112, + G_CODE_PASSES = 113, + G_CODE_FEED = 114, + G_CODE_PLUNGE_FEED = 115, + AUTOSAVE_INTERVAL = 116, // For TTF text TTF_TEXT = 300, // For the step dimension screen @@ -467,6 +468,7 @@ class TextWindow { static void ScreenChangeCameraTangent(int link, uint32_t v); static void ScreenChangeGridSpacing(int link, uint32_t v); static void ScreenChangeDigitsAfterDecimal(int link, uint32_t v); + static void ScreenChangeDigitsAfterDecimalDegree(int link, uint32_t v); static void ScreenChangeExportScale(int link, uint32_t v); static void ScreenChangeExportOffset(int link, uint32_t v); static void ScreenChangeGCodeParameter(int link, uint32_t v);