Exemplo n.º 1
0
/* Used for drawing number buttons, try keep fast.
 * Return the length of the generated string.
 */
size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
{
	bUnitCollection *usys = unit_get_system(system, type);

	if (usys == NULL || usys->units[0].name == NULL)
		usys = &buDummyCollection;

	/* split output makes sense only for length, mass and time */
	if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) {
		bUnitDef *unit_a, *unit_b;
		double value_a, value_b;

		unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b);

		/* check the 2 is a smaller unit */
		if (unit_b > unit_a) {
			size_t i;
			i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');

			/* is there enough space for at least 1 char of the next unit? */
			if (i + 2 < len_max) {
				str[i++] = ' ';

				/* use low precision since this is a smaller unit */
				i += unit_as_string(str + i, len_max - i, value_b, prec ? 1 : 0, usys, unit_b, '\0');
			}
			return i;
		}
	}

	return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0');
}
Exemplo n.º 2
0
void bUnit_GetSystem(void **usys_pt, int *len, int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);
	*usys_pt = usys;

	if (usys == NULL) {
		*len = 0;
		return;
	}

	*len = usys->length;
}
Exemplo n.º 3
0
double bUnit_ClosestScalar(double value, int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);
	bUnitDef *unit;

	if (usys == NULL)
		return -1;

	unit = unit_best_fit(value, usys, NULL, 1);
	if (unit == NULL)
		return -1;

	return unit->scalar;
}
Exemplo n.º 4
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);
}
Exemplo n.º 5
0
double bUnit_BaseScalar(int system, int type)
{
	bUnitCollection *usys = unit_get_system(system, type);
	return unit_default(usys)->scalar;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
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 an add sign
 * 5'2" -> 5*0.3048 + 2*0.0254
 *
 * 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.
 */
bool 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 = NULL, *default_unit;
	double scale_pref_base = scale_pref;
	char str_tmp[TEMP_STR_SIZE];
	bool changed = false;

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

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

	/* Try to find a default unit from current or previous string. */
	default_unit = unit_detect_from_str(usys, str, str_prev);

	/* We apply the default unit to the whole expression (default unit is now the reference '1.0' one). */
	scale_pref_base *= default_unit->scalar;

	/* Apply the default unit on the whole expression, this allows to handle nasty cases like '2+2in'. */
	if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) < sizeof(str_tmp)) {
		strncpy(str, str_tmp, len_max);
	}
	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 changed;
	}

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

	{
		/* try other unit systems now, so we can evaluate imperial when metric is set for eg. */
		/* Note that checking other systems at that point means we do not support their units as 'default' one.
		 * In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
		 * I do think this is the desired behavior!
		 */
		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_base, unit)))
							changed = true;
					}
				}
			}
		}
	}
	unit = NULL;

	/* replace # with add sign 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;
		const char *ch = str;

		while ((str_found = strchr(str_found, SEP_CHR))) {
			bool op_found = false;

			/* any operators after this? */
			for (ch = str_found + 1; *ch != '\0'; ch++) {
				if (*ch == ' ' || *ch == '\t') {
					continue;
				}
				op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')'));
				break;
			}

			/* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */
			*str_found++ = op_found ? ' ' : '+';
		}
	}

	return changed;
}