Exemple #1
0
static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *unit_start, int suppress)
{
	bUnitDef *unit;
	double value_abs = value > 0.0 ? value : -value;

	for (unit = unit_start ? unit_start : usys->units; unit->name; unit++) {

		if (suppress && (unit->flag & B_UNIT_DEF_SUPPRESS))
			continue;

		/* scale down scalar so 1cm doesnt convert to 10mm because of float error */
		if (UNLIKELY(unit->flag & B_UNIT_DEF_TENTH)) {
			if (value_abs >= unit->scalar * (0.1 - EPS)) {
				return unit;
			}
		}
		else {
			if (value_abs >= unit->scalar * (1.0 - EPS)) {
				return unit;
			}
		}
	}

	return unit_default(usys);
}
static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, const char *str_prev)
{
	/* Try to find a default unit from current or previous string.
	 * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
	 * Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
	bUnitDef *unit = NULL;

	/* see which units the new value has */
	for (unit = usys->units; unit->name; unit++) {
		if (unit_find(str, unit))
			break;
	}
	/* Else, try to infer the default unit from the previous string. */
	if (str_prev && (unit == NULL || unit->name == NULL)) {
		/* see which units the original value had */
		for (unit = usys->units; unit->name; unit++) {
			if (unit_find(str_prev, unit))
				break;
		}
	}
	/* Else, fall back to default unit. */
	if (unit == NULL || unit->name == NULL) {
		unit = unit_default(usys);
	}

	return unit;
}
Exemple #3
0
/* 45µm --> 45um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);

	bUnitDef *unit;
	bUnitDef *unit_def = unit_default(usys);

	/* find and substitute all units */
	for (unit = usys->units; unit->name; unit++) {
		if (len_max > 0 && (unit->name_alt || unit == unit_def)) {
			const char *found = unit_find_str(orig_str, unit->name_short);
			if (found) {
				int offset = (int)(found - orig_str);
				int len_name = 0;

				/* copy everything before the unit */
				offset = (offset < len_max ? offset : len_max);
				strncpy(str, orig_str, offset);

				str += offset;
				orig_str += offset + strlen(unit->name_short);
				len_max -= offset;

				/* print the alt_name */
				if (unit->name_alt)
					len_name = BLI_strncpy_rlen(str, unit->name_alt, len_max);
				else
					len_name = 0;

				len_name = (len_name < len_max ? len_name : len_max);
				str += len_name;
				len_max -= len_name;
			}
		}
	}

	/* finally copy the rest of the string */
	strncpy(str, orig_str, len_max);
}
Exemple #4
0
double bUnit_BaseScalar(int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);
	return unit_default(usys)->scalar;
}
Exemple #5
0
/* make a copy of the string that replaces the units with numbers
 * this is used before parsing
 * 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..
 * 10.1km -> 10.1*1000.0
 * ...will be resolved by python.
 *
 * values will be split by a comma's
 * 5'2" -> 5'0.0254, 2*0.3048
 *
 * str_prev is optional, when valid it is used to get a base unit when none is set.
 *
 * return true of a change was made.
 */
int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);

	bUnitDef *unit;
	char str_tmp[TEMP_STR_SIZE];
	int changed = 0;

	if (usys == NULL || usys->units[0].name == NULL) {
		return 0;
	}

	/* make lowercase */
	BLI_ascii_strtolower(str, len_max);

	for (unit = usys->units; unit->name; unit++) {
		/* in case there are multiple instances */
		while (unit_replace(str, len_max, str_tmp, scale_pref, unit))
			changed = true;
	}
	unit = NULL;

	{
		/* try other unit systems now, so we can evaluate imperial when metric is set for eg. */
		bUnitCollection *usys_iter;
		int system_iter;

		for (system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
			if (system_iter != system) {
				usys_iter = unit_get_system(system_iter, type);
				if (usys_iter) {
					for (unit = usys_iter->units; unit->name; unit++) {
						int ofs = 0;
						/* in case there are multiple instances */
						while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref, unit)))
							changed = true;
					}
				}
			}
		}
	}
	unit = NULL;

	if (changed == 0) {
		/* no units given so infer a unit from the previous string or default */
		if (str_prev) {
			/* see which units the original value had */
			for (unit = usys->units; unit->name; unit++) {
				if (unit_find(str_prev, unit))
					break;
			}
		}

		if (unit == NULL || unit->name == NULL)
			unit = unit_default(usys);

		/* add the unit prefix and re-run, use brackets in case there was an expression given */
		if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) {
			strncpy(str, str_tmp, len_max);
			return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type);
		}
		else {
			/* BLI_snprintf would not fit into str_tmp, cant do much in this case
			 * check for this because otherwise bUnit_ReplaceString could call its self forever */
			return 0;
		}

	}

	/* replace # with commas when there is no operator between it and the next number
	 *
	 * "1*1# 3*100# * 3"  ->  "1 *1, 3 *100  * 3"
	 *
	 * */
	{
		char *str_found = str;
		char *ch = str;

		while ((str_found = strchr(str_found, SEP_CHR))) {

			int op_found = 0;
			/* any operators after this?*/
			for (ch = str_found + 1; *ch != '\0'; ch++) {

				if (*ch == ' ' || *ch == '\t') {
					/* do nothing */
				}
				else if (ch_is_op(*ch) || *ch == ',') { /* found an op, no need to insert a ',' */
					op_found = 1;
					break;
				}
				else { /* found a non-op character */
					op_found = 0;
					break;
				}
			}

			*str_found++ = op_found ? ' ' : ',';
		}
	}

	return changed;
}
Exemple #6
0
static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys,
                             /* non exposed options */
                             bUnitDef *unit, char pad)
{
	double value_conv;
	size_t len, i;

	if (unit) {
		/* use unit without finding the best one */
	}
	else if (value == 0.0) {
		/* use the default units since there is no way to convert */
		unit = unit_default(usys);
	}
	else {
		unit = unit_best_fit(value, usys, NULL, 1);
	}

	value_conv = value / unit->scalar;

	/* Convert to a string */
	{
		len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv);

		if (len >= len_max)
			len = len_max;
	}

	/* Add unit prefix and strip zeros */

	/* replace trailing zero's with spaces
	 * so the number is less complicated but alignment in a button wont
	 * jump about while dragging */
	i = len - 1;

	if (prec > 0) {
		while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
			str[i--] = pad;
		}

		if (i > 0 && str[i] == '.') { /* 10. -> 10 */
			str[i--] = pad;
		}
	}

	/* Now add the suffix */
	if (i < len_max) {
		int j = 0;
		i++;
		while (unit->name_short[j] && (i < len_max)) {
			str[i++] = unit->name_short[j++];
		}
#if 0
		if (pad) {
			/* this loop only runs if so many zeros were removed that
			 * the unit name only used padded chars,
			 * In that case add padding for the name. */

			while (i <= len + j && (i < len_max)) {
				str[i++] = pad;
			}
		}
#endif
	}

	/* terminate no matter whats done with padding above */
	if (i >= len_max)
		i = len_max - 1;

	str[i] = '\0';
	return i;
}