[Bf-blender-cvs] [36aeb0ec1e2] master: UI: Add temperature units

Hans Goudey noreply at git.blender.org
Mon Sep 7 21:59:24 CEST 2020


Commit: 36aeb0ec1e2ec8cd6a3690ac11cd3c50f3851802
Author: Hans Goudey
Date:   Mon Sep 7 14:59:07 2020 -0500
Branches: master
https://developer.blender.org/rB36aeb0ec1e2ec8cd6a3690ac11cd3c50f3851802

UI: Add temperature units

Based on the original patch by Vaishnav S (@padthai), this adds
support for temperature units. Initially supported units are Celsius,
Kelvin, and Fahrenheit.

The units aren't used anywhere with this commit. Those changes should
happen in separate patches by adding PROP_TEMPERATURE to RNA property
definitions. But it should be ensured that the various solvers and
simulations actually properly use real units.

The complexity of some of the changes comes from the fact that these
units have offsets from each other as well as coefficients. This also
makes the implementation in the current unit system troublesome.
For example, entering 0C evaluates correctly to 273K, but 0C + 0C
doubles that result, because each unit value is evaluated separately.
This is quite hard to solve in the general case with Blender's current
unit system, though, so it is not handled in this commit.

Differential Revision: https://developer.blender.org/D4401

===================================================================

M	release/scripts/startup/bl_ui/properties_scene.py
M	source/blender/blenkernel/BKE_unit.h
M	source/blender/blenkernel/intern/scene.c
M	source/blender/blenkernel/intern/unit.c
M	source/blender/editors/util/numinput.c
M	source/blender/makesdna/DNA_scene_types.h
M	source/blender/makesrna/RNA_types.h
M	source/blender/makesrna/intern/makesrna.c
M	source/blender/makesrna/intern/rna_rna.c
M	source/blender/makesrna/intern/rna_scene.c
M	source/blender/python/intern/bpy_props.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index df4793cab19..8618c201312 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -92,6 +92,7 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
         subcol.prop(unit, "length_unit", text="Length")
         subcol.prop(unit, "mass_unit", text="Mass")
         subcol.prop(unit, "time_unit", text="Time")
+        subcol.prop(unit, "temperature_unit", text="Temperature")
 
 
 class SceneKeyingSetsPanel:
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index a797c5555ff..d47cebb5dc8 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -46,8 +46,8 @@ bool bUnit_ReplaceString(
 /* return true if the string contains any valid unit for the given type */
 bool bUnit_ContainsUnit(const char *str, int type);
 
-/* if user does not specify a unit, multiply with this value */
-double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type);
+/* If user does not specify a unit, this converts it to the unit from the settings. */
+double bUnit_ApplyPreferredUnit(const struct UnitSettings *settings, int type, double value);
 
 /* make string keyboard-friendly: 10µm --> 10um */
 void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type);
@@ -86,7 +86,8 @@ enum {
   B_UNIT_ACCELERATION = 8,
   B_UNIT_CAMERA = 9,
   B_UNIT_POWER = 10,
-  B_UNIT_TYPE_TOT = 11,
+  B_UNIT_TEMPERATURE = 11,
+  B_UNIT_TYPE_TOT = 12,
 };
 
 #ifdef __cplusplus
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 00218b1be51..a1f74dddbad 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -157,6 +157,8 @@ static void scene_init_data(ID *id)
   scene->unit.length_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
   scene->unit.mass_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
   scene->unit.time_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
+  scene->unit.temperature_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC,
+                                                                B_UNIT_TEMPERATURE);
 
   /* Anti-Aliasing threshold. */
   scene->grease_pencil_settings.smaa_threshold = 1.0f;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5af24152972..c5782d846bb 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -80,6 +80,8 @@
 #define UN_SC_LB    0.45359237f
 #define UN_SC_OZ    0.028349523125f
 
+#define UN_SC_FAH	0.555555555555f
+
 /* clang-format on */
 
 /* Define a single unit. */
