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