1 #include <math.h>
2 #include "global.h"
3 
4 #define RSTEP 5.0
5 #define DEG_TO_RAD (M_PI/180.0)
6 
make_arc(int offset,double centerx,double centery,double radius,double start_angle,double finish_angle,double zcoor)7 int make_arc(int offset,	/* offset into array of points */
8 	     double centerx, double centery,
9 	     double radius, double start_angle, double finish_angle,
10 	     double zcoor)
11 {
12     float theta;		/* the angle used for calculating a given point */
13     float alpha;		/* theta converted into radians for use in math */
14     int arr_size;
15 
16     arr_size = offset;
17     G_debug(3,
18 	    "making arc: offset %d  x %.1f y %.1f rad %.1f a1 %.1f a2 %.1f\n",
19 	    offset, centerx, centery, radius, start_angle, finish_angle);
20     if (start_angle > finish_angle)
21 	finish_angle = 360. + finish_angle;
22     /* negative radius indicates that arc is to be drawn in a clockwise
23      * direction from start_angle to finish_angle
24      */
25     if (radius < 0) {
26 	start_angle = 360. + start_angle;
27 	theta = start_angle;
28 	radius = -radius;
29 	while (theta > finish_angle) {
30 	    alpha = theta * DEG_TO_RAD;	/* converting to radians */
31 	    xpnts[arr_size] = radius * cos(alpha) + centerx;
32 	    ypnts[arr_size] = radius * sin(alpha) + centery;
33 	    zpnts[arr_size] = zcoor;
34 	    arr_size++;
35 	    theta -= RSTEP;
36 	    if (arr_size == arr_max) {
37 		arr_max += ARR_INCR;
38 		xpnts = (double *)G_realloc(xpnts, arr_max * sizeof(double));
39 		ypnts = (double *)G_realloc(ypnts, arr_max * sizeof(double));
40 		zpnts = (double *)G_realloc(zpnts, arr_max * sizeof(double));
41 	    }
42 	}
43     }
44     else {
45 	theta = start_angle;
46 	while (theta < finish_angle) {	/* draw arc counterclockwise */
47 	    alpha = theta * DEG_TO_RAD;	/* converting to radians */
48 	    xpnts[arr_size] = radius * cos(alpha) + centerx;
49 	    ypnts[arr_size] = radius * sin(alpha) + centery;
50 	    zpnts[arr_size] = zcoor;
51 	    arr_size++;
52 	    theta += RSTEP;
53 	    if (arr_size == arr_max) {
54 		arr_max += ARR_INCR;
55 		xpnts = (double *)G_realloc(xpnts, arr_max * sizeof(double));
56 		ypnts = (double *)G_realloc(ypnts, arr_max * sizeof(double));
57 		zpnts = (double *)G_realloc(zpnts, arr_max * sizeof(double));
58 	    }
59 	}
60     }
61     /* this insures that the last point will be correct */
62     alpha = finish_angle * DEG_TO_RAD;	/* converting to radians */
63     xpnts[arr_size] = radius * cos(alpha) + centerx;
64     ypnts[arr_size] = radius * sin(alpha) + centery;
65     zpnts[arr_size] = zcoor;
66     arr_size++;
67     if (arr_size == arr_max) {
68 	arr_max += ARR_INCR;
69 	xpnts = (double *)G_realloc(xpnts, arr_max * sizeof(double));
70 	ypnts = (double *)G_realloc(ypnts, arr_max * sizeof(double));
71 	zpnts = (double *)G_realloc(zpnts, arr_max * sizeof(double));
72     }
73 
74     return arr_size - offset;
75 }
76 
make_arc_from_polyline(int arr_size,double bulge,double prev_bulge)77 int make_arc_from_polyline(int arr_size, double bulge, double prev_bulge)
78 {
79     int arc_arr_size;
80     float ang1, ang2;
81     double x1, x2, y1, y2, cent_x, cent_y, rad, beta, half_alpha;
82     double arc_tan = 0.0;
83 
84     /* if prev segment is an arc (prev_bulge != 0) prepare to make arc */
85     if (prev_bulge > 0.0)
86 	arc_tan = prev_bulge;
87     else if (prev_bulge < 0.0)
88 	arc_tan = (-1.0) * prev_bulge;
89 
90     if (arc_tan == 0.0) {	/* straight line segment */
91 	arr_size++;
92 	if (arr_size == arr_max) {
93 	    arr_max += ARR_INCR;
94 	    xpnts = (double *)G_realloc(xpnts, arr_max * sizeof(double));
95 	    ypnts = (double *)G_realloc(ypnts, arr_max * sizeof(double));
96 	    zpnts = (double *)G_realloc(zpnts, arr_max * sizeof(double));
97 	}
98     }
99     else if (!(xpnts[arr_size - 1] == xpnts[arr_size] &&
100 	       ypnts[arr_size - 1] == ypnts[arr_size]))
101 	/* make an arc */
102     {
103 	/* compute cent_x, cent_y, ang1, ang2 */
104 	if (prev_bulge > 0.0) {
105 	    x1 = xpnts[arr_size - 1];
106 	    x2 = xpnts[arr_size];
107 	    y1 = ypnts[arr_size - 1];
108 	    y2 = ypnts[arr_size];
109 	}
110 	else {
111 	    /* figure out how to compute the opposite center */
112 	    x2 = xpnts[arr_size - 1];
113 	    x1 = xpnts[arr_size];
114 	    y2 = ypnts[arr_size - 1];
115 	    y1 = ypnts[arr_size];
116 	}
117 	half_alpha = (double)atan(arc_tan) * 2.;
118 	rad = hypot(x1 - x2, y1 - y2) * .5 / sin(half_alpha);
119 	beta = atan2(x1 - x2, y1 - y2);
120 	/* now bring it into range 0 to 360 */
121 	beta = 90.0 * DEG_TO_RAD - beta;
122 	if (beta <= 0.0)
123 	    beta = 360.0 * DEG_TO_RAD + beta;
124 	/* now beta is counter clock wise from 0 (direction of (1,0)) to 360 */
125 	if (beta >= 0.0 && beta < 90.0) {
126 	    cent_x = x2 + rad * sin(half_alpha + beta);
127 	    cent_y = y2 - rad * cos(half_alpha + beta);
128 	    ang2 = (half_alpha + beta) / DEG_TO_RAD + 90.0;
129 	    ang1 = (beta - half_alpha) / DEG_TO_RAD + 90.0;
130 	}
131 	else if (beta >= 90.0 && beta < 180.0) {
132 	    beta -= 90.0;
133 	    cent_y = y2 + rad * sin(half_alpha + beta);
134 	    cent_x = x2 + rad * cos(half_alpha + beta);
135 	    ang2 = (half_alpha + beta) / DEG_TO_RAD + 180.0;
136 	    ang1 = (beta - half_alpha) / DEG_TO_RAD + 180.0;
137 	}
138 	else if (beta >= 180.0 && beta < 270.0) {
139 	    beta -= 180.0;
140 	    cent_x = x2 - rad * sin(half_alpha + beta);
141 	    cent_y = y2 + rad * cos(half_alpha + beta);
142 	    ang2 = (half_alpha + beta) / DEG_TO_RAD + 270.0;
143 	    ang1 = (beta - half_alpha) / DEG_TO_RAD + 270.0;
144 	}
145 	else {			/* 270 <= beta < 360 */
146 
147 	    beta -= 270.0;
148 	    cent_y = y2 - rad * sin(half_alpha + beta);
149 	    cent_x = x2 - rad * cos(half_alpha + beta);
150 	    ang2 = (half_alpha + beta) / DEG_TO_RAD;
151 	    ang1 = (beta - half_alpha) / DEG_TO_RAD;
152 	}
153 
154 	arr_size--;		/* disregard last 2 points */
155 	if (prev_bulge < 0.0)
156 	    arc_arr_size = make_arc(arr_size, cent_x, cent_y,
157 				    -rad, ang2, ang1, zpnts[0]);
158 	/* arc is going in clockwise direction from x2 to x1 */
159 	else
160 
161 	    arc_arr_size = make_arc(arr_size, cent_x, cent_y,
162 				    rad, ang1, ang2, zpnts[0]);
163 	arr_size += arc_arr_size;
164 	while (arr_size >= arr_max) {
165 	    arr_max += ARR_INCR;
166 	    xpnts = (double *)G_realloc(xpnts, arr_max * sizeof(double));
167 	    ypnts = (double *)G_realloc(ypnts, arr_max * sizeof(double));
168 	    zpnts = (double *)G_realloc(zpnts, arr_max * sizeof(double));
169 	}
170     }				/* arc */
171 
172     return arr_size;
173 }
174