home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / path_curves.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-09  |  9.3 KB  |  329 lines

  1. /* The GIMP -- an image manipulation program
  2.  *
  3.  * This file Copyright (C) 1999 Simon Budig
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. #include <math.h>
  21. #include "path_curves.h"
  22. #include "path_bezier.h"
  23.  
  24. /* only here temporarily */
  25. PathSegment * path_split_segment   (PathSegment *, gdouble);
  26.  
  27. /* Here the different curves register their functions */
  28.  
  29. static CurveDescription CurveTypes[] =
  30.     /* SEGMENT_LINE */
  31.    {
  32.       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  33.     },
  34.  
  35.     /* SEGMENT_BEZIER */
  36.    {
  37.       NULL, /* path_bezier_get_points, */
  38.       path_bezier_get_point,
  39.       path_bezier_draw_handles,
  40.       NULL, /* path_bezier_draw_segment, */
  41.       NULL, /* path_bezier_on_segment, */
  42.       path_bezier_drag_segment,
  43.       path_bezier_on_handles,
  44.       path_bezier_drag_handles, 
  45.       NULL, /* path_bezier_insert_anchor, */
  46.       NULL, /* path_bezier_update_segment, */
  47.       path_bezier_flip_segment,
  48.       path_bezier_init_segment,
  49.       NULL /* path_bezier_cleanup_segment */
  50.     }
  51. };
  52.  
  53.  
  54. /*
  55.  * these functions implement the dispatching for the different
  56.  * curve-types. It implements default actions, which happen
  57.  * to work with straight lines.
  58.  */
  59.  
  60.  
  61. guint
  62. path_curve_get_points (PathTool *path_tool,
  63.                        PathSegment *segment,
  64.                GdkPoint *points,
  65.                guint npoints,
  66.                gdouble start,
  67.                gdouble end)
  68. {
  69.    gdouble pos, x, y;
  70.    gint index=0;
  71.  
  72.    if (segment && segment->next) {
  73.       if (CurveTypes[segment->type].get_points)
  74.      return (* CurveTypes[segment->type].get_points) (path_tool, segment, points, npoints, start, end);
  75.       else {
  76.      if (npoints > 1 && segment && segment->next) {
  77.            for (pos = start; pos <= end; pos += (end - start) / (npoints -1)) {
  78.               path_curve_get_point (path_tool, segment, pos, &x, &y);
  79.               points[index].x = (guint) (x + 0.5);
  80.               points[index].y = (guint) (y + 0.5);
  81.               index++;
  82.            }
  83.            return index;
  84.           } else
  85.                return 0;
  86.       }
  87.    }
  88. #ifdef PATH_TOOL_DEBUG
  89.    else
  90.       fprintf (stderr, "path_curve_get_point called without valid curve");
  91. #endif
  92.    return 0;
  93. }
  94.  
  95.  
  96. void
  97. path_curve_get_point (PathTool *path_tool,
  98.               PathSegment *segment,
  99.               gdouble position,
  100.               gdouble *x,
  101.               gdouble *y)
  102. {
  103.    if (segment && segment->next) {
  104.       if (CurveTypes[segment->type].get_point)
  105.      (* CurveTypes[segment->type].get_point) (path_tool, segment, position, x, y);
  106.       else {
  107. #if 0
  108.      *x = segment->x + (segment->next->x - segment->x) * position;
  109.          *y = segment->y + (segment->next->y - segment->y) * position;
  110. #else
  111.      /* Only here for debugging purposes: A bezier curve fith fixed tangents */
  112.  
  113.      *x = (1-position)*(1-position)*(1-position) * segment->x +
  114.         3 * position *(1-position)*(1-position) * (segment->x - 60) +
  115.         3 * position * position *(1-position) * (segment->next->x + 60) +
  116.         position * position * position * (segment->next->x);
  117.      *y = (1-position)*(1-position)*(1-position) * segment->y +
  118.         3 * position *(1-position)*(1-position) * (segment->y + 60) +
  119.         3 * position * position *(1-position) * (segment->next->y + 60) +
  120.         position * position * position * (segment->next->y);
  121. #endif
  122.       }
  123.    }
  124. #ifdef PATH_TOOL_DEBUG
  125.    else
  126.       fprintf (stderr, "path_curve_get_point called without valid curve");
  127. #endif
  128.    return;
  129. }
  130.  
  131. void
  132. path_curve_draw_handles (Tool *tool,
  133.              PathSegment *segment)
  134. {
  135.    if (segment && CurveTypes[segment->type].draw_handles)
  136.       (* CurveTypes[segment->type].draw_handles) (tool, segment);
  137.  
  138.    /* straight lines do not have handles... */
  139.    return;
  140. }
  141.               
  142. void
  143. path_curve_draw_segment (Tool *tool,
  144.              PathSegment *segment)
  145. {
  146.    gint x, y, numpts, index;
  147.  
  148.    if (segment && segment->next) {
  149.       if (CurveTypes[segment->type].draw_segment) {
  150.          (* CurveTypes[segment->type].draw_segment) (tool, segment);
  151.          return;
  152.       } else {
  153.      GdkPoint *coordinates = g_new (GdkPoint, 100);
  154.          numpts = path_curve_get_points (((PathTool *) tool->private), segment,
  155.                          coordinates, 100, 0, 1);
  156.      for (index=0; index < numpts; index++) {
  157.         gdisplay_transform_coords (tool->gdisp_ptr,
  158.                                coordinates[index].x,
  159.                        coordinates[index].y,
  160.                        &x, &y, FALSE);
  161.         coordinates[index].x = x;
  162.         coordinates[index].y = y;
  163.      }
  164.      gdk_draw_lines (((PathTool *) tool->private)->core->win,
  165.                      ((PathTool *) tool->private)->core->gc,
  166.              coordinates, numpts);
  167.      g_free (coordinates);
  168.       }
  169.  
  170. #ifdef PATH_TOOL_DEBUG
  171.    } else {
  172.       fprintf (stderr, "Fatal Error: path_curve_draw_segment called without valid segment *\n");
  173. #endif
  174.       
  175.    }
  176.  
  177.    return;
  178. }
  179.               
  180.  
  181. gdouble
  182. path_curve_on_segment (Tool *tool,
  183.                PathSegment *segment,
  184.                gint x,
  185.                gint y,
  186.                gint halfwidth,
  187.                gint *distance)
  188. {
  189.  
  190.    if (segment && CurveTypes[segment->type].on_segment)
  191.       return (* CurveTypes[segment->type].on_segment) (tool, segment, x, y, halfwidth, distance);
  192.    else {
  193.       if (segment && segment->next) {
  194. #if 1
  195.      gint x1, y1, numpts, index;
  196.      GdkPoint *coordinates = g_new (GdkPoint, 100);
  197.      gint bestindex = -1;
  198.  
  199.      *distance = halfwidth * halfwidth + 1;
  200.  
  201.          numpts = path_curve_get_points (((PathTool *) tool->private), segment,
  202.                          coordinates, 100, 0, 1);
  203.      for (index=0; index < numpts; index++) {
  204.         x1 = coordinates[index].x;
  205.         y1 = coordinates[index].y;
  206.         if (((x - x1) * (x - x1) + (y - y1) * (y - y1)) < *distance) {
  207.            *distance = (x - x1) * (x - x1) + (y - y1) * (y - y1);
  208.            bestindex = index;
  209.         }
  210.      }
  211.      g_free (coordinates);
  212.      if (numpts == 1) {
  213.         *distance = (gint) sqrt ((gdouble) *distance);
  214.         return bestindex;
  215.      }
  216.      if (bestindex >= 0 && (*distance <= halfwidth * halfwidth)) {
  217.         *distance = (gint) sqrt ((gdouble) *distance);
  218.         return bestindex == 0 ? 0 : ((gdouble) bestindex) / (numpts - 1);
  219.      }
  220.  
  221. #else
  222.  
  223.          /* Special case for lines */
  224.          gdouble Ax, Ay, Bx, By, r, d;
  225.          Ax = segment->x;
  226.          Ay = segment->y;
  227.          Bx = segment->next->x;
  228.          By = segment->next->y;
  229.  
  230.          r = (( x - Ax)*(Bx - Ax) + ( y - Ay)* (By - Ay)) /
  231.              ((Bx - Ax)*(Bx - Ax) + (By - Ay)* (By - Ay)) ;
  232.  
  233.          if (r >= 0 && r <= 1) {
  234.             d = (((Ax + (Bx - Ax) * r) - x) * ((Ax + (Bx - Ax) * r) - x) +
  235.              ((Ay + (By - Ay) * r) - y) * ((Ay + (By - Ay) * r) - y));
  236.         if (d <= halfwidth * halfwidth) {
  237.            *distance = (gint) (d + 0.5);
  238.                return r;
  239.         }
  240.      }
  241. #endif
  242.       }
  243.    }
  244.       
  245.    return -1;
  246. }
  247.  
  248. void
  249. path_curve_drag_segment (PathTool *path_tool,
  250.              PathSegment *segment,
  251.              gdouble position,
  252.              gdouble dx,
  253.              gdouble dy)
  254. {
  255.    if (segment && CurveTypes[segment->type].drag_segment)
  256.       (* CurveTypes[segment->type].drag_segment) (path_tool, segment, position, dx, dy);
  257.    return;
  258. }
  259.  
  260. gint
  261. path_curve_on_handle (PathTool *path_tool,
  262.               PathSegment *segment,
  263.               gdouble x,
  264.               gdouble y,
  265.               gdouble halfwidth)
  266. {
  267.    if (segment && CurveTypes[segment->type].on_handles)
  268.       return (* CurveTypes[segment->type].on_handles) (path_tool, segment, x, y, halfwidth);
  269.    return FALSE;
  270. }
  271.  
  272. void
  273. path_curve_drag_handle (PathTool *path_tool,
  274.             PathSegment *segment,
  275.             gdouble dx,
  276.             gdouble dy,
  277.             gint handle_id)
  278. {
  279.    if (segment && CurveTypes[segment->type].drag_handle)
  280.       (* CurveTypes[segment->type].drag_handle) (path_tool, segment, dx, dy, handle_id);
  281. }
  282.  
  283. PathSegment *
  284. path_curve_insert_anchor (PathTool *path_tool,
  285.               PathSegment *segment,
  286.               gdouble position)
  287. {
  288.    if (segment && CurveTypes[segment->type].insert_anchor)
  289.       return (* CurveTypes[segment->type].insert_anchor) (path_tool, segment, position);
  290.    else {
  291.       return path_split_segment (segment, position);
  292.    }
  293. }
  294.  
  295. void
  296. path_curve_flip_segment (PathSegment *segment)
  297. {
  298.    if (segment && CurveTypes[segment->type].flip_segment)
  299.       (* CurveTypes[segment->type].flip_segment) (segment);
  300.    return;
  301. }
  302.  
  303. void
  304. path_curve_update_segment (PathTool *path_tool,
  305.                PathSegment *segment)
  306. {
  307.    if (segment && CurveTypes[segment->type].update_segment)
  308.       (* CurveTypes[segment->type].update_segment) (path_tool, segment);
  309.    return;
  310. }
  311.  
  312. void
  313. path_curve_init_segment (PathSegment *segment)
  314. {
  315.    if (segment && CurveTypes[segment->type].init_segment)
  316.       (* CurveTypes[segment->type].init_segment) (segment);
  317.    return;
  318. }
  319.  
  320. void
  321. path_curve_cleanup_segment (PathSegment *segment)
  322. {
  323.    if (segment && CurveTypes[segment->type].cleanup_segment)
  324.       (* CurveTypes[segment->type].cleanup_segment) (segment);
  325.    return;
  326. }
  327.  
  328.