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.
This commit is contained in:
whitequark 2019-05-23 17:19:37 +00:00
parent d01f715ebf
commit ac7b82d7c1
6 changed files with 61 additions and 39 deletions

View File

@ -60,10 +60,15 @@ void TextWindow::ScreenChangeGridSpacing(int link, uint32_t v) {
} }
void TextWindow::ScreenChangeDigitsAfterDecimal(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; 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) { void TextWindow::ScreenChangeExportScale(int link, uint32_t v) {
SS.TW.ShowEditControl(5, ssprintf("%.3f", (double)SS.exportScale)); SS.TW.ShowEditControl(5, ssprintf("%.3f", (double)SS.exportScale));
SS.TW.edit.meaning = Edit::EXPORT_SCALE; SS.TW.edit.meaning = Edit::EXPORT_SCALE;
@ -235,10 +240,14 @@ void TextWindow::ShowConfiguration() {
SS.MmToString(SS.gridSpacing).c_str(), SS.MmToString(SS.gridSpacing).c_str(),
&ScreenChangeGridSpacing, 0); &ScreenChangeGridSpacing, 0);
Printf(false, "%Ft digits after decimal point to show%E"); 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(), SS.UnitDigitsAfterDecimal(),
&ScreenChangeDigitsAfterDecimal, 0, &ScreenChangeDigitsAfterDecimal, 0,
SS.MmToString(SS.StringToMm("1.23456789")).c_str()); 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, "");
Printf(false, "%Ft export scale factor (1:1=mm, 1:25.4=inch)"); 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: { case Edit::DIGITS_AFTER_DECIMAL: {
int v = atoi(s.c_str()); int v = atoi(s.c_str());
if(v < 0 || v > 8) { 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 { } else {
SS.SetUnitDigitsAfterDecimal(v); SS.SetUnitDigitsAfterDecimal(v);
SS.GW.Invalidate(); SS.GW.Invalidate();
} }
break; 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: { case Edit::EXPORT_SCALE: {
Expr *e = Expr::From(s, /*popUpError=*/true); Expr *e = Expr::From(s, /*popUpError=*/true);
if(e) { if(e) {

View File

@ -11,11 +11,7 @@
std::string Constraint::Label() const { std::string Constraint::Label() const {
std::string result; std::string result;
if(type == Type::ANGLE) { if(type == Type::ANGLE) {
if(valA == floor(valA)) { result = SS.DegreeToString(valA) + "°";
result = ssprintf("%.0f°", valA);
} else {
result = ssprintf("%.2f°", valA);
}
} else if(type == Type::LENGTH_RATIO) { } else if(type == Type::LENGTH_RATIO) {
result = ssprintf("%.3f:1", valA); result = ssprintf("%.3f:1", valA);
} else if(type == Type::COMMENT) { } else if(type == Type::COMMENT) {

View File

@ -1361,36 +1361,30 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
editPlaceholder = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; editPlaceholder = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
break; break;
case Constraint::Type::ANGLE:
case Constraint::Type::LENGTH_RATIO:
editValue = ssprintf("%.3f", c->valA);
editPlaceholder = "0.000";
break;
default: { default: {
double v = fabs(c->valA); double value = fabs(c->valA);
// If displayed as radius, also edit as radius. // If displayed as radius, also edit as radius.
if(c->type == Constraint::Type::DIAMETER && c->other) if(c->type == Constraint::Type::DIAMETER && c->other)
v /= 2; value /= 2;
std::string def = SS.MmToString(v); // Try showing value with default number of digits after decimal first.
double eps = 1e-12; if(c->type == Constraint::Type::LENGTH_RATIO) {
if(fabs(SS.StringToMm(def) - v) < eps) { editValue = ssprintf("%.3f", value);
// Show value with default number of digits after decimal, } else if(c->type == Constraint::Type::ANGLE) {
// which is at least enough to represent it exactly. editValue = SS.DegreeToString(value);
editValue = def;
} else { } else {
// Show value with as many digits after decimal as editValue = SS.MmToString(value);
// required to represent it exactly, up to 10. value /= SS.MmPerUnit();
v /= SS.MmPerUnit();
int i;
for(i = 0; i <= 10; i++) {
editValue = ssprintf("%.*f", i, v);
if(fabs(std::stod(editValue) - v) < eps) break;
} }
// 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; break;
} }
} }

View File

@ -56,6 +56,7 @@ void SolveSpaceUI::Init() {
// Number of digits after the decimal point // Number of digits after the decimal point
afterDecimalMm = settings->ThawInt("AfterDecimalMm", 2); afterDecimalMm = settings->ThawInt("AfterDecimalMm", 2);
afterDecimalInch = settings->ThawInt("AfterDecimalInch", 3); afterDecimalInch = settings->ThawInt("AfterDecimalInch", 3);
afterDecimalDegree = settings->ThawInt("AfterDecimalDegree", 2);
// Camera tangent (determines perspective) // Camera tangent (determines perspective)
cameraTangent = settings->ThawFloat("CameraTangent", 0.3f/1e3); cameraTangent = settings->ThawFloat("CameraTangent", 0.3f/1e3);
// Grid spacing // Grid spacing
@ -229,6 +230,7 @@ void SolveSpaceUI::Exit() {
// Number of digits after the decimal point // Number of digits after the decimal point
settings->FreezeInt("AfterDecimalMm", (uint32_t)afterDecimalMm); settings->FreezeInt("AfterDecimalMm", (uint32_t)afterDecimalMm);
settings->FreezeInt("AfterDecimalInch", (uint32_t)afterDecimalInch); settings->FreezeInt("AfterDecimalInch", (uint32_t)afterDecimalInch);
settings->FreezeInt("AfterDecimalDegree", (uint32_t)afterDecimalDegree);
// Camera tangent (determines perspective) // Camera tangent (determines perspective)
settings->FreezeFloat("CameraTangent", (float)cameraTangent); settings->FreezeFloat("CameraTangent", (float)cameraTangent);
// Grid spacing // Grid spacing
@ -320,6 +322,13 @@ std::string SolveSpaceUI::MmToString(double v) {
} }
return ""; 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) { double SolveSpaceUI::ExprToMm(Expr *e) {
return (e->Eval()) * MmPerUnit(); return (e->Eval()) * MmPerUnit();
} }

View File

@ -621,9 +621,11 @@ public:
Unit viewUnits; Unit viewUnits;
int afterDecimalMm; int afterDecimalMm;
int afterDecimalInch; int afterDecimalInch;
int afterDecimalDegree;
int autosaveInterval; // in minutes int autosaveInterval; // in minutes
std::string MmToString(double v); std::string MmToString(double v);
std::string DegreeToString(double v);
double ExprToMm(Expr *e); double ExprToMm(Expr *e);
double StringToMm(const std::string &s); double StringToMm(const std::string &s);
const char *UnitName(); const char *UnitName();

View File

@ -300,14 +300,15 @@ public:
CAMERA_TANGENT = 105, CAMERA_TANGENT = 105,
GRID_SPACING = 106, GRID_SPACING = 106,
DIGITS_AFTER_DECIMAL = 107, DIGITS_AFTER_DECIMAL = 107,
EXPORT_SCALE = 108, DIGITS_AFTER_DECIMAL_DEGREE = 108,
EXPORT_OFFSET = 109, EXPORT_SCALE = 109,
CANVAS_SIZE = 110, EXPORT_OFFSET = 110,
G_CODE_DEPTH = 120, CANVAS_SIZE = 111,
G_CODE_PASSES = 121, G_CODE_DEPTH = 112,
G_CODE_FEED = 122, G_CODE_PASSES = 113,
G_CODE_PLUNGE_FEED = 123, G_CODE_FEED = 114,
AUTOSAVE_INTERVAL = 124, G_CODE_PLUNGE_FEED = 115,
AUTOSAVE_INTERVAL = 116,
// For TTF text // For TTF text
TTF_TEXT = 300, TTF_TEXT = 300,
// For the step dimension screen // For the step dimension screen
@ -467,6 +468,7 @@ public:
static void ScreenChangeCameraTangent(int link, uint32_t v); static void ScreenChangeCameraTangent(int link, uint32_t v);
static void ScreenChangeGridSpacing(int link, uint32_t v); static void ScreenChangeGridSpacing(int link, uint32_t v);
static void ScreenChangeDigitsAfterDecimal(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 ScreenChangeExportScale(int link, uint32_t v);
static void ScreenChangeExportOffset(int link, uint32_t v); static void ScreenChangeExportOffset(int link, uint32_t v);
static void ScreenChangeGCodeParameter(int link, uint32_t v); static void ScreenChangeGCodeParameter(int link, uint32_t v);