static GimpBezierDesc *
gimp_brush_transform_boundary_exact (GimpBrush *brush,
                                     gdouble    scale,
                                     gdouble    aspect_ratio,
                                     gdouble    angle,
                                     gdouble    hardness)
{
  const GimpTempBuf *mask;

  mask = gimp_brush_transform_mask (brush, NULL,
                                    scale, aspect_ratio, angle, hardness);

  if (mask)
    {
      GeglBuffer    *buffer;
      GimpBoundSeg  *bound_segs;
      gint           n_bound_segs;

      buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) mask);

      bound_segs = gimp_boundary_find (buffer, NULL,
                                       babl_format ("Y float"),
                                       GIMP_BOUNDARY_WITHIN_BOUNDS,
                                       0, 0,
                                       gegl_buffer_get_width  (buffer),
                                       gegl_buffer_get_height (buffer),
                                       0.0,
                                       &n_bound_segs);

      g_object_unref (buffer);

      if (bound_segs)
        {
          GimpBoundSeg *stroke_segs;
          gint          n_stroke_groups;

          stroke_segs = gimp_boundary_sort (bound_segs, n_bound_segs,
                                            &n_stroke_groups);

          g_free (bound_segs);

          if (stroke_segs)
            {
              GimpBezierDesc *path;

              path = gimp_bezier_desc_new_from_bound_segs (stroke_segs,
                                                           n_bound_segs,
                                                           n_stroke_groups);

              g_free (stroke_segs);

              return path;
            }
        }
    }

  return NULL;
}
示例#2
0
gboolean
gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
                                 GimpDrawable       *drawable,
                                 GimpPaintOptions   *paint_options,
                                 gboolean            emulate_dynamics,
                                 const GimpBoundSeg *bound_segs,
                                 gint                n_bound_segs,
                                 gint                offset_x,
                                 gint                offset_y,
                                 gboolean            push_undo,
                                 GError            **error)
{
  GimpBoundSeg *stroke_segs;
  gint          n_stroke_segs;
  gint          off_x;
  gint          off_y;
  GimpCoords   *coords;
  gboolean      initialized = FALSE;
  gint          n_coords;
  gint          seg;
  gint          s;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
  g_return_val_if_fail (bound_segs != NULL && n_bound_segs > 0, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  stroke_segs = gimp_boundary_sort (bound_segs, n_bound_segs,
                                    &n_stroke_segs);

  if (n_stroke_segs == 0)
    return TRUE;

  gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

  off_x -= offset_x;
  off_y -= offset_y;

  coords = g_new0 (GimpCoords, n_bound_segs + 4);

  seg      = 0;
  n_coords = 0;

  /* we offset all coordinates by 0.5 to align the brush with the path */

  coords[n_coords]   = default_coords;
  coords[n_coords].x = (gdouble) (stroke_segs[0].x1 - off_x + 0.5);
  coords[n_coords].y = (gdouble) (stroke_segs[0].y1 - off_y + 0.5);

  n_coords++;

  for (s = 0; s < n_stroke_segs; s++)
    {
      while (stroke_segs[seg].x1 != -1 ||
             stroke_segs[seg].x2 != -1 ||
             stroke_segs[seg].y1 != -1 ||
             stroke_segs[seg].y2 != -1)
        {
          coords[n_coords]   = default_coords;
          coords[n_coords].x = (gdouble) (stroke_segs[seg].x1 - off_x + 0.5);
          coords[n_coords].y = (gdouble) (stroke_segs[seg].y1 - off_y + 0.5);

          n_coords++;
          seg++;
        }

      /* Close the stroke points up */
      coords[n_coords] = coords[0];

      n_coords++;

      if (emulate_dynamics)
        gimp_paint_core_stroke_emulate_dynamics (coords, n_coords);

      if (initialized ||
          gimp_paint_core_start (core, drawable, paint_options, &coords[0],
                                 error))
        {
          gint i;

          initialized = TRUE;

          core->cur_coords  = coords[0];
          core->last_coords = coords[0];

          gimp_paint_core_paint (core, drawable, paint_options,
                                 GIMP_PAINT_STATE_INIT, 0);

          gimp_paint_core_paint (core, drawable, paint_options,
                                 GIMP_PAINT_STATE_MOTION, 0);

          for (i = 1; i < n_coords; i++)
            {
              gimp_paint_core_interpolate (core, drawable, paint_options,
                                           &coords[i], 0);
            }

          gimp_paint_core_paint (core, drawable, paint_options,
                                 GIMP_PAINT_STATE_FINISH, 0);
        }
      else
        {
          break;
        }

      n_coords = 0;
      seg++;

      coords[n_coords]   = default_coords;
      coords[n_coords].x = (gdouble) (stroke_segs[seg].x1 - off_x + 0.5);
      coords[n_coords].y = (gdouble) (stroke_segs[seg].y1 - off_y + 0.5);

      n_coords++;
    }

  if (initialized)
    {
      gimp_paint_core_finish (core, drawable, push_undo);

      gimp_paint_core_cleanup (core);
    }

  g_free (coords);
  g_free (stroke_segs);

  return initialized;
}