Add a setting to format constraint labels using SI prefixes.
Supported metric units: km, m, cm, mm, µm, nm. Supported USCS units: in, mil, µin. Also, use the newly introduced unit formatting machinery in tools for measuring perimeter, area and volume, so that e.g. volume is not displayed in millions of cubic millimeters.pull/434/head
parent
9faa7cb0ca
commit
9d1c295495
|
@ -33,6 +33,8 @@ New constraint features:
|
||||||
in the text window.
|
in the text window.
|
||||||
* When selecting an entity, the constraints applied to it can be selected
|
* When selecting an entity, the constraints applied to it can be selected
|
||||||
in the text window.
|
in the text window.
|
||||||
|
* Distance constraint labels can now be formatted to use SI prefixes.
|
||||||
|
Values are edited in the configured unit regardless of label format.
|
||||||
* It is now possible to turn off automatic creation of horizontal/vertical
|
* It is now possible to turn off automatic creation of horizontal/vertical
|
||||||
constraints on line segments.
|
constraints on line segments.
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,11 @@ void TextWindow::ScreenChangeDigitsAfterDecimalDegree(int link, uint32_t v) {
|
||||||
SS.TW.edit.meaning = Edit::DIGITS_AFTER_DECIMAL_DEGREE;
|
SS.TW.edit.meaning = Edit::DIGITS_AFTER_DECIMAL_DEGREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextWindow::ScreenChangeUseSIPrefixes(int link, uint32_t v) {
|
||||||
|
SS.useSIPrefixes = !SS.useSIPrefixes;
|
||||||
|
SS.GW.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -239,15 +244,20 @@ void TextWindow::ShowConfiguration() {
|
||||||
Printf(false, "%Ba %s %Fl%Ll%f%D[change]%E",
|
Printf(false, "%Ba %s %Fl%Ll%f%D[change]%E",
|
||||||
SS.MmToString(SS.gridSpacing).c_str(),
|
SS.MmToString(SS.gridSpacing).c_str(),
|
||||||
&ScreenChangeGridSpacing, 0);
|
&ScreenChangeGridSpacing, 0);
|
||||||
|
|
||||||
|
Printf(false, "");
|
||||||
Printf(false, "%Ft digits after decimal point to show%E");
|
Printf(false, "%Ft digits after decimal point to show%E");
|
||||||
Printf(false, "%Ba%Ft distances: %Fd%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')",
|
Printf(false, "%Bd%Ft angles: %Fd%d %Fl%Ll%f%D[change]%E (e.g. '%s')",
|
||||||
SS.afterDecimalDegree,
|
SS.afterDecimalDegree,
|
||||||
&ScreenChangeDigitsAfterDecimalDegree, 0,
|
&ScreenChangeDigitsAfterDecimalDegree, 0,
|
||||||
SS.DegreeToString(1.23456789).c_str());
|
SS.DegreeToString(1.23456789).c_str());
|
||||||
|
Printf(false, " %Fd%f%Ll%s use SI prefixes for distances%E",
|
||||||
|
&ScreenChangeUseSIPrefixes,
|
||||||
|
SS.useSIPrefixes ? CHECK_TRUE : CHECK_FALSE);
|
||||||
|
|
||||||
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)");
|
||||||
|
|
|
@ -18,13 +18,13 @@ std::string Constraint::Label() const {
|
||||||
result = comment;
|
result = comment;
|
||||||
} else if(type == Type::DIAMETER) {
|
} else if(type == Type::DIAMETER) {
|
||||||
if(!other) {
|
if(!other) {
|
||||||
result = "⌀" + SS.MmToString(valA);
|
result = "⌀" + SS.MmToStringSI(valA);
|
||||||
} else {
|
} else {
|
||||||
result = "R" + SS.MmToString(valA / 2);
|
result = "R" + SS.MmToStringSI(valA / 2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// valA has units of distance
|
// valA has units of distance
|
||||||
result = SS.MmToString(fabs(valA));
|
result = SS.MmToStringSI(fabs(valA));
|
||||||
}
|
}
|
||||||
if(reference) {
|
if(reference) {
|
||||||
result += " REF";
|
result += " REF";
|
||||||
|
|
|
@ -57,6 +57,7 @@ void SolveSpaceUI::Init() {
|
||||||
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);
|
afterDecimalDegree = settings->ThawInt("AfterDecimalDegree", 2);
|
||||||
|
useSIPrefixes = settings->ThawBool("UseSIPrefixes", false);
|
||||||
// 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
|
||||||
|
@ -231,6 +232,7 @@ void SolveSpaceUI::Exit() {
|
||||||
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);
|
settings->FreezeInt("AfterDecimalDegree", (uint32_t)afterDecimalDegree);
|
||||||
|
settings->FreezeBool("UseSIPrefixes", useSIPrefixes);
|
||||||
// Camera tangent (determines perspective)
|
// Camera tangent (determines perspective)
|
||||||
settings->FreezeFloat("CameraTangent", (float)cameraTangent);
|
settings->FreezeFloat("CameraTangent", (float)cameraTangent);
|
||||||
// Grid spacing
|
// Grid spacing
|
||||||
|
@ -307,7 +309,7 @@ double SolveSpaceUI::MmPerUnit() {
|
||||||
}
|
}
|
||||||
const char *SolveSpaceUI::UnitName() {
|
const char *SolveSpaceUI::UnitName() {
|
||||||
switch(viewUnits) {
|
switch(viewUnits) {
|
||||||
case Unit::INCHES: return "inch";
|
case Unit::INCHES: return "in";
|
||||||
case Unit::METERS: return "m";
|
case Unit::METERS: return "m";
|
||||||
case Unit::MM: return "mm";
|
case Unit::MM: return "mm";
|
||||||
}
|
}
|
||||||
|
@ -315,13 +317,60 @@ const char *SolveSpaceUI::UnitName() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SolveSpaceUI::MmToString(double v) {
|
std::string SolveSpaceUI::MmToString(double v) {
|
||||||
|
v /= MmPerUnit();
|
||||||
switch(viewUnits) {
|
switch(viewUnits) {
|
||||||
case Unit::INCHES: return ssprintf("%.*f", afterDecimalInch, v / 25.4);
|
case Unit::INCHES:
|
||||||
case Unit::METERS: return ssprintf("%.*f", afterDecimalMm, v / 1000.0);
|
return ssprintf("%.*f", afterDecimalInch, v);
|
||||||
case Unit::MM: return ssprintf("%.*f", afterDecimalMm, v);
|
case Unit::METERS:
|
||||||
|
case Unit::MM:
|
||||||
|
return ssprintf("%.*f", afterDecimalMm, v);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
static const char *DimToString(int dim) {
|
||||||
|
switch(dim) {
|
||||||
|
case 3: return "³";
|
||||||
|
case 2: return "²";
|
||||||
|
case 1: return "";
|
||||||
|
default: ssassert(false, "Unexpected dimension");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static std::pair<int, std::string> SelectSIPrefixMm(int deg) {
|
||||||
|
if(deg >= 3) return { 3, "km" };
|
||||||
|
else if(deg >= 0) return { 0, "m" };
|
||||||
|
else if(deg >= -2) return { -2, "cm" };
|
||||||
|
else if(deg >= -3) return { -3, "mm" };
|
||||||
|
else if(deg >= -6) return { -6, "µm" };
|
||||||
|
else return { -9, "nm" };
|
||||||
|
}
|
||||||
|
static std::pair<int, std::string> SelectSIPrefixInch(int deg) {
|
||||||
|
if(deg >= 0) return { 0, "in" };
|
||||||
|
else if(deg >= -3) return { -3, "mil" };
|
||||||
|
else return { -6, "µin" };
|
||||||
|
}
|
||||||
|
std::string SolveSpaceUI::MmToStringSI(double v, int dim) {
|
||||||
|
bool compact = false;
|
||||||
|
if(dim == 0) {
|
||||||
|
if(!useSIPrefixes) return MmToString(v);
|
||||||
|
compact = true;
|
||||||
|
dim = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v /= pow((viewUnits == Unit::INCHES) ? 25.4 : 1000, dim);
|
||||||
|
int vdeg = floor((log10(fabs(v))) / dim);
|
||||||
|
std::string unit;
|
||||||
|
if(fabs(v) > 0.0) {
|
||||||
|
int sdeg = 0;
|
||||||
|
std::tie(sdeg, unit) =
|
||||||
|
(viewUnits == Unit::INCHES)
|
||||||
|
? SelectSIPrefixInch(vdeg)
|
||||||
|
: SelectSIPrefixMm(vdeg);
|
||||||
|
v /= pow(10.0, sdeg * dim);
|
||||||
|
}
|
||||||
|
int pdeg = ceil(log10(fabs(v) + 1e-10));
|
||||||
|
return ssprintf("%#.*g%s%s%s", pdeg + UnitDigitsAfterDecimal(), v,
|
||||||
|
compact ? "" : " ", unit.c_str(), DimToString(dim));
|
||||||
|
}
|
||||||
std::string SolveSpaceUI::DegreeToString(double v) {
|
std::string SolveSpaceUI::DegreeToString(double v) {
|
||||||
if(fabs(v - floor(v)) > 1e-10) {
|
if(fabs(v - floor(v)) > 1e-10) {
|
||||||
return ssprintf("%.*f", afterDecimalDegree, v);
|
return ssprintf("%.*f", afterDecimalDegree, v);
|
||||||
|
@ -777,18 +826,11 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
||||||
|
|
||||||
vol += integral;
|
vol += integral;
|
||||||
}
|
}
|
||||||
|
Message(_("The volume of the solid model is:\n\n"
|
||||||
std::string msg = ssprintf(_("The volume of the solid model is:\n\n"
|
" %s\n\n"
|
||||||
" %.3f %s^3"),
|
"Curved surfaces have been approximated as triangles.\n"
|
||||||
vol / pow(SS.MmPerUnit(), 3),
|
"This introduces error, typically of around 1%%."),
|
||||||
SS.UnitName());
|
SS.MmToStringSI(vol, /*dim=*/3).c_str());
|
||||||
|
|
||||||
if(SS.viewUnits == Unit::MM) {
|
|
||||||
msg += ssprintf("\n %.2f mL", vol/(10*10*10));
|
|
||||||
}
|
|
||||||
msg += _("\n\nCurved surfaces have been approximated as triangles.\n"
|
|
||||||
"This introduces error, typically of around 1%.");
|
|
||||||
Message("%s", msg.c_str());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,13 +849,11 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
||||||
sp.normal = sp.ComputeNormal();
|
sp.normal = sp.ComputeNormal();
|
||||||
sp.FixContourDirections();
|
sp.FixContourDirections();
|
||||||
double area = sp.SignedArea();
|
double area = sp.SignedArea();
|
||||||
double scale = SS.MmPerUnit();
|
|
||||||
Message(_("The area of the region sketched in this group is:\n\n"
|
Message(_("The area of the region sketched in this group is:\n\n"
|
||||||
" %.3f %s^2\n\n"
|
" %s\n\n"
|
||||||
"Curves have been approximated as piecewise linear.\n"
|
"Curves have been approximated as piecewise linear.\n"
|
||||||
"This introduces error, typically of around 1%%."),
|
"This introduces error, typically of around 1%%."),
|
||||||
area / (scale*scale),
|
SS.MmToStringSI(area, /*dim=*/2).c_str());
|
||||||
SS.UnitName());
|
|
||||||
sel.Clear();
|
sel.Clear();
|
||||||
sp.Clear();
|
sp.Clear();
|
||||||
break;
|
break;
|
||||||
|
@ -829,14 +869,11 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
||||||
perimeter += e.b.Minus(e.a).Magnitude();
|
perimeter += e.b.Minus(e.a).Magnitude();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double scale = SS.MmPerUnit();
|
|
||||||
Message(_("The total length of the selected entities is:\n\n"
|
Message(_("The total length of the selected entities is:\n\n"
|
||||||
" %.3f %s\n\n"
|
" %s\n\n"
|
||||||
"Curves have been approximated as piecewise linear.\n"
|
"Curves have been approximated as piecewise linear.\n"
|
||||||
"This introduces error, typically of around 1%%."),
|
"This introduces error, typically of around 1%%."),
|
||||||
perimeter / scale,
|
SS.MmToStringSI(perimeter, /*dim=*/1).c_str());
|
||||||
SS.UnitName());
|
|
||||||
} else {
|
} else {
|
||||||
Error(_("Bad selection for perimeter; select line segments, arcs, and curves."));
|
Error(_("Bad selection for perimeter; select line segments, arcs, and curves."));
|
||||||
}
|
}
|
||||||
|
|
|
@ -621,9 +621,11 @@ public:
|
||||||
int afterDecimalMm;
|
int afterDecimalMm;
|
||||||
int afterDecimalInch;
|
int afterDecimalInch;
|
||||||
int afterDecimalDegree;
|
int afterDecimalDegree;
|
||||||
|
bool useSIPrefixes;
|
||||||
int autosaveInterval; // in minutes
|
int autosaveInterval; // in minutes
|
||||||
|
|
||||||
std::string MmToString(double v);
|
std::string MmToString(double v);
|
||||||
|
std::string MmToStringSI(double v, int dim = 0);
|
||||||
std::string DegreeToString(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);
|
||||||
|
|
1
src/ui.h
1
src/ui.h
|
@ -469,6 +469,7 @@ public:
|
||||||
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 ScreenChangeDigitsAfterDecimalDegree(int link, uint32_t v);
|
||||||
|
static void ScreenChangeUseSIPrefixes(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);
|
||||||
|
|
Loading…
Reference in New Issue