static void update_vector_prev (void) { static gint ok = 0; gint i, x, y; gdouble dir, xo, yo; gdouble val; static gdouble last_val = 0.0; guchar gray[3] = {120, 120, 120}; guchar red[3] = {255, 0, 0}; guchar white[3] = {255, 255, 255}; if (vector_preview_brightness_adjust) val = 1.0 - gtk_adjustment_get_value (GTK_ADJUSTMENT (vector_preview_brightness_adjust)) / 100.0; else val = 0.5; if (!ok || (val != last_val)) { infile_copy_to_ppm (&update_vector_preview_backup); ppm_apply_brightness (&update_vector_preview_backup, val, 1,1,1); if ((update_vector_preview_backup.width != OMWIDTH) || (update_vector_preview_backup.height != OMHEIGHT)) resize_fast (&update_vector_preview_backup, OMWIDTH, OMHEIGHT); ok = 1; } ppm_copy (&update_vector_preview_backup, &update_vector_preview_buffer); for (i = 0; i < num_vectors; i++) { gdouble s; x = vector[i].x * OMWIDTH; y = vector[i].y * OMHEIGHT; dir = gimp_deg_to_rad (vector[i].dir); s = gimp_deg_to_rad (vector[i].str); xo = sin (dir) * (6.0+100*s); yo = cos (dir) * (6.0+100*s); if (i == selectedvector) { ppm_drawline (&update_vector_preview_buffer, x - xo, y - yo, x + xo, y + yo, red); } else { ppm_drawline (&update_vector_preview_buffer, x - xo, y - yo, x + xo, y + yo, gray); } ppm_put_rgb (&update_vector_preview_buffer, x - xo, y - yo, white); } gimp_preview_area_draw (GIMP_PREVIEW_AREA (vector_preview), 0, 0, OMWIDTH, OMHEIGHT, GIMP_RGB_IMAGE, (guchar *)update_vector_preview_buffer.col, OMWIDTH * 3); }
static void angle_adjust_move_callback (GtkWidget *w, gpointer data) { if (adjignore) return; vector[selectedvector].dir = gtk_adjustment_get_value (GTK_ADJUSTMENT (angle_adjust)); vector[selectedvector].dx = sin (gimp_deg_to_rad (vector[selectedvector].dir)); vector[selectedvector].dy = cos (gimp_deg_to_rad (vector[selectedvector].dir)); update_vector_prev (); update_orient_map_preview_prev (); }
static void add_new_vector (gdouble x, gdouble y) { vector[num_vectors].x = x; vector[num_vectors].y = y; vector[num_vectors].dir = 0.0; vector[num_vectors].dx = sin (gimp_deg_to_rad (0.0)); vector[num_vectors].dy = cos (gimp_deg_to_rad (0.0)); vector[num_vectors].str = 1.0; vector[num_vectors].type = 0; selectedvector = num_vectors; num_vectors++; }
static void update_orient_map_preview_prev (void) { int x, y; guchar black[3] = {0, 0, 0}; guchar gray[3] = {120, 120, 120}; guchar white[3] = {255, 255, 255}; if (!PPM_IS_INITED (&update_om_preview_nbuffer)) ppm_new (&update_om_preview_nbuffer,OMWIDTH,OMHEIGHT); fill (&update_om_preview_nbuffer, black); for (y = 6; y < OMHEIGHT-4; y += 10) for (x = 6; x < OMWIDTH-4; x += 10) { double dir = gimp_deg_to_rad (get_direction (x / (double)OMWIDTH, y / (double)OMHEIGHT,0)); double xo = sin (dir) * 4.0; double yo = cos (dir) * 4.0; ppm_drawline (&update_om_preview_nbuffer, x - xo, y - yo, x + xo, y + yo, gray); ppm_put_rgb (&update_om_preview_nbuffer, x - xo, y - yo, white); } gimp_preview_area_draw (GIMP_PREVIEW_AREA (orient_map_preview_prev), 0, 0, OMWIDTH, OMHEIGHT, GIMP_RGB_IMAGE, (guchar *)update_om_preview_nbuffer.col, OMWIDTH * 3); gtk_widget_queue_draw (orient_map_preview_prev); gtk_widget_set_sensitive (prev_button, (num_vectors > 1)); gtk_widget_set_sensitive (next_button, (num_vectors > 1)); gtk_widget_set_sensitive (add_button, (num_vectors < MAXORIENTVECT)); gtk_widget_set_sensitive (kill_button, (num_vectors > 1)); }
static void rotate_angle_changed (GtkAdjustment *adj, GimpTransformTool *tr_tool) { gdouble value = gimp_deg_to_rad (gtk_adjustment_get_value (adj)); #define ANGLE_EPSILON 0.0001 if (ABS (value - tr_tool->trans_info[ANGLE]) > ANGLE_EPSILON) { gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool)); tr_tool->trans_info[REAL_ANGLE] = tr_tool->trans_info[ANGLE] = value; gimp_transform_tool_push_internal_undo (tr_tool); gimp_transform_tool_recalc_matrix (tr_tool); gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool)); } #undef ANGLE_EPSILON }
static void mblur_radial (GimpDrawable *drawable, GimpPreview *preview, gint x1, gint y1, gint width, gint height) { GimpPixelRgn dest_rgn; GimpPixelFetcher *pft; gpointer pr; GimpRGB background; gdouble center_x; gdouble center_y; guchar *dest; guchar *d; guchar pixel[4]; guchar p1[4], p2[4], p3[4], p4[4]; gint32 sum[4]; gint progress, max_progress, c; gint x, y, i, p, n, count; gdouble angle, theta, r, xx, yy, xr, yr; gdouble phi, phi_start, s_val, c_val; gdouble dx, dy; /* initialize */ xx = 0.0; yy = 0.0; center_x = mbvals.center_x; center_y = mbvals.center_y; gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_context_get_background (&background); gimp_pixel_fetcher_set_bg_color (pft, &background); progress = 0; max_progress = width * height; angle = gimp_deg_to_rad (mbvals.angle); for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0; pr != NULL; pr = gimp_pixel_rgns_process (pr), p++) { dest = dest_rgn.data; for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++) { d = dest; for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++) { xr = (gdouble) x - center_x; yr = (gdouble) y - center_y; r = sqrt (SQR (xr) + SQR (yr)); n = r * angle; if (angle == 0.0) { gimp_pixel_fetcher_get_pixel (pft, x, y, d); d += dest_rgn.bpp; continue; } /* ensure quality with small angles */ if (n < 3) n = 3; /* always use at least 3 (interpolation) steps */ /* limit loop count due to performanc reasons */ if (n > 100) n = 100 + sqrt (n-100); if (xr != 0.0) { phi = atan(yr/xr); if (xr < 0.0) phi = G_PI + phi; } else { if (yr >= 0.0) phi = G_PI_2; else phi = -G_PI_2; } for (c = 0; c < img_bpp; c++) sum[c] = 0; if (n == 1) phi_start = phi; else phi_start = phi + angle/2.0; theta = angle / (gdouble)n; count = 0; for (i = 0; i < n; i++) { s_val = sin (phi_start - (gdouble) i * theta); c_val = cos (phi_start - (gdouble) i * theta); xx = center_x + r * c_val; yy = center_y + r * s_val; if ((yy < y1) || (yy >= y1 + height) || (xx < x1) || (xx >= x1 + width)) continue; ++count; if ((xx + 1 < x1 + width) && (yy + 1 < y1 + height)) { dx = xx - floor (xx); dy = yy - floor (yy); gimp_pixel_fetcher_get_pixel (pft, xx, yy, p1); gimp_pixel_fetcher_get_pixel (pft, xx+1, yy, p2); gimp_pixel_fetcher_get_pixel (pft, xx, yy+1, p3); gimp_pixel_fetcher_get_pixel (pft, xx+1, yy+1, p4); for (c = 0; c < img_bpp; c++) { pixel[c] = (((gdouble) p1[c] * (1.0-dx) + (gdouble) p2[c] * dx) * (1.0-dy) + ((gdouble) p3[c] * (1.0-dx) + (gdouble) p4[c] * dx) * dy); } } else { gimp_pixel_fetcher_get_pixel (pft, xx+.5, yy+.5, pixel); } if (has_alpha) { gint32 alpha = pixel[img_bpp-1]; sum[img_bpp-1] += alpha; for (c = 0; c < img_bpp-1; c++) sum[c] += pixel[c] * alpha; } else { for (c = 0; c < img_bpp; c++) sum[c] += pixel[c]; } } if (count == 0) { gimp_pixel_fetcher_get_pixel (pft, xx, yy, d); } else { if (has_alpha) { gint32 alpha = sum[img_bpp-1]; if ((d[img_bpp-1] = alpha/count) != 0) { for (c = 0; c < img_bpp-1; c++) d[c] = sum[c] / alpha; } } else { for (c = 0; c < img_bpp; c++) d[c] = sum[c] / count; } } d += dest_rgn.bpp; } dest += dest_rgn.rowstride; } if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += dest_rgn.w * dest_rgn.h; if ((p % 8) == 0) gimp_progress_update ((gdouble) progress / max_progress); } } gimp_pixel_fetcher_destroy (pft); }
static void gimp_brush_generated_dirty (GimpBrushGenerated *brush) { gint x, y; guchar *centerp; double d; double exponent; guchar a; gint length; gint width = 0; gint height = 0; guchar *lookup; double sum; double c, s, cs, ss; double short_radius; double buffer[OVERSAMPLING]; s = sin (gimp_deg_to_rad (brush->angle)); c = cos (gimp_deg_to_rad (brush->angle)); short_radius = brush->radius / brush->aspect_ratio; brush->x_axis.x = c * brush->radius; brush->x_axis.y = -1.0 * s * brush->radius; brush->y_axis.x = s * short_radius; brush->y_axis.y = c * short_radius; switch (brush->shape) { case BRUSH_SHAPE_CIRCLE: width = static_cast<int>(ceil (sqrt (brush->x_axis.x * brush->x_axis.x + brush->y_axis.x * brush->y_axis.x))); height = static_cast<int>(ceil (sqrt (brush->x_axis.y * brush->x_axis.y + brush->y_axis.y * brush->y_axis.y))); break; case BRUSH_SHAPE_SQUARE: width = static_cast<int>(ceil (fabs (brush->x_axis.x) + fabs (brush->y_axis.x))); height = static_cast<int>(ceil (fabs (brush->x_axis.y) + fabs (brush->y_axis.y))); break; case BRUSH_SHAPE_DIAMOND: width = static_cast<int>(ceil (std::max(fabs (brush->x_axis.x), fabs (brush->y_axis.x)))); height = static_cast<int>(ceil (std::max(fabs (brush->x_axis.y), fabs (brush->y_axis.y)))); break; default: return; } if (brush->spikes > 2) { /* could be optimized by respecting the angle */ width = height = static_cast<int>(ceil (sqrt (brush->radius * brush->radius + short_radius * short_radius))); brush->y_axis.x = s * brush->radius; brush->y_axis.y = c * brush->radius; } brush->mask = new GrayscaleBuffer(width * 2 + 1, height * 2 + 1, 0); centerp = brush->mask->get_data() + height * brush->mask->get_width() + width; /* set up lookup table */ length = static_cast<int>(OVERSAMPLING * ceil (1 + sqrt (2 * ceil (brush->radius + 1.0) * ceil (brush->radius + 1.0)))); if ((1.0 - brush->hardness) < 0.0000004) exponent = 1000000.0; else exponent = 0.4 / (1.0 - brush->hardness); lookup = new guchar[length]; sum = 0.0; for (x = 0; x < OVERSAMPLING; x++) { d = fabs ((x + 0.5) / OVERSAMPLING - 0.5); if (d > brush->radius) buffer[x] = 0.0; else buffer[x] = gauss (pow (d / brush->radius, exponent)); sum += buffer[x]; } for (x = 0; d < brush->radius || sum > 0.00001; d += 1.0 / OVERSAMPLING) { sum -= buffer[x % OVERSAMPLING]; if (d > brush->radius) buffer[x % OVERSAMPLING] = 0.0; else buffer[x % OVERSAMPLING] = gauss (pow (d / brush->radius, exponent)); sum += buffer[x % OVERSAMPLING]; lookup[x++] = static_cast<int>(rint(sum * (255.0 / OVERSAMPLING))); } while (x < length) { lookup[x++] = 0; } cs = cos (- 2 * M_PI / brush->spikes); ss = sin (- 2 * M_PI / brush->spikes); /* for an even number of spikes compute one half and mirror it */ for (y = (brush->spikes % 2 ? -height : 0); y <= height; y++) { for (x = -width; x <= width; x++) { double tx, ty, angle; tx = c*x - s*y; ty = fabs (s*x + c*y); if (brush->spikes > 2) { angle = atan2 (ty, tx); while (angle > M_PI / brush->spikes) { double sx = tx, sy = ty; tx = cs * sx - ss * sy; ty = ss * sx + cs * sy; angle -= 2 * M_PI / brush->spikes; } } ty *= brush->aspect_ratio; switch (brush->shape) { case BRUSH_SHAPE_CIRCLE: d = sqrt (tx*tx + ty*ty); break; case BRUSH_SHAPE_SQUARE: d = std::max (fabs (tx), fabs (ty)); break; case BRUSH_SHAPE_DIAMOND: d = fabs (tx) + fabs (ty); break; } if (d < brush->radius + 1) a = lookup[(gint) rint (d * OVERSAMPLING)]; else a = 0; centerp[ y * brush->mask->get_width() + x] = a; if (brush->spikes % 2 == 0) centerp[-1 * y * brush->mask->get_width() - x] = a; } } delete lookup; }
static GimpBlob * ink_pen_ellipse (GimpInkOptions *options, gdouble x_center, gdouble y_center, gdouble pressure, gdouble xtilt, gdouble ytilt, gdouble velocity) { GimpBlobFunc blob_function; gdouble size; gdouble tsin, tcos; gdouble aspect, radmin; gdouble x,y; gdouble tscale; gdouble tscale_c; gdouble tscale_s; /* Adjust the size depending on pressure. */ size = options->size * (1.0 + options->size_sensitivity * (2.0 * pressure - 1.0)); /* Adjust the size further depending on pointer velocity and * velocity-sensitivity. These 'magic constants' are 'feels * natural' tigert-approved. --ADM */ if (velocity < 3.0) velocity = 3.0; #ifdef VERBOSE g_printerr ("%g (%g) -> ", size, velocity); #endif size = (options->vel_sensitivity * ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity))) + (1.0 - options->vel_sensitivity) * size); #ifdef VERBOSE g_printerr ("%g\n", (gfloat) size); #endif /* Clamp resulting size to sane limits */ if (size > options->size * (1.0 + options->size_sensitivity)) size = options->size * (1.0 + options->size_sensitivity); if (size * SUBSAMPLE < 1.0) size = 1.0 / SUBSAMPLE; /* Add brush angle/aspect to tilt vectorially */ /* I'm not happy with the way the brush widget info is combined with * tilt info from the brush. My personal feeling is that * representing both as affine transforms would make the most * sense. -RLL */ tscale = options->tilt_sensitivity * 10.0; tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle)); tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle)); x = (options->blob_aspect * cos (options->blob_angle) + xtilt * tscale_c - ytilt * tscale_s); y = (options->blob_aspect * sin (options->blob_angle) + ytilt * tscale_c + xtilt * tscale_s); #ifdef VERBOSE g_printerr ("angle %g aspect %g; %g %g; %g %g\n", options->blob_angle, options->blob_aspect, tscale_c, tscale_s, x, y); #endif aspect = sqrt (SQR (x) + SQR (y)); if (aspect != 0) { tcos = x / aspect; tsin = y / aspect; } else { tsin = sin (options->blob_angle); tcos = cos (options->blob_angle); } aspect = CLAMP (aspect, 1.0, 10.0); radmin = MAX (1.0, SUBSAMPLE * size / aspect); switch (options->blob_type) { case GIMP_INK_BLOB_TYPE_CIRCLE: blob_function = gimp_blob_ellipse; break; case GIMP_INK_BLOB_TYPE_SQUARE: blob_function = gimp_blob_square; break; case GIMP_INK_BLOB_TYPE_DIAMOND: blob_function = gimp_blob_diamond; break; default: g_return_val_if_reached (NULL); break; } return (* blob_function) (x_center * SUBSAMPLE, y_center * SUBSAMPLE, radmin * aspect * tcos, radmin * aspect * tsin, -radmin * tsin, radmin * tcos); }
/* This function is shared between gimp_brush_generated_scale_size and * gimp_brush_generated_calc, therefore we provide a bunch of optional * pointers for returnvalues. */ static void gimp_brush_generated_get_half_size (GimpBrushGenerated *gbrush, GimpBrushGeneratedShape shape, gfloat radius, gint spikes, gfloat hardness, gfloat aspect_ratio, gdouble angle_in_degrees, gint *half_width, gint *half_height, gdouble *_s, gdouble *_c, GimpVector2 *_x_axis, GimpVector2 *_y_axis) { gdouble c, s; gdouble short_radius; GimpVector2 x_axis; GimpVector2 y_axis; s = sin (gimp_deg_to_rad (angle_in_degrees)); c = cos (gimp_deg_to_rad (angle_in_degrees)); short_radius = radius / aspect_ratio; x_axis.x = c * radius; x_axis.y = -1.0 * s * radius; y_axis.x = s * short_radius; y_axis.y = c * short_radius; switch (shape) { case GIMP_BRUSH_GENERATED_CIRCLE: *half_width = ceil (sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x)); *half_height = ceil (sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y)); break; case GIMP_BRUSH_GENERATED_SQUARE: *half_width = ceil (fabs (x_axis.x) + fabs (y_axis.x)); *half_height = ceil (fabs (x_axis.y) + fabs (y_axis.y)); break; case GIMP_BRUSH_GENERATED_DIAMOND: *half_width = ceil (MAX (fabs (x_axis.x), fabs (y_axis.x))); *half_height = ceil (MAX (fabs (x_axis.y), fabs (y_axis.y))); break; } if (spikes > 2) { /* could be optimized by respecting the angle */ *half_width = *half_height = ceil (sqrt (radius * radius + short_radius * short_radius)); y_axis.x = s * radius; y_axis.y = c * radius; } /* These will typically be set then this function is called by * gimp_brush_generated_calc, which needs the values in its algorithms. */ if (_s != NULL) *_s = s; if (_c != NULL) *_c = c; if (_x_axis != NULL) *_x_axis = x_axis; if (_y_axis != NULL) *_y_axis = y_axis; }
static void draw_wireframe_sphere (gint startx, gint starty, gint pw, gint ph) { GimpVector3 p[2 * (WIRESIZE + 5)]; gint cnt, cnt2, n = 0; gdouble x1, y1, x2, y2, twopifac, cx1, cy1, cx2, cy2; /* Compute wireframe points */ /* ======================== */ twopifac = (2.0 * G_PI) / WIRESIZE; for (cnt = 0; cnt < WIRESIZE; cnt++) { p[cnt].x = mapvals.radius * cos ((gdouble) cnt * twopifac); p[cnt].y = 0.0; p[cnt].z = mapvals.radius * sin ((gdouble) cnt * twopifac); gimp_vector3_rotate (&p[cnt], gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position); } p[cnt] = p[0]; for (cnt = WIRESIZE + 1; cnt < 2 * WIRESIZE + 1; cnt++) { p[cnt].x = mapvals.radius * cos ((gdouble) (cnt-(WIRESIZE+1))*twopifac); p[cnt].y = mapvals.radius * sin ((gdouble) (cnt-(WIRESIZE+1))*twopifac); p[cnt].z = 0.0; gimp_vector3_rotate (&p[cnt], gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position); } p[cnt] = p[WIRESIZE+1]; cnt++; cnt2 = cnt; /* Find rotated axis */ /* ================= */ gimp_vector3_set (&p[cnt], 0.0, -0.35, 0.0); gimp_vector3_rotate (&p[cnt], gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); p[cnt+1] = mapvals.position; gimp_vector3_set (&p[cnt+2], 0.0, 0.0, -0.35); gimp_vector3_rotate (&p[cnt+2], gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); p[cnt+3] = mapvals.position; p[cnt + 4] = p[cnt]; gimp_vector3_mul (&p[cnt + 4], -1.0); p[cnt + 5] = p[cnt + 1]; gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position); gimp_vector3_add (&p[cnt + 2], &p[cnt + 2], &mapvals.position); gimp_vector3_add (&p[cnt + 4], &p[cnt + 4], &mapvals.position); /* Draw the circles (equator and zero meridian) */ /* ============================================ */ cx1 = (gdouble) startx; cy1 = (gdouble) starty; cx2 = cx1 + (gdouble) pw; cy2 = cy1 + (gdouble) ph; for (cnt = 0; cnt < cnt2 - 1; cnt++) { if (p[cnt].z > mapvals.position.z && p[cnt + 1].z > mapvals.position.z) { gimp_vector_3d_to_2d (startx, starty, pw, ph, &x1, &y1, &mapvals.viewpoint, &p[cnt]); gimp_vector_3d_to_2d (startx, starty, pw, ph, &x2, &y2, &mapvals.viewpoint, &p[cnt + 1]); if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE) { linetab[n].x1 = (gint) (x1 + 0.5); linetab[n].y1 = (gint) (y1 + 0.5); linetab[n].x2 = (gint) (x2 + 0.5); linetab[n].y2 = (gint) (y2 + 0.5); linetab[n].linewidth = 3; linetab[n].linestyle = GDK_LINE_SOLID; gdk_gc_set_line_attributes (gc, linetab[n].linewidth, linetab[n].linestyle, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); gdk_draw_line (previewarea->window, gc, linetab[n].x1, linetab[n].y1, linetab[n].x2, linetab[n].y2); n++; } } } /* Draw the axis (pole to pole and center to zero meridian) */ /* ======================================================== */ for (cnt = 0; cnt < 3; cnt++) { gimp_vector_3d_to_2d (startx, starty, pw, ph, &x1, &y1, &mapvals.viewpoint, &p[cnt2]); gimp_vector_3d_to_2d (startx, starty, pw, ph, &x2, &y2, &mapvals.viewpoint, &p[cnt2 + 1]); if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE) { linetab[n].x1 = RINT (x1); linetab[n].y1 = RINT (y1); linetab[n].x2 = RINT (x2); linetab[n].y2 = RINT (y2); if (p[cnt2].z < mapvals.position.z || p[cnt2+1].z < mapvals.position.z) { linetab[n].linewidth = 1; linetab[n].linestyle = GDK_LINE_DOUBLE_DASH; } else { linetab[n].linewidth = 3; linetab[n].linestyle = GDK_LINE_SOLID; } gdk_gc_set_line_attributes (gc, linetab[n].linewidth, linetab[n].linestyle, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); gdk_draw_line (previewarea->window, gc, linetab[n].x1, linetab[n].y1, linetab[n].x2, linetab[n].y2); n++; } cnt2 += 2; } /* Mark end of lines */ /* ================= */ linetab[n].x1 = -1; }
static void draw_wireframe_plane (gint startx, gint starty, gint pw, gint ph) { GimpVector3 v1, v2, a, b, c, d, dir1, dir2; gint cnt, n = 0; gdouble x1, y1, x2, y2, cx1, cy1, cx2, cy2, fac; /* Find rotated box corners */ /* ======================== */ gimp_vector3_set (&v1, 0.5, 0.0, 0.0); gimp_vector3_set (&v2, 0.0, 0.5, 0.0); gimp_vector3_rotate (&v1, gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); gimp_vector3_rotate (&v2, gimp_deg_to_rad (mapvals.alpha), gimp_deg_to_rad (mapvals.beta), gimp_deg_to_rad (mapvals.gamma)); dir1 = v1; gimp_vector3_normalize (&dir1); dir2 = v2; gimp_vector3_normalize (&dir2); fac = 1.0 / (gdouble) WIRESIZE; gimp_vector3_mul (&dir1, fac); gimp_vector3_mul (&dir2, fac); gimp_vector3_add (&a, &mapvals.position, &v1); gimp_vector3_sub (&b, &a, &v2); gimp_vector3_add (&a, &a, &v2); gimp_vector3_sub (&d, &mapvals.position, &v1); gimp_vector3_sub (&d, &d, &v2); c = b; cx1 = (gdouble) startx; cy1 = (gdouble) starty; cx2 = cx1 + (gdouble) pw; cy2 = cy1 + (gdouble) ph; for (cnt = 0; cnt <= WIRESIZE; cnt++) { gimp_vector_3d_to_2d (startx, starty, pw, ph, &x1, &y1, &mapvals.viewpoint, &a); gimp_vector_3d_to_2d (startx, starty, pw, ph, &x2, &y2, &mapvals.viewpoint, &b); if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE) { linetab[n].x1 = RINT (x1); linetab[n].y1 = RINT (y1); linetab[n].x2 = RINT (x2); linetab[n].y2 = RINT (y2); linetab[n].linewidth = 1; linetab[n].linestyle = GDK_LINE_SOLID; gdk_gc_set_line_attributes (gc, linetab[n].linewidth, linetab[n].linestyle, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); gdk_draw_line (previewarea->window, gc, linetab[n].x1, linetab[n].y1, linetab[n].x2, linetab[n].y2); n++; } gimp_vector_3d_to_2d (startx, starty, pw, ph, &x1, &y1, &mapvals.viewpoint, &c); gimp_vector_3d_to_2d (startx, starty, pw, ph, &x2, &y2, &mapvals.viewpoint, &d); if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE) { linetab[n].x1 = RINT (x1); linetab[n].y1 = RINT (y1); linetab[n].x2 = RINT (x2); linetab[n].y2 = RINT (y2); linetab[n].linewidth = 1; linetab[n].linestyle = GDK_LINE_SOLID; gdk_gc_set_line_attributes (gc, linetab[n].linewidth, linetab[n].linestyle, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); gdk_draw_line (previewarea->window, gc, linetab[n].x1, linetab[n].y1, linetab[n].x2, linetab[n].y2); n++; } gimp_vector3_sub (&a, &a, &dir1); gimp_vector3_sub (&b, &b, &dir1); gimp_vector3_add (&c, &c, &dir2); gimp_vector3_add (&d, &d, &dir2); } /* Mark end of lines */ /* ================= */ linetab[n].x1 = -1; }
/* --------------------------------- * gap_colordiff_LabDeltaE2000 * --------------------------------- * uses algortihm found at http://colormine.org/delta-e-calculator/cie2000 * based on L*a*b Colorspace. * returns deltaE scaled down to a range of 0.0 to 1.0 */ gdouble gap_colordiff_LabDeltaE2000(guchar *aPixelPtr , guchar *bPixelPtr , gboolean debugPrint ) { //Set weighting factors to 1 gdouble k_L = 1.0; gdouble k_C = 1.0; gdouble k_H = 1.0; GapColorLAB lab1; GapColorLAB lab2; //Change Color Space to L*a*b: p_convert_rgb8_to_Lab(aPixelPtr, &lab1); p_convert_rgb8_to_Lab(bPixelPtr, &lab2); //Calculate Cprime1, Cprime2, Cabbar gdouble c_star_1_ab = sqrt(lab1.A * lab1.A + lab1.B * lab1.B); gdouble c_star_2_ab = sqrt(lab2.A * lab2.A + lab2.B * lab2.B); gdouble c_star_average_ab = (c_star_1_ab + c_star_2_ab) / 2; gdouble c_star_average_ab_pot7 = c_star_average_ab * c_star_average_ab * c_star_average_ab; c_star_average_ab_pot7 *= c_star_average_ab_pot7 * c_star_average_ab; gdouble G = 0.5 * (1 - sqrt(c_star_average_ab_pot7 / (c_star_average_ab_pot7 + 6103515625))); //25^7 gdouble a1_prime = (1 + G) * lab1.A; gdouble a2_prime = (1 + G) * lab2.A; gdouble C_prime_1 = sqrt(a1_prime * a1_prime + lab1.B * lab1.B); gdouble C_prime_2 = sqrt(a2_prime * a2_prime + lab2.B * lab2.B); //Angles in Degree. gdouble h_prime_1 = (int)rint(gimp_rad_to_deg(atan2(lab1.B, a1_prime)) + 360) % 360; gdouble h_prime_2 = (int)rint(gimp_rad_to_deg(atan2(lab2.B, a2_prime)) + 360) % 360; gdouble delta_L_prime = lab2.L - lab1.L; gdouble delta_C_prime = C_prime_2 - C_prime_1; gdouble h_bar = abs(h_prime_1 - h_prime_2); gdouble delta_h_prime; if (C_prime_1 * C_prime_2 == 0) delta_h_prime = 0; else { if (h_bar <= 180.0) { delta_h_prime = h_prime_2 - h_prime_1; } else if (h_bar > 180.0 && h_prime_2 <= h_prime_1) { delta_h_prime = h_prime_2 - h_prime_1 + 360.0; } else { delta_h_prime = h_prime_2 - h_prime_1 - 360.0; } } gdouble delta_H_prime = 2 * sqrt(C_prime_1 * C_prime_2) * sin(gimp_deg_to_rad(delta_h_prime / 2)); // Calculate CIEDE2000 gdouble L_prime_average = (lab1.L + lab2.L) / 2.0; gdouble C_prime_average = (C_prime_1 + C_prime_2) / 2.0; //Calculate h_prime_average gdouble h_prime_average; if (C_prime_1 * C_prime_2 == 0) h_prime_average = 0; else { if (h_bar <= 180.0) { h_prime_average = (h_prime_1 + h_prime_2) / 2; } else if (h_bar > 180.0 && (h_prime_1 + h_prime_2) < 360.0) { h_prime_average = (h_prime_1 + h_prime_2 + 360.0) / 2; } else { h_prime_average = (h_prime_1 + h_prime_2 - 360.0) / 2; } } gdouble L_prime_average_minus_50_square = (L_prime_average - 50); L_prime_average_minus_50_square *= L_prime_average_minus_50_square; gdouble S_L = 1 + ((.015d * L_prime_average_minus_50_square) / sqrt(20 + L_prime_average_minus_50_square)); gdouble S_C = 1 + .045d * C_prime_average; gdouble T = 1 - .17 * cos(gimp_deg_to_rad(h_prime_average - 30)) + .24 * cos(gimp_deg_to_rad(h_prime_average * 2)) + .32 * cos(gimp_deg_to_rad(h_prime_average * 3 + 6)) - .2 * cos(gimp_deg_to_rad(h_prime_average * 4 - 63)); gdouble S_H = 1 + .015 * T * C_prime_average; gdouble h_prime_average_minus_275_div_25_square = (h_prime_average - 275) / (25); h_prime_average_minus_275_div_25_square *= h_prime_average_minus_275_div_25_square; gdouble delta_theta = 30 * exp(-h_prime_average_minus_275_div_25_square); gdouble C_prime_average_pot_7 = C_prime_average * C_prime_average * C_prime_average; C_prime_average_pot_7 *= C_prime_average_pot_7 * C_prime_average; gdouble R_C = 2 * sqrt(C_prime_average_pot_7 / (C_prime_average_pot_7 + 6103515625)); gdouble R_T = -sin(gimp_deg_to_rad(2 * delta_theta)) * R_C; gdouble delta_L_prime_div_k_L_S_L = delta_L_prime / (S_L * k_L); gdouble delta_C_prime_div_k_C_S_C = delta_C_prime / (S_C * k_C); gdouble delta_H_prime_div_k_H_S_H = delta_H_prime / (S_H * k_H); gdouble CIEDE2000 = sqrt( delta_L_prime_div_k_L_S_L * delta_L_prime_div_k_L_S_L + delta_C_prime_div_k_C_S_C * delta_C_prime_div_k_C_S_C + delta_H_prime_div_k_H_S_H * delta_H_prime_div_k_H_S_H + R_T * delta_C_prime_div_k_C_S_C * delta_H_prime_div_k_H_S_H ); gdouble colorDiff = CIEDE2000 / 100.0; /* normalize range [from 0.0 to 100.0] ==> [from 0.0 to 1.0] */ if(debugPrint) { printf("L*a*b (%.3f, %.3f, %.3f) rgb 1/2 (%03d %03d %03d) / (%03d %03d %03d) CIEDE2000:%f colorDiff:%f\n" , lab1.L , lab1.A , lab1.B , (int)(aPixelPtr[0]) , (int)(aPixelPtr[1]) , (int)(aPixelPtr[2]) , (int)(bPixelPtr[0]) , (int)(bPixelPtr[1]) , (int)(bPixelPtr[2]) , CIEDE2000 , colorDiff ); } return (colorDiff); } /* end gap_colordiff_LabDeltaE2000 */
/* This function is shared between gimp_brush_generated_transform_size and * gimp_brush_generated_calc, therefore we provide a bunch of optional * pointers for returnvalues. */ static void gimp_brush_generated_get_size (GimpBrushGenerated *gbrush, GimpBrushGeneratedShape shape, gfloat radius, gint spikes, gfloat hardness, gfloat aspect_ratio, gdouble angle_in_degrees, gint *width, gint *height, gdouble *_s, gdouble *_c, GimpVector2 *_x_axis, GimpVector2 *_y_axis) { gdouble half_width = 0.0; gdouble half_height = 0.0; gint w, h; gdouble c, s; gdouble short_radius; GimpVector2 x_axis; GimpVector2 y_axis; /* Since floatongpoint is not really accurate, * we need to round to limit the errors. * Errors in some border cases resulted in * different height and width reported for * the same input value on calling procedure side. * This became problem at the rise of dynamics that * allows for any angle to turn up. **/ angle_in_degrees = ROUND (angle_in_degrees * 1000.0) / 1000.0; s = sin (gimp_deg_to_rad (angle_in_degrees)); c = cos (gimp_deg_to_rad (angle_in_degrees)); short_radius = radius / aspect_ratio; x_axis.x = c * radius; x_axis.y = -1.0 * s * radius; y_axis.x = s * short_radius; y_axis.y = c * short_radius; switch (shape) { case GIMP_BRUSH_GENERATED_CIRCLE: half_width = sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x); half_height = sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y); break; case GIMP_BRUSH_GENERATED_SQUARE: half_width = fabs (x_axis.x) + fabs (y_axis.x); half_height = fabs (x_axis.y) + fabs (y_axis.y); break; case GIMP_BRUSH_GENERATED_DIAMOND: half_width = MAX (fabs (x_axis.x), fabs (y_axis.x)); half_height = MAX (fabs (x_axis.y), fabs (y_axis.y)); break; } if (spikes > 2) { /* could be optimized by respecting the angle */ half_width = half_height = sqrt (radius * radius + short_radius * short_radius); y_axis.x = s * radius; y_axis.y = c * radius; } w = MAX (1, ceil (half_width * 2)); h = MAX (1, ceil (half_height * 2)); if (! (w & 0x1)) w++; if (! (h & 0x1)) h++; *width = w; *height = h; /* These will typically be set then this function is called by * gimp_brush_generated_calc, which needs the values in its algorithms. */ if (_s != NULL) *_s = s; if (_c != NULL) *_c = c; if (_x_axis != NULL) *_x_axis = x_axis; if (_y_axis != NULL) *_y_axis = y_axis; }