home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xfig / part05 / d_intspline.c next >
Encoding:
C/C++ Source or Header  |  1993-05-27  |  7.0 KB  |  291 lines

  1. /*
  2.  * FIG : Facility for Interactive Generation of figures
  3.  * Copyright (c) 1985 by Supoj Sutanthavibul
  4.  *
  5.  * "Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both the copyright
  8.  * notice and this permission notice appear in supporting documentation. 
  9.  * No representations are made about the suitability of this software for 
  10.  * any purpose.  It is provided "as is" without express or implied warranty."
  11.  */
  12.  
  13. #include "fig.h"
  14. #include "resources.h"
  15. #include "mode.h"
  16. #include "object.h"
  17. #include "paintop.h"
  18. #include "u_create.h"
  19. #include "u_elastic.h"
  20. #include "u_list.h"
  21. #include "w_canvas.h"
  22. #include "w_mousefun.h"
  23.  
  24. static int    create_intsplineobject();
  25. static int    init_intspline_drawing();
  26.  
  27. intspline_drawing_selected()
  28. {
  29.     set_mousefun("first point", "", "");
  30.     canvas_kbd_proc = null_proc;
  31.     canvas_locmove_proc = null_proc;
  32.     canvas_leftbut_proc = init_intspline_drawing;
  33.     canvas_middlebut_proc = null_proc;
  34.     canvas_rightbut_proc = null_proc;
  35.     set_cursor(arrow_cursor);
  36.     reset_action_on();
  37. }
  38.  
  39. static
  40. init_intspline_drawing(x, y)
  41.     int            x, y;
  42. {
  43.     min_num_points = 3;
  44.     init_trace_drawing(x, y);
  45.     canvas_middlebut_save = create_intsplineobject;
  46.     return_proc = intspline_drawing_selected;
  47. }
  48.  
  49. static
  50. create_intsplineobject(x, y)
  51.     int            x, y;
  52. {
  53.     F_spline       *spline;
  54.  
  55.     if (x != fix_x || y != fix_y || num_point < min_num_points) {
  56.     get_intermediatepoint(x, y);
  57.     }
  58.     elastic_line();
  59.     if ((spline = create_spline()) == NULL) {
  60.     if (num_point == 1) {
  61.         free((char *) cur_point);
  62.         cur_point = NULL;
  63.     }
  64.     free((char *) first_point);
  65.     first_point = NULL;
  66.     return;
  67.     }
  68.     spline->style = cur_linestyle;
  69.     spline->thickness = cur_linewidth;
  70.     spline->style_val = cur_styleval * (cur_linewidth + 1) / 2;
  71.     spline->color = cur_color;
  72.     spline->depth = cur_depth;
  73.     spline->fill_style = cur_fillstyle;
  74.     /*
  75.      * The current fill style is saved in all intspline objects (but support
  76.      * for filling may not be available in all fig2dev languages).
  77.      */
  78.     spline->pen = 0;
  79.     spline->points = first_point;
  80.     spline->controls = NULL;
  81.     spline->next = NULL;
  82.     cur_x = cur_y = fix_x = fix_y = 0;    /* used in elastic_moveline */
  83.     elastic_moveline(spline->points);    /* erase control vector */
  84.     /* initialize to no arrows - changed below if necessary */
  85.     spline->for_arrow = NULL;
  86.     spline->back_arrow = NULL;
  87.     if (cur_mode == F_CLOSED_INTSPLINE) {
  88.     spline->type = T_CLOSED_INTERP;
  89.     num_point++;
  90.     append_point(first_point->x, first_point->y, &cur_point);
  91.     } else {
  92.     spline->type = T_OPEN_INTERP;
  93.     if (autoforwardarrow_mode)
  94.         spline->for_arrow = forward_arrow();
  95.     if (autobackwardarrow_mode)
  96.         spline->back_arrow = backward_arrow();
  97.     }
  98.     make_control_points(spline);
  99.     draw_intspline(spline, PAINT);
  100.     if (appres.DEBUG) {
  101.     int        xmin, ymin, xmax, ymax;
  102.  
  103.     spline_bound(spline, &xmin, &ymin, &xmax, &ymax);
  104.     elastic_box(xmin, ymin, xmax, ymax);
  105.     }
  106.     add_spline(spline);
  107.     intspline_drawing_selected();
  108.     draw_mousefun_canvas();
  109. }
  110.  
  111. /* Tension : 0 (min) -> 1 (max)     */
  112.  
  113. create_control_list(s)
  114.     F_spline       *s;
  115. {
  116.     F_point       *p;
  117.     F_control       *cp;
  118.  
  119.     if ((cp = create_cpoint()) == NULL)
  120.     return (-1);
  121.  
  122.     s->controls = cp;
  123.     for (p = s->points->next; p != NULL; p = p->next) {
  124.     if ((cp->next = create_cpoint()) == NULL)
  125.         return (-1);
  126.     cp = cp->next;
  127.     }
  128.     cp->next = NULL;
  129.     return (1);
  130. }
  131.  
  132. make_control_points(s)
  133.     F_spline       *s;
  134. {
  135.     if (-1 == create_control_list(s))
  136.     return;
  137.  
  138.     remake_control_points(s);
  139. }
  140.  
  141. remake_control_points(s)
  142.     F_spline       *s;
  143. {
  144.     if (s->type == T_CLOSED_INTERP)
  145.     compute_cp(s->points, s->controls, CLOSED_PATH);
  146.     else
  147.     compute_cp(s->points, s->controls, OPEN_PATH);
  148. }
  149.  
  150. #define        T        0.45
  151. #define        _2xPI        6.2832
  152. #define        _1dSQR2        0.7071
  153. #define        _SQR2        1.4142
  154.  
  155. compute_cp(points, controls, path)
  156.     F_point       *points;
  157.     F_control       *controls;
  158.     int            path;
  159. {
  160.     F_control       *cp, *cpn;
  161.     F_point       *p, *p2, *pk;/* Pk is the next-to-last point. */
  162.     float        dx, dy;
  163.     float        x1, y1, x2, y2, x3, y3;
  164.     float        l1, l2, theta1, theta2;
  165.  
  166.     x1 = points->x;
  167.     y1 = points->y;
  168.     pk = p2 = points->next;
  169.     x2 = p2->x;
  170.     y2 = p2->y;
  171.     p = p2->next;
  172.     x3 = p->x;
  173.     y3 = p->y;
  174.  
  175.     dx = x1 - x2;
  176.     dy = y2 - y1;
  177.     l1 = sqrt((double) (dx * dx + dy * dy));
  178.     if (l1 == 0.0)
  179.     theta1 = 0.0;
  180.     else
  181.     theta1 = atan2((double) dy, (double) dx);
  182.     dx = x3 - x2;
  183.     dy = y2 - y3;
  184.     l2 = sqrt((double) (dx * dx + dy * dy));
  185.     if (l2 == 0.0)
  186.     theta2 = 0.0;
  187.     else
  188.     theta2 = atan2((double) dy, (double) dx);
  189.     /* -PI <= theta1, theta2 <= PI */
  190.     if (theta1 < 0)
  191.     theta1 += _2xPI;
  192.     if (theta2 < 0)
  193.     theta2 += _2xPI;
  194.     /* 0 <= theta1, theta2 < 2PI */
  195.  
  196.     cp = controls->next;
  197.     control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  198.     /* control points for (x2, y2) */
  199.     if (path == OPEN_PATH) {
  200.     controls->lx = 0.0;
  201.     controls->ly = 0.0;
  202.     controls->rx = (x1 + 3 * cp->lx) / 4;
  203.     controls->ry = (y1 + 3 * cp->ly) / 4;
  204.     cp->lx = (3 * cp->lx + x2) / 4;
  205.     cp->ly = (3 * cp->ly + y2) / 4;
  206.     }
  207.     while (1) {
  208.     x2 = x3;
  209.     y2 = y3;
  210.     l1 = l2;
  211.     if (theta2 >= M_PI)
  212.         theta1 = theta2 - M_PI;
  213.     else
  214.         theta1 = theta2 + M_PI;
  215.     if ((p = p->next) == NULL)
  216.         break;
  217.     pk = pk->next;
  218.     x3 = p->x;
  219.     y3 = p->y;
  220.     dx = x3 - x2;
  221.     dy = y2 - y3;
  222.     l2 = sqrt((double) (dx * dx + dy * dy));
  223.     if (l2 == 0.0)
  224.         theta2 = 0.0;
  225.     else
  226.         theta2 = atan2((double) dy, (double) dx);
  227.     if (theta2 < 0)
  228.         theta2 += _2xPI;
  229.     cp = cp->next;
  230.     control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  231.     };
  232.  
  233.     if (path == CLOSED_PATH) {
  234.     dx = p2->x - x2;
  235.     dy = y2 - p2->y;
  236.     l2 = sqrt((double) (dx * dx + dy * dy));
  237.     theta2 = atan2((double) dy, (double) dx);
  238.     if (theta2 < 0)
  239.         theta2 += _2xPI;
  240.     cp = cp->next;
  241.     control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  242.     controls->lx = cp->lx;
  243.     controls->ly = cp->ly;
  244.     controls->rx = cp->rx;
  245.     controls->ry = cp->ry;
  246.     } else {
  247.     cpn = cp->next;
  248.     cpn->lx = (3 * cp->rx + x2) / 4;
  249.     cpn->ly = (3 * cp->ry + y2) / 4;
  250.     cpn->rx = 0.0;
  251.     cpn->ry = 0.0;
  252.     cp->rx = (pk->x + 3 * cp->rx) / 4;
  253.     cp->ry = (pk->y + 3 * cp->ry) / 4;
  254.     }
  255. }
  256.  
  257. /*
  258.  * The parameter t is the tension.  It must range in [0, 1]. The bigger the
  259.  * value of t, the higher the tension.
  260.  */
  261.  
  262. control_points(x, y, l1, l2, theta1, theta2, t, cp)
  263.     float        x, y, l1, l2, theta1, theta2, t;
  264.     F_control       *cp;
  265. {
  266.     float        s, theta, r = 1 - t;
  267.  
  268.     /* 0 <= theta1, theta2 < 2PI */
  269.  
  270.     theta = (theta1 + theta2) / 2;
  271.  
  272.     if (theta1 > theta2) {
  273.     s = sin((double) (theta - theta2));
  274.     theta1 = theta + M_PI_2;
  275.     theta2 = theta - M_PI_2;
  276.     } else {
  277.     s = sin((double) (theta2 - theta));
  278.     theta1 = theta - M_PI_2;
  279.     theta2 = theta + M_PI_2;
  280.     }
  281.     if (s > _1dSQR2)
  282.     s = _SQR2 - s;
  283.     s *= r;
  284.     l1 *= s;
  285.     l2 *= s;
  286.     cp->lx = x + l1 * cos((double) theta1);
  287.     cp->ly = y - l1 * sin((double) theta1);
  288.     cp->rx = x + l2 * cos((double) theta2);
  289.     cp->ry = y - l2 * sin((double) theta2);
  290. }
  291.