8 /* Lifted from InterViews */
14 fprintf (stderr, "No more memory\n");
22 spline* s = (spline*)calloc (1, sizeof (spline));
26 s->control_x = (double*)calloc (s->n_controls, sizeof (double));
27 s->control_y = (double*)calloc (s->n_controls, sizeof (double));
30 s->allocated_points = s->n_controls;
31 s->points = (XPoint*)calloc (s->allocated_points, sizeof (XPoint));
33 if (!s->control_x || !s->control_y || !s->points)
40 grow_spline_points (s)
43 s->allocated_points *= 2;
45 (XPoint*)realloc (s->points, s->allocated_points * sizeof (XPoint));
52 mid_point (x0, y0, x1, y1, mx, my)
53 double x0, y0, x1, y1, *mx, *my;
55 *mx = (x0 + x1) / 2.0;
56 *my = (y0 + y1) / 2.0;
60 third_point (x0, y0, x1, y1, tx, ty)
61 double x0, y0, x1, y1, *tx, *ty;
63 *tx = (2 * x0 + x1) / 3.0;
64 *ty = (2 * y0 + y1) / 3.0;
68 can_approx_with_line (x0, y0, x2, y2, x3, y3)
69 double x0, y0, x2, y2, x3, y3;
71 double triangle_area, side_squared, dx, dy;
73 triangle_area = x0 * y2 - x2 * y0 + x2 * y3 - x3 * y2 + x3 * y0 - x0 * y3;
74 /* actually 4 times the area. */
75 triangle_area *= triangle_area;
78 side_squared = dx * dx + dy * dy;
79 return triangle_area <= SMOOTHNESS * side_squared;
83 add_line (s, x0, y0, x1, y1)
85 double x0, y0, x1, y1;
87 if (s->n_points >= s->allocated_points)
88 grow_spline_points (s);
92 s->points [s->n_points].x = x0;
93 s->points [s->n_points].y = y0;
96 s->points [s->n_points].x = x1;
97 s->points [s->n_points].y = y1;
102 add_bezier_arc (s, x0, y0, x1, y1, x2, y2, x3, y3)
104 double x0, y0, x1, y1, x2, y2, x3, y3;
106 double midx01, midx12, midx23, midlsegx, midrsegx, cx,
107 midy01, midy12, midy23, midlsegy, midrsegy, cy;
109 mid_point (x0, y0, x1, y1, &midx01, &midy01);
110 mid_point (x1, y1, x2, y2, &midx12, &midy12);
111 mid_point (x2, y2, x3, y3, &midx23, &midy23);
112 mid_point (midx01, midy01, midx12, midy12, &midlsegx, &midlsegy);
113 mid_point (midx12, midy12, midx23, midy23, &midrsegx, &midrsegy);
114 mid_point (midlsegx, midlsegy, midrsegx, midrsegy, &cx, &cy);
116 if (can_approx_with_line (x0, y0, midlsegx, midlsegy, cx, cy))
117 add_line (s, x0, y0, cx, cy);
118 else if ((midx01 != x1) || (midy01 != y1) || (midlsegx != x2)
119 || (midlsegy != y2) || (cx != x3) || (cy != y3))
120 add_bezier_arc (s, x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy);
122 if (can_approx_with_line (cx, cy, midx23, midy23, x3, y3))
123 add_line (s, cx, cy, x3, y3);
124 else if ((cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1)
125 || (midx23 != x2) || (midy23 != y2))
126 add_bezier_arc (s, cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3);
130 calc_section (s, cminus1x, cminus1y, cx, cy, cplus1x, cplus1y,
133 double cminus1x, cminus1y, cx, cy, cplus1x, cplus1y, cplus2x, cplus2y;
135 double p0x, p1x, p2x, p3x, tempx,
136 p0y, p1y, p2y, p3y, tempy;
138 third_point (cx, cy, cplus1x, cplus1y, &p1x, &p1y);
139 third_point (cplus1x, cplus1y, cx, cy, &p2x, &p2y);
140 third_point (cx, cy, cminus1x, cminus1y, &tempx, &tempy);
141 mid_point (tempx, tempy, p1x, p1y, &p0x, &p0y);
142 third_point (cplus1x, cplus1y, cplus2x, cplus2y, &tempx, &tempy);
143 mid_point (tempx, tempy, p2x, p2y, &p3x, &p3y);
144 add_bezier_arc (s, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y);
154 if (s->n_controls < 3)
157 calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
158 s->control_y [0], s->control_x [0], s->control_y [0],
159 s->control_x [1], s->control_y [1]);
160 calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
161 s->control_y [0], s->control_x [1], s->control_y [1],
162 s->control_x [2], s->control_y [2]);
164 for (i = 1; i < s->n_controls - 2; i++)
165 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
166 s->control_x [i], s->control_y [i],
167 s->control_x [i + 1], s->control_y [i + 1],
168 s->control_x [i + 2], s->control_y [i + 2]);
170 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
171 s->control_x [i], s->control_y [i],
172 s->control_x [i + 1], s->control_y [i + 1],
173 s->control_x [i + 1], s->control_y [i + 1]);
174 calc_section (s, s->control_x [i], s->control_y [i],
175 s->control_x [i + 1], s->control_y [i + 1],
176 s->control_x [i + 1], s->control_y [i + 1],
177 s->control_x [i + 1], s->control_y [i + 1]);
181 compute_closed_spline (s)
187 if (s->n_controls < 3)
191 s->control_x [s->n_controls - 1],
192 s->control_y [s->n_controls - 1],
193 s->control_x [0], s->control_y [0],
194 s->control_x [1], s->control_y [1],
195 s->control_x [2], s->control_y [2]);
197 for (i = 1; i < s->n_controls - 2; i++)
198 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
199 s->control_x [i], s->control_y [i],
200 s->control_x [i + 1], s->control_y [i + 1],
201 s->control_x [i + 2], s->control_y [i + 2]);
203 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
204 s->control_x [i], s->control_y [i],
205 s->control_x [i + 1], s->control_y [i + 1],
206 s->control_x [0], s->control_y [0]);
207 calc_section (s, s->control_x [i], s->control_y [i],
208 s->control_x [i + 1], s->control_y [i + 1],
209 s->control_x [0], s->control_y [0],
210 s->control_x [1], s->control_y [1]);
219 while (s->allocated_points < s->n_controls + 1)
220 grow_spline_points (s);
222 for (i = 0; i < s->n_controls; i++)
224 s->points [i].x = s->control_x [i];
225 s->points [i].y = s->control_y [i];
227 s->points [s->n_controls].x = s->control_x [0];
228 s->points [s->n_controls].y = s->control_y [0];
229 s->n_points = s->n_controls + 1;
233 append_spline_points (s1, s2)
237 while (s1->allocated_points < s1->n_points + s2->n_points)
238 grow_spline_points (s1);
239 for (i = s1->n_points; i < s1->n_points + s2->n_points; i++)
241 s1->points [i].x = s2->points [i - s1->n_points].x;
242 s1->points [i].y = s2->points [i - s1->n_points].y;
244 s1->n_points = s1->n_points + s2->n_points;
248 spline_bounding_box (s, rectangle_out)
250 XRectangle* rectangle_out;
258 if (s->n_points == 0)
260 rectangle_out->x = 0;
261 rectangle_out->y = 0;
262 rectangle_out->width = 0;
263 rectangle_out->height = 0;
266 min_x = s->points [0].x;
268 min_y = s->points [0].y;
271 for (i = 1; i < s->n_points; i++)
273 if (s->points [i].x < min_x)
274 min_x = s->points [i].x;
275 if (s->points [i].x > max_x)
276 max_x = s->points [i].x;
277 if (s->points [i].y < min_y)
278 min_y = s->points [i].y;
279 if (s->points [i].y > max_y)
280 max_y = s->points [i].y;
282 rectangle_out->x = min_x;
283 rectangle_out->y = min_y;
284 rectangle_out->width = max_x - min_x;
285 rectangle_out->height = max_y - min_y;