2 * Copyright (c) 1987, 1988, 1989 Stanford University
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Stanford not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. Stanford makes no representations about
11 * the suitability of this software for any purpose. It is provided "as is"
12 * without express or implied warranty.
14 * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
20 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 /* This code came with the InterViews distribution, and was translated
24 from C++ to C by Matthieu Devin <devin@lucid.com> some time in 1992.
30 #define SMOOTHNESS 1.0
32 static void no_more_memory (void);
33 static void grow_spline_points (spline* s);
34 static void mid_point (double x0, double y0, double x1, double y1,
35 double *mx, double *my);
36 static int can_approx_with_line (double x0, double y0, double x2,
37 double y2, double x3, double y3);
38 static void add_line (spline* s, double x0, double y0, double x1, double y1);
39 static void add_bezier_arc (spline* s,
40 double x0, double y0, double x1, double y1,
41 double x2, double y2, double x3, double y3);
42 static void third_point (double x0, double y0, double x1, double y1,
43 double *tx, double *ty);
44 static void calc_section (spline* s, double cminus1x, double cminus1y,
45 double cx, double cy, double cplus1x, double cplus1y,
46 double cplus2x, double cplus2y);
51 fprintf (stderr, "No more memory\n");
56 make_spline (unsigned int size)
58 spline* s = (spline*)calloc (1, sizeof (spline));
62 s->control_x = (double*)calloc (s->n_controls, sizeof (double));
63 s->control_y = (double*)calloc (s->n_controls, sizeof (double));
66 s->allocated_points = s->n_controls;
67 s->points = (XPoint*)calloc (s->allocated_points, sizeof (XPoint));
69 if (!s->control_x || !s->control_y || !s->points)
76 grow_spline_points (spline *s)
78 s->allocated_points *= 2;
80 (XPoint*)realloc (s->points, s->allocated_points * sizeof (XPoint));
87 mid_point (double x0, double y0,
89 double *mx, double *my)
91 *mx = (x0 + x1) / 2.0;
92 *my = (y0 + y1) / 2.0;
96 third_point (double x0, double y0,
98 double *tx, double *ty)
100 *tx = (2 * x0 + x1) / 3.0;
101 *ty = (2 * y0 + y1) / 3.0;
105 can_approx_with_line (double x0, double y0,
106 double x2, double y2,
107 double x3, double y3)
109 double triangle_area, side_squared, dx, dy;
111 triangle_area = x0 * y2 - x2 * y0 + x2 * y3 - x3 * y2 + x3 * y0 - x0 * y3;
112 /* actually 4 times the area. */
113 triangle_area *= triangle_area;
116 side_squared = dx * dx + dy * dy;
117 return triangle_area <= SMOOTHNESS * side_squared;
122 double x0, double y0,
123 double x1, double y1)
125 if (s->n_points >= s->allocated_points)
126 grow_spline_points (s);
128 if (s->n_points == 0)
130 s->points [s->n_points].x = x0;
131 s->points [s->n_points].y = y0;
134 s->points [s->n_points].x = x1;
135 s->points [s->n_points].y = y1;
140 add_bezier_arc (spline *s,
141 double x0, double y0,
142 double x1, double y1,
143 double x2, double y2,
144 double x3, double y3)
146 double midx01, midx12, midx23, midlsegx, midrsegx, cx,
147 midy01, midy12, midy23, midlsegy, midrsegy, cy;
149 mid_point (x0, y0, x1, y1, &midx01, &midy01);
150 mid_point (x1, y1, x2, y2, &midx12, &midy12);
151 mid_point (x2, y2, x3, y3, &midx23, &midy23);
152 mid_point (midx01, midy01, midx12, midy12, &midlsegx, &midlsegy);
153 mid_point (midx12, midy12, midx23, midy23, &midrsegx, &midrsegy);
154 mid_point (midlsegx, midlsegy, midrsegx, midrsegy, &cx, &cy);
156 if (can_approx_with_line (x0, y0, midlsegx, midlsegy, cx, cy))
157 add_line (s, x0, y0, cx, cy);
158 else if ((midx01 != x1) || (midy01 != y1) || (midlsegx != x2)
159 || (midlsegy != y2) || (cx != x3) || (cy != y3))
160 add_bezier_arc (s, x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy);
162 if (can_approx_with_line (cx, cy, midx23, midy23, x3, y3))
163 add_line (s, cx, cy, x3, y3);
164 else if ((cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1)
165 || (midx23 != x2) || (midy23 != y2))
166 add_bezier_arc (s, cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3);
170 calc_section (spline *s,
171 double cminus1x, double cminus1y,
172 double cx, double cy,
173 double cplus1x, double cplus1y,
174 double cplus2x, double cplus2y)
176 double p0x, p1x, p2x, p3x, tempx,
177 p0y, p1y, p2y, p3y, tempy;
179 third_point (cx, cy, cplus1x, cplus1y, &p1x, &p1y);
180 third_point (cplus1x, cplus1y, cx, cy, &p2x, &p2y);
181 third_point (cx, cy, cminus1x, cminus1y, &tempx, &tempy);
182 mid_point (tempx, tempy, p1x, p1y, &p0x, &p0y);
183 third_point (cplus1x, cplus1y, cplus2x, cplus2y, &tempx, &tempy);
184 mid_point (tempx, tempy, p2x, p2y, &p3x, &p3y);
185 add_bezier_arc (s, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y);
189 compute_spline (spline *s)
194 if (s->n_controls < 3)
197 calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
198 s->control_y [0], s->control_x [0], s->control_y [0],
199 s->control_x [1], s->control_y [1]);
200 calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
201 s->control_y [0], s->control_x [1], s->control_y [1],
202 s->control_x [2], s->control_y [2]);
204 for (i = 1; i < s->n_controls - 2; i++)
205 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
206 s->control_x [i], s->control_y [i],
207 s->control_x [i + 1], s->control_y [i + 1],
208 s->control_x [i + 2], s->control_y [i + 2]);
210 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
211 s->control_x [i], s->control_y [i],
212 s->control_x [i + 1], s->control_y [i + 1],
213 s->control_x [i + 1], s->control_y [i + 1]);
214 calc_section (s, s->control_x [i], s->control_y [i],
215 s->control_x [i + 1], s->control_y [i + 1],
216 s->control_x [i + 1], s->control_y [i + 1],
217 s->control_x [i + 1], s->control_y [i + 1]);
221 compute_closed_spline (spline *s)
226 if (s->n_controls < 3)
230 s->control_x [s->n_controls - 1],
231 s->control_y [s->n_controls - 1],
232 s->control_x [0], s->control_y [0],
233 s->control_x [1], s->control_y [1],
234 s->control_x [2], s->control_y [2]);
236 for (i = 1; i < s->n_controls - 2; i++)
237 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
238 s->control_x [i], s->control_y [i],
239 s->control_x [i + 1], s->control_y [i + 1],
240 s->control_x [i + 2], s->control_y [i + 2]);
242 calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
243 s->control_x [i], s->control_y [i],
244 s->control_x [i + 1], s->control_y [i + 1],
245 s->control_x [0], s->control_y [0]);
246 calc_section (s, s->control_x [i], s->control_y [i],
247 s->control_x [i + 1], s->control_y [i + 1],
248 s->control_x [0], s->control_y [0],
249 s->control_x [1], s->control_y [1]);
253 just_fill_spline (spline *s)
257 while (s->allocated_points < s->n_controls + 1)
258 grow_spline_points (s);
260 for (i = 0; i < s->n_controls; i++)
262 s->points [i].x = s->control_x [i];
263 s->points [i].y = s->control_y [i];
265 s->points [s->n_controls].x = s->control_x [0];
266 s->points [s->n_controls].y = s->control_y [0];
267 s->n_points = s->n_controls + 1;
271 append_spline_points (spline *s1, spline *s2)
274 while (s1->allocated_points < s1->n_points + s2->n_points)
275 grow_spline_points (s1);
276 for (i = s1->n_points; i < s1->n_points + s2->n_points; i++)
278 s1->points [i].x = s2->points [i - s1->n_points].x;
279 s1->points [i].y = s2->points [i - s1->n_points].y;
281 s1->n_points = s1->n_points + s2->n_points;
285 spline_bounding_box (spline *s, XRectangle *rectangle_out)
293 if (s->n_points == 0)
295 rectangle_out->x = 0;
296 rectangle_out->y = 0;
297 rectangle_out->width = 0;
298 rectangle_out->height = 0;
301 min_x = s->points [0].x;
303 min_y = s->points [0].y;
306 for (i = 1; i < s->n_points; i++)
308 if (s->points [i].x < min_x)
309 min_x = s->points [i].x;
310 if (s->points [i].x > max_x)
311 max_x = s->points [i].x;
312 if (s->points [i].y < min_y)
313 min_y = s->points [i].y;
314 if (s->points [i].y > max_y)
315 max_y = s->points [i].y;
317 rectangle_out->x = min_x;
318 rectangle_out->y = min_y;
319 rectangle_out->width = max_x - min_x;
320 rectangle_out->height = max_y - min_y;
324 free_spline(spline * s)
326 free ((void *) s->control_x);
327 free ((void *) s->control_y);
328 free ((void *) s->points);