Blender  V2.93
unit.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "BLI_math.h"
27 #include "BLI_string.h"
28 #include "BLI_string_utf8.h"
29 #include "BLI_sys_types.h"
30 
31 #include "DNA_scene_types.h"
32 
33 #include "BKE_unit.h" /* own include */
34 
35 #ifdef WIN32
36 # include "BLI_winstuff.h"
37 #endif
38 
39 /* No BKE or DNA includes! */
40 
41 /* Keep alignment. */
42 /* clang-format off */
43 
44 #define TEMP_STR_SIZE 256
45 
46 #define SEP_CHR '#'
47 #define SEP_STR "#"
48 
49 #define EPS 0.001
50 
51 #define UN_SC_KM 1000.0f
52 #define UN_SC_HM 100.0f
53 #define UN_SC_DAM 10.0f
54 #define UN_SC_M 1.0f
55 #define UN_SC_DM 0.1f
56 #define UN_SC_CM 0.01f
57 #define UN_SC_MM 0.001f
58 #define UN_SC_UM 0.000001f
59 
60 #define UN_SC_MI 1609.344f
61 #define UN_SC_FUR 201.168f
62 #define UN_SC_CH 20.1168f
63 #define UN_SC_YD 0.9144f
64 #define UN_SC_FT 0.3048f
65 #define UN_SC_IN 0.0254f
66 #define UN_SC_MIL 0.0000254f
67 
68 #define UN_SC_MTON 1000.0f /* Metric ton. */
69 #define UN_SC_QL 100.0f
70 #define UN_SC_KG 1.0f
71 #define UN_SC_HG 0.1f
72 #define UN_SC_DAG 0.01f
73 #define UN_SC_G 0.001f
74 #define UN_SC_MG 0.000001f
75 
76 #define UN_SC_ITON 907.18474f /* Imperial ton. */
77 #define UN_SC_CWT 45.359237f
78 #define UN_SC_ST 6.35029318f
79 #define UN_SC_LB 0.45359237f
80 #define UN_SC_OZ 0.028349523125f
81 
82 #define UN_SC_FAH 0.555555555555f
83 
84 /* clang-format on */
85 
86 /* Define a single unit. */
87 typedef struct bUnitDef {
88  const char *name;
90  const char *name_plural;
92  const char *name_short;
97  const char *name_alt;
98 
100  const char *name_display;
102  const char *identifier;
103 
104  double scalar;
106  double bias;
107  int flag;
109 
110 enum {
120 };
121 
122 /* Define a single unit system. */
123 typedef struct bUnitCollection {
124  const struct bUnitDef *units;
128  int flag;
130  int length;
132 
133 /* Keep table Alignment. */
134 /* clang-format off */
135 
136 #define UNIT_COLLECTION_LENGTH(def) (ARRAY_SIZE(def) - 1)
137 #define NULL_UNIT {NULL, NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
138 
139 /* Dummy */
140 static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, NULL, 1.0, 0.0}, NULL_UNIT};
141 static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)};
142 
143 /* Lengths. */
144 static struct bUnitDef buMetricLenDef[] = {
145  {"kilometer", "kilometers", "km", NULL, "Kilometers", "KILOMETERS", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
146  {"hectometer", "hectometers", "hm", NULL, "100 Meters", "HECTOMETERS", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
147  {"dekameter", "dekameters", "dam", NULL, "10 Meters", "DEKAMETERS", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
148  {"meter", "meters", "m", NULL, "Meters", "METERS", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
149  {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", "DECIMETERS", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
150  {"centimeter", "centimeters", "cm", NULL, "Centimeters", "CENTIMETERS", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
151  {"millimeter", "millimeters", "mm", NULL, "Millimeters", "MILLIMETERS", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
152  {"micrometer", "micrometers", "µm", "um", "Micrometers", "MICROMETERS", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
153 
154  /* These get displayed because of float precision problems in the transform header,
155  * could work around, but for now probably people wont use these. */
156 #if 0
157  {"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE},
158  {"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0, B_UNIT_DEF_NONE},
159 #endif
160  NULL_UNIT,
161 };
163 
164 static struct bUnitDef buImperialLenDef[] = {
165  {"mile", "miles", "mi", NULL, "Miles", "MILES", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
166  {"furlong", "furlongs", "fur", NULL, "Furlongs", "FURLONGS", UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
167  {"chain", "chains", "ch", NULL, "Chains", "CHAINS", UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
168  {"yard", "yards", "yd", NULL, "Yards", "YARDS", UN_SC_YD, 0.0, B_UNIT_DEF_SUPPRESS},
169  {"foot", "feet", "'", "ft", "Feet", "FEET", UN_SC_FT, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_NO_SPACE}, /* Base unit. */
170  {"inch", "inches", "\"", "in", "Inches", "INCHES", UN_SC_IN, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_NO_SPACE},
171  {"thou", "thou", "thou", "mil", "Thou", "THOU", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* Plural for "thou" has no 's'. */
172  NULL_UNIT,
173 };
175 
176 /* Areas. */
177 static struct bUnitDef buMetricAreaDef[] = {
178  {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
179  {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* Hectare. */
180  {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */
181  {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
182  {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
183  {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
184  {"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},
185  {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
186  NULL_UNIT,
187 };
189 
190 static struct bUnitDef buImperialAreaDef[] = {
191  {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
192  {"square furlong", "square furlongs", "sq fur", NULL, "Square Furlongs", NULL, UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
193  {"square chain", "square chains", "sq ch", NULL, "Square Chains", NULL, UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
194  {"square yard", "square yards", "sq yd", NULL, "Square Yards", NULL, UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
195  {"square foot", "square feet", "sq ft", NULL, "Square Feet", NULL, UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
196  {"square inch", "square inches", "sq in", NULL, "Square Inches", NULL, UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
197  {"square thou", "square thou", "sq mil", NULL, "Square Thou", NULL, UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
198  NULL_UNIT,
199 };
201 
202 /* Volumes. */
203 static struct bUnitDef buMetricVolDef[] = {
204  {"cubic kilometer", "cubic kilometers", "km³", "km3", "Cubic Kilometers", NULL, UN_SC_KM * UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
205  {"cubic hectometer", "cubic hectometers", "hm³", "hm3", "Cubic Hectometers", NULL, UN_SC_HM * UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
206  {"cubic dekameter", "cubic dekameters", "dam³", "dam3", "Cubic Dekameters", NULL, UN_SC_DAM * UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
207  {"cubic meter", "cubic meters", "m³", "m3", "Cubic Meters", NULL, UN_SC_M * UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
208  {"cubic decimeter", "cubic decimeters", "dm³", "dm3", "Cubic Decimeters", NULL, UN_SC_DM * UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
209  {"cubic centimeter", "cubic centimeters", "cm³", "cm3", "Cubic Centimeters", NULL, UN_SC_CM * UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
210  {"cubic millimeter", "cubic millimeters", "mm³", "mm3", "Cubic Millimeters", NULL, UN_SC_MM * UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
211  {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", NULL, UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
212  NULL_UNIT,
213 };
215 
216 static struct bUnitDef buImperialVolDef[] = {
217  {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", NULL, UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
218  {"cubic furlong", "cubic furlongs", "cu fur", NULL, "Cubic Furlongs", NULL, UN_SC_FUR * UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
219  {"cubic chain", "cubic chains", "cu ch", NULL, "Cubic Chains", NULL, UN_SC_CH * UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
220  {"cubic yard", "cubic yards", "cu yd", NULL, "Cubic Yards", NULL, UN_SC_YD * UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
221  {"cubic foot", "cubic feet", "cu ft", NULL, "Cubic Feet", NULL, UN_SC_FT * UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
222  {"cubic inch", "cubic inches", "cu in", NULL, "Cubic Inches", NULL, UN_SC_IN * UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
223  {"cubic thou", "cubic thou", "cu mil", NULL, "Cubic Thou", NULL, UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
224  NULL_UNIT,
225 };
227 
228 /* Mass. */
229 static struct bUnitDef buMetricMassDef[] = {
230  {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
231  {"quintal", "quintals", "ql", "q", "100 Kilograms", "QUINTALS", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
232  {"kilogram", "kilograms", "kg", NULL, "Kilograms", "KILOGRAMS", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
233  {"hectogram", "hectograms", "hg", NULL, "Hectograms", "HECTOGRAMS", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
234  {"dekagram", "dekagrams", "dag", NULL, "10 Grams", "DEKAGRAMS", UN_SC_DAG, 0.0, B_UNIT_DEF_SUPPRESS},
235  {"gram", "grams", "g", NULL, "Grams", "GRAMS", UN_SC_G, 0.0, B_UNIT_DEF_NONE},
236  {"milligram", "milligrams", "mg", NULL, "Milligrams", "MILLIGRAMS", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
237  NULL_UNIT,
238 };
240 
241 static struct bUnitDef buImperialMassDef[] = {
242  {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
243  {"centum weight", "centum weights", "cwt", NULL, "Centum weights", "CENTUM_WEIGHTS", UN_SC_CWT, 0.0, B_UNIT_DEF_NONE},
244  {"stone", "stones", "st", NULL, "Stones", "STONES", UN_SC_ST, 0.0, B_UNIT_DEF_NONE},
245  {"pound", "pounds", "lb", NULL, "Pounds", "POUNDS", UN_SC_LB, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
246  {"ounce", "ounces", "oz", NULL, "Ounces", "OUNCES", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
247  NULL_UNIT,
248 };
250 
251 /* Even if user scales the system to a point where km^3 is used, velocity and
252  * acceleration aren't scaled: that's why we have so few units for them. */
253 
254 /* Velocity. */
255 static struct bUnitDef buMetricVelDef[] = {
256  {"meter per second", "meters per second", "m/s", NULL, "Meters per second", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
257  {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", NULL, UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
258  NULL_UNIT,
259 };
261 
262 static struct bUnitDef buImperialVelDef[] = {
263  {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
264  {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", NULL, UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
265  NULL_UNIT,
266 };
268 
269 /* Acceleration. */
270 static struct bUnitDef buMetricAclDef[] = {
271  {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
272  NULL_UNIT,
273 };
275 
276 static struct bUnitDef buImperialAclDef[] = {
277  {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
278  NULL_UNIT,
279 };
281 
282 /* Time. */
283 static struct bUnitDef buNaturalTimeDef[] = {
284  /* Weeks? - probably not needed for Blender. */
285  {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
286  {"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
287  {"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
288  {"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
289  {"millisecond", "milliseconds", "ms", NULL, "Milliseconds", "MILLISECONDS", 0.001, 0.0, B_UNIT_DEF_NONE},
290  {"microsecond", "microseconds", "µs", "us", "Microseconds", "MICROSECONDS", 0.000001, 0.0, B_UNIT_DEF_NONE},
291  NULL_UNIT,
292 };
294 
295 
296 static struct bUnitDef buNaturalRotDef[] = {
297  {"degree", "degrees", "°", "d", "Degrees", "DEGREES", M_PI / 180.0, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_NO_SPACE},
298  /* arcminutes/arcseconds are used in Astronomy/Navigation areas... */
299  {"arcminute", "arcminutes", "'", NULL, "Arcminutes", "ARCMINUTES", (M_PI / 180.0) / 60.0, 0.0, B_UNIT_DEF_SUPPRESS | B_UNIT_DEF_NO_SPACE},
300  {"arcsecond", "arcseconds", "\"", NULL, "Arcseconds", "ARCSECONDS", (M_PI / 180.0) / 3600.0, 0.0, B_UNIT_DEF_SUPPRESS | B_UNIT_DEF_NO_SPACE},
301  {"radian", "radians", "r", NULL, "Radians", "RADIANS", 1.0, 0.0, B_UNIT_DEF_NONE},
302 #if 0
303  {"turn", "turns", "t", NULL, "Turns", NULL, 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
304 #endif
305  NULL_UNIT,
306 };
308 
309 /* Camera Lengths. */
310 static struct bUnitDef buCameraLenDef[] = {
311  {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
312  {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
313  {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
314  {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE},
315  {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
316  NULL_UNIT,
317 };
319 
320 /* (Light) Power. */
321 static struct bUnitDef buPowerDef[] = {
322  {"gigawatt", "gigawatts", "GW", NULL, "Gigawatts", NULL, 1e9f, 0.0, B_UNIT_DEF_NONE},
323  {"megawatt", "megawatts", "MW", NULL, "Megawatts", NULL, 1e6f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
324  {"kilowatt", "kilowatts", "kW", NULL, "Kilowatts", NULL, 1e3f, 0.0, B_UNIT_DEF_SUPPRESS},
325  {"watt", "watts", "W", NULL, "Watts", NULL, 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
326  {"milliwatt", "milliwatts", "mW", NULL, "Milliwatts", NULL, 1e-3f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
327  {"microwatt", "microwatts", "µW", "uW", "Microwatts", NULL, 1e-6f, 0.0, B_UNIT_DEF_NONE},
328  {"nanowatt", "nanowatts", "nW", NULL, "Nanowatts", NULL, 1e-9f, 0.0, B_UNIT_DEF_NONE},
329  NULL_UNIT,
330 };
332 
333 /* Temperature */
334 static struct bUnitDef buMetricTempDef[] = {
335  {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
336  {"celsius", "celsius", "°C", "C", "Celsius", "CELSIUS", 1.0f, 273.15, B_UNIT_DEF_NONE},
337  NULL_UNIT,
338 };
340 
341 static struct bUnitDef buImperialTempDef[] = {
342  {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
343  {"fahrenheit", "fahrenheit", "°F", "F", "Fahrenheit", "FAHRENHEIT", UN_SC_FAH, 459.67, B_UNIT_DEF_NONE},
344  NULL_UNIT,
345 };
348 
349 /* clang-format on */
350 
351 #define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
352 static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
353  /* Natural. */
354  {NULL,
355  NULL,
356  NULL,
357  NULL,
358  NULL,
361  NULL,
362  NULL,
363  NULL,
364  NULL,
365  NULL},
366  /* Metric. */
367  {NULL,
379  /* Imperial. */
380  {NULL,
392  {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
393 };
394 
395 static const bUnitCollection *unit_get_system(int system, int type)
396 {
397  BLI_assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) &&
398  (type < B_UNIT_TYPE_TOT));
399  return bUnitSystems[system][type]; /* Select system to use: metric/imperial/other? */
400 }
401 
402 static const bUnitDef *unit_default(const bUnitCollection *usys)
403 {
404  return &usys->units[usys->base_unit];
405 }
406 
407 static const bUnitDef *unit_best_fit(double value,
408  const bUnitCollection *usys,
409  const bUnitDef *unit_start,
410  int suppress)
411 {
412  double value_abs = value > 0.0 ? value : -value;
413 
414  for (const bUnitDef *unit = unit_start ? unit_start : usys->units; unit->name; unit++) {
415 
416  if (suppress && (unit->flag & B_UNIT_DEF_SUPPRESS)) {
417  continue;
418  }
419 
420  /* Scale down scalar so 1cm doesn't convert to 10mm because of float error. */
421  if (UNLIKELY(unit->flag & B_UNIT_DEF_TENTH)) {
422  if (value_abs >= unit->scalar * (0.1 - EPS)) {
423  return unit;
424  }
425  }
426  else {
427  if (value_abs >= unit->scalar * (1.0 - EPS)) {
428  return unit;
429  }
430  }
431  }
432 
433  return unit_default(usys);
434 }
435 
436 /* Convert into 2 units and 2 values for "2ft, 3inch" syntax. */
437 static void unit_dual_convert(double value,
438  const bUnitCollection *usys,
439  bUnitDef const **r_unit_a,
440  bUnitDef const **r_unit_b,
441  double *r_value_a,
442  double *r_value_b,
443  const bUnitDef *main_unit)
444 {
445  const bUnitDef *unit = (main_unit) ? main_unit : unit_best_fit(value, usys, NULL, 1);
446 
447  *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
448  *r_value_b = value - (*r_value_a);
449 
450  *r_unit_a = unit;
451  *r_unit_b = unit_best_fit(*r_value_b, usys, *r_unit_a, 1);
452 }
453 
454 static size_t unit_as_string(char *str,
455  int len_max,
456  double value,
457  int prec,
458  const bUnitCollection *usys,
459  /* Non exposed options. */
460  const bUnitDef *unit,
461  char pad)
462 {
463  if (unit == NULL) {
464  if (value == 0.0) {
465  /* Use the default units since there is no way to convert. */
466  unit = unit_default(usys);
467  }
468  else {
469  unit = unit_best_fit(value, usys, NULL, 1);
470  }
471  }
472 
473  double value_conv = (value / unit->scalar) - unit->bias;
474 
475  /* Adjust precision to expected number of significant digits.
476  * Note that here, we shall not have to worry about very big/small numbers, units are expected
477  * to replace 'scientific notation' in those cases. */
478  prec -= integer_digits_d(value_conv);
479  CLAMP(prec, 0, 6);
480 
481  /* Convert to a string. */
482  size_t len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
483 
484  /* Add unit prefix and strip zeros. */
485 
486  /* Replace trailing zero's with spaces so the number
487  * is less complicated but alignment in a button won't
488  * jump about while dragging. */
489  size_t i = len - 1;
490 
491  if (prec > 0) {
492  while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
493  str[i--] = pad;
494  }
495 
496  if (i > 0 && str[i] == '.') { /* 10. -> 10 */
497  str[i--] = pad;
498  }
499  }
500 
501  /* Now add a space for all units except foot, inch, degree, arcminute, arcsecond. */
502  if (!(unit->flag & B_UNIT_DEF_NO_SPACE)) {
503  str[++i] = ' ';
504  }
505 
506  /* Now add the suffix. */
507  if (i < len_max) {
508  int j = 0;
509  i++;
510  while (unit->name_short[j] && (i < len_max)) {
511  str[i++] = unit->name_short[j++];
512  }
513  }
514 
515  /* Terminate no matter what's done with padding above. */
516  if (i >= len_max) {
517  i = len_max - 1;
518  }
519 
520  str[i] = '\0';
521  return i;
522 }
523 
524 static bool unit_should_be_split(int type)
525 {
527 }
528 
529 typedef struct {
530  int system;
531  int rotation;
532  /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection. */
533  int length;
534  int mass;
535  int time;
538 
540 {
541  PreferredUnits units = {0};
542  units.system = settings->system;
543  units.rotation = settings->system_rotation;
544  units.length = settings->length_unit;
545  units.mass = settings->mass_unit;
546  units.time = settings->time_unit;
547  units.temperature = settings->temperature_unit;
548  return units;
549 }
550 
551 static size_t unit_as_string_split_pair(char *str,
552  int len_max,
553  double value,
554  int prec,
555  const bUnitCollection *usys,
556  const bUnitDef *main_unit)
557 {
558  const bUnitDef *unit_a, *unit_b;
559  double value_a, value_b;
560  unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit);
561 
562  /* Check the 2 is a smaller unit. */
563  if (unit_b > unit_a) {
564  size_t i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
565 
566  prec -= integer_digits_d(value_a / unit_b->scalar) -
567  integer_digits_d(value_b / unit_b->scalar);
568  prec = max_ii(prec, 0);
569 
570  /* Is there enough space for at least 1 char of the next unit? */
571  if (i + 2 < len_max) {
572  str[i++] = ' ';
573 
574  /* Use low precision since this is a smaller unit. */
575  i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
576  }
577  return i;
578  }
579 
580  return -1;
581 }
582 
584 {
585  return usys != NULL && usys->units[0].name != NULL;
586 }
587 
589 {
590  const bUnitCollection *usys = unit_get_system(units.system, type);
591  if (!is_valid_unit_collection(usys)) {
592  return NULL;
593  }
594 
595  int max_offset = usys->length - 1;
596 
597  switch (type) {
598  case B_UNIT_LENGTH:
599  case B_UNIT_AREA:
600  case B_UNIT_VOLUME:
601  if (units.length == USER_UNIT_ADAPTIVE) {
602  return NULL;
603  }
604  return usys->units + MIN2(units.length, max_offset);
605  case B_UNIT_MASS:
606  if (units.mass == USER_UNIT_ADAPTIVE) {
607  return NULL;
608  }
609  return usys->units + MIN2(units.mass, max_offset);
610  case B_UNIT_TIME:
611  if (units.time == USER_UNIT_ADAPTIVE) {
612  return NULL;
613  }
614  return usys->units + MIN2(units.time, max_offset);
615  case B_UNIT_ROTATION:
616  if (units.rotation == 0) {
617  return usys->units + 0;
618  }
619  else if (units.rotation == USER_UNIT_ROT_RADIANS) {
620  return usys->units + 3;
621  }
622  break;
623  case B_UNIT_TEMPERATURE:
624  if (units.temperature == USER_UNIT_ADAPTIVE) {
625  return NULL;
626  }
627  return usys->units + MIN2(units.temperature, max_offset);
628  default:
629  break;
630  }
631  return NULL;
632 }
633 
634 /* Return the length of the generated string. */
635 static size_t unit_as_string_main(char *str,
636  int len_max,
637  double value,
638  int prec,
639  int type,
640  bool split,
641  bool pad,
642  PreferredUnits units)
643 {
644  const bUnitCollection *usys = unit_get_system(units.system, type);
645  const bUnitDef *main_unit = NULL;
646 
647  if (!is_valid_unit_collection(usys)) {
648  usys = &buDummyCollection;
649  }
650  else {
651  main_unit = get_preferred_display_unit_if_used(type, units);
652  }
653 
654  if (split && unit_should_be_split(type)) {
655  int length = unit_as_string_split_pair(str, len_max, value, prec, usys, main_unit);
656  /* Failed when length is negative, fallback to no split. */
657  if (length >= 0) {
658  return length;
659  }
660  }
661 
662  return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
663 }
664 
666  char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
667 {
668  PreferredUnits units;
669  units.system = system;
670  units.rotation = 0;
671  units.length = USER_UNIT_ADAPTIVE;
672  units.mass = USER_UNIT_ADAPTIVE;
673  units.time = USER_UNIT_ADAPTIVE;
675  return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
676 }
677 
679  int len_max,
680  double value,
681  int prec,
682  int type,
683  const UnitSettings *settings,
684  bool pad)
685 {
686  bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
688  return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units);
689 }
690 
691 BLI_INLINE bool isalpha_or_utf8(const int ch)
692 {
693  return (ch >= 128 || isalpha(ch));
694 }
695 
696 static const char *unit_find_str(const char *str, const char *substr, bool case_sensitive)
697 {
698  if (substr == NULL || substr[0] == '\0') {
699  return NULL;
700  }
701 
702  while (true) {
703  /* Unit detection is case insensitive. */
704  const char *str_found;
705  if (case_sensitive) {
706  str_found = strstr(str, substr);
707  }
708  else {
709  str_found = BLI_strcasestr(str, substr);
710  }
711 
712  if (str_found) {
713  /* Previous char cannot be a letter. */
714  if (str_found == str ||
715  /* Weak unicode support!, so "µm" won't match up be replaced by "m"
716  * since non ascii utf8 values will NEVER return true */
717  isalpha_or_utf8(*BLI_str_prev_char_utf8(str_found)) == 0) {
718  /* Next char cannot be alphanum. */
719  int len_name = strlen(substr);
720 
721  if (!isalpha_or_utf8(*(str_found + len_name))) {
722  return str_found;
723  }
724  }
725  /* If str_found is not a valid unit, we have to check further in the string... */
726  for (str_found++; isalpha_or_utf8(*str_found); str_found++) {
727  /* Pass. */
728  }
729  str = str_found;
730  }
731  else {
732  break;
733  }
734  }
735 
736  return NULL;
737 }
738 
739 /* Note that numbers are added within brackets.
740  * ") " - is used to detect numbers we added so we can detect if commas need to be added.
741  *
742  * "1m1cm+2mm" - Original value.
743  * "1*1#1*0.01#+2*0.001#" - Replace numbers.
744  * "1*1+1*0.01 +2*0.001 " - Add add signs if ( + - * / | & ~ < > ^ ! = % ) not found in between.
745  */
746 
747 /* Not too strict, (+ - * /) are most common. */
748 static bool ch_is_op(char op)
749 {
750  switch (op) {
751  case '+':
752  case '-':
753  case '*':
754  case '/':
755  case '|':
756  case '&':
757  case '~':
758  case '<':
759  case '>':
760  case '^':
761  case '!':
762  case '=':
763  case '%':
764  return true;
765  default:
766  return false;
767  }
768 }
769 
776 static char *find_next_negative(const char *str, const char *remaining_str)
777 {
778  char *str_found = strstr(remaining_str, "-");
779 
780  if (str_found == NULL) {
781  return NULL;
782  }
783 
784  /* Don't use the "-" from scientific notation, but make sure we can look backwards first. */
785  if ((str_found != str) && ELEM(*(str_found - 1), 'e', 'E')) {
786  return find_next_negative(str, str_found + 1);
787  }
788 
789  if (*(str_found + 1) == ' ') {
790  str_found++;
791  }
792 
793  return str_found + 1;
794 }
795 
802 static char *find_next_op(const char *str, char *remaining_str, int len_max)
803 {
804  int i;
805  for (i = 0; i < len_max; i++) {
806  if (remaining_str[i] == '\0') {
807  return remaining_str + i;
808  }
809 
810  if (ch_is_op(remaining_str[i])) {
811  /* Make sure we don't look backwards before the start of the string. */
812  if (remaining_str != str && i != 0) {
813  /* Check for velocity or acceleration (e.g. '/' in 'ft/s' is not an op). */
814  if ((remaining_str[i] == '/') && ELEM(remaining_str[i - 1], 't', 'T', 'm', 'M') &&
815  ELEM(remaining_str[i + 1], 's', 'S')) {
816  continue;
817  }
818 
819  /* Check for scientific notation. */
820  if (ELEM(remaining_str[i - 1], 'e', 'E')) {
821  continue;
822  }
823 
824  /* Return position before a space character. */
825  if (remaining_str[i - 1] == ' ') {
826  i--;
827  }
828  }
829 
830  return remaining_str + i;
831  }
832  }
833  BLI_assert(!"String should be NULL terminated");
834  return remaining_str + i;
835 }
836 
843 static bool unit_distribute_negatives(char *str, const int len_max)
844 {
845  bool changed = false;
846 
847  char *remaining_str = str;
848  int remaining_str_len = len_max;
849  while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) {
850  /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */
851  remaining_str_len = len_max - (int)(remaining_str - str);
852  if (remaining_str_len <= 2) {
853  return changed;
854  }
855 
856  changed = true;
857 
858  /* Add '(', shift the following characters to the right to make space. */
859  memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
860  *remaining_str = '(';
861 
862  /* Add the ')' before the next operation or at the end. */
863  remaining_str = find_next_op(str, remaining_str + 1, remaining_str_len);
864  remaining_str_len = len_max - (int)(remaining_str - str);
865  memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
866  *remaining_str = ')';
867 
868  /* Only move forward by 1 even though we added two characters. Minus signs need to be able to
869  * apply to the next block of values too. */
870  remaining_str += 1;
871  }
872 
873  return changed;
874 }
875 
880 static int find_previous_non_value_char(const char *str, const int start_ofs)
881 {
882  for (int i = start_ofs; i > 0; i--) {
883  if (ch_is_op(str[i - 1]) || strchr("( )", str[i - 1])) {
884  return i;
885  }
886  }
887  return 0;
888 }
889 
894 static int find_end_of_value_chars(const char *str, const int len_max, const int start_ofs)
895 {
896  int i;
897  for (i = start_ofs; i < len_max; i++) {
898  if (!strchr("0123456789eE.", str[i])) {
899  return i;
900  }
901  }
902  return i;
903 }
904 
905 static int unit_scale_str(char *str,
906  int len_max,
907  char *str_tmp,
908  double scale_pref,
909  const bUnitDef *unit,
910  const char *replace_str,
911  bool case_sensitive)
912 {
913  if (len_max < 0) {
914  return 0;
915  }
916 
917  /* XXX - investigate, does not respect len_max properly. */
918  char *str_found = (char *)unit_find_str(str, replace_str, case_sensitive);
919 
920  if (str_found == NULL) {
921  return 0;
922  }
923 
924  int found_ofs = (int)(str_found - str);
925 
926  int len = strlen(str);
927 
928  /* Deal with unit bias for temperature units. Order of operations is important, so we
929  * have to add parentheses, add the bias, then multiply by the scalar like usual.
930  *
931  * Note: If these changes don't fit in the buffer properly unit evaluation has failed,
932  * just try not to destroy anything while failing. */
933  if (unit->bias != 0.0) {
934  /* Add the open parenthesis. */
935  int prev_op_ofs = find_previous_non_value_char(str, found_ofs);
936  if (len + 1 < len_max) {
937  memmove(str + prev_op_ofs + 1, str + prev_op_ofs, len - prev_op_ofs + 1);
938  str[prev_op_ofs] = '(';
939  len++;
940  found_ofs++;
941  str_found++;
942  } /* If this doesn't fit, we have failed. */
943 
944  /* Add the addition sign, the bias, and the close parenthesis after the value. */
945  int value_end_ofs = find_end_of_value_chars(str, len_max, prev_op_ofs + 2);
946  int len_bias_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "+%.9g)", unit->bias);
947  if (value_end_ofs + len_bias_num < len_max) {
948  memmove(str + value_end_ofs + len_bias_num, str + value_end_ofs, len - value_end_ofs + 1);
949  memcpy(str + value_end_ofs, str_tmp, len_bias_num);
950  len += len_bias_num;
951  found_ofs += len_bias_num;
952  str_found += len_bias_num;
953  } /* If this doesn't fit, we have failed. */
954  }
955 
956  int len_name = strlen(replace_str);
957  int len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator. */
958 
959  /* "#" Removed later */
960  int len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref);
961 
962  if (len_num > len_max) {
963  len_num = len_max;
964  }
965 
966  if (found_ofs + len_num + len_move > len_max) {
967  /* Can't move the whole string, move just as much as will fit. */
968  len_move -= (found_ofs + len_num + len_move) - len_max;
969  }
970 
971  if (len_move > 0) {
972  /* Resize the last part of the string.
973  * May grow or shrink the string. */
974  memmove(str_found + len_num, str_found + len_name, len_move);
975  }
976 
977  if (found_ofs + len_num > len_max) {
978  /* Not even the number will fit into the string, only copy part of it. */
979  len_num -= (found_ofs + len_num) - len_max;
980  }
981 
982  if (len_num > 0) {
983  /* It's possible none of the number could be copied in. */
984  memcpy(str_found, str_tmp, len_num); /* Without the string terminator. */
985  }
986 
987  /* Since the null terminator wont be moved if the stringlen_max
988  * was not long enough to fit everything in it. */
989  str[len_max - 1] = '\0';
990  return found_ofs + len_num;
991 }
992 
993 static int unit_replace(
994  char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
995 {
996  const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
997  int ofs = 0;
998  ofs += unit_scale_str(
999  str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_short, case_sensitive);
1000  ofs += unit_scale_str(
1001  str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_plural, false);
1002  ofs += unit_scale_str(
1003  str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_alt, case_sensitive);
1004  ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name, false);
1005  return ofs;
1006 }
1007 
1008 static bool unit_find(const char *str, const bUnitDef *unit)
1009 {
1010  const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
1011  if (unit_find_str(str, unit->name_short, case_sensitive)) {
1012  return true;
1013  }
1014  if (unit_find_str(str, unit->name_plural, false)) {
1015  return true;
1016  }
1017  if (unit_find_str(str, unit->name_alt, case_sensitive)) {
1018  return true;
1019  }
1020  if (unit_find_str(str, unit->name, false)) {
1021  return true;
1022  }
1023 
1024  return false;
1025 }
1026 
1034  const char *str,
1035  const char *str_prev)
1036 {
1037  const bUnitDef *unit = NULL;
1038 
1039  /* See which units the new value has. */
1040  for (unit = usys->units; unit->name; unit++) {
1041  if (unit_find(str, unit)) {
1042  break;
1043  }
1044  }
1045  /* Else, try to infer the default unit from the previous string. */
1046  if (str_prev && (unit == NULL || unit->name == NULL)) {
1047  /* See which units the original value had. */
1048  for (unit = usys->units; unit->name; unit++) {
1049  if (unit_find(str_prev, unit)) {
1050  break;
1051  }
1052  }
1053  }
1054  /* Else, fall back to default unit. */
1055  if (unit == NULL || unit->name == NULL) {
1056  unit = unit_default(usys);
1057  }
1058 
1059  return unit;
1060 }
1061 
1063 {
1064  for (int system = 0; system < UNIT_SYSTEM_TOT; system++) {
1065  const bUnitCollection *usys = unit_get_system(system, type);
1066  if (!is_valid_unit_collection(usys)) {
1067  continue;
1068  }
1069 
1070  for (int i = 0; i < usys->length; i++) {
1071  if (unit_find(str, usys->units + i)) {
1072  return true;
1073  }
1074  }
1075  }
1076  return false;
1077 }
1078 
1079 double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value)
1080 {
1082  const bUnitDef *unit = get_preferred_display_unit_if_used(type, units);
1083 
1084  const double scalar = (unit == NULL) ? BKE_unit_base_scalar(units.system, type) : unit->scalar;
1085  const double bias = (unit == NULL) ? 0.0 : unit->bias; /* Base unit shouldn't have a bias. */
1086 
1087  return value * scalar + bias;
1088 }
1089 
1107  char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
1108 {
1109  const bUnitCollection *usys = unit_get_system(system, type);
1110  if (!is_valid_unit_collection(usys)) {
1111  return false;
1112  }
1113 
1114  double scale_pref_base = scale_pref;
1115  char str_tmp[TEMP_STR_SIZE];
1116  bool changed = false;
1117 
1118  /* Fix cases like "-1m50cm" which would evaluate to -0.5m without this. */
1119  changed |= unit_distribute_negatives(str, len_max);
1120 
1121  /* Try to find a default unit from current or previous string. */
1122  const bUnitDef *default_unit = unit_detect_from_str(usys, str, str_prev);
1123 
1124  /* We apply the default unit to the whole expression (default unit is now the reference
1125  * '1.0' one). */
1126  scale_pref_base *= default_unit->scalar;
1127 
1128  /* Apply the default unit on the whole expression, this allows to handle nasty cases like
1129  * '2+2in'. */
1130  if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) <
1131  sizeof(str_tmp)) {
1132  strncpy(str, str_tmp, len_max);
1133  }
1134  else {
1135  /* BLI_snprintf would not fit into str_tmp, cant do much in this case.
1136  * Check for this because otherwise BKE_unit_replace_string could call its self forever. */
1137  return changed;
1138  }
1139 
1140  for (const bUnitDef *unit = usys->units; unit->name; unit++) {
1141  /* In case there are multiple instances. */
1142  while (unit_replace(str, len_max, str_tmp, scale_pref_base, unit)) {
1143  changed = true;
1144  }
1145  }
1146 
1147  /* Try other unit systems now, so we can evaluate imperial when metric is set for eg. */
1148  /* Note that checking other systems at that point means we do not support their units as
1149  * 'default' one. In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches,
1150  * not 4 inches. I do think this is the desired behavior!
1151  */
1152  for (int system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
1153  if (system_iter != system) {
1154  const bUnitCollection *usys_iter = unit_get_system(system_iter, type);
1155  if (usys_iter) {
1156  for (const bUnitDef *unit = usys_iter->units; unit->name; unit++) {
1157  int ofs = 0;
1158  /* In case there are multiple instances. */
1159  while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref_base, unit))) {
1160  changed = true;
1161  }
1162  }
1163  }
1164  }
1165  }
1166 
1167  /* Replace # with add sign when there is no operator between it and the next number.
1168  *
1169  * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3"
1170  */
1171  {
1172  char *str_found = str;
1173  const char *ch = str;
1174 
1175  while ((str_found = strchr(str_found, SEP_CHR))) {
1176  bool op_found = false;
1177 
1178  /* Any operators after this? */
1179  for (ch = str_found + 1; *ch != '\0'; ch++) {
1180  if (ELEM(*ch, ' ', '\t')) {
1181  continue;
1182  }
1183  op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')'));
1184  break;
1185  }
1186 
1187  /* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */
1188  *str_found++ = op_found ? ' ' : '+';
1189  }
1190  }
1191 
1192  return changed;
1193 }
1194 
1195 /* 45µm --> 45um */
1196 void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
1197 {
1198  const bUnitCollection *usys = unit_get_system(system, type);
1199 
1200  /* Find and substitute all units. */
1201  for (const bUnitDef *unit = usys->units; unit->name; unit++) {
1202  if (len_max > 0 && unit->name_alt) {
1203  const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
1204  const char *found = unit_find_str(orig_str, unit->name_short, case_sensitive);
1205  if (found) {
1206  int offset = (int)(found - orig_str);
1207  int len_name = 0;
1208 
1209  /* Copy everything before the unit. */
1210  offset = (offset < len_max ? offset : len_max);
1211  strncpy(str, orig_str, offset);
1212 
1213  str += offset;
1214  orig_str += offset + strlen(unit->name_short);
1215  len_max -= offset;
1216 
1217  /* Print the alt_name. */
1218  if (unit->name_alt) {
1219  len_name = BLI_strncpy_rlen(str, unit->name_alt, len_max);
1220  }
1221  else {
1222  len_name = 0;
1223  }
1224 
1225  len_name = (len_name < len_max ? len_name : len_max);
1226  str += len_name;
1227  len_max -= len_name;
1228  }
1229  }
1230  }
1231 
1232  /* Finally copy the rest of the string. */
1233  strncpy(str, orig_str, len_max);
1234 }
1235 
1236 double BKE_unit_closest_scalar(double value, int system, int type)
1237 {
1238  const bUnitCollection *usys = unit_get_system(system, type);
1239 
1240  if (usys == NULL) {
1241  return -1;
1242  }
1243 
1244  const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
1245  if (unit == NULL) {
1246  return -1;
1247  }
1248 
1249  return unit->scalar;
1250 }
1251 
1252 double BKE_unit_base_scalar(int system, int type)
1253 {
1254  const bUnitCollection *usys = unit_get_system(system, type);
1255  if (usys) {
1256  return unit_default(usys)->scalar;
1257  }
1258 
1259  return 1.0;
1260 }
1261 
1262 bool BKE_unit_is_valid(int system, int type)
1263 {
1264  return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
1265 }
1266 
1267 void BKE_unit_system_get(int system, int type, void const **r_usys_pt, int *r_len)
1268 {
1269  const bUnitCollection *usys = unit_get_system(system, type);
1270  *r_usys_pt = usys;
1271 
1272  if (usys == NULL) {
1273  *r_len = 0;
1274  return;
1275  }
1276 
1277  *r_len = usys->length;
1278 }
1279 
1280 int BKE_unit_base_get(const void *usys_pt)
1281 {
1282  return ((bUnitCollection *)usys_pt)->base_unit;
1283 }
1284 
1285 int BKE_unit_base_of_type_get(int system, int type)
1286 {
1287  return unit_get_system(system, type)->base_unit;
1288 }
1289 
1290 const char *BKE_unit_name_get(const void *usys_pt, int index)
1291 {
1292  return ((bUnitCollection *)usys_pt)->units[index].name;
1293 }
1294 const char *BKE_unit_display_name_get(const void *usys_pt, int index)
1295 {
1296  return ((bUnitCollection *)usys_pt)->units[index].name_display;
1297 }
1298 const char *BKE_unit_identifier_get(const void *usys_pt, int index)
1299 {
1300  const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
1301  if (unit->identifier == NULL) {
1302  BLI_assert(false && "identifier for this unit is not specified yet");
1303  }
1304  return unit->identifier;
1305 }
1306 
1307 double BKE_unit_scalar_get(const void *usys_pt, int index)
1308 {
1309  return ((bUnitCollection *)usys_pt)->units[index].scalar;
1310 }
1311 
1312 bool BKE_unit_is_suppressed(const void *usys_pt, int index)
1313 {
1314  return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
1315 }
@ B_UNIT_AREA
Definition: BKE_unit.h:80
@ B_UNIT_TYPE_TOT
Definition: BKE_unit.h:90
@ B_UNIT_VOLUME
Definition: BKE_unit.h:81
@ B_UNIT_LENGTH
Definition: BKE_unit.h:79
@ B_UNIT_ROTATION
Definition: BKE_unit.h:83
@ B_UNIT_TEMPERATURE
Definition: BKE_unit.h:89
@ B_UNIT_CAMERA
Definition: BKE_unit.h:87
@ B_UNIT_MASS
Definition: BKE_unit.h:82
@ B_UNIT_TIME
Definition: BKE_unit.h:84
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
MINLINE int integer_digits_d(const double d)
MINLINE int max_ii(int a, int b)
#define M_PI
Definition: BLI_math_base.h:38
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:578
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:187
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_str_prev_char_utf8(const char *p) ATTR_NONNULL()
Definition: string_utf8.c:838
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
Compatibility-like things for windows.
#define USER_UNIT_OPT_SPLIT
#define USER_UNIT_ROT_RADIANS
#define USER_UNIT_ADAPTIVE
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Group RGB to Bright Vector Camera CLAMP
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
#define str(s)
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
int time
Definition: unit.c:535
int mass
Definition: unit.c:534
int temperature
Definition: unit.c:536
int length
Definition: unit.c:533
int rotation
Definition: unit.c:531
int system
Definition: unit.c:530
int base_unit
Definition: unit.c:126
int length
Definition: unit.c:130
const struct bUnitDef * units
Definition: unit.c:124
Definition: unit.c:87
const char * identifier
Definition: unit.c:102
const char * name_short
Definition: unit.c:92
const char * name_display
Definition: unit.c:100
const char * name_alt
Definition: unit.c:97
double scalar
Definition: unit.c:104
int flag
Definition: unit.c:107
const char * name
Definition: unit.c:88
const char * name_plural
Definition: unit.c:90
double bias
Definition: unit.c:106
static struct bUnitCollection buMetricTempCollection
Definition: unit.c:339
static int find_end_of_value_chars(const char *str, const int len_max, const int start_ofs)
Definition: unit.c:894
static struct bUnitDef buImperialLenDef[]
Definition: unit.c:164
int BKE_unit_base_of_type_get(int system, int type)
Definition: unit.c:1285
static struct bUnitCollection buNaturalTimeCollection
Definition: unit.c:293
@ B_UNIT_DEF_SUPPRESS
Definition: unit.c:113
@ B_UNIT_DEF_NO_SPACE
Definition: unit.c:119
@ B_UNIT_DEF_CASE_SENSITIVE
Definition: unit.c:117
@ B_UNIT_DEF_TENTH
Definition: unit.c:115
@ B_UNIT_DEF_NONE
Definition: unit.c:111
#define UN_SC_ITON
Definition: unit.c:76
static const struct bUnitCollection * bUnitSystems[][B_UNIT_TYPE_TOT]
Definition: unit.c:352
static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
Definition: unit.c:539
static char * find_next_op(const char *str, char *remaining_str, int len_max)
Definition: unit.c:802
static struct bUnitDef buMetricAreaDef[]
Definition: unit.c:177
static struct bUnitCollection buCameraLenCollection
Definition: unit.c:318
static struct bUnitDef buCameraLenDef[]
Definition: unit.c:310
#define UN_SC_FUR
Definition: unit.c:61
static struct bUnitDef buMetricAclDef[]
Definition: unit.c:270
static struct bUnitCollection buImperialLenCollection
Definition: unit.c:174
#define UN_SC_FT
Definition: unit.c:64
#define UN_SC_DAM
Definition: unit.c:53
static struct bUnitDef buMetricVelDef[]
Definition: unit.c:255
static char * find_next_negative(const char *str, const char *remaining_str)
Definition: unit.c:776
#define UN_SC_CWT
Definition: unit.c:77
static struct bUnitCollection buImperialVelCollection
Definition: unit.c:267
#define UN_SC_DM
Definition: unit.c:55
#define UN_SC_MG
Definition: unit.c:74
bool BKE_unit_is_valid(int system, int type)
Definition: unit.c:1262
static struct bUnitCollection buMetricVolCollection
Definition: unit.c:214
static struct bUnitDef buMetricMassDef[]
Definition: unit.c:229
static const bUnitCollection * unit_get_system(int system, int type)
Definition: unit.c:395
static struct bUnitCollection buDummyCollection
Definition: unit.c:141
#define UN_SC_MTON
Definition: unit.c:68
#define UN_SC_HG
Definition: unit.c:71
size_t BKE_unit_value_as_string_adaptive(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
Definition: unit.c:665
#define SEP_CHR
Definition: unit.c:46
static struct bUnitCollection buMetricAclCollection
Definition: unit.c:274
#define UN_SC_KM
Definition: unit.c:51
static struct bUnitCollection buPowerCollection
Definition: unit.c:331
static void unit_dual_convert(double value, const bUnitCollection *usys, bUnitDef const **r_unit_a, bUnitDef const **r_unit_b, double *r_value_a, double *r_value_b, const bUnitDef *main_unit)
Definition: unit.c:437
static bool is_valid_unit_collection(const bUnitCollection *usys)
Definition: unit.c:583
#define UN_SC_G
Definition: unit.c:73
#define UN_SC_IN
Definition: unit.c:65
const char * BKE_unit_display_name_get(const void *usys_pt, int index)
Definition: unit.c:1294
#define NULL_UNIT
Definition: unit.c:137
static const struct bUnitCollection buMetricLenCollection
Definition: unit.c:162
bool BKE_unit_is_suppressed(const void *usys_pt, int index)
Definition: unit.c:1312
#define UNIT_COLLECTION_LENGTH(def)
Definition: unit.c:136
void BKE_unit_system_get(int system, int type, void const **r_usys_pt, int *r_len)
Definition: unit.c:1267
#define UN_SC_LB
Definition: unit.c:79
#define UN_SC_MIL
Definition: unit.c:66
static struct bUnitCollection buImperialVolCollection
Definition: unit.c:226
#define TEMP_STR_SIZE
Definition: unit.c:44
static const bUnitDef * unit_best_fit(double value, const bUnitCollection *usys, const bUnitDef *unit_start, int suppress)
Definition: unit.c:407
#define EPS
Definition: unit.c:49
static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
Definition: unit.c:993
static struct bUnitDef buMetricTempDef[]
Definition: unit.c:334
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
Definition: unit.c:1196
static struct bUnitCollection buMetricMassCollection
Definition: unit.c:239
#define UN_SC_MI
Definition: unit.c:60
static struct bUnitDef buNaturalTimeDef[]
Definition: unit.c:283
#define UN_SC_CH
Definition: unit.c:62
static struct bUnitDef buImperialAclDef[]
Definition: unit.c:276
static const bUnitDef * unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev)
Definition: unit.c:1033
const char * BKE_unit_identifier_get(const void *usys_pt, int index)
Definition: unit.c:1298
static size_t unit_as_string_split_pair(char *str, int len_max, double value, int prec, const bUnitCollection *usys, const bUnitDef *main_unit)
Definition: unit.c:551
static bool unit_find(const char *str, const bUnitDef *unit)
Definition: unit.c:1008
int BKE_unit_base_get(const void *usys_pt)
Definition: unit.c:1280
static struct bUnitCollection buImperialAreaCollection
Definition: unit.c:200
static struct bUnitDef buImperialMassDef[]
Definition: unit.c:241
static size_t unit_as_string(char *str, int len_max, double value, int prec, const bUnitCollection *usys, const bUnitDef *unit, char pad)
Definition: unit.c:454
double BKE_unit_scalar_get(const void *usys_pt, int index)
Definition: unit.c:1307
#define UN_SC_YD
Definition: unit.c:63
static struct bUnitDef buPowerDef[]
Definition: unit.c:321
static struct bUnitDef buImperialTempDef[]
Definition: unit.c:341
static bool ch_is_op(char op)
Definition: unit.c:748
double BKE_unit_closest_scalar(double value, int system, int type)
Definition: unit.c:1236
static struct bUnitDef buImperialVolDef[]
Definition: unit.c:216
static struct bUnitCollection buImperialMassCollection
Definition: unit.c:249
#define UN_SC_ST
Definition: unit.c:78
static size_t unit_as_string_main(char *str, int len_max, double value, int prec, int type, bool split, bool pad, PreferredUnits units)
Definition: unit.c:635
static struct bUnitCollection buImperialTempCollection
Definition: unit.c:346
size_t BKE_unit_value_as_string(char *str, int len_max, double value, int prec, int type, const UnitSettings *settings, bool pad)
Definition: unit.c:678
static struct bUnitDef buMetricLenDef[]
Definition: unit.c:144
bool BKE_unit_replace_string(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
Definition: unit.c:1106
#define UN_SC_QL
Definition: unit.c:69
#define UN_SC_OZ
Definition: unit.c:80
#define UN_SC_DAG
Definition: unit.c:72
double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value)
Definition: unit.c:1079
static int find_previous_non_value_char(const char *str, const int start_ofs)
Definition: unit.c:880
#define UN_SC_MM
Definition: unit.c:57
static struct bUnitCollection buImperialAclCollection
Definition: unit.c:280
double BKE_unit_base_scalar(int system, int type)
Definition: unit.c:1252
struct bUnitCollection bUnitCollection
#define UN_SC_CM
Definition: unit.c:56
static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit, const char *replace_str, bool case_sensitive)
Definition: unit.c:905
static struct bUnitDef buMetricVolDef[]
Definition: unit.c:203
static const bUnitDef * unit_default(const bUnitCollection *usys)
Definition: unit.c:402
static const char * unit_find_str(const char *str, const char *substr, bool case_sensitive)
Definition: unit.c:696
bool BKE_unit_string_contains_unit(const char *str, int type)
Definition: unit.c:1062
struct bUnitDef bUnitDef
static struct bUnitCollection buMetricAreaCollection
Definition: unit.c:188
static struct bUnitCollection buMetricVelCollection
Definition: unit.c:260
static struct bUnitDef buImperialVelDef[]
Definition: unit.c:262
const char * BKE_unit_name_get(const void *usys_pt, int index)
Definition: unit.c:1290
#define UN_SC_FAH
Definition: unit.c:82
static struct bUnitCollection buNaturalRotCollection
Definition: unit.c:307
static bool unit_distribute_negatives(char *str, const int len_max)
Definition: unit.c:843
#define UN_SC_UM
Definition: unit.c:58
static struct bUnitDef buImperialAreaDef[]
Definition: unit.c:190
#define UN_SC_KG
Definition: unit.c:70
static const bUnitDef * get_preferred_display_unit_if_used(int type, PreferredUnits units)
Definition: unit.c:588
static struct bUnitDef buDummyDef[]
Definition: unit.c:140
#define UN_SC_HM
Definition: unit.c:52
static struct bUnitDef buNaturalRotDef[]
Definition: unit.c:296
BLI_INLINE bool isalpha_or_utf8(const int ch)
Definition: unit.c:691
#define SEP_STR
Definition: unit.c:47
static bool unit_should_be_split(int type)
Definition: unit.c:524
#define UN_SC_M
Definition: unit.c:54
#define UNIT_SYSTEM_TOT
Definition: unit.c:351
ccl_device_inline float2 floor(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)
uint len