Changeset View
Standalone View
source/blender/blenkernel/intern/unit.c
| Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
| #define UN_SC_MG 0.000001f | #define UN_SC_MG 0.000001f | ||||
| #define UN_SC_ITON 907.18474f /* Imperial ton. */ | #define UN_SC_ITON 907.18474f /* Imperial ton. */ | ||||
| #define UN_SC_CWT 45.359237f | #define UN_SC_CWT 45.359237f | ||||
| #define UN_SC_ST 6.35029318f | #define UN_SC_ST 6.35029318f | ||||
| #define UN_SC_LB 0.45359237f | #define UN_SC_LB 0.45359237f | ||||
| #define UN_SC_OZ 0.028349523125f | #define UN_SC_OZ 0.028349523125f | ||||
| #define UN_SC_FAH 0.555555555555f | |||||
JacquesLucke: You can add a couple more 5s here. | |||||
| /* clang-format on */ | /* clang-format on */ | ||||
| /* Define a single unit. */ | /* Define a single unit. */ | ||||
| typedef struct bUnitDef { | typedef struct bUnitDef { | ||||
| const char *name; | const char *name; | ||||
| /** Abused a bit for the display name. */ | /** Abused a bit for the display name. */ | ||||
| const char *name_plural; | const char *name_plural; | ||||
| /** This is used for display. */ | /** This is used for display. */ | ||||
| const char *name_short; | const char *name_short; | ||||
| /** | /** | ||||
| * Keyboard-friendly ASCII-only version of name_short, can be NULL. | * Keyboard-friendly ASCII-only version of name_short, can be NULL. | ||||
| * If name_short has non-ASCII chars, name_alt should be present. | * If name_short has non-ASCII chars, name_alt should be present. | ||||
| */ | */ | ||||
| const char *name_alt; | const char *name_alt; | ||||
| /** Can be NULL. */ | /** Can be NULL. */ | ||||
| const char *name_display; | const char *name_display; | ||||
| /** When NULL, a transformed version of the name will be taken in some cases. */ | /** When NULL, a transformed version of the name will be taken in some cases. */ | ||||
| const char *identifier; | const char *identifier; | ||||
| double scalar; | double scalar; | ||||
| /** Not used yet, needed for converting temperature. */ | /** Needed for converting temperatures. */ | ||||
| double bias; | double bias; | ||||
| int flag; | int flag; | ||||
| } bUnitDef; | } bUnitDef; | ||||
| enum { | enum { | ||||
| B_UNIT_DEF_NONE = 0, | B_UNIT_DEF_NONE = 0, | ||||
| /** Use for units that are not used enough to be translated into for common use. */ | /** Use for units that are not used enough to be translated into for common use. */ | ||||
| B_UNIT_DEF_SUPPRESS = 1, | B_UNIT_DEF_SUPPRESS = 1, | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
| /* Areas. */ | /* Areas. */ | ||||
| static struct bUnitDef buMetricAreaDef[] = { | static struct bUnitDef buMetricAreaDef[] = { | ||||
| {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, | {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, | ||||
| {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* Hectare. */ | {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* Hectare. */ | ||||
| {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */ | {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */ | ||||
| {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | ||||
| {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS}, | {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS}, | ||||
| {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE}, | {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE}, | ||||
Done Inline ActionsThanks for those typo fixes. I'll commit those separately. JacquesLucke: Thanks for those typo fixes. I'll commit those separately. | |||||
| {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", NULL, UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH}, | {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", NULL, UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH}, | ||||
| {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, | {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, | ||||
| NULL_UNIT, | NULL_UNIT, | ||||
| }; | }; | ||||
| static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)}; | static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)}; | ||||
| static struct bUnitDef buImperialAreaDef[] = { | static struct bUnitDef buImperialAreaDef[] = { | ||||
| {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE}, | {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE}, | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | static struct bUnitDef buCameraLenDef[] = { | ||||
| {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | ||||
| {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, | {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, | ||||
| {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, | {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, | ||||
| {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, | {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, | ||||
| {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS}, | {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS}, | ||||
| NULL_UNIT, | NULL_UNIT, | ||||
| }; | }; | ||||
| static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)}; | static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)}; | ||||
Done Inline ActionsI wonder if we should use oC or just C. The latter is more comfortable to type. JacquesLucke: I wonder if we should use `oC` or just `C`. The latter is more comfortable to type. | |||||
| /* (Light) Power. */ | /* (Light) Power. */ | ||||
| static struct bUnitDef buPowerDef[] = { | static struct bUnitDef buPowerDef[] = { | ||||
| {"gigawatt", "gigawatts", "GW", NULL, "Gigawatts", NULL, 1e9f, 0.0, B_UNIT_DEF_NONE}, | {"gigawatt", "gigawatts", "GW", NULL, "Gigawatts", NULL, 1e9f, 0.0, B_UNIT_DEF_NONE}, | ||||
| {"megawatt", "megawatts", "MW", NULL, "Megawatts", NULL, 1e6f, 0.0, B_UNIT_DEF_CASE_SENSITIVE}, | {"megawatt", "megawatts", "MW", NULL, "Megawatts", NULL, 1e6f, 0.0, B_UNIT_DEF_CASE_SENSITIVE}, | ||||
| {"kilowatt", "kilowatts", "kW", NULL, "Kilowatts", NULL, 1e3f, 0.0, B_UNIT_DEF_SUPPRESS}, | {"kilowatt", "kilowatts", "kW", NULL, "Kilowatts", NULL, 1e3f, 0.0, B_UNIT_DEF_SUPPRESS}, | ||||
| {"watt", "watts", "W", NULL, "Watts", NULL, 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | {"watt", "watts", "W", NULL, "Watts", NULL, 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | ||||
Done Inline ActionsUnfortunately, the conversion is not that simple. Currently switching between the unit systems changes the absolute value of the temperature, i.e. it thinks 5C = 5F. A bit more work has to be done to get this conversion working, because it is different from all the other conversions we have so far. Also there is a missing white space. JacquesLucke: Unfortunately, the conversion is not that simple. Currently switching between the unit systems… | |||||
| {"milliwatt", "milliwatts", "mW", NULL, "Milliwatts", NULL, 1e-3f, 0.0, B_UNIT_DEF_CASE_SENSITIVE}, | {"milliwatt", "milliwatts", "mW", NULL, "Milliwatts", NULL, 1e-3f, 0.0, B_UNIT_DEF_CASE_SENSITIVE}, | ||||
| {"microwatt", "microwatts", "µW", "uW", "Microwatts", NULL, 1e-6f, 0.0, B_UNIT_DEF_NONE}, | {"microwatt", "microwatts", "µW", "uW", "Microwatts", NULL, 1e-6f, 0.0, B_UNIT_DEF_NONE}, | ||||
| {"nanowatt", "nanowatts", "nW", NULL, "Nanowatts", NULL, 1e-9f, 0.0, B_UNIT_DEF_NONE}, | {"nanowatt", "nanowatts", "nW", NULL, "Nanowatts", NULL, 1e-9f, 0.0, B_UNIT_DEF_NONE}, | ||||
| NULL_UNIT, | NULL_UNIT, | ||||
| }; | }; | ||||
| static struct bUnitCollection buPowerCollection = {buPowerDef, 3, 0, UNIT_COLLECTION_LENGTH(buPowerDef)}; | static struct bUnitCollection buPowerCollection = {buPowerDef, 3, 0, UNIT_COLLECTION_LENGTH(buPowerDef)}; | ||||
| /* Temperature */ | |||||
Done Inline ActionsIt's probably a good time to split this into multiple lines now, one line per unit collection. JacquesLucke: It's probably a good time to split this into multiple lines now, one line per unit collection. | |||||
| static struct bUnitDef buMetricTempDef[] = { | |||||
| {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | |||||
| {"celsius", "celsius", "°C", "C", "Celsius", "CELCIUS", 1.0f, 273.15, B_UNIT_DEF_NONE}, | |||||
| NULL_UNIT, | |||||
| }; | |||||
| static struct bUnitCollection buMetricTempCollection = {buMetricTempDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricTempDef)}; | |||||
| static struct bUnitDef buImperialTempDef[] = { | |||||
| {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */ | |||||
Done Inline ActionsI think Kelvin should also be the base unit in imperial? Something like color temperature you would still want to see as Kelvin even if you use imperial length units. brecht: I think Kelvin should also be the base unit in imperial? Something like color temperature you… | |||||
Done Inline ActionsI was thinking about that too, I'll add that. HooglyBoogly: I was thinking about that too, I'll add that. | |||||
| {"fahrenheit", "fahrenheit", "°F", "F", "Fahrenheit", "FAHRENHEIT", UN_SC_FAH, 459.67, B_UNIT_DEF_NONE}, | |||||
| NULL_UNIT, | |||||
| }; | |||||
| static struct bUnitCollection buImperialTempCollection = { | |||||
| buImperialTempDef, 1, 0, UNIT_COLLECTION_LENGTH(buImperialTempDef)}; | |||||
| /* clang-format on */ | /* clang-format on */ | ||||
| #define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1) | #define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1) | ||||
| static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = { | static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = { | ||||
| /* Natural. */ | /* Natural. */ | ||||
| {NULL, | {NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| &buNaturalRotCollection, | &buNaturalRotCollection, | ||||
| &buNaturalTimeCollection, | &buNaturalTimeCollection, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | |||||
| NULL}, | NULL}, | ||||
| /* Metric. */ | /* Metric. */ | ||||
| {NULL, | {NULL, | ||||
| &buMetricLenCollection, | &buMetricLenCollection, | ||||
| &buMetricAreaCollection, | &buMetricAreaCollection, | ||||
| &buMetricVolCollection, | &buMetricVolCollection, | ||||
| &buMetricMassCollection, | &buMetricMassCollection, | ||||
| &buNaturalRotCollection, | &buNaturalRotCollection, | ||||
| &buNaturalTimeCollection, | &buNaturalTimeCollection, | ||||
| &buMetricVelCollection, | &buMetricVelCollection, | ||||
| &buMetricAclCollection, | &buMetricAclCollection, | ||||
| &buCameraLenCollection, | &buCameraLenCollection, | ||||
| &buPowerCollection}, | &buPowerCollection, | ||||
| &buMetricTempCollection}, | |||||
| /* Imperial. */ | /* Imperial. */ | ||||
| {NULL, | {NULL, | ||||
| &buImperialLenCollection, | &buImperialLenCollection, | ||||
| &buImperialAreaCollection, | &buImperialAreaCollection, | ||||
| &buImperialVolCollection, | &buImperialVolCollection, | ||||
| &buImperialMassCollection, | &buImperialMassCollection, | ||||
| &buNaturalRotCollection, | &buNaturalRotCollection, | ||||
| &buNaturalTimeCollection, | &buNaturalTimeCollection, | ||||
| &buImperialVelCollection, | &buImperialVelCollection, | ||||
| &buImperialAclCollection, | &buImperialAclCollection, | ||||
| &buCameraLenCollection, | &buCameraLenCollection, | ||||
| &buPowerCollection}, | &buPowerCollection, | ||||
| &buImperialTempCollection}, | |||||
| {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, | {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, | ||||
| }; | }; | ||||
| static const bUnitCollection *unit_get_system(int system, int type) | static const bUnitCollection *unit_get_system(int system, int type) | ||||
| { | { | ||||
| assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT)); | assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT)); | ||||
| return bUnitSystems[system][type]; /* Select system to use: metric/imperial/other? */ | return bUnitSystems[system][type]; /* Select system to use: metric/imperial/other? */ | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if (value == 0.0) { | ||||
| /* Use the default units since there is no way to convert. */ | /* Use the default units since there is no way to convert. */ | ||||
| unit = unit_default(usys); | unit = unit_default(usys); | ||||
| } | } | ||||
| else { | else { | ||||
| unit = unit_best_fit(value, usys, NULL, 1); | unit = unit_best_fit(value, usys, NULL, 1); | ||||
| } | } | ||||
| } | } | ||||
| double value_conv = value / unit->scalar; | double value_conv = (value / unit->scalar) - unit->bias; | ||||
| /* Adjust precision to expected number of significant digits. | /* Adjust precision to expected number of significant digits. | ||||
| * Note that here, we shall not have to worry about very big/small numbers, units are expected | * Note that here, we shall not have to worry about very big/small numbers, units are expected | ||||
| * to replace 'scientific notation' in those cases. */ | * to replace 'scientific notation' in those cases. */ | ||||
| prec -= integer_digits_d(value_conv); | prec -= integer_digits_d(value_conv); | ||||
| CLAMP(prec, 0, 6); | CLAMP(prec, 0, 6); | ||||
| /* Convert to a string. */ | /* Convert to a string. */ | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
| typedef struct { | typedef struct { | ||||
| int system; | int system; | ||||
| int rotation; | int rotation; | ||||
| /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection. */ | /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection. */ | ||||
| int length; | int length; | ||||
| int mass; | int mass; | ||||
| int time; | int time; | ||||
| int temperature; | |||||
| } PreferredUnits; | } PreferredUnits; | ||||
| static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings) | static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings) | ||||
| { | { | ||||
| PreferredUnits units = {0}; | PreferredUnits units = {0}; | ||||
| units.system = settings->system; | units.system = settings->system; | ||||
| units.rotation = settings->system_rotation; | units.rotation = settings->system_rotation; | ||||
| units.length = settings->length_unit; | units.length = settings->length_unit; | ||||
| units.mass = settings->mass_unit; | units.mass = settings->mass_unit; | ||||
| units.time = settings->time_unit; | units.time = settings->time_unit; | ||||
| units.temperature = settings->temperature_unit; | |||||
| return units; | return units; | ||||
| } | } | ||||
| static size_t unit_as_string_split_pair(char *str, | static size_t unit_as_string_split_pair(char *str, | ||||
| int len_max, | int len_max, | ||||
| double value, | double value, | ||||
| int prec, | int prec, | ||||
| const bUnitCollection *usys, | const bUnitCollection *usys, | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | switch (type) { | ||||
| case B_UNIT_ROTATION: | case B_UNIT_ROTATION: | ||||
| if (units.rotation == 0) { | if (units.rotation == 0) { | ||||
| return usys->units + 0; | return usys->units + 0; | ||||
| } | } | ||||
| else if (units.rotation == USER_UNIT_ROT_RADIANS) { | else if (units.rotation == USER_UNIT_ROT_RADIANS) { | ||||
| return usys->units + 3; | return usys->units + 3; | ||||
| } | } | ||||
| break; | break; | ||||
| case B_UNIT_TEMPERATURE: | |||||
| if (units.temperature == USER_UNIT_ADAPTIVE) { | |||||
| return NULL; | |||||
| } | |||||
| return usys->units + MIN2(units.temperature, max_offset); | |||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* Return the length of the generated string. */ | /* Return the length of the generated string. */ | ||||
| static size_t unit_as_string_main(char *str, | static size_t unit_as_string_main(char *str, | ||||
| Show All 30 Lines | size_t bUnit_AsString( | ||||
| char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad) | char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad) | ||||
| { | { | ||||
| PreferredUnits units; | PreferredUnits units; | ||||
| units.system = system; | units.system = system; | ||||
| units.rotation = 0; | units.rotation = 0; | ||||
| units.length = USER_UNIT_ADAPTIVE; | units.length = USER_UNIT_ADAPTIVE; | ||||
| units.mass = USER_UNIT_ADAPTIVE; | units.mass = USER_UNIT_ADAPTIVE; | ||||
| units.time = USER_UNIT_ADAPTIVE; | units.time = USER_UNIT_ADAPTIVE; | ||||
| units.temperature = USER_UNIT_ADAPTIVE; | |||||
| return unit_as_string_main(str, len_max, value, prec, type, split, pad, units); | return unit_as_string_main(str, len_max, value, prec, type, split, pad, units); | ||||
| } | } | ||||
| size_t bUnit_AsString2(char *str, | size_t bUnit_AsString2(char *str, | ||||
| int len_max, | int len_max, | ||||
| double value, | double value, | ||||
| int prec, | int prec, | ||||
| int type, | int type, | ||||
| ▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) { | ||||
| /* Only move forward by 1 even though we added two characters. Minus signs need to be able to | /* Only move forward by 1 even though we added two characters. Minus signs need to be able to | ||||
| * apply to the next block of values too. */ | * apply to the next block of values too. */ | ||||
| remaining_str += 1; | remaining_str += 1; | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** | |||||
| * Helper for #unit_scale_str for the process of correctly applying the order of operations | |||||
| * for the unit's bias term. | |||||
| */ | |||||
| static int find_previous_non_digit_char(const char *str, const int start_ofs) | |||||
JacquesLuckeUnsubmitted Not Done Inline ActionsBased on the name, I'd expect this function to compare chars to digits, but that does not seem to be what it is doing. JacquesLucke: Based on the name, I'd expect this function to compare chars to digits, but that does not seem… | |||||
HooglyBooglyAuthorUnsubmitted Done Inline ActionsI used "value" instead for both the helper functions. Hopefully that's more clear. HooglyBoogly: I used "value" instead for both the helper functions. Hopefully that's more clear. | |||||
| { | |||||
| for (int i = start_ofs; i > 0; i--) { | |||||
| if (ch_is_op(str[i - 1]) || strchr("( )", str[i - 1])) { | |||||
| return i; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| /** | |||||
| * Helper for #unit_scale_str for the process of correctly applying the order of operations | |||||
| * for the unit's bias term. | |||||
| */ | |||||
| static int find_end_of_num_chars(const char *str, const int len_max, const int start_ofs) | |||||
| { | |||||
| int i; | |||||
| for (i = start_ofs; i < len_max; i++) { | |||||
| if (!strchr("0123456789eE.", str[i])) { | |||||
| return i; | |||||
| } | |||||
| } | |||||
| return i; | |||||
| } | |||||
| static int unit_scale_str(char *str, | static int unit_scale_str(char *str, | ||||
| int len_max, | int len_max, | ||||
| char *str_tmp, | char *str_tmp, | ||||
| double scale_pref, | double scale_pref, | ||||
| const bUnitDef *unit, | const bUnitDef *unit, | ||||
| const char *replace_str, | const char *replace_str, | ||||
| bool case_sensitive) | bool case_sensitive) | ||||
| { | { | ||||
| if (len_max < 0) { | if (len_max < 0) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* XXX - investigate, does not respect len_max properly. */ | /* XXX - investigate, does not respect len_max properly. */ | ||||
| char *str_found = (char *)unit_find_str(str, replace_str, case_sensitive); | char *str_found = (char *)unit_find_str(str, replace_str, case_sensitive); | ||||
| if (str_found == NULL) { | if (str_found == NULL) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int found_ofs = (int)(str_found - str); | int found_ofs = (int)(str_found - str); | ||||
| int len = strlen(str); | int len = strlen(str); | ||||
| /* Deal with unit bias for temperature units. Order of operations is important so we have to | |||||
| * add parentheses, add the bias, then multiply by the scalar like usual. | |||||
| * | |||||
| * Note: If these changes don't fit in the buffer properly unit evaluation has failed, | |||||
| * just try not to destroy anything while failing. */ | |||||
| if (unit->bias != 0.0) { | |||||
| /* Add the open paranthesis. */ | |||||
JacquesLuckeUnsubmitted Done Inline Actionstypo JacquesLucke: typo | |||||
| int prev_op_ofs = find_previous_non_digit_char(str, found_ofs); | |||||
| if (len + 1 < len_max) { | |||||
| memmove(str + prev_op_ofs + 1, str + prev_op_ofs, len - prev_op_ofs + 1); | |||||
| str[prev_op_ofs] = '('; | |||||
| len++; | |||||
| found_ofs++; | |||||
| str_found++; | |||||
| } /* If this doesn't fit, we have failed. */ | |||||
| /* Add the addition sign, the bias, and the close paranthesis after the value. */ | |||||
JacquesLuckeUnsubmitted Done Inline Actionstypo JacquesLucke: typo | |||||
| int value_end_ofs = find_end_of_num_chars(str, len_max, prev_op_ofs + 2); | |||||
| int len_bias_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "+%.9g)", unit->bias); | |||||
| if (value_end_ofs + len_bias_num < len_max) { | |||||
| memmove(str + value_end_ofs + len_bias_num, str + value_end_ofs, len - value_end_ofs + 1); | |||||
| memcpy(str + value_end_ofs, str_tmp, len_bias_num); | |||||
| len += len_bias_num; | |||||
| found_ofs += len_bias_num; | |||||
| str_found += len_bias_num; | |||||
| } /* If this doesn't fit, we have failed. */ | |||||
| } | |||||
| int len_name = strlen(replace_str); | int len_name = strlen(replace_str); | ||||
| int len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator. */ | int len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator. */ | ||||
| /* "#" Removed later */ | /* "#" Removed later */ | ||||
| int len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref); | int len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref); | ||||
| if (len_num > len_max) { | if (len_num > len_max) { | ||||
| len_num = len_max; | len_num = len_max; | ||||
| ▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type) | ||||
| const bUnitDef *unit = get_preferred_display_unit_if_used(type, units); | const bUnitDef *unit = get_preferred_display_unit_if_used(type, units); | ||||
| if (unit) { | if (unit) { | ||||
| return unit->scalar; | return unit->scalar; | ||||
| } | } | ||||
| return bUnit_BaseScalar(units.system, type); | return bUnit_BaseScalar(units.system, type); | ||||
| } | } | ||||
| double bUnit_PreferredInputUnitBias(const struct UnitSettings *settings, int type) | |||||
| { | |||||
| PreferredUnits units = preferred_units_from_UnitSettings(settings); | |||||
| const bUnitDef *unit = get_preferred_display_unit_if_used(type, units); | |||||
| return (unit == NULL) ? 0.0 : unit->bias; /* Base unit shouldn't have a bias. */ | |||||
| } | |||||
| /** | /** | ||||
| * Make a copy of the string that replaces the units with numbers. | * Make a copy of the string that replaces the units with numbers. | ||||
| * | * | ||||
| * This is only used when evaluating user input and can afford to be a bit slower | * This is only used when evaluating user input and can afford to be a bit slower | ||||
| * | * | ||||
| * This is to be used before python evaluation so.. | * This is to be used before python evaluation so.. | ||||
| * 10.1km -> 10.1*1000.0 | * 10.1km -> 10.1*1000.0 | ||||
| * ...will be resolved by python. | * ...will be resolved by python. | ||||
| ▲ Show 20 Lines • Show All 219 Lines • Show Last 20 Lines | |||||
You can add a couple more 5s here.