1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * This part Copyright (c) 1999-2002 Alexander Durner
4  *
5  * Any party obtaining a copy of these files is granted, free of charge, a
6  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
7  * nonexclusive right and license to deal in this software and documentation
8  * files (the "Software"), including without limitation the rights to use,
9  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
10  * the Software, and to permit persons who receive copies from any such
11  * party to do so, with the only requirement being that the above copyright
12  * and this permission notice remain intact.
13  *
14  */
15 
16 #include "e_tangent.h"
17 
18 #include <math.h>
19 #include <stddef.h>
20 
21 #include "resources.h"
22 #include "mode.h"
23 #include "object.h"
24 #include "paintop.h"
25 #include "f_util.h"
26 #include "u_create.h"
27 #include "u_draw.h"
28 #include "u_list.h"
29 #include "u_markers.h"
30 #include "u_smartsearch.h"
31 #include "w_canvas.h"
32 #include "w_cursor.h"
33 #include "w_mousefun.h"
34 #include "w_msgpanel.h"
35 #include "w_setup.h"
36 #include "xfig_math.h"
37 
38 #define ZERO_TOLERANCE 2.0
39 
40 static void	init_tangent_adding(char *p, int type, int x, int y,
41 					int px, int py);
42 static void	init_normal_adding(char *p, int type, int x, int y,
43 					int px, int py);
44 static void	tangent_or_normal(int x, int y, int flag);
45 static void	tangent_normal_line(int x, int y, float vx, float vy);
46 
47 
48 void
tangent_selected(void)49 tangent_selected(void)
50 {
51     set_mousefun("add tangent", "add normal", "", LOC_OBJ, LOC_OBJ, LOC_OBJ);
52     canvas_kbd_proc = null_proc;
53     canvas_locmove_proc = smart_null_proc;
54     canvas_ref_proc = smart_null_proc;
55     init_smart_searchproc_left(init_tangent_adding);
56     init_smart_searchproc_middle(init_normal_adding);
57     canvas_leftbut_proc = smart_object_search_left;
58     canvas_middlebut_proc = smart_object_search_middle;
59     canvas_rightbut_proc = smart_null_proc;
60     set_cursor(pick9_cursor);
61     /*    force_nopositioning(); */
62     reset_action_on();
63 }
64 
65 /*  smart_point1, smart_point2 are two points of the tangent */
66 
67 static void
init_tangent_adding(char * p,int type,int x,int y,int px,int py)68 init_tangent_adding(char *p, int type, int x, int y, int px, int py)
69 {
70 	(void)p; (void)type; (void)x; (void)y;
71 
72 	tangent_or_normal(px, py, 0);
73 }
74 
75 static void
init_normal_adding(char * p,int type,int x,int y,int px,int py)76 init_normal_adding(char *p, int type, int x, int y, int px, int py)
77 {
78 	(void)p; (void)type; (void)x; (void)y;
79 
80 	tangent_or_normal(px, py, 1);
81 }
82 
83 static void
tangent_or_normal(int x,int y,int flag)84 tangent_or_normal(int x, int y, int flag)
85 {
86     float dx, dy, length, sx, sy, tanlen;
87 
88     dx = (float)(smart_point2.x - smart_point1.x);
89     dy = (float)(smart_point2.y - smart_point1.y);
90     if (dx == 0.0 && dy == 0.0)
91         length = 0.0;
92     else
93         length = sqrt(dx * dx + dy * dy);
94     if (length < ZERO_TOLERANCE) {
95         put_msg("%s", "singularity, can't draw tangent/normal");
96 	beep();
97         return;
98     }
99     tanlen = cur_tangnormlen * (appres.INCHES? PIX_PER_INCH: PIX_PER_CM) / 2.0;
100     sx = dx * tanlen / length;
101     sy = dy * tanlen / length;
102     if (flag) {
103        tangent_normal_line(x, y, -sy, sx);
104        put_msg("%s", "added normal");
105     }
106     else {
107        tangent_normal_line(x, y, sx, sy);
108        put_msg("%s", "added tangent");
109     }
110 }
111 
112 static void
tangent_normal_line(int x,int y,float vx,float vy)113 tangent_normal_line(int x, int y, float vx, float vy)
114 {
115     int dx, dy, xl, yl, xr, yr;
116     F_line	   *line;
117 
118     dx = round(vx);
119     dy = round(vy);
120 
121     xl = x - dx;
122     yl = y - dy;
123     xr = x + dx;
124     yr = y + dy;
125 
126     if ((first_point = create_point()) == NULL)
127         return;
128     cur_point = first_point;
129     first_point->x = xl;
130     first_point->y = yl;
131     first_point->next = NULL;
132     append_point(x, y, &cur_point);
133     append_point(xr, yr, &cur_point);
134 
135     if ((line = create_line()) == NULL)
136         return; /* an error occured */
137     line->type = T_POLYLINE;
138     line->style = cur_linestyle;
139     line->thickness = cur_linewidth;
140     line->pen_color = cur_pencolor;
141     line->fill_color = cur_fillcolor;
142     line->depth = cur_depth;
143     line->pen_style = -1;
144     line->join_style = cur_joinstyle;
145     line->cap_style = cur_capstyle;
146     line->fill_style = cur_fillstyle;
147     line->style_val = cur_styleval * (cur_linewidth + 1) / 2;
148     line->points = first_point;
149 		/* polyline; draw any arrows */
150     if (autoforwardarrow_mode)
151 	line->for_arrow = forward_arrow();
152     /* arrow will be drawn in draw_line below */
153     if (autobackwardarrow_mode)
154 	line->back_arrow = backward_arrow();
155     /* arrow will be drawn in draw_line below */
156     draw_line(line, PAINT);	/* draw final */
157     add_line(line);
158     toggle_linemarker(line);
159 }
160