void surface_randomize(GwySurface *surface, GRand *rng) { GwyXYZ *d = surface->data; for (guint n = surface->n; n; n--, d++) { d->x = g_rand_double(rng); d->y = g_rand_double(rng); d->z = g_rand_double(rng); } }
/** * random_int_poisson: * @lambda: Lambda parameter for the distribution function, which must be * non-zero * * Generate a random variable from a Poisson distribution with parameter * @lambda. This consumes one %gdouble’s worth of randomness from the global * @prng. * * This is implemented using the inverse transform of the Poisson CDF, and is * guaranteed to return in time linearly proportional to @lambda. * * Returns: Poisson-distributed pseudo-random variable */ static guint32 random_int_poisson (guint lambda) { gdouble U; guint32 i; gdouble p, F; g_return_val_if_fail (lambda > 0, 0); /* * Reference: http://www.cs.bgu.ac.il/~mps042/invtransnote.htm, * §Simulating a Poisson random variable. */ U = g_rand_double (prng); /* step 1 */ i = 0; p = exp (0.0 - (gdouble) lambda); F = p; /* step 2 */ while (U >= F) { /* step 3 */ p = (lambda * p) / (i + 1); F += p; i += 1; /* step 4 and 5 */ } return i; }
void dp_evaluation_individ_prepare(DpEvaluationCtrl*hevalctrl, DpIndivid*individ) { int i; double y; for ( i = 0; i < hevalctrl->eval->size; i++) { if ( hevalctrl->eval->points[i]->limited ) { if ( hevalctrl->eval_strategy == sin_trans_flag ) { y = hevalctrl->eval->points[i]->alpha + hevalctrl->eval->points[i]->beta * sin(hevalctrl->eval->points[i]->gamma * individ->x[i]); y /= hevalctrl->eval->points[i]->scale; individ->z[i] = y; } else if ( hevalctrl->eval_strategy == tanh_trans_flag ) { y = hevalctrl->eval->points[i]->alpha + hevalctrl->eval->points[i]->beta * tanh(hevalctrl->eval->points[i]->gamma * individ->x[i]); y /= hevalctrl->eval->points[i]->scale; individ->z[i] = y; } else if ( hevalctrl->eval_strategy == alg_trans_flag ) { if ( individ->x[i] > hevalctrl->eval->points[i]->lower && individ->x[i] < hevalctrl->eval->points[i]->upper ) { individ->z[i] = individ->x[i] / hevalctrl->eval->points[i]->scale; } else { individ->x[i] = hevalctrl->eval->points[i]->lower + 2.0 * g_rand_double(individ->hrand) * hevalctrl->eval->points[i]->beta; individ->z[i] = individ->x[i] / hevalctrl->eval->points[i]->scale; } } else if ( hevalctrl->eval_strategy == rand_trans_flag ) { while ( individ->x[i] < hevalctrl->eval->points[i]->lower || individ->x[i] > hevalctrl->eval->points[i]->upper ) { individ->x[i] = hevalctrl->eval->points[i]->alpha + dp_rand_gauss(individ->hrand, 0, 1) * hevalctrl->eval->points[i]->beta; } individ->z[i] = individ->x[i] / hevalctrl->eval->points[i]->scale; } } else { individ->z[i] = individ->x[i] / hevalctrl->eval->points[i]->scale; } } }
int dp_evaluation_individ_compare(const void *p1, const void *p2, void *user_data) { int i, need_swap; DpIndivid**i1 = (DpIndivid**)p1; DpIndivid**i2 = (DpIndivid**)p2; DpIndivid*individ = *i1; DpIndivid*trial = *i2; DpEvaluationCtrl*hevalctrl = (DpEvaluationCtrl*)user_data; int ignore_cost = hevalctrl->eval_target->ignore_cost; double use_crdist = hevalctrl->eval_target->use_crdist; need_swap = 0; if ( individ->invalid == 1 && trial->invalid == 0 ) { need_swap = 1; } else if ( ignore_cost == 0 && trial->cost < individ->cost ) { need_swap = 1; } else if ( use_crdist > 0 && ( trial->pareto_front < individ->pareto_front || (( trial->pareto_front == individ->pareto_front ) && trial->crdist > individ->crdist) ) && g_rand_double(individ->hrand) < use_crdist ) { need_swap = 1; } else { need_swap = -1; for ( i = 0; i < hevalctrl->eval_target->size; i++ ) { if ( trial->targets[i] < individ->targets[i] && g_rand_double(individ->hrand) < hevalctrl->eval_target->penalty[i]->rank ) { need_swap = 1; break; } } } return need_swap; }
static int semi_uniform (RLearner *rl, const unsigned int state) { double rand_value = 0.0; int action = 0; if (rl == NULL) { fprintf(stderr, "RLearner-WARNING **: RLearner *rl is NULL\n"); } else { rand_value = g_rand_double(rl->random); if (rand_value > (1.0 - EXPLORATION_THRESHOLD)) { /* Random action */ action = g_rand_int_range(rl->random, 0, rl->num_actions); } else { action = best_action(rl, state); } } return action; }
static void print_current_frame (gchar *buffer, guint number, guint width, guint height, GRand *rand) { guint divisor = 10000000; int x = 1; while (divisor > 0) { print_number (buffer, number / divisor, x, 1, width); number = number % divisor; divisor = divisor / 10; x += DIGIT_WIDTH + 1; } //Grayscale pattern is the same for every row. Just calculate one single //Scanline, so we can reuse it and dont have to do the whole calculation //for every row again. char default_line[width]; for (guint p = 0; p < width; p++) { default_line[p] = (char) ((p * 256) / (width)); } //Use memcpy to quickly fill every row with the precalculated grayscale //pattern for (guint y = 16; y < height; y++) { guint index = y * width; memcpy (buffer + index, &default_line[0], width); } //This block will fill a square at the center of the image with normal //distributed random data const double mean = 128.0; const double std = 32.0; for (guint y = (height / 3); y < ((height * 2) / 3); y++) { guint row_start = y * width; for (guint i = (width / 3); i < ((width * 2) / 3); i++) { int index = row_start + i; double u1 = g_rand_double (rand); double u2 = g_rand_double (rand); double r = sqrt (-2 * log (u1)) * cos (2 * G_PI * u2); buffer[index] = (guint8) (r * std + mean); } } }
static gint random_integer(GRand *rng) { gdouble x = -5.0*log(g_rand_double(rng)); if (g_rand_boolean(rng)) x = -x; return (gint)gwy_round(x); }
void swfdec_as_math_random (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { double unused, unused2; *ret = swfdec_as_value_from_number (cx, NAN); SWFDEC_AS_CHECK (0, NULL, "|nn", &unused, &unused2); *ret = swfdec_as_value_from_number (cx, g_rand_double (cx->rand)); }
static gdouble gauss (GRand *gr) { gdouble sum = 0.0; gint i; for (i = 0; i < 6; i++) sum += g_rand_double (gr); return sum / 6.0; }
void swfdec_as_math_random (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { double unused, unused2; SWFDEC_AS_VALUE_SET_NUMBER (ret, NAN); SWFDEC_AS_CHECK (0, NULL, "|nn", &unused, &unused2); SWFDEC_AS_VALUE_SET_NUMBER (ret, g_rand_double (cx->rand)); }
/** * crank_bench_run_rand_double_array: (skip) * @run: A benchmark run. * @length: Length of required random array. * * Constructs random double array of given @length. * * Returns: (array) (transfer container): A random double array. */ gdouble* crank_bench_run_rand_double_array (CrankBenchRun *run, const guint length) { gdouble *result = g_new (gdouble, length); guint i; for (i = 0;i < length; i++) result[i] = g_rand_double (run->random); return result; }
double dp_rand_gauss(GRand*hrand, double mean, double dev) { static double V2, fac; static int phase = 0; double S, Z, U1, U2, V1; if ( phase == 1 ) { Z = V2 * fac; } else { do { U1 = g_rand_double(hrand); U2 = g_rand_double(hrand); V1 = 2 * U1 - 1; V2 = 2 * U2 - 1; S = V1 * V1 + V2 * V2; } while ( S >= 1 || S == 0.0 ); fac = sqrt (-2 * log(S) / S); Z = V1 * fac; } phase = 1 - phase; Z = mean + dev*Z; return Z; }
static void randomize(GwyMaskField *field, GRand *rng, gdouble p) { for (guint i = 0; i < field->yres; i++) { GwyMaskIter iter; gwy_mask_field_iter_init(field, iter, 0, i); for (guint j = 0; j < field->xres; j++) { gboolean v = (g_rand_double(rng) <= p); gwy_mask_iter_set(iter, v); gwy_mask_iter_next(iter); } } gwy_mask_field_invalidate(field); }
static void random_test (void) { /* * outline: * 1. create new tree and empty list of intervals * 2. insert some intervals into tree and list * 3. do various searches, compare results of both structures * 4. delete some intervals * 5. do various searches, compare results of both structures * 6. free memory */ gint i, start, end; EInterval *interval = NULL; EIntervalTree *tree; GList *l1, *l2, *next; gint num_deleted = 0; tree = e_intervaltree_new (); for (i = 0; i < NUM_INTERVALS_CLOSED; i++) { ECalComponent *comp; start = g_rand_int_range (myrand, 0, 1000); end = g_rand_int_range (myrand, start, 2000); comp = create_test_component (start, end); if (!comp) { g_message (G_STRLOC ": error"); exit (-1); } interval = g_new (EInterval, 1); interval->start = start; interval->end = end; interval->comp = comp; list = g_list_insert (list, interval, -1); e_intervaltree_insert (tree, start, end, comp); } /* insert open ended intervals */ for (i = 0; i < NUM_INTERVALS_OPEN; i++) { ECalComponent *comp; start = g_rand_int_range (myrand, 0, 1000); comp = create_test_component (start, end); if (!comp) { g_message (G_STRLOC ": error"); exit (-1); } interval = g_new (EInterval, 1); interval->start = start; interval->end = _TIME_MAX; interval->comp = comp; list = g_list_insert (list, interval, -1); e_intervaltree_insert (tree, start, interval->end, comp); /* g_print ("%d - %d\n", start, interval->end); */ } g_print ("Number of intervals inserted: %d\n", NUM_INTERVALS_CLOSED + NUM_INTERVALS_OPEN); for (i = 0; i < NUM_SEARCHES; i++) { start = g_rand_int_range (myrand, 0, 1000); end = g_rand_int_range (myrand, 2000, _TIME_MAX); /* g_print ("Search for : %d - %d\n", start, end); */ l1 = e_intervaltree_search (tree, start, end); l2 = search_in_list (list, start, end); if (!compare_interval_lists (l2, l1)) { e_intervaltree_dump (tree); g_message (G_STRLOC "Error"); exit (-1); } /* g_print ("OK\n"); */ g_list_foreach (l1, (GFunc)g_object_unref, NULL); g_list_foreach (l2, (GFunc)unref_comp, NULL); g_list_free (l1); g_list_free (l2); } /* open-ended intervals */ for (i = 0; i < 20; i++) { start = g_rand_int_range (myrand, 0, 1000); end = _TIME_MAX; /* g_print ("Search for : %d - %d\n", start, end); */ l1 = e_intervaltree_search (tree, start, end); l2 = search_in_list (list, start, end); if (!compare_interval_lists (l2, l1)) { e_intervaltree_dump (tree); g_message (G_STRLOC "Error"); exit (-1); } /* g_print ("OK\n"); */ g_list_foreach (l1, (GFunc)g_object_unref, NULL); g_list_foreach (l2, (GFunc)unref_comp, NULL); g_list_free (l1); g_list_free (l2); } l1 = list; while (l1) { /* perhaps we will delete l1 */ next = l1->next; if (g_rand_double (myrand) < pbality_delete) { ECalComponent *comp; const gchar *uid = NULL; gchar *rid; interval = (EInterval*) l1->data; comp = interval->comp; /* delete l1 */ /* g_print ("Deleting interval %d - %d\n", interval->start, interval->end); */ rid = e_cal_component_get_recurid_as_string (comp); e_cal_component_get_uid (comp, &uid); if (!e_intervaltree_remove (tree, uid, rid)) { g_free (rid); e_intervaltree_dump (tree); g_print ("Deleting interval %d - %d ERROR\n", interval->start, interval->end); exit (-1); } g_free (rid); g_object_unref (interval->comp); g_free (l1->data); list = g_list_delete_link (list, l1); num_deleted++; } l1 = next; } g_print ("Number of intervals deleted: %d\n", num_deleted); for (i = 0; i < NUM_SEARCHES; i++) { start = g_rand_int_range (myrand, 0, 1000); end = g_rand_int_range (myrand, start, 2000); /* g_print ("Search for : %d - %d\n", start, end); */ l1 = e_intervaltree_search (tree, start, end); /* g_print ("Results from tree:\n"); print_nodes_list (l1); */ l2 = search_in_list (list, start, end); if (!compare_interval_lists (l2, l1)) { g_print ("ERROR!\n\n"); return; } g_list_foreach (l1, (GFunc)g_object_unref, NULL); g_list_foreach (l2, (GFunc)unref_comp, NULL); g_list_free (l1); g_list_free (l2); /* g_print ("OK\n"); */ } e_intervaltree_destroy (tree); g_list_foreach (list, (GFunc)unref_comp, NULL); g_list_free (list); }
// This function runs a brush "simulation" step. Usually it is // called once or twice per dab. In theory the precision of the // "simulation" gets better when it is called more often. In // practice this only matters if there are some highly nonlinear // mappings in critical places or extremely few events per second. // // note: parameters are is dx/ddab, ..., dtime/ddab (dab is the number, 5.0 = 5th dab) void update_states_and_setting_values (float step_dx, float step_dy, float step_dpressure, float step_declination, float step_ascension, float step_dtime) { float pressure; float inputs[INPUT_COUNT]; if (step_dtime < 0.0) { printf("Time is running backwards!\n"); step_dtime = 0.001; } else if (step_dtime == 0.0) { // FIXME: happens about every 10th start, workaround (against division by zero) step_dtime = 0.001; } states[STATE_X] += step_dx; states[STATE_Y] += step_dy; states[STATE_PRESSURE] += step_dpressure; states[STATE_DECLINATION] += step_declination; states[STATE_ASCENSION] += step_ascension; float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value); // FIXME: does happen (interpolation problem?) states[STATE_PRESSURE] = CLAMP(states[STATE_PRESSURE], 0.0, 1.0); pressure = states[STATE_PRESSURE]; { // start / end stroke (for "stroke" input only) if (!states[STATE_STROKE_STARTED]) { if (pressure > settings[BRUSH_STROKE_THRESHOLD]->base_value + 0.0001) { // start new stroke //printf("stroke start %f\n", pressure); states[STATE_STROKE_STARTED] = 1; states[STATE_STROKE] = 0.0; } } else { if (pressure <= settings[BRUSH_STROKE_THRESHOLD]->base_value * 0.9 + 0.0001) { // end stroke //printf("stroke end\n"); states[STATE_STROKE_STARTED] = 0; } } } // now follows input handling float norm_dx, norm_dy, norm_dist, norm_speed; norm_dx = step_dx / step_dtime / base_radius; norm_dy = step_dy / step_dtime / base_radius; norm_speed = sqrt(SQR(norm_dx) + SQR(norm_dy)); norm_dist = norm_speed * step_dtime; inputs[INPUT_PRESSURE] = pressure; inputs[INPUT_SPEED1] = log(speed_mapping_gamma[0] + states[STATE_NORM_SPEED1_SLOW])*speed_mapping_m[0] + speed_mapping_q[0]; inputs[INPUT_SPEED2] = log(speed_mapping_gamma[1] + states[STATE_NORM_SPEED2_SLOW])*speed_mapping_m[1] + speed_mapping_q[1]; inputs[INPUT_RANDOM] = g_rand_double (rng); inputs[INPUT_STROKE] = MIN(states[STATE_STROKE], 1.0); inputs[INPUT_DIRECTION] = fmodf (atan2f (states[STATE_DIRECTION_DY], states[STATE_DIRECTION_DX])/(2*M_PI)*360 + 180.0, 180.0); inputs[INPUT_TILT_DECLINATION] = states[STATE_DECLINATION]; inputs[INPUT_TILT_ASCENSION] = states[STATE_ASCENSION]; inputs[INPUT_CUSTOM] = states[STATE_CUSTOM_INPUT]; if (print_inputs) { g_print("press=% 4.3f, speed1=% 4.4f\tspeed2=% 4.4f\tstroke=% 4.3f\tcustom=% 4.3f\n", (double)inputs[INPUT_PRESSURE], (double)inputs[INPUT_SPEED1], (double)inputs[INPUT_SPEED2], (double)inputs[INPUT_STROKE], (double)inputs[INPUT_CUSTOM]); } // FIXME: this one fails!!! //assert(inputs[INPUT_SPEED1] >= 0.0 && inputs[INPUT_SPEED1] < 1e8); // checking for inf for (int i=0; i<BRUSH_SETTINGS_COUNT; i++) { settings_value[i] = settings[i]->calculate (inputs); } { float fac = 1.0 - exp_decay (settings_value[BRUSH_SLOW_TRACKING_PER_DAB], 1.0); states[STATE_ACTUAL_X] += (states[STATE_X] - states[STATE_ACTUAL_X]) * fac; // FIXME: should this depend on base radius? states[STATE_ACTUAL_Y] += (states[STATE_Y] - states[STATE_ACTUAL_Y]) * fac; } { // slow speed float fac; fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED1_SLOWNESS], step_dtime); states[STATE_NORM_SPEED1_SLOW] += (norm_speed - states[STATE_NORM_SPEED1_SLOW]) * fac; fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED2_SLOWNESS], step_dtime); states[STATE_NORM_SPEED2_SLOW] += (norm_speed - states[STATE_NORM_SPEED2_SLOW]) * fac; } { // slow speed, but as vector this time // FIXME: offset_by_speed should be removed. // Is it broken, non-smooth, system-dependent math?! // A replacement could be a directed random offset. float time_constant = exp(settings_value[BRUSH_OFFSET_BY_SPEED_SLOWNESS]*0.01)-1.0; // Workaround for a bug that happens mainly on Windows, causing // individual dabs to be placed far far away. Using the speed // with zero filtering is just asking for trouble anyway. if (time_constant < 0.002) time_constant = 0.002; float fac = 1.0 - exp_decay (time_constant, step_dtime); states[STATE_NORM_DX_SLOW] += (norm_dx - states[STATE_NORM_DX_SLOW]) * fac; states[STATE_NORM_DY_SLOW] += (norm_dy - states[STATE_NORM_DY_SLOW]) * fac; } { // orientation (similar lowpass filter as above, but use dabtime instead of wallclock time) float dx = step_dx / base_radius; float dy = step_dy / base_radius; float step_in_dabtime = hypotf(dx, dy); // FIXME: are we recalculating something here that we already have? float fac = 1.0 - exp_decay (exp(settings_value[BRUSH_DIRECTION_FILTER]*0.5)-1.0, step_in_dabtime); float dx_old = states[STATE_DIRECTION_DX]; float dy_old = states[STATE_DIRECTION_DY]; // use the opposite speed vector if it is closer (we don't care about 180 degree turns) if (SQR(dx_old-dx) + SQR(dy_old-dy) > SQR(dx_old-(-dx)) + SQR(dy_old-(-dy))) { dx = -dx; dy = -dy; } states[STATE_DIRECTION_DX] += (dx - states[STATE_DIRECTION_DX]) * fac; states[STATE_DIRECTION_DY] += (dy - states[STATE_DIRECTION_DY]) * fac; } { // custom input float fac; fac = 1.0 - exp_decay (settings_value[BRUSH_CUSTOM_INPUT_SLOWNESS], 0.1); states[STATE_CUSTOM_INPUT] += (settings_value[BRUSH_CUSTOM_INPUT] - states[STATE_CUSTOM_INPUT]) * fac; } { // stroke length float frequency; float wrap; frequency = expf(-settings_value[BRUSH_STROKE_DURATION_LOGARITHMIC]); states[STATE_STROKE] += norm_dist * frequency; // can happen, probably caused by rounding if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0; wrap = 1.0 + settings_value[BRUSH_STROKE_HOLDTIME]; if (states[STATE_STROKE] > wrap) { if (wrap > 9.9 + 1.0) { // "inifinity", just hold stroke somewhere >= 1.0 states[STATE_STROKE] = 1.0; } else { states[STATE_STROKE] = fmodf(states[STATE_STROKE], wrap); // just in case if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0; } } } // calculate final radius float radius_log; radius_log = settings_value[BRUSH_RADIUS_LOGARITHMIC]; states[STATE_ACTUAL_RADIUS] = expf(radius_log); if (states[STATE_ACTUAL_RADIUS] < ACTUAL_RADIUS_MIN) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MIN; if (states[STATE_ACTUAL_RADIUS] > ACTUAL_RADIUS_MAX) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MAX; // aspect ratio (needs to be caluclated here because it can affect the dab spacing) states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO] = settings_value[BRUSH_ELLIPTICAL_DAB_RATIO]; states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE] = settings_value[BRUSH_ELLIPTICAL_DAB_ANGLE]; }
/** * oil_rand_f64: * @r: a #GRand, representing a random seed * * Returns: a double, in range [0, 1) */ gdouble oil_rand_f64 (GRand *r) { return g_rand_double (r); }
/** * oil_rand_f32: * @r: a #GRand, representing a random seed * * Returns: a float, in range [0, 1) */ gfloat oil_rand_f32 (GRand *r) { return (gfloat) g_rand_double (r); }
/** * crank_bench_run_rand_double: (skip) * @run: A benchmark run. * * Returns random double. * * Returns: A random double. */ gdouble crank_bench_run_rand_double (CrankBenchRun *run) { return g_rand_double (run->random); }
/** * crank_bench_run_rand_float: (skip) * @run: A benchmark run. * * Returns random float. * * Returns: A random float. */ gfloat crank_bench_run_rand_float (CrankBenchRun *run) { return (gfloat) g_rand_double (run->random); }
// This function runs a brush "simulation" step. Usually it is // called once or twice per dab. In theory the precision of the // "simulation" gets better when it is called more often. In // practice this only matters if there are some highly nonlinear // mappings in critical places or extremely few events per second. // // note: parameters are is dx/ddab, ..., dtime/ddab (dab is the number, 5.0 = 5th dab) void update_states_and_setting_values (float step_dx, float step_dy, float step_dpressure, float step_dtime) { float pressure; float inputs[INPUT_COUNT]; if (step_dtime < 0.0) { printf("Time is running backwards!\n"); step_dtime = 0.001; } else if (step_dtime == 0.0) { // FIXME: happens about every 10th start, workaround (against division by zero) step_dtime = 0.001; } states[STATE_X] += step_dx; states[STATE_Y] += step_dy; states[STATE_PRESSURE] += step_dpressure; float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value); // FIXME: does happen (interpolation problem?) states[STATE_PRESSURE] = CLAMP(states[STATE_PRESSURE], 0.0, 1.0); pressure = states[STATE_PRESSURE]; { // start / end stroke (for "stroke" input only) if (!states[STATE_STROKE_STARTED]) { if (pressure > settings[BRUSH_STROKE_THRESHOLD]->base_value + 0.0001) { // start new stroke //printf("stroke start %f\n", pressure); states[STATE_STROKE_STARTED] = 1; states[STATE_STROKE] = 0.0; } } else { if (pressure <= settings[BRUSH_STROKE_THRESHOLD]->base_value * 0.9 + 0.0001) { // end stroke //printf("stroke end\n"); states[STATE_STROKE_STARTED] = 0; } } } // now follows input handling float norm_dx, norm_dy, norm_dist, norm_speed; norm_dx = step_dx / step_dtime / base_radius; norm_dy = step_dy / step_dtime / base_radius; norm_speed = sqrt(SQR(norm_dx) + SQR(norm_dy)); norm_dist = norm_speed * step_dtime; inputs[INPUT_PRESSURE] = pressure; inputs[INPUT_SPEED1] = log(speed_mapping_gamma[0] + states[STATE_NORM_SPEED1_SLOW])*speed_mapping_m[0] + speed_mapping_q[0]; inputs[INPUT_SPEED2] = log(speed_mapping_gamma[1] + states[STATE_NORM_SPEED2_SLOW])*speed_mapping_m[1] + speed_mapping_q[1]; inputs[INPUT_RANDOM] = g_rand_double (rng); inputs[INPUT_STROKE] = MIN(states[STATE_STROKE], 1.0); //if (states[STATE_NORM_DY_SLOW] == 0 && states[STATE_NORM_DX_SLOW] == 0) { //inputs[INPUT_ANGLE] = fmodf(atan2f (states[STATE_NORM_DY_SLOW], states[STATE_NORM_DX_SLOW])/(M_PI) + 1.0, 1.0); inputs[INPUT_CUSTOM] = states[STATE_CUSTOM_INPUT]; if (print_inputs) { g_print("press=% 4.3f, speed1=% 4.4f\tspeed2=% 4.4f\tstroke=% 4.3f\tcustom=% 4.3f\n", (double)inputs[INPUT_PRESSURE], (double)inputs[INPUT_SPEED1], (double)inputs[INPUT_SPEED2], (double)inputs[INPUT_STROKE], (double)inputs[INPUT_CUSTOM]); } // FIXME: this one fails!!! //assert(inputs[INPUT_SPEED1] >= 0.0 && inputs[INPUT_SPEED1] < 1e8); // checking for inf for (int i=0; i<BRUSH_SETTINGS_COUNT; i++) { settings_value[i] = settings[i]->calculate (inputs); } { float fac = 1.0 - exp_decay (settings_value[BRUSH_SLOW_TRACKING_PER_DAB], 1.0); states[STATE_ACTUAL_X] += (states[STATE_X] - states[STATE_ACTUAL_X]) * fac; // FIXME: should this depend on base radius? states[STATE_ACTUAL_Y] += (states[STATE_Y] - states[STATE_ACTUAL_Y]) * fac; } { // slow speed float fac; fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED1_SLOWNESS], step_dtime); states[STATE_NORM_SPEED1_SLOW] += (norm_speed - states[STATE_NORM_SPEED1_SLOW]) * fac; fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED2_SLOWNESS], step_dtime); states[STATE_NORM_SPEED2_SLOW] += (norm_speed - states[STATE_NORM_SPEED2_SLOW]) * fac; } { // slow speed, but as vector this time float fac = 1.0 - exp_decay (exp(settings_value[BRUSH_OFFSET_BY_SPEED_SLOWNESS]*0.01)-1.0, step_dtime); states[STATE_NORM_DX_SLOW] += (norm_dx - states[STATE_NORM_DX_SLOW]) * fac; states[STATE_NORM_DY_SLOW] += (norm_dy - states[STATE_NORM_DY_SLOW]) * fac; } { // custom input float fac; fac = 1.0 - exp_decay (settings_value[BRUSH_CUSTOM_INPUT_SLOWNESS], 0.1); states[STATE_CUSTOM_INPUT] += (settings_value[BRUSH_CUSTOM_INPUT] - states[STATE_CUSTOM_INPUT]) * fac; } { // stroke length float frequency; float wrap; frequency = expf(-settings_value[BRUSH_STROKE_DURATION_LOGARITHMIC]); states[STATE_STROKE] += norm_dist * frequency; // can happen, probably caused by rounding if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0; wrap = 1.0 + settings_value[BRUSH_STROKE_HOLDTIME]; if (states[STATE_STROKE] > wrap) { if (wrap > 9.9 + 1.0) { // "inifinity", just hold stroke somewhere >= 1.0 states[STATE_STROKE] = 1.0; } else { states[STATE_STROKE] = fmodf(states[STATE_STROKE], wrap); // just in case if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0; } } } // calculate final radius float radius_log; radius_log = settings_value[BRUSH_RADIUS_LOGARITHMIC]; states[STATE_ACTUAL_RADIUS] = expf(radius_log); if (states[STATE_ACTUAL_RADIUS] < ACTUAL_RADIUS_MIN) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MIN; if (states[STATE_ACTUAL_RADIUS] > ACTUAL_RADIUS_MAX) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MAX; // aspect ratio (needs to be caluclated here because it can affect the dab spacing) float ratio = settings_value[BRUSH_ELLIPTICAL_DAB_RATIO]; //float angle = atan2(states[STATE_NORM_DY_SLOW], -states[STATE_NORM_DX_SLOW]) / M_PI * 180; float angle = settings_value[BRUSH_ELLIPTICAL_DAB_ANGLE]; states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO] = ratio; states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE] = angle; }