home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume8 / xfig2.8 / part08 / intspline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-03  |  8.1 KB  |  321 lines

  1. /* 
  2.  *    FIG : Facility for Interactive Generation of figures
  3.  *
  4.  *    Copyright (c) 1985 by Supoj Sutanthavibul (supoj@sally.UTEXAS.EDU)
  5.  *    January 1985.
  6.  *    1st revision : Aug 1985.
  7.  *
  8.  *    %W%    %G%
  9. */
  10. #include "fig.h"
  11. #include "resources.h"
  12. #include "alloc.h"
  13. #include "func.h"
  14. #include "object.h"
  15. #include "paintop.h"
  16.  
  17. extern            (*canvas_kbd_proc)();
  18. extern            (*canvas_locmove_proc)();
  19. extern            (*canvas_leftbut_proc)();
  20. extern            (*canvas_middlebut_proc)();
  21. extern            (*canvas_rightbut_proc)();
  22. extern            null_proc();
  23. extern            set_popupmenu();
  24.  
  25. extern int        line_style, line_thickness;
  26. extern float        cur_styleval;
  27. extern int        cur_color;
  28. extern int        cur_areafill;
  29. extern int        fill_mode;
  30. extern int        fix_x, fix_y, cur_x, cur_y;
  31. extern int        cur_command;
  32. extern int        manhattan_mode, mountain_mode;
  33. extern int        autoforwardarrow_mode;
  34. extern int        autobackwardarrow_mode;
  35. extern F_compound    objects;
  36. extern int        num_point;
  37. extern F_point        *first_point, *cur_point;
  38. extern appresStruct    appres;
  39.  
  40. extern int        create_intsplineobject();
  41. extern int        init_intspline_drawing();
  42.  
  43. draw_intspline_selected()
  44. {
  45.     canvas_kbd_proc = null_proc;
  46.     canvas_locmove_proc = null_proc;
  47.     canvas_leftbut_proc = init_intspline_drawing;
  48.     canvas_middlebut_proc = null_proc;
  49.     canvas_rightbut_proc = set_popupmenu;
  50.     set_cursor(&arrow_cursor);
  51.     reset_action_on();
  52.     }
  53.  
  54. init_intspline_drawing(x, y)
  55. int    x, y;
  56. {
  57.     init_line_drawing(x, y);
  58.     canvas_middlebut_proc = create_intsplineobject;
  59.     canvas_rightbut_proc = null_proc;
  60.     }
  61.  
  62. create_intsplineobject(x, y)
  63. int    x, y;
  64. {
  65.     extern F_arrow    *forward_arrow(), *backward_arrow();
  66.     F_spline    *spline;
  67.  
  68.     if (x != fix_x || y != fix_y) get_intermediatepoint(x, y);
  69.     draw_elasticline();
  70.     if (num_point <= 2) {
  71.         pw_vector(canvas_win, first_point->x, first_point->y,
  72.             cur_point->x, cur_point->y, PAINT, 1, SOLID_LINE, 0.0);
  73.         if (num_point == 1) {
  74.         free((char*)cur_point);
  75.         cur_point = NULL;
  76.         }
  77.         free((char*)first_point);
  78.         first_point = NULL;
  79.         draw_intspline_selected();
  80.         return;
  81.         }
  82.     if (NULL == (Spline_malloc(spline))) {
  83.         if (num_point == 1) {
  84.         free((char*)cur_point);
  85.         cur_point = NULL;
  86.         }
  87.         free((char*)first_point);
  88.         first_point = NULL;
  89.         put_msg(Err_mem);
  90.         return;
  91.         }
  92.     spline->style = line_style;
  93.     spline->thickness = line_thickness;
  94.     spline->style_val = cur_styleval;
  95.     spline->color = cur_color;
  96.     spline->depth = 0;
  97.     spline->area_fill = 0;
  98.     spline->pen = 0;
  99.     spline->points = first_point;
  100.     spline->controls = NULL; 
  101.     spline->next = NULL; 
  102.     cur_x = cur_y = fix_x = fix_y = 0; /* used in draw_movingpoint */
  103.     draw_movingpoint(spline->points, INV_PAINT); /* erase control vector */
  104.     spline->for_arrow = NULL;
  105.     spline->back_arrow  = NULL;
  106.     if (cur_command == F_CLOSED_INTSPLINE) {
  107.         spline->type = T_CLOSED_INTERPOLATED;
  108.         /* added 3/1/89 B.V.Smith */
  109.         /* The current area fill color will be saved in the object if 
  110.            fill_mode is != 0, but the method presently used to draw
  111.            the spline doesn't easily lend itself to area fill,
  112.            so it is not filled.
  113.            The spline is drawn in sections that aren't adjacent, 
  114.            and have overlapping sections. */
  115.         spline->area_fill = fill_mode? cur_areafill : 0;
  116.         num_point++;
  117.         append_point(first_point->x, first_point->y, &cur_point);
  118.         }
  119.     else {
  120.         spline->type = T_OPEN_INTERPOLATED;
  121.         if (autoforwardarrow_mode) spline->for_arrow = forward_arrow();
  122.         if (autobackwardarrow_mode) spline->back_arrow = backward_arrow();
  123.         }
  124.     make_control_points(spline);
  125.     draw_intspline(spline, PAINT);
  126.     if (appres.DEBUG) {
  127.         int    xmin, ymin, xmax, ymax;
  128.         spline_bound(spline, &xmin, &ymin, &xmax, &ymax);
  129.         draw_rectbox(xmin, ymin, xmax, ymax, PAINT);
  130.         }
  131.     clean_up();
  132.     set_action_object(F_CREATE, O_SPLINE);
  133.     insert_spline(&objects.splines, spline);
  134.     set_latestspline(spline);
  135.     set_modifiedflag();
  136.     draw_intspline_selected();
  137.     }
  138.  
  139. /* Tension : 0 (min) -> 1 (max)    */
  140.  
  141. #define        round(x)    ((int) (x + .5))
  142.  
  143. create_control_list(s)
  144. F_spline    *s;
  145. {
  146.     F_point        *p;
  147.     F_control    *cp;
  148.  
  149.     if (NULL == (Control_malloc(cp))) {
  150.         put_msg(Err_mem);
  151.         return(-1);
  152.         }
  153.     s->controls = cp;
  154.     for (p = s->points->next; p != NULL; p = p->next) {
  155.         if (NULL == (Control_malloc(cp->next))) {
  156.         put_msg(Err_mem);
  157.         return(-1);
  158.         }
  159.         cp = cp->next;
  160.         }
  161.     cp->next = NULL;
  162.     return(1);
  163.     }
  164.  
  165. make_control_points(s)
  166. F_spline    *s;
  167. {
  168.     if (-1 == create_control_list(s)) return;
  169.  
  170.     remake_control_points(s);
  171.     }
  172.  
  173. remake_control_points(s)
  174. F_spline    *s;
  175. {
  176.     if (s->type == T_CLOSED_INTERPOLATED)
  177.         compute_cp(s->points, s->controls, CLOSED_PATH);
  178.     else
  179.         compute_cp(s->points, s->controls, OPEN_PATH);
  180.     }
  181.  
  182. draw_intspline(s, op)
  183. F_spline    *s;
  184. int        op;
  185. {
  186.     F_point        *p1, *p2;
  187.     F_control    *cp1, *cp2;
  188.  
  189.     p1 = s->points;
  190.     cp1 = s->controls;
  191.     cp2 = cp1->next;
  192.     if (s->back_arrow)
  193.         draw_arrow(round(cp2->lx), round(cp2->ly), p1->x, p1->y, 
  194.                s->back_arrow, op);
  195.     for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
  196.         p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
  197.         bezier_spline((float)p1->x, (float)p1->y, cp1->rx, cp1->ry,
  198.             cp2->lx, cp2->ly, (float)p2->x, (float)p2->y, op, 
  199.             s->thickness, s->style, s->style_val);
  200.         }
  201.     if (s->for_arrow)
  202.         draw_arrow(round(cp1->lx), round(cp1->ly), p1->x,
  203.             p1->y, s->for_arrow, op);
  204.     }
  205.  
  206. #define        T        0.45
  207. #define        _2xPI        6.2832
  208. #define        _1dSQR2        0.7071
  209. #define        _SQR2        1.4142
  210.  
  211. compute_cp(points, controls, path)
  212. F_point        *points;
  213. F_control    *controls;
  214. int        path;
  215. {
  216.     F_control    *cp, *cpn;
  217.     F_point        *p, *p2, *pk;    /* Pk is the next-to-last point. */
  218.     float        dx, dy;
  219.     float        x1, y1, x2, y2, x3, y3;
  220.     float        l1, l2, theta1, theta2;
  221.  
  222.     x1 = points->x;  y1 = points->y;
  223.     pk = p2 = points->next;
  224.     x2 = p2->x;  y2 = p2->y;
  225.     p = p2->next;
  226.     x3 = p->x;  y3 = p->y;
  227.  
  228.     dx = x1 - x2;
  229.     dy = y2 - y1;
  230.     l1 = sqrt((double)(dx*dx + dy*dy));
  231.     theta1 = atan2((double)dy, (double)dx);
  232.     dx = x3 - x2;
  233.     dy = y2 - y3;
  234.     l2 = sqrt((double)(dx*dx + dy*dy));
  235.     theta2 = atan2((double)dy, (double)dx);
  236.     /* -PI <= theat1, theta2 <= PI */
  237.     if (theta1 < 0) theta1 += _2xPI;
  238.     if (theta2 < 0) theta2 += _2xPI;
  239.     /* 0 <= theat1, theta2 < 2PI */
  240.  
  241.     cp = controls->next;
  242.     control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  243.     /* control points for (x2, y2) */
  244.     if (path == OPEN_PATH) {
  245.         controls->lx = 0.0; controls->ly = 0.0;
  246.         controls->rx = (x1 + 3*cp->lx)/4; controls->ry = (y1 + 3*cp->ly)/4;
  247.         cp->lx = (3*cp->lx + x2)/4; cp->ly = (3*cp->ly + y2)/4;
  248.         }
  249.  
  250.     while (1) {
  251.         x2 = x3; y2 = y3;
  252.         l1 = l2;
  253.         if (theta2 >= M_PI)
  254.         theta1 = theta2 - M_PI;
  255.         else
  256.         theta1 = theta2 + M_PI;
  257.         if ((p = p->next) == NULL) break;
  258.         pk = pk->next;
  259.         x3 = p->x; y3 = p->y;
  260.         dx = x3 - x2;
  261.         dy = y2 - y3;
  262.         l2 = sqrt((double)(dx*dx + dy*dy));
  263.         theta2 = atan2((double)dy, (double)dx);
  264.         if (theta2 < 0) theta2 += _2xPI;
  265.         cp = cp->next;
  266.         control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  267.         };
  268.  
  269.     if (path == CLOSED_PATH) {
  270.         dx = p2->x - x2;
  271.         dy = y2 - p2->y;
  272.         l2 = sqrt((double)(dx*dx + dy*dy));
  273.         theta2 = atan2((double)dy, (double)dx);
  274.         if (theta2 < 0) theta2 += _2xPI;
  275.         cp = cp->next;
  276.         control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  277.         controls->lx = cp->lx; controls->ly = cp->ly;
  278.         controls->rx = cp->rx; controls->ry = cp->ry;
  279.         }
  280.     else {
  281.         cpn = cp->next;
  282.         cpn->lx = (3*cp->rx + x2) / 4; cpn->ly = (3*cp->ry + y2) / 4;
  283.         cpn->rx = 0.0; cpn->ry = 0.0;
  284.         cp->rx = (pk->x + 3*cp->rx) / 4; cp->ry = (pk->y + 3*cp->ry) / 4;
  285.         }
  286.     }
  287.  
  288. /*
  289. The parameter t is the tension.  It must range in [0, 1].
  290. The bigger the value of t, the higher the tension.
  291. */
  292.  
  293. control_points(x, y, l1, l2, theta1, theta2, t, cp)
  294. float    x, y, l1, l2, theta1, theta2, t;
  295. F_control    *cp;
  296. {
  297.     float    s, theta, r = 1 - t;
  298.  
  299.     /* 0 <= theat1, theta2 < 2PI */
  300.  
  301.     theta = (theta1 + theta2) / 2;
  302.  
  303.     if (theta1 > theta2) {
  304.         s = sin((double)(theta-theta2));
  305.         theta1 = theta + M_PI_2;
  306.         theta2 = theta - M_PI_2;
  307.         }
  308.     else {
  309.         s = sin((double)(theta2-theta));
  310.         theta1 = theta - M_PI_2;
  311.         theta2 = theta + M_PI_2;
  312.         }
  313.     if (s > _1dSQR2) s = _SQR2 - s;
  314.     s *= r;
  315.     l1 *= s; l2 *= s;
  316.     cp->lx = x + l1 * cos((double)theta1);
  317.     cp->ly = y - l1 * sin((double)theta1);
  318.     cp->rx = x + l2 * cos((double)theta2);
  319.     cp->ry = y - l2 * sin((double)theta2);
  320.     }
  321.