1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file also contains the ellipse method, which is a GNU extension to
20 libplot. It draws an object: an ellipse with center xc,yc and semi-axes
21 of length rx and ry (the former at a specified angle with the x-axis).
22 Ellipses are one of the three types of primitive closed path that
23 libplot supports, along with boxes and circles.
24
25 In this generic version, we usually draw the ellipse by drawing four
26 elliptic arcs (quarter-ellipses) into the path buffer's segment list.
27 Plotters that don't support elliptic arcs draw polygonal approximations
28 instead. Plotters that are sufficiently powerful that they support
29 ellipses as primitive drawing elements place an ellipse primitive in the
30 path buffer, instead.
31
32 Note that some Plotters support the drawing of any ellipse; some require
33 that they be aligned with the coordinate axes. Some don't support the
34 drawing of ellipses at all. The constraints on the user frame -> device
35 frame map (e.g., it must preserve coordinate axes) are specified by the
36 internal `allowed_ellipse_scaling' parameter, which this code checks. */
37
38 #include "sys-defines.h"
39 #include "extern.h"
40
41 int
_API_fellipse(R___ (Plotter * _plotter)double xc,double yc,double rx,double ry,double angle)42 _API_fellipse (R___(Plotter *_plotter) double xc, double yc, double rx, double ry, double angle)
43 {
44 if (!_plotter->data->open)
45 {
46 _plotter->error (R___(_plotter)
47 "fellipse: invalid operation");
48 return -1;
49 }
50
51 /* If a simple path is under construction (so that endsubpath() must not
52 have been invoked), flush out the whole compound path. (It may
53 include other, previously drawn simple paths.) */
54 if (_plotter->drawstate->path)
55 _API_endpath (S___(_plotter));
56
57 if (!_plotter->drawstate->points_are_connected)
58 /* line type is `disconnected', so do nothing (libplot convention) */
59 {
60 }
61
62 else
63 /* general case */
64 {
65 plPoint pc;
66 bool clockwise;
67
68 /* determine whether ellipse's axes are aligned with the coordinate
69 axes in the user frame, so that (if the device->user frame map
70 preserves axes) the same will be true in the device frame */
71 bool aligned_ellipse = false;
72 int iangle = IROUND(angle);
73
74 if (iangle < 0)
75 iangle += (1 + (-iangle / 90)) * 90;
76 if (iangle % 90 == 0 && angle == (double)iangle)
77 aligned_ellipse = true;
78
79 /* begin a new path */
80 _plotter->drawstate->path = _new_plPath ();
81
82 /* place ellipse in path buffer */
83
84 pc.x = xc;
85 pc.y = yc;
86 clockwise = _plotter->drawstate->orientation < 0 ? true : false;
87
88 if ((_plotter->data->allowed_ellipse_scaling == AS_ANY)
89 ||
90 (_plotter->data->allowed_ellipse_scaling == AS_AXES_PRESERVED
91 && _plotter->drawstate->transform.axes_preserved
92 && aligned_ellipse))
93 /* place ellipse as a primitive, since this Plotter supports
94 drawing ellipses as primitives */
95 _add_ellipse (_plotter->drawstate->path,
96 pc, rx, ry, angle, clockwise);
97
98 else if (_plotter->data->allowed_ellarc_scaling == AS_ANY
99 || (_plotter->data->allowed_ellarc_scaling == AS_AXES_PRESERVED
100 && _plotter->drawstate->transform.axes_preserved
101 && aligned_ellipse))
102 /* draw ellipse by placing four elliptic arcs into path buffer
103 (allowed since this Plotter supports elliptic arcs) */
104 _add_ellipse_as_ellarcs (_plotter->drawstate->path,
105 pc, rx, ry, angle, clockwise);
106
107 else if (_plotter->data->allowed_cubic_scaling == AS_ANY)
108 /* draw ellipse by placing four cubic Beziers into path buffer
109 (allowed since this Plotter supports cubic Beziers) */
110 _add_ellipse_as_bezier3s (_plotter->drawstate->path,
111 pc, rx, ry, angle, clockwise);
112 else
113 /* draw a polygonal approximation to the ellipse */
114 _add_ellipse_as_lines (_plotter->drawstate->path,
115 pc, rx, ry, angle, clockwise);
116
117 if (_plotter->drawstate->path->type == PATH_SEGMENT_LIST)
118 /* pass all the newly added segments to the Plotter-specific
119 function maybe_paint_segments(), since some Plotters plot paths
120 in real time, i.e., prepaint them, rather than waiting until
121 endpath() is called */
122 _plotter->maybe_prepaint_segments (R___(_plotter) 0);
123 }
124
125 /* move to center (libplot convention) */
126 _plotter->drawstate->pos.x = xc;
127 _plotter->drawstate->pos.y = yc;
128
129 return 0;
130 }
131