@@ -101,7 +103,7 @@ typedef struct bUnitDef {
   const char *identifier;
 
   double scalar;
-  /** Not used yet, needed for converting temperature. */
+  /** Needed for converting temperatures. */
   double bias;
   int flag;
 } bUnitDef;
@@ -329,6 +331,22 @@ static struct bUnitDef buPowerDef[] = {
 };
 static struct bUnitCollection buPowerCollection = {buPowerDef, 3, 0, UNIT_COLLECTION_LENGTH(buPowerDef)};
 
+/* Temperature */
+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. */
+	{"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 */
 
 #define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
@@ -344,6 +362,7 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
      NULL,
      NULL,
      NULL,
+     NULL,
      NULL},
     /* Metric. */
     {NULL,
@@ -356,7 +375,8 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
      &buMetricVelCollection,
      &buMetricAclCollection,
      &buCameraLenCollection,
-     &buPowerCollection},
+     &buPowerCollection,
+     &buMetricTempCollection},
     /* Imperial. */
     {NULL,
      &buImperialLenCollection,
@@ -368,7 +388,8 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
      &buImperialVelCollection,
      &buImperialAclCollection,
      &buCameraLenCollection,
-     &buPowerCollection},
+     &buPowerCollection,
+     &buImperialTempCollection},
     {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 };
 
@@ -449,7 +470,7 @@ static size_t unit_as_string(char *str,
     }
   }
 
-  double value_conv = value / unit->scalar;
+  double value_conv = (value / unit->scalar) - unit->bias;
 
   /* 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
@@ -512,6 +533,7 @@ typedef struct {
   int length;
   int mass;
   int time;
+  int temperature;
 } PreferredUnits;
 
 static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
@@ -522,6 +544,7 @@ static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *sett
   units.length = settings->length_unit;
   units.mass = settings->mass_unit;
   units.time = settings->time_unit;
+  units.temperature = settings->temperature_unit;
   return units;
 }
 
@@ -597,6 +620,11 @@ static const bUnitDef *get_preferred_display_unit_if_used(int type, PreferredUni
         return usys->units + 3;
       }
       break;
+    case B_UNIT_TEMPERATURE:
+      if (units.temperature == USER_UNIT_ADAPTIVE) {
+        return NULL;
+      }
+      return usys->units + MIN2(units.temperature, max_offset);
     default:
       break;
   }
@@ -643,6 +671,7 @@ size_t bUnit_AsString(
   units.length = USER_UNIT_ADAPTIVE;
   units.mass = 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);
 }
 
@@ -844,6 +873,35 @@ static bool unit_distribute_negatives(char *str, const int len_max)
   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_value_char(const char *str, const int start_ofs)
+{
+  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_value_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,
                           int len_max,
                           char *str_tmp,
@@ -867,6 +925,34 @@ static int unit_scale_str(char *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 parenthesis. */
+    int prev_op_ofs = find_previous_non_value_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 parenthesis after the value. */
+    int value_end_ofs = find_end_of_value_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_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator. */
 
@@ -990,15 +1076,15 @@ bool bUnit_ContainsUnit(const char *str, int type)
   return false;
 }
 
-double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type)
+double bUnit_ApplyPreferredUnit(const struct UnitSettings *settings, int type, double value)
 {
   PreferredUnits units = preferred_units_from_UnitSettings(settings);
   const bUnitDef *unit = get_preferred_display_unit_if_used(type, units);
-  if (unit) {
-    return unit->scalar;
-  }
 
-  return bUnit_BaseScalar(units.system, type);
+  const double scalar = (unit == NULL) ? bUnit_BaseScalar(units.system, type) : unit->scalar;
+  const double bias = (unit == NULL) ? 0.0 : unit->bias; /* Base unit shouldn't have a bias. */
+
+  return value * scalar + bias;
 }
 
 /**
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 041b2fec00b..f8e3dda0ed3 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -298,7 +298,7 @@ bool user_string_to_number(bContext *C,
   }
 
   int success = BPY_run_string_as_number(C, N

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list