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