The current gimp_rotate procedure does not allow for rotation around an
arbitrary point even though its code is quite capable of it.  It just selects
the center of the image and uses that as the rotation origin.  I added a
gimp_rotate_around_point procedure and use it in all the scripts I'm
writing.  With the new procedure, you only need to select the region you wish
to rotate (just like the interactive rotate tool in the toolbox).  Below I've
included the source code additions I made to tools_cmds.c (I don't know how to
use diff and patch yet).  All I really did was copy the original rotate_invoker
and add X and Y center point parameters to it.  Obviously, the two procedures
could be written to reuse the same invoker code.


-Michael




/*
--Added declaration
*/

static ProcRecord rotate_around_point_proc;




/*
--Added register function call
*/

void
register_tools_procs (void)
{
  ...
  
  procedural_db_register (&rotate_around_point_proc);
  
  ...
}




/*
--Added new invoker
--It just gets its center point from the arguments and sets
--the return arguments to reference the correct PDB proc
*/

static Argument *
rotate_around_point_invoker (Argument *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gboolean interpolation;
  gdouble angle;
  GimpImage *gimage;
  TileManager *float_tiles, *new_tiles;
  gboolean new_layer;
  double cx, cy;
  GimpMatrix3 matrix;

  drawable = gimp_drawable_get_ID (args[0].value.pdb_int);
  if (drawable == NULL)
    success = FALSE;

  interpolation = args[1].value.pdb_int ? TRUE : FALSE;

  angle = args[2].value.pdb_float;

  if (success)
    {
      gimage = drawable_gimage (GIMP_DRAWABLE (drawable));
    
      /* Start a transform undo group */
      undo_push_group_start (gimage, TRANSFORM_CORE_UNDO);
    
      /* Cut/Copy from the specified drawable */
      float_tiles = transform_core_cut (gimage, drawable, &new_layer);

          /* get the center from the arguments passed in */
          cx = args[3].value.pdb_int;
          cy = args[4].value.pdb_int;

#if 0
      cx = float_tiles->x + float_tiles->width / 2.0;
      cy = float_tiles->y + float_tiles->height / 2.0;
#endif

      /* Assemble the transformation matrix */
      gimp_matrix3_identity  (matrix);
      gimp_matrix3_translate (matrix, -cx, -cy);
      gimp_matrix3_rotate    (matrix, angle);
      gimp_matrix3_translate (matrix, +cx, +cy);
    
      /* Rotate the buffer */
      new_tiles = rotate_tool_rotate (gimage, drawable, NULL, angle,
                                      float_tiles, interpolation, matrix);
    
      /* Free the cut/copied buffer */
      tile_manager_destroy (float_tiles);
    
      if (new_tiles)
        success = transform_core_paste (gimage, drawable, new_tiles, new_layer);
      else
        success = FALSE;
    
      /* Push the undo group end */
      undo_push_group_end (gimage);
    }

  return_args = procedural_db_return_args (&rotate_around_point_proc, success);

  if (success)
    return_args[1].value.pdb_int = drawable_ID (GIMP_DRAWABLE (drawable));

  return return_args;
}




/*
--It gets its own input arguments
--Note: I reused the output argments since they are identical.
*/

static ProcArg rotate_around_point_inargs[] =
{
  {
    PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    PDB_INT32,
    "interpolation",
    "Whether to use interpolation"
  },
  {
    PDB_FLOAT,
    "angle",
    "The angle of rotation (radians)"
  },
  {
    PDB_INT32,
    "x",
    "the x coordinate of the point"
  },
  {
    PDB_INT32,
    "y",
    "the y coordinate of the point"
  }
};




/*
--Added the procedure info
*/

static ProcRecord rotate_around_point_proc =
{
  "gimp_rotate_around_point",
  "Rotate the specified drawable about a point through the specified angle.",
  "This tool rotates the specified drawable if no selection exists. If a selection 
exists, the portion of the drawable which lies under the selection is cut from the 
drawable and made into a floating selection which is then rotated by the specified 
amount. The interpolation parameter can be set to TRUE to indicate that either linear 
or cubic interpolation should be used to smooth the resulting rotated drawable. The 
return value is the ID of the rotated drawable. If there was no selection, this will 
be equal to the drawable ID supplied as input. Otherwise, this will be the newly 
created and rotated drawable.",
  "Spencer Kimball & Peter Mattis",
  "Spencer Kimball & Peter Mattis",
  "1995-1996",
  PDB_INTERNAL,
  5,
  rotate_around_point_inargs,
  1,
  rotate_outargs,
  { { rotate_around_point_invoker } }
};

Reply via email